add configure, revive pnd build, unify/refactor things
[picodrive.git] / platform / common / emu.c
index a075abd..8eda13a 100644 (file)
@@ -1,7 +1,10 @@
-// (c) Copyright 2006-2009 notaz, All rights reserved.\r
-// Free for non-commercial use.\r
-\r
-// For commercial use, separate licencing terms must be obtained.\r
+/*\r
+ * PicoDrive\r
+ * (C) notaz, 2007-2010\r
+ *\r
+ * This work is licensed under the terms of MAME license.\r
+ * See COPYING file in the top-level directory.\r
+ */\r
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
 #include <unistd.h>\r
 #endif\r
 \r
+#include "../libpicofe/posix.h"\r
+#include "../libpicofe/input.h"\r
+#include "../libpicofe/fonts.h"\r
+#include "../libpicofe/sndout.h"\r
+#include "../libpicofe/lprintf.h"\r
+#include "../libpicofe/plat.h"\r
 #include "emu.h"\r
-#include "menu.h"\r
-#include "fonts.h"\r
-#include "lprintf.h"\r
-#include "config.h"\r
-#include "plat.h"\r
-#include "input.h"\r
-#include "posix.h"\r
+#include "input_pico.h"\r
+#include "menu_pico.h"\r
+#include "config_file.h"\r
 \r
 #include <pico/pico_int.h>\r
 #include <pico/patch.h>\r
@@ -41,10 +46,11 @@ int pico_pen_x = 320/2, pico_pen_y = 240/2;
 int pico_inp_mode = 0;\r
 int engineState = PGS_Menu;\r
 \r
+static short __attribute__((aligned(4))) sndBuffer[2*44100/50];\r
+\r
 /* tmp buff to reduce stack usage for plats with small stack */\r
 static char static_buff[512];\r
-/* TODO: len checking */\r
-char rom_fname_reload[512];\r
+const char *rom_fname_reload;\r
 char rom_fname_loaded[512];\r
 int rom_loaded = 0;\r
 int reset_timing = 0;\r
@@ -143,7 +149,7 @@ static const char * const biosfiles_us[] = { "us_scd1_9210", "us_scd2_9306", "Se
 static const char * const biosfiles_eu[] = { "eu_mcd1_9210", "eu_mcd2_9306", "eu_mcd2_9303"   };\r
 static const char * const biosfiles_jp[] = { "jp_mcd1_9112", "jp_mcd1_9111" };\r
 \r
-static int find_bios(int region, char **bios_file)\r
+static int find_bios(int region, const char **bios_file)\r
 {\r
        int i, count;\r
        const char * const *files;\r
@@ -184,7 +190,7 @@ static int find_bios(int region, char **bios_file)
        } else {\r
                sprintf(static_buff, "no %s BIOS files found, read docs",\r
                        region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");\r
-               me_update_msg(static_buff);\r
+               menu_update_msg(static_buff);\r
                return 0;\r
        }\r
 }\r
@@ -453,11 +459,14 @@ static void shutdown_MCD(void)
 \r
 static void system_announce(void)\r
 {\r
-       const char *sys_name, *tv_standard;\r
+       const char *sys_name, *tv_standard, *extra = "";\r
        int fps;\r
 \r
        if (PicoAHW & PAHW_SMS) {\r
                sys_name = "Master System";\r
+#ifdef NO_SMS\r
+               extra = " [no support]";\r
+#endif\r
        } else if (PicoAHW & PAHW_PICO) {\r
                sys_name = "Pico";\r
        } else if (PicoAHW & PAHW_MCD) {\r
@@ -474,64 +483,73 @@ static void system_announce(void)
        tv_standard = Pico.m.pal ? "PAL" : "NTSC";\r
        fps = Pico.m.pal ? 50 : 60;\r
 \r
-       emu_status_msg("%s %s / %dFPS", tv_standard, sys_name, fps);\r
+       emu_status_msg("%s %s / %dFPS%s", tv_standard, sys_name, fps, extra);\r
 }\r
 \r
-// note: this function might mangle rom_fname\r
 // XXX: portions of this code should move to pico/\r
-int emu_reload_rom(char *rom_fname)\r
+int emu_reload_rom(const char *rom_fname_in)\r
 {\r
        unsigned int rom_size = 0;\r
-       char *used_rom_name = rom_fname;\r
+       const char *used_rom_name = NULL;\r
+       char *rom_fname = NULL;\r
        unsigned char *rom_data = NULL;\r
        char ext[5];\r
        pm_file *rom = NULL;\r
        int cd_state = CIT_NOT_CD;\r
        int ret, media_type, cd_region;\r
        int cfg_loaded = 0, bad_rom = 0;\r
+       int menu_romload_started = 0;\r
+       int retval = 0;\r
 \r
-       lprintf("emu_ReloadRom(%s)\n", rom_fname);\r
+       lprintf("emu_ReloadRom(%s)\n", rom_fname_in);\r
 \r
+       rom_fname = strdup(rom_fname_in);\r
+       if (rom_fname == NULL)\r
+               return 0;\r
+\r
+       used_rom_name = rom_fname;\r
        get_ext(rom_fname, ext);\r
 \r
-       // check for movie file\r
+       // early cleanup\r
+       PicoPatchUnload();\r
        if (movie_data) {\r
                free(movie_data);\r
                movie_data = 0;\r
        }\r
+\r
        if (!strcmp(ext, ".gmv"))\r
        {\r
                // check for both gmv and rom\r
                int dummy;\r
                FILE *movie_file = fopen(rom_fname, "rb");\r
                if (!movie_file) {\r
-                       me_update_msg("Failed to open movie.");\r
-                       return 0;\r
+                       menu_update_msg("Failed to open movie.");\r
+                       goto out;\r
                }\r
                fseek(movie_file, 0, SEEK_END);\r
                movie_size = ftell(movie_file);\r
                fseek(movie_file, 0, SEEK_SET);\r
                if (movie_size < 64+3) {\r
-                       me_update_msg("Invalid GMV file.");\r
+                       menu_update_msg("Invalid GMV file.");\r
                        fclose(movie_file);\r
-                       return 0;\r
+                       goto out;\r
                }\r
                movie_data = malloc(movie_size);\r
                if (movie_data == NULL) {\r
-                       me_update_msg("low memory.");\r
+                       menu_update_msg("low memory.");\r
                        fclose(movie_file);\r
-                       return 0;\r
+                       goto out;\r
                }\r
                dummy = fread(movie_data, 1, movie_size, movie_file);\r
                fclose(movie_file);\r
                if (strncmp((char *)movie_data, "Gens Movie TEST", 15) != 0) {\r
-                       me_update_msg("Invalid GMV file.");\r
-                       return 0;\r
+                       menu_update_msg("Invalid GMV file.");\r
+                       goto out;\r
                }\r
                dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);\r
                if (!dummy) {\r
-                       me_update_msg("Could't find a ROM for movie.");\r
-                       return 0;\r
+                       menu_update_msg("Could't find a ROM for movie.");\r
+                       goto out;\r
                }\r
                get_ext(rom_fname, ext);\r
                lprintf("gmv loaded for %s\n", rom_fname);\r
@@ -542,20 +560,19 @@ int emu_reload_rom(char *rom_fname)
                PicoPatchLoad(rom_fname);\r
                dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);\r
                if (!dummy) {\r
-                       me_update_msg("Could't find a ROM to patch.");\r
-                       return 0;\r
+                       menu_update_msg("Could't find a ROM to patch.");\r
+                       goto out;\r
                }\r
                get_ext(rom_fname, ext);\r
        }\r
 \r
        media_type = detect_media(rom_fname);\r
        if (media_type == PM_BAD) {\r
-               me_update_msg("Not a ROM/CD img selected.");\r
-               return 0;\r
+               menu_update_msg("Not a ROM/CD img selected.");\r
+               goto out;\r
        }\r
 \r
        shutdown_MCD();\r
-       PicoPatchUnload();\r
        PicoCartUnload();\r
        rom_loaded = 0;\r
 \r
@@ -580,14 +597,14 @@ int emu_reload_rom(char *rom_fname)
                                        (cd_region == 8 ? "EU" : "JAP") : "USA");\r
                        }\r
                        if (!find_bios(cd_region, &used_rom_name))\r
-                               return 0;\r
+                               goto out;\r
 \r
                        get_ext(used_rom_name, ext);\r
                        PicoAHW |= PAHW_MCD;\r
                }\r
                else {\r
-                       me_update_msg("Invalid CD image");\r
-                       return 0;\r
+                       menu_update_msg("Invalid CD image");\r
+                       goto out;\r
                }\r
        }\r
        else if (media_type == PM_MARK3) {\r
@@ -597,20 +614,21 @@ int emu_reload_rom(char *rom_fname)
 \r
        rom = pm_open(used_rom_name);\r
        if (rom == NULL) {\r
-               me_update_msg("Failed to open ROM");\r
-               return 0;\r
+               menu_update_msg("Failed to open ROM");\r
+               goto out;\r
        }\r
 \r
        menu_romload_prepare(used_rom_name); // also CD load\r
+       menu_romload_started = 1;\r
        used_rom_name = NULL; // uses static_buff\r
 \r
        ret = PicoCartLoad(rom, &rom_data, &rom_size, (PicoAHW & PAHW_SMS) ? 1 : 0);\r
        pm_close(rom);\r
        if (ret != 0) {\r
-               if      (ret == 2) me_update_msg("Out of memory");\r
-               else if (ret == 3) me_update_msg("Read failed");\r
-               else               me_update_msg("PicoCartLoad() failed.");\r
-               goto fail;\r
+               if      (ret == 2) menu_update_msg("Out of memory");\r
+               else if (ret == 3) menu_update_msg("Read failed");\r
+               else               menu_update_msg("PicoCartLoad() failed.");\r
+               goto out;\r
        }\r
 \r
        // detect wrong files\r
@@ -625,8 +643,8 @@ int emu_reload_rom(char *rom_fname)
        }\r
 \r
        if (bad_rom) {\r
-               me_update_msg("Bad ROM detected.");\r
-               goto fail;\r
+               menu_update_msg("Bad ROM detected.");\r
+               goto out;\r
        }\r
 \r
        // load config for this ROM (do this before insert to get correct region)\r
@@ -639,8 +657,8 @@ int emu_reload_rom(char *rom_fname)
 \r
        emu_make_path(static_buff, "carthw.cfg", sizeof(static_buff));\r
        if (PicoCartInsert(rom_data, rom_size, static_buff)) {\r
-               me_update_msg("Failed to load ROM.");\r
-               goto fail;\r
+               menu_update_msg("Failed to load ROM.");\r
+               goto out;\r
        }\r
 \r
        // insert CD if it was detected\r
@@ -649,12 +667,13 @@ int emu_reload_rom(char *rom_fname)
                if (ret != 0) {\r
                        PicoCartUnload();\r
                        rom_data = NULL; // freed by unload\r
-                       me_update_msg("Insert_CD() failed, invalid CD image?");\r
-                       goto fail;\r
+                       menu_update_msg("Insert_CD() failed, invalid CD image?");\r
+                       goto out;\r
                }\r
        }\r
 \r
        menu_romload_end();\r
+       menu_romload_started = 0;\r
 \r
        if (PicoPatches) {\r
                PicoPatchPrepare();\r
@@ -694,13 +713,14 @@ int emu_reload_rom(char *rom_fname)
        if (currentConfig.EmuOpt & EOPT_EN_SRAM)\r
                emu_save_load_game(1, 1);\r
 \r
-       return 1;\r
-\r
-fail:\r
-       if (rom_data)\r
+       retval = 1;\r
+out:\r
+       if (retval == 0 && rom_data)\r
                free(rom_data);\r
-       menu_romload_end();\r
-       return 0;\r
+       if (menu_romload_started)\r
+               menu_romload_end();\r
+       free(rom_fname);\r
+       return retval;\r
 }\r
 \r
 int emu_swap_cd(const char *fname)\r
@@ -712,7 +732,7 @@ int emu_swap_cd(const char *fname)
        if (cd_type != CIT_NOT_CD)\r
                ret = Insert_CD(fname, cd_type);\r
        if (ret != 0) {\r
-               me_update_msg("Load failed, invalid CD image?");\r
+               menu_update_msg("Load failed, invalid CD image?");\r
                return 0;\r
        }\r
 \r
@@ -1008,7 +1028,7 @@ char *emu_get_save_fname(int load, int is_sram, int slot)
        return NULL;\r
 }\r
 \r
-int emu_check_save_file(int slot)\r
+int emu_check_save_file(int slot, int *time)\r
 {\r
        return emu_get_save_fname(1, 0, slot) ? 1 : 0;\r
 }\r
@@ -1137,8 +1157,11 @@ static void emu_tray_close(void)
 \r
 void emu_32x_startup(void)\r
 {\r
-       plat_video_toggle_renderer(0, 0);\r
+       plat_video_toggle_renderer(0, 0); // HACK\r
        system_announce();\r
+\r
+       // force mode change event\r
+       rendstatus_old = -1;\r
 }\r
 \r
 void emu_reset_game(void)\r
@@ -1232,7 +1255,7 @@ static void run_events_ui(unsigned int which)
        if (which & (PEV_STATE_LOAD|PEV_STATE_SAVE))\r
        {\r
                int do_it = 1;\r
-               if ( emu_check_save_file(state_slot) &&\r
+               if ( emu_check_save_file(state_slot, NULL) &&\r
                        (((which & PEV_STATE_LOAD) && (currentConfig.confirm_save & EOPT_CONFIRM_LOAD)) ||\r
                         ((which & PEV_STATE_SAVE) && (currentConfig.confirm_save & EOPT_CONFIRM_SAVE))) )\r
                {\r
@@ -1250,16 +1273,16 @@ static void run_events_ui(unsigned int which)
 \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
+                       in_set_config_int(0, IN_CFG_BLOCKING, 1);\r
+                       while (in_menu_wait_any(NULL, 50) & (PBTN_MA3|PBTN_MBACK))\r
                                ;\r
-                       while ( !((keys = in_menu_wait_any(50)) & (PBTN_MA3|PBTN_MBACK)) )\r
+                       while ( !((keys = in_menu_wait_any(NULL, 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
+                       while (in_menu_wait_any(NULL, 50) & (PBTN_MA3|PBTN_MBACK))\r
                                ;\r
-                       in_set_blocking(0);\r
+                       in_set_config_int(0, IN_CFG_BLOCKING, 0);\r
                }\r
                if (do_it) {\r
                        plat_status_msg_busy_first((which & PEV_STATE_LOAD) ? "LOADING STATE" : "SAVING STATE");\r
@@ -1285,7 +1308,7 @@ static void run_events_ui(unsigned int which)
                }\r
 \r
                emu_status_msg("SAVE SLOT %i [%s]", state_slot,\r
-                       emu_check_save_file(state_slot) ? "USED" : "FREE");\r
+                       emu_check_save_file(state_slot, NULL) ? "USED" : "FREE");\r
        }\r
        if (which & PEV_MENU)\r
                engineState = PGS_Menu;\r
@@ -1344,6 +1367,27 @@ static void mkdir_path(char *path_with_reserve, int pos, const char *name)
                lprintf("failed to create: %s\n", path_with_reserve);\r
 }\r
 \r
+void emu_cmn_forced_frame(int no_scale, int do_emu)\r
+{\r
+       int po_old = PicoOpt;\r
+\r
+       memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4);\r
+\r
+       PicoOpt &= ~POPT_ALT_RENDERER;\r
+       PicoOpt |= POPT_ACC_SPRITES;\r
+       if (!no_scale)\r
+               PicoOpt |= POPT_EN_SOFTSCALE;\r
+\r
+       PicoDrawSetOutFormat(PDF_RGB555, 1);\r
+       Pico.m.dirtyPal = 1;\r
+       if (do_emu)\r
+               PicoFrame();\r
+       else\r
+               PicoFrameDrawOnly();\r
+\r
+       PicoOpt = po_old;\r
+}\r
+\r
 void emu_init(void)\r
 {\r
        char path[512];\r
@@ -1377,6 +1421,8 @@ void emu_init(void)
        PicoMessage = plat_status_msg_busy_next;\r
        PicoMCDopenTray = emu_tray_open;\r
        PicoMCDcloseTray = emu_tray_close;\r
+\r
+       sndout_init();\r
 }\r
 \r
 void emu_finish(void)\r
@@ -1399,6 +1445,65 @@ void emu_finish(void)
        pprof_finish();\r
 \r
        PicoExit();\r
+       sndout_exit();\r
+}\r
+\r
+static void snd_write_nonblocking(int len)\r
+{\r
+       sndout_write_nb(PsndOut, len);\r
+}\r
+\r
+void emu_sound_start(void)\r
+{\r
+       PsndOut = NULL;\r
+\r
+       if (currentConfig.EmuOpt & EOPT_EN_SOUND)\r
+       {\r
+               int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;\r
+\r
+               PsndRerate(Pico.m.frame_count ? 1 : 0);\r
+\r
+               printf("starting audio: %i len: %i stereo: %i, pal: %i\n",\r
+                       PsndRate, PsndLen, is_stereo, Pico.m.pal);\r
+               sndout_start(PsndRate, is_stereo);\r
+               PicoWriteSound = snd_write_nonblocking;\r
+               plat_update_volume(0, 0);\r
+               memset(sndBuffer, 0, sizeof(sndBuffer));\r
+               PsndOut = sndBuffer;\r
+       }\r
+}\r
+\r
+void emu_sound_stop(void)\r
+{\r
+       sndout_stop();\r
+}\r
+\r
+void emu_sound_wait(void)\r
+{\r
+       sndout_wait();\r
+}\r
+\r
+static void emu_loop_prep(void)\r
+{\r
+       static int pal_old = -1;\r
+       static int filter_old = -1;\r
+\r
+       if (currentConfig.CPUclock != plat_target_cpu_clock_get())\r
+               plat_target_cpu_clock_set(currentConfig.CPUclock);\r
+\r
+       if (Pico.m.pal != pal_old) {\r
+               plat_target_lcdrate_set(Pico.m.pal);\r
+               pal_old = Pico.m.pal;\r
+       }\r
+\r
+       if (currentConfig.filter != filter_old) {\r
+               plat_target_hwfilter_set(currentConfig.filter);\r
+               filter_old = currentConfig.filter;\r
+       }\r
+\r
+       plat_target_gamma_set(currentConfig.gamma, 0);\r
+\r
+       pemu_loop_prep();\r
 }\r
 \r
 static void skip_frame(int do_audio)\r
@@ -1428,6 +1533,16 @@ void emu_loop(void)
        Pico.m.dirtyPal = 1;\r
        rendstatus_old = -1;\r
 \r
+       PicoLoopPrepare();\r
+\r
+       // prepare CD buffer\r
+       if (PicoAHW & PAHW_MCD)\r
+               PicoCDBufferInit();\r
+\r
+       plat_video_loop_prepare();\r
+       emu_loop_prep();\r
+       pemu_sound_start();\r
+\r
        /* number of ticks per frame */\r
        if (Pico.m.pal) {\r
                target_fps = 50;\r
@@ -1437,13 +1552,6 @@ void emu_loop(void)
                target_frametime = ms_to_ticks(1000) / 60 + 1;\r
        }\r
 \r
-       // prepare CD buffer\r
-       if (PicoAHW & PAHW_MCD)\r
-               PicoCDBufferInit();\r
-       PicoLoopPrepare();\r
-\r
-       pemu_loop_prep();\r
-\r
        timestamp_fps = get_ticks();\r
        reset_timing = 1;\r
 \r
@@ -1598,6 +1706,7 @@ void emu_loop(void)
        }\r
 \r
        pemu_loop_end();\r
+       emu_sound_stop();\r
 \r
        // pemu_loop_end() might want to do 1 frame for bg image,\r
        // so free CD buffer here\r