1633 lines
49 KiB
Plaintext
1633 lines
49 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 {
|
|
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;
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
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 : Bucket_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_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;
|
|
}
|
|
|
|
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();
|
|
|
|
array_reserve(*engine.renderer.command_buffer.commands, 4096);
|
|
|
|
engine.renderer.render_graph = new_render_graph();
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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");
|
|
|
|
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 {
|
|
shader.info = info;
|
|
shader.backend_shader = backend_shader;
|
|
array_add(*shaders, shader);
|
|
return xx shaders.count;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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 {
|
|
shader.info = info;
|
|
shader.backend_shader = backend_shader;
|
|
array_add(*shaders, shader);
|
|
return xx shaders.count;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
|
|
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, path, generate_mips=generate_mips, format);
|
|
}
|
|
|
|
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_state2 :: (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_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_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 #must {
|
|
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;
|
|
}
|
|
|
|
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 "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";
|
|
//}
|
|
//ImGui :: #import "ImGui";
|
|
|
|
#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);
|
|
}
|
|
}
|
|
}
|