Files
coven/renderer/renderer.jai

1782 lines
54 KiB
Plaintext

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;
entity_pipeline : 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();
init_default_pipelines();
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", FALLBACK_SHADER, "VS", mesh_data_types = .[.POSITION]);
// ps := create_pixel_shader_from_source(engine.renderer, "fallback", 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);
}
set_default_entity_pipeline :: (pipeline: Pipeline_State_Handle) {
engine.renderer.default_pipelines.entity_pipeline = pipeline;
}
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";
//}
render_default_renderable_entities :: () {
for e: engine.current_scene.entities {
if e.enabled && e.flags & .RENDERABLE && e.renderable.use_default_pipeline {
render_entity(e, engine.renderer.default_pipelines.entity_pipeline);
}
}
}
render_entity :: (e: *Entity, pipeline: Pipeline_State_Handle) {
if e.renderable.type == {
case .MODEL; {
model := get_model_by_handle(e.renderable.model);
if model == null return;
for node, node_index: model.nodes {
render_data := e.renderable.nodes[node_index];
if !render_data.enabled continue;
if node.meshes.count > 0 {
for m, mi: node.meshes {
push_cmd_set_pipeline_state(engine.renderer, pipeline);
push_cmd_set_constant_buffer(engine.renderer, 1, engine.directional_light_buffer, .VERTEX);
push_cmd_set_constant_buffer(engine.renderer, 1, engine.directional_light_buffer, .PIXEL);
push_cmd_set_constant_buffer(engine.renderer, 2, render_data.transform_buffer, .VERTEX);
push_cmd_set_constant_buffer(engine.renderer, 3, render_data.material_buffer, .PIXEL);
if node.num_bones > 0 {
push_cmd_set_constant_buffer(engine.renderer, 4, render_data.bone_buffers[mi], .VERTEX);
}
mesh := parray_get(*engine.renderer.meshes, m);
vb := get_mesh_vb(mesh);
push_cmd_set_vertex_buffer(engine.renderer, vb);
if mesh.ib != 0 {
push_cmd_set_index_buffer(engine.renderer, mesh.ib);
push_cmd_draw_indexed(engine.renderer, mesh.indices.count);
} else {
push_cmd_draw(engine.renderer, mesh.positions.count);
}
}
}
}
}
}
}
#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