further unification and refactoring
[libpicofe.git] / common / emu.c
index a1c461a..2535abe 100644 (file)
@@ -5,7 +5,6 @@
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
-#include <ctype.h> // tolower\r
 #ifndef NO_SYNC\r
 #include <unistd.h>\r
 #endif\r
@@ -15,8 +14,9 @@
 #include "fonts.h"\r
 #include "lprintf.h"\r
 #include "config.h"\r
-#include "common.h"\r
 #include "plat.h"\r
+#include "input.h"\r
+#include "posix.h"\r
 \r
 #include <pico/pico_int.h>\r
 #include <pico/patch.h>\r
@@ -33,9 +33,9 @@ int g_screen_height = SCREEN_HEIGHT;
 \r
 char *PicoConfigFile = "config.cfg";\r
 currentConfig_t currentConfig, defaultConfig;\r
-char noticeMsg[64] = { 0, };\r
 int state_slot = 0;\r
 int config_slot = 0, config_slot_current = 0;\r
+int pico_pen_x = 320/2, pico_pen_y = 240/2;\r
 int pico_inp_mode = 0;\r
 int engineState = PGS_Menu;\r
 \r
@@ -43,17 +43,19 @@ int engineState = PGS_Menu;
 char rom_fname_reload[512] = { 0, };\r
 char rom_fname_loaded[512] = { 0, };\r
 int rom_loaded = 0;\r
+int reset_timing = 0;\r
 \r
 unsigned char *movie_data = NULL;\r
 static int movie_size = 0;\r
 \r
 \r
-// utilities\r
+/* don't use tolower() for easy old glibc binary compatibility */\r
 static void strlwr_(char *string)\r
 {\r
        char *p;\r
        for (p = string; *p; p++)\r
-               *p = (char)tolower(*p);\r
+               if ('A' <= *p && *p <= 'Z')\r
+                       *p += 'a' - 'A';\r
 }\r
 \r
 static int try_rfn_cut(char *fname)\r
@@ -110,7 +112,7 @@ int emu_findBios(int region, char **bios_file)
 \r
        for (i = 0; i < count; i++)\r
        {\r
-               emu_getMainDir(bios_path, sizeof(bios_path));\r
+               plat_get_root_dir(bios_path, sizeof(bios_path));\r
                strcat(bios_path, files[i]);\r
                strcat(bios_path, ".bin");\r
                f = fopen(bios_path, "rb");\r
@@ -478,18 +480,13 @@ int emu_ReloadRom(char *rom_fname)
                        // TODO: bits 6 & 5\r
                }\r
                movie_data[0x18+30] = 0;\r
-               sprintf(noticeMsg, "MOVIE: %s", (char *) &movie_data[0x18]);\r
+               plat_status_msg("MOVIE: %s", (char *) &movie_data[0x18]);\r
        }\r
        else\r
        {\r
                PicoOpt &= ~POPT_DIS_VDP_FIFO;\r
-               if (Pico.m.pal) {\r
-                       strcpy(noticeMsg, "PAL SYSTEM / 50 FPS");\r
-               } else {\r
-                       strcpy(noticeMsg, "NTSC SYSTEM / 60 FPS");\r
-               }\r
+               plat_status_msg(Pico.m.pal ? "PAL SYSTEM / 50 FPS" : "NTSC SYSTEM / 60 FPS");\r
        }\r
-       emu_noticeMsgUpdated();\r
 \r
        // load SRAM for this ROM\r
        if (currentConfig.EmuOpt & EOPT_USE_SRAM)\r
@@ -525,7 +522,7 @@ static void romfname_ext(char *dst, const char *prefix, const char *ext)
        for (; p >= rom_fname_loaded && *p != PATH_SEP_C; p--); p++;\r
        *dst = 0;\r
        if (prefix) {\r
-               int len = emu_getMainDir(dst, 512);\r
+               int len = plat_get_root_dir(dst, 512);\r
                strcpy(dst + len, prefix);\r
                prefix_len = len + strlen(prefix);\r
        }\r
@@ -542,7 +539,7 @@ static void romfname_ext(char *dst, const char *prefix, const char *ext)
 static void make_config_cfg(char *cfg)\r
 {\r
        int len;\r
-       len = emu_getMainDir(cfg, 512);\r
+       len = plat_get_root_dir(cfg, 512);\r
        strncpy(cfg + len, PicoConfigFile, 512-6-1-len);\r
        if (config_slot != 0)\r
        {\r
@@ -622,23 +619,21 @@ int emu_ReadConfig(int game, int no_defaults)
                }\r
        }\r
 \r
+       plat_validate_config();\r
+\r
        // some sanity checks\r
-       if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200;\r
 #ifdef PSP\r
+       /* TODO: mv to plat_validate_config() */\r
+       if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200;\r
        if (currentConfig.gamma < -4 || currentConfig.gamma >  16) currentConfig.gamma = 0;\r
        if (currentConfig.gamma2 < 0 || currentConfig.gamma2 > 2)  currentConfig.gamma2 = 0;\r
-#else\r
-       if (currentConfig.gamma < 10 || currentConfig.gamma > 300) currentConfig.gamma = 100;\r
-#endif\r
-       if (currentConfig.volume < 0 || currentConfig.volume > 99) currentConfig.volume = 50;\r
-#ifdef __GP2X__\r
-       // if volume keys are unbound, bind them to volume control\r
-       if (!currentConfig.KeyBinds[23] && !currentConfig.KeyBinds[22]) {\r
-               currentConfig.KeyBinds[23] = 1<<29; // vol up\r
-               currentConfig.KeyBinds[22] = 1<<30; // vol down\r
-       }\r
 #endif\r
-       if (ret == 0) config_slot_current = config_slot;\r
+       if (currentConfig.volume < 0 || currentConfig.volume > 99)\r
+               currentConfig.volume = 50;\r
+\r
+       if (ret == 0)\r
+               config_slot_current = config_slot;\r
+\r
        return (ret == 0);\r
 }\r
 \r
@@ -715,15 +710,14 @@ mk_text_out(emu_textOut16, unsigned short, 0xffff)
 #undef mk_text_out\r
 \r
 \r
-void emu_updateMovie(void)\r
+void update_movie(void)\r
 {\r
        int offs = Pico.m.frame_count*3 + 0x40;\r
        if (offs+3 > movie_size) {\r
                free(movie_data);\r
                movie_data = 0;\r
-               strcpy(noticeMsg, "END OF MOVIE.");\r
+               plat_status_msg("END OF MOVIE.");\r
                lprintf("END OF MOVIE.\n");\r
-               emu_noticeMsgUpdated();\r
        } else {\r
                // MXYZ SACB RLDU\r
                PicoPad[0] = ~movie_data[offs]   & 0x8f; // ! SCBA RLDU\r
@@ -843,10 +837,8 @@ int emu_SaveLoadGame(int load, int sram)
        // make save filename\r
        saveFname = emu_GetSaveFName(load, sram, state_slot);\r
        if (saveFname == NULL) {\r
-               if (!sram) {\r
-                       strcpy(noticeMsg, load ? "LOAD FAILED (missing file)" : "SAVE FAILED  ");\r
-                       emu_noticeMsgUpdated();\r
-               }\r
+               if (!sram)\r
+                       plat_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED");\r
                return -1;\r
        }\r
 \r
@@ -932,14 +924,13 @@ int emu_SaveLoadGame(int load, int sram)
                }\r
                else    ret = -1;\r
                if (!ret)\r
-                       strcpy(noticeMsg, load ? "GAME LOADED  " : "GAME SAVED        ");\r
+                       plat_status_msg(load ? "GAME LOADED" : "GAME SAVED");\r
                else\r
                {\r
-                       strcpy(noticeMsg, load ? "LOAD FAILED  " : "SAVE FAILED       ");\r
+                       plat_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");\r
                        ret = -1;\r
                }\r
 \r
-               emu_noticeMsgUpdated();\r
                return ret;\r
        }\r
 }\r
@@ -958,8 +949,7 @@ void emu_changeFastForward(int set_on)
                currentConfig.EmuOpt &= ~4;\r
                currentConfig.EmuOpt |= 0x40000;\r
                is_on = 1;\r
-               strcpy(noticeMsg, "FAST FORWARD   ");\r
-               emu_noticeMsgUpdated();\r
+               plat_status_msg("FAST FORWARD");\r
        }\r
        else if (!set_on && is_on) {\r
                PsndOut = set_PsndOut;\r
@@ -970,35 +960,74 @@ void emu_changeFastForward(int set_on)
        }\r
 }\r
 \r
-void emu_RunEventsPico(unsigned int events)\r
+static void emu_msg_tray_open(void)\r
+{\r
+       plat_status_msg("CD tray opened");\r
+}\r
+\r
+void emu_reset_game(void)\r
+{\r
+       PicoReset();\r
+       reset_timing = 1;\r
+}\r
+\r
+void run_events_pico(unsigned int events)\r
 {\r
-       if (events & (1 << 3)) {\r
+       int lim_x;\r
+\r
+       if (events & PEV_PICO_SWINP) {\r
                pico_inp_mode++;\r
-               if (pico_inp_mode > 2) pico_inp_mode = 0;\r
+               if (pico_inp_mode > 2)\r
+                       pico_inp_mode = 0;\r
                switch (pico_inp_mode) {\r
-                       case 2: strcpy(noticeMsg, "Input: Pen on Pad      "); break;\r
-                       case 1: strcpy(noticeMsg, "Input: Pen on Storyware"); break;\r
-                       case 0: strcpy(noticeMsg, "Input: Joytick         ");\r
+                       case 2: plat_status_msg("Input: Pen on Pad"); break;\r
+                       case 1: plat_status_msg("Input: Pen on Storyware"); break;\r
+                       case 0: plat_status_msg("Input: Joystick");\r
                                PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;\r
                                break;\r
                }\r
-               emu_noticeMsgUpdated();\r
        }\r
-       if (events & (1 << 4)) {\r
+       if (events & PEV_PICO_PPREV) {\r
                PicoPicohw.page--;\r
-               if (PicoPicohw.page < 0) PicoPicohw.page = 0;\r
-               sprintf(noticeMsg, "Page %i                 ", PicoPicohw.page);\r
-               emu_noticeMsgUpdated();\r
+               if (PicoPicohw.page < 0)\r
+                       PicoPicohw.page = 0;\r
+               plat_status_msg("Page %i", PicoPicohw.page);\r
        }\r
-       if (events & (1 << 5)) {\r
+       if (events & PEV_PICO_PNEXT) {\r
                PicoPicohw.page++;\r
-               if (PicoPicohw.page > 6) PicoPicohw.page = 6;\r
-               sprintf(noticeMsg, "Page %i                 ", PicoPicohw.page);\r
-               emu_noticeMsgUpdated();\r
+               if (PicoPicohw.page > 6)\r
+                       PicoPicohw.page = 6;\r
+               plat_status_msg("Page %i", PicoPicohw.page);\r
        }\r
+\r
+       if (pico_inp_mode == 0)\r
+               return;\r
+\r
+       /* handle other input modes */\r
+       if (PicoPad[0] & 1) pico_pen_y--;\r
+       if (PicoPad[0] & 2) pico_pen_y++;\r
+       if (PicoPad[0] & 4) pico_pen_x--;\r
+       if (PicoPad[0] & 8) pico_pen_x++;\r
+       PicoPad[0] &= ~0x0f; // release UDLR\r
+\r
+       lim_x = (Pico.video.reg[12]&1) ? 319 : 255;\r
+       if (pico_pen_y < 8)\r
+               pico_pen_y = 8;\r
+       if (pico_pen_y > 224 - PICO_PEN_ADJUST_Y)\r
+               pico_pen_y = 224 - PICO_PEN_ADJUST_Y;\r
+       if (pico_pen_x < 0)\r
+               pico_pen_x = 0;\r
+       if (pico_pen_x > lim_x - PICO_PEN_ADJUST_X)\r
+               pico_pen_x = lim_x - PICO_PEN_ADJUST_X;\r
+\r
+       PicoPicohw.pen_pos[0] = pico_pen_x;\r
+       if (!(Pico.video.reg[12] & 1))\r
+               PicoPicohw.pen_pos[0] += pico_pen_x / 4;\r
+       PicoPicohw.pen_pos[0] += 0x3c;\r
+       PicoPicohw.pen_pos[1] = pico_inp_mode == 1 ? (0x2f8 + pico_pen_y) : (0x1fc + pico_pen_y);\r
 }\r
 \r
-void emu_DoTurbo(int *pad, int acts)\r
+static void do_turbo(int *pad, int acts)\r
 {\r
        static int turbo_pad = 0;\r
        static unsigned char turbo_cnt[3] = { 0, 0, 0 };\r
@@ -1022,3 +1051,145 @@ void emu_DoTurbo(int *pad, int acts)
        *pad |= turbo_pad & (acts >> 8);\r
 }\r
 \r
+static void run_events_ui(unsigned int which)\r
+{\r
+       if (which & (PEV_STATE_LOAD|PEV_STATE_SAVE))\r
+       {\r
+               int do_it = 1;\r
+               if ( emu_checkSaveFile(state_slot) &&\r
+                               (((which & PEV_STATE_LOAD) && (currentConfig.EmuOpt & EOPT_CONFIRM_LOAD)) ||\r
+                                ((which & PEV_STATE_SAVE) && (currentConfig.EmuOpt & EOPT_CONFIRM_SAVE))) )\r
+               {\r
+                       const char *nm;\r
+                       char tmp[64];\r
+                       int keys, len;\r
+\r
+                       strcpy(tmp, (which & PEV_STATE_LOAD) ? "LOAD STATE?" : "OVERWRITE SAVE?");\r
+                       len = strlen(tmp);\r
+                       nm = in_get_key_name(-1, -PBTN_MA3);\r
+                       snprintf(tmp + len, sizeof(tmp) - len, "(%s=yes, ", nm);\r
+                       len = strlen(tmp);\r
+                       nm = in_get_key_name(-1, -PBTN_MBACK);\r
+                       snprintf(tmp + len, sizeof(tmp) - len, "%s=no)", nm);\r
+\r
+                       plat_status_msg_busy_first(tmp);\r
+\r
+                       in_set_blocking(1);\r
+                       while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK))\r
+                               ;\r
+                       while ( !((keys = in_menu_wait_any(50)) & (PBTN_MA3|PBTN_MBACK)) )\r
+                               ;\r
+                       if (keys & PBTN_MBACK)\r
+                               do_it = 0;\r
+                       while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK))\r
+                               ;\r
+                       in_set_blocking(0);\r
+               }\r
+               if (do_it) {\r
+                       plat_status_msg_busy_first((which & PEV_STATE_LOAD) ? "LOADING GAME" : "SAVING GAME");\r
+                       PicoStateProgressCB = plat_status_msg_busy_next;\r
+                       emu_SaveLoadGame((which & PEV_STATE_LOAD) ? 1 : 0, 0);\r
+                       PicoStateProgressCB = NULL;\r
+               }\r
+       }\r
+       if (which & PEV_SWITCH_RND)\r
+       {\r
+               plat_video_toggle_renderer();\r
+       }\r
+       if (which & (PEV_SSLOT_PREV|PEV_SSLOT_NEXT))\r
+       {\r
+               if (which & PEV_SSLOT_PREV) {\r
+                       state_slot -= 1;\r
+                       if (state_slot < 0)\r
+                               state_slot = 9;\r
+               } else {\r
+                       state_slot += 1;\r
+                       if (state_slot > 9)\r
+                               state_slot = 0;\r
+               }\r
+\r
+               plat_status_msg("SAVE SLOT %i [%s]", state_slot,\r
+                       emu_checkSaveFile(state_slot) ? "USED" : "FREE");\r
+       }\r
+       if (which & PEV_MENU)\r
+               engineState = PGS_Menu;\r
+}\r
+\r
+void emu_update_input(void)\r
+{\r
+       unsigned int allActions[2] = { 0, 0 }, events;\r
+       static unsigned int prevEvents = 0;\r
+\r
+       /* FIXME: player2 */\r
+       allActions[0] = in_update();\r
+\r
+       PicoPad[0] = allActions[0] & 0xfff;\r
+       PicoPad[1] = allActions[1] & 0xfff;\r
+\r
+       if (allActions[0] & 0x7000) do_turbo(&PicoPad[0], allActions[0]);\r
+       if (allActions[1] & 0x7000) do_turbo(&PicoPad[1], allActions[1]);\r
+\r
+       events = (allActions[0] | allActions[1]) & PEV_MASK;\r
+\r
+       // volume is treated in special way and triggered every frame\r
+       if (events & (PEV_VOL_DOWN|PEV_VOL_UP))\r
+               plat_update_volume(1, events & PEV_VOL_UP);\r
+\r
+       if ((events ^ prevEvents) & PEV_FF) {\r
+               emu_changeFastForward(events & PEV_FF);\r
+               plat_update_volume(0, 0);\r
+               reset_timing = 1;\r
+       }\r
+\r
+       events &= ~prevEvents;\r
+\r
+       if (PicoAHW == PAHW_PICO)\r
+               run_events_pico(events);\r
+       if (events)\r
+               run_events_ui(events);\r
+       if (movie_data)\r
+               update_movie();\r
+\r
+       prevEvents = (allActions[0] | allActions[1]) & PEV_MASK;\r
+}\r
+\r
+static void mkdir_path(char *path_with_reserve, int pos, const char *name)\r
+{\r
+       strcpy(path_with_reserve + pos, name);\r
+       if (plat_is_dir(path_with_reserve))\r
+               return;\r
+       if (mkdir(path_with_reserve, 0777) < 0)\r
+               lprintf("failed to create: %s\n", path_with_reserve);\r
+}\r
+\r
+void emu_init(void)\r
+{\r
+       char dir[256];\r
+       int pos;\r
+\r
+       /* make dirs for saves */\r
+       pos = plat_get_root_dir(dir, sizeof(dir) - 4);\r
+       mkdir_path(dir, pos, "mds");\r
+       mkdir_path(dir, pos, "srm");\r
+       mkdir_path(dir, pos, "brm");\r
+\r
+       PicoInit();\r
+       PicoMessage = plat_status_msg_busy_next;\r
+       PicoMCDopenTray = emu_msg_tray_open;\r
+       PicoMCDcloseTray = menu_loop_tray;\r
+}\r
+\r
+void emu_finish(void)\r
+{\r
+       // save SRAM\r
+       if ((currentConfig.EmuOpt & EOPT_USE_SRAM) && SRam.changed) {\r
+               emu_SaveLoadGame(0, 1);\r
+               SRam.changed = 0;\r
+       }\r
+\r
+       if (!(currentConfig.EmuOpt & EOPT_NO_AUTOSVCFG))\r
+               emu_writelrom();\r
+\r
+       PicoExit();\r
+}\r
+\r