From 8be2966ecb727332cea133e3507eb53ca495cc3c Mon Sep 17 00:00:00 2001 From: Bart Trzynadlowski Date: Sat, 27 Aug 2011 21:37:37 +0000 Subject: [PATCH] - Added crosshairs for light gun games and disabled mouse cursor in full screen mode (no way to re-enable it now). - Fixed Real3D FIFO buffer overflow bug. - Input system cannot be changed for non-Windows builds (only SDL is available). - Added Spikeout-specific controls. --- Src/Games.cpp | 4 +- Src/Games.h | 3 +- Src/Inputs/Input.cpp | 3 +- Src/Inputs/Inputs.cpp | 10 +++- Src/Inputs/Inputs.h | 9 +++- Src/Model3/DSB.cpp | 22 ++++---- Src/Model3/Model3.cpp | 10 +++- Src/Model3/Real3D.cpp | 13 ++++- Src/Model3/Real3D.h | 3 ++ Src/OSD/SDL/Main.cpp | 114 ++++++++++++++++++++++++++++++++++++++---- 10 files changed, 158 insertions(+), 33 deletions(-) diff --git a/Src/Games.cpp b/Src/Games.cpp index 10d33e4..fba91bf 100644 --- a/Src/Games.cpp +++ b/Src/Games.cpp @@ -1497,7 +1497,7 @@ const struct GameInfo g_Model3GameList[] = FALSE, // 96 MB of banked CROM (Do not Mirror) 0x4000000, // 64 MB of VROM 0x1000000, // 16 MB of sample ROMs - GAME_INPUT_COMMON|GAME_INPUT_JOYSTICK1|GAME_INPUT_FIGHTING, + GAME_INPUT_COMMON|GAME_INPUT_JOYSTICK1|GAME_INPUT_SPIKEOUT, 2, // DSB2 MPEG board { @@ -1577,7 +1577,7 @@ const struct GameInfo g_Model3GameList[] = FALSE, // 96 MB of banked CROM (Do not Mirror) 0x4000000, // 64 MB of VROM 0x1000000, // 16 MB of sample ROMs - GAME_INPUT_COMMON|GAME_INPUT_JOYSTICK1|GAME_INPUT_FIGHTING, + GAME_INPUT_COMMON|GAME_INPUT_JOYSTICK1|GAME_INPUT_SPIKEOUT, 2, // DSB2 MPEG board { diff --git a/Src/Games.h b/Src/Games.h index 8ebcf46..4631812 100644 --- a/Src/Games.h +++ b/Src/Games.h @@ -50,7 +50,8 @@ #define GAME_INPUT_ANALOG_JOYSTICK 0x0400 // game has analog joystick #define GAME_INPUT_TWIN_JOYSTICKS 0x0800 // game has twin joysticks #define GAME_INPUT_SOCCER 0x1000 // game has soccer controls -#define GAME_INPUT_ALL 0x1FFF +#define GAME_INPUT_SPIKEOUT 0x2000 // game has Spikeout buttons +#define GAME_INPUT_ALL 0x3FFF /****************************************************************************** diff --git a/Src/Inputs/Input.cpp b/Src/Inputs/Input.cpp index 48e4169..b89892b 100644 --- a/Src/Inputs/Input.cpp +++ b/Src/Inputs/Input.cpp @@ -58,8 +58,9 @@ const char* CInput::GetInputGroup() case GAME_INPUT_UI: return "User Interface Controls"; case GAME_INPUT_COMMON: return "Common Controls"; case GAME_INPUT_JOYSTICK1: // Fall through to below - case GAME_INPUT_JOYSTICK2: return "8-Way Joysticks"; + case GAME_INPUT_JOYSTICK2: return "4-Way Joysticks"; case GAME_INPUT_FIGHTING: return "Fighting Game Buttons"; + case GAME_INPUT_SPIKEOUT: return "Spikeout Buttons"; case GAME_INPUT_SOCCER: return "Virtua Striker Buttons"; case GAME_INPUT_VEHICLE: return "Racing Game Steering Controls"; case GAME_INPUT_SHIFT4: return "Racing Game Gear Shift"; diff --git a/Src/Inputs/Inputs.cpp b/Src/Inputs/Inputs.cpp index be37a18..522f9e6 100644 --- a/Src/Inputs/Inputs.cpp +++ b/Src/Inputs/Inputs.cpp @@ -17,7 +17,7 @@ CInputs::CInputs(CInputSystem *system) : m_system(system) uiLoadState = AddSwitchInput("UILoadState", "Load State", GAME_INPUT_UI, "KEY_F7"); uiDumpInpState = AddSwitchInput("UIDumpInputState", "Dump Input State", GAME_INPUT_UI, "KEY_F8"); uiClearNVRAM = AddSwitchInput("UIClearNVRAM", "Clear NVRAM", GAME_INPUT_UI, "KEY_ALT+KEY_N"); - uiToggleCursor = AddSwitchInput("UIToggleCursor", "Toggle Cursor", GAME_INPUT_UI, "KEY_ALT+KEY_I"); + uiSelectCrosshairs = AddSwitchInput("UISelectCrosshairs", "Select Crosshairs", GAME_INPUT_UI, "KEY_ALT+KEY_I"); uiToggleFrLimit = AddSwitchInput("UIToggleFrameLimit", "Toggle Frame Limiting", GAME_INPUT_UI, "KEY_ALT+KEY_T"); #ifdef SUPERMODEL_DEBUGGER uiEnterDebugger = AddSwitchInput("UIEnterDebugger", "Enter Debugger", GAME_INPUT_UI, "KEY_ALT+KEY_B"); @@ -33,7 +33,7 @@ CInputs::CInputs(CInputSystem *system) : m_system(system) test[0] = AddSwitchInput("TestA", "Test A", GAME_INPUT_COMMON, "KEY_6"); test[1] = AddSwitchInput("TestB", "Test B", GAME_INPUT_COMMON, "KEY_8"); - // 8-Way Joysticks + // 4-Way Joysticks up[0] = AddSwitchInput("JoyUp", "P1 Joystick Up", GAME_INPUT_JOYSTICK1, "KEY_UP,JOY1_UP"); down[0] = AddSwitchInput("JoyDown", "P1 Joystick Down", GAME_INPUT_JOYSTICK1, "KEY_DOWN,JOY1_DOWN"); left[0] = AddSwitchInput("JoyLeft", "P1 Joystick Left", GAME_INPUT_JOYSTICK1, "KEY_LEFT,JOY1_LEFT"); @@ -52,6 +52,12 @@ CInputs::CInputs(CInputSystem *system) : m_system(system) kick[1] = AddSwitchInput("Kick2", "P2 Kick", GAME_INPUT_FIGHTING, "JOY2_BUTTON2"); guard[1] = AddSwitchInput("Guard2", "P2 Guard", GAME_INPUT_FIGHTING, "JOY2_BUTTON3"); escape[1] = AddSwitchInput("Escape2", "P2 Escape", GAME_INPUT_FIGHTING, "JOY2_BUTTON4"); + + // Spikeout Buttons + shift = AddSwitchInput("Shift", "Shift", GAME_INPUT_SPIKEOUT, "KEY_A,JOY1_BUTTON1"); + beat = AddSwitchInput("Beat", "Beat", GAME_INPUT_SPIKEOUT, "KEY_S,JOY1_BUTTON2"); + charge = AddSwitchInput("Charge", "Charge",GAME_INPUT_SPIKEOUT, "KEY_D,JOY1_BUTTON3"); + jump = AddSwitchInput("Jump", "Jump", GAME_INPUT_SPIKEOUT, "KEY_F,JOY1_BUTTON4"); // Virtua Striker Buttons shortPass[0] = AddSwitchInput("ShortPass", "P1 Short Pass", GAME_INPUT_SOCCER, "KEY_A,JOY1_BUTTON1"); diff --git a/Src/Inputs/Inputs.h b/Src/Inputs/Inputs.h index cba96d4..e62864a 100644 --- a/Src/Inputs/Inputs.h +++ b/Src/Inputs/Inputs.h @@ -72,7 +72,7 @@ public: CSwitchInput *uiLoadState; CSwitchInput *uiDumpInpState; CSwitchInput *uiClearNVRAM; - CSwitchInput *uiToggleCursor; + CSwitchInput *uiSelectCrosshairs; CSwitchInput *uiToggleFrLimit; #ifdef SUPERMODEL_DEBUGGER CSwitchInput *uiEnterDebugger; @@ -95,6 +95,12 @@ public: CSwitchInput *kick[2]; CSwitchInput *guard[2]; CSwitchInput *escape[2]; + + // Spikeout controls + CSwitchInput *shift; + CSwitchInput *beat; + CSwitchInput *charge; + CSwitchInput *jump; // Soccer game controls (players 1 and 2) CSwitchInput *shortPass[2]; @@ -140,7 +146,6 @@ public: CSwitchInput *twinJoyJump; CSwitchInput *twinJoyCrouch; - // Analog joystick CAxisInput *analogJoyX; CAxisInput *analogJoyY; diff --git a/Src/Model3/DSB.cpp b/Src/Model3/DSB.cpp index a5211c2..0fef435 100644 --- a/Src/Model3/DSB.cpp +++ b/Src/Model3/DSB.cpp @@ -677,7 +677,7 @@ static const char *stateName[] = void CDSB2::WriteMPEGFIFO(UINT8 byte) { - printf("fifo: %x (state %s)\n", byte, stateName[mpegState]); + //printf("fifo: %x (state %s)\n", byte, stateName[mpegState]); switch (mpegState) { case ST_IDLE: @@ -693,7 +693,7 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte) usingMPEGStart = mpegStart; usingMPEGEnd = mpegEnd; MPEG_PlayMemory((const char *) &mpegROM[mpegStart], mpegEnd-mpegStart); - printf("playing %X\n", mpegStart); + //printf("playing %X\n", mpegStart); mpegState = ST_IDLE; playing = 1; } @@ -737,13 +737,13 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte) if (playing) { - printf("Setting loop point to %x\n", mpegStart); + //printf("Setting loop point to %x\n", mpegStart); usingLoopStart = mpegStart; usingLoopEnd = mpegEnd-mpegStart; MPEG_SetLoop((const char *) &mpegROM[usingLoopStart], usingLoopEnd); } - printf("mpegStart=%x\n", mpegStart); + //printf("mpegStart=%x\n", mpegStart); break; case ST_GOT24: mpegEnd &= 0x00FFFF; @@ -758,7 +758,7 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte) case ST_24_1: mpegEnd &= 0xFFFF00; mpegEnd |= (byte); - printf("mpegEnd=%x\n", mpegEnd); + //printf("mpegEnd=%x\n", mpegEnd); // default to full stereo // mixer_set_stereo_volume(0, 255, 255); @@ -781,7 +781,7 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte) usingMPEGStart = mpegStart; usingMPEGEnd = mpegEnd; MPEG_PlayMemory((const char *) &mpegROM[mpegStart], mpegEnd-mpegStart); - printf("playing %X (from st_gota4)\n", mpegStart); + //printf("playing %X (from st_gota4)\n", mpegStart); playing = 1; } break; @@ -816,14 +816,14 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte) case ST_GOTB6: // rear left(?) volume case ST_GOTB0: // left volume volume[0] = byte; - printf("Set L Volume: %02X\n", byte); + //printf("Set L Volume: %02X\n", byte); mpegState = ST_IDLE; break; case ST_GOTA7: // rear right(?) volume case ST_GOTA1: // right volume case ST_GOTA0: volume[1] = byte; - printf("Set R Volume: %02X\n", byte); + //printf("Set R Volume: %02X\n", byte); mpegState = ST_IDLE; break; case ST_GOTB2: @@ -929,7 +929,7 @@ void CDSB2::Write16(UINT32 addr, UINT16 data) *(UINT16 *) &ram[addr] = data; return; } - printf("W16: %x @ %x\n", data, addr); + //printf("W16: %x @ %x\n", data, addr); } void CDSB2::Write32(UINT32 addr, UINT32 data) @@ -941,7 +941,7 @@ void CDSB2::Write32(UINT32 addr, UINT32 data) *(UINT16 *) &ram[addr+2] = data&0xFFFF; return; } - printf("W32: %x @ %x\n", data, addr); + //printf("W32: %x @ %x\n", data, addr); } void CDSB2::SendCommand(UINT8 data) @@ -1023,7 +1023,7 @@ void CDSB2::Reset(void) M68KSetContext(&M68K); M68KReset(); - printf("DSB2 PC=%06X\n", M68KGetPC()); + //printf("DSB2 PC=%06X\n", M68KGetPC()); M68KGetContext(&M68K); DebugLog("DSB2 Reset\n"); diff --git a/Src/Model3/Model3.cpp b/Src/Model3/Model3.cpp index f0421e9..591ed18 100644 --- a/Src/Model3/Model3.cpp +++ b/Src/Model3/Model3.cpp @@ -247,6 +247,14 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->punch[0]->value<<0); // P1 Punch } + if ((Game->inputFlags&GAME_INPUT_SPIKEOUT)) + { + data &= ~(Inputs->shift->value<<2); // Shift + data &= ~(Inputs->beat->value<<0); // Beat + data &= ~(Inputs->charge->value<<1); // Charge + data &= ~(Inputs->jump->value<<3); // Jump + } + if ((Game->inputFlags&GAME_INPUT_SOCCER)) { data &= ~(Inputs->shortPass[0]->value<<2); // P1 Short Pass @@ -2164,7 +2172,7 @@ void CModel3::RunMainBoardFrame(void) ++irqCount; if (irqCount > 128) { - printf("\tMIDI FIFO OVERFLOW! (IRQEn=%02X, IRQPend=%02X)\n", IRQ.ReadIRQEnable()&0x40, IRQ.ReadIRQState()); + //printf("\tMIDI FIFO OVERFLOW! (IRQEn=%02X, IRQPend=%02X)\n", IRQ.ReadIRQEnable()&0x40, IRQ.ReadIRQState()); break; } } diff --git a/Src/Model3/Real3D.cpp b/Src/Model3/Real3D.cpp index 9fc1723..c94a672 100644 --- a/Src/Model3/Real3D.cpp +++ b/Src/Model3/Real3D.cpp @@ -132,6 +132,7 @@ void CReal3D::BeginFrame(void) void CReal3D::EndFrame(void) { + error = false; // clear error (just needs to be done once per frame) status &= ~2; Render3D->EndFrame(); } @@ -698,9 +699,14 @@ void CReal3D::Flush(void) void CReal3D::WriteTextureFIFO(UINT32 data) { - textureFIFO[fifoIdx++] = data; if (fifoIdx >= (0x100000/4)) - ErrorLog("Real3D texture FIFO maxed out!"); + { + if (!error) + ErrorLog("Overflow in Real3D texture FIFO!"); + error = true; + } + else + textureFIFO[fifoIdx++] = data; } void CReal3D::WriteTexturePort(unsigned reg, UINT32 data) @@ -797,6 +803,8 @@ void CReal3D::WritePCIConfigSpace(unsigned device, unsigned reg, unsigned bits, void CReal3D::Reset(void) { + error = false; + commandPortWritten = FALSE; fifoIdx = 0; @@ -885,6 +893,7 @@ CReal3D::CReal3D(void) textureRAM = NULL; textureFIFO = NULL; vrom = NULL; + error = false; fifoIdx = 0; vromTextureAddr = 0; vromTextureHeader = 0; diff --git a/Src/Model3/Real3D.h b/Src/Model3/Real3D.h index 8e62f1c..31dc75d 100644 --- a/Src/Model3/Real3D.h +++ b/Src/Model3/Real3D.h @@ -351,6 +351,9 @@ private: int step; // hardware stepping (as in GameInfo structure) UINT32 pciID; // PCI vendor and device ID + // Error flag (to limit errors to once per frame) + bool error; // true if an error occurred this frame + // Real3D memory UINT8 *memoryPool; // all memory allocated here UINT32 *cullingRAMLo; // 4MB of culling RAM at 8C000000 diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp index 84281ff..1a83057 100644 --- a/Src/OSD/SDL/Main.cpp +++ b/Src/OSD/SDL/Main.cpp @@ -1,3 +1,12 @@ +//TODO before release: +// - Controls for Dirt Devils, and other recent games (is bass working?) +// - Crosshairs +// - Comment source code, clean up +// - BOOL -> bool, TRUE/FALSE -> true/false +// - Add option for building with /MD in MSVC Makefile +// - Remove SUPERMODEL_SOUND +// - EmulateSCSP -> EmulateSound ? + /** ** Supermodel ** A Sega Model 3 Arcade Emulator. @@ -571,6 +580,70 @@ static void LoadNVRAM(CModel3 *Model3) } +/****************************************************************************** + UI Rendering + + Currently, only does crosshairs for light gun games. +******************************************************************************/ + +static void GunToViewCoords(float *x, float *y) +{ + *x = (*x-150.0f)/(651.0f-150.0f); // Scale [150,651] -> [0.0,1.0] + *y = (*y-80.0f)/(465.0f-80.0f); // Scale [80,465] -> [0.0,1.0] +} + +static void DrawCrosshair(float x, float y, float r, float g, float b) +{ + glColor3f(r, g, b); + glVertex2f(x-0.01f, y); + glVertex2f(x-0.002f, y); + glVertex2f(x+0.003f, y); + glVertex2f(x+0.01f, y); + glVertex2f(x, y-0.01f*(float)xRes/(float)yRes); + glVertex2f(x, y-0.003f*(float)xRes/(float)yRes); + glVertex2f(x, y+0.002f*(float)xRes/(float)yRes); + glVertex2f(x, y+0.01f*(float)xRes/(float)yRes); +} + +static void UpdateCrosshairs(CInputs *Inputs, unsigned showCrosshairs) +{ + float x[2], y[2]; + + showCrosshairs &= 3; + if (!showCrosshairs) + return; + + // Set up the viewport and orthogonal projection + glViewport(xOffset, yOffset, xRes, yRes); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.0, 1.0, 1.0, 0.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glDisable(GL_TEXTURE_2D); // no texture mapping + glDisable(GL_BLEND); // no blending + glDisable(GL_DEPTH_TEST); // no Z-buffering needed + glUseProgram(NULL); // no shaders + + // Convert gun coordinates to viewspace coordinates + x[0] = (float) Inputs->gunX[0]->value; + y[0] = (float) Inputs->gunY[0]->value; + x[1] = (float) Inputs->gunX[1]->value; + y[1] = (float) Inputs->gunY[1]->value; + GunToViewCoords(&x[0], &y[0]); + GunToViewCoords(&x[1], &y[1]); + + // Draw visible crosshairs + glBegin(GL_LINES); + glLineWidth(1.0f); + if ((showCrosshairs & 2) && !Inputs->trigger[0]->offscreenValue) // Player 1 + DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f); + if ((showCrosshairs & 1) && !Inputs->trigger[1]->offscreenValue) // Player 2 + DrawCrosshair(x[1], y[1], 0.0f, 1.0f, 0.0f); + glEnd(); +} + + /****************************************************************************** Main Program Loop ******************************************************************************/ @@ -589,7 +662,8 @@ int Supermodel(const char *zipFile, CInputs *Inputs, CINIFile *CmdLine) CRender3D *Render3D = new CRender3D(); unsigned prevFPSTicks, currentFPSTicks, currentTicks, targetTicks, startTicks; unsigned fpsFramesElapsed, framesElapsed; - BOOL showCursor = FALSE; // show cursor in full screen mode? + unsigned showCrosshairs = 0; // bit 1: player 1 crosshair, bit 0: player 2 + bool gameHasLightguns = false; BOOL quit = 0; BOOL paused = 0; @@ -621,8 +695,14 @@ int Supermodel(const char *zipFile, CInputs *Inputs, CINIFile *CmdLine) if (OKAY != OpenAudio()) return 1; - // Hide mouse if fullscreen + // Hide mouse if fullscreen, enable crosshairs for gun games Inputs->GetInputSystem()->SetMouseVisibility(!g_Config.fullScreen); + gameHasLightguns = !!(Model3->GetGameInfo()->inputFlags & (GAME_INPUT_GUN1|GAME_INPUT_GUN2)); + if (g_Config.fullScreen) + { + if (gameHasLightguns) + showCrosshairs = 3; + } // Attach the inputs to the emulator Model3->AttachInputs(Inputs); @@ -659,6 +739,9 @@ int Supermodel(const char *zipFile, CInputs *Inputs, CINIFile *CmdLine) { // If not, run one frame Model3->RunFrame(); + + // Show crosshairs for light gun games + UpdateCrosshairs(Inputs, showCrosshairs); // Swap the buffers SDL_GL_SwapBuffers(); @@ -699,7 +782,7 @@ int Supermodel(const char *zipFile, CInputs *Inputs, CINIFile *CmdLine) Debugger->Reset(); #endif // SUPERMODEL_DEBUGGER - printf("Model 3 reset.\n"); + puts("Model 3 reset."); } else if (Inputs->uiPause->Pressed()) { @@ -734,17 +817,23 @@ int Supermodel(const char *zipFile, CInputs *Inputs, CINIFile *CmdLine) // Dump input states Inputs->DumpState(Model3->GetGameInfo()); } - else if (Inputs->uiToggleCursor->Pressed() && g_Config.fullScreen) + else if (Inputs->uiSelectCrosshairs->Pressed() && gameHasLightguns) { - // Toggle cursor in full screen mode - showCursor = !showCursor; - Inputs->GetInputSystem()->SetMouseVisibility(!!showCursor); + // Count downwards to get this sequence: both, player 1, player 2, none + showCrosshairs--; + switch ((showCrosshairs&3)) + { + case 0: puts("Crosshairs disabled."); break; + case 3: puts("Crosshairs enabled."); break; + case 2: puts("Showing Player 1 crosshair only."); break; + case 1: puts("Showing Player 2 crosshair only."); break; + } } else if (Inputs->uiClearNVRAM->Pressed()) { // Clear NVRAM Model3->ClearNVRAM(); - printf("NVRAM cleared.\n"); + puts("NVRAM cleared."); } else if (Inputs->uiToggleFrLimit->Pressed()) { @@ -928,8 +1017,7 @@ static int DisassembleCROM(const char *zipFile, UINT32 addr, unsigned n) static void Title(void) { puts("Supermodel: A Sega Model 3 Arcade Emulator (Version "SUPERMODEL_VERSION")"); - puts("Copyright (C) 2011 by Bart Trzynadlowski"); - puts(""); + puts("Copyright (C) 2011 by Bart Trzynadlowski\n"); } // Print usage information @@ -965,7 +1053,9 @@ static void Help(void) puts(" -music-volume= Set volume of MPEG music in % [Default: 100]"); puts(""); puts("Input Options:"); +#ifdef SUPERMODEL_WIN32 puts(" -input-system= Set input system [Default: SDL]"); +#endif puts(" -print-inputs Prints current input configuration"); puts(" -config-inputs Configure inputs for keyboards, mice, and joysticks"); puts(""); @@ -1142,6 +1232,7 @@ int main(int argc, char **argv) else CmdLine.Set("Global", "FragmentShader", &argv[i][13]); } +#ifdef SUPERMODEL_WIN32 else if (!strncmp(argv[i],"-input-system=", 14)) { if (argv[i][14] == '\0') @@ -1149,6 +1240,7 @@ int main(int argc, char **argv) else CmdLine.Set("Global", "InputSystem", &argv[i][14]); } +#endif else if (!strcmp(argv[i],"-print-inputs")) cmdPrintInputs = true; else if (!strcmp(argv[i],"-config-inputs")) @@ -1172,7 +1264,7 @@ int main(int argc, char **argv) return 0; } else if (argv[i][0] == '-') - ErrorLog("Ignoring invalid option: %s.", argv[i]); + ErrorLog("Ignoring unrecognized option: %s.", argv[i]); else { if (fileIdx) // already specified a file