maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
retrowin.h
Go to the documentation of this file.
1
2#ifndef RETROW3D_H
3#define RETROW3D_H
4
48
49#ifndef RETROWIN_TRACE_LVL
50# define RETROWIN_TRACE_LVL 0
51#endif /* !RETROWIN_TRACE_LVL */
52
58#define RETROWIN_FLAG_INIT_GUI 0x10
59
60#define RETROWIN_FLAG_INIT_BMP 0x20
61
62#define RETROWIN_FLAG_GUI_LOCKED 0x04
63
64#define RETROWIN_FLAG_BORDER_NONE 0x00
65#define RETROWIN_FLAG_BORDER_GRAY 0x01
66#define RETROWIN_FLAG_BORDER_BLUE 0x02
67
68#define retrowin_win_is_active( win ) \
69 (RETROWIN_FLAG_INIT_BMP == (RETROWIN_FLAG_INIT_BMP & (win)->flags))
70
71#define RETROWIN_FLAG_BORDER_MASK 0x03
72
73#define retrowin_lock_gui( win ) \
74 if( \
75 RETROWIN_FLAG_INIT_GUI == (RETROWIN_FLAG_INIT_GUI & (win)->flags) && \
76 RETROWIN_FLAG_GUI_LOCKED != (RETROWIN_FLAG_GUI_LOCKED & (win)->flags) \
77 ) { \
78 debug_printf( RETROWIN_TRACE_LVL, "locking managed gui handle %p...", \
79 (win)->gui_h ); \
80 maug_mlock( (win)->gui_h, (win)->gui_p ); \
81 maug_cleanup_if_null_lock( struct RETROGUI*, (win)->gui_p ); \
82 (win)->flags |= RETROWIN_FLAG_GUI_LOCKED; \
83 debug_printf( RETROWIN_TRACE_LVL, "locked managed gui to pointer %p!", \
84 (win)->gui_p ); \
85 }
86
87#define retrowin_unlock_gui( win ) \
88 if( \
89 RETROWIN_FLAG_INIT_GUI == (RETROWIN_FLAG_INIT_GUI & (win)->flags) && \
90 RETROWIN_FLAG_GUI_LOCKED == (RETROWIN_FLAG_GUI_LOCKED & (win)->flags) \
91 ) { \
92 debug_printf( RETROWIN_TRACE_LVL, "unlocking managed gui pointer %p...", \
93 (win)->gui_h ); \
94 maug_munlock( (win)->gui_h, (win)->gui_p ); \
95 (win)->flags &= ~RETROWIN_FLAG_GUI_LOCKED; \
96 }
97
98struct RETROWIN {
99 uint8_t flags;
100 size_t idc;
101 size_t x;
102 size_t y;
103 MAUG_MHANDLE gui_h;
104 struct RETROGUI* gui_p;
105 retroflat_blit_t gui_bmp;
106};
107
108MERROR_RETVAL retrowin_redraw_win_stack( struct MDATA_VECTOR* win_stack );
109
114
115retrogui_idc_t retrowin_poll_win_stack(
116 struct MDATA_VECTOR* win_stack, retrogui_idc_t idc_active,
117 RETROFLAT_IN_KEY* p_input, struct RETROFLAT_INPUT* input_evt );
118
119void retrowin_free_win( struct RETROWIN* win );
120
121ssize_t retrowin_get_by_idc( size_t idc, struct MDATA_VECTOR* win_stack );
122
132 struct RETROGUI* gui, struct MDATA_VECTOR* win_stack,
133 size_t idc, const char* font_filename,
134 size_t x, size_t y, size_t w, size_t h, uint8_t flags );
135
142 struct MDATA_VECTOR* win_stack, size_t idc );
143
144#ifdef RETROW3D_C
145
146static MERROR_RETVAL _retrowin_draw_border( struct RETROWIN* win ) {
147 MERROR_RETVAL retval = MERROR_OK;
148
149 assert(
150 RETROWIN_FLAG_INIT_GUI != (RETROWIN_FLAG_INIT_GUI & win->flags) ||
151 RETROWIN_FLAG_GUI_LOCKED == (RETROWIN_FLAG_GUI_LOCKED & win->flags) );
152
153 switch( RETROWIN_FLAG_BORDER_MASK & win->flags ) {
154 case RETROWIN_FLAG_BORDER_GRAY:
155 retroflat_2d_rect(
156 win->gui_p->draw_bmp,
157 2 < retroflat_screen_colors() ?
158 RETROFLAT_COLOR_GRAY : RETROFLAT_COLOR_WHITE, 0, 0,
159 retroflat_2d_bitmap_w( win->gui_p->draw_bmp ),
160 retroflat_2d_bitmap_h( win->gui_p->draw_bmp ),
162
163 /* Draw the border. */
164 retroflat_2d_rect(
165 win->gui_p->draw_bmp, RETROFLAT_COLOR_BLACK, 0, 0,
166 retroflat_2d_bitmap_w( win->gui_p->draw_bmp ),
167 retroflat_2d_bitmap_h( win->gui_p->draw_bmp ),
168 0 );
169 if( 2 < retroflat_screen_colors() ) {
170 /* Draw highlight lines only visible in >2-color mode. */
171 retroflat_2d_line(
172 win->gui_p->draw_bmp, RETROFLAT_COLOR_WHITE,
173 1, 1, retroflat_2d_bitmap_w( win->gui_p->draw_bmp ) - 2, 1, 0 );
174 retroflat_2d_line(
175 win->gui_p->draw_bmp, RETROFLAT_COLOR_WHITE,
176 1, 2, 1, retroflat_2d_bitmap_h( win->gui_p->draw_bmp ) - 3, 0 );
177 }
178 break;
179
180 case RETROWIN_FLAG_BORDER_BLUE:
181 retroflat_2d_rect(
182 win->gui_p->draw_bmp,
183 2 < retroflat_screen_colors() ?
184 RETROFLAT_COLOR_BLUE : RETROFLAT_COLOR_BLACK, 0, 0,
185 retroflat_2d_bitmap_w( win->gui_p->draw_bmp ),
186 retroflat_2d_bitmap_h( win->gui_p->draw_bmp ),
188
189 /* Draw the border. */
190 retroflat_2d_rect(
191 win->gui_p->draw_bmp, RETROFLAT_COLOR_BLACK, 2, 2,
192 retroflat_2d_bitmap_w( win->gui_p->draw_bmp ) - 4,
193 retroflat_2d_bitmap_h( win->gui_p->draw_bmp ) - 4,
194 0 );
195 retroflat_2d_rect(
196 win->gui_p->draw_bmp, RETROFLAT_COLOR_WHITE, 1, 1,
197 retroflat_2d_bitmap_w( win->gui_p->draw_bmp ) - 2,
198 retroflat_2d_bitmap_h( win->gui_p->draw_bmp ) - 2,
199 0 );
200 retroflat_2d_rect(
201 win->gui_p->draw_bmp, RETROFLAT_COLOR_BLACK, 0, 0,
202 retroflat_2d_bitmap_w( win->gui_p->draw_bmp ),
203 retroflat_2d_bitmap_h( win->gui_p->draw_bmp ),
204 0 );
205 break;
206 }
207
208 return retval;
209}
210
211/* === */
212
213static MERROR_RETVAL _retrowin_redraw_win( struct RETROWIN* win ) {
214 MERROR_RETVAL retval = MERROR_OK;
215
216 assert(
217 RETROWIN_FLAG_INIT_GUI != (RETROWIN_FLAG_INIT_GUI & win->flags) ||
218 RETROWIN_FLAG_GUI_LOCKED == (RETROWIN_FLAG_GUI_LOCKED & win->flags) );
219
220 retroflat_2d_lock_bitmap( &(win->gui_bmp) );
221
222 /* Dirty detection is in retrogui_redraw_ctls(). */
223 win->gui_p->draw_bmp = &(win->gui_bmp);
224
225 debug_printf( RETROWIN_TRACE_LVL,
226 "redrawing window " SIZE_T_FMT " (GUI %p)...", win->idc, win->gui_p );
227
228 _retrowin_draw_border( win );
229
230 /* This is a bit of a hack... Set X/Y to 0 so that we draw at the top
231 * of the bitmap that will be used as a texture. Reset it below so input
232 * detection works!
233 */
234 win->gui_p->x = 0;
235 win->gui_p->y = 0;
236 retval = retrogui_redraw_ctls( win->gui_p );
237 win->gui_p->x = win->x;
238 win->gui_p->y = win->y;
239 maug_cleanup_if_not_ok();
240
241 retroflat_2d_release_bitmap( &(win->gui_bmp) );
242
243cleanup:
244
245 return retval;
246}
247
248/* === */
249
250MERROR_RETVAL retrowin_redraw_win_stack( struct MDATA_VECTOR* win_stack ) {
251 MERROR_RETVAL retval = MERROR_OK;
252 size_t i = 0;
253 struct RETROWIN* win = NULL;
254
255 if( 0 == mdata_vector_ct( win_stack ) ) {
256 goto cleanup;
257 }
258
259 assert( !mdata_vector_is_locked( win_stack ) );
260 mdata_vector_lock( win_stack );
261
262 for( i = 0 ; mdata_vector_ct( win_stack ) > i ; i++ ) {
263 win = mdata_vector_get( win_stack, i, struct RETROWIN );
264 assert( NULL != win );
265
266 if( !retrowin_win_is_active( win ) ) {
267 continue;
268 }
269
270 retrowin_lock_gui( win );
271
272 /* OpenGL tends to call glClear on every frame, so always redraw! */
273 if( RETROGUI_FLAGS_DIRTY == (RETROGUI_FLAGS_DIRTY & win->gui_p->flags) ) {
274 debug_printf( RETROWIN_TRACE_LVL,
275 "redrawing window idx " SIZE_T_FMT ", IDC " SIZE_T_FMT,
276 i, win->idc );
277
278 /* Redraw the window bitmap, including controls. */
279 retval = _retrowin_redraw_win( win );
280 maug_cleanup_if_not_ok();
281 }
282
283 /* Always blit the finished window to the screen, to compensate for e.g.
284 * the implicit screen-clearing of the engine loop.
285 */
286 retval = retroflat_2d_blit_win(
287 &(win->gui_bmp), win->gui_p->x, win->gui_p->y );
288
289 retrowin_unlock_gui( win );
290 }
291
292cleanup:
293
294 mdata_vector_unlock( win_stack );
295
296 return retval;
297}
298
299/* === */
300
302 MERROR_RETVAL retval = MERROR_OK;
303 size_t i = 0;
304 struct RETROWIN* win = NULL;
305
306 if( 0 == mdata_vector_ct( win_stack ) ) {
307 goto cleanup;
308 }
309
310 assert( !mdata_vector_is_locked( win_stack ) );
311 mdata_vector_lock( win_stack );
312
313 for( i = 0 ; mdata_vector_ct( win_stack ) > i ; i++ ) {
314 win = mdata_vector_get( win_stack, i, struct RETROWIN );
315 assert( NULL != win );
316
317 if( !retrowin_win_is_active( win ) ) {
318 continue;
319 }
320
321 retrowin_lock_gui( win );
322
323 debug_printf( RETROWIN_TRACE_LVL,
324 "refreshing window idx " SIZE_T_FMT ", IDC " SIZE_T_FMT,
325 i, win->idc );
326
327 win->gui_p->flags |= RETROGUI_FLAGS_DIRTY;
328
329 retrowin_unlock_gui( win );
330 }
331
332cleanup:
333
334 mdata_vector_unlock( win_stack );
335
336 return retval;
337}
338
339/* === */
340
341retrogui_idc_t retrowin_poll_win_stack(
342 struct MDATA_VECTOR* win_stack, retrogui_idc_t idc_active,
343 RETROFLAT_IN_KEY* p_input, struct RETROFLAT_INPUT* input_evt
344) {
345 size_t i = 0;
346 retrogui_idc_t idc_out = 0;
347 MERROR_RETVAL retval = MERROR_OK;
348 struct RETROWIN* win = NULL;
349
350 assert( !mdata_vector_is_locked( win_stack ) );
351 mdata_vector_lock( win_stack );
352
353 for( i = 0 ; mdata_vector_ct( win_stack ) > i ; i++ ) {
354 win = mdata_vector_get( win_stack, i, struct RETROWIN );
355 assert( NULL != win );
356 if( idc_active != win->idc || !retrowin_win_is_active( win ) ) {
357 continue;
358 }
359
360 debug_printf( RETROWIN_TRACE_LVL, "polling window: " SIZE_T_FMT,
361 win->idc );
362
363 retrowin_lock_gui( win );
364
365 idc_out = retrogui_poll_ctls( win->gui_p, p_input, input_evt );
366
367 retrowin_unlock_gui( win );
368
369 break;
370 }
371
372cleanup:
373
374 if( MERROR_OK != retval ) {
375 error_printf( "error redrawing windows!" );
376 idc_out = 0;
377 }
378
379 mdata_vector_unlock( win_stack );
380
381 return idc_out;
382}
383
384/* === */
385
386void retrowin_free_win( struct RETROWIN* win ) {
387 MERROR_RETVAL retval = MERROR_OK;
388
389 if( RETROWIN_FLAG_INIT_BMP == (RETROWIN_FLAG_INIT_BMP & win->flags) ) {
390 retroflat_2d_destroy_bitmap( &(win->gui_bmp) );
391 retrowin_lock_gui( win );
392 win->gui_p->draw_bmp = NULL;
393 retrowin_unlock_gui( win );
394 }
395
396 if( RETROWIN_FLAG_INIT_GUI == (RETROWIN_FLAG_INIT_GUI & win->flags) ) {
397 /* This GUI was created by a NULL to push_win(). */
398 retrowin_lock_gui( win )
399 retrogui_destroy( win->gui_p );
400 retrowin_unlock_gui( win )
401 maug_mfree( win->gui_h );
402 }
403
404cleanup:
405
406 if( MERROR_OK != retval ) {
407 error_printf( "error while locking self-managed GUI! not freed!" );
408 }
409
410 maug_mzero( win, sizeof( struct RETROWIN ) );
411}
412
413/* === */
414
415ssize_t retrowin_get_by_idc( size_t idc, struct MDATA_VECTOR* win_stack ) {
416 ssize_t idx_out = -1;
417 int autolock = 0;
418 size_t i = 0;
419 struct RETROWIN* win = NULL;
420 MERROR_RETVAL retval = MERROR_OK;
421
422 if( 0 == mdata_vector_ct( win_stack ) ) {
423 goto cleanup;
424 }
425
426 if( !mdata_vector_is_locked( win_stack ) ) {
427 mdata_vector_lock( win_stack );
428 autolock = 1;
429 }
430
431 for( i = 0 ; mdata_vector_ct( win_stack ) > i ; i++ ) {
432 win = mdata_vector_get( win_stack, i, struct RETROWIN );
433 if( idc == win->idc ) {
434 idx_out = i;
435 goto cleanup;
436 }
437 }
438
439cleanup:
440
441 if( autolock ) {
442 mdata_vector_unlock( win_stack );
443 }
444
445 if( MERROR_OK != retval ) {
446 idx_out = merror_retval_to_sz( retval );
447 }
448
449 return idx_out;
450}
451
452/* === */
453
454ssize_t retrowin_push_win(
455 struct RETROGUI* gui, struct MDATA_VECTOR* win_stack,
456 size_t idc, const char* font_filename,
457 size_t x, size_t y, size_t w, size_t h, uint8_t flags
458) {
459 MERROR_RETVAL retval = MERROR_OK;
460 struct RETROWIN win;
461 ssize_t idx_out = -1;
462
463 idx_out = retrowin_get_by_idc( idc, win_stack );
464 if( 0 <= idx_out ) {
465 error_printf( "window IDC " SIZE_T_FMT " already exists!", idc );
466 goto cleanup;
467 }
468
469 maug_mzero( &win, sizeof( struct RETROWIN ) );
470
471 win.flags = 0;
472
473 if( NULL != gui ) {
474 win.gui_p = gui;
475 } else {
476 win.gui_p = NULL;
477 win.gui_h = maug_malloc( 1, sizeof( struct RETROGUI ) );
478 maug_cleanup_if_null_alloc( MAUG_MHANDLE, win.gui_h );
479
480 win.flags |= RETROWIN_FLAG_INIT_GUI;
481
482 /* Prepare gui_p for use as if it had just been assigned. */
483 retrowin_lock_gui( &win );
484
485 retval = retrogui_init( win.gui_p );
486 maug_cleanup_if_not_ok();
487
488 retval = retrogui_set_font( win.gui_p, font_filename );
489 maug_cleanup_if_not_ok();
490 }
491
492 retval = retroflat_2d_create_bitmap(
493 w, h, &(win.gui_bmp), RETROFLAT_FLAGS_OPAQUE );
494 maug_cleanup_if_not_ok();
495
496 win.flags |= RETROWIN_FLAG_INIT_BMP;
497
498 win.gui_p->w = w;
499 win.gui_p->h = h;
500 /* These might seem redundant, but check out retrowin_redraw_win()
501 * to see how they're used.
502 */
503 win.x = x;
504 win.y = y;
505 win.gui_p->x = x;
506 win.gui_p->y = y;
507 win.idc = idc;
508 win.flags |= flags;
509
510 debug_printf( RETROWIN_TRACE_LVL,
511 "pushing window IDC " SIZE_T_FMT ", GUI %p: " SIZE_T_FMT "x" SIZE_T_FMT
512 " @ " SIZE_T_FMT ", " SIZE_T_FMT,
513 win.idc, win.gui_p,
514 win.gui_p->w, win.gui_p->h, win.gui_p->x, win.gui_p->y );
515
516 retrowin_unlock_gui( &win );
517
518 idx_out = mdata_vector_append( win_stack, &win, sizeof( struct RETROWIN ) );
519 if( 0 > idx_out ) {
520 goto cleanup;
521 }
522
523 if( w != h ) {
524 /* TODO: Update to detect proportional windows. */
525 error_printf(
526 "non-square window created; some systems may have trouble!" );
527 }
528
529 retrowin_refresh_win_stack( win_stack );
530
531cleanup:
532
533 /* Unlock if unlock above was skipped due to error. */
534 retrowin_unlock_gui( &win );
535
536 return idx_out;
537}
538
539/* === */
540
542 struct MDATA_VECTOR* win_stack, size_t idc
543) {
544 size_t i = 0;
545 MERROR_RETVAL retval = MERROR_OK;
546 struct RETROWIN* win = NULL;
547 ssize_t i_free = -1;
548 int autolock = 0;
549
550 debug_printf( RETROWIN_TRACE_LVL,
551 "attempting to destroy window: " SIZE_T_FMT, idc );
552
553 if( !mdata_vector_is_locked( win_stack ) ) {
554 mdata_vector_lock( win_stack );
555 autolock = 1;
556 }
557
558 for( i = 0 ; mdata_vector_ct( win_stack ) > i ; i++ ) {
559 win = mdata_vector_get( win_stack, i, struct RETROWIN );
560 assert( NULL != win );
561 if( idc != win->idc ) {
562 continue;
563 }
564
565 if( !retrowin_win_is_active( win ) ) {
566 debug_printf( RETROWIN_TRACE_LVL,
567 "window IDC " SIZE_T_FMT " found, but not active! (flags: 0x%02x)",
568 idc, win->flags );
569 continue;
570 }
571
572 debug_printf( RETROWIN_TRACE_LVL, "freeing window: " SIZE_T_FMT,
573 win->idc );
574
575 retrowin_free_win( win );
576
577 i_free = i;
578
579 break;
580 }
581
582 /* Remove the window from the vector if asked to. */
583 if( 0 <= i_free ) {
584 if( autolock ) {
585 mdata_vector_unlock( win_stack );
586 }
587 mdata_vector_remove( win_stack, i_free );
588 if( autolock ) {
589 mdata_vector_lock( win_stack );
590 }
591 }
592
593cleanup:
594
595 if( autolock ) {
596 mdata_vector_unlock( win_stack );
597 }
598
599 return retval;
600}
601
602#endif /* RETROW3D_C */
603 /* maug_retrowin */
605 /* maug_retroflt */
607
608#endif /* !RETROW3D_H */
609
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
#define RETROFLAT_FLAGS_OPAQUE
Flag for retroflat_create_bitmap() or retroflat_load_bitmap() to create or load a bitmap without tran...
Definition retroflt.h:379
#define RETROFLAT_FLAGS_FILL
Flag for retroflat_rect() or retroflat_ellipse(), indicating drawn shape should be filled.
Definition retroflt.h:373
retrogui_idc_t retrogui_poll_ctls(struct RETROGUI *gui, RETROFLAT_IN_KEY *p_input, struct RETROFLAT_INPUT *input_evt)
Poll for the last clicked control and maintain listboxes and menus.
MERROR_RETVAL retrogui_set_font(struct RETROGUI *gui, const char *font_path)
Load the RetroFont API for the given RETROGUI to draw its controls with. Use RetroGXCache API if avai...
int16_t retrogui_idc_t
Unique identifying constant number for controls.
Definition retrogui.h:231
MERROR_RETVAL retrowin_refresh_win_stack(struct MDATA_VECTOR *win_stack)
Force all windows on the stack to redraw.
ssize_t retrowin_push_win(struct RETROGUI *gui, struct MDATA_VECTOR *win_stack, size_t idc, const char *font_filename, size_t x, size_t y, size_t w, size_t h, uint8_t flags)
Create a new window on the given win_stack.
MERROR_RETVAL retrowin_destroy_win(struct MDATA_VECTOR *win_stack, size_t idc)
Destroy the given window's resources and remove it from the window stack.
#define RETROWIN_FLAG_INIT_GUI
Flag for RETROWIN::flags indicating RETROWIN::gui_p should be locked from RETROWIN::gui_h before use.
Definition retrowin.h:58
A vector of uniformly-sized objects, stored contiguously.
Definition mdata.h:83
Struct passed to retroflat_poll_input() to hold return data.
Definition retroflt.h:814
Definition retrogui.h:328
Definition retrowin.h:98