draw ui & world to separate texture

This commit is contained in:
jacob 2025-01-18 12:29:10 -06:00
parent acced9dfed
commit 511783243d
3 changed files with 233 additions and 136 deletions

View File

@ -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);

View File

@ -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;
@ -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;

View File

@ -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 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 */