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