diff --git a/core/cfg/cfg.cpp b/core/cfg/cfg.cpp index 84aa405c1..1d221ea8d 100644 --- a/core/cfg/cfg.cpp +++ b/core/cfg/cfg.cpp @@ -21,7 +21,7 @@ void savecfgf() FILE* cfgfile = fopen(cfgPath.c_str(),"wt"); if (!cfgfile) { - printf("Error : Unable to open file for saving \n"); + printf("Error: Unable to open file '%s' for saving\n", cfgPath.c_str()); } else { @@ -76,6 +76,10 @@ void cfgSaveStr(const wchar * Section, const wchar * Key, const wchar * String) bool cfgOpen() { + if (get_writable_config_path("").empty()) + // Config dir not set (android onboarding) + return false; + const char* filename = "/emu.cfg"; string config_path_read = get_readonly_config_path(filename); cfgPath = get_writable_config_path(filename); diff --git a/core/hw/naomi/naomi_cart.cpp b/core/hw/naomi/naomi_cart.cpp index 270351490..fcb90ee38 100644 --- a/core/hw/naomi/naomi_cart.cpp +++ b/core/hw/naomi/naomi_cart.cpp @@ -461,6 +461,9 @@ bool naomi_cart_LoadRom(char* file) if (RomCacheMap) { + for (int i = 0; i < RomCacheMapCount; i++) + if (RomCacheMap[i] != INVALID_FD) + close(RomCacheMap[i]); RomCacheMapCount = 0; delete[] RomCacheMap; } diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index f4221d417..8bea55896 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -270,6 +270,8 @@ bool rend_single_frame() //wait render start only if no frame pending do { + // FIXME not here + os_DoEvents(); #if !defined(TARGET_NO_THREADS) if (gui_is_open()) { @@ -285,12 +287,8 @@ bool rend_single_frame() if (renderer != NULL) renderer->RenderLastFrame(); -#if defined(_ANDROID) if (!rs.Wait(100)) return false; -#else - rs.Wait(); -#endif } #else if (gui_is_open()) @@ -378,6 +376,7 @@ void rend_term_renderer() delete fallback_renderer; fallback_renderer = NULL; } + tactx_Term(); } void* rend_thread(void* p) @@ -386,33 +385,6 @@ void* rend_thread(void* p) install_prof_handler(1); #endif - #if SET_AFNT - cpu_set_t mask; - - /* CPU_ZERO initializes all the bits in the mask to zero. */ - - CPU_ZERO( &mask ); - - - - /* CPU_SET sets only the bit corresponding to cpu. */ - - CPU_SET( 1, &mask ); - - - - /* sched_setaffinity returns 0 in success */ - - if( sched_setaffinity( 0, sizeof(mask), &mask ) == -1 ) - - { - - printf("WARNING: Could not set CPU Affinity, continuing...\n"); - - } - #endif - - rend_init_renderer(); //we don't know if this is true, so let's not speculate here @@ -436,10 +408,6 @@ void* rend_thread(void* p) return NULL; } -#if !defined(TARGET_NO_THREADS) -cThread rthd(rend_thread,0); -#endif - bool pend_rend = false; void rend_resize(int width, int height) { @@ -570,79 +538,9 @@ void rend_end_render() } } -/* -void rend_end_wait() -{ - #if HOST_OS!=OS_WINDOWS && !defined(_ANDROID) - // if (!re.state) printf("Render End: Waiting ...\n"); - #endif - re.Wait(); - pvrrc.InUse=false; -} -*/ - -bool rend_init() -{ - rend_create_renderer(); - -#if !defined(_ANDROID) && HOST_OS != OS_DARWIN - #if !defined(TARGET_NO_THREADS) - rthd.Start(); - #else - rend_init_renderer(); - - renderer->Resize(640, 480); - #endif -#endif - -#if SET_AFNT - cpu_set_t mask; - - - - /* CPU_ZERO initializes all the bits in the mask to zero. */ - - CPU_ZERO( &mask ); - - - - /* CPU_SET sets only the bit corresponding to cpu. */ - - CPU_SET( 0, &mask ); - - - - /* sched_setaffinity returns 0 in success */ - - if( sched_setaffinity( 0, sizeof(mask), &mask ) == -1 ) - - { - - printf("WARNING: Could not set CPU Affinity, continuing...\n"); - - } -#endif - - return true; -} - -void rend_term() +void rend_stop_renderer() { renderer_enabled = false; -#if !defined(TARGET_NO_THREADS) - rs.Set(); -#endif - - if (fCheckFrames) - fclose(fCheckFrames); - - if (fLogFrames) - fclose(fLogFrames); - -#if !defined(TARGET_NO_THREADS) - rthd.WaitToEnd(); -#endif - tactx_Term(); } void rend_vblank() @@ -656,8 +554,6 @@ void rend_vblank() } render_called = false; check_framebuffer_write(); - - os_DoEvents(); } void check_framebuffer_write() diff --git a/core/hw/pvr/Renderer_if.h b/core/hw/pvr/Renderer_if.h index 833e94d5b..3625a2159 100644 --- a/core/hw/pvr/Renderer_if.h +++ b/core/hw/pvr/Renderer_if.h @@ -5,14 +5,14 @@ extern u32 VertexCount; extern u32 FrameCount; -bool rend_init(); -void rend_term(); - +void rend_init_renderer(); +void rend_term_renderer(); +void rend_stop_renderer(); void rend_vblank(); void rend_start_render(); void rend_end_render(); -void rend_end_wait(); void rend_cancel_emu_wait(); +bool rend_single_frame(); void rend_set_fb_scale(float x,float y); void rend_resize(int width, int height); diff --git a/core/hw/pvr/drkPvr.cpp b/core/hw/pvr/drkPvr.cpp index d372c910c..0e809b974 100644 --- a/core/hw/pvr/drkPvr.cpp +++ b/core/hw/pvr/drkPvr.cpp @@ -28,7 +28,6 @@ void libPvr_Reset(bool Manual) { Regs_Reset(Manual); spg_Reset(Manual); - //rend_reset(); //*TODO* wtf ? } s32 libPvr_Init() @@ -38,11 +37,6 @@ s32 libPvr_Init() //failed return rv_error; } - if (!rend_init()) - { - //failed - return rv_error; - } return rv_ok; } @@ -50,6 +44,5 @@ s32 libPvr_Init() //called when exiting from sh4 thread , from the new thread context (for any thread specific de init) :P void libPvr_Term() { - rend_term(); spg_Term(); -} \ No newline at end of file +} diff --git a/core/hw/pvr/ta_ctx.cpp b/core/hw/pvr/ta_ctx.cpp index a858fdf21..781d82aa4 100644 --- a/core/hw/pvr/ta_ctx.cpp +++ b/core/hw/pvr/ta_ctx.cpp @@ -300,6 +300,7 @@ void tactx_Term() ctx_list[i]->Free(); delete ctx_list[i]; } + ctx_list.clear(); mtx_pool.Lock(); { for (size_t i = 0; i < ctx_pool.size(); i++) @@ -308,5 +309,6 @@ void tactx_Term() delete ctx_pool[i]; } } + ctx_pool.clear(); mtx_pool.Unlock(); } diff --git a/core/hw/sh4/interpr/sh4_interpreter.cpp b/core/hw/sh4/interpr/sh4_interpreter.cpp index 83358ae71..4cfee87d2 100644 --- a/core/hw/sh4/interpr/sh4_interpreter.cpp +++ b/core/hw/sh4/interpr/sh4_interpreter.cpp @@ -195,8 +195,8 @@ void ExecuteDelayslot_RTE() #define AICA_SAMPLE_GCM 441 #define AICA_SAMPLE_CYCLES (SH4_MAIN_CLOCK/(44100/AICA_SAMPLE_GCM)*32) -int aica_schid; -int rtc_schid; +int aica_schid = -1; +int rtc_schid = -1; //14336 Cycles @@ -281,11 +281,14 @@ void Sh4_int_Init() { verify(sizeof(Sh4cntx)==448); - aica_schid=sh4_sched_register(0,&AicaUpdate); - sh4_sched_request(aica_schid,AICA_TICK); + if (aica_schid == -1) + { + aica_schid=sh4_sched_register(0,&AicaUpdate); + sh4_sched_request(aica_schid,AICA_TICK); - rtc_schid=sh4_sched_register(0,&DreamcastSecond); - sh4_sched_request(rtc_schid,SH4_MAIN_CLOCK); + rtc_schid=sh4_sched_register(0,&DreamcastSecond); + sh4_sched_request(rtc_schid,SH4_MAIN_CLOCK); + } memset(&p_sh4rcb->cntx, 0, sizeof(p_sh4rcb->cntx)); } diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index 1e15cdb5a..996159c4d 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -21,7 +21,7 @@ #include "gamepad_device.h" #include "rend/gui.h" -extern void dc_stop(); +extern void dc_exit(); extern u16 kcode[4]; extern u8 rt[4], lt[4]; @@ -56,7 +56,7 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed) { case EMU_BTN_ESCAPE: if (pressed) - dc_stop(); + dc_exit(); break; case EMU_BTN_MENU: if (pressed) diff --git a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp index eeedb540c..24e8dff7d 100644 --- a/core/linux-dist/main.cpp +++ b/core/linux-dist/main.cpp @@ -179,9 +179,9 @@ void os_CreateWindow() } void common_linux_setup(); -int dc_init(int argc,wchar* argv[]); -void dc_run(); +int reicast_init(int argc, char* argv[]); void dc_term(); +void* rend_thread(void* p); #ifdef TARGET_PANDORA void gl_term(); @@ -391,14 +391,14 @@ int main(int argc, wchar* argv[]) settings.profile.run_counts=0; - if (dc_init(argc,argv)) + if (reicast_init(argc, argv)) die("Reicast initialization failed\n"); #if !defined(TARGET_EMSCRIPTEN) #if FEAT_HAS_NIXPROF install_prof_handler(0); #endif - dc_run(); + rend_thread(NULL); #else emscripten_set_main_loop(&dc_run, 100, false); #endif diff --git a/core/linux-dist/x11.cpp b/core/linux-dist/x11.cpp index febb8fd35..da977e6b3 100644 --- a/core/linux-dist/x11.cpp +++ b/core/linux-dist/x11.cpp @@ -86,7 +86,7 @@ extern bool dump_frame_switch; extern bool naomi_test_button; extern bool coin_chute; -void dc_stop(void); +void dc_exit(void); enum { @@ -122,7 +122,7 @@ void event_x11_handle() if (event.type == ClientMessage && event.xclient.data.l[0] == wmDeleteMessage) - dc_stop(); + dc_exit(); else if (event.type == ConfigureNotify) { x11_width = event.xconfigure.width; diff --git a/core/nullDC.cpp b/core/nullDC.cpp index 718a5a7aa..5d6979951 100755 --- a/core/nullDC.cpp +++ b/core/nullDC.cpp @@ -13,7 +13,6 @@ #include "hw/maple/maple_cfg.h" #include "hw/sh4/sh4_mem.h" -#include "webui/server.h" #include "hw/naomi/naomi_cart.h" #include "reios/reios.h" #include "hw/sh4/sh4_sched.h" @@ -21,10 +20,12 @@ #include "hw/pvr/spg.h" #include "hw/aica/dsp.h" #include "imgread/common.h" +#include "rend/gui.h" void FlushCache(); void LoadCustom(); -void dc_resume_emu(bool continue_running); +void* dc_run(void*); +void dc_resume(); settings_t settings; // Set if game has corresponding option by default, so that it's not saved in the config @@ -33,26 +34,7 @@ static bool safemode_game; static bool tr_poly_depth_mask_game; static bool extra_depth_game; -static bool continue_running = false; -static cMutex mtx_mainloop ; -static cResetEvent resume_mainloop(false, true); - -/* - libndc - - //initialise (and parse the command line) - ndc_init(argc,argv); - - ... - //run a dreamcast slice - //either a frame, or up to 25 ms of emulation - //returns 1 if the frame is ready (fb needs to be flipped -- i'm looking at you android) - ndc_step(); - - ... - //terminate (and free everything) - ndc_term() -*/ +cThread emu_thread(&dc_run, NULL); #if HOST_OS==OS_WINDOWS #include @@ -133,14 +115,14 @@ s32 plugins_Init() if (s32 rv = libPvr_Init()) return rv; - #ifndef TARGET_DISPFRAME +#ifndef TARGET_DISPFRAME if (s32 rv = libGDR_Init()) return rv; - #endif - #if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE +#endif +#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE if (!naomi_cart_SelectFile(libPvr_GetRenderTarget())) return rv_serror; - #endif +#endif if (s32 rv = libAICA_Init()) return rv; @@ -148,18 +130,12 @@ s32 plugins_Init() if (s32 rv = libARM_Init()) return rv; - //if (s32 rv = libExtDevice_Init()) - // return rv; - - - return rv_ok; } void plugins_Term() { //term all plugins - //libExtDevice_Term(); libARM_Term(); libAICA_Term(); libGDR_Term(); @@ -168,6 +144,7 @@ void plugins_Term() void plugins_Reset(bool Manual) { + reios_reset(); libPvr_Reset(Manual); libGDR_Reset(Manual); libAICA_Reset(Manual); @@ -175,17 +152,6 @@ void plugins_Reset(bool Manual) //libExtDevice_Reset(Manual); } -#if !defined(TARGET_NO_WEBUI) && !defined(TARGET_NO_THREADS) - -void* webui_th(void* p) -{ - webui_start(); - return 0; -} - -cThread webui_thd(&webui_th,0); -#endif - void LoadSpecialSettings() { #if DC_PLATFORM == DC_PLATFORM_DREAMCAST @@ -308,48 +274,60 @@ void dc_reset() static bool init_done; -int dc_init(int argc,wchar* argv[]) +int reicast_init(int argc, char* argv[]) { - setbuf(stdin,0); - setbuf(stdout,0); - setbuf(stderr,0); - if (init_done) - { - if(ParseCommandLine(argc,argv)) - { - return 69; - } - InitSettings(); - LoadSettings(false); - if (DiscSwap()) - LoadCustom(); - dc_reset(); - - return 0; - } if (!_vmem_reserve()) { printf("Failed to alloc mem\n"); return -1; } - -#if !defined(TARGET_NO_WEBUI) && !defined(TARGET_NO_THREADS) - webui_thd.Start(); -#endif - - if(ParseCommandLine(argc,argv)) + if (ParseCommandLine(argc, argv)) { return 69; } - if(!cfgOpen()) - { - msgboxf("Unable to open config file",MBX_ICONERROR); - return -4; - } InitSettings(); - LoadSettings(false); + if (!cfgOpen()) + { + printf("Config directory is not set. Starting onboarding\n"); + gui_open_onboarding(); + } + else + LoadSettings(false); os_CreateWindow(); + os_SetupInput(); + + // Needed to avoid crash calling dc_is_running() in gui + Get_Sh4Interpreter(&sh4_cpu); + sh4_cpu.Init(); + + return 0; +} + +bool game_started; + +int dc_start_game(const char *path) +{ + cfgSetVirtual("config", "image", path); + + if (init_done) + { + InitSettings(); + LoadSettings(false); +#if DC_PLATFORM == DC_PLATFORM_DREAMCAST + if (DiscSwap()) + LoadCustom(); +#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE + if (!naomi_cart_SelectFile(libPvr_GetRenderTarget())) + return rv_serror; +#endif + dc_reset(); + + game_started = true; + dc_resume(); + + return 0; + } #if HOST_OS != OS_DARWIN #define DATA_PATH "/data/" @@ -357,6 +335,7 @@ int dc_init(int argc,wchar* argv[]) #define DATA_PATH "/" #endif + settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH))) { #ifdef USE_REIOS @@ -375,9 +354,7 @@ int dc_init(int argc,wchar* argv[]) } if (plugins_Init()) - { return -3; - } LoadCustom(); @@ -392,20 +369,14 @@ int dc_init(int argc,wchar* argv[]) #endif { Get_Sh4Interpreter(&sh4_cpu); -#if FEAT_SHREC == DYNAREC_NONE sh4_cpu.Init(); -#endif printf("Using Interpreter\n"); } - InitAudio(); - mem_Init(); mem_map_default(); - os_SetupInput(); - #if DC_PLATFORM == DC_PLATFORM_NAOMI mcfg_CreateNAOMIJamma(); #elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE @@ -415,6 +386,9 @@ int dc_init(int argc,wchar* argv[]) dc_reset(); + game_started = true; + dc_resume(); + return 0; } @@ -424,46 +398,26 @@ bool dc_is_running() } #ifndef TARGET_DISPFRAME -void dc_run() +void* dc_run(void*) { - resume_mainloop.Set(); + InitAudio(); - while ( true ) - { - bool dynarec_enabled = settings.dynarec.Enable; - continue_running = false ; - mtx_mainloop.Lock() ; - sh4_cpu.Run(); - mtx_mainloop.Unlock() ; + if (settings.dynarec.Enable) + { + Get_Sh4Recompiler(&sh4_cpu); + printf("Using Recompiler\n"); + } + else + { + Get_Sh4Interpreter(&sh4_cpu); + printf("Using Interpreter\n"); + } + sh4_cpu.Run(); -#ifdef _WIN32 - // Avoid the looping audio when the emulator is paused - TermAudio(); -#endif - while (!resume_mainloop.Wait(20)) - os_DoEvents(); - resume_mainloop.Set(); + SaveRomFiles(get_writable_data_path("/data/")); + TermAudio(); - if (dynarec_enabled != settings.dynarec.Enable) - { - if (settings.dynarec.Enable) - { - Get_Sh4Recompiler(&sh4_cpu); - printf("Using Recompiler\n"); - } - else - { - Get_Sh4Interpreter(&sh4_cpu); - printf("Using Interpreter\n"); - } - sh4_cpu.ResetCache(); - } - if (!continue_running) - break ; -#ifdef _WIN32 - InitAudio(); -#endif - } + return NULL; } #endif @@ -476,36 +430,19 @@ void dc_term() mcfg_DestroyDevices(); SaveSettings(); - SaveRomFiles(get_writable_data_path("/data/")); - - TermAudio(); - -#if !defined(TARGET_NO_WEBUI) && !defined(TARGET_NO_THREADS) - extern void sighandler(int sig); - sighandler(0); - webui_thd.WaitToEnd(); -#endif - } -#if defined(_ANDROID) -void dc_pause() -{ - SaveRomFiles(get_writable_data_path("/data/")); -} -#endif - void dc_stop() { - if (sh4_cpu.IsCpuRunning()) - sh4_cpu.Stop(); - else - dc_resume_emu(false); + sh4_cpu.Stop(); + rend_cancel_emu_wait(); + emu_thread.WaitToEnd(); } -void dc_start() +void dc_exit() { - sh4_cpu.Start(); + dc_stop(); + rend_stop_renderer(); } void InitSettings() @@ -659,6 +596,23 @@ void LoadSettings(bool game_specific) settings.omx.Audio_HDMI = cfgLoadBool(game_specific ? cfgGetGameId() : "omx", "audio_hdmi", settings.omx.Audio_HDMI); #endif + if (!game_specific) + { + settings.dreamcast.ContentPath.clear(); + std::string paths = cfgLoadStr(config_section, "Dreamcast.ContentPath", ""); + std::string::size_type start = 0; + while (true) + { + std::string::size_type end = paths.find(';', start); + if (end == std::string::npos) + end = paths.size(); + if (start != end) + settings.dreamcast.ContentPath.push_back(paths.substr(start, end - start)); + if (end == paths.size()) + break; + start = end + 1; + } + } /* //make sure values are valid settings.dreamcast.cable = min(max(settings.dreamcast.cable, 0),3); @@ -734,74 +688,24 @@ void SaveSettings() sprintf(device_name, "device%d.2", i + 1); cfgSaveInt("input", device_name, (s32)settings.input.maple_expansion_devices[i][1]); } - -} - -static bool wait_until_dc_running() -{ - int64_t start_time = get_time_usec() ; - const int64_t FIVE_SECONDS = 5*1000000 ; - while(!dc_is_running()) + // FIXME This should never be a game-specific setting + std::string paths; + for (auto path : settings.dreamcast.ContentPath) { - if ( start_time+FIVE_SECONDS < get_time_usec() ) - { - //timeout elapsed - dc not getting a chance to run - just bail - return false ; - } + if (!paths.empty()) + paths += ";"; + paths += path; } - return true ; -} - -static bool acquire_mainloop_lock() -{ - bool result = false ; - int64_t start_time = get_time_usec() ; - const int64_t FIVE_SECONDS = 5*1000000 ; - - while ( ( start_time+FIVE_SECONDS > get_time_usec() ) && !(result = mtx_mainloop.TryLock()) ) - { - rend_cancel_emu_wait() ; - } - - return result ; -} - -bool dc_pause_emu() -{ - if (sh4_cpu.IsCpuRunning()) - { -#ifndef TARGET_NO_THREADS - if (!wait_until_dc_running()) { - printf("Can't open settings - dc loop kept running\n"); - return false; - } - resume_mainloop.Reset(); - - dc_stop(); - - if (!acquire_mainloop_lock()) - { - printf("Can't open settings - could not acquire main loop lock\n"); - continue_running = true; - resume_mainloop.Set(); - return false; - } -#else - dc_stop(); + cfgSaveStr("config", "Dreamcast.ContentPath", paths.c_str()); +#ifdef _ANDROID + void SaveAndroidSettings(); + SaveAndroidSettings(); #endif - } - return true; } -void dc_resume_emu(bool continue_running) +void dc_resume() { - if (!sh4_cpu.IsCpuRunning()) - { - ::continue_running = continue_running; - rend_cancel_emu_wait(); - resume_mainloop.Set(); - mtx_mainloop.Unlock(); - } + emu_thread.Start(); } static void cleanup_serialize(void *data) @@ -809,7 +713,7 @@ static void cleanup_serialize(void *data) if ( data != NULL ) free(data) ; - dc_resume_emu(true); + dc_resume(); } static string get_savestate_file_path() @@ -825,7 +729,7 @@ static string get_savestate_file_path() return get_writable_data_path("/data/") + state_file; } -static void* dc_savestate_thread(void* p) +void dc_savestate() { string filename; unsigned int total_size = 0 ; @@ -833,14 +737,13 @@ static void* dc_savestate_thread(void* p) void *data_ptr = NULL ; FILE *f ; - if (!dc_pause_emu()) - return NULL; + dc_stop(); if ( ! dc_serialize(&data, &total_size) ) { printf("Failed to save state - could not initialize total size\n") ; cleanup_serialize(data) ; - return NULL; + return; } data = malloc(total_size) ; @@ -848,7 +751,7 @@ static void* dc_savestate_thread(void* p) { printf("Failed to save state - could not malloc %d bytes", total_size) ; cleanup_serialize(data) ; - return NULL; + return; } data_ptr = data ; @@ -857,7 +760,7 @@ static void* dc_savestate_thread(void* p) { printf("Failed to save state - could not serialize data\n") ; cleanup_serialize(data) ; - return NULL; + return; } filename = get_savestate_file_path(); @@ -867,7 +770,7 @@ static void* dc_savestate_thread(void* p) { printf("Failed to save state - could not open %s for writing\n", filename.c_str()) ; cleanup_serialize(data) ; - return NULL; + return; } fwrite(data, 1, total_size, f) ; @@ -875,11 +778,9 @@ static void* dc_savestate_thread(void* p) cleanup_serialize(data) ; printf("Saved state to %s\n size %d", filename.c_str(), total_size) ; - - return NULL; } -static void* dc_loadstate_thread(void* p) +void dc_loadstate() { string filename; unsigned int total_size = 0 ; @@ -887,8 +788,7 @@ static void* dc_loadstate_thread(void* p) void *data_ptr = NULL ; FILE *f ; - if (!dc_pause_emu()) - return NULL; + dc_stop(); filename = get_savestate_file_path(); f = fopen(filename.c_str(), "rb") ; @@ -897,7 +797,7 @@ static void* dc_loadstate_thread(void* p) { printf("Failed to load state - could not open %s for reading\n", filename.c_str()) ; cleanup_serialize(data) ; - return NULL; + return; } fseek(f, 0, SEEK_END); total_size = ftell(f); @@ -907,7 +807,7 @@ static void* dc_loadstate_thread(void* p) { printf("Failed to load state - could not malloc %d bytes", total_size) ; cleanup_serialize(data) ; - return NULL; + return; } fread(data, 1, total_size, f) ; @@ -925,7 +825,7 @@ static void* dc_loadstate_thread(void* p) { printf("Failed to load state - could not unserialize data\n") ; cleanup_serialize(data) ; - return NULL; + return; } dsp.dyndirty = true; @@ -934,19 +834,4 @@ static void* dc_loadstate_thread(void* p) cleanup_serialize(data) ; printf("Loaded state from %s size %d\n", filename.c_str(), total_size) ; - - return NULL; -} - - -void dc_savestate() -{ - cThread thd(dc_savestate_thread,0); - thd.Start() ; -} - -void dc_loadstate() -{ - cThread thd(dc_loadstate_thread,0); - thd.Start() ; } diff --git a/core/reios/reios.cpp b/core/reios/reios.cpp index a0783af3e..397efc7b9 100644 --- a/core/reios/reios.cpp +++ b/core/reios/reios.cpp @@ -689,7 +689,7 @@ bool reios_init(u8* rom, u8* flash) { } void reios_reset() { - + pre_init = false; } void reios_term() { diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 398f38f0d..48c9f0b15 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -16,7 +16,10 @@ You should have received a copy of the GNU General Public License along with reicast. If not, see . */ +#include #include +#include +#include #include "oslib/oslib.h" #include "cfg/cfg.h" @@ -26,14 +29,18 @@ #include "imgui/roboto_medium.h" #include "gles/gles.h" #include "input/gamepad_device.h" +#include "input/keyboard_device.h" #include "linux-dist/main.h" // FIXME for kcode[] +#include "gui_util.h" -extern bool dc_pause_emu(); -extern void dc_resume_emu(bool continue_running); extern void dc_loadstate(); extern void dc_savestate(); +extern void dc_stop(); extern void dc_reset(); +extern void dc_resume(); +extern int dc_start_game(const char *path); extern void UpdateInputState(u32 port); +extern bool game_started; extern int screen_width, screen_height; extern u8 kb_shift; // shift keys pressed (bitmask) @@ -41,13 +48,16 @@ extern u8 kb_key[6]; // normal keys pressed extern s32 mo_x_abs; extern s32 mo_y_abs; extern u32 mo_buttons; +extern f32 mo_x_delta; +extern f32 mo_y_delta; +extern f32 mo_wheel_delta; extern bool renderer_changed; int screen_dpi = 96; static bool inited = false; static float scaling = 1; -static enum { Closed, Commands, Settings, ClosedNoResume } gui_state; +static enum { Closed, Commands, Settings, ClosedNoResume, Main, Onboarding } gui_state = Main; static bool settings_opening; static bool touch_up; @@ -172,6 +182,14 @@ static void ImGui_Impl_NewFrame() touch_up = true; } #endif + if (io.WantCaptureMouse) + { + io.MouseWheel = -mo_wheel_delta / 16; + // Reset all relative mouse positions + mo_x_delta = 0; + mo_y_delta = 0; + mo_wheel_delta = 0; + } io.MouseDown[0] = (mo_buttons & (1 << 2)) == 0; io.MouseDown[1] = (mo_buttons & (1 << 1)) == 0; io.MouseDown[2] = (mo_buttons & (1 << 3)) == 0; @@ -180,7 +198,7 @@ static void ImGui_Impl_NewFrame() io.NavInputs[ImGuiNavInput_Activate] = (kcode[0] & DC_BTN_A) == 0; io.NavInputs[ImGuiNavInput_Cancel] = (kcode[0] & DC_BTN_B) == 0; io.NavInputs[ImGuiNavInput_Input] = (kcode[0] & DC_BTN_X) == 0; - io.NavInputs[ImGuiNavInput_Menu] = (kcode[0] & DC_BTN_Y) == 0; + //io.NavInputs[ImGuiNavInput_Menu] = (kcode[0] & DC_BTN_Y) == 0; io.NavInputs[ImGuiNavInput_DpadLeft] = (kcode[0] & DC_DPAD_LEFT) == 0; io.NavInputs[ImGuiNavInput_DpadRight] = (kcode[0] & DC_DPAD_RIGHT) == 0; io.NavInputs[ImGuiNavInput_DpadUp] = (kcode[0] & DC_DPAD_UP) == 0; @@ -197,6 +215,13 @@ static void ImGui_Impl_NewFrame() io.NavInputs[ImGuiNavInput_LStickDown] = joyy[0] > 0 ? (float)joyy[0] / 128.f : 0.f; if (io.NavInputs[ImGuiNavInput_LStickDown] < 0.1f) io.NavInputs[ImGuiNavInput_LStickDown] = 0.f; + + if (KeyboardDevice::GetInstance() != NULL) + { + std:string input_text = KeyboardDevice::GetInstance()->get_character_input(); + if (io.WantCaptureKeyboard) + io.AddInputCharactersUTF8(input_text.c_str()); + } } static double last_render; @@ -256,11 +281,7 @@ bool gui_is_open() static void gui_display_commands() { - if (!dc_pause_emu()) - { - gui_state = Closed; - return; - } + dc_stop(); ImGui_Impl_NewFrame(); ImGui::NewFrame(); @@ -305,8 +326,9 @@ static void gui_display_commands() ImGui::NextColumn(); if (ImGui::Button("Exit", ImVec2(150 * scaling, 50 * scaling))) { - dc_resume_emu(false); - gui_state = ClosedNoResume; + // Exit to main menu + gui_state = Main; + game_started = false; } ImGui::End(); @@ -538,6 +560,18 @@ static void controller_mapping_popup(std::shared_ptr gamepad) } ImGui::PopStyleVar(); } + +static bool game_list_done; // Set to false to refresh the game list + +void directory_selected_callback(bool cancelled, std::string selection) +{ + if (!cancelled) + { + settings.dreamcast.ContentPath.push_back(selection); + game_list_done = false; + } +} + static void gui_display_settings() { ImGui_Impl_NewFrame(); @@ -558,7 +592,10 @@ static void gui_display_settings() if (ImGui::Button("Done", ImVec2(100 * scaling, 30 * scaling))) { - gui_state = Commands; + if (game_started) + gui_state = Commands; + else + gui_state = Main; #if DC_PLATFORM == DC_PLATFORM_DREAMCAST // TODO only if changed? sleep time on emu thread? mcfg_DestroyDevices(); @@ -566,23 +603,26 @@ static void gui_display_settings() #endif SaveSettings(); } - ImGui::SameLine(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(16 * scaling, normal_padding.y)); - if (cfgHasGameSpecificConfig()) - { - if (ImGui::Button("Delete Game Config", ImVec2(0, 30 * scaling))) - { - cfgDeleteGameSpecificConfig(); - InitSettings(); - LoadSettings(false); - } - } - else - { - if (ImGui::Button("Make Game Config", ImVec2(0, 30 * scaling))) - cfgMakeGameSpecificConfig(); - } - ImGui::PopStyleVar(); + if (game_started) + { + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(16 * scaling, normal_padding.y)); + if (cfgHasGameSpecificConfig()) + { + if (ImGui::Button("Delete Game Config", ImVec2(0, 30 * scaling))) + { + cfgDeleteGameSpecificConfig(); + InitSettings(); + LoadSettings(false); + } + } + else + { + if (ImGui::Button("Make Game Config", ImVec2(0, 30 * scaling))) + cfgMakeGameSpecificConfig(); + } + ImGui::PopStyleVar(); + } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(16 * scaling, 6 * scaling)); // from 4, 3 @@ -655,6 +695,46 @@ static void gui_display_settings() ImGui::SameLine(); ShowHelpMarker("Video connection type"); + static int current_item; + std::vector paths; + for (auto path : settings.dreamcast.ContentPath) + paths.push_back(path.c_str()); + + ImVec2 size; + size.x = 0.0f; + size.y = (ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().FramePadding.y * 2.f) + * (settings.dreamcast.ContentPath.size() + 1) ;//+ ImGui::GetStyle().FramePadding.y * 2.f; + + if (ImGui::ListBoxHeader("Content Location", size)) + { + int to_delete = -1; + for (int i = 0; i < settings.dreamcast.ContentPath.size(); i++) + { + ImGui::PushID(settings.dreamcast.ContentPath[i].c_str()); + ImGui::AlignTextToFramePadding(); + ImGui::Text("%s", settings.dreamcast.ContentPath[i].c_str()); + ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - ImGui::CalcTextSize("X").x - ImGui::GetStyle().FramePadding.x); + if (ImGui::Button("X")) + to_delete = i; + ImGui::PopID(); + } + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(24 * scaling, 3 * scaling)); + if (ImGui::Button("Add")) + ImGui::OpenPopup("Select Directory"); + select_directory_popup("Select Directory", scaling, &directory_selected_callback); + ImGui::PopStyleVar(); + + ImGui::ListBoxFooter(); + if (to_delete >= 0) + { + settings.dreamcast.ContentPath.erase(settings.dreamcast.ContentPath.begin() + to_delete); + game_list_done = false; + } + } + ImGui::SameLine(); + ShowHelpMarker("The directories where your games are stored"); + + ImGui::PopStyleVar(); ImGui::EndTabItem(); } @@ -903,6 +983,182 @@ static void gui_display_settings() settings.dynarec.Enable = (bool)dynarec_enabled; } +#ifdef _ANDROID +static std::string current_library_path("/storage/emulated/0/Download"); +#else +static std::string current_library_path("/home/raph/RetroPie/roms/dreamcast/"); +#endif +struct GameMedia { + std::string name; + std::string path; +}; + +static bool operator<(const GameMedia &left, const GameMedia &right) +{ + return left.name < right.name; +} + +static void add_game_directory(const std::string& path, std::vector& game_list) +{ + //printf("Exploring %s\n", path.c_str()); + DIR *dir = opendir(path.c_str()); + if (dir == NULL) + return; + while (true) + { + struct dirent *entry = readdir(dir); + if (entry == NULL) + break; + std:string name(entry->d_name); + if (name == "." || name == "..") + continue; + std::string child_path = path + "/" + name; + if (entry->d_type == DT_UNKNOWN) + { + struct stat st; + if (stat(child_path.c_str(), &st) != 0) + continue; + if (S_ISDIR(st.st_mode)) + entry->d_type = DT_DIR; + } + if (entry->d_type == DT_DIR) + { + add_game_directory(child_path, game_list); + } + else + { +#if DC_PLATFORM == DC_PLATFORM_DREAMCAST + if (name.size() >= 4) + { + std::string extension = name.substr(name.size() - 4).c_str(); + //printf(" found game %s ext %s\n", entry->d_name, extension.c_str()); + if (stricmp(extension.c_str(), ".cdi") && stricmp(extension.c_str(), ".gdi") && stricmp(extension.c_str(), ".chd") && stricmp(extension.c_str(), ".cue")) + continue; + game_list.push_back({ name, child_path }); + } +#else + std::string::size_type dotpos = name.find_last_of("."); + if (dotpos == std::string::npos || dotpos == name.size() - 1) + continue; + std::string extension = name.substr(dotpos); + if (stricmp(extension.c_str(), ".zip") && stricmp(extension.c_str(), ".7z") && stricmp(extension.c_str(), ".bin") + && stricmp(extension.c_str(), ".lst") && stricmp(extension.c_str(), ".dat")) + continue; + game_list.push_back({ name, child_path }); +#endif + } + } + closedir(dir); +} + +static std::vector game_list; + +static void fetch_game_list() +{ + if (game_list_done) + return; + game_list.clear(); + for (auto path : settings.dreamcast.ContentPath) + add_game_directory(path, game_list); + std::stable_sort(game_list.begin(), game_list.end()); + game_list_done = true; +} + +static void gui_display_demo() +{ + ImGui_Impl_NewFrame(); + ImGui::NewFrame(); + + ImGui::ShowDemoWindow(); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData(), false); +} + +static void gui_start_game(const std::string& path) +{ + dc_start_game(path.c_str()); +} + +static void gui_display_content() +{ + ImGui_Impl_NewFrame(); + ImGui::NewFrame(); + + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0); + + ImGui::Begin("##main", NULL, ImGuiWindowFlags_NoDecoration); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20 * scaling, 8 * scaling)); // from 8, 4 + ImGui::AlignTextToFramePadding(); + ImGui::Text("GAMES"); + + static ImGuiTextFilter filter; + if (KeyboardDevice::GetInstance() != NULL) + { + ImGui::SameLine(0, 32 * scaling); + filter.Draw("Filter"); + } + + ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - ImGui::CalcTextSize("Settings").x - ImGui::GetStyle().FramePadding.x * 2.0f /*+ ImGui::GetStyle().ItemSpacing.x*/); + if (ImGui::Button("Settings"))//, ImVec2(0, 30 * scaling))) + gui_state = Settings; + ImGui::PopStyleVar(); + + fetch_game_list(); + + // Only if Filter and Settings aren't focused... ImGui::SetNextWindowFocus(); + ImGui::BeginChild(ImGui::GetID("library"), ImVec2(0, 0), true); + { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8 * scaling, 20 * scaling)); // from 8, 4 + + for (auto game : game_list) + if (filter.PassFilter(game.name.c_str())) + { + if (ImGui::Selectable(game.name.c_str())) + { + gui_start_game(game.path); + gui_state = ClosedNoResume; + } + } + ImGui::PopStyleVar(); + } + ImGui::EndChild(); + ImGui::End(); + ImGui::PopStyleVar(); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData(), false); +} + +void systemdir_selected_callback(bool cancelled, std::string selection) +{ + if (!cancelled) + { + set_user_config_dir(selection); + set_user_data_dir(selection); + if (cfgOpen()) + { + LoadSettings(false); + gui_state = Main; + // FIXME Save config dir in android app prefs + } + } +} + +void gui_display_onboarding() +{ + ImGui_Impl_NewFrame(); + ImGui::NewFrame(); + + ImGui::OpenPopup("Select System Directory"); + select_directory_popup("Select System Directory", scaling, &systemdir_selected_callback); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData(), false); +} + void gui_display_ui() { switch (gui_state) @@ -913,13 +1169,20 @@ void gui_display_ui() case Commands: gui_display_commands(); break; + case Main: + //gui_display_demo(); + gui_display_content(); + break; case Closed: case ClosedNoResume: break; + case Onboarding: + gui_display_onboarding(); + break; } if (gui_state == Closed) - dc_resume_emu(true); + dc_resume(); else if (gui_state == ClosedNoResume) gui_state = Closed; } @@ -942,6 +1205,11 @@ void gui_display_fps(const char *string) ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } +void gui_open_onboarding() +{ + gui_state = Onboarding; +} + void gui_term() { inited = false; diff --git a/core/rend/gui.h b/core/rend/gui.h index fded32d04..0d49bf61d 100644 --- a/core/rend/gui.h +++ b/core/rend/gui.h @@ -23,6 +23,7 @@ void gui_open_settings(); bool gui_is_open(); void gui_display_ui(); void gui_display_fps(const char *string); +void gui_open_onboarding(); void gui_term(); extern int screen_dpi; diff --git a/core/rend/gui_util.cpp b/core/rend/gui_util.cpp new file mode 100644 index 000000000..15b0689cf --- /dev/null +++ b/core/rend/gui_util.cpp @@ -0,0 +1,213 @@ +/* + Copyright 2019 flyinghead + + This file is part of reicast. + + reicast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + reicast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with reicast. If not, see . + */ +#include "gui_util.h" +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "stdclass.h" +#include "imgui/imgui.h" + +extern int screen_width, screen_height; + +static std::string select_current_directory; +static std::vector select_subfolders; +static bool subfolders_read; +#ifdef _WIN32 +static const std::string separators = "/\\"; +static const std::string native_separator = "\\"; +#else +static const std::string separators = "/"; +static const std::string native_separator = "/"; +#endif + +void select_directory_popup(const char *prompt, float scaling, StringCallback callback) +{ + if (select_current_directory.empty()) + { +#if defined(_ANDROID) + const char *home = getenv("REICAST_HOME"); + if (home != NULL) + select_current_directory = home; +#elif HOST_OS == OS_LINUX || HOST_OS == OS_DARWIN + const char *home = getenv("HOME"); + if (home != NULL) + select_current_directory = home; +#elif HOST_OS == OS_WINDOWS + const char *home = getenv("HOMEPATH"); + if (home != NULL) + select_current_directory = home; +#endif + if (select_current_directory.empty()) + { + select_current_directory = get_writable_config_path(""); + if (select_current_directory.empty()) + select_current_directory = "."; + } + } + + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0); + + if (ImGui::BeginPopupModal(prompt, NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize )) + { + std::string path = select_current_directory; + int last_sep = path.find_last_of(separators); + if (last_sep == path.size() - 1) + path.pop_back(); + + static std::string error_message; + + if (!subfolders_read) + { + select_subfolders.clear(); + error_message.clear(); +#ifdef _WIN32 + if (select_current_directory.empty()) + { + // List all the drives + u32 drives = GetLogicalDrives(); + for (int i = 0; i < 32; i++) + if ((drives & (1 << i)) != 0) + select_subfolders.push_back(std::string(1, (char)('A' + i) + ":\\"); + } + else +#endif + { + DIR *dir = opendir(select_current_directory.c_str()); + if (dir == NULL) + { + error_message = "Cannot read " + select_current_directory; + select_subfolders.push_back(".."); + } + else + { + bool dotdot_seen = false; + while (true) + { + struct dirent *entry = readdir(dir); + if (entry == NULL) + break; + std:string name(entry->d_name); + if (name == ".") + continue; + if (name == "..") + dotdot_seen = true; + std::string child_path = path + "/" + name; + if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) + { + struct stat st; + if (stat(child_path.c_str(), &st) != 0) + continue; + if (S_ISDIR(st.st_mode)) + entry->d_type = DT_DIR; + } + if (entry->d_type == DT_DIR && access(child_path.c_str(), R_OK) == 0) + select_subfolders.push_back(name); + } + closedir(dir); +#ifdef _WIN32 + if (!dotdot_seen) + select_subfolders.push_back(".."); +#endif + } + } + + std::stable_sort(select_subfolders.begin(), select_subfolders.end()); + subfolders_read = true; + } + + ImGui::Text("%s", error_message.empty() ? select_current_directory.c_str() : error_message.c_str()); + ImGui::BeginChild(ImGui::GetID("dir_list"), ImVec2(0, -ImGui::CalcTextSize("Cancel").y - ImGui::GetStyle().FramePadding. y * 2 - ImGui::GetStyle().ItemSpacing.y), true); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8 * scaling, 20 * scaling)); // from 8, 4 + + + for (auto name : select_subfolders) + { + std::string child_path; + if (name == "..") + { + std::string::size_type last_sep = path.find_last_of(separators); + if (last_sep == std::string::npos) + { + if (path.empty()) + // Root folder + continue; +#ifdef _WIN32 + if (path.size() == 2 && path[1] == ':') + child_path = ""; + else +#endif + if (path == ".") + child_path = ".."; + else if (path == "..") + child_path = ".." + native_separator + ".."; + else + child_path = "."; + } + else if (last_sep == 0) + child_path = native_separator; + else if (path.size() >= 2 && path.substr(path.size() - 2) == "..") + child_path = path + native_separator + ".."; + else + child_path = path.substr(0, last_sep); + } + else + { + if (!path.empty()) + { + std::string::size_type last_sep = path.find_last_of(separators); + if (last_sep == path.size() - 1) + path.pop_back(); + } + child_path = path + native_separator + name; + } + if (ImGui::Selectable(name.c_str())) + { + subfolders_read = false; + select_current_directory = child_path; + } + } + ImGui::PopStyleVar(); + ImGui::EndChild(); + if (ImGui::Button("Select Current Directory")) + { + subfolders_read = false; + callback(false, select_current_directory); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) + { + subfolders_read = false; + callback(true, ""); + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + ImGui::PopStyleVar(); +} diff --git a/core/rend/gui_util.h b/core/rend/gui_util.h new file mode 100644 index 000000000..689419c55 --- /dev/null +++ b/core/rend/gui_util.h @@ -0,0 +1,23 @@ +/* + Copyright 2019 flyinghead + + This file is part of reicast. + + reicast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + reicast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with reicast. If not, see . + */ +#include + +typedef void (*StringCallback)(bool cancelled, std::string selection); + +void select_directory_popup(const char *prompt, float scaling, StringCallback callback); diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index e4fb7abae..100a888eb 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -28,7 +28,7 @@ static std::shared_ptr sdl_mouse_gamepad; static std::shared_ptr sdl_kb_gamepad; static SDLKeyboardDevice* sdl_keyboard = NULL; -extern void dc_stop(); +extern void dc_exit(); #ifdef TARGET_PANDORA extern char OSD_Info[128]; @@ -122,7 +122,7 @@ void input_sdl_handle(u32 port) switch (event.type) { case SDL_QUIT: - dc_stop(); + dc_exit(); break; case SDL_KEYDOWN: case SDL_KEYUP: diff --git a/core/types.h b/core/types.h index fb627d819..383e80c93 100644 --- a/core/types.h +++ b/core/types.h @@ -750,7 +750,7 @@ struct settings_t u32 region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default u32 broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default u32 language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default - + std::vector ContentPath; } dreamcast; struct @@ -918,11 +918,6 @@ u32 libGDR_GetDiscType(); void libGDR_GetSessionInfo(u8* pout,u8 session); -//ExtDev -s32 libExtDevice_Init(); -void libExtDevice_Reset(bool M); -void libExtDevice_Term(); - // 0x00600000 - 0x006007FF [NAOMI] (modem area for dreamcast) u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size); void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size); diff --git a/core/windows/winmain.cpp b/core/windows/winmain.cpp index 9c388af25..d80315054 100644 --- a/core/windows/winmain.cpp +++ b/core/windows/winmain.cpp @@ -106,7 +106,7 @@ PCHAR* return argv; } -void dc_stop(void); +void dc_exit(void); bool VramLockedWrite(u8* address); bool ngen_Rewrite(unat& addr,unat retadr,unat acc); @@ -658,16 +658,19 @@ int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine #endif #endif { - int dc_init(int argc,wchar* argv[]); - void dc_run(); + int reicast_init(int argc, char* argv[]); + void *rend_thread(void *); void dc_term(); - dc_init(argc,argv); + + if (reicast_init(argc, argv) != 0) + die("Reicast initialization failed"); #ifdef _WIN64 setup_seh(); #endif - dc_run(); + rend_thread(NULL); + dc_term(); } #ifndef __GNUC__ @@ -710,7 +713,7 @@ void os_DoEvents() // If the message is WM_QUIT, exit the while loop if (msg.message == WM_QUIT) { - dc_stop(); + dc_exit(); } // Translate the message and dispatch it to WindowProc() diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java index b6131e5cc..2e33c29b0 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java @@ -8,6 +8,7 @@ import android.preference.PreferenceManager; import android.support.v7.app.AppCompatDelegate; import android.util.Log; +import com.reicast.emulator.config.Config; import com.reicast.emulator.emu.JNIdc; public class Emulator extends Application { @@ -188,9 +189,9 @@ public class Emulator extends Application { * Fetch current configuration settings from the emulator and save them * */ - public void SaveSettings() + public void SaveAndroidSettings(String homeDirectory) { - Log.i("Emulator", "SaveSettings: saving preferences"); + Log.i("Emulator", "SaveAndroidSettings: saving preferences"); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); Emulator.dynarecopt = JNIdc.getDynarec(); @@ -223,6 +224,7 @@ public class Emulator extends Application { JNIdc.getControllers(maple_devices, maple_expansion_devices); SharedPreferences.Editor editor = prefs.edit() + .putString(Config.pref_home, homeDirectory) .putBoolean(Emulator.pref_dynarecopt, Emulator.dynarecopt) .putBoolean(Emulator.pref_idleskip, Emulator.idleskip) .putBoolean(Emulator.pref_unstable, Emulator.unstableopt) diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/FileBrowser.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/FileBrowser.java index be97d533c..8b12f4ae9 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/FileBrowser.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/FileBrowser.java @@ -396,7 +396,7 @@ public class FileBrowser extends Fragment { mCallback.onFolderSelected( Uri.fromFile(new File(home_directory))); } - JNIdc.config(home_directory); + //JNIdc.config(home_directory); } } }); @@ -545,7 +545,7 @@ public class FileBrowser extends Fragment { browser.get().mCallback.onFolderSelected(Uri.fromFile( new File(browser.get().home_directory))); } - JNIdc.config(browser.get().home_directory); + //JNIdc.config(browser.get().home_directory); } } diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/GL2JNIActivity.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/GL2JNIActivity.java index 588d0014c..c51de8d47 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/GL2JNIActivity.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/GL2JNIActivity.java @@ -333,7 +333,7 @@ public class GL2JNIActivity extends Activity implements ActivityCompat.OnRequest @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (permissions.length > 0 && permissions[0] == Manifest.permission.RECORD_AUDIO && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (permissions.length > 0 && Manifest.permission.RECORD_AUDIO .equals(permissions[0]) && grantResults[0] == PackageManager.PERMISSION_GRANTED) { SipEmulator sip = new SipEmulator(); sip.startRecording(); JNIdc.setupMic(sip); diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java index ff042bcad..10ba26f17 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java @@ -38,7 +38,6 @@ import com.reicast.emulator.config.Config; import com.reicast.emulator.config.EditVJoyActivity; import com.reicast.emulator.config.InputFragment; import com.reicast.emulator.config.OptionsFragment; -import com.reicast.emulator.config.PGConfigFragment; import com.reicast.emulator.debug.GenerateLogs; import com.reicast.emulator.emu.JNIdc; @@ -47,7 +46,7 @@ import java.util.List; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, FileBrowser.OnItemSelectedListener, - OptionsFragment.OnClickListener, InputFragment.OnClickListener { + OptionsFragment.OnClickListener, InputFragment.OnClickListener { private static final int PERMISSION_REQUEST = 1001; private SharedPreferences mPrefs; @@ -119,7 +118,14 @@ public class MainActivity extends AppCompatActivity implements if (!getFilesDir().exists()) { getFilesDir().mkdir(); } - JNIdc.initEnvironment((Emulator)getApplicationContext()); + String home_directory = mPrefs.getString(Config.pref_home, ""); + String result = JNIdc.initEnvironment((Emulator)getApplicationContext(), home_directory); + if (result != null) + showToastMessage("Initialization failed: " + result, + Snackbar.LENGTH_LONG); + + String android_home_directory = Environment.getExternalStorageDirectory().getAbsolutePath(); + JNIdc.config(android_home_directory); // When viewing a resource, pass its URI to the native code for opening Intent intent = getIntent(); @@ -231,7 +237,7 @@ public class MainActivity extends AppCompatActivity implements String home_directory = mPrefs.getString(Config.pref_home, Environment.getExternalStorageDirectory().getAbsolutePath()); - JNIdc.config(home_directory); + //JNIdc.config(home_directory); startActivity(new Intent("com.reicast.EMULATOR", uri, getApplicationContext(), EditVJoyActivity.class)); @@ -244,7 +250,7 @@ public class MainActivity extends AppCompatActivity implements String home_directory = mPrefs.getString(Config.pref_home, Environment.getExternalStorageDirectory().getAbsolutePath()); - JNIdc.config(home_directory); + //JNIdc.config(home_directory); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = Uri.parse(uri.toString().replace("content://" @@ -547,4 +553,14 @@ public class MainActivity extends AppCompatActivity implements .getDimensionPixelOffset(R.dimen.snackbar_icon_padding)); snackbar.show(); } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (permissions.length > 0 && (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permissions[0]) || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[0])) + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + onGameSelected(Uri.parse("file://whatever")); + } + } + } diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/NativeGLActivity.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/NativeGLActivity.java index 348928865..d36a95c1e 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/NativeGLActivity.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/NativeGLActivity.java @@ -129,7 +129,7 @@ public class NativeGLActivity extends BaseNativeGLActivity implements ActivityCo @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (permissions.length > 0 && permissions[0] == Manifest.permission.RECORD_AUDIO && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (permissions.length > 0 && Manifest.permission.RECORD_AUDIO .equals(permissions[0]) && grantResults[0] == PackageManager.PERMISSION_GRANTED) { SipEmulator sip = new SipEmulator(); sip.startRecording(); JNIdc.setupMic(sip); diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java index a82f01235..1985c5ba4 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java @@ -111,7 +111,7 @@ public class OptionsFragment extends Fragment { mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - // Specialized handler for devices with an extSdCard mount for external + // FIXME Specialized handler for devices with an extSdCard mount for external HashSet extStorage = FileBrowser.getExternalMounts(); if (extStorage != null && !extStorage.isEmpty()) { for (String sd : extStorage) { @@ -157,7 +157,7 @@ public class OptionsFragment extends Fragment { Snackbar.LENGTH_SHORT); } mPrefs.edit().putString(Config.pref_home, home_directory).apply(); - JNIdc.config(home_directory); + //JNIdc.config(home_directory); new LocateThemes(OptionsFragment.this).execute(home_directory + "/themes"); } hideSoftKeyBoard(); diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/GL2JNIView.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/GL2JNIView.java index b94024b43..64ac3a1b5 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/GL2JNIView.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/GL2JNIView.java @@ -134,8 +134,8 @@ public class GL2JNIView extends GLSurfaceView implements IEmulatorView DisplayMetrics dm = context.getResources().getDisplayMetrics(); JNIdc.screenDpi((int)Math.max(dm.xdpi, dm.ydpi)); - JNIdc.config(prefs.getString(Config.pref_home, - Environment.getExternalStorageDirectory().getAbsolutePath())); + //JNIdc.config(prefs.getString(Config.pref_home, + // Environment.getExternalStorageDirectory().getAbsolutePath())); ethd = new EmuThread(this); diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java index 6baa5bcd6..7e7341db8 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java @@ -9,7 +9,7 @@ public final class JNIdc { static { System.loadLibrary("dc"); } - public static native void initEnvironment(Emulator emulator); + public static native String initEnvironment(Emulator emulator, String homeDirectory); public static native void config(String dirName); public static native String init(String fileName); public static native void query(EmuThread thread); diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/NativeGLView.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/NativeGLView.java index dc2f021bb..05e9f8eb9 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/NativeGLView.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/NativeGLView.java @@ -90,8 +90,8 @@ public class NativeGLView extends SurfaceView implements IEmulatorView { DisplayMetrics dm = context.getResources().getDisplayMetrics(); JNIdc.screenDpi((int)Math.max(dm.xdpi, dm.ydpi)); - JNIdc.config(prefs.getString(Config.pref_home, - Environment.getExternalStorageDirectory().getAbsolutePath())); + //JNIdc.config(prefs.getString(Config.pref_home, + // Environment.getExternalStorageDirectory().getAbsolutePath())); ethd = new EmuThread(this); @@ -109,7 +109,7 @@ public class NativeGLView extends SurfaceView implements IEmulatorView { if (NativeGLActivity.syms != null) JNIdc.data(1, NativeGLActivity.syms); - +/* final String initStatus = JNIdc.init(fileName); if (initStatus != null) { @@ -120,25 +120,25 @@ public class NativeGLView extends SurfaceView implements IEmulatorView { } }); - throw new EmulatorInitFailed(); } JNIdc.query(ethd); - +*/ // Continuously render frames until the emulator stops handler.post(new Runnable() { @Override public void run() { - if (ethd.getState() == Thread.State.TERMINATED) - ((Activity)getContext()).finish(); - else { + //if (ethd.getState() == Thread.State.TERMINATED) + // ((Activity)getContext()).finish(); + //else + { JNIdc.rendframeNative(); handler.post(this); } } }); - ethd.start(); + ethd.run(); // FIXME Not a thread anymore } @@ -509,11 +509,13 @@ public class NativeGLView extends SurfaceView implements IEmulatorView { Log.i("NativeGLView", "Stopping emulator"); //JNIdc.destroy(); JNIdc.stop(); + /* try { ethd.join(); } catch (InterruptedException e) { e.printStackTrace(); } + */ Log.i("NativeGLView", "Stopping emulator completed"); } diff --git a/shell/android-studio/reicast/src/main/jni/src/Android.cpp b/shell/android-studio/reicast/src/main/jni/src/Android.cpp index 2876cd9da..a7ee30be3 100644 --- a/shell/android-studio/reicast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/reicast/src/main/jni/src/Android.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -13,6 +14,7 @@ #include #include "hw/maple/maple_cfg.h" +#include "hw/pvr/Renderer_if.h" #include "profiler/profiler.h" #include "rend/TexCache.h" #include "hw/maple/maple_devs.h" @@ -26,8 +28,7 @@ JavaVM* g_jvm; // Convenience class to get the java environment for the current thread. -// Also attach the threads, and detach it on destruction, if needed. This is probably not very efficient -// but shouldn't be needed except for error reporting. +// Also attach the threads, and detach it on destruction, if needed. class JVMAttacher { public: JVMAttacher() : env(NULL), detach_thread(false) { @@ -55,14 +56,16 @@ public: g_jvm->DetachCurrentThread(); } + bool failed() { return env == NULL; } + + JNIEnv *env; + +private: void log_error(const char *reason) { LOGE("JVMAttacher cannot attach to JVM: %s", reason); } - bool failed() { return env == NULL; } - - JNIEnv *env; bool detach_thread = false; }; @@ -82,7 +85,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_set ## jsetting(JNIEn extern "C" { -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEnv *env, jobject obj, jobject emulator) __attribute__((visibility("default"))); +JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEnv *env, jobject obj, jobject emulator, jstring homeDirectory) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_config(JNIEnv *env,jobject obj,jstring dirName) __attribute__((visibility("default"))); JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_init(JNIEnv *env,jobject obj,jstring fileName) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_query(JNIEnv *env,jobject obj,jobject emu_thread) __attribute__((visibility("default"))); @@ -159,28 +162,15 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_screenDpi(JNIEnv *env screen_dpi = screenDpi; } -void SetApplicationPath(wchar *path); -int dc_init(int argc, wchar* argv[]); -void dc_run(); -void dc_pause(); -void dc_pause_emu(); -void dc_resume_emu(bool continue_running); +int reicast_init(int argc, char* argv[]); +void dc_resume(); void dc_stop(); void dc_term(); -bool dc_is_running(); -bool VramLockedWrite(u8* address); - -bool rend_single_frame(); -void rend_init_renderer(); -void rend_term_renderer(); -void rend_cancel_emu_wait(); bool egl_makecurrent(); -//extern cResetEvent rs,re; extern int screen_width,screen_height; -static u64 tvs_base; static char gamedisk[256]; u16 kcode[4] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; @@ -197,7 +187,7 @@ extern bool print_stats; //stuff for saving prefs jobject g_emulator; -jmethodID saveSettingsMid; +jmethodID saveAndroidSettingsMid; static ANativeWindow *g_window = 0; void os_DoEvents() @@ -231,21 +221,6 @@ void *libPvr_GetRenderSurface() void common_linux_setup(); -MapleDeviceType GetMapleDeviceType(int value) -{ - switch (value) - { - case 1: - return MDT_SegaVMU; - case 2: - return MDT_Microphone; - case 3: - return MDT_PurupuruPack; - default: - return MDT_None; - } -} - void os_SetupInput() { #if DC_PLATFORM == DC_PLATFORM_DREAMCAST @@ -258,7 +233,7 @@ void os_SetWindowText(char const *Text) putinf("%s",Text); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEnv *env, jobject obj, jobject emulator) +JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEnv *env, jobject obj, jobject emulator, jstring homeDirectory) { // Initialize platform-specific stuff common_linux_setup(); @@ -268,18 +243,37 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEn env->GetJavaVM(&g_jvm); if (g_emulator == NULL) { g_emulator = env->NewGlobalRef(emulator); - saveSettingsMid = env->GetMethodID(env->GetObjectClass(emulator), "SaveSettings", "()V"); + saveAndroidSettingsMid = env->GetMethodID(env->GetObjectClass(emulator), "SaveAndroidSettings", "(Ljava/lang/String;)V"); } + // Set home directory based on User config + const char* path = homeDirectory != NULL ? env->GetStringUTFChars(homeDirectory, 0) : ""; + set_user_config_dir(path); + set_user_data_dir(path); + printf("Config dir is: %s\n", get_writable_config_path("").c_str()); + printf("Data dir is: %s\n", get_writable_data_path("").c_str()); + if (homeDirectory != NULL) + env->ReleaseStringUTFChars(homeDirectory, path); + + jstring msg = NULL; + int rc = reicast_init(0, NULL); + if (rc == -4) + msg = env->NewStringUTF("Cannot find configuration"); + else if (rc == 69) + msg = env->NewStringUTF("Invalid command line"); + else if (rc == -1) + msg = env->NewStringUTF("Memory initialization failed"); + return msg; } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_config(JNIEnv *env,jobject obj,jstring dirName) { // Set home directory based on User config const char* D = dirName? env->GetStringUTFChars(dirName,0):0; - set_user_config_dir(D); - set_user_data_dir(D); - printf("Config dir is: %s\n", get_writable_config_path("/").c_str()); - printf("Data dir is: %s\n", get_writable_data_path("/").c_str()); +// set_user_config_dir(D); +// set_user_data_dir(D); +// printf("Config dir is: %s\n", get_writable_config_path("").c_str()); +// printf("Data dir is: %s\n", get_writable_data_path("").c_str()); + setenv("REICAST_HOME", D, 1); env->ReleaseStringUTFChars(dirName,D); } @@ -299,6 +293,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_bootdisk(JNIEnv *env, JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_init(JNIEnv *env,jobject obj,jstring fileName) { + /* FIXME // Get filename string from Java const char* P = fileName ? env->GetStringUTFChars(fileName,0) : 0; if (!P) gamedisk[0] = '\0'; @@ -313,23 +308,8 @@ JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_init(JNIEnv *env,j // Set configuration settings.profile.run_counts = 0; - // Make up argument list - char *args[3]; - args[0] = "dc"; - args[1] = "-config"; - args[2] = gamedisk[0] != 0 ? (char *)malloc(strlen(gamedisk) + 32) : NULL; - - if (args[2] != NULL) - { - strcpy(args[2], "config:image="); - strcat(args[2], gamedisk); - } - // Run nullDC emulator - int rc = dc_init(args[2] ? 3 : 1, args); - - if (args[2] != NULL) - free(args[2]); + int rc = dc_start_game(gamedisk); jstring msg = NULL; if (rc == -5) @@ -344,6 +324,8 @@ JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_init(JNIEnv *env,j msg = env->NewStringUTF("Memory initialization failed"); return msg; + */ + return NULL; } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_diskSwap(JNIEnv *env,jobject obj,jstring disk) @@ -384,9 +366,11 @@ jmethodID getmicdata; jobject vmulcd = NULL; jbyteArray jpix = NULL; jmethodID updatevmuscreen; +extern bool game_started; JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_query(JNIEnv *env,jobject obj,jobject emu_thread) { + /* FIXME jmethodID reiosInfoMid=env->GetMethodID(env->GetObjectClass(emu_thread),"reiosInfo","(Ljava/lang/String;Ljava/lang/String;)V"); char *id = (char*)malloc(11); @@ -398,23 +382,25 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_query(JNIEnv *env,job jstring reios_name = env->NewStringUTF(name); env->CallVoidMethod(emu_thread, reiosInfoMid, reios_id, reios_name); + */ } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_run(JNIEnv *env,jobject obj,jobject emu_thread) { install_prof_handler(0); jenv = env; - emu = env->NewGlobalRef(emu_thread); + emu = env->NewGlobalRef(emu_thread); // FIXME Delete ref jsamples=env->NewShortArray(SAMPLE_COUNT*2); + jsamples = (jshortArray)env->NewGlobalRef(jsamples); // FIXME Delete ref writemid=env->GetMethodID(env->GetObjectClass(emu),"WriteBuffer","([SI)I"); coreMessageMid=env->GetMethodID(env->GetObjectClass(emu),"coreMessage","([B)I"); dieMid=env->GetMethodID(env->GetObjectClass(emu),"Die","()V"); - dc_run(); + //dc_run(NULL); - env->DeleteGlobalRef(emu); - emu = NULL; + //env->DeleteGlobalRef(emu); + //emu = NULL; } int msgboxf(const wchar* text,unsigned int type,...) { @@ -455,21 +441,20 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupVmu(JNIEnv *env, JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,jobject obj) { - dc_pause(); - dc_pause_emu(); + if (game_started) + dc_stop(); } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNIEnv *env,jobject obj) { - dc_resume_emu(true); + if (game_started) + dc_resume(); } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj) { - if (dc_is_running()) { + if (game_started) dc_stop(); - rend_cancel_emu_wait(); - } } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,jobject obj) @@ -651,9 +636,12 @@ JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsOpen(JNIEnv u32 androidaudio_push(void* frame, u32 amt, bool wait) { verify(amt==SAMPLE_COUNT); + JVMAttacher attacher; // FIXME don't attach/detach every call... + if (attacher.failed()) + return 0; //yeah, do some audio piping magic here ! - jenv->SetShortArrayRegion(jsamples,0,amt*2,(jshort*)frame); - return jenv->CallIntMethod(emu,writemid,jsamples,wait); + attacher.env->SetShortArrayRegion(jsamples, 0, amt * 2, (jshort *)frame); + return attacher.env->CallIntMethod(emu, writemid, jsamples, wait); } void androidaudio_init() @@ -705,13 +693,25 @@ void os_DebugBreak() { // TODO: notify the parent thread about it ... - //raise(SIGABRT); - pthread_exit(NULL); + raise(SIGABRT); + //pthread_exit(NULL); // Attach debugger here to figure out what went wrong for(;;) ; } +void SaveAndroidSettings() +{ + JVMAttacher attacher; + if (attacher.failed()) + return; + + jstring homeDirectory = attacher.env->NewStringUTF(get_writable_config_path("").c_str()); + + attacher.env->CallVoidMethod(g_emulator, saveAndroidSettingsMid, homeDirectory); + attacher.env->DeleteLocalRef(homeDirectory); +} + JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(JNIEnv *env, jobject obj) { input_device_manager = env->NewGlobalRef(obj);