diff --git a/core/hw/aica/aica.cpp b/core/hw/aica/aica.cpp index 1eea5a03d..3cbf02bd9 100644 --- a/core/hw/aica/aica.cpp +++ b/core/hw/aica/aica.cpp @@ -1,4 +1,5 @@ #include "aica.h" +#include "aica_if.h" #include "sgc_if.h" #include "aica_mem.h" #include @@ -180,6 +181,7 @@ template void WriteAicaReg<2>(u32 reg,u32 data); s32 libAICA_Init() { init_mem(); + aica_Init(); verify(sizeof(*CommonData)==0x508); verify(sizeof(*DSPData)==0x15C8); @@ -203,9 +205,12 @@ s32 libAICA_Init() return rv_ok; } -void libAICA_Reset(bool m) +void libAICA_Reset(bool manual) { + if (!manual) + init_mem(); sgc_Init(); + aica_Reset(manual); } void libAICA_Term() diff --git a/core/hw/aica/aica_if.cpp b/core/hw/aica/aica_if.cpp index c717f8507..9ba65c0a7 100644 --- a/core/hw/aica/aica_if.cpp +++ b/core/hw/aica/aica_if.cpp @@ -18,6 +18,7 @@ u32 VREG;//video reg =P u32 ARMRST;//arm reset reg u32 rtc_EN=0; int dma_sched_id; +u32 RealTimeClock; u32 GetRTC_now() { @@ -39,9 +40,9 @@ u32 ReadMem_aica_rtc(u32 addr,u32 sz) switch( addr & 0xFF ) { case 0: - return settings.dreamcast.RTC>>16; + return RealTimeClock>>16; case 4: - return settings.dreamcast.RTC &0xFFFF; + return RealTimeClock &0xFFFF; case 8: return 0; } @@ -57,16 +58,16 @@ void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz) case 0: if (rtc_EN) { - settings.dreamcast.RTC&=0xFFFF; - settings.dreamcast.RTC|=(data&0xFFFF)<<16; + RealTimeClock&=0xFFFF; + RealTimeClock|=(data&0xFFFF)<<16; rtc_EN=0; } return; case 4: if (rtc_EN) { - settings.dreamcast.RTC&=0xFFFF0000; - settings.dreamcast.RTC|= data&0xFFFF; + RealTimeClock&=0xFFFF0000; + RealTimeClock|= data&0xFFFF; //TODO: Clean the internal timer ? } return; @@ -153,15 +154,12 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz) //Init/res/term void aica_Init() { - //mmnnn ? gotta fill it w/ something + RealTimeClock = GetRTC_now(); } void aica_Reset(bool Manual) { - if (!Manual) - { - aica_ram.Zero(); - } + aica_Init(); } void aica_Term() diff --git a/core/hw/aica/aica_if.h b/core/hw/aica/aica_if.h index 8c6009a66..8c58b5326 100644 --- a/core/hw/aica/aica_if.h +++ b/core/hw/aica/aica_if.h @@ -3,6 +3,7 @@ extern u32 VREG; extern VArray2 aica_ram; +extern u32 RealTimeClock; u32 ReadMem_aica_rtc(u32 addr,u32 sz); void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz); u32 ReadMem_aica_reg(u32 addr,u32 sz); @@ -17,4 +18,4 @@ void aica_Term(); void aica_sb_Init(); void aica_sb_Reset(bool Manual); -void aica_sb_Term(); \ No newline at end of file +void aica_sb_Term(); diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index f14562411..4f8c9d2d6 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -115,7 +115,7 @@ bool maple_atomiswave_coin_chute(int slot) { for (int i = 0; i < 16; i++) { - if (awave_button_mapping[i] == AWAVE_COIN_KEY && (kcode[slot] & (1 << i)) == 0) + if ((kcode[slot] & (1 << i)) == 0 && awave_button_mapping[i] == AWAVE_COIN_KEY) return true; } return false; @@ -149,16 +149,27 @@ void mcfg_CreateAtomisWaveControllers() // Game needs analog axes mcfg_Create(MDT_SegaController, 2, 5, 0); mcfg_Create(MDT_SegaController, 3, 5, 1); + // Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes) + // Maximum Speed same + } + else if (settings.input.JammaSetup == 1) + { + // 4 players + mcfg_Create(MDT_SegaController, 2, 5); + mcfg_Create(MDT_SegaController, 3, 5); + } + else if (settings.input.JammaSetup == 5) + { + // Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3 + // Sports Shooting same + mcfg_Create(MDT_LightGun, 2, 5, 0); + mcfg_Create(MDT_LightGun, 3, 5, 1); + } + else if (settings.input.JammaSetup == 3) + { + // Sega Bass Fishing Challenge needs a mouse (track-ball) on port 2 + mcfg_Create(MDT_Mouse, 2, 5, 0); } -// mcfg_Create(MDT_LightGun, 2, 5, 0); -// mcfg_Create(MDT_LightGun, 3, 5, 1); -// mcfg_Create(MDT_Mouse, 2, 5, 0); - // Guilty Gear Isuka (4P) needs 4 std controllers - // Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes) - // Maximum Speed same - // Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3 - // Sports Shooting same - // Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3 } void mcfg_CreateDevices() diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index a26a3f01a..90b4c972a 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -199,6 +199,35 @@ struct maple_base: maple_device */ struct maple_sega_controller: maple_base { + virtual u32 get_capabilities() { + // byte 0: 0 0 0 0 0 0 0 0 + // byte 1: 0 0 a5 a4 a3 a2 a1 a0 + // byte 2: R2 L2 D2 U2 D X Y Z + // byte 3: R L D U St A B C + + return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R + } + + virtual u32 transform_kcode(u32 kcode) { + return kcode; + } + + virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) { + switch (index) + { + case 0: + return pjs.trigger[PJTI_R]; // Right trigger + case 1: + return pjs.trigger[PJTI_L]; // Left trigger + case 2: + return pjs.joy[PJAI_X1]; // Stick X + case 3: + return pjs.joy[PJAI_Y1]; // Stick Y + default: + return 0x80; // unused + } + } + virtual MapleDeviceType get_device_type() { return MDT_SegaController; @@ -216,14 +245,9 @@ struct maple_sega_controller: maple_base //struct data //3*4 -#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE - w32(0xfe060f00); -#else - // More buttons, more digital axes - w32(0xff663f00); -#endif - w32( 0); - w32( 0); + w32(get_capabilities()); + w32(0); + w32(0); //1 area code w8(0xFF); @@ -254,54 +278,28 @@ struct maple_sega_controller: maple_base //4 w32(MFID_0_Input); -#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE //state data //2 key code - w16(pjs.kcode); + w16(transform_kcode(pjs.kcode)); //triggers //1 R - w8(pjs.trigger[PJTI_R]); + w8(get_analog_axis(0, pjs)); //1 L - w8(pjs.trigger[PJTI_L]); + w8(get_analog_axis(1, pjs)); //joyx //1 - w8(pjs.joy[PJAI_X1]); + w8(get_analog_axis(2, pjs)); //joyy //1 - w8(pjs.joy[PJAI_Y1]); + w8(get_analog_axis(3, pjs)); //not used //1 - w8(0x80); + w8(get_analog_axis(4, pjs)); //1 - w8(0x80); -#else - //state data - //2 key code - w16(pjs.kcode | AWAVE_TRIGGER_KEY); - - //not used - //1 - w8(0); - //1 - w8(0); - - //joyx - //1 - w8(pjs.joy[PJAI_X1]); - //joyy - //1 - w8(pjs.joy[PJAI_Y1]); - - //joyrx - //1 - w8(pjs.joy[PJAI_X2]); - //joyry - //1 - w8(pjs.joy[PJAI_Y2]); -#endif + w8(get_analog_axis(5, pjs)); } return MDRS_DataTransfer; @@ -313,6 +311,38 @@ struct maple_sega_controller: maple_base } }; +struct maple_atomiswave_controller: maple_sega_controller +{ + virtual u32 get_capabilities() override { + // byte 0: 0 0 0 0 0 0 0 0 + // byte 1: 0 0 a5 a4 a3 a2 a1 a0 + // byte 2: R2 L2 D2 U2 D X Y Z + // byte 3: R L D U St A B C + + return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R + } + + virtual u32 transform_kcode(u32 kcode) override { + return kcode | AWAVE_TRIGGER_KEY; + } + + virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override { + switch (index) + { + case 2: + return pjs.joy[PJAI_X1]; + case 3: + return pjs.joy[PJAI_Y1]; + case 4: + return pjs.joy[PJAI_X2]; + case 5: + return pjs.joy[PJAI_Y2]; + default: + return 0x80; + } + } +}; + /* Sega Dreamcast Visual Memory Unit This is pretty much done (?) @@ -1299,6 +1329,10 @@ struct maple_mouse : maple_base struct maple_lightgun : maple_base { + virtual u32 transform_kcode(u32 kcode) { + return kcode | 0xFF01; + } + virtual MapleDeviceType get_device_type() { return MDT_LightGun; @@ -1347,21 +1381,13 @@ struct maple_lightgun : maple_base PlainJoystickState pjs; config->GetInput(&pjs); - // Also use the mouse buttons - if (!(mo_buttons & 4)) // Left button - pjs.kcode &= ~4; // A - if (!(mo_buttons & 2)) // Right button - pjs.kcode &= ~2; // B - if (!(mo_buttons & 8)) // Wheel button - pjs.kcode &= ~8; // Start - //caps //4 w32(MFID_0_Input); //state data //2 key code - w16(pjs.kcode | 0xFF01); + w16(transform_kcode(pjs.kcode)); //not used //2 @@ -1387,6 +1413,13 @@ struct maple_lightgun : maple_base } }; +struct atomiswave_lightgun : maple_lightgun +{ + virtual u32 transform_kcode(u32 kcode) override { + return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0; + } +}; + extern u16 kcode[4]; extern s8 joyx[4],joyy[4]; extern u8 rt[4], lt[4]; @@ -2592,7 +2625,11 @@ maple_device* maple_Create(MapleDeviceType type) switch(type) { case MDT_SegaController: - rv=new maple_sega_controller(); +#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE + rv = new maple_sega_controller(); +#else + rv = new maple_atomiswave_controller(); +#endif break; case MDT_Microphone: @@ -2616,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type) break; case MDT_LightGun: +#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE rv = new maple_lightgun(); +#else + rv = new atomiswave_lightgun(); +#endif break; case MDT_NaomiJamma: diff --git a/core/hw/sh4/interpr/sh4_interpreter.cpp b/core/hw/sh4/interpr/sh4_interpreter.cpp index ddc7d509c..5f48886a2 100644 --- a/core/hw/sh4/interpr/sh4_interpreter.cpp +++ b/core/hw/sh4/interpr/sh4_interpreter.cpp @@ -232,7 +232,7 @@ int AicaUpdate(int tag, int c, int j) int DreamcastSecond(int tag, int c, int j) { - settings.dreamcast.RTC++; + RealTimeClock++; #if 1 //HOST_OS==OS_WINDOWS prof_periodical(); diff --git a/core/nullDC.cpp b/core/nullDC.cpp index d93fbb7b9..2f673fc5f 100755 --- a/core/nullDC.cpp +++ b/core/nullDC.cpp @@ -213,12 +213,14 @@ void LoadSpecialSettings() printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id); settings.input.JammaSetup = 2; } - else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id)) + else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id) // Naomi + || !strcmp("GUILTY GEAR isuka", naomi_game_id)) // AW { printf("Enabling 4-player setup for game %s\n", naomi_game_id); settings.input.JammaSetup = 1; } - else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id)) + else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id) + || !strcmp(naomi_game_id, "BASS FISHING SIMULATOR VER.A")) // AW { printf("Enabling specific JVS setup for game %s\n", naomi_game_id); settings.input.JammaSetup = 3; @@ -228,9 +230,11 @@ void LoadSpecialSettings() printf("Enabling specific JVS setup for game %s\n", naomi_game_id); settings.input.JammaSetup = 4; } - else if (!strcmp("NINJA ASSAULT", naomi_game_id)) + else if (!strcmp("NINJA ASSAULT", naomi_game_id) + || !strcmp(naomi_game_id, "Sports Shooting USA") // AW + || !strcmp(naomi_game_id, "SEGA CLAY CHALLENGE")) // AW { - printf("Enabling specific JVS setup for game %s\n", naomi_game_id); + printf("Enabling lightgun setup for game %s\n", naomi_game_id); settings.input.JammaSetup = 5; } else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id)) @@ -309,7 +313,6 @@ int dc_start_game(const char *path) { InitSettings(); LoadSettings(false); - settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore #if DC_PLATFORM == DC_PLATFORM_DREAMCAST if (!settings.bios.UseReios) #endif @@ -347,7 +350,6 @@ int dc_start_game(const char *path) return 0; } - 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 @@ -487,7 +489,6 @@ void dc_exit() void InitSettings() { - settings.dreamcast.RTC = GetRTC_now(); settings.dynarec.Enable = true; settings.dynarec.idleskip = true; settings.dynarec.unstable_opt = false; @@ -518,6 +519,8 @@ void InitSettings() settings.rend.ScreenScaling = 100; settings.rend.ScreenStretching = 100; settings.rend.Fog = true; + settings.rend.FloatVMUs = false; + settings.rend.Rotate90 = false; settings.pvr.ta_skip = 0; settings.pvr.rend = 0; @@ -604,6 +607,8 @@ void LoadSettings(bool game_specific) settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100); settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching); settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog); + settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs); + settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90); settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip); settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend); @@ -730,6 +735,8 @@ void SaveSettings() cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling); cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching); cfgSaveBool("config", "rend.Fog", settings.rend.Fog); + cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs); + cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90); cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip); cfgSaveInt("config", "pvr.rend", settings.pvr.rend); diff --git a/core/rend/gl4/abuffer.cpp b/core/rend/gl4/abuffer.cpp index b09cc962d..7e9b67c64 100644 --- a/core/rend/gl4/abuffer.cpp +++ b/core/rend/gl4/abuffer.cpp @@ -331,23 +331,23 @@ void initABuffer() { char source[16384]; sprintf(source, final_shader_source, 1); - gl4CompilePipelineShader(&g_abuffer_final_shader, source); + gl4CompilePipelineShader(&g_abuffer_final_shader, false, source); } if (g_abuffer_final_nosort_shader.program == 0) { char source[16384]; sprintf(source, final_shader_source, 0); - gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, source); + gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, false, source); } if (g_abuffer_clear_shader.program == 0) - gl4CompilePipelineShader(&g_abuffer_clear_shader, clear_shader_source); + gl4CompilePipelineShader(&g_abuffer_clear_shader, false, clear_shader_source); if (g_abuffer_tr_modvol_shaders[0].program == 0) { char source[16384]; for (int mode = 0; mode < ModeCount; mode++) { sprintf(source, tr_modvol_shader_source, mode); - gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], source); + gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], false, source); } } @@ -417,6 +417,17 @@ void termABuffer() glDeleteBuffers(1, &g_quadBuffer); g_quadBuffer = 0; } + glcache.DeleteProgram(g_abuffer_final_shader.program); + g_abuffer_final_shader.program = 0; + glcache.DeleteProgram(g_abuffer_final_nosort_shader.program); + g_abuffer_final_nosort_shader.program = 0; + glcache.DeleteProgram(g_abuffer_clear_shader.program); + g_abuffer_clear_shader.program = 0; + for (int mode = 0; mode < ModeCount; mode++) + { + glcache.DeleteProgram(g_abuffer_tr_modvol_shaders[mode].program); + g_abuffer_tr_modvol_shaders[mode].program = 0; + } } void reshapeABuffer(int w, int h) diff --git a/core/rend/gl4/gl4.h b/core/rend/gl4/gl4.h index 5ca4dd141..4c3ca82ac 100755 --- a/core/rend/gl4/gl4.h +++ b/core/rend/gl4/gl4.h @@ -45,6 +45,7 @@ struct gl4_ctx } modvol_shader; std::unordered_map shaders; + bool rotate90; struct { @@ -66,7 +67,8 @@ bool gl4_render_output_framebuffer(); void abufferDrawQuad(bool upsideDown = false, float x = 0.f, float y = 0.f, float w = 0.f, float h = 0.f); extern const char *gl4PixelPipelineShader; -bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *source = gl4PixelPipelineShader); +bool gl4CompilePipelineShader(gl4PipelineShader* s, bool rotate_90, const char *source = gl4PixelPipelineShader); +void gl4_delete_shaders(); extern GLuint stencilTexId; extern GLuint depthTexId; diff --git a/core/rend/gl4/gldraw.cpp b/core/rend/gl4/gldraw.cpp index 75ad7eda9..dfa403a19 100644 --- a/core/rend/gl4/gldraw.cpp +++ b/core/rend/gl4/gldraw.cpp @@ -49,6 +49,11 @@ static gl4PipelineShader *gl4GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode, u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset, u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass) { + if (settings.rend.Rotate90 != gl4.rotate90) + { + gl4_delete_shaders(); + gl4.rotate90 = settings.rend.Rotate90; + } u32 rv=0; rv|=pp_ClipTestMode; @@ -83,7 +88,7 @@ static gl4PipelineShader *gl4GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode, shader->pp_BumpMap = pp_BumpMap; shader->fog_clamping = fog_clamping; shader->pass = pass; - gl4CompilePipelineShader(shader); + gl4CompilePipelineShader(shader, settings.rend.Rotate90); } return shader; diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index 93700f20b..aa2da9c99 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -14,6 +14,7 @@ static const char* VertexShaderSource = "\ #version 140 \n\ #define pp_Gouraud %d \n\ +#define ROTATE_90 %d \n\ \n\ #if pp_Gouraud == 0 \n\ #define INTERPOLATION flat \n\ @@ -56,6 +57,9 @@ void main() \n\ \n\ vpos.w = extra_depth_scale / vpos.z; \n\ vpos.z = vpos.w; \n\ +#if ROTATE_90 == 1 \n\ + vpos.xy = vec2(vpos.y, -vpos.x); \n\ +#endif \n\ vpos.xy=vpos.xy*scale.xy-scale.zw; \n\ vpos.xy*=vpos.w; \n\ gl_Position = vpos; \n\ @@ -393,11 +397,11 @@ gl4_ctx gl4; struct gl4ShaderUniforms_t gl4ShaderUniforms; -bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *source /* = PixelPipelineShader */) +bool gl4CompilePipelineShader( gl4PipelineShader* s, bool rotate_90, const char *source /* = PixelPipelineShader */) { char vshader[16384]; - sprintf(vshader, VertexShaderSource, s->pp_Gouraud); + sprintf(vshader, VertexShaderSource, s->pp_Gouraud, rotate_90); char pshader[16384]; @@ -478,27 +482,45 @@ bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *source /* = Pix void gl_term(); +void gl4_delete_shaders() +{ + for (auto it : gl4.shaders) + { + if (it.second.program != 0) + glcache.DeleteProgram(it.second.program); + } + gl4.shaders.clear(); + glcache.DeleteProgram(gl4.modvol_shader.program); + gl4.modvol_shader.program = 0; +} + static void gles_term(void) { - glDeleteProgram(gl4.modvol_shader.program); glDeleteBuffers(1, &gl4.vbo.geometry); gl4.vbo.geometry = 0; glDeleteBuffers(1, &gl4.vbo.modvols); glDeleteBuffers(1, &gl4.vbo.idxs); glDeleteBuffers(1, &gl4.vbo.idxs2); glDeleteBuffers(1, &gl4.vbo.tr_poly_params); - for (auto it = gl4.shaders.begin(); it != gl4.shaders.end(); it++) - { - if (it->second.program != 0) - glDeleteProgram(it->second.program); - } - gl4.shaders.clear(); + gl4_delete_shaders(); glDeleteVertexArrays(1, &gl4.vbo.main_vao); glDeleteVertexArrays(1, &gl4.vbo.modvol_vao); gl_term(); } +static void create_modvol_shader() +{ + if (gl4.modvol_shader.program != 0) + return; + char vshader[16384]; + sprintf(vshader, VertexShaderSource, 1, settings.rend.Rotate90); + + gl4.modvol_shader.program=gl_CompileAndLink(vshader, ModifierVolumeShader); + gl4.modvol_shader.scale = glGetUniformLocation(gl4.modvol_shader.program, "scale"); + gl4.modvol_shader.extra_depth_scale = glGetUniformLocation(gl4.modvol_shader.program, "extra_depth_scale"); +} + static bool gl_create_resources() { if (gl4.vbo.geometry != 0) @@ -520,12 +542,7 @@ static bool gl_create_resources() gl4SetupMainVBO(); gl4SetupModvolVBO(); - char vshader[16384]; - sprintf(vshader, VertexShaderSource, 1); - - gl4.modvol_shader.program=gl_CompileAndLink(vshader, ModifierVolumeShader); - gl4.modvol_shader.scale = glGetUniformLocation(gl4.modvol_shader.program, "scale"); - gl4.modvol_shader.extra_depth_scale = glGetUniformLocation(gl4.modvol_shader.program, "extra_depth_scale"); + create_modvol_shader(); gl_load_osd_resources(); @@ -603,6 +620,7 @@ static bool RenderFrame() old_screen_scaling = settings.rend.ScreenScaling; } DoCleanup(); + create_modvol_shader(); bool is_rtt=pvrrc.isRTT; @@ -661,17 +679,41 @@ static bool RenderFrame() /* Handle Dc to screen scaling */ - float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f; + float screen_scaling = settings.rend.ScreenScaling / 100.f; float screen_stretching = settings.rend.ScreenStretching / 100.f; - float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0); - float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2); + float dc2s_scale_h; + float ds2s_offs_x; - //-1 -> too much to left - gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; - gl4ShaderUniforms.scale_coefs[1] = (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512 - gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width; - gl4ShaderUniforms.scale_coefs[3] = (is_rtt ? 1 : -1); + if (is_rtt) + { + gl4ShaderUniforms.scale_coefs[0] = 2.0f / dc_width; + gl4ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512 + gl4ShaderUniforms.scale_coefs[2] = 1; + gl4ShaderUniforms.scale_coefs[3] = 1; + } + else + { + if (settings.rend.Rotate90) + { + dc2s_scale_h = screen_height / 640.0; + ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2; + gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; + gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_width; + gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width; + gl4ShaderUniforms.scale_coefs[3] = 1; + } + else + { + dc2s_scale_h = screen_height / 480.0; + ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2; + //-1 -> too much to left + gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; + gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_height; + gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width; + gl4ShaderUniforms.scale_coefs[3] = -1; + } + } gl4ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; @@ -826,11 +868,20 @@ static bool RenderFrame() float min_y = pvrrc.fb_Y_CLIP.min / scale_y; if (!is_rtt) { + if (settings.rend.Rotate90) + { + float t = width; + width = height; + height = t; + t = min_x; + min_x = min_y; + min_y = 640 - t - height; + } // Add x offset for aspect ratio > 4/3 - min_x = min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x * screen_scaling; + min_x = (min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x) * screen_scaling; // Invert y coordinates when rendering to screen min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling; - width *= dc2s_scale_h * screen_scaling * screen_stretching; + width *= dc2s_scale_h * screen_stretching * screen_scaling; height *= dc2s_scale_h * screen_scaling; if (ds2s_offs_x > 0) diff --git a/core/rend/gles/glcache.h b/core/rend/gles/glcache.h index e245a368d..32c73c644 100644 --- a/core/rend/gles/glcache.h +++ b/core/rend/gles/glcache.h @@ -149,6 +149,19 @@ public: return _texture_ids[--_texture_cache_size]; } + void DeleteProgram(GLuint program) + { + GLsizei shader_count; + GLuint shaders[2]; + glGetAttachedShaders(program, ARRAY_SIZE(shaders), &shader_count, shaders); + for (int i = 0; i < shader_count; i++) + glDeleteShader(shaders[i]); + + glDeleteProgram(program); + if (_program == program) + _program = 0; + } + void Reset() { _texture = 0xFFFFFFFFu; _src_blend_factor = 0xFFFFFFFFu; diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index 618a3e33f..b4381170d 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -114,13 +114,30 @@ s32 SetTileClip(u32 val, GLint uniform) csy /= scale_y; cex /= scale_x; cey /= scale_y; - float t = cey; - cey = 480 - csy; - csy = 480 - t; - float dc2s_scale_h = screen_height / 480.0f; - float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2; - csx = csx * dc2s_scale_h + ds2s_offs_x; - cex = cex * dc2s_scale_h + ds2s_offs_x; + float dc2s_scale_h; + float ds2s_offs_x; + float screen_stretching = settings.rend.ScreenStretching / 100.f; + + if (settings.rend.Rotate90) + { + float t = cex; + cex = cey; + cey = 640 - csx; + csx = csy; + csy = 640 - t; + dc2s_scale_h = screen_height / 640.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2; + } + else + { + float t = cey; + cey = 480 - csy; + csy = 480 - t; + dc2s_scale_h = screen_height / 480.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2; + } + csx = csx * dc2s_scale_h * screen_stretching + ds2s_offs_x; + cex = cex * dc2s_scale_h * screen_stretching + ds2s_offs_x; csy = csy * dc2s_scale_h; cey = cey * dc2s_scale_h; } diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index fad89106d..a2155f460 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -79,6 +79,7 @@ const char* VertexShaderSource = %s \n\ #define TARGET_GL %s \n\ #define pp_Gouraud %d \n\ +#define ROTATE_90 %d \n\ \n\ #define GLES2 0 \n\ #define GLES3 1 \n\ @@ -136,6 +137,9 @@ void main() \n\ vpos.z = vpos.w; \n\ #else \n\ vpos.z=depth_scale.x+depth_scale.y*vpos.w; \n\ +#endif \n\ +#if ROTATE_90 == 1 \n\ + vpos.xy = vec2(vpos.y, -vpos.x); \n\ #endif \n\ vpos.xy=vpos.xy*scale.xy-scale.zw; \n\ vpos.xy*=vpos.w; \n\ @@ -850,9 +854,20 @@ GLuint fogTextureId; extern void gl_term(); #endif +static void gl_delete_shaders() +{ + for (auto it : gl.shaders) + { + if (it.second.program != 0) + glcache.DeleteProgram(it.second.program); + } + gl.shaders.clear(); + glcache.DeleteProgram(gl.modvol_shader.program); + gl.modvol_shader.program = 0; +} + static void gles_term() { - glDeleteProgram(gl.modvol_shader.program); glDeleteBuffers(1, &gl.vbo.geometry); gl.vbo.geometry = 0; glDeleteBuffers(1, &gl.vbo.modvols); @@ -865,7 +880,7 @@ static void gles_term() gl_free_osd_resources(); free_output_framebuffer(); - gl.shaders.clear(); + gl_delete_shaders(); gl_term(); } @@ -1018,6 +1033,11 @@ PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode, u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset, u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear) { + if (settings.rend.Rotate90 != gl.rotate90) + { + gl_delete_shaders(); + gl.rotate90 = settings.rend.Rotate90; + } u32 rv=0; rv|=pp_ClipTestMode; @@ -1058,7 +1078,7 @@ bool CompilePipelineShader( PipelineShader* s) { char vshader[8192]; - sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud); + sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud, settings.rend.Rotate90); char pshader[8192]; @@ -1144,13 +1164,30 @@ void gl_load_osd_resources() void gl_free_osd_resources() { - glDeleteProgram(gl.OSD_SHADER.program); + glcache.DeleteProgram(gl.OSD_SHADER.program); if (osd_tex != 0) { glcache.DeleteTextures(1, &osd_tex); osd_tex = 0; } } + +static void create_modvol_shader() +{ + if (gl.modvol_shader.program != 0) + return; + char vshader[8192]; + sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1, settings.rend.Rotate90); + char fshader[8192]; + sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version); + + gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader); + gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale"); + gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor"); + gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale"); + gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale"); +} + bool gl_create_resources() { if (gl.vbo.geometry != 0) @@ -1174,25 +1211,7 @@ bool gl_create_resources() glGenBuffers(1, &gl.vbo.idxs); glGenBuffers(1, &gl.vbo.idxs2); - char vshader[8192]; - sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1); - char fshader[8192]; - sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version); - - gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader); - gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale"); - gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor"); - gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale"); - gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale"); - - //#define PRECOMPILE_SHADERS - #ifdef PRECOMPILE_SHADERS - for (u32 i=0;i too much to left - ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; - ShaderUniforms.scale_coefs[1]= (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512 - ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / screen_width; - ShaderUniforms.scale_coefs[3]= (is_rtt ? 1 : -1); + float dc2s_scale_h; + float ds2s_offs_x; + if (is_rtt) + { + ShaderUniforms.scale_coefs[0] = 2.0f / dc_width; + ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512 + ShaderUniforms.scale_coefs[2] = 1; + ShaderUniforms.scale_coefs[3] = 1; + } + else + { + if (settings.rend.Rotate90) + { + dc2s_scale_h = screen_height / 640.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2; + ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; + ShaderUniforms.scale_coefs[1] = -2.0f / dc_width; + ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width; + ShaderUniforms.scale_coefs[3] = 1; + } + else + { + dc2s_scale_h = screen_height / 480.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2; + ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; + ShaderUniforms.scale_coefs[1] = -2.0f / dc_height; + ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width; + ShaderUniforms.scale_coefs[3] = -1; + } + //-1 -> too much to left + } ShaderUniforms.depth_coefs[0]=2/(vtx_max_fZ-vtx_min_fZ); ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1; @@ -1857,11 +1900,20 @@ bool RenderFrame() float min_y = pvrrc.fb_Y_CLIP.min / scale_y; if (!is_rtt) { + if (settings.rend.Rotate90) + { + float t = width; + width = height; + height = t; + t = min_x; + min_x = min_y; + min_y = 640 - t - height; + } // Add x offset for aspect ratio > 4/3 - min_x = min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x * screen_scaling; + min_x = (min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x) * screen_scaling; // Invert y coordinates when rendering to screen min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling; - width *= dc2s_scale_h * screen_scaling * screen_stretching; + width *= dc2s_scale_h * screen_stretching * screen_scaling; height *= dc2s_scale_h * screen_scaling; if (ds2s_offs_x > 0) diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index 7e0cec3cb..85f1b90e8 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -96,6 +96,7 @@ struct gl_ctx } modvol_shader; std::unordered_map shaders; + bool rotate90; struct { diff --git a/core/rend/gles/imgui_impl_opengl3.cpp b/core/rend/gles/imgui_impl_opengl3.cpp index ddb363c1c..0380a8901 100644 --- a/core/rend/gles/imgui_impl_opengl3.cpp +++ b/core/rend/gles/imgui_impl_opengl3.cpp @@ -490,15 +490,9 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects() if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); g_VboHandle = g_ElementsHandle = 0; - if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle); - if (g_VertHandle) glDeleteShader(g_VertHandle); + glcache.DeleteProgram(g_ShaderHandle); g_VertHandle = 0; - - if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle); - if (g_FragHandle) glDeleteShader(g_FragHandle); g_FragHandle = 0; - - if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; ImGui_ImplOpenGL3_DestroyFontsTexture(); diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 4131695e4..814c60981 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -296,7 +296,9 @@ static void gui_display_commands() if (!settings_opening) ImGui_ImplOpenGL3_DrawBackground(); - display_vmus(); + if (!settings.rend.FloatVMUs) + // If floating VMUs, they are already visible on the background + display_vmus(); ImGui::SetNextWindowPos(ImVec2(screen_width / 2.f, screen_height / 2.f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(ImVec2(330 * scaling, 0)); @@ -619,6 +621,8 @@ void directory_selected_callback(bool cancelled, std::string selection) static void gui_display_settings() { + static bool maple_devices_changed; + ImGui_Impl_NewFrame(); ImGui::NewFrame(); @@ -641,10 +645,14 @@ static void gui_display_settings() gui_state = Commands; else gui_state = Main; + if (maple_devices_changed) + { + maple_devices_changed = false; #if DC_PLATFORM == DC_PLATFORM_DREAMCAST - maple_ReconnectDevices(); - reset_vmus(); + maple_ReconnectDevices(); + reset_vmus(); #endif + } SaveSettings(); } if (game_started) @@ -798,13 +806,14 @@ static void gui_display_settings() if (ImGui::BeginTabItem("Controls")) { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding); -#if DC_PLATFORM == DC_PLATFORM_DREAMCAST +#if DC_PLATFORM == DC_PLATFORM_DREAMCAST || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE if (ImGui::CollapsingHeader("Dreamcast Devices", ImGuiTreeNodeFlags_DefaultOpen)) { for (int bus = 0; bus < MAPLE_PORTS; bus++) { ImGui::Text("Device %c", bus + 'A'); ImGui::SameLine(); +#if DC_PLATFORM == DC_PLATFORM_DREAMCAST char device_name[32]; sprintf(device_name, "##device%d", bus); float w = ImGui::CalcItemWidth() / 3; @@ -815,7 +824,10 @@ static void gui_display_settings() { bool is_selected = settings.input.maple_devices[bus] == maple_device_type_from_index(i); if (ImGui::Selectable(maple_device_types[i], &is_selected)) + { settings.input.maple_devices[bus] = maple_device_type_from_index(i); + maple_devices_changed = true; + } if (is_selected) ImGui::SetItemDefaultFocus(); } @@ -833,7 +845,10 @@ static void gui_display_settings() { bool is_selected = settings.input.maple_expansion_devices[bus][port] == maple_expansion_device_type_from_index(i); if (ImGui::Selectable(maple_expansion_device_types[i], &is_selected)) + { settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i); + maple_devices_changed = true; + } if (is_selected) ImGui::SetItemDefaultFocus(); } @@ -842,6 +857,10 @@ static void gui_display_settings() ImGui::PopID(); } ImGui::PopItemWidth(); +#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE + if (MapleDevices[bus][5] != NULL) + ImGui::Text("%s", maple_device_name(MapleDevices[bus][5]->get_device_type())); +#endif } ImGui::Spacing(); } @@ -951,6 +970,12 @@ static void gui_display_settings() ImGui::Checkbox("Show FPS Counter", &settings.rend.ShowFPS); ImGui::SameLine(); ShowHelpMarker("Show on-screen frame/sec counter"); + ImGui::Checkbox("Show VMU in game", &settings.rend.FloatVMUs); + ImGui::SameLine(); + ShowHelpMarker("Show the VMU LCD screens while in game"); + ImGui::Checkbox("Rotate screen 90°", &settings.rend.Rotate90); + ImGui::SameLine(); + ShowHelpMarker("Rotate the screen 90° counterclockwise"); ImGui::SliderInt("Scaling", (int *)&settings.rend.ScreenScaling, 1, 100); ImGui::SameLine(); ShowHelpMarker("Downscaling factor relative to native screen resolution. Higher is better"); @@ -1503,26 +1528,32 @@ void gui_display_osd() if (osd_message.empty()) { message = getFPSNotification(); - if (message.empty()) - return; } else message = osd_message; - ImGui_Impl_NewFrame(); - ImGui::NewFrame(); + if (!message.empty() || settings.rend.FloatVMUs) + { + ImGui_Impl_NewFrame(); + ImGui::NewFrame(); - ImGui::SetNextWindowBgAlpha(0); - ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner + if (!message.empty()) + { + ImGui::SetNextWindowBgAlpha(0); + ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner - ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav - | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground); - ImGui::SetWindowFontScale(1.5); - ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str()); - ImGui::End(); + ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav + | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground); + ImGui::SetWindowFontScale(1.5); + ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str()); + ImGui::End(); + } + if (settings.rend.FloatVMUs) + display_vmus(); - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + } } void gui_open_onboarding() diff --git a/core/types.h b/core/types.h index 8b82a413d..4d9369127 100644 --- a/core/types.h +++ b/core/types.h @@ -635,6 +635,8 @@ struct settings_t int ScreenScaling; // in percent. 50 means half the native resolution int ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3 bool Fog; + bool FloatVMUs; + bool Rotate90; // Rotate the screen 90 deg CC } rend; struct @@ -655,7 +657,6 @@ struct settings_t struct { u32 cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV - u32 RTC; 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 diff --git a/core/windows/winmain.cpp b/core/windows/winmain.cpp index 68db4682c..b2a90b8ed 100644 --- a/core/windows/winmain.cpp +++ b/core/windows/winmain.cpp @@ -749,6 +749,7 @@ cThread::cThread(ThreadEntryFP* function,void* prm) void cThread::Start() { + verify(hThread == NULL); hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Entry,param,0,NULL); ResumeThread(hThread); } @@ -756,6 +757,8 @@ void cThread::Start() void cThread::WaitToEnd() { WaitForSingleObject(hThread,INFINITE); + CloseHandle(hThread); + hThread = NULL; } //End thread class diff --git a/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml b/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml index 165b7b014..112f56962 100644 --- a/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml +++ b/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml @@ -52,5 +52,56 @@ android:scheme="file" /> + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shell/android-studio/reicast/src/main/AndroidManifest.xml b/shell/android-studio/reicast/src/main/AndroidManifest.xml index de600f7bc..ac89e2bb2 100644 --- a/shell/android-studio/reicast/src/main/AndroidManifest.xml +++ b/shell/android-studio/reicast/src/main/AndroidManifest.xml @@ -61,6 +61,16 @@ + + + + + + + + + android:name="com.reicast.emulator.NativeGLActivity"> @@ -62,5 +62,66 @@ android:scheme="file" /> + + + + + + + + + + + + + + + + + + +