render to aspect-ratio-locked viewport

This commit is contained in:
jacob 2024-03-18 00:54:00 -05:00
parent 4a68e0c6c7
commit e3ffcaa2a1
6 changed files with 174 additions and 98 deletions

View File

@ -444,11 +444,17 @@ struct mat4x4 {
f32 e[4][4];
};
#define RECT(x, y, width, height) (struct rect) { (x), (y), (width), (height) }
#define RECT(_x, _y, _width, _height) (struct rect) { .x = (_x), .y = (_y), .width = (_width), .height = (_height) }
#define RECT_FROM_V2(_pos, _size) (struct rect) { .pos = (_pos), .size = (_size) }
struct rect {
f32 x, y, width, height;
union {
struct { f32 x, y, width, height; };
struct { struct v2 pos, size; };
};
};
INLINE b32 rect_eq(struct rect r1, struct rect r2) { return r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height == r2.height; }
/* Values expected to be normalized 0.0 -> 1.0 */
#define CLIP_ALL ((struct clip_rect) { { 0.0f, 0.0f }, { 1.0f, 1.0f } })
struct clip_rect {
@ -457,7 +463,6 @@ struct clip_rect {
#define QUAD_UNIT_SQUARE (struct quad) { V2(0, 0), V2(0, 1), V2(1, 1), V2(1, 0) }
#define QUAD_UNIT_SQUARE_CENTERED (struct quad) { V2(-0.5f, -0.5f), V2(0.5f, -0.5f), V2(0.5f, 0.5f), V2(-0.5f, 0.5f) }
struct quad {
struct v2 p1, p2, p3, p4;
};

View File

@ -5,7 +5,8 @@
* system. */
#define RESOURCES_EMBEDDED !(DEVELOPER)
#define ASPECT_RATIO (16.0 / 9.0)
//#define ASPECT_RATIO (16.0 / 9.0)
#define ASPECT_RATIO (4.0 / 3.0)
#define PIXELS_PER_UNIT 256
#define GAME_FPS 50

View File

@ -72,7 +72,7 @@ void renderer_canvas_ensure_texture_cmd(struct renderer_canvas *canvas, struct t
void renderer_canvas_send_to_gpu(struct renderer_canvas *canvas);
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, f32 viewport_width, f32 viewport_height, i32 vsync);
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, struct v2 screen_size, struct rect viewport, i32 vsync);
/* ========================== *
* Texture

View File

@ -124,8 +124,11 @@ GLOBAL struct {
ID3D11DeviceContext *devcon;
IDXGISwapChain1 *swapchain;
ID3D11RenderTargetView *back_buffer_view;
D3D11_VIEWPORT viewport; /* Here for caching/comparison */
ID3D11RenderTargetView *backbuffer_view;
/* Here for caching/comparison */
struct v2 backbuffer_size;
struct rect viewport;
ID3D11BlendState *blend_state;
ID3D11RasterizerState *rasterizer_state;
@ -789,35 +792,37 @@ void renderer_canvas_send_to_gpu(struct renderer_canvas *canvas)
* Present canvas
* ========================== */
INTERNAL void recreate_backbuffer_and_viewport(f32 width, f32 height)
INTERNAL void resize_backbuffer(struct v2 size)
{
__prof;
/* TODO: error handling */
/* Release all outstanding references to the swap chain's buffers. */
if (L.back_buffer_view) {
ID3D11RenderTargetView_Release(L.back_buffer_view);
if (L.backbuffer_view) {
ID3D11RenderTargetView_Release(L.backbuffer_view);
}
IDXGISwapChain_ResizeBuffers(L.swapchain, 0, (UINT)width, (UINT)height, DXGI_FORMAT_UNKNOWN, 0);
IDXGISwapChain_ResizeBuffers(L.swapchain, 0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
/* Get buffer and create a render-target-view. */
ID3D11Texture2D *back_buffer_texture = NULL;
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&back_buffer_texture);
ID3D11Texture2D *backbuffer_texture = NULL;
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer_texture);
ID3D11Device_CreateRenderTargetView(L.dev, (ID3D11Resource *)back_buffer_texture, NULL, &L.back_buffer_view);
ID3D11Texture2D_Release(back_buffer_texture);
ID3D11Device_CreateRenderTargetView(L.dev, (ID3D11Resource *)backbuffer_texture, NULL, &L.backbuffer_view);
ID3D11Texture2D_Release(backbuffer_texture);
}
/* Set up the viewport */
L.viewport = (D3D11_VIEWPORT){
.Width = width,
.Height = height,
INTERNAL void resize_viewport(struct rect viewport)
{
D3D11_VIEWPORT d3d11_viewport = {
.Width = viewport.width,
.Height = viewport.height,
.MinDepth = 0.0f,
.MaxDepth = 1.0f,
.TopLeftX = 0,
.TopLeftY = 0
.TopLeftX = viewport.x,
.TopLeftY = viewport.y
};
ID3D11DeviceContext_RSSetViewports(L.devcon, 1, &L.viewport);
ID3D11DeviceContext_RSSetViewports(L.devcon, 1, &d3d11_viewport);
}
/* TODO: Lock canvas or at least global state? (in-case multi-threaded present).
@ -825,21 +830,26 @@ INTERNAL void recreate_backbuffer_and_viewport(f32 width, f32 height)
* research if that is smart first).
*
* I'm thinking we may also just need to lock texture modification access while presenting */
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, f32 viewport_width, f32 viewport_height, i32 vsync)
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, struct v2 screen_size, struct rect viewport, i32 vsync)
{
__prof;
/* Resize back buffer */
D3D11_VIEWPORT old_vp = L.viewport;
if (old_vp.Width != viewport_width || old_vp.Height != viewport_height) {
recreate_backbuffer_and_viewport(viewport_width, viewport_height);
if (!v2_eq(L.backbuffer_size, screen_size)) {
resize_backbuffer(screen_size);
L.backbuffer_size = screen_size;
}
ID3D11DeviceContext_OMSetRenderTargets(L.devcon, 1, &L.back_buffer_view, NULL);
if (!rect_eq(L.viewport, viewport)) {
resize_viewport(viewport);
L.viewport = viewport;
}
ID3D11DeviceContext_OMSetRenderTargets(L.devcon, 1, &L.backbuffer_view, NULL);
/* Clear back buffer */
f32 clear_color[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
ID3D11DeviceContext_ClearRenderTargetView(L.devcon, L.back_buffer_view, clear_color);
f32 clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
ID3D11DeviceContext_ClearRenderTargetView(L.devcon, L.backbuffer_view, clear_color);
/* Set draw mode */
ID3D11DeviceContext_IASetPrimitiveTopology(L.devcon, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
@ -850,7 +860,7 @@ void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_cou
/* Fill and set constant buffer
* NOTE: We're only doing this once per canvas, rather than once per draw call since
* the only constant right now is VP. */
struct mat4x4 vp_matrix = calculate_vp(canvas->view, viewport_width, viewport_height);
struct mat4x4 vp_matrix = calculate_vp(canvas->view, viewport.width, viewport.height);
send_constant_buffer_data(L.vs_constant_buffer, vp_matrix);
ID3D11DeviceContext_VSSetConstantBuffers(L.devcon, 0, 1, &L.vs_constant_buffer);
@ -898,7 +908,7 @@ void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_cou
IDXGISwapChain1_Present(L.swapchain, vsync, 0);
__profframe(0);
}
renderer_capture_image_for_profiler(viewport_width, viewport_height);
renderer_capture_image_for_profiler(viewport.width, viewport.height);
}
/* ========================== *
@ -989,22 +999,22 @@ INTERNAL void renderer_capture_image_for_profiler(f32 width, f32 height)
static u32 cap_index = 0;
static b32 ready_to_read = false;
ID3D11Texture2D *back_buffer = NULL;
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *) & back_buffer);
ID3D11Texture2D *backbuffer = NULL;
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer);
struct prof_cap *write_cap = &staging_caps[cap_index];
*write_cap = (struct prof_cap) { .size = V2(width, height) };
{
D3D11_TEXTURE2D_DESC staging_desc;
ID3D11Texture2D_GetDesc(back_buffer, &staging_desc);
ID3D11Texture2D_GetDesc(backbuffer, &staging_desc);
staging_desc.Usage = D3D11_USAGE_STAGING;
staging_desc.BindFlags = 0;
staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
ID3D11Device_CreateTexture2D(L.dev, &staging_desc, NULL, &write_cap->texture);
}
ID3D11DeviceContext_CopyResource(L.devcon, (ID3D11Resource *)write_cap->texture, (ID3D11Resource *)back_buffer);
ID3D11Texture2D_Release(back_buffer);
ID3D11DeviceContext_CopyResource(L.devcon, (ID3D11Resource *)write_cap->texture, (ID3D11Resource *)backbuffer);
ID3D11Texture2D_Release(backbuffer);
++cap_index;
if (cap_index >= ARRAY_COUNT(staging_caps)) {

View File

@ -1626,7 +1626,7 @@ u32 sys_rand_u32(void)
void sys_panic_raw(char *msg_cstr)
{
app_quit();
/* FIXME: Exit other threads before showing message box */
MessageBoxExA(NULL, msg_cstr, "Fatal error", MB_ICONSTOP, 0);
ASSERT(false);
sys_exit();
@ -1813,7 +1813,7 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
wc->lpszClassName = "power_play_window_class";
wc->hCursor = LoadCursor(NULL, IDC_ARROW);
wc->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
//wc->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc->lpfnWndProc = win32_window_proc;
wc->hInstance = instance;

View File

@ -36,7 +36,8 @@ GLOBAL struct {
struct sys_window *window;
struct renderer_canvas *world_canvas;
struct renderer_canvas *screen_canvas;
struct renderer_canvas *viewport_bg_canvas;
struct renderer_canvas *viewport_canvas;
struct xform world_view_last_frame;
struct xform world_view;
@ -60,8 +61,11 @@ GLOBAL struct {
f64 time;
f64 dt;
struct v2 screen_size;
struct v2 screen_center;
struct v2 screen_cursor;
struct v2 viewport_screen_offset;
struct v2 viewport_size;
struct v2 viewport_center;
struct v2 viewport_cursor;
struct v2 world_cursor;
} L = { 0 }, DEBUG_LVAR(L_user);
@ -304,9 +308,9 @@ INTERNAL void debug_draw_xform(struct xform xf)
struct quad quad = quad_from_rect(RECT(0, 0, 1, -1));
quad = quad_mul_xform(quad_scale(quad, 0.075), xf);
draw_solid_arrow_ray(L.screen_canvas, pos, x_ray, thickness, arrowhead_len, color_x);
draw_solid_arrow_ray(L.screen_canvas, pos, y_ray, thickness, arrowhead_len, color_y);
draw_solid_quad(L.screen_canvas, quad, color);
draw_solid_arrow_ray(L.viewport_canvas, pos, x_ray, thickness, arrowhead_len, color_x);
draw_solid_arrow_ray(L.viewport_canvas, pos, y_ray, thickness, arrowhead_len, color_y);
draw_solid_quad(L.viewport_canvas, quad, color);
}
/* TODO: remove this (testing) */
@ -322,8 +326,8 @@ INTERNAL void debug_draw_movement(struct entity *ent)
struct v2 vel_ray = xform_basis_mul_v2(L.world_view, ent->velocity);
struct v2 acc_ray = xform_basis_mul_v2(L.world_view, ent->acceleration);
draw_solid_arrow_ray(L.screen_canvas, pos, vel_ray, thickness, arrow_len, color_vel);
draw_solid_arrow_ray(L.screen_canvas, pos, acc_ray, thickness, arrow_len, color_acc);
draw_solid_arrow_ray(L.viewport_canvas, pos, vel_ray, thickness, arrow_len, color_vel);
draw_solid_arrow_ray(L.viewport_canvas, pos, acc_ray, thickness, arrow_len, color_acc);
}
INTERNAL void user_update(void)
@ -338,9 +342,32 @@ INTERNAL void user_update(void)
L.dt = max_f64(0.0, cur_time - L.time);
L.time += L.dt;
/* Calculate screen & viewport dimensions */
{
/* Get screen dimensions */
L.screen_size = sys_window_get_size(L.window);
L.screen_center = v2_mul(L.screen_size, 0.5);
/* Enforce viewport at aspect ratio */
f32 aspect_ratio = ASPECT_RATIO;
f32 width = L.screen_size.x;
f32 height = L.screen_size.y;
if (width / height > aspect_ratio) {
width = height * aspect_ratio;
} else {
height = width / aspect_ratio;
}
L.viewport_size = V2(width, height);
/* Center viewport in window */
f32 x = 0;
f32 y = 0;
x = math_round(L.screen_size.x / 2 - width / 2);
y = math_round(L.screen_size.y / 2 - height / 2);
L.viewport_screen_offset = V2(x, y);
/* Get center */
L.viewport_center = v2_mul(L.viewport_size, 0.5);
}
/* ========================== *
* Produce interpolated tick
@ -469,6 +496,7 @@ INTERNAL void user_update(void)
/* Update mouse pos */
if (event->kind == SYS_EVENT_KIND_CURSOR_MOVE) {
L.screen_cursor = event->cursor_position;
L.viewport_cursor = v2_sub(L.screen_cursor, L.viewport_screen_offset);;
}
/* Update bind states */
@ -520,12 +548,12 @@ INTERNAL void user_update(void)
/* Pan view */
if (L.bind_states[USER_BIND_KIND_PAN].is_held) {
if (!L.debug_camera_panning) {
L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.screen_cursor);
L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.viewport_cursor);
}
L.debug_camera_panning = true;
struct v2 offset = v2_sub(L.debug_camera_pan_start, xform_invert_mul_v2(L.world_view, L.screen_cursor));
struct v2 offset = v2_sub(L.debug_camera_pan_start, xform_invert_mul_v2(L.world_view, L.viewport_cursor));
L.world_view = xform_translate(L.world_view, v2_neg(offset));
L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.screen_cursor);
L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.viewport_cursor);
} else {
L.debug_camera_panning = false;
}
@ -548,7 +576,7 @@ INTERNAL void user_update(void)
}
/* Zoom to cursor */
struct v2 world_cursor = xform_invert_mul_v2(L.world_view, L.screen_cursor);
struct v2 world_cursor = xform_invert_mul_v2(L.world_view, L.viewport_cursor);
L.world_view = xform_translate(L.world_view, world_cursor);
L.world_view = xform_scale(L.world_view, V2(zoom, zoom));
L.world_view = xform_translate(L.world_view, v2_neg(world_cursor));
@ -560,7 +588,7 @@ INTERNAL void user_update(void)
zoom = zoom > 0 ? zoom : 1;
struct trs trs = TRS(
.t = v2_sub(L.screen_center, center),
.t = v2_sub(L.viewport_center, center),
.r = rot,
.s = v2_mul(V2(PIXELS_PER_UNIT, PIXELS_PER_UNIT), zoom)
);
@ -570,7 +598,7 @@ INTERNAL void user_update(void)
L.world_view = xform_translate(L.world_view, pivot);
L.world_view = xform_trs_pivot_rs(L.world_view, trs, pivot);
}
L.world_cursor = xform_invert_mul_v2(L.world_view, L.screen_cursor);
L.world_cursor = xform_invert_mul_v2(L.world_view, L.viewport_cursor);
/* ========================== *
* Update listener
@ -578,17 +606,26 @@ INTERNAL void user_update(void)
{
struct v2 up = V2(0, -1);
struct v2 listener_pos = xform_invert_mul_v2(L.world_view, L.screen_center);
struct v2 listener_pos = xform_invert_mul_v2(L.world_view, L.viewport_center);
struct v2 listener_dir = v2_norm(xform_basis_invert_mul_v2(L.world_view, up));
mixer_set_listener(listener_pos, listener_dir);
}
/* ========================== *
* Draw test BG
* ========================== */
{
u32 color = RGBA_F(0.2f, 0.2f, 0.2f, 1.f);
draw_solid_rect(L.viewport_bg_canvas, RECT(0, 0, L.viewport_size.x, L.viewport_size.y), color);
}
/* ========================== *
* Draw test grid
* ========================== */
{
f32 thickness = 3.f / xform_get_scale(L.world_view).x;
f32 thickness = 3.f;
u32 color = RGBA(0x3f, 0x3f, 0x3f, 0xFF);
u32 x_color = RGBA(0x3f, 0, 0, 0xFF);
u32 y_color = RGBA(0, 0x3f, 0, 0xFF);
@ -599,25 +636,25 @@ INTERNAL void user_update(void)
i64 cols = 20;
/* Draw column lines */
struct v2 col_ray = V2(0, rows);
struct v2 col_ray = xform_basis_mul_v2(L.world_view, V2(0, rows));
for (i64 col = starty; col <= (starty + cols); ++col) {
u32 line_color = color;
if (col == 0) {
line_color = y_color;
}
struct v2 pos = V2(col, starty);
draw_solid_ray(L.world_canvas, pos, col_ray, thickness, line_color);
struct v2 pos = xform_mul_v2(L.world_view, V2(col, starty));
draw_solid_ray(L.viewport_bg_canvas, pos, col_ray, thickness, line_color);
}
struct v2 row_ray = V2(cols, 0);
struct v2 row_ray = xform_basis_mul_v2(L.world_view, V2(cols, 0));
for (i64 row = startx; row <= (startx + rows); ++row) {
u32 line_color = color;
if (row == 0) {
line_color = x_color;
}
struct v2 pos = V2(startx, row);
draw_solid_ray(L.world_canvas, pos, row_ray, thickness, line_color);
struct v2 pos = xform_mul_v2(L.world_view, V2(startx, row));
draw_solid_ray(L.viewport_bg_canvas, pos, row_ray, thickness, line_color);
}
}
@ -736,7 +773,7 @@ INTERNAL void user_update(void)
);
draw_text(L.screen_canvas, disp_font, pos, text);
draw_text(L.viewport_canvas, disp_font, pos, text);
}
#endif
@ -752,7 +789,7 @@ INTERNAL void user_update(void)
struct v2 start = xform_mul_v2(L.world_view, ent->world_xform.og);
struct v2 end = xform_mul_v2(L.world_view, parent->world_xform.og);
draw_solid_arrow_line(L.screen_canvas, start, end, thickness, arrow_height, color);
draw_solid_arrow_line(L.viewport_canvas, start, end, thickness, arrow_height, color);
}
/* Draw aim */
@ -762,7 +799,7 @@ INTERNAL void user_update(void)
f32 arrow_height = 10;
struct v2 pos = xform_mul_v2(L.world_view, ent->world_xform.og);
struct v2 aim_ray = xform_basis_mul_v2(L.world_view, ent->player_aim);
draw_solid_arrow_ray(L.screen_canvas, pos, aim_ray, thickness, arrow_height, color);
draw_solid_arrow_ray(L.viewport_canvas, pos, aim_ray, thickness, arrow_height, color);
}
arena_temp_end(temp);
@ -771,8 +808,8 @@ INTERNAL void user_update(void)
/* Draw crosshair or show cursor */
if (!L.debug_camera) {
struct v2 crosshair_pos = L.screen_cursor;
u32 tint = RGBA_F(1, 1, 1, 1 );
struct v2 crosshair_pos = L.viewport_cursor;
u32 tint = RGBA_F(1, 1, 1, 1);
struct v2 size = V2(0, 0);
struct texture *t = texture_load_async(STR("res/graphics/crosshair.ase"));
@ -780,11 +817,15 @@ INTERNAL void user_update(void)
size = t->size;
struct xform xf = XFORM_TRS(.t = crosshair_pos, .s = size);
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xf);
draw_texture_quad(L.screen_canvas, DRAW_TEXTURE_PARAMS(.texture = t, .tint = tint), quad);
draw_texture_quad(L.viewport_canvas, DRAW_TEXTURE_PARAMS(.texture = t, .tint = tint), quad);
}
struct rect cursor_clip = RECT_FROM_V2(L.viewport_screen_offset, L.viewport_size);
cursor_clip.pos = v2_add(cursor_clip.pos, v2_mul(size, 0.5f));
cursor_clip.pos = v2_add(cursor_clip.pos, V2(1, 1));
cursor_clip.size = v2_sub(cursor_clip.size, size);
sys_window_cursor_hide(L.window);
sys_window_cursor_enable_clip(L.window, RECT(size.x / 2, size.y / 2, L.screen_size.x - size.x, L.screen_size.y - size.y));
sys_window_cursor_enable_clip(L.window, cursor_clip);
} else {
sys_window_cursor_disable_clip(L.window);
sys_window_cursor_show(L.window);
@ -854,31 +895,40 @@ INTERNAL void user_update(void)
struct v2 pos = V2(10, 8);
struct font *font = font_load(STR("res/fonts/fixedsys.ttf"), 12.0f);
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT((f64)L.time)));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT((f64)L.time)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("screen_size: (%F, %F)"), FMT_FLOAT((f64)L.screen_size.x), FMT_FLOAT((f64)L.screen_size.y)));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("screen_size: (%F, %F)"), FMT_FLOAT((f64)L.screen_size.x), FMT_FLOAT((f64)L.screen_size.y)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("screen_center: (%F, %F)"), FMT_FLOAT((f64)L.screen_center.x), FMT_FLOAT((f64)L.screen_center.y)));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("screen_cursor: (%F, %F)"), FMT_FLOAT((f64)L.screen_cursor.x), FMT_FLOAT((f64)L.screen_cursor.y)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("screen_cursor: (%F, %F)"), FMT_FLOAT((f64)L.screen_cursor.x), FMT_FLOAT((f64)L.screen_cursor.y)));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_screen_offset: (%F, %F)"), FMT_FLOAT((f64)L.viewport_screen_offset.x), FMT_FLOAT((f64)L.viewport_screen_offset.y)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.og: (%F, %F)"), FMT_FLOAT((f64)L.world_view.og.x), FMT_FLOAT((f64)L.world_view.og.y)));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_size: (%F, %F)"), FMT_FLOAT((f64)L.viewport_size.x), FMT_FLOAT((f64)L.viewport_size.y)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view rotation: %F"), FMT_FLOAT((f64)xform_get_rotation(L.world_view))));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_center: (%F, %F)"), FMT_FLOAT((f64)L.viewport_center.x), FMT_FLOAT((f64)L.viewport_center.y)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view scale: (%F, %F)"), FMT_FLOAT((f64)xform_get_scale(L.world_view).x), FMT_FLOAT((f64)xform_get_scale(L.world_view).x)));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("viewport_cursor: (%F, %F)"), FMT_FLOAT((f64)L.viewport_cursor.x), FMT_FLOAT((f64)L.viewport_cursor.y)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_cursor: (%F, %F)"), FMT_FLOAT((f64)L.world_cursor.x), FMT_FLOAT((f64)L.world_cursor.y)));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("world_view.og: (%F, %F)"), FMT_FLOAT((f64)L.world_view.og.x), FMT_FLOAT((f64)L.world_view.og.y)));
pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(L.debug_camera ? STR("true") : STR("false"))));
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("world_view rotation: %F"), FMT_FLOAT((f64)xform_get_rotation(L.world_view))));
pos.y += spacing;
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("world_view scale: (%F, %F)"), FMT_FLOAT((f64)xform_get_scale(L.world_view).x), FMT_FLOAT((f64)xform_get_scale(L.world_view).x)));
pos.y += spacing;
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("world_cursor: (%F, %F)"), FMT_FLOAT((f64)L.world_cursor.x), FMT_FLOAT((f64)L.world_cursor.y)));
pos.y += spacing;
draw_text(L.viewport_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(L.debug_camera ? STR("true") : STR("false"))));
pos.y += spacing;
arena_temp_end(temp);
@ -892,12 +942,14 @@ INTERNAL void user_update(void)
* ========================== */
/* Send canvases to GPU */
renderer_canvas_send_to_gpu(L.viewport_bg_canvas);
renderer_canvas_send_to_gpu(L.world_canvas);
renderer_canvas_send_to_gpu(L.screen_canvas);
renderer_canvas_send_to_gpu(L.viewport_canvas);
/* Set canvas views before presenting */
renderer_canvas_set_view(L.viewport_bg_canvas, XFORM_IDENT);
renderer_canvas_set_view(L.world_canvas, L.world_view);
renderer_canvas_set_view(L.screen_canvas, XFORM_IDENT);
renderer_canvas_set_view(L.viewport_canvas, XFORM_IDENT);
/* Present */
i32 vsync = VSYNC_ENABLED;
@ -905,17 +957,24 @@ INTERNAL void user_update(void)
struct renderer_canvas **canvases = arena_dry_push(scratch.arena, struct renderer_canvas *);
u64 canvases_count = 0;
{
/* Only render world if not on first frame */
/* Viewport background canvas */
*arena_push(scratch.arena, struct renderer_canvas *) = L.viewport_bg_canvas;
++canvases_count;
/* World canvas */
if (!tick_is_first_frame) {
/* Only render world if not on first frame */
*arena_push(scratch.arena, struct renderer_canvas *) = L.world_canvas;
++canvases_count;
}
*arena_push(scratch.arena, struct renderer_canvas *) = L.screen_canvas;
/* Viewport canvas */
*arena_push(scratch.arena, struct renderer_canvas *) = L.viewport_canvas;
++canvases_count;
}
renderer_canvas_present(canvases, canvases_count, L.screen_size.x, L.screen_size.y, vsync);
renderer_canvas_present(canvases, canvases_count, L.screen_size, RECT_FROM_V2(L.viewport_screen_offset, L.viewport_size), vsync);
scratch_end(scratch);
}
@ -951,7 +1010,8 @@ void user_startup(struct sys_window *window)
L.world_canvas = renderer_canvas_alloc();
L.world_view = XFORM_TRS(.t = V2(0, 0), .r = 0, .s = V2(PIXELS_PER_UNIT, PIXELS_PER_UNIT));
L.screen_canvas = renderer_canvas_alloc();
L.viewport_bg_canvas = renderer_canvas_alloc();
L.viewport_canvas = renderer_canvas_alloc();
L.window = window;
sys_window_register_event_callback(L.window, &window_event_callback);