maug
Quick and dirty C mini-augmentation library.
retrogxc.h
1
2#ifndef RETROGXC_H
3#define RETROGXC_H
4
12#include <maug.h>
13
14/* TODO: Unified asset type that automatically uses RetroGXC if present and
15 * directly loads assets to handles if not.
16 *
17 * *or*
18 *
19 * Loader function that passes back a pointer to the cached object
20 * to be used with the normal functions associated with it.
21 */
22
23/* TODO: The loaders here pass path to file-loading functions. What they
24 * *should* do is open those paths into mfiles on their own, so that
25 * a shim can be inserted to force loading from arrays in memory.
26 */
27
28#define RETROGXC_PRESENT 1
29
30#ifndef RETROGXC_INITIAL_SZ
31# define RETROGXC_INITIAL_SZ 16
32#endif /* !RETROGXC_INITIAL_SZ */
33
34#ifndef RETROGXC_TRACE_LVL
35# define RETROGXC_TRACE_LVL 0
36#endif /* !RETROGXC_TRACE_LVL */
37
38#define RETROGXC_ERROR_CACHE_MISS (-1)
39
40#define RETROGXC_ASSET_TYPE_NONE 0
41#define RETROGXC_ASSET_TYPE_BITMAP 1
42#define RETROGXC_ASSET_TYPE_FONT 2
43
44#define retrogxc_load_bitmap( res_p, flags ) \
45 retrogxc_load_asset( res_p, retrogxc_loader_bitmap, NULL, flags )
46
47typedef int8_t retrogxc_asset_type_t;
48
49typedef retrogxc_asset_type_t (*retrogxc_loader)(
50 const maug_path res_p, MAUG_MHANDLE* handle_p,
51 void* data, uint8_t flags );
52
54 uint8_t type;
55 MAUG_MHANDLE handle;
56 maug_path id;
57};
58
60 uint8_t glyph_h;
61 uint16_t first_glyph;
62 uint16_t glyphs_count;
63};
64
65MERROR_RETVAL retrogxc_init();
66
67void retrogxc_clear_cache();
68
69void retrogxc_shutdown();
70
71retrogxc_asset_type_t retrogxc_loader_bitmap(
72 const maug_path res_p, MAUG_MHANDLE* handle_p,
73 void* data, uint8_t flags );
74
75retrogxc_asset_type_t retrogxc_loader_xpm(
76 const maug_path res_p, MAUG_MHANDLE* handle_p,
77 void* data, uint8_t flags );
78
79retrogxc_asset_type_t retrogxc_loader_font(
80 const maug_path res_p, MAUG_MHANDLE* handle_p,
81 void* data, uint8_t flags );
82
83int16_t retrogxc_load_font(
84 const maug_path font_name,
85 uint8_t glyph_h, uint16_t first_glyph, uint16_t glyphs_count );
86
92 const maug_path res_p, retrogxc_loader l, void* data,
93 uint8_t flags );
94
102 size_t asset_idx, retrogxc_asset_type_t asset_type );
103
104MERROR_RETVAL retrogxc_blit_bitmap(
105 retroflat_blit_t* target, size_t bitmap_idx,
108 retroflat_pxxy_t w, retroflat_pxxy_t h, int16_t instance );
109
110MERROR_RETVAL retrogxc_string(
111 retroflat_blit_t* target, RETROFLAT_COLOR color,
112 const char* str, size_t str_sz,
113 size_t font_idx, retroflat_pxxy_t x, retroflat_pxxy_t y,
114 retroflat_pxxy_t max_w, retroflat_pxxy_t max_h, uint8_t flags );
115
116MERROR_RETVAL retrogxc_string_indent(
117 retroflat_blit_t* target, RETROFLAT_COLOR color,
118 const char* str, size_t str_sz,
119 size_t font_idx, retroflat_pxxy_t x, retroflat_pxxy_t y,
121 uint8_t flags );
122
123MERROR_RETVAL retrogxc_string_sz(
124 retroflat_blit_t* target, const char* str, size_t str_sz,
125 size_t font_idx, retroflat_pxxy_t max_w, retroflat_pxxy_t max_h,
126 retroflat_pxxy_t* out_w_p, retroflat_pxxy_t* out_h_p, uint8_t flags );
127
128MERROR_RETVAL retrogxc_bitmap_wh(
129 size_t bitmap_idx, retroflat_pxxy_t* p_w, retroflat_pxxy_t* p_h );
130
131#ifdef RETROGXC_C
132
133static struct MDATA_VECTOR SEG_MGLOBAL gs_retrogxc_bitmaps;
134
135/* === */
136
137MERROR_RETVAL retrogxc_init() {
138 MERROR_RETVAL retval = MERROR_OK;
139
140 /*
141 size_printf( RETROGXC_TRACE_LVL,
142 "asset struct", sizeof( struct RETROFLAT_CACHE_ASSET ) );
143 size_printf( RETROGXC_TRACE_LVL, "initial graphics cache",
144 sizeof( struct RETROFLAT_CACHE_ASSET ) * gs_retrogxc_sz );
145 */
146
147 return retval;
148}
149
150/* === */
151
152void retrogxc_clear_cache() {
153 size_t dropped_count = 0;
154 struct RETROFLAT_CACHE_ASSET* asset = NULL;
155 retroflat_blit_t* bitmap = NULL;
156 MERROR_RETVAL retval = MERROR_OK;
157
158 if( 0 == mdata_vector_ct( &gs_retrogxc_bitmaps ) ) {
159 /* Nothing to do! */
160 return;
161 }
162
163 mdata_vector_lock( &gs_retrogxc_bitmaps );
164
165 while( 0 < mdata_vector_ct( &gs_retrogxc_bitmaps ) ) {
166 asset = mdata_vector_get(
167 &gs_retrogxc_bitmaps, 0, struct RETROFLAT_CACHE_ASSET );
168 assert( NULL != asset );
169
170 /* Asset-type-specific cleanup. */
171 switch( asset->type ) {
172 case RETROGXC_ASSET_TYPE_BITMAP:
173 maug_mlock( asset->handle, bitmap );
174 if( NULL != bitmap ) {
175 retroflat_2d_destroy_bitmap( bitmap );
176 }
177 maug_munlock( asset->handle, bitmap );
178 maug_mfree( asset->handle );
179 dropped_count++;
180
181 case RETROGXC_ASSET_TYPE_FONT:
182 /* Fonts are just a blob of data after a struct, so just free it! */
183 retrofont_free( &(asset->handle) );
184 dropped_count++;
185 }
186
187 mdata_vector_unlock( &gs_retrogxc_bitmaps );
188 mdata_vector_remove( &gs_retrogxc_bitmaps, 0 );
189 mdata_vector_lock( &gs_retrogxc_bitmaps );
190 }
191
192 debug_printf( RETROGXC_TRACE_LVL,
193 "graphics cache cleared (" SIZE_T_FMT " assets)", dropped_count );
194
195cleanup:
196
197 if( MERROR_OK == retval ) {
198 mdata_vector_unlock( &gs_retrogxc_bitmaps );
199 }
200
201 return;
202}
203
204/* === */
205
206void retrogxc_shutdown() {
207 retrogxc_clear_cache();
208 mdata_vector_free( &gs_retrogxc_bitmaps );
209}
210
211/* === */
212
213retrogxc_asset_type_t retrogxc_loader_bitmap(
214 const maug_path res_p, MAUG_MHANDLE* handle_p, void* data,
215 uint8_t flags
216) {
217 MERROR_RETVAL retval = MERROR_OK;
218 retroflat_blit_t* bitmap = NULL;
219
220 assert( (MAUG_MHANDLE)NULL == *handle_p );
221
222 maug_malloc_test( *handle_p, 1, sizeof( retroflat_blit_t ) );
223
224 maug_mlock( *handle_p, bitmap );
225 maug_cleanup_if_null_alloc( retroflat_blit_t*, bitmap );
226
227 /* Load requested bitmap into the cache. */
228#ifdef RETROFLAT_XPM
229 retval = retroflat_load_xpm( res_p, bitmap, flags );
230#else
231 retval = retroflat_2d_load_bitmap( res_p, bitmap, flags );
232#endif /* RETROFLAT_XPM */
233 maug_cleanup_if_not_ok();
234
235cleanup:
236
237 if( NULL != bitmap ) {
238 maug_munlock( *handle_p, bitmap );
239 }
240
241 if( MERROR_OK == retval ) {
242 return RETROGXC_ASSET_TYPE_BITMAP;
243 } else {
244 if( (MAUG_MHANDLE)NULL != *handle_p ) {
245 maug_mfree( *handle_p );
246 }
247 return RETROGXC_ASSET_TYPE_NONE;
248 }
249}
250
251/* === */
252
253#ifdef RETROFONT_PRESENT
254
255retrogxc_asset_type_t retrogxc_loader_font(
256 const maug_path res_p, MAUG_MHANDLE* handle_p, void* data,
257 uint8_t flags
258) {
259 MERROR_RETVAL retval = MERROR_OK;
260 struct RETROGXC_FONT_PARMS* parms = (struct RETROGXC_FONT_PARMS*)data;
261
262 assert( (MAUG_MHANDLE)NULL == *handle_p );
263
264 debug_printf( 1, "loading font into cache: %s (%d, %d, %d)",
265 res_p, parms->glyph_h, parms->first_glyph, parms->glyphs_count );
266
267 retval = retrofont_load( res_p, handle_p,
268 parms->glyph_h, parms->first_glyph, parms->glyphs_count );
269 maug_cleanup_if_not_ok();
270
271cleanup:
272
273 if( MERROR_OK == retval ) {
274 return RETROGXC_ASSET_TYPE_FONT;
275 } else {
276 return RETROGXC_ASSET_TYPE_NONE;
277 }
278}
279
280#endif /* RETROFONT_PRESENT */
281
282/* === */
283
284int16_t retrogxc_load_asset(
285 const maug_path res_p, retrogxc_loader l, void* data,
286 uint8_t flags
287) {
288 int16_t idx = RETROGXC_ERROR_CACHE_MISS,
289 i = 0;
290 struct RETROFLAT_CACHE_ASSET asset_new;
291 struct RETROFLAT_CACHE_ASSET* asset_iter = NULL;
292 retrogxc_asset_type_t asset_type = RETROGXC_ASSET_TYPE_NONE;
293 MERROR_RETVAL retval = MERROR_OK;
294
295 maug_mzero( &asset_new, sizeof( struct RETROFLAT_CACHE_ASSET ) );
296
297 if( 0 == mdata_vector_ct( &gs_retrogxc_bitmaps ) ) {
298 goto just_load_asset;
299 }
300
301 /* Try to find the bitmap already in the cache. */
302 mdata_vector_lock( &gs_retrogxc_bitmaps );
303 for( i = 0 ; mdata_vector_ct( &gs_retrogxc_bitmaps ) > (size_t)i ; i++ ) {
304 asset_iter = mdata_vector_get(
305 &gs_retrogxc_bitmaps, i, struct RETROFLAT_CACHE_ASSET );
306 assert( NULL != asset_iter );
307 debug_printf( RETROGXC_TRACE_LVL, "\"%s\" vs \"%s\"",
308 asset_iter->id, res_p );
309 if( 0 == mfile_cmp_path( asset_iter->id, res_p ) ) {
310 debug_printf( RETROGXC_TRACE_LVL,
311 "found asset \"%s\" at index %d with type %d!",
312 res_p, i, asset_iter->type );
313 idx = i;
314 mdata_vector_unlock( &gs_retrogxc_bitmaps );
315 goto cleanup;
316 }
317 }
318 mdata_vector_unlock( &gs_retrogxc_bitmaps );
319
320just_load_asset:
321
322 /* Bitmap not found. */
323 debug_printf( RETROGXC_TRACE_LVL,
324 "asset %s not found in cache; loading...", res_p );
325
326 /* Call the format-specific loader. */
327 asset_type = l( res_p, &asset_new.handle, data, flags );
328 if( RETROGXC_ASSET_TYPE_NONE != asset_type ) {
329 asset_new.type = asset_type;
330 mfile_assign_path( asset_new.id, res_p, 0 );
332 &gs_retrogxc_bitmaps, &asset_new,
333 sizeof( struct RETROFLAT_CACHE_ASSET ) );
334 if( 0 > idx ) {
335 goto cleanup;
336 }
337 debug_printf( RETROGXC_TRACE_LVL,
338 "asset type %d, \"%s\" assigned cache ID: %d",
339 asset_type, res_p, idx );
340 goto cleanup;
341 }
342
343 /* Still not found! */
344 error_printf( "unable to load asset; cache full or not initialized?" );
345
346cleanup:
347
348 if( MERROR_OK != retval ) {
349 idx = retval * -1;
350 }
351
352 return idx;
353}
354
355/* === */
356
357MAUG_MHANDLE retrogxc_get_asset(
358 size_t asset_idx, retrogxc_asset_type_t asset_type
359) {
360 MAUG_MHANDLE handle_out = (MAUG_MHANDLE)NULL;
361 MERROR_RETVAL retval = MERROR_OK;
362 struct RETROFLAT_CACHE_ASSET* asset = NULL;
363
364 assert( (MAUG_MHANDLE)NULL != gs_retrogxc_bitmaps.data_h );
365
366 mdata_vector_lock( &gs_retrogxc_bitmaps );
367
368 if( mdata_vector_ct( &gs_retrogxc_bitmaps ) <= asset_idx ) {
369 error_printf( "invalid asset index: " SIZE_T_FMT, asset_idx );
370 goto cleanup;
371 }
372
373 asset = mdata_vector_get(
374 &gs_retrogxc_bitmaps, asset_idx, struct RETROFLAT_CACHE_ASSET );
375
376 if( asset_type != asset->type ) {
377 error_printf(
378 "index " SIZE_T_FMT
379 " not present in cache or not requested type %d (%d)!",
380 asset_idx, asset_type, asset->type );
381 goto cleanup;
382 }
383
384 handle_out = asset->handle;
385
386cleanup:
387
388 if( MERROR_OK != retval ) {
389 handle_out = NULL;
390 }
391
392 mdata_vector_unlock( &gs_retrogxc_bitmaps );
393
394 return handle_out;
395}
396
397/* === */
398
399MERROR_RETVAL retrogxc_blit_bitmap(
400 retroflat_blit_t* target, size_t bitmap_idx,
403 retroflat_pxxy_t w, retroflat_pxxy_t h, int16_t instance
404) {
405 MERROR_RETVAL retval = MERROR_OK;
406 struct RETROFLAT_CACHE_ASSET* asset = NULL;
407 retroflat_blit_t* bitmap = NULL;
408
409 assert( (MAUG_MHANDLE)NULL != gs_retrogxc_bitmaps.data_h );
410
411 mdata_vector_lock( &gs_retrogxc_bitmaps );
412
413 if( mdata_vector_ct( &gs_retrogxc_bitmaps ) <= bitmap_idx ) {
414 error_printf( "invalid bitmap index: " SIZE_T_FMT, bitmap_idx );
415 retval = MERROR_OVERFLOW;
416 goto cleanup;
417 }
418
419 asset = mdata_vector_get(
420 &gs_retrogxc_bitmaps, bitmap_idx, struct RETROFLAT_CACHE_ASSET );
421
422 if( RETROGXC_ASSET_TYPE_BITMAP != asset->type ) {
423 error_printf(
424 "index " SIZE_T_FMT " not present in cache or not bitmap (%d)!",
425 bitmap_idx, asset->type );
426 retval = MERROR_FILE;
427 goto cleanup;
428 }
429
430 maug_mlock( asset->handle, bitmap );
431
432 retval = retroflat_2d_blit_bitmap(
433 target, bitmap, s_x, s_y, d_x, d_y, w, h, instance );
434
435cleanup:
436
437 if( NULL != bitmap ) {
438 maug_munlock( asset->handle, bitmap );
439 }
440
441 mdata_vector_unlock( &gs_retrogxc_bitmaps );
442
443 return retval;
444}
445
446/* === */
447
448MERROR_RETVAL retrogxc_bitmap_wh(
449 size_t bitmap_idx, retroflat_pxxy_t* p_w, retroflat_pxxy_t* p_h
450) {
451 MERROR_RETVAL retval = MERROR_OK;
452 struct RETROFLAT_CACHE_ASSET* asset = NULL;
453 retroflat_blit_t* bitmap = NULL;
454
455 mdata_vector_lock( &gs_retrogxc_bitmaps );
456
457 if( mdata_vector_ct( &gs_retrogxc_bitmaps ) <= bitmap_idx ) {
458 error_printf( "invalid bitmap index: " SIZE_T_FMT, bitmap_idx );
459 retval = MERROR_OVERFLOW;
460 goto cleanup;
461 }
462
463 asset = mdata_vector_get(
464 &gs_retrogxc_bitmaps, bitmap_idx, struct RETROFLAT_CACHE_ASSET );
465
466 if( RETROGXC_ASSET_TYPE_BITMAP != asset->type ) {
467 error_printf(
468 "index " SIZE_T_FMT " not present in cache or not bitmap (%d)!",
469 bitmap_idx, asset->type );
470 retval = MERROR_FILE;
471 goto cleanup;
472 }
473
474 maug_mlock( asset->handle, bitmap );
475
476 if( NULL != p_w ) {
477 *p_w = retroflat_2d_bitmap_w( bitmap );
478 }
479
480 if( NULL != p_h ) {
481 *p_h = retroflat_2d_bitmap_h( bitmap );
482 }
483
484cleanup:
485
486 if( NULL != bitmap ) {
487 maug_munlock( asset->handle, bitmap );
488 }
489
490 mdata_vector_unlock( &gs_retrogxc_bitmaps );
491
492 return retval;
493}
494
495/* === */
496
497#ifdef RETROFONT_PRESENT
498
499int16_t retrogxc_load_font(
500 const maug_path font_name,
501 uint8_t glyph_h, uint16_t first_glyph, uint16_t glyphs_count
502) {
503 int16_t idx = -1;
504 struct RETROGXC_FONT_PARMS parms;
505
506 parms.glyph_h = glyph_h;
507 parms.first_glyph = first_glyph;
508 parms.glyphs_count = glyphs_count;
509
510 idx = retrogxc_load_asset( font_name, retrogxc_loader_font, &parms, 0 );
511
512 return idx;
513}
514
515/* === */
516
517/* TODO: Remove retrogxc_string_* functions and use retrogxc_get_asset()! */
518
519MERROR_RETVAL retrogxc_string(
520 retroflat_blit_t* target, RETROFLAT_COLOR color,
521 const char* str, size_t str_sz,
522 size_t font_idx, retroflat_pxxy_t x, retroflat_pxxy_t y,
523 retroflat_pxxy_t max_w, retroflat_pxxy_t max_h, uint8_t flags
524) {
525
526 return retrogxc_string_indent(
527 target, color, str, str_sz, font_idx, x, y, max_w, max_h, 0, flags );
528}
529
530/* === */
531
532MERROR_RETVAL retrogxc_string_indent(
533 retroflat_blit_t* target, RETROFLAT_COLOR color,
534 const char* str, size_t str_sz,
535 size_t font_idx, retroflat_pxxy_t x, retroflat_pxxy_t y,
537 uint8_t flags
538) {
539 MERROR_RETVAL retval = MERROR_OK;
540 struct RETROFLAT_CACHE_ASSET* asset = NULL;
541
542 mdata_vector_lock( &gs_retrogxc_bitmaps );
543
544 if( mdata_vector_ct( &gs_retrogxc_bitmaps ) <= font_idx ) {
545 error_printf( "invalid font index: " SIZE_T_FMT, font_idx );
546 retval = MERROR_OVERFLOW;
547 goto cleanup;
548 }
549
550 asset = mdata_vector_get(
551 &gs_retrogxc_bitmaps, font_idx, struct RETROFLAT_CACHE_ASSET );
552
553 if( RETROGXC_ASSET_TYPE_FONT != asset->type ) {
554 error_printf(
555 "index " SIZE_T_FMT " not present in cache or not font (%d)!",
556 font_idx, asset->type );
557 retval = MERROR_FILE;
558 goto cleanup;
559 }
560
561 retrofont_string_indent(
562 target, color, str, str_sz, asset->handle, x, y, max_w, max_h,
563 indent, flags );
564
565cleanup:
566
567 mdata_vector_unlock( &gs_retrogxc_bitmaps );
568
569 return retval;
570}
571
572/* === */
573
574MERROR_RETVAL retrogxc_string_sz(
575 retroflat_blit_t* target, const char* str, size_t str_sz,
576 size_t font_idx, retroflat_pxxy_t max_w, retroflat_pxxy_t max_h,
577 retroflat_pxxy_t* out_w_p, retroflat_pxxy_t* out_h_p, uint8_t flags
578) {
579 MERROR_RETVAL retval = MERROR_OK;
580 struct RETROFLAT_CACHE_ASSET* asset = NULL;
581
582 mdata_vector_lock( &gs_retrogxc_bitmaps );
583
584 if( mdata_vector_ct( &gs_retrogxc_bitmaps ) <= font_idx ) {
585 error_printf( "invalid font index: " SIZE_T_FMT, font_idx );
586 retval = MERROR_OVERFLOW;
587 goto cleanup;
588 }
589
590 asset = mdata_vector_get(
591 &gs_retrogxc_bitmaps, font_idx, struct RETROFLAT_CACHE_ASSET );
592
593 if( RETROGXC_ASSET_TYPE_FONT != asset->type ) {
594 error_printf(
595 "index " SIZE_T_FMT " not present in cache or not font (%d)!",
596 font_idx, asset->type );
597 retval = MERROR_FILE;
598 goto cleanup;
599 }
600
601 retrofont_string_sz(
602 target, str, str_sz, asset->handle,
603 max_w, max_h, out_w_p, out_h_p, flags );
604
605cleanup:
606
607 mdata_vector_unlock( &gs_retrogxc_bitmaps );
608
609 return retval;
610}
611
612#endif /* RETROFONT_PRESENT */
613
614#endif /* RETROGXC_C */
615 /* maug_retroflt */
617 /* maug_retrogxc */
619
620#endif /* !RETROGXC_H */
621
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition: merror.h:28
#define mfile_cmp_path(a, b)
Compare two asset paths. Return 0 if they're the same.
Definition: mfile.h:146
MERROR_RETVAL mfile_assign_path(maug_path tgt, const maug_path src, uint8_t flags)
Copy a maug_path from one place to another, safely observing character limits, etc.
char maug_path[MAUG_PATH_SZ_MAX]
Path/name used to load an asset from disk or access other files.
Definition: mfile.h:141
int8_t RETROFLAT_COLOR
Defines an index in the platform-specific color-table.
Definition: retroflt.h:326
int16_t retroflat_pxxy_t
Type used for surface pixel coordinates.
Definition: retroflt.h:879
int16_t retrogxc_load_asset(const maug_path res_p, retrogxc_loader l, void *data, uint8_t flags)
Try to load an asset by file path. Return a cached copy if it's already been loaded.
MAUG_MHANDLE retrogxc_get_asset(size_t asset_idx, retrogxc_asset_type_t asset_type)
Retrive an asset for which we have a prior cached index.
ssize_t mdata_vector_append(struct MDATA_VECTOR *v, const void *item, size_t item_sz)
Append an item to the specified vector.
MERROR_RETVAL mdata_vector_remove(struct MDATA_VECTOR *v, size_t idx)
Remove item at the given index, shifting subsequent items up by 1.
MERROR_RETVAL retrofont_load(const char *font_name, MAUG_MHANDLE *p_font_h, uint8_t glyph_h, uint16_t first_glyph, uint16_t glyphs_count)
Load a font for drawing.
A vector of uniformly-sized objects, stored contiguously.
Definition: mdata.h:108
#define mdata_vector_lock(v)
Lock the vector. This should be done when items from the vector are actively being referenced,...
Definition: mdata.h:372
#define mdata_vector_unlock(v)
Unlock the vector so items may be added and removed.
Definition: mdata.h:405
#define mdata_vector_ct(v)
Number of items of MDATA_VECTOR::item_sz bytes actively stored in this vector.
Definition: mdata.h:448
Definition: retrogxc.h:53
Definition: retrogxc.h:59