From 9f44dc055ce146f114477f76df4a8960d3dbe7e0 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Thu, 5 Dec 2019 21:30:23 -0600 Subject: [PATCH] Keyboard and mouse mostly implemented. --- singe/main.c | 2 + singe/singe.c | 614 +++++++++++++++++++++++++++++++++++++++----- singe/videoPlayer.c | 58 ++++- singe/videoPlayer.h | 2 + 4 files changed, 608 insertions(+), 68 deletions(-) diff --git a/singe/main.c b/singe/main.c index 6641c7d5b..9b850f8cd 100644 --- a/singe/main.c +++ b/singe/main.c @@ -450,6 +450,8 @@ int main(int argc, char *argv[]) { window = SDL_CreateWindow("SINGE", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _confXResolution, _confYResolution, SDL_WINDOW_RESIZABLE); if (window == NULL) utilDie("%s", SDL_GetError()); + //***TODO*** Window Icon + // Do we want full screen of some kind? if (_confFullScreen || _confFullScreenWindow) { flags = _confFullScreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; diff --git a/singe/singe.c b/singe/singe.c index e20f8af3c..ffba97b7f 100644 --- a/singe/singe.c +++ b/singe/singe.c @@ -31,6 +31,7 @@ #include #include "thirdparty/uthash.h" +#include "thirdparty/manymouse/manymouse.h" #include "common.h" #include "util.h" @@ -38,10 +39,31 @@ #include "singe.h" -#define AUDIO_MAX_VOLUME 63 -#define MAX_TITLE_LENGTH 1024 +#define AUDIO_MAX_VOLUME 63 +#define MAX_TITLE_LENGTH 1024 +#define MAX_MICE 128 +#define SCROLLWHEEL_DISPLAY_TICKS 100 +#define NOMOUSE -1 +#define KEYBD_ARRAY_SIZE 15 +typedef struct MouseS { + int x; + int y; + int relx; + int rely; + char name[64]; + bool connected; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpadded" + Uint32 buttons; +#pragma GCC diagnostic pop + Uint32 scrolluptick; + Uint32 scrolldowntick; + Uint32 scrolllefttick; + Uint32 scrollrighttick; +} MouseT; + typedef struct SpriteS { int id; #pragma GCC diagnostic push @@ -70,6 +92,35 @@ typedef struct FontS { } FontT; +enum { + SWITCH_UP, + SWITCH_LEFT, + SWITCH_DOWN, + SWITCH_RIGHT, + SWITCH_START1, + SWITCH_START2, + SWITCH_BUTTON1, + SWITCH_BUTTON2, + SWITCH_BUTTON3, + SWITCH_COIN1, + SWITCH_COIN2, + SWITCH_SKILL1, + SWITCH_SKILL2, + SWITCH_SKILL3, + SWITCH_SERVICE, + SWITCH_TEST, + SWITCH_RESET, + SWITCH_SCREENSHOT, + SWITCH_QUIT, + SWITCH_PAUSE, + SWITCH_CONSOLE, + SWITCH_TILT, + SWITCH_MOUSE_SCROLL_UP, + SWITCH_MOUSE_SCROLL_DOWN, + SWITCH_MOUSE_DISCONNECT, + SWITCH_COUNT +}; + enum { KEYBD_NORMAL = 0, KEYBD_FULL @@ -107,6 +158,7 @@ int _confYResolution = -1; // Other globals +static MouseT _mice[MAX_MICE]; static lua_State *_luaContext = NULL; static SDL_Color _colorForeground = { 255, 255, 255, 255 }; static SDL_Color _colorBackground = { 0, 0, 0, 255 }; @@ -120,16 +172,63 @@ static int _effectsVolume = AUDIO_MAX_VOLUME; static int _keyboardMode = KEYBD_NORMAL; static int _videoHandle = -1; static int _fontQuality = 1; -static double _overlayScaleX = 1; -static double _overlayScaleY = 1; +static int _mouseMode = MOUSE_SINGLE; +static int _mouseCount = 0; +static double _overlayScaleX = 1; // Difference between overlay and video +static double _overlayScaleY = 1; // Difference between overlay and video static bool _pauseState = false; // by RDG2010 static bool _pauseEnabled = true; // by RDG2010 static bool _running = true; +static bool _discStopped = true; +static bool _mouseEnabled = true; static SpriteT *_spriteList = NULL; static SoundT *_soundList = NULL; static FontT *_fontList = NULL; static FontT *_fontCurrent = NULL; +static int _keyDefs[SWITCH_COUNT][2] = { + { SDLK_UP, SDLK_KP_8 }, // Up + { SDLK_LEFT, SDLK_KP_4 }, // Left + { SDLK_DOWN, SDLK_KP_2 }, // Down + { SDLK_RIGHT, SDLK_KP_6 }, // Right + { SDLK_1, 0 }, // 1 player start + { SDLK_2, 0 }, // 2 player start + { SDLK_SPACE, SDLK_LCTRL }, // Action button 1 + { SDLK_LALT, 0 }, // Action button 2 + { SDLK_LSHIFT, 0 }, // Action button 3 + { SDLK_5, SDLK_c }, // Coin chute left + { SDLK_6, 0 }, // Coin chute right + { SDLK_KP_DIVIDE, 0 }, // Skill easy + { SDLK_KP_MULTIPLY, 0 }, // Skill medium + { SDLK_KP_MINUS, 0 }, // Skill hard + { SDLK_9, 0 }, // Service coin + { SDLK_F2, 0 }, // Test mode + { SDLK_F3, 0 }, // Reset cpu + { SDLK_F12, SDLK_F11 }, // Take screenshot + { SDLK_ESCAPE, SDLK_q }, // Quit + { SDLK_p, 0 }, // Pause game + { SDLK_BACKQUOTE, 0 }, // Toggle console + { SDLK_t, 0 } // Tilt/Slam switch +}; + +static int _fullKeybdDefs[] = { + SDLK_BACKSPACE, + SDLK_TAB, + SDLK_RETURN, + SDLK_PAUSE, + SDLK_SPACE, + SDLK_QUOTE, + SDLK_COMMA, + SDLK_SEMICOLON, + SDLK_EQUALS, + SDLK_LEFTBRACKET, + SDLK_RIGHTBRACKET, + SDLK_BACKSLASH, + SDLK_SLASH, + SDLK_DELETE, + SDLK_PERIOD +}; + int apiColorBackground(lua_State *L); int apiColorForeground(lua_State *L); @@ -194,16 +293,64 @@ int apiSingeQuit(lua_State *L); int apiSingeVersion(lua_State *L); int apiSingeSetGameName(lua_State *L); int apiSingeGetScriptPath(lua_State *L); +void callLua(const char *func, const char *sig, ...); int luaError(lua_State *L); +void processKey(bool down, int keysym); int apiColorBackground(lua_State *L) { + int n = lua_gettop(L); + if ((n == 3) || (n == 4)) { + if (lua_isinteger(L, 1)) { + if (lua_isinteger(L, 2)) { + if (lua_isinteger(L, 3)) { + _colorBackground.r = (byte)lua_tointeger(L, 1); + _colorBackground.g = (byte)lua_tointeger(L, 2); + _colorBackground.b = (byte)lua_tointeger(L, 3); + if (n == 3) { + _colorBackground.a = (byte)255; + } else { + if (lua_isinteger(L, 4)) { + _colorBackground.a = (byte)lua_tointeger(L, 4); + } else { + _colorBackground.a = (byte)255; + } + } + } + } + } + } + + return 0; } int apiColorForeground(lua_State *L) { + int n = lua_gettop(L); + if ((n == 3) || (n == 4)) { + if (lua_isinteger(L, 1)) { + if (lua_isinteger(L, 2)) { + if (lua_isinteger(L, 3)) { + _colorForeground.r = (byte)lua_tointeger(L, 1); + _colorForeground.g = (byte)lua_tointeger(L, 2); + _colorForeground.b = (byte)lua_tointeger(L, 3); + if (n == 3) { + _colorForeground.a = (byte)255; + } else { + if (lua_isinteger(L, 4)) { + _colorForeground.a = (byte)lua_tointeger(L, 4); + } else { + _colorForeground.a = (byte)255; + } + } + } + } + } + } + + return 0; } @@ -224,7 +371,37 @@ int apiDaphneGetWidth(lua_State *L) { int apiDaphneScreenshot(lua_State *L) { + int x = 0; + int y = 0; + Uint32 format = 0; + char filename[128]; + void *pixels = NULL; + SDL_Surface *surface = NULL; + SDL_Texture *texture = NULL; + (void)L; + + while (x <= 999) { + snprintf(filename, 128, "singe%03d", x); + if (!utilFileExists(filename)) break; + x++; + } + if (x > 999) utilDie("Seriously? You have 1000 screenshots in this folder? Remove some."); + + SDL_SetRenderTarget(_renderer, NULL); + texture = SDL_GetRenderTarget(_renderer); + SDL_QueryTexture(texture, &format, NULL, &x, &y); + pixels = malloc((size_t)x * (size_t)y * SDL_BYTESPERPIXEL(format)); + if (!pixels) utilDie("Unable to allocate screenshot."); + if (SDL_RenderReadPixels(_renderer, NULL, format, pixels, (Uint16)x * SDL_BYTESPERPIXEL(format)) < 0) utilDie("%s", SDL_GetError()); + surface = SDL_CreateRGBSurfaceWithFormatFrom(pixels, x, y, SDL_BITSPERPIXEL(format), (Uint16)x * SDL_BYTESPERPIXEL(format), format); + if (!surface) utilDie("%s", SDL_GetError()); + if (IMG_SavePNG(surface, filename) < 0) utilDie("%s", IMG_GetError()); + SDL_FreeSurface(surface); + free(pixels); + SDL_SetRenderTarget(_renderer, _overlay); + + return 0; } @@ -242,7 +419,25 @@ int apiDebugPrint(lua_State *L) { int apiDiscAudio(lua_State *L) { + int n = lua_gettop(L); + int channel = 0; + int left = 0; + int right = 0; + bool onOff = false; + if (n == 2) { + if (lua_isinteger(L, 1)) { + if (lua_isboolean(L, 2)) { + channel = (int)lua_tointeger(L, 1); + onOff = (bool)lua_toboolean(L, 2); + if ((channel == 1) && onOff) left = _confVolumeVldp; + if ((channel == 2) && onOff) right = _confVolumeVldp; + videoSetVolume(_videoHandle, left, right); + } + } + } + + return 0; } @@ -254,14 +449,20 @@ int apiDiscChangeSpeed(lua_State *L) { int apiDiscGetFrame(lua_State *L) { - lua_pushinteger(L, videoGetFrame(_videoHandle)); + if (_discStopped) { + lua_pushinteger(L, 0); + } else { + lua_pushinteger(L, videoGetFrame(_videoHandle)); + } return 1; } int apiDiscPause(lua_State *L) { (void)L; - videoPause(_videoHandle); + if (!_discStopped) { + videoPause(_videoHandle); + } return 0; } @@ -269,10 +470,12 @@ int apiDiscPause(lua_State *L) { int apiDiscPauseAtFrame(lua_State *L) { int n = lua_gettop(L); - if (n == 1) { - if (lua_isinteger(L, 1)) { - videoSeek(_videoHandle, (int)lua_tointeger(L, 1)); - videoPause(_videoHandle); + if (!_discStopped) { + if (n == 1) { + if (lua_isinteger(L, 1)) { + videoSeek(_videoHandle, (int)lua_tointeger(L, 1)); + videoPause(_videoHandle); + } } } @@ -283,15 +486,18 @@ int apiDiscPauseAtFrame(lua_State *L) { int apiDiscPlay(lua_State *L) { (void)L; videoPlay(_videoHandle); + _discStopped = false; } int apiDiscSearch(lua_State *L) { int n = lua_gettop(L); - if (n == 1) { - if (lua_isinteger(L, 1)) { - videoSeek(_videoHandle, (int)lua_tointeger(L, 1)); + if (!_discStopped) { + if (n == 1) { + if (lua_isinteger(L, 1)) { + videoSeek(_videoHandle, (int)lua_tointeger(L, 1)); + } } } @@ -316,9 +522,11 @@ int apiDiscSetFps(lua_State *L) { int apiDiscSkipBackward(lua_State *L) { int n = lua_gettop(L); - if (n == 1) { - if (lua_isinteger(L, 1)) { - videoSeek(_videoHandle, videoGetFrame(_videoHandle) - (int)lua_tointeger(L, 1)); + if (!_discStopped) { + if (n == 1) { + if (lua_isinteger(L, 1)) { + videoSeek(_videoHandle, videoGetFrame(_videoHandle) - (int)lua_tointeger(L, 1)); + } } } @@ -336,9 +544,11 @@ int apiDiscSkipBlanking(lua_State *L) { int apiDiscSkipForward(lua_State *L) { int n = lua_gettop(L); - if (n == 1) { - if (lua_isinteger(L, 1)) { - videoSeek(_videoHandle, videoGetFrame(_videoHandle) + (int)lua_tointeger(L, 1)); + if (!_discStopped) { + if (n == 1) { + if (lua_isinteger(L, 1)) { + videoSeek(_videoHandle, videoGetFrame(_videoHandle) + (int)lua_tointeger(L, 1)); + } } } @@ -354,22 +564,26 @@ int apiDiscSkipToFrame(lua_State *L) { int apiDiscStepBackward(lua_State *L) { (void)L; - videoSeek(_videoHandle, videoGetFrame(_videoHandle) - 1); + if (!_discStopped) { + videoSeek(_videoHandle, videoGetFrame(_videoHandle) - 1); + } return 0; } int apiDiscStepForward(lua_State *L) { (void)L; - videoSeek(_videoHandle, videoGetFrame(_videoHandle) + 1); + if (!_discStopped) { + videoSeek(_videoHandle, videoGetFrame(_videoHandle) + 1); + } return 0; } int apiDiscStop(lua_State *L) { (void)L; - //***TODO*** Add a real stopped state videoPause(_videoHandle); + _discStopped = true; } @@ -391,9 +605,9 @@ int apiFontLoad(lua_State *L) { font->font = TTF_OpenFont(name, points); if (!font->font) utilDie("%s", TTF_GetError()); // Make it the current font and mark it as loaded. - _fontCurrent = _nextFontId++; - font->id = _fontCurrent; - result = _fontCurrent; + font->id = _nextFontId; + result = _nextFontId++; + _fontCurrent = font; HASH_ADD_INT(_fontList, id, font); } } @@ -405,7 +619,53 @@ int apiFontLoad(lua_State *L) { int apiFontPrint(lua_State *L) { + int n = lua_gettop(L); + const char *message = NULL; + SDL_Surface *textSurface = NULL; + SDL_Texture *texture = NULL; + SDL_Rect dest; + if (n == 3) { + if (lua_isinteger(L, 1)) { + if (lua_isinteger(L, 2)) { + if (lua_isstring(L, 3)) { + if (_fontCurrent) { + dest.x = (int)lua_tointeger(L, 1); + dest.y = (int)lua_tointeger(L, 2); + textSurface = NULL; + message = lua_tostring(L, 3); + switch (_fontQuality) { + case 1: + textSurface = TTF_RenderText_Solid(_fontCurrent->font, message, _colorForeground); + break; + + case 2: + textSurface = TTF_RenderText_Shaded(_fontCurrent->font, message, _colorForeground, _colorBackground); + break; + + case 3: + textSurface = TTF_RenderText_Blended(_fontCurrent->font, message, _colorForeground); + break; + } + if (!textSurface) { + utilDie("Font surface is null!"); + } else { + SDL_SetSurfaceBlendMode(textSurface, SDL_BLENDMODE_BLEND); + // Transparent index is 0 + SDL_SetColorKey(textSurface, true, 0); + texture = SDL_CreateTextureFromSurface(_renderer, textSurface); + SDL_FreeSurface(textSurface); + if (!texture) utilDie("%s", SDL_GetError()); + if (SDL_QueryTexture(texture, NULL, NULL, &dest.w, &dest.h) < 0) utilDie("%s", SDL_GetError()); + SDL_RenderCopy(_renderer, texture, NULL, &dest); + } + } + } + } + } + } + + return 0; } @@ -443,7 +703,7 @@ int apiFontSelect(lua_State *L) { int apiFontToSprite(lua_State *L) { int n = lua_gettop(L); int result = -1; - const char *message = NULL; + const char *message = NULL; SDL_Surface *textSurface = NULL; SpriteT *sprite = NULL; @@ -525,7 +785,19 @@ int apiOverlayGetWidth(lua_State *L) { int apiOverlayPrint(lua_State *L) { + int n = lua_gettop(L); + if (n == 3) { + if (lua_isinteger(L, 1)) { + if (lua_isinteger(L, 2)) { + if (lua_isinteger(L, 3)) { + //***TODO*** g_pSingeIn->draw_string((char *)lua_tostring(L, 3), lua_tonumber(L, 1), lua_tonumber(L, 2), g_se_surface); + } + } + } + } + + return 0; } @@ -564,6 +836,7 @@ int apiSoundPlay(lua_State *L) { HASH_FIND_INT(_soundList, &id, sound); if (!sound) utilDie("No sound at index %d in apiSoundPlay.", id); result = Mix_PlayChannel(-1, sound->chunk, 0); + Mix_Volume(result, _effectsVolume * 2); } } lua_pushnumber(L, result); @@ -711,7 +984,6 @@ int apiSoundSetVolume(lua_State *L) { if (thisValue >= 0 && thisValue <= AUDIO_MAX_VOLUME) { _effectsVolume = thisValue; Mix_Volume(-1, _effectsVolume * 2); - //***TODO*** Handle laser volume } else { utilDie("Invalid sound volume value."); } @@ -862,7 +1134,37 @@ int apiVldpGetHeight(lua_State *L) { int apiVldpGetPixel(lua_State *L) { + int n = lua_gettop(L); + bool result = false; + byte pixel[SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_BGRA32)]; + SDL_Rect rect; + if (n == 2) { + if (lua_isinteger(L, 1)) { + if (lua_isinteger(L, 2)) { + rect.h = 1; + rect.w = 1; + rect.x = (int)lua_tointeger(L, 1); + rect.y = (int)lua_tointeger(L, 2); + SDL_SetRenderTarget(_renderer, NULL); + if (SDL_RenderReadPixels(_renderer, &rect, SDL_PIXELFORMAT_BGRA32, pixel, SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_BGRA32)) < 0) utilDie("%s", SDL_GetError()); + SDL_SetRenderTarget(_renderer, _overlay); + result = true; + } + } + } + + if (result) { + lua_pushinteger(L, (int)pixel[2]); // R + lua_pushinteger(L, (int)pixel[1]); // G + lua_pushinteger(L, (int)pixel[0]); // B + } else { + lua_pushinteger(L, -1); + lua_pushinteger(L, -1); + lua_pushinteger(L, -1); + } + + return 3; } @@ -917,7 +1219,7 @@ int apiKeyboardSetMode(lua_State *L) { int apiMouseEnable(lua_State *L) { // Enables mouse monitoring (void)L; - //***TODO*** g_pSingeIn->dll_side_mouse_enable(g_pSingeIn->pSingeInstance); + _mouseEnabled = (bool)!_confNoMouse; return 0; } @@ -925,7 +1227,7 @@ int apiMouseEnable(lua_State *L) { int apiMouseDisable(lua_State *L) { // Disables mouse monitoring (void)L; - //***TODO*** g_pSingeIn->dll_side_mouse_disable(g_pSingeIn->pSingeInstance); + _mouseEnabled = false; return 0; } @@ -949,24 +1251,22 @@ int apiMouseSetMode(lua_State *L) { // --rdg int n = lua_gettop(L); - int thisValue = 0; bool result = false; if (n == 1) { if (lua_isinteger(L, 1)) { - thisValue = (int)lua_tointeger(L, 1); - //***TODO*** result = g_pSingeIn->dll_side_set_mouse_mode(thisValue); - if (!result) utilDie("mouseSetMode failed. Is mouse enabled?"); + _mouseMode = (int)lua_tointeger(L, 1); + result = true; } } + lua_pushboolean(L, result); return 1; } int apiMouseHowMany(lua_State *L) { - int total = 1; //***TODO*** g_pSingeIn->dll_side_mouse_get_how_many(g_pSingeIn->pSingeInstance); - lua_pushinteger(L, total); + lua_pushinteger(L, _mouseCount); return 1; } @@ -985,9 +1285,8 @@ int apiDiscGetState(lua_State *L) { * */ - //***TODO*** Add a STOPPED state where a black screen is displayed // Our player isn't as sophisticated as the one in Daphne - lua_pushinteger(L, videoIsPlaying(_videoHandle) ? LDP_PLAYING : LDP_PAUSE); + lua_pushinteger(L, _discStopped ? LDP_STOPPED : (videoIsPlaying(_videoHandle) ? LDP_PLAYING : LDP_PAUSE)); return 1; } @@ -1067,7 +1366,8 @@ int apiSingeSetGameName(lua_State *L) { if (n == 1) { if (lua_isstring(L, 1)) { sprintf(thisName,"%.40s",lua_tostring(L, 1)); // Need a better way to do this... - //***TODO*** g_pSingeIn->dll_side_set_caption(g_pSingeIn->pSingeInstance, thisName); + SDL_SetWindowTitle(_window, thisName); + result = true; } } @@ -1200,18 +1500,99 @@ int luaError(lua_State *L) { } +void processKey(bool down, int keysym) { + int move; + + if (_keyboardMode == KEYBD_NORMAL) { + // Daphne keys + for (move=0; movetoggle_game_pause(); + } + if ((move == SWITCH_QUIT) || (keysym == SDLK_ESCAPE)) { + _running = false; + } + if (move == SWITCH_SCREENSHOT) { + //***TODO*** g_ldp->request_screenshot(); + } + } + if (move != SWITCH_PAUSE) { + callLua(down ? "onInputPressed" : "onInputReleased", "ii", move, NOMOUSE); + } + } + } + } else { + //***TODO*** Why is RDG filtering keys? + // Full keyboard + if (keysym >= SDLK_a && keysym <= SDLK_z) + callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE); + // check to see if key is a number on the top row of the keyboard (not keypad) + else if (keysym >= SDLK_MINUS && keysym <= SDLK_9) + callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE); + // numeric keypad keys + else if (keysym >= SDLK_KP_0 && keysym <= SDLK_KP_EQUALS) + callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE); + // arrow keys and insert, delete, home, end, pgup, pgdown + else if (keysym >= SDLK_UP && keysym <= SDLK_PAGEDOWN) + callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE); + // function keys + else if (keysym >= SDLK_F1 && keysym <= SDLK_F15) + callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE); + // Key state modifier keys (left and right ctrls, alts) + else if (keysym >= SDLK_NUMLOCKCLEAR && keysym <= SDLK_LGUI) + callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE); + // International keys + /* + else if (keysym >= SDLK_WORLD_0 && keysym <= SDLK_WORLD_95) + callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE); + */ + else { + /* + * SDLK_BACKSPACE, SDLK_TAB, SDLK_RETURN, SDLK_PAUSE, + * SDLK_SPACE, SDLK_QUOTE, SDLK_COMMA, SDLK_SEMICOLON, + * SDLK_EQUALS, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, + * SDLK_BACKSLASH, SDLK_SLASH, SDLK_DELETE, SDLK_PERIOD }; + */ + for (move=0; move MAX_MICE) { + _mouseCount = MAX_MICE; + } + memset(_mice, 0, sizeof(_mice)); + _mouseEnabled = (bool)!_confNoMouse; + for (x=0; x<_mouseCount; x++) { + strncpy(_mice[x].name, ManyMouse_DeviceName((unsigned)x), sizeof(_mice[x].name)); + _mice[x].name[sizeof(_mice[x].name) - 1] = 0; + _mice[x].x = videoGetWidth(_videoHandle) / 2; + _mice[x].y = videoGetHeight(_videoHandle) / 2; + } + SDL_SetWindowGrab(_window, SDL_TRUE); // Create overlay texture _overlay = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_TARGET, videoGetWidth(_videoHandle), videoGetHeight(_videoHandle)); if (_overlay == NULL) utilDie("%s", SDL_GetError()); + SDL_SetTextureBlendMode(_overlay, SDL_BLENDMODE_BLEND); if (_confStretchVideo) { SDL_RenderSetLogicalSize(_renderer, videoGetWidth(_videoHandle), videoGetHeight(_videoHandle)); } @@ -1313,39 +1711,118 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) { // Set volume _effectsVolume = (int)((float)AUDIO_MAX_VOLUME * (float)_confVolumeNonVldp * (float)0.01); Mix_Volume(-1, _effectsVolume * 2); - //***TODO*** Handle laser volume + + // Start video + videoPlay(_videoHandle); + _discStopped = false; + + //***TODO*** Sound completed callback // Game Loop while (_running) { - // Event Loop - SDL_Event event; + // SDL Event Loop while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - default: - //***TODO*** Process key - break; - } + processKey(true, event.key.keysym.sym); + //***TODO*** RDG used "g" to re-grab/re-scan for mice break; case SDL_KEYUP: - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - _running = false; - break; - - default: - //***TODO*** Process key - break; - } + processKey(false, event.key.keysym.sym); break; case SDL_QUIT: _running = 0; break; } + + // Mouse Event Loop + while (ManyMouse_PollEvent(&mouseEvent)) { + + if (mouseEvent.device >= (unsigned)_mouseCount) continue; + mouse = &_mice[mouseEvent.device]; + + switch (mouseEvent.type) { + case MANYMOUSE_EVENT_RELMOTION: + switch (mouseEvent.item) { + case 0: + mouse->relx += mouseEvent.value; + break; + + case 1: + mouse->rely += mouseEvent.value; + break; + } + // Clamp to video size + if (mouse->relx < 0) mouse->relx = 0; + if (mouse->relx > videoGetWidth(_videoHandle)) mouse->relx = videoGetWidth(_videoHandle) - 1; + if (mouse->rely < 0) mouse->rely = 0; + if (mouse->rely > videoGetHeight(_videoHandle)) mouse->rely = videoGetHeight(_videoHandle) - 1; + x *= _overlayScaleX; + y *= _overlayScaleY; + xr *= _overlayScaleX; + yr *= _overlayScaleY; + callLua("onMouseMoved", "iiiii", x, y, xr, yr, mouseEvent.device); + break; + + case MANYMOUSE_EVENT_ABSMOTION: + switch (mouseEvent.item) { + case 0: + mouse->x += mouseEvent.value; + break; + + case 1: + mouse->y += mouseEvent.value; + break; + } + x *= _overlayScaleX; + y *= _overlayScaleY; + xr *= _overlayScaleX; + yr *= _overlayScaleY; + callLua("onMouseMoved", "iiiii", x, y, xr, yr, mouseEvent.device); + break; + + case MANYMOUSE_EVENT_BUTTON: + if (mouseEvent.item < 32) { + if (mouseEvent.value == 1) { + // Button pressed + callLua("onInputPressed", "ii", mouseButtonMap[mouseEvent.item], mouseEvent.device); + mouse->buttons |= (1 << mouseEvent.item); + } else { + // Button released + callLua("onInputReleased", "ii", mouseButtonMap[mouseEvent.item], mouseEvent.device); + mouse->buttons &= ~(1 << mouseEvent.item); + } + } + break; + + case MANYMOUSE_EVENT_SCROLL: + if (mouseEvent.item == 0) { + if (mouseEvent.value > 0) { + // Scroll up + callLua("onInputPressed", "ii", SWITCH_MOUSE_SCROLL_UP, mouseEvent.device); + callLua("onInputReleased", "ii", SWITCH_MOUSE_SCROLL_UP, mouseEvent.device); + } else { + // Scroll down + callLua("onInputPressed", "ii", SWITCH_MOUSE_SCROLL_DOWN, mouseEvent.device); + callLua("onInputReleased", "ii", SWITCH_MOUSE_SCROLL_DOWN, mouseEvent.device); + } + } + break; + + case MANYMOUSE_EVENT_DISCONNECT: + mouse->connected = false; + callLua("onInputPressed", "ii", SWITCH_MOUSE_DISCONNECT, mouseEvent.device); + callLua("onInputReleased", "ii", SWITCH_MOUSE_DISCONNECT, mouseEvent.device); + break; + + case MANYMOUSE_EVENT_MAX: + // We don't use this + break; + } + } } // Call game code @@ -1412,4 +1889,7 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) { // Unload video videoUnload(_videoHandle); + + // Stop mice + ManyMouse_Quit(); } diff --git a/singe/videoPlayer.c b/singe/videoPlayer.c index 7538bf72d..c9d52df18 100644 --- a/singe/videoPlayer.c +++ b/singe/videoPlayer.c @@ -44,6 +44,8 @@ typedef struct VideoPlayerS { byte audioSampleBytes; byte *audioSilenceRaw; char errMsg[1024]; + int volumeLeft; + int volumeRight; int audioTrack; int videoTrack; int frame; @@ -91,6 +93,9 @@ void _dequeueVideoAudio(int channel, void *stream, int bytes, void *udata) { int bytesToCopy = bytes; int available = SDL_AudioStreamAvailable(v->audioStream); int remainder = 0; + int bytesRead = 0; + int i = 0; + Sint16 *data = stream; (void)channel; @@ -103,7 +108,22 @@ void _dequeueVideoAudio(int channel, void *stream, int bytes, void *udata) { remainder = bytesToCopy % v->audioSampleSize; bytesToCopy -= remainder; - if (SDL_AudioStreamGet(v->audioStream, stream, bytesToCopy) < 0) utilDie("%s", SDL_GetError()); + // Read audio data + bytesRead = SDL_AudioStreamGet(v->audioStream, stream, bytesToCopy); + if (bytesRead < 0) utilDie("%s", SDL_GetError()); + + // We do our own volume per channel here in the mixer + if (_mixChannels < 2) { + // Mono output, average volume levels together + Mix_Volume(channel, (int)((float)MIX_MAX_VOLUME * ((float)v->volumeLeft * (float)v->volumeRight / (float)2) * (float)0.01)); + } else { + // Stereo output. Assumes MIX_DEFAULT_FORMAT for now. + Mix_Volume(channel, MIX_MAX_VOLUME); + for (i=0; ivolumeLeft * (float)0.01); + data[i + 1] = (Sint16)((float)data[i] * (float)v->volumeRight * (float)0.01); + } + } } @@ -120,6 +140,7 @@ int FFMS_CC _indexCallBack(int64_t current, int64_t total, void *ICPrivate) { if (thisPercent != lastPercent) { lastPercent = thisPercent; utilSay("Indexing: %d%%", thisPercent); + //***TODO*** GUI } } @@ -138,6 +159,9 @@ int videoInit(void) { if (!Mix_QuerySpec(&_mixRate, &_mixFormat, &channels)) utilDie("%s", Mix_GetError()); _mixChannels = (Uint8)channels; + // Volume only works with MIX_DEFAULT_FORMAT + if (_mixFormat != MIX_DEFAULT_FORMAT) utilDie("videoInit: Only MIX_DEFAULT_FORMAT audio is supported."); + return 0; } @@ -186,6 +210,20 @@ int videoGetWidth(int playerIndex) { } +int videoGetVolume(int playerIndex, int *leftPercent, int *rightPercent) { + VideoPlayerT *v = NULL; + + // Get our player structure + HASH_FIND_INT(_videoPlayerHash, &playerIndex, v); + if (!v) utilDie("No video player at index %d in videoGetVolume.", playerIndex); + + if (leftPercent != NULL) *leftPercent = v->volumeLeft; + if (rightPercent != NULL) *rightPercent = v->volumeRight; + + return 0; +} + + int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer) { char indexName[1024]; int pixelFormats[2]; @@ -321,6 +359,10 @@ int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer * // Register effect to provide video stream audio on this channel Mix_RegisterEffect(v->audioSilenceChannel, _dequeueVideoAudio, NULL, v); + // Default volume, in percent + v->volumeLeft = 100; + v->volumeRight = 100; + /* utilSay("Frames: %d (%dx%d) Audio Samples: %ld (%d Hz) %d Channel%s", v->videoProps->NumFrames, @@ -407,6 +449,20 @@ int videoSeek(int playerIndex, int seekFrame) { } +int videoSetVolume(int playerIndex, int leftPercent, int rightPercent) { + VideoPlayerT *v = NULL; + + // Get our player structure + HASH_FIND_INT(_videoPlayerHash, &playerIndex, v); + if (!v) utilDie("No video player at index %d in videoSetVolume.", playerIndex); + + v->volumeLeft = leftPercent; + v->volumeRight = rightPercent; + + return 0; +} + + int videoUnload(int playerIndex) { VideoPlayerT *v = NULL; diff --git a/singe/videoPlayer.h b/singe/videoPlayer.h index 564ae1e70..d76b3ea75 100644 --- a/singe/videoPlayer.h +++ b/singe/videoPlayer.h @@ -34,11 +34,13 @@ int videoIsPlaying(int playerIndex); int videoGetFrame(int playerIndex); int videoGetHeight(int playerIndex); int videoGetWidth(int playerIndex); +int videoGetVolume(int playerIndex, int *leftPercent, int *rightPercent); int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer); int videoPause(int playerIndex); int videoPlay(int playerIndex); int videoQuit(void); int videoSeek(int playerIndex, int seekFrame); +int videoSetVolume(int playerIndex, int leftPercent, int rightPercent); int videoUnload(int playerIndex); int videoUpdate(int playerIndex, SDL_Texture **texture);