diff --git a/first.jai b/first.jai index b1510b3..4e6ab43 100644 --- a/first.jai +++ b/first.jai @@ -1,4 +1,5 @@ #load "./src/meta/meta.jai"; +#load "./src/renderer_sokol/shaders/build.jai"; Iprof :: #import "Iprof"(IMPORT_MODE = .METAPROGRAM); #import "File_Utilities"; @@ -12,6 +13,7 @@ Trueno_Build_Options :: struct { test_game : bool; test_exe_engine : bool; test_exe_game : bool; + renderer : string = "sokol"; } // Engine tests build against test_game/ so they work without the game/ directory; @@ -25,6 +27,10 @@ build_options_from_args :: (args: []string) -> Trueno_Build_Options { opts : Trueno_Build_Options; for arg : args { + if begins_with(arg, "renderer=") { + opts.renderer = slice(arg, 9, arg.count - 9); + continue; + } if arg == { case "wasm"; opts.wasm_build = true; @@ -96,11 +102,13 @@ add_trueno_opts_to_compiler_strings :: (trueno_opts : Trueno_Build_Options, w: W trueno_opts_info := type_info(Trueno_Build_Options); for trueno_opts_info.members { + if it.type.type != .BOOL continue; optPtr := (cast(*bool)(*trueno_opts)) + it.offset_in_bytes; name := tprint("%", it.name); to_upper_in_place(name); add_build_string(tprint("FLAG_% :: %;\n", name, bool_to_string(optPtr.*)), w); } + add_build_string(tprint("RENDERER :: \"%\";\n", trueno_opts.renderer), w); } wasm_copy_assets :: () { @@ -245,6 +253,8 @@ wasm_build :: (opts: Build_Options, trueno_opts: Trueno_Build_Options) { use_test_game := uses_test_game(trueno_opts); create_pack(use_test_game, ifx use_test_game then "./test_packs" else "./packs"); + if trueno_opts.renderer == "sokol" && !compile_sokol_shaders() exit(1); + if trueno_opts.wasm_build { wasm_build(opt, trueno_opts); } else { diff --git a/src/main.jai b/src/main.jai index 51d9454..5016fd9 100644 --- a/src/main.jai +++ b/src/main.jai @@ -96,6 +96,7 @@ round_pow2 :: (v: float) -> s32 { debug_font : *Font; init :: () { + scene_init(); sfetch_setup(*(sfetch_desc_t.{ max_requests = 128, num_channels = 2, @@ -272,6 +273,7 @@ frame :: () { cleanup :: () { log_info("Cleanup called...."); audio_cleanup(); + scene_shutdown(); } get_window_size :: () -> (s32, s32) { diff --git a/src/meta/lint.jai b/src/meta/lint.jai index 80dfedf..02d8903 100644 --- a/src/meta/lint.jai +++ b/src/meta/lint.jai @@ -12,9 +12,8 @@ lint_checks :: (message: *Message) -> bool { if message.kind != .TYPECHECKED then return true; code := cast(*Message_Typechecked) message; - lint_ok := true; + lint_ok := lint_sokol_graphics(code); - for code.declarations { import := it.expression.enclosing_load.enclosing_import; if import.module_type != .MAIN_PROGRAM then return true; @@ -56,3 +55,39 @@ lint_procedure_name :: (name: string, node: Code_Node) -> bool { return true; } } + +lint_sokol_graphics :: (code: *Message_Typechecked) -> bool { + SOKOL_GRAPHICS_MODULES :: string.["gfx", "glue", "gl", "shape", "debugtext", "fontstash"]; + + is_sokol_graphics :: (path: string) -> bool { + for SOKOL_GRAPHICS_MODULES { + if contains(path, tprint("/sokol-jai/sokol/%/", it)) then return true; + } + return false; + } + + ok := true; + for code.all { + load := it.expression.enclosing_load; + if !load || !load.enclosing_import || load.enclosing_import.module_type != .MAIN_PROGRAM then continue; + if contains(load.fully_pathed_filename, "/renderer_sokol/") then continue; + in_scene := ends_with(load.fully_pathed_filename, "/rendering/scene.jai"); + + for sub: it.subexpressions { + if sub.kind != .IDENT then continue; + decl := (cast(*Code_Ident) sub).resolved_declaration; + if !decl || !decl.enclosing_load then continue; + decl_path := decl.enclosing_load.fully_pathed_filename; + if is_sokol_graphics(decl_path) { + compiler_report(sprint("Linter: % is sokol graphics; only src/renderer_sokol/ may use it\n", decl.name), make_location(sub), .ERROR); + } else if contains(decl_path, "/renderer_sokol/") && !in_scene { + compiler_report(sprint("Linter: % is part of the renderer; only src/rendering/scene.jai may use it\n", decl.name), make_location(sub), .ERROR); + } else { + continue; + } + lint_errors_found += 1; + ok = false; + } + } + return ok; +} diff --git a/src/renderer_sokol/renderer.jai b/src/renderer_sokol/renderer.jai new file mode 100644 index 0000000..317deae --- /dev/null +++ b/src/renderer_sokol/renderer.jai @@ -0,0 +1,92 @@ +#import,dir "../../modules/sokol-jai/sokol/gfx"(DEBUG = !FLAG_RELEASE_BUILD); +#import,dir "../../modules/sokol-jai/sokol/glue"(DEBUG = !FLAG_RELEASE_BUILD); + +#load "shaders/jai/ui.jai"; +#load "ui.jai"; + +renderer_init :: () { + sg_setup(*(sg_desc.{ + environment = cast,force(sg_environment) sglue_environment(), + logger = .{ func = slog_func }, + })); + + white := u8.[255, 255, 255, 255]; + renderer.white = make_image(1, 1, white); + + ui_init(); +} + +renderer_shutdown :: () { + sg_shutdown(); +} + +renderer_texture_create :: (width: s32, height: s32, pixels: []u8) -> u32 { + slot : *Renderer_Texture; + index : int; + if renderer.free_textures.count { + index = pop(*renderer.free_textures); + slot = *renderer.textures[index]; + } else { + index = renderer.textures.count; + slot = array_add(*renderer.textures); + } + slot.width = width; + slot.height = height; + slot.image = make_image(width, height, pixels); + return xx (index + 1); +} + +// Immutable images are recreated rather than updated, so a texture can be +// updated any number of times in a frame. +renderer_texture_update :: (id: u32, pixels: []u8) { + slot := *renderer.textures[id - 1]; + sg_destroy_image(slot.image); + slot.image = make_image(slot.width, slot.height, pixels); +} + +renderer_texture_destroy :: (id: u32) { + slot := *renderer.textures[id - 1]; + sg_destroy_image(slot.image); + slot.* = .{}; + array_add(*renderer.free_textures, xx (id - 1)); +} + +renderer_render :: (scene: *Scene, width: s32, height: s32) { + ui_upload(scene); + + pass_action : sg_pass_action; + pass_action.colors[0] = .{ load_action = .CLEAR, clear_value = .{0, 0, 0, 1} }; + sg_begin_pass(*(sg_pass.{ action = pass_action, swapchain = cast,force(sg_swapchain) sglue_swapchain() })); + ui_draw(scene, width, height); + sg_end_pass(); + sg_commit(); +} + +texture_image :: (id: u32) -> sg_image { + if id == 0 return renderer.white; + return renderer.textures[id - 1].image; +} + +#scope_file + +Renderer_Texture :: struct { + image : sg_image; + width : s32; + height : s32; +} + +renderer : struct { + textures : [..]Renderer_Texture; + free_textures : [..]s32; + white : sg_image; +} + +make_image :: (width: s32, height: s32, pixels: []u8) -> sg_image { + desc := sg_image_desc.{ + width = width, + height = height, + pixel_format = .RGBA8, + }; + desc.data.subimage[0][0] = .{ pixels.data, xx pixels.count }; + return sg_make_image(*desc); +} diff --git a/src/renderer_sokol/shaders/build.jai b/src/renderer_sokol/shaders/build.jai new file mode 100644 index 0000000..728fc7a --- /dev/null +++ b/src/renderer_sokol/shaders/build.jai @@ -0,0 +1,22 @@ +compile_sokol_shaders :: () -> bool { + dir :: "src/renderer_sokol/shaders"; + shdc :: #ifx OS == .MACOS then "sokol-shdc-mac" else "sokol-shdc"; + + for file_list(dir) { + if !ends_with(it, ".glsl") continue; + name := path_strip_extension(path_filename(it)); + out := tprint("%/jai/%.jai", dir, name); + + src_time := file_modtime_and_size(it); + out_time, _, out_exists := file_modtime_and_size(out); + if out_exists && compare_apollo_times(out_time, src_time) >= 0 continue; + + result, output, error := run_command(tprint("%/%", dir, shdc), "-i", it, "-o", out, + "-l", "glsl430:glsl300es:metal_macos", "-f", "sokol_jai", capture_and_return_output = true); + if result.exit_code != 0 { + log_error("sokol-shdc failed on %:\n%%", it, output, error); + return false; + } + } + return true; +} diff --git a/src/renderer_sokol/shaders/jai/ui.jai b/src/renderer_sokol/shaders/jai/ui.jai new file mode 100644 index 0000000..7353949 --- /dev/null +++ b/src/renderer_sokol/shaders/jai/ui.jai @@ -0,0 +1,422 @@ +/* + #version:1# (machine generated, don't edit!) + + Generated by sokol-shdc (https://github.com/floooh/sokol-tools) + + Cmdline: + sokol-shdc -i src/renderer_sokol/shaders/ui.glsl -o src/renderer_sokol/shaders/jai/ui.jai -l glsl430:glsl300es:metal_macos -f sokol_jai + + Overview: + ========= + Shader program: 'ui': + Get shader desc: ui_shader_desc(sg_query_backend()) + Vertex Shader: vs_ui + Fragment Shader: fs_ui + Attributes: + ATTR_ui_position => 0 + ATTR_ui_uv => 1 + ATTR_ui_color0 => 2 + Bindings: + Uniform block 'ui_vs_params': + Jai struct: Ui_Vs_Params + Bind slot: UB_ui_vs_params => 0 + Image 'tex': + Image type: ._2D + Sample type: .FLOAT + Multisampled: false + Bind slot: IMG_tex => 0 + Sampler 'smp': + Type: .FILTERING + Bind slot: SMP_smp => 0 +*/ +ATTR_ui_position :: 0; +ATTR_ui_uv :: 1; +ATTR_ui_color0 :: 2; +UB_ui_vs_params :: 0; +IMG_tex :: 0; +SMP_smp :: 0; +Ui_Vs_Params :: struct { + screen_size: [2]float; + _: [8]u8; +}; +/* + #version 430 + + uniform vec4 ui_vs_params[1]; + layout(location = 0) in vec2 position; + layout(location = 0) out vec2 v_uv; + layout(location = 1) in vec2 uv; + layout(location = 1) out vec4 v_color; + layout(location = 2) in vec4 color0; + + void main() + { + vec2 _26 = ((position / ui_vs_params[0].xy) * 2.0) - vec2(1.0); + gl_Position = vec4(_26.x, -_26.y, 0.0, 1.0); + v_uv = uv; + v_color = color0; + } + +*/ +vs_ui_source_glsl430 := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x75,0x6e, + 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x69,0x5f,0x76,0x73, + 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, + 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, + 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, + 0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32, + 0x20,0x76,0x5f,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76, + 0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c, + 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x6f,0x75,0x74, + 0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c, + 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f, + 0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29, + 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x32,0x20,0x5f,0x32,0x36,0x20, + 0x3d,0x20,0x28,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x75, + 0x69,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78, + 0x79,0x29,0x20,0x2a,0x20,0x32,0x2e,0x30,0x29,0x20,0x2d,0x20,0x76,0x65,0x63,0x32, + 0x28,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f, + 0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x32, + 0x36,0x2e,0x78,0x2c,0x20,0x2d,0x5f,0x32,0x36,0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30, + 0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x76,0x5f,0x75,0x76, + 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x20,0x20,0x76,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a, + 0x00, +]; +/* + #version 430 + + layout(binding = 16) uniform sampler2D tex_smp; + + layout(location = 0) out vec4 frag_color; + layout(location = 0) in vec2 v_uv; + layout(location = 1) in vec4 v_color; + + void main() + { + frag_color = texture(tex_smp, v_uv) * v_color; + } + +*/ +fs_ui_source_glsl430 := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x6c,0x61, + 0x79,0x6f,0x75,0x74,0x28,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x20,0x3d,0x20,0x31, + 0x36,0x29,0x20,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c, + 0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c, + 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61, + 0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, + 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, + 0x20,0x76,0x65,0x63,0x32,0x20,0x76,0x5f,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f, + 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29, + 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x5f,0x63,0x6f,0x6c,0x6f,0x72, + 0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, + 0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20, + 0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d, + 0x70,0x2c,0x20,0x76,0x5f,0x75,0x76,0x29,0x20,0x2a,0x20,0x76,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +/* + #version 300 es + + uniform vec4 ui_vs_params[1]; + layout(location = 0) in vec2 position; + out vec2 v_uv; + layout(location = 1) in vec2 uv; + out vec4 v_color; + layout(location = 2) in vec4 color0; + + void main() + { + vec2 _26 = ((position / ui_vs_params[0].xy) * 2.0) - vec2(1.0); + gl_Position = vec4(_26.x, -_26.y, 0.0, 1.0); + v_uv = uv; + v_color = color0; + } + +*/ +vs_ui_source_glsl300es := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, + 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x69, + 0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c, + 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69, + 0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x76, + 0x5f,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, + 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, + 0x32,0x20,0x75,0x76,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x76, + 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c, + 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20, + 0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f, + 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, + 0x76,0x65,0x63,0x32,0x20,0x5f,0x32,0x36,0x20,0x3d,0x20,0x28,0x28,0x70,0x6f,0x73, + 0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x75,0x69,0x5f,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29,0x20,0x2a,0x20,0x32,0x2e, + 0x30,0x29,0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x28,0x31,0x2e,0x30,0x29,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, + 0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x32,0x36,0x2e,0x78,0x2c,0x20,0x2d,0x5f, + 0x32,0x36,0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b, + 0x0a,0x20,0x20,0x20,0x20,0x76,0x5f,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x76,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f, + 0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +/* + #version 300 es + precision mediump float; + precision highp int; + + uniform highp sampler2D tex_smp; + + layout(location = 0) out highp vec4 frag_color; + in highp vec2 v_uv; + in highp vec4 v_color; + + void main() + { + frag_color = texture(tex_smp, v_uv) * v_color; + } + +*/ +fs_ui_source_glsl300es := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, + 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, + 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, + 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, + 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, + 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, + 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, + 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, + 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, + 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x76, + 0x5f,0x75,0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65, + 0x63,0x34,0x20,0x76,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69, + 0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, + 0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x76,0x5f,0x75, + 0x76,0x29,0x20,0x2a,0x20,0x76,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a, + 0x0a,0x00, +]; +/* + #include + #include + + using namespace metal; + + struct ui_vs_params + { + float2 screen_size; + }; + + struct main0_out + { + float2 v_uv [[user(locn0)]]; + float4 v_color [[user(locn1)]]; + float4 gl_Position [[position]]; + }; + + struct main0_in + { + float2 position [[attribute(0)]]; + float2 uv [[attribute(1)]]; + float4 color0 [[attribute(2)]]; + }; + + vertex main0_out main0(main0_in in [[stage_in]], constant ui_vs_params& _15 [[buffer(0)]]) + { + main0_out out = {}; + float2 _26 = ((in.position / _15.screen_size) * 2.0) - float2(1.0); + out.gl_Position = float4(_26.x, -_26.y, 0.0, 1.0); + out.v_uv = in.uv; + out.v_color = in.color0; + return out; + } + +*/ +vs_ui_source_metal_macos := u8.[ + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x75, + 0x69,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20, + 0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f, + 0x73,0x69,0x7a,0x65,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74, + 0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20, + 0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x76,0x5f,0x75,0x76,0x20,0x5b,0x5b,0x75, + 0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x76,0x5f,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f, + 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74, + 0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63, + 0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20, + 0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, + 0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d, + 0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x75,0x76, + 0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d, + 0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f, + 0x6c,0x6f,0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65, + 0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65, + 0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e, + 0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b, + 0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73, + 0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, + 0x73,0x26,0x20,0x5f,0x31,0x35,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28, + 0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e, + 0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x5f,0x32,0x36,0x20,0x3d, + 0x20,0x28,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f, + 0x20,0x5f,0x31,0x35,0x2e,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f,0x73,0x69,0x7a,0x65, + 0x29,0x20,0x2a,0x20,0x32,0x2e,0x30,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x32,0x28,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, + 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x34,0x28,0x5f,0x32,0x36,0x2e,0x78,0x2c,0x20,0x2d,0x5f,0x32,0x36, + 0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x76,0x5f,0x75,0x76,0x20,0x3d,0x20,0x69,0x6e, + 0x2e,0x75,0x76,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x76,0x5f,0x63, + 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74, + 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +/* + #include + #include + + using namespace metal; + + struct main0_out + { + float4 frag_color [[color(0)]]; + }; + + struct main0_in + { + float2 v_uv [[user(locn0)]]; + float4 v_color [[user(locn1)]]; + }; + + fragment main0_out main0(main0_in in [[stage_in]], texture2d tex [[texture(0)]], sampler smp [[sampler(0)]]) + { + main0_out out = {}; + out.frag_color = tex.sample(smp, in.v_uv) * in.v_color; + return out; + } + +*/ +fs_ui_source_metal_macos := u8.[ + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, + 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, + 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, + 0x76,0x5f,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, + 0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, + 0x20,0x76,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28, + 0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72, + 0x61,0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74, + 0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20, + 0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c, + 0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74, + 0x3e,0x20,0x74,0x65,0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, + 0x30,0x29,0x5d,0x5d,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d, + 0x70,0x20,0x5b,0x5b,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d, + 0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75, + 0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, + 0x20,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c, + 0x20,0x69,0x6e,0x2e,0x76,0x5f,0x75,0x76,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x76, + 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75, + 0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +ui_shader_desc :: (backend: sg_backend) -> sg_shader_desc { + desc: sg_shader_desc; + desc.label = "ui_shader"; + if backend == { + case .GLCORE; + desc.vertex_func.source = xx *vs_ui_source_glsl430; + desc.vertex_func.entry = "main"; + desc.fragment_func.source = xx *fs_ui_source_glsl430; + desc.fragment_func.entry = "main"; + desc.attrs[0].base_type = .FLOAT; + desc.attrs[0].glsl_name = "position"; + desc.attrs[1].base_type = .FLOAT; + desc.attrs[1].glsl_name = "uv"; + desc.attrs[2].base_type = .FLOAT; + desc.attrs[2].glsl_name = "color0"; + desc.uniform_blocks[0].stage = .VERTEX; + desc.uniform_blocks[0].layout = .STD140; + desc.uniform_blocks[0].size = 16; + desc.uniform_blocks[0].glsl_uniforms[0].type = .FLOAT4; + desc.uniform_blocks[0].glsl_uniforms[0].array_count = 1; + desc.uniform_blocks[0].glsl_uniforms[0].glsl_name = "ui_vs_params"; + desc.images[0].stage = .FRAGMENT; + desc.images[0].multisampled = false; + desc.images[0].image_type = ._2D; + desc.images[0].sample_type = .FLOAT; + desc.samplers[0].stage = .FRAGMENT; + desc.samplers[0].sampler_type = .FILTERING; + desc.image_sampler_pairs[0].stage = .FRAGMENT; + desc.image_sampler_pairs[0].image_slot = 0; + desc.image_sampler_pairs[0].sampler_slot = 0; + desc.image_sampler_pairs[0].glsl_name = "tex_smp"; + case .GLES3; + desc.vertex_func.source = xx *vs_ui_source_glsl300es; + desc.vertex_func.entry = "main"; + desc.fragment_func.source = xx *fs_ui_source_glsl300es; + desc.fragment_func.entry = "main"; + desc.attrs[0].base_type = .FLOAT; + desc.attrs[0].glsl_name = "position"; + desc.attrs[1].base_type = .FLOAT; + desc.attrs[1].glsl_name = "uv"; + desc.attrs[2].base_type = .FLOAT; + desc.attrs[2].glsl_name = "color0"; + desc.uniform_blocks[0].stage = .VERTEX; + desc.uniform_blocks[0].layout = .STD140; + desc.uniform_blocks[0].size = 16; + desc.uniform_blocks[0].glsl_uniforms[0].type = .FLOAT4; + desc.uniform_blocks[0].glsl_uniforms[0].array_count = 1; + desc.uniform_blocks[0].glsl_uniforms[0].glsl_name = "ui_vs_params"; + desc.images[0].stage = .FRAGMENT; + desc.images[0].multisampled = false; + desc.images[0].image_type = ._2D; + desc.images[0].sample_type = .FLOAT; + desc.samplers[0].stage = .FRAGMENT; + desc.samplers[0].sampler_type = .FILTERING; + desc.image_sampler_pairs[0].stage = .FRAGMENT; + desc.image_sampler_pairs[0].image_slot = 0; + desc.image_sampler_pairs[0].sampler_slot = 0; + desc.image_sampler_pairs[0].glsl_name = "tex_smp"; + case .METAL_MACOS; + desc.vertex_func.source = xx *vs_ui_source_metal_macos; + desc.vertex_func.entry = "main0"; + desc.fragment_func.source = xx *fs_ui_source_metal_macos; + desc.fragment_func.entry = "main0"; + desc.attrs[0].base_type = .FLOAT; + desc.attrs[1].base_type = .FLOAT; + desc.attrs[2].base_type = .FLOAT; + desc.uniform_blocks[0].stage = .VERTEX; + desc.uniform_blocks[0].layout = .STD140; + desc.uniform_blocks[0].size = 16; + desc.uniform_blocks[0].msl_buffer_n = 0; + desc.images[0].stage = .FRAGMENT; + desc.images[0].multisampled = false; + desc.images[0].image_type = ._2D; + desc.images[0].sample_type = .FLOAT; + desc.images[0].msl_texture_n = 0; + desc.samplers[0].stage = .FRAGMENT; + desc.samplers[0].sampler_type = .FILTERING; + desc.samplers[0].msl_sampler_n = 0; + desc.image_sampler_pairs[0].stage = .FRAGMENT; + desc.image_sampler_pairs[0].image_slot = 0; + desc.image_sampler_pairs[0].sampler_slot = 0; + } + return desc; +} diff --git a/src/renderer_sokol/shaders/sokol-shdc b/src/renderer_sokol/shaders/sokol-shdc new file mode 100755 index 0000000..13500ba Binary files /dev/null and b/src/renderer_sokol/shaders/sokol-shdc differ diff --git a/src/renderer_sokol/shaders/sokol-shdc-mac b/src/renderer_sokol/shaders/sokol-shdc-mac new file mode 100755 index 0000000..17e99ca Binary files /dev/null and b/src/renderer_sokol/shaders/sokol-shdc-mac differ diff --git a/src/renderer_sokol/shaders/ui.glsl b/src/renderer_sokol/shaders/ui.glsl new file mode 100644 index 0000000..1f9bc04 --- /dev/null +++ b/src/renderer_sokol/shaders/ui.glsl @@ -0,0 +1,34 @@ +@vs vs_ui +in vec2 position; +in vec2 uv; +in vec4 color0; + +layout(binding=0) uniform ui_vs_params { + vec2 screen_size; +}; + +out vec2 v_uv; +out vec4 v_color; + +void main() { + vec2 ndc = position / screen_size * 2.0 - 1.0; + gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0); + v_uv = uv; + v_color = color0; +} +@end + +@fs fs_ui +in vec2 v_uv; +in vec4 v_color; +out vec4 frag_color; + +layout(binding=0) uniform texture2D tex; +layout(binding=0) uniform sampler smp; + +void main() { + frag_color = texture(sampler2D(tex, smp), v_uv) * v_color; +} +@end + +@program ui vs_ui fs_ui diff --git a/src/renderer_sokol/ui.jai b/src/renderer_sokol/ui.jai new file mode 100644 index 0000000..b40ff30 --- /dev/null +++ b/src/renderer_sokol/ui.jai @@ -0,0 +1,73 @@ +ui_init :: () { + shader_desc := ui_shader_desc(sg_query_backend()); + + desc : sg_pipeline_desc; + desc.shader = sg_make_shader(*shader_desc); + desc.layout.attrs[ATTR_ui_position] = .{ format = .FLOAT2 }; + desc.layout.attrs[ATTR_ui_uv] = .{ format = .FLOAT2 }; + desc.layout.attrs[ATTR_ui_color0] = .{ format = .FLOAT4 }; + desc.colors[0].blend = .{ + enabled = true, + src_factor_rgb = .SRC_ALPHA, + dst_factor_rgb = .ONE_MINUS_SRC_ALPHA, + }; + ui.pipeline = sg_make_pipeline(*desc); + + ui.sampler = sg_make_sampler(*(sg_sampler_desc.{ + wrap_u = .CLAMP_TO_EDGE, + wrap_v = .CLAMP_TO_EDGE, + min_filter = .NEAREST, + mag_filter = .NEAREST, + })); +} + +ui_upload :: (scene: *Scene) { + array_reset_keeping_memory(*ui.vertices); + for scene.ui array_add(*ui.vertices, ..it.vertices); + if ui.vertices.count == 0 return; + + size := ui.vertices.count * size_of(Ui_Vertex); + if size > ui.buffer_size { + if ui.buffer_size sg_destroy_buffer(ui.buffer); + ui.buffer_size = max(size, ui.buffer_size * 2); + ui.buffer = sg_make_buffer(*(sg_buffer_desc.{ size = xx ui.buffer_size, usage = .STREAM })); + } + sg_update_buffer(ui.buffer, *(sg_range.{ ui.vertices.data, xx size })); +} + +ui_draw :: (scene: *Scene, w: s32, h: s32) { + if ui.vertices.count == 0 return; + + sg_apply_pipeline(ui.pipeline); + params := Ui_Vs_Params.{ screen_size = .[xx w, xx h] }; + sg_apply_uniforms(UB_ui_vs_params, *(sg_range.{ *params, size_of(Ui_Vs_Params) })); + + bind : sg_bindings; + bind.vertex_buffers[0] = ui.buffer; + bind.samplers[SMP_smp] = ui.sampler; + + first : s32; + for scene.ui { + if it.set_scissor { + s := it.scissor; + sg_apply_scissor_rect(s.x, s.y, max(s.w, 0), max(s.h, 0), true); + } else if it.clear_scissor { + sg_apply_scissor_rect(0, 0, w, h, true); + } else if it.vertices.count { + bind.images[IMG_tex] = texture_image(it.texture.id); + sg_apply_bindings(*bind); + sg_draw(first, xx it.vertices.count, 1); + first += xx it.vertices.count; + } + } +} + +#scope_file + +ui : struct { + pipeline : sg_pipeline; + sampler : sg_sampler; + buffer : sg_buffer; + buffer_size : int; + vertices : [..]Ui_Vertex; +} diff --git a/src/rendering/rendering.jai b/src/rendering/rendering.jai index 50d2f29..0986f98 100644 --- a/src/rendering/rendering.jai +++ b/src/rendering/rendering.jai @@ -7,9 +7,16 @@ #load "debug_draw.jai"; #load "animation.jai"; +#if RENDERER == "sokol" { + #load "../renderer_sokol/renderer.jai"; +} else { + #assert false "Unknown renderer; build with renderer=sokol."; +} + render :: () { text_end_frame(); - scene_end_frame(); + w, h := get_window_size(); + scene_end_frame(w, h); g_debug_line_count = 0; g_overlay_line_count = 0; } diff --git a/src/rendering/scene.jai b/src/rendering/scene.jai index 8c26b71..28e8315 100644 --- a/src/rendering/scene.jai +++ b/src/rendering/scene.jai @@ -1,14 +1,13 @@ -// The Scene API. Game, editor and UI code say what to draw through this file; -// how it gets drawn is the renderer's business. The world is persistent: chunks -// are uploaded when loaded or edited. Everything else is submitted every frame -// and dropped by render(). +// The new scene API. The idea is that what to draw is defined trough this, +// and the renderer can be nicely separated and tested. +// +// I'm also planning to maybe add a WGPU backend at some point or something. Trile_Mesh :: struct { id: u32; } Texture :: struct { id: u32; } Font_Face :: struct { id: s32; } View_Id :: struct { index: s32; } -// Grows as each part of the renderer comes back: sky, sun, fog, water, post. Environment :: struct { } @@ -24,7 +23,7 @@ Trile_Tint :: enum u8 { DELETE_PREVIEW; } -// A billboard with this face direction turns to face the camera. +// This direction means that the billboard should face the camera. BILLBOARD_FACE_CAMERA :: Vector3.{-100, -100, -100}; Blend_Mode :: enum u8 { @@ -35,19 +34,17 @@ Blend_Mode :: enum u8 { Particle_Instance :: struct { position : Vector3; size : float; - uv_rect : Vector4; // x, y, w, h in the sheet, normalized + uv_rect : Vector4; // x, y, w, h, 0..1 color : Vector4; } -// Screen-space, in pixels from the top left. +// Pixels from top left. Ui_Vertex :: struct { position : Vector2; uv : Vector2; color : Vector4; } -// --- Persistent resources ------------------------------------------------- - trile_mesh_create :: (trile: *Trile) -> Trile_Mesh { scene.trile_mesh_count += 1; return .{scene.trile_mesh_count}; @@ -61,24 +58,22 @@ trile_mesh_destroy :: (mesh: Trile_Mesh) { // Pixels are RGBA8. texture_create :: (width: s32, height: s32, pixels: []u8) -> Texture { - scene.texture_count += 1; - return .{scene.texture_count}; + return .{renderer_texture_create(width, height, pixels)}; } texture_update :: (texture: Texture, pixels: []u8) { + renderer_texture_update(texture.id, pixels); } texture_destroy :: (texture: Texture) { + renderer_texture_destroy(texture.id); } -// --- Persistent world ----------------------------------------------------- - World_Group :: struct { mesh : Trile_Mesh; instances : []Trile_Instance; } -// Replaces whatever the chunk held before. The groups are copied. world_set_chunk :: (key: Chunk_Key, groups: []World_Group) { chunk := find_or_add(*scene.chunks, key); for chunk.groups array_free(it.instances); @@ -106,8 +101,6 @@ world_clear :: () { table_reset(*scene.chunks); } -// --- Per frame ------------------------------------------------------------ - add_view :: (view: View) -> View_Id { array_add(*scene.views, view); return .{xx (scene.views.count - 1)}; @@ -139,8 +132,6 @@ ui_scissor_clear :: () { array_add(*scene.ui, .{clear_scissor = true}); } -// --- Renderer side: only src/rendering reads these ------------------------- - Scene_Chunk :: struct { groups : [..]World_Group; } @@ -169,7 +160,6 @@ Scene_Particles :: struct { particles : []Particle_Instance; } -// One entry of the UI stream: either a batch of triangles or a scissor change. Scene_Ui :: struct { texture : Texture; vertices : []Ui_Vertex; @@ -178,9 +168,8 @@ Scene_Ui :: struct { clear_scissor : bool; } -scene : struct { +Scene :: struct { trile_mesh_count : u32; - texture_count : u32; chunks : Table(Chunk_Key, Scene_Chunk, chunk_key_hash, chunk_key_compare); @@ -191,10 +180,23 @@ scene : struct { ui : [..]Scene_Ui; } -scene_end_frame :: () { +scene_init :: () { + renderer_init(); +} + +scene_shutdown :: () { + renderer_shutdown(); +} + +scene_end_frame :: (width: s32, height: s32) { + renderer_render(*scene, width, height); array_reset_keeping_memory(*scene.views); array_reset_keeping_memory(*scene.triles); array_reset_keeping_memory(*scene.billboards); array_reset_keeping_memory(*scene.particles); array_reset_keeping_memory(*scene.ui); } + +#scope_file + +scene : Scene;