maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
retrotil.h
Go to the documentation of this file.
1
2#ifndef RETROTIL_H
3#define RETROTIL_H
4
5#include <mjson.h>
6#include <mfile.h>
7
16
17#define RETROTILE_PRESENT
18
19typedef int16_t retrotile_coord_t;
20
21#ifndef RETROTILE_TRACE_CHARS
22# define RETROTILE_TRACE_CHARS 0
23#endif /* !RETROTILE_TRACE_TOKENS */
24
25#ifndef RETROTILE_NAME_SZ_MAX
27# define RETROTILE_NAME_SZ_MAX 10
28#endif /* !RETROTILE_NAME_SZ_MAX */
29
30#ifndef RETROTILE_PROP_NAME_SZ_MAX
32# define RETROTILE_PROP_NAME_SZ_MAX 10
33#endif /* !RETROTILE_PROP_NAME_SZ_MAX */
34
35#ifndef RETROTILE_TILE_SCALE_DEFAULT
37# define RETROTILE_TILE_SCALE_DEFAULT 1.0f
38#endif /* !RETROTILE_TILE_SCALE_DEFAULT */
39
40#ifndef RETROTILE_TRACE_LVL
42# define RETROTILE_TRACE_LVL 0
43#endif /* !RETROTILE_TRACE_LVL */
44
45#ifndef RETROTILE_VORONOI_DEFAULT_SPB
46# define RETROTILE_VORONOI_DEFAULT_SPB 8
47#endif /* !RETROTILE_VORONOI_DEFAULT_SPB */
48
49#ifndef RETROTILE_VORONOI_DEFAULT_DRIFT
50# define RETROTILE_VORONOI_DEFAULT_DRIFT 4
51#endif /* !RETROTILE_VORONOI_DEFAULT_DRIFT */
52
53#ifdef MPARSER_TRACE_NAMES
54# define retrotile_mstate_name( state ) gc_retrotile_mstate_names[state]
55#else
56# define retrotile_mstate_name( state ) state
57#endif /* MPARSER_TRACE_NAMES */
58
59#ifndef RETROTILE_PARSER_FLAG_LITERAL_PATHS
65# define RETROTILE_PARSER_FLAG_LITERAL_PATHS 0x02
66#endif /* !RETROTILE_PARSER_FLAG_LITERAL_PATHS */
67
73#define RETROTILE_PARSER_MODE_MAP 0
74
80#define RETROTILE_PARSER_MODE_DEFS 1
81
82#define RETROTILE_CLASS_TABLE( f ) \
83 f( TILE, tile, 0 ) \
84 f( MOBILE, mobile, 1 ) \
85 f( WARP, warp, 2 ) \
86 f( ITEM, item, 3 ) \
87 f( CROP, crop, 4 )
88
93
98
103#define RETROTILE_TILE_FLAG_BLOCK 0x01
104
109#define RETROTILE_TILE_FLAG_RESERVED1 0x02
110
115#define RETROTILE_TILE_FLAG_RESERVED2 0x04
116
121#define RETROTILE_TILE_FLAG_RESERVED3 0x08
122 /* retrotile_defs_types */
124
129#define RETROTILE_PROP_TYPE_OTHER 0
130
135#define RETROTILE_PROP_TYPE_STRING 1
136
141#define RETROTILE_PROP_TYPE_FILE 2
142
147#define RETROTILE_PROP_TYPE_INT 3
148
159#define RETROTILE_DS_FLAG_INIT_DATA 0x02
160
164#define RETROTILE_IDX_FMT "%u"
165
168 size_t sz;
169 uint8_t flags;
170 retroflat_asset_path image_path;
171 size_t x;
172 size_t y;
173 uint16_t tile_class;
174 char warp_dest[RETROTILE_NAME_SZ_MAX + 1];
181 retrotile_coord_t warp_x;
182 retrotile_coord_t warp_y;
184 int8_t no_serial;
185#ifdef RETROFLAT_3D
186 /* TODO: Work this into retrogxc? */
187 struct RETRO3DP_MODEL model;
188#endif /* RETROFLAT_3D */
189#ifdef RETROGXC_PRESENT
190 ssize_t image_cache_id;
191#else
192 struct RETROFLAT_BITMAP image;
193#endif /* RETROGXC_PRESENT */
194};
195 /* retrotile_defs */
197
200 size_t sz;
202 size_t total_sz;
203 uint16_t layer_class;
204};
205
211 /* \brief X position in tilemap tiles. */
212 retrotile_coord_t x;
213 /* \brief Y position in tilemap tiles. */
214 retrotile_coord_t y;
215};
216
222struct RETROTILE {
224 size_t sz;
225 char name[RETROTILE_NAME_SZ_MAX + 1];
226 char tileset[RETROTILE_NAME_SZ_MAX + 1];
228 uint32_t total_sz;
230 uint32_t layers_count;
234 size_t tiles_h;
236 size_t tiles_w;
242};
243
250 int16_t sect_x;
252 int16_t sect_y;
254 int16_t sect_w;
256 int16_t sect_h;
258 int16_t sect_w_half;
260 int16_t sect_h_half;
261 retroflat_tile_t highest_generated;
262 retroflat_tile_t lowest_generated;
263};
264
266 int16_t tiles_changed;
267 retroflat_tile_t center;
268 retroflat_tile_t outside;
271};
272
273#define retrotile_get_tile( tilemap, layer, x, y ) \
274 (retrotile_get_tiles_p( layer )[((y) * (tilemap)->tiles_w) + (x)])
275
276#define retrotile_set_tile( tilemap, layer, x, y, new_val ) \
277 (retrotile_get_tiles_p( layer )[((y) * (tilemap)->tiles_w) + (x)])
278
279#define retrotile_get_tiles_p( layer ) \
280 ((retroflat_tile_t*)(((uint8_t*)(layer)) + \
281 sizeof( struct RETROTILE_LAYER )))
282
283#ifdef MAUG_NO_STDLIB
284/* Loop is slower, but doesn't use memset. */
285/* TODO: This kinda assumes retroflat_tile_t is 8 bits... Fix that! */
286# define retrotile_clear_tiles( t, layer, i ) \
287 assert( 1 == sizeof( retroflat_tile_t ) ); \
288 for( \
289 i = 0 ; \
290 (t)->tiles_w * (t)->tiles_h * sizeof( retroflat_tile_t ) > i ; \
291 i++ \
292 ) { \
293 retrotile_get_tiles_p( layer )[i] = -1; \
294 }
295#else
296# define retrotile_clear_tiles( t, layer, i ) \
297 memset( retrotile_get_tiles_p( layer ), -1, \
298 (t)->tiles_w * (t)->tiles_h * sizeof( retroflat_tile_t ) )
299#endif /* MAUG_NO_STDLIB */
300
305
306typedef MERROR_RETVAL (*retrotile_tj_parse_cb)(
307 const char* dirname, const char* filename, MAUG_MHANDLE* p_tm_h,
308 struct MDATA_VECTOR* p_td, mparser_wait_cb_t wait_cb, void* wait_data,
309 mparser_parse_token_cb token_cb, void* token_cb_data, uint8_t passes,
310 uint8_t flags );
311
313 uint8_t mstate;
314 uint16_t flags;
315 /* TODO: Use flags and combine these. */
316 uint8_t pass;
317 uint8_t passes_max;
319 uint8_t mode;
320 mparser_wait_cb_t wait_cb;
321 void* wait_data;
322 retroflat_ms_t wait_last;
323 size_t layer_tile_iter;
326 int last_prop_type;
327 size_t last_prop_name_sz;
330 char tileset_name[RETROTILE_NAME_SZ_MAX + 1];
331 size_t pass_layer_iter;
337 size_t tiles_w;
338 size_t tiles_h;
339 struct RETROTILE* t;
340 retrotile_tj_parse_cb tj_parse_cb;
346 mparser_parse_token_cb custom_token_cb;
347 void* custom_token_cb_data;
348 struct MJSON_PARSER jparser;
349 struct MDATA_VECTOR* p_tile_defs;
350 char dirname[MAUG_PATH_SZ_MAX + 1];
351 uint16_t layer_class;
352};
353
354/* State Idx JSONKeyWord Parent ParseMode */
355#define RETROTILE_PARSER_MSTATE_TABLE( f ) \
356 f( MTILESTATE_NONE, 0, "", 0, 0 ) \
357 f( MTILESTATE_HEIGHT, 1, "height", 0 , 0 ) \
358 f( MTILESTATE_WIDTH, 2, "width", 0 , 0 ) \
359 f( MTILESTATE_LAYERS, 3, "layers", 0 , 0 ) \
360 f( MTILESTATE_LAYER_DATA, 4, "data", 15 /* LAYER */ , 0 ) \
361 f( MTILESTATE_LAYER_NAME, 5, "name", 15 /* LAYER */ , 0 ) \
362 f( MTILESTATE_TILES, 6, "tiles", 0 , 1 ) \
363 f( MTILESTATE_TILES_ID, 7, "id", 6 /* TILES */ , 1 ) \
364 f( MTILESTATE_TILES_IMAGE, 8, "image", 6 /* TILES */ , 1 ) \
365 f( MTILESTATE_TILESETS, 9, "tilesets", 0 , 0 ) \
366 f( MTILESTATE_TILESETS_SRC, 10, "source", 9 /* TILESETS */ , 0 ) \
367 f( MTILESTATE_TILESETS_FGID, 11, "firstgid", 9 /* TILESETS */ , 0 ) \
368 f( MTILESTATE_TILESETS_PROP, 12, "firstgid", 9 /* TILESETS */ , 0 ) \
369 f( MTILESTATE_GRID, 13, "grid", 0 , 1 ) \
370 f( MTILESTATE_TILES_PROP, 14, "properties", 6 /* TILES */ , 1 ) \
371 f( MTILESTATE_LAYER, 15, "layers", /* [sic] */ 3 , 0 ) \
372 f( MTILESTATE_TILES_PROP_NAME, 16, "name", 14 /* TIL_PROP */ , 1 ) \
373 f( MTILESTATE_TILES_PROP_TYPE, 17, "type", 14 /* TIL_PROP */ , 1 ) \
374 f( MTILESTATE_TILES_PROP_VAL, 18, "value", 14 /* TIL_PROP */ , 1 ) \
375 f( MTILESTATE_PROP, 19, "properties", 0 /* NONE */ , 0 ) \
376 f( MTILESTATE_PROP_NAME, 20, "name", 19 /* PROP */ , 0 ) \
377 f( MTILESTATE_PROP_TYPE, 21, "type", 19 /* PROP */ , 0 ) \
378 f( MTILESTATE_PROP_VAL, 22, "value", 19 /* PROP */ , 0 ) \
379 f( MTILESTATE_LAYER_CLASS, 23, "class", 15 /* LAYER */ , 0 ) \
380 f( MTILESTATE_TILES_CLASS, 24, "type", 6 /* TILES */ , 1 ) \
381 f( MTILESTATE_NAME, 25, "name", 0 , 1 ) \
382 f( MTILESTATE_WANGSETS, 26, "wangsets", 0 , 1 ) \
383 f( MTILESTATE_TPROP, 27, "properties", 0 /* NONE */ , 1 ) \
384 f( MTILESTATE_TPROP_NAME, 28, "name", 27 /* PROP */ , 1 ) \
385 f( MTILESTATE_TPROP_TYPE, 29, "type", 27 /* PROP */ , 1 ) \
386 f( MTILESTATE_TPROP_VAL, 30, "value", 27 /* PROP */ , 1 )
387
388/* TODO: Mine wangsets for slowdown values, etc. */
389
391retrotile_parse_json_c( struct RETROTILE_PARSER* parser, char c );
392
397int retrotile_parse_prop_type( const char* token, size_t token_sz );
398
406mfix_t retrotile_static_rotation_from_dir( const char* dir );
407
433 const char* dirname, const char* filename, MAUG_MHANDLE* p_tilemap_h,
434 struct MDATA_VECTOR* p_tile_defs,
435 mparser_wait_cb_t wait_cb, void* wait_data,
436 mparser_parse_token_cb token_cb, void* token_cb_data, uint8_t passes,
437 uint8_t flags );
438 /* retrotile_parser */
440
446
447typedef MERROR_RETVAL (*retrotile_ani_cb)(
448 void* animation_cb_data, int16_t iter );
449
450typedef MERROR_RETVAL (*retrotile_gen_cb)(
451 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
452 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
453 retrotile_ani_cb animation_cb, void* animation_cb_data );
454
465 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
466 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
467 retrotile_ani_cb animation_cb, void* animation_cb_data );
468
480 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
481 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
482 retrotile_ani_cb animation_cb, void* animation_cb_data );
483
492 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
493 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
494 retrotile_ani_cb animation_cb, void* animation_cb_data );
495
503 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
504 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
505 retrotile_ani_cb animation_cb, void* animation_cb_data );
506 /* retrotile_gen */
508
509struct RETROTILE_LAYER* retrotile_get_layer_p(
510 struct RETROTILE* tilemap, uint32_t layer_idx );
511
512MERROR_RETVAL retrotile_alloc(
513 MAUG_MHANDLE* p_tilemap_h, size_t w, size_t h, size_t layers_count,
514 const char* tilemap_name, const char* tileset_name );
515
516void retrotile_format_asset_path(
517 retroflat_asset_path path_out, const char* afile,
518 struct RETROTILE_PARSER* parser );
519
520MERROR_RETVAL retrotile_clear_refresh( retroflat_pxxy_t y_max );
521
522MERROR_RETVAL retrotile_topdown_draw(
523 struct RETROFLAT_BITMAP* target,
524 struct RETROTILE* t, struct MDATA_VECTOR* t_defs );
525
526#ifdef RETROTIL_C
527
528# include <mparser.h>
529
530/* TODO: Function names should be verb_noun! */
531
532#if RETROTILE_TRACE_LVL > 0
533# define retrotile_parser_mstate( parser, new_mstate ) \
534 parser->mstate = new_mstate; \
535 debug_printf( \
536 RETROTILE_TRACE_LVL, "parser mstate: %d", parser->mstate );
537#else
538# define retrotile_parser_mstate( parser, new_mstate ) \
539 parser->mstate = new_mstate;
540#endif /* RETROTILE_TRACE_LVL */
541
542# define RETROTILE_PARSER_MSTATE_TABLE_CONST( name, idx, tokn, parent, m ) \
543 MAUG_CONST uint8_t SEG_MCONST name = idx;
544
545RETROTILE_PARSER_MSTATE_TABLE( RETROTILE_PARSER_MSTATE_TABLE_CONST )
546
547#ifdef MPARSER_TRACE_NAMES
548# define RETROTILE_PARSER_MSTATE_TABLE_NAME( name, idx, tokn, parent, m ) \
549 #name,
550
551static MAUG_CONST char* SEG_MCONST gc_retrotile_mstate_names[] = {
552 RETROTILE_PARSER_MSTATE_TABLE( RETROTILE_PARSER_MSTATE_TABLE_NAME )
553 ""
554};
555#endif /* MPARSER_TRACE_NAMES */
556
557# define RETROTILE_PARSER_MSTATE_TABLE_TOKEN( name, idx, tokn, parent, m ) \
558 tokn,
559
560static MAUG_CONST char* SEG_MCONST gc_retrotile_mstate_tokens[] = {
561 RETROTILE_PARSER_MSTATE_TABLE( RETROTILE_PARSER_MSTATE_TABLE_TOKEN )
562 ""
563};
564
565# define RETROTILE_PARSER_MSTATE_TABLE_PARNT( name, idx, tokn, parent, m ) \
566 parent,
567
568static MAUG_CONST uint8_t SEG_MCONST gc_retrotile_mstate_parents[] = {
569 RETROTILE_PARSER_MSTATE_TABLE( RETROTILE_PARSER_MSTATE_TABLE_PARNT )
570 0
571};
572
573# define RETROTILE_PARSER_MSTATE_TABLE_MODE( name, idx, tokn, parent, m ) \
574 m,
575
576static MAUG_CONST uint8_t SEG_MCONST gc_retrotile_mstate_modes[] = {
577 RETROTILE_PARSER_MSTATE_TABLE( RETROTILE_PARSER_MSTATE_TABLE_MODE )
578 0
579};
580
581# define RETROTILE_CLASS_TABLE_CONSTS( A, a, i ) \
582 MAUG_CONST uint8_t SEG_MCONST RETROTILE_CLASS_ ## A = i;
583
584RETROTILE_CLASS_TABLE( RETROTILE_CLASS_TABLE_CONSTS )
585
586/* === */
587
588static void retrotile_parser_match_token(
589 const char* token, size_t token_sz, struct RETROTILE_PARSER* parser
590) {
591 size_t j = 1;
592
593 /* Figure out what the key is for. */
594 while( '\0' != gc_retrotile_mstate_tokens[j][0] ) {
595 if(
596 /* Make sure tokens match. */
597 maug_strlen( gc_retrotile_mstate_tokens[j] ) != token_sz ||
598 0 != strncmp(
599 token, gc_retrotile_mstate_tokens[j], token_sz
600 )
601 ) {
602 j++;
603 continue;
604
605 } else if(
606 /* This state can only be
607 * reached THROUGH that parent state. This allows us to have
608 * keys with the same name but different parents!
609 */
610 parser->mstate != gc_retrotile_mstate_parents[j]
611 ) {
612#ifdef RETROTILE_TRACE_TOKENS
613 debug_printf(
615 "found token \"%s\" "
616#ifdef MPARSER_TRACE_NAMES
617 "but incorrect parent %s (%d) (needs %s (%d))!",
618#else
619 "but incorrect parent %d (needs %d)!",
620#endif /* MPARSER_TRACE_NAMES */
621 token,
622#ifdef MPARSER_TRACE_NAMES
623 retrotile_mstate_name( parser->mstate ),
624 parser->mstate,
625 retrotile_mstate_name( gc_retrotile_mstate_parents[j] ),
626 gc_retrotile_mstate_parents[j]
627#else
628 parser->mstate,
629 gc_retrotile_mstate_parents[j]
630#endif /* MPARSER_TRACE_NAMES */
631 );
632#endif /* !RETROTILE_TRACE_TOKENS */
633 j++;
634 continue;
635
636 } else if( parser->mode != gc_retrotile_mstate_modes[j] ) {
637#ifdef RETROTILE_TRACE_TOKENS
638 debug_printf(
639 RETROTILE_TRACE_LVL, "found token %s but incorrect mode %u!",
640 token,
641 gc_retrotile_mstate_modes[j] );
642#endif /* !RETROTILE_TRACE_TOKENS */
643 j++;
644 continue;
645
646 } else {
647 /* Found it! */
648#ifdef RETROTILE_TRACE_TOKENS
649 debug_printf(
651 "found token \"%s\" "
652#ifdef MPARSER_TRACE_NAMES
653 "under correct parent %s (%d)!",
654#else
655 "under correct parent %d!",
656#endif /* MPARSER_TRACE_NAMES */
657 token,
658#ifdef MPARSER_TRACE_NAMES
659 retrotile_mstate_name( parser->mstate ),
660 parser->mstate
661#else
662 parser->mstate
663#endif /* MPARSER_TRACE_NAMES */
664 );
665#endif /* !RETROTILE_TRACE_TOKENS */
666
667 retrotile_parser_mstate( parser, j );
668 return;
669 }
670 }
671}
672
673/* === */
674
675MERROR_RETVAL retrotile_parser_parse_tiledef_token(
676 void* jparser_void, const char* token, size_t token_sz, void* parser_arg
677) {
678 MERROR_RETVAL retval = MERROR_OK;
679 struct RETROTILE_TILE_DEF* tile_def = NULL;
680 struct RETROTILE_PARSER* parser = (struct RETROTILE_PARSER*)parser_arg;
681 size_t tileset_id_parsed = 0;
682
683 /* We don't lock the vector right away, since we might reallocate tile defs
684 * later on, below.
685 */
686
687 /* Try the custom parser. */
688 if(
689 NULL != parser->custom_token_cb &&
690 /* MERROR_PREEMPT is dealt with in cleanup. */
691 MERROR_OK != (retval = parser->custom_token_cb(
692 parser, token, token_sz, parser_arg ))
693 ) {
694 goto cleanup;
695 }
696
697 if( MJSON_PSTATE_OBJECT_VAL != mjson_parser_pstate( &(parser->jparser) ) ) {
698 /* Not a token we have to worry about! */
699 retrotile_parser_match_token( token, token_sz, parser );
700 goto cleanup;
701 }
702
703 if( MTILESTATE_TILES_ID == parser->mstate ) {
704 retrotile_parser_mstate( parser, MTILESTATE_TILES );
705 if( 0 == parser->pass ) {
706 /* Parse tile ID. */
707 tileset_id_parsed = maug_atou32( token, token_sz, 10 );
708 if( tileset_id_parsed > parser->tileset_id_cur ) {
709 parser->tileset_id_cur = tileset_id_parsed;
710#if RETROTILE_TRACE_LVL > 0
711 debug_printf(
713 "new highest tile ID: " SIZE_T_FMT, parser->tileset_id_cur );
714#endif /* RETROTILE_TRACE_LVL */
715 }
716 } else {
717 assert( 0 < mdata_vector_ct( parser->p_tile_defs ) );
718 parser->tileset_id_cur = maug_atou32( token, token_sz, 10 );
719#if RETROTILE_TRACE_LVL > 0
720 debug_printf(
722 "next tile ID: " SIZE_T_FMT, parser->tileset_id_cur );
723#endif /* RETROTILE_TRACE_LVL */
724 }
725 retrotile_parser_mstate( parser, MTILESTATE_TILES );
726
727 } else if( MTILESTATE_TILES_IMAGE == parser->mstate ) {
728 if( 1 == parser->pass ) {
729 /* Need this pass 1 so tile_defs vector is allocated. */
730 mdata_vector_lock( parser->p_tile_defs );
731 tile_def = mdata_vector_get(
732 parser->p_tile_defs, parser->tileset_id_cur,
733 struct RETROTILE_TILE_DEF );
734 assert( NULL != tile_def );
735
736 /* Parse tile image. */
737 if(
740 ) {
741 mfile_assign_path( tile_def->image_path, token, 0 );
742 } else {
743 mfile_assign_path(
744 tile_def->image_path, token, MFILE_ASSIGN_FLAG_TRIM_EXT );
745 }
746
747 /* Setup tile_def sz for serializing. */
748 tile_def->sz = sizeof( struct RETROTILE_TILE_DEF );
749
750#if RETROTILE_TRACE_LVL > 0
751 debug_printf(
752 RETROTILE_TRACE_LVL, "set tile ID " SIZE_T_FMT " to: %s",
753 parser->tileset_id_cur, tile_def->image_path );
754#endif /* RETROTILE_TRACE_LVL */
755 }
756 retrotile_parser_mstate( parser, MTILESTATE_TILES );
757
758 } else if( MTILESTATE_TILES_CLASS == parser->mstate ) {
759 if( 1 == parser->pass ) {
760 /* Set the class from the pass 1 so the custom function can use
761 * it on pass 2 even if it's alphabetically out of order.
762 * (Tiled calls it "type" and puts it near the bottom!)
763 *
764 * We can't do this on pass 0 since tiles aren't allocated yet!
765 */
766 mdata_vector_lock( parser->p_tile_defs );
767 tile_def = mdata_vector_get(
768 parser->p_tile_defs, parser->tileset_id_cur,
769 struct RETROTILE_TILE_DEF );
770 assert( NULL != tile_def );
771 assert( 0 == tile_def->tile_class );
772
773#if RETROTILE_TRACE_LVL > 0
774 #define RETROTILE_CLASS_TABLE_SET( A, a, i ) \
775 } else if( 0 == strncmp( #a, token, maug_strlen( #a ) + 1 ) ) { \
776 tile_def->tile_class = RETROTILE_CLASS_ ## A; \
777 debug_printf( RETROTILE_TRACE_LVL, \
778 "set tile " SIZE_T_FMT " type: " #a " (%u)", \
779 parser->tileset_id_cur, tile_def->tile_class );
780#else
781 #define RETROTILE_CLASS_TABLE_SET( A, a, i ) \
782 } else if( 0 == strncmp( #a, token, maug_strlen( #a ) + 1 ) ) { \
783 tile_def->tile_class = RETROTILE_CLASS_ ## A;
784#endif /* RETROTILE_TRACE_LVL */
785
786 if( 0 ) {
787 RETROTILE_CLASS_TABLE( RETROTILE_CLASS_TABLE_SET )
788 } else {
789 tile_def->tile_class = RETROTILE_CLASS_TILE;
790#if RETROTILE_TRACE_LVL > 0
791 debug_printf( RETROTILE_TRACE_LVL,
792 "set tile " SIZE_T_FMT " type: tile (%u)",
793 parser->tileset_id_cur, tile_def->tile_class );
794#endif /* RETROTILE_TRACE_LVL */
795 }
796 }
797 retrotile_parser_mstate( parser, MTILESTATE_TILES );
798
799 } else if( MTILESTATE_TILES_PROP_NAME == parser->mstate ) {
800#if RETROTILE_TRACE_LVL > 0
801 debug_printf( RETROTILE_TRACE_LVL, "parsing property: %s", token );
802#endif /* RETROTILE_TRACE_LVL */
803 maug_mzero( parser->last_prop_name, RETROTILE_PROP_NAME_SZ_MAX + 1 );
804 maug_strncpy( parser->last_prop_name, token, RETROTILE_PROP_NAME_SZ_MAX );
805 retrotile_parser_mstate( parser, MTILESTATE_TILES_PROP );
806
807 } else if( MTILESTATE_TILES_PROP_TYPE == parser->mstate ) {
808#if RETROTILE_TRACE_LVL > 0
809 debug_printf( RETROTILE_TRACE_LVL, "property %s is type: %s",
810 parser->last_prop_name, token );
811#endif /* RETROTILE_TRACE_LVL */
812 parser->last_prop_type = retrotile_parse_prop_type( token, token_sz );
813 retrotile_parser_mstate( parser, MTILESTATE_TILES_PROP );
814
815 } else if( MTILESTATE_TILES_PROP_VAL == parser->mstate ) {
816 /* This would be ideal to be handled in the custom token parser callback.
817 */
818
819 if( 1 == parser->pass ) {
820 mdata_vector_lock( parser->p_tile_defs );
821 tile_def = mdata_vector_get(
822 parser->p_tile_defs, parser->tileset_id_cur,
823 struct RETROTILE_TILE_DEF );
824 assert( NULL != tile_def );
825
826 if( 0 == strncmp( "warp_dest", parser->last_prop_name, 10 ) ) {
827 maug_mzero( tile_def->warp_dest, RETROTILE_NAME_SZ_MAX );
828 maug_strncpy( tile_def->warp_dest, token, RETROTILE_NAME_SZ_MAX );
829#if RETROTILE_TRACE_LVL > 0
830 debug_printf(
831 RETROTILE_TRACE_LVL, "set tile " SIZE_T_FMT " warp_dest: %s",
832 parser->tileset_id_cur, tile_def->warp_dest );
833#endif /* RETROTILE_TRACE_LVL */
834
835 } else if( 0 == strncmp( "warp_x", parser->last_prop_name, 7 ) ) {
836 tile_def->warp_x = maug_atos32( token, token_sz );
837#if RETROTILE_TRACE_LVL > 0
838 debug_printf(
839 RETROTILE_TRACE_LVL, "set tile " SIZE_T_FMT " warp_x: %d",
840 parser->tileset_id_cur, tile_def->warp_x );
841#endif /* RETROTILE_TRACE_LVL */
842
843 } else if( 0 == strncmp( "warp_y", parser->last_prop_name, 7 ) ) {
844 tile_def->warp_y = maug_atos32( token, token_sz );
845#if RETROTILE_TRACE_LVL > 0
846 debug_printf(
847 RETROTILE_TRACE_LVL, "set tile " SIZE_T_FMT " warp_y: %d",
848 parser->tileset_id_cur, tile_def->warp_y );
849#endif /* RETROTILE_TRACE_LVL */
850
851 }
852 }
853
854 maug_mzero( parser->last_prop_name, RETROTILE_PROP_NAME_SZ_MAX + 1 );
855 retrotile_parser_mstate( parser, MTILESTATE_TILES_PROP );
856
857 } else if( MTILESTATE_NAME == parser->mstate ) {
858 maug_strncpy( parser->tileset_name, token, RETROTILE_NAME_SZ_MAX );
859#if RETROTILE_TRACE_LVL > 0
860 debug_printf(
861 RETROTILE_TRACE_LVL, "tileset name: %s", parser->tileset_name );
862#endif /* RETROTILE_TRACE_LVL */
863
864 retrotile_parser_mstate( parser, 0 );
865
866 } else if( MTILESTATE_TPROP_NAME == parser->mstate ) {
867 maug_mzero( parser->last_prop_name, RETROTILE_PROP_NAME_SZ_MAX + 1 );
868 maug_strncpy(
870 parser->last_prop_name_sz = token_sz;
871 retrotile_parser_mstate( parser, MTILESTATE_TPROP );
872
873 } else if( MTILESTATE_TPROP_TYPE == parser->mstate ) {
874#if RETROTILE_TRACE_LVL > 0
875 debug_printf( RETROTILE_TRACE_LVL, "property %s is type: %s",
876 parser->last_prop_name, token );
877#endif /* RETROTILE_TRACE_LVL */
878 parser->last_prop_type = retrotile_parse_prop_type( token, token_sz );
879 retrotile_parser_mstate( parser, MTILESTATE_TPROP );
880
881 } else if( MTILESTATE_TPROP_VAL == parser->mstate ) {
882 /* This should be handled in the custom_cb above! */
883 maug_mzero( parser->last_prop_name, RETROTILE_PROP_NAME_SZ_MAX + 1 );
884 retrotile_parser_mstate( parser, MTILESTATE_TPROP );
885 }
886
887cleanup:
888
889 mdata_vector_unlock( parser->p_tile_defs );
890
891 if( MERROR_PREEMPT == retval ) {
892 /* Reset custom callback retval. */
893 retval = MERROR_OK;
894 }
895
896 return retval;
897}
898
899/* === */
900
901MERROR_RETVAL retrotile_parser_parse_token(
902 void* jparser_void, const char* token, size_t token_sz, void* parser_arg
903) {
904 MERROR_RETVAL retval = MERROR_OK;
905 struct RETROTILE_LAYER* tiles_layer = NULL;
906 struct RETROTILE_PARSER* parser = (struct RETROTILE_PARSER*)parser_arg;
907 retroflat_tile_t* tiles = NULL;
908
909 /* Try the custom parser. */
910 if(
911 NULL != parser->custom_token_cb &&
912 /* MERROR_PREEMPT is dealt with in cleanup. */
913 MERROR_OK != (retval = parser->custom_token_cb(
914 parser, token, token_sz, parser_arg ))
915 ) {
916 goto cleanup;
917 }
918
919 if( MJSON_PSTATE_LIST == mjson_parser_pstate( &(parser->jparser) ) ) {
920 /* We're parsing a list. What lists do we care about? */
921
922 /* Please note that this is for new tokens encountered inside of a list.
923 * For dealing with the closing of a list, see
924 * retrotile_json_close_list()!
925 */
926
927 if(
928 1 == parser->pass &&
929 MTILESTATE_LAYER_DATA == parser->mstate
930 ) {
931 /* This is a list of layer data... AKA tiles! */
932
933 /*
934 assert( NULL != *(parser->p_tilemap_h) );
935 maug_mlock( *(parser->p_tilemap_h), tilemap );
936 maug_cleanup_if_null_alloc( struct RETROTILE*, tilemap );
937 */
938
939 /*
940 debug_printf( RETROTILE_TRACE_LVL,
941 "selecting layer " SIZE_T_FMT "...",
942 parser->pass_layer_iter );
943 */
944 assert( NULL != parser->t );
945 tiles_layer = retrotile_get_layer_p(
946 parser->t, parser->pass_layer_iter );
947 assert( NULL != tiles_layer );
948
949 /* Apply the class parsed previously. */
950 tiles_layer->layer_class = parser->layer_class;
951
952 tiles = retrotile_get_tiles_p( tiles_layer );
953
954 /* Parse tilemap tile. */
955 /*
956 debug_printf( RETROTILE_TRACE_LVL,
957 "layer " SIZE_T_FMT " tile: " SIZE_T_FMT " (tiles: %p)",
958 parser->pass_layer_iter, parser->layer_tile_iter,
959 tiles );
960 */
961 assert( NULL != token );
962 assert( NULL != parser );
963 assert( NULL != tiles );
964
965 if(
966 parser->layer_tile_iter >=
967 parser->t->tiles_w * parser->t->tiles_h
968 ) {
969 /* Tile is outside of layer! */
970 error_printf(
971 "tile " SIZE_T_FMT " outside of layer tile buffer size "
972 SIZE_T_FMT "!",
973 parser->layer_tile_iter,
974 parser->t->tiles_w * parser->t->tiles_h );
975 retval = MERROR_OVERFLOW;
976 goto cleanup;
977 }
978
979 assert( 0 == tiles[parser->layer_tile_iter] );
980
981 tiles[parser->layer_tile_iter] = atoi( token );
982
983 }
984 parser->layer_tile_iter++;
985 goto cleanup;
986
987 } else if(
988 MJSON_PSTATE_OBJECT_VAL ==
989 mjson_parser_pstate( &(parser->jparser) )
990 ) {
991
992 /* Pay attention to the retrotile_parser_mstate() calls here. We don't
993 * have a stack of states, and we really only track a few we're
994 * interested in. Even if we don't process their data here, we still
995 * use retrotile_parser_mstate() to move the parser mstate back up
996 * to the parent mstate when we're done with it. This kind of "fakes" a
997 * stack (in a well-formed file, of course).
998 */
999
1000 if( MTILESTATE_TILESETS_FGID == parser->mstate ) {
1001 if( 1 == parser->pass ) {
1002 parser->t->tileset_fgid = maug_atou32( token, token_sz, 10 );
1003#if RETROTILE_TRACE_LVL > 0
1004 debug_printf(
1005 RETROTILE_TRACE_LVL, "tileset FGID set to: " SIZE_T_FMT,
1006 parser->t->tileset_fgid );
1007#endif /* RETROTILE_TRACE_LVL */
1008 }
1009 retrotile_parser_mstate( parser, MTILESTATE_TILESETS );
1010
1011 } else if( MTILESTATE_TILESETS_SRC == parser->mstate ) {
1012 if( 1 == parser->pass ) {
1013#if RETROTILE_TRACE_LVL > 0
1014 debug_printf( RETROTILE_TRACE_LVL, "parsing %s...", token );
1015#endif /* RETROTILE_TRACE_LVL */
1016 parser->tj_parse_cb(
1017 parser->dirname, token, NULL, parser->p_tile_defs,
1018 parser->wait_cb, parser->wait_data,
1019 parser->custom_token_cb, parser->custom_token_cb_data,
1020 parser->passes_max, parser->flags );
1021 }
1022 retrotile_parser_mstate( parser, MTILESTATE_TILESETS );
1023
1024 } else if( MTILESTATE_HEIGHT == parser->mstate ) {
1025 if( 0 == parser->pass ) {
1026 /* Need this to allocate on pass 1. */
1027 parser->tiles_h = atoi( token );
1028#if RETROTILE_TRACE_LVL > 0
1029 debug_printf(
1030 RETROTILE_TRACE_LVL, "tilemap height: " SIZE_T_FMT,
1031 parser->tiles_h );
1032#endif /* RETROTILE_TRACE_LVL */
1033 }
1034 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1035
1036 } else if( MTILESTATE_WIDTH == parser->mstate ) {
1037 if( 0 == parser->pass ) {
1038 /* Need this to allocate on pass 1. */
1039 parser->tiles_w = atoi( token );
1040#if RETROTILE_TRACE_LVL > 0
1041 debug_printf(
1042 RETROTILE_TRACE_LVL, "tilemap width: " SIZE_T_FMT,
1043 parser->tiles_w );
1044#endif /* RETROTILE_TRACE_LVL */
1045 }
1046 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1047
1048 } else if( MTILESTATE_LAYER_NAME == parser->mstate ) {
1049 /* TODO: Store */
1050 retrotile_parser_mstate( parser, MTILESTATE_LAYER );
1051
1052 } else if( MTILESTATE_LAYER_CLASS == parser->mstate ) {
1053 /* TODO: Use the class table to create layers for e.g. crops, items. */
1054 if( 0 == strncmp( "mobile", token, 7 ) ) {
1055#if RETROTILE_TRACE_LVL > 0
1056 debug_printf( RETROTILE_TRACE_LVL,
1057 "layer " SIZE_T_FMT " type: mobile",
1058 parser->pass_layer_iter );
1059#endif /* RETROTILE_TRACE_LVL */
1060 parser->layer_class = RETROTILE_CLASS_MOBILE;
1061 } else {
1062#if RETROTILE_TRACE_LVL > 0
1063 debug_printf( RETROTILE_TRACE_LVL,
1064 "layer " SIZE_T_FMT " type: tile",
1065 parser->pass_layer_iter );
1066#endif /* RETROTILE_TRACE_LVL */
1067 parser->layer_class = RETROTILE_CLASS_TILE;
1068 }
1069 retrotile_parser_mstate( parser, MTILESTATE_LAYER );
1070
1071 } else if( MTILESTATE_PROP_NAME == parser->mstate ) {
1072 maug_mzero( parser->last_prop_name, RETROTILE_PROP_NAME_SZ_MAX + 1 );
1073 maug_strncpy(
1075 parser->last_prop_name_sz = token_sz;
1076 retrotile_parser_mstate( parser, MTILESTATE_PROP );
1077
1078 } else if( MTILESTATE_PROP_TYPE == parser->mstate ) {
1079#if RETROTILE_TRACE_LVL > 0
1080 debug_printf( RETROTILE_TRACE_LVL, "property %s is type: %s",
1081 parser->last_prop_name, token );
1082#endif /* RETROTILE_TRACE_LVL */
1083 parser->last_prop_type = retrotile_parse_prop_type( token, token_sz );
1084 retrotile_parser_mstate( parser, MTILESTATE_PROP );
1085
1086 } else if( MTILESTATE_PROP_VAL == parser->mstate ) {
1087 /* We're dealing with properties of the tilemap. */
1088 if( 0 == strncmp( parser->last_prop_name, "name", 5 ) ) {
1089#if RETROTILE_TRACE_LVL > 0
1090 debug_printf( RETROTILE_TRACE_LVL, "tilemap name: %s", token );
1091#endif /* RETROTILE_TRACE_LVL */
1092 maug_strncpy( parser->tilemap_name, token, RETROTILE_NAME_SZ_MAX );
1093 }
1094
1095 maug_mzero( parser->last_prop_name, RETROTILE_PROP_NAME_SZ_MAX + 1 );
1096 retrotile_parser_mstate( parser, MTILESTATE_PROP );
1097 }
1098 goto cleanup;
1099 }
1100
1101 retrotile_parser_match_token( token, token_sz, parser );
1102
1103cleanup:
1104
1105 return retval;
1106}
1107
1108/* === */
1109
1110MERROR_RETVAL retrotile_json_close_list(
1111 struct MJSON_PARSER* jparser, void* parg
1112) {
1113 struct RETROTILE_PARSER* parser = (struct RETROTILE_PARSER*)parg;
1114
1115 if( MTILESTATE_LAYER_DATA == parser->mstate ) {
1116 assert( RETROTILE_PARSER_MODE_MAP == parser->mode );
1117#if RETROTILE_TRACE_LVL > 0
1118 debug_printf( RETROTILE_TRACE_LVL, "parsed " SIZE_T_FMT " tiles!",
1119 parser->layer_tile_iter );
1120#endif /* RETROTILE_TRACE_LVL */
1121 assert( parser->layer_tile_iter > 0 );
1122 retrotile_parser_mstate( parser, MTILESTATE_LAYER );
1123
1124 } else if( MTILESTATE_LAYERS == parser->mstate ) {
1125 assert( RETROTILE_PARSER_MODE_MAP == parser->mode );
1126 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1127
1128 } else if( MTILESTATE_TILESETS == parser->mstate ) {
1129 assert( RETROTILE_PARSER_MODE_MAP == parser->mode );
1130 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1131
1132 } else if( MTILESTATE_TILES_PROP == parser->mstate ) {
1133 assert( RETROTILE_PARSER_MODE_DEFS == parser->mode );
1134 retrotile_parser_mstate( parser, MTILESTATE_TILES );
1135
1136 } else if( MTILESTATE_TILES == parser->mstate ) {
1137 assert( RETROTILE_PARSER_MODE_DEFS == parser->mode );
1138 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1139
1140 } else if( MTILESTATE_PROP == parser->mstate ) {
1141 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1142
1143 } else if( MTILESTATE_TPROP == parser->mstate ) {
1144 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1145 }
1146
1147 return MERROR_OK;
1148}
1149
1150/* === */
1151
1152MERROR_RETVAL retrotile_json_open_obj(
1153 struct MJSON_PARSER* jparser, void* parg
1154) {
1155 struct RETROTILE_PARSER* parser = (struct RETROTILE_PARSER*)parg;
1156
1157 if( MTILESTATE_LAYERS == parser->mstate ) {
1158 assert( RETROTILE_PARSER_MODE_MAP == parser->mode );
1159 /* Reset on open so count is retained for allocating after first
1160 * pass. */
1161 parser->layer_tile_iter = 0;
1162 retrotile_parser_mstate( parser, MTILESTATE_LAYER );
1163 }
1164
1165 return MERROR_OK;
1166}
1167
1168/* === */
1169
1170MERROR_RETVAL retrotile_json_close_obj(
1171 struct MJSON_PARSER* jparser, void* parg
1172) {
1173 struct RETROTILE_PARSER* parser = (struct RETROTILE_PARSER*)parg;
1174
1175 if( MTILESTATE_LAYER == parser->mstate ) {
1176 assert( RETROTILE_PARSER_MODE_MAP == parser->mode );
1177#if RETROTILE_TRACE_LVL > 0
1178 debug_printf( RETROTILE_TRACE_LVL,
1179 "incrementing pass layer to " SIZE_T_FMT " after " SIZE_T_FMT
1180 " tiles...",
1181 parser->pass_layer_iter + 1, parser->layer_tile_iter );
1182#endif /* RETROTILE_TRACE_LVL */
1183 parser->pass_layer_iter++;
1184 retrotile_parser_mstate( parser, MTILESTATE_LAYERS );
1185
1186 } else if( MTILESTATE_GRID == parser->mstate ) {
1187 retrotile_parser_mstate( parser, MTILESTATE_NONE );
1188 }
1189
1190 return MERROR_OK;
1191}
1192
1193/* === */
1194
1195int retrotile_parse_prop_type( const char* token, size_t token_sz ) {
1196 int out = RETROTILE_PROP_TYPE_OTHER;
1197
1198 if( 0 == strncmp( "string", token, 7 ) ) {
1200 } else if( 0 == strncmp( "file", token, 5 ) ) {
1202 } else if( 0 == strncmp( "int", token, 4 ) ) {
1204 }
1205
1206 return out;
1207}
1208
1209/* === */
1210
1211mfix_t retrotile_static_rotation_from_dir( const char* dir ) {
1212 mfix_t static_rotate_out = 0;
1213
1214 if( NULL == dir ) {
1215 return 0;
1216 }
1217
1218 /* Translate dir into rotation value. */
1219 if( 0 == strncmp( dir, "NW", 2 ) ) {
1220 static_rotate_out = mfix_from_f( 90.0f );
1221 } else if( 0 == strncmp( dir, "SW", 2 ) ) {
1222 static_rotate_out = mfix_from_f( 180.0f );
1223 } else if( 0 == strncmp( dir, "SE", 2 ) ) {
1224 static_rotate_out = mfix_from_f( 270.0f );
1225
1226 } else if( 0 == strncmp( dir, "W", 1 ) ) {
1227 static_rotate_out = mfix_from_f( 90.0f );
1228 } else if( 0 == strncmp( dir, "S", 1 ) ) {
1229 static_rotate_out = mfix_from_f( 180.0f );
1230 } else if( 0 == strncmp( dir, "E", 1 ) ) {
1231 static_rotate_out = mfix_from_f( 270.0f );
1232
1233 } else {
1234 static_rotate_out = 0;
1235 }
1236
1237 return static_rotate_out;
1238}
1239
1240/* === */
1241
1243 const char* dirname, const char* filename, MAUG_MHANDLE* p_tilemap_h,
1244 struct MDATA_VECTOR* p_tile_defs, mparser_wait_cb_t wait_cb, void* wait_data,
1245 mparser_parse_token_cb token_cb, void* token_cb_data, uint8_t passes,
1246 uint8_t flags
1247) {
1248 MERROR_RETVAL retval = MERROR_OK;
1249 MAUG_MHANDLE parser_h = (MAUG_MHANDLE)NULL;
1250 struct RETROTILE_PARSER* parser = NULL;
1251 char filename_path[MAUG_PATH_SZ_MAX];
1252 mfile_t tile_file;
1253 char c;
1254 char* filename_ext = NULL;
1255
1256 /* Initialize parser. */
1257 parser_h = maug_malloc( 1, sizeof( struct RETROTILE_PARSER ) );
1258 maug_cleanup_if_null_alloc( MAUG_MHANDLE, parser_h );
1259
1260 maug_mlock( parser_h, parser );
1261 maug_cleanup_if_null_alloc( struct RETROTILE_PARSER*, parser );
1262 maug_mzero( parser, sizeof( struct RETROTILE_PARSER ) );
1263
1264 parser->flags = flags;
1265 parser->tj_parse_cb = retrotile_parse_json_file;
1266 parser->custom_token_cb = token_cb;
1267 parser->custom_token_cb_data = token_cb_data;
1268
1269 maug_strncpy( parser->dirname, dirname, MAUG_PATH_SZ_MAX );
1270
1271 if( 2 > passes ) {
1272#if RETROTILE_TRACE_LVL > 0
1273 debug_printf( RETROTILE_TRACE_LVL,
1274 "increasing parse passes to minimum, 2!" );
1275#endif /* RETROTILE_TRACE_LVL */
1276 passes = 2;
1277 }
1278
1279 parser->passes_max = passes;
1280
1281 /* Setup filename path. */
1282 maug_mzero( filename_path, MAUG_PATH_SZ_MAX );
1283 /* TODO: Configurable path. */
1284 maug_snprintf(
1285 filename_path, MAUG_PATH_SZ_MAX, "%s/%s", dirname, filename );
1286
1287#if RETROTILE_TRACE_LVL > 0
1288 debug_printf( RETROTILE_TRACE_LVL, "opening %s...", filename_path );
1289#endif /* RETROTILE_TRACE_LVL */
1290
1291 retval = mfile_open_read( filename_path, &tile_file );
1292 maug_cleanup_if_not_ok();
1293
1294 /* Parse JSON and react to state. */
1295 for( parser->pass = 0 ; passes > parser->pass ; parser->pass++ ) {
1296#if RETROTILE_TRACE_LVL > 0
1297 debug_printf( RETROTILE_TRACE_LVL, "beginning pass #%u...",
1298 parser->pass );
1299#endif /* RETROTILE_TRACE_LVL */
1300
1301 /* Reset tilemap parser. */
1302 parser->mstate = 0;
1303
1304 /* Reset JSON parser. */
1305 maug_mzero( &(parser->jparser.base), sizeof( struct MJSON_PARSER ) );
1306
1307 parser->wait_cb = wait_cb;
1308 parser->wait_data = wait_data;
1309 parser->jparser.base.wait_cb = wait_cb;
1310 parser->jparser.base.wait_data = wait_data;
1311
1312 /* Figure out if we're parsing a .tmj or .tsj. */
1313 filename_ext = maug_strrchr( filename, '.' );
1314 if( NULL == filename_ext ) {
1315 error_printf( "could not parse filename extension!" );
1316 retval = MERROR_FILE;
1317 goto cleanup;
1318 }
1319 if( 's' == filename_ext[2] ) {
1320#if RETROTILE_TRACE_LVL > 0
1321 debug_printf( RETROTILE_TRACE_LVL,
1322 "(tile_defs pass %u)", parser->pass );
1323#endif /* RETROTILE_TRACE_LVL */
1325 parser->jparser.token_parser = retrotile_parser_parse_tiledef_token;
1326 parser->jparser.token_parser_arg = parser;
1327 parser->jparser.close_list = retrotile_json_close_list;
1328 parser->jparser.close_list_arg = parser;
1329 parser->jparser.close_obj = retrotile_json_close_obj;
1330 parser->jparser.close_obj_arg = parser;
1331 /*
1332 parser->jparser.base.close_val = retrotile_json_close_val;
1333 parser->jparser.base.close_val_arg = parser;
1334 */
1335 parser->p_tile_defs = p_tile_defs;
1336
1337 assert( NULL != p_tile_defs );
1338 if( 1 == parser->pass ) {
1339 /* Allocate tile defs based on highest tile ID found on
1340 * first pass.
1341 */
1342 assert( 0 < parser->tileset_id_cur );
1343#if RETROTILE_TRACE_LVL > 0
1344 debug_printf(
1345 RETROTILE_TRACE_LVL, "allocating " SIZE_T_FMT " tile defs...",
1346 parser->tileset_id_cur + 1 );
1347#endif /* RETROTILE_TRACE_LVL */
1348 mdata_vector_fill(
1349 parser->p_tile_defs, parser->tileset_id_cur + 1,
1350 sizeof( struct RETROTILE_TILE_DEF ) );
1351 }
1352 } else {
1353#if RETROTILE_TRACE_LVL > 0
1354 debug_printf( RETROTILE_TRACE_LVL, "(tilemap pass %u)", parser->pass );
1355#endif /* RETROTILE_TRACE_LVL */
1357
1358 parser->jparser.close_list = retrotile_json_close_list;
1359 parser->jparser.close_list_arg = parser;
1360 parser->jparser.open_obj = retrotile_json_open_obj;
1361 parser->jparser.open_obj_arg = parser;
1362 parser->jparser.close_obj = retrotile_json_close_obj;
1363 parser->jparser.close_obj_arg = parser;
1364 parser->jparser.token_parser = retrotile_parser_parse_token;
1365 parser->jparser.token_parser_arg = parser;
1366 parser->p_tile_defs = p_tile_defs;
1367
1368 assert( NULL != p_tilemap_h );
1369 assert( NULL != p_tile_defs );
1370 if( 1 == parser->pass ) {
1371 /* Allocate tiles for the new layers. */
1372 retval = retrotile_alloc(
1373 p_tilemap_h, parser->tiles_w, parser->tiles_h,
1374 parser->pass_layer_iter, parser->tilemap_name,
1375 parser->tileset_name );
1376 maug_cleanup_if_not_ok();
1377 maug_mlock( *p_tilemap_h, parser->t );
1378 }
1379 parser->pass_layer_iter = 0;
1380 }
1381
1382 while( tile_file.has_bytes( &tile_file ) ) {
1383 tile_file.read_int( &tile_file, (uint8_t*)&c, 1, 0 );
1384#if RETROTILE_TRACE_CHARS > 0
1385 debug_printf( RETROTILE_TRACE_CHARS, "%c", c );
1386#endif /* RETROTILE_TRACE_CHARS */
1387 retval = mjson_parse_c( &(parser->jparser), c );
1388 if( MERROR_OK != retval ) {
1389 error_printf( "error parsing JSON!" );
1390 goto cleanup;
1391 }
1392 }
1393
1394 tile_file.seek( &tile_file, 0 );
1395
1396 filename_ext = maug_strrchr( filename, '.' );
1397 if( NULL == filename_ext ) {
1398 error_printf( "could not parse filename extension!" );
1399 retval = MERROR_FILE;
1400 goto cleanup;
1401 }
1402 if( 's' != filename_ext[2] ) {
1403#if RETROTILE_TRACE_LVL > 0
1404 debug_printf( RETROTILE_TRACE_LVL,
1405 "pass %u found " SIZE_T_FMT " layers",
1406 parser->pass, parser->pass_layer_iter );
1407#endif /* RETROTILE_TRACE_LVL */
1408 }
1409 }
1410
1411#if RETROTILE_TRACE_LVL > 0
1412 debug_printf(
1413 RETROTILE_TRACE_LVL, "finished parsing %s, retval: %d",
1414 filename_path, retval );
1415#endif /* RETROTILE_TRACE_LVL */
1416
1417cleanup:
1418
1419 if( NULL != parser ) {
1420 if( NULL != parser->t ) {
1421 maug_munlock( *p_tilemap_h, parser->t );
1422 }
1423 maug_munlock( parser_h, parser );
1424 }
1425
1426 if( (MAUG_MHANDLE)NULL != parser_h ) {
1427 maug_mfree( parser_h );
1428 }
1429
1430 return retval;
1431}
1432
1433/* === */
1434
1435static retroflat_tile_t retrotile_gen_diamond_square_rand(
1436 retroflat_tile_t min_z, retroflat_tile_t max_z, uint32_t tuning,
1437 retroflat_tile_t top_left_z
1438) {
1439 retroflat_tile_t avg = top_left_z;
1440
1441 if( 8 > rand() % 10 ) {
1442 /* avg = min_z + (rand() % (max_z - min_z)); */
1443 avg -= (min_z / tuning) + (rand() % (max_z / tuning));
1444 /* } else {
1445 avg += (min_z / 10) + (rand() % (max_z / 10)); */
1446 }
1447
1448 /* Clamp the result. */
1449
1450 if( min_z > avg ) {
1451 avg = min_z;
1452 }
1453
1454 if( max_z < avg ) {
1455 avg = max_z;
1456 }
1457
1458 return avg;
1459}
1460
1461/* === */
1462
1463static void retrotile_gen_diamond_square_corners(
1464 int16_t corners_x[2][2], int16_t corners_y[2][2],
1466 uint32_t tuning, struct RETROTILE_DATA_DS* data_ds,
1467 struct RETROTILE_LAYER* layer, struct RETROTILE* t
1468) {
1469 int16_t iter_x = 0,
1470 iter_y = 0;
1471 retroflat_tile_t* tile_iter = NULL;
1472 retroflat_tile_t top_left_z = 0;
1473
1474 /* Generate missing corner data. Loop through X/Y coords stored in
1475 * corners_x/corners_y convenience arrays.
1476 */
1477 for( iter_y = 0 ; iter_y < 2 ; iter_y++ ) {
1478 for( iter_x = 0 ; iter_x < 2 ; iter_x++ ) {
1479
1480 /* Make sure corner X is in bounds. */
1481 corners_x[iter_x][iter_y] =
1482 (data_ds->sect_x - 1) + (iter_x * data_ds->sect_w);
1483 if( 0 > corners_x[iter_x][iter_y] ) {
1484 corners_x[iter_x][iter_y] += 1;
1485 }
1486
1487 /* Make sure corner Y is in bounds. */
1488 corners_y[iter_x][iter_y] =
1489 (data_ds->sect_y - 1) + (iter_y * data_ds->sect_h);
1490 if( 0 > corners_y[iter_x][iter_y] ) {
1491 corners_y[iter_x][iter_y] += 1;
1492 }
1493 }
1494 }
1495
1496 /* Should be handled by the check above. */
1497 assert( 0 <= corners_x[0][0] );
1498 assert( 0 <= corners_y[0][0] );
1499 assert( t->tiles_w > corners_x[0][0] );
1500 assert( t->tiles_h > corners_y[0][0] );
1501
1502 /* Grab the top-left Z-value to anchor generated corners to. */
1503 top_left_z = retrotile_get_tile(
1504 t, layer,
1505 corners_x[0][0],
1506 corners_y[0][0] );
1507
1508 if( 0 > top_left_z ) {
1509 retrotile_get_tile(
1510 t, layer,
1511 corners_x[0][0] >= 0 ? corners_x[0][0] : 0,
1512 corners_y[0][0] >= 0 ? corners_y[0][0] : 0 ) = max_z;
1513 top_left_z = max_z;
1514 }
1515
1516 /* Fill in missing corners. */
1517 for( iter_y = 0 ; iter_y < 2 ; iter_y++ ) {
1518 for( iter_x = 0 ; iter_x < 2 ; iter_x++ ) {
1519 /* Grab a pointer to the corner so we can modify it easily. */
1520 tile_iter = &(retrotile_get_tile(
1521 t, layer,
1522 corners_x[iter_x][iter_y],
1523 corners_y[iter_x][iter_y] ));
1524
1525 /* Check if corner is already filled in. */
1526 if( -1 != *tile_iter ) {
1527#if RETROTILE_TRACE_LVL > 0
1528 debug_printf(
1529 RETROTILE_TRACE_LVL, "corner coord %d x %d present: %d",
1530 corners_x[iter_x][iter_y], corners_y[iter_x][iter_y],
1531 retrotile_get_tile(
1532 t, layer,
1533 corners_x[iter_x][iter_y],
1534 corners_y[iter_x][iter_y] ) );
1535#endif /* RETROTILE_TRACE_LVL */
1536 continue;
1537 }
1538
1539 /* Generate a new value for this corner. */
1540 *tile_iter = retrotile_gen_diamond_square_rand(
1541 min_z, max_z, tuning, top_left_z );
1542
1543#if RETROTILE_TRACE_LVL > 0
1544 debug_printf( RETROTILE_TRACE_LVL,
1545 "missing corner coord %d x %d: %d",
1546 corners_x[iter_x][iter_y], corners_y[iter_x][iter_y],
1547 *tile_iter );
1548#endif /* RETROTILE_TRACE_LVL */
1549 }
1550 }
1551}
1552
1553/* === */
1554
1555static retroflat_tile_t retrotile_gen_diamond_square_avg(
1556 int16_t corners_x[2][2], int16_t corners_y[2][2],
1557 struct RETROTILE* t, struct RETROTILE_LAYER* layer
1558) {
1559 retroflat_tile_t* tile_iter = NULL;
1560 int16_t iter_x = 0,
1561 iter_y = 0;
1562 retroflat_tile_t avg = 0;
1563
1564 /* Average corner data. */
1565 for( iter_y = 0 ; 2 > iter_y ; iter_y++ ) {
1566 for( iter_x = 0 ; 2 > iter_x ; iter_x++ ) {
1567 tile_iter = &(retrotile_get_tile(
1568 t, layer,
1569 corners_x[iter_x][iter_y],
1570 corners_y[iter_x][iter_y] ));
1571 assert( -1 != *tile_iter );
1572 /*
1573 debug_printf(
1574 RETROTILE_TRACE_LVL, "%d: adding from coords %d x %d: %d",
1575 iter_depth,
1576 corners_x[iter_x][iter_y], corners_y[iter_x][iter_y],
1577 *tile_iter ); */
1578 avg += *tile_iter;
1579 }
1580 }
1581
1582 /* TODO: Use right shift? */
1583 avg /= 4;
1584
1585 return avg;
1586}
1587
1588/* === */
1589
1591 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
1592 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
1593 retrotile_ani_cb animation_cb, void* animation_cb_data
1594) {
1595 int16_t iter_x = 0,
1596 iter_y = 0
1597#if RETROTILE_TRACE_LVL > 0
1598 , iter_depth = 0;
1599#else
1600 ;
1601#endif /* RETROTILE_TRACE_LVL */
1602 int16_t corners_x[2][2];
1603 int16_t corners_y[2][2];
1604 int32_t avg = 0;
1605 /* size_t tile_idx = 0; */
1606 struct RETROTILE_DATA_DS data_ds_sub;
1607 MAUG_MHANDLE data_ds_h = (MAUG_MHANDLE)NULL;
1608 struct RETROTILE_DATA_DS* data_ds = NULL;
1609 /* retroflat_tile_t* tiles = NULL; */
1610 MERROR_RETVAL retval = MERROR_OK;
1611 struct RETROTILE_LAYER* layer = NULL;
1612 retroflat_tile_t* tile_iter = NULL;
1613 uint8_t free_ds_data = 0;
1614#ifdef MAUG_NO_STDLIB
1615 size_t i = 0;
1616#endif /* MAUG_NO_STDLIB */
1617
1618 /*
1619 maug_mlock( t->tiles, tiles );
1620 maug_cleanup_if_null_alloc( struct GRIDCITY_TILE*, tiles );
1621 */
1622
1623 #define _retrotile_ds_update_statistics( data, tile ) \
1624 /* Gather statistics. */ \
1625 if( (data)->highest_generated < (tile) && 32767 > (tile) ) { \
1626 (data)->highest_generated = (tile); \
1627 } \
1628 if( (data)->lowest_generated > (tile) && 0 < (tile) ) { \
1629 (data)->lowest_generated = (tile); \
1630 }
1631
1632 layer = retrotile_get_layer_p( t, layer_idx );
1633
1634 if(
1635 NULL == data ||
1637 ) {
1638 /* This must be the first call, so initialize or allocate a new struct.
1639 */
1640 if( NULL == data ) {
1641 /* An internal struct needs to be allocated before initialization. */
1642 data_ds_h = maug_malloc( 1, sizeof( struct RETROTILE_DATA_DS ) );
1643 maug_cleanup_if_null_alloc( MAUG_MHANDLE, data_ds_h );
1644 free_ds_data = 1;
1645 maug_mlock( data_ds_h, data_ds );
1646 maug_cleanup_if_null_alloc( struct RETROTILE_DATA_DS*, data_ds );
1647 } else {
1648 data_ds = (struct RETROTILE_DATA_DS*)data;
1649 }
1650
1651 /* Initialize passed tilemap while we're handling first call stuff. */
1652 retrotile_clear_tiles( t, layer, i );
1653
1654 /* Initialize DS struct from tilemap properties. */
1655 maug_mzero( data_ds, sizeof( struct RETROTILE_DATA_DS ) );
1656 data_ds->sect_w = t->tiles_w;
1657 data_ds->sect_h = t->tiles_h;
1658 data_ds->sect_w_half = data_ds->sect_w >> 1;
1659 data_ds->sect_h_half = data_ds->sect_h >> 1;
1660 data_ds->lowest_generated = 32767;
1661
1662 /* Disable this flag for subsequent calls. */
1664 } else {
1665 data_ds = (struct RETROTILE_DATA_DS*)data;
1666 }
1667 assert( NULL != data_ds );
1668
1669 /* Trivial case; end recursion. */
1670 if( 0 == data_ds->sect_w ) {
1671#if RETROTILE_TRACE_LVL > 0
1672 debug_printf(
1673 RETROTILE_TRACE_LVL, "%d return: null sector", iter_depth );
1674#endif /* RETROTILE_TRACE_LVL */
1675 goto cleanup;
1676 }
1677
1678 if(
1679 data_ds->sect_x + data_ds->sect_w > t->tiles_w ||
1680 data_ds->sect_y + data_ds->sect_h > t->tiles_h
1681 ) {
1682#if RETROTILE_TRACE_LVL > 0
1683 debug_printf(
1684 RETROTILE_TRACE_LVL, "%d return: overflow sector", iter_depth );
1685#endif /* RETROTILE_TRACE_LVL */
1686 goto cleanup;
1687 }
1688
1689#if RETROTILE_TRACE_LVL > 0
1690 iter_depth = t->tiles_w / data_ds->sect_w;
1691#endif /* RETROTILE_TRACE_LVL */
1692
1693 /* Generate/grab corners before averaging them! */
1694 retrotile_gen_diamond_square_corners(
1695 corners_x, corners_y, min_z, max_z, tuning, data_ds, layer, t );
1696
1697 if( 2 == data_ds->sect_w || 2 == data_ds->sect_h ) {
1698 /* Nothing to average, this sector is just corners! */
1699#if RETROTILE_TRACE_LVL > 0
1700 debug_printf(
1702 "%d return: reached innermost point", iter_depth );
1703#endif /* RETROTILE_TRACE_LVL */
1704 goto cleanup; /* Skip further descent regardless. */
1705 }
1706
1707 avg =
1708 retrotile_gen_diamond_square_avg( corners_x, corners_y, t, layer );
1709
1710#if RETROTILE_TRACE_LVL > 0
1711 debug_printf( RETROTILE_TRACE_LVL, "avg: " S32_FMT, avg );
1712#endif /* RETROTILE_TRACE_LVL */
1713
1714 tile_iter = &(retrotile_get_tile(
1715 t, layer,
1716 data_ds->sect_x + data_ds->sect_w_half,
1717 data_ds->sect_y + data_ds->sect_h_half ));
1718 if( -1 != *tile_iter ) {
1719#if RETROTILE_TRACE_LVL > 0
1720 debug_printf( RETROTILE_TRACE_LVL, "avg already present at %d x %d!",
1721 data_ds->sect_x + data_ds->sect_w_half,
1722 data_ds->sect_y + data_ds->sect_h_half );
1723#endif /* RETROTILE_TRACE_LVL */
1724 goto cleanup;
1725 }
1726 *tile_iter = avg;
1727 _retrotile_ds_update_statistics( data_ds, avg );
1728
1729 /* assert( 0 <= tiles[tile_idx].terrain );
1730
1731 maug_munlock( city->tiles, tiles );
1732 tiles = NULL; */
1733
1734 /* Recurse into subsectors. */
1735 for(
1736 iter_y = data_ds->sect_y ;
1737 iter_y < (data_ds->sect_y + data_ds->sect_h) ;
1738 iter_y++
1739 ) {
1740 for(
1741 iter_x = data_ds->sect_x ;
1742 iter_x < (data_ds->sect_x + data_ds->sect_w) ;
1743 iter_x++
1744 ) {
1745 data_ds_sub.sect_x = data_ds->sect_x + iter_x;
1746
1747 data_ds_sub.sect_y = data_ds->sect_y + iter_y;
1748
1749 data_ds_sub.sect_w = data_ds->sect_w_half;
1750 data_ds_sub.sect_h = data_ds->sect_h_half;
1751 data_ds_sub.sect_w_half = data_ds_sub.sect_w >> 1;
1752 data_ds_sub.sect_h_half = data_ds_sub.sect_h >> 1;
1753 data_ds_sub.lowest_generated = 32767;
1754 data_ds_sub.highest_generated = 0;
1755
1756#if RETROTILE_TRACE_LVL > 0
1757 debug_printf(
1758 RETROTILE_TRACE_LVL, "%d: child sector at %d x %d, %d wide",
1759 iter_depth,
1760 data_ds_sub.sect_x, data_ds_sub.sect_y, data_ds_sub.sect_w );
1761#endif /* RETROTILE_TRACE_LVL */
1762
1764 t, min_z, max_z, tuning, layer_idx, flags, &data_ds_sub,
1765 animation_cb, animation_cb_data );
1766 maug_cleanup_if_not_ok();
1767
1768 _retrotile_ds_update_statistics(
1769 data_ds, data_ds_sub.highest_generated );
1770 _retrotile_ds_update_statistics(
1771 data_ds, data_ds_sub.lowest_generated );
1772 }
1773 }
1774
1775 if(
1776 data_ds->sect_w == (t->tiles_w >> 1) &&
1777 NULL != animation_cb
1778 ) {
1779 retval = animation_cb( animation_cb_data, iter_y );
1780 maug_cleanup_if_not_ok();
1781 }
1782
1783#if RETROTILE_TRACE_LVL > 0
1784 debug_printf(
1785 RETROTILE_TRACE_LVL, "%d return: all sectors complete", iter_depth );
1786#endif /* RETROTILE_TRACE_LVL */
1787
1788cleanup:
1789
1790 if( free_ds_data && NULL != data_ds ) {
1791 maug_munlock( data_ds_h, data_ds );
1792 }
1793
1794 if( free_ds_data && (MAUG_MHANDLE)NULL != data_ds_h ) {
1795 maug_mfree( data_ds_h );
1796 }
1797
1798 return retval;
1799}
1800
1801/* === */
1802
1804 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
1805 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
1806 retrotile_ani_cb animation_cb, void* animation_cb_data
1807) {
1808 size_t x = 0,
1809 y = 0;
1810 int16_t offset_x = 0,
1811 offset_y = 0,
1812 finished = 0;
1813 MERROR_RETVAL retval = MERROR_OK;
1814 struct RETROTILE_LAYER* layer = NULL;
1815 int16_t spb = RETROTILE_VORONOI_DEFAULT_SPB;
1816 int16_t drift = RETROTILE_VORONOI_DEFAULT_DRIFT;
1817 MAUG_MHANDLE temp_grid_h = (MAUG_MHANDLE)NULL;
1818 retroflat_tile_t* temp_grid = NULL;
1819 retroflat_tile_t* tiles = NULL;
1820 /* Only use 4 cardinal directions. */
1821 int8_t side_iter = 0;
1822#ifdef MAUG_NO_STDLIB
1823 size_t i = 0;
1824#endif /* MAUG_NO_STDLIB */
1825
1826 layer = retrotile_get_layer_p( t, 0 );
1827
1828 tiles = retrotile_get_tiles_p( layer );
1829
1830 /* Initialize grid to empty. */
1831 retrotile_clear_tiles( t, layer, i );
1832
1833 /* Generate the initial sector starting points. */
1834 for( y = 0 ; t->tiles_w > y ; y += spb ) {
1835 for( x = 0 ; t->tiles_w > x ; x += spb ) {
1836 offset_x = x + ((drift * -1) + (rand() % drift));
1837 offset_y = y + ((drift * -1) + (rand() % drift));
1838
1839 /* Clamp sector offsets onto map borders. */
1840 if( 0 > offset_x ) {
1841 offset_x = 0;
1842 }
1843 if( offset_x >= t->tiles_w ) {
1844 offset_x = t->tiles_w - 1;
1845 }
1846 if( 0 > offset_y ) {
1847 offset_y = 0;
1848 }
1849 if( offset_y >= t->tiles_h ) {
1850 offset_y = t->tiles_h - 1;
1851 }
1852
1853 retrotile_get_tile( t, layer, offset_x, offset_y ) =
1854 min_z + (rand() % max_z);
1855 }
1856 }
1857
1858 temp_grid_h = maug_malloc(
1859 sizeof( retroflat_tile_t ), t->tiles_w * t->tiles_h );
1860 maug_cleanup_if_null_alloc( MAUG_MHANDLE, temp_grid_h );
1861
1862 maug_mlock( temp_grid_h, temp_grid );
1863 maug_cleanup_if_null_alloc( retroflat_tile_t*, temp_grid );
1864
1865 /* Grow the sector starting points. */
1866 while( !finished ) {
1867 if( NULL != animation_cb ) {
1868 retval = animation_cb( animation_cb_data, -1 );
1869 maug_cleanup_if_not_ok();
1870 }
1871
1872 /* Prepare sampling grid so we're working from unexpanded sections
1873 * below.
1874 */
1875 memcpy(
1876 temp_grid, tiles,
1877 sizeof( retroflat_tile_t ) * t->tiles_w * t->tiles_h );
1878
1879 /* Starting another pass, assume finished until proven otherwise. */
1880 finished = 1;
1881 for( y = 0 ; t->tiles_h > y ; y++ ) {
1882 for( x = 0 ; t->tiles_w > x ; x++ ) {
1883 if( -1 == retrotile_get_tile( t, layer, x, y ) ) {
1884 /* If there are still unfilled tiles, we're not finished
1885 * yet!
1886 */
1887 finished = 0;
1888
1889 /* Skip filled tile. */
1890 continue;
1891 }
1892
1893
1894 for( side_iter = 0 ; 4 > side_iter ; side_iter++ ) {
1895#if RETROTILE_TRACE_LVL > 0
1896 debug_printf( RETROTILE_TRACE_LVL,
1897 SIZE_T_FMT " (%d), " SIZE_T_FMT " (%d) ("
1898 SIZE_T_FMT ", " SIZE_T_FMT ")",
1899 x,
1900 gc_retroflat_offsets4_x[side_iter],
1901 y,
1902 gc_retroflat_offsets4_y[side_iter],
1903 t->tiles_w, t->tiles_h );
1904#endif /* RETROTILE_TRACE_LVL */
1905
1906 /* Iterate through directions to expand. */
1907 /* TODO: Add tuning to select directional probability. */
1908 if(
1909 t->tiles_w > x + gc_retroflat_offsets4_x[side_iter] &&
1910 t->tiles_h > y + gc_retroflat_offsets4_y[side_iter] &&
1911 -1 == temp_grid[
1912 ((y + gc_retroflat_offsets4_y[side_iter]) *
1913 t->tiles_w) +
1914 (x + gc_retroflat_offsets4_x[side_iter])]
1915 ) {
1916 /* Copy center tile to this direction. */
1917 retrotile_get_tile( t, layer,
1918 x + gc_retroflat_offsets4_x[side_iter],
1919 y + gc_retroflat_offsets4_y[side_iter] ) =
1920 retrotile_get_tile( t, layer, x, y );
1921 break;
1922 }
1923 }
1924 }
1925 }
1926 }
1927
1928cleanup:
1929
1930 if( NULL != temp_grid ) {
1931 maug_munlock( temp_grid_h, temp_grid );
1932 }
1933
1934 if( (MAUG_MHANDLE)NULL != temp_grid_h ) {
1935 maug_mfree( temp_grid_h );
1936 }
1937
1938 return retval;
1939}
1940
1941/* === */
1942
1944 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
1945 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
1946 retrotile_ani_cb animation_cb, void* animation_cb_data
1947) {
1948 MERROR_RETVAL retval = MERROR_OK;
1949 size_t x = 0,
1950 y = 0;
1951 int16_t side_iter = 0,
1952 sides_avail = 0,
1953 sides_sum = 0;
1954 /* Sides start from 12 on the clock (up). */
1955 struct RETROTILE_LAYER* layer = NULL;
1956
1957 assert( NULL != t );
1958 layer = retrotile_get_layer_p( t, layer_idx );
1959 assert( NULL != layer );
1960
1961 for( y = 0 ; t->tiles_h > y ; y++ ) {
1962 if( NULL != animation_cb ) {
1963 retval = animation_cb( animation_cb_data, y );
1964 maug_cleanup_if_not_ok();
1965 }
1966 for( x = 0 ; t->tiles_w > x ; x++ ) {
1967 /* Reset average. */
1968 sides_avail = 0;
1969 sides_sum = 0;
1970
1971 /* Grab values for available sides. */
1972 for( side_iter = 0 ; 8 > side_iter ; side_iter++ ) {
1973 if(
1974 t->tiles_w <= x + gc_retroflat_offsets8_x[side_iter] ||
1975 t->tiles_h <= y + gc_retroflat_offsets8_y[side_iter]
1976 ) {
1977 continue;
1978 }
1979
1980 sides_avail++;
1981#if RETROTILE_TRACE_LVL > 0
1982 debug_printf(
1984 "si %d: x, y: " SIZE_T_FMT " (+%d), " SIZE_T_FMT
1985 " (+%d) idx: " SIZE_T_FMT,
1986 side_iter,
1987 x + gc_retroflat_offsets8_x[side_iter],
1988 gc_retroflat_offsets8_x[side_iter],
1989 y + gc_retroflat_offsets8_y[side_iter],
1990 gc_retroflat_offsets8_y[side_iter],
1991 ((y + gc_retroflat_offsets8_y[side_iter]) * t->tiles_w) +
1992 x + gc_retroflat_offsets8_x[side_iter] );
1993#endif /* RETROTILE_TRACE_LVL */
1994 sides_sum += retrotile_get_tile(
1995 t, layer,
1996 x + gc_retroflat_offsets8_x[side_iter],
1997 y + gc_retroflat_offsets8_y[side_iter] );
1998 }
1999
2000 retrotile_get_tile( t, layer, x, y ) = sides_sum / sides_avail;
2001 }
2002 }
2003
2004cleanup:
2005
2006 return retval;
2007}
2008
2009/* === */
2010
2012 struct RETROTILE* t, retroflat_tile_t min_z, retroflat_tile_t max_z,
2013 uint32_t tuning, size_t layer_idx, uint8_t flags, void* data,
2014 retrotile_ani_cb animation_cb, void* animation_cb_data
2015) {
2016 MERROR_RETVAL retval = MERROR_OK;
2017 struct RETROTILE_DATA_BORDER* borders =
2018 (struct RETROTILE_DATA_BORDER*)data;
2019 size_t i = 0,
2020 x = 0,
2021 y = 0,
2022 x_plus_1 = 0,
2023 y_plus_1 = 0,
2024 side = 0;
2025 int16_t ctr_iter = 0,
2026 outside_iter = 0;
2027 struct RETROTILE_LAYER* layer = NULL;
2028
2029 assert( NULL != t );
2030 layer = retrotile_get_layer_p( t, layer_idx );
2031 assert( NULL != layer );
2032
2033 /* Reset tile counter for all defined borders. */
2034 for( i = 0 ; 0 <= borders[i].center ; i++ ) {
2035 borders[i].tiles_changed = 0;
2036 }
2037
2038#if RETROTILE_TRACE_LVL > 0
2039 debug_printf( RETROTILE_TRACE_LVL, "adding borders..." );
2040#endif /* RETROTILE_TRACE_LVL */
2041
2042 for( y = 0 ; t->tiles_h > y ; y++ ) {
2043 for( x = 0 ; t->tiles_w > x ; x++ ) {
2044 i = 0;
2045 while( 0 <= borders[i].center ) {
2046 /* Compare/grab current center tile. */
2047 ctr_iter = retrotile_get_tile( t, layer, x, y );
2048#if RETROTILE_TRACE_LVL > 0
2049 debug_printf( RETROTILE_TRACE_LVL,
2050 "x: " SIZE_T_FMT ", y: " SIZE_T_FMT ", 0x%04x vs 0x%04x",
2051 x, y, ctr_iter, borders[i].center );
2052#endif /* RETROTILE_TRACE_LVL */
2053 if( ctr_iter != borders[i].center ) {
2054 i++;
2055 continue;
2056 }
2057
2058#if RETROTILE_TRACE_LVL > 0
2059 debug_printf( RETROTILE_TRACE_LVL, "comparing sides..." );
2060#endif /* RETROTILE_TRACE_LVL */
2061
2062 /* Zeroth pass: look for stick-outs. */
2063 for( side = 0 ; 8 > side ; side += 2 ) {
2064 if(
2065 x + gc_retroflat_offsets8_x[side] > t->tiles_w ||
2066 y + gc_retroflat_offsets8_y[side] > t->tiles_h
2067 ) {
2068 /* Skip out-of-bounds. */
2069 continue;
2070 }
2071 /* Get the outside tile on this side. */
2072 outside_iter = retrotile_get_tile( t, layer,
2073 x + gc_retroflat_offsets8_x[side],
2074 y + gc_retroflat_offsets8_y[side] );
2075
2076 /* Get the outside tile next two clock-steps from this one.
2077 */
2078 if( side + 4 < 8 ) {
2079 x_plus_1 = x + gc_retroflat_offsets8_x[side + 4];
2080 y_plus_1 = y + gc_retroflat_offsets8_y[side + 4];
2081 } else {
2082 x_plus_1 = x + gc_retroflat_offsets8_x[side - 4];
2083 y_plus_1 = y + gc_retroflat_offsets8_y[side - 4];
2084 }
2085
2086 if(
2087 x_plus_1 < t->tiles_w && y_plus_1 < t->tiles_h &&
2088 outside_iter == borders[i].outside &&
2089 outside_iter == retrotile_get_tile( t, layer,
2090 x_plus_1, y_plus_1 )
2091 ) {
2092 /* This has the outside on two opposing sides, so just
2093 * erase it and use the outside. */
2094 retrotile_get_tile( t, layer, x, y ) =
2095 borders[i].outside;
2096 borders[i].tiles_changed++;
2097 goto tile_done;
2098 }
2099 }
2100
2101
2102 /* First pass: look for corners. */
2103 for( side = 0 ; 8 > side ; side += 2 ) {
2104 if(
2105 x + gc_retroflat_offsets8_x[side] > t->tiles_w ||
2106 y + gc_retroflat_offsets8_y[side] > t->tiles_h
2107 ) {
2108 /* Skip out-of-bounds. */
2109 continue;
2110 }
2111 /* Get the outside tile on this side. */
2112 outside_iter = retrotile_get_tile( t, layer,
2113 x + gc_retroflat_offsets8_x[side],
2114 y + gc_retroflat_offsets8_y[side] );
2115
2116 /* Get the outside tile next two clock-steps from this one.
2117 */
2118 if( side + 2 < 8 ) {
2119 x_plus_1 = x + gc_retroflat_offsets8_x[side + 2];
2120 y_plus_1 = y + gc_retroflat_offsets8_y[side + 2];
2121 } else {
2122 x_plus_1 = x + gc_retroflat_offsets8_x[0];
2123 y_plus_1 = y + gc_retroflat_offsets8_y[0];
2124 }
2125
2126 if(
2127 x_plus_1 < t->tiles_w && y_plus_1 < t->tiles_h &&
2128 outside_iter == borders[i].outside &&
2129 outside_iter == retrotile_get_tile( t, layer,
2130 x_plus_1, y_plus_1 )
2131 ) {
2132 /* This has the outside on two sides, so use a corner. */
2133 retrotile_get_tile( t, layer, x, y ) =
2134 borders[i].mod_to[side + 1 < 8 ? side + 1 : 0];
2135 borders[i].tiles_changed++;
2136 goto tile_done;
2137 }
2138 }
2139
2140 /* Second pass (if first pass fails): look for edges. */
2141 for( side = 0 ; 8 > side ; side += 2 ) {
2142 if(
2143 x + gc_retroflat_offsets8_x[side] > t->tiles_w ||
2144 y + gc_retroflat_offsets8_y[side] > t->tiles_h
2145 ) {
2146 /* Skip out-of-bounds. */
2147 continue;
2148 }
2149 /* Get the outside tile on this side. */
2150 outside_iter = retrotile_get_tile( t, layer,
2151 x + gc_retroflat_offsets8_x[side],
2152 y + gc_retroflat_offsets8_y[side] );
2153
2154 if( outside_iter == borders[i].outside ) {
2155 /* It only matches on this side. */
2156#if RETROTILE_TRACE_LVL > 0
2157 debug_printf( RETROTILE_TRACE_LVL, "replacing..." );
2158#endif /* RETROTILE_TRACE_LVL */
2159 retrotile_get_tile( t, layer, x, y ) =
2160 borders[i].mod_to[side];
2161 borders[i].tiles_changed++;
2162 goto tile_done;
2163 }
2164 }
2165
2166tile_done:
2167 /* Tile replaced or not replaceable. */
2168 break;
2169 }
2170 }
2171 }
2172
2173 return retval;
2174}
2175
2176/* === */
2177
2178struct RETROTILE_LAYER* retrotile_get_layer_p(
2179 struct RETROTILE* tilemap, uint32_t layer_idx
2180) {
2181 struct RETROTILE_LAYER* layer_iter = NULL;
2182 uint8_t* tilemap_buf = (uint8_t*)tilemap;
2183
2184 if( 0 == tilemap->layers_count || layer_idx >= tilemap->layers_count ) {
2185 error_printf( "invalid layer " U32_FMT
2186 " requested (of " U32_FMT ")!",
2187 layer_idx, tilemap->layers_count );
2188 return NULL;
2189 }
2190
2191 /* Advance to first grid. */
2192 tilemap_buf += sizeof( struct RETROTILE );
2193 layer_iter = (struct RETROTILE_LAYER*)tilemap_buf;
2194 while( layer_idx > 0 ) {
2195 tilemap_buf += layer_iter->total_sz;
2196 layer_iter = (struct RETROTILE_LAYER*)tilemap_buf;
2197 layer_idx--;
2198 }
2199
2200 return layer_iter;
2201}
2202
2203/* === */
2204
2205MERROR_RETVAL retrotile_alloc(
2206 MAUG_MHANDLE* p_tilemap_h, size_t w, size_t h, size_t layers_count,
2207 const char* tilemap_name, const char* tileset_name
2208) {
2209 struct RETROTILE_LAYER* layer_iter = NULL;
2210 MERROR_RETVAL retval = MERROR_OK;
2211 size_t tilemap_sz = 0;
2212 struct RETROTILE* tilemap = NULL;
2213 size_t i = 0;
2214
2215 tilemap_sz = sizeof( struct RETROTILE ) +
2216 (layers_count * sizeof( struct RETROTILE_LAYER )) +
2217 (layers_count * (w * h * sizeof( retroflat_tile_t ) ));
2218
2219#if RETROTILE_TRACE_LVL > 0
2220 debug_printf(
2221 RETROTILE_TRACE_LVL, "allocating new tilemap " SIZE_T_FMT "x" SIZE_T_FMT
2222 " tiles, " SIZE_T_FMT " layers (" SIZE_T_FMT " bytes)...",
2223 w, h, layers_count, tilemap_sz );
2224#endif /* RETROTILE_TRACE_LVL */
2225
2226 *p_tilemap_h = maug_malloc( 1, tilemap_sz );
2227 maug_cleanup_if_null_alloc( MAUG_MHANDLE, *p_tilemap_h );
2228
2229 maug_mlock( *p_tilemap_h, tilemap );
2230 maug_cleanup_if_null_alloc( struct RETROTILE*, tilemap );
2231
2232 maug_mzero( tilemap, tilemap_sz );
2233 tilemap->total_sz = tilemap_sz;
2234 tilemap->layers_count = layers_count;
2235 tilemap->tiles_w = w;
2236 tilemap->tiles_h = h;
2238 tilemap->sz = sizeof( struct RETROTILE );
2239
2240 maug_strncpy( tilemap->name, tilemap_name, RETROTILE_NAME_SZ_MAX );
2241
2242 maug_strncpy( tilemap->tileset, tileset_name, RETROTILE_NAME_SZ_MAX );
2243
2244 for( i = 0 ; layers_count > i ; i++ ) {
2245 layer_iter = retrotile_get_layer_p( tilemap, i );
2246 assert( NULL != layer_iter );
2247 layer_iter->total_sz = sizeof( struct RETROTILE_LAYER ) +
2248 (w * h * sizeof( retroflat_tile_t ));
2249 maug_cleanup_if_not_ok();
2250 layer_iter->sz = sizeof( struct RETROTILE_LAYER );
2251 }
2252
2253cleanup:
2254
2255 if( NULL != tilemap ) {
2256 maug_munlock( *p_tilemap_h, tilemap );
2257 }
2258
2259 return retval;
2260}
2261
2262/* === */
2263
2264void retrotile_format_asset_path(
2265 retroflat_asset_path path_out, const char* afile,
2266 struct RETROTILE_PARSER* parser
2267) {
2268 /* Load the portrait. */
2269 maug_mzero( path_out, MAUG_PATH_SZ_MAX + 1 );
2270 maug_snprintf( path_out, MAUG_PATH_SZ_MAX, "%s/%s",
2271 parser->dirname, afile );
2272}
2273
2274/* === */
2275
2276MERROR_RETVAL retrotile_clear_refresh( retroflat_pxxy_t y_max ) {
2277 MERROR_RETVAL retval = MERROR_OK;
2278#ifndef RETROFLAT_NO_VIEWPORT_REFRESH
2279 int16_t x = 0,
2280 y = 0;
2281
2282#if RETROTILE_TRACE_LVL > 0
2283 debug_printf( RETROTILE_TRACE_LVL,
2284 "clearing " SIZE_T_FMT " vertical viewport pixels (" SIZE_T_FMT
2285 " rows)...",
2286 y_max, y_max / RETROFLAT_TILE_H );
2287#endif /* RETROTILE_TRACE_LVL */
2288
2289 retroflat_viewport_lock_refresh();
2290 for( y = 0 ; y_max > y ; y += RETROFLAT_TILE_H ) {
2291 for( x = 0 ; retroflat_viewport_screen_w() > x ; x += RETROFLAT_TILE_W ) {
2292 retroflat_viewport_set_refresh( x, y, -1 );
2293 }
2294 }
2295
2296cleanup:
2297
2298 retroflat_viewport_unlock_refresh();
2299
2300#endif /* !RETROFLAT_NO_VIEWPORT_REFRESH */
2301
2302 return retval;
2303}
2304
2305/* === */
2306
2307MERROR_RETVAL retrotile_topdown_draw(
2308 struct RETROFLAT_BITMAP* target,
2309 struct RETROTILE* t, struct MDATA_VECTOR* t_defs
2310) {
2311 int16_t x = 0,
2312 y = 0,
2313 x_tile = 0,
2314 y_tile = 0;
2315 retroflat_tile_t tile_id = 0;
2316 struct RETROTILE_LAYER* layer = NULL;
2317 struct RETROTILE_TILE_DEF* t_def = NULL;
2318 MERROR_RETVAL retval = MERROR_OK;
2319
2320 layer = retrotile_get_layer_p( t, 0 );
2321
2322 mdata_vector_lock( t_defs );
2323 /* TODO: Rework this so it uses viewport tile indexes and then calculates
2324 * screen pixel X/Y from those? For performance?
2325 */
2326 for(
2327 y = ((retroflat_viewport_world_y() >>
2328 RETROFLAT_TILE_H_BITS) << RETROFLAT_TILE_H_BITS) ;
2329 y < (int)retroflat_viewport_world_y() +
2330 (int)retroflat_viewport_screen_h() ;
2331 y += RETROFLAT_TILE_H
2332 ) {
2333 for(
2334 x = ((retroflat_viewport_world_x() >>
2335 RETROFLAT_TILE_W_BITS) << RETROFLAT_TILE_W_BITS) ;
2336 x < (int)retroflat_viewport_world_x() +
2337 (int)retroflat_viewport_screen_w() ;
2338 x += RETROFLAT_TILE_W
2339 ) {
2340 /* Limit to tiles that exist in the world. */
2341 if(
2342 -1 > x || -1 > y ||
2343 (int)retroflat_viewport_world_w() <= x ||
2344 (int)retroflat_viewport_world_h() <= y
2345 ) {
2346 continue;
2347 }
2348
2349 /* Divide by tile width (16), or shift by 2^4. */
2350 x_tile = x >> RETROFLAT_TILE_W_BITS;
2351 y_tile = y >> RETROFLAT_TILE_H_BITS;
2352
2353 tile_id = retrotile_get_tile( t, layer, x_tile, y_tile );
2354 t_def = mdata_vector_get(
2355 t_defs, tile_id - t->tileset_fgid, struct RETROTILE_TILE_DEF );
2356 if( NULL == t_def ) {
2357 error_printf(
2358 "invalid tile ID: %d (- " SIZE_T_FMT " = " SIZE_T_FMT ")",
2359 tile_id, t->tileset_fgid, tile_id - t->tileset_fgid );
2360 continue;
2361 }
2362 assert( NULL != t_def );
2363
2364#ifndef RETROFLAT_NO_VIEWPORT_REFRESH
2365 /* Check tile refresh buffer. */
2366 retroflat_viewport_lock_refresh();
2367 if( !retroflat_viewport_tile_is_stale(
2368 x - retroflat_viewport_world_x(),
2369 y - retroflat_viewport_world_y(), tile_id
2370 ) ) {
2371 retroflat_viewport_unlock_refresh();
2372 continue;
2373 }
2374 /* Noisy! */
2375 /*
2376 debug_printf( RETROTILE_TRACE_LVL, "redrawing tile: %u, %u",
2377 x - retroflat_viewport_world_x(),
2378 y - retroflat_viewport_world_y() );
2379 */
2380 retroflat_viewport_set_refresh(
2381 x - retroflat_viewport_world_x(),
2382 y - retroflat_viewport_world_y(), tile_id );
2383 retroflat_viewport_unlock_refresh();
2384#endif /* !RETROFLAT_NO_VIEWPORT_REFRESH */
2385
2386#ifdef RETROGXC_PRESENT
2387 retrogxc_blit_bitmap( target, t_def->image_cache_id,
2388 t_def->x, t_def->y,
2391 RETROFLAT_TILE_W, RETROFLAT_TILE_H,
2392 retroflat_instance_tile( tile_id ) );
2393#else
2394 retroflat_blit_bitmap( target, &(t_def->image),
2395 t_def->x, t_def->y,
2398 RETROFLAT_TILE_W, RETROFLAT_TILE_H,
2399 retroflat_instance_tile( tile_id ) );
2400#endif /* RETROGXC_PRESENT */
2401 }
2402 }
2403
2404cleanup:
2405
2406 mdata_vector_unlock( t_defs );
2407
2408 return retval;
2409}
2410
2411#else
2412
2413/* This is defined externally so custom token callbacks can reference it. */
2414
2415# define RETROTILE_PARSER_MSTATE_TABLE_CONST( name, idx, tokn, parent, m ) \
2416 extern MAUG_CONST uint8_t SEG_MCONST name;
2417
2418RETROTILE_PARSER_MSTATE_TABLE( RETROTILE_PARSER_MSTATE_TABLE_CONST )
2419
2420# define RETROTILE_CLASS_TABLE_CONSTS( A, a, i ) \
2421 extern MAUG_CONST uint8_t SEG_MCONST RETROTILE_CLASS_ ## A;
2422
2423RETROTILE_CLASS_TABLE( RETROTILE_CLASS_TABLE_CONSTS )
2424
2425
2426#endif /* RETROTIL_C */
2427 /* retrotile */
2429 /* maug_retroflt */
2431
2432#endif /* !RETROTIL_H */
2433
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
#define MAUG_PATH_SZ_MAX
Maximum size allocated for asset paths.
Definition mfile.h:35
MERROR_RETVAL mfile_open_read(const char *filename, mfile_t *p_file)
Open a file and read it into memory or memory-map it.
#define MERROR_PREEMPT
Indicates MLISP_AST_NODE can be executed again on next step iter pass.
Definition merror.h:58
char retroflat_asset_path[MAUG_PATH_SZ_MAX+1]
Path/name used to load an asset from disk.
Definition mfile.h:129
MERROR_RETVAL retroflat_blit_bitmap(struct RETROFLAT_BITMAP *target, struct RETROFLAT_BITMAP *src, size_t s_x, size_t s_y, int16_t d_x, int16_t d_y, size_t w, size_t h, int16_t instance)
Blit the contents of a ::RETROFLAT_BITMAP onto another ::RETROFLAT_BITMAP.
#define retroflat_instance_tile(instance)
Declare that a given instance ID is for a tile, rather than a sprite.
Definition retroflt.h:575
#define retroflat_viewport_screen_y(world_y)
Return the screenspace Y coordinate at which something at the given world coordinate should be drawn.
Definition retroflt.h:1526
#define retroflat_viewport_screen_x(world_x)
Return the screenspace X coordinate at which something at the given world coordinate should be drawn.
Definition retroflt.h:1519
size_t retroflat_pxxy_t
Type used for surface pixel coordinates.
Definition retroflt.h:870
#define RETROTILE_DS_FLAG_INIT_DATA
Flag for retrotile_gen_diamond_square_iter() indicating that passed RETROTILE_DATA_DS object should b...
Definition retrotil.h:159
#define RETROTILE_PROP_TYPE_FILE
Value for RETROTILE_PARSER::last_prop_type indicating file path.
Definition retrotil.h:141
#define RETROTILE_PROP_TYPE_STRING
Value for RETROTILE_PARSER::last_prop_type indicating string.
Definition retrotil.h:135
#define RETROTILE_PROP_TYPE_INT
Value for RETROTILE_PARSER::last_prop_type indicating integer.
Definition retrotil.h:147
#define RETROTILE_PROP_TYPE_OTHER
Value for RETROTILE_PARSER::last_prop_type indicating other type.
Definition retrotil.h:129
MERROR_RETVAL retrotile_gen_smooth_iter(struct RETROTILE *t, retroflat_tile_t min_z, retroflat_tile_t max_z, uint32_t tuning, size_t layer_idx, uint8_t flags, void *data, retrotile_ani_cb animation_cb, void *animation_cb_data)
Average the values in adjacent tiles over an already-generated tilemap.
MERROR_RETVAL retrotile_gen_borders_iter(struct RETROTILE *t, retroflat_tile_t min_z, retroflat_tile_t max_z, uint32_t tuning, size_t layer_idx, uint8_t flags, void *data, retrotile_ani_cb animation_cb, void *animation_cb_data)
Given a list of RETROTILE_DATA_BORDER structs, this will search for occurrences of RETROTILE_DATA_BOR...
MERROR_RETVAL retrotile_gen_diamond_square_iter(struct RETROTILE *t, retroflat_tile_t min_z, retroflat_tile_t max_z, uint32_t tuning, size_t layer_idx, uint8_t flags, void *data, retrotile_ani_cb animation_cb, void *animation_cb_data)
Generate tilemap terrain using diamond square algorithm.
MERROR_RETVAL retrotile_gen_voronoi_iter(struct RETROTILE *t, retroflat_tile_t min_z, retroflat_tile_t max_z, uint32_t tuning, size_t layer_idx, uint8_t flags, void *data, retrotile_ani_cb animation_cb, void *animation_cb_data)
Generate tilemap terrain using voronoi graph.
int retrotile_parse_prop_type(const char *token, size_t token_sz)
Convert a Tiled "type" field to an integer suitable for use with RETROTILE_PARSER::last_prop_type.
MERROR_RETVAL retrotile_parse_json_file(const char *dirname, const char *filename, MAUG_MHANDLE *p_tilemap_h, struct MDATA_VECTOR *p_tile_defs, mparser_wait_cb_t wait_cb, void *wait_data, mparser_parse_token_cb token_cb, void *token_cb_data, uint8_t passes, uint8_t flags)
Parse the JSON file at the given path into a heap-allocated tilemap with a RETROTILE struct header.
mfix_t retrotile_static_rotation_from_dir(const char *dir)
Convert a less-or-equal-to-two-character string to a direction in degrees.
#define RETROTILE_TILE_SCALE_DEFAULT
Default value for RETROTILE::tile_scale.
Definition retrotil.h:37
#define RETROTILE_PROP_NAME_SZ_MAX
Maximum number of chars in a parsed property name.
Definition retrotil.h:32
#define RETROTILE_PARSER_MODE_DEFS
Value for RETROTILE_PARSER::mode indicating the parser is currently parsing tile definitions.
Definition retrotil.h:80
#define RETROTILE_TRACE_LVL
If defined, bring debug printf statements up to this level.
Definition retrotil.h:42
#define RETROTILE_PARSER_MODE_MAP
Value for RETROTILE_PARSER::mode indicating the parser is currently parsing a tilemap.
Definition retrotil.h:73
int16_t retroflat_tile_t
Value for an individual tile in a RETROTILE_LAYER.
Definition retroflt.h:19
#define RETROTILE_NAME_SZ_MAX
Maximum number of chars in a RETROTILE::name.
Definition retrotil.h:27
#define RETROTILE_PARSER_FLAG_LITERAL_PATHS
Flag for RETROTILE_PARSER::flags indicating to use literal image asset paths.
Definition retrotil.h:65
A vector of uniformly-sized objects, stored contiguously.
Definition mdata.h:93
This is not currently used for anything, but is provided as a a convenience for game logic.
Definition retrotil.h:210
Definition retrotil.h:265
retroflat_tile_t mod_to[8]
If the center and outside match, use this mod-to.
Definition retrotil.h:270
Internal data structure used by retrotile_gen_diamond_square_iter().
Definition retrotil.h:248
int16_t sect_y
Starting Y of subsector in a given iteration.
Definition retrotil.h:252
int16_t sect_w
Width of subsector in a given iteration.
Definition retrotil.h:254
int16_t sect_w_half
Half of the width of subsector in a given iteration.
Definition retrotil.h:258
int16_t sect_x
Starting X of subsector in a given iteration.
Definition retrotil.h:250
int16_t sect_h
Height of subsector in a given iteration.
Definition retrotil.h:256
int16_t sect_h_half
Half of the height of subsector in a given iteration.
Definition retrotil.h:260
Definition retrotil.h:198
size_t total_sz
Size of the layer in bytes (including this struct header).
Definition retrotil.h:202
size_t sz
Size of this struct (useful for serializing).
Definition retrotil.h:200
Definition retrotil.h:312
mparser_parse_token_cb custom_token_cb
Callback to parse engine-specific custom tokens from the tilemap JSON. Should return MERROR_PREEMPT i...
Definition retrotil.h:346
char tilemap_name[RETROTILE_NAME_SZ_MAX+1]
The name to give to the new tilemap.
Definition retrotil.h:329
char last_prop_name[RETROTILE_PROP_NAME_SZ_MAX+1]
The name of the last property key/value pair parsed.
Definition retrotil.h:325
uint8_t mode
Value indicating the current type of object being parsed into.
Definition retrotil.h:319
size_t tileset_id_cur
Highest tileset ID on first pass and next ID to be assigned on second.
Definition retrotil.h:336
Definition retrotil.h:166
mfix_t static_rotation
Field indicating how many degrees the tile should always be rotated before drawin on-screen....
Definition retrotil.h:180
size_t sz
Size of this struct (useful for serializing).
Definition retrotil.h:168
int8_t no_serial
Dummy field; do not serialize fields after this!
Definition retrotil.h:184
A struct representing a tilemap.
Definition retrotil.h:222
size_t tiles_h
Height of all layers of the tilemap in tiles.
Definition retrotil.h:234
uint32_t total_sz
Size of the tilemap in bytes (including this struct header).
Definition retrotil.h:228
size_t tileset_fgid
First GID in the accompanying tileset.
Definition retrotil.h:232
float tile_scale
Amount by which to scale tiles (convenience property).
Definition retrotil.h:241
size_t tiles_w
Width of all layers of the tilemap in tiles.
Definition retrotil.h:236
uint32_t layers_count
Number of tile layers in this tilemap.
Definition retrotil.h:230
size_t sz
Size of this struct (useful for serializing).
Definition retrotil.h:224