102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
graphics.c
Go to the documentation of this file.
1#include "graphics_private.h"
2#include "hooks_private.h"
3
4#include <dttr_config.h>
5#include <dttr_errors.h>
6#include <dttr_log.h>
7#include <dttr_sdl.h>
8
9#include <stddef.h>
10#include <windows.h>
11
12#ifdef DTTR_MODS_ENABLED
13#include "mods/mods_private.h"
14#endif
15#include "sds.h"
16#include "sidecar_private.h"
17
18#define DTTR_MIN_WINDOW_DIM 64
19#define BACKEND_COUNT SDL_arraysize(backend_candidates)
20
21typedef struct {
25
28 {SDL_WINDOW_OPENGL, dttr_graphics_opengl_init},
29};
30
31#define IDX_SDL_GPU 0
32#define IDX_OPENGL 1
33
34static sds window_title = NULL;
35
36typedef struct {
37 int start;
38 int end;
40
41// Show renderer and pixel size in the window title.
43 int w = 0, h = 0;
44 SDL_GetWindowSizeInPixels(state->window, &w, &h);
45
46 const char *driver = state->renderer ? state->renderer->get_driver_name(state)
47 : "unknown";
48
49 if (!window_title) {
50 window_title = sdsempty();
51 }
52
53 sdsclear(window_title);
54 window_title = sdscatprintf(
56#ifdef DTTR_MODS_ENABLED
57 "102 Dalmatians - DttR - Modding - " DTTR_VERSION " - %s - %dx%d",
58#else
59 "102 Dalmatians - DttR - " DTTR_VERSION " - %s - %dx%d",
60#endif
61 driver ? driver : "unknown",
62 w,
63 h
64 );
65
66 SDL_SetWindowTitle(state->window, window_title);
67}
68
69// Clamp bogus render sizes to the game default.
70static int clamp_dim(int value, int fallback) {
71 return (value < DTTR_MIN_WINDOW_DIM) ? fallback : value;
72}
73
74// Derives the internal render target size from logical-scaling settings and the current
75// window size.
78 int *out_width,
79 int *out_height
80) {
81 int width = state->logical_width;
82 int height = state->logical_height;
83
84 if (dttr_config.scaling_method == DTTR_SCALING_METHOD_LOGICAL) {
85 int window_px_width = 0;
86 int window_px_height = 0;
87 int target_width = dttr_config.window_width;
88 int target_height = dttr_config.window_height;
89
90 if (state->window
91 && SDL_GetWindowSizeInPixels(
92 state->window,
93 &window_px_width,
94 &window_px_height
95 )) {
96 if (window_px_width > target_width) {
97 target_width = window_px_width;
98 }
99
100 if (window_px_height > target_height) {
101 target_height = window_px_height;
102 }
103 }
104
105 if (dttr_config.scaling_fit == DTTR_SCALING_MODE_STRETCH) {
106 width = target_width;
107 height = target_height;
108 } else {
109 const int lw = clamp_dim(state->logical_width, WINDOW_WIDTH);
110 const int lh = clamp_dim(state->logical_height, WINDOW_HEIGHT);
111 const float scale = SDL_min(
112 (float)target_width / (float)lw,
113 (float)target_height / (float)lh
114 );
115
116 width = (int)((float)lw * scale);
117 height = (int)((float)lh * scale);
118 }
119 }
120
121 *out_width = clamp_dim(width, WINDOW_WIDTH);
122 *out_height = clamp_dim(height, WINDOW_HEIGHT);
123}
124
125// Resizes backend render targets only when the selected logical resolution has changed.
127 int rw = state->width;
128 int rh = state->height;
130
131 if (rw == state->width && rh == state->height) {
132 return;
133 }
134
135 if (!state->renderer->resize(state, rw, rh)) {
136 DTTR_LOG_WARN("Failed to resize render targets to %dx%d", rw, rh);
137 }
138}
139
140// Seeds renderer-independent state before either SDL GPU or OpenGL owns the backend.
145
146 state->texture_mutex = SDL_CreateMutex();
147 kv_init(state->pending_upload_indices);
148 kv_init(state->batch_records);
150
151 state->clear_color = (SDL_FColor){0, 0, 0, 1};
152 state->depth_test = true;
153 state->depth_write = true;
154 state->blend_enabled = false;
155 state->addr_u = DTTR_TEXADDR_WRAP;
156 state->addr_v = DTTR_TEXADDR_WRAP;
157 state->blend_dst = DTTR_BLEND_ZERO;
158 state->stage_color_op = DTTR_D3DTOP_MODULATE;
159 state->stage_color_arg1 = DTTR_D3DTA_TEXTURE;
160 state->stage_color_arg2 = DTTR_D3DTA_DIFFUSE;
161 state->stage_alpha_op = DTTR_D3DTOP_SELECTARG1;
162 state->stage_alpha_arg1 = DTTR_D3DTA_TEXTURE;
163 state->stage_alpha_arg2 = DTTR_D3DTA_DIFFUSE;
164
165 state->viewport_x = 0;
166 state->viewport_y = 0;
167 state->viewport_w = state->logical_width;
168 state->viewport_h = state->logical_height;
169 state->viewport_min_z = 0.0f;
170 state->viewport_max_z = 1.0f;
171
172 state->initialized = true;
173 state->gpu_thread_id = SDL_GetCurrentThreadID();
174}
175
176// Retrieves the native Win32 handle that the original game and modding callbacks expect.
177static HWND get_hwnd(SDL_Window *window) {
178 if (!window) {
179 return NULL;
180 }
181
182 const SDL_PropertiesID props = SDL_GetWindowProperties(window);
183 return (HWND)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
184}
185
186#ifdef DTTR_MODS_ENABLED
187// Scales mod coordinates from the original 480-line game space into the active
188// render target.
189static float graphics_scale(uint32_t height) {
190 return height > 0 ? (float)height / 480.0f : 1.0f;
191}
192
193// Reads the real SDL window size and falls back to render-target dimensions during
194// early startup.
195static void graphics_window_size(const DTTR_BackendState *state, uint32_t *w, uint32_t *h) {
196 int win_w = 0;
197 int win_h = 0;
198 if (state && state->window) {
199 SDL_GetWindowSizeInPixels(state->window, &win_w, &win_h);
200 }
201
202 *w = (uint32_t)((win_w > 0) ? win_w : (state ? state->width : 0));
203 *h = (uint32_t)((win_h > 0) ? win_h : (state ? state->height : 0));
204}
205
206// Builds the per-frame mod payload from the current game and window dimensions.
207static DTTR_Mods_FrameContext graphics_frame_context(const DTTR_BackendState *state) {
208 uint32_t window_w = 0;
209 uint32_t window_h = 0;
210 const uint32_t game_w = (uint32_t)(state ? state->width : 0);
211 const uint32_t game_h = (uint32_t)(state ? state->height : 0);
212 graphics_window_size(state, &window_w, &window_h);
213 return (DTTR_Mods_FrameContext){
214 .frame_index = state ? state->frame_index : 0,
215 .window_w = window_w,
216 .window_h = window_h,
217 .game_x = 0,
218 .game_y = 0,
219 .game_w = game_w,
220 .game_h = game_h,
221 .scale = graphics_scale(game_h),
222 };
223}
224
225// Combines viewport bounds, overlay state, and scale into the mod present payload.
226static DTTR_Mods_PresentContext graphics_present_context(
228 uint32_t game_x,
229 uint32_t game_y,
230 uint32_t game_w,
231 uint32_t game_h,
232 bool imgui_frame_active,
233 bool overlay_rendered
234) {
235 uint32_t window_w = 0;
236 uint32_t window_h = 0;
237 graphics_window_size(state, &window_w, &window_h);
239 .frame_index = state ? state->frame_index : 0,
240 .window_w = window_w,
241 .window_h = window_h,
242 .game_x = game_x,
243 .game_y = game_y,
244 .game_w = game_w,
245 .game_h = game_h,
246 .scale = graphics_scale(game_h),
247 .imgui_frame_active = imgui_frame_active,
248 .overlay_rendered = overlay_rendered,
249 };
250}
251
252// Converts the active SDL window into the mod window payload used by lifecycle
253// callbacks.
254static DTTR_Mods_WindowContext graphics_window_context(const DTTR_BackendState *state) {
255 uint32_t window_w = 0;
256 uint32_t window_h = 0;
257 graphics_window_size(state, &window_w, &window_h);
259 .window = state ? state->window : NULL,
260 .hwnd = state ? get_hwnd(state->window) : NULL,
261 .window_w = window_w,
262 .window_h = window_h,
263 };
264}
265
266// Maps the selected renderer implementation to the public mod backend enum.
267static DTTR_Mods_GraphicsBackend graphics_backend(const DTTR_BackendState *state) {
268 if (!state) {
270 }
271
272 switch (state->backend_type) {
277 default:
279 }
280}
281
282// Packages the active window, backend, and render target into the mod graphics
283// context.
284static DTTR_Mods_GraphicsContext graphics_context(const DTTR_BackendState *state) {
286 .window = state ? state->window : NULL,
287 .hwnd = state ? get_hwnd(state->window) : NULL,
288 .backend = graphics_backend(state),
289 .driver_name = (state && state->renderer)
291 : NULL,
292 .render_w = (uint32_t)(state ? state->width : 0),
293 .render_h = (uint32_t)(state ? state->height : 0),
294 };
295}
296
297static void call_frame_mod(DTTR_BackendState *state, DTTR_Mods_FrameBeginFn callback) {
298 const DTTR_Mods_FrameContext ctx = graphics_frame_context(state);
299 callback(&ctx);
300}
301
302static void call_present_mod(
304 uint32_t game_x,
305 uint32_t game_y,
306 uint32_t game_w,
307 uint32_t game_h,
308 bool imgui_frame_active,
309 bool overlay_rendered,
311) {
312 const DTTR_Mods_PresentContext ctx = graphics_present_context(
313 state,
314 game_x,
315 game_y,
316 game_w,
317 game_h,
318 imgui_frame_active,
319 overlay_rendered
320 );
321 callback(&ctx);
322}
323
324static void call_window_mod(DTTR_BackendState *state, DTTR_Mods_WindowCreatedFn callback) {
325 const DTTR_Mods_WindowContext ctx = graphics_window_context(state);
326 callback(&ctx);
327}
328
329static void call_graphics_mod(
332) {
333 const DTTR_Mods_GraphicsContext ctx = graphics_context(state);
334 callback(&ctx);
335}
336
338 call_frame_mod(state, dttr_mods_frame_begin);
339}
340
342 call_frame_mod(state, dttr_mods_before_game_frame);
343}
344
346 call_frame_mod(state, dttr_mods_after_game_frame);
347}
348
351 uint32_t game_x,
352 uint32_t game_y,
353 uint32_t game_w,
354 uint32_t game_h,
355 bool imgui_frame_active,
356 bool overlay_rendered
357) {
358 call_present_mod(
359 state,
360 game_x,
361 game_y,
362 game_w,
363 game_h,
364 imgui_frame_active,
365 overlay_rendered,
367 );
368}
369
372 uint32_t game_x,
373 uint32_t game_y,
374 uint32_t game_w,
375 uint32_t game_h,
376 bool imgui_frame_active,
377 bool overlay_rendered
378) {
379 call_present_mod(
380 state,
381 game_x,
382 game_y,
383 game_w,
384 game_h,
385 imgui_frame_active,
386 overlay_rendered,
388 );
389}
390
392 call_frame_mod(state, dttr_mods_frame_end);
393}
394
396 call_window_mod(state, dttr_mods_window_created);
397}
398
400 call_window_mod(state, dttr_mods_window_resized);
401}
402
404 call_window_mod(state, dttr_mods_window_destroying);
405}
406
408 call_graphics_mod(state, dttr_mods_graphics_device_created);
409}
410
412 call_graphics_mod(state, dttr_mods_graphics_device_lost);
413}
414
416 call_graphics_mod(state, dttr_mods_graphics_device_restored);
417}
418
421}
422#endif
423
426 const DTTR_PresentRect *present
427) {
429 state,
430 (uint32_t)present->x,
431 (uint32_t)present->y,
432 (uint32_t)present->w,
433 (uint32_t)present->h,
434 false,
435 true
436 );
437}
438
441 const DTTR_PresentRect *present,
442 bool overlay_rendered
443) {
445 state,
446 (uint32_t)present->x,
447 (uint32_t)present->y,
448 (uint32_t)present->w,
449 (uint32_t)present->h,
450 false,
451 overlay_rendered
452 );
453}
454
455// Tears down the SDL window after notifying mods so no lifecycle callback sees a
456// dangling window handle.
458 if (!state->window) {
459 return;
460 }
461
463 SDL_DestroyWindow(state->window);
464 state->window = NULL;
465}
466
467// Limits backend probing to the user-selected API while preserving the fallback order
468// for automatic graphics selection.
470 switch (api) {
475 default:
477 }
478}
479
480// Probes the configured graphics backends, creates the game window, and publishes the
481// chosen device to mods.
484
485 if (state->initialized && state->window) {
486 return get_hwnd(state->window);
487 }
488
489 if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
490 DTTR_LOG_ERROR("SDL_Init failed: %s", SDL_GetError());
491 return NULL;
492 }
493
494 int win_w = clamp_dim(dttr_config.window_width, WINDOW_WIDTH);
495 int win_h = clamp_dim(dttr_config.window_height, WINDOW_HEIGHT);
496
497 state->logical_width = WINDOW_WIDTH;
498 state->logical_height = WINDOW_HEIGHT;
499 select_render_resolution(state, &state->width, &state->height);
500
502
503 for (int i = backend_range.start; i <= backend_range.end; i++) {
505
506 state->window = SDL_CreateWindow(
507 "102 Dalmatians",
508 win_w,
509 win_h,
510 SDL_WINDOW_RESIZABLE | backend_candidates[i].window_flags
511 );
512
513 if (!state->window) {
514 continue;
515 }
516
517 if (!backend_candidates[i].init(state)) {
518 continue;
519 }
520
524
525 if (dttr_config.fullscreen) {
526 if (!SDL_SetWindowFullscreen(state->window, true)) {
527 DTTR_LOG_WARN("SDL_SetWindowFullscreen failed: %s", SDL_GetError());
528 }
529 }
530
533
534 return get_hwnd(state->window);
535 }
536
537 {
538 sds msg;
539 if (dttr_config.graphics_api == DTTR_GRAPHICS_API_AUTO) {
540 msg = sdsnew("All graphics backends failed to initialize");
541 } else {
542 msg = sdscatprintf(
543 sdsempty(),
544 "Graphics backend '%s' failed to initialize. "
545 "It may not be supported on this system.",
547 );
548 }
549
550 DTTR_LOG_ERROR("%s", msg);
551 DTTR_Errors_ShowMessage("DttR: Error", msg);
552 sdsfree(msg);
553 }
554
556
557 return NULL;
558}
559
560// Updates the game-space resolution and resizes backend targets when scaling settings
561// require it.
562void dttr_graphics_set_logical_resolution(int width, int height) {
564
565 state->logical_width = clamp_dim(width, WINDOW_WIDTH);
566 state->logical_height = clamp_dim(height, WINDOW_HEIGHT);
567
568 if (state->viewport_w <= 0 || state->viewport_h <= 0
569 || (state->viewport_x == 0 && state->viewport_y == 0)) {
570 state->viewport_w = state->logical_width;
571 state->viewport_h = state->logical_height;
572 }
573
575}
576
577// Returns the SDL window owned by the active graphics backend.
581
582// Returns the SDL GPU device when the active backend owns one.
583SDL_GPUDevice *dttr_graphics_get_device() {
584 return dttr_backend.device;
585}
586
587// Applies a user window resize to render targets before notifying mods.
597
598// Starts backend frame rendering after mod frame-begin callbacks run.
601
602 if (state->frame_active) {
603 return;
604 }
605
606 state->renderer->begin_frame(state);
607}
608
609// Finishes backend frame rendering before mod frame-end callbacks run.
612
613 if (!state->frame_active) {
614 return;
615 }
616
617 state->renderer->end_frame(state);
618}
619
620// Uploads a decoded BGRA movie frame through the active renderer for fullscreen playback.
622 const uint8_t *pixels,
623 int width,
624 int height,
625 int stride
626) {
628
629 if (!pixels || width <= 0 || height <= 0 || stride < (width * 4)) {
630 return false;
631 }
632
633 return state->renderer->present_video_frame_bgra(state, pixels, width, height, stride);
634}
635
636// Tears down graphics lifecycle callbacks, backend resources, and the SDL window in
637// order.
641
643
644 if (state->renderer) {
645 state->renderer->cleanup(state);
646 state->renderer = NULL;
647 }
648
649 if (state->texture_mutex) {
650 SDL_DestroyMutex(state->texture_mutex);
651 state->texture_mutex = NULL;
652 }
653
655 kv_destroy(state->pending_upload_indices);
656 kv_destroy(state->batch_records);
657 kv_init(state->pending_upload_indices);
658 kv_init(state->batch_records);
659
661 state->initialized = false;
662
663 SDL_Quit();
664}
bool dttr_graphics_opengl_init(DTTR_BackendState *state)
static const char * get_driver_name(const DTTR_BackendState *state)
static const DTTR_RendererVtbl renderer
bool dttr_graphics_sdl3gpu_init(DTTR_BackendState *state)
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD idx float
size_t stride
const DTTR_BackendState * state
void void * ctx
DTTR_Graphics_COM_DirectDraw7 *self DWORD DWORD h
DTTR_Graphics_COM_DirectDraw7 *self DWORD w
void dttr_graphics_surface_texture_cache_reset()
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
DTTR_GraphicsApi
Definition dttr_config.h:36
@ DTTR_GRAPHICS_API_AUTO
Definition dttr_config.h:37
@ DTTR_GRAPHICS_API_OPENGL
Definition dttr_config.h:40
#define WINDOW_WIDTH
Definition dttr_config.h:11
#define WINDOW_HEIGHT
Definition dttr_config.h:12
@ DTTR_SCALING_METHOD_LOGICAL
Definition dttr_config.h:22
const char * DTTR_Config_GraphicsAPIName(DTTR_GraphicsApi api)
Returns the config token for a graphics API selection.
Definition defaults.c:192
@ DTTR_SCALING_MODE_STRETCH
Definition dttr_config.h:16
DTTR_Config dttr_config
Definition defaults.c:53
void DTTR_Errors_ShowMessage(const char *title, const char *message)
Definition errors.c:10
#define DTTR_LOG_WARN(...)
Definition dttr_log.h:30
#define DTTR_LOG_ERROR(...)
Definition dttr_log.h:31
void(* DTTR_Mods_BeforePresentFn)(const DTTR_Mods_PresentContext *ctx)
Definition dttr_mods.h:182
struct SDL_Window SDL_Window
Definition dttr_mods.h:19
void(* DTTR_Mods_FrameBeginFn)(const DTTR_Mods_FrameContext *ctx)
Definition dttr_mods.h:179
void(* DTTR_Mods_GraphicsDeviceCreatedFn)(const DTTR_Mods_GraphicsContext *ctx)
Definition dttr_mods.h:191
DTTR_Mods_GraphicsBackend
Definition dttr_mods.h:140
@ DTTR_MODS_GRAPHICS_BACKEND_UNKNOWN
Definition dttr_mods.h:141
@ DTTR_MODS_GRAPHICS_BACKEND_SDL_GPU
Definition dttr_mods.h:142
@ DTTR_MODS_GRAPHICS_BACKEND_OPENGL
Definition dttr_mods.h:143
void(* DTTR_Mods_WindowCreatedFn)(const DTTR_Mods_WindowContext *ctx)
Definition dttr_mods.h:188
SDL_Window * dttr_graphics_get_window()
Definition graphics.c:578
void dttr_graphics_set_logical_resolution(int width, int height)
Definition graphics.c:562
SDL_GPUDevice * dttr_graphics_get_device()
Definition graphics.c:583
static void select_render_resolution(const DTTR_BackendState *state, int *out_width, int *out_height)
Definition graphics.c:76
HWND dttr_graphics_init()
Definition graphics.c:482
static void refresh_render_resolution(DTTR_BackendState *state)
Definition graphics.c:126
static HWND get_hwnd(SDL_Window *window)
Definition graphics.c:177
#define BACKEND_COUNT
Definition graphics.c:19
void dttr_graphics_handle_window_resize(int width, int height)
Definition graphics.c:588
static int clamp_dim(int value, int fallback)
Definition graphics.c:70
void dttr_graphics_mod_present_rect_before(DTTR_BackendState *state, const DTTR_PresentRect *present)
Definition graphics.c:424
#define DTTR_MIN_WINDOW_DIM
Definition graphics.c:18
static sds window_title
Definition graphics.c:34
void dttr_graphics_mod_present_rect_after(DTTR_BackendState *state, const DTTR_PresentRect *present, bool overlay_rendered)
Definition graphics.c:439
static void init_common_state(DTTR_BackendState *state)
Definition graphics.c:141
static void update_window_title(const DTTR_BackendState *state)
Definition graphics.c:42
static void destroy_window(DTTR_BackendState *state)
Definition graphics.c:457
void dttr_graphics_begin_frame()
Definition graphics.c:599
#define IDX_SDL_GPU
Definition graphics.c:31
void dttr_graphics_cleanup()
Definition graphics.c:638
#define IDX_OPENGL
Definition graphics.c:32
bool dttr_graphics_present_video_frame_bgra(const uint8_t *pixels, int width, int height, int stride)
Definition graphics.c:621
static const backend_candidate backend_candidates[]
Definition graphics.c:26
void dttr_graphics_end_frame()
Definition graphics.c:610
static backend_range select_backend_range(DTTR_GraphicsApi api)
Definition graphics.c:469
static void dttr_graphics_mod_device_destroying(DTTR_BackendState *)
void dttr_graphics_mat4_identity(float *m)
Definition util.c:116
@ DTTR_BLEND_ZERO
#define DTTR_D3DTA_DIFFUSE
static void dttr_graphics_mod_window_resized(DTTR_BackendState *)
#define DTTR_D3DTOP_SELECTARG1
@ DTTR_BACKEND_OPENGL
@ DTTR_BACKEND_SDL_GPU
static void dttr_graphics_mod_device_lost(DTTR_BackendState *)
static void dttr_graphics_mod_before_game_frame(DTTR_BackendState *)
#define DTTR_D3DTA_TEXTURE
static void dttr_graphics_mod_device_restored(DTTR_BackendState *)
static void dttr_graphics_mod_before_present(DTTR_BackendState *, uint32_t, uint32_t, uint32_t, uint32_t, bool, bool)
static void dttr_graphics_mod_device_created(DTTR_BackendState *)
@ DTTR_TEXADDR_WRAP
#define DTTR_D3DTOP_MODULATE
static void dttr_graphics_mod_window_destroying(DTTR_BackendState *)
DTTR_BackendState dttr_backend
Definition util.c:8
static void dttr_graphics_mod_window_created(DTTR_BackendState *)
static void dttr_graphics_mod_after_present(DTTR_BackendState *, uint32_t, uint32_t, uint32_t, uint32_t, bool, bool)
static void dttr_graphics_mod_after_game_frame(DTTR_BackendState *)
static void dttr_graphics_mod_frame_begin(DTTR_BackendState *)
static void dttr_graphics_mod_frame_end(DTTR_BackendState *)
#define DTTR_VERSION
void dttr_mods_window_destroying(const DTTR_Mods_WindowContext *ctx)
Definition mods.c:666
void dttr_mods_after_game_frame(const DTTR_Mods_FrameContext *ctx)
Definition mods.c:630
void dttr_mods_frame_begin(const DTTR_Mods_FrameContext *ctx)
Definition mods.c:622
void dttr_mods_before_present(const DTTR_Mods_PresentContext *ctx)
Definition mods.c:634
void dttr_mods_graphics_device_destroying(const DTTR_Mods_GraphicsContext *ctx)
Definition mods.c:682
void dttr_mods_after_present(const DTTR_Mods_PresentContext *ctx)
Definition mods.c:638
void dttr_mods_window_resized(const DTTR_Mods_WindowContext *ctx)
Definition mods.c:662
void dttr_mods_frame_end(const DTTR_Mods_FrameContext *ctx)
Definition mods.c:642
void dttr_mods_graphics_device_created(const DTTR_Mods_GraphicsContext *ctx)
Definition mods.c:670
void dttr_mods_window_created(const DTTR_Mods_WindowContext *ctx)
Definition mods.c:658
void dttr_mods_before_game_frame(const DTTR_Mods_FrameContext *ctx)
Definition mods.c:626
void dttr_mods_graphics_device_restored(const DTTR_Mods_GraphicsContext *ctx)
Definition mods.c:678
void dttr_mods_graphics_device_lost(const DTTR_Mods_GraphicsContext *ctx)
Definition mods.c:674
Game-image placement within the present target, in target pixels.
bool(* init)(DTTR_BackendState *state)
Definition graphics.c:23
Uint64 window_flags
Definition graphics.c:22