maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
retroflt.h
Go to the documentation of this file.
1
2#ifndef RETROFLT_H
3#define RETROFLT_H
4
5#ifdef RETROFLAT_OPENGL
6# define RETROFLAT_BMP_TEX
7#endif /* RETROFLAT_OPENGL */
8
13
19typedef int16_t retroflat_tile_t;
20
22
42
163
277
278/* === Generic Includes and Defines === */
279
280#ifndef RETROFLAT_BITMAP_TRACE_LVL
281# define RETROFLAT_BITMAP_TRACE_LVL 0
282#endif /* !RETROFLAT_BITMAP_TRACE_LVL */
283
284#ifndef RETROINPUT_TRACE_LVL
285# define RETROINPUT_TRACE_LVL 0
286#endif /* !RETROINPUT_TRACE_LVL */
287
288#include <stdarg.h>
289
290#include <marge.h>
291
296
307#define RETROFLAT_COLOR_TABLE( f ) \
308 f( 0, black, BLACK, 0, 0, 0, BLACK, BLACK ) \
309 f( 1, darkblue, DARKBLUE, 0, 0, 170, CYAN, BLACK ) \
310 f( 2, darkgreen, DARKGREEN, 0, 170, 0, CYAN, BLACK ) \
311 f( 3, teal, TEAL, 0, 170, 170, CYAN, CYAN ) \
312 f( 4, darkred, DARKRED, 170, 0, 0, MAGENTA, BLACK ) \
313 f( 5, violet, VIOLET, 170, 0, 170, MAGENTA, BLACK ) \
314 f( 6, brown, BROWN, 170, 85, 0, CYAN, MAGENTA ) \
315 f( 7, gray, GRAY, 170, 170, 170, WHITE, BLACK ) \
316 f( 8, darkgray, DARKGRAY, 85, 85, 85, WHITE, BLACK ) \
317 f( 9, blue, BLUE, 85, 85, 255, CYAN, WHITE ) \
318 f( 10, green, GREEN, 85, 255, 85, CYAN, CYAN ) \
319 f( 11, cyan, CYAN, 85, 255, 255, CYAN, CYAN ) \
320 f( 12, red, RED, 255, 85, 85, MAGENTA, WHITE ) \
321 f( 13, magenta, MAGENTA, 255, 85, 255, MAGENTA, MAGENTA ) \
322 f( 14, yellow, YELLOW, 255, 255, 85, CYAN, MAGENTA ) \
323 f( 15, white, WHITE, 255, 255, 255, WHITE, WHITE )
324
326typedef int8_t RETROFLAT_COLOR;
327
328# define RETROFLAT_COLOR_NULL (-1)
329
330# define RETROFLAT_COLORS_CT 16
331
333
334/* TODO: Mouse is broken under DOS/Allegro. */
335#if defined( RETROFLAT_OS_UNIX ) || defined( RETROFLAT_OS_WIN )
336#define RETROFLAT_MOUSE
337#endif /* RETROFLAT_OS_WIN || RETROFLAT_OS_WIN */
338
344
346#define RETROFLAT_OK 0x00
347#define RETROFLAT_ERROR_ENGINE 0x01
348#define RETROFLAT_ERROR_GRAPHICS 0x02
349#define RETROFLAT_ERROR_MOUSE 0x04
350
355#define RETROFLAT_ERROR_BITMAP 0x08
356#define RETROFLAT_ERROR_TIMER 0x0f
357 /* maug_retroflt_retval */
359
369
374#define RETROFLAT_DRAW_FLAG_FILL 0x01
375
380#define RETROFLAT_BITMAP_FLAG_OPAQUE 0x01
381
385#define RETROFLAT_BITMAP_FLAG_LITERAL_PATH 0x02
386
393#define RETROFLAT_FONT_FLAG_ALL_CAPS 0x02
394
401#define RETROFLAT_BITMAP_FLAG_SCREEN_BUFFER 0x80
402 /* maug_retroflt_drawing */
404
411#define RETROFLAT_STATE_FLAG_RUNNING 0x01
412
418#define RETROFLAT_STATE_FLAG_UNLOCK_FPS 0x02
419
425#define RETROFLAT_STATE_FLAG_KEY_REPEAT 0x04
426
432#define RETROFLAT_STATE_FLAG_SCREENSAVER 0x08
433
438#define RETROFLAT_STATE_FLAG_WAIT_FOR_FPS 0x20
439
444#define RETROFLAT_STATE_FLAG_USE_GXC 0x40
445
450#define RETROFLAT_STATE_FLAG_QUIT_REQUESTED 0x80
451
458
462#define RETROFLAT_MSG_FLAG_TYPE_MASK 0x07
463
468#define RETROFLAT_MSG_FLAG_ERROR 0x01
469
475#define RETROFLAT_MSG_FLAG_INFO 0x02
476
482#define RETROFLAT_MSG_FLAG_WARNING 0x04
483 /* maug_retroflt_msg_api */
485
486struct RETROFLAT_STATE;
487
499
507#define RETROFLAT_VDP_FLAG_PXLOCK 0x01
508
521
522#define retroflat_vdp_available() (NULL != g_retroflat_state->vdp_exe)
523 /* maug_retroflt_vdp */
525
530
531typedef MERROR_RETVAL (*retroflat_proc_resize_t)(
532 uint16_t new_w, uint16_t new_h, void* data );
533
534#define RETROFLAT_FOCUS_FLAG_ACTIVE 0x01
535
536#define RETROFLAT_FOCUS_FLAG_VISIBLE 0x02
537
538typedef MERROR_RETVAL (*retroflat_proc_focus_t)( uint8_t flags, void* data );
539
544typedef MERROR_RETVAL (*retroflat_proc_quit_t)( void* data );
545 /* maug_retroflt_platform */
547
552
553#define RETROSND_ARGS_FLAG_LIST_DEVS 0x01
554
556
582
586#define RETROFLAT_BITMAP_FLAG_LOCK 0x08
587
588#define RETROFLAT_BITMAP_FLAG_SCREEN_LOCK 0x02
589
590#define RETROFLAT_BITMAP_FLAG_RO 0x04
591
597#define RETROFLAT_INSTANCE_NULL (0)
598
603#define retroflat_instance_tile( instance ) \
604 (instance * -1)
605
610#ifndef RETROFLAT_BITMAP_EXT
611# define RETROFLAT_BITMAP_EXT "bmp"
612#endif /* !RETROFLAT_BITMAP_EXT */
613
614#ifndef RETROFLAT_OPENGL_BPP
615# define RETROFLAT_OPENGL_BPP 32
616#endif /* !RETROFLAT_OPENGL_BPP */
617
618#ifndef RETROFLAT_TILE_W
619# define RETROFLAT_TILE_W 16
620#endif /* !RETROFLAT_TILE_W */
621
622#ifndef RETROFLAT_TILE_W_BITS
623# define RETROFLAT_TILE_W_BITS 4
624#endif /* !RETROFLAT_TILE_W_BITS */
625
626#ifndef RETROFLAT_TILE_H
627# define RETROFLAT_TILE_H 16
628#endif /* !RETROFLAT_TILE_H */
629
630#ifndef RETROFLAT_TILE_H_BITS
631# define RETROFLAT_TILE_H_BITS 4
632#endif /* !RETROFLAT_TILE_H_BITS */
633
634/* Transparency background color: black by default, to match Allegro. */
635#ifndef RETROFLAT_TXP_R
641# define RETROFLAT_TXP_R 0x00
642#endif /* !RETROFLAT_TXP_R */
643
644#ifndef RETROFLAT_TXP_G
650# define RETROFLAT_TXP_G 0x00
651#endif /* !RETROFLAT_TXP_G */
652
653#ifndef RETROFLAT_TXP_B
659# define RETROFLAT_TXP_B 0x00
660#endif /* !RETROFLAT_TXP_B */
661
662#ifndef RETROFLAT_TXP_PAL_IDX
663# define RETROFLAT_TXP_PAL_IDX 0
664#endif /* !RETROFLAT_TXP_PAL_IDX */
665 /* maug_retroflt_bitmap */
667
668#ifndef RETROFLAT_DEFAULT_SCREEN_W
669# define RETROFLAT_DEFAULT_SCREEN_W 320
670#endif /* !RETROFLAT_DEFAULT_SCREEN_W */
671
672#ifndef RETROFLAT_DEFAULT_SCREEN_H
673# define RETROFLAT_DEFAULT_SCREEN_H 200
674#endif /* !RETROFLAT_DEFAULT_SCREEN_H */
675
676#ifndef RETROFLAT_DEFAULT_SCREEN_SCALE
677# define RETROFLAT_DEFAULT_SCREEN_SCALE 1
678#endif /* !RETROFLAT_DEFAULT_SCREEN_SCALE */
679
680#define retroflat_on_resize( w, h ) \
681 g_retroflat_state->screen_w = (w); \
682 g_retroflat_state->screen_h = (h);
683
688
689#ifndef RETROFLAT_LINE_THICKNESS
694# define RETROFLAT_LINE_THICKNESS 1
695#endif /* !RETROFLAT_LINE_THICKNESS */
696
697#define RETROFLAT_PI 3.14159
698 /* maug_retroflt_drawing */
700
705
706#ifndef RETROFLAT_FPS
711# define RETROFLAT_FPS 30
712#endif /* !RETROFLAT_FPS */
713
714#define retroflat_fps_next() (1000 / RETROFLAT_FPS)
715
716#ifndef RETROFLAT_WINDOW_CLASS
721# define RETROFLAT_WINDOW_CLASS "RetroFlatWindowClass"
722#endif /* !RETROFLAT_WINDOW_CLASS */
723
724#ifndef RETROFLAT_WIN_FRAME_TIMER_ID
729# define RETROFLAT_WIN_FRAME_TIMER_ID 6001
730#endif /* !RETROFLAT_WIN_FRAME_TIMER_ID */
731
732#ifndef RETROFLAT_WIN_LOOP_TIMER_ID
737# define RETROFLAT_WIN_LOOP_TIMER_ID 6002
738#endif /* !RETROFLAT_WIN_LOOP_TIMER_ID */
739
740#ifndef RETROFLAT_MSG_MAX
745# define RETROFLAT_MSG_MAX 4096
746#endif /* !RETROFLAT_MSG_MAX */
747
748#ifndef RETROFLAT_TITLE_MAX
749# define RETROFLAT_TITLE_MAX 255
750#endif /* !RETROFLAT_TITLE_MAX */
751
752#ifndef RETROFLAT_VDP_ARGS_SZ_MAX
756# define RETROFLAT_VDP_ARGS_SZ_MAX 255
757#endif /* !RETROFLAT_VDP_ARGS_SZ_MAX */
758
759#if defined( RETROFLAT_API_SDL2 )
760# if !defined( NO_RETROFLAT_RESIZABLE )
761# define RETROFLAT_WIN_FLAGS SDL_WINDOW_RESIZABLE
762# else
763# define RETROFLAT_WIN_FLAGS 0
764# endif /* !NO_RETROFLAT_RESIZABLE */
765#endif /* RETROFLAT_API_SDL2 */
766
767#if defined( RETROFLAT_API_SDL1 )
768# define RETROFLAT_SDL_CC_FLAGS (SDL_RLEACCEL | SDL_SRCCOLORKEY)
769#elif defined( RETROFLAT_API_SDL2 )
770# define RETROFLAT_SDL_CC_FLAGS (SDL_TRUE)
771#endif /* RETROFLAT_API_SDL1 || RETROFLAT_API_SDL2 */
772
773#ifdef RETROFLAT_OS_DOS
774# define RETROFLAT_PATH_SEP '\\'
775#else
777# define RETROFLAT_PATH_SEP '/'
778#endif /* RETROFLAT_OS_DOS */
779
780#ifndef RETROFLAT_COLORS_CT_MAX
781# define RETROFLAT_COLORS_CT_MAX 256
782#endif /* !RETROFLAT_COLORS_CT_MAX */
783
784#ifndef RETROFLAT_TIMER_CT_MAX
785# define RETROFLAT_TIMER_CT_MAX 10
786#endif /* !RETROFLAT_TIMER_CT_MAX */
787 /* maug_retroflt_compiling */
789
790#define retroflat_wait_for_frame() \
791 (g_retroflat_state->retroflat_flags |= RETROFLAT_STATE_FLAG_WAIT_FOR_FPS)
792
793#define retroflat_is_waiting_for_frame() \
794 (RETROFLAT_STATE_FLAG_WAIT_FOR_FPS == \
795 (g_retroflat_state->retroflat_flags & RETROFLAT_STATE_FLAG_WAIT_FOR_FPS))
796
800typedef void (*retroflat_loop_iter)(void* data);
801
807
811#define retroflat_buffer_bksp( buffer, buffer_cur, buffer_sz ) \
812 if( 0 < buffer_cur ) { \
813 if( buffer_cur < buffer_sz ) { \
814 memmove( \
815 &(buffer[(buffer_cur) - 1]), \
816 &(buffer[buffer_cur]), \
817 (buffer_sz) - (buffer_cur) ); \
818 } \
819 buffer_cur--; \
820 buffer_sz--; \
821 buffer[buffer_sz] = '\0'; \
822 }
823
827#define retroflat_buffer_insert( c, buffer, buffer_cur, buffer_sz, buffer_mx ) \
828 if( buffer_sz + 1 < buffer_mx ) { \
829 if( buffer_cur < buffer_sz ) { \
830 memmove( \
831 &(buffer[(buffer_cur) + 1]), \
832 &(buffer[buffer_cur]), \
833 (buffer_sz) - (buffer_cur) ); \
834 } \
835 buffer[buffer_cur] = c; \
836 buffer_cur++; \
837 buffer_sz++; \
838 buffer[buffer_sz] = '\0'; \
839 }
840
841#define RETROFLAT_INPUT_MOD_SHIFT 0x01
842
843#define RETROFLAT_INPUT_MOD_ALT 0x02
844
845#define RETROFLAT_INPUT_MOD_CTRL 0x04
846
847#define RETROFLAT_INPUT_FORCE_UPPER 0x08
848
861 uint8_t key_flags;
862};
863 /* maug_retroflt_input */
865
872
873typedef int8_t retroflat_dir4_t;
874
875typedef int8_t retroflat_dir8_t;
876
877#define RETROFLAT_DIR4_NONE (-1)
878#define RETROFLAT_DIR4_NORTH 0
879#define RETROFLAT_DIR4_EAST 1
880#define RETROFLAT_DIR4_SOUTH 2
881#define RETROFLAT_DIR4_WEST 3
882
883#define RETROFLAT_DIR8_NONE (-1)
884#define RETROFLAT_DIR8_NORTH 0
885#define RETROFLAT_DIR8_EAST 2
886#define RETROFLAT_DIR8_SOUTH 4
887#define RETROFLAT_DIR8_WEST 6
888
889#define retroflat_dir4_rotate_cw( dir ) \
890 ((dir + 1) % 4)
891
892#define retroflat_dir8_reverse( dir ) \
893 ((dir + 4) % 8)
894
895#define retroflat_dir8_bounce( dir ) \
896 ((dir + 2) % 8)
897 /* maug_retroflt_dir */
899
906typedef int16_t retroflat_pxxy_t;
907
908#define PXXY_FMT "%d"
909
910#define PXXY_MAX INT16_MAX
911
912struct RETROFLAT_ARGS;
913
914#ifndef RETRO2D_TRACE_LVL
915# define RETRO2D_TRACE_LVL 0
916#endif /* !RETRO2D_TRACE_LVL */
917
918#ifndef RETRO2D_DRAW_TRACE_LVL
919# define RETRO2D_DRAW_TRACE_LVL 0
920#endif /* !RETRO2D_DRAW_TRACE_LVL */
921
922#ifndef RETRO2D_LOCK_TRACE_LVL
923# define RETRO2D_LOCK_TRACE_LVL 0
924#endif /* !RETRO2D_LOCK_TRACE_LVL */
925
926#ifndef RETROFLAT_NO_SOUND
927
955
956#ifndef RETROSND_TRACE_LVL
957# define RETROSND_TRACE_LVL 0
958#endif /* !RETROSND_TRACE_LVL */
959
960#ifndef RETROSND_REG_TRACE_LVL
961# define RETROSND_REG_TRACE_LVL 0
962#endif /* !RETROSND_REG_TRACE_LVL */
963
969
974#define RETROSND_FLAG_INIT 0x01
975 /* maug_retrosnd_flags */
977
978#define RETROSND_VOICE_BREATH 122
979
980#define RETROSND_VOICE_SEASHORE 123
981
982#define RETROSND_VOICE_BIRD_TWEET 124
983
984#define RETROSND_VOICE_PHONE_RING 125
985
986#define RETROSND_VOICE_HELICOPTER 126
987
988#define RETROSND_VOICE_APPLAUSE 127
989
994#define RETROSND_VOICE_GUNSHOT 128
995
996#define RETROSND_CHANNEL_CT 8
997
1007
1011void retrosnd_set_sf_bank( const char* filename_in );
1012
1013void retrosnd_midi_set_voice( uint8_t channel, uint8_t voice );
1014
1015void retrosnd_midi_set_control( uint8_t channel, uint8_t key, uint8_t val );
1016
1017void retrosnd_midi_note_on( uint8_t channel, uint8_t pitch, uint8_t vel );
1018
1019void retrosnd_midi_note_off( uint8_t channel, uint8_t pitch, uint8_t vel );
1020
1021MERROR_RETVAL retrosnd_midi_play_smf( const char* filename );
1022
1023uint8_t retrosnd_midi_is_playing_smf();
1024
1025void retrosnd_shutdown();
1026 /* maug_retrosnd */
1028
1029#endif /* !RETROFLAT_NO_SOUND */
1030
1031/* === Platform-specific APIs === */
1032
1033/* The first call to these headers should just establish definitions (macros, defines, prototypes,
1034 * typedefs, etc). The later call below should then define function bodies.
1035 */
1036#ifndef RETROFLAT_NO_SOUND
1037# include <retapis.h>
1038#endif /* !RETROFLAT_NO_SOUND */
1039#include <retapii.h>
1040
1041/* === End platform-specific APIs === */
1042
1047
1048# if defined( RETROFLAT_NO_KEYBOARD )
1049# define retroflat_case_key( key, pad ) case pad:
1050# define retroflat_or_key( input, key, pad ) ((input) == (pad))
1051# elif defined( RETROFLAT_NO_PAD )
1052# define retroflat_case_key( key, pad ) case key:
1053# define retroflat_or_key( input, key, pad ) ((input) == (key))
1054# else
1062# define retroflat_case_key( key, pad ) case pad: case key:
1063# define retroflat_or_key( input, key, pad ) \
1064 (((input) == (pad)) || ((input) == (key)))
1065# endif
1066 /* maug_retroflt_input */
1068
1069/* === OS-Specific Includes and Defines === */
1070
1071#if defined( RETROFLAT_OS_WIN ) && !defined( MAUG_WINDOWS_H )
1072# include <windows.h>
1073# define MAUG_WINDOWS_H
1074#endif /* !MAUG_WINDOWS_H */
1075
1076#if defined( RETROFLAT_BMP_TEX ) || defined( DOCUMENTATION )
1077
1079 uint8_t flags;
1080 MAUG_MHANDLE bytes_h;
1081 uint8_t* bytes;
1082 uint32_t bpp;
1083 uint32_t sz;
1084 uint8_t* px;
1085 uint32_t id;
1086 size_t w;
1087 size_t h;
1088};
1089
1090#endif /* RETROFLAT_BMP_TEX */
1091
1092/* TODO: Migrate all platform-specific parts below to retapid.h. */
1093#include <retapid.h>
1094
1095#ifndef retroflat_system_task
1101# define retroflat_system_task()
1102#endif /* !retroflat_system_task */
1103
1104typedef maug_ms_t retroflat_ms_t;
1105
1106typedef void (*retroflat_timer_cb_t)( retroflat_ms_t time, void* data );
1107
1108#include "retrom2d.h"
1109
1110/* === Structures === */
1111
1112/* TODO: Break the args into API-specific headers. */
1113
1116 uint8_t flags;
1121 char* title;
1144 int screen_scale;
1152 int joystick_id;
1153 struct RETROFLAT_PLATFORM_ARGS platform;
1154# ifndef RETROFLAT_NO_SOUND
1155 struct RETROFLAT_SOUND_ARGS sound;
1156# endif /* !RETROFLAT_NO_SOUND */
1157};
1158
1169
1270
1271# define retroflat_screen_colors() (g_retroflat_state->screen_colors)
1272
1273#ifndef DOCUMENTATION
1274
1275# define retroflat_viewport_world_x_generic() \
1276 (g_retroflat_state->viewport.world_x)
1277
1278# define retroflat_viewport_world_y_generic() \
1279 (g_retroflat_state->viewport.world_y)
1280
1281# define retroflat_viewport_world_tile_x_generic() \
1282 (g_retroflat_state->viewport.world_tile_x)
1283
1284# define retroflat_viewport_world_tile_y_generic() \
1285 (g_retroflat_state->viewport.world_tile_y)
1286
1287# define retroflat_viewport_world_w_generic() \
1288 (g_retroflat_state->viewport.world_w)
1289
1290# define retroflat_viewport_world_h_generic() \
1291 (g_retroflat_state->viewport.world_h)
1292
1293# define retroflat_viewport_screen_tile_w_generic() \
1294 (g_retroflat_state->viewport.screen_tile_w)
1295
1296# define retroflat_viewport_screen_tile_h_generic() \
1297 (g_retroflat_state->viewport.screen_tile_h)
1298
1299# define retroflat_viewport_screen_w_generic() \
1300 (g_retroflat_state->viewport.screen_w)
1301
1302# define retroflat_viewport_screen_h_generic() \
1303 (g_retroflat_state->viewport.screen_h)
1304
1305# define retroflat_viewport_screen_w_remainder_generic() \
1306 (g_retroflat_state->viewport.screen_w_remainder)
1307
1308# define retroflat_viewport_screen_h_remainder_generic() \
1309 (g_retroflat_state->viewport.screen_h_remainder)
1310
1311# define retroflat_viewport_set_world_generic( w, h ) \
1312 debug_printf( 1, "setting viewport size to %d x %d...", \
1313 (int16_t)(w), (int16_t)(h) ); \
1314 (g_retroflat_state->viewport.world_w) = w; \
1315 (g_retroflat_state->viewport.world_h) = h;
1316
1317# define retroflat_viewport_set_world_pos_generic( x, y ) \
1318 debug_printf( 1, "setting viewport world pos to %d, %d...", x, y ); \
1319 (g_retroflat_state->viewport.world_x) = x; \
1320 (g_retroflat_state->viewport.world_y) = y; \
1321 (g_retroflat_state->viewport.world_tile_x) = (x) >> RETROFLAT_TILE_W_BITS; \
1322 (g_retroflat_state->viewport.world_tile_y) = (y) >> RETROFLAT_TILE_H_BITS;
1323
1324# define retroflat_viewport_set_pos_size_generic( x_px, y_px, w_px, h_px ) \
1325 g_retroflat_state->viewport.screen_x = (x_px); \
1326 g_retroflat_state->viewport.screen_y = (y_px); \
1327 g_retroflat_state->viewport.screen_tile_w = \
1328 ((w_px) / RETROFLAT_TILE_W); \
1329 g_retroflat_state->viewport.screen_tile_h = \
1330 ((h_px) / RETROFLAT_TILE_H); \
1331 /* We're not adding the extra room here since this won't be used for
1332 * indexing or allocation but rather pixel detection.
1333 */ \
1334 g_retroflat_state->viewport.screen_w = \
1335 ((w_px) / RETROFLAT_TILE_W) * RETROFLAT_TILE_W; \
1336 g_retroflat_state->viewport.screen_h = \
1337 ((h_px) / RETROFLAT_TILE_H) * RETROFLAT_TILE_H; \
1338 g_retroflat_state->viewport.screen_w_remainder = \
1339 (x_px) + (w_px) - g_retroflat_state->viewport.screen_w; \
1340 g_retroflat_state->viewport.screen_h_remainder = \
1341 (y_px) + (h_px) - g_retroflat_state->viewport.screen_h;
1342
1343#ifndef RETROFLAT_NO_VIEWPORT_REFRESH
1344
1345# define retroflat_viewport_lock_refresh_generic() \
1346 if( NULL == g_retroflat_state->viewport.refresh_grid ) { \
1347 maug_mlock( \
1348 g_retroflat_state->viewport.refresh_grid_h, \
1349 g_retroflat_state->viewport.refresh_grid ); \
1350 maug_cleanup_if_null_lock( retroflat_tile_t*, \
1351 g_retroflat_state->viewport.refresh_grid ); \
1352 }
1353
1354# define retroflat_viewport_unlock_refresh_generic() \
1355 if( NULL != g_retroflat_state->viewport.refresh_grid ) { \
1356 maug_munlock( \
1357 g_retroflat_state->viewport.refresh_grid_h, \
1358 g_retroflat_state->viewport.refresh_grid ); \
1359 }
1360
1361# define _retroflat_viewport_refresh_tile_x( x_px ) \
1362 (((x_px) + RETROFLAT_TILE_W) >> RETROFLAT_TILE_W_BITS)
1363
1364# define _retroflat_viewport_refresh_tile_y( y_px ) \
1365 (((y_px) + RETROFLAT_TILE_H) >> RETROFLAT_TILE_H_BITS)
1366
1367# define retroflat_viewport_set_refresh_generic( x_px, y_px, tid ) \
1368 assert( NULL != g_retroflat_state->viewport.refresh_grid ); \
1369 if( \
1370 /* Expand the range by -1 to account for just off-screen tile. */ \
1371 -(RETROFLAT_TILE_W) <= x_px && -(RETROFLAT_TILE_H) <= y_px && \
1372 retroflat_screen_w() > x_px && \
1373 retroflat_screen_h() > y_px \
1374 ) { \
1375 assert( 0 < g_retroflat_state->viewport.screen_tile_w ); \
1376 assert( 0 <= (((y_px) + RETROFLAT_TILE_H) >> RETROFLAT_TILE_H_BITS) ); \
1377 assert( 0 <= (((x_px) + RETROFLAT_TILE_W) >> RETROFLAT_TILE_W_BITS) ); \
1378 g_retroflat_state->viewport.refresh_grid[ \
1379 /* Add +1 tile to make off-screen "-1" tile positive. */ \
1380 ((_retroflat_viewport_refresh_tile_y( y_px ) + 1) * \
1381 (g_retroflat_state->viewport.screen_tile_w + 2)) + \
1382 (_retroflat_viewport_refresh_tile_x( x_px ) + 1)] = tid; \
1383 }
1384
1385# define retroflat_viewport_tile_is_stale( x_px, y_px, tile_id ) \
1386 ((tile_id) != \
1387 g_retroflat_state->viewport.refresh_grid[ \
1388 ((_retroflat_viewport_refresh_tile_y( y_px ) + 1) * \
1389 (g_retroflat_state->viewport.screen_tile_w + 2)) + \
1390 (_retroflat_viewport_refresh_tile_x( x_px ) + 1)])
1391
1392#endif /* !RETROFLAT_NO_VIEWPORT_REFRESH */
1393
1394uint8_t retroflat_viewport_move_x_generic( int16_t x );
1395
1396uint8_t retroflat_viewport_move_y_generic( int16_t y );
1397
1398uint8_t retroflat_viewport_focus_generic(
1400 retroflat_pxxy_t range, retroflat_pxxy_t speed );
1401
1402# define retroflat_viewport_screen_x_generic( world_x ) \
1403 (g_retroflat_state->viewport.screen_x + \
1404 ((world_x) - retroflat_viewport_world_x()))
1405
1406# define retroflat_viewport_screen_y_generic( world_y ) \
1407 (g_retroflat_state->viewport.screen_y + \
1408 ((world_y) - retroflat_viewport_world_y()))
1409
1410# define retroflat_viewport_screen_get_x_generic() \
1411 (g_retroflat_state->viewport.screen_x)
1412
1413# define retroflat_viewport_screen_get_y_generic() \
1414 (g_retroflat_state->viewport.screen_y)
1415
1416#endif /* !DOCUMENTATION */
1417
1418#if defined( RETROFLAT_SOFT_VIEWPORT ) || defined( DOCUMENTATION )
1419
1420# ifndef RETROFLAT_NO_VIEWPORT_REFRESH
1421 /* These clamp world coordinates to tile borders to allow refresh grid to
1422 * function properly (smooth-scrolling tiles will always be in motion).
1423 */
1424
1429# define retroflat_viewport_world_x() \
1430 ((retroflat_viewport_world_x_generic() \
1431 >> RETROFLAT_TILE_W_BITS) << RETROFLAT_TILE_W_BITS)
1432
1437# define retroflat_viewport_world_y() \
1438 ((retroflat_viewport_world_y_generic() \
1439 >> RETROFLAT_TILE_H_BITS) << RETROFLAT_TILE_H_BITS)
1440# else
1441# define retroflat_viewport_world_x() retroflat_viewport_world_x_generic()
1442# define retroflat_viewport_world_y() retroflat_viewport_world_y_generic()
1443#endif /* !RETROFLAT_NO_VIEWPORT_REFRESH */
1444
1445# define retroflat_viewport_world_tile_x() \
1446 retroflat_viewport_world_tile_x_generic()
1447# define retroflat_viewport_world_tile_y() \
1448 retroflat_viewport_world_tile_y_generic()
1449
1454# define retroflat_viewport_world_w() \
1455 retroflat_viewport_world_w_generic()
1456
1461# define retroflat_viewport_world_h() \
1462 retroflat_viewport_world_h_generic()
1463
1468# define retroflat_viewport_screen_tile_w() \
1469 retroflat_viewport_screen_tile_w_generic()
1470
1475# define retroflat_viewport_screen_tile_h() \
1476 retroflat_viewport_screen_tile_h_generic()
1477
1482# define retroflat_viewport_screen_w() \
1483 retroflat_viewport_screen_w_generic()
1484
1489# define retroflat_viewport_screen_h() \
1490 retroflat_viewport_screen_h_generic()
1491
1497# define retroflat_viewport_screen_w_remainder() \
1498 retroflat_viewport_screen_w_remainder_generic()
1499
1505# define retroflat_viewport_screen_h_remainder() \
1506 retroflat_viewport_screen_h_remainder_generic()
1507
1515# define retroflat_viewport_set_world( w, h ) \
1516 retroflat_viewport_set_world_generic( w, h )
1517
1522# define retroflat_viewport_set_world_pos( x, y ) \
1523 retroflat_viewport_set_world_pos_generic( x, y )
1524
1530# define retroflat_viewport_set_pos_size( x_px, y_px, w_px, h_px ) \
1531 retroflat_viewport_set_pos_size_generic( x_px, y_px, w_px, h_px )
1532
1533#ifndef RETROFLAT_NO_VIEWPORT_REFRESH
1534
1542# define retroflat_viewport_lock_refresh() \
1543 retroflat_viewport_lock_refresh_generic()
1544
1552# define retroflat_viewport_unlock_refresh() \
1553 retroflat_viewport_unlock_refresh_generic()
1554
1566# define retroflat_viewport_set_refresh( x, y, tid ) \
1567 retroflat_viewport_set_refresh_generic( x, y, tid )
1568
1569#endif /* !RETROFLAT_NO_VIEWPORT_REFRESH */
1570
1583# define retroflat_viewport_focus( x1, y1, range, speed ) \
1584 retroflat_viewport_focus_generic( x1, y1, range, speed )
1585
1590# define retroflat_viewport_screen_x( world_x ) \
1591 retroflat_viewport_screen_x_generic( world_x )
1592
1597# define retroflat_viewport_screen_y( world_y ) \
1598 retroflat_viewport_screen_y_generic( world_y )
1599
1600# define retroflat_viewport_screen_get_x() \
1601 retroflat_viewport_screen_get_x_generic()
1602
1603# define retroflat_viewport_screen_get_y() \
1604 retroflat_viewport_screen_get_y_generic()
1605
1606# ifndef RETROFLAT_VIEWPORT_OVERRIDE_MOVE
1607# define retroflat_viewport_move_x( x ) \
1608 retroflat_viewport_move_x_generic( x )
1609
1610# define retroflat_viewport_move_y( y ) \
1611 retroflat_viewport_move_y_generic( y )
1612# endif /* !RETROFLAT_VIEWPORT_OVERRIDE_MOVE */
1613
1614#endif /* RETROFLAT_SOFT_VIEWPORT || DOCUMENTATION */
1615
1617
1624#define retroflat_heartbeat_set( len, max ) \
1625 g_retroflat_state->heartbeat_max = max; \
1626 g_retroflat_state->heartbeat_len = len;
1627
1632#define retroflat_heartbeat() (g_retroflat_state->heartbeat_frame)
1633
1641#define retroflat_heartbeat_update() \
1642 /* Update the heartbeat animation frame. */ \
1643 if( g_retroflat_state->heartbeat_next <= retroflat_get_ms() ) { \
1644 g_retroflat_state->heartbeat_frame++; \
1645 if( \
1646 g_retroflat_state->heartbeat_frame >= \
1647 g_retroflat_state->heartbeat_max \
1648 ) { \
1649 g_retroflat_state->heartbeat_frame = 0; \
1650 } \
1651 g_retroflat_state->heartbeat_next = \
1652 retroflat_get_ms() + g_retroflat_state->heartbeat_len; \
1653 }
1654
1662 /* TODO: Set this up in the initialization function! */
1663 /* TODO: We probably need more of these. */
1664 size_t sz;
1665 size_t offset_pal;
1666 size_t offset_tex_pal;
1667
1668 void* loop_data;
1669 MERROR_RETVAL retval;
1672 maug_path config_path;
1673 maug_path assets_path;
1674 maug_path saves_path;
1675
1677 /* struct RETROFLAT_BITMAP buffer; */
1679
1680# if defined( RETROFLAT_VDP ) || defined( DOCUMENTATION ) || \
1681defined( RETROVDP_C )
1689 struct RETROFLAT_BITMAP* vdp_buffer_in;
1690 struct RETROFLAT_BITMAP* vdp_buffer_out;
1691# ifdef RETROFLAT_OS_WIN
1692 HMODULE vdp_exe;
1693# else
1695 void* vdp_exe;
1696# endif /* RETROFLAT_OS_WIN */
1705 uint8_t vdp_flags;
1706# endif /* RETROFLAT_VDP || DOCUMENTATION || RETROVDP_C */
1707
1708 /* These are used by VDP so should be standardized/not put in plat-spec! */
1709
1710 struct RETROFLAT_VIEWPORT viewport;
1711
1727 size_t screen_w;
1729 size_t screen_h;
1732
1733 /* WARNING: The VDP requires the state specifier to be the same size
1734 * as the one it was compiled for! Do not modify above here!
1735 */
1736
1737 /* TODO: Put these in a platform-specific struct of some kind to maintain
1738 * consistent state struct size for VDP?
1739 */
1740
1741 retroflat_ms_t heartbeat_next;
1759
1761 retroflat_proc_resize_t on_resize;
1762 void* on_resize_data;
1763
1765 retroflat_proc_focus_t on_focus;
1766 void* on_focus_data;
1769
1772 void* on_quit_data;
1773
1774#ifndef RETROFLAT_BMP_TEX
1776 RETROFLAT_COLOR_DEF palette[RETROFLAT_COLORS_CT_MAX];
1777#endif /* !RETROFLAT_BMP_TEX */
1778
1779 retroflat_loop_iter loop_iter;
1780 retroflat_loop_iter frame_iter;
1781
1782 struct RETROFLAT_PLATFORM platform;
1783
1784# if defined( RETROFLAT_BMP_TEX )
1785 /* This allows native colors to be used for things like glColor3fv while
1786 * these colors are used to manipulate textures passed through
1787 * retroflat_bitmap_*().
1788 */
1789 RETROFLAT_TEX_COLOR_DEF tex_palette[RETROFLAT_COLORS_CT_MAX];
1790# endif /* RETROFLAT_BMP_TEX */
1791
1792 struct RETROFLAT_INPUT_STATE input;
1793
1798 retroflat_timer_cb_t timers_cb[RETROFLAT_TIMER_CT_MAX];
1799 retroflat_ms_t timers_at[RETROFLAT_TIMER_CT_MAX];
1800 void* timers_data[RETROFLAT_TIMER_CT_MAX];
1801 size_t timers_ct;
1802
1803# ifndef RETROFLAT_NO_SOUND
1804 struct RETROFLAT_SOUND_STATE sound;
1805# endif /* !RETROFLAT_NO_SOUND */
1806};
1807
1808/* === Translation Module === */
1809
1810/* Declare the prototypes so that internal functions can call each other. */
1811
1812# ifdef retroflat_loop
1813MERROR_RETVAL retroflat_loop_generic(
1814 retroflat_loop_iter frame_iter, retroflat_loop_iter loop_iter, void* data );
1815# else
1822 retroflat_loop_iter frame_iter, retroflat_loop_iter loop_iter, void* data );
1823# endif /* retroflat_loop */
1824
1825#define retroflat_get_assets_path() (g_retroflat_state->assets_path)
1826
1827MERROR_RETVAL retroflat_build_filename_path(
1828 const maug_path filename_in, const char* filename_ext,
1829 char* buffer_out, size_t buffer_out_sz, uint8_t flags );
1830
1835
1843 uint8_t flags, const char* title, const char* format, ... );
1844 /* maug_retroflt_msg_api */
1846
1854MERROR_RETVAL retroflat_init( int argc, char* argv[], struct RETROFLAT_ARGS* args );
1855
1862void retroflat_shutdown( int retval );
1863
1864# if defined( RETROFLAT_VDP ) || defined( DOCUMENTATION )
1869
1873MERROR_RETVAL retroflat_vdp_call( const char* proc_name );
1874
1875uint8_t* retroflat_vdp_get_vdp_in();
1876
1877uint8_t* retroflat_vdp_get_vdp_out();
1878 /* maug_retroflt_vdp */
1880# endif /* RETROFLAT_VDP || DOCUMENTATION */
1881
1882RETROFLAT_IN_KEY retroflat_repeat_input(
1883 RETROFLAT_IN_KEY key_out, struct RETROFLAT_INPUT* input,
1884 RETROFLAT_IN_KEY* prev_input, int* prev_delay );
1885
1886void retroflat_set_title( const char* format, ... );
1887
1888retroflat_ms_t retroflat_get_ms();
1889
1890uint32_t retroflat_get_rand();
1891
1892# if !defined( RETROFLAT_NO_KEYBOARD )
1893char retroflat_vk_to_ascii( RETROFLAT_IN_KEY k, uint8_t flags );
1894# endif /* !RETROFLAT_NO_KEYBOARD */
1895
1900
1912 const char* filename, struct RETROFLAT_BITMAP* bmp_out, uint8_t flags );
1913
1914MERROR_RETVAL retroflat_create_bitmap(
1916 struct RETROFLAT_BITMAP* bmp_out, uint8_t flags );
1917
1923void retroflat_destroy_bitmap( struct RETROFLAT_BITMAP* bitmap );
1924
1941 struct RETROFLAT_BITMAP* target, struct RETROFLAT_BITMAP* src,
1945 int16_t instance );
1946
1947#ifdef RETROFLAT_TRACE_CONSTRAIN
1948# define retroflat_constrain_px( x, y, bmp, retact ) \
1949 if( \
1950 x >= retroflat_bitmap_w( bmp ) || y >= retroflat_bitmap_h( bmp ) || \
1951 0 > x || 0 > y \
1952 ) { \
1953 error_printf( "attempted draw at %d, %d, out of bounds %d x %d", \
1954 x, y, retroflat_bitmap_w( bmp ), retroflat_bitmap_h( bmp ) ); \
1955 retact; \
1956 }
1957#else
1965# define retroflat_constrain_px( x, y, bmp, retact ) \
1966 if( \
1967 x >= retroflat_bitmap_w( bmp ) || y >= retroflat_bitmap_h( bmp ) || \
1968 0 > x || 0 > y \
1969 ) { \
1970 retact; \
1971 }
1972#endif /* RETROFLAT_TRACE_CONSTRAIN */
1973
1978 struct RETROFLAT_BITMAP* bitmap,
1979 int16_t instance,
1983 /* maug_retroflt_bitmap */
1985
1990
2000MERROR_RETVAL retroflat_draw_lock( struct RETROFLAT_BITMAP* bmp );
2001
2002MERROR_RETVAL retroflat_draw_release( struct RETROFLAT_BITMAP* bmp );
2003
2004void retroflat_px(
2005 struct RETROFLAT_BITMAP* target, const RETROFLAT_COLOR color,
2006 retroflat_pxxy_t x, retroflat_pxxy_t y, uint8_t flags );
2007
2008#ifdef RETROFLAT_SOFT_SHAPES
2009# ifdef RETROFLAT_OPENGL
2010/* Make sure we're not passing NULL to openGL texture drawers... they can't
2011 * handle that!
2012 */
2013# define retroflat_rect( t, c, x, y, w, h, f ) \
2014 assert( NULL != t ); \
2015 retrosoft_rect( t, c, x, y, w, h, f );
2016# define retroflat_ellipse( t, c, x, y, w, h, f ) \
2017 assert( NULL != t ); \
2018 retrosoft_ellipse( t, c, x, y, w, h, f )
2019# else
2020# define retroflat_rect( t, c, x, y, w, h, f ) \
2021 retrosoft_rect( t, c, x, y, w, h, f )
2022# define retroflat_ellipse( t, c, x, y, w, h, f ) \
2023 retrosoft_ellipse( t, c, x, y, w, h, f )
2024# endif /* RETROFLAT_3D */
2025#else
2026
2038 struct RETROFLAT_BITMAP* target, const RETROFLAT_COLOR color,
2040 retroflat_pxxy_t w, retroflat_pxxy_t h, uint8_t flags );
2041
2053 struct RETROFLAT_BITMAP* target, const RETROFLAT_COLOR color,
2055 retroflat_pxxy_t w, retroflat_pxxy_t h, uint8_t flags );
2056
2057#endif /* RETROFLAT_SOFT_SHAPES */
2058
2059#ifdef RETROFLAT_SOFT_LINES
2060# define retroflat_line( t, c, x1, y1, x2, y2, f ) \
2061 retrosoft_line( t, c, x1, y1, x2, y2, f )
2062#else
2063
2076 struct RETROFLAT_BITMAP* target, const RETROFLAT_COLOR color,
2078 retroflat_pxxy_t x2, retroflat_pxxy_t y2, uint8_t flags );
2079
2080#endif /* RETROFLAT_SOFT_LINES */
2081
2082void retroflat_cursor( struct RETROFLAT_BITMAP* target, uint8_t flags );
2083
2097 struct RETROFLAT_BITMAP* target, const char* str, size_t str_sz,
2098 const char* font_str,
2099 retroflat_pxxy_t* w_out, retroflat_pxxy_t* h_out, uint8_t flags );
2100
2119 struct RETROFLAT_BITMAP* target, const RETROFLAT_COLOR color,
2120 const char* str, int str_sz, const char* font_str,
2121 retroflat_pxxy_t x_orig, retroflat_pxxy_t y_orig,
2122 uint8_t flags );
2123
2124/* TODO: Documentation! */
2125void retroflat_get_palette( uint8_t idx, uint32_t* rgb );
2126
2127MERROR_RETVAL retroflat_set_palette( uint8_t idx, uint32_t rgb );
2128 /* maug_retroflt_bitmap */
2130
2136
2147 retroflat_proc_resize_t on_resize_in, void* data_in );
2148
2154 retroflat_ms_t time, retroflat_timer_cb_t cb, void* data );
2155
2165 retroflat_proc_focus_t on_focus_in, void* data_in );
2166
2176 retroflat_proc_quit_t on_quit_in, void* data_in );
2177
2186
2191#define retroflat_soft_quit( retval ) \
2192 if( \
2193 NULL == g_retroflat_state->on_quit || \
2194 MERROR_PREEMPT != g_retroflat_state->on_quit( \
2195 g_retroflat_state->on_quit_data \
2196 ) ) { \
2197 retroflat_quit( retval ); \
2198 }
2199
2205
2211
2217 /* maug_retroflt_platform_handler */
2219 /* maug_retroflt_platform */
2221
2226
2232RETROFLAT_IN_KEY retroflat_poll_input( struct RETROFLAT_INPUT* input );
2233 /* maug_retroflt_input */
2235
2236#ifdef RETROFLT_C
2237
2238MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets8_x[8] =
2239 { 0, 1, 1, 1, 0, -1, -1, -1 };
2240MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets8_y[8] =
2241 { -1, -1, 0, 1, 1, 1, 0, -1 };
2242
2243MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets4_x[4] =
2244 { 0, 1, 0, -1 };
2245MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets4_y[4] =
2246 { -1, 0, 1, 0 };
2247
2248# ifdef RETROFLAT_STATE_ON_STACK
2249struct RETROFLAT_STATE SEG_MGLOBAL g_retroflat_state_stack;
2250# else
2251MAUG_MHANDLE SEG_MGLOBAL g_retroflat_state_h = (MAUG_MHANDLE)NULL;
2252# endif /* RETROFLAT_STATE_ON_STACK */
2253struct RETROFLAT_STATE* SEG_MGLOBAL g_retroflat_state = NULL;
2254
2255# define RETROFLAT_COLOR_TABLE_CONSTS( idx, name_l, name_u, r, g, b, cgac, cgad ) \
2256 MAUG_CONST RETROFLAT_COLOR SEG_MCONST RETROFLAT_COLOR_ ## name_u = idx;
2257
2258RETROFLAT_COLOR_TABLE( RETROFLAT_COLOR_TABLE_CONSTS )
2259
2260# define RETROFLAT_COLOR_TABLE_NAMES( idx, name_l, name_u, r, g, b, cgac, cgad ) \
2261 #name_u,
2262
2263MAUG_CONST char* SEG_MCONST gc_retroflat_color_names[] = {
2264 RETROFLAT_COLOR_TABLE( RETROFLAT_COLOR_TABLE_NAMES )
2265};
2266
2267/* Callback table is down below, after the statically-defined callbacks. */
2268
2269/* === Function Definitions === */
2270
2271MERROR_RETVAL retroflat_build_filename_path(
2272 const maug_path filename_in, const char* filename_ext,
2273 char* buffer_out, size_t buffer_out_sz, uint8_t flags
2274) {
2275 MERROR_RETVAL retval = MERROR_OK;
2276
2277 assert( 1 < buffer_out_sz );
2278
2279 /* Build the path to the bitmap. */
2280 maug_mzero( buffer_out, buffer_out_sz );
2281 if(
2284 ) {
2285 /* TODO: Error checking. */
2286 maug_snprintf( buffer_out, buffer_out_sz - 1, "%s", filename_in );
2287 } else if( NULL != filename_ext ) {
2288 /* TODO: Error checking. */
2289 maug_snprintf( buffer_out, buffer_out_sz - 1, "%s%c%s.%s",
2290 g_retroflat_state->assets_path, RETROFLAT_PATH_SEP,
2291 filename_in, filename_ext );
2292 } else {
2293 maug_snprintf( buffer_out, buffer_out_sz - 1, "%s%c%s",
2294 g_retroflat_state->assets_path, RETROFLAT_PATH_SEP,
2295 filename_in );
2296 }
2297
2298 return retval;
2299}
2300
2301/* === */
2302
2303# if (defined( RETROFLAT_SOFT_SHAPES ) || defined( RETROFLAT_SOFT_LINES ) || \
2304 defined( RETROFLAT_3D ))
2305/* RETROSOFT_PRESENT is different from RETROFLAT_SOFT_SHAPES in that it only
2306 * indicates that the retrosoft library is loaded, not that it is the default
2307 * for drawing primatives!
2308 */
2309# define RETROSOFT_PRESENT
2310# endif
2311
2312# if defined( RETROFLAT_3D )
2313# if !defined( MAUG_NO_AUTO_C )
2314# define RETRO3D_C
2315# define RETRO3DP_C
2316# define RETROFP_C
2317# endif /* MAUG_NO_AUTO_C */
2318# include <retro3dp.h>
2319# include <retro3d.h>
2320# include <retro3du.h>
2321# include <retapi3.h>
2322# endif /* RETROFLAT_3D */
2323
2324# ifdef RETROSOFT_PRESENT
2325# if !defined( MAUG_NO_AUTO_C )
2326# define RETROSFT_C
2327# endif /* !MAUG_NO_AUTO_C */
2328# define RETROSOFT_PRESENT
2329# include <retrosft.h>
2330# endif /* RETROFLAT_SOFT_SHAPES */
2331
2332# ifndef RETROFLAT_NO_SOUND
2333# include <retapis.h>
2334# endif /* !RETROFLAT_NO_SOUND */
2335
2336# include <retapii.h>
2337
2338# if defined( RETROFLAT_VDP ) && defined( RETROFLAT_OS_UNIX )
2339# include <dlfcn.h>
2340# endif
2341
2342/* Still inside RETROFLT_C! */
2343
2344/* === */
2345
2346#ifndef RETROFLAT_NO_GENERIC_LOOP
2347
2348MERROR_RETVAL retroflat_loop_generic(
2349 retroflat_loop_iter frame_iter, retroflat_loop_iter loop_iter, void* data
2350) {
2351 MERROR_RETVAL retval = MERROR_OK;
2352 retroflat_ms_t next = 0,
2353 now = 0;
2354
2355 g_retroflat_state->loop_iter = (retroflat_loop_iter)loop_iter;
2356 g_retroflat_state->loop_data = (void*)data;
2357 g_retroflat_state->frame_iter = (retroflat_loop_iter)frame_iter;
2358
2359 if(
2361 (g_retroflat_state->retroflat_flags & RETROFLAT_STATE_FLAG_RUNNING)
2362 ) {
2363 /* Main loop is already running, so we're just changing the iter call
2364 * and leaving!
2365 */
2366 debug_printf( 1, "main loop already running!" );
2367 goto cleanup;
2368 }
2369
2370 g_retroflat_state->retroflat_flags |= RETROFLAT_STATE_FLAG_RUNNING;
2371 do {
2373
2374 if(
2375 /* Not waiting for the next frame? */
2377 (RETROFLAT_STATE_FLAG_WAIT_FOR_FPS & g_retroflat_state->retroflat_flags) &&
2378 /* Inter-frame loop present? */
2379 NULL != g_retroflat_state->loop_iter
2380 ) {
2381 /* Run the loop iter as many times as possible. */
2382 g_retroflat_state->loop_iter( g_retroflat_state->loop_data );
2383 }
2384 if(
2386 (RETROFLAT_STATE_FLAG_UNLOCK_FPS & g_retroflat_state->retroflat_flags) &&
2387 retroflat_get_ms() < next
2388 ) {
2389 /* Sleep/low power for a bit. */
2390 continue;
2391 }
2392
2394
2396
2397 if(
2398 NULL != g_retroflat_state->on_focus &&
2399 g_retroflat_state->last_focus_flags != retroflat_focus_platform()
2400 ) {
2401 g_retroflat_state->last_focus_flags = retroflat_focus_platform();
2402 retval = g_retroflat_state->on_focus(
2403 g_retroflat_state->last_focus_flags,
2404 g_retroflat_state->on_focus_data );
2405 maug_cleanup_if_not_ok();
2406 }
2407
2408 if( NULL != g_retroflat_state->frame_iter ) {
2409 /* Run the frame iterator once per FPS tick. */
2410 g_retroflat_state->frame_iter( g_retroflat_state->loop_data );
2411 }
2412 /* Reset wait-for-frame flag AFTER frame callback. */
2413 g_retroflat_state->retroflat_flags &= ~RETROFLAT_STATE_FLAG_WAIT_FOR_FPS;
2414 now = retroflat_get_ms();
2415 if( now + retroflat_fps_next() > now ) {
2416 next = now + retroflat_fps_next();
2417 } else {
2418 /* Rollover protection. */
2419 /* TODO: Add difference from now/next to 0 here. */
2420 next = 0;
2421 }
2422 } while(
2424 (RETROFLAT_STATE_FLAG_RUNNING & g_retroflat_state->retroflat_flags)
2425 );
2426 retval = g_retroflat_state->retval;
2427
2428cleanup:
2429
2430 /* This should be set by retroflat_quit(). */
2431 return retval;
2432}
2433
2434#endif /* !RETROFLAT_NO_GENERIC_LOOP */
2435
2436/* === */
2437
2438# if !defined( RETROFLAT_NO_KEYBOARD )
2439
2440char retroflat_vk_to_ascii( RETROFLAT_IN_KEY k, uint8_t flags ) {
2441 char c = 0;
2442 char offset_lower = 0;
2443
2444 if( RETROFLAT_INPUT_MOD_SHIFT != (RETROFLAT_INPUT_MOD_SHIFT & flags) ) {
2445 /* Shift is *not* being held down. */
2446
2447 if( RETROFLAT_KEY_A <= k && RETROFLAT_KEY_Z >= k ) {
2448 if(
2449 RETROFLAT_INPUT_FORCE_UPPER !=
2450 (RETROFLAT_INPUT_FORCE_UPPER & flags)
2451 ) {
2452 /* Key is alphabetical and we're not forcing uppercase. */
2453 offset_lower = 0x20;
2454 }
2455 } else {
2456 offset_lower = 1;
2457 }
2458 }
2459
2460 switch( k ) {
2461 case RETROFLAT_KEY_A: c = 0x41 + offset_lower; break;
2462 case RETROFLAT_KEY_B: c = 0x42 + offset_lower; break;
2463 case RETROFLAT_KEY_C: c = 0x43 + offset_lower; break;
2464 case RETROFLAT_KEY_D: c = 0x44 + offset_lower; break;
2465 case RETROFLAT_KEY_E: c = 0x45 + offset_lower; break;
2466 case RETROFLAT_KEY_F: c = 0x46 + offset_lower; break;
2467 case RETROFLAT_KEY_G: c = 0x47 + offset_lower; break;
2468 case RETROFLAT_KEY_H: c = 0x48 + offset_lower; break;
2469 case RETROFLAT_KEY_I: c = 0x49 + offset_lower; break;
2470 case RETROFLAT_KEY_J: c = 0x4a + offset_lower; break;
2471 case RETROFLAT_KEY_K: c = 0x4b + offset_lower; break;
2472 case RETROFLAT_KEY_L: c = 0x4c + offset_lower; break;
2473 case RETROFLAT_KEY_M: c = 0x4d + offset_lower; break;
2474 case RETROFLAT_KEY_N: c = 0x4e + offset_lower; break;
2475 case RETROFLAT_KEY_O: c = 0x4f + offset_lower; break;
2476 case RETROFLAT_KEY_P: c = 0x50 + offset_lower; break;
2477 case RETROFLAT_KEY_Q: c = 0x51 + offset_lower; break;
2478 case RETROFLAT_KEY_R: c = 0x52 + offset_lower; break;
2479 case RETROFLAT_KEY_S: c = 0x53 + offset_lower; break;
2480 case RETROFLAT_KEY_T: c = 0x54 + offset_lower; break;
2481 case RETROFLAT_KEY_U: c = 0x55 + offset_lower; break;
2482 case RETROFLAT_KEY_V: c = 0x56 + offset_lower; break;
2483 case RETROFLAT_KEY_W: c = 0x57 + offset_lower; break;
2484 case RETROFLAT_KEY_X: c = 0x58 + offset_lower; break;
2485 case RETROFLAT_KEY_Y: c = 0x59 + offset_lower; break;
2486 case RETROFLAT_KEY_Z: c = 0x60 + offset_lower; break;
2487 case RETROFLAT_KEY_0: c = offset_lower ? 0x30 : ')'; break;
2488 case RETROFLAT_KEY_1: c = offset_lower ? 0x31 : '!'; break;
2489 case RETROFLAT_KEY_2: c = offset_lower ? 0x32 : '@'; break;
2490 case RETROFLAT_KEY_3: c = offset_lower ? 0x33 : '#'; break;
2491 case RETROFLAT_KEY_4: c = offset_lower ? 0x34 : '$'; break;
2492 case RETROFLAT_KEY_5: c = offset_lower ? 0x35 : '%'; break;
2493 case RETROFLAT_KEY_6: c = offset_lower ? 0x36 : '^'; break;
2494 case RETROFLAT_KEY_7: c = offset_lower ? 0x37 : '&'; break;
2495 case RETROFLAT_KEY_8: c = offset_lower ? 0x38 : '*'; break;
2496 case RETROFLAT_KEY_9: c = offset_lower ? 0x39 : '('; break;
2497 case RETROFLAT_KEY_SPACE: c = ' '; break;
2498 case RETROFLAT_KEY_BKSP: c = 0x08; break;
2499 case RETROFLAT_KEY_ENTER: c = '\n'; break;
2500 case RETROFLAT_KEY_SEMICOLON: c = offset_lower ? ';' : ':'; break;
2501 case RETROFLAT_KEY_DASH: c = offset_lower ? '-' : '_'; break;
2502 case RETROFLAT_KEY_SLASH: c = offset_lower ? '/' : '?'; break;
2503 case RETROFLAT_KEY_PERIOD: c = offset_lower ? '.' : '>'; break;
2504 case RETROFLAT_KEY_COMMA: c = offset_lower ? ',' : '<'; break;
2505 case RETROFLAT_KEY_QUOTE: c = offset_lower ? '\'' : '"'; break;
2506 case RETROFLAT_KEY_EQUALS: c = offset_lower ? '=' : '+'; break;
2507 case RETROFLAT_KEY_BACKSLASH: c = offset_lower ? '\\' : '|'; break;
2508 case RETROFLAT_KEY_BRACKETL: c = offset_lower ? '[' : '{'; break;
2509 case RETROFLAT_KEY_BRACKETR: c = offset_lower ? ']' : '}'; break;
2510#ifndef RETROFLAT_API_PC_BIOS
2511 /* TODO: FIXME in DOS! */
2512 case RETROFLAT_KEY_GRAVE: c = offset_lower ? '`' : '~'; break;
2513#endif /* !RETROFLAT_API_PC_BIOS */
2514 }
2515
2516 debug_printf( RETROINPUT_TRACE_LVL, "0x%02x", c );
2517
2518 return c;
2519}
2520
2521#endif /* !RETROFLAT_NO_KEYBOARD */
2522
2523/* === */
2524
2525/* TODO: Migrate all platform-specific parts below to retapif.h. */
2526#include <retapif.h>
2527
2528/* === */
2529
2530# ifndef RETROFLAT_NO_CLI
2531
2532# if !defined( RETROFLAT_NO_SOUND ) && defined( RETROSND_ARGS )
2533
2534static MERROR_RETVAL retrosnd_cli_rsl(
2535 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2536) {
2537 if(
2538 0 <= arg_c &&
2539 0 == maug_strncmp( MAUG_CLI_SIGIL "rsl", arg, MAUG_CLI_SIGIL_SZ + 4 )
2540 ) {
2541 args->sound.flags |= RETROSND_ARGS_FLAG_LIST_DEVS;
2542 }
2543 return MERROR_OK;
2544}
2545
2546# endif /* !RETROFLAT_NO_SOUND && RETROSND_ARGS */
2547
2548# if !defined( RETROFLAT_API_PC_BIOS ) && !defined( RETROFLAT_NO_CLI_SZ )
2549
2550static MERROR_RETVAL retroflat_cli_rfs(
2551 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2552) {
2553 if( 1 < arg_c ) {
2554 args->screen_scale = atoi( arg );
2555 debug_printf( 3, "screen scale arg set to: %d", args->screen_scale );
2556 }
2557 return MERROR_OK;
2558}
2559
2560static MERROR_RETVAL retroflat_cli_rfx(
2561 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2562) {
2563 if( 0 > arg_c ) {
2564 if( 0 == args->screen_w ) {
2565 args->screen_x = 0;
2566 }
2567 } else if(
2568 0 == maug_strncmp( MAUG_CLI_SIGIL "rfx", arg, MAUG_CLI_SIGIL_SZ + 4 )
2569 ) {
2570 /* The next arg must be the new var. */
2571 } else {
2572 args->screen_x = atoi( arg );
2573 }
2574 return MERROR_OK;
2575}
2576
2577static MERROR_RETVAL retroflat_cli_rfy(
2578 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2579) {
2580 if( 0 > arg_c ) {
2581 if( 0 == args->screen_h ) {
2582 args->screen_y = 0;
2583 }
2584 } else if(
2585 0 == maug_strncmp( MAUG_CLI_SIGIL "rfy", arg, MAUG_CLI_SIGIL_SZ + 4 )
2586 ) {
2587 /* The next arg must be the new var. */
2588 } else {
2589 args->screen_y = atoi( arg );
2590 }
2591 return MERROR_OK;
2592}
2593
2594static MERROR_RETVAL retroflat_cli_rfw(
2595 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2596) {
2597 if( 0 > arg_c ) {
2598 if( 0 == args->screen_w ) {
2599 args->screen_w = RETROFLAT_DEFAULT_SCREEN_W;
2600 debug_printf( 1, "setting arg screen_w to default %d:",
2601 args->screen_w );
2602 }
2603 } else if(
2604 0 == maug_strncmp( MAUG_CLI_SIGIL "rfw", arg, MAUG_CLI_SIGIL_SZ + 4 )
2605 ) {
2606 /* The next arg must be the new var. */
2607 } else {
2608 args->screen_w = atoi( arg );
2609 debug_printf( 1, "setting arg screen_w to: %d",
2610 args->screen_w );
2611 }
2612 return MERROR_OK;
2613}
2614
2615static MERROR_RETVAL retroflat_cli_rfh(
2616 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2617) {
2618 if( 0 > arg_c ) {
2619 if( 0 == args->screen_h ) {
2620 args->screen_h = RETROFLAT_DEFAULT_SCREEN_H;
2621 debug_printf( 1, "setting arg screen_h to default: %d",
2622 args->screen_h );
2623 }
2624 } else if(
2625 0 == maug_strncmp( MAUG_CLI_SIGIL "rfh", arg, MAUG_CLI_SIGIL_SZ + 4 )
2626 ) {
2627 /* The next arg must be the new var. */
2628 } else {
2629 args->screen_h = atoi( arg );
2630 debug_printf( 1, "setting arg screen_h to: %d",
2631 args->screen_h );
2632 }
2633 return MERROR_OK;
2634}
2635
2636# endif /* !RETROFLAT_API_PC_BIOS && !RETROFLAT_NO_CLI_SZ */
2637
2638# ifdef RETROFLAT_VDP
2639static MERROR_RETVAL retroflat_cli_vdp(
2640 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2641) {
2642 if( 0 == maug_strncmp( MAUG_CLI_SIGIL "vdp", arg, MAUG_CLI_SIGIL_SZ + 4 ) ) {
2643 /* Next arg is VDP args str. */
2644 } else {
2645 maug_mzero( g_retroflat_state->vdp_args, RETROFLAT_VDP_ARGS_SZ_MAX + 1 );
2646 maug_strncpy(
2647 g_retroflat_state->vdp_args, arg, RETROFLAT_VDP_ARGS_SZ_MAX );
2648 debug_printf( 1, "VDP args: %s", g_retroflat_state->vdp_args );
2649 }
2650 return MERROR_OK;
2651}
2652# endif /* RETROFLAT_VDP */
2653
2654static MERROR_RETVAL retroflat_cli_u(
2655 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2656) {
2657 if( 0 > arg_c ) {
2658 args->flags &= ~RETROFLAT_STATE_FLAG_UNLOCK_FPS;
2659 } else if(
2660 0 == maug_strncmp( MAUG_CLI_SIGIL "rfu", arg, MAUG_CLI_SIGIL_SZ + 4 )
2661 ) {
2662 debug_printf( 1, "unlocking FPS..." );
2663 args->flags |= RETROFLAT_STATE_FLAG_UNLOCK_FPS;
2664 }
2665 return MERROR_OK;
2666}
2667
2668# ifndef RETROFLAT_NO_PAD
2669
2670static MERROR_RETVAL retroflat_cli_rfj(
2671 const char* arg, ssize_t arg_c, struct RETROFLAT_ARGS* args
2672) {
2673 if( 0 > arg_c ) {
2674 args->joystick_id = -1;
2675 debug_printf( 1, "setting arg joystick_id to default: %d",
2676 args->joystick_id );
2677 } else if(
2678 0 == maug_strncmp( MAUG_CLI_SIGIL "rfj", arg, MAUG_CLI_SIGIL_SZ + 4 )
2679 ) {
2680 /* The next arg must be the new var. */
2681 } else {
2682 args->joystick_id = atoi( arg );
2683 debug_printf( 1, "setting arg joystick_id to: %d",
2684 args->joystick_id );
2685 }
2686 return MERROR_OK;
2687}
2688
2689# endif /* !RETROFLAT_NO_PAD */
2690
2691#endif /* !RETROFLAT_NO_CLI */
2692
2693/* === */
2694
2695/* Still inside RETROFLT_C! */
2696
2698 int argc, char* argv[], struct RETROFLAT_ARGS* args
2699) {
2700
2701 /* = Declare Init Vars = */
2702
2703 MERROR_RETVAL retval = 0;
2704
2705 /* = Begin Init Procedure = */
2706
2707# ifdef RETROFLAT_COMMIT_HASH
2708 debug_printf( 1, "retroflat commit: " RETROFLAT_COMMIT_HASH );
2709# endif /* RETROFLAT_COMMIT_HASH */
2710
2711 debug_printf( 1, "retroflat: initializing..." );
2712
2713 /* System sanity checks. */
2714 assert( 2 <= sizeof( MERROR_RETVAL ) );
2715 assert( 4 == sizeof( uint32_t ) );
2716 assert( 4 == sizeof( int32_t ) );
2717 assert( 2 == sizeof( uint16_t ) );
2718 assert( 2 == sizeof( int16_t ) );
2719 assert( 1 == sizeof( uint8_t ) );
2720 assert( 1 == sizeof( int8_t ) );
2721 assert( NULL != args );
2722 assert( 1 << RETROFLAT_TILE_W_BITS == RETROFLAT_TILE_W );
2723 assert( 1 << RETROFLAT_TILE_H_BITS == RETROFLAT_TILE_H );
2724
2725 debug_printf( 1, "initializing drawing routines..." );
2726
2727 /* Initialize 2D callbacks depending on if we're in 2D or 3D mode.
2728 * Please see retrom2d.h for more information.
2729 */
2730# if defined( RETROFLAT_BMP_TEX )
2731 retroflat_2d_px = (retroflat_px_cb)retro3d_texture_px;
2732 retroflat_2d_line = (retroflat_line_cb)retrosoft_line;
2733 retroflat_2d_rect = (retroflat_rect_cb)retrosoft_rect;
2734 retroflat_2d_ellipse = (retroflat_ellipse_cb)retrosoft_ellipse;
2735 retroflat_2d_blit_bitmap = (retroflat_blit_bitmap_cb)retro3d_texture_blit;
2736 retroflat_2d_load_bitmap =
2737 (retroflat_load_bitmap_cb)retro3d_texture_load_bitmap;
2738 retroflat_2d_create_bitmap =
2739 (retroflat_create_bitmap_cb)retro3d_texture_create;
2740# else
2741 retroflat_2d_px = (retroflat_px_cb)retroflat_px;
2742# ifdef RETROFLAT_SOFT_SHAPES
2743 /* TODO: Work retrosoft routines to use retroflat_blit_t */
2744 retroflat_2d_line = (retroflat_line_cb)retrosoft_line;
2745 retroflat_2d_rect = (retroflat_rect_cb)retrosoft_rect;
2746 retroflat_2d_ellipse = (retroflat_ellipse_cb)retrosoft_ellipse;
2747# else
2748 retroflat_2d_line = (retroflat_line_cb)retroflat_line;
2749 retroflat_2d_rect = (retroflat_rect_cb)retroflat_rect;
2750 retroflat_2d_ellipse = (retroflat_ellipse_cb)retroflat_ellipse;
2751# endif /* RETROFLAT_SOFT_SHAPES */
2752 retroflat_2d_blit_bitmap = (retroflat_blit_bitmap_cb)retroflat_blit_bitmap;
2753 retroflat_2d_load_bitmap = (retroflat_load_bitmap_cb)retroflat_load_bitmap;
2754 retroflat_2d_create_bitmap =
2755 (retroflat_create_bitmap_cb)retroflat_create_bitmap;
2756# endif /* RETROFLAT_BMP_TEX */
2757
2758 debug_printf( 1, "retroflat: MFIX_PRECISION: %f", MFIX_PRECISION );
2759
2760 debug_printf( 1, "retroflat: allocating state (" SIZE_T_FMT " bytes)...",
2761 sizeof( struct RETROFLAT_STATE ) );
2762
2763 debug_printf( 1, "retroflat: size_t is (" SIZE_T_FMT " bytes)...",
2764 sizeof( size_t ) );
2765
2766 debug_printf( 1, "retroflat: ssize_t is (" SIZE_T_FMT " bytes)...",
2767 sizeof( ssize_t ) );
2768
2769 debug_printf( 1, "retroflat: off_t is (" SIZE_T_FMT " bytes)...",
2770 sizeof( off_t ) );
2771
2772 debug_printf( 1, "initializing global state..." );
2773
2774# ifdef RETROFLAT_STATE_ON_STACK
2775 g_retroflat_state = &g_retroflat_state_stack;
2776# else
2777 maug_malloc_test( g_retroflat_state_h, 1, sizeof( struct RETROFLAT_STATE ) );
2778
2779 maug_mlock( g_retroflat_state_h, g_retroflat_state );
2780 if( NULL == g_retroflat_state ) {
2782 "Error", "Could not lock global state!" );
2783 retval = MERROR_ALLOC;
2784 goto cleanup;
2785 }
2786# endif /* RETROFLAT_STATE_ON_STACK */
2787
2788 maug_mzero( g_retroflat_state, sizeof( struct RETROFLAT_STATE ) );
2789
2790 retroflat_heartbeat_set( 1000, 2 );
2791
2792 debug_printf( 1, "initializing platform filesystem..." );
2793 retval = mfile_plt_init();
2794 maug_cleanup_if_not_ok();
2795
2796# ifndef RETROFLAT_NO_CLI
2797
2798 debug_printf( 1, "retroflat: parsing args..." );
2799
2800 /* All platforms: add command-line args based on compile definitons. */
2801
2802 retval = maug_add_arg(
2803 MAUG_CLI_SIGIL "h", MAUG_CLI_SIGIL_SZ + 2, "Display command-line help",
2804 26, maug_cli_h, NULL );
2805
2806# if !defined( RETROFLAT_NO_SOUND ) && defined( RETROSND_ARGS )
2807 retval = maug_add_arg( MAUG_CLI_SIGIL "rsd", MAUG_CLI_SIGIL_SZ + 4,
2808 "Select MIDI device", 0, (maug_cli_cb)retrosnd_cli_rsd, args );
2809 maug_cleanup_if_not_ok();
2810 retval = maug_add_arg( MAUG_CLI_SIGIL "rsl", MAUG_CLI_SIGIL_SZ + 4,
2811 "List MIDI devices", 0, (maug_cli_cb)retrosnd_cli_rsl, args );
2812 maug_cleanup_if_not_ok();
2813# endif /* !RETROFLAT_NO_SOUND && RETROSND_ARGS */
2814
2815# ifdef RETROFLAT_SCREENSAVER
2816 retval = maug_add_arg( MAUG_CLI_SIGIL "p", MAUG_CLI_SIGIL_SZ + 2,
2817 "Preview screensaver", 0, (maug_cli_cb)retroflat_cli_p, args );
2818 maug_cleanup_if_not_ok();
2819 retval = maug_add_arg( MAUG_CLI_SIGIL "s", MAUG_CLI_SIGIL_SZ + 2,
2820 "Launch screensaver", 0, (maug_cli_cb)retroflat_cli_s, args );
2821 maug_cleanup_if_not_ok();
2822# endif /* RETROFLAT_SCREENSAVER */
2823
2824# ifdef RETROFLAT_API_PC_BIOS
2825 retval = maug_add_arg( MAUG_CLI_SIGIL "rfm", MAUG_CLI_SIGIL_SZ + 4,
2826 "Set the screen mode.", 0,
2827 (maug_cli_cb)retroflat_cli_rfm, args );
2828 maug_cleanup_if_not_ok();
2829# elif !defined( RETROFLAT_NO_CLI_SZ )
2830 retval = maug_add_arg( MAUG_CLI_SIGIL "rfs", MAUG_CLI_SIGIL_SZ + 4,
2831 "Set screen scale factor.", 0,
2832 (maug_cli_cb)retroflat_cli_rfs, args );
2833 maug_cleanup_if_not_ok();
2834 retval = maug_add_arg( MAUG_CLI_SIGIL "rfx", MAUG_CLI_SIGIL_SZ + 4,
2835 "Set the screen X position.", 0,
2836 (maug_cli_cb)retroflat_cli_rfx, args );
2837 maug_cleanup_if_not_ok();
2838 retval = maug_add_arg( MAUG_CLI_SIGIL "rfy", MAUG_CLI_SIGIL_SZ + 4,
2839 "Set the screen Y position.", 0,
2840 (maug_cli_cb)retroflat_cli_rfy, args );
2841 maug_cleanup_if_not_ok();
2842 retval = maug_add_arg( MAUG_CLI_SIGIL "rfw", MAUG_CLI_SIGIL_SZ + 4,
2843 "Set the screen width.", 0,
2844 (maug_cli_cb)retroflat_cli_rfw, args );
2845 maug_cleanup_if_not_ok();
2846 retval = maug_add_arg( MAUG_CLI_SIGIL "rfh", MAUG_CLI_SIGIL_SZ + 4,
2847 "Set the screen height.", 0,
2848 (maug_cli_cb)retroflat_cli_rfh, args );
2849 maug_cleanup_if_not_ok();
2850# endif /* !RETROFLAT_NO_CLI_SZ */
2851
2852# ifdef RETROFLAT_VDP
2853 retval = maug_add_arg( MAUG_CLI_SIGIL "vdp", MAUG_CLI_SIGIL_SZ + 4,
2854 "Pass a string of args to the VDP.", 0,
2855 (maug_cli_cb)retroflat_cli_vdp, args );
2856 maug_cleanup_if_not_ok();
2857# endif /* RETROFLAT_VDP */
2858
2859 retval = maug_add_arg( MAUG_CLI_SIGIL "rfu", MAUG_CLI_SIGIL_SZ + 4,
2860 "Unlock FPS.", 0,
2861 (maug_cli_cb)retroflat_cli_u, args );
2862 maug_cleanup_if_not_ok();
2863
2864# ifndef RETROFLAT_NO_PAD
2865 retval = maug_add_arg( MAUG_CLI_SIGIL "rfj", MAUG_CLI_SIGIL_SZ + 4,
2866 "Specify joystick ID to use.", 0,
2867 (maug_cli_cb)retroflat_cli_rfj, args );
2868 maug_cleanup_if_not_ok();
2869# endif /* !RETROFLAT_NO_PAD */
2870
2871 /* Parse command line args. */
2872 retval = maug_parse_args( argc, argv );
2873 maug_cleanup_if_not_ok();
2874
2875# endif /* !RETROFLAT_NO_CLI */
2876
2877 if( 0 == args->screen_w ) {
2878 args->screen_w = RETROFLAT_DEFAULT_SCREEN_W;
2879 debug_printf( 1, "setting arg screen_w to default: %d",
2880 args->screen_w );
2881 }
2882 if( 0 == args->screen_h ) {
2883 args->screen_h = RETROFLAT_DEFAULT_SCREEN_H;
2884 debug_printf( 1, "setting arg screen_h to default: %d",
2885 args->screen_h );
2886 }
2887 if( 0 == args->screen_scale ) {
2888 args->screen_scale = RETROFLAT_DEFAULT_SCREEN_SCALE;
2889 debug_printf( 1, "setting arg screen_scale to default: %d",
2890 args->screen_scale );
2891 }
2892 if( 0 == args->screen_colors ) {
2893 args->screen_colors = 16;
2894 debug_printf( 1, "setting arg screen_colors to default: %d",
2895 args->screen_colors );
2896 }
2897 args->joystick_id = -1;
2898
2899 if(
2901 ) {
2902 g_retroflat_state->retroflat_flags |= RETROFLAT_STATE_FLAG_UNLOCK_FPS;
2903 }
2904
2905 debug_printf( 1, "retroflat: setting config..." );
2906
2907 /* Set the assets path. */
2908 if( NULL != args->assets_path ) {
2909 maug_mzero( g_retroflat_state->assets_path, MAUG_PATH_SZ_MAX );
2910 maug_strncpy( g_retroflat_state->assets_path,
2911 args->assets_path, MAUG_PATH_SZ_MAX - 1 );
2912 }
2913
2914# if defined( RETROFLAT_SCREENSAVER )
2915 if(
2917 (RETROFLAT_STATE_FLAG_SCREENSAVER & args->flags)
2918 ) {
2919 g_retroflat_state->retroflat_flags |= RETROFLAT_STATE_FLAG_SCREENSAVER;
2920 }
2921# endif /* RETROFLAT_SCREENSAVER */
2922
2923# if !defined( RETROFLAT_NO_CLI_SZ )
2924 /* Setup intended screen size. */
2925 g_retroflat_state->screen_scale = args->screen_scale;
2926 g_retroflat_state->screen_v_w = args->screen_w;
2927 g_retroflat_state->screen_v_h = args->screen_h;
2928 g_retroflat_state->screen_w = args->screen_w *
2929 g_retroflat_state->screen_scale;
2930 g_retroflat_state->screen_h = args->screen_h *
2931 g_retroflat_state->screen_scale;
2932 g_retroflat_state->screen_colors = args->screen_colors;
2933
2934 debug_printf( 3, "attempting to initialize platform with: "
2935 SIZE_T_FMT "x" SIZE_T_FMT " pixels (scaled to " SIZE_T_FMT "x" SIZE_T_FMT
2936 ") and " SIZE_T_FMT " colors",
2937 g_retroflat_state->screen_v_w, g_retroflat_state->screen_v_h,
2938 g_retroflat_state->screen_w, g_retroflat_state->screen_h,
2939 g_retroflat_state->screen_colors );
2940# endif /* !RETROFLAT_NO_CLI_SZ */
2941
2942 /* == Platform-Specific Init == */
2943
2944 retval = retroflat_init_platform( argc, argv, args );
2945 maug_cleanup_if_not_ok();
2946
2947# if defined( RETROFLAT_NO_CLI_SZ )
2948 g_retroflat_state->screen_scale = args->screen_scale;
2949 g_retroflat_state->screen_v_w = args->screen_w;
2950 g_retroflat_state->screen_v_h = args->screen_h;
2951 g_retroflat_state->screen_w = args->screen_w *
2952 g_retroflat_state->screen_scale;
2953 g_retroflat_state->screen_h = args->screen_h *
2954 g_retroflat_state->screen_scale;
2955 g_retroflat_state->screen_colors = args->screen_colors;
2956
2957 debug_printf( 3, "initialized platform with: "
2958 SIZE_T_FMT "x" SIZE_T_FMT " pixels (scaled to " SIZE_T_FMT "x" SIZE_T_FMT
2959 ") and " SIZE_T_FMT " colors",
2960 g_retroflat_state->screen_v_w, g_retroflat_state->screen_v_h,
2961 g_retroflat_state->screen_w, g_retroflat_state->screen_h,
2962 g_retroflat_state->screen_colors );
2963# endif /* RETROFLAT_NO_CLI_SZ */
2964
2965 retval = retroflat_init_input( args );
2966 maug_cleanup_if_not_ok();
2967
2968 debug_printf( 3, "screen initialized with: " SIZE_T_FMT "x" SIZE_T_FMT
2969 " pixels (scaled to " SIZE_T_FMT "x" SIZE_T_FMT
2970 ") with " SIZE_T_FMT " colors",
2971 g_retroflat_state->screen_v_w, g_retroflat_state->screen_v_h,
2972 g_retroflat_state->screen_w, g_retroflat_state->screen_h,
2973 retroflat_screen_colors() );
2974
2975 /* Setup the refresh grid, if requested, only after screen space has been
2976 * determined by the platform!
2977 */
2978 maug_cleanup_if_eq(
2979 (size_t)0, retroflat_screen_w(), SIZE_T_FMT, MERROR_GUI );
2980 maug_cleanup_if_eq(
2981 (size_t)0, retroflat_screen_h(), SIZE_T_FMT, MERROR_GUI );
2982 maug_cleanup_if_eq(
2983 (size_t)0, retroflat_screen_colors(), SIZE_T_FMT, MERROR_GUI );
2984
2985 /* This is intended as a default and can be modified by calling this macro
2986 * again later.
2987 */
2988 retroflat_viewport_set_pos_size(
2989 0, 0, retroflat_screen_w(), retroflat_screen_h() );
2990
2991#ifndef RETROFLAT_NO_VIEWPORT_REFRESH
2992 debug_printf( 1, "allocating refresh grid (%d tiles...)",
2993 g_retroflat_state->viewport.screen_tile_w *
2994 g_retroflat_state->viewport.screen_tile_h );
2995 maug_malloc_test(
2996 g_retroflat_state->viewport.refresh_grid_h,
2997 (g_retroflat_state->viewport.screen_tile_w + 2) *
2998 (g_retroflat_state->viewport.screen_tile_h + 2),
2999 sizeof( retroflat_tile_t ) );
3000#endif /* !RETROFLAT_NO_VIEWPORT_REFRESH */
3001
3002# ifdef RETROFLAT_VDP
3003# if defined( RETROFLAT_OS_UNIX )
3004 g_retroflat_state->vdp_exe = dlopen(
3005 "./" RETROFLAT_VDP_LIB_NAME ".so", RTLD_LAZY );
3006# elif defined( RETROFLAT_OS_WIN )
3007 g_retroflat_state->vdp_exe = LoadLibrary(
3008 "./" RETROFLAT_VDP_LIB_NAME ".dll" );
3009# else
3010# error "dlopen undefined!"
3011# endif /* RETROFLAT_OS_UNIX */
3012
3013 if( !(g_retroflat_state->vdp_exe) ) {
3014 error_printf( "not loading VDP" );
3015 /* Skip creating the buffer or trying to run the init proc. */
3016 goto skip_vdp;
3017 }
3018
3019 debug_printf( 1, "initializing VDP..." );
3020 retval = retroflat_vdp_call( "retroflat_vdp_init" );
3021 maug_cleanup_if_not_ok();
3022
3023skip_vdp:
3024
3025# endif /* RETROFLAT_VDP */
3026
3027# ifdef RETROFLAT_3D
3028 retro3d_platform_init();
3029# endif /* RETROFLAT_3D */
3030
3031# if !defined( RETROFLAT_NO_BLANK_INIT ) && !defined( RETROFLAT_3D )
3032 retroflat_draw_lock( NULL );
3034 NULL, RETROFLAT_COLOR_BLACK, 0, 0,
3035 retroflat_screen_w(), retroflat_screen_h(),
3037 retroflat_draw_release( NULL );
3038# endif /* !RETROFLAT_NO_BLANK_INIT */
3039
3040cleanup:
3041
3042 return retval;
3043}
3044
3045/* === */
3046
3047void retroflat_shutdown( int retval ) {
3048
3049 debug_printf( 1, "retroflat shutdown called..." );
3050
3051#ifndef RETROFLAT_NO_VIEWPORT_REFRESH
3052 if(
3053 NULL != g_retroflat_state &&
3054 (MAUG_MHANDLE)NULL != g_retroflat_state->viewport.refresh_grid_h
3055 ) {
3056 maug_mfree( g_retroflat_state->viewport.refresh_grid_h );
3057 }
3058#endif /* !RETROFLAT_NO_VIEWPORT_REFRESH */
3059
3060# if defined( RETROFLAT_VDP )
3061 if( NULL != g_retroflat_state->vdp_exe ) {
3062 retroflat_vdp_call( "retroflat_vdp_shutdown" );
3063# ifdef RETROFLAT_OS_UNIX
3064 dlclose( g_retroflat_state->vdp_exe );
3065# elif defined( RETROFLAT_OS_WIN )
3066 FreeLibrary( g_retroflat_state->vdp_exe );
3067# else
3068# error "dlclose undefined!"
3069# endif /* RETROFLAT_OS_UNIX || RETROFLAT_OS_WIN */
3070 }
3071# endif /* RETROFLAT_VDP */
3072
3073 /* === Platform-Specific Shutdown === */
3074
3075#ifdef RETROFLAT_3D
3076 retro3d_platform_shutdown();
3077#endif /* RETROFLAT_3D */
3078
3079 retroflat_shutdown_platform( retval );
3080
3081#ifndef RETROFLAT_STATE_ON_STACK
3082 maug_munlock( g_retroflat_state_h, g_retroflat_state );
3083 maug_mfree( g_retroflat_state_h );
3084#endif /* !RETROFLAT_STATE_ON_STACK */
3085
3086}
3087
3088/* === */
3089
3090RETROFLAT_IN_KEY retroflat_repeat_input(
3091 RETROFLAT_IN_KEY key_out, struct RETROFLAT_INPUT* input,
3092 RETROFLAT_IN_KEY* prev_input, int* prev_delay
3093) {
3094
3095 /* Add a slight debounce for gamepad button repeat. */
3096 if( 0 < (*prev_delay) ) {
3097 debug_printf(
3098 RETROINPUT_TRACE_LVL,
3099 "repeat delay: %d", (*prev_delay) );
3100 (*prev_delay)--;
3101 }
3102
3103 /* If nothing else happened and repeat is enabled and a joypad button is
3104 * down, then emulate repeat for it.
3105 */
3106 if(
3107 0 == key_out &&
3109 (RETROFLAT_STATE_FLAG_KEY_REPEAT & g_retroflat_state->retroflat_flags) &&
3110 /* There is an input to repeat. */
3111 0 != *prev_input &&
3112 /* Delay countdown reached. */
3113 0 == *prev_delay
3114 ) {
3115 key_out = *prev_input;
3116 *prev_delay = 1;
3117 debug_printf( RETROINPUT_TRACE_LVL, "repeat: %d", key_out );
3118 }
3119
3120 return key_out;
3121}
3122
3123/* === */
3124
3125ssize_t retroflat_timer_add(
3126 retroflat_ms_t at_time, retroflat_timer_cb_t cb, void* data
3127) {
3128 if( retroflat_get_ms() > at_time ) {
3129 error_printf( "timer time is in the past!" );
3130 return merror_retval_to_sz( MERROR_EXEC );
3131 }
3132
3133 if( g_retroflat_state->timers_ct + 1 < RETROFLAT_TIMER_CT_MAX ) {
3134 g_retroflat_state->timers_cb[g_retroflat_state->timers_ct] = cb;
3135 g_retroflat_state->timers_at[g_retroflat_state->timers_ct] = at_time;
3136 g_retroflat_state->timers_ct++;
3137 return g_retroflat_state->timers_ct - 1;
3138 }
3139
3140 error_printf( "too many timers!" );
3141 return merror_retval_to_sz( MERROR_OVERFLOW );
3142}
3143
3144/* === */
3145
3147 size_t i = 0;
3148 retroflat_ms_t time_now = 0;
3149
3150 time_now = retroflat_get_ms();
3151
3152 for( i = 0 ; g_retroflat_state->timers_ct > i ; i++ ) {
3153 if( g_retroflat_state->timers_at[i] <= time_now ) {
3154 g_retroflat_state->timers_cb[i](
3155 time_now, g_retroflat_state->timers_data[i] );
3156 memmove(
3157 &(g_retroflat_state->timers_cb[i]),
3158 &(g_retroflat_state->timers_cb[i + 1]),
3159 sizeof( retroflat_timer_cb_t ) *
3160 ((g_retroflat_state->timers_ct - i) - 1)
3161 );
3162 memmove(
3163 &(g_retroflat_state->timers_at[i]),
3164 &(g_retroflat_state->timers_at[i + 1]),
3165 sizeof( retroflat_ms_t ) * ((g_retroflat_state->timers_ct - i) - 1)
3166 );
3167 memmove(
3168 &(g_retroflat_state->timers_data[i]),
3169 &(g_retroflat_state->timers_data[i + 1]),
3170 sizeof( void* ) * ((g_retroflat_state->timers_ct - i) - 1)
3171 );
3172 g_retroflat_state->timers_ct--;
3173 i--;
3174 }
3175 }
3176}
3177
3178/* === */
3179
3181 struct RETROFLAT_BITMAP* bitmap,
3182 int16_t instance,
3186) {
3187 retroflat_pxxy_t trim_bottom = *d_y + *h;
3188 retroflat_pxxy_t trim_right = *d_x + *w;
3189 retroflat_pxxy_t viewport_bottom = 0;
3190 retroflat_pxxy_t viewport_right = 0;
3191 retroflat_pxxy_t viewport_left = 0;
3192 retroflat_pxxy_t viewport_top = 0;
3193
3194 if(
3195 /* On the screen, constrain to the edges of the viewport. */
3196 retroflat_screen_buffer() == bitmap &&
3197 /* Probably blitting a window or other element that can go anywhere. */
3198 RETROFLAT_INSTANCE_NULL != instance
3199 ) {
3200 viewport_left = retroflat_viewport_screen_get_x();
3201 viewport_top = retroflat_viewport_screen_get_y();
3202 viewport_bottom =
3203 (retroflat_viewport_screen_get_y() + retroflat_viewport_screen_h());
3204 viewport_right =
3205 (retroflat_viewport_screen_get_x() + retroflat_viewport_screen_w());
3206
3207 } else {
3208 /* Constrain to the edges of the arbitrary bitmap. */
3209 viewport_bottom = retroflat_bitmap_h( bitmap );
3210 viewport_right = retroflat_bitmap_w( bitmap );
3211 }
3212
3213 if( viewport_bottom < *d_y || trim_bottom < viewport_top ) {
3214#ifdef RETROFLAT_TRACE_CONSTRAIN
3215 error_printf( "attempted to blit bitmap way out of bounds at %d, %d!",
3216 *d_x, *d_y );
3217#endif /* RETROFLAT_TRACE_CONSTRAIN */
3218 return MERROR_GUI;
3219
3220 } else if( viewport_bottom <= trim_bottom ) {
3221#ifdef RETROFLAT_TRACE_CONSTRAIN
3222 error_printf(
3223 "trimming " SIZE_T_FMT " pixels to get " SIZE_T_FMT " under "
3224 SIZE_T_FMT,
3225 trim_bottom - viewport_bottom, trim_bottom, viewport_bottom );
3226#endif /* RETROFLAT_TRACE_CONSTRAIN */
3227 *h -= (trim_bottom - viewport_bottom);
3228
3229 } else if( viewport_top > *d_y ) {
3230#ifdef RETROFLAT_TRACE_CONSTRAIN
3231 error_printf(
3232 "trimming " SIZE_T_FMT " pixels to get " SIZE_T_FMT " under "
3233 SIZE_T_FMT,
3234 trim_bottom - viewport_bottom, trim_bottom, viewport_bottom );
3235#endif /* RETROFLAT_TRACE_CONSTRAIN */
3236 *h -= (viewport_top - *d_y);
3237 if( NULL != s_y ) {
3238 *s_y += (viewport_top - *d_y);
3239 }
3240 *d_y += (viewport_top - *d_y);
3241 assert( viewport_top == *d_y );
3242 }
3243
3244 if( viewport_right < *d_x || trim_right < viewport_left ) {
3245#ifdef RETROFLAT_TRACE_CONSTRAIN
3246 error_printf( "attempted to blit bitmap way out of bounds at %d, %d!",
3247 *d_x, *d_y );
3248#endif /* RETROFLAT_TRACE_CONSTRAIN */
3249 return MERROR_GUI;
3250
3251 } else if( viewport_right <= trim_right ) {
3252#ifdef RETROFLAT_TRACE_CONSTRAIN
3253 error_printf(
3254 "trimming " SIZE_T_FMT " pixels to get " SIZE_T_FMT " under "
3255 SIZE_T_FMT,
3256 trim_right - viewport_right, trim_right, viewport_right );
3257#endif /* RETROFLAT_TRACE_CONSTRAIN */
3258 *w -= (trim_right - viewport_right);
3259
3260 } else if( viewport_left > *d_x ) {
3261#ifdef RETROFLAT_TRACE_CONSTRAIN
3262 error_printf(
3263 "trimming " SIZE_T_FMT " pixels to get " SIZE_T_FMT " under "
3264 SIZE_T_FMT,
3265 trim_bottom - viewport_bottom, trim_bottom, viewport_bottom );
3266#endif /* RETROFLAT_TRACE_CONSTRAIN */
3267 *w -= (viewport_left - *d_x);
3268 if( NULL != s_x ) {
3269 *s_x += (viewport_left - *d_x);
3270 }
3271 *d_x += (viewport_left - *d_x);
3272 assert( viewport_left == *d_x );
3273 }
3274
3275 if( 0 == w && 0 == h ) {
3276 return MERROR_GUI;
3277 }
3278
3279 return MERROR_OK;
3280}
3281
3282/* === */
3283
3284# ifdef RETROFLAT_VDP
3285
3286MERROR_RETVAL retroflat_vdp_call( const char* proc_name ) {
3287 MERROR_RETVAL retval = MERROR_OK;
3289# ifdef RETROFLAT_OS_WIN
3290 char proc_name_ex[256];
3291# endif /* RETROFLAT_OS_WIN */
3292
3293 if( NULL == g_retroflat_state->vdp_exe ) {
3294 goto cleanup;
3295 }
3296
3297# ifdef RETROFLAT_OS_UNIX
3298 vdp_proc = dlsym( g_retroflat_state->vdp_exe, proc_name );
3299# elif defined( RETROFLAT_OS_WIN )
3300 /* Append a _ to the proc_name because Watcom? Windows? */
3301 maug_snprintf( proc_name_ex, 255, "%s_", proc_name );
3302 vdp_proc = (retroflat_vdp_proc_t)GetProcAddress(
3303 g_retroflat_state->vdp_exe, proc_name_ex );
3304# else
3305# error "dlsym undefined!"
3306# endif
3307 if( (retroflat_vdp_proc_t)NULL == vdp_proc ) {
3308 goto cleanup;
3309 }
3310
3311# ifdef RETROFLAT_OS_WIN
3312 retroflat_draw_lock( g_retroflat_state->vdp_buffer_in );
3313# endif /* RETROFLAT_OS_WIN */
3314
3315 if(
3316 /* Don't pxlock before init can set the flag! */
3317 0 == strcmp( "retroflat_vdp_flip", proc_name ) &&
3319 (RETROFLAT_VDP_FLAG_PXLOCK & g_retroflat_state->vdp_flags)
3320 ) {
3321 retroflat_vdp_lock( g_retroflat_state->vdp_buffer_in );
3322 retroflat_vdp_lock( g_retroflat_state->vdp_buffer_out );
3323 }
3324
3325 retval = vdp_proc( g_retroflat_state );
3326
3327 if(
3328 0 == strcmp( "retroflat_vdp_flip", proc_name ) &&
3330 (RETROFLAT_VDP_FLAG_PXLOCK & g_retroflat_state->vdp_flags)
3331 ) {
3332 retroflat_vdp_release( g_retroflat_state->vdp_buffer_out );
3333 retroflat_vdp_release( g_retroflat_state->vdp_buffer_in );
3334 }
3335
3336# ifdef RETROFLAT_OS_WIN
3337 retroflat_draw_release( g_retroflat_state->vdp_buffer );
3338# endif /* RETROFLAT_OS_WIN */
3339
3340cleanup:
3341 return retval;
3342}
3343
3344# endif /* RETROFLAT_VDP */
3345
3346/* === */
3347
3348#if 0
3349
3350void retroflat_cursor( struct RETROFLAT_BITMAP* target, uint8_t flags ) {
3351#if 0
3352 char mouse_str[11] = "";
3353
3354 maug_snprintf(
3355 mouse_str, 10, "%02d, %02d", g_retroflat_state->last_mouse_x, g_retroflat_state->last_mouse_y );
3356
3358 target, RETROFLAT_COLOR_BLACK,
3359 mouse_str, 10, NULL, 0, 0, 0 );
3361 target, RETROFLAT_COLOR_BLACK,
3362 g_retroflat_state->last_mouse_x - 5, g_retroflat_state->last_mouse_y - 5, 10, 10, 0 );
3363#endif
3364}
3365
3366#endif
3367
3368/* === */
3369
3370void maug_critical_error( const char* msg ) {
3372}
3373
3374/* === */
3375
3377 retroflat_proc_resize_t on_resize_in, void* data_in
3378) {
3379 g_retroflat_state->on_resize = on_resize_in;
3380 g_retroflat_state->on_resize_data = data_in;
3381}
3382
3383/* === */
3384
3386 retroflat_proc_focus_t on_focus_in, void* data_in
3387) {
3388 g_retroflat_state->on_focus = on_focus_in;
3389 g_retroflat_state->on_focus_data = data_in;
3390}
3391
3392/* === */
3393
3395 retroflat_proc_quit_t on_quit_in, void* data_in
3396) {
3397 g_retroflat_state->on_quit = on_quit_in;
3398 g_retroflat_state->on_quit_data = data_in;
3399}
3400
3401/* === */
3402
3403uint8_t retroflat_viewport_move_x_generic( int16_t x ) {
3404 int16_t new_world_x = g_retroflat_state->viewport.world_x + x;
3405
3406 /* Keep the viewport in the world arena. */
3407 if(
3408 0 <= new_world_x &&
3409 g_retroflat_state->viewport.world_w >= new_world_x +
3410 g_retroflat_state->viewport.screen_w
3411 ) {
3412 g_retroflat_state->viewport.world_x += x;
3413 g_retroflat_state->viewport.world_tile_x += x >> RETROFLAT_TILE_W_BITS;
3414 return 1;
3415 }
3416
3417 return 0;
3418}
3419
3420/* === */
3421
3422uint8_t retroflat_viewport_move_y_generic( int16_t y ) {
3423 int16_t new_world_y = g_retroflat_state->viewport.world_y + y;
3424
3425 /* Keep the viewport in the world arena. */
3426 if(
3427 0 <= new_world_y &&
3428 g_retroflat_state->viewport.world_h >= new_world_y +
3429 g_retroflat_state->viewport.screen_h
3430 ) {
3431 g_retroflat_state->viewport.world_y += y;
3432 g_retroflat_state->viewport.world_tile_y += y >> RETROFLAT_TILE_H_BITS;
3433 return 1;
3434 }
3435
3436 return 0;
3437}
3438
3439/* === */
3440
3441uint8_t retroflat_viewport_focus_generic(
3444) {
3445 uint8_t moved = 0,
3446 new_moved = 0;
3447 int16_t new_pt = 0;
3448
3449# define _retroflat_viewport_focus_dir( n, xy, wh, gl, pm, dir, range, speed ) \
3450 new_pt = n - retroflat_viewport_world_ ## xy(); \
3451 if( new_pt gl (retroflat_screen_ ## wh() >> 1) pm range ) { \
3452 new_moved = retroflat_viewport_move_ ## xy( \
3453 gc_retroflat_offsets8_ ## xy[RETROFLAT_DIR8_ ## dir] * speed ); \
3454 if( !moved && new_moved ) { \
3455 moved = new_moved; \
3456 } \
3457 }
3458
3459 _retroflat_viewport_focus_dir( x1, x, w, <, -, WEST, range, speed );
3460 _retroflat_viewport_focus_dir( x1, x, w, >, +, EAST, range, speed );
3461 _retroflat_viewport_focus_dir( y1, y, h, <, -, NORTH, range, speed );
3462 _retroflat_viewport_focus_dir( y1, y, h, >, +, SOUTH, range, speed );
3463
3464 return moved;
3465}
3466
3467/* === */
3468
3469#ifdef RETROFLAT_LOAD_BITMAP_GENERIC
3470
3471/* This is a generic function that uses the callback
3472 * retroflat_load_bitmap_px_cb(), which should be defined by the
3473 * platform-specific API to draw the loaded bitmap onto a native canvas.
3474 */
3475
3477 const char* filename, struct RETROFLAT_BITMAP* bmp_out, uint8_t flags
3478) {
3479 maug_path filename_path;
3480 MERROR_RETVAL retval = MERROR_OK;
3481 mfile_t bmp_file;
3482 struct MFMT_STRUCT_BMPFILE header_bmp;
3483 uint8_t bmp_flags = 0;
3484
3485 assert( NULL != bmp_out );
3486 maug_mzero( bmp_out, sizeof( struct RETROFLAT_BITMAP ) );
3487 retval = retroflat_build_filename_path(
3488 filename, RETROFLAT_BITMAP_EXT, filename_path,
3489 MAUG_PATH_SZ_MAX, flags );
3490 maug_cleanup_if_not_ok();
3491 debug_printf( 1, "retroflat: loading bitmap: %s", filename_path );
3492
3493 bmp_out->flags = flags;
3494
3495 /* Open the bitmap file. */
3496 retval = mfile_open_read( filename_path, &bmp_file );
3497 maug_cleanup_if_not_ok();
3498
3499 /* mfmt file detection system. */
3500 maug_mzero( &header_bmp, sizeof( struct MFMT_STRUCT_BMPFILE ) );
3501 header_bmp.magic[0] = 'B';
3502 header_bmp.magic[1] = 'M';
3503 header_bmp.info.sz = 40;
3504
3505 retval = mfmt_read_bmp_header(
3506 (struct MFMT_STRUCT*)&header_bmp,
3507 &bmp_file, 0, mfile_get_sz( &bmp_file ), &bmp_flags );
3508 maug_cleanup_if_not_ok();
3509
3510 retval = retroflat_create_bitmap(
3511 header_bmp.info.width, header_bmp.info.height, bmp_out, flags );
3512 maug_cleanup_if_not_ok();
3513
3514 retroflat_draw_lock( bmp_out );
3515
3516 retval = mfmt_read_bmp_px_cb(
3517 (struct MFMT_STRUCT*)&header_bmp,
3518 &bmp_file,
3519 header_bmp.px_offset,
3520 mfile_get_sz( &bmp_file ) - header_bmp.px_offset,
3521 bmp_flags,
3522 retroflat_load_bitmap_px_cb,
3523 bmp_out );
3524 maug_cleanup_if_not_ok();
3525
3526 retroflat_draw_release( bmp_out );
3527
3528cleanup:
3529
3530 mfile_close( &bmp_file );
3531
3532 return retval;
3533}
3534
3535#endif /* RETROFLAT_LOAD_BITMAP_GENERIC */
3536
3537#elif !defined( RETROVDP_C ) /* End of RETROFLT_C */
3538
3543
3544extern MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets8_x[8];
3545extern MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets8_y[8];
3546extern MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets4_x[4];
3547extern MAUG_CONST int16_t SEG_MCONST gc_retroflat_offsets4_y[4];
3548
3550
3551#define RETROFLAT_COLOR_TABLE_CONSTS( idx, name_l, name_u, r, g, b, cgac, cgad ) \
3552 extern MAUG_CONST RETROFLAT_COLOR SEG_MCONST RETROFLAT_COLOR_ ## name_u;
3553
3554RETROFLAT_COLOR_TABLE( RETROFLAT_COLOR_TABLE_CONSTS )
3555
3556extern MAUG_CONST char* SEG_MCONST gc_retroflat_color_names[];
3557
3558extern struct RETROFLAT_STATE* SEG_MGLOBAL g_retroflat_state;
3559
3560# if (defined( RETROFLAT_SOFT_SHAPES ) || defined( RETROFLAT_SOFT_LINES ) || \
3561 defined( RETROFLAT_3D ))
3562# define RETROSOFT_PRESENT
3563# endif
3564
3565# ifdef RETROFLAT_3D
3566# include <retro3dp.h>
3567# include <retro3d.h>
3568# include <retro3du.h>
3569# endif /* RETROFLAT_3D */
3570
3571# ifdef RETROSOFT_PRESENT
3572# include <retrosft.h>
3573# endif /* RETROFLAT_SOFT_SHAPES */
3574
3575/* Second retapis.h include for function bodies not needed. */
3576
3577/* Second retapii.h include for function bodies not needed. */
3578
3579#endif /* RETROFLT_C */
3580
3581#ifdef RETROFLAT_XPM
3582#include <retroxpm.h>
3583#endif /* RETROFLAT_XPM */
3584
3585#ifdef RETROVDP_C
3586
3587/* Declarations for VDP sources. */
3588
3589#endif /* RETROVDP_C */
3590 /* maug_retroflt */
3592
3593#endif /* RETROFLT_H */
3594
MERROR_RETVAL maug_add_arg(const char *arg, int arg_sz, const char *help, int help_sz, maug_cli_cb arg_cb, void *data)
Add a command-line argument to the built-in parser.
#define MAUG_CLI_SIGIL
Default flag to prepend to CLI arguments. Is "/" on Windows/DOS and "-" on other platforms....
Definition marge.h:39
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:28
void maug_critical_error(const char *msg)
Display an error dialog. This is a minimal function that can be called early on (e....
MERROR_RETVAL mfmt_read_bmp_px_cb(struct MFMT_STRUCT *header, mfile_t *p_file_in, uint32_t px_offset, off_t file_sz, uint8_t flags, mfmt_read_1px_cb px_cb, void *px_cb_data)
Read mfmt_bitmap pixels and process them using a callback.
MERROR_RETVAL mfile_open_read(const maug_path filename, mfile_t *p_file)
Open a file and read it into memory or memory-map it.
#define MAUG_PATH_SZ_MAX
Maximum size allocated for asset paths.
Definition mfile.h:41
void mfile_close(mfile_t *p_file)
Close a file opened with mfile_open_read().
char maug_path[MAUG_PATH_SZ_MAX]
Path/name used to load an asset from disk or access other files.
Definition mfile.h:141
#define RETROFLAT_BITMAP_EXT
The filename suffix to be appended with a "." to filenames passed to retroflat_load_bitmap()....
Definition retroflt.h:611
void retroflat_destroy_bitmap(struct RETROFLAT_BITMAP *bitmap)
Unload a bitmap from a RETROFLAT_BITMAP struct. The struct, itself, is not freed (in case it is on th...
MERROR_RETVAL retroflat_load_bitmap(const char *filename, struct RETROFLAT_BITMAP *bmp_out, uint8_t flags)
Load a bitmap into the given RETROFLAT_BITMAP structure if it is available. Bitmaps are subject to th...
#define RETROFLAT_INSTANCE_NULL
Pass to retroflat_blit_bitmap() instance arg if this is not a sprite (i.e. if it is a background tile...
Definition retroflt.h:597
MERROR_RETVAL retroflat_trim_px(struct RETROFLAT_BITMAP *bitmap, int16_t instance, retroflat_pxxy_t *s_x, retroflat_pxxy_t *s_y, retroflat_pxxy_t *d_x, retroflat_pxxy_t *d_y, retroflat_pxxy_t *w, retroflat_pxxy_t *h)
Chop w/h down to fit inside viewport or just fail if it's impossible.
MERROR_RETVAL retroflat_blit_bitmap(struct RETROFLAT_BITMAP *target, struct RETROFLAT_BITMAP *src, retroflat_pxxy_t s_x, retroflat_pxxy_t s_y, retroflat_pxxy_t d_x, retroflat_pxxy_t d_y, retroflat_pxxy_t w, retroflat_pxxy_t h, int16_t instance)
Blit the contents of a RETROFLAT_BITMAP onto another RETROFLAT_BITMAP.
int8_t RETROFLAT_COLOR
Defines an index in the platform-specific color-table.
Definition retroflt.h:326
#define RETROFLAT_COLOR_TABLE(f)
This macro defines all colors supported by RetroFlat for primative operations, particularly using ret...
Definition retroflt.h:307
#define RETROFLAT_VDP_ARGS_SZ_MAX
Definition retroflt.h:756
#define RETROFLAT_PATH_SEP
The valid path separator on the target platform.
Definition retroflt.h:777
void retroflat_ellipse(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, retroflat_pxxy_t x, retroflat_pxxy_t y, retroflat_pxxy_t w, retroflat_pxxy_t h, uint8_t flags)
Draw an ellipse onto the target RETROFLAT_BITMAP.
#define RETROFLAT_BITMAP_FLAG_LITERAL_PATH
Flag for retroflat_load_bitmap() to not use assets path.
Definition retroflt.h:385
MERROR_RETVAL retroflat_draw_lock(struct RETROFLAT_BITMAP *bmp)
Lock a bitmap for drawing. This will be done automatically if necessary and not called explicitly,...
#define RETROFLAT_DRAW_FLAG_FILL
Flag for retroflat_rect() or retroflat_ellipse(), indicating drawn shape should be filled.
Definition retroflt.h:374
void retroflat_line(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, retroflat_pxxy_t x1, retroflat_pxxy_t y1, retroflat_pxxy_t x2, retroflat_pxxy_t y2, uint8_t flags)
Draw a straight line onto the target RETROFLAT_BITMAP.
void retroflat_string(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, const char *str, int str_sz, const char *font_str, retroflat_pxxy_t x_orig, retroflat_pxxy_t y_orig, uint8_t flags)
Draw a text string at the specified location in the specified font and color on the target RETROFLAT_...
void retroflat_rect(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, retroflat_pxxy_t x, retroflat_pxxy_t y, retroflat_pxxy_t w, retroflat_pxxy_t h, uint8_t flags)
Draw a rectangle onto the target RETROFLAT_BITMAP.
void retroflat_string_sz(struct RETROFLAT_BITMAP *target, const char *str, size_t str_sz, const char *font_str, retroflat_pxxy_t *w_out, retroflat_pxxy_t *h_out, uint8_t flags)
Get the size in pixels of a text string when drawn with a given font by retroflat_string().
RETROFLAT_IN_KEY retroflat_poll_input(struct RETROFLAT_INPUT *input)
Poll input devices (keyboard/mouse) and return the latest event.
void retroflat_message(uint8_t flags, const char *title, const char *format,...)
Display a message in a dialog box and/or on stderr.
#define RETROFLAT_MSG_FLAG_ERROR
This icon/type flag indicates an error. It will try to display messages in an urgent way with a red i...
Definition retroflt.h:468
void retroflat_timer_handle()
This should be called in the API HAL on every iteration of the main loop (this is done automatically ...
void retroflat_resize_v()
Platform-specific function to resize virtual screen to match physical window size.
uint8_t retroflat_focus_platform()
Platform-specific function to get current focus flags for the generic loop.
void retroflat_set_proc_quit(retroflat_proc_quit_t on_quit_in, void *data_in)
Set the procedure to call when the window is attempted to be closed (on platforms that support window...
MERROR_RETVAL(* retroflat_proc_quit_t)(void *data)
Callback to call when window closing is attempted. Should return MERROR_PREEMPT to defer or MERROR_OK...
Definition retroflt.h:544
ssize_t retroflat_timer_add(retroflat_ms_t time, retroflat_timer_cb_t cb, void *data)
Add a timer callback to be executed at the given time.
void retroflat_set_proc_focus(retroflat_proc_focus_t on_focus_in, void *data_in)
Set the procedure to call when the window gains or loses focus (on platforms that support multitaskin...
void retroflat_set_proc_resize(retroflat_proc_resize_t on_resize_in, void *data_in)
Set the procedure to call when the window is resized (on platforms that support resizing).
MERROR_RETVAL retroflat_vdp_call(const char *proc_name)
Call a function from the retroflat VDP.
MERROR_RETVAL(* retroflat_vdp_proc_t)(struct RETROFLAT_STATE *)
VDP function called from the VDP library.
Definition retroflt.h:520
#define RETROFLAT_VDP_FLAG_PXLOCK
Flag for RETROFLAT_STATE::vdp_flags indicating the VDP requires RetroFlat to pixel-lock the frame bef...
Definition retroflt.h:507
#define retroflat_heartbeat_update()
Check and update RETROFLAT_STATE::heartbeat_frame.
Definition retroflt.h:1641
void retroflat_shutdown(int retval)
Deinitialize RetroFlat and its underlying layers. This should be called once at the end of the progra...
#define RETROFLAT_STATE_FLAG_KEY_REPEAT
Flag indicating keyboard repeat is enabled.
Definition retroflt.h:425
#define RETROFLAT_STATE_FLAG_SCREENSAVER
Flag indicating the current application is running as a screensaver.
Definition retroflt.h:432
int16_t retroflat_pxxy_t
Type used for surface pixel coordinates.
Definition retroflt.h:906
#define RETROFLAT_STATE_FLAG_WAIT_FOR_FPS
Do not execute any more inter-frame loops until next frame.
Definition retroflt.h:438
#define RETROFLAT_STATE_FLAG_RUNNING
Flag indicating that retroflat_loop() should continue executing.
Definition retroflt.h:411
#define retroflat_heartbeat_set(len, max)
Set parameters for the RETROFLAT_STATE::heartbeat_frame.
Definition retroflt.h:1624
#define retroflat_system_task()
Platform-specific task that should be called on every iteration of the generic loop....
Definition retroflt.h:1101
void(* retroflat_loop_iter)(void *data)
Prototype for the main loop function passed to retroflat_loop().
Definition retroflt.h:800
MERROR_RETVAL retroflat_loop(retroflat_loop_iter frame_iter, retroflat_loop_iter loop_iter, void *data)
This should be called once in the main body of the program in order to enter the main loop....
MERROR_RETVAL retroflat_init(int argc, char *argv[], struct RETROFLAT_ARGS *args)
Initialize RetroFlat and its underlying layers. This should be called once at the beginning of the pr...
#define RETROFLAT_STATE_FLAG_UNLOCK_FPS
Flag indicating FPS should not be capped.
Definition retroflt.h:418
void retrosoft_rect(retroflat_blit_t *target, const RETROFLAT_COLOR color_idx, int x, int y, int w, int h, uint8_t flags)
Draw a rectangle at the given coordinates, with the given dimensions.
void retrosoft_ellipse(retroflat_blit_t *target, RETROFLAT_COLOR color, int x, int y, int w, int h, uint8_t flags)
Draw an ellipsoid at the given coordinates, with the given dimensions.
void retrosoft_line(retroflat_blit_t *target, RETROFLAT_COLOR color, int x1, int y1, int x2, int y2, uint8_t flags)
Draw a line from x1, y1 to x2, y2.
void retrosnd_set_sf_bank(const char *filename_in)
Set the name of the voice bank filename to use.
MERROR_RETVAL retrosnd_init(struct RETROFLAT_ARGS *args)
Initialize retrosnd engine.
int16_t retroflat_tile_t
Value for an individual tile in a RETROTILE_LAYER.
Definition retroflt.h:19
Lower-level retargetable 3D engine wrapper.
Tools for drawing shape primatives.
Definition mfmt.h:124
Generic image description struct.
Definition mfmt.h:69
Definition retroflt.h:1078
Struct containing configuration values for a RetroFlat program.
Definition retroflt.h:1115
char * config_path
Relative path of local config file (if not using registry).
Definition retroflt.h:1125
char * assets_path
Relative path under which bitmap assets are stored.
Definition retroflt.h:1123
int screen_w
Desired screen or window width in pixels.
Definition retroflt.h:1132
int screen_h
Desired screen or window height in pixels.
Definition retroflt.h:1139
int screen_colors
Desired colors (2, 4, or 16, for now). \TODO Implement command-line argument for this....
Definition retroflt.h:1151
char * title
Title to set for the main program Window if applicable on the target platform.
Definition retroflt.h:1121
int screen_y
Desired window Y position in pixels.
Definition retroflt.h:1143
int screen_x
Desired window X position in pixels.
Definition retroflt.h:1141
Struct passed to retroflat_poll_input() to hold return data.
Definition retroflt.h:850
int mouse_y
Y-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:860
int mouse_x
X-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:855
Global singleton containing state for the current platform.
Definition retroflt.h:1661
size_t screen_h
The screen height as seen by the system, after scaling.
Definition retroflt.h:1729
uint8_t vdp_flags
Flags set by the RetroFlat VDP API.
Definition retroflt.h:1705
size_t screen_v_w
The screen width as seen by our program, before scaling.
Definition retroflt.h:1718
size_t screen_colors
The number of colors the screen is capable of displaying.
Definition retroflt.h:1731
RETROFLAT_COLOR_DEF palette[RETROFLAT_COLORS_CT_MAX]
Index of available colors, initialized on platform init.
Definition retroflt.h:1776
uint8_t retroflat_flags
maug_retroflt_flags indicating current system status.
Definition retroflt.h:1671
uint8_t heartbeat_max
When RETROFLAT_STATE::heartbeat_frame reaches this value, it will reset to 0.
Definition retroflt.h:1758
retroflat_timer_cb_t timers_cb[RETROFLAT_TIMER_CT_MAX]
List of installable timers that should be tended every frame with retroflat_handle_timers().
Definition retroflt.h:1798
uint8_t heartbeat_frame
Simple iteration loop that can be used to time e.g. perpetual sprite animations. Modify parameters wi...
Definition retroflt.h:1753
size_t screen_w
The screen width as seen by the system, after scaling.
Definition retroflt.h:1727
void * vdp_exe
A handle for the loaded RetroFlat VDP API module.
Definition retroflt.h:1695
uint8_t last_focus_flags
Used internally to track whether to call on_focus().
Definition retroflt.h:1768
uint16_t heartbeat_len
Number of ms to stay on current value of RETROFLAT_STATE::heartbeat_frame before incrementing....
Definition retroflt.h:1747
void * vdp_data
Pointer to data defined by the RetroFlat VDP API for its use.
Definition retroflt.h:1701
struct RETROFLAT_BITMAP * vdp_buffer_in
A buffer assembled and passed to the RetroFlat VDP API for it to modify, or NULL if no VDP is loaded.
Definition retroflt.h:1689
size_t screen_v_h
The screen height as seen by our program, before scaling.
Definition retroflt.h:1725
int screen_scale
Off-screen buffer bitmap.
Definition retroflt.h:1678
retroflat_proc_quit_t on_quit
Should be set with retroflat_set_proc_focus().
Definition retroflt.h:1771
char vdp_args[RETROFLAT_VDP_ARGS_SZ_MAX+1]
CLI args passed with -vdp to the RetroFlat VDP API.
Definition retroflt.h:1703
retroflat_proc_focus_t on_focus
Should be set with retroflat_set_proc_focus().
Definition retroflt.h:1765
retroflat_proc_resize_t on_resize
Should be set with retroflat_set_proc_resize().
Definition retroflt.h:1761
The viewport data struct.
Definition retroflt.h:1176
retroflat_pxxy_t world_x
The X offset, in pixels, of the viewport on the world tilemap. Should only be retrieved through retro...
Definition retroflt.h:1194
retroflat_tile_t * refresh_grid
A grid of tile values representing the last-drawn values on-screen.
Definition retroflt.h:1267
retroflat_pxxy_t screen_h
Viewport height in pixels. Should only be retrieved through retroflat_viewport_screen_w() and set thr...
Definition retroflt.h:1224
retroflat_pxxy_t screen_h_remainder
Difference between viewport height and screen height in pixels. Should only be retrieved through retr...
Definition retroflt.h:1238
retroflat_pxxy_t screen_y
Y position of the viewport in real screen memory in pixels. Should only be retrieved through retrofla...
Definition retroflt.h:1188
retroflat_pxxy_t screen_x
X position of the viewport in real screen memory in pixels. Should only be retrieved through retrofla...
Definition retroflt.h:1182
int16_t screen_tile_w
The number of tiles across that fit in the viewport. Should only be retrieved through retroflat_viewp...
Definition retroflt.h:1245
retroflat_pxxy_t world_w
The width of the entire world tilemap in pixels. Should only be retrieved through retroflat_viewport_...
Definition retroflt.h:1206
retroflat_pxxy_t world_y
The Y offset, in pixels, of the viewport on the world tilemap. Should only be retrieved through retro...
Definition retroflt.h:1200
retroflat_pxxy_t screen_w_remainder
Difference between viewport width and screen width in pixels. Should only be retrieved through retrof...
Definition retroflt.h:1231
retroflat_pxxy_t screen_w
Viewport width in pixels. Should only be retrieved through retroflat_viewport_screen_w() and set thro...
Definition retroflt.h:1218
int16_t screen_tile_h
The number of tiles high that fit in the viewport. Should only be retrieved through retroflat_viewpor...
Definition retroflt.h:1252
retroflat_pxxy_t world_h
The height of the entire world tilemap in pixels. Should only be retrieved through retroflat_viewport...
Definition retroflt.h:1212