Merge pull request #1548 from reicast/fh/float-vmu

Float VMU option. Android renderer native thread. 90° screen rotation option. AW fixes.
This commit is contained in:
flyinghead 2019-04-10 21:53:41 +02:00 committed by GitHub
commit 8cdbb9c2fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 594 additions and 228 deletions

View File

@ -1,4 +1,5 @@
#include "aica.h"
#include "aica_if.h"
#include "sgc_if.h"
#include "aica_mem.h"
#include <math.h>
@ -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()

View File

@ -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()

View File

@ -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();
void aica_sb_Term();

View File

@ -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()

View File

@ -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:

View File

@ -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();

View File

@ -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);

View File

@ -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)

View File

@ -45,6 +45,7 @@ struct gl4_ctx
} modvol_shader;
std::unordered_map<u32, gl4PipelineShader> 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;

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++)
{
if (!CompilePipelineShader( &gl.pogram_table[i] ))
return false;
}
#endif
create_modvol_shader();
gl_load_osd_resources();
@ -1512,6 +1531,7 @@ static void upload_vertex_indices()
bool RenderFrame()
{
DoCleanup();
create_modvol_shader();
bool is_rtt=pvrrc.isRTT;
@ -1681,15 +1701,38 @@ bool RenderFrame()
float screen_stretching = settings.rend.ScreenStretching / 100.f;
float screen_scaling = settings.rend.ScreenScaling / 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);
//-1 -> 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)

View File

@ -96,6 +96,7 @@ struct gl_ctx
} modvol_shader;
std::unordered_map<u32, PipelineShader> shaders;
bool rotate90;
struct
{

View File

@ -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();

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -52,5 +52,56 @@
android:scheme="file" />
</intent-filter>
</activity>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.GDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.gdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CHD"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.chd"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CUE"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cue"
android:scheme="file" />
</intent-filter>
</activity-alias>
</application>
</manifest>

View File

@ -61,6 +61,16 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="tv.ouya.intent.category.GAME" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity-alias>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"

View File

@ -21,8 +21,7 @@ public final class JNIdc
public static native int send(int cmd, int opt);
public static native int data(int cmd, byte[] data);
public static native void rendinitNative(Surface surface, int w, int h);
public static native boolean rendframeNative();
public static native void rendinitNative(Surface surface);
public static native void rendinitJava(int w, int h);
public static native boolean rendframeJava();
public static native void rendtermJava();

View File

@ -19,8 +19,6 @@ import com.reicast.emulator.NativeGLActivity;
import com.reicast.emulator.config.Config;
public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback {
private Handler handler = new Handler();
private boolean surfaceReady = false;
private boolean paused = false;
VirtualJoystickDelegate vjoyDelegate;
@ -66,23 +64,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
if (NativeGLActivity.syms != null)
JNIdc.data(1, NativeGLActivity.syms);
startRendering();
}
private void startRendering() {
// Continuously render frames
handler.removeCallbacksAndMessages(null);
handler.postAtTime(new Runnable() {
@Override
public void run() {
if (!paused)
{
JNIdc.rendframeNative();
handler.post(this);
}
}
}, SystemClock.uptimeMillis() + 500);
}
@Override
@ -111,7 +92,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
//Log.i("reicast", "NativeGLView.surfaceChanged: " + w + "x" + h);
surfaceReady = true;
JNIdc.rendinitNative(surfaceHolder.getSurface(), w, h);
JNIdc.rendinitNative(surfaceHolder.getSurface());
Emulator.getCurrentActivity().handleStateChange(false);
}
@ -119,7 +100,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//Log.i("reicast", "NativeGLView.surfaceDestroyed");
surfaceReady = false;
JNIdc.rendinitNative(null, 0, 0);
JNIdc.rendinitNative(null);
Emulator.getCurrentActivity().handleStateChange(true);
}
@ -142,7 +123,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
requestFocus();
JNIdc.resume();
}
startRendering();
}
@TargetApi(19)

View File

@ -91,8 +91,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,j
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_send(JNIEnv *env,jobject obj,jint id, jint v) __attribute__((visibility("default")));
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env,jobject obj,jint id, jbyteArray d) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface, jint w, jint h) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv *env, jobject obj, jint w, jint h) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendtermJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
@ -404,35 +403,57 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env, job
extern void gl_swap();
extern void egl_stealcntx();
volatile static bool render_running;
volatile static bool render_reinit;
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj)
void *render_thread_func(void *)
{
if (g_window == NULL)
return false;
if (!egl_makecurrent())
return false;
jboolean ret = (jboolean)rend_single_frame();
if (ret)
gl_swap();
return ret;
render_running = true;
rend_init_renderer();
while (render_running) {
if (render_reinit)
{
render_reinit = false;
rend_init_renderer();
}
else
if (!egl_makecurrent())
break;;
bool ret = rend_single_frame();
if (ret)
gl_swap();
}
egl_makecurrent();
rend_term_renderer();
ANativeWindow_release(g_window);
g_window = NULL;
render_running = false;
return NULL;
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface, jint width, jint height)
static cThread render_thread(render_thread_func, NULL);
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface)
{
if (g_window != NULL)
{
egl_makecurrent();
rend_term_renderer();
ANativeWindow_release(g_window);
g_window = NULL;
}
if (surface != NULL)
{
if (render_thread.hThread != NULL)
{
if (surface == NULL)
{
render_running = false;
render_thread.WaitToEnd();
}
else
render_reinit = true;
}
else if (surface != NULL)
{
g_window = ANativeWindow_fromSurface(env, surface);
rend_init_renderer();
screen_width = width;
screen_height = height;
}
render_thread.Start();
}
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv * env, jobject obj, jint width, jint height)

View File

@ -3,7 +3,7 @@
android:name="com.reicast.emulator.Emulator">
<activity
android:name="com.reicast.emulator.MainActivity">
android:name="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -62,5 +62,66 @@
android:scheme="file" />
</intent-filter>
</activity>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.LST"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.lst"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.BIN"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.bin"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.DAT"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.dat"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.ZIP"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.zip"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.7Z"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.7z"
android:scheme="file" />
</intent-filter>
</activity-alias>
</application>
</manifest>