Subversion Repositories Kolibri OS

Rev

Rev 9840 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /**
  2.  * SDL interface
  3.  */
  4.  
  5. #ifdef __MINGW32__
  6. #undef __STRICT_ANSI__
  7. #endif
  8.  
  9. #include <sys/time.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <stdint.h>
  13. #include <string.h>
  14. #include <strings.h>
  15. #include <stdarg.h>
  16. #include <unistd.h>
  17. #include <errno.h>
  18. #include <ctype.h>
  19. #include <assert.h>
  20. #include <SDL.h>
  21. #include <SDL_audio.h>
  22.  
  23. #ifdef WITH_OPENGL
  24. # include <SDL_opengl.h>
  25. #endif
  26.  
  27. #ifdef WITH_THREADS
  28. #include <SDL_thread.h>
  29. #endif
  30.  
  31. #ifdef HAVE_MEMCPY_H
  32. #include "memcpy.h"
  33. #endif
  34. #include "md.h"
  35. #include "rc.h"
  36. #include "rc-vars.h"
  37. #include "pd.h"
  38. #include "pd-defs.h"
  39. #include "font.h"
  40. #include "system.h"
  41. #include "prompt.h"
  42. #include "romload.h"
  43. #include "splash.h"
  44.  
  45. #ifdef WITH_HQX
  46. #define HQX_NO_UINT24
  47. #include "hqx.h"
  48. #endif
  49.  
  50. #ifdef WITH_SCALE2X
  51. extern "C" {
  52. #include "scalebit.h"
  53. }
  54. #endif
  55.  
  56. #ifdef _KOLIBRI
  57. extern "C" {
  58. #include <ksys.h>
  59. }
  60. #endif
  61.  
  62. /// Number of microseconds to sustain messages
  63. #define MESSAGE_LIFE 3000000
  64.  
  65. static void pd_message_process(void);
  66. static size_t pd_message_write(const char *msg, size_t len, unsigned int mark);
  67. static size_t pd_message_display(const char *msg, size_t len,
  68.                                  unsigned int mark, bool update);
  69. static void pd_message_postpone(const char *msg);
  70. static void pd_message_cursor(unsigned int mark, const char *msg, ...);
  71.  
  72. /// Generic type for supported colour depths.
  73. typedef union {
  74.         uint8_t *u8;
  75.         uint32_t *u32;
  76.         uint24_t *u24;
  77.         uint16_t *u16;
  78.         uint16_t *u15;
  79. } bpp_t;
  80.  
  81. #ifdef WITH_OPENGL
  82.  
  83. /// Framebuffer texture.
  84. struct texture {
  85.         unsigned int width; ///< texture width
  86.         unsigned int height; ///< texture height
  87.         unsigned int vis_width; ///< visible width
  88.         unsigned int vis_height; ///< visible height
  89.         GLuint id; ///< texture identifier
  90.         GLuint dlist; ///< display list
  91.         unsigned int u32:1; ///< texture is 32-bit
  92.         unsigned int linear:1; ///< linear filtering is enabled
  93.         union {
  94.                 uint16_t *u16;
  95.                 uint32_t *u32;
  96.         } buf; ///< 16 or 32-bit buffer
  97. };
  98.  
  99. static void release_texture(struct texture&);
  100. static int init_texture(struct screen *);
  101. static void update_texture(struct texture&);
  102.  
  103. #endif // WITH_OPENGL
  104.  
  105. struct screen {
  106.         unsigned int window_width; ///< window width
  107.         unsigned int window_height; ///< window height
  108.         unsigned int width; ///< buffer width
  109.         unsigned int height; ///< buffer height
  110.         unsigned int bpp; ///< bits per pixel
  111.         unsigned int Bpp; ///< bytes per pixel
  112.         unsigned int x_scale; ///< horizontal scale factor
  113.         unsigned int y_scale; ///< vertical scale factor
  114.         unsigned int info_height; ///< message bar height (included in height)
  115.         bpp_t buf; ///< generic pointer to pixel data
  116.         unsigned int pitch; ///< number of bytes per line in buf
  117.         SDL_Surface *surface; ///< SDL surface
  118.         unsigned int want_fullscreen:1; ///< want fullscreen
  119.         unsigned int is_fullscreen:1; ///< fullscreen enabled
  120. #ifdef WITH_OPENGL
  121.         struct texture texture; ///< OpenGL texture data
  122.         unsigned int want_opengl:1; ///< want OpenGL
  123.         unsigned int is_opengl:1; ///< OpenGL enabled
  124. #endif
  125. #ifdef WITH_THREADS
  126.         unsigned int want_thread:1; ///< want updates from a separate thread
  127.         unsigned int is_thread:1; ///< thread is present
  128.         SDL_Thread *thread; ///< thread itself
  129.         SDL_mutex *lock; ///< lock for updates
  130.         SDL_cond *cond; ///< condition variable to signal updates
  131. #endif
  132.         SDL_Color color[64]; ///< SDL colors for 8bpp modes
  133. };
  134.  
  135. static struct screen screen;
  136.  
  137. static struct {
  138.         const unsigned int width; ///< 320
  139.         unsigned int height; ///< 224 or 240 (NTSC_VBLANK or PAL_VBLANK)
  140.         unsigned int hz; ///< refresh rate
  141.         unsigned int is_pal: 1; ///< PAL enabled
  142.         uint8_t palette[256]; ///< palette for 8bpp modes (mdpal)
  143. } video = {
  144.         320, ///< width is always 320
  145.         NTSC_VBLANK, ///< NTSC height by default
  146.         NTSC_HZ, ///< 60Hz
  147.         0, ///< NTSC is enabled
  148.         { 0 }
  149. };
  150.  
  151. /**
  152.  * Call this before accessing screen.buf.
  153.  * No syscalls allowed before screen_unlock().
  154.  */
  155. static int screen_lock()
  156. {
  157. #ifdef WITH_THREADS
  158.         if (screen.is_thread) {
  159.                 assert(screen.lock != NULL);
  160.                 SDL_LockMutex(screen.lock);
  161.         }
  162. #endif
  163. #ifdef WITH_OPENGL
  164.         if (screen.is_opengl)
  165.                 return 0;
  166. #endif
  167.         if (SDL_MUSTLOCK(screen.surface) == 0)
  168.                 return 0;
  169.         return SDL_LockSurface(screen.surface);
  170. }
  171.  
  172. /**
  173.  * Call this after accessing screen.buf.
  174.  */
  175. static void screen_unlock()
  176. {
  177. #ifdef WITH_THREADS
  178.         if (screen.is_thread) {
  179.                 assert(screen.lock != NULL);
  180.                 SDL_UnlockMutex(screen.lock);
  181.         }
  182. #endif
  183. #ifdef WITH_OPENGL
  184.         if (screen.is_opengl)
  185.                 return;
  186. #endif
  187.         if (SDL_MUSTLOCK(screen.surface) == 0)
  188.                 return;
  189.         SDL_UnlockSurface(screen.surface);
  190. }
  191.  
  192. /**
  193.  * Do not call this directly, use screen_update() instead.
  194.  */
  195. static void screen_update_once()
  196. {
  197. #ifdef WITH_OPENGL
  198.         if (screen.is_opengl) {
  199.                 update_texture(screen.texture);
  200.                 return;
  201.         }
  202. #endif
  203.         SDL_Flip(screen.surface);
  204. }
  205.  
  206. #ifdef WITH_THREADS
  207.  
  208. static int screen_update_thread(void *)
  209. {
  210.         assert(screen.lock != NULL);
  211.         assert(screen.cond != NULL);
  212.         SDL_LockMutex(screen.lock);
  213.         while (screen.want_thread) {
  214.                 SDL_CondWait(screen.cond, screen.lock);
  215.                 screen_update_once();
  216.         }
  217.         SDL_UnlockMutex(screen.lock);
  218.         return 0;
  219. }
  220.  
  221. static void screen_update_thread_start()
  222. {
  223.         DEBUG(("starting thread..."));
  224.         assert(screen.want_thread);
  225.         assert(screen.lock == NULL);
  226.         assert(screen.cond == NULL);
  227.         assert(screen.thread == NULL);
  228. #ifdef WITH_OPENGL
  229.         if (screen.is_opengl) {
  230.                 DEBUG(("this is not supported when OpenGL is enabled"));
  231.                 return;
  232.         }
  233. #endif
  234.         if ((screen.lock = SDL_CreateMutex()) == NULL) {
  235.                 DEBUG(("unable to create lock"));
  236.                 goto error;
  237.         }
  238.  
  239.         if ((screen.cond = SDL_CreateCond()) == NULL) {
  240.                 DEBUG(("unable to create condition variable"));
  241.                 goto error;
  242.         }
  243.         screen.thread = SDL_CreateThread(screen_update_thread, NULL);
  244.         if (screen.thread == NULL) {
  245.                 DEBUG(("unable to start thread"));
  246.                 goto error;
  247.         }
  248.         screen.is_thread = 1;
  249.         DEBUG(("thread started"));
  250.         return;
  251. error:
  252.         if (screen.cond != NULL) {
  253.                 SDL_DestroyCond(screen.cond);
  254.                 screen.cond = NULL;
  255.         }
  256.         if (screen.lock != NULL) {
  257.                 SDL_DestroyMutex(screen.lock);
  258.                 screen.lock = NULL;
  259.         }
  260. }
  261.  
  262. static void screen_update_thread_stop()
  263. {
  264.         if (!screen.is_thread) {
  265.                 assert(screen.thread == NULL);
  266.                 return;
  267.         }
  268.         DEBUG(("stopping thread..."));
  269.         assert(screen.thread != NULL);
  270.         screen.want_thread = 0;
  271.         SDL_CondSignal(screen.cond);
  272.         SDL_WaitThread(screen.thread, NULL);
  273.         screen.thread = NULL;
  274.         SDL_DestroyCond(screen.cond);
  275.         screen.cond = NULL;
  276.         SDL_DestroyMutex(screen.lock);
  277.         screen.lock = NULL;
  278.         screen.is_thread = 0;
  279.         DEBUG(("thread stopped"));
  280. }
  281.  
  282. #endif // WITH_THREADS
  283.  
  284. /**
  285.  * Call this after writing into screen.buf.
  286.  */
  287. static void screen_update()
  288. {
  289. #ifdef WITH_THREADS
  290.         if (screen.is_thread)
  291.                 SDL_CondSignal(screen.cond);
  292.         else
  293. #endif // WITH_THREADS
  294.                 screen_update_once();
  295. }
  296.  
  297. /**
  298.  * Clear screen.
  299.  */
  300. static void screen_clear()
  301. {
  302.         if ((screen.buf.u8 == NULL) || (screen_lock()))
  303.                 return;
  304.         memset(screen.buf.u8, 0, (screen.pitch * screen.height));
  305.         screen_unlock();
  306. }
  307.  
  308. // Bad hack- extern slot etc. from main.cpp so we can save/load states
  309. extern int slot;
  310. void md_save(md &megad);
  311. void md_load(md &megad);
  312.  
  313. // Define externed variables
  314. struct bmap mdscr;
  315. unsigned char *mdpal = NULL;
  316. struct sndinfo sndi;
  317. const char *pd_options =
  318. #ifdef WITH_OPENGL
  319.         "g:"
  320. #endif
  321.         "fX:Y:S:G:";
  322.  
  323. static void mdscr_splash();
  324.  
  325. /// Circular buffer and related functions.
  326. typedef struct {
  327.         size_t i; ///< data start index
  328.         size_t s; ///< data size
  329.         size_t size; ///< buffer size
  330.         union {
  331.                 uint8_t *u8;
  332.                 int16_t *i16;
  333.         } data; ///< storage
  334. } cbuf_t;
  335.  
  336. /**
  337.  * Write/copy data into a circular buffer.
  338.  * @param[in,out] cbuf Destination buffer.
  339.  * @param[in] src Buffer to copy from.
  340.  * @param size Size of src.
  341.  * @return Number of bytes copied.
  342.  */
  343. size_t cbuf_write(cbuf_t *cbuf, uint8_t *src, size_t size)
  344. {
  345.         size_t j;
  346.         size_t k;
  347.  
  348.         if (size > cbuf->size) {
  349.                 src += (size - cbuf->size);
  350.                 size = cbuf->size;
  351.         }
  352.         k = (cbuf->size - cbuf->s);
  353.         j = ((cbuf->i + cbuf->s) % cbuf->size);
  354.         if (size > k) {
  355.                 cbuf->i = ((cbuf->i + (size - k)) % cbuf->size);
  356.                 cbuf->s = cbuf->size;
  357.         }
  358.         else
  359.                 cbuf->s += size;
  360.         k = (cbuf->size - j);
  361.         if (k >= size) {
  362.                 memcpy(&cbuf->data.u8[j], src, size);
  363.         }
  364.         else {
  365.                 memcpy(&cbuf->data.u8[j], src, k);
  366.                 memcpy(&cbuf->data.u8[0], &src[k], (size - k));
  367.         }
  368.         return size;
  369. }
  370.  
  371. /**
  372.  * Read bytes out of a circular buffer.
  373.  * @param[out] dst Destination buffer.
  374.  * @param[in,out] cbuf Circular buffer to read from.
  375.  * @param size Maximum number of bytes to copy to dst.
  376.  * @return Number of bytes copied.
  377.  */
  378. size_t cbuf_read(uint8_t *dst, cbuf_t *cbuf, size_t size)
  379. {
  380.         if (size > cbuf->s)
  381.                 size = cbuf->s;
  382.         if ((cbuf->i + size) > cbuf->size) {
  383.                 size_t k = (cbuf->size - cbuf->i);
  384.  
  385.                 memcpy(&dst[0], &cbuf->data.u8[(cbuf->i)], k);
  386.                 memcpy(&dst[k], &cbuf->data.u8[0], (size - k));
  387.         }
  388.         else
  389.                 memcpy(&dst[0], &cbuf->data.u8[(cbuf->i)], size);
  390.         cbuf->i = ((cbuf->i + size) % cbuf->size);
  391.         cbuf->s -= size;
  392.         return size;
  393. }
  394.  
  395. /// Sound
  396. static struct {
  397.         unsigned int rate; ///< samples rate
  398.         unsigned int samples; ///< number of samples required by the callback
  399.         cbuf_t cbuf; ///< circular buffer
  400. } sound;
  401.  
  402. /// Messages
  403. static struct {
  404.         unsigned int displayed:1; ///< whether message is currently displayed
  405.         unsigned long since; ///< since this number of microseconds
  406.         size_t length; ///< remaining length to display
  407.         char message[2048]; ///< message
  408. } info;
  409.  
  410. /// Prompt
  411. static struct {
  412.         struct prompt status; ///< prompt status
  413.         char** complete; ///< completion results array
  414.         unsigned int skip; ///< number of entries to skip in the array
  415.         unsigned int common; ///< common length of all entries
  416. } prompt;
  417.  
  418. /// Prompt return values
  419. #define PROMPT_RET_CONT 0x01 ///< waiting for more input
  420. #define PROMPT_RET_EXIT 0x02 ///< leave prompt normally
  421. #define PROMPT_RET_ERROR 0x04 ///< leave prompt with error
  422. #define PROMPT_RET_ENTER 0x10 ///< previous line entered
  423. #define PROMPT_RET_MSG 0x80 ///< pd_message() has been used
  424.  
  425. struct prompt_command {
  426.         const char* name;
  427.         /// command function pointer
  428.         int (*cmd)(class md&, unsigned int, const char**);
  429.         /// completion function shoud complete the last entry in the array
  430.         char* (*cmpl)(class md&, unsigned int, const char**, unsigned int);
  431. };
  432.  
  433. // Extra commands usable from prompt.
  434. static int prompt_cmd_exit(class md&, unsigned int, const char**);
  435. static int prompt_cmd_load(class md&, unsigned int, const char**);
  436. static char* prompt_cmpl_load(class md&, unsigned int, const char**,
  437.                               unsigned int);
  438. static int prompt_cmd_unload(class md&, unsigned int, const char**);
  439. static int prompt_cmd_reset(class md&, unsigned int, const char**);
  440. static int prompt_cmd_unbind(class md&, unsigned int, const char**);
  441. static char* prompt_cmpl_unbind(class md&, unsigned int, const char**,
  442.                                 unsigned int);
  443. #ifdef WITH_CTV
  444. static int prompt_cmd_filter_push(class md&, unsigned int, const char**);
  445. static char* prompt_cmpl_filter_push(class md&, unsigned int, const char**,
  446.                                      unsigned int);
  447. static int prompt_cmd_filter_pop(class md&, unsigned int, const char**);
  448. static int prompt_cmd_filter_none(class md&, unsigned int, const char**);
  449. #endif
  450. static int prompt_cmd_calibrate(class md&, unsigned int, const char**);
  451. static int prompt_cmd_config_load(class md&, unsigned int, const char**);
  452. static int prompt_cmd_config_save(class md&, unsigned int, const char**);
  453. static char* prompt_cmpl_config_file(class md&, unsigned int, const char**,
  454.                                      unsigned int);
  455. #ifdef WITH_VGMDUMP
  456. static char* prompt_cmpl_vgmdump(class md&, unsigned int, const char**,
  457.                                  unsigned int);
  458. static int prompt_cmd_vgmdump(class md&, unsigned int, const char**);
  459. #endif
  460.  
  461. /**
  462.  * List of commands to auto complete.
  463.  */
  464. static const struct prompt_command prompt_command[] = {
  465.         { "quit", prompt_cmd_exit, NULL },
  466.         { "q", prompt_cmd_exit, NULL },
  467.         { "exit", prompt_cmd_exit, NULL },
  468.         { "load", prompt_cmd_load, prompt_cmpl_load },
  469.         { "open", prompt_cmd_load, prompt_cmpl_load },
  470.         { "o", prompt_cmd_load, prompt_cmpl_load },
  471.         { "plug", prompt_cmd_load, prompt_cmpl_load },
  472.         { "unload", prompt_cmd_unload, NULL },
  473.         { "close", prompt_cmd_unload, NULL },
  474.         { "unplug", prompt_cmd_unload, NULL },
  475.         { "reset", prompt_cmd_reset, NULL },
  476.         { "unbind", prompt_cmd_unbind, prompt_cmpl_unbind },
  477. #ifdef WITH_CTV
  478.         { "ctv_push", prompt_cmd_filter_push, prompt_cmpl_filter_push },
  479.         { "ctv_pop", prompt_cmd_filter_pop, NULL },
  480.         { "ctv_none", prompt_cmd_filter_none, NULL },
  481. #endif
  482.         { "calibrate", prompt_cmd_calibrate, NULL },
  483.         { "calibrate_js", prompt_cmd_calibrate, NULL }, // deprecated name
  484.         { "config_load", prompt_cmd_config_load, prompt_cmpl_config_file },
  485.         { "config_save", prompt_cmd_config_save, prompt_cmpl_config_file },
  486. #ifdef WITH_VGMDUMP
  487.         { "vgmdump", prompt_cmd_vgmdump, prompt_cmpl_vgmdump },
  488. #endif
  489.         { NULL, NULL, NULL }
  490. };
  491.  
  492. /// Extra commands return values.
  493. #define CMD_OK 0x00 ///< command successful
  494. #define CMD_EINVAL 0x01 ///< invalid argument
  495. #define CMD_FAIL 0x02 ///< command failed
  496. #define CMD_ERROR 0x03 ///< fatal error, DGen should exit
  497. #define CMD_MSG 0x80 ///< pd_message() has been used
  498.  
  499. /// Stopped flag used by pd_stopped()
  500. static int stopped = 0;
  501.  
  502. /// Events handling status.
  503. static enum events {
  504.         STARTED,
  505.         STOPPED,
  506.         STOPPED_PROMPT,
  507.         STOPPED_GAME_GENIE,
  508.         PROMPT,
  509.         GAME_GENIE
  510. } events = STARTED;
  511.  
  512. static int stop_events(md& megad, enum events status);
  513. static void restart_events(md &megad);
  514.  
  515. /// Messages shown whenever events are stopped.
  516. static const char stopped_str[] = "STOPPED.";
  517. static const char prompt_str[] = ":";
  518. static const char game_genie_str[] = "Enter Game Genie/Hex code: ";
  519.  
  520. /// Enable emulation by default.
  521. bool pd_freeze = false;
  522. static unsigned int pd_freeze_ref = 0;
  523.  
  524. static void freeze(bool toggle)
  525. {
  526.         if (toggle == true) {
  527.                 if (!pd_freeze_ref) {
  528.                         assert(pd_freeze == false);
  529.                         pd_freeze = true;
  530.                 }
  531.                 pd_freeze_ref++;
  532.         }
  533.         else {
  534.                 if (pd_freeze_ref) {
  535.                         assert(pd_freeze == true);
  536.                         pd_freeze_ref--;
  537.                         if (!pd_freeze_ref)
  538.                                 pd_freeze = false;
  539.                 }
  540.                 else
  541.                         assert(pd_freeze == false);
  542.         }
  543. }
  544.  
  545. /**
  546.  * Elapsed time in microseconds.
  547.  * @return Microseconds.
  548.  */
  549. unsigned long pd_usecs(void)
  550. {
  551. #ifndef _KOLIBRI
  552.         struct timeval tv;
  553.         gettimeofday(&tv, NULL);
  554.         return (unsigned long)((tv.tv_sec * 1000000) + tv.tv_usec);
  555. #else
  556.         return _ksys_get_tick_count()*10000;
  557. #endif
  558. }
  559.  
  560. /**
  561.  * Prompt "exit" command handler.
  562.  * @return Error status to make DGen exit.
  563.  */
  564. static int prompt_cmd_exit(class md&, unsigned int, const char**)
  565. {
  566.         return (CMD_ERROR | CMD_MSG);
  567. }
  568.  
  569. /**
  570.  * Prompt "load" command handler.
  571.  * @param md Context.
  572.  * @param ac Number of arguments in av.
  573.  * @param av Arguments.
  574.  * @return Status code.
  575.  */
  576. static int prompt_cmd_load(class md& md, unsigned int ac, const char** av)
  577. {
  578.         extern int slot;
  579.         extern void ram_save(class md&);
  580.         extern void ram_load(class md&);
  581.         char *s;
  582.  
  583.         if (ac != 2)
  584.                 return CMD_EINVAL;
  585.         s = backslashify((const uint8_t *)av[1], strlen(av[1]), 0, NULL);
  586.         if (s == NULL)
  587.                 return CMD_FAIL;
  588.         ram_save(md);
  589.         if (dgen_autosave) {
  590.                 slot = 0;
  591.                 md_save(md);
  592.         }
  593.         md.unplug();
  594.         pd_message("");
  595.         if (md.load(av[1])) {
  596.                 mdscr_splash();
  597.                 pd_message("Unable to load \"%s\"", s);
  598.                 free(s);
  599.                 return (CMD_FAIL | CMD_MSG);
  600.         }
  601.         pd_message("Loaded \"%s\"", s);
  602.         free(s);
  603.         if (dgen_show_carthead)
  604.                 pd_show_carthead(md);
  605.         // Initialize like main() does.
  606.         md.reset();
  607.  
  608.         if (!dgen_region) {
  609.                 uint8_t c = md.region_guess();
  610.                 int hz;
  611.                 int pal;
  612.  
  613.                 md::region_info(c, &pal, &hz, 0, 0, 0);
  614.                 if ((hz != dgen_hz) || (pal != dgen_pal) || (c != md.region)) {
  615.                         md.region = c;
  616.                         dgen_hz = hz;
  617.                         dgen_pal = pal;
  618.                         printf("sdl: reconfiguring for region \"%c\": "
  619.                                "%dHz (%s)\n", c, hz, (pal ? "PAL" : "NTSC"));
  620.                         pd_graphics_reinit(dgen_sound, dgen_pal, dgen_hz);
  621.                         if (dgen_sound) {
  622.                                 long rate = dgen_soundrate;
  623.                                 unsigned int samples;
  624.  
  625.                                 pd_sound_deinit();
  626.                                 samples = (dgen_soundsegs * (rate / dgen_hz));
  627.                                 pd_sound_init(rate, samples);
  628.                         }
  629.                         md.pal = pal;
  630.                         md.init_pal();
  631.                         md.init_sound();
  632.                 }
  633.         }
  634.  
  635.         ram_load(md);
  636.         if (dgen_autoload) {
  637.                 slot = 0;
  638.                 md_load(md);
  639.         }
  640.         return (CMD_OK | CMD_MSG);
  641. }
  642.  
  643. static void rehash_prompt_complete_common()
  644. {
  645.         size_t i;
  646.         unsigned int common;
  647.  
  648.         prompt.common = 0;
  649.         if ((prompt.complete == NULL) || (prompt.complete[0] == NULL))
  650.                 return;
  651.         common = strlen(prompt.complete[0]);
  652.         for (i = 1; (prompt.complete[i] != NULL); ++i) {
  653.                 unsigned int tmp;
  654.  
  655.                 tmp = strcommon(prompt.complete[i], prompt.complete[(i - 1)]);
  656.                 if (tmp < common)
  657.                         common = tmp;
  658.                 if (common == 0)
  659.                         break;
  660.         }
  661.         prompt.common = common;
  662. }
  663.  
  664. static char* prompt_cmpl_load(class md& md, unsigned int ac, const char** av,
  665.                               unsigned int len)
  666. {
  667.         const char *prefix;
  668.         size_t i;
  669.         unsigned int skip;
  670.  
  671.         (void)md;
  672.         assert(ac != 0);
  673.         if ((ac == 1) || (len == ~0u) || (av[(ac - 1)] == NULL)) {
  674.                 prefix = "";
  675.                 len = 0;
  676.         }
  677.         else
  678.                 prefix = av[(ac - 1)];
  679.         if (prompt.complete == NULL) {
  680.                 // Rebuild cache.
  681.                 prompt.skip = 0;
  682.                 prompt.complete = complete_path(prefix, len,
  683.                                                 dgen_rom_path.val);
  684.                 if (prompt.complete == NULL)
  685.                         return NULL;
  686.                 rehash_prompt_complete_common();
  687.         }
  688. retry:
  689.         skip = prompt.skip;
  690.         for (i = 0; (prompt.complete[i] != NULL); ++i) {
  691.                 if (skip == 0)
  692.                         break;
  693.                 --skip;
  694.         }
  695.         if (prompt.complete[i] == NULL) {
  696.                 if (prompt.skip != 0) {
  697.                         prompt.skip = 0;
  698.                         goto retry;
  699.                 }
  700.                 return NULL;
  701.         }
  702.         ++prompt.skip;
  703.         return strdup(prompt.complete[i]);
  704. }
  705.  
  706. static int prompt_cmd_unload(class md& md, unsigned int, const char**)
  707. {
  708.         extern int slot;
  709.         extern void ram_save(class md&);
  710.  
  711.         info.length = 0; // clear postponed messages
  712.         pd_message("No cartridge.");
  713.         ram_save(md);
  714.         if (dgen_autosave) {
  715.                 slot = 0;
  716.                 md_save(md);
  717.         }
  718.         if (md.unplug())
  719.                 return (CMD_FAIL | CMD_MSG);
  720.         mdscr_splash();
  721.         return (CMD_OK | CMD_MSG);
  722. }
  723.  
  724. static char* prompt_cmpl_config_file(class md& md, unsigned int ac,
  725.                                      const char** av, unsigned int len)
  726. {
  727.         const char *prefix;
  728.         size_t i;
  729.         unsigned int skip;
  730.  
  731.         (void)md;
  732.         assert(ac != 0);
  733.         if ((ac == 1) || (len == ~0u) || (av[(ac - 1)] == NULL)) {
  734.                 prefix = "";
  735.                 len = 0;
  736.         }
  737.         else
  738.                 prefix = av[(ac - 1)];
  739.         if (prompt.complete == NULL) {
  740.                 // Rebuild cache.
  741.                 prompt.skip = 0;
  742.                 prompt.complete = complete_path(prefix, len, "config");
  743.                 if (prompt.complete == NULL)
  744.                         return NULL;
  745.                 rehash_prompt_complete_common();
  746.         }
  747. retry:
  748.         skip = prompt.skip;
  749.         for (i = 0; (prompt.complete[i] != NULL); ++i) {
  750.                 if (skip == 0)
  751.                         break;
  752.                 --skip;
  753.         }
  754.         if (prompt.complete[i] == NULL) {
  755.                 if (prompt.skip != 0) {
  756.                         prompt.skip = 0;
  757.                         goto retry;
  758.                 }
  759.                 return NULL;
  760.         }
  761.         ++prompt.skip;
  762.         return strdup(prompt.complete[i]);
  763. }
  764.  
  765. static int prompt_rehash_rc_field(const struct rc_field*, md&);
  766.  
  767. /**
  768.  * Prompt "config_load" command handler.
  769.  * @param md Context.
  770.  * @param ac Number of arguments in av.
  771.  * @param av Arguments.
  772.  * @return Status code.
  773.  */
  774. static int prompt_cmd_config_load(class md& md, unsigned int ac,
  775.                                   const char** av)
  776. {
  777.         FILE *f;
  778.         char *s;
  779.         unsigned int i;
  780.  
  781.         if (ac != 2)
  782.                 return CMD_EINVAL;
  783.         s = backslashify((const uint8_t *)av[1], strlen(av[1]), 0, NULL);
  784.         if (s == NULL)
  785.                 return CMD_FAIL;
  786.         f = dgen_fopen("config", av[1], (DGEN_READ | DGEN_CURRENT));
  787.         if (f == NULL) {
  788.                 pd_message("Cannot load configuration \"%s\": %s.",
  789.                            s, strerror(errno));
  790.                 free(s);
  791.                 return (CMD_FAIL | CMD_MSG);
  792.         }
  793.         parse_rc(f, av[1]);
  794.         fclose(f);
  795.         for (i = 0; (rc_fields[i].fieldname != NULL); ++i)
  796.                 prompt_rehash_rc_field(&rc_fields[i], md);
  797.         pd_message("Loaded configuration \"%s\".", s);
  798.         free(s);
  799.         return (CMD_OK | CMD_MSG);
  800. }
  801.  
  802. /**
  803.  * Prompt "config_save" command handler.
  804.  * @param md Context.
  805.  * @param ac Number of arguments in av.
  806.  * @param av Arguments.
  807.  * @return Status code.
  808.  */
  809. static int prompt_cmd_config_save(class md& md, unsigned int ac,
  810.                                   const char** av)
  811. {
  812.         FILE *f;
  813.         char *s;
  814.  
  815.         (void)md;
  816.         if (ac != 2)
  817.                 return CMD_EINVAL;
  818.         s = backslashify((const uint8_t *)av[1], strlen(av[1]), 0, NULL);
  819.         if (s == NULL)
  820.                 return CMD_FAIL;
  821.         f = dgen_fopen("config", av[1], (DGEN_WRITE | DGEN_TEXT));
  822.         if (f == NULL) {
  823.                 pd_message("Cannot save configuration \"%s\": %s",
  824.                            s, strerror(errno));
  825.                 free(s);
  826.                 return (CMD_FAIL | CMD_MSG);
  827.         }
  828.         dump_rc(f);
  829.         fclose(f);
  830.         pd_message("Saved configuration \"%s\"", s);
  831.         free(s);
  832.         return (CMD_OK | CMD_MSG);
  833. }
  834.  
  835. static int prompt_cmd_reset(class md& md, unsigned int, const char**)
  836. {
  837.         md.reset();
  838.         return CMD_OK;
  839. }
  840.  
  841. static int prompt_cmd_unbind(class md&, unsigned int ac, const char** av)
  842. {
  843.         unsigned int i;
  844.         int ret;
  845.  
  846.         if (ac < 2)
  847.                 return CMD_EINVAL;
  848.         ret = CMD_FAIL;
  849.         for (i = 1; (i != ac); ++i) {
  850.                 struct rc_field *rcf = rc_fields;
  851.  
  852.                 while (rcf->fieldname != NULL) {
  853.                         if ((rcf->parser == rc_bind) &&
  854.                             (!strcasecmp(av[i], rcf->fieldname))) {
  855.                                 rc_binding_del(rcf);
  856.                                 ret = CMD_OK;
  857.                         }
  858.                         else
  859.                                 ++rcf;
  860.                 }
  861.         }
  862.         return ret;
  863. }
  864.  
  865. static char* prompt_cmpl_unbind(class md&, unsigned int ac,
  866.                                 const char** av, unsigned int len)
  867. {
  868.         const struct rc_binding *rcb;
  869.         const char *prefix;
  870.         unsigned int skip;
  871.  
  872.         assert(ac != 0);
  873.         if ((ac == 1) || (len == ~0u) || (av[(ac - 1)] == NULL)) {
  874.                 prefix = "";
  875.                 len = 0;
  876.         }
  877.         else
  878.                 prefix = av[(ac - 1)];
  879.         skip = prompt.skip;
  880. retry:
  881.         for (rcb = rc_binding_head.next;
  882.              (rcb != &rc_binding_head);
  883.              rcb = rcb->next) {
  884.                 if (strncasecmp(prefix, rcb->rc, len))
  885.                         continue;
  886.                 if (skip == 0)
  887.                         break;
  888.                 --skip;
  889.         }
  890.         if (rcb == &rc_binding_head) {
  891.                 if (prompt.skip != 0) {
  892.                         prompt.skip = 0;
  893.                         goto retry;
  894.                 }
  895.                 return NULL;
  896.         }
  897.         ++prompt.skip;
  898.         return strdup(rcb->rc);
  899. }
  900.  
  901. #ifdef WITH_VGMDUMP
  902.  
  903. static char* prompt_cmpl_vgmdump(class md& md, unsigned int ac,
  904.                                  const char** av, unsigned int len)
  905. {
  906.         const char *prefix;
  907.         size_t i;
  908.         unsigned int skip;
  909.  
  910.         (void)md;
  911.         assert(ac != 0);
  912.         if ((ac == 1) || (len == ~0u) || (av[(ac - 1)] == NULL)) {
  913.                 prefix = "";
  914.                 len = 0;
  915.         }
  916.         else
  917.                 prefix = av[(ac - 1)];
  918.         if (prompt.complete == NULL) {
  919.                 // Rebuild cache.
  920.                 prompt.skip = 0;
  921.                 prompt.complete = complete_path(prefix, len, "vgm");
  922.                 if (prompt.complete == NULL)
  923.                         return NULL;
  924.                 rehash_prompt_complete_common();
  925.         }
  926. retry:
  927.         skip = prompt.skip;
  928.         for (i = 0; (prompt.complete[i] != NULL); ++i) {
  929.                 if (skip == 0)
  930.                         break;
  931.                 --skip;
  932.         }
  933.         if (prompt.complete[i] == NULL) {
  934.                 if (prompt.skip != 0) {
  935.                         prompt.skip = 0;
  936.                         goto retry;
  937.                 }
  938.                 return NULL;
  939.         }
  940.         ++prompt.skip;
  941.         return strdup(prompt.complete[i]);
  942. }
  943.  
  944. static int prompt_cmd_vgmdump(class md& md, unsigned int ac, const char** av)
  945. {
  946.         char *s;
  947.  
  948.         if (ac < 2)
  949.                 return CMD_EINVAL;
  950.         if (!strcasecmp(av[1], "stop")) {
  951.                 if (md.vgm_dump == false)
  952.                         pd_message("VGM dumping already stopped.");
  953.                 else {
  954.                         md.vgm_dump_stop();
  955.                         pd_message("Stopped VGM dumping.");
  956.                 }
  957.                 return (CMD_OK | CMD_MSG);
  958.         }
  959.         if (strcasecmp(av[1], "start"))
  960.                 return CMD_EINVAL;
  961.         if (ac < 3) {
  962.                 pd_message("VGM file name required.");
  963.                 return (CMD_EINVAL | CMD_MSG);
  964.         }
  965.         s = backslashify((const uint8_t *)av[2], strlen(av[2]), 0, NULL);
  966.         if (s == NULL)
  967.                 return CMD_FAIL;
  968.         if (md.vgm_dump_start(av[2])) {
  969.                 pd_message("Cannot dump VGM to \"%s\": %s",
  970.                            s, strerror(errno));
  971.                 free(s);
  972.                 return (CMD_FAIL | CMD_MSG);
  973.         }
  974.         pd_message("Started VGM dumping to \"%s\"", s);
  975.         free(s);
  976.         return (CMD_OK | CMD_MSG);
  977. }
  978.  
  979. #endif
  980.  
  981. struct filter_data {
  982.         bpp_t buf; ///< Input or output buffer.
  983.         unsigned int width; ///< Buffer width.
  984.         unsigned int height; ///< Buffer height.
  985.         unsigned int pitch; ///< Number of bytes per line in buffer.
  986.         void *data; ///< Filter-specific data.
  987.         bool updated:1; ///< Filter updated data to match its output.
  988.         bool failed:1; ///< Filter failed.
  989. };
  990.  
  991. typedef void filter_func_t(const struct filter_data *in,
  992.                            struct filter_data *out);
  993.  
  994. struct filter {
  995.         const char *name; ///< Filter name.
  996.         filter_func_t *func; ///< Filtering function.
  997.         bool safe:1; ///< Output buffer can be the same as input.
  998.         bool ctv:1; ///< Part of the CTV filters set.
  999.         bool resize:1; ///< Filter resizes input.
  1000. };
  1001.  
  1002. static filter_func_t filter_scale;
  1003. static filter_func_t filter_off;
  1004. static filter_func_t filter_stretch;
  1005. #ifdef WITH_SCALE2X
  1006. static filter_func_t filter_scale2x;
  1007. #endif
  1008. #ifdef WITH_HQX
  1009. static filter_func_t filter_hqx;
  1010. #endif
  1011. #ifdef WITH_CTV
  1012. static filter_func_t filter_blur;
  1013. static filter_func_t filter_scanline;
  1014. static filter_func_t filter_interlace;
  1015. static filter_func_t filter_swab;
  1016.  
  1017. static void set_swab();
  1018. #endif
  1019.  
  1020. static const struct filter filters_available[] = {
  1021.         { "stretch", filter_stretch, false, false, true },
  1022.         { "scale", filter_scale, false, false, true },
  1023. #ifdef WITH_SCALE2X
  1024.         { "scale2x", filter_scale2x, false, false, true },
  1025. #endif
  1026. #ifdef WITH_HQX
  1027.         { "hqx", filter_hqx, false, false, true },
  1028. #endif
  1029.         { "none", filter_off, true, false, true },
  1030. #ifdef WITH_CTV
  1031.         // These filters must match ctv_names in rc.cpp.
  1032.         { "off", filter_off, true, true, false },
  1033.         { "blur", filter_blur, true, true, false },
  1034.         { "scanline", filter_scanline, true, true, false },
  1035.         { "interlace", filter_interlace, true, true, false },
  1036.         { "swab", filter_swab, true, true, false },
  1037. #endif
  1038. };
  1039.  
  1040. static unsigned int filters_stack_size;
  1041. static bool filters_stack_default;
  1042. static const struct filter *filters_stack[64];
  1043. static bpp_t filters_stack_data_buf[2];
  1044. static struct filter_data filters_stack_data[1 + elemof(filters_stack)];
  1045.  
  1046. /**
  1047.  * Return filter structure associated with name.
  1048.  * @param name Name of filter.
  1049.  * @return Pointer to filter or NULL if not found.
  1050.  */
  1051. static const struct filter *filters_find(const char *name)
  1052. {
  1053.         size_t i;
  1054.  
  1055.         for (i = 0; (i != elemof(filters_available)); ++i)
  1056.                 if (!strcasecmp(name, filters_available[i].name))
  1057.                         return &filters_available[i];
  1058.         return NULL;
  1059. }
  1060.  
  1061. /**
  1062.  * Update filters data, reallocate extra buffers if necessary.
  1063.  */
  1064. static void filters_stack_update()
  1065. {
  1066.         size_t i;
  1067.         const struct filter *f;
  1068.         struct filter_data *fd;
  1069.         unsigned int buffers;
  1070.         bpp_t buf[2];
  1071.         struct filter_data in_fd = {
  1072.                 // Use the same formula as draw_scanline() in ras.cpp to avoid
  1073.                 // the messy border for any supported depth.
  1074.                 { ((uint8_t *)mdscr.data + (mdscr.pitch * 8) + 16) },
  1075.                 video.width,
  1076.                 video.height,
  1077.                 (unsigned int)mdscr.pitch,
  1078.                 NULL,
  1079.                 false,
  1080.                 false,
  1081.         };
  1082.         struct filter_data out_fd = {
  1083.                 { screen.buf.u8 },
  1084.                 screen.width,
  1085.                 (screen.height - screen.info_height),
  1086.                 screen.pitch,
  1087.                 NULL,
  1088.                 false,
  1089.                 false,
  1090.         };
  1091.         struct filter_data *prev_fd;
  1092.  
  1093.         DEBUG(("updating filters data"));
  1094. retry:
  1095.         assert(filters_stack_size <= elemof(filters_stack));
  1096.         buffers = 0;
  1097.         buf[0].u8 = filters_stack_data_buf[0].u8;
  1098.         buf[1].u8 = filters_stack_data_buf[1].u8;
  1099.         // Get the number of defined filters and count how many of them cannot
  1100.         // use the same buffer for both input and output.
  1101.         // Unless they are on top, "unsafe" filters require extra buffers.
  1102.         assert(filters_stack_data[0].data == NULL);
  1103.         for (i = 0; (i != elemof(filters_stack)); ++i) {
  1104.                 if (i == filters_stack_size)
  1105.                         break;
  1106.                 f = filters_stack[i];
  1107.                 assert(f != NULL);
  1108.                 if ((f->safe == false) && (i != (filters_stack_size - 1)))
  1109.                         ++buffers;
  1110.                 // Clear filters stack output data.
  1111.                 free(filters_stack_data[i + 1].data);
  1112.         }
  1113.         memset(filters_stack_data, 0, sizeof(filters_stack_data));
  1114.         // Add a valid default filter if stack is empty.
  1115.         if (i == 0) {
  1116.                 assert(filters_stack_size == 0);
  1117.                 filters_stack[0] = &filters_available[0];
  1118.                 ++filters_stack_size;
  1119.                 filters_stack_default = true;
  1120.                 goto retry;
  1121.         }
  1122.         // Remove default filter if there is one and stack is not empty.
  1123.         else if ((i > 1) && (filters_stack_default == true)) {
  1124.                 assert(filters_stack_size > 1);
  1125.                 --filters_stack_size;
  1126.                 memmove(&filters_stack[0], &filters_stack[1],
  1127.                         (sizeof(filters_stack[0]) * filters_stack_size));
  1128.                 filters_stack_default = false;
  1129.                 goto retry;
  1130.         }
  1131.         // Check if extra buffers are required.
  1132.         if (buffers) {
  1133.                 if (buffers > 2)
  1134.                         buffers = 2;
  1135.                 else {
  1136.                         // Remove unnecessary buffer.
  1137.                         free(buf[1].u8);
  1138.                         buf[1].u8 = NULL;
  1139.                         filters_stack_data_buf[1].u8 = NULL;
  1140.                 }
  1141.                 DEBUG(("requiring %u extra buffer(s)", buffers));
  1142.                 // Reallocate them.
  1143.                 for (i = 0; (i != buffers); ++i) {
  1144.                         size_t size = (screen.pitch * screen.height);
  1145.  
  1146.                         DEBUG(("temporary buffer %u size: %zu", i, size));
  1147.                         buf[i].u8 =
  1148.                                 (uint8_t *)realloc((void *)buf[i].u8, size);
  1149.                         if (size == 0) {
  1150.                                 assert(buf[i].u8 == NULL);
  1151.                                 DEBUG(("freed zero-sized buffer"));
  1152.                                 filters_stack_data_buf[i].u8 = NULL;
  1153.                                 continue;
  1154.                         }
  1155.                         if (buf[i].u8 == NULL) {
  1156.                                 // Not good, remove one of the filters that
  1157.                                 // require an extra buffer and try again.
  1158.                                 free(filters_stack_data_buf[i].u8);
  1159.                                 filters_stack_data_buf[i].u8 = NULL;
  1160.                                 for (i = 0;
  1161.                                      (i < filters_stack_size);
  1162.                                      ++i) {
  1163.                                         if (filters_stack[i]->safe == true)
  1164.                                                 continue;
  1165.                                         --filters_stack_size;
  1166.                                         memmove(&filters_stack[i],
  1167.                                                 &filters_stack[i + 1],
  1168.                                                 (sizeof(filters_stack[i]) *
  1169.                                                  (filters_stack_size - i)));
  1170.                                         break;
  1171.                                 }
  1172.                                 goto retry;
  1173.                         }
  1174.                         filters_stack_data_buf[i].u8 = buf[i].u8;
  1175.                 }
  1176.         }
  1177.         else {
  1178.                 // No extra buffer required, deallocate them.
  1179.                 DEBUG(("removing temporary buffers"));
  1180.                 for (i = 0; (i != elemof(buf)); ++i) {
  1181.                         free(buf[i].u8);
  1182.                         buf[i].u8 = NULL;
  1183.                         filters_stack_data_buf[i].u8 = NULL;
  1184.                 }
  1185.         }
  1186.         // Update I/O buffers.
  1187.         buffers = 0;
  1188.         prev_fd = &filters_stack_data[0];
  1189.         memcpy(prev_fd, &in_fd, sizeof(*prev_fd));
  1190.         for (i = 0; (i != elemof(filters_stack)); ++i) {
  1191.                 if (i == filters_stack_size)
  1192.                         break;
  1193.                 f = filters_stack[i];
  1194.                 fd = &filters_stack_data[i + 1];
  1195.                 // The last filter uses screen output.
  1196.                 if (i == (filters_stack_size - 1))
  1197.                         memcpy(fd, &out_fd, sizeof(*fd));
  1198.                 // Safe filters have the same input as their output.
  1199.                 else if (f->safe == true)
  1200.                         memcpy(fd, prev_fd, sizeof(*fd));
  1201.                 // Other filters output to a temporary buffer.
  1202.                 else {
  1203.                         fd->buf.u8 = buf[buffers].u8;
  1204.                         fd->width = screen.width;
  1205.                         fd->height = (screen.height - screen.info_height);
  1206.                         fd->pitch = screen.pitch;
  1207.                         fd->data = NULL;
  1208.                         fd->updated = false;
  1209.                         fd->failed = false;
  1210.                         buffers ^= 1;
  1211.                 }
  1212.                 prev_fd = fd;
  1213.         }
  1214. #ifndef NDEBUG
  1215.         DEBUG(("filters stack:"));
  1216.         for (i = 0; (i != filters_stack_size); ++i)
  1217.                 DEBUG(("- %s (input: %p output: %p)",
  1218.                        filters_stack[i]->name,
  1219.                        (void *)filters_stack_data[i].buf.u8,
  1220.                        (void *)filters_stack_data[i + 1].buf.u8));
  1221. #endif
  1222.         screen_clear();
  1223. }
  1224.  
  1225. /**
  1226.  * Add filter to stack.
  1227.  * @param f Filter to add.
  1228.  */
  1229. static void filters_push(const struct filter *f)
  1230. {
  1231.         assert(filters_stack_size <= elemof(filters_stack));
  1232.         if ((f == NULL) || (filters_stack_size == elemof(filters_stack)))
  1233.                 return;
  1234.         DEBUG(("%s", f->name));
  1235.         filters_stack[filters_stack_size] = f;
  1236.         filters_stack_data[filters_stack_size + 1].data = NULL;
  1237.         ++filters_stack_size;
  1238.         filters_stack_update();
  1239. }
  1240.  
  1241. /**
  1242.  * Insert filter at the bottom of the stack.
  1243.  * @param f Filter to insert.
  1244.  */
  1245. static void filters_insert(const struct filter *f)
  1246. {
  1247.         assert(filters_stack_size <= elemof(filters_stack));
  1248.         if ((f == NULL) ||
  1249.             (filters_stack_size == elemof(filters_stack)))
  1250.                 return;
  1251.         DEBUG(("%s", f->name));
  1252.         memmove(&filters_stack[1], &filters_stack[0],
  1253.                 (filters_stack_size * sizeof(filters_stack[0])));
  1254.         filters_stack[0] = f;
  1255.         filters_stack_data[0 + 1].data = NULL;
  1256.         ++filters_stack_size;
  1257.         filters_stack_update();
  1258. }
  1259.  
  1260. // Currently unused.
  1261. #if 0
  1262.  
  1263. /**
  1264.  * Add filter to stack if not already in it.
  1265.  * @param f Filter to add.
  1266.  */
  1267. static void filters_push_once(const struct filter *f)
  1268. {
  1269.         size_t i;
  1270.  
  1271.         assert(filters_stack_size <= elemof(filters_stack));
  1272.         if (f == NULL)
  1273.                 return;
  1274.         DEBUG(("%s", f->name));
  1275.         for (i = 0; (i != filters_stack_size); ++i)
  1276.                 if (filters_stack[i] == f)
  1277.                         return;
  1278.         filters_push(f);
  1279. }
  1280.  
  1281. #endif
  1282.  
  1283. #ifdef WITH_CTV
  1284.  
  1285. /**
  1286.  * Remove last filter from stack.
  1287.  */
  1288. static void filters_pop()
  1289. {
  1290.         assert(filters_stack_size <= elemof(filters_stack));
  1291.         if (filters_stack_size) {
  1292.                 --filters_stack_size;
  1293.                 DEBUG(("%s", filters_stack[filters_stack_size]->name));
  1294.                 free(filters_stack_data[filters_stack_size + 1].data);
  1295. #ifndef NDEBUG
  1296.                 memset(&filters_stack[filters_stack_size], 0xf0,
  1297.                        sizeof(filters_stack[filters_stack_size]));
  1298.                 memset(&filters_stack_data[filters_stack_size + 1], 0xf1,
  1299.                        sizeof(filters_stack_data[filters_stack_size + 1]));
  1300. #endif
  1301.         }
  1302.         filters_stack_update();
  1303. }
  1304.  
  1305. #endif
  1306.  
  1307. /**
  1308.  * Remove a filter from anywhere in the stack.
  1309.  * @param index Filters stack index.
  1310.  */
  1311. static void filters_remove(unsigned int index)
  1312. {
  1313.         assert(filters_stack_size <= elemof(filters_stack));
  1314.         if (index >= filters_stack_size)
  1315.                 return;
  1316.         --filters_stack_size;
  1317.         DEBUG(("%s", filters_stack[index]->name));
  1318.         free(filters_stack_data[index + 1].data);
  1319. #ifndef NDEBUG
  1320.         memset(&filters_stack[index], 0xf2, sizeof(filters_stack[index]));
  1321.         memset(&filters_stack_data[index + 1], 0xf3,
  1322.                sizeof(filters_stack_data[index + 1]));
  1323. #endif
  1324.         memmove(&filters_stack[index], &filters_stack[index + 1],
  1325.                 (sizeof(filters_stack[index]) * (filters_stack_size - index)));
  1326.         memmove(&filters_stack_data[index + 1], &filters_stack_data[index + 2],
  1327.                 (sizeof(filters_stack_data[index + 1]) *
  1328.                  (filters_stack_size - index)));
  1329.         filters_stack_update();
  1330. }
  1331.  
  1332. /**
  1333.  * Remove all occurences of filter from the stack.
  1334.  * @param f Filter to remove.
  1335.  */
  1336. static void filters_pluck(const struct filter *f)
  1337. {
  1338.         size_t i;
  1339.  
  1340.         assert(filters_stack_size <= elemof(filters_stack));
  1341.         if (f == NULL)
  1342.                 return;
  1343.         DEBUG(("%s", f->name));
  1344.         for (i = 0; (i < filters_stack_size); ++i) {
  1345.                 if (filters_stack[i] != f)
  1346.                         continue;
  1347.                 --filters_stack_size;
  1348.                 DEBUG(("%s", filters_stack[i]->name));
  1349.                 free(filters_stack_data[i + 1].data);
  1350. #ifndef NDEBUG
  1351.                 memset(&filters_stack[i], 0xf4, sizeof(filters_stack[i]));
  1352.                 memset(&filters_stack_data[i + 1], 0xf5,
  1353.                        sizeof(filters_stack_data[i + 1]));
  1354. #endif
  1355.                 memmove(&filters_stack[i], &filters_stack[i + 1],
  1356.                         (sizeof(filters_stack[i]) * (filters_stack_size - i)));
  1357.                 memmove(&filters_stack_data[i + 1], &filters_stack_data[i + 2],
  1358.                         (sizeof(filters_stack_data[i + 1]) *
  1359.                          (filters_stack_size - i)));
  1360.                 --i;
  1361.         }
  1362.         filters_stack_update();
  1363. }
  1364.  
  1365. #ifdef WITH_CTV
  1366.  
  1367. /**
  1368.  * Remove all occurences of CTV filters from the stack.
  1369.  */
  1370. static void filters_pluck_ctv()
  1371. {
  1372.         size_t i;
  1373.  
  1374.         assert(filters_stack_size <= elemof(filters_stack));
  1375.         for (i = 0; (i < filters_stack_size); ++i) {
  1376.                 if (filters_stack[i]->ctv == false)
  1377.                         continue;
  1378.                 --filters_stack_size;
  1379.                 DEBUG(("%s", filters_stack[i]->name));
  1380.                 free(filters_stack_data[i + 1].data);
  1381. #ifndef NDEBUG
  1382.                 memset(&filters_stack[i], 0xf6, sizeof(filters_stack[i]));
  1383.                 memset(&filters_stack_data[i + 1], 0xf6,
  1384.                        sizeof(filters_stack_data[i + 1]));
  1385. #endif
  1386.                 memmove(&filters_stack[i], &filters_stack[i + 1],
  1387.                         (sizeof(filters_stack[i]) * (filters_stack_size - i)));
  1388.                 memmove(&filters_stack_data[i + 1], &filters_stack_data[i + 2],
  1389.                         (sizeof(filters_stack_data[i + 1]) *
  1390.                          (filters_stack_size - i)));
  1391.                 --i;
  1392.         }
  1393.         filters_stack_update();
  1394. }
  1395.  
  1396. #endif
  1397.  
  1398. #ifdef WITH_CTV
  1399.  
  1400. /**
  1401.  * Empty filters stack.
  1402.  */
  1403. static void filters_empty()
  1404. {
  1405.         size_t i;
  1406.  
  1407.         assert(filters_stack_size <= elemof(filters_stack));
  1408.         DEBUG(("stack size was %u", filters_stack_size));
  1409.         for (i = 0; (i < filters_stack_size); ++i)
  1410.                 free(filters_stack_data[i + 1].data);
  1411.         filters_stack_size = 0;
  1412. #ifndef NDEBUG
  1413.         memset(filters_stack, 0xb0, sizeof(filters_stack));
  1414.         memset(filters_stack_data, 0xb0, sizeof(filters_stack_data));
  1415.         filters_stack_data[0].data = NULL;
  1416. #endif
  1417.         filters_stack_update();
  1418. }
  1419.  
  1420. #endif
  1421.  
  1422. /**
  1423.  * Take a screenshot.
  1424.  */
  1425. static void do_screenshot(md& megad)
  1426. {
  1427.         static unsigned int n = 0;
  1428.         static char romname_old[sizeof(megad.romname)];
  1429.         FILE *fp;
  1430. #ifdef HAVE_FTELLO
  1431.         off_t pos;
  1432. #else
  1433.         long pos;
  1434. #endif
  1435.         bpp_t line;
  1436.         unsigned int width;
  1437.         unsigned int height;
  1438.         unsigned int pitch;
  1439.         unsigned int bpp = mdscr.bpp;
  1440.         uint8_t (*out)[3]; // 24 bpp
  1441.         char name[(sizeof(megad.romname) + 32)];
  1442.  
  1443.         if (dgen_raw_screenshots) {
  1444.                 width = video.width;
  1445.                 height = video.height;
  1446.                 pitch = mdscr.pitch;
  1447.                 line.u8 = ((uint8_t *)mdscr.data + (pitch * 8) + 16);
  1448.         }
  1449.         else {
  1450.                 width = screen.width;
  1451.                 height = screen.height;
  1452.                 pitch = screen.pitch;
  1453.                 line = screen.buf;
  1454.         }
  1455.         switch (bpp) {
  1456.         case 15:
  1457.         case 16:
  1458.         case 24:
  1459.         case 32:
  1460.                 break;
  1461.         default:
  1462.                 pd_message("Screenshots unsupported in %d bpp.", bpp);
  1463.                 return;
  1464.         }
  1465.         // Make take a long time, let the main loop know about it.
  1466.         stopped = 1;
  1467.         // If megad.romname is different from last time, reset n.
  1468.         if (memcmp(romname_old, megad.romname, sizeof(romname_old))) {
  1469.                 memcpy(romname_old, megad.romname, sizeof(romname_old));
  1470.                 n = 0;
  1471.         }
  1472. retry:
  1473.         snprintf(name, sizeof(name), "%s-%06u.tga",
  1474.                  ((megad.romname[0] == '\0') ? "unknown" : megad.romname), n);
  1475.         fp = dgen_fopen("screenshots", name, DGEN_APPEND);
  1476.         if (fp == NULL) {
  1477.                 pd_message("Can't open %s.", name);
  1478.                 return;
  1479.         }
  1480.         fseek(fp, 0, SEEK_END);
  1481. #ifdef HAVE_FTELLO
  1482.         pos = ftello(fp);
  1483. #else
  1484.         pos = ftell(fp);
  1485. #endif
  1486.         if (((off_t)pos == (off_t)-1) || ((off_t)pos != (off_t)0)) {
  1487.                 fclose(fp);
  1488.                 n = ((n + 1) % 1000000);
  1489.                 goto retry;
  1490.         }
  1491.         // Allocate line buffer.
  1492.         if ((out = (uint8_t (*)[3])malloc(sizeof(*out) * width)) == NULL)
  1493.                 goto error;
  1494.         // Header
  1495.         {
  1496.                 uint8_t tmp[(3 + 5)] = {
  1497.                         0x00, // length of the image ID field
  1498.                         0x00, // whether a color map is included
  1499.                         0x02 // image type: uncompressed, true-color image
  1500.                         // 5 bytes of color map specification
  1501.                 };
  1502.  
  1503.                 if (!fwrite(tmp, sizeof(tmp), 1, fp))
  1504.                         goto error;
  1505.         }
  1506.         {
  1507.                 uint16_t tmp[4] = {
  1508.                         0, // x-origin
  1509.                         0, // y-origin
  1510.                         h2le16(width), // width
  1511.                         h2le16(height) // height
  1512.                 };
  1513.  
  1514.                 if (!fwrite(tmp, sizeof(tmp), 1, fp))
  1515.                         goto error;
  1516.         }
  1517.         {
  1518.                 uint8_t tmp[2] = {
  1519.                         24, // always output 24 bits per pixel
  1520.                         (1 << 5) // top-left origin
  1521.                 };
  1522.  
  1523.                 if (!fwrite(tmp, sizeof(tmp), 1, fp))
  1524.                         goto error;
  1525.         }
  1526.         // Data
  1527.         switch (bpp) {
  1528.                 unsigned int y;
  1529.                 unsigned int x;
  1530.  
  1531.         case 15:
  1532.                 for (y = 0; (y < height); ++y) {
  1533.                         if (screen_lock())
  1534.                                 goto error;
  1535.                         for (x = 0; (x < width); ++x) {
  1536.                                 uint16_t v = line.u16[x];
  1537.  
  1538.                                 out[x][0] = ((v << 3) & 0xf8);
  1539.                                 out[x][1] = ((v >> 2) & 0xf8);
  1540.                                 out[x][2] = ((v >> 7) & 0xf8);
  1541.                         }
  1542.                         screen_unlock();
  1543.                         if (!fwrite(out, (sizeof(*out) * width), 1, fp))
  1544.                                 goto error;
  1545.                         line.u8 += pitch;
  1546.                 }
  1547.                 break;
  1548.         case 16:
  1549.                 for (y = 0; (y < height); ++y) {
  1550.                         if (screen_lock())
  1551.                                 goto error;
  1552.                         for (x = 0; (x < width); ++x) {
  1553.                                 uint16_t v = line.u16[x];
  1554.  
  1555.                                 out[x][0] = ((v << 3) & 0xf8);
  1556.                                 out[x][1] = ((v >> 3) & 0xfc);
  1557.                                 out[x][2] = ((v >> 8) & 0xf8);
  1558.                         }
  1559.                         screen_unlock();
  1560.                         if (!fwrite(out, (sizeof(*out) * width), 1, fp))
  1561.                                 goto error;
  1562.                         line.u8 += pitch;
  1563.                 }
  1564.                 break;
  1565.         case 24:
  1566.                 for (y = 0; (y < height); ++y) {
  1567.                         if (screen_lock())
  1568.                                 goto error;
  1569. #ifdef WORDS_BIGENDIAN
  1570.                         for (x = 0; (x < width); ++x) {
  1571.                                 out[x][0] = line.u24[x][2];
  1572.                                 out[x][1] = line.u24[x][1];
  1573.                                 out[x][2] = line.u24[x][0];
  1574.                         }
  1575. #else
  1576.                         memcpy(out, line.u24, (sizeof(*out) * width));
  1577. #endif
  1578.                         screen_unlock();
  1579.                         if (!fwrite(out, (sizeof(*out) * width), 1, fp))
  1580.                                 goto error;
  1581.                         line.u8 += pitch;
  1582.                 }
  1583.                 break;
  1584.         case 32:
  1585.                 for (y = 0; (y < height); ++y) {
  1586.                         if (screen_lock())
  1587.                                 goto error;
  1588.                         for (x = 0; (x < width); ++x) {
  1589. #ifdef WORDS_BIGENDIAN
  1590.                                 uint32_t rgb = h2le32(line.u32[x]);
  1591.  
  1592.                                 memcpy(&(out[x]), &rgb, 3);
  1593. #else
  1594.                                 memcpy(&(out[x]), &(line.u32[x]), 3);
  1595. #endif
  1596.                         }
  1597.                         screen_unlock();
  1598.                         if (!fwrite(out, (sizeof(*out) * width), 1, fp))
  1599.                                 goto error;
  1600.                         line.u8 += pitch;
  1601.                 }
  1602.                 break;
  1603.         }
  1604.         pd_message("Screenshot written to %s.", name);
  1605.         free(out);
  1606.         fclose(fp);
  1607.         return;
  1608. error:
  1609.         pd_message("Error while generating screenshot %s.", name);
  1610.         free(out);
  1611.         fclose(fp);
  1612. }
  1613.  
  1614. /**
  1615.  * SDL flags help.
  1616.  */
  1617. void pd_help()
  1618. {
  1619.   printf(
  1620. #ifdef WITH_OPENGL
  1621.   "    -g (1|0)        Enable/disable OpenGL.\n"
  1622. #endif
  1623.   "    -f              Attempt to run fullscreen.\n"
  1624.   "    -X scale        Scale the screen in the X direction.\n"
  1625.   "    -Y scale        Scale the screen in the Y direction.\n"
  1626.   "    -S scale        Scale the screen by the same amount in both directions.\n"
  1627.   "    -G WxH          Desired window size.\n"
  1628.   );
  1629. }
  1630.  
  1631. /**
  1632.  * Handle rc variables
  1633.  */
  1634. void pd_rc()
  1635. {
  1636.         // Set stuff up from the rcfile first, so we can override it with
  1637.         // command-line options
  1638.         if (dgen_scale >= 1) {
  1639.                 dgen_x_scale = dgen_scale;
  1640.                 dgen_y_scale = dgen_scale;
  1641.         }
  1642. #ifdef WITH_CTV
  1643.         set_swab();
  1644. #endif
  1645. }
  1646.  
  1647. /**
  1648.  * Handle the switches.
  1649.  * @param c Switch's value.
  1650.  */
  1651. void pd_option(char c, const char *)
  1652. {
  1653.         int xs, ys;
  1654.  
  1655.         switch (c) {
  1656. #ifdef WITH_OPENGL
  1657.         case 'g':
  1658.                 dgen_opengl = atoi(optarg);
  1659.                 break;
  1660. #endif
  1661.         case 'f':
  1662.                 dgen_fullscreen = 1;
  1663.                 break;
  1664.         case 'X':
  1665.                 if ((xs = atoi(optarg)) <= 0)
  1666.                         break;
  1667.                 dgen_x_scale = xs;
  1668.                 break;
  1669.         case 'Y':
  1670.                 if ((ys = atoi(optarg)) <= 0)
  1671.                         break;
  1672.                 dgen_y_scale = ys;
  1673.                 break;
  1674.         case 'S':
  1675.                 if ((xs = atoi(optarg)) <= 0)
  1676.                         break;
  1677.                 dgen_x_scale = xs;
  1678.                 dgen_y_scale = xs;
  1679.                 break;
  1680.         case 'G':
  1681.                 if ((sscanf(optarg, " %d x %d ", &xs, &ys) != 2) ||
  1682.                     (xs < 0) || (ys < 0))
  1683.                         break;
  1684.                 dgen_width = xs;
  1685.                 dgen_height = ys;
  1686.                 break;
  1687.         }
  1688. }
  1689.  
  1690. #ifdef WITH_OPENGL
  1691.  
  1692. #ifdef WORDS_BIGENDIAN
  1693. #define TEXTURE_16_TYPE GL_UNSIGNED_SHORT_5_6_5
  1694. #define TEXTURE_32_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
  1695. #else
  1696. #define TEXTURE_16_TYPE GL_UNSIGNED_SHORT_5_6_5
  1697. #define TEXTURE_32_TYPE GL_UNSIGNED_BYTE
  1698. #endif
  1699.  
  1700. static void texture_init_id(struct texture& texture)
  1701. {
  1702.         GLint param;
  1703.  
  1704.         if (texture.linear)
  1705.                 param = GL_LINEAR;
  1706.         else
  1707.                 param = GL_NEAREST;
  1708.         glBindTexture(GL_TEXTURE_2D, texture.id);
  1709.         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  1710.         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1711.         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
  1712.         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
  1713.         if (texture.u32 == 0)
  1714.                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
  1715.                              texture.width, texture.height,
  1716.                              0, GL_RGB, TEXTURE_16_TYPE,
  1717.                              texture.buf.u16);
  1718.         else
  1719.                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
  1720.                              texture.width, texture.height,
  1721.                              0, GL_BGRA, TEXTURE_32_TYPE,
  1722.                              texture.buf.u32);
  1723. }
  1724.  
  1725. static void texture_init_dlist(struct texture& texture)
  1726. {
  1727.         glNewList(texture.dlist, GL_COMPILE);
  1728.         glMatrixMode(GL_MODELVIEW);
  1729.         glPushMatrix();
  1730.         glLoadIdentity();
  1731.         glOrtho(0, texture.vis_width, texture.vis_height, 0, 0, 1);
  1732.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1733.         glEnable(GL_TEXTURE_2D);
  1734.         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  1735.  
  1736.         glBindTexture(GL_TEXTURE_2D, texture.id);
  1737.         glBegin(GL_QUADS);
  1738.         glTexCoord2i(0, 1);
  1739.         glVertex2i(0, texture.height); // lower left
  1740.         glTexCoord2i(0, 0);
  1741.         glVertex2i(0, 0); // upper left
  1742.         glTexCoord2i(1, 0);
  1743.         glVertex2i(texture.width, 0); // upper right
  1744.         glTexCoord2i(1, 1);
  1745.         glVertex2i(texture.width, texture.height); // lower right
  1746.         glEnd();
  1747.  
  1748.         glDisable(GL_TEXTURE_2D);
  1749.         glPopMatrix();
  1750.         glEndList();
  1751. }
  1752.  
  1753. /**
  1754.  * Round a value up to nearest power of two.
  1755.  * @param v Value.
  1756.  * @return Rounded value.
  1757.  */
  1758. static uint32_t roundup2(uint32_t v)
  1759. {
  1760.         --v;
  1761.         v |= (v >> 1);
  1762.         v |= (v >> 2);
  1763.         v |= (v >> 4);
  1764.         v |= (v >> 8);
  1765.         v |= (v >> 16);
  1766.         ++v;
  1767.         return v;
  1768. }
  1769.  
  1770. static void release_texture(struct texture& texture)
  1771. {
  1772.         if ((texture.dlist != 0) && (glIsList(texture.dlist))) {
  1773.                 glDeleteTextures(1, &texture.id);
  1774.                 glDeleteLists(texture.dlist, 1);
  1775.                 texture.dlist = 0;
  1776.         }
  1777.         free(texture.buf.u32);
  1778.         texture.buf.u32 = NULL;
  1779. }
  1780.  
  1781. static int init_texture(struct screen *screen)
  1782. {
  1783.         struct texture& texture = screen->texture;
  1784.         unsigned int vis_width;
  1785.         unsigned int vis_height;
  1786.         unsigned int x;
  1787.         unsigned int y;
  1788.         unsigned int w;
  1789.         unsigned int h;
  1790.         void *tmp;
  1791.         size_t i;
  1792.         GLenum error;
  1793.  
  1794.         // When bool_opengl_stretch is enabled, width and height are redefined
  1795.         // using X and Y scale factors with additional room for the info bar.
  1796.         if (dgen_opengl_stretch) {
  1797.                 vis_width = (video.width *
  1798.                              (screen->x_scale ? screen->x_scale : 1));
  1799.                 vis_height = (video.height *
  1800.                               (screen->y_scale ? screen->y_scale : 1));
  1801.                 vis_height += screen->info_height;
  1802.                 if (dgen_aspect) {
  1803.                         // Keep scaled aspect ratio.
  1804.                         w = ((screen->height * vis_width) / vis_height);
  1805.                         h = ((screen->width * vis_height) / vis_width);
  1806.                         if (w >= screen->width) {
  1807.                                 w = screen->width;
  1808.                                 if (h == 0)
  1809.                                         ++h;
  1810.                         }
  1811.                         else {
  1812.                                 h = screen->height;
  1813.                                 if (w == 0)
  1814.                                         ++w;
  1815.                         }
  1816.                 }
  1817.                 else {
  1818.                         // Aspect ratio won't be kept.
  1819.                         w = screen->width;
  1820.                         h = screen->height;
  1821.                 }
  1822.         }
  1823.         else {
  1824.                 w = vis_width = screen->width;
  1825.                 h = vis_height = screen->height;
  1826.         }
  1827.         if (screen->width > w)
  1828.                 x = ((screen->width - w) / 2);
  1829.         else
  1830.                 x = 0;
  1831.         if (screen->height > h)
  1832.                 y = ((screen->height - h) / 2);
  1833.         else
  1834.                 y = 0;
  1835.         DEBUG(("initializing for width=%u height=%u", vis_width, vis_height));
  1836.         // Set viewport.
  1837.         DEBUG(("glViewport(%u, %u, %u, %u)", x, y, w, h));
  1838.         glViewport(x, y, w, h);
  1839.         // Disable dithering
  1840.         glDisable(GL_DITHER);
  1841.         // Disable anti-aliasing
  1842.         glDisable(GL_LINE_SMOOTH);
  1843.         glDisable(GL_POINT_SMOOTH);
  1844.         // Disable depth buffer
  1845.         glDisable(GL_DEPTH_TEST);
  1846.  
  1847.         glClearColor(0.0, 0.0, 0.0, 0.0);
  1848.         glShadeModel(GL_FLAT);
  1849.  
  1850.         // Initialize and allocate texture.
  1851.         texture.u32 = (!!dgen_opengl_32bit);
  1852.         texture.linear = (!!dgen_opengl_linear);
  1853.         texture.width = roundup2(vis_width);
  1854.         texture.height = roundup2(vis_height);
  1855.         if (dgen_opengl_square) {
  1856.                 // Texture must be square.
  1857.                 if (texture.width < texture.height)
  1858.                         texture.width = texture.height;
  1859.                 else
  1860.                         texture.height = texture.width;
  1861.         }
  1862.         texture.vis_width = vis_width;
  1863.         texture.vis_height = vis_height;
  1864.         DEBUG(("texture width=%u height=%u", texture.width, texture.height));
  1865.         if ((texture.width == 0) || (texture.height == 0))
  1866.                 goto fail;
  1867.         i = ((texture.width * texture.height) * (2 << texture.u32));
  1868.         DEBUG(("texture size=%lu (%u Bpp)",
  1869.                (unsigned long)i, (2 << texture.u32)));
  1870.         if ((tmp = realloc(texture.buf.u32, i)) == NULL)
  1871.                 goto fail;
  1872.         memset(tmp, 0, i);
  1873.         texture.buf.u32 = (uint32_t *)tmp;
  1874.         if ((texture.dlist != 0) && (glIsList(texture.dlist))) {
  1875.                 glDeleteTextures(1, &texture.id);
  1876.                 glDeleteLists(texture.dlist, 1);
  1877.         }
  1878.         DEBUG(("texture buf=%p", (void *)texture.buf.u32));
  1879.         if ((texture.dlist = glGenLists(1)) == 0)
  1880.                 goto fail;
  1881.         if ((glGenTextures(1, &texture.id), error = glGetError()) ||
  1882.             (texture_init_id(texture), error = glGetError()) ||
  1883.             (texture_init_dlist(texture), error = glGetError())) {
  1884.                 // Do something with "error".
  1885.                 goto fail;
  1886.         }
  1887.         DEBUG(("texture initialization OK"));
  1888.         return 0;
  1889. fail:
  1890.         release_texture(texture);
  1891.         DEBUG(("texture initialization failed"));
  1892.         return -1;
  1893. }
  1894.  
  1895. static void update_texture(struct texture& texture)
  1896. {
  1897.         glBindTexture(GL_TEXTURE_2D, texture.id);
  1898.         if (texture.u32 == 0)
  1899.                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
  1900.                                 texture.vis_width, texture.vis_height,
  1901.                                 GL_RGB, TEXTURE_16_TYPE,
  1902.                                 texture.buf.u16);
  1903.         else
  1904.                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
  1905.                                 texture.vis_width, texture.vis_height,
  1906.                                 GL_BGRA, TEXTURE_32_TYPE,
  1907.                                 texture.buf.u32);
  1908.         glCallList(texture.dlist);
  1909.         SDL_GL_SwapBuffers();
  1910. }
  1911.  
  1912. #endif // WITH_OPENGL
  1913.  
  1914. /**
  1915.  * This filter passes input to output unchanged, only centered or truncated
  1916.  * if necessary. Doesn't have any fallback, thus cannot fail.
  1917.  * @param in Input buffer data.
  1918.  * @param out Output buffer data.
  1919.  */
  1920. static void filter_off(const struct filter_data *in, struct filter_data *out)
  1921. {
  1922.         unsigned int line;
  1923.         unsigned int height;
  1924.         uint8_t *in_buf;
  1925.         uint8_t *out_buf;
  1926.  
  1927.         // Check if copying is necessary.
  1928.         if (in->buf.u8 == out->buf.u8)
  1929.                 return;
  1930.         // Copy line by line and center.
  1931.         if (in->height > out->height)
  1932.                 height = out->height;
  1933.         else
  1934.                 height = in->height;
  1935.         if (out->updated == false) {
  1936.                 if (in->width <= out->width) {
  1937.                         unsigned int x_off = ((out->width - in->width) / 2);
  1938.                         unsigned int y_off = ((out->height - height) / 2);
  1939.  
  1940.                         out->buf.u8 += (x_off * screen.Bpp);
  1941.                         out->buf.u8 += (out->pitch * y_off);
  1942.                         out->width = in->width;
  1943.                 }
  1944.                 out->height = height;
  1945.                 out->updated = true;
  1946.         }
  1947.         in_buf = in->buf.u8;
  1948.         out_buf = out->buf.u8;
  1949.         for (line = 0; (line != height); ++line) {
  1950.                 memcpy(out_buf, in_buf, (out->width * screen.Bpp));
  1951.                 in_buf += in->pitch;
  1952.                 out_buf += out->pitch;
  1953.         }
  1954. }
  1955.  
  1956. // Copy/rescale functions.
  1957.  
  1958. struct filter_scale_data {
  1959.         unsigned int x_scale;
  1960.         unsigned int y_scale;
  1961.         filter_func_t *filter;
  1962. };
  1963.  
  1964. template <typename uintX_t>
  1965. static void filter_scale_X(const struct filter_data *in,
  1966.                            struct filter_data *out)
  1967. {
  1968.         struct filter_scale_data *data =
  1969.                 (struct filter_scale_data *)out->data;
  1970.         uintX_t *dst = (uintX_t *)out->buf.u32;
  1971.         unsigned int dst_pitch = out->pitch;
  1972.         uintX_t *src = (uintX_t *)in->buf.u32;
  1973.         unsigned int src_pitch = in->pitch;
  1974.         unsigned int width = in->width;
  1975.         unsigned int x_scale = data->x_scale;
  1976.         unsigned int y_scale = data->y_scale;
  1977.         unsigned int height = in->height;
  1978.         unsigned int y;
  1979.  
  1980.         for (y = 0; (y != height); ++y) {
  1981.                 uintX_t *out = dst;
  1982.                 unsigned int i;
  1983.                 unsigned int x;
  1984.  
  1985.                 for (x = 0; (x != width); ++x) {
  1986.                         uintX_t tmp = src[x];
  1987.  
  1988.                         for (i = 0; (i != x_scale); ++i)
  1989.                                 *(out++) = tmp;
  1990.                 }
  1991.                 out = dst;
  1992.                 dst = (uintX_t *)((uint8_t *)dst + dst_pitch);
  1993.                 for (i = 1; (i < y_scale); ++i) {
  1994.                         memcpy(dst, out, (width * sizeof(*dst) * x_scale));
  1995.                         out = dst;
  1996.                         dst = (uintX_t *)((uint8_t *)dst + dst_pitch);
  1997.                 }
  1998.                 src = (uintX_t *)((uint8_t *)src + src_pitch);
  1999.         }
  2000. }
  2001.  
  2002. static void filter_scale_3(const struct filter_data *in,
  2003.                            struct filter_data *out)
  2004. {
  2005.         struct filter_scale_data *data =
  2006.                 (struct filter_scale_data *)out->data;
  2007.         uint24_t *dst = out->buf.u24;
  2008.         unsigned int dst_pitch = out->pitch;
  2009.         uint24_t *src = in->buf.u24;
  2010.         unsigned int src_pitch = in->pitch;
  2011.         unsigned int width = in->width;
  2012.         unsigned int x_scale = data->x_scale;
  2013.         unsigned int y_scale = data->y_scale;
  2014.         unsigned int height = in->height;
  2015.         unsigned int y;
  2016.  
  2017.         for (y = 0; (y != height); ++y) {
  2018.                 uint24_t *out = dst;
  2019.                 unsigned int i;
  2020.                 unsigned int x;
  2021.  
  2022.                 for (x = 0; (x != width); ++x) {
  2023.                         uint24_t tmp;
  2024.  
  2025.                         u24cpy(&tmp, &src[x]);
  2026.                         for (i = 0; (i != x_scale); ++i)
  2027.                                 u24cpy((out++), &tmp);
  2028.                 }
  2029.                 out = dst;
  2030.                 dst = (uint24_t *)((uint8_t *)dst + dst_pitch);
  2031.                 for (i = 1; (i < y_scale); ++i) {
  2032.                         memcpy(dst, out, (width * sizeof(*dst) * x_scale));
  2033.                         out = dst;
  2034.                         dst = (uint24_t *)((uint8_t *)dst + dst_pitch);
  2035.                 }
  2036.                 src = (uint24_t *)((uint8_t *)src + src_pitch);
  2037.         }
  2038. }
  2039.  
  2040. /**
  2041.  * This filter attempts to rescale according to screen X/Y factors.
  2042.  * @param in Input buffer data.
  2043.  * @param out Output buffer data.
  2044.  */
  2045. static void filter_scale(const struct filter_data *in,
  2046.                          struct filter_data *out)
  2047. {
  2048.         static const struct {
  2049.                 unsigned int Bpp;
  2050.                 filter_func_t *func;
  2051.         } scale_mode[] = {
  2052.                 { 1, filter_scale_X<uint8_t> },
  2053.                 { 2, filter_scale_X<uint16_t> },
  2054.                 { 3, filter_scale_3 },
  2055.                 { 4, filter_scale_X<uint32_t> },
  2056.         };
  2057.         struct filter_scale_data *data;
  2058.         unsigned int width;
  2059.         unsigned int height;
  2060.         unsigned int x_off;
  2061.         unsigned int y_off;
  2062.         unsigned int x_scale;
  2063.         unsigned int y_scale;
  2064.         filter_func_t *filter;
  2065.         unsigned int i;
  2066.  
  2067.         if (out->failed == true) {
  2068.         failed:
  2069.                 filter_off(in, out);
  2070.                 return;
  2071.         }
  2072.         if (out->updated == true) {
  2073.                 data = (struct filter_scale_data *)out->data;
  2074.                 filter = data->filter;
  2075.         process:
  2076.                 // Feed this to the basic scaler.
  2077.                 (*filter)(in, out);
  2078.                 return;
  2079.         }
  2080.         // Initialize filter.
  2081.         assert(out->data == NULL);
  2082.         x_scale = screen.x_scale;
  2083.         y_scale = screen.y_scale;
  2084.         while ((width = (in->width * x_scale)) > out->width)
  2085.                 --x_scale;
  2086.         while ((height = (in->height * y_scale)) > out->height)
  2087.                 --y_scale;
  2088.         // Check whether output is large enough.
  2089.         if ((x_scale == 0) || (y_scale == 0)) {
  2090.                 DEBUG(("cannot rescale by %ux%u", x_scale, y_scale));
  2091.                 out->failed = true;
  2092.                 goto failed;
  2093.         }
  2094.         // Not rescaling is faster through filter_off().
  2095.         if ((x_scale == 1) && (y_scale == 1)) {
  2096.                 DEBUG(("using faster fallback for %ux%u", x_scale, y_scale));
  2097.                 out->failed = true;
  2098.                 goto failed;
  2099.         }
  2100.         // Find a suitable filter.
  2101.         for (i = 0; (i != elemof(scale_mode)); ++i)
  2102.                 if (scale_mode[i].Bpp == screen.Bpp)
  2103.                         break;
  2104.         if (i == elemof(scale_mode)) {
  2105.                 DEBUG(("%u Bpp depth is not supported", screen.Bpp));
  2106.                 out->failed = true;
  2107.                 goto failed;
  2108.         }
  2109.         DEBUG(("using %u Bpp function to scale by %ux%u",
  2110.                screen.Bpp, x_scale, y_scale));
  2111.         data = (struct filter_scale_data *)malloc(sizeof(*data));
  2112.         if (data == NULL) {
  2113.                 DEBUG(("allocation failure"));
  2114.                 out->failed = true;
  2115.                 goto failed;
  2116.         }
  2117.         filter = scale_mode[i].func;
  2118.         data->filter = filter;
  2119.         data->x_scale = x_scale;
  2120.         data->y_scale = y_scale;
  2121.         // Center output.
  2122.         x_off = ((out->width - width) / 2);
  2123.         y_off = ((out->height - height) / 2);
  2124.         out->buf.u8 += (x_off * screen.Bpp);
  2125.         out->buf.u8 += (out->pitch * y_off);
  2126.         out->width = width;
  2127.         out->height = height;
  2128.         out->data = (void *)data;
  2129.         out->updated = true;
  2130.         goto process;
  2131. }
  2132.  
  2133. struct filter_stretch_data {
  2134.         uint8_t *h_table;
  2135.         uint8_t *v_table;
  2136.         filter_func_t *filter;
  2137. };
  2138.  
  2139. template <typename uintX_t>
  2140. static void filter_stretch_X(const struct filter_data *in,
  2141.                              struct filter_data *out)
  2142. {
  2143.         struct filter_stretch_data *data =
  2144.                 (struct filter_stretch_data *)out->data;
  2145.         uint8_t *h_table = data->h_table;
  2146.         uint8_t *v_table = data->v_table;
  2147.         uintX_t *dst = (uintX_t *)out->buf.u8;
  2148.         unsigned int dst_pitch = out->pitch;
  2149.         unsigned int dst_w = out->width;
  2150.         uintX_t *src = (uintX_t *)in->buf.u8;
  2151.         unsigned int src_pitch = in->pitch;
  2152.         unsigned int src_w = in->width;
  2153.         unsigned int src_h = in->height;
  2154.         unsigned int src_y;
  2155.  
  2156.         dst_pitch /= sizeof(*dst);
  2157.         src_pitch /= sizeof(*src);
  2158.         for (src_y = 0; (src_y != src_h); ++src_y) {
  2159.                 uint8_t v_repeat = v_table[src_y];
  2160.                 unsigned int src_x;
  2161.                 unsigned int dst_x;
  2162.  
  2163.                 if (!v_repeat) {
  2164.                         src += src_pitch;
  2165.                         continue;
  2166.                 }
  2167.                 for (src_x = 0, dst_x = 0; (src_x != src_w); ++src_x) {
  2168.                         uint8_t h_repeat = h_table[src_x];
  2169.  
  2170.                         if (!h_repeat)
  2171.                                 continue;
  2172.                         while (h_repeat--)
  2173.                                 dst[dst_x++] = src[src_x];
  2174.                 }
  2175.                 dst += dst_pitch;
  2176.                 while (--v_repeat) {
  2177.                         memcpy(dst, (dst - dst_pitch), (dst_w * sizeof(*dst)));
  2178.                         dst += dst_pitch;
  2179.                 }
  2180.                 src += src_pitch;
  2181.         }
  2182. }
  2183.  
  2184. static void filter_stretch_3(const struct filter_data *in,
  2185.                              struct filter_data *out)
  2186. {
  2187.         struct filter_stretch_data *data =
  2188.                 (struct filter_stretch_data *)out->data;
  2189.         uint8_t *h_table = data->h_table;
  2190.         uint8_t *v_table = data->v_table;
  2191.         uint24_t *dst = out->buf.u24;
  2192.         unsigned int dst_pitch = out->pitch;
  2193.         unsigned int dst_w = out->width;
  2194.         uint24_t *src = in->buf.u24;
  2195.         unsigned int src_pitch = in->pitch;
  2196.         unsigned int src_w = in->width;
  2197.         unsigned int src_h = in->height;
  2198.         unsigned int src_y;
  2199.  
  2200.         dst_pitch /= sizeof(*dst);
  2201.         src_pitch /= sizeof(*src);
  2202.         for (src_y = 0; (src_y != src_h); ++src_y) {
  2203.                 uint8_t v_repeat = v_table[src_y];
  2204.                 unsigned int src_x;
  2205.                 unsigned int dst_x;
  2206.  
  2207.                 if (!v_repeat) {
  2208.                         src += src_pitch;
  2209.                         continue;
  2210.                 }
  2211.                 for (src_x = 0, dst_x = 0; (src_x != src_w); ++src_x) {
  2212.                         uint8_t h_repeat = h_table[src_x];
  2213.  
  2214.                         if (!h_repeat)
  2215.                                 continue;
  2216.                         while (h_repeat--)
  2217.                                 u24cpy(&dst[dst_x++], &src[src_x]);
  2218.                 }
  2219.                 dst += dst_pitch;
  2220.                 while (--v_repeat) {
  2221.                         memcpy(dst, (dst - dst_pitch), (dst_w * sizeof(*dst)));
  2222.                         dst += dst_pitch;
  2223.                 }
  2224.                 src += src_pitch;
  2225.         }
  2226. }
  2227.  
  2228. /**
  2229.  * This filter stretches the input buffer to fill the entire output.
  2230.  * @param in Input buffer data.
  2231.  * @param out Output buffer data.
  2232.  */
  2233. static void filter_stretch(const struct filter_data *in,
  2234.                            struct filter_data *out)
  2235. {
  2236.         static const struct {
  2237.                 unsigned int Bpp;
  2238.                 filter_func_t *func;
  2239.         } stretch_mode[] = {
  2240.                 { 1, filter_stretch_X<uint8_t> },
  2241.                 { 2, filter_stretch_X<uint16_t> },
  2242.                 { 3, filter_stretch_3 },
  2243.                 { 4, filter_stretch_X<uint32_t> },
  2244.         };
  2245.         struct filter_stretch_data *data;
  2246.         unsigned int dst_w;
  2247.         unsigned int dst_h;
  2248.         unsigned int src_w;
  2249.         unsigned int src_h;
  2250.         unsigned int h_ratio;
  2251.         unsigned int v_ratio;
  2252.         unsigned int dst_x;
  2253.         unsigned int dst_y;
  2254.         unsigned int src_x;
  2255.         unsigned int src_y;
  2256.         filter_func_t *filter;
  2257.         unsigned int i;
  2258.  
  2259.         if (out->failed == true) {
  2260.         failed:
  2261.                 filter_off(in, out);
  2262.                 return;
  2263.         }
  2264.         if (out->updated == true) {
  2265.                 data = (struct filter_stretch_data *)out->data;
  2266.                 filter = data->filter;
  2267.         process:
  2268.                 (*filter)(in, out);
  2269.                 return;
  2270.         }
  2271.         // Initialize filter.
  2272.         assert(out->data == NULL);
  2273.         dst_w = out->width;
  2274.         dst_h = out->height;
  2275.         src_w = in->width;
  2276.         src_h = in->height;
  2277.         if ((src_h == 0) || (src_w == 0)) {
  2278.                 DEBUG(("invalid input size: %ux%u", src_h, src_w));
  2279.                 out->failed = true;
  2280.                 goto failed;
  2281.         }
  2282.         // Make sure input and output pitches are multiples of pixel size
  2283.         // at the current depth.
  2284.         if ((in->pitch % screen.Bpp) || (out->pitch % screen.Bpp)) {
  2285.                 DEBUG(("Bpp: %u, in->pitch: %u, out->pitch: %u",
  2286.                        screen.Bpp, in->pitch, out->pitch));
  2287.                 out->failed = true;
  2288.                 goto failed;
  2289.         }
  2290.         // Find a suitable filter.
  2291.         for (i = 0; (i != elemof(stretch_mode)); ++i)
  2292.                 if (stretch_mode[i].Bpp == screen.Bpp)
  2293.                         break;
  2294.         if (i == elemof(stretch_mode)) {
  2295.                 DEBUG(("%u Bpp depth is not supported", screen.Bpp));
  2296.                 out->failed = true;
  2297.                 goto failed;
  2298.         }
  2299.         filter = stretch_mode[i].func;
  2300.         // Fix output if original aspect ratio must be kept.
  2301.         if (dgen_aspect) {
  2302.                 unsigned int w = ((dst_h * src_w) / src_h);
  2303.                 unsigned int h = ((dst_w * src_h) / src_w);
  2304.  
  2305.                 if (w >= dst_w) {
  2306.                         w = dst_w;
  2307.                         if (h == 0)
  2308.                                 ++h;
  2309.                 }
  2310.                 else {
  2311.                         h = dst_h;
  2312.                         if (w == 0)
  2313.                                 ++w;
  2314.                 }
  2315.                 dst_w = w;
  2316.                 dst_h = h;
  2317.         }
  2318.         // Precompute H and V pixel ratios.
  2319.         h_ratio = ((dst_w << 10) / src_w);
  2320.         v_ratio = ((dst_h << 10) / src_h);
  2321.         data = (struct filter_stretch_data *)
  2322.                 calloc(1, sizeof(*data) + src_w + src_h);
  2323.         if (data == NULL) {
  2324.                 DEBUG(("allocation failure"));
  2325.                 out->failed = true;
  2326.                 goto failed;
  2327.         }
  2328.         DEBUG(("stretching %ux%u to %ux%u/%ux%u (aspect ratio %s)",
  2329.                src_w, src_h, dst_w, dst_h, out->width, out->height,
  2330.                (dgen_aspect ? "must be kept" : "is free")));
  2331.         data->h_table = (uint8_t *)(data + 1);
  2332.         data->v_table = (data->h_table + src_w);
  2333.         data->filter = filter;
  2334.         for (dst_x = 0; (dst_x != dst_w); ++dst_x) {
  2335.                 src_x = ((dst_x << 10) / h_ratio);
  2336.                 if (src_x < src_w)
  2337.                         ++data->h_table[src_x];
  2338.         }
  2339.         for (dst_y = 0; (dst_y != dst_h); ++dst_y) {
  2340.                 src_y = ((dst_y << 10) / v_ratio);
  2341.                 if (src_y < src_h)
  2342.                         ++data->v_table[src_y];
  2343.         }
  2344.         // Center output.
  2345.         dst_x = ((out->width - dst_w) / 2);
  2346.         dst_y = ((out->height - dst_h) / 2);
  2347.         out->buf.u8 += (dst_x * screen.Bpp);
  2348.         out->buf.u8 += (out->pitch * dst_y);
  2349.         out->width = dst_w;
  2350.         out->height = dst_h;
  2351.         out->data = (void *)data;
  2352.         out->updated = true;
  2353.         goto process;
  2354. }
  2355.  
  2356. #ifdef WITH_HQX
  2357.  
  2358. /**
  2359.  * This filter attempts to rescale with HQX.
  2360.  * @param in Input buffer data.
  2361.  * @param out Output buffer data.
  2362.  */
  2363. static void filter_hqx(const struct filter_data *in, struct filter_data *out)
  2364. {
  2365.         typedef void hqx_func_t(void *src, uint32_t src_pitch,
  2366.                                 void *dst, uint32_t dst_pitch,
  2367.                                 int width, int height);
  2368.  
  2369.         static const struct {
  2370.                 unsigned int Bpp;
  2371.                 unsigned int scale;
  2372.                 hqx_func_t *func;
  2373.         } hqx_mode[] = {
  2374.                 { 2, 2, (hqx_func_t *)hq2x_16_rb },
  2375.                 { 2, 3, (hqx_func_t *)hq3x_16_rb },
  2376.                 { 2, 4, (hqx_func_t *)hq4x_16_rb },
  2377.                 { 3, 2, (hqx_func_t *)hq2x_24_rb },
  2378.                 { 3, 3, (hqx_func_t *)hq3x_24_rb },
  2379.                 { 3, 4, (hqx_func_t *)hq4x_24_rb },
  2380.                 { 4, 2, (hqx_func_t *)hq2x_32_rb },
  2381.                 { 4, 3, (hqx_func_t *)hq3x_32_rb },
  2382.                 { 4, 4, (hqx_func_t *)hq4x_32_rb },
  2383.         };
  2384.         static bool hqx_initialized = false;
  2385.         unsigned int width;
  2386.         unsigned int height;
  2387.         unsigned int x_off;
  2388.         unsigned int y_off;
  2389.         unsigned int x_scale;
  2390.         unsigned int y_scale;
  2391.         hqx_func_t *hqx;
  2392.         unsigned int i;
  2393.  
  2394.         if (out->failed == true) {
  2395.         failed:
  2396.                 filter_off(in, out);
  2397.                 return;
  2398.         }
  2399.         if (out->updated == true) {
  2400.                 hqx = *(hqx_func_t **)out->data;
  2401.         process:
  2402.                 // Feed this to HQX.
  2403.                 (*hqx)((void *)in->buf.u32, in->pitch,
  2404.                        (void *)out->buf.u32, out->pitch,
  2405.                        in->width, in->height);
  2406.                 return;
  2407.         }
  2408.         // Initialize filter.
  2409.         assert(out->data == NULL);
  2410.         x_scale = screen.x_scale;
  2411.         y_scale = screen.y_scale;
  2412. retry:
  2413.         while ((width = (in->width * x_scale)) > out->width)
  2414.                 --x_scale;
  2415.         while ((height = (in->height * y_scale)) > out->height)
  2416.                 --y_scale;
  2417.         // Check whether output is large enough.
  2418.         if ((x_scale == 0) || (y_scale == 0)) {
  2419.                 DEBUG(("cannot rescale by %ux%u", x_scale, y_scale));
  2420.                 out->failed = true;
  2421.                 goto failed;
  2422.         }
  2423.         // Find a suitable combination.
  2424.         for (i = 0; (i != elemof(hqx_mode)); ++i)
  2425.                 if ((hqx_mode[i].Bpp == screen.Bpp) &&
  2426.                     (hqx_mode[i].scale == x_scale) &&
  2427.                     (hqx_mode[i].scale == y_scale))
  2428.                         break;
  2429.         if (i == elemof(hqx_mode)) {
  2430.                 // Nothing matches, find something that fits.
  2431.                 DEBUG(("%ux%u @%u Bpp scale factor not supported, trying"
  2432.                        " another",
  2433.                        x_scale, y_scale, screen.Bpp));
  2434.                 // Must be square.
  2435.                 if (x_scale > y_scale)
  2436.                         x_scale = y_scale;
  2437.                 else if (y_scale > x_scale)
  2438.                         y_scale = x_scale;
  2439.                 assert(x_scale == y_scale);
  2440.                 (void)y_scale;
  2441.                 do {
  2442.                         --i;
  2443.                         if ((hqx_mode[i].Bpp == screen.Bpp) &&
  2444.                             (hqx_mode[i].scale <= x_scale)) {
  2445.                                 x_scale = hqx_mode[i].scale;
  2446.                                 y_scale = hqx_mode[i].scale;
  2447.                                 goto retry;
  2448.                         }
  2449.                 }
  2450.                 while (i != 0);
  2451.                 DEBUG(("failed to use %ux%u @%u Bpp scale factor",
  2452.                        x_scale, y_scale, screen.Bpp));
  2453.                 out->failed = true;
  2454.                 goto failed;
  2455.         }
  2456.         DEBUG(("using %ux%u @%u Bpp scale factor",
  2457.                x_scale, y_scale, screen.Bpp));
  2458.         hqx = hqx_mode[i].func;
  2459.         out->data = malloc(sizeof(hqx));
  2460.         if (out->data == NULL) {
  2461.                 DEBUG(("allocation failure"));
  2462.                 out->failed = true;
  2463.                 goto failed;
  2464.         }
  2465.         *(hqx_func_t **)out->data = hqx;
  2466.         // Center output.
  2467.         x_off = ((out->width - width) / 2);
  2468.         y_off = ((out->height - height) / 2);
  2469.         out->buf.u8 += (x_off * screen.Bpp);
  2470.         out->buf.u8 += (out->pitch * y_off);
  2471.         out->width = width;
  2472.         out->height = height;
  2473.         out->updated = true;
  2474.         // Initialize HQX if necessary.
  2475.         if (hqx_initialized == false) {
  2476.                 pd_message_cursor(~0u, "Initializing hqx...");
  2477.                 stopped = 1;
  2478.                 hqxInit();
  2479.                 pd_message_cursor(~0u, "");
  2480.                 hqx_initialized = true;
  2481.         }
  2482.         goto process;
  2483. }
  2484.  
  2485. #endif // WITH_HQX
  2486.  
  2487. #ifdef WITH_SCALE2X
  2488.  
  2489. /**
  2490.  * This filter attempts to rescale with Scale2x.
  2491.  * @param in Input buffer data.
  2492.  * @param out Output buffer data.
  2493.  */
  2494. static void filter_scale2x(const struct filter_data *in,
  2495.                            struct filter_data *out)
  2496. {
  2497.         static const struct {
  2498.                 unsigned int x_scale;
  2499.                 unsigned int y_scale;
  2500.                 unsigned int mode;
  2501.         } scale2x_mode[] = {
  2502.                 { 2, 2, 2 },
  2503.                 { 2, 3, 203 },
  2504.                 { 2, 4, 204 },
  2505.                 { 3, 3, 3 },
  2506.                 { 4, 4, 4 }
  2507.         };
  2508.         unsigned int width;
  2509.         unsigned int height;
  2510.         unsigned int x_off;
  2511.         unsigned int y_off;
  2512.         unsigned int x_scale;
  2513.         unsigned int y_scale;
  2514.         unsigned int mode;
  2515.         unsigned int i;
  2516.  
  2517.         if (out->failed == true) {
  2518.         failed:
  2519.                 filter_off(in, out);
  2520.                 return;
  2521.         }
  2522.         if (out->updated == true) {
  2523.                 mode = *(unsigned int *)out->data;
  2524.         process:
  2525.                 // Feed this to scale2x.
  2526.                 scale(mode, out->buf.u32, out->pitch, in->buf.u32, in->pitch,
  2527.                       screen.Bpp, in->width, in->height);
  2528.                 return;
  2529.         }
  2530.         // Initialize filter.
  2531.         assert(out->data == NULL);
  2532.         x_scale = screen.x_scale;
  2533.         y_scale = screen.y_scale;
  2534. retry:
  2535.         while ((width = (in->width * x_scale)) > out->width)
  2536.                 --x_scale;
  2537.         while ((height = (in->height * y_scale)) > out->height)
  2538.                 --y_scale;
  2539.         // Check whether output is large enough.
  2540.         if ((x_scale == 0) || (y_scale == 0)) {
  2541.                 DEBUG(("cannot rescale by %ux%u", x_scale, y_scale));
  2542.                 out->failed = true;
  2543.                 goto failed;
  2544.         }
  2545.         // Check whether depth is supported by filter.
  2546.         if ((screen.Bpp != 4) && (screen.Bpp != 2)) {
  2547.                 DEBUG(("unsupported depth %u", screen.bpp));
  2548.                 out->failed = true;
  2549.                 goto failed;
  2550.         }
  2551.         // Find a suitable combination.
  2552.         for (i = 0; (i != elemof(scale2x_mode)); ++i)
  2553.                 if ((scale2x_mode[i].x_scale == x_scale) &&
  2554.                     (scale2x_mode[i].y_scale == y_scale))
  2555.                         break;
  2556.         if (i == elemof(scale2x_mode)) {
  2557.                 // Nothing matches, find something that fits.
  2558.                 DEBUG(("%ux%u scale factor not supported, trying another",
  2559.                        x_scale, y_scale));
  2560.                 do {
  2561.                         --i;
  2562.                         if ((scale2x_mode[i].x_scale <= x_scale) &&
  2563.                             (scale2x_mode[i].y_scale <= y_scale)) {
  2564.                                 x_scale = scale2x_mode[i].x_scale;
  2565.                                 y_scale = scale2x_mode[i].y_scale;
  2566.                                 goto retry;
  2567.                         }
  2568.                 }
  2569.                 while (i != 0);
  2570.                 DEBUG(("failed to use %ux%u scale factor", x_scale, y_scale));
  2571.                 out->failed = true;
  2572.                 goto failed;
  2573.         }
  2574.         DEBUG(("using %ux%u scale factor", x_scale, y_scale));
  2575.         mode = scale2x_mode[i].mode;
  2576.         out->data = malloc(sizeof(mode));
  2577.         if (out->data == NULL) {
  2578.                 DEBUG(("allocation failure"));
  2579.                 out->failed = true;
  2580.                 goto failed;
  2581.         }
  2582.         *(unsigned int *)out->data = mode;
  2583.         // Center output.
  2584.         x_off = ((out->width - width) / 2);
  2585.         y_off = ((out->height - height) / 2);
  2586.         out->buf.u8 += (x_off * screen.Bpp);
  2587.         out->buf.u8 += (out->pitch * y_off);
  2588.         out->width = width;
  2589.         out->height = height;
  2590.         out->updated = true;
  2591.         goto process;
  2592. }
  2593.  
  2594. #endif // WITH_SCALE2X
  2595.  
  2596. #ifdef WITH_CTV
  2597.  
  2598. // "Blur" CTV filters.
  2599.  
  2600. static void filter_blur_32(const struct filter_data *in,
  2601.                            struct filter_data *out)
  2602. {
  2603.         bpp_t in_buf = in->buf;
  2604.         bpp_t out_buf = out->buf;
  2605.         unsigned int xsize = out->width;
  2606.         unsigned int ysize = out->height;
  2607.         unsigned int y;
  2608.  
  2609.         for (y = 0; (y < ysize); ++y) {
  2610.                 uint32_t old = *in_buf.u32;
  2611.                 unsigned int x;
  2612.  
  2613.                 for (x = 0; (x < xsize); ++x) {
  2614.                         uint32_t tmp = in_buf.u32[x];
  2615.  
  2616.                         tmp = (((((tmp & 0x00ff00ff) +
  2617.                                   (old & 0x00ff00ff)) >> 1) & 0x00ff00ff) |
  2618.                                ((((tmp & 0xff00ff00) +
  2619.                                   (old & 0xff00ff00)) >> 1) & 0xff00ff00));
  2620.                         old = in_buf.u32[x];
  2621.                         out_buf.u32[x] = tmp;
  2622.                 }
  2623.                 in_buf.u8 += in->pitch;
  2624.                 out_buf.u8 += out->pitch;
  2625.         }
  2626. }
  2627.  
  2628. static void filter_blur_24(const struct filter_data *in,
  2629.                            struct filter_data *out)
  2630. {
  2631.         bpp_t in_buf = in->buf;
  2632.         bpp_t out_buf = out->buf;
  2633.         unsigned int xsize = out->width;
  2634.         unsigned int ysize = out->height;
  2635.         unsigned int y;
  2636.  
  2637.         for (y = 0; (y < ysize); ++y) {
  2638.                 uint24_t old;
  2639.                 unsigned int x;
  2640.  
  2641.                 u24cpy(&old, in_buf.u24);
  2642.                 for (x = 0; (x < xsize); ++x) {
  2643.                         uint24_t tmp;
  2644.  
  2645.                         u24cpy(&tmp, &in_buf.u24[x]);
  2646.                         out_buf.u24[x][0] = ((tmp[0] + old[0]) >> 1);
  2647.                         out_buf.u24[x][1] = ((tmp[1] + old[1]) >> 1);
  2648.                         out_buf.u24[x][2] = ((tmp[2] + old[2]) >> 1);
  2649.                         u24cpy(&old, &tmp);
  2650.                 }
  2651.                 in_buf.u8 += in->pitch;
  2652.                 out_buf.u8 += out->pitch;
  2653.         }
  2654. }
  2655.  
  2656. static void filter_blur_16(const struct filter_data *in,
  2657.                            struct filter_data *out)
  2658. {
  2659.         bpp_t in_buf = in->buf;
  2660.         bpp_t out_buf = out->buf;
  2661.         unsigned int xsize = out->width;
  2662.         unsigned int ysize = out->height;
  2663.         unsigned int y;
  2664.  
  2665. #ifdef WITH_X86_CTV
  2666.         if (in_buf.u16 == out_buf.u16) {
  2667.                 for (y = 0; (y < ysize); ++y) {
  2668.                         // Blur, by Dave
  2669.                         blur_bitmap_16((uint8_t *)out_buf.u16, (xsize - 1));
  2670.                         out_buf.u8 += out->pitch;
  2671.                 }
  2672.                 return;
  2673.         }
  2674. #endif
  2675.         for (y = 0; (y < ysize); ++y) {
  2676.                 uint16_t old = *in_buf.u16;
  2677.                 unsigned int x;
  2678.  
  2679.                 for (x = 0; (x < xsize); ++x) {
  2680.                         uint16_t tmp = in_buf.u16[x];
  2681.  
  2682.                         tmp = (((((tmp & 0xf81f) +
  2683.                                   (old & 0xf81f)) >> 1) & 0xf81f) |
  2684.                                ((((tmp & 0x07e0) +
  2685.                                   (old & 0x07e0)) >> 1) & 0x07e0));
  2686.                         old = in_buf.u16[x];
  2687.                         out_buf.u16[x] = tmp;
  2688.                 }
  2689.                 in_buf.u8 += in->pitch;
  2690.                 out_buf.u8 += out->pitch;
  2691.         }
  2692. }
  2693.  
  2694. static void filter_blur_15(const struct filter_data *in,
  2695.                            struct filter_data *out)
  2696. {
  2697.         bpp_t in_buf = in->buf;
  2698.         bpp_t out_buf = out->buf;
  2699.         unsigned int xsize = out->width;
  2700.         unsigned int ysize = out->height;
  2701.         unsigned int y;
  2702.  
  2703. #ifdef WITH_X86_CTV
  2704.         if (in_buf.u15 == out_buf.u15) {
  2705.                 for (y = 0; (y < ysize); ++y) {
  2706.                         // Blur, by Dave
  2707.                         blur_bitmap_15((uint8_t *)out_buf.u15, (xsize - 1));
  2708.                         out_buf.u8 += out->pitch;
  2709.                 }
  2710.                 return;
  2711.         }
  2712. #endif
  2713.         for (y = 0; (y < ysize); ++y) {
  2714.                 uint16_t old = *in_buf.u15;
  2715.                 unsigned int x;
  2716.  
  2717.                 for (x = 0; (x < xsize); ++x) {
  2718.                         uint16_t tmp = in_buf.u15[x];
  2719.  
  2720.                         tmp = (((((tmp & 0x7c1f) +
  2721.                                   (old & 0x7c1f)) >> 1) & 0x7c1f) |
  2722.                                ((((tmp & 0x03e0) +
  2723.                                   (old & 0x03e0)) >> 1) & 0x03e0));
  2724.                         old = in_buf.u15[x];
  2725.                         out_buf.u15[x] = tmp;
  2726.                 }
  2727.                 in_buf.u8 += in->pitch;
  2728.                 out_buf.u8 += out->pitch;
  2729.         }
  2730. }
  2731.  
  2732. static void filter_blur(const struct filter_data *in,
  2733.                         struct filter_data *out)
  2734. {
  2735.         static const struct {
  2736.                 unsigned int bpp;
  2737.                 filter_func_t *filter;
  2738.         } blur_mode[] = {
  2739.                 { 32, filter_blur_32 },
  2740.                 { 24, filter_blur_24 },
  2741.                 { 16, filter_blur_16 },
  2742.                 { 15, filter_blur_15 },
  2743.         };
  2744.         filter_func_t *blur;
  2745.  
  2746.         if (out->failed == true) {
  2747.         failed:
  2748.                 filter_off(in, out);
  2749.                 return;
  2750.         }
  2751.         if (out->updated == false) {
  2752.                 unsigned int i;
  2753.  
  2754.                 for (i = 0; (i != elemof(blur_mode)); ++i)
  2755.                         if (blur_mode[i].bpp == screen.bpp)
  2756.                                 break;
  2757.                 if (i == elemof(blur_mode)) {
  2758.                         DEBUG(("%u bpp depth is not supported", screen.bpp));
  2759.                         out->failed = true;
  2760.                         goto failed;
  2761.                 }
  2762.                 blur = blur_mode[i].filter;
  2763.                 out->data = malloc(sizeof(filter));
  2764.                 if (out->data == NULL) {
  2765.                         DEBUG(("allocation failure"));
  2766.                         out->failed = true;
  2767.                         goto failed;
  2768.                 }
  2769.                 if (in->width <= out->width) {
  2770.                         unsigned int x_off = ((out->width - in->width) / 2);
  2771.                         unsigned int y_off = ((out->height - in->height) / 2);
  2772.  
  2773.                         out->buf.u8 += (x_off * screen.Bpp);
  2774.                         out->buf.u8 += (out->pitch * y_off);
  2775.                         out->width = in->width;
  2776.                 }
  2777.                 if (in->height <= out->height)
  2778.                         out->height = in->height;
  2779.                 *((filter_func_t **)out->data) = blur;
  2780.                 out->updated = true;
  2781.         }
  2782.         else
  2783.                 blur = *(filter_func_t **)out->data;
  2784.         (*blur)(in, out);
  2785. }
  2786.  
  2787. // Scanline/Interlace CTV filters.
  2788.  
  2789. static void filter_scanline_frame(const struct filter_data *in,
  2790.                                   struct filter_data *out)
  2791. {
  2792.         unsigned int frame = ((unsigned int *)out->data)[0];
  2793.         unsigned int bpp = ((unsigned int *)out->data)[1];
  2794.         bpp_t in_buf = in->buf;
  2795.         bpp_t out_buf = out->buf;
  2796.         unsigned int xsize = out->width;
  2797.         unsigned int ysize = out->height;
  2798.  
  2799.         out_buf.u8 += (out->pitch * !!frame);
  2800.         switch (bpp) {
  2801.                 unsigned int x;
  2802.                 unsigned int y;
  2803.  
  2804.         case 32:
  2805.                 for (y = frame; (y < ysize); y += 2) {
  2806.                         for (x = 0; (x < xsize); ++x)
  2807.                                 out_buf.u32[x] =
  2808.                                         ((in_buf.u32[x] >> 1) & 0x7f7f7f7f);
  2809.                         in_buf.u8 += (in->pitch * 2);
  2810.                         out_buf.u8 += (out->pitch * 2);
  2811.                 }
  2812.                 break;
  2813.         case 24:
  2814.                 for (y = frame; (y < ysize); y += 2) {
  2815.                         for (x = 0; (x < xsize); ++x) {
  2816.                                 out_buf.u24[x][0] = (in_buf.u24[x][0] >> 1);
  2817.                                 out_buf.u24[x][1] = (in_buf.u24[x][1] >> 1);
  2818.                                 out_buf.u24[x][2] = (in_buf.u24[x][2] >> 1);
  2819.                         }
  2820.                         in_buf.u8 += (in->pitch * 2);
  2821.                         out_buf.u8 += (out->pitch * 2);
  2822.                 }
  2823.                 break;
  2824.         case 16:
  2825.                 for (y = frame; (y < ysize); y += 2) {
  2826. #ifdef WITH_X86_CTV
  2827.                         if (in_buf.u16 == out_buf.u16) {
  2828.                                 // Scanline, by Phil
  2829.                                 test_ctv((uint8_t *)out_buf.u16, xsize);
  2830.                         }
  2831.                         else
  2832. #endif
  2833.                         for (x = 0; (x < xsize); ++x)
  2834.                                 out_buf.u16[x] =
  2835.                                         ((in_buf.u16[x] >> 1) & 0x7bef);
  2836.                         in_buf.u8 += (in->pitch * 2);
  2837.                         out_buf.u8 += (out->pitch * 2);
  2838.                 }
  2839.                 break;
  2840.         case 15:
  2841.                 for (y = frame; (y < ysize); y += 2) {
  2842. #ifdef WITH_X86_CTV
  2843.                         if (in_buf.u15 == out_buf.u15) {
  2844.                                 // Scanline, by Phil
  2845.                                 test_ctv((uint8_t *)out_buf.u16, xsize);
  2846.                         }
  2847.                         else
  2848. #endif
  2849.                         for (x = 0; (x < xsize); ++x)
  2850.                                 out_buf.u15[x] =
  2851.                                         ((in_buf.u15[x] >> 1) & 0x3def);
  2852.                         in_buf.u8 += (in->pitch * 2);
  2853.                         out_buf.u8 += (out->pitch * 2);
  2854.                 }
  2855.                 break;
  2856.         }
  2857. }
  2858.  
  2859. static void filter_scanline(const struct filter_data *in,
  2860.                             struct filter_data *out)
  2861. {
  2862.         if (out->failed == true) {
  2863.         failed:
  2864.                 filter_off(in, out);
  2865.                 return;
  2866.         }
  2867.         if (out->updated == false) {
  2868.                 if ((screen.bpp != 32) &&
  2869.                     (screen.bpp != 24) &&
  2870.                     (screen.bpp != 16) &&
  2871.                     (screen.bpp != 15)) {
  2872.                         DEBUG(("%u bpp depth is not supported", screen.bpp));
  2873.                         out->failed = true;
  2874.                         goto failed;
  2875.                 }
  2876.                 out->data = malloc(sizeof(unsigned int [2]));
  2877.                 if (out->data == NULL) {
  2878.                         DEBUG(("allocation failure"));
  2879.                         out->failed = true;
  2880.                         goto failed;
  2881.                 }
  2882.                 if (in->width <= out->width) {
  2883.                         unsigned int x_off = ((out->width - in->width) / 2);
  2884.                         unsigned int y_off = ((out->height - in->height) / 2);
  2885.  
  2886.                         out->buf.u8 += (x_off * screen.Bpp);
  2887.                         out->buf.u8 += (out->pitch * y_off);
  2888.                         out->width = in->width;
  2889.                 }
  2890.                 if (in->height <= out->height)
  2891.                         out->height = in->height;
  2892.                 ((unsigned int *)out->data)[0] = 0;
  2893.                 ((unsigned int *)out->data)[1] = screen.bpp;
  2894.                 out->updated = true;
  2895.         }
  2896.         filter_scanline_frame(in, out);
  2897. }
  2898.  
  2899. static void filter_interlace(const struct filter_data *in,
  2900.                              struct filter_data *out)
  2901. {
  2902.         if (out->failed == true) {
  2903.         failed:
  2904.                 filter_off(in, out);
  2905.                 return;
  2906.         }
  2907.         if (out->updated == false) {
  2908.                 if ((screen.bpp != 32) &&
  2909.                     (screen.bpp != 24) &&
  2910.                     (screen.bpp != 16) &&
  2911.                     (screen.bpp != 15)) {
  2912.                         DEBUG(("%u bpp depth is not supported", screen.bpp));
  2913.                         out->failed = true;
  2914.                         goto failed;
  2915.                 }
  2916.                 out->data = malloc(sizeof(unsigned int [2]));
  2917.                 if (out->data == NULL) {
  2918.                         DEBUG(("allocation failure"));
  2919.                         out->failed = true;
  2920.                         goto failed;
  2921.                 }
  2922.                 if (in->width <= out->width) {
  2923.                         unsigned int x_off = ((out->width - in->width) / 2);
  2924.                         unsigned int y_off = ((out->height - in->height) / 2);
  2925.  
  2926.                         out->buf.u8 += (x_off * screen.Bpp);
  2927.                         out->buf.u8 += (out->pitch * y_off);
  2928.                         out->width = in->width;
  2929.                 }
  2930.                 if (in->height <= out->height)
  2931.                         out->height = in->height;
  2932.                 ((unsigned int *)out->data)[0] = 0;
  2933.                 ((unsigned int *)out->data)[1] = screen.bpp;
  2934.                 out->updated = true;
  2935.         }
  2936.         filter_scanline_frame(in, out);
  2937.         ((unsigned int *)out->data)[0] ^= 1;
  2938. }
  2939.  
  2940. // Byte swap filter.
  2941. static void filter_swab(const struct filter_data *in,
  2942.                         struct filter_data *out)
  2943. {
  2944.         bpp_t in_buf;
  2945.         bpp_t out_buf;
  2946.         unsigned int xsize;
  2947.         unsigned int ysize;
  2948.  
  2949.         if (out->failed == true) {
  2950.         failed:
  2951.                 filter_off(in, out);
  2952.                 return;
  2953.         }
  2954.         if (out->updated == false) {
  2955.                 if ((screen.Bpp != 4) &&
  2956.                     (screen.Bpp != 3) &&
  2957.                     (screen.Bpp != 2)) {
  2958.                         DEBUG(("%u Bpp depth is not supported", screen.Bpp));
  2959.                         out->failed = true;
  2960.                         goto failed;
  2961.                 }
  2962.                 if (in->width <= out->width) {
  2963.                         unsigned int x_off = ((out->width - in->width) / 2);
  2964.                         unsigned int y_off = ((out->height - in->height) / 2);
  2965.  
  2966.                         out->buf.u8 += (x_off * screen.Bpp);
  2967.                         out->buf.u8 += (out->pitch * y_off);
  2968.                         out->width = in->width;
  2969.                 }
  2970.                 if (in->height <= out->height)
  2971.                         out->height = in->height;
  2972.                 out->updated = true;
  2973.         }
  2974.         in_buf = in->buf;
  2975.         out_buf = out->buf;
  2976.         ysize = out->height;
  2977.         xsize = out->width;
  2978.         switch (screen.Bpp) {
  2979.                 unsigned int x;
  2980.                 unsigned int y;
  2981.  
  2982.         case 4:
  2983.                 for (y = 0; (y < ysize); ++y) {
  2984.                         for (x = 0; (x < xsize); ++x) {
  2985.                                 union {
  2986.                                         uint32_t u32;
  2987.                                         uint8_t u8[4];
  2988.                                 } tmp[2];
  2989.  
  2990.                                 tmp[0].u32 = in_buf.u32[x];
  2991.                                 tmp[1].u8[0] = tmp[0].u8[3];
  2992.                                 tmp[1].u8[1] = tmp[0].u8[2];
  2993.                                 tmp[1].u8[2] = tmp[0].u8[1];
  2994.                                 tmp[1].u8[3] = tmp[0].u8[0];
  2995.                                 out_buf.u32[x] = tmp[1].u32;
  2996.                         }
  2997.                         in_buf.u8 += in->pitch;
  2998.                         out_buf.u8 += out->pitch;
  2999.                 }
  3000.                 break;
  3001.         case 3:
  3002.                 for (y = 0; (y < ysize); ++y) {
  3003.                         for (x = 0; (x < xsize); ++x) {
  3004.                                 uint24_t tmp = {
  3005.                                         in_buf.u24[x][2],
  3006.                                         in_buf.u24[x][1],
  3007.                                         in_buf.u24[x][0]
  3008.                                 };
  3009.  
  3010.                                 u24cpy(&out_buf.u24[x], &tmp);
  3011.                         }
  3012.                         in_buf.u8 += in->pitch;
  3013.                         out_buf.u8 += out->pitch;
  3014.                 }
  3015.                 break;
  3016.         case 2:
  3017.                 for (y = 0; (y < ysize); ++y) {
  3018.                         for (x = 0; (x < xsize); ++x)
  3019.                                 out_buf.u16[x] = ((in_buf.u16[x] << 8) |
  3020.                                                   (in_buf.u16[x] >> 8));
  3021.                         in_buf.u8 += in->pitch;
  3022.                         out_buf.u8 += out->pitch;
  3023.                 }
  3024.                 break;
  3025.         }
  3026. }
  3027.  
  3028. #endif // WITH_CTV
  3029.  
  3030. /**
  3031.  * Special characters interpreted by filter_text().
  3032.  * FILTER_TEXT_BG_NONE  transparent background.
  3033.  * FILTER_TEXT_BG_BLACK black background.
  3034.  * FILTER_TEXT_7X6      use 7x6 font.
  3035.  * FILTER_TEXT_8X13     use 8x13 font.
  3036.  * FILTER_TEXT_16X26    use 16x26 font.
  3037.  * FILTER_TEXT_CENTER   center justify.
  3038.  * FILTER_TEXT_LEFT     left justify.
  3039.  * FILTER_TEXT_RIGHT    right justify.
  3040.  */
  3041. #define FILTER_TEXT_ESCAPE "\033"
  3042. #define FILTER_TEXT_BG_NONE FILTER_TEXT_ESCAPE "\x01\x01"
  3043. #define FILTER_TEXT_BG_BLACK FILTER_TEXT_ESCAPE "\x01\x02"
  3044. #define FILTER_TEXT_7X6 FILTER_TEXT_ESCAPE "\x02\x01"
  3045. #define FILTER_TEXT_8X13 FILTER_TEXT_ESCAPE "\x02\x02"
  3046. #define FILTER_TEXT_16X26 FILTER_TEXT_ESCAPE "\x02\x03"
  3047. #define FILTER_TEXT_CENTER FILTER_TEXT_ESCAPE "\x03\x01"
  3048. #define FILTER_TEXT_LEFT FILTER_TEXT_ESCAPE "\x03\x02"
  3049. #define FILTER_TEXT_RIGHT FILTER_TEXT_ESCAPE "\x03\x03"
  3050.  
  3051. static char filter_text_str[2048];
  3052.  
  3053. /**
  3054.  * Append message to filter_text_str[].
  3055.  */
  3056. static void filter_text_msg(const char *fmt, ...)
  3057. {
  3058.         size_t off;
  3059.         size_t len = sizeof(filter_text_str);
  3060.         va_list vl;
  3061.  
  3062.         assert(filter_text_str[(len - 1)] == '\0');
  3063.         off = strlen(filter_text_str);
  3064.         len -= off;
  3065.         if (len == 0)
  3066.                 return;
  3067.         va_start(vl, fmt);
  3068.         vsnprintf(&filter_text_str[off], len, fmt, vl);
  3069.         va_end(vl);
  3070. }
  3071.  
  3072. /**
  3073.  * Text overlay filter.
  3074.  * @param in Input buffer data.
  3075.  * @param out Output buffer data.
  3076.  */
  3077. static void filter_text(const struct filter_data *in,
  3078.                         struct filter_data *out)
  3079. {
  3080.         bpp_t buf = out->buf;
  3081.         unsigned int buf_pitch = out->pitch;
  3082.         unsigned int xsize = out->width;
  3083.         unsigned int ysize = out->height;
  3084.         unsigned int bpp = screen.bpp;
  3085.         unsigned int Bpp = ((bpp + 1) / 8);
  3086.         const char *str = filter_text_str;
  3087.         const char *next = str;
  3088.         bool clear = false;
  3089.         bool flush = false;
  3090.         enum { LEFT, CENTER, RIGHT } justify = LEFT;
  3091.         const struct {
  3092.                 enum font_type type;
  3093.                 unsigned int width;
  3094.                 unsigned int height;
  3095.         } font_data[] = {
  3096.                 { FONT_TYPE_7X5, 7, (5 + 1) }, // +1 for vertical spacing.
  3097.                 { FONT_TYPE_8X13, 8, 13 },
  3098.                 { FONT_TYPE_16X26, 16, 26 }
  3099.         }, *font = &font_data[0], *old_font = font;
  3100.         unsigned int line_length = 0;
  3101.         unsigned int line_off = 0;
  3102.         unsigned int line_width = 0;
  3103.         unsigned int line_height = font->height;
  3104.  
  3105.         // Input is unused.
  3106.         (void)in;
  3107.         assert(filter_text_str[(sizeof(filter_text_str) - 1)] == '\0');
  3108.         while (1) {
  3109.                 unsigned int len;
  3110.                 unsigned int width;
  3111.  
  3112.                 if ((*next == '\0') || (*next == '\n')) {
  3113.                 trunc:
  3114.                         if (flush == false) {
  3115.                                 next = str;
  3116.                                 assert(line_width <= xsize);
  3117.                                 switch (justify) {
  3118.                                 case LEFT:
  3119.                                         line_off = 0;
  3120.                                         break;
  3121.                                 case CENTER:
  3122.                                         line_off = ((xsize - line_width) / 2);
  3123.                                         break;
  3124.                                 case RIGHT:
  3125.                                         line_off = (xsize - line_width);
  3126.                                         break;
  3127.                                 }
  3128.                                 if (clear)
  3129.                                         memset(buf.u8, 0,
  3130.                                                (buf_pitch * line_height));
  3131.                                 font = old_font;
  3132.                                 flush = true;
  3133.                         }
  3134.                         else if (*next == '\0')
  3135.                                 break;
  3136.                         else {
  3137.                                 if (*next == '\n')
  3138.                                         ++next;
  3139.                                 str = next;
  3140.                                 old_font = font;
  3141.                                 line_length = 0;
  3142.                                 line_off = 0;
  3143.                                 line_width = 0;
  3144.                                 buf.u8 += (buf_pitch * line_height);
  3145.                                 ysize -= line_height;
  3146.                                 line_height = font->height;
  3147.                                 // Still enough vertical pixels for this line?
  3148.                                 if (ysize < line_height)
  3149.                                         break;
  3150.                                 flush = false;
  3151.                         }
  3152.                 }
  3153.                 else if (*next == *FILTER_TEXT_ESCAPE) {
  3154.                         const char *tmp;
  3155.                         size_t sz;
  3156.  
  3157. #define FILTER_TEXT_IS(f)                               \
  3158.                         (tmp = (f), sz = strlen(f),     \
  3159.                          !strncmp(tmp, next, sz))
  3160.  
  3161.                         if (FILTER_TEXT_IS(FILTER_TEXT_BG_NONE))
  3162.                                 clear = false;
  3163.                         else if (FILTER_TEXT_IS(FILTER_TEXT_BG_BLACK))
  3164.                                 clear = true;
  3165.                         else if (FILTER_TEXT_IS(FILTER_TEXT_CENTER))
  3166.                                 justify = CENTER;
  3167.                         else if (FILTER_TEXT_IS(FILTER_TEXT_LEFT))
  3168.                                 justify = LEFT;
  3169.                         else if (FILTER_TEXT_IS(FILTER_TEXT_RIGHT))
  3170.                                 justify = RIGHT;
  3171.                         else if (FILTER_TEXT_IS(FILTER_TEXT_7X6))
  3172.                                 font = &font_data[0];
  3173.                         else if (FILTER_TEXT_IS(FILTER_TEXT_8X13))
  3174.                                 font = &font_data[1];
  3175.                         else if (FILTER_TEXT_IS(FILTER_TEXT_16X26))
  3176.                                 font = &font_data[2];
  3177.                         next += sz;
  3178.                 }
  3179.                 else if ((line_width + font->width) <= xsize) {
  3180.                         ++line_length;
  3181.                         line_width += font->width;
  3182.                         if (line_height < font->height) {
  3183.                                 line_height = font->height;
  3184.                                 // Still enough vertical pixels for this line?
  3185.                                 if (ysize < line_height)
  3186.                                         break;
  3187.                         }
  3188.                         ++next;
  3189.                 }
  3190.                 else // Truncate line.
  3191.                         goto trunc;
  3192.                 if (flush == false)
  3193.                         continue;
  3194.                 // Compute number of characters and width.
  3195.                 len = 0;
  3196.                 width = 0;
  3197.                 while ((len != line_length) &&
  3198.                        (next[len] != '\0') &&
  3199.                        (next[len] != '\n') &&
  3200.                        (next[len] != *FILTER_TEXT_ESCAPE)) {
  3201.                         width += font->width;
  3202.                         ++len;
  3203.                 }
  3204.                 // Display.
  3205.                 len = font_text((buf.u8 +
  3206.                                  // Horizontal offset.
  3207.                                  (line_off * Bpp) +
  3208.                                  // Vertical offset.
  3209.                                  ((line_height - font->height) * buf_pitch)),
  3210.                                 (xsize - line_off),
  3211.                                 line_height, Bpp, buf_pitch, next, len, ~0u,
  3212.                                 font->type);
  3213.                 line_off += width;
  3214.                 next += len;
  3215.         }
  3216. }
  3217.  
  3218. static const struct filter filter_text_def = {
  3219.         "text", filter_text, true, false, false
  3220. };
  3221.  
  3222. #ifdef WITH_CTV
  3223.  
  3224. static void set_swab()
  3225. {
  3226.         const struct filter *f = filters_find("swab");
  3227.  
  3228.         if (f == NULL)
  3229.                 return;
  3230.         filters_pluck(f);
  3231.         if (dgen_swab)
  3232.                 filters_insert(f);
  3233. }
  3234.  
  3235. static int prompt_cmd_filter_push(class md&, unsigned int ac, const char** av)
  3236. {
  3237.         unsigned int i;
  3238.  
  3239.         if (ac < 2)
  3240.                 return CMD_EINVAL;
  3241.         for (i = 1; (i != ac); ++i) {
  3242.                 const struct filter *f = filters_find(av[i]);
  3243.  
  3244.                 if (f == NULL)
  3245.                         return CMD_EINVAL;
  3246.                 filters_push(f);
  3247.         }
  3248.         return CMD_OK;
  3249. }
  3250.  
  3251. static char* prompt_cmpl_filter_push(class md&, unsigned int ac,
  3252.                                      const char** av, unsigned int len)
  3253. {
  3254.         const struct filter *f;
  3255.         const char *prefix;
  3256.         unsigned int skip;
  3257.         unsigned int i;
  3258.  
  3259.         assert(ac != 0);
  3260.         if ((ac == 1) || (len == ~0u) || (av[(ac - 1)] == NULL)) {
  3261.                 prefix = "";
  3262.                 len = 0;
  3263.         }
  3264.         else
  3265.                 prefix = av[(ac - 1)];
  3266.         skip = prompt.skip;
  3267. retry:
  3268.         for (i = 0; (i != elemof(filters_available)); ++i) {
  3269.                 f = &filters_available[i];
  3270.                 if (strncasecmp(prefix, f->name, len))
  3271.                         continue;
  3272.                 if (skip == 0)
  3273.                         break;
  3274.                 --skip;
  3275.         }
  3276.         if (i == elemof(filters_available)) {
  3277.                 if (prompt.skip != 0) {
  3278.                         prompt.skip = 0;
  3279.                         goto retry;
  3280.                 }
  3281.                 return NULL;
  3282.         }
  3283.         ++prompt.skip;
  3284.         return strdup(f->name);
  3285. }
  3286.  
  3287. static int prompt_cmd_filter_pop(class md&, unsigned int ac, const char**)
  3288. {
  3289.         if (ac != 1)
  3290.                 return CMD_EINVAL;
  3291.         filters_pop();
  3292.         return CMD_OK;
  3293. }
  3294.  
  3295. static int prompt_cmd_filter_none(class md&, unsigned int ac, const char**)
  3296. {
  3297.         if (ac != 1)
  3298.                 return CMD_EINVAL;
  3299.         filters_empty();
  3300.         return CMD_OK;
  3301. }
  3302.  
  3303. #endif // WITH_CTV
  3304.  
  3305. static bool calibrating = false; //< True during calibration.
  3306. static unsigned int calibrating_controller; ///< Controller being calibrated.
  3307.  
  3308. static void manage_calibration(enum rc_binding_type type, intptr_t code);
  3309.  
  3310. /**
  3311.  * Interactively calibrate a controller.
  3312.  * If n_args == 1, controller 0 will be configured.
  3313.  * If n_args == 2, configure controller in string args[1].
  3314.  * @param n_args Number of arguments.
  3315.  * @param[in] args List of arguments.
  3316.  * @return Status code.
  3317.  */
  3318. static int
  3319. prompt_cmd_calibrate(class md&, unsigned int n_args, const char** args)
  3320. {
  3321.         /* check args first */
  3322.         if (n_args == 1)
  3323.                 calibrating_controller = 0;
  3324.         else if (n_args == 2) {
  3325.                 calibrating_controller = (atoi(args[1]) - 1);
  3326.                 if (calibrating_controller > 1)
  3327.                         return CMD_EINVAL;
  3328.         }
  3329.         else
  3330.                 return CMD_EINVAL;
  3331.         manage_calibration(RCB_NUM, -1);
  3332.         return (CMD_OK | CMD_MSG);
  3333. }
  3334.  
  3335. static int set_scaling(const char *name)
  3336. {
  3337.         unsigned int i = filters_stack_size;
  3338.  
  3339.         assert(i <= elemof(filters_stack));
  3340.         // Replace all current scalers with these.
  3341.         while (i != 0) {
  3342.                 --i;
  3343.                 if (filters_stack[i]->resize == true)
  3344.                         filters_remove(i);
  3345.         }
  3346.         while (name += strspn(name, " \t\n"), name[0] != '\0') {
  3347.                 const struct filter *f;
  3348.                 int len = strcspn(name, " \t\n");
  3349.                 char token[64];
  3350.  
  3351.                 snprintf(token, sizeof(token), "%.*s", len, name);
  3352.                 name += len;
  3353.                 if (((f = filters_find(token)) == NULL) ||
  3354.                     (filters_stack_size == elemof(filters_stack)))
  3355.                         return -1;
  3356.                 filters_push(f);
  3357.         }
  3358.         return 0;
  3359. }
  3360.  
  3361. /**
  3362.  * Display splash screen.
  3363.  */
  3364. static void mdscr_splash()
  3365. {
  3366.         unsigned int x;
  3367.         unsigned int y;
  3368.         bpp_t src;
  3369.         unsigned int src_pitch = (dgen_splash_data.width *
  3370.                                   dgen_splash_data.bytes_per_pixel);
  3371.         unsigned int sw = dgen_splash_data.width;
  3372.         unsigned int sh = dgen_splash_data.height;
  3373.         bpp_t dst;
  3374.         unsigned int dst_pitch = mdscr.pitch;
  3375.         unsigned int dw = video.width;
  3376.         unsigned int dh = video.height;
  3377.  
  3378.         if ((dgen_splash_data.bytes_per_pixel != 3) || (sw != dw))
  3379.                 return;
  3380.         src.u8 = (uint8_t *)dgen_splash_data.pixel_data;
  3381.         dst.u8 = ((uint8_t *)mdscr.data + (dst_pitch * 8) + 16);
  3382.         // Center it.
  3383.         if (sh < dh) {
  3384.                 unsigned int off = ((dh - sh) / 2);
  3385.  
  3386.                 memset(dst.u8, 0x00, (dst_pitch * off));
  3387.                 memset(&dst.u8[(dst_pitch * (off + sh))], 0x00,
  3388.                        (dst_pitch * (dh - (off + sh))));
  3389.                 dst.u8 += (dst_pitch * off);
  3390.         }
  3391.         switch (mdscr.bpp) {
  3392.         case 32:
  3393.                 for (y = 0; ((y != dh) && (y != sh)); ++y) {
  3394.                         for (x = 0; ((x != dw) && (x != sw)); ++x) {
  3395.                                 dst.u32[x] = ((src.u24[x][0] << 16) |
  3396.                                               (src.u24[x][1] << 8) |
  3397.                                               (src.u24[x][2] << 0));
  3398.                         }
  3399.                         src.u8 += src_pitch;
  3400.                         dst.u8 += dst_pitch;
  3401.                 }
  3402.                 break;
  3403.         case 24:
  3404.                 for (y = 0; ((y != dh) && (y != sh)); ++y) {
  3405.                         for (x = 0; ((x != dw) && (x != sw)); ++x) {
  3406.                                 dst.u24[x][0] = src.u24[x][2];
  3407.                                 dst.u24[x][1] = src.u24[x][1];
  3408.                                 dst.u24[x][2] = src.u24[x][0];
  3409.                         }
  3410.                         src.u8 += src_pitch;
  3411.                         dst.u8 += dst_pitch;
  3412.                 }
  3413.                 break;
  3414.         case 16:
  3415.                 for (y = 0; ((y != dh) && (y != sh)); ++y) {
  3416.                         for (x = 0; ((x != dw) && (x != sw)); ++x) {
  3417.                                 dst.u16[x] = (((src.u24[x][0] & 0xf8) << 8) |
  3418.                                               ((src.u24[x][1] & 0xfc) << 3) |
  3419.                                               ((src.u24[x][2] & 0xf8) >> 3));
  3420.                         }
  3421.                         src.u8 += src_pitch;
  3422.                         dst.u8 += dst_pitch;
  3423.                 }
  3424.                 break;
  3425.         case 15:
  3426.                 for (y = 0; ((y != dh) && (y != sh)); ++y) {
  3427.                         for (x = 0; ((x != dw) && (x != sw)); ++x) {
  3428.                                 dst.u16[x] = (((src.u24[x][0] & 0xf8) << 7) |
  3429.                                               ((src.u24[x][1] & 0xf8) << 2) |
  3430.                                               ((src.u24[x][2] & 0xf8) >> 3));
  3431.                         }
  3432.                         src.u8 += src_pitch;
  3433.                         dst.u8 += dst_pitch;
  3434.                 }
  3435.                 break;
  3436.         case 8:
  3437.                 break;
  3438.         }
  3439. }
  3440.  
  3441. /**
  3442.  * Initialize screen.
  3443.  *
  3444.  * @param width Width of display.
  3445.  * @param height Height of display.
  3446.  * @return 0 on success, -1 if screen could not be initialized with current
  3447.  * options but remains in its previous state, -2 if screen is unusable.
  3448.  */
  3449. static int screen_init(unsigned int width, unsigned int height)
  3450. {
  3451.         static bool once = true;
  3452.         uint32_t flags = (SDL_RESIZABLE | SDL_ANYFORMAT | SDL_HWPALETTE |
  3453.                         SDL_HWSURFACE);
  3454.         struct screen scrtmp;
  3455.         const struct dgen_font *font;
  3456.  
  3457. #ifdef WITH_THREADS
  3458.         screen_update_thread_stop();
  3459. #endif
  3460.         DEBUG(("want width=%u height=%u", width, height));
  3461.         stopped = 1;
  3462.         // Copy current screen data.
  3463.         memcpy(&scrtmp, &screen, sizeof(scrtmp));
  3464.         if (once) {
  3465.                 unsigned int info_height = dgen_font[FONT_TYPE_8X13].h;
  3466.                 // Force defaults once.
  3467.                 scrtmp.window_width = 0;
  3468.                 scrtmp.window_height = 0;
  3469.                 scrtmp.width = (video.width * 2);
  3470.                 scrtmp.height = ((video.height * 2) + info_height);
  3471.                 scrtmp.x_scale = (scrtmp.width / video.width);
  3472.                 scrtmp.y_scale = (scrtmp.height / video.height);
  3473.                 scrtmp.bpp = 0;
  3474.                 scrtmp.Bpp = 0;
  3475.                 scrtmp.info_height = info_height;
  3476.                 scrtmp.buf.u8 = 0;
  3477.                 scrtmp.pitch = 0;
  3478.                 scrtmp.surface = 0;
  3479.                 scrtmp.want_fullscreen = 0;
  3480.                 scrtmp.is_fullscreen = 0;
  3481. #ifdef WITH_OPENGL
  3482.                 scrtmp.want_opengl = 0;
  3483.                 scrtmp.is_opengl = 0;
  3484. #endif
  3485. #ifdef WITH_THREADS
  3486.                 scrtmp.want_thread = 0;
  3487.                 scrtmp.is_thread = 0;
  3488.                 scrtmp.thread = 0;
  3489.                 scrtmp.lock = 0;
  3490.                 scrtmp.cond = 0;
  3491. #endif
  3492.                 memset(scrtmp.color, 0, sizeof(scrtmp.color));
  3493.                 once = false;
  3494.         }
  3495.         // Use configuration data.
  3496.         if (width != 0)
  3497.                 scrtmp.width = width;
  3498.         if (dgen_width >= 1)
  3499.                 scrtmp.width = dgen_width;
  3500.         if (height != 0)
  3501.                 scrtmp.height = height;
  3502.         if (dgen_height >= 1)
  3503.                 scrtmp.height = dgen_height;
  3504.         if (dgen_depth >= 0) {
  3505.                 scrtmp.bpp = dgen_depth;
  3506.                 scrtmp.Bpp = 0;
  3507.         }
  3508.         // scrtmp.x_scale, scrtmp.y_scale and scrtmp.info_height cannot be
  3509.         // determined yet.
  3510.         scrtmp.want_fullscreen = !!dgen_fullscreen;
  3511. #ifdef WITH_OPENGL
  3512. opengl_failed:
  3513.         scrtmp.want_opengl = !!dgen_opengl;
  3514. #endif
  3515. #ifdef WITH_THREADS
  3516.         scrtmp.want_thread = !!dgen_screen_thread;
  3517. #endif
  3518.         // Configure SDL_SetVideoMode().
  3519.         if (scrtmp.want_fullscreen)
  3520.                 flags |= SDL_FULLSCREEN;
  3521. #ifdef WITH_OPENGL
  3522.         if (scrtmp.want_opengl) {
  3523.                 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
  3524.                 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
  3525.                 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
  3526.                 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
  3527.                 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, !!dgen_doublebuffer);
  3528.                 flags |= SDL_OPENGL;
  3529.         }
  3530.         else
  3531. #endif
  3532.                 flags |= ((dgen_doublebuffer ? SDL_DOUBLEBUF : 0) |
  3533.                           SDL_ASYNCBLIT);
  3534.         if (scrtmp.want_fullscreen) {
  3535.                 SDL_Rect **modes;
  3536.  
  3537.                 // Check if we're going to be bound to a particular resolution.
  3538.                 modes = SDL_ListModes(NULL, (flags | SDL_FULLSCREEN));
  3539.                 if ((modes != NULL) && (modes != (SDL_Rect **)-1)) {
  3540.                         unsigned int i;
  3541.                         struct {
  3542.                                 unsigned int i;
  3543.                                 unsigned int w;
  3544.                                 unsigned int h;
  3545.                         } best = { 0, (unsigned int)-1, (unsigned int)-1 };
  3546.  
  3547.                         // Find the best resolution available.
  3548.                         for (i = 0; (modes[i] != NULL); ++i) {
  3549.                                 unsigned int w, h;
  3550.  
  3551.                                 DEBUG(("checking mode %dx%d",
  3552.                                        modes[i]->w, modes[i]->h));
  3553.                                 if ((modes[i]->w < scrtmp.width) ||
  3554.                                     (modes[i]->h < scrtmp.height))
  3555.                                         continue;
  3556.                                 w = (modes[i]->w - scrtmp.width);
  3557.                                 h = (modes[i]->h - scrtmp.height);
  3558.                                 if ((w <= best.w) && (h <= best.h)) {
  3559.                                         best.i = i;
  3560.                                         best.w = w;
  3561.                                         best.h = h;
  3562.                                 }
  3563.                         }
  3564.                         if ((best.w == (unsigned int)-1) ||
  3565.                             (best.h == (unsigned int)-1))
  3566.                                 DEBUG(("no mode looks good"));
  3567.                         else {
  3568.                                 scrtmp.width = modes[best.i]->w;
  3569.                                 scrtmp.height = modes[best.i]->h;
  3570.                                 DEBUG(("mode %ux%u looks okay",
  3571.                                        scrtmp.width, scrtmp.height));
  3572.                         }
  3573.                 }
  3574.                 DEBUG(("adjusted fullscreen resolution to %ux%u",
  3575.                        scrtmp.width, scrtmp.height));
  3576.         }
  3577.         // Set video mode.
  3578.         DEBUG(("SDL_SetVideoMode(%u, %u, %d, 0x%08x)",
  3579.                scrtmp.width, scrtmp.height, scrtmp.bpp, flags));
  3580.         scrtmp.surface = SDL_SetVideoMode(scrtmp.width, scrtmp.height,
  3581.                                           scrtmp.bpp, flags);
  3582.         if (scrtmp.surface == NULL) {
  3583. #ifdef WITH_OPENGL
  3584.                 // Try again without OpenGL.
  3585.                 if (flags & SDL_OPENGL) {
  3586.                         assert(scrtmp.want_opengl);
  3587.                         DEBUG(("OpenGL initialization failed, retrying"
  3588.                                " without it."));
  3589.                         dgen_opengl = 0;
  3590.                         flags &= ~SDL_OPENGL;
  3591.                         goto opengl_failed;
  3592.                 }
  3593. #endif
  3594.                 return -1;
  3595.         }
  3596.         DEBUG(("SDL_SetVideoMode succeeded"));
  3597.         // Update with current values.
  3598.         scrtmp.window_width = scrtmp.surface->w;
  3599.         scrtmp.window_height = scrtmp.surface->h;
  3600.         scrtmp.width = scrtmp.window_width;
  3601.         scrtmp.height = scrtmp.window_height;
  3602.         // By default, using 5% of the vertical resolution for info bar ought
  3603.         // to be good enough for anybody. Pick something close.
  3604.         if (dgen_info_height < 0)
  3605.                 scrtmp.info_height = ((scrtmp.height * 5) / 100);
  3606.         else
  3607.                 scrtmp.info_height = dgen_info_height;
  3608.         if (scrtmp.info_height > scrtmp.height)
  3609.                 scrtmp.info_height = scrtmp.height;
  3610.         font = font_select(scrtmp.width, scrtmp.info_height, FONT_TYPE_AUTO);
  3611.         if (font == NULL)
  3612.                 scrtmp.info_height = 0;
  3613.         else
  3614.                 scrtmp.info_height = font->h;
  3615.         assert(scrtmp.info_height <= scrtmp.height); // Do not forget.
  3616.         // Determine default X and Y scale values from what remains.
  3617.         if (dgen_x_scale >= 0)
  3618.                 scrtmp.x_scale = dgen_x_scale;
  3619.         else
  3620.                 scrtmp.x_scale = (scrtmp.width / video.width);
  3621.         if (dgen_y_scale >= 0)
  3622.                 scrtmp.y_scale = dgen_y_scale;
  3623.         else
  3624.                 scrtmp.y_scale = ((scrtmp.height - scrtmp.info_height) /
  3625.                                   video.height);
  3626.         if (dgen_aspect) {
  3627.                 if (scrtmp.x_scale >= scrtmp.y_scale)
  3628.                         scrtmp.x_scale = scrtmp.y_scale;
  3629.                 else
  3630.                         scrtmp.y_scale = scrtmp.x_scale;
  3631.         }
  3632.         // Fix bpp.
  3633.         assert(scrtmp.surface->format != NULL);
  3634.         scrtmp.bpp = scrtmp.surface->format->BitsPerPixel;
  3635.         // 15 bpp has be forced if it was required. SDL does not return the
  3636.         // right value.
  3637.         if ((dgen_depth == 15) && (scrtmp.bpp == 16))
  3638.                 scrtmp.bpp = 15;
  3639.         scrtmp.Bpp = scrtmp.surface->format->BytesPerPixel;
  3640.         scrtmp.buf.u8 = (uint8_t *)scrtmp.surface->pixels;
  3641.         scrtmp.pitch = scrtmp.surface->pitch;
  3642.         scrtmp.is_fullscreen = scrtmp.want_fullscreen;
  3643.         DEBUG(("video configuration: x_scale=%u y_scale=%u",
  3644.                scrtmp.x_scale, scrtmp.y_scale));
  3645.         DEBUG(("screen configuration: width=%u height=%u bpp=%u Bpp=%u"
  3646.                " info_height=%u"
  3647.                " buf.u8=%p pitch=%u surface=%p want_fullscreen=%u"
  3648.                " is_fullscreen=%u",
  3649.                scrtmp.width, scrtmp.height, scrtmp.bpp, scrtmp.Bpp,
  3650.                scrtmp.info_height,
  3651.                (void *)scrtmp.buf.u8, scrtmp.pitch, (void *)scrtmp.surface,
  3652.                scrtmp.want_fullscreen, scrtmp.is_fullscreen));
  3653. #ifdef WITH_OPENGL
  3654.         if (scrtmp.want_opengl) {
  3655.                 if (init_texture(&scrtmp)) {
  3656.                         DEBUG(("OpenGL initialization failed, retrying"
  3657.                                " without it."));
  3658.                         dgen_opengl = 0;
  3659.                         flags &= ~SDL_OPENGL;
  3660.                         goto opengl_failed;
  3661.                 }
  3662.                 // Update using texture info.
  3663.                 scrtmp.Bpp = (2 << scrtmp.texture.u32);
  3664.                 scrtmp.bpp = (scrtmp.Bpp * 8);
  3665.                 scrtmp.buf.u32 = scrtmp.texture.buf.u32;
  3666.                 scrtmp.width = scrtmp.texture.vis_width;
  3667.                 scrtmp.height = scrtmp.texture.vis_height;
  3668.                 scrtmp.pitch = (scrtmp.texture.vis_width <<
  3669.                                 (1 << scrtmp.texture.u32));
  3670.         }
  3671.         scrtmp.is_opengl = scrtmp.want_opengl;
  3672.         DEBUG(("OpenGL screen configuration: is_opengl=%u buf.u32=%p pitch=%u",
  3673.                scrtmp.is_opengl, (void *)scrtmp.buf.u32, scrtmp.pitch));
  3674. #endif
  3675.         // Screen is now initialized, update data.
  3676.         screen = scrtmp;
  3677. #ifdef WITH_OPENGL
  3678.         if (!screen.is_opengl) {
  3679.                 // Free OpenGL resources.
  3680.                 DEBUG(("releasing OpenGL resources"));
  3681.                 release_texture(screen.texture);
  3682.         }
  3683. #endif
  3684.         // Set up the Mega Drive screen.
  3685.         // Could not be done earlier because bpp was unknown.
  3686.         if ((mdscr.data == NULL) ||
  3687.             ((unsigned int)mdscr.bpp != screen.bpp) ||
  3688.             ((unsigned int)mdscr.w != (video.width + 16)) ||
  3689.             ((unsigned int)mdscr.h != (video.height + 16))) {
  3690.                 mdscr.w = (video.width + 16);
  3691.                 mdscr.h = (video.height + 16);
  3692.                 mdscr.pitch = (mdscr.w * screen.Bpp);
  3693.                 mdscr.bpp = screen.bpp;
  3694.                 free(mdscr.data);
  3695.                 mdscr.data = (uint8_t *)calloc(mdscr.h, mdscr.pitch);
  3696.                 if (mdscr.data == NULL) {
  3697.                         // Cannot recover. Clean up and bail out.
  3698.                         memset(&mdscr, 0, sizeof(mdscr));
  3699.                         return -2;
  3700.                 }
  3701.                 mdscr_splash();
  3702.         }
  3703.         DEBUG(("md screen configuration: w=%d h=%d bpp=%d pitch=%d data=%p",
  3704.                mdscr.w, mdscr.h, mdscr.bpp, mdscr.pitch, (void *)mdscr.data));
  3705.         // If we're in 8 bit mode, set color 0xff to white for the text,
  3706.         // and make a palette buffer.
  3707.         if (screen.bpp == 8) {
  3708.                 SDL_Color color = { 0xff, 0xff, 0xff, 0x00 };
  3709.                 SDL_SetColors(screen.surface, &color, 0xff, 1);
  3710.                 memset(video.palette, 0x00, sizeof(video.palette));
  3711.                 mdpal = video.palette;
  3712.         }
  3713.         else
  3714.                 mdpal = NULL;
  3715. #ifdef WITH_THREADS
  3716.         if (screen.want_thread)
  3717.                 screen_update_thread_start();
  3718. #endif
  3719.         // Rehash filters.
  3720.         filters_stack_update();
  3721.         // Update screen.
  3722.         pd_graphics_update(true);
  3723.         return 0;
  3724. }
  3725.  
  3726. /**
  3727.  * Set fullscreen mode.
  3728.  * @param toggle Nonzero to enable fullscreen, otherwise disable it.
  3729.  * @return 0 on success.
  3730.  */
  3731. static int set_fullscreen(int toggle)
  3732. {
  3733.         unsigned int w;
  3734.         unsigned int h;
  3735.  
  3736.         if (((!toggle) && (!screen.is_fullscreen)) ||
  3737.             ((toggle) && (screen.is_fullscreen))) {
  3738.                 // Already in the desired mode.
  3739.                 DEBUG(("already %s fullscreen mode, ret=-1",
  3740.                        (toggle ? "in" : "not in")));
  3741.                 return -1;
  3742.         }
  3743. #ifdef HAVE_SDL_WM_TOGGLEFULLSCREEN
  3744.         // Try this first.
  3745.         DEBUG(("trying SDL_WM_ToggleFullScreen(%p)", (void *)screen.surface));
  3746.         if (SDL_WM_ToggleFullScreen(screen.surface))
  3747.                 return 0;
  3748.         DEBUG(("falling back to screen_init()"));
  3749. #endif
  3750.         dgen_fullscreen = toggle;
  3751.         if (screen.surface != NULL) {
  3752.                 // Try to keep the current mode.
  3753.                 w = screen.surface->w;
  3754.                 h = screen.surface->h;
  3755.         }
  3756.         else if ((dgen_width > 0) && (dgen_height > 0)) {
  3757.                 // Use configured mode.
  3758.                 w = dgen_width;
  3759.                 h = dgen_height;
  3760.         }
  3761.         else {
  3762.                 // Try to make a guess.
  3763.                 w = (video.width * screen.x_scale);
  3764.                 h = (video.height * screen.y_scale);
  3765.         }
  3766.         DEBUG(("reinitializing screen with want_fullscreen=%u,"
  3767.                " screen_init(%u, %u)",
  3768.                screen.want_fullscreen, w, h));
  3769.         return screen_init(w, h);
  3770. }
  3771.  
  3772. /**
  3773.  * Initialize SDL, and the graphics.
  3774.  * @param want_sound Nonzero if we want sound.
  3775.  * @param want_pal Nonzero for PAL mode.
  3776.  * @param hz Requested frame rate (between 0 and 1000).
  3777.  * @return Nonzero if successful.
  3778.  */
  3779. int pd_graphics_init(int want_sound, int want_pal, int hz)
  3780. {
  3781.         SDL_Event event;
  3782.  
  3783.         prompt_init(&prompt.status);
  3784.         if ((hz <= 0) || (hz > 1000)) {
  3785.                 // You may as well disable bool_frameskip.
  3786.                 fprintf(stderr, "sdl: invalid frame rate (%d)\n", hz);
  3787.                 return 0;
  3788.         }
  3789.         video.hz = hz;
  3790.         if (want_pal) {
  3791.                 // PAL
  3792.                 video.is_pal = 1;
  3793.                 video.height = 240;
  3794.         }
  3795.         else {
  3796.                 // NTSC
  3797.                 video.is_pal = 0;
  3798.                 video.height = 224;
  3799.         }
  3800. #if !defined __MINGW32__ && !defined _KOLIBRI
  3801.         // [fbcon workaround]
  3802.         // Disable SDL_FBACCEL (if unset) before calling SDL_Init() in case
  3803.         // fbcon is to be used. Prevents SDL_FillRect() and SDL_SetVideoMode()
  3804.         // from hanging when hardware acceleration is available.
  3805.         setenv("SDL_FBACCEL", "0", 0);
  3806.         // [fbcon workaround]
  3807.         // A mouse is never required.
  3808.         setenv("SDL_NOMOUSE", "1", 0);
  3809. #endif
  3810.         if (SDL_Init(SDL_INIT_VIDEO | (want_sound ? SDL_INIT_AUDIO : 0))) {
  3811.                 fprintf(stderr, "sdl: can't init SDL: %s\n", SDL_GetError());
  3812.                 return 0;
  3813.         }
  3814. #ifndef __MINGW32__
  3815.         {
  3816.                 char buf[32];
  3817.  
  3818.                 // [fbcon workaround]
  3819.                 // Double buffering usually makes screen blink during refresh.
  3820.                 if ((SDL_VideoDriverName(buf, sizeof(buf))) &&
  3821.                     (!strcmp(buf, "fbcon")))
  3822.                         dgen_doublebuffer = 0;
  3823.         }
  3824. #endif
  3825.         // Required for text input.
  3826.         SDL_EnableUNICODE(1);
  3827.         // Set the titlebar.
  3828.         SDL_WM_SetCaption("DGen/SDL " VER, "DGen/SDL " VER);
  3829.         // Hide the cursor.
  3830.         SDL_ShowCursor(0);
  3831.         // Initialize screen.
  3832.         if (screen_init(0, 0))
  3833.                 goto fail;
  3834.         // Initialize scaling.
  3835.         set_scaling(scaling_names[dgen_scaling % NUM_SCALING]);
  3836.         DEBUG(("using scaling filter \"%s\"",
  3837.                scaling_names[dgen_scaling % NUM_SCALING]));
  3838.         DEBUG(("screen initialized"));
  3839. #if !defined __MINGW32__  && !defined _KOLIBRI
  3840.         // We don't need setuid privileges anymore
  3841.         if (getuid() != geteuid())
  3842.                 setuid(getuid());
  3843.         DEBUG(("setuid privileges dropped"));
  3844. #endif
  3845. #ifdef WITH_CTV
  3846.         filters_pluck_ctv();
  3847.         {
  3848.                 const struct filter *f;
  3849.  
  3850.                 f = filters_find(ctv_names[dgen_craptv % NUM_CTV]);
  3851.                 if ((f != NULL) && (f->func != filter_off))
  3852.                         filters_insert(f);
  3853.         }
  3854. #endif // WITH_CTV
  3855.         DEBUG(("ret=1"));
  3856.         fprintf(stderr, "video: %dx%d, %u bpp (%u Bpp), %uHz\n",
  3857.                 screen.surface->w, screen.surface->h, screen.bpp,
  3858.                 screen.Bpp, video.hz);
  3859. #ifdef WITH_OPENGL
  3860.         if (screen.is_opengl) {
  3861.                 DEBUG(("GL_VENDOR=\"%s\" GL_RENDERER=\"%s\""
  3862.                        " GL_VERSION=\"%s\"",
  3863.                        glGetString(GL_VENDOR), glGetString(GL_RENDERER),
  3864.                        glGetString(GL_VERSION)));
  3865.                 fprintf(stderr,
  3866.                         "video: OpenGL texture %ux%ux%u (%ux%u)\n",
  3867.                         screen.texture.width,
  3868.                         screen.texture.height,
  3869.                         (2 << screen.texture.u32),
  3870.                         screen.texture.vis_width,
  3871.                         screen.texture.vis_height);
  3872.         }
  3873. #endif
  3874.         while (SDL_PollEvent(&event)) {
  3875.                 switch (event.type) {
  3876.                 case SDL_VIDEORESIZE:
  3877.                         if (screen_init(event.resize.w, event.resize.h))
  3878.                                 goto fail;
  3879.                         break;
  3880.                 }
  3881.         }
  3882.         return 1;
  3883. fail:
  3884.         fprintf(stderr, "sdl: can't initialize graphics.\n");
  3885.         return 0;
  3886. }
  3887.  
  3888. /**
  3889.  * Reinitialize graphics.
  3890.  * @param want_pal Nonzero for PAL mode.
  3891.  * @param hz Requested frame rate (between 0 and 1000).
  3892.  * @return Nonzero if successful.
  3893.  */
  3894. int pd_graphics_reinit(int, int want_pal, int hz)
  3895. {
  3896.         if ((hz <= 0) || (hz > 1000)) {
  3897.                 // You may as well disable bool_frameskip.
  3898.                 fprintf(stderr, "sdl: invalid frame rate (%d)\n", hz);
  3899.                 return 0;
  3900.         }
  3901.         video.hz = hz;
  3902.         if (want_pal) {
  3903.                 // PAL
  3904.                 video.is_pal = 1;
  3905.                 video.height = 240;
  3906.         }
  3907.         else {
  3908.                 // NTSC
  3909.                 video.is_pal = 0;
  3910.                 video.height = 224;
  3911.         }
  3912.         // Reinitialize screen.
  3913.         if (screen_init(screen.window_width, screen.window_height))
  3914.                 goto fail;
  3915.        
  3916.         DEBUG(("screen reinitialized"));
  3917.         return 1;
  3918. fail:
  3919.         fprintf(stderr, "sdl: can't reinitialize graphics.\n");
  3920.         return 0;
  3921. }
  3922.  
  3923. /**
  3924.  * Update palette.
  3925.  */
  3926. void pd_graphics_palette_update()
  3927. {
  3928.         unsigned int i;
  3929.  
  3930.         for (i = 0; (i < 64); ++i) {
  3931.                 screen.color[i].r = mdpal[(i << 2)];
  3932.                 screen.color[i].g = mdpal[((i << 2) + 1)];
  3933.                 screen.color[i].b = mdpal[((i << 2) + 2)];
  3934.         }
  3935. #ifdef WITH_OPENGL
  3936.         if (!screen.is_opengl)
  3937. #endif
  3938.                 SDL_SetColors(screen.surface, screen.color, 0, 64);
  3939. }
  3940.  
  3941. /**
  3942.  * Display screen.
  3943.  * @param update False if screen buffer is garbage and must be updated first.
  3944.  */
  3945. void pd_graphics_update(bool update)
  3946. {
  3947.         static unsigned long fps_since = 0;
  3948.         static unsigned long frames_old = 0;
  3949.         static unsigned long frames = 0;
  3950.         unsigned long usecs = pd_usecs();
  3951.         const struct filter *f;
  3952.         struct filter_data *fd;
  3953.         size_t i;
  3954.  
  3955.         // Check whether the message must be processed.
  3956.         if ((events == STARTED) &&
  3957.             ((info.displayed) || (info.length))  &&
  3958.             ((usecs - info.since) >= MESSAGE_LIFE))
  3959.                 pd_message_process();
  3960.         else if (dgen_fps) {
  3961.                 unsigned long tmp = ((usecs - fps_since) & 0x3fffff);
  3962.  
  3963.                 ++frames;
  3964.                 if (tmp >= 1000000) {
  3965.                         unsigned long fps;
  3966.  
  3967.                         fps_since = usecs;
  3968.                         if (frames_old > frames)
  3969.                                 fps = (frames_old - frames);
  3970.                         else
  3971.                                 fps = (frames - frames_old);
  3972.                         frames_old = frames;
  3973.                         if (!info.displayed) {
  3974.                                 char buf[16];
  3975.  
  3976.                                 snprintf(buf, sizeof(buf), "%lu FPS", fps);
  3977.                                 pd_message_write(buf, strlen(buf), ~0u);
  3978.                         }
  3979.                 }
  3980.         }
  3981.         if (update == false)
  3982.                 mdscr_splash();
  3983.         // Process output through filters.
  3984.         for (i = 0; (i != elemof(filters_stack)); ++i) {
  3985.                 f = filters_stack[i];
  3986.                 fd = &filters_stack_data[i];
  3987.                 if ((filters_stack_size == 0) ||
  3988.                     (i == (filters_stack_size - 1)))
  3989.                         break;
  3990.                 f->func(fd, (fd + 1));
  3991.         }
  3992.         // Lock screen.
  3993.         if (screen_lock())
  3994.                 return;
  3995.         // Generate screen output with the last filter.
  3996.         f->func(fd, (fd + 1));
  3997.         // Unlock screen.
  3998.         screen_unlock();
  3999.         // Update the screen.
  4000.         screen_update();
  4001. }
  4002.  
  4003. /**
  4004.  * Callback for sound.
  4005.  * @param stream Sound destination buffer.
  4006.  * @param len Length of destination buffer.
  4007.  */
  4008. static void snd_callback(void *, Uint8 *stream, int len)
  4009. {
  4010.         size_t wrote;
  4011.  
  4012.         // Slurp off the play buffer
  4013.         wrote = cbuf_read(stream, &sound.cbuf, len);
  4014.         if (wrote == (size_t)len)
  4015.                 return;
  4016.         // Not enough data, fill remaining space with silence.
  4017.         memset(&stream[wrote], 0, ((size_t)len - wrote));
  4018. }
  4019.  
  4020. /**
  4021.  * Initialize the sound.
  4022.  * @param freq Sound samples rate.
  4023.  * @param[in,out] samples Minimum buffer size in samples.
  4024.  * @return Nonzero on success.
  4025.  */
  4026. int pd_sound_init(long &freq, unsigned int &samples)
  4027. {
  4028.         SDL_AudioSpec wanted;
  4029.         SDL_AudioSpec spec;
  4030.  
  4031.         // Clean up first.
  4032.         pd_sound_deinit();
  4033.  
  4034.         // Set the desired format
  4035.         wanted.freq = freq;
  4036. #ifdef WORDS_BIGENDIAN
  4037.         wanted.format = AUDIO_S16MSB;
  4038. #else
  4039.         wanted.format = AUDIO_S16LSB;
  4040. #endif
  4041.         wanted.channels = 2;
  4042.         wanted.samples = dgen_soundsamples;
  4043.         wanted.callback = snd_callback;
  4044.         wanted.userdata = NULL;
  4045.  
  4046.         if (SDL_InitSubSystem(SDL_INIT_AUDIO)) {
  4047.                 fprintf(stderr, "sdl: unable to initialize audio\n");
  4048.                 return 0;
  4049.         }
  4050.  
  4051.         // Open audio, and get the real spec
  4052.         if (SDL_OpenAudio(&wanted, &spec) < 0) {
  4053.                 fprintf(stderr,
  4054.                         "sdl: couldn't open audio: %s\n",
  4055.                         SDL_GetError());
  4056.                 return 0;
  4057.         }
  4058.  
  4059.         // Check everything
  4060.         if (spec.channels != 2) {
  4061.                 fprintf(stderr, "sdl: couldn't get stereo audio format.\n");
  4062.                 goto snd_error;
  4063.         }
  4064.         if (spec.format != wanted.format) {
  4065.                 fprintf(stderr, "sdl: unable to get 16-bit audio.\n");
  4066.                 goto snd_error;
  4067.         }
  4068.  
  4069.         // Set things as they really are
  4070.         sound.rate = freq = spec.freq;
  4071.         sndi.len = (spec.freq / video.hz);
  4072.         sound.samples = spec.samples;
  4073.         samples += sound.samples;
  4074.  
  4075.         // Calculate buffer size (sample size = (channels * (bits / 8))).
  4076.         sound.cbuf.size = (samples * (2 * (16 / 8)));
  4077.         sound.cbuf.i = 0;
  4078.         sound.cbuf.s = 0;
  4079.  
  4080.         fprintf(stderr, "sound: %uHz, %d samples, buffer: %u bytes\n",
  4081.                 sound.rate, spec.samples, (unsigned int)sound.cbuf.size);
  4082.  
  4083.         // Allocate zero-filled play buffer.
  4084.         sndi.lr = (int16_t *)calloc(2, (sndi.len * sizeof(sndi.lr[0])));
  4085.  
  4086.         sound.cbuf.data.i16 = (int16_t *)calloc(1, sound.cbuf.size);
  4087.         if ((sndi.lr == NULL) || (sound.cbuf.data.i16 == NULL)) {
  4088.                 fprintf(stderr, "sdl: couldn't allocate sound buffers.\n");
  4089.                 goto snd_error;
  4090.         }
  4091.  
  4092.         // Start sound output.
  4093.         SDL_PauseAudio(0);
  4094.  
  4095.         // It's all good!
  4096.         return 1;
  4097.  
  4098. snd_error:
  4099.         // Oops! Something bad happened, cleanup.
  4100.         SDL_CloseAudio();
  4101.         free((void *)sndi.lr);
  4102.         sndi.lr = NULL;
  4103.         sndi.len = 0;
  4104.         free((void *)sound.cbuf.data.i16);
  4105.         sound.cbuf.data.i16 = NULL;
  4106.         memset(&sound, 0, sizeof(sound));
  4107.         return 0;
  4108. }
  4109.  
  4110. /**
  4111.  * Deinitialize sound subsystem.
  4112.  */
  4113. void pd_sound_deinit()
  4114. {
  4115.         if (sound.cbuf.data.i16 != NULL) {
  4116.                 SDL_PauseAudio(1);
  4117.                 SDL_CloseAudio();
  4118.                 free((void *)sound.cbuf.data.i16);
  4119.         }
  4120.         memset(&sound, 0, sizeof(sound));
  4121.         free((void*)sndi.lr);
  4122.         sndi.lr = NULL;
  4123. }
  4124.  
  4125. /**
  4126.  * Return samples read/write indices in the buffer.
  4127.  */
  4128. unsigned int pd_sound_rp()
  4129. {
  4130.         unsigned int ret;
  4131.  
  4132.         if (!sound.cbuf.size)
  4133.                 return 0;
  4134.         SDL_LockAudio();
  4135.         ret = sound.cbuf.i;
  4136.         SDL_UnlockAudio();
  4137.         return (ret >> 2);
  4138. }
  4139.  
  4140. unsigned int pd_sound_wp()
  4141. {
  4142.         unsigned int ret;
  4143.  
  4144.         if (!sound.cbuf.size)
  4145.                 return 0;
  4146.         SDL_LockAudio();
  4147.         ret = ((sound.cbuf.i + sound.cbuf.s) % sound.cbuf.size);
  4148.         SDL_UnlockAudio();
  4149.         return (ret >> 2);
  4150. }
  4151.  
  4152. /**
  4153.  * Write contents of sndi to sound.cbuf.
  4154.  */
  4155. void pd_sound_write()
  4156. {
  4157.         if (!sound.cbuf.size)
  4158.                 return;
  4159.         SDL_LockAudio();
  4160.         cbuf_write(&sound.cbuf, (uint8_t *)sndi.lr, (sndi.len * 4));
  4161.         SDL_UnlockAudio();
  4162. }
  4163.  
  4164. /**
  4165.  * Tells whether DGen stopped intentionally so emulation can resume without
  4166.  * skipping frames.
  4167.  */
  4168. int pd_stopped()
  4169. {
  4170.         int ret = stopped;
  4171.  
  4172.         stopped = 0;
  4173.         return ret;
  4174. }
  4175.  
  4176. /**
  4177.  * Keyboard input.
  4178.  */
  4179. typedef struct {
  4180.         char *buf;
  4181.         size_t pos;
  4182.         size_t size;
  4183. } kb_input_t;
  4184.  
  4185. /**
  4186.  * Keyboard input results.
  4187.  */
  4188. enum kb_input {
  4189.         KB_INPUT_ABORTED,
  4190.         KB_INPUT_ENTERED,
  4191.         KB_INPUT_CONSUMED,
  4192.         KB_INPUT_IGNORED
  4193. };
  4194.  
  4195. /**
  4196.  * Manage text input with some rudimentary history.
  4197.  * @param input Input buffer.
  4198.  * @param ksym Keyboard symbol.
  4199.  * @param ksym_uni Unicode translation for keyboard symbol.
  4200.  * @return Input result.
  4201.  */
  4202. static enum kb_input kb_input(kb_input_t *input, uint32_t ksym,
  4203.                               uint16_t ksym_uni)
  4204. {
  4205. #define HISTORY_LEN 32
  4206.         static char history[HISTORY_LEN][64];
  4207.         static int history_pos = -1;
  4208.         static int history_len = 0;
  4209.         char c;
  4210.  
  4211.         if (ksym & KEYSYM_MOD_CTRL)
  4212.                 return KB_INPUT_IGNORED;
  4213.         if (isprint((c = ksym_uni))) {
  4214.                 if (input->pos >= (input->size - 1))
  4215.                         return KB_INPUT_CONSUMED;
  4216.                 if (input->buf[input->pos] == '\0')
  4217.                         input->buf[(input->pos + 1)] = '\0';
  4218.                 input->buf[input->pos] = c;
  4219.                 ++input->pos;
  4220.                 return KB_INPUT_CONSUMED;
  4221.         }
  4222.         else if (ksym == SDLK_DELETE) {
  4223.                 size_t tail;
  4224.  
  4225.                 if (input->buf[input->pos] == '\0')
  4226.                         return KB_INPUT_CONSUMED;
  4227.                 tail = ((input->size - input->pos) + 1);
  4228.                 memmove(&input->buf[input->pos],
  4229.                         &input->buf[(input->pos + 1)],
  4230.                         tail);
  4231.                 return KB_INPUT_CONSUMED;
  4232.         }
  4233.         else if (ksym == SDLK_BACKSPACE) {
  4234.                 size_t tail;
  4235.  
  4236.                 if (input->pos == 0)
  4237.                         return KB_INPUT_CONSUMED;
  4238.                 --input->pos;
  4239.                 tail = ((input->size - input->pos) + 1);
  4240.                 memmove(&input->buf[input->pos],
  4241.                         &input->buf[(input->pos + 1)],
  4242.                         tail);
  4243.                 return KB_INPUT_CONSUMED;
  4244.         }
  4245.         else if (ksym == SDLK_LEFT) {
  4246.                 if (input->pos != 0)
  4247.                         --input->pos;
  4248.                 return KB_INPUT_CONSUMED;
  4249.         }
  4250.         else if (ksym == SDLK_RIGHT) {
  4251.                 if (input->buf[input->pos] != '\0')
  4252.                         ++input->pos;
  4253.                 return KB_INPUT_CONSUMED;
  4254.         }
  4255.         else if ((ksym == SDLK_RETURN) || (ksym == SDLK_KP_ENTER)) {
  4256.                 history_pos = -1;
  4257.                 if (input->pos == 0)
  4258.                         return KB_INPUT_ABORTED;
  4259.                 if (history_len < HISTORY_LEN)
  4260.                         ++history_len;
  4261.                 memmove(&history[1], &history[0],
  4262.                         ((history_len - 1) * sizeof(history[0])));
  4263.                 strncpy(history[0], input->buf, sizeof(history[0]));
  4264.                 return KB_INPUT_ENTERED;
  4265.         }
  4266.         else if (ksym == SDLK_ESCAPE) {
  4267.                 history_pos = 0;
  4268.                 return KB_INPUT_ABORTED;
  4269.         }
  4270.         else if (ksym == SDLK_UP) {
  4271.                 if (input->size == 0)
  4272.                         return KB_INPUT_CONSUMED;
  4273.                 if (history_pos < (history_len - 1))
  4274.                         ++history_pos;
  4275.                 strncpy(input->buf, history[history_pos], input->size);
  4276.                 input->buf[(input->size - 1)] = '\0';
  4277.                 input->pos = strlen(input->buf);
  4278.                 return KB_INPUT_CONSUMED;
  4279.         }
  4280.         else if (ksym == SDLK_DOWN) {
  4281.                 if ((input->size == 0) || (history_pos < 0))
  4282.                         return KB_INPUT_CONSUMED;
  4283.                 if (history_pos > 0)
  4284.                         --history_pos;
  4285.                 strncpy(input->buf, history[history_pos], input->size);
  4286.                 input->buf[(input->size - 1)] = '\0';
  4287.                 input->pos = strlen(input->buf);
  4288.                 return KB_INPUT_CONSUMED;
  4289.         }
  4290.         return KB_INPUT_IGNORED;
  4291. }
  4292.  
  4293. /**
  4294.  * Write a message to the status bar while displaying a cursor and without
  4295.  * buffering.
  4296.  */
  4297. static void pd_message_cursor(unsigned int mark, const char *msg, ...)
  4298. {
  4299.         va_list vl;
  4300.         char buf[1024];
  4301.         size_t len;
  4302.         size_t disp_len;
  4303.  
  4304.         va_start(vl, msg);
  4305.         len = (size_t)vsnprintf(buf, sizeof(buf), msg, vl);
  4306.         va_end(vl);
  4307.         buf[(sizeof(buf) - 1)] = '\0';
  4308.         disp_len = font_text_max_len(screen.width, screen.info_height,
  4309.                                      FONT_TYPE_AUTO);
  4310.         if (mark > len) {
  4311.                 if (len <= disp_len)
  4312.                         pd_message_display(buf, len, ~0u, true);
  4313.                 else
  4314.                         pd_message_display(&(buf[(len - disp_len)]), disp_len,
  4315.                                            ~0u, true);
  4316.                 return;
  4317.         }
  4318.         if (len <= disp_len)
  4319.                 pd_message_display(buf, len, mark, true);
  4320.         else if (len == mark)
  4321.                 pd_message_display(&buf[((len - disp_len) + 1)],
  4322.                                    disp_len, (disp_len - 1), true);
  4323.         else if ((len - mark) < disp_len)
  4324.                 pd_message_display(&buf[(len - disp_len)], disp_len,
  4325.                                    (mark - (len - disp_len)), true);
  4326.         else if (mark != ~0u)
  4327.                 pd_message_display(&buf[mark], disp_len, 0, true);
  4328. }
  4329.  
  4330. /**
  4331.  * Rehash rc vars that require special handling (see "SH" in rc.cpp).
  4332.  */
  4333. static int prompt_rehash_rc_field(const struct rc_field *rc, md& megad)
  4334. {
  4335.         bool fail = false;
  4336.         bool init_video = false;
  4337.         bool init_sound = false;
  4338.         bool init_joystick = false;
  4339.  
  4340.         if (rc->variable == &dgen_craptv) {
  4341. #ifdef WITH_CTV
  4342.                 filters_pluck_ctv();
  4343.                 filters_insert(filters_find(ctv_names[dgen_craptv % NUM_CTV]));
  4344. #else
  4345.                 fail = true;
  4346. #endif
  4347.         }
  4348.         else if (rc->variable == &dgen_scaling) {
  4349.                 if (set_scaling(scaling_names[dgen_scaling]) == 0)
  4350.                         fail = true;
  4351.         }
  4352.         else if (rc->variable == &dgen_emu_z80) {
  4353.                 megad.z80_state_dump();
  4354.                 // Z80: 0 = none, 1 = CZ80, 2 = MZ80, 3 = DRZ80
  4355.                 switch (dgen_emu_z80) {
  4356. #ifdef WITH_MZ80
  4357.                 case 1:
  4358.                         megad.z80_core = md::Z80_CORE_MZ80;
  4359.                         break;
  4360. #endif
  4361. #ifdef WITH_CZ80
  4362.                 case 2:
  4363.                         megad.z80_core = md::Z80_CORE_CZ80;
  4364.                         break;
  4365. #endif
  4366. #ifdef WITH_DRZ80
  4367.                 case 3:
  4368.                         megad.z80_core = md::Z80_CORE_DRZ80;
  4369.                         break;
  4370. #endif
  4371.                 default:
  4372.                         megad.z80_core = md::Z80_CORE_NONE;
  4373.                         break;
  4374.                 }
  4375.                 megad.z80_state_restore();
  4376.         }
  4377.         else if (rc->variable == &dgen_emu_m68k) {
  4378.                 megad.m68k_state_dump();
  4379.                 // M68K: 0 = none, 1 = StarScream, 2 = Musashi, 3 = Cyclone
  4380.                 switch (dgen_emu_m68k) {
  4381. #ifdef WITH_STAR
  4382.                 case 1:
  4383.                         megad.cpu_emu = md::CPU_EMU_STAR;
  4384.                         break;
  4385. #endif
  4386. #ifdef WITH_MUSA
  4387.                 case 2:
  4388.                         megad.cpu_emu = md::CPU_EMU_MUSA;
  4389.                         break;
  4390. #endif
  4391. #ifdef WITH_CYCLONE
  4392.                 case 3:
  4393.                         megad.cpu_emu = md::CPU_EMU_CYCLONE;
  4394.                         break;
  4395. #endif
  4396.                 default:
  4397.                         megad.cpu_emu = md::CPU_EMU_NONE;
  4398.                         break;
  4399.                 }
  4400.                 megad.m68k_state_restore();
  4401.         }
  4402.         else if ((rc->variable == &dgen_sound) ||
  4403.                  (rc->variable == &dgen_soundrate) ||
  4404.                  (rc->variable == &dgen_soundsegs) ||
  4405.                  (rc->variable == &dgen_soundsamples) ||
  4406.                  (rc->variable == &dgen_mjazz))
  4407.                 init_sound = true;
  4408.         else if (rc->variable == &dgen_fullscreen) {
  4409.                 if (screen.want_fullscreen != (!!dgen_fullscreen)) {
  4410.                         init_video = true;
  4411.                 }
  4412.         }
  4413.         else if ((rc->variable == &dgen_info_height) ||
  4414.                  (rc->variable == &dgen_width) ||
  4415.                  (rc->variable == &dgen_height) ||
  4416.                  (rc->variable == &dgen_x_scale) ||
  4417.                  (rc->variable == &dgen_y_scale) ||
  4418.                  (rc->variable == &dgen_depth) ||
  4419.                  (rc->variable == &dgen_doublebuffer) ||
  4420.                  (rc->variable == &dgen_screen_thread))
  4421.                 init_video = true;
  4422.         else if (rc->variable == &dgen_swab) {
  4423. #ifdef WITH_CTV
  4424.                 set_swab();
  4425. #else
  4426.                 fail = true;
  4427. #endif
  4428.         }
  4429.         else if ((rc->variable == &dgen_scale) ||
  4430.                  (rc->variable == &dgen_aspect)) {
  4431.                 dgen_x_scale = dgen_scale;
  4432.                 dgen_y_scale = dgen_scale;
  4433.                 init_video = true;
  4434.         }
  4435.         else if ((rc->variable == &dgen_opengl) ||
  4436.                  (rc->variable == &dgen_opengl_stretch) ||
  4437.                  (rc->variable == &dgen_opengl_linear) ||
  4438.                  (rc->variable == &dgen_opengl_32bit) ||
  4439.                  (rc->variable == &dgen_opengl_square)) {
  4440. #ifdef WITH_OPENGL
  4441.                 init_video = true;
  4442. #else
  4443.                 (void)0;
  4444. #endif
  4445.         }
  4446.         else if (rc->variable == &dgen_joystick)
  4447.                 init_joystick = true;
  4448.         else if (rc->variable == &dgen_hz) {
  4449.                 // See md::md().
  4450.                 if (dgen_hz <= 0)
  4451.                         dgen_hz = 1;
  4452.                 else if (dgen_hz > 1000)
  4453.                         dgen_hz = 1000;
  4454.                 if (((unsigned int)dgen_hz != video.hz) ||
  4455.                     ((unsigned int)dgen_hz != megad.vhz)) {
  4456.                         video.hz = dgen_hz;
  4457.                         init_video = true;
  4458.                         init_sound = true;
  4459.                 }
  4460.         }
  4461.         else if (rc->variable == &dgen_pal) {
  4462.                 // See md::md().
  4463.                 if ((dgen_pal) &&
  4464.                     ((video.is_pal == false) ||
  4465.                      (megad.pal == 0) ||
  4466.                      (video.height != PAL_VBLANK))) {
  4467.                         megad.pal = 1;
  4468.                         megad.init_pal();
  4469.                         video.is_pal = true;
  4470.                         video.height = PAL_VBLANK;
  4471.                         init_video = true;
  4472.                 }
  4473.                 else if ((!dgen_pal) &&
  4474.                          ((video.is_pal == true) ||
  4475.                           (megad.pal == 1) ||
  4476.                           (video.height != NTSC_VBLANK))) {
  4477.                         megad.pal = 0;
  4478.                         megad.init_pal();
  4479.                         video.is_pal = false;
  4480.                         video.height = NTSC_VBLANK;
  4481.                         init_video = true;
  4482.                 }
  4483.         }
  4484.         else if (rc->variable == &dgen_region) {
  4485.                 uint8_t c;
  4486.                 int hz;
  4487.                 int pal;
  4488.                 int vblank;
  4489.  
  4490.                 if (dgen_region)
  4491.                         c = dgen_region;
  4492.                 else
  4493.                         c = megad.region_guess();
  4494.                 md::region_info(c, &pal, &hz, &vblank, 0, 0);
  4495.                 if ((hz != dgen_hz) || (pal != dgen_pal) ||
  4496.                     (c != megad.region)) {
  4497.                         megad.region = c;
  4498.                         dgen_hz = hz;
  4499.                         dgen_pal = pal;
  4500.                         megad.pal = pal;
  4501.                         megad.init_pal();
  4502.                         video.is_pal = pal;
  4503.                         video.height = vblank;
  4504.                         video.hz = hz;
  4505.                         init_video = true;
  4506.                         init_sound = true;
  4507.                         fprintf(stderr,
  4508.                                 "sdl: reconfiguring for region \"%c\": "
  4509.                                 "%dHz (%s)\n", megad.region, hz,
  4510.                                 (pal ? "PAL" : "NTSC"));
  4511.                 }
  4512.         }
  4513.         else if (rc->variable == (intptr_t *)((void *)&dgen_rom_path))
  4514.                 set_rom_path(dgen_rom_path.val);
  4515.         if (init_video) {
  4516.                 // This is essentially what pd_graphics_init() does.
  4517.                 memset(megad.vdp.dirt, 0xff, 0x35);
  4518.                 switch (screen_init(screen.window_width,
  4519.                                     screen.window_height)) {
  4520.                 case 0:
  4521.                         break;
  4522.                 case -1:
  4523.                         goto video_warn;
  4524.                 default:
  4525.                         goto video_fail;
  4526.                 }
  4527.         }
  4528.         if (init_sound) {
  4529.                 if (video.hz == 0)
  4530.                         fail = true;
  4531.                 else if (dgen_sound == 0)
  4532.                         pd_sound_deinit();
  4533.                 else {
  4534.                         uint8_t ym2612_buf[512];
  4535.                         uint8_t sn76496_buf[16];
  4536.                         unsigned int samples;
  4537.                         long rate = dgen_soundrate;
  4538.  
  4539.                         pd_sound_deinit();
  4540.                         samples = (dgen_soundsegs * (rate / video.hz));
  4541.                         if (!pd_sound_init(rate, samples))
  4542.                                 fail = true;
  4543.                         YM2612_dump(0, ym2612_buf);
  4544.                         SN76496_dump(0, sn76496_buf);
  4545.                         megad.init_sound();
  4546.                         SN76496_restore(0, sn76496_buf);
  4547.                         YM2612_restore(0, ym2612_buf);
  4548.                 }
  4549.         }
  4550.         if (init_joystick) {
  4551. #ifdef WITH_JOYSTICK
  4552.                 megad.deinit_joysticks();
  4553.                 if (dgen_joystick)
  4554.                         megad.init_joysticks();
  4555. #else
  4556.                 fail = true;
  4557. #endif
  4558.         }
  4559.         if (fail) {
  4560.                 pd_message("Failed to rehash value.");
  4561.                 return (PROMPT_RET_EXIT | PROMPT_RET_MSG);
  4562.         }
  4563.         return PROMPT_RET_CONT;
  4564. video_warn:
  4565.         pd_message("Failed to reinitialize video.");
  4566.         return (PROMPT_RET_EXIT | PROMPT_RET_MSG);
  4567. video_fail:
  4568.         fprintf(stderr, "sdl: fatal error while trying to change screen"
  4569.                 " resolution.\n");
  4570.         return (PROMPT_RET_ERROR | PROMPT_RET_MSG);
  4571. }
  4572.  
  4573. static void prompt_show_rc_field(const struct rc_field *rc)
  4574. {
  4575.         size_t i;
  4576.         intptr_t val = *rc->variable;
  4577.  
  4578.         if ((rc->parser == rc_number) ||
  4579.             (rc->parser == rc_soundrate))
  4580.                 pd_message("%s is %ld", rc->fieldname, val);
  4581.         else if (rc->parser == rc_keysym) {
  4582.                 char *ks = dump_keysym(val);
  4583.  
  4584.                 if ((ks == NULL) || (ks[0] == '\0'))
  4585.                         pd_message("%s isn't bound", rc->fieldname);
  4586.                 else
  4587.                         pd_message("%s is bound to \"%s\"", rc->fieldname, ks);
  4588.                 free(ks);
  4589.         }
  4590.         else if (rc->parser == rc_boolean)
  4591.                 pd_message("%s is %s", rc->fieldname,
  4592.                            ((val) ? "true" : "false"));
  4593.         else if (rc->parser == rc_joypad) {
  4594.                 char *js = dump_joypad(val);
  4595.  
  4596.                 if ((js == NULL) || (js[0] == '\0'))
  4597.                         pd_message("%s isn't bound", rc->fieldname);
  4598.                 else
  4599.                         pd_message("%s is bound to \"%s\"", rc->fieldname, js);
  4600.                 free(js);
  4601.         }
  4602.         else if (rc->parser == rc_mouse) {
  4603.                 char *mo = dump_mouse(val);
  4604.  
  4605.                 if ((mo == NULL) || (mo[0] == '\0'))
  4606.                         pd_message("%s isn't bound", rc->fieldname);
  4607.                 else
  4608.                         pd_message("%s is bound to \"%s\"", rc->fieldname, mo);
  4609.                 free(mo);
  4610.         }
  4611.         else if (rc->parser == rc_ctv) {
  4612.                 i = val;
  4613.                 if (i >= NUM_CTV)
  4614.                         pd_message("%s is undefined", rc->fieldname);
  4615.                 else
  4616.                         pd_message("%s is \"%s\"", rc->fieldname,
  4617.                                    ctv_names[i]);
  4618.         }
  4619.         else if (rc->parser == rc_scaling) {
  4620.                 i = val;
  4621.                 if (i >= NUM_SCALING)
  4622.                         pd_message("%s is undefined", rc->fieldname);
  4623.                 else
  4624.                         pd_message("%s is \"%s\"", rc->fieldname,
  4625.                                    scaling_names[i]);
  4626.         }
  4627.         else if (rc->parser == rc_emu_z80) {
  4628.                 for (i = 0; (emu_z80_names[i] != NULL); ++i)
  4629.                         if (i == (size_t)val)
  4630.                                 break;
  4631.                 if (emu_z80_names[i] == NULL)
  4632.                         pd_message("%s is undefined", rc->fieldname);
  4633.                 else
  4634.                         pd_message("%s is \"%s\"", rc->fieldname,
  4635.                                    emu_z80_names[i]);
  4636.         }
  4637.         else if (rc->parser == rc_emu_m68k) {
  4638.                 for (i = 0; (emu_m68k_names[i] != NULL); ++i)
  4639.                         if (i == (size_t)val)
  4640.                                 break;
  4641.                 if (emu_m68k_names[i] == NULL)
  4642.                         pd_message("%s is undefined", rc->fieldname);
  4643.                 else
  4644.                         pd_message("%s is \"%s\"", rc->fieldname,
  4645.                                    emu_m68k_names[i]);
  4646.         }
  4647.         else if (rc->parser == rc_region) {
  4648.                 const char *s;
  4649.  
  4650.                 if (val == 'U')
  4651.                         s = "America (NTSC)";
  4652.                 else if (val == 'E')
  4653.                         s = "Europe (PAL)";
  4654.                 else if (val == 'J')
  4655.                         s = "Japan (NTSC)";
  4656.                 else if (val == 'X')
  4657.                         s = "Japan (PAL)";
  4658.                 else
  4659.                         s = "Auto";
  4660.                 pd_message("%s is \"%c\" (%s)", rc->fieldname,
  4661.                            (val ? (char)val : (char)' '), s);
  4662.         }
  4663.         else if ((rc->parser == rc_string) ||
  4664.                  (rc->parser == rc_rom_path)) {
  4665.                 struct rc_str *rs = (struct rc_str *)rc->variable;
  4666.                 char *s;
  4667.  
  4668.                 if (rs->val == NULL)
  4669.                         pd_message("%s has no value", rc->fieldname);
  4670.                 else if ((s = backslashify((const uint8_t *)rs->val,
  4671.                                            strlen(rs->val), 0,
  4672.                                            NULL)) != NULL) {
  4673.                         pd_message("%s is \"%s\"", rc->fieldname, s);
  4674.                         free(s);
  4675.                 }
  4676.                 else
  4677.                         pd_message("%s can't be displayed", rc->fieldname);
  4678.         }
  4679.         else if (rc->parser == rc_bind) {
  4680.                 char *f = backslashify((uint8_t *)rc->fieldname,
  4681.                                        strlen(rc->fieldname), 0, NULL);
  4682.                 char *s = *(char **)rc->variable;
  4683.  
  4684.                 assert(s != NULL);
  4685.                 assert((intptr_t)s != -1);
  4686.                 s = backslashify((uint8_t *)s, strlen(s), 0, NULL);
  4687.                 if ((f == NULL) || (s == NULL))
  4688.                         pd_message("%s can't be displayed", rc->fieldname);
  4689.                 else
  4690.                         pd_message("%s is bound to \"%s\"", f, s);
  4691.                 free(f);
  4692.                 free(s);
  4693.         }
  4694.         else
  4695.                 pd_message("%s: can't display value", rc->fieldname);
  4696. }
  4697.  
  4698. static int handle_prompt_enter(class md& md)
  4699. {
  4700.         struct prompt_parse pp;
  4701.         struct prompt *p = &prompt.status;
  4702.         size_t i;
  4703.         int ret;
  4704.         bool binding_tried = false;
  4705.  
  4706.         if (prompt_parse(p, &pp) == NULL)
  4707.                 return PROMPT_RET_ERROR;
  4708.         if (pp.argc == 0) {
  4709.                 ret = PROMPT_RET_EXIT;
  4710.                 goto end;
  4711.         }
  4712.         ret = 0;
  4713.         // Look for a command with that name.
  4714.         for (i = 0; (prompt_command[i].name != NULL); ++i) {
  4715.                 int cret;
  4716.  
  4717.                 if (strcasecmp(prompt_command[i].name, (char *)pp.argv[0]))
  4718.                         continue;
  4719.                 cret = prompt_command[i].cmd(md, pp.argc,
  4720.                                              (const char **)pp.argv);
  4721.                 if ((cret & ~CMD_MSG) == CMD_ERROR)
  4722.                         ret |= PROMPT_RET_ERROR;
  4723.                 if (cret & CMD_MSG)
  4724.                         ret |= PROMPT_RET_MSG;
  4725.                 else if (cret & CMD_FAIL) {
  4726.                         pd_message("%s: command failed", (char *)pp.argv[0]);
  4727.                         ret |= PROMPT_RET_MSG;
  4728.                 }
  4729.                 else if (cret & CMD_EINVAL) {
  4730.                         pd_message("%s: invalid argument", (char *)pp.argv[0]);
  4731.                         ret |= PROMPT_RET_MSG;
  4732.                 }
  4733.                 goto end;
  4734.         }
  4735. binding_retry:
  4736.         // Look for a variable with that name.
  4737.         for (i = 0; (rc_fields[i].fieldname != NULL); ++i) {
  4738.                 intptr_t potential;
  4739.  
  4740.                 if (strcasecmp(rc_fields[i].fieldname, (char *)pp.argv[0]))
  4741.                         continue;
  4742.                 // Display current value?
  4743.                 if (pp.argv[1] == NULL) {
  4744.                         prompt_show_rc_field(&rc_fields[i]);
  4745.                         ret |= PROMPT_RET_MSG;
  4746.                         break;
  4747.                 }
  4748.                 // Parse and set value.
  4749.                 potential = rc_fields[i].parser((char *)pp.argv[1],
  4750.                                                 rc_fields[i].variable);
  4751.                 if ((rc_fields[i].parser != rc_number) && (potential == -1)) {
  4752.                         pd_message("%s: invalid value", (char *)pp.argv[0]);
  4753.                         ret |= PROMPT_RET_MSG;
  4754.                         break;
  4755.                 }
  4756.                 if ((rc_fields[i].parser == rc_string) ||
  4757.                     (rc_fields[i].parser == rc_rom_path)) {
  4758.                         struct rc_str *rs;
  4759.  
  4760.                         rs = (struct rc_str *)rc_fields[i].variable;
  4761.                         if (rc_str_list == NULL) {
  4762.                                 atexit(rc_str_cleanup);
  4763.                                 rc_str_list = rs;
  4764.                         }
  4765.                         else if (rs->alloc == NULL) {
  4766.                                 rs->next = rc_str_list;
  4767.                                 rc_str_list = rs;
  4768.                         }
  4769.                         else
  4770.                                 free(rs->alloc);
  4771.                         rs->alloc = (char *)potential;
  4772.                         rs->val = rs->alloc;
  4773.                 }
  4774.                 else
  4775.                         *(rc_fields[i].variable) = potential;
  4776.                 ret |= prompt_rehash_rc_field(&rc_fields[i], md);
  4777.                 break;
  4778.         }
  4779.         if (rc_fields[i].fieldname == NULL) {
  4780.                 if ((binding_tried == false) &&
  4781.                     (rc_binding_add((char *)pp.argv[0], "") != NULL)) {
  4782.                         binding_tried = true;
  4783.                         goto binding_retry;
  4784.                 }
  4785.                 pd_message("%s: unknown command", (char *)pp.argv[0]);
  4786.                 ret |= PROMPT_RET_MSG;
  4787.         }
  4788. end:
  4789.         prompt_parse_clean(&pp);
  4790.         prompt_push(p);
  4791.         ret |= PROMPT_RET_ENTER;
  4792.         return ret;
  4793. }
  4794.  
  4795. static void handle_prompt_complete_clear()
  4796. {
  4797.         complete_path_free(prompt.complete);
  4798.         prompt.complete = NULL;
  4799.         prompt.skip = 0;
  4800.         prompt.common = 0;
  4801. }
  4802.  
  4803. static int handle_prompt_complete(class md& md, bool rwd)
  4804. {
  4805.         struct prompt_parse pp;
  4806.         struct prompt *p = &prompt.status;
  4807.         size_t prompt_common = 0; // escaped version of prompt.common
  4808.         unsigned int skip;
  4809.         size_t i;
  4810.         const char *arg;
  4811.         unsigned int alen;
  4812.         char *s = NULL;
  4813.  
  4814.         if (prompt_parse(p, &pp) == NULL)
  4815.                 return PROMPT_RET_ERROR;
  4816.         if (rwd)
  4817.                 prompt.skip -= 2;
  4818.         if (pp.index == 0) {
  4819.                 const char *cs = NULL;
  4820.                 const char *cm = NULL;
  4821.                 size_t common;
  4822.                 unsigned int tmp;
  4823.  
  4824.                 assert(prompt.complete == NULL);
  4825.                 // The first argument needs to be completed. This is either
  4826.                 // a command or a variable name.
  4827.                 arg = (const char *)pp.argv[0];
  4828.                 alen = pp.cursor;
  4829.                 if ((arg == NULL) || (alen == ~0u)) {
  4830.                         arg = "";
  4831.                         alen = 0;
  4832.                 }
  4833.                 common = ~0u;
  4834.         complete_cmd_var:
  4835.                 skip = prompt.skip;
  4836.                 for (i = 0; (prompt_command[i].name != NULL); ++i) {
  4837.                         if (strncasecmp(prompt_command[i].name, arg, alen))
  4838.                                 continue;
  4839.                         if (cm == NULL)
  4840.                                 tmp = strlen(prompt_command[i].name);
  4841.                         else
  4842.                                 tmp = strcommon(prompt_command[i].name, cm);
  4843.                         cm = prompt_command[i].name;
  4844.                         if (tmp < common)
  4845.                                 common = tmp;
  4846.                         if (skip != 0) {
  4847.                                 --skip;
  4848.                                 continue;
  4849.                         }
  4850.                         if (cs == NULL)
  4851.                                 cs = prompt_command[i].name;
  4852.                         if (common == 0)
  4853.                                 goto complete_cmd_found;
  4854.                 }
  4855.                 // Variables.
  4856.                 for (i = 0; (rc_fields[i].fieldname != NULL); ++i) {
  4857.                         if (strncasecmp(rc_fields[i].fieldname, arg, alen))
  4858.                                 continue;
  4859.                         if (cm == NULL)
  4860.                                 tmp = strlen(rc_fields[i].fieldname);
  4861.                         else
  4862.                                 tmp = strcommon(rc_fields[i].fieldname, cm);
  4863.                         cm = rc_fields[i].fieldname;
  4864.                         if (tmp < common)
  4865.                                 common = tmp;
  4866.                         if (skip != 0) {
  4867.                                 --skip;
  4868.                                 continue;
  4869.                         }
  4870.                         if (cs == NULL)
  4871.                                 cs = rc_fields[i].fieldname;
  4872.                         if (common == 0)
  4873.                                 break;
  4874.                 }
  4875.                 if (cs == NULL) {
  4876.                         // Nothing matched, try again if possible.
  4877.                         if (prompt.skip) {
  4878.                                 prompt.skip = 0;
  4879.                                 goto complete_cmd_var;
  4880.                         }
  4881.                         goto end;
  4882.                 }
  4883.         complete_cmd_found:
  4884.                 ++prompt.skip;
  4885.                 s = backslashify((const uint8_t *)cs, strlen(cs), 0, &common);
  4886.                 if (s == NULL)
  4887.                         goto end;
  4888.                 if (common != ~0u) {
  4889.                         prompt.common = common;
  4890.                         prompt_common = common;
  4891.                 }
  4892.                 goto replace;
  4893.         }
  4894.         // Complete function arguments.
  4895.         for (i = 0; (prompt_command[i].name != NULL); ++i) {
  4896.                 char *t;
  4897.  
  4898.                 if (strcasecmp(prompt_command[i].name,
  4899.                                (const char *)pp.argv[0]))
  4900.                         continue;
  4901.                 if (prompt_command[i].cmpl == NULL)
  4902.                         goto end;
  4903.                 t = prompt_command[i].cmpl(md, pp.argc, (const char **)pp.argv,
  4904.                                            pp.cursor);
  4905.                 if (t == NULL)
  4906.                         goto end;
  4907.                 prompt_common = prompt.common;
  4908.                 s = backslashify((const uint8_t *)t, strlen(t), 0,
  4909.                                  &prompt_common);
  4910.                 free(t);
  4911.                 if (s == NULL)
  4912.                         goto end;
  4913.                 goto replace;
  4914.         }
  4915.         // Variable value completion.
  4916.         arg = (const char *)pp.argv[pp.index];
  4917.         alen = pp.cursor;
  4918.         if ((arg == NULL) || (alen == ~0u)) {
  4919.                 arg = "";
  4920.                 alen = 0;
  4921.         }
  4922.         for (i = 0; (rc_fields[i].fieldname != NULL); ++i) {
  4923.                 struct rc_field *rc = &rc_fields[i];
  4924.                 const char **names;
  4925.  
  4926.                 if (strcasecmp(rc->fieldname, (const char *)pp.argv[0]))
  4927.                         continue;
  4928.                 // Boolean values.
  4929.                 if (rc->parser == rc_boolean)
  4930.                         s = strdup((prompt.skip & 1) ? "true" : "false");
  4931.                 // ROM path.
  4932.                 else if (rc->parser == rc_rom_path) {
  4933.                         if (prompt.complete == NULL) {
  4934.                                 prompt.complete =
  4935.                                         complete_path(arg, alen, NULL);
  4936.                                 prompt.skip = 0;
  4937.                                 rehash_prompt_complete_common();
  4938.                         }
  4939.                         if (prompt.complete != NULL) {
  4940.                                 char **ret = prompt.complete;
  4941.  
  4942.                         rc_rom_path_retry:
  4943.                                 skip = prompt.skip;
  4944.                                 for (i = 0; (ret[i] != NULL); ++i) {
  4945.                                         if (skip == 0)
  4946.                                                 break;
  4947.                                         --skip;
  4948.                                 }
  4949.                                 if (ret[i] == NULL) {
  4950.                                         if (prompt.skip != 0) {
  4951.                                                 prompt.skip = 0;
  4952.                                                 goto rc_rom_path_retry;
  4953.                                         }
  4954.                                 }
  4955.                                 else {
  4956.                                         prompt_common = prompt.common;
  4957.                                         s = backslashify
  4958.                                                 ((const uint8_t *)ret[i],
  4959.                                                  strlen(ret[i]), 0,
  4960.                                                  &prompt_common);
  4961.                                 }
  4962.                         }
  4963.                 }
  4964.                 // Numbers.
  4965.                 else if ((rc->parser == rc_number) ||
  4966.                          (rc->parser == rc_soundrate)) {
  4967.                         char buf[10];
  4968.  
  4969.                 rc_number_retry:
  4970.                         if (snprintf(buf, sizeof(buf), "%d",
  4971.                                      (int)prompt.skip) >= (int)sizeof(buf)) {
  4972.                                 prompt.skip = 0;
  4973.                                 goto rc_number_retry;
  4974.                         }
  4975.                         s = strdup(buf);
  4976.                 }
  4977.                 // CTV filters, scaling algorithms, Z80, M68K.
  4978.                 else if ((names = ctv_names, rc->parser == rc_ctv) ||
  4979.                          (names = scaling_names, rc->parser == rc_scaling) ||
  4980.                          (names = emu_z80_names, rc->parser == rc_emu_z80) ||
  4981.                          (names = emu_m68k_names, rc->parser == rc_emu_m68k)) {
  4982.                 rc_names_retry:
  4983.                         skip = prompt.skip;
  4984.                         for (i = 0; (names[i] != NULL); ++i) {
  4985.                                 if (skip == 0)
  4986.                                         break;
  4987.                                 --skip;
  4988.                         }
  4989.                         if (names[i] == NULL) {
  4990.                                 if (prompt.skip != 0) {
  4991.                                         prompt.skip = 0;
  4992.                                         goto rc_names_retry;
  4993.                                 }
  4994.                         }
  4995.                         else
  4996.                                 s = strdup(names[i]);
  4997.                 }
  4998.                 if (s == NULL)
  4999.                         break;
  5000.                 ++prompt.skip;
  5001.                 goto replace;
  5002.         }
  5003.         goto end;
  5004. replace:
  5005.         prompt_replace(p, pp.argo[pp.index].pos, pp.argo[pp.index].len,
  5006.                        (const uint8_t *)s, strlen(s));
  5007.         if (prompt_common) {
  5008.                 unsigned int cursor;
  5009.  
  5010.                 cursor = (pp.argo[pp.index].pos + prompt_common);
  5011.                 if (cursor > p->history[(p->current)].length)
  5012.                         cursor = p->history[(p->current)].length;
  5013.                 if (cursor != p->cursor) {
  5014.                         p->cursor = cursor;
  5015.                         handle_prompt_complete_clear();
  5016.                 }
  5017.         }
  5018. end:
  5019.         free(s);
  5020.         prompt_parse_clean(&pp);
  5021.         return 0;
  5022. }
  5023.  
  5024. static int handle_prompt(uint32_t ksym, uint16_t ksym_uni, md& megad)
  5025. {
  5026.         struct prompt::prompt_history *ph;
  5027.         size_t sz;
  5028.         uint8_t c[6];
  5029.         char *s;
  5030.         int ret = PROMPT_RET_CONT;
  5031.         struct prompt *p = &prompt.status;
  5032.         struct prompt_parse pp;
  5033.  
  5034.         if (ksym == 0)
  5035.                 goto end;
  5036.         switch (ksym & ~KEYSYM_MOD_MASK) {
  5037.         case SDLK_UP:
  5038.                 handle_prompt_complete_clear();
  5039.                 prompt_older(p);
  5040.                 break;
  5041.         case SDLK_DOWN:
  5042.                 handle_prompt_complete_clear();
  5043.                 prompt_newer(p);
  5044.                 break;
  5045.         case SDLK_LEFT:
  5046.                 handle_prompt_complete_clear();
  5047.                 prompt_left(p);
  5048.                 break;
  5049.         case SDLK_RIGHT:
  5050.                 handle_prompt_complete_clear();
  5051.                 prompt_right(p);
  5052.                 break;
  5053.         case SDLK_HOME:
  5054.                 handle_prompt_complete_clear();
  5055.                 prompt_begin(p);
  5056.                 break;
  5057.         case SDLK_END:
  5058.                 handle_prompt_complete_clear();
  5059.                 prompt_end(p);
  5060.                 break;
  5061.         case SDLK_BACKSPACE:
  5062.                 handle_prompt_complete_clear();
  5063.                 prompt_backspace(p);
  5064.                 break;
  5065.         case SDLK_DELETE:
  5066.                 handle_prompt_complete_clear();
  5067.                 prompt_delete(p);
  5068.                 break;
  5069.         case SDLK_a:
  5070.                 // ^A
  5071.                 if ((ksym & KEYSYM_MOD_CTRL) == 0)
  5072.                         goto other;
  5073.                 handle_prompt_complete_clear();
  5074.                 prompt_begin(p);
  5075.                 break;
  5076.         case SDLK_e:
  5077.                 // ^E
  5078.                 if ((ksym & KEYSYM_MOD_CTRL) == 0)
  5079.                         goto other;
  5080.                 handle_prompt_complete_clear();
  5081.                 prompt_end(p);
  5082.                 break;
  5083.         case SDLK_u:
  5084.                 // ^U
  5085.                 if ((ksym & KEYSYM_MOD_CTRL) == 0)
  5086.                         goto other;
  5087.                 handle_prompt_complete_clear();
  5088.                 prompt_clear(p);
  5089.                 break;
  5090.         case SDLK_k:
  5091.                 // ^K
  5092.                 if ((ksym & KEYSYM_MOD_CTRL) == 0)
  5093.                         goto other;
  5094.                 handle_prompt_complete_clear();
  5095.                 prompt_replace(p, p->cursor, ~0u, NULL, 0);
  5096.                 break;
  5097.         case SDLK_w:
  5098.                 // ^W
  5099.                 if ((ksym & KEYSYM_MOD_CTRL) == 0)
  5100.                         goto other;
  5101.                 if (prompt_parse(p, &pp) == NULL)
  5102.                         break;
  5103.                 if (pp.argv[pp.index] == NULL) {
  5104.                         if (pp.index == 0) {
  5105.                                 prompt_parse_clean(&pp);
  5106.                                 break;
  5107.                         }
  5108.                         --pp.index;
  5109.                 }
  5110.                 handle_prompt_complete_clear();
  5111.                 if (pp.argv[(pp.index + 1)] != NULL)
  5112.                         prompt_replace(p, pp.argo[pp.index].pos,
  5113.                                        (pp.argo[(pp.index + 1)].pos -
  5114.                                         pp.argo[pp.index].pos),
  5115.                                        NULL, 0);
  5116.                 else
  5117.                         prompt_replace(p, pp.argo[pp.index].pos, ~0u, NULL, 0);
  5118.                 p->cursor = pp.argo[pp.index].pos;
  5119.                 prompt_parse_clean(&pp);
  5120.                 break;
  5121.         case SDLK_RETURN:
  5122.         case SDLK_KP_ENTER:
  5123.                 handle_prompt_complete_clear();
  5124.                 ret |= handle_prompt_enter(megad);
  5125.                 break;
  5126.         case SDLK_ESCAPE:
  5127.                 handle_prompt_complete_clear();
  5128.                 ret |= PROMPT_RET_EXIT;
  5129.                 break;
  5130.         case SDLK_TAB:
  5131.                 if (ksym & KEYSYM_MOD_SHIFT)
  5132.                         ret |= handle_prompt_complete(megad, true);
  5133.                 else
  5134.                         ret |= handle_prompt_complete(megad, false);
  5135.                 break;
  5136.         default:
  5137.         other:
  5138.                 if (ksym_uni == 0)
  5139.                         break;
  5140.                 handle_prompt_complete_clear();
  5141.                 sz = utf32u8(c, ksym_uni);
  5142.                 if ((sz != 0) &&
  5143.                     ((s = backslashify(c, sz, BACKSLASHIFY_NOQUOTES,
  5144.                                        NULL)) != NULL)) {
  5145.                         size_t i;
  5146.  
  5147.                         for (i = 0; (i != strlen(s)); ++i)
  5148.                                 prompt_put(p, s[i]);
  5149.                         free(s);
  5150.                 }
  5151.                 break;
  5152.         }
  5153. end:
  5154.         if ((ret & ~(PROMPT_RET_CONT | PROMPT_RET_ENTER)) == 0) {
  5155.                 ph = &p->history[(p->current)];
  5156.                 pd_message_cursor((p->cursor + 1),
  5157.                                   "%s%.*s", prompt_str, ph->length, ph->line);
  5158.         }
  5159.         return ret;
  5160. }
  5161.  
  5162. // Controls enum. You must add new entries at the end. Do not change the order.
  5163. enum ctl_e {
  5164.         CTL_PAD1_UP,
  5165.         CTL_PAD1_DOWN,
  5166.         CTL_PAD1_LEFT,
  5167.         CTL_PAD1_RIGHT,
  5168.         CTL_PAD1_A,
  5169.         CTL_PAD1_B,
  5170.         CTL_PAD1_C,
  5171.         CTL_PAD1_X,
  5172.         CTL_PAD1_Y,
  5173.         CTL_PAD1_Z,
  5174.         CTL_PAD1_MODE,
  5175.         CTL_PAD1_START,
  5176.         CTL_PAD2_UP,
  5177.         CTL_PAD2_DOWN,
  5178.         CTL_PAD2_LEFT,
  5179.         CTL_PAD2_RIGHT,
  5180.         CTL_PAD2_A,
  5181.         CTL_PAD2_B,
  5182.         CTL_PAD2_C,
  5183.         CTL_PAD2_X,
  5184.         CTL_PAD2_Y,
  5185.         CTL_PAD2_Z,
  5186.         CTL_PAD2_MODE,
  5187.         CTL_PAD2_START,
  5188. #ifdef WITH_PICO
  5189.         CTL_PICO_PEN_UP,
  5190.         CTL_PICO_PEN_DOWN,
  5191.         CTL_PICO_PEN_LEFT,
  5192.         CTL_PICO_PEN_RIGHT,
  5193.         CTL_PICO_PEN_BUTTON,
  5194. #endif
  5195.         CTL_DGEN_QUIT,
  5196.         CTL_DGEN_CRAPTV_TOGGLE,
  5197.         CTL_DGEN_SCALING_TOGGLE,
  5198.         CTL_DGEN_RESET,
  5199.         CTL_DGEN_SLOT0,
  5200.         CTL_DGEN_SLOT1,
  5201.         CTL_DGEN_SLOT2,
  5202.         CTL_DGEN_SLOT3,
  5203.         CTL_DGEN_SLOT4,
  5204.         CTL_DGEN_SLOT5,
  5205.         CTL_DGEN_SLOT6,
  5206.         CTL_DGEN_SLOT7,
  5207.         CTL_DGEN_SLOT8,
  5208.         CTL_DGEN_SLOT9,
  5209.         CTL_DGEN_SLOT_NEXT,
  5210.         CTL_DGEN_SLOT_PREV,
  5211.         CTL_DGEN_SAVE,
  5212.         CTL_DGEN_LOAD,
  5213.         CTL_DGEN_Z80_TOGGLE,
  5214.         CTL_DGEN_CPU_TOGGLE,
  5215.         CTL_DGEN_STOP,
  5216.         CTL_DGEN_PROMPT,
  5217.         CTL_DGEN_GAME_GENIE,
  5218.         CTL_DGEN_VOLUME_INC,
  5219.         CTL_DGEN_VOLUME_DEC,
  5220.         CTL_DGEN_FULLSCREEN_TOGGLE,
  5221.         CTL_DGEN_FIX_CHECKSUM,
  5222.         CTL_DGEN_SCREENSHOT,
  5223.         CTL_DGEN_DEBUG_ENTER,
  5224.         CTL_
  5225. };
  5226.  
  5227. // Controls definitions.
  5228. struct ctl {
  5229.         const enum ctl_e type;
  5230.         intptr_t (*const rc)[RCB_NUM];
  5231.         int (*const press)(struct ctl&, md&);
  5232.         int (*const release)(struct ctl&, md&);
  5233. #define DEF 0, 0, 0, 0
  5234.         unsigned int pressed:1;
  5235.         unsigned int coord:1;
  5236.         unsigned int x:10;
  5237.         unsigned int y:10;
  5238. };
  5239.  
  5240. static int ctl_pad1(struct ctl& ctl, md& megad)
  5241. {
  5242.         switch (ctl.type) {
  5243.         case CTL_PAD1_UP:
  5244.                 megad.pad[0] &= ~MD_UP_MASK;
  5245.                 break;
  5246.         case CTL_PAD1_DOWN:
  5247.                 megad.pad[0] &= ~MD_DOWN_MASK;
  5248.                 break;
  5249.         case CTL_PAD1_LEFT:
  5250.                 megad.pad[0] &= ~MD_LEFT_MASK;
  5251.                 break;
  5252.         case CTL_PAD1_RIGHT:
  5253.                 megad.pad[0] &= ~MD_RIGHT_MASK;
  5254.                 break;
  5255.         case CTL_PAD1_A:
  5256.                 megad.pad[0] &= ~MD_A_MASK;
  5257.                 break;
  5258.         case CTL_PAD1_B:
  5259.                 megad.pad[0] &= ~MD_B_MASK;
  5260.                 break;
  5261.         case CTL_PAD1_C:
  5262.                 megad.pad[0] &= ~MD_C_MASK;
  5263.                 break;
  5264.         case CTL_PAD1_X:
  5265.                 megad.pad[0] &= ~MD_X_MASK;
  5266.                 break;
  5267.         case CTL_PAD1_Y:
  5268.                 megad.pad[0] &= ~MD_Y_MASK;
  5269.                 break;
  5270.         case CTL_PAD1_Z:
  5271.                 megad.pad[0] &= ~MD_Z_MASK;
  5272.                 break;
  5273.         case CTL_PAD1_MODE:
  5274.                 megad.pad[0] &= ~MD_MODE_MASK;
  5275.                 break;
  5276.         case CTL_PAD1_START:
  5277.                 megad.pad[0] &= ~MD_START_MASK;
  5278.                 break;
  5279.         default:
  5280.                 break;
  5281.         }
  5282.         return 1;
  5283. }
  5284.  
  5285. static int ctl_pad1_release(struct ctl& ctl, md& megad)
  5286. {
  5287.         switch (ctl.type) {
  5288.         case CTL_PAD1_UP:
  5289.                 megad.pad[0] |= MD_UP_MASK;
  5290.                 break;
  5291.         case CTL_PAD1_DOWN:
  5292.                 megad.pad[0] |= MD_DOWN_MASK;
  5293.                 break;
  5294.         case CTL_PAD1_LEFT:
  5295.                 megad.pad[0] |= MD_LEFT_MASK;
  5296.                 break;
  5297.         case CTL_PAD1_RIGHT:
  5298.                 megad.pad[0] |= MD_RIGHT_MASK;
  5299.                 break;
  5300.         case CTL_PAD1_A:
  5301.                 megad.pad[0] |= MD_A_MASK;
  5302.                 break;
  5303.         case CTL_PAD1_B:
  5304.                 megad.pad[0] |= MD_B_MASK;
  5305.                 break;
  5306.         case CTL_PAD1_C:
  5307.                 megad.pad[0] |= MD_C_MASK;
  5308.                 break;
  5309.         case CTL_PAD1_X:
  5310.                 megad.pad[0] |= MD_X_MASK;
  5311.                 break;
  5312.         case CTL_PAD1_Y:
  5313.                 megad.pad[0] |= MD_Y_MASK;
  5314.                 break;
  5315.         case CTL_PAD1_Z:
  5316.                 megad.pad[0] |= MD_Z_MASK;
  5317.                 break;
  5318.         case CTL_PAD1_MODE:
  5319.                 megad.pad[0] |= MD_MODE_MASK;
  5320.                 break;
  5321.         case CTL_PAD1_START:
  5322.                 megad.pad[0] |= MD_START_MASK;
  5323.                 break;
  5324.         default:
  5325.                 break;
  5326.         }
  5327.         return 1;
  5328. }
  5329.  
  5330. static int ctl_pad2(struct ctl& ctl, md& megad)
  5331. {
  5332.         switch (ctl.type) {
  5333.         case CTL_PAD2_UP:
  5334.                 megad.pad[1] &= ~MD_UP_MASK;
  5335.                 break;
  5336.         case CTL_PAD2_DOWN:
  5337.                 megad.pad[1] &= ~MD_DOWN_MASK;
  5338.                 break;
  5339.         case CTL_PAD2_LEFT:
  5340.                 megad.pad[1] &= ~MD_LEFT_MASK;
  5341.                 break;
  5342.         case CTL_PAD2_RIGHT:
  5343.                 megad.pad[1] &= ~MD_RIGHT_MASK;
  5344.                 break;
  5345.         case CTL_PAD2_A:
  5346.                 megad.pad[1] &= ~MD_A_MASK;
  5347.                 break;
  5348.         case CTL_PAD2_B:
  5349.                 megad.pad[1] &= ~MD_B_MASK;
  5350.                 break;
  5351.         case CTL_PAD2_C:
  5352.                 megad.pad[1] &= ~MD_C_MASK;
  5353.                 break;
  5354.         case CTL_PAD2_X:
  5355.                 megad.pad[1] &= ~MD_X_MASK;
  5356.                 break;
  5357.         case CTL_PAD2_Y:
  5358.                 megad.pad[1] &= ~MD_Y_MASK;
  5359.                 break;
  5360.         case CTL_PAD2_Z:
  5361.                 megad.pad[1] &= ~MD_Z_MASK;
  5362.                 break;
  5363.         case CTL_PAD2_MODE:
  5364.                 megad.pad[1] &= ~MD_MODE_MASK;
  5365.                 break;
  5366.         case CTL_PAD2_START:
  5367.                 megad.pad[1] &= ~MD_START_MASK;
  5368.                 break;
  5369.         default:
  5370.                 break;
  5371.         }
  5372.         return 1;
  5373. }
  5374.  
  5375. static int ctl_pad2_release(struct ctl& ctl, md& megad)
  5376. {
  5377.         switch (ctl.type) {
  5378.         case CTL_PAD2_UP:
  5379.                 megad.pad[1] |= MD_UP_MASK;
  5380.                 break;
  5381.         case CTL_PAD2_DOWN:
  5382.                 megad.pad[1] |= MD_DOWN_MASK;
  5383.                 break;
  5384.         case CTL_PAD2_LEFT:
  5385.                 megad.pad[1] |= MD_LEFT_MASK;
  5386.                 break;
  5387.         case CTL_PAD2_RIGHT:
  5388.                 megad.pad[1] |= MD_RIGHT_MASK;
  5389.                 break;
  5390.         case CTL_PAD2_A:
  5391.                 megad.pad[1] |= MD_A_MASK;
  5392.                 break;
  5393.         case CTL_PAD2_B:
  5394.                 megad.pad[1] |= MD_B_MASK;
  5395.                 break;
  5396.         case CTL_PAD2_C:
  5397.                 megad.pad[1] |= MD_C_MASK;
  5398.                 break;
  5399.         case CTL_PAD2_X:
  5400.                 megad.pad[1] |= MD_X_MASK;
  5401.                 break;
  5402.         case CTL_PAD2_Y:
  5403.                 megad.pad[1] |= MD_Y_MASK;
  5404.                 break;
  5405.         case CTL_PAD2_Z:
  5406.                 megad.pad[1] |= MD_Z_MASK;
  5407.                 break;
  5408.         case CTL_PAD2_MODE:
  5409.                 megad.pad[1] |= MD_MODE_MASK;
  5410.                 break;
  5411.         case CTL_PAD2_START:
  5412.                 megad.pad[1] |= MD_START_MASK;
  5413.                 break;
  5414.         default:
  5415.                 break;
  5416.         }
  5417.         return 1;
  5418. }
  5419.  
  5420. #ifdef WITH_PICO
  5421.  
  5422. static int ctl_pico_pen(struct ctl& ctl, md& megad)
  5423. {
  5424.         static unsigned int min_y = 0x1fc;
  5425.         static unsigned int max_y = 0x2f7;
  5426.         static unsigned int min_x = 0x3c;
  5427.         static unsigned int max_x = 0x17c;
  5428.         static const struct {
  5429.                 enum ctl_e type;
  5430.                 unsigned int coords:1;
  5431.                 unsigned int dir:1;
  5432.                 unsigned int lim[2];
  5433.         } motion[] = {
  5434.                 { CTL_PICO_PEN_UP, 1, 0, { min_y, max_y } },
  5435.                 { CTL_PICO_PEN_DOWN, 1, 1, { min_y, max_y } },
  5436.                 { CTL_PICO_PEN_LEFT, 0, 0, { min_x, max_x } },
  5437.                 { CTL_PICO_PEN_RIGHT, 0, 1, { min_x, max_x } }
  5438.         };
  5439.         unsigned int i;
  5440.  
  5441.         if (ctl.type == CTL_PICO_PEN_BUTTON) {
  5442.                 megad.pad[0] &= ~MD_PICO_PENBTN_MASK;
  5443.                 return 1;
  5444.         }
  5445.         // Use coordinates if available.
  5446.         if ((ctl.coord) &&
  5447.             (screen.window_width != 0) &&
  5448.             (screen.window_height != 0)) {
  5449.                 megad.pico_pen_coords[1] =
  5450.                         (min_y + ((ctl.y * (max_y - min_y)) /
  5451.                                   screen.window_height));
  5452.                 megad.pico_pen_coords[0] =
  5453.                         (min_x + ((ctl.x * (max_x - min_x)) /
  5454.                                   screen.window_width));
  5455.                 return 1;
  5456.         }
  5457.         for (i = 0; (i != elemof(motion)); ++i) {
  5458.                 unsigned int coords;
  5459.  
  5460.                 if (motion[i].type != ctl.type)
  5461.                         continue;
  5462.                 coords = motion[i].coords;
  5463.                 if (motion[i].dir)
  5464.                         megad.pico_pen_coords[coords] += pico_pen_stride;
  5465.                 else
  5466.                         megad.pico_pen_coords[coords] -= pico_pen_stride;
  5467.                 if ((megad.pico_pen_coords[coords] < motion[i].lim[0]) ||
  5468.                     (megad.pico_pen_coords[coords] > motion[i].lim[1]))
  5469.                         megad.pico_pen_coords[coords] =
  5470.                                 motion[i].lim[motion[i].dir];
  5471.                 break;
  5472.         }
  5473.         return 1;
  5474. }
  5475.  
  5476. static int ctl_pico_pen_release(struct ctl& ctl, md& megad)
  5477. {
  5478.         if (ctl.type == CTL_PICO_PEN_BUTTON)
  5479.                 megad.pad[0] |= MD_PICO_PENBTN_MASK;
  5480.         return 1;
  5481. }
  5482.  
  5483. #endif
  5484.  
  5485. static int ctl_dgen_quit(struct ctl&, md&)
  5486. {
  5487.         return 0;
  5488. }
  5489.  
  5490. static int ctl_dgen_craptv_toggle(struct ctl&, md&)
  5491. {
  5492. #ifdef WITH_CTV
  5493.         dgen_craptv = ((dgen_craptv + 1) % NUM_CTV);
  5494.         filters_pluck_ctv();
  5495.         filters_insert(filters_find(ctv_names[dgen_craptv]));
  5496.         pd_message("Crap TV mode \"%s\".", ctv_names[dgen_craptv]);
  5497. #endif // WITH_CTV
  5498.         return 1;
  5499. }
  5500.  
  5501. static int ctl_dgen_scaling_toggle(struct ctl&, md&)
  5502. {
  5503.         dgen_scaling = ((dgen_scaling + 1) % NUM_SCALING);
  5504.         if (set_scaling(scaling_names[dgen_scaling]))
  5505.                 pd_message("Scaling algorithm \"%s\" unavailable.",
  5506.                            scaling_names[dgen_scaling]);
  5507.         else
  5508.                 pd_message("Using scaling algorithm \"%s\".",
  5509.                            scaling_names[dgen_scaling]);
  5510.         return 1;
  5511. }
  5512.  
  5513. static int ctl_dgen_reset(struct ctl&, md& megad)
  5514. {
  5515.         megad.reset();
  5516.         pd_message("Genesis reset.");
  5517.         return 1;
  5518. }
  5519.  
  5520. static int ctl_dgen_slot(struct ctl& ctl, md&)
  5521. {
  5522.         slot = ((int)ctl.type - CTL_DGEN_SLOT0);
  5523.         pd_message("Selected save slot %d.", slot);
  5524.         return 1;
  5525. }
  5526.  
  5527. static int ctl_dgen_slot_next(struct ctl&, md&)
  5528. {
  5529.         if (slot == 9)
  5530.                 slot = 0;
  5531.         else
  5532.                 slot++;
  5533.         pd_message("Selected next save slot (%d).", slot);
  5534.         return 1;
  5535. }
  5536.  
  5537. static int ctl_dgen_slot_prev(struct ctl&, md&)
  5538. {
  5539.         if (slot == 0)
  5540.                 slot = 9;
  5541.         else
  5542.                 slot--;
  5543.         pd_message("Selected previous save slot (%d).", slot);
  5544.         return 1;
  5545. }
  5546.  
  5547. static int ctl_dgen_save(struct ctl&, md& megad)
  5548. {
  5549.         md_save(megad);
  5550.         return 1;
  5551. }
  5552.  
  5553. static int ctl_dgen_load(struct ctl&, md& megad)
  5554. {
  5555.         md_load(megad);
  5556.         return 1;
  5557. }
  5558.  
  5559. // Cycle Z80 core.
  5560. static int ctl_dgen_z80_toggle(struct ctl&, md& megad)
  5561. {
  5562.         const char *msg;
  5563.  
  5564.         megad.cycle_z80();
  5565.         switch (megad.z80_core) {
  5566. #ifdef WITH_CZ80
  5567.         case md::Z80_CORE_CZ80:
  5568.                 msg = "CZ80 core activated.";
  5569.                 break;
  5570. #endif
  5571. #ifdef WITH_MZ80
  5572.         case md::Z80_CORE_MZ80:
  5573.                 msg = "MZ80 core activated.";
  5574.                 break;
  5575. #endif
  5576. #ifdef WITH_DRZ80
  5577.         case md::Z80_CORE_DRZ80:
  5578.                 msg = "DrZ80 core activated.";
  5579.                 break;
  5580. #endif
  5581.         default:
  5582.                 msg = "Z80 core disabled.";
  5583.                 break;
  5584.         }
  5585.         pd_message(msg);
  5586.         return 1;
  5587. }
  5588.  
  5589. // Added this CPU core hot swap.  Compile both Musashi and StarScream
  5590. // in, and swap on the fly like DirectX DGen. [PKH]
  5591. static int ctl_dgen_cpu_toggle(struct ctl&, md& megad)
  5592. {
  5593.         const char *msg;
  5594.  
  5595.         megad.cycle_cpu();
  5596.         switch (megad.cpu_emu) {
  5597. #ifdef WITH_STAR
  5598.         case md::CPU_EMU_STAR:
  5599.                 msg = "StarScream CPU core activated.";
  5600.                 break;
  5601. #endif
  5602. #ifdef WITH_MUSA
  5603.         case md::CPU_EMU_MUSA:
  5604.                 msg = "Musashi CPU core activated.";
  5605.                 break;
  5606. #endif
  5607. #ifdef WITH_CYCLONE
  5608.         case md::CPU_EMU_CYCLONE:
  5609.                 msg = "Cyclone CPU core activated.";
  5610.                 break;
  5611. #endif
  5612.         default:
  5613.                 msg = "CPU core disabled.";
  5614.                 break;
  5615.         }
  5616.         pd_message(msg);
  5617.         return 1;
  5618. }
  5619.  
  5620. static int ctl_dgen_stop(struct ctl&, md& megad)
  5621. {
  5622.         pd_message(stopped_str);
  5623.         if (stop_events(megad, STOPPED) != 0)
  5624.                 return 0;
  5625.         return 1;
  5626. }
  5627.  
  5628. static int ctl_dgen_prompt(struct ctl&, md& megad)
  5629. {
  5630.         pd_message_cursor(strlen(prompt_str), prompt_str);
  5631.         if (stop_events(megad, PROMPT) != 0)
  5632.                 return 0;
  5633.         return 1;
  5634. }
  5635.  
  5636. static int ctl_dgen_game_genie(struct ctl&, md& megad)
  5637. {
  5638.         pd_message_cursor(strlen(game_genie_str), game_genie_str);
  5639.         if (stop_events(megad, GAME_GENIE) != 0)
  5640.                 return 0;
  5641.         return 1;
  5642. }
  5643.  
  5644. static int ctl_dgen_volume(struct ctl& ctl, md&)
  5645. {
  5646.         if (ctl.type == CTL_DGEN_VOLUME_INC)
  5647.                 ++dgen_volume;
  5648.         else
  5649.                 --dgen_volume;
  5650.         if (dgen_volume < 0)
  5651.                 dgen_volume = 0;
  5652.         else if (dgen_volume > 100)
  5653.                 dgen_volume = 100;
  5654.         pd_message("Volume %d%%.", (int)dgen_volume);
  5655.         return 1;
  5656. }
  5657.  
  5658. static int ctl_dgen_fullscreen_toggle(struct ctl&, md&)
  5659. {
  5660.         switch (set_fullscreen(!screen.is_fullscreen)) {
  5661.         case -2:
  5662.                 fprintf(stderr,
  5663.                         "sdl: fatal error while trying to change screen"
  5664.                         " resolution.\n");
  5665.                 return 0;
  5666.         case -1:
  5667.                 pd_message("Failed to toggle fullscreen mode.");
  5668.                 break;
  5669.         default:
  5670.                 pd_message("Fullscreen mode toggled.");
  5671.         }
  5672.         return 1;
  5673. }
  5674.  
  5675. static int ctl_dgen_fix_checksum(struct ctl&, md& megad)
  5676. {
  5677.         pd_message("Checksum fixed.");
  5678.         megad.fix_rom_checksum();
  5679.         return 1;
  5680. }
  5681.  
  5682. static int ctl_dgen_screenshot(struct ctl&, md& megad)
  5683. {
  5684.         do_screenshot(megad);
  5685.         return 1;
  5686. }
  5687.  
  5688. static int ctl_dgen_debug_enter(struct ctl&, md& megad)
  5689. {
  5690. #ifdef WITH_DEBUGGER
  5691.         stopped = 1;
  5692.         if (megad.debug_trap == false)
  5693.                 megad.debug_enter();
  5694.         else
  5695.                 megad.debug_leave();
  5696. #else
  5697.         (void)megad;
  5698.         pd_message("Debugger support not built in.");
  5699. #endif
  5700.         return 1;
  5701. }
  5702.  
  5703. static struct ctl control[] = {
  5704.         // Array indices and control[].type must match enum ctl_e's order.
  5705.         { CTL_PAD1_UP, &pad1_up, ctl_pad1, ctl_pad1_release, DEF },
  5706.         { CTL_PAD1_DOWN, &pad1_down, ctl_pad1, ctl_pad1_release, DEF },
  5707.         { CTL_PAD1_LEFT, &pad1_left, ctl_pad1, ctl_pad1_release, DEF },
  5708.         { CTL_PAD1_RIGHT, &pad1_right, ctl_pad1, ctl_pad1_release, DEF },
  5709.         { CTL_PAD1_A, &pad1_a, ctl_pad1, ctl_pad1_release, DEF },
  5710.         { CTL_PAD1_B, &pad1_b, ctl_pad1, ctl_pad1_release, DEF },
  5711.         { CTL_PAD1_C, &pad1_c, ctl_pad1, ctl_pad1_release, DEF },
  5712.         { CTL_PAD1_X, &pad1_x, ctl_pad1, ctl_pad1_release, DEF },
  5713.         { CTL_PAD1_Y, &pad1_y, ctl_pad1, ctl_pad1_release, DEF },
  5714.         { CTL_PAD1_Z, &pad1_z, ctl_pad1, ctl_pad1_release, DEF },
  5715.         { CTL_PAD1_MODE, &pad1_mode, ctl_pad1, ctl_pad1_release, DEF },
  5716.         { CTL_PAD1_START, &pad1_start, ctl_pad1, ctl_pad1_release, DEF },
  5717.         { CTL_PAD2_UP, &pad2_up, ctl_pad2, ctl_pad2_release, DEF },
  5718.         { CTL_PAD2_DOWN, &pad2_down, ctl_pad2, ctl_pad2_release, DEF },
  5719.         { CTL_PAD2_LEFT, &pad2_left, ctl_pad2, ctl_pad2_release, DEF },
  5720.         { CTL_PAD2_RIGHT, &pad2_right, ctl_pad2, ctl_pad2_release, DEF },
  5721.         { CTL_PAD2_A, &pad2_a, ctl_pad2, ctl_pad2_release, DEF },
  5722.         { CTL_PAD2_B, &pad2_b, ctl_pad2, ctl_pad2_release, DEF },
  5723.         { CTL_PAD2_C, &pad2_c, ctl_pad2, ctl_pad2_release, DEF },
  5724.         { CTL_PAD2_X, &pad2_x, ctl_pad2, ctl_pad2_release, DEF },
  5725.         { CTL_PAD2_Y, &pad2_y, ctl_pad2, ctl_pad2_release, DEF },
  5726.         { CTL_PAD2_Z, &pad2_z, ctl_pad2, ctl_pad2_release, DEF },
  5727.         { CTL_PAD2_MODE, &pad2_mode, ctl_pad2, ctl_pad2_release, DEF },
  5728.         { CTL_PAD2_START, &pad2_start, ctl_pad2, ctl_pad2_release, DEF },
  5729. #ifdef WITH_PICO
  5730.         { CTL_PICO_PEN_UP,
  5731.           &pico_pen_up, ctl_pico_pen, ctl_pico_pen_release, DEF },
  5732.         { CTL_PICO_PEN_DOWN,
  5733.           &pico_pen_down, ctl_pico_pen, ctl_pico_pen_release, DEF },
  5734.         { CTL_PICO_PEN_LEFT,
  5735.           &pico_pen_left, ctl_pico_pen, ctl_pico_pen_release, DEF },
  5736.         { CTL_PICO_PEN_RIGHT,
  5737.           &pico_pen_right, ctl_pico_pen, ctl_pico_pen_release, DEF },
  5738.         { CTL_PICO_PEN_BUTTON,
  5739.           &pico_pen_button, ctl_pico_pen, ctl_pico_pen_release, DEF },
  5740. #endif
  5741.         { CTL_DGEN_QUIT, &dgen_quit, ctl_dgen_quit, NULL, DEF },
  5742.         { CTL_DGEN_CRAPTV_TOGGLE,
  5743.           &dgen_craptv_toggle, ctl_dgen_craptv_toggle, NULL, DEF },
  5744.         { CTL_DGEN_SCALING_TOGGLE,
  5745.           &dgen_scaling_toggle, ctl_dgen_scaling_toggle, NULL, DEF },
  5746.         { CTL_DGEN_RESET, &dgen_reset, ctl_dgen_reset, NULL, DEF },
  5747.         { CTL_DGEN_SLOT0, &dgen_slot_0, ctl_dgen_slot, NULL, DEF },
  5748.         { CTL_DGEN_SLOT1, &dgen_slot_1, ctl_dgen_slot, NULL, DEF },
  5749.         { CTL_DGEN_SLOT2, &dgen_slot_2, ctl_dgen_slot, NULL, DEF },
  5750.         { CTL_DGEN_SLOT3, &dgen_slot_3, ctl_dgen_slot, NULL, DEF },
  5751.         { CTL_DGEN_SLOT4, &dgen_slot_4, ctl_dgen_slot, NULL, DEF },
  5752.         { CTL_DGEN_SLOT5, &dgen_slot_5, ctl_dgen_slot, NULL, DEF },
  5753.         { CTL_DGEN_SLOT6, &dgen_slot_6, ctl_dgen_slot, NULL, DEF },
  5754.         { CTL_DGEN_SLOT7, &dgen_slot_7, ctl_dgen_slot, NULL, DEF },
  5755.         { CTL_DGEN_SLOT8, &dgen_slot_8, ctl_dgen_slot, NULL, DEF },
  5756.         { CTL_DGEN_SLOT9, &dgen_slot_9, ctl_dgen_slot, NULL, DEF },
  5757.         { CTL_DGEN_SLOT_NEXT, &dgen_slot_next, ctl_dgen_slot_next, NULL, DEF },
  5758.         { CTL_DGEN_SLOT_PREV, &dgen_slot_prev, ctl_dgen_slot_prev, NULL, DEF },
  5759.         { CTL_DGEN_SAVE, &dgen_save, ctl_dgen_save, NULL, DEF },
  5760.         { CTL_DGEN_LOAD, &dgen_load, ctl_dgen_load, NULL, DEF },
  5761.         { CTL_DGEN_Z80_TOGGLE,
  5762.           &dgen_z80_toggle, ctl_dgen_z80_toggle, NULL, DEF },
  5763.         { CTL_DGEN_CPU_TOGGLE,
  5764.           &dgen_cpu_toggle, ctl_dgen_cpu_toggle, NULL, DEF },
  5765.         { CTL_DGEN_STOP, &dgen_stop, ctl_dgen_stop, NULL, DEF },
  5766.         { CTL_DGEN_PROMPT, &dgen_prompt, ctl_dgen_prompt, NULL, DEF },
  5767.         { CTL_DGEN_GAME_GENIE,
  5768.           &dgen_game_genie, ctl_dgen_game_genie, NULL, DEF },
  5769.         { CTL_DGEN_VOLUME_INC,
  5770.           &dgen_volume_inc, ctl_dgen_volume, NULL, DEF },
  5771.         { CTL_DGEN_VOLUME_DEC,
  5772.           &dgen_volume_dec, ctl_dgen_volume, NULL, DEF },
  5773.         { CTL_DGEN_FULLSCREEN_TOGGLE,
  5774.           &dgen_fullscreen_toggle, ctl_dgen_fullscreen_toggle, NULL, DEF },
  5775.         { CTL_DGEN_FIX_CHECKSUM,
  5776.           &dgen_fix_checksum, ctl_dgen_fix_checksum, NULL, DEF },
  5777.         { CTL_DGEN_SCREENSHOT,
  5778.           &dgen_screenshot, ctl_dgen_screenshot, NULL, DEF },
  5779.         { CTL_DGEN_DEBUG_ENTER,
  5780.           &dgen_debug_enter, ctl_dgen_debug_enter, NULL, DEF },
  5781.         { CTL_, NULL, NULL, NULL, DEF }
  5782. };
  5783.  
  5784. static struct {
  5785.         char const* name; ///< Controller button name.
  5786.         enum ctl_e const id[2]; ///< Controls indices in control[].
  5787.         bool once; ///< If button has been pressed once.
  5788.         bool twice; ///< If button has been pressed twice.
  5789.         enum rc_binding_type type; ///< Type of code.
  5790.         intptr_t code; ///< Temporary code.
  5791. } calibration_steps[] = {
  5792.         { "START", { CTL_PAD1_START, CTL_PAD2_START },
  5793.           false, false, RCB_NUM, -1 },
  5794.         { "MODE", { CTL_PAD1_MODE, CTL_PAD2_MODE },
  5795.           false, false, RCB_NUM, -1 },
  5796.         { "A", { CTL_PAD1_A, CTL_PAD2_A },
  5797.           false, false, RCB_NUM, -1 },
  5798.         { "B", { CTL_PAD1_B, CTL_PAD2_B },
  5799.           false, false, RCB_NUM, -1 },
  5800.         { "C", { CTL_PAD1_C, CTL_PAD2_C },
  5801.           false, false, RCB_NUM, -1 },
  5802.         { "X", { CTL_PAD1_X, CTL_PAD2_X },
  5803.           false, false, RCB_NUM, -1 },
  5804.         { "Y", { CTL_PAD1_Y, CTL_PAD2_Y },
  5805.           false, false, RCB_NUM, -1 },
  5806.         { "Z", { CTL_PAD1_Z, CTL_PAD2_Z },
  5807.           false, false, RCB_NUM, -1 },
  5808.         { "UP", { CTL_PAD1_UP, CTL_PAD2_UP },
  5809.           false, false, RCB_NUM, -1 },
  5810.         { "DOWN", { CTL_PAD1_DOWN, CTL_PAD2_DOWN },
  5811.           false, false, RCB_NUM, -1 },
  5812.         { "LEFT", { CTL_PAD1_LEFT, CTL_PAD2_LEFT },
  5813.           false, false, RCB_NUM, -1 },
  5814.         { "RIGHT", { CTL_PAD1_RIGHT, CTL_PAD2_RIGHT },
  5815.           false, false, RCB_NUM, -1 },
  5816.         { NULL, { CTL_, CTL_ },
  5817.           false, false, RCB_NUM, -1 }
  5818. };
  5819.  
  5820. /**
  5821.  * Handle input during calibration process.
  5822.  * @param type Type of code.
  5823.  * @param code Code to process.
  5824.  */
  5825. static void manage_calibration(enum rc_binding_type type, intptr_t code)
  5826. {
  5827.         unsigned int step = 0;
  5828.  
  5829.         assert(calibrating_controller < 2);
  5830.         if (!calibrating) {
  5831.                 // Stop emulation, enter calibration mode.
  5832.                 freeze(true);
  5833.                 calibrating = true;
  5834.                 filter_text_str[0] = '\0';
  5835.                 filter_text_msg(FILTER_TEXT_BG_BLACK
  5836.                                 FILTER_TEXT_CENTER
  5837.                                 FILTER_TEXT_8X13
  5838.                                 "CONTROLLER %u CALIBRATION\n"
  5839.                                 "\n"
  5840.                                 FILTER_TEXT_7X6
  5841.                                 FILTER_TEXT_LEFT
  5842.                                 "Press each button twice,\n"
  5843.                                 "or two different buttons to skip them.\n"
  5844.                                 "\n",
  5845.                                 (calibrating_controller + 1));
  5846.                 filters_pluck(&filter_text_def);
  5847.                 filters_insert(&filter_text_def);
  5848.                 goto ask;
  5849.         }
  5850.         while (step != elemof(calibration_steps))
  5851.                 if ((calibration_steps[step].once == true) &&
  5852.                     (calibration_steps[step].twice == true))
  5853.                         ++step;
  5854.                 else
  5855.                         break;
  5856.         if (step == elemof(calibration_steps)) {
  5857.                 // Reset everything.
  5858.                 for (step = 0; (step != elemof(calibration_steps)); ++step) {
  5859.                         calibration_steps[step].once = false;
  5860.                         calibration_steps[step].twice = false;
  5861.                         calibration_steps[step].type = RCB_NUM;
  5862.                         calibration_steps[step].code = -1;
  5863.                 }
  5864.                 // Restart emulation.
  5865.                 freeze(false);
  5866.                 calibrating = false;
  5867.                 filters_pluck(&filter_text_def);
  5868.                 return;
  5869.         }
  5870.         if (calibration_steps[step].once == false) {
  5871.                 char *dump;
  5872.  
  5873.                 if (type == RCBK)
  5874.                         dump = dump_keysym(code);
  5875.                 else if (type == RCBJ)
  5876.                         dump = dump_joypad(code);
  5877.                 else if (type == RCBM)
  5878.                         dump = dump_mouse(code);
  5879.                 else
  5880.                         dump = NULL;
  5881.                 assert(calibration_steps[step].twice == false);
  5882.                 calibration_steps[step].once = true;
  5883.                 calibration_steps[step].type = type;
  5884.                 calibration_steps[step].code = code;
  5885.                 filter_text_msg("\"%s\", confirm: ", (dump ? dump : ""));
  5886.                 free(dump);
  5887.         }
  5888.         else if (calibration_steps[step].twice == false) {
  5889.                 calibration_steps[step].twice = true;
  5890.                 if ((calibration_steps[step].type == type) &&
  5891.                     (calibration_steps[step].code == code))
  5892.                         filter_text_msg("OK\n");
  5893.                 else {
  5894.                         calibration_steps[step].type = RCB_NUM;
  5895.                         calibration_steps[step].code = -1;
  5896.                         filter_text_msg("none\n");
  5897.                 }
  5898.         }
  5899.         if ((calibration_steps[step].once != true) ||
  5900.             (calibration_steps[step].twice != true))
  5901.                 return;
  5902.         ++step;
  5903. ask:
  5904.         if (step == elemof(calibration_steps)) {
  5905.                 code = calibration_steps[(elemof(calibration_steps) - 1)].code;
  5906.                 if (code == -1)
  5907.                         filter_text_msg("\n"
  5908.                                         "Aborted.");
  5909.                 else {
  5910.                         unsigned int i;
  5911.  
  5912.                         for (i = 0; (i != elemof(calibration_steps)); ++i) {
  5913.                                 enum ctl_e id;
  5914.  
  5915.                                 id = calibration_steps[i].id
  5916.                                         [calibrating_controller];
  5917.                                 type = calibration_steps[i].type;
  5918.                                 code = calibration_steps[i].code;
  5919.                                 assert((size_t)id < elemof(control));
  5920.                                 assert(control[id].type == id);
  5921.                                 if ((id != CTL_) && (type != RCB_NUM))
  5922.                                         (*control[id].rc)[type] = code;
  5923.                         }
  5924.                         filter_text_msg("\n"
  5925.                                         "Applied.");
  5926.                 }
  5927.         }
  5928.         else if (calibration_steps[step].name != NULL)
  5929.                 filter_text_msg("%s: ", calibration_steps[step].name);
  5930.         else
  5931.                 filter_text_msg("\n"
  5932.                                 "Press any button twice to apply settings:\n"
  5933.                                 "");
  5934. }
  5935.  
  5936. static struct rc_binding_item combos[64];
  5937.  
  5938. static void manage_combos(md& md, bool pressed, enum rc_binding_type type,
  5939.                           intptr_t code)
  5940. {
  5941.         unsigned int i;
  5942.  
  5943.         (void)md;
  5944.         for (i = 0; (i != elemof(combos)); ++i) {
  5945.                 if (!combos[i].assigned) {
  5946.                         if (!pressed)
  5947.                                 return; // Not in the list, nothing to do.
  5948.                         // Not found, add it to the list.
  5949.                         combos[i].assigned = true;
  5950.                         combos[i].type = type;
  5951.                         combos[i].code = code;
  5952.                         return;
  5953.                 }
  5954.                 if ((combos[i].type != type) || (combos[i].code != code))
  5955.                         continue; // Does not match.
  5956.                 if (pressed)
  5957.                         return; // Already pressed.
  5958.                 // Release entry.
  5959.                 memmove(&combos[i], &combos[i + 1],
  5960.                         ((elemof(combos) - (i + 1)) * sizeof(combos[i])));
  5961.                 break;
  5962.         }
  5963. }
  5964.  
  5965. static bool check_combos(md& md, struct rc_binding_item item[],
  5966.                          unsigned int num)
  5967. {
  5968.         unsigned int i;
  5969.         unsigned int found = 0;
  5970.  
  5971.         (void)md;
  5972.         for (i = 0; (i != num); ++i) {
  5973.                 unsigned int j;
  5974.  
  5975.                 if (!item[i].assigned) {
  5976.                         num = i;
  5977.                         break;
  5978.                 }
  5979.                 for (j = 0; (j != elemof(combos)); ++j) {
  5980.                         if (!combos[j].assigned)
  5981.                                 break;
  5982.                         if ((combos[j].type != item[i].type) ||
  5983.                             (combos[j].code != item[i].code))
  5984.                                 continue;
  5985.                         ++found;
  5986.                         break;
  5987.                 }
  5988.         }
  5989.         if (num == 0)
  5990.                 return false;
  5991.         return (found == num);
  5992. }
  5993.  
  5994. static int manage_bindings(md& md, bool pressed, enum rc_binding_type type,
  5995.                            intptr_t code)
  5996. {
  5997.         struct rc_binding *rcb = rc_binding_head.next;
  5998.         size_t pos = 0;
  5999.         size_t seek = 0;
  6000.  
  6001.         if ((dgen_buttons) && (pressed)) {
  6002.                 char *dump;
  6003.  
  6004.                 if (type == RCBK)
  6005.                         dump = dump_keysym(code);
  6006.                 else if (type == RCBJ)
  6007.                         dump = dump_joypad(code);
  6008.                 else if (type == RCBM)
  6009.                         dump = dump_mouse(code);
  6010.                 else
  6011.                         dump = NULL;
  6012.                 if (dump != NULL) {
  6013.                         pd_message("Pressed \"%s\".", dump);
  6014.                         free(dump);
  6015.                 }
  6016.         }
  6017.         while (rcb != &rc_binding_head) {
  6018.                 if ((pos < seek) ||
  6019.                     (!check_combos(md, rcb->item, elemof(rcb->item)))) {
  6020.                         ++pos;
  6021.                         rcb = rcb->next;
  6022.                         continue;
  6023.                 }
  6024.                 assert(rcb->to != NULL);
  6025.                 assert((intptr_t)rcb->to != -1);
  6026.                 // For keyboard and joystick bindings, perform related action.
  6027.                 if ((type = RCBK, !strncasecmp("key_", rcb->to, 4)) ||
  6028.                     (type = RCBJ, !strncasecmp("joy_", rcb->to, 4)) ||
  6029.                     (type = RCBM, !strncasecmp("mou_", rcb->to, 4))) {
  6030.                         struct rc_field *rcf = rc_fields;
  6031.  
  6032.                         while (rcf->fieldname != NULL) {
  6033.                                 struct ctl *ctl = control;
  6034.  
  6035.                                 if (strcasecmp(rcb->to, rcf->fieldname)) {
  6036.                                         ++rcf;
  6037.                                         continue;
  6038.                                 }
  6039.                                 while (ctl->rc != NULL) {
  6040.                                         if (&(*ctl->rc)[type] !=
  6041.                                             rcf->variable) {
  6042.                                                 ++ctl;
  6043.                                                 continue;
  6044.                                         }
  6045.                                         // Got it, finally.
  6046.                                         if (pressed) {
  6047.                                                 assert(ctl->press != NULL);
  6048.                                                 if (!ctl->press(*ctl, md))
  6049.                                                         return 0;
  6050.                                         }
  6051.                                         else if (ctl->release != NULL) {
  6052.                                                 if (!ctl->release(*ctl, md))
  6053.                                                         return 0;
  6054.                                         }
  6055.                                         break;
  6056.                                 }
  6057.                                 break;
  6058.                         }
  6059.                 }
  6060.                 // Otherwise, pass it to the prompt.
  6061.                 else if (pressed) {
  6062.                         handle_prompt_complete_clear();
  6063.                         prompt_replace(&prompt.status, 0, 0,
  6064.                                        (uint8_t *)rcb->to, strlen(rcb->to));
  6065.                         if (handle_prompt_enter(md) & PROMPT_RET_ERROR)
  6066.                                 return 0;
  6067.                 }
  6068.                 // In case the current (or any other binding) has been
  6069.                 // removed, rewind and seek to the next position.
  6070.                 rcb = rc_binding_head.next;
  6071.                 seek = (pos + 1);
  6072.                 pos = 0;
  6073.         }
  6074.         return 1;
  6075. }
  6076.  
  6077. static int manage_game_genie(md& megad, intptr_t ksym, intptr_t ksym_uni)
  6078. {
  6079.         static char buf[12];
  6080.         static kb_input_t input = { buf, 0, sizeof(buf) };
  6081.         unsigned int len = strlen(game_genie_str);
  6082.  
  6083.         switch (kb_input(&input, ksym, ksym_uni)) {
  6084.                 unsigned int errors;
  6085.                 unsigned int applied;
  6086.                 unsigned int reverted;
  6087.  
  6088.         case KB_INPUT_ENTERED:
  6089.                 megad.patch(input.buf, &errors, &applied, &reverted);
  6090.                 if (errors)
  6091.                         pd_message("Invalid code.");
  6092.                 else if (reverted)
  6093.                         pd_message("Reverted.");
  6094.                 else if (applied)
  6095.                         pd_message("Applied.");
  6096.                 else {
  6097.                 case KB_INPUT_ABORTED:
  6098.                         pd_message("Aborted.");
  6099.                 }
  6100.                 goto over;
  6101.         case KB_INPUT_CONSUMED:
  6102.                 pd_message_cursor((len + input.pos), "%s%.*s", game_genie_str,
  6103.                                   (int)input.pos, buf);
  6104.                 break;
  6105.         case KB_INPUT_IGNORED:
  6106.                 break;
  6107.         }
  6108.         return 0;
  6109. over:
  6110.         input.buf = buf;
  6111.         input.pos = 0;
  6112.         input.size = sizeof(buf);
  6113.         memset(buf, 0, sizeof(buf));
  6114.         return 1;
  6115. }
  6116.  
  6117. #ifdef WITH_PICO
  6118.  
  6119. static void manage_pico_pen(md& megad)
  6120. {
  6121.         static unsigned long pico_pen_last_update;
  6122.         unsigned long pico_pen_now;
  6123.  
  6124.         if (!megad.pico_enabled)
  6125.                 return;
  6126.         // Repeat pen motion as long as buttons are not released.
  6127.         // This is not necessary when pen is managed by direct coordinates.
  6128.         if ((((control[CTL_PICO_PEN_UP].pressed) &&
  6129.               (!control[CTL_PICO_PEN_UP].coord)) ||
  6130.              ((control[CTL_PICO_PEN_DOWN].pressed) &&
  6131.               (!control[CTL_PICO_PEN_DOWN].coord)) ||
  6132.              ((control[CTL_PICO_PEN_LEFT].pressed) &&
  6133.               (!control[CTL_PICO_PEN_LEFT].coord)) ||
  6134.              ((control[CTL_PICO_PEN_RIGHT].pressed) &&
  6135.               (!control[CTL_PICO_PEN_RIGHT].coord))) &&
  6136.             (pico_pen_now = pd_usecs(),
  6137.              ((pico_pen_now - pico_pen_last_update) >=
  6138.               ((unsigned long)pico_pen_delay * 1000)))) {
  6139.                 if (control[CTL_PICO_PEN_UP].pressed)
  6140.                         ctl_pico_pen
  6141.                                 (control[CTL_PICO_PEN_UP], megad);
  6142.                 if (control[CTL_PICO_PEN_DOWN].pressed)
  6143.                         ctl_pico_pen
  6144.                                 (control[CTL_PICO_PEN_DOWN], megad);
  6145.                 if (control[CTL_PICO_PEN_LEFT].pressed)
  6146.                         ctl_pico_pen
  6147.                                 (control[CTL_PICO_PEN_LEFT], megad);
  6148.                 if (control[CTL_PICO_PEN_RIGHT].pressed)
  6149.                         ctl_pico_pen
  6150.                                 (control[CTL_PICO_PEN_RIGHT], megad);
  6151.                 pico_pen_last_update = pico_pen_now;
  6152.         }
  6153. }
  6154.  
  6155. #endif
  6156.  
  6157. static bool mouse_is_grabbed()
  6158. {
  6159.         return (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON);
  6160. }
  6161.  
  6162. static void mouse_grab(bool grab)
  6163. {
  6164.         SDL_GrabMode mode = SDL_WM_GrabInput(SDL_GRAB_QUERY);
  6165.  
  6166.         if ((grab) && (!pd_freeze) && (mode == SDL_GRAB_OFF)) {
  6167.                 // Hide the cursor.
  6168.                 SDL_ShowCursor(0);
  6169.                 pd_message("Mouse trapped. Stop emulation to release.");
  6170.                 SDL_WM_GrabInput(SDL_GRAB_ON);
  6171.         }
  6172.         else if ((!grab) && (mode == SDL_GRAB_ON)) {
  6173.                 SDL_ShowCursor(1);
  6174.                 SDL_WM_GrabInput(SDL_GRAB_OFF);
  6175.         }
  6176. }
  6177.  
  6178. static int stop_events(md& megad, enum events status)
  6179. {
  6180.         struct ctl* ctl;
  6181.  
  6182.         stopped = 1;
  6183.         freeze(true);
  6184.         events = status;
  6185.         // Release controls.
  6186.         for (ctl = control; (ctl->rc != NULL); ++ctl) {
  6187.                 if (ctl->pressed == false)
  6188.                         continue;
  6189.                 ctl->pressed = false;
  6190.                 ctl->coord = false;
  6191.                 if ((ctl->release != NULL) &&
  6192.                     (ctl->release(*ctl, megad) == 0))
  6193.                         return -1; // XXX do something about this.
  6194.         }
  6195.         SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
  6196.                             SDL_DEFAULT_REPEAT_INTERVAL);
  6197.         // Switch out of fullscreen mode (assuming this is supported)
  6198.         if (screen.is_fullscreen) {
  6199.                 if (set_fullscreen(0) < -1)
  6200.                         return -1;
  6201.                 pd_graphics_update(true);
  6202.         }
  6203.         mouse_grab(false);
  6204.         return 0;
  6205. }
  6206.  
  6207. static void restart_events(md& megad)
  6208. {
  6209.         (void)megad;
  6210.         stopped = 1;
  6211.         freeze(false);
  6212.         handle_prompt_complete_clear();
  6213.         SDL_EnableKeyRepeat(0, 0);
  6214.         events = STARTED;
  6215. }
  6216.  
  6217. static struct {
  6218.         unsigned long when[0x100];
  6219.         uint8_t enabled[0x100 / 8];
  6220.         unsigned int count;
  6221. } mouse_motion_release;
  6222.  
  6223. #define MOUSE_MOTION_RELEASE_IS_ENABLED(which) \
  6224.         (mouse_motion_release.enabled[(which) / 8] & (1 << ((which) % 8)))
  6225. #define MOUSE_MOTION_RELEASE_DISABLE(which) \
  6226.         (mouse_motion_release.enabled[(which) / 8] &= ~(1 << ((which) % 8)))
  6227. #define MOUSE_MOTION_RELEASE_ENABLE(which) \
  6228.         (mouse_motion_release.enabled[(which) / 8] |= (1 << ((which) % 8)))
  6229.  
  6230. static void mouse_motion_delay_release(unsigned int which, bool enable)
  6231. {
  6232.         if (which >= elemof(mouse_motion_release.when)) {
  6233.                 DEBUG(("mouse index too high (%u)", which));
  6234.                 return;
  6235.         }
  6236.         if (!enable) {
  6237.                 if (!MOUSE_MOTION_RELEASE_IS_ENABLED(which))
  6238.                         return;
  6239.                 MOUSE_MOTION_RELEASE_DISABLE(which);
  6240.                 assert(mouse_motion_release.count != 0);
  6241.                 --mouse_motion_release.count;
  6242.                 return;
  6243.         }
  6244.         if (!MOUSE_MOTION_RELEASE_IS_ENABLED(which)) {
  6245.                 MOUSE_MOTION_RELEASE_ENABLE(which);
  6246.                 ++mouse_motion_release.count;
  6247.                 assert(mouse_motion_release.count <=
  6248.                        elemof(mouse_motion_release.when));
  6249.         }
  6250.         mouse_motion_release.when[which] =
  6251.                 (pd_usecs() + (dgen_mouse_delay * 1000));
  6252. }
  6253.  
  6254. static bool mouse_motion_released(SDL_Event *event)
  6255. {
  6256.         unsigned int i;
  6257.         unsigned long now;
  6258.  
  6259.         if (mouse_motion_release.count == 0)
  6260.                 return false;
  6261.         now = pd_usecs();
  6262.         for (i = 0; (i != mouse_motion_release.count); ++i) {
  6263.                 unsigned long diff;
  6264.  
  6265.                 if (!MOUSE_MOTION_RELEASE_IS_ENABLED(i))
  6266.                         continue;
  6267.                 diff = (mouse_motion_release.when[i] - now);
  6268.                 if (diff < (unsigned long)(dgen_mouse_delay * 1000))
  6269.                         continue;
  6270.                 event->motion.type = SDL_MOUSEMOTION;
  6271.                 event->motion.which = i;
  6272.                 event->motion.xrel = 0;
  6273.                 event->motion.yrel = 0;
  6274.                 MOUSE_MOTION_RELEASE_DISABLE(i);
  6275.                 --mouse_motion_release.count;
  6276.                 return true;
  6277.         }
  6278.         return false;
  6279. }
  6280.  
  6281. #define MOUSE_SHOW_USECS (unsigned long)(2 * 1000000)
  6282.  
  6283. // The massive event handler!
  6284. // I know this is an ugly beast, but please don't be discouraged. If you need
  6285. // help, don't be afraid to ask me how something works. Basically, just handle
  6286. // all the event keys, or even ignore a few if they don't make sense for your
  6287. // interface.
  6288. int pd_handle_events(md &megad)
  6289. {
  6290.         static uint16_t kpress[0x100];
  6291. #ifdef WITH_DEBUGGER
  6292.         static bool debug_trap;
  6293. #endif
  6294.         static unsigned long hide_mouse_when;
  6295.         static bool hide_mouse;
  6296. #ifdef WITH_JOYSTICK
  6297.         static uint32_t const axis_value[][3] = {
  6298.                 // { pressed, [implicitly released ...] }
  6299.                 { JS_AXIS_NEGATIVE, JS_AXIS_BETWEEN, JS_AXIS_POSITIVE },
  6300.                 { JS_AXIS_POSITIVE, JS_AXIS_BETWEEN, JS_AXIS_NEGATIVE },
  6301.                 { JS_AXIS_BETWEEN, JS_AXIS_POSITIVE, JS_AXIS_NEGATIVE }
  6302.         };
  6303.         static uint32_t const hat_value[][2] = {
  6304.                 // { SDL value, pressed }
  6305.                 { SDL_HAT_UP, JS_HAT_UP },
  6306.                 { SDL_HAT_RIGHT, JS_HAT_RIGHT },
  6307.                 { SDL_HAT_DOWN, JS_HAT_DOWN },
  6308.                 { SDL_HAT_LEFT, JS_HAT_LEFT }
  6309.         };
  6310.         unsigned int hat_value_map;
  6311.         intptr_t joypad;
  6312.         bool pressed;
  6313. #endif
  6314.         uint32_t plist[8];
  6315.         uint32_t rlist[8];
  6316.         unsigned int i, pi, ri;
  6317.         SDL_Event event;
  6318.         uint16_t ksym_uni;
  6319.         intptr_t ksym;
  6320.         intptr_t mouse;
  6321.         unsigned int which;
  6322.  
  6323. #ifdef WITH_DEBUGGER
  6324.         if ((megad.debug_trap) && (megad.debug_enter() < 0))
  6325.                 return 0;
  6326.         if (debug_trap != megad.debug_trap) {
  6327.                 debug_trap = megad.debug_trap;
  6328.                 if (debug_trap)
  6329.                         mouse_grab(false);
  6330.                 if (sound.cbuf.size)
  6331.                         SDL_PauseAudio(debug_trap == true);
  6332.         }
  6333. #endif
  6334.         if ((hide_mouse) &&
  6335.             ((hide_mouse_when - pd_usecs()) >= MOUSE_SHOW_USECS)) {
  6336.                 if (!mouse_is_grabbed())
  6337.                         SDL_ShowCursor(0);
  6338.                 hide_mouse = false;
  6339.         }
  6340. next_event:
  6341.         if (mouse_motion_released(&event))
  6342.                 goto mouse_motion;
  6343.         if (!SDL_PollEvent(&event)) {
  6344. #ifdef WITH_PICO
  6345.                 manage_pico_pen(megad);
  6346. #endif
  6347.                 return 1;
  6348.         }
  6349.         switch (event.type) {
  6350. #ifdef WITH_JOYSTICK
  6351.         case SDL_JOYAXISMOTION:
  6352.                 if (event.jaxis.value <= -16384)
  6353.                         i = 0;
  6354.                 else if (event.jaxis.value >= 16384)
  6355.                         i = 1;
  6356.                 else
  6357.                         i = 2;
  6358.                 plist[0] = JS_AXIS(event.jaxis.which,
  6359.                                    event.jaxis.axis,
  6360.                                    axis_value[i][0]);
  6361.                 rlist[0] = JS_AXIS(event.jaxis.which,
  6362.                                    event.jaxis.axis,
  6363.                                    axis_value[i][1]);
  6364.                 rlist[1] = JS_AXIS(event.jaxis.which,
  6365.                                    event.jaxis.axis,
  6366.                                    axis_value[i][2]);
  6367.                 // "between" causes problems during calibration, ignore it.
  6368.                 if (axis_value[i][0] == JS_AXIS_BETWEEN)
  6369.                         pi = 0;
  6370.                 else
  6371.                         pi = 1;
  6372.                 ri = 2;
  6373.                 goto joypad_axis;
  6374.         case SDL_JOYHATMOTION:
  6375.                 pi = 0;
  6376.                 ri = 0;
  6377.                 hat_value_map = 0;
  6378.                 for (i = 0; (i != elemof(hat_value)); ++i)
  6379.                         if (event.jhat.value & hat_value[i][0]) {
  6380.                                 plist[pi++] = JS_HAT(event.jhat.which,
  6381.                                                      event.jhat.hat,
  6382.                                                      hat_value[i][1]);
  6383.                                 hat_value_map |= (1 << i);
  6384.                         }
  6385.                 for (i = 0; (i != elemof(hat_value)); ++i)
  6386.                         if ((hat_value_map & (1 << i)) == 0)
  6387.                                 rlist[ri++] = JS_HAT(event.jhat.which,
  6388.                                                      event.jhat.hat,
  6389.                                                      hat_value[i][1]);
  6390.         joypad_axis:
  6391.                 for (i = 0; (i != ri); ++i)
  6392.                         manage_combos(megad, false, RCBJ, rlist[i]);
  6393.                 for (i = 0; (i != pi); ++i)
  6394.                         manage_combos(megad, true, RCBJ, plist[i]);
  6395.                 if (events != STARTED)
  6396.                         break;
  6397.                 if (calibrating) {
  6398.                         for (i = 0; ((calibrating) && (i != pi)); ++i)
  6399.                                 manage_calibration(RCBJ, plist[i]);
  6400.                         break;
  6401.                 }
  6402.                 for (struct ctl* ctl = control; (ctl->rc != NULL); ++ctl) {
  6403.                         // Release buttons first.
  6404.                         for (i = 0; (i != ri); ++i) {
  6405.                                 if ((ctl->pressed == false) ||
  6406.                                     ((uint32_t)(*ctl->rc)[RCBJ] != rlist[i]))
  6407.                                         continue;
  6408.                                 ctl->pressed = false;
  6409.                                 ctl->coord = false;
  6410.                                 if ((ctl->release != NULL) &&
  6411.                                     (ctl->release(*ctl, megad) == 0))
  6412.                                         return 0;
  6413.                         }
  6414.                         for (i = 0; (i != pi); ++i) {
  6415.                                 if ((uint32_t)(*ctl->rc)[RCBJ] == plist[i]) {
  6416.                                         assert(ctl->press != NULL);
  6417.                                         ctl->pressed = true;
  6418.                                         ctl->coord = false;
  6419.                                         if (ctl->press(*ctl, megad) == 0)
  6420.                                                 return 0;
  6421.                                 }
  6422.                         }
  6423.                 }
  6424.                 for (i = 0; (i != ri); ++i)
  6425.                         if (!manage_bindings(megad, false, RCBJ, rlist[i]))
  6426.                                 return 0;
  6427.                 for (i = 0; (i != pi); ++i)
  6428.                         if (!manage_bindings(megad, true, RCBJ, plist[i]))
  6429.                                 return 0;
  6430.                 break;
  6431.         case SDL_JOYBUTTONDOWN:
  6432.                 assert(event.jbutton.state == SDL_PRESSED);
  6433.                 pressed = true;
  6434.                 goto joypad_button;
  6435.         case SDL_JOYBUTTONUP:
  6436.                 assert(event.jbutton.state == SDL_RELEASED);
  6437.                 pressed = false;
  6438.         joypad_button:
  6439.                 joypad = JS_BUTTON(event.jbutton.which, event.jbutton.button);
  6440.                 manage_combos(megad, pressed, RCBJ, joypad);
  6441.                 if (events != STARTED)
  6442.                         break;
  6443.                 if (calibrating) {
  6444.                         if (pressed)
  6445.                                 manage_calibration(RCBJ, joypad);
  6446.                         break;
  6447.                 }
  6448.                 for (struct ctl* ctl = control; (ctl->rc != NULL); ++ctl) {
  6449.                         if ((*ctl->rc)[RCBJ] != joypad)
  6450.                                 continue;
  6451.                         ctl->pressed = pressed;
  6452.                         ctl->coord = false;
  6453.                         if (pressed == false) {
  6454.                                 if ((ctl->release != NULL) &&
  6455.                                     (ctl->release(*ctl, megad) == 0))
  6456.                                         return 0;
  6457.                         }
  6458.                         else {
  6459.                                 assert(ctl->press != NULL);
  6460.                                 if (ctl->press(*ctl, megad) == 0)
  6461.                                         return 0;
  6462.                         }
  6463.                 }
  6464.                 if (manage_bindings(megad, pressed, RCBJ, joypad) == 0)
  6465.                         return 0;
  6466.                 break;
  6467. #endif // WITH_JOYSTICK
  6468.         case SDL_KEYDOWN:
  6469.                 ksym = event.key.keysym.sym;
  6470.                 ksym_uni = event.key.keysym.unicode;
  6471.                 if ((ksym_uni < 0x20) ||
  6472.                     ((ksym >= SDLK_KP0) && (ksym <= SDLK_KP_EQUALS)))
  6473.                         ksym_uni = 0;
  6474.                 kpress[(ksym & 0xff)] = ksym_uni;
  6475.                 if (ksym_uni)
  6476.                         ksym = ksym_uni;
  6477.                 else if (event.key.keysym.mod & KMOD_SHIFT)
  6478.                         ksym |= KEYSYM_MOD_SHIFT;
  6479.  
  6480.                 // Check for modifiers
  6481.                 if (event.key.keysym.mod & KMOD_CTRL)
  6482.                         ksym |= KEYSYM_MOD_CTRL;
  6483.                 if (event.key.keysym.mod & KMOD_ALT)
  6484.                         ksym |= KEYSYM_MOD_ALT;
  6485.                 if (event.key.keysym.mod & KMOD_META)
  6486.                         ksym |= KEYSYM_MOD_META;
  6487.  
  6488.                 manage_combos(megad, true, RCBK, ksym);
  6489.  
  6490.                 if (calibrating) {
  6491.                         manage_calibration(RCBK, ksym);
  6492.                         break;
  6493.                 }
  6494.  
  6495.                 switch (events) {
  6496.                         int ret;
  6497.  
  6498.                 case STARTED:
  6499.                         break;
  6500.                 case PROMPT:
  6501.                 case STOPPED_PROMPT:
  6502.                         ret = handle_prompt(ksym, ksym_uni, megad);
  6503.                         if (ret & PROMPT_RET_ERROR) {
  6504.                                 restart_events(megad);
  6505.                                 return 0;
  6506.                         }
  6507.                         if (ret & PROMPT_RET_EXIT) {
  6508.                                 if (events == STOPPED_PROMPT) {
  6509.                                         // Return to stopped mode.
  6510.                                         pd_message(stopped_str);
  6511.                                         events = STOPPED;
  6512.                                         goto next_event;
  6513.                                 }
  6514.                                 if ((ret & PROMPT_RET_MSG) == 0)
  6515.                                         pd_message("RUNNING.");
  6516.                                 restart_events(megad);
  6517.                                 goto next_event;
  6518.                         }
  6519.                         if (ret & PROMPT_RET_ENTER) {
  6520.                                 // Back to the prompt only in stopped mode.
  6521.                                 if (events == STOPPED_PROMPT)
  6522.                                         goto next_event;
  6523.                                 if ((ret & PROMPT_RET_MSG) == 0)
  6524.                                         pd_message("");
  6525.                                 restart_events(megad);
  6526.                                 goto next_event;
  6527.                         }
  6528.                         // PROMPT_RET_CONT
  6529.                         goto next_event;
  6530.                 case GAME_GENIE:
  6531.                 case STOPPED_GAME_GENIE:
  6532.                         if (manage_game_genie(megad, ksym, ksym_uni) == 0)
  6533.                                 goto next_event;
  6534.                         if (events == STOPPED_GAME_GENIE) {
  6535.                                 // Return to stopped mode.
  6536.                                 pd_message(stopped_str);
  6537.                                 events = STOPPED;
  6538.                         }
  6539.                         else
  6540.                                 restart_events(megad);
  6541.                         goto next_event;
  6542.                 case STOPPED:
  6543.                         // In basic stopped mode, handle a few keysyms.
  6544.                         if (ksym == dgen_game_genie[0]) {
  6545.                                 pd_message_cursor(strlen(game_genie_str),
  6546.                                                   game_genie_str);
  6547.                                 events = STOPPED_GAME_GENIE;
  6548.                         }
  6549.                         else if (ksym == dgen_prompt[0]) {
  6550.                                 pd_message_cursor(strlen(prompt_str),
  6551.                                                   prompt_str);
  6552.                                 events = STOPPED_PROMPT;
  6553.                         }
  6554.                         else if (ksym == dgen_quit[0]) {
  6555.                                 restart_events(megad);
  6556.                                 return 0;
  6557.                         }
  6558.                         else if (ksym == dgen_stop[0]) {
  6559.                                 pd_message("RUNNING.");
  6560.                                 restart_events(megad);
  6561.                         }
  6562. #ifdef WITH_DEBUGGER
  6563.                         else if (ksym == dgen_debug_enter[0])
  6564.                                 ctl_dgen_debug_enter(*(struct ctl *)0, megad);
  6565. #endif
  6566.                 default:
  6567.                         goto next_event;
  6568.                 }
  6569.  
  6570.                 for (struct ctl* ctl = control; (ctl->rc != NULL); ++ctl) {
  6571.                         if (ksym != (*ctl->rc)[RCBK])
  6572.                                 continue;
  6573.                         assert(ctl->press != NULL);
  6574.                         ctl->pressed = true;
  6575.                         ctl->coord = false;
  6576.                         if (ctl->press(*ctl, megad) == 0)
  6577.                                 return 0;
  6578.                 }
  6579.                 if (manage_bindings(megad, true, RCBK, ksym) == 0)
  6580.                         return 0;
  6581.                 break;
  6582.         case SDL_KEYUP:
  6583.                 ksym = event.key.keysym.sym;
  6584.                 ksym_uni = kpress[(ksym & 0xff)];
  6585.                 if ((ksym_uni < 0x20) ||
  6586.                     ((ksym >= SDLK_KP0) && (ksym <= SDLK_KP_EQUALS)))
  6587.                         ksym_uni = 0;
  6588.                 kpress[(ksym & 0xff)] = 0;
  6589.                 if (ksym_uni)
  6590.                         ksym = ksym_uni;
  6591.  
  6592.                 manage_combos(megad, false, RCBK, ksym);
  6593.                 manage_combos(megad, false, RCBK, (ksym | KEYSYM_MOD_ALT));
  6594.                 manage_combos(megad, false, RCBK, (ksym | KEYSYM_MOD_SHIFT));
  6595.                 manage_combos(megad, false, RCBK, (ksym | KEYSYM_MOD_CTRL));
  6596.                 manage_combos(megad, false, RCBK, (ksym | KEYSYM_MOD_META));
  6597.  
  6598.                 if (calibrating)
  6599.                         break;
  6600.                 if (events != STARTED)
  6601.                         break;
  6602.  
  6603.                 // The only time we care about key releases is for the
  6604.                 // controls, but ignore key modifiers so they never get stuck.
  6605.                 for (struct ctl* ctl = control; (ctl->rc != NULL); ++ctl) {
  6606.                         if (ksym != ((*ctl->rc)[RCBK] & ~KEYSYM_MOD_MASK))
  6607.                                 continue;
  6608.                         ctl->pressed = false;
  6609.                         ctl->coord = false;
  6610.                         if ((ctl->release != NULL) &&
  6611.                             (ctl->release(*ctl, megad) == 0))
  6612.                                 return 0;
  6613.                 }
  6614.                 if (manage_bindings(megad, false, RCBK, ksym) == 0)
  6615.                         return 0;
  6616.                 break;
  6617.         case SDL_MOUSEMOTION:
  6618.                 if (!mouse_is_grabbed()) {
  6619.                         // Only show mouse pointer for a few seconds.
  6620.                         SDL_ShowCursor(1);
  6621.                         hide_mouse_when = (pd_usecs() + MOUSE_SHOW_USECS);
  6622.                         hide_mouse = true;
  6623.                         break;
  6624.                 }
  6625.         mouse_motion:
  6626.                 which = event.motion.which;
  6627.                 pi = 0;
  6628.                 ri = 0;
  6629.                 if (event.motion.xrel < 0) {
  6630.                         plist[pi++] = MO_MOTION(which, 'l');
  6631.                         rlist[ri++] = MO_MOTION(which, 'r');
  6632.                 }
  6633.                 else if (event.motion.xrel > 0) {
  6634.                         plist[pi++] = MO_MOTION(which, 'r');
  6635.                         rlist[ri++] = MO_MOTION(which, 'l');
  6636.                 }
  6637.                 else {
  6638.                         rlist[ri++] = MO_MOTION(which, 'r');
  6639.                         rlist[ri++] = MO_MOTION(which, 'l');
  6640.                 }
  6641.                 if (event.motion.yrel < 0) {
  6642.                         plist[pi++] = MO_MOTION(which, 'u');
  6643.                         rlist[ri++] = MO_MOTION(which, 'd');
  6644.                 }
  6645.                 else if (event.motion.yrel > 0) {
  6646.                         plist[pi++] = MO_MOTION(which, 'd');
  6647.                         rlist[ri++] = MO_MOTION(which, 'u');
  6648.                 }
  6649.                 else {
  6650.                         rlist[ri++] = MO_MOTION(which, 'd');
  6651.                         rlist[ri++] = MO_MOTION(which, 'u');
  6652.                 }
  6653.                 if (pi)
  6654.                         mouse_motion_delay_release(which, true);
  6655.                 else
  6656.                         mouse_motion_delay_release(which, false);
  6657.                 for (i = 0; (i != ri); ++i)
  6658.                         manage_combos(megad, false, RCBM, rlist[i]);
  6659.                 for (i = 0; (i != pi); ++i)
  6660.                         manage_combos(megad, true, RCBM, plist[i]);
  6661.                 if (calibrating) {
  6662.                         for (i = 0; ((calibrating) && (i != pi)); ++i)
  6663.                                 manage_calibration(RCBM, plist[i]);
  6664.                         break;
  6665.                 }
  6666.                 if (events != STARTED)
  6667.                         break;
  6668.                 for (struct ctl* ctl = control; (ctl->rc != NULL); ++ctl) {
  6669.                         // Release buttons first.
  6670.                         for (i = 0; (i != ri); ++i) {
  6671.                                 if ((ctl->pressed == false) ||
  6672.                                     ((uint32_t)(*ctl->rc)[RCBM] != rlist[i]))
  6673.                                         continue;
  6674.                                 ctl->pressed = false;
  6675.                                 ctl->coord = true;
  6676.                                 ctl->x = event.motion.x;
  6677.                                 ctl->y = event.motion.y;
  6678.                                 if ((ctl->release != NULL) &&
  6679.                                     (ctl->release(*ctl, megad) == 0))
  6680.                                         return 0;
  6681.                         }
  6682.                         for (i = 0; (i != pi); ++i) {
  6683.                                 if ((uint32_t)(*ctl->rc)[RCBM] == plist[i]) {
  6684.                                         assert(ctl->press != NULL);
  6685.                                         ctl->pressed = true;
  6686.                                         ctl->coord = true;
  6687.                                         ctl->x = event.motion.x;
  6688.                                         ctl->y = event.motion.y;
  6689.                                         if (ctl->press(*ctl, megad) == 0)
  6690.                                                 return 0;
  6691.                                 }
  6692.                         }
  6693.                 }
  6694.                 for (i = 0; (i != ri); ++i)
  6695.                         if (!manage_bindings(megad, false, RCBM, rlist[i]))
  6696.                                 return 0;
  6697.                 for (i = 0; (i != pi); ++i)
  6698.                         if (!manage_bindings(megad, true, RCBM, plist[i]))
  6699.                                 return 0;
  6700.                 break;
  6701.         case SDL_MOUSEBUTTONDOWN:
  6702.                 assert(event.button.state == SDL_PRESSED);
  6703. #ifdef WITH_DEBUGGER
  6704.                 if (!debug_trap)
  6705. #endif
  6706.                         mouse_grab(true);
  6707.                 pressed = true;
  6708.                 goto mouse_button;
  6709.         case SDL_MOUSEBUTTONUP:
  6710.                 assert(event.button.state == SDL_RELEASED);
  6711.                 pressed = false;
  6712.         mouse_button:
  6713.                 mouse = MO_BUTTON(event.button.which, event.button.button);
  6714.                 manage_combos(megad, pressed, RCBM, mouse);
  6715.                 if (calibrating) {
  6716.                         if (pressed)
  6717.                                 manage_calibration(RCBM, mouse);
  6718.                         break;
  6719.                 }
  6720.                 if (events != STARTED)
  6721.                         break;
  6722.                 for (struct ctl* ctl = control; (ctl->rc != NULL); ++ctl) {
  6723.                         if ((*ctl->rc)[RCBM] != mouse)
  6724.                                 continue;
  6725.                         ctl->pressed = pressed;
  6726.                         ctl->coord = true;
  6727.                         ctl->x = event.button.x;
  6728.                         ctl->y = event.button.y;
  6729.                         if (pressed == false) {
  6730.                                 if ((ctl->release != NULL) &&
  6731.                                     (ctl->release(*ctl, megad) == 0))
  6732.                                         return 0;
  6733.                         }
  6734.                         else {
  6735.                                 assert(ctl->press != NULL);
  6736.                                 if (ctl->press(*ctl, megad) == 0)
  6737.                                         return 0;
  6738.                         }
  6739.                 }
  6740.                 if (manage_bindings(megad, pressed, RCBM, mouse) == 0)
  6741.                         return 0;
  6742.                 break;
  6743.         case SDL_VIDEORESIZE:
  6744.                 switch (screen_init(event.resize.w, event.resize.h)) {
  6745.                 case 0:
  6746.                         pd_message("Video resized to %ux%u.",
  6747.                                    screen.surface->w,
  6748.                                    screen.surface->h);
  6749.                         break;
  6750.                 case -1:
  6751.                         pd_message("Failed to resize video to %ux%u.",
  6752.                                    event.resize.w,
  6753.                                    event.resize.h);
  6754.                         break;
  6755.                 default:
  6756.                         fprintf(stderr,
  6757.                                 "sdl: fatal error while trying to change screen"
  6758.                                 " resolution.\n");
  6759.                         return 0;
  6760.                 }
  6761.                 break;
  6762.         case SDL_QUIT:
  6763.                 // We've been politely asked to exit, so let's leave
  6764.                 return 0;
  6765.         default:
  6766.                 break;
  6767.         }
  6768.         goto next_event;
  6769. }
  6770.  
  6771. static size_t pd_message_write(const char *msg, size_t len, unsigned int mark)
  6772. {
  6773.         uint8_t *buf = (screen.buf.u8 +
  6774.                         (screen.pitch * (screen.height - screen.info_height)));
  6775.         size_t ret = 0;
  6776.  
  6777.         screen_lock();
  6778.         // Clear text area.
  6779.         memset(buf, 0x00, (screen.pitch * screen.info_height));
  6780.         // Write message.
  6781.         if (len != 0)
  6782.                 ret = font_text(buf, screen.width, screen.info_height,
  6783.                                 screen.Bpp, screen.pitch, msg, len,
  6784.                                 mark, FONT_TYPE_AUTO);
  6785.         screen_unlock();
  6786.         return ret;
  6787. }
  6788.  
  6789. static size_t pd_message_display(const char *msg, size_t len,
  6790.                                  unsigned int mark, bool update)
  6791. {
  6792.         size_t ret = pd_message_write(msg, len, mark);
  6793.  
  6794.         if (update)
  6795.                 screen_update();
  6796.         if (len == 0)
  6797.                 info.displayed = 0;
  6798.         else {
  6799.                 info.displayed = 1;
  6800.                 info.since = pd_usecs();
  6801.         }
  6802.         return ret;
  6803. }
  6804.  
  6805. /**
  6806.  * Process status bar message.
  6807.  */
  6808. static void pd_message_process(void)
  6809. {
  6810.         size_t len = info.length;
  6811.         size_t n;
  6812.         size_t r;
  6813.  
  6814.         if (len == 0) {
  6815.                 pd_clear_message();
  6816.                 return;
  6817.         }
  6818.         for (n = 0; (n < len); ++n)
  6819.                 if (info.message[n] == '\n') {
  6820.                         len = (n + 1);
  6821.                         break;
  6822.                 }
  6823.         r = pd_message_display(info.message, n, ~0u, false);
  6824.         if (r < n)
  6825.                 len = r;
  6826.         memmove(info.message, &(info.message[len]), (info.length - len));
  6827.         info.length -= len;
  6828. }
  6829.  
  6830. /**
  6831.  * Postpone a message.
  6832.  */
  6833. static void pd_message_postpone(const char *msg)
  6834. {
  6835.         strncpy(&info.message[info.length], msg,
  6836.                 (sizeof(info.message) - info.length));
  6837.         info.length = strlen(info.message);
  6838.         info.displayed = 1;
  6839. }
  6840.  
  6841. /**
  6842.  * Write a message to the status bar.
  6843.  */
  6844.  
  6845. void pd_message(const char *msg, ...)
  6846. {
  6847.         va_list vl;
  6848.  
  6849.         va_start(vl, msg);
  6850.         vsnprintf(info.message, sizeof(info.message), msg, vl);
  6851.         va_end(vl);
  6852.         info.length = strlen(info.message);
  6853.         pd_message_process();
  6854. }
  6855.  
  6856. void pd_clear_message()
  6857. {
  6858.         pd_message_display(NULL, 0, ~0u, false);
  6859. }
  6860.  
  6861. void pd_show_carthead(md& megad)
  6862. {
  6863.         struct {
  6864.                 const char *p;
  6865.                 const char *s;
  6866.                 size_t len;
  6867.         } data[] = {
  6868. #define CE(i, s) { i, s, sizeof(s) }
  6869.                 CE("System", megad.cart_head.system_name),
  6870.                 CE("Copyright", megad.cart_head.copyright),
  6871.                 CE("Domestic name", megad.cart_head.domestic_name),
  6872.                 CE("Overseas name", megad.cart_head.overseas_name),
  6873.                 CE("Product number", megad.cart_head.product_no),
  6874.                 CE("Memo", megad.cart_head.memo),
  6875.                 CE("Countries", megad.cart_head.countries)
  6876.         };
  6877.         size_t i;
  6878.  
  6879.         pd_message_postpone("\n");
  6880.         for (i = 0; (i < (sizeof(data) / sizeof(data[0]))); ++i) {
  6881.                 char buf[256];
  6882.                 size_t j, k;
  6883.  
  6884.                 k = (size_t)snprintf(buf, sizeof(buf), "%s: ", data[i].p);
  6885.                 if (k >= (sizeof(buf) - 1))
  6886.                         continue;
  6887.                 // Filter out extra spaces.
  6888.                 for (j = 0; (j < data[i].len); ++j)
  6889.                         if (isgraph(data[i].s[j]))
  6890.                                 break;
  6891.                 if (j == data[i].len)
  6892.                         continue;
  6893.                 while ((j < data[i].len) && (k < (sizeof(buf) - 2))) {
  6894.                         if (isgraph(data[i].s[j])) {
  6895.                                 buf[(k++)] = data[i].s[j];
  6896.                                 ++j;
  6897.                                 continue;
  6898.                         }
  6899.                         buf[(k++)] = ' ';
  6900.                         while ((j < data[i].len) && (!isgraph(data[i].s[j])))
  6901.                                 ++j;
  6902.                 }
  6903.                 if (buf[(k - 1)] == ' ')
  6904.                         --k;
  6905.                 buf[k] = '\n';
  6906.                 buf[(k + 1)] = '\0';
  6907.                 pd_message_postpone(buf);
  6908.         }
  6909. }
  6910.  
  6911. /* Clean up this awful mess :) */
  6912. void pd_quit()
  6913. {
  6914.         size_t i;
  6915.  
  6916. #ifdef WITH_THREADS
  6917.         screen_update_thread_stop();
  6918. #endif
  6919.         if (mdscr.data) {
  6920.                 free((void*)mdscr.data);
  6921.                 mdscr.data = NULL;
  6922.         }
  6923.         SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
  6924.         pd_sound_deinit();
  6925.         if (mdpal)
  6926.                 mdpal = NULL;
  6927. #ifdef WITH_OPENGL
  6928.         release_texture(screen.texture);
  6929. #endif
  6930.         free(filters_stack_data_buf[0].u8);
  6931.         free(filters_stack_data_buf[1].u8);
  6932.         assert(filters_stack_size <= elemof(filters_stack));
  6933.         assert(filters_stack_data[0].data == NULL);
  6934.         filters_stack_default = false;
  6935.         for (i = 0; (i != filters_stack_size); ++i) {
  6936.                 free(filters_stack_data[i + 1].data);
  6937.                 filters_stack_data[i + 1].data = NULL;
  6938.         }
  6939.         filters_stack_size = 0;
  6940.         SDL_Quit();
  6941. }
  6942.