From 511783243dbb2b413deda690ec097a78c6fb6f77 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 18 Jan 2025 12:29:10 -0600 Subject: [PATCH] draw ui & world to separate texture --- src/renderer.h | 10 +- src/renderer_d3d11.c | 106 +++++++++++++----- src/user.c | 253 +++++++++++++++++++++++++------------------ 3 files changed, 233 insertions(+), 136 deletions(-) diff --git a/src/renderer.h b/src/renderer.h index c2d6c0ae..7e26f15b 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -78,9 +78,15 @@ void renderer_canvas_ensure_cmd(struct renderer_canvas *canvas, struct renderer_ void renderer_canvas_send_to_gpu(struct renderer_canvas *canvas); -void renderer_render_to_texture(struct renderer_handle target_handle, struct renderer_canvas *canvas, u32 clear_color, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); +void renderer_render_to_texture(struct renderer_handle target_handle, struct renderer_canvas *canvas, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); -void renderer_render_to_backbuffer(struct v2 backbuffer_size, struct renderer_canvas *canvas, u32 clear_color, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); +void renderer_render_to_backbuffer(struct renderer_canvas *canvas, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); + +void renderer_clear_texture(struct renderer_handle target_handle, u32 clear_color); + +void renderer_clear_backbuffer(u32 clear_color); + +void renderer_resize_backbuffer(struct v2 size); void renderer_present_backbuffer(i32 vsync); diff --git a/src/renderer_d3d11.c b/src/renderer_d3d11.c index f1a40f28..b07170ce 100644 --- a/src/renderer_d3d11.c +++ b/src/renderer_d3d11.c @@ -124,9 +124,6 @@ GLOBAL struct { IDXGISwapChain1 *swapchain; - /* For caching/comparison */ - struct v2 backbuffer_size; - ID3D11BlendState *blend_state; ID3D11RasterizerState *rasterizer_state; ID3D11DepthStencilState *depth_stencil_state; @@ -323,7 +320,7 @@ INTERNAL void init_shader_table(void) sizeof(struct grid_shader_vertex), { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "THICKNESS", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "SPACING", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "OFFSET", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } @@ -829,19 +826,12 @@ void renderer_canvas_send_to_gpu(struct renderer_canvas *canvas) * Render * ========================== */ -INTERNAL void resize_backbuffer(struct v2 size) -{ - __prof; - IDXGISwapChain_ResizeBuffers(G.swapchain, 0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); - G.backbuffer_size = size; -} - /* TODO: Lock canvas or at least global state? (in-case multi-threaded present). * Another option is to store a separate device on each canvas (need to * research if that is smart first). * * I'm thinking we may also just need to lock texture modification access while presenting */ -INTERNAL void dx11_render_to_target(ID3D11RenderTargetView *target, struct renderer_canvas *canvas, u32 clear_color, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) +INTERNAL void dx11_render_to_target(ID3D11RenderTargetView *target, struct renderer_canvas *canvas, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) { __prof; ID3D11DeviceContext_OMSetRenderTargets(G.devcon, 1, &target, NULL); @@ -863,14 +853,6 @@ INTERNAL void dx11_render_to_target(ID3D11RenderTargetView *target, struct rende ID3D11DeviceContext_VSSetConstantBuffers(G.devcon, 0, 1, &G.vs_constant_buffer); struct dx11_shader *last_shader = NULL; - if (clear_color) { - f32 r = (f32)((clear_color >> 0) & 0xFF) / 255.0f; - f32 g = (f32)((clear_color >> 8) & 0xFF) / 255.0f; - f32 b = (f32)((clear_color >> 16) & 0xFF) / 255.0f; - f32 a = (f32)((clear_color >> 24) & 0xFF) / 255.0f; - f32 fill[4] = { r, g, b, a }; - ID3D11DeviceContext_ClearRenderTargetView(G.devcon, target, fill); - } struct renderer_cmd *cmd = canvas ? canvas->gpu_cmd_store.cmd_first : NULL; for (; cmd; cmd = cmd->next) { @@ -953,7 +935,7 @@ INTERNAL void dx11_render_to_target(ID3D11RenderTargetView *target, struct rende } } -void renderer_render_to_texture(struct renderer_handle target_handle, struct renderer_canvas *canvas, u32 clear_color, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) +void renderer_render_to_texture(struct renderer_handle target_handle, struct renderer_canvas *canvas, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) { __prof; @@ -969,7 +951,9 @@ void renderer_render_to_texture(struct renderer_handle target_handle, struct ren ID3D11RenderTargetView *target_view = NULL; ID3D11Device_CreateRenderTargetView(G.dev, target_resource, NULL, &target_view); - dx11_render_to_target(target_view, canvas, clear_color, view, viewport, sprite_scope); + if (target_view) { + dx11_render_to_target(target_view, canvas, view, viewport, sprite_scope); + } if (target_view) { ID3D11RenderTargetView_Release(target_view); @@ -979,22 +963,19 @@ void renderer_render_to_texture(struct renderer_handle target_handle, struct ren } } -void renderer_render_to_backbuffer(struct v2 backbuffer_size, struct renderer_canvas *canvas, u32 clear_color, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) +void renderer_render_to_backbuffer(struct renderer_canvas *canvas, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) { __prof; - /* Resize back buffer */ - if (!v2_eq(G.backbuffer_size, backbuffer_size)) { - resize_backbuffer(backbuffer_size); - } - ID3D11Texture2D *backbuffer_texture = NULL; IDXGISwapChain_GetBuffer(G.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer_texture); ID3D11RenderTargetView *backbuffer_view = NULL; ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)backbuffer_texture, NULL, &backbuffer_view); - dx11_render_to_target(backbuffer_view, canvas, clear_color, view, viewport, sprite_scope); + if (backbuffer_view) { + dx11_render_to_target(backbuffer_view, canvas, view, viewport, sprite_scope); + } if (backbuffer_view) { ID3D11RenderTargetView_Release(backbuffer_view); @@ -1004,6 +985,73 @@ void renderer_render_to_backbuffer(struct v2 backbuffer_size, struct renderer_ca } } +void renderer_clear_texture(struct renderer_handle target_handle, u32 clear_color) +{ + __prof; + + ID3D11ShaderResourceView *target_srv = handle_data(target_handle); + if (!target_srv) { + /* Invalid handle */ + ASSERT(false); + return; + } + + ID3D11Resource *target_resource = NULL; + ID3D11View_GetResource(target_srv, &target_resource); + + ID3D11RenderTargetView *target_view = NULL; + ID3D11Device_CreateRenderTargetView(G.dev, target_resource, NULL, &target_view); + if (target_view) { + f32 r = (f32)((clear_color >> 0) & 0xFF) / 255.0f; + f32 g = (f32)((clear_color >> 8) & 0xFF) / 255.0f; + f32 b = (f32)((clear_color >> 16) & 0xFF) / 255.0f; + f32 a = (f32)((clear_color >> 24) & 0xFF) / 255.0f; + f32 fill[4] = { r, g, b, a }; + ID3D11DeviceContext_ClearRenderTargetView(G.devcon, target_view, fill); + } + + + if (target_view) { + ID3D11RenderTargetView_Release(target_view); + } + if (target_resource) { + ID3D11Texture2D_Release((ID3D11Texture2D *)target_resource); + } +} + +void renderer_clear_backbuffer(u32 clear_color) +{ + __prof; + + ID3D11Texture2D *backbuffer_texture = NULL; + IDXGISwapChain_GetBuffer(G.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer_texture); + + ID3D11RenderTargetView *backbuffer_view = NULL; + ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)backbuffer_texture, NULL, &backbuffer_view); + + if (backbuffer_view) { + f32 r = (f32)((clear_color >> 0) & 0xFF) / 255.0f; + f32 g = (f32)((clear_color >> 8) & 0xFF) / 255.0f; + f32 b = (f32)((clear_color >> 16) & 0xFF) / 255.0f; + f32 a = (f32)((clear_color >> 24) & 0xFF) / 255.0f; + f32 fill[4] = { r, g, b, a }; + ID3D11DeviceContext_ClearRenderTargetView(G.devcon, backbuffer_view, fill); + } + + if (backbuffer_view) { + ID3D11RenderTargetView_Release(backbuffer_view); + } + if (backbuffer_texture) { + ID3D11Texture2D_Release(backbuffer_texture); + } +} + +void renderer_resize_backbuffer(struct v2 size) +{ + __prof; + IDXGISwapChain_ResizeBuffers(G.swapchain, 0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); +} + void renderer_present_backbuffer(i32 vsync) { __prof; diff --git a/src/user.c b/src/user.c index 411a71c3..e3e2b3ee 100644 --- a/src/user.c +++ b/src/user.c @@ -41,13 +41,19 @@ GLOBAL struct { struct sys_window *window; - struct renderer_handle render_target; - struct v2 render_target_resolution; + struct renderer_handle final_rt; + struct renderer_handle world_rt; + struct renderer_handle ui_rt; + + struct v2 final_rt_resolution; + struct v2 world_rt_resolution; + struct v2 ui_rt_resolution; + struct v2 backbuffer_size; - struct renderer_canvas *backbuffer_canvas; struct renderer_canvas *world_canvas; - struct renderer_canvas *viewport_bg_canvas; - struct renderer_canvas *viewport_canvas; + struct renderer_canvas *ui_canvas; + struct renderer_canvas *final_canvas; + struct renderer_canvas *backbuffer_canvas; struct xform world_view; struct blend_tick *head_free_blend_tick; @@ -148,12 +154,12 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, G.sys_events_arena = arena_alloc(GIGABYTE(64)); world_alloc(&G.world); - G.render_target = renderer_handle_nil(); - G.backbuffer_canvas = renderer_canvas_alloc(); - G.world_canvas = renderer_canvas_alloc(); G.world_view = XFORM_TRS(.t = V2(0, 0), .r = 0, .s = V2(PIXELS_PER_UNIT, PIXELS_PER_UNIT)); - G.viewport_bg_canvas = renderer_canvas_alloc(); - G.viewport_canvas = renderer_canvas_alloc(); + G.world_canvas = renderer_canvas_alloc(); + G.ui_canvas = renderer_canvas_alloc(); + G.final_canvas = renderer_canvas_alloc(); + G.backbuffer_canvas = renderer_canvas_alloc(); + G.window = window; sys_window_register_event_callback(G.window, &window_event_callback); @@ -412,13 +418,13 @@ INTERNAL void debug_draw_xform(struct xform xf, u32 color_x, u32 color_y) x_ray = v2_mul(x_ray, ray_scale); y_ray = v2_mul(y_ray, ray_scale); - draw_arrow_ray(G.viewport_canvas, pos, x_ray, thickness, arrowhead_len, color_x); - draw_arrow_ray(G.viewport_canvas, pos, y_ray, thickness, arrowhead_len, color_y); + draw_arrow_ray(G.ui_canvas, pos, x_ray, thickness, arrowhead_len, color_x); + draw_arrow_ray(G.ui_canvas, pos, y_ray, thickness, arrowhead_len, color_y); //u32 color_quad = RGBA_32_F(0, 1, 1, 0.3); //struct quad quad = quad_from_rect(RECT(0, 0, 1, -1)); //quad = xform_mul_quad(xf, quad_scale(quad, 0.075f)); - //draw_quad(G.viewport_canvas, quad, color); + //draw_quad(G.ui_canvas, quad, color); } /* TODO: remove this (testing) */ @@ -435,7 +441,7 @@ INTERNAL void debug_draw_movement(struct entity *ent) struct v2 pos = xform_mul_v2(G.world_view, xf.og); struct v2 vel_ray = xform_basis_mul_v2(G.world_view, velocity); - draw_arrow_ray(G.viewport_canvas, pos, vel_ray, thickness, arrow_len, color_vel); + draw_arrow_ray(G.ui_canvas, pos, vel_ray, thickness, arrow_len, color_vel); } /* ========================== * @@ -497,7 +503,6 @@ INTERNAL void user_update(void) * Produce interpolated tick * ========================== */ - b32 tick_is_first_frame = false; { __profscope(produce_interpolated_tick); @@ -511,8 +516,6 @@ INTERNAL void user_update(void) struct world *t0 = interp_ticks.from_tick; struct world *t1 = interp_ticks.to_tick; - tick_is_first_frame = (t0->tick_id == 0 || t1->tick_id == 0); - f32 tick_blend = 0; { f64 t0_time = sys_timestamp_seconds(t0->tick_ts); @@ -880,7 +883,9 @@ INTERNAL void user_update(void) struct v2 offset = v2_neg(xform_mul_v2(G.world_view, V2(0, 0))); f32 spacing = xform_get_scale(G.world_view).x; - draw_grid(G.viewport_bg_canvas, RECT(0, 0, G.viewport_size.x, G.viewport_size.y), color, thickness, spacing, offset); + struct v2 pos = xform_invert_mul_v2(G.world_view, V2(0, 0)); + struct v2 size = xform_basis_invert_mul_v2(G.world_view, G.viewport_size); + draw_grid(G.world_canvas, RECT_FROM_V2(pos, size), color, thickness, spacing, offset); } /* ---------------------------------------------------------------------- */ @@ -1012,7 +1017,7 @@ INTERNAL void user_update(void) start = xform_mul_v2(G.world_view, start); struct v2 end = v2_add(xf.og, ent->control.focus); end = xform_mul_v2(G.world_view, end); - draw_arrow_line(G.viewport_canvas, start, end, 3, 10, RGBA_32_F(1, 1, 1, 0.5)); + draw_arrow_line(G.ui_canvas, start, end, 3, 10, RGBA_32_F(1, 1, 1, 0.5)); } #if 0 @@ -1042,16 +1047,16 @@ INTERNAL void user_update(void) struct quad quad = quad_from_rect(slice.rect); quad = xform_mul_quad(sprite_xform, quad); quad = xform_mul_quad(G.world_view, quad); - draw_quad_line(G.viewport_canvas, quad, 2, quad_color); + draw_quad_line(G.ui_canvas, quad, 2, quad_color); } - draw_circle(G.viewport_canvas, center, 3, point_color, 20); + draw_circle(G.ui_canvas, center, 3, point_color, 20); if (slice.has_ray) { struct v2 ray = xform_basis_mul_v2(sprite_xform, slice.dir); ray = xform_basis_mul_v2(G.world_view, ray); ray = v2_with_len(ray, 25); - draw_arrow_ray(G.viewport_canvas, center, ray, 2, 10, ray_color); + draw_arrow_ray(G.ui_canvas, center, ray, 2, 10, ray_color); } } } @@ -1061,19 +1066,19 @@ INTERNAL void user_update(void) /* Draw collider */ if (entity_has_prop(ent, ENTITY_PROP_PHYSICAL_DYNAMIC)) { struct collider_shape collider = ent->local_collider; - u32 color = RGBA_32_F(1, 1, 0, 0.25); + u32 color = RGBA_32_F(1, 1, 0, 0.5); f32 thickness = 2; { /* Draw collider using support points */ //u32 detail = 64; u32 detail = 512; - draw_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail); + draw_collider_line(G.ui_canvas, G.world_view, collider, xf, thickness, color, detail); } { /* Draw collider shape points */ for (u32 i = 0; i < collider.count; ++i) { struct v2 p = xform_mul_v2(xform_mul(G.world_view, xf), collider.points[i]); - draw_circle(G.viewport_canvas, p, 3, COLOR_BLUE, 10); + draw_circle(G.ui_canvas, p, 3, COLOR_BLUE, 10); } } if (collider.count == 1 && collider.radius > 0) { @@ -1082,14 +1087,14 @@ INTERNAL void user_update(void) struct v2 end = collider_get_support_point(&collider, xf, v2_neg(xf.by)).p; start = xform_mul_v2(G.world_view, start); end = xform_mul_v2(G.world_view, end); - draw_line(G.viewport_canvas, start, end, thickness, color); + draw_line(G.ui_canvas, start, end, thickness, color); } #if 0 /* Draw support point at focus dir */ { struct v2 p = collider_support_point(&collider, xf, ent->control.focus); p = xform_mul_v2(G.world_view, p); - draw_circle(G.viewport_canvas, p, 3, COLOR_RED, 10); + draw_circle(G.ui_canvas, p, 3, COLOR_RED, 10); } #endif } @@ -1121,7 +1126,7 @@ INTERNAL void user_update(void) u32 color = RGBA_32_F(1, 1, 0, 0.50); //struct v2 point = xform_mul_v2(e0_xf, contact.p0_local); //struct v2 point = contact.p0_initial_world; - draw_circle(G.viewport_canvas, xform_mul_v2(G.world_view, dbg_pt), radius, color, 10); + draw_circle(G.ui_canvas, xform_mul_v2(G.world_view, dbg_pt), radius, color, 10); } /* Draw normal */ { @@ -1131,7 +1136,7 @@ INTERNAL void user_update(void) f32 arrow_height = 5; struct v2 start = xform_mul_v2(G.world_view, dbg_pt); struct v2 end = xform_mul_v2(G.world_view, v2_add(dbg_pt, v2_mul(v2_norm(data->normal), len))); - draw_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); + draw_arrow_line(G.ui_canvas, start, end, arrow_thickness, arrow_height, color); } #if 0 /* Draw contact info */ @@ -1161,7 +1166,7 @@ INTERNAL void user_update(void) FMT_UINT(data->num_points)); - draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, dbg_pt)), V2(0, offset_px)), text); + draw_text(G.ui_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, dbg_pt)), V2(0, offset_px)), text); } } #endif @@ -1188,8 +1193,8 @@ INTERNAL void user_update(void) u32 color = RGBA_32_F(1, 1, 0, 0.5); struct v2 a = xform_mul_v2(G.world_view, data->closest0); struct v2 b = xform_mul_v2(G.world_view, data->closest1); - draw_circle(G.viewport_canvas, a, radius, color, 10); - draw_circle(G.viewport_canvas, b, radius, color, 10); + draw_circle(G.ui_canvas, a, radius, color, 10); + draw_circle(G.ui_canvas, b, radius, color, 10); } #endif @@ -1206,28 +1211,28 @@ INTERNAL void user_update(void) { struct v2 a = xform_mul_v2(G.world_view, collider_res.a0); struct v2 b = xform_mul_v2(G.world_view, collider_res.b0); - draw_line(G.viewport_canvas, a, b, thickness, color_line); - draw_circle(G.viewport_canvas, a, radius, color_a, 10); - draw_circle(G.viewport_canvas, b, radius, color_b, 10); + draw_line(G.ui_canvas, a, b, thickness, color_line); + draw_circle(G.ui_canvas, a, radius, color_a, 10); + draw_circle(G.ui_canvas, b, radius, color_b, 10); struct v2 a_clipped = xform_mul_v2(G.world_view, collider_res.a0_clipped); struct v2 b_clipped = xform_mul_v2(G.world_view, collider_res.b0_clipped); - draw_line(G.viewport_canvas, a_clipped, b_clipped, thickness, color_line_clipped); - draw_circle(G.viewport_canvas, a_clipped, radius, color_a_clipped, 10); - draw_circle(G.viewport_canvas, b_clipped, radius, color_b_clipped, 10); + draw_line(G.ui_canvas, a_clipped, b_clipped, thickness, color_line_clipped); + draw_circle(G.ui_canvas, a_clipped, radius, color_a_clipped, 10); + draw_circle(G.ui_canvas, b_clipped, radius, color_b_clipped, 10); } { struct v2 a = xform_mul_v2(G.world_view, collider_res.a1); struct v2 b = xform_mul_v2(G.world_view, collider_res.b1); - draw_line(G.viewport_canvas, a, b, thickness, color_line); - draw_circle(G.viewport_canvas, a, radius, color_a, 10); - draw_circle(G.viewport_canvas, b, radius, color_b, 10); + draw_line(G.ui_canvas, a, b, thickness, color_line); + draw_circle(G.ui_canvas, a, radius, color_a, 10); + draw_circle(G.ui_canvas, b, radius, color_b, 10); struct v2 a_clipped = xform_mul_v2(G.world_view, collider_res.a1_clipped); struct v2 b_clipped = xform_mul_v2(G.world_view, collider_res.b1_clipped); - draw_line(G.viewport_canvas, a_clipped, b_clipped, thickness, color_line_clipped); - draw_circle(G.viewport_canvas, a_clipped, radius, color_a_clipped, 10); - draw_circle(G.viewport_canvas, b_clipped, radius, color_b_clipped, 10); + draw_line(G.ui_canvas, a_clipped, b_clipped, thickness, color_line_clipped); + draw_circle(G.ui_canvas, a_clipped, radius, color_a_clipped, 10); + draw_circle(G.ui_canvas, b_clipped, radius, color_b_clipped, 10); } } @@ -1268,7 +1273,7 @@ INTERNAL void user_update(void) FMT_FLOAT_P(xform_get_rotation(e1_xf), 24)); - draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, V2(0, 0))), V2(0, offset_px)), text); + draw_text(G.ui_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, V2(0, 0))), V2(0, offset_px)), text); } } #endif @@ -1284,8 +1289,8 @@ INTERNAL void user_update(void) struct v2_array m = menkowski(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf, detail); for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); - draw_poly_line(G.viewport_canvas, m, true, thickness, color); - //draw_poly(G.viewport_canvas, m, color); + draw_poly_line(G.ui_canvas, m, true, thickness, color); + //draw_poly(G.ui_canvas, m, color); } /* Draw cloud */ @@ -1297,7 +1302,7 @@ INTERNAL void user_update(void) for (u64 i = 0; i < m.count; ++i) { struct v2 p = xform_mul_v2(G.world_view, m.points[i]); - draw_circle(G.viewport_canvas, p, radius, color, 10); + draw_circle(G.ui_canvas, p, radius, color, 10); } } @@ -1309,7 +1314,7 @@ INTERNAL void user_update(void) f32 arrow_height = 5; struct v2 start = xform_mul_v2(G.world_view, V2(0, 0)); struct v2 end = xform_mul_v2(G.world_view, v2_mul(v2_norm(collider_res.normal), len)); - draw_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); + draw_arrow_line(G.ui_canvas, start, end, arrow_thickness, arrow_height, color); } /* Draw prototype */ @@ -1322,8 +1327,8 @@ INTERNAL void user_update(void) .count = collider_res.prototype.len }; for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); - draw_poly_line(G.viewport_canvas, m, true, thickness, color); - for (u64 i = 0; i < m.count; ++i) draw_circle(G.viewport_canvas, m.points[i], 10, color, 10); + draw_poly_line(G.ui_canvas, m, true, thickness, color); + for (u64 i = 0; i < m.count; ++i) draw_circle(G.ui_canvas, m.points[i], 10, color, 10); } /* Draw simplex */ @@ -1341,18 +1346,18 @@ INTERNAL void user_update(void) if (simplex.len >= 1) { u32 color = simplex.len == 1 ? color_first : (simplex.len == 2 ? color_second : color_third); - draw_circle(G.viewport_canvas, simplex_array.points[0], thickness * 3, color, 10); + draw_circle(G.ui_canvas, simplex_array.points[0], thickness * 3, color, 10); } if (simplex.len >= 2) { u32 color = simplex.len == 2 ? color_first : color_second; - draw_circle(G.viewport_canvas, simplex_array.points[1], thickness * 3, color, 10); + draw_circle(G.ui_canvas, simplex_array.points[1], thickness * 3, color, 10); } if (simplex.len >= 3) { u32 color = color_first; - draw_circle(G.viewport_canvas, simplex_array.points[2], thickness * 3, color, 10); + draw_circle(G.ui_canvas, simplex_array.points[2], thickness * 3, color, 10); } if (simplex.len >= 2) { - draw_poly_line(G.viewport_canvas, simplex_array, simplex.len > 2, thickness, line_color); + draw_poly_line(G.ui_canvas, simplex_array, simplex.len > 2, thickness, line_color); } } } @@ -1369,7 +1374,7 @@ INTERNAL void user_update(void) struct v2 start = xform_mul_v2(G.world_view, xf.og); struct v2 end = xform_mul_v2(G.world_view, parent_xf.og); - draw_arrow_line(G.viewport_canvas, start, end, thickness, arrow_height, color); + draw_arrow_line(G.ui_canvas, start, end, thickness, arrow_height, color); } /* Draw camera rect */ @@ -1381,7 +1386,7 @@ INTERNAL void user_update(void) struct quad quad = xform_mul_quad(quad_xf, QUAD_UNIT_SQUARE_CENTERED); quad = xform_mul_quad(G.world_view, quad); - draw_quad_line(G.viewport_canvas, quad, thickness, color); + draw_quad_line(G.ui_canvas, quad, thickness, color); } arena_temp_end(temp); @@ -1400,7 +1405,7 @@ INTERNAL void user_update(void) struct v2 size = V2(t->width, t->height); struct xform xf = XFORM_TRS(.t = crosshair_pos, .s = size); struct quad quad = xform_mul_quad(xf, QUAD_UNIT_SQUARE_CENTERED); - draw_quad_texture(G.viewport_canvas, DRAW_TEXTURE_PARAMS(.sprite = crosshair_tag, .tint = tint), quad); + draw_quad_texture(G.ui_canvas, DRAW_TEXTURE_PARAMS(.sprite = crosshair_tag, .tint = tint), quad); struct rect cursor_clip = RECT_FROM_V2(G.viewport_screen_offset, G.viewport_size); cursor_clip.pos = v2_add(cursor_clip.pos, v2_mul(size, 0.5f)); @@ -1519,65 +1524,65 @@ INTERNAL void user_update(void) if (font) { struct temp_arena temp = arena_temp_begin(scratch.arena); - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT((f64)G.time))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT((f64)G.time))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time))); pos.y += spacing; - //draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("time - world time: %F"), FMT_FLOAT((f64)G.time - (f64)G.world.time))); + //draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("time - world time: %F"), FMT_FLOAT((f64)G.time - (f64)G.world.time))); //pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("entities: %F/%F"), FMT_UINT(G.world.entity_store->allocated), FMT_UINT(G.world.entity_store->reserved))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("entities: %F/%F"), FMT_UINT(G.world.entity_store->allocated), FMT_UINT(G.world.entity_store->reserved))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("screen_size: (%F, %F)"), FMT_FLOAT((f64)G.screen_size.x), FMT_FLOAT((f64)G.screen_size.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("screen_size: (%F, %F)"), FMT_FLOAT((f64)G.screen_size.x), FMT_FLOAT((f64)G.screen_size.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("screen_cursor: (%F, %F)"), FMT_FLOAT((f64)G.screen_cursor.x), FMT_FLOAT((f64)G.screen_cursor.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("screen_cursor: (%F, %F)"), FMT_FLOAT((f64)G.screen_cursor.x), FMT_FLOAT((f64)G.screen_cursor.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_screen_offset: (%F, %F)"), FMT_FLOAT((f64)G.viewport_screen_offset.x), FMT_FLOAT((f64)G.viewport_screen_offset.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("viewport_screen_offset: (%F, %F)"), FMT_FLOAT((f64)G.viewport_screen_offset.x), FMT_FLOAT((f64)G.viewport_screen_offset.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_size: (%F, %F)"), FMT_FLOAT((f64)G.viewport_size.x), FMT_FLOAT((f64)G.viewport_size.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("viewport_size: (%F, %F)"), FMT_FLOAT((f64)G.viewport_size.x), FMT_FLOAT((f64)G.viewport_size.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_center: (%F, %F)"), FMT_FLOAT((f64)G.viewport_center.x), FMT_FLOAT((f64)G.viewport_center.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("viewport_center: (%F, %F)"), FMT_FLOAT((f64)G.viewport_center.x), FMT_FLOAT((f64)G.viewport_center.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_cursor: (%F, %F)"), FMT_FLOAT((f64)G.viewport_cursor.x), FMT_FLOAT((f64)G.viewport_cursor.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("viewport_cursor: (%F, %F)"), FMT_FLOAT((f64)G.viewport_cursor.x), FMT_FLOAT((f64)G.viewport_cursor.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world_view.og: (%F, %F)"), FMT_FLOAT((f64)G.world_view.og.x), FMT_FLOAT((f64)G.world_view.og.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("world_view.og: (%F, %F)"), FMT_FLOAT((f64)G.world_view.og.x), FMT_FLOAT((f64)G.world_view.og.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world_view rotation: %F"), FMT_FLOAT((f64)xform_get_rotation(G.world_view)))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("world_view rotation: %F"), FMT_FLOAT((f64)xform_get_rotation(G.world_view)))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world_view scale: (%F, %F)"), FMT_FLOAT((f64)xform_get_scale(G.world_view).x), FMT_FLOAT((f64)xform_get_scale(G.world_view).x))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("world_view scale: (%F, %F)"), FMT_FLOAT((f64)xform_get_scale(G.world_view).x), FMT_FLOAT((f64)xform_get_scale(G.world_view).x))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world_cursor: (%F, %F)"), FMT_FLOAT((f64)G.world_cursor.x), FMT_FLOAT((f64)G.world_cursor.y))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("world_cursor: (%F, %F)"), FMT_FLOAT((f64)G.world_cursor.x), FMT_FLOAT((f64)G.world_cursor.y))); pos.y += spacing; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(G.debug_camera ? STR("true") : STR("false")))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(G.debug_camera ? STR("true") : STR("false")))); pos.y += spacing; struct v2 player_linear_vel = entity_find_first_match_one(store, ENTITY_PROP_PLAYER_CONTROLLED)->linear_velocity; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("player linear velocity: (%F, %F)"), FMT_FLOAT_P((f64)player_linear_vel.x, 12), FMT_FLOAT_P((f64)player_linear_vel.y, 12))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("player linear velocity: (%F, %F)"), FMT_FLOAT_P((f64)player_linear_vel.x, 12), FMT_FLOAT_P((f64)player_linear_vel.y, 12))); pos.y += spacing; f32 player_angular_vel = entity_find_first_match_one(store, ENTITY_PROP_PLAYER_CONTROLLED)->angular_velocity; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("player angular velocity: %F"), FMT_FLOAT_P((f64)player_angular_vel, 12))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("player angular velocity: %F"), FMT_FLOAT_P((f64)player_angular_vel, 12))); pos.y += spacing; struct v2 player_pos = entity_get_xform(entity_find_first_match_one(store, ENTITY_PROP_PLAYER_CONTROLLED)).og; - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("player pos: (%F, %F)"), FMT_FLOAT_P((f64)player_pos.x, 12), FMT_FLOAT_P((f64)player_pos.y, 12))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("player pos: (%F, %F)"), FMT_FLOAT_P((f64)player_pos.x, 12), FMT_FLOAT_P((f64)player_pos.y, 12))); pos.y += spacing; #if COLLIDER_DEBUG - draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("collider gjk steps: %F"), FMT_UINT(collider_debug_steps))); + draw_text(G.ui_canvas, font, pos, string_format(temp.arena, STR("collider gjk steps: %F"), FMT_UINT(collider_debug_steps))); pos.y += spacing; #endif @@ -1594,55 +1599,93 @@ INTERNAL void user_update(void) * ========================== */ { + __profscope(render); struct rect target_viewport = RECT_FROM_V2(V2(0, 0), G.viewport_size); struct rect backbuffer_viewport = RECT_FROM_V2(V2(0, 0), G.screen_size); - /* Allocate target texture */ - struct renderer_handle target; + /* Allocate rt textures */ + struct v2 final_rt_resolution = G.viewport_size; + struct v2 ui_rt_resolution = final_rt_resolution; + struct v2 world_rt_resolution = V2(target_viewport.width + target_viewport.x, target_viewport.height + target_viewport.y); { - struct v2 size = ZI; - size.x = target_viewport.width + target_viewport.x; - size.y = target_viewport.height + target_viewport.y; - if (renderer_handle_is_nil(G.render_target) || !v2_eq(size, G.render_target_resolution)) { - if (!renderer_handle_is_nil(G.render_target)) { - renderer_texture_release(G.render_target); + /* World rt */ + if (renderer_handle_is_nil(G.world_rt) || !v2_eq(G.world_rt_resolution, world_rt_resolution)) { + if (!renderer_handle_is_nil(G.world_rt)) { + renderer_texture_release(G.world_rt); } - G.render_target = renderer_texture_target_alloc(size); - G.render_target_resolution = size; + G.world_rt_resolution = world_rt_resolution; + G.world_rt = renderer_texture_target_alloc(G.world_rt_resolution); } - target = G.render_target; + /* Ui rt */ + if (renderer_handle_is_nil(G.ui_rt) || !v2_eq(G.ui_rt_resolution, ui_rt_resolution)) { + if (!renderer_handle_is_nil(G.ui_rt)) { + renderer_texture_release(G.ui_rt); + } + G.ui_rt_resolution = ui_rt_resolution; + G.ui_rt = renderer_texture_target_alloc(G.ui_rt_resolution); + } + /* Final rt */ + if (renderer_handle_is_nil(G.final_rt) || !v2_eq(G.final_rt_resolution, final_rt_resolution)) { + if (!renderer_handle_is_nil(G.final_rt)) { + renderer_texture_release(G.final_rt); + } + G.final_rt_resolution = final_rt_resolution; + G.final_rt = renderer_texture_target_alloc(G.final_rt_resolution); + } + } + if (!v2_eq(G.backbuffer_size, G.screen_size)) { + G.backbuffer_size = G.screen_size; + renderer_resize_backbuffer(G.backbuffer_size); } - /* Draw target texture to backbuffer */ { - struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.texture = target); - struct rect rect = RECT_FROM_V2(G.viewport_screen_offset, G.viewport_size); - struct quad quad = quad_from_rect(rect); - draw_quad_texture(G.backbuffer_canvas, params, quad); + /* Draw world texture to final */ + { + struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.texture = G.world_rt); + struct quad quad = quad_from_rect(RECT_FROM_V2(V2(0, 0), final_rt_resolution)); + draw_quad_texture(G.final_canvas, params, quad); + } + + /* Draw ui texture to final */ + { + struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.texture = G.ui_rt); + struct quad quad = quad_from_rect(RECT_FROM_V2(V2(0, 0), final_rt_resolution)); + draw_quad_texture(G.final_canvas, params, quad); + } + + /* Draw final texture to backbuffer */ + { + struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.texture = G.final_rt); + struct quad quad = quad_from_rect(RECT_FROM_V2(G.viewport_screen_offset, G.viewport_size)); + draw_quad_texture(G.backbuffer_canvas, params, quad); + } } /* Send canvases to GPU */ - renderer_canvas_send_to_gpu(G.viewport_bg_canvas); renderer_canvas_send_to_gpu(G.world_canvas); - renderer_canvas_send_to_gpu(G.viewport_canvas); + renderer_canvas_send_to_gpu(G.ui_canvas); + renderer_canvas_send_to_gpu(G.final_canvas); renderer_canvas_send_to_gpu(G.backbuffer_canvas); /* Execute render cmds */ { /* Clear textures */ - renderer_render_to_texture(target, NULL, RGBA_32_F(0.2f, 0.2f, 0.2f, 1.f), XFORM_IDENT, target_viewport, sprite_frame_scope); - renderer_render_to_backbuffer(G.screen_size, NULL, COLOR_BLACK, XFORM_IDENT, target_viewport, sprite_frame_scope); + renderer_clear_texture(G.world_rt, RGBA_32_F(0.2f, 0.2f, 0.2f, 1.f)); + renderer_clear_texture(G.ui_rt, RGBA_32_F(0, 0, 0, 0)); + renderer_clear_texture(G.final_rt, RGBA_32_F(0, 0, 0, 0)); + renderer_clear_backbuffer(RGBA_32_F(0, 0, 0, 1)); - /* Render to target */ - renderer_render_to_texture(target, G.viewport_bg_canvas, 0, XFORM_IDENT, target_viewport, sprite_frame_scope); - if (!tick_is_first_frame) { - /* Only draw world canvas past first tick */ - renderer_render_to_texture(target, G.world_canvas, 0, G.world_view, target_viewport, sprite_frame_scope); - } - renderer_render_to_texture(target, G.viewport_canvas, 0, XFORM_IDENT, target_viewport, sprite_frame_scope); + /* Render to world texture */ + renderer_render_to_texture(G.world_rt, G.world_canvas, G.world_view, target_viewport, sprite_frame_scope); + + /* Render to UI texture */ + renderer_render_to_texture(G.ui_rt, G.ui_canvas, XFORM_IDENT, target_viewport, sprite_frame_scope); + + /* Render to final texture */ + renderer_render_to_texture(G.final_rt, G.final_canvas, XFORM_IDENT, target_viewport, sprite_frame_scope); /* Render to backbuffer */ - renderer_render_to_backbuffer(G.screen_size, G.backbuffer_canvas, 0, XFORM_IDENT, backbuffer_viewport, sprite_frame_scope); + renderer_render_to_backbuffer(G.backbuffer_canvas, XFORM_IDENT, backbuffer_viewport, sprite_frame_scope); } /* Present */