Pipeline_State_Handle :: #type, distinct u32; Shader_Handle :: #type, distinct u32; Buffer_Handle :: #type, distinct u32; Texture_Handle :: #type, distinct u32; Sampler_Handle :: #type, distinct u32; Render_Target_Handle :: #type, distinct u32; Depth_Stencil_Buffer_Handle :: #type, distinct u32; Format :: enum { UNKNOWN :: 0; R32G32B32A32_TYPELESS :: 1; R32G32B32A32_FLOAT :: 2; R32G32B32A32_UINT :: 3; R32G32B32A32_SINT :: 4; R32G32B32_TYPELESS :: 5; R32G32B32_FLOAT :: 6; R32G32B32_UINT :: 7; R32G32B32_SINT :: 8; R16G16B16A16_TYPELESS :: 9; R16G16B16A16_FLOAT :: 10; R16G16B16A16_UNORM :: 11; R16G16B16A16_UINT :: 12; R16G16B16A16_SNORM :: 13; R16G16B16A16_SINT :: 14; R32G32_TYPELESS :: 15; R32G32_FLOAT :: 16; R32G32_UINT :: 17; R32G32_SINT :: 18; R32G8X24_TYPELESS :: 19; D32_FLOAT_S8X24_UINT :: 20; R32_FLOAT_X8X24_TYPELESS :: 21; X32_TYPELESS_G8X24_UINT :: 22; R10G10B10A2_TYPELESS :: 23; R10G10B10A2_UNORM :: 24; R10G10B10A2_UINT :: 25; R11G11B10_FLOAT :: 26; R8G8B8A8_TYPELESS :: 27; R8G8B8A8_UNORM :: 28; R8G8B8A8_UNORM_SRGB :: 29; R8G8B8A8_UINT :: 30; R8G8B8A8_SNORM :: 31; R8G8B8A8_SINT :: 32; R16G16_TYPELESS :: 33; R16G16_FLOAT :: 34; R16G16_UNORM :: 35; R16G16_UINT :: 36; R16G16_SNORM :: 37; R16G16_SINT :: 38; R32_TYPELESS :: 39; D32_FLOAT :: 40; R32_FLOAT :: 41; R32_UINT :: 42; R32_SINT :: 43; R24G8_TYPELESS :: 44; D24_UNORM_S8_UINT :: 45; R24_UNORM_X8_TYPELESS :: 46; X24_TYPELESS_G8_UINT :: 47; R8G8_TYPELESS :: 48; R8G8_UNORM :: 49; R8G8_UINT :: 50; R8G8_SNORM :: 51; R8G8_SINT :: 52; R16_TYPELESS :: 53; R16_FLOAT :: 54; D16_UNORM :: 55; R16_UNORM :: 56; R16_UINT :: 57; R16_SNORM :: 58; R16_SINT :: 59; R8_TYPELESS :: 60; R8_UNORM :: 61; R8_UINT :: 62; R8_SNORM :: 63; R8_SINT :: 64; A8_UNORM :: 65; R1_UNORM :: 66; R9G9B9E5_SHAREDEXP :: 67; R8G8_B8G8_UNORM :: 68; G8R8_G8B8_UNORM :: 69; BC1_TYPELESS :: 70; BC1_UNORM :: 71; BC1_UNORM_SRGB :: 72; BC2_TYPELESS :: 73; BC2_UNORM :: 74; BC2_UNORM_SRGB :: 75; BC3_TYPELESS :: 76; BC3_UNORM :: 77; BC3_UNORM_SRGB :: 78; BC4_TYPELESS :: 79; BC4_UNORM :: 80; BC4_SNORM :: 81; BC5_TYPELESS :: 82; BC5_UNORM :: 83; BC5_SNORM :: 84; B5G6R5_UNORM :: 85; B5G5R5A1_UNORM :: 86; B8G8R8A8_UNORM :: 87; B8G8R8X8_UNORM :: 88; R10G10B10_XR_BIAS_A2_UNORM :: 89; B8G8R8A8_TYPELESS :: 90; B8G8R8A8_UNORM_SRGB :: 91; B8G8R8X8_TYPELESS :: 92; B8G8R8X8_UNORM_SRGB :: 93; BC6H_TYPELESS :: 94; BC6H_UF16 :: 95; BC6H_SF16 :: 96; BC7_TYPELESS :: 97; BC7_UNORM :: 98; BC7_UNORM_SRGB :: 99; AYUV :: 100; Y410 :: 101; Y416 :: 102; NV12 :: 103; P010 :: 104; P016 :: 105; //420_OPAQUE :: 106; YUY2 :: 107; Y210 :: 108; Y216 :: 109; NV11 :: 110; AI44 :: 111; IA44 :: 112; P8 :: 113; A8P8 :: 114; B4G4R4A4_UNORM :: 115; P208 :: 130; V208 :: 131; V408 :: 132; SAMPLER_FEEDBACK_MIN_MIP_OPAQUE; SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE; FORCE_UINT :: 0xffffffff; } SWAPCHAIN_SIZE :: 42000; Render_Target :: struct { width: u32; height: u32; format: Format; backend_render_target: Backend_Render_Target; texture: Texture_Handle; actual_width: u32; actual_height: u32; } Depth_Stencil_Buffer :: struct { width: u32; height: u32; format: Format; backend_depth_stencil_buffer: Backend_Depth_Stencil_Buffer; actual_width: u32; actual_height: u32; } Blend_Type :: enum { OPAQUE; TRANSPARENT; } Shader_Type :: enum { VERTEX; PIXEL; } Shader_Info :: struct { input: [..] Vertex_Input; parameters: [..] Shader_Parameter; } Shader :: struct { compiled : bool; type : Shader_Type; backend_shader : Backend_Shader; defines : [..] string; mesh_data_types : [..] Mesh_Vertex_Data_Type; entry_point : string; info : Shader_Info; path: string; } Primitive_Topology :: enum { TRIANGLE_LIST; LINE_LIST; TRIANGLE_STRIP; LINE_STRIP; } Buffer_Type :: enum { VERTEX; INDEX; CONSTANT; STRUCTURED; } Vertex_Data_Type :: enum { POSITION; POSITION2D; POSITION1; POSITION1_2D; NORMAL; COLOR; COLOR_WITH_ALPHA; COLOR_WITH_ALPHA8; TEXCOORD0; TEXCOORD1; TEXCOORD2; TEXCOORD3; TEXCOORD4; COLOR0; TANGENT0; TANGENT1; INSTANCED_MAT0; INSTANCED_MAT1; INSTANCED_MAT2; INSTANCED_MAT3; VERTEX_ID; INSTANCE_ID; } Vertex_Data_Info :: struct { slot: s32; type: Vertex_Data_Type; instanced_step_rate: s32 = 0; } Vertex_Input :: struct { format : Format; mesh_data_type : Mesh_Vertex_Data_Type; slot: int; semantic_name: string; semantic_index: int; instanced_step_rate: s32; } Buffer :: struct { type : Buffer_Type; stride : u32; backend_buffer : Backend_Buffer; } Texture :: struct { //format; width: u32; height: u32; backend_texture: Backend_Texture; format: Format; path: string; } Sampling_Filter :: enum { POINT; LINEAR; ANISOTROPIC; } Wrap_Mode :: enum { CLAMP; REPEAT; } Sampler :: struct { filter: Sampling_Filter; wrap_mode: Wrap_Mode; backend_sampler : Backend_Sampler; } Cull_Face :: enum { NONE; FRONT; BACK; } Shader_Parameter_Mapping :: enum { NONE; TIME; MODEL_MATRIX; MATERIAL; CAMERA_DATA; DIRECTIONAL_LIGHT; POINT_LIGHTS; BONE_MATRICES; BASE_COLOR_TEXTURE; NORMAL_MAP; SCREEN_DATA; SHADER_ATTACHMENT0; SHADER_ATTACHMENT1; SHADER_ATTACHMENT2; SHADER_ATTACHMENT3; SHADER_ATTACHMENT4; SHADER_ATTACHMENT5; SHADER_ATTACHMENT6; REPEAT_SAMPLER; CLAMP_SAMPLER; CUSTOM; } Shader_Parameter_Type :: enum { BUFFER; TEXTURE; SAMPLER; } Shader_Property_Type :: enum { INVALID; FLOAT; FLOAT2; FLOAT3; FLOAT4; MATRIX3; MATRIX4; INTEGER; BOOL; TEXTURE; SAMPLER; } Shader_Property :: struct { type : Shader_Property_Type; name: string; buffer_offset: u32; } Shader_Parameter :: struct { name: string; type: Shader_Parameter_Type; mapping: Shader_Parameter_Mapping; mapping_str: string; shader: Shader_Type; slot: u32; default_value : struct { union { buffer: Buffer_Handle; texture: Texture_Handle; sampler: Sampler_Handle; } } size: u32; // Only for buffers properties: [16] Shader_Property; num_properties: s64; } Pipeline_State :: struct { vs : Shader_Handle; ps : Shader_Handle; mesh_data_types : [..] Mesh_Vertex_Data_Type; vertex_layout : Backend_Vertex_Input; blend_state : Backend_Blend_State; blend_type : Blend_Type; shader_input: : [..] Vertex_Data_Info; shader_parameters : [..] Shader_Parameter; is_new : bool; } Material_Property_Old :: struct { parameter : Shader_Parameter; union { buffer: Buffer_Handle; texture: Texture_Handle; sampler: Sampler_Handle; } } Material_Pass_Old :: struct { pass: Render_Pass_Handle; pipeline: Pipeline_State_Handle; properties: [..] Material_Property_Old; } Base_Material :: struct { base_color : Vector4; } Material_Old :: struct { passes: [..] Material_Pass_Old; depth_write : bool = true; cull_face : Cull_Face = .BACK; } Draw_Mode :: enum { FILL; WIREFRAME; } Render_Command_Type :: enum { SET_PIPELINE_STATE; SET_VERTEX_BUFFER; SET_INDEX_BUFFER; SET_CONSTANT_BUFFER; SET_STRUCTURED_BUFFER; SET_TEXTURE; SET_TEXTURE_FROM_RENDER_TARGET; SET_TEXTURE_FROM_DEPTH_STENCIL; SET_RENDER_TARGETS; SET_BACKBUFFER; SET_SAMPLER; SET_VIEWPORT; SET_SCISSOR; CLEAR_SCISSOR; CLEAR_RENDER_TARGET; CLEAR_DEPTH_STENCIL; CLEAR_BACKBUFFER; DRAW; DRAW_INDEXED; DRAW_INSTANCED; DRAW_INDEXED_INSTANCED; SET_DRAW_MODE; SET_CULL_FACE; SET_DEPTH_WRITE; RENDER_IMGUI; } MAX_RENDER_TARGETS :: 8; Render_Command :: struct { type : Render_Command_Type; union { set_pipeline_state : struct { vs: Backend_Shader; ps: Backend_Shader; vertex_layout: Backend_Vertex_Input; blend_type: Blend_Type; blend_state: Backend_Blend_State; } set_vertex_buffer : struct { buffer: Backend_Buffer; stride: u32; offset: u32; start_slot: u32; } set_index_buffer : struct { buffer: Backend_Buffer; } set_constant_buffer : struct { buffer : Backend_Buffer; slot : u32; shader_type : Shader_Type; } set_structured_buffer : struct { buffer : Backend_Buffer; slot : u32; shader_type : Shader_Type; } set_texture : struct { texture : Backend_Texture; slot : u32; } set_texture_from_rt : struct { rt : Backend_Render_Target; slot : u32; } set_texture_from_ds : struct { ds : Backend_Depth_Stencil_Buffer; slot : u32; } set_render_targets : struct { render_targets: [MAX_RENDER_TARGETS] Backend_Render_Target; num_render_targets: u32; depth_stencil_enabled: bool; depth_stencil_buffer: Backend_Depth_Stencil_Buffer; } set_backbuffer : struct { } set_sampler : struct { sampler : Backend_Sampler; slot : u32; } set_viewport : struct { width: u32; height: u32; x: u32; y: u32; min_depth: float; max_depth: float = 1.0; } set_scissor : struct { width: u32; height: u32; x: u32; y: u32; } clear_render_target : struct { rt: Backend_Render_Target; color : Vector4; } clear_depth_stencil : struct { ds: Backend_Depth_Stencil_Buffer; depth: float; } clear_backbuffer : struct { color : Vector4; } draw : struct { topology : Primitive_Topology; vertex_count : s64; start_vertex_index : s64; } draw_instanced : struct { topology : Primitive_Topology; vertex_count : s64; instance_count: u32; start_vertex_index : s64; start_instance_index : s64; } draw_indexed : struct { topology : Primitive_Topology; index_count : s64; start_index : s64; base_vertex : s64; } draw_indexed_instanced : struct { topology : Primitive_Topology; index_count : s64; instance_count: u32; start_index : s64; base_vertex : s64; } set_draw_mode : struct { draw_mode : Draw_Mode; } set_cull_face : struct { cull_face : Cull_Face; } set_depth_write : struct { enabled : bool; } } } Render_Command_Buffer :: struct { commands: [..] Render_Command; } Material_Mapping_Info :: struct { buffer: Buffer_Handle; texture: Texture_Handle; } Renderer :: struct { pool : Flat_Pool; allocator : Allocator; backend : *Graphics_Backend; command_buffer : Render_Command_Buffer; draw_call_count : s32; last_draw_call_count : s32; last_render_time_cpu : float; last_render_time_gpu : float; shaders : [..] Shader; buffers : PArray(Buffer, Buffer_Handle); textures : PArray(Texture, Texture_Handle); render_targets : PArray(Render_Target, Render_Target_Handle); depth_stencil_buffers : PArray(Depth_Stencil_Buffer, Depth_Stencil_Buffer_Handle); meshes : PArray(Mesh, Mesh_Handle); samplers : [..] Sampler; pipeline_states : [..] Pipeline_State; fonts : [..] Font; render_graph : *Render_Graph; model_lib : Static_Array(Model, 128); callbacks : struct { get_custom_material_parameter_mapping: (mapping_str: string) -> bool, Material_Mapping_Info; } current_state : struct { last_set_pipeline : Pipeline_State_Handle; } // Text buffers max_characters_per_buffer :: 256; used_text_buffers_count: u32; text_render_buffers : [..] Buffer_Handle; render_target_width: u32; render_target_height: u32; default_models : struct { sphere: Model_Handle; } default_meshes : struct { plane : Mesh_Handle; cube : Mesh_Handle; sphere : Mesh_Handle; capsule : Mesh_Handle; fullscreen_plane : Mesh_Handle; textured_quad : Mesh_Handle; translation_gizmo : Mesh_Handle; scale_gizmo : Mesh_Handle; rotation_gizmo : Mesh_Handle; } default_pipelines : struct { message_text : Pipeline_State_Handle; } default_samplers : struct { repeat : Sampler_Handle; clamp : Sampler_Handle; } default_textures : struct { fallback : Texture_Handle; } watcher: File_Watcher(string); vsync: bool = true; } create_renderer :: (window: *Window) -> *Renderer { engine.renderer = New(Renderer); engine.renderer.pool = .{}; a : Allocator; a.proc = flat_pool_allocator_proc; a.data = *engine.renderer.pool; engine.renderer.allocator = a; if !init(*engine.renderer.watcher, file_change_callback, *"Cowabunga", events_to_watch = .MODIFIED) { log_error("Could not initialize watcher"); } // @Incomplete //if !add_directories(*engine.renderer.watcher, "../assets/shaders") { // exit(4); //} engine.renderer.backend = create_backend(window); engine.renderer.render_target_width = engine.window.width; engine.renderer.render_target_height = engine.window.height; engine.renderer.pipeline_states.allocator = engine.renderer.allocator; engine.renderer.fonts.allocator = engine.renderer.allocator; engine.renderer.textures.data.allocator = engine.renderer.allocator; engine.renderer.textures.indices.allocator = engine.renderer.allocator; engine.renderer.buffers.data.allocator = engine.renderer.allocator; engine.renderer.buffers.indices.allocator = engine.renderer.allocator; engine.renderer.shaders.allocator = engine.renderer.allocator; engine.renderer.command_buffer.commands.allocator = engine.renderer.allocator; engine.renderer.text_render_buffers.allocator = engine.renderer.allocator; engine.renderer.render_targets.data.allocator = engine.renderer.allocator; engine.renderer.render_targets.indices.allocator = engine.renderer.allocator; engine.renderer.depth_stencil_buffers.data.allocator = engine.renderer.allocator; engine.renderer.depth_stencil_buffers.indices.allocator = engine.renderer.allocator; for 0..1024 { buffer := create_vertex_buffer(engine.renderer, null, size_of(Point) * 6 * engine.renderer.max_characters_per_buffer, stride=size_of(Point), mappable=true); array_add(*engine.renderer.text_render_buffers, buffer); } init_freetype(); init_default_meshes(); init_trigger_line_rendering(); array_reserve(*engine.renderer.command_buffer.commands, 4096); engine.renderer.render_graph = new_render_graph(); data := u8.[255]; engine.renderer.default_textures.fallback = create_texture(engine.renderer, data.data, 1, 1, 1, "engine/fallback", generate_mips=false, .R8_UNORM); return engine.renderer; } init_default_pipelines :: () { { vs := create_vertex_shader(renderer, "../modules/Coven/shaders/font.hlsl", "VS"); ps := create_pixel_shader(renderer, "../modules/Coven/shaders/font.hlsl", "PS"); layout : [3] Vertex_Data_Info; layout[0] = .{0,.POSITION2D, 0}; layout[1] = .{0,.TEXCOORD0, 0}; layout[2] = .{0,.COLOR_WITH_ALPHA, 0}; params : [2] Shader_Parameter; params[0].shader = .PIXEL; params[0].type = .SAMPLER; params[0].name = "ss"; params[0].slot = 0; params[0].mapping = .CLAMP_SAMPLER; params[1].shader = .PIXEL; params[1].type = .TEXTURE; params[1].name = "tex"; params[1].slot = 1; engine.renderer.default_pipelines.message_text = create_pipeline_state(renderer, vs, ps, layout, params, blend_type=.TRANSPARENT); } { vs := create_vertex_shader_from_source(engine.renderer, FALLBACK_SHADER, "VS", mesh_data_types = .[.POSITION]); ps := create_pixel_shader_from_source(engine.renderer, FALLBACK_SHADER, "PS"); projectile_pipeline = create_pipeline_state2(engine.renderer, vs, ps, blend_type=.OPAQUE); } } init_default_meshes :: () { { // Default plane // Since this is used for sprites, we want the origin to be in the center in x, but at the bottom in y mesh : Mesh; mesh.name = copy_string("Plane"); array_add(*mesh.positions, .{1, 0, 1}); array_add(*mesh.positions, .{-1, 0, -1}); array_add(*mesh.positions, .{1, 0, -1}); array_add(*mesh.positions, .{-1, 0, 1}); array_add(*mesh.normals, .{0, 1, 0}); array_add(*mesh.normals, .{0, 1, 0}); array_add(*mesh.normals, .{0, 1, 0}); array_add(*mesh.normals, .{0, 1, 0}); array_add(*mesh.texcoords, .{1, 0}); array_add(*mesh.texcoords, .{0, 1}); array_add(*mesh.texcoords, .{1, 1}); array_add(*mesh.texcoords, .{0, 0}); array_add(*mesh.indices, 2); array_add(*mesh.indices, 1); array_add(*mesh.indices, 0); array_add(*mesh.indices, 1); array_add(*mesh.indices, 3); array_add(*mesh.indices, 0); stride := size_of(float)*8; vb_size := stride*mesh.positions.count; ib_size := size_of(u32)*mesh.indices.count; //mesh.vb = create_vertex_buffer(renderer, vertices.data, xx vb_size, stride=xx stride); mesh.ib = create_index_buffer(engine.renderer, mesh.indices.data, xx ib_size); engine.renderer.default_meshes.plane = parray_add(*engine.renderer.meshes, mesh); } { // Fullscreeboat_n plane mesh : Mesh; array_add(*mesh.positions, .{1, 1, 0}); array_add(*mesh.positions, .{-1, -1, 0}); array_add(*mesh.positions, .{1, -1, 0}); array_add(*mesh.positions, .{-1, 1, 0}); array_add(*mesh.texcoords, .{1, 0}); array_add(*mesh.texcoords, .{0, 1}); array_add(*mesh.texcoords, .{1, 1}); array_add(*mesh.texcoords, .{0, 0}); array_add(*mesh.indices, 2); array_add(*mesh.indices, 1); array_add(*mesh.indices, 0); array_add(*mesh.indices, 1); array_add(*mesh.indices, 3); array_add(*mesh.indices, 0); ib_size := size_of(u32)*mesh.indices.count; mesh.ib = create_index_buffer(engine.renderer, mesh.indices.data, xx ib_size); engine.renderer.default_meshes.fullscreen_plane = parray_add(*engine.renderer.meshes, mesh); } { // Textured quad mesh : Mesh; array_add(*mesh.positions, .{0.5, 0.5, 0}); array_add(*mesh.positions, .{-0.5, -0.5, 0}); array_add(*mesh.positions, .{0.5, -0.5, 0}); array_add(*mesh.positions, .{-0.5, 0.5, 0}); array_add(*mesh.texcoords, .{1, 0}); array_add(*mesh.texcoords, .{0, 1}); array_add(*mesh.texcoords, .{1, 1}); array_add(*mesh.texcoords, .{0, 0}); array_add(*mesh.indices, 2); array_add(*mesh.indices, 1); array_add(*mesh.indices, 0); array_add(*mesh.indices, 1); array_add(*mesh.indices, 3); array_add(*mesh.indices, 0); ib_size := size_of(u32)*mesh.indices.count; mesh.ib = create_index_buffer(engine.renderer, mesh.indices.data, xx ib_size); engine.renderer.default_meshes.textured_quad = parray_add(*engine.renderer.meshes, mesh); } engine.renderer.default_samplers.repeat = create_sampler(engine.renderer, wrap_mode = .REPEAT); engine.renderer.default_samplers.clamp = create_sampler(engine.renderer, wrap_mode = .CLAMP); { sphere_model := load_fbx("../modules/Coven/assets/models/sphere.fbx"); engine.renderer.default_models.sphere = sphere_model; sphere_mesh, success := get_first_mesh_from_model(sphere_model); assert(success); engine.renderer.default_meshes.sphere = sphere_mesh; } cube_model := load_fbx("../assets/models/cube.fbx"); cube_mesh, success := get_first_mesh_from_model(cube_model); assert(success); engine.renderer.default_meshes.cube = cube_mesh; translation_arrow_model := load_fbx("../modules/Coven/assets/models/translation_arrow.fbx"); translation_arrow_mesh :, success = get_first_mesh_from_model(translation_arrow_model); assert(success); engine.renderer.default_meshes.translation_gizmo = translation_arrow_mesh; scale_gizmo_model := load_fbx("../modules/Coven/assets/models/scale_gizmo.fbx"); scale_gizmo_mesh :, success = get_first_mesh_from_model(scale_gizmo_model); assert(success); engine.renderer.default_meshes.scale_gizmo = scale_gizmo_mesh; rotation_gizmo_model := load_fbx("../modules/Coven/assets/models/rotation_gizmo.fbx"); rotation_gizmo_mesh :, success = get_first_mesh_from_model(rotation_gizmo_model); assert(success); engine.renderer.default_meshes.rotation_gizmo = rotation_gizmo_mesh; } deinit_renderer :: (renderer: *Renderer) { deinit_backend(engine.renderer.backend); } get_shader :: (handle: Shader_Handle) -> Shader { assert(handle - 1 < xx engine.renderer.shaders.count); return engine.renderer.shaders[handle-1]; } create_shader :: (using renderer: *Renderer, path: string, entry_point: string, shader_type: Shader_Type, defines: [] string = .[], mesh_data_types: [] Mesh_Vertex_Data_Type = .[.POSITION, .NORMAL, .TEXCOORD]) -> Shader_Handle { shader : Shader; shader.type = shader_type; shader.path = copy_string(path); shader.entry_point = copy_string(entry_point); array_reserve(*shader.defines, defines.count); for i: 0..defines.count-1 { array_add(*shader.defines, copy_string(defines[i])); } if shader_type == .VERTEX { array_reserve(*shader.mesh_data_types, mesh_data_types.count); for i: 0..mesh_data_types.count-1 { array_add(*shader.mesh_data_types, mesh_data_types[i]); } } backend_shader, info, success := create_backend_shader(engine.renderer.backend, path, entry_point, shader_type, defines); if !success { log_error("Error: Failed compiling shader '%'\n", path); } shader.info = info; shader.compiled = success; shader.backend_shader = backend_shader; array_add(*shaders, shader); return xx shaders.count; } reload_shader :: (using renderer: *Renderer, shader: *Shader) { backend_shader, success := reload_backend_shader(engine.renderer.backend, shader.path, shader.entry_point, shader.type, shader.defines); if success { destroy_shader(shader.*); shader.backend_shader = backend_shader; log("SHADER: Successfully reloaded shader '%'\n", shader.path); } else { log("SHADER: Compilation error when reloading shader '%'\n", shader.path); } } create_shader_from_source :: (using renderer: *Renderer, name: string, source: string, entry_point: string, shader_type: Shader_Type, defines: [] string = string.[], mesh_data_types: [] Mesh_Vertex_Data_Type = .[.POSITION, .NORMAL, .TEXCOORD]) -> Shader_Handle { shader : Shader; shader.type = shader_type; // lexer : Lexer; // read_input_from_string(*lexer, source); // token := scan_next_token(*lexer); // while token.type != .TOKEN_EOF { // token = scan_next_token(*lexer); // } if shader_type == .VERTEX { array_reserve(*shader.mesh_data_types, mesh_data_types.count); for i: 0..mesh_data_types.count-1 { array_add(*shader.mesh_data_types, mesh_data_types[i]); } } backend_shader, info, success := create_backend_shader_from_source(engine.renderer.backend, name, source, entry_point, shader_type, defines); if !success { log_error("Error: Failed compiling shader '%'\n", name); } shader.info = info; shader.compiled = success; shader.backend_shader = backend_shader; array_add(*shaders, shader); return xx shaders.count; } create_vertex_shader :: #bake_arguments create_shader(shader_type=.VERTEX); create_pixel_shader :: #bake_arguments create_shader(shader_type=.PIXEL); create_vertex_shader_from_source :: #bake_arguments create_shader_from_source(shader_type=.VERTEX); create_pixel_shader_from_source :: #bake_arguments create_shader_from_source(shader_type=.PIXEL); create_buffer :: (using renderer: *Renderer, data: *void, size: u32, type: Buffer_Type, stride: u32 = 0, mappable: bool = false) -> Buffer_Handle { buffer : Buffer; buffer.type = type; buffer.stride = stride; if type == .VERTEX { assert(stride > 0); } backend_buffer, success := create_backend_buffer(engine.renderer.backend, data, size, stride, type, mappable); if success { buffer.backend_buffer = backend_buffer; return parray_add(*buffers, buffer); } return 0; } create_vertex_buffer :: #bake_arguments create_buffer(type=.VERTEX); create_index_buffer :: #bake_arguments create_buffer(type=.INDEX); create_constant_buffer :: #bake_arguments create_buffer(type=.CONSTANT); create_structured_buffer :: #bake_arguments create_buffer(type=.STRUCTURED); destroy_buffer :: (using renderer: *Renderer, handle: Buffer_Handle) { assert(handle > 0); buffer := parray_get(*buffers, handle); destroy_backend_buffer(engine.renderer.backend, buffer.backend_buffer); parray_remove(*buffers, handle); } create_texture :: (using renderer: *Renderer, path: string, generate_mips: bool = true, format: Format = .R8G8B8A8_UNORM_SRGB) -> Texture_Handle { image_width : s32; image_height : s32; image_channels : s32; image_desired_channels : s32 = 4; image_data := stbi_load(to_temp_c_string(path), *image_width, *image_height, *image_channels, image_desired_channels); data : [32] u8; stbi_load_from_memory(data.data, 32, *image_width, *image_height, *image_channels, image_desired_channels); if image_data { defer stbi_image_free(image_data); return create_texture(renderer, image_data, xx image_width, xx image_height, xx image_desired_channels, path, generate_mips=generate_mips, format); } else { log_error("Unable to load texture '%'\n", path); return renderer.default_textures.fallback; } } create_texture :: (using renderer: *Renderer, data: *void, width: u32, height: u32, channels: u32, path: string = "", generate_mips: bool = true, format: Format = .R8G8B8A8_UNORM_SRGB) -> Texture_Handle { texture : Texture; texture.path = copy_string(path); texture.width = width; texture.height = height; texture.format = format; backend_texture, success := create_backend_texture(engine.renderer.backend, data, width, height, channels, generate_mips, format); if success { texture.backend_texture = backend_texture; return parray_add(*textures, texture); } assert(false); return 0; } load_texture_from_data :: (using renderer: *Renderer, data: *void, length: u64, generate_mips: bool = true, format: Format = .R8G8B8A8_UNORM_SRGB) -> Texture_Handle { image_width : s32; image_height : s32; image_channels : s32; image_desired_channels : s32 = 4; image_data := stbi_load_from_memory(data, xx length, *image_width, *image_height, *image_channels, image_desired_channels); //image_data := stbi_load(to_temp_c_string(path), *image_width, *image_height, *image_channels, image_desired_channels); assert(image_data != null); defer stbi_image_free(image_data); return create_texture(renderer, image_data, xx image_width, xx image_height, xx image_desired_channels, "", generate_mips=generate_mips, format); } destroy_texture :: (using renderer: *Renderer, handle: Texture_Handle) { assert(handle > 0); texture := parray_get(*textures, handle); destroy_backend_texture(engine.renderer.backend, texture.backend_texture); parray_remove(*textures, handle); } get_texture_size :: (using renderer: *Renderer, handle: Texture_Handle) -> u32, u32 { assert(handle > 0); texture := parray_get(*textures, handle); return texture.width, texture.height; } get_texture_path :: (using renderer: *Renderer, handle: Texture_Handle) -> string { assert(handle > 0); texture := parray_get(*textures, handle); return texture.path; } update_texture_region :: (using renderer: *Renderer, handle: Texture_Handle, xoffset: u32, yoffset: u32, width: u32, height: u32, pitch: u32, data: *void) { assert(handle > 0); texture := parray_get(*textures, handle); update_backend_texture_region(engine.renderer.backend, texture.backend_texture, xoffset, yoffset, width, height, pitch, data); } create_sampler :: (using renderer: *Renderer, filter: Sampling_Filter = .LINEAR, wrap_mode: Wrap_Mode = .CLAMP) -> Sampler_Handle { sampler : Sampler; sampler.filter = filter; sampler.wrap_mode = wrap_mode; backend_sampler, success := create_backend_sampler(engine.renderer.backend, filter, wrap_mode); if success { sampler.backend_sampler = backend_sampler; array_add(*samplers, sampler); return xx samplers.count; } return 0; } create_pipeline_state :: (using renderer: *Renderer, vs: Shader_Handle, ps: Shader_Handle, blend_type: Blend_Type = .OPAQUE) -> Pipeline_State_Handle { pipeline_state : Pipeline_State; pipeline_state.is_new = true; pipeline_state.vs = vs; pipeline_state.ps = ps; pipeline_state.blend_type = blend_type; if pipeline_state.blend_type == .TRANSPARENT { pipeline_state.blend_state = create_backend_blend_state(engine.renderer.backend, .TRANSPARENT); } shader := *shaders[vs - 1]; pipeline_state.vertex_layout = create_backend_input_layout2(engine.renderer.backend, shader.info.input, shader.backend_shader); array_reserve(*pipeline_state.mesh_data_types, shader.mesh_data_types.count); for type: shader.mesh_data_types { array_add(*pipeline_state.mesh_data_types, type); } array_add(*pipeline_states, pipeline_state); return xx pipeline_states.count; } create_pipeline_state :: (using renderer: *Renderer, vs: Shader_Handle, ps: Shader_Handle, layout: [] Vertex_Data_Info, shader_parameters: [] Shader_Parameter, blend_type: Blend_Type = .OPAQUE) -> Pipeline_State_Handle { pipeline_state : Pipeline_State; pipeline_state.vs = vs; pipeline_state.ps = ps; array_resize(*pipeline_state.shader_parameters, shader_parameters.count); for shader_parameters { pipeline_state.shader_parameters[it_index] = it; } pipeline_state.blend_type = blend_type; if pipeline_state.blend_type == .TRANSPARENT { pipeline_state.blend_state = create_backend_blend_state(engine.renderer.backend, .TRANSPARENT); } shader := *shaders[vs - 1]; if layout.count > 0 { pipeline_state.vertex_layout = create_backend_input_layout(engine.renderer.backend, layout, shader.backend_shader); } array_reserve(*pipeline_state.mesh_data_types, shader.mesh_data_types.count); for type: shader.mesh_data_types { array_add(*pipeline_state.mesh_data_types, type); } array_add(*pipeline_states, pipeline_state); return xx pipeline_states.count; } push_cmd_render_imgui :: (using renderer: *Renderer) { command : Render_Command; command.type = .RENDER_IMGUI; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_pipeline_state :: (using renderer: *Renderer, handle: Pipeline_State_Handle) { assert(handle > 0); engine.renderer.current_state.last_set_pipeline = handle; state := *pipeline_states[handle - 1]; vs := *shaders[state.vs - 1]; ps := *shaders[state.ps - 1]; command : Render_Command; command.type = .SET_PIPELINE_STATE; command.set_pipeline_state.vs = vs.backend_shader; command.set_pipeline_state.ps = ps.backend_shader; command.set_pipeline_state.vertex_layout = state.vertex_layout; command.set_pipeline_state.blend_type = state.blend_type; command.set_pipeline_state.blend_state = state.blend_state; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_vertex_buffer :: (using renderer: *Renderer, handle: Buffer_Handle, start_slot: u32 = 0) { assert(handle > 0); buffer := parray_get(*buffers, handle); command : Render_Command; command.type = .SET_VERTEX_BUFFER; command.set_vertex_buffer.buffer = buffer.backend_buffer; command.set_vertex_buffer.stride = buffer.stride; command.set_vertex_buffer.start_slot = start_slot; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_index_buffer :: (using renderer: *Renderer, handle: Buffer_Handle) { assert(handle > 0); buffer := parray_get(*buffers, handle); command : Render_Command; command.type = .SET_INDEX_BUFFER; command.set_index_buffer.buffer = buffer.backend_buffer; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_constant_buffer :: (using renderer: *Renderer, slot: u32, handle: Buffer_Handle, shader_type: Shader_Type) { assert(handle > 0); buffer := parray_get(*buffers, handle); command : Render_Command; command.type = .SET_CONSTANT_BUFFER; command.set_constant_buffer.buffer = buffer.backend_buffer; command.set_constant_buffer.shader_type = shader_type; command.set_constant_buffer.slot = slot; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_structured_buffer :: (using renderer: *Renderer, slot: u32, handle: Buffer_Handle, shader_type: Shader_Type) { assert(handle > 0); buffer := parray_get(*buffers, handle); command : Render_Command; command.type = .SET_STRUCTURED_BUFFER; command.set_structured_buffer.buffer = buffer.backend_buffer; command.set_structured_buffer.shader_type = shader_type; command.set_structured_buffer.slot = slot; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_texture :: (using renderer: *Renderer, slot: u32, handle: Texture_Handle) { assert(handle > 0); texture := parray_get(*textures, handle); command : Render_Command; command.type = .SET_TEXTURE; command.set_texture.texture = texture.backend_texture; command.set_texture.slot = slot; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_texture :: (using renderer: *Renderer, slot: u32, handle: Render_Target_Handle) { assert(handle > 0); rt := parray_get(*render_targets, handle); command : Render_Command; command.type = .SET_TEXTURE_FROM_RENDER_TARGET; command.set_texture_from_rt.rt = rt.backend_render_target; command.set_texture_from_rt.slot = slot; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_texture :: (using renderer: *Renderer, slot: u32, handle: Depth_Stencil_Buffer_Handle) { assert(handle > 0); ds := parray_get(*depth_stencil_buffers, handle); command : Render_Command; command.type = .SET_TEXTURE_FROM_DEPTH_STENCIL; command.set_texture_from_ds.ds = ds.backend_depth_stencil_buffer; command.set_texture_from_ds.slot = slot; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_render_targets :: (renderer: *Renderer, render_targets: ..Render_Target_Handle = .[], depth_stencil_enabled: bool = false, depth_stencil_buffer: Depth_Stencil_Buffer_Handle = 0) { assert(render_targets.count <= MAX_RENDER_TARGETS); command : Render_Command; command.type = .SET_RENDER_TARGETS; command.set_render_targets.num_render_targets = xx render_targets.count; for render_targets { rt := parray_get(*engine.renderer.render_targets, it); command.set_render_targets.render_targets[it_index] = rt.backend_render_target; } command.set_render_targets.depth_stencil_enabled = depth_stencil_enabled; if depth_stencil_enabled { ds := parray_get(*engine.renderer.depth_stencil_buffers, depth_stencil_buffer); command.set_render_targets.depth_stencil_buffer = ds.backend_depth_stencil_buffer; } array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_backbuffer :: (renderer: *Renderer) { command : Render_Command; command.type = .SET_BACKBUFFER; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_sampler :: (using renderer: *Renderer, slot: u32, handle: Sampler_Handle) { assert(handle > 0); sampler := *samplers[handle - 1]; command : Render_Command; command.type = .SET_SAMPLER; command.set_sampler.sampler = sampler.backend_sampler; command.set_sampler.slot = slot; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_viewport :: (using renderer: *Renderer, width: u32, height: u32, x: u32 = 0, y: u32 = 0, min_depth: float = 0.0, max_depth: float = 1.0) { command : Render_Command; command.type = .SET_VIEWPORT; command.set_viewport.width = width; command.set_viewport.height = height; command.set_viewport.x = x; command.set_viewport.y = y; command.set_viewport.min_depth = min_depth; command.set_viewport.max_depth = max_depth; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_scissor :: (using renderer: *Renderer, width: u32, height: u32, x: u32 = 0, y: u32 = 0) { command : Render_Command; command.type = .SET_SCISSOR; command.set_scissor.width = width; command.set_scissor.height = height; command.set_scissor.x = x; command.set_scissor.y = y; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_clear_scissor :: (using renderer: *Renderer) { command : Render_Command; command.type = .CLEAR_SCISSOR; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_clear_render_target :: (using renderer: *Renderer, rt: Render_Target_Handle, color: Vector4) { command : Render_Command; command.type = .CLEAR_RENDER_TARGET; render_target := parray_get(*engine.renderer.render_targets, rt); command.clear_render_target.rt = render_target.backend_render_target; command.clear_render_target.color = color; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_clear_depth_stencil :: (using renderer: *Renderer, handle: Depth_Stencil_Buffer_Handle, depth: float) { command : Render_Command; command.type = .CLEAR_DEPTH_STENCIL; ds := parray_get(*engine.renderer.depth_stencil_buffers, handle); command.clear_depth_stencil.ds = ds.backend_depth_stencil_buffer; command.clear_depth_stencil.depth = depth; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_clear_backbuffer :: (using renderer: *Renderer, color: Vector4) { command : Render_Command; command.type = .CLEAR_BACKBUFFER; command.clear_backbuffer.color = color; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_draw :: (using renderer: *Renderer, vertex_count: s64, start_vertex_index: s64 = 0, topology: Primitive_Topology = .TRIANGLE_LIST) { engine.renderer.draw_call_count += 1; command : Render_Command; command.type = .DRAW; command.draw.topology = topology; command.draw.vertex_count = vertex_count; command.draw.start_vertex_index = start_vertex_index; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_draw_instanced :: (using renderer: *Renderer, vertex_count: s64, instance_count: s64, start_vertex_index: s64 = 0, start_instance_index: s64 = 0, topology: Primitive_Topology = .TRIANGLE_LIST) { engine.renderer.draw_call_count += 1; command : Render_Command; command.type = .DRAW_INSTANCED; command.draw_instanced.topology = topology; command.draw_instanced.vertex_count = vertex_count; command.draw_instanced.instance_count = xx instance_count; command.draw_instanced.start_vertex_index = start_vertex_index; command.draw_instanced.start_instance_index = start_instance_index; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_draw_indexed :: (using renderer: *Renderer, index_count: s64, start_index: s64 = 0, base_vertex: s64 = 0, topology: Primitive_Topology = .TRIANGLE_LIST) { engine.renderer.draw_call_count += 1; command : Render_Command; command.type = .DRAW_INDEXED; command.draw_indexed.topology = topology; command.draw_indexed.index_count = index_count; command.draw_indexed.start_index = start_index; command.draw_indexed.base_vertex = base_vertex; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_draw_indexed_instanced :: (using renderer: *Renderer, index_count: s64, instance_count: u32, start_index: s64 = 0, base_vertex: s64 = 0, topology: Primitive_Topology = .TRIANGLE_LIST) { engine.renderer.draw_call_count += 1; command : Render_Command; command.type = .DRAW_INDEXED_INSTANCED; command.draw_indexed_instanced.topology = topology; command.draw_indexed_instanced.index_count = index_count; command.draw_indexed_instanced.instance_count = instance_count; command.draw_indexed_instanced.start_index = start_index; command.draw_indexed_instanced.base_vertex = base_vertex; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_draw_mode :: (using renderer: *Renderer, draw_mode: Draw_Mode) { command : Render_Command; command.type = .SET_DRAW_MODE; command.set_draw_mode.draw_mode = draw_mode; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_cull_face :: (using renderer: *Renderer, cull_face: Cull_Face) { command : Render_Command; command.type = .SET_CULL_FACE; command.set_cull_face.cull_face = cull_face; array_add(*engine.renderer.command_buffer.commands, command); } push_cmd_set_depth_write :: (using renderer: *Renderer, enabled: bool) { command : Render_Command; command.type = .SET_DEPTH_WRITE; command.set_depth_write.enabled = enabled; array_add(*engine.renderer.command_buffer.commands, command); } map_buffer :: (using renderer: *Renderer, handle: Buffer_Handle) -> *void{ assert(handle > 0); buffer := parray_get(*buffers, handle); return map_backend_buffer(backend, buffer.backend_buffer); } unmap_buffer :: (using renderer: *Renderer, handle: Buffer_Handle) { assert(handle > 0); buffer := parray_get(*buffers, handle); unmap_backend_buffer(backend, buffer.backend_buffer); } upload_data_to_buffer :: (using renderer: *Renderer, handle: Buffer_Handle, data: *void, size: s64) { mapped_ptr := map_buffer(renderer, handle); if mapped_ptr != null { memcpy(mapped_ptr, data, size); unmap_buffer(renderer, handle); } else { log_error("Buffer with handle % was not mappable\n", handle); } } Text_Render_Data :: struct { vb: Buffer_Handle; vert_count: u32; size: Vector2; } make_point :: (x: float, y: float, s: float, t: float, color: Vector4) -> Point { point : Point = ---; point.x = x; point.y = y; point.s = s; point.t = t; point.color = color; return point; } get_text_size :: (using renderer: *Renderer, text: string, font_handle: Font_Handle) -> Vector2 { if text.count == 0 return .{0,0}; size : Vector2; font := *engine.renderer.fonts[font_handle - 1]; characters := font.glyphs; has_character := false; for 0..text.count-1 { char := text.data[it]; if char >= characters.count continue; has_character = true; c := characters[char]; size.x += c.ax; size.y += c.ay; size.y = max(size.y, c.bh); } // @Hack: This is just to get a random valid size, if the string is empty if !has_character { index := 0; c := characters[#char "S"]; size.x += c.ax; size.y += c.ay; size.y = max(size.y, c.bh); } return size; } bake_text :: (using renderer: *Renderer, x: float, y: float, text: string, font_handle: Font_Handle, color: Vector4 = .{1, 1, 1, 1}) -> Text_Render_Data { buffer := engine.renderer.text_render_buffers[engine.renderer.used_text_buffers_count]; engine.renderer.used_text_buffers_count += 1; x -= (cast(float)engine.renderer.render_target_width) * 0.5; y -= (cast(float)engine.renderer.render_target_height) * 0.5; sx := 2.0 / cast(float)engine.renderer.render_target_width; sy := 2.0 / cast(float)engine.renderer.render_target_height; render_x := x * sx; render_y := y * sy; coords : [..] Point; coords.allocator = temp; font := *engine.renderer.fonts[font_handle - 1]; characters := font.glyphs; atlas_width := cast(float)font.atlas_width; atlas_height := cast(float)font.atlas_height; size : Vector2; for 0..text.count-1 { char := text.data[it]; if char >= characters.count continue; c := characters[char]; x2 := render_x + c.bl * sx; y2 := -render_y - c.bt * sy; w := c.bw * sx; h := c.bh * sy; /* Advance the cursor to the start of the next character */ render_x += c.ax * sx; render_y += c.ay * sy; size.x += c.ax; size.y += c.ay; size.y = max(size.y, c.bh); /* Skip glyphs that have no pixels */ if !w || !h continue; array_add(*coords, make_point(x2, -y2, c.tx, 0.0, color)); array_add(*coords, make_point(x2 + w, -y2, c.tx + c.bw / atlas_width, 0.0, color)); array_add(*coords, make_point(x2, -y2 - h, c.tx, c.bh / atlas_height, color)); array_add(*coords, make_point(x2 + w, -y2 - h, c.tx + c.bw / atlas_width, c.bh / atlas_height, color)); array_add(*coords, make_point(x2, -y2 - h, c.tx, c.bh / atlas_height, color)); array_add(*coords, make_point(x2 + w, -y2, c.tx + c.bw / atlas_width, 0.0, color)); } data : Text_Render_Data; data.vb = buffer; data.vert_count = xx coords.count; data.size = size; upload_data_to_buffer(renderer, buffer, coords.data, cast(s32)size_of(Point) * cast(s32)coords.count); return data; } draw_fullscreen_quad :: () { plane := parray_get(*engine.renderer.meshes, engine.renderer.default_meshes.fullscreen_plane); vb := get_mesh_vb(plane); push_cmd_set_vertex_buffer(engine.renderer, vb); push_cmd_set_index_buffer(engine.renderer, plane.ib); push_cmd_draw_indexed(engine.renderer, plane.indices.count); } create_render_target :: (width: u32, height: u32, format: Format) -> Render_Target_Handle { render_target : Render_Target; if width == SWAPCHAIN_SIZE || height == SWAPCHAIN_SIZE { render_target.width = width; render_target.height = height; render_target.actual_width = engine.renderer.render_target_width; render_target.actual_height = engine.renderer.render_target_height; } else { render_target.width = width; render_target.height = height; render_target.actual_width = width; render_target.actual_height = height; } render_target.format = format; render_target.backend_render_target = create_backend_render_target(engine.renderer.backend, render_target.actual_width, render_target.actual_height, format); texture : Texture; texture.width = render_target.actual_width; texture.height = render_target.actual_height; texture.backend_texture = get_backend_texture_from_render_target(engine.renderer.backend, render_target.backend_render_target); render_target.texture = parray_add(*engine.renderer.textures, texture); return parray_add(*engine.renderer.render_targets, render_target); } create_depth_stencil_buffer :: (width: u32, height: u32, format: Format) -> Depth_Stencil_Buffer_Handle { depth_stencil_buffer : Depth_Stencil_Buffer; if width == SWAPCHAIN_SIZE || height == SWAPCHAIN_SIZE { depth_stencil_buffer.width = width; depth_stencil_buffer.height = height; depth_stencil_buffer.actual_width = engine.renderer.render_target_width; depth_stencil_buffer.actual_height = engine.renderer.render_target_height; } else { depth_stencil_buffer.width = width; depth_stencil_buffer.height = height; depth_stencil_buffer.actual_width = width; depth_stencil_buffer.actual_height = height; } //depth_stencil_buffer.format = format; depth_stencil_buffer.backend_depth_stencil_buffer = create_backend_depth_stencil_buffer(engine.renderer.backend, depth_stencil_buffer.actual_width, depth_stencil_buffer.actual_height); return parray_add(*engine.renderer.depth_stencil_buffers, depth_stencil_buffer); } create_material_from_pipeline :: (pipeline: Pipeline_State_Handle) -> Material_Old { material : Material_Old; pass : Material_Pass_Old; pass.pipeline = pipeline; pipeline_state := *engine.renderer.pipeline_states[pipeline-1]; for pipeline_state.shader_parameters { prop : Material_Property_Old; prop.parameter = it; if it.mapping == { case .REPEAT_SAMPLER; prop.sampler = engine.renderer.default_samplers.repeat; case .CLAMP_SAMPLER; prop.sampler = engine.renderer.default_samplers.clamp; case .TIME; //prop.buffer = engine.time_buffer; // @Incomplete } array_add(*pass.properties, prop); } array_add(*material.passes, pass); return material; } get_model_by_handle :: (handle: Model_Handle) -> *Model { if handle == 0 return null; return *engine.renderer.model_lib[handle-1]; } check_for_shader_modifications :: () { changed, needs_wait, wait_seconds := process_changes(*engine.renderer.watcher); } render :: () { engine.renderer.command_buffer.commands.count = 0; engine.renderer.last_draw_call_count = engine.renderer.draw_call_count; engine.renderer.draw_call_count = 0; execute_render_graph(engine.renderer.render_graph); render(engine.renderer.backend, *engine.renderer.command_buffer); engine.renderer.used_text_buffers_count = 0; } #load "trigger_rendering.jai"; #load "render_graph.jai"; #load "font.jai"; #load "mesh.jai"; #load "material.jai"; #load "model.jai"; #import "Bucket_Array"; #import "Hash_Table"; #import "stb_image"; #load "vertex.jai"; //#if NEW_UI { // #load "ui/ui.jai"; //} else { // #load "ui_system.jai"; // #load "ui.jai"; //} #scope_module #load "dx11_renderer.jai"; #import "File_Watcher"; file_change_callback :: (watcher: *File_Watcher(string), change: *File_Change, user_data: *string) { for *shader: engine.renderer.shaders { if shader.path == change.full_path { reload_shader(engine.renderer, shader); } } } FALLBACK_SHADER :: #string DONE cbuffer Model : register(b0) { float4x4 model; }; struct PSInput { float4 position : SV_POSITION; }; PSInput VS(float3 pos : POSITION) { PSInput input; input.position = mul(float4(pos, 1.0), model); return input; } float4 PS(PSInput input) : SV_Target { return float4(1,0,1,1); } DONE