work on refactoring the rendering pipeline

This commit is contained in:
Tuomas Katajisto 2025-10-05 21:49:09 +03:00
parent 0b820e19c1
commit fde02a1dc7
15 changed files with 300 additions and 62 deletions

View File

@ -6,7 +6,7 @@ rotation : float = 0.0;
cam : Camera = .{
far = 2000.0,
near = 1.0,
target = .{0.0, 0.0, 0.0},
target = .{0.0, 4.0, 0.0},
position = .{3.0, 5.0, 3.0}
};
@ -22,19 +22,19 @@ game_init :: () {
world.ground[501][500] = .GRASS;
}
game_ui :: () {
}
game_tick :: () {
}
game_draw :: () {
if !is_in_reflection_pass then update_image_from_ground(*world, *gPipelines.plane.bind.images[1]);
if is_in_reflection_pass {
cam.position.y *= -1;
cam.target.y *= -1;
}
draw_sky(*cam);
if !is_in_reflection_pass then draw_ground_plane(*cam, *world.conf);
if is_in_reflection_pass {
cam.position.y *= -1;
cam.target.y *= -1;
}
camtask := Rendering_Task_Set_Camera.{type = .SET_CAMERA, camera = cam};
add_rendering_task(camtask);
skytask := Rendering_Task_Sky.{type = .SKY, worldConfig = *world.conf};
add_rendering_task(skytask);
groundtask := Rendering_Task_Ground.{type = .GROUND, world = *world};
add_rendering_task(groundtask);
}

View File

@ -270,13 +270,9 @@ handle_tool_click :: (x: int, y: int, z: int) {
case .TRILES;
if editor_current_trile != null then add_trile(editor_current_trile.name, cast(float)x, cast(float)y, cast(float)z);
case .GROUND;
ray := get_mouse_ray(*get_level_editor_camera());
hit, point := ray_plane_collision_point(ray, 0, 100);
print("ground point: %\n");
if hit {
if hit {
world.ground[floor(point.y).(int) + 500][floor(point.x).(int) + 500] = groundType;
}
}
@ -384,9 +380,7 @@ draw_world_triles :: (cam: *Camera, world: *World) {
draw_level_editor :: () {
cam := get_level_editor_camera();
if !is_in_reflection_pass then update_image_from_ground(*world, *gPipelines.plane.bind.images[1]);
draw_sky(*get_level_editor_camera(), *world.conf);
if !is_in_reflection_pass then draw_ground_plane(*get_level_editor_camera(), *world.conf);
draw_world_triles(*cam, *world);
}

View File

@ -17,12 +17,9 @@ stbi :: #import "stb_image";
#load "input/hotkeys.jai";
#load "ui/ui.jai";
#load "editor/editor.jai";
#load "pipelines.jai";
#load "time.jai";
#load "arbtri.jai";
#load "events.jai";
#load "load.jai";
#load "camera.jai";
#load "ray.jai";
#load "world.jai";
@ -96,7 +93,6 @@ init :: () {
}
init_after_asset_pack :: () {
add_font_from_pack("./resources/DroidSerif-Regular.ttf");
ui_init_font_fields(*state.font_default);
@ -148,20 +144,23 @@ frame :: () {
tick_ui();
sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, attachments = gPipelines.plane.attachments}));
is_in_reflection_pass = true;
draw_editor();
// This populates our render task queue.
if !in_editor_view then game_draw();
is_in_reflection_pass = false;
sg_end_pass();
sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, swapchain = cast,force(sg_swapchain) sglue_swapchain() }));
draw_editor();
if !in_editor_view then game_draw();
ui_clear_mouse_occluders();
ui_pass();
sg_end_pass();
sg_commit();
render();
// sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, attachments = gPipelines.plane.attachments}));
// is_in_reflection_pass = true;
// draw_editor();
// is_in_reflection_pass = false;
// sg_end_pass();
// sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, swapchain = cast,force(sg_swapchain) sglue_swapchain() }));
// draw_editor();
// if !in_editor_view then game_draw();
// ui_clear_mouse_occluders();
// ui_pass();
// sg_end_pass();
// sg_commit();
input_per_frame_event_and_flag_update();
#if MEM_DEBUG {

51
src/rendering/backend.jai Normal file
View File

@ -0,0 +1,51 @@
#scope_export
Render_Command_Buckets :: struct {
setup : [..]*Render_Command;
shadow : [..]*Render_Command;
reflection : [..]*Render_Command;
main : [..]*Render_Command;
ui : [..]*Render_Command;
}
render_command_buckets : Render_Command_Buckets;
Render_Command_Type :: enum {
INVALID;
DRAW_SKY;
SET_CAMERA;
DRAW_GROUND;
GENERATE_GROUND;
}
Render_Command :: struct {
type: Render_Command_Type = .INVALID;
}
Render_Command_Sky :: struct {
#as using c : Render_Command;
worldConfig : *World_Config;
}
Render_Command_Draw_Ground :: struct {
#as using c : Render_Command;
worldConfig : *World_Config;
}
Render_Command_Generate_Ground_Texture :: struct {
#as using c : Render_Command;
world : *World;
}
Render_Command_Set_Camera :: struct {
#as using c : Render_Command;
camera: Camera;
}
process_command_buckets :: () {
backend_process_command_buckets();
}
#scope_file
#load "backend_sokol.jai";

View File

@ -0,0 +1,84 @@
camera: Camera;
backend_handle_command :: (cmd: *Render_Command) {
if cmd.type == {
case .DRAW_SKY;
sky_command := cast(*Render_Command_Sky)cmd;
backend_draw_sky(sky_command.worldConfig);
case .SET_CAMERA;
camera_command := cast(*Render_Command_Set_Camera)cmd;
camera = camera_command.camera;
case .GENERATE_GROUND;
gen_command := cast(*Render_Command_Generate_Ground_Texture)cmd;
update_image_from_ground(gen_command.world, *gPipelines.plane.bind.images[1]);
case .DRAW_GROUND;
ground_command := cast(*Render_Command_Draw_Ground)cmd;
backend_draw_ground(ground_command.worldConfig);
}
}
backend_draw_sky :: (wc: *World_Config) {
mvp := create_viewproj(*camera);
vs_params : Sky_Vs_Params;
world_conf : Sky_World_Config;
world_config_to_shader_type(wc, *world_conf);
vs_params.mvp = mvp.floats;
sg_apply_pipeline(gPipelines.sky.pipeline);
sg_apply_bindings(*gPipelines.sky.bind);
sg_apply_uniforms(UB_sky_vs_params, *(sg_range.{ ptr = *vs_params, size = size_of(type_of(vs_params)) }));
sg_apply_uniforms(UB_sky_world_config, *(sg_range.{ptr = *world_conf, size = size_of(type_of(world_conf))}));
sg_draw(0, 36, 1);
}
backend_draw_ground :: (wc: *World_Config) {
mvp := create_viewproj(*camera);
vs_params : Plane_Vs_Params;
world_conf : Plane_World_Config;
plane_data : Plane_Data;
w, h := get_window_size();
plane_data.screen_w = w;
plane_data.screen_h = h;
world_config_to_shader_type(wc, *world_conf);
vs_params.mvp = mvp.floats;
sg_apply_pipeline(gPipelines.plane.pipeline);
sg_apply_bindings(*gPipelines.plane.bind);
sg_apply_uniforms(UB_plane_vs_params, *(sg_range.{ ptr = *vs_params, size = size_of(type_of(vs_params)) }));
sg_apply_uniforms(UB_plane_world_config, *(sg_range.{ptr = *world_conf, size = size_of(type_of(world_conf))}));
sg_apply_uniforms(UB_plane_data, *(sg_range.{ptr = *plane_data, size = size_of(type_of(plane_data))}));
sg_draw(0, 6, 1);
}
backend_process_command_buckets :: () {
// 1. Set up textures and buffers.
for render_command_buckets.setup {
backend_handle_command(it);
}
// 2. Reflection pass
sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, attachments = gPipelines.plane.attachments}));
for render_command_buckets.reflection {
backend_handle_command(it);
}
sg_end_pass();
// 3. Main pass
sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, swapchain = cast,force(sg_swapchain) sglue_swapchain() }));
for render_command_buckets.main {
backend_handle_command(it);
}
sg_end_pass();
sg_commit();
array_reset_keeping_memory(*render_command_buckets.setup);
array_reset_keeping_memory(*render_command_buckets.shadow);
array_reset_keeping_memory(*render_command_buckets.reflection);
array_reset_keeping_memory(*render_command_buckets.main);
array_reset_keeping_memory(*render_command_buckets.ui);
}

17
src/rendering/core.jai Normal file
View File

@ -0,0 +1,17 @@
#scope_export
#load "backend.jai";
// Core rendering function, runs several passes.
render :: () {
tasks_to_commands();
process_command_buckets();
// // @ToDo: Consider a depth pre-pass here? Research required.
// shadow_pass();
// reflection_pass();
// forward_pass();
// // @ToDo: Post-processing.
}
#scope_file

View File

@ -1,25 +1 @@
draw_ground_plane :: (cam: *Camera, worldConfig: *World_Config = null) {
mvp := create_viewproj(cam);
vs_params : Plane_Vs_Params;
world_conf : Plane_World_Config;
plane_data : Plane_Data;
w, h := get_window_size();
plane_data.screen_w = w;
plane_data.screen_h = h;
plane_data.is_reflection_pass = xx ifx is_in_reflection_pass then 1 else 0;
wc : *World_Config = ifx worldConfig == null then *(World_Config.{}) else worldConfig;
world_config_to_shader_type(wc, *world_conf);
vs_params.mvp = mvp.floats;
sg_apply_pipeline(gPipelines.plane.pipeline);
sg_apply_bindings(*gPipelines.plane.bind);
sg_apply_uniforms(UB_plane_vs_params, *(sg_range.{ ptr = *vs_params, size = size_of(type_of(vs_params)) }));
sg_apply_uniforms(UB_plane_world_config, *(sg_range.{ptr = *world_conf, size = size_of(type_of(world_conf))}));
sg_apply_uniforms(UB_plane_data, *(sg_range.{ptr = *plane_data, size = size_of(type_of(plane_data))}));
sg_draw(0, 6, 1);
}

View File

@ -1,5 +1,20 @@
/*
The rendering pipeline.
@ToDo: Write something smart about our rendering
architecture.
*/
#load "groundplane.jai";
#load "tasks.jai";
#load "sky.jai";
#load "core.jai";
#load "camera.jai";
#load "pipelines.jai";
#load "meshgen.jai";
#load "arbtri.jai";
#scope_file

View File

@ -13,5 +13,26 @@ draw_sky :: (cam: *Camera, worldConfig: *World_Config = null) {
sg_apply_bindings(*gPipelines.sky.bind);
sg_apply_uniforms(UB_sky_vs_params, *(sg_range.{ ptr = *vs_params, size = size_of(type_of(vs_params)) }));
sg_apply_uniforms(UB_sky_world_config, *(sg_range.{ptr = *world_conf, size = size_of(type_of(world_conf))}));
sg_draw(0, 36, 1);
sg_draw(0, 36, 1);
}
sun_shadowmap_viewproj :: (cam: *Camera, conf: *World_Config) -> Matrix4 {
up: Vector3 = .{0, 1, 0};
targetToPos := conf.sunPosition;
A := normalize(targetToPos);
B := normalize(cross(up, A));
C := cross(A, B);
sunCameraPosition := cam.target + 20*A;
view := Matrix4.{
B.x, C.x, A.x, 0,
B.y, C.y, A.y, 0,
B.z, C.z, A.z, 0,
-dot(B, sunCameraPosition), -dot(C, sunCameraPosition), -dot(A, sunCameraPosition), 1
};
top := 10.0; right := 10.0;
proj := orthographic_projection_matrix(-right, right, -top, top, 5, 100, true);
return view * proj;
}

83
src/rendering/tasks.jai Normal file
View File

@ -0,0 +1,83 @@
#scope_export
Rendering_Task_Type :: enum {
INVALID;
GROUND;
SKY;
SET_CAMERA;
TRILE; // not implemented yet
SPRITE; // not implemented yet
PARTICLES; // not implemented yet
};
Rendering_Task :: struct {
type : Rendering_Task_Type = .INVALID;
};
Rendering_Task_World :: struct {
#as using t : Rendering_Task;
world : *World;
}
Rendering_Task_Sky :: struct {
#as using t : Rendering_Task;
t.type = .SKY;
worldConfig : *World_Config;
}
Rendering_Task_Ground :: struct {
#as using t : Rendering_Task;
t.type = .GROUND;
world : *World;
}
Rendering_Task_Set_Camera :: struct {
#as using t : Rendering_Task;
camera : Camera;
}
rendering_tasklist_clear :: () {
array_reset_keeping_memory(*rendering_tasklist);
}
add_rendering_task :: (task: $T) {
task_ptr := New(T,, temp);
task_ptr.* = task;
array_add(*rendering_tasklist, task_ptr);
}
rendering_tasklist : [..]*Rendering_Task;
tasks_to_commands :: () {
for rendering_tasklist {
if it.type == {
case .SKY;
command := New(Render_Command_Sky,, temp);
command.type = .DRAW_SKY;
command.worldConfig = (cast(*Rendering_Task_Sky)it).worldConfig;
array_add(*render_command_buckets.reflection, command);
array_add(*render_command_buckets.main, command);
case .GROUND;
commandDrawGround := New(Render_Command_Draw_Ground,, temp);
commandDrawGround.type = .DRAW_GROUND;
commandDrawGround.worldConfig = *(cast(*Rendering_Task_Ground)it).world.conf;
commandGenGround := New(Render_Command_Generate_Ground_Texture,, temp);
commandGenGround.type = .GENERATE_GROUND;
commandGenGround.world = (cast(*Rendering_Task_Ground)it).world;
array_add(*render_command_buckets.setup, commandGenGround);
array_add(*render_command_buckets.main, commandDrawGround);
case .SET_CAMERA;
command := New(Render_Command_Set_Camera,, temp);
command.type = .SET_CAMERA;
command.camera = (cast(*Rendering_Task_Set_Camera)it).camera;
array_add(*render_command_buckets.main, command);
commandReflected := New(Render_Command_Set_Camera,, temp);
commandReflected.type = .SET_CAMERA;
commandReflected.camera = (cast(*Rendering_Task_Set_Camera)it).camera;
commandReflected.camera.target *= Vector3.{1, -1, 1};
commandReflected.camera.position *= Vector3.{1, -1, 1};
array_add(*render_command_buckets.reflection, commandReflected);
}
}
rendering_tasklist_clear();
}

View File

@ -1,5 +1,3 @@
#load "meshgen.jai";
#scope_file
trile_gfx_table : Table(string, Trile_GFX);