render to aspect-ratio-locked viewport
This commit is contained in:
parent
4a68e0c6c7
commit
e3ffcaa2a1
39
src/common.h
39
src/common.h
@ -266,27 +266,27 @@ typedef i32 b32;
|
|||||||
typedef u64 umm;
|
typedef u64 umm;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define U8_MAX (0xFF)
|
#define U8_MAX (0xFF)
|
||||||
#define U16_MAX (0xFFFF)
|
#define U16_MAX (0xFFFF)
|
||||||
#define U32_MAX (0xFFFFFFFF)
|
#define U32_MAX (0xFFFFFFFF)
|
||||||
#define U64_MAX (0xFFFFFFFFFFFFFFFFULL)
|
#define U64_MAX (0xFFFFFFFFFFFFFFFFULL)
|
||||||
|
|
||||||
#define I8_MAX (0x7F)
|
#define I8_MAX (0x7F)
|
||||||
#define I16_MAX (0x7FFF)
|
#define I16_MAX (0x7FFF)
|
||||||
#define I32_MAX (0x7FFFFFFF)
|
#define I32_MAX (0x7FFFFFFF)
|
||||||
#define I64_MAX (0x7FFFFFFFFFFFFFFFLL)
|
#define I64_MAX (0x7FFFFFFFFFFFFFFFLL)
|
||||||
|
|
||||||
#define I8_MIN ((i8)-0x80)
|
#define I8_MIN ((i8)-0x80)
|
||||||
#define I16_MIN ((i16)-0x8000)
|
#define I16_MIN ((i16)-0x8000)
|
||||||
#define I32_MIN ((i32)-0x80000000)
|
#define I32_MIN ((i32)-0x80000000)
|
||||||
#define I64_MIN ((i64)-0x8000000000000000LL)
|
#define I64_MIN ((i64)-0x8000000000000000LL)
|
||||||
|
|
||||||
#define F32_INFINITY (1.0 / 0.0f)
|
#define F32_INFINITY (1.0 / 0.0f)
|
||||||
#define F32_MAX (3.402823466e+38F)
|
#define F32_MAX (3.402823466e+38F)
|
||||||
#define F32_MIN (1.175494351e-38F)
|
#define F32_MIN (1.175494351e-38F)
|
||||||
|
|
||||||
#define PI ((f32)3.14159265358979323846)
|
#define PI ((f32)3.14159265358979323846)
|
||||||
#define TAU ((f32)6.28318530717958647693)
|
#define TAU ((f32)6.28318530717958647693)
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Atomics
|
* Atomics
|
||||||
@ -444,11 +444,17 @@ struct mat4x4 {
|
|||||||
f32 e[4][4];
|
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 {
|
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 */
|
/* Values expected to be normalized 0.0 -> 1.0 */
|
||||||
#define CLIP_ALL ((struct clip_rect) { { 0.0f, 0.0f }, { 1.0f, 1.0f } })
|
#define CLIP_ALL ((struct clip_rect) { { 0.0f, 0.0f }, { 1.0f, 1.0f } })
|
||||||
struct clip_rect {
|
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 (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) }
|
#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 quad {
|
||||||
struct v2 p1, p2, p3, p4;
|
struct v2 p1, p2, p3, p4;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,8 @@
|
|||||||
* system. */
|
* system. */
|
||||||
#define RESOURCES_EMBEDDED !(DEVELOPER)
|
#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 PIXELS_PER_UNIT 256
|
||||||
|
|
||||||
#define GAME_FPS 50
|
#define GAME_FPS 50
|
||||||
|
|||||||
@ -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_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
|
* Texture
|
||||||
|
|||||||
@ -124,8 +124,11 @@ GLOBAL struct {
|
|||||||
ID3D11DeviceContext *devcon;
|
ID3D11DeviceContext *devcon;
|
||||||
|
|
||||||
IDXGISwapChain1 *swapchain;
|
IDXGISwapChain1 *swapchain;
|
||||||
ID3D11RenderTargetView *back_buffer_view;
|
ID3D11RenderTargetView *backbuffer_view;
|
||||||
D3D11_VIEWPORT viewport; /* Here for caching/comparison */
|
|
||||||
|
/* Here for caching/comparison */
|
||||||
|
struct v2 backbuffer_size;
|
||||||
|
struct rect viewport;
|
||||||
|
|
||||||
ID3D11BlendState *blend_state;
|
ID3D11BlendState *blend_state;
|
||||||
ID3D11RasterizerState *rasterizer_state;
|
ID3D11RasterizerState *rasterizer_state;
|
||||||
@ -789,35 +792,37 @@ void renderer_canvas_send_to_gpu(struct renderer_canvas *canvas)
|
|||||||
* Present canvas
|
* Present canvas
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void recreate_backbuffer_and_viewport(f32 width, f32 height)
|
INTERNAL void resize_backbuffer(struct v2 size)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
/* TODO: error handling */
|
/* TODO: error handling */
|
||||||
|
|
||||||
/* Release all outstanding references to the swap chain's buffers. */
|
/* Release all outstanding references to the swap chain's buffers. */
|
||||||
if (L.back_buffer_view) {
|
if (L.backbuffer_view) {
|
||||||
ID3D11RenderTargetView_Release(L.back_buffer_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. */
|
/* Get buffer and create a render-target-view. */
|
||||||
ID3D11Texture2D *back_buffer_texture = NULL;
|
ID3D11Texture2D *backbuffer_texture = NULL;
|
||||||
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&back_buffer_texture);
|
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer_texture);
|
||||||
|
|
||||||
ID3D11Device_CreateRenderTargetView(L.dev, (ID3D11Resource *)back_buffer_texture, NULL, &L.back_buffer_view);
|
ID3D11Device_CreateRenderTargetView(L.dev, (ID3D11Resource *)backbuffer_texture, NULL, &L.backbuffer_view);
|
||||||
ID3D11Texture2D_Release(back_buffer_texture);
|
ID3D11Texture2D_Release(backbuffer_texture);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set up the viewport */
|
INTERNAL void resize_viewport(struct rect viewport)
|
||||||
L.viewport = (D3D11_VIEWPORT){
|
{
|
||||||
.Width = width,
|
D3D11_VIEWPORT d3d11_viewport = {
|
||||||
.Height = height,
|
.Width = viewport.width,
|
||||||
|
.Height = viewport.height,
|
||||||
.MinDepth = 0.0f,
|
.MinDepth = 0.0f,
|
||||||
.MaxDepth = 1.0f,
|
.MaxDepth = 1.0f,
|
||||||
.TopLeftX = 0,
|
.TopLeftX = viewport.x,
|
||||||
.TopLeftY = 0
|
.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).
|
/* 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).
|
* research if that is smart first).
|
||||||
*
|
*
|
||||||
* I'm thinking we may also just need to lock texture modification access while presenting */
|
* 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;
|
__prof;
|
||||||
|
|
||||||
/* Resize back buffer */
|
/* Resize back buffer */
|
||||||
D3D11_VIEWPORT old_vp = L.viewport;
|
if (!v2_eq(L.backbuffer_size, screen_size)) {
|
||||||
if (old_vp.Width != viewport_width || old_vp.Height != viewport_height) {
|
resize_backbuffer(screen_size);
|
||||||
recreate_backbuffer_and_viewport(viewport_width, viewport_height);
|
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 */
|
/* Clear back buffer */
|
||||||
f32 clear_color[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
|
f32 clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
ID3D11DeviceContext_ClearRenderTargetView(L.devcon, L.back_buffer_view, clear_color);
|
ID3D11DeviceContext_ClearRenderTargetView(L.devcon, L.backbuffer_view, clear_color);
|
||||||
|
|
||||||
/* Set draw mode */
|
/* Set draw mode */
|
||||||
ID3D11DeviceContext_IASetPrimitiveTopology(L.devcon, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
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
|
/* Fill and set constant buffer
|
||||||
* NOTE: We're only doing this once per canvas, rather than once per draw call since
|
* NOTE: We're only doing this once per canvas, rather than once per draw call since
|
||||||
* the only constant right now is VP. */
|
* 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);
|
send_constant_buffer_data(L.vs_constant_buffer, vp_matrix);
|
||||||
ID3D11DeviceContext_VSSetConstantBuffers(L.devcon, 0, 1, &L.vs_constant_buffer);
|
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);
|
IDXGISwapChain1_Present(L.swapchain, vsync, 0);
|
||||||
__profframe(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 u32 cap_index = 0;
|
||||||
static b32 ready_to_read = false;
|
static b32 ready_to_read = false;
|
||||||
|
|
||||||
ID3D11Texture2D *back_buffer = NULL;
|
ID3D11Texture2D *backbuffer = NULL;
|
||||||
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *) & back_buffer);
|
IDXGISwapChain_GetBuffer(L.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer);
|
||||||
|
|
||||||
struct prof_cap *write_cap = &staging_caps[cap_index];
|
struct prof_cap *write_cap = &staging_caps[cap_index];
|
||||||
*write_cap = (struct prof_cap) { .size = V2(width, height) };
|
*write_cap = (struct prof_cap) { .size = V2(width, height) };
|
||||||
{
|
{
|
||||||
D3D11_TEXTURE2D_DESC staging_desc;
|
D3D11_TEXTURE2D_DESC staging_desc;
|
||||||
ID3D11Texture2D_GetDesc(back_buffer, &staging_desc);
|
ID3D11Texture2D_GetDesc(backbuffer, &staging_desc);
|
||||||
staging_desc.Usage = D3D11_USAGE_STAGING;
|
staging_desc.Usage = D3D11_USAGE_STAGING;
|
||||||
staging_desc.BindFlags = 0;
|
staging_desc.BindFlags = 0;
|
||||||
staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||||
ID3D11Device_CreateTexture2D(L.dev, &staging_desc, NULL, &write_cap->texture);
|
ID3D11Device_CreateTexture2D(L.dev, &staging_desc, NULL, &write_cap->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D11DeviceContext_CopyResource(L.devcon, (ID3D11Resource *)write_cap->texture, (ID3D11Resource *)back_buffer);
|
ID3D11DeviceContext_CopyResource(L.devcon, (ID3D11Resource *)write_cap->texture, (ID3D11Resource *)backbuffer);
|
||||||
ID3D11Texture2D_Release(back_buffer);
|
ID3D11Texture2D_Release(backbuffer);
|
||||||
|
|
||||||
++cap_index;
|
++cap_index;
|
||||||
if (cap_index >= ARRAY_COUNT(staging_caps)) {
|
if (cap_index >= ARRAY_COUNT(staging_caps)) {
|
||||||
|
|||||||
@ -1626,7 +1626,7 @@ u32 sys_rand_u32(void)
|
|||||||
|
|
||||||
void sys_panic_raw(char *msg_cstr)
|
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);
|
MessageBoxExA(NULL, msg_cstr, "Fatal error", MB_ICONSTOP, 0);
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
sys_exit();
|
sys_exit();
|
||||||
@ -1813,7 +1813,7 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
|||||||
wc->lpszClassName = "power_play_window_class";
|
wc->lpszClassName = "power_play_window_class";
|
||||||
wc->hCursor = LoadCursor(NULL, IDC_ARROW);
|
wc->hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
wc->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
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->lpfnWndProc = win32_window_proc;
|
||||||
wc->hInstance = instance;
|
wc->hInstance = instance;
|
||||||
|
|
||||||
|
|||||||
152
src/user.c
152
src/user.c
@ -36,7 +36,8 @@ GLOBAL struct {
|
|||||||
|
|
||||||
struct sys_window *window;
|
struct sys_window *window;
|
||||||
struct renderer_canvas *world_canvas;
|
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_last_frame;
|
||||||
struct xform world_view;
|
struct xform world_view;
|
||||||
|
|
||||||
@ -60,8 +61,11 @@ GLOBAL struct {
|
|||||||
f64 time;
|
f64 time;
|
||||||
f64 dt;
|
f64 dt;
|
||||||
struct v2 screen_size;
|
struct v2 screen_size;
|
||||||
struct v2 screen_center;
|
|
||||||
struct v2 screen_cursor;
|
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;
|
struct v2 world_cursor;
|
||||||
} L = { 0 }, DEBUG_LVAR(L_user);
|
} 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));
|
struct quad quad = quad_from_rect(RECT(0, 0, 1, -1));
|
||||||
quad = quad_mul_xform(quad_scale(quad, 0.075), xf);
|
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.viewport_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_arrow_ray(L.viewport_canvas, pos, y_ray, thickness, arrowhead_len, color_y);
|
||||||
draw_solid_quad(L.screen_canvas, quad, color);
|
draw_solid_quad(L.viewport_canvas, quad, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: remove this (testing) */
|
/* 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 vel_ray = xform_basis_mul_v2(L.world_view, ent->velocity);
|
||||||
struct v2 acc_ray = xform_basis_mul_v2(L.world_view, ent->acceleration);
|
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.viewport_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, acc_ray, thickness, arrow_len, color_acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void user_update(void)
|
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.dt = max_f64(0.0, cur_time - L.time);
|
||||||
L.time += L.dt;
|
L.time += L.dt;
|
||||||
|
|
||||||
/* Get screen dimensions */
|
/* Calculate screen & viewport dimensions */
|
||||||
L.screen_size = sys_window_get_size(L.window);
|
{
|
||||||
L.screen_center = v2_mul(L.screen_size, 0.5);
|
/* Get screen dimensions */
|
||||||
|
L.screen_size = sys_window_get_size(L.window);
|
||||||
|
|
||||||
|
/* 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
|
* Produce interpolated tick
|
||||||
@ -469,6 +496,7 @@ INTERNAL void user_update(void)
|
|||||||
/* Update mouse pos */
|
/* Update mouse pos */
|
||||||
if (event->kind == SYS_EVENT_KIND_CURSOR_MOVE) {
|
if (event->kind == SYS_EVENT_KIND_CURSOR_MOVE) {
|
||||||
L.screen_cursor = event->cursor_position;
|
L.screen_cursor = event->cursor_position;
|
||||||
|
L.viewport_cursor = v2_sub(L.screen_cursor, L.viewport_screen_offset);;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update bind states */
|
/* Update bind states */
|
||||||
@ -520,12 +548,12 @@ INTERNAL void user_update(void)
|
|||||||
/* Pan view */
|
/* Pan view */
|
||||||
if (L.bind_states[USER_BIND_KIND_PAN].is_held) {
|
if (L.bind_states[USER_BIND_KIND_PAN].is_held) {
|
||||||
if (!L.debug_camera_panning) {
|
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;
|
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.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 {
|
} else {
|
||||||
L.debug_camera_panning = false;
|
L.debug_camera_panning = false;
|
||||||
}
|
}
|
||||||
@ -548,7 +576,7 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Zoom to cursor */
|
/* 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_translate(L.world_view, world_cursor);
|
||||||
L.world_view = xform_scale(L.world_view, V2(zoom, zoom));
|
L.world_view = xform_scale(L.world_view, V2(zoom, zoom));
|
||||||
L.world_view = xform_translate(L.world_view, v2_neg(world_cursor));
|
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;
|
zoom = zoom > 0 ? zoom : 1;
|
||||||
|
|
||||||
struct trs trs = TRS(
|
struct trs trs = TRS(
|
||||||
.t = v2_sub(L.screen_center, center),
|
.t = v2_sub(L.viewport_center, center),
|
||||||
.r = rot,
|
.r = rot,
|
||||||
.s = v2_mul(V2(PIXELS_PER_UNIT, PIXELS_PER_UNIT), zoom)
|
.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_translate(L.world_view, pivot);
|
||||||
L.world_view = xform_trs_pivot_rs(L.world_view, trs, 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
|
* Update listener
|
||||||
@ -578,17 +606,26 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
{
|
{
|
||||||
struct v2 up = V2(0, -1);
|
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));
|
struct v2 listener_dir = v2_norm(xform_basis_invert_mul_v2(L.world_view, up));
|
||||||
mixer_set_listener(listener_pos, listener_dir);
|
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
|
* 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 color = RGBA(0x3f, 0x3f, 0x3f, 0xFF);
|
||||||
u32 x_color = RGBA(0x3f, 0, 0, 0xFF);
|
u32 x_color = RGBA(0x3f, 0, 0, 0xFF);
|
||||||
u32 y_color = RGBA(0, 0x3f, 0, 0xFF);
|
u32 y_color = RGBA(0, 0x3f, 0, 0xFF);
|
||||||
@ -599,25 +636,25 @@ INTERNAL void user_update(void)
|
|||||||
i64 cols = 20;
|
i64 cols = 20;
|
||||||
|
|
||||||
/* Draw column lines */
|
/* 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) {
|
for (i64 col = starty; col <= (starty + cols); ++col) {
|
||||||
u32 line_color = color;
|
u32 line_color = color;
|
||||||
if (col == 0) {
|
if (col == 0) {
|
||||||
line_color = y_color;
|
line_color = y_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct v2 pos = V2(col, starty);
|
struct v2 pos = xform_mul_v2(L.world_view, V2(col, starty));
|
||||||
draw_solid_ray(L.world_canvas, pos, col_ray, thickness, line_color);
|
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) {
|
for (i64 row = startx; row <= (startx + rows); ++row) {
|
||||||
u32 line_color = color;
|
u32 line_color = color;
|
||||||
if (row == 0) {
|
if (row == 0) {
|
||||||
line_color = x_color;
|
line_color = x_color;
|
||||||
}
|
}
|
||||||
struct v2 pos = V2(startx, row);
|
struct v2 pos = xform_mul_v2(L.world_view, V2(startx, row));
|
||||||
draw_solid_ray(L.world_canvas, pos, row_ray, thickness, line_color);
|
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
|
#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 start = xform_mul_v2(L.world_view, ent->world_xform.og);
|
||||||
struct v2 end = xform_mul_v2(L.world_view, parent->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 */
|
/* Draw aim */
|
||||||
@ -762,7 +799,7 @@ INTERNAL void user_update(void)
|
|||||||
f32 arrow_height = 10;
|
f32 arrow_height = 10;
|
||||||
struct v2 pos = xform_mul_v2(L.world_view, ent->world_xform.og);
|
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);
|
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);
|
arena_temp_end(temp);
|
||||||
@ -771,8 +808,8 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
/* Draw crosshair or show cursor */
|
/* Draw crosshair or show cursor */
|
||||||
if (!L.debug_camera) {
|
if (!L.debug_camera) {
|
||||||
struct v2 crosshair_pos = L.screen_cursor;
|
struct v2 crosshair_pos = L.viewport_cursor;
|
||||||
u32 tint = RGBA_F(1, 1, 1, 1 );
|
u32 tint = RGBA_F(1, 1, 1, 1);
|
||||||
|
|
||||||
struct v2 size = V2(0, 0);
|
struct v2 size = V2(0, 0);
|
||||||
struct texture *t = texture_load_async(STR("res/graphics/crosshair.ase"));
|
struct texture *t = texture_load_async(STR("res/graphics/crosshair.ase"));
|
||||||
@ -780,11 +817,15 @@ INTERNAL void user_update(void)
|
|||||||
size = t->size;
|
size = t->size;
|
||||||
struct xform xf = XFORM_TRS(.t = crosshair_pos, .s = size);
|
struct xform xf = XFORM_TRS(.t = crosshair_pos, .s = size);
|
||||||
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xf);
|
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_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 {
|
} else {
|
||||||
sys_window_cursor_disable_clip(L.window);
|
sys_window_cursor_disable_clip(L.window);
|
||||||
sys_window_cursor_show(L.window);
|
sys_window_cursor_show(L.window);
|
||||||
@ -854,31 +895,40 @@ INTERNAL void user_update(void)
|
|||||||
struct v2 pos = V2(10, 8);
|
struct v2 pos = V2(10, 8);
|
||||||
struct font *font = font_load(STR("res/fonts/fixedsys.ttf"), 12.0f);
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
pos.y += spacing;
|
||||||
|
|
||||||
arena_temp_end(temp);
|
arena_temp_end(temp);
|
||||||
@ -892,12 +942,14 @@ INTERNAL void user_update(void)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Send canvases to GPU */
|
/* 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.world_canvas);
|
||||||
renderer_canvas_send_to_gpu(L.screen_canvas);
|
renderer_canvas_send_to_gpu(L.viewport_canvas);
|
||||||
|
|
||||||
/* Set canvas views before presenting */
|
/* 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.world_canvas, L.world_view);
|
||||||
renderer_canvas_set_view(L.screen_canvas, XFORM_IDENT);
|
renderer_canvas_set_view(L.viewport_canvas, XFORM_IDENT);
|
||||||
|
|
||||||
/* Present */
|
/* Present */
|
||||||
i32 vsync = VSYNC_ENABLED;
|
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 *);
|
struct renderer_canvas **canvases = arena_dry_push(scratch.arena, struct renderer_canvas *);
|
||||||
u64 canvases_count = 0;
|
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) {
|
if (!tick_is_first_frame) {
|
||||||
|
/* Only render world if not on first frame */
|
||||||
*arena_push(scratch.arena, struct renderer_canvas *) = L.world_canvas;
|
*arena_push(scratch.arena, struct renderer_canvas *) = L.world_canvas;
|
||||||
++canvases_count;
|
++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;
|
++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);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
@ -951,7 +1010,8 @@ void user_startup(struct sys_window *window)
|
|||||||
L.world_canvas = renderer_canvas_alloc();
|
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.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;
|
L.window = window;
|
||||||
sys_window_register_event_callback(L.window, &window_event_callback);
|
sys_window_register_event_callback(L.window, &window_event_callback);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user