From fa91f8e2817bd7feb6463793e4984d6ff64e3396 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Wed, 4 Dec 2019 21:32:31 -0600 Subject: [PATCH] Massive amount of untested Singe code added. --- singe/main.c | 158 +++-- singe/singe.c | 1368 +++++++++++++++++++++++++++++++++++++++++++ singe/singe.h | 12 + singe/videoPlayer.c | 43 +- singe/videoPlayer.h | 7 +- 5 files changed, 1493 insertions(+), 95 deletions(-) diff --git a/singe/main.c b/singe/main.c index 7233f1ecc..6641c7d5b 100644 --- a/singe/main.c +++ b/singe/main.c @@ -37,10 +37,6 @@ #include "extensions.h" -#define VERSION_STRING "v2.00" -#define COPYRIGHT_END_YEAR "2020" - - typedef struct RatioS { int aspectNum; int aspectDom; @@ -85,6 +81,8 @@ void showUsage(char *name, char *message) { // 00000000011111111112222222222333333333344444444445555555555666666666677777777778 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 utilSay(" -z, --scalefactor=PERCENT reduce screen size for overscan compensation"); + utilSay(" -a, --aspect=N:D force aspect ratio"); + utilSay(" -u, --stretch use ugly stretched video"); utilSay(" -x, --xresolution=VALUE specify horizontal resolution"); utilSay(" -y, --yresolution=VALUE specify vertical resolution"); utilSay(" -h, --help this display"); @@ -103,36 +101,36 @@ int main(int argc, char *argv[]) { int x = 0; int err = 0; int flags = 0; - int thisFrame = -1; - int lastFrame = -1; - int videoHandle = -1; int optionIndex = 0; int bestResIndex = -1; int bestRatioIndex = -1; + int aspectNum = -1; + int aspectDom = -1; char *temp = NULL; + char *aspectString = NULL; float thisRatio = 0; float bestRatio = 9999; - bool running = true; SDL_Window *window = NULL; SDL_Renderer *renderer = NULL; - SDL_Texture *texture = NULL; SDL_DisplayMode mode; static struct option options[] = { - { "nomouse", no_argument, NULL, 'm' }, - { "noserversend", no_argument, NULL, 'n' }, - { "nosound", no_argument, NULL, 's' }, - { "mutesound", no_argument, NULL, 's' }, - { "fullscreen", no_argument, NULL, 'f' }, - { "fullscreen_window", no_argument, NULL, 'w' }, - { "datadir", optional_argument, NULL, 'd' }, - { "framefile", optional_argument, NULL, 'v' }, - { "volume_vldp", optional_argument, NULL, 'l' }, - { "volume_nonlvdp", optional_argument, NULL, 'e' }, - { "scalefactor", optional_argument, NULL, 'z' }, - { "xresolution", optional_argument, NULL, 'x' }, - { "yresolution", optional_argument, NULL, 'y' }, - { "help", no_argument, NULL, 'h' }, - { NULL, 0, NULL, 0 } + { "nomouse", no_argument, NULL, 'm' }, + { "noserversend", no_argument, NULL, 'n' }, + { "nosound", no_argument, NULL, 's' }, + { "mutesound", no_argument, NULL, 's' }, + { "fullscreen", no_argument, NULL, 'f' }, + { "fullscreen_window", no_argument, NULL, 'w' }, + { "stretch", no_argument, NULL, 'u' }, + { "datadir", optional_argument, NULL, 'd' }, + { "framefile", optional_argument, NULL, 'v' }, + { "volume_vldp", optional_argument, NULL, 'l' }, + { "volume_nonlvdp", optional_argument, NULL, 'e' }, + { "scalefactor", optional_argument, NULL, 'z' }, + { "aspect", optional_argument, NULL, 'a' }, + { "xresolution", optional_argument, NULL, 'x' }, + { "yresolution", optional_argument, NULL, 'y' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } }; static ModeT modes[] = { { { 4, 3 }, { 640, 480 } }, @@ -167,7 +165,7 @@ int main(int argc, char *argv[]) { while (true) { optionIndex = 0; opterr = 0; - x = getopt_long(argc, argv, "mnsfwhd:v:l:e:z:x:y:", options, &optionIndex); + x = getopt_long(argc, argv, "mnsfwha:d:v:l:e:z:x:y:", options, &optionIndex); // Out of options? if (x == -1) break; @@ -199,6 +197,11 @@ int main(int argc, char *argv[]) { _confFullScreenWindow = true; break; + // Ugly Stretched Video + case 'u': + _confStretchVideo = true; + break; + // Video File case 'v': if (_confVideoFile) free(_confVideoFile); @@ -226,6 +229,12 @@ int main(int argc, char *argv[]) { _confScaleFactor = atoi(optarg); break; + // Aspect + case 'a': + if (aspectString) free(aspectString); + aspectString = strdup(optarg); + break; + // X Resolution case 'x': _confXResolution = atoi(optarg); @@ -339,16 +348,39 @@ int main(int argc, char *argv[]) { // Determine resolution if not specified if ((_confXResolution <= 0) || (_confYResolution <= 0)) { - // Find our current aspect ratio - x = 0; - while (modes[x].ratio.aspectNum != 0) { - thisRatio = fabsf(((float)modes[x].ratio.aspectNum / (float)modes[x].ratio.aspectDom) - ((float)mode.w / (float)mode.h)); - if (thisRatio < bestRatio) { - bestRatio = thisRatio; - bestRatioIndex = x; + // Did they specify an aspect ratio? + if (aspectString) { + aspectNum = atoi(aspectString); + temp = strstr(aspectString, ":"); + if (temp) { + temp++; + aspectDom = atoi(temp); + temp = NULL; + } + if ((aspectNum > 0) && (aspectDom > 0)) { + // Do we understand what they asked for? + x = 0; + while (modes[x].ratio.aspectNum != 0) { + if ((modes[x].ratio.aspectNum == aspectNum) && (modes[x].ratio.aspectDom == aspectDom)) { + bestRatioIndex = x; + break; + } + x++; + } + } + } else { + // Find our current aspect ratio + x = 0; + while (modes[x].ratio.aspectNum != 0) { + thisRatio = fabsf(((float)modes[x].ratio.aspectNum / (float)modes[x].ratio.aspectDom) - ((float)mode.w / (float)mode.h)); + if (thisRatio < bestRatio) { + bestRatio = thisRatio; + bestRatioIndex = x; + } + x++; } - x++; } + if (bestRatioIndex < 0) showUsage(argv[0], "Unknown aspect ratio."); x = 0; // Were both resolutions not specified? if ((_confXResolution <= 0) && (_confYResolution <= 0)) { @@ -436,65 +468,13 @@ int main(int argc, char *argv[]) { err = Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 44100 /* freq */ * 16 /* bits */ * 2 /* channels */ * 2 /* seconds */); if (err != 0) utilDie("%s", Mix_GetError()); + // Start our video playback system + if (videoInit()) utilDie("Unable to initialize video player."); + // Finish our setup SDL_DisableScreenSaver(); - if (videoInit()) utilDie("Unable to initialize video player."); - - videoHandle = videoLoad(_confVideoFile, _confDataDir, renderer); - if (videoHandle < 0) utilDie("Unable to load video file: %s", _confVideoFile); - - videoPlay(videoHandle); - - while (running) { - - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYUP: - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - running = false; - break; - case SDLK_SPACE: - if (videoIsPlaying(videoHandle)) { - videoPause(videoHandle); - } else { - videoPlay(videoHandle); - } - break; - case SDLK_RIGHT: - videoSeek(videoHandle, lastFrame + 1); - break; - case SDLK_LEFT: - videoSeek(videoHandle, lastFrame - 1); - break; - case SDLK_UP: - videoSeek(videoHandle, lastFrame + 100); - break; - case SDLK_DOWN: - videoSeek(videoHandle, lastFrame - 100); - break; - } - break; - - case SDL_QUIT: - running = 0; - break; - } - } - - thisFrame = videoUpdate(videoHandle, &texture); - if ((thisFrame != lastFrame) && (thisFrame >= 0)) { - utilSay("Presenting frame %d", thisFrame); - lastFrame = thisFrame; - SDL_RenderCopy(renderer, texture, NULL, NULL); - SDL_RenderPresent(renderer); - } - } - - videoUnload(videoHandle); - + singe(window, renderer); // Shutdown videoQuit(); diff --git a/singe/singe.c b/singe/singe.c index cbb361365..e20f8af3c 100644 --- a/singe/singe.c +++ b/singe/singe.c @@ -20,6 +20,12 @@ */ +#include + +#include +#include +#include +#include #include #include #include @@ -28,13 +34,66 @@ #include "common.h" #include "util.h" +#include "videoPlayer.h" #include "singe.h" +#define AUDIO_MAX_VOLUME 63 +#define MAX_TITLE_LENGTH 1024 + + +typedef struct SpriteS { + int id; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpadded" + SDL_Texture *texture; +#pragma GCC diagnostic pop + UT_hash_handle hh; +} SpriteT; + +typedef struct SoundS { + int id; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpadded" + Mix_Chunk *chunk; +#pragma GCC diagnostic pop + UT_hash_handle hh; +} SoundT; + +typedef struct FontS { + int id; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpadded" + TTF_Font *font; +#pragma GCC diagnostic pop + UT_hash_handle hh; +} FontT; + + +enum { + KEYBD_NORMAL = 0, + KEYBD_FULL +}; + +enum { + MOUSE_SINGLE = 100, + MOUSE_MANY = 200 +}; + +enum { + LDP_ERROR = 0, + LDP_SEARCHING, + LDP_STOPPED, + LDP_PLAYING, + LDP_PAUSE, +}; + + // Command line options char *_confVideoFile = NULL; char *_confScriptFile = NULL; char *_confDataDir = NULL; +int _confStretchVideo = false; int _confNoMouse = false; int _confNoStats = false; int _confNoSound = false; @@ -45,3 +104,1312 @@ int _confVolumeNonVldp = 100; int _confScaleFactor = 100; int _confXResolution = -1; int _confYResolution = -1; + + +// Other globals +static lua_State *_luaContext = NULL; +static SDL_Color _colorForeground = { 255, 255, 255, 255 }; +static SDL_Color _colorBackground = { 0, 0, 0, 255 }; +static SDL_Texture *_overlay = NULL; +static SDL_Window *_window = NULL; +static SDL_Renderer *_renderer = NULL; +static int _nextSpriteId = 0; +static int _nextSoundId = 0; +static int _nextFontId = 0; +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 bool _pauseState = false; // by RDG2010 +static bool _pauseEnabled = true; // by RDG2010 +static bool _running = true; +static SpriteT *_spriteList = NULL; +static SoundT *_soundList = NULL; +static FontT *_fontList = NULL; +static FontT *_fontCurrent = NULL; + + +int apiColorBackground(lua_State *L); +int apiColorForeground(lua_State *L); +int apiDaphneGetHeight(lua_State *L); +int apiDaphneGetWidth(lua_State *L); +int apiDaphneScreenshot(lua_State *L); +int apiDebugPrint(lua_State *L); +int apiDiscAudio(lua_State *L); +int apiDiscChangeSpeed(lua_State *L); +int apiDiscGetFrame(lua_State *L); +int apiDiscPause(lua_State *L); +int apiDiscPauseAtFrame(lua_State *L); +int apiDiscPlay(lua_State *L); +int apiDiscSearch(lua_State *L); +int apiDiscSearchBlanking(lua_State *L); +int apiDiscSetFps(lua_State *L); +int apiDiscSkipBackward(lua_State *L); +int apiDiscSkipBlanking(lua_State *L); +int apiDiscSkipForward(lua_State *L); +int apiDiscSkipToFrame(lua_State *L); +int apiDiscStepBackward(lua_State *L); +int apiDiscStepForward(lua_State *L); +int apiDiscStop(lua_State *L); +int apiFontLoad(lua_State *L); +int apiFontPrint(lua_State *L); +int apiFontQuality(lua_State *L); +int apiFontSelect(lua_State *L); +int apiFontToSprite(lua_State *L); +int apiOverlayClear(lua_State *L); +int apiOverlayGetHeight(lua_State *L); +int apiOverlayGetWidth(lua_State *L); +int apiOverlayPrint(lua_State *L); +int apiSoundLoad(lua_State *L); +int apiSoundPlay(lua_State *L); +int apiSoundPause(lua_State *L); +int apiSoundResume(lua_State *L); +int apiSoundIsPlaying(lua_State *L); +int apiSoundStop(lua_State *L); +int apiSoundSetVolume(lua_State *L); +int apiSoundGetVolume(lua_State *L); +int apiSoundFullStop(lua_State *L); +int apiSpriteDraw(lua_State *L); +int apiSpriteGetHeight(lua_State *L); +int apiSpriteGetWidth(lua_State *L); +int apiSpriteLoad(lua_State *L); +int apiVldpGetHeight(lua_State *L); +int apiVldpGetPixel(lua_State *L); +int apiVldpGetWidth(lua_State *L); +int apiVldpVerbose(lua_State *L); +int apiKeyboardGetMode(lua_State *L); +int apiKeyboardSetMode(lua_State *L); +int apiMouseEnable(lua_State *L); +int apiMouseDisable(lua_State *L); +int apiMouseSetMode(lua_State *L); +int apiMouseHowMany(lua_State *L); +int apiDiscGetState(lua_State *L); +int apiSingeGetPauseFlag(lua_State *L); +int apiSingeSetPauseFlag(lua_State *L); +int apiSingeEnablePauseKey(lua_State *L); +int apiSingeDisablePauseKey(lua_State *L); +int apiSingeQuit(lua_State *L); +int apiSingeVersion(lua_State *L); +int apiSingeSetGameName(lua_State *L); +int apiSingeGetScriptPath(lua_State *L); +int luaError(lua_State *L); + + +int apiColorBackground(lua_State *L) { + +} + + +int apiColorForeground(lua_State *L) { + +} + + +int apiDaphneGetHeight(lua_State *L) { + int y; + SDL_GetWindowSize(_window, NULL, &y); + lua_pushinteger(L, y); + return 1; +} + + +int apiDaphneGetWidth(lua_State *L) { + int x; + SDL_GetWindowSize(_window, &x, NULL); + lua_pushinteger(L, x); + return 1; +} + + +int apiDaphneScreenshot(lua_State *L) { + +} + + +int apiDebugPrint(lua_State *L) { + int n = lua_gettop(L); + + if (n == 1) { + if (lua_isstring(L, 1)) { + utilSay("%s", lua_tostring(L, 1)); + } + } + + return 0; +} + + +int apiDiscAudio(lua_State *L) { + +} + + +int apiDiscChangeSpeed(lua_State *L) { + (void)L; + //***REMOVED*** + return 0; +} + + +int apiDiscGetFrame(lua_State *L) { + lua_pushinteger(L, videoGetFrame(_videoHandle)); + return 1; +} + + +int apiDiscPause(lua_State *L) { + (void)L; + videoPause(_videoHandle); + return 0; +} + + +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); + } + } + + return 0; +} + + +int apiDiscPlay(lua_State *L) { + (void)L; + videoPlay(_videoHandle); +} + + +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)); + } + } + + return 0; +} + + +int apiDiscSearchBlanking(lua_State *L) { + (void)L; + //***REMOVED*** + return 0; +} + + +int apiDiscSetFps(lua_State *L) { + (void)L; + //***REMOVED*** + return 0; +} + + +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)); + } + } + + return 0; +} + + +int apiDiscSkipBlanking(lua_State *L) { + (void)L; + //***REMOVED*** + return 0; +} + + +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)); + } + } + + return 0; +} + + +int apiDiscSkipToFrame(lua_State *L) { + // Not really sure what this is, so just seek to a new frame. + return apiDiscSearch(L); +} + + +int apiDiscStepBackward(lua_State *L) { + (void)L; + videoSeek(_videoHandle, videoGetFrame(_videoHandle) - 1); + return 0; +} + + +int apiDiscStepForward(lua_State *L) { + (void)L; + videoSeek(_videoHandle, videoGetFrame(_videoHandle) + 1); + return 0; +} + + +int apiDiscStop(lua_State *L) { + (void)L; + //***TODO*** Add a real stopped state + videoPause(_videoHandle); +} + + +int apiFontLoad(lua_State *L) { + int n = lua_gettop(L); + int result = -1; + int points = 0; + const char *name = NULL; + FontT *font = NULL; + + if (n == 2) { + if (lua_isstring(L, 1)) { + if (lua_isinteger(L, 2)) { + name = lua_tostring(L, 1); + points = (int)lua_tointeger(L, 2); + font = (FontT *)calloc(1, sizeof(FontT)); + if (!font) utilDie("Unable to allocate new font."); + // Load this font. + 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; + HASH_ADD_INT(_fontList, id, font); + } + } + } + + lua_pushnumber(L, result); + return 1; +} + + +int apiFontPrint(lua_State *L) { + +} + + +int apiFontQuality(lua_State *L) { + int n = lua_gettop(L); + + if (n == 1) { + if (lua_isinteger(L, 1)) { + _fontQuality = (int)lua_tointeger(L, 1); + } + } + + return 0; +} + + +int apiFontSelect(lua_State *L) { + int n = lua_gettop(L); + int id = -1; + FontT *font = NULL; + + if (n == 1) { + if (lua_isinteger(L, 1)) { + id = (int)lua_tointeger(L, 1); + HASH_FIND_INT(_fontList, &id, font); + if (!font) utilDie("No font at index %d in apiSpriteGetWidth.", id); + _fontCurrent = font; + } + } + + return 0; +} + + +int apiFontToSprite(lua_State *L) { + int n = lua_gettop(L); + int result = -1; + const char *message = NULL; + SDL_Surface *textSurface = NULL; + SpriteT *sprite = NULL; + + if (n == 1) { + if (lua_isstring(L, 1)) { + if (_fontCurrent) { + textSurface = NULL; + message = lua_tostring(L, 1); + 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); + // Create spirte + sprite = (SpriteT *)calloc(1, sizeof(SpriteT)); + if (!sprite) utilDie("Unable to allocate new text sprite."); + sprite->texture = SDL_CreateTextureFromSurface(_renderer, textSurface); + SDL_FreeSurface(textSurface); + if (!sprite->texture) utilDie("%s", SDL_GetError()); + sprite->id = _nextSpriteId; + result = _nextSpriteId++; + HASH_ADD_INT(_spriteList, id, sprite); + } + } + } + } + + lua_pushinteger(L, result); + return 1; +} + + +int apiOverlayClear(lua_State *L) { + (void)L; + SDL_SetRenderDrawColor(_renderer, _colorBackground.r, _colorBackground.g, _colorBackground.b, _colorBackground.a); + SDL_RenderClear(_renderer); +} + + +int apiOverlayGetHeight(lua_State *L) { + Uint32 format; + int access; + int x; + int y; + + if (SDL_QueryTexture(_overlay, &format, &access, &x, &y) < 0) utilDie("%s", SDL_GetError()); + + lua_pushinteger(L, y); + return 1; +} + + +int apiOverlayGetWidth(lua_State *L) { + Uint32 format; + int access; + int x; + int y; + + if (SDL_QueryTexture(_overlay, &format, &access, &x, &y) < 0) utilDie("%s", SDL_GetError()); + + lua_pushinteger(L, x); + return 1; +} + + +int apiOverlayPrint(lua_State *L) { + +} + + +int apiSoundLoad(lua_State *L) { + int n = lua_gettop(L); + int result = -1; + SoundT *sound = NULL; + + if (n == 1) { + if (lua_isstring(L, 1)) { + sound = (SoundT *)calloc(1, sizeof(SoundT)); + if (!sound) utilDie("Unable to allocate new sound."); + sound->chunk = Mix_LoadWAV(lua_tostring(L, 1)); + if (!sound->chunk) utilDie("%s", Mix_GetError()); + sound->id = _nextSoundId; + result = _nextSoundId++; + HASH_ADD_INT(_soundList, id, sound); + } + } + + lua_pushnumber(L, result); + return 1; +} + + +int apiSoundPlay(lua_State *L) { + int n = lua_gettop(L); + int result = -1; + int id = -1; + SoundT *sound = NULL; + + if (n == 1) { + if (lua_isinteger(L, 1)) { + id = (int)lua_tointeger(L, 1); + // Get our sound structure + HASH_FIND_INT(_soundList, &id, sound); + if (!sound) utilDie("No sound at index %d in apiSoundPlay.", id); + result = Mix_PlayChannel(-1, sound->chunk, 0); + } + } + lua_pushnumber(L, result); + return 1; +} + + +int apiSoundPause(lua_State *L) { + // Instructs Daphne to pause a given sample from playing. + // User must feed the sound handle on the lua side. + // e.g. lua code, + // + // thisHandle = soundPlay(mySound) + // soundPause(thisHandle) + // + // Function returns true if sample was paused, false otherwise. + // + // --rdg + + int n = lua_gettop(L); + bool result = false; + int channel = -1; + + if (n == 1) { + if (lua_isinteger(L, 1)) { + channel = (int)lua_tointeger(L, 1); + Mix_Pause(channel); + result = true; + } + } + + lua_pushboolean(L, result); + return 1; +} + + +int apiSoundResume(lua_State *L) { + // Instructs Daphne to unpause a sound that was previously paused. + // User must feed the sound handle on the lua side. + // e.g. lua code, + // + // thisHandle = soundPlay(mySound) + // soundPause(thisHandle) + // soundResume(thisHandle) + // + // Function returns true if sample was unpaused, false otherwise. + // + // --rdg + + int n = lua_gettop(L); + bool result = false; + int channel = -1; + + if (n == 1) { + if (lua_isinteger(L, 1)) { + channel = (int)lua_tointeger(L, 1); + Mix_Resume(channel); + result = true; + } + } + + lua_pushboolean(L, result); + return 1; +} + + +int apiSoundIsPlaying(lua_State *L) { + // Checks to see if a certain sound has finished playing. + // User must feed the sound handle on the lua side. + // e.g. lua code, + // + // thisHandle = soundPlay(mySound) + // if (soundIsPlaying(thisSound)) then do something ... end + // + // Function returns true if sample is still playing, false otherwise. + // + // --rdg + + int n = lua_gettop(L); + bool result = false; + int channel = -1; + + if (n == 1) { + if (lua_isinteger(L, 1)) { + channel = (int)lua_tointeger(L, 1); + result = (bool)Mix_Playing(channel); + } + } + + lua_pushboolean(L, result); + return 1; +} + + +int apiSoundStop(lua_State *L) { + // Instructs Daphne to end a sound early. + // User must feed the sound handle on the lua side. + // e.g. lua code, + // + // thisHandle = soundPlay(mySound) + // soundStop(thisHandle) + // + // Function returns true if sample was stopped, false otherwise. + // NOTE: thisHandle will be invalidated as a result of this function. + // Lua doesn't do variables by reference, so it is + // up to the user to keep track of sound handles on the lua script. + // + // --rdg + + int n = lua_gettop(L); + bool result = false; + int channel = -1; + + if (n == 1) { + if (lua_isinteger(L, 1)) { + channel = (int)lua_tointeger(L, 1); + Mix_HaltChannel(channel); + result = true; + } + } + + lua_pushboolean(L, result); + return 1; +} + + +int apiSoundSetVolume(lua_State *L) { + // Allows manipulation of sample volume. + // Valid values range from 0 to 63 + // e.g. lua code, + // + // soundSetVolume(32) + // + // Function returns nothing. + // + // --rdg + + int n = lua_gettop(L); + bool result = false; + int thisValue = 0; + + if (n == 1) { + if (lua_isinteger(L, 1)) { + thisValue = (int)lua_tointeger(L, 1); + if (thisValue >= 0 && thisValue <= AUDIO_MAX_VOLUME) { + _effectsVolume = thisValue; + Mix_Volume(-1, _effectsVolume * 2); + //***TODO*** Handle laser volume + } else { + utilDie("Invalid sound volume value."); + } + } + } + + lua_pushboolean(L, result); + return 0; +} + + +int apiSoundGetVolume(lua_State *L) { + // Returns the current sample volume value. + // e.g. lua code, + // + // local iVolume = soundGetVolume() + // + // Function returns an integer value ranging from 0 to 63. + // + // --rdg + + lua_pushinteger(L, _effectsVolume); + return 1; +} + + +int apiSoundFullStop(lua_State *L) { + // Clears the audio queue of any samples actively playing. + // No parameters needed. Function returns nothing. + // e.g. lua code, + // + // soundFullStop() + + (void)L; + Mix_HaltChannel(-1); + return 0; +} + + +int apiSpriteDraw(lua_State *L) { + int n = lua_gettop(L); + int id = -1; + SpriteT *sprite = NULL; + SDL_Rect dest; + + if (n == 3) { + if (lua_isinteger(L, 1)) { + if (lua_isinteger(L, 2)) { + if (lua_isinteger(L, 3)) { + id = (int)lua_tointeger(L, 1); + dest.x = (int)lua_tointeger(L, 2); + dest.y = (int)lua_tointeger(L, 3); + HASH_FIND_INT(_spriteList, &id, sprite); + if (!sprite) utilDie("No sprite at index %d in apiSpriteGetWidth.", id); + if (SDL_QueryTexture(sprite->texture, NULL, NULL, &dest.w, &dest.h) < 0) utilDie("%s", SDL_GetError()); + SDL_RenderCopy(_renderer, sprite->texture, NULL, &dest); + } + } + } + } + + return 0; +} + + +int apiSpriteGetHeight(lua_State *L) { + int n = lua_gettop(L); + int result = -1; + int id = -1; + int access; + int x; + int y; + Uint32 format; + SpriteT *sprite = NULL; + + if (n == 1) { + if (lua_isstring(L, 1)) { + id = (int)lua_tointeger(L, 1); + // Get our sprite structure + HASH_FIND_INT(_spriteList, &id, sprite); + if (!sprite) utilDie("No sprite at index %d in apiSpriteGetWidth.", id); + if (SDL_QueryTexture(sprite->texture, &format, &access, &x, &y) < 0) utilDie("%s", SDL_GetError()); + result = y; + } + } + + lua_pushinteger(L, result); + return 1; +} + + +int apiSpriteGetWidth(lua_State *L) { + int n = lua_gettop(L); + int result = -1; + int id = -1; + int access; + int x; + int y; + Uint32 format; + SpriteT *sprite = NULL; + + if (n == 1) { + if (lua_isstring(L, 1)) { + id = (int)lua_tointeger(L, 1); + // Get our sprite structure + HASH_FIND_INT(_spriteList, &id, sprite); + if (!sprite) utilDie("No sprite at index %d in apiSpriteGetWidth.", id); + if (SDL_QueryTexture(sprite->texture, &format, &access, &x, &y) < 0) utilDie("%s", SDL_GetError()); + result = x; + } + } + + lua_pushinteger(L, result); + return 1; +} + + +int apiSpriteLoad(lua_State *L) { + int n = lua_gettop(L); + int result = -1; + SpriteT *sprite = NULL; + SDL_Surface *image = NULL; + + if (n == 1) { + if (lua_isstring(L, 1)) { + image = IMG_Load(lua_tostring(L, 1)); + if (!image) utilDie("%s", IMG_GetError()); + sprite = (SpriteT *)calloc(1, sizeof(SpriteT)); + if (!sprite) utilDie("Unable to allocate new sprite."); + sprite->texture = SDL_CreateTextureFromSurface(_renderer, image); + SDL_FreeSurface(image); + if (!sprite->texture) utilDie("%s", SDL_GetError()); + sprite->id = _nextSpriteId; + result = _nextSpriteId++; + HASH_ADD_INT(_spriteList, id, sprite); + } + } + + lua_pushnumber(L, result); + return 1; +} + + +int apiVldpGetHeight(lua_State *L) { + lua_pushinteger(L, videoGetHeight(_videoHandle)); + return 1; +} + + +int apiVldpGetPixel(lua_State *L) { + +} + + +int apiVldpGetWidth(lua_State *L) { + lua_pushinteger(L, videoGetWidth(_videoHandle)); + return 1; +} + + +int apiVldpVerbose(lua_State *L) { + /* + * Enables/Disables writing of VLDP playback activity to daphne_log.txt + * Enabled by default. + */ + (void)L; + + //***REMOVED*** + + return 0; +} + + +int apiKeyboardGetMode(lua_State *L) { + lua_pushinteger(L, _keyboardMode); + return 1; +} + + +int apiKeyboardSetMode(lua_State *L) { + /* + * Singe can scan keyboard input in two ways: + * + * MODE_NORMAL - Singe will only check for keys defined + * in daphne.ini. This is the default behavior. + * + * MODE_FULL - Singe will scan the keyboard for most keypresses. + * + */ + + int n = lua_gettop(L); + + if (n == 1) { + if (lua_isinteger(L, 1)) { + _keyboardMode = (int)lua_tointeger(L, 1); + } + } + + return 0; +} + + +int apiMouseEnable(lua_State *L) { + // Enables mouse monitoring + (void)L; + //***TODO*** g_pSingeIn->dll_side_mouse_enable(g_pSingeIn->pSingeInstance); + return 0; +} + + +int apiMouseDisable(lua_State *L) { + // Disables mouse monitoring + (void)L; + //***TODO*** g_pSingeIn->dll_side_mouse_disable(g_pSingeIn->pSingeInstance); + return 0; +} + + +int apiMouseSetMode(lua_State *L) { + // Sets the scanning mode for mouse input. + // Can be one of two values: + // + // SINGLE_MOUSE = 100 + // MANY_MOUSE = 200 + // + // Be sure to add these constant declarations to your framework.singe + // By default Singe starts in single mouse mode. + // Use this command if you need to scan multiple mice. + // e.g. lua code, + // + // mouseSetMode(MANY_MOUSE) + // + // Function returns TRUE is mode set was successful, FALSE otherwise. + // + // --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?"); + } + } + 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); + return 1; +} + + +int apiDiscGetState(lua_State *L) { + /* + * Returns the status of the vldp + * Values returned are + * based on the following enumeration (found in ldp.h). + * + * LDP_ERROR = 0 + * LDP_SEARCHING = 1 + * LDP_STOPPED = 2 + * LDP_PLAYING = 3 + * LDP_PAUSE = 4 + * + */ + + //***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); + return 1; +} + + +int apiSingeGetPauseFlag(lua_State *L) { + /* + * This function returns g_pause_state's value to the lua script. + * + * Sometimes game logic pauses the game (which implies pausing video playback). + * When implementing a pause state it is possible for the player + * to resume playblack at moments where the game is not intended to. + * Boolean g_pause state is an internal variable that keeps track + * of this. It's set to true whenever sep_pre_pause is called. + * It's set to false whenever sep_pre_play or sep_skip_to_frame is called. + * + * A lua programmer can use this to prevent resuming playback accidentally. + */ + lua_pushboolean(L, _pauseState); + return 1; +} + + +int apiSingeSetPauseFlag(lua_State *L) { + int n = lua_gettop(L); + + if (n == 1) { + if (lua_isboolean(L, 1)) { + _pauseState = (bool)lua_toboolean(L, 1); + } + } + + return 0; +} + + +int apiSingeEnablePauseKey(lua_State *L) { + (void)L; + _pauseEnabled = true; + return 0; +} + + +int apiSingeDisablePauseKey(lua_State *L) { + (void)L; + _pauseEnabled = false; + return 0; +} + + +int apiSingeQuit(lua_State *L) { + (void)L; + _running = false; +} + + +int apiSingeVersion(lua_State *L) { + lua_pushnumber(L, SINGE_VERSION); + return 1; +} + + +int apiSingeSetGameName(lua_State *L) { + // Adds the name of the singe game to the window's title bar. + // Valid value is a string no longer than 25 characters. + // e.g. lua code, + // + // singeSetGameName("My FMV game") + // + // Function returns nothing. + // + // --rdg + + int n = lua_gettop(L); + bool result = false; + char thisName[MAX_TITLE_LENGTH]; + + 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); + } + } + + lua_pushboolean(L, result); + return 0; +} + + +int apiSingeGetScriptPath(lua_State *L) { + // Returns the path to the singe script. + // e.g. lua code, + // + // sGameDirectory = singeGetScriptPath() + // + + lua_pushstring(L, _confScriptFile); + return 1; +} + + +void callLua(const char *func, const char *sig, ...) { + va_list vl; + bool done = false; + int narg; + int nres; + int popCount; + const int top = lua_gettop(_luaContext); + + va_start(vl, sig); + + // Get Function + lua_getglobal(_luaContext, func); + if (!lua_isfunction(_luaContext, -1)) { + // Function does not exist. Bail. + lua_settop(_luaContext, top); + return; + } + + // Push Arguments + narg = 0; + while ((*sig) && (!done)) { + switch (*sig++) { + + case 'd': // Double + lua_pushnumber(_luaContext, va_arg(vl, double)); + break; + + case 'i': // Int + lua_pushinteger(_luaContext, va_arg(vl, int)); + break; + + case 's': // String + lua_pushstring(_luaContext, va_arg(vl, char *)); + break; + + case '>': + done = true; + break; + + default: + utilDie("Invalid argument option (%c)", *(sig - 1)); + } + if (!done) { + narg++; + luaL_checkstack(_luaContext, 1, "Too many arguments"); + } + } + + // Do the call + popCount = nres = (int)strlen(sig); // Number of expected results + if (lua_pcall(_luaContext, narg, nres, 0) != 0) { + utilDie("Error executing function '%s': %s", func, lua_tostring(_luaContext, -1)); + } + + // Retrieve results + nres = -nres; // Stack index of first result + while (*sig) { + switch (*sig++) { + + case 'd': // Double + if (!lua_isnumber(_luaContext, nres)) { + utilDie("Wrong result type"); + } + *va_arg(vl, double *) = lua_tonumber(_luaContext, nres); + break; + + case 'i': // Int + if (!lua_isinteger(_luaContext, nres)) { + utilDie("Wrong result type"); + } + *va_arg(vl, int *) = (int)lua_tointeger(_luaContext, nres); + break; + + case 's': // String + if (!lua_isstring(_luaContext, nres)) { + utilDie("Wrong result type"); + } + *va_arg(vl, const char **) = lua_tostring(_luaContext, nres); + break; + + default: + utilDie("Invalid option (%c)", *(sig - 1)); + } + nres++; + } + va_end(vl); + + if (popCount > 0) { + lua_pop(_luaContext, popCount); + } +} + + +int luaError(lua_State *L) { + lua_Debug ar; + int level = 0; + + utilSay("Singe has panicked! Very bad!"); + utilSay("Error: %s", lua_tostring(L, -1)); + + utilSay("Stack trace:"); + while (lua_getstack(L, level, &ar) != 0) { + lua_getinfo(L, "nSl", &ar); + utilSay(" %d: function `%s' at line %d %s", level, ar.name, ar.currentline, ar.short_src); + level++; + } + utilSay("Trace complete."); + + return 0; +} + + +void singe(SDL_Window *window, SDL_Renderer *renderer) { + int thisFrame = -1; + int lastFrame = -1; + int intReturn = 0; + bool refresh = false; + SDL_Texture *videoTexture = NULL; + SpriteT *sprite = NULL; + SpriteT *spriteTemp = NULL; + SoundT *sound = NULL; + SoundT *soundTemp = NULL; + FontT *font = NULL; + FontT *fontTemp = NULL; + + // Hang on to some SDL stuff + _window = window; + _renderer = renderer; + + // Start Lua + _luaContext = luaL_newstate(); + luaL_openlibs(_luaContext); + lua_atpanic(_luaContext, luaError); + if (luaL_dofile(_luaContext, _confScriptFile) != 0) utilDie("Error compiling script: %s", lua_tostring(_luaContext, -1)); + + // Lua API for Singe + lua_register(_luaContext, "colorBackground", apiColorBackground); + lua_register(_luaContext, "colorForeground", apiColorForeground); + + lua_register(_luaContext, "daphneGetHeight", apiDaphneGetHeight); + lua_register(_luaContext, "daphneGetWidth", apiDaphneGetWidth); + lua_register(_luaContext, "daphneScreenshot", apiDaphneScreenshot); + + lua_register(_luaContext, "debugPrint", apiDebugPrint); + + lua_register(_luaContext, "discAudio", apiDiscAudio); + lua_register(_luaContext, "discChangeSpeed", apiDiscChangeSpeed); + lua_register(_luaContext, "discGetFrame", apiDiscGetFrame); + lua_register(_luaContext, "discPause", apiDiscPause); + lua_register(_luaContext, "discPauseAtFrame", apiDiscPauseAtFrame); + lua_register(_luaContext, "discPlay", apiDiscPlay); + lua_register(_luaContext, "discSearch", apiDiscSearch); + lua_register(_luaContext, "discSearchBlanking", apiDiscSearchBlanking); + lua_register(_luaContext, "discSetFPS", apiDiscSetFps); + lua_register(_luaContext, "discSkipBackward", apiDiscSkipBackward); + lua_register(_luaContext, "discSkipBlanking", apiDiscSkipBlanking); + lua_register(_luaContext, "discSkipForward", apiDiscSkipForward); + lua_register(_luaContext, "discSkipToFrame", apiDiscSkipToFrame); + lua_register(_luaContext, "discStepBackward", apiDiscStepBackward); + lua_register(_luaContext, "discStepForward", apiDiscStepForward); + lua_register(_luaContext, "discStop", apiDiscStop); + + lua_register(_luaContext, "fontLoad", apiFontLoad); + lua_register(_luaContext, "fontPrint", apiFontPrint); + lua_register(_luaContext, "fontQuality", apiFontQuality); + lua_register(_luaContext, "fontSelect", apiFontSelect); + lua_register(_luaContext, "fontToSprite", apiFontToSprite); + + lua_register(_luaContext, "overlayClear", apiOverlayClear); + lua_register(_luaContext, "overlayGetHeight", apiOverlayGetHeight); + lua_register(_luaContext, "overlayGetWidth", apiOverlayGetWidth); + lua_register(_luaContext, "overlayPrint", apiOverlayPrint); + + lua_register(_luaContext, "soundLoad", apiSoundLoad); + lua_register(_luaContext, "soundPlay", apiSoundPlay); + lua_register(_luaContext, "soundPause", apiSoundPause); // rdg + lua_register(_luaContext, "soundResume", apiSoundResume); // + lua_register(_luaContext, "soundIsPlaying", apiSoundIsPlaying); // + lua_register(_luaContext, "soundStop", apiSoundStop); // + lua_register(_luaContext, "soundSetVolume", apiSoundSetVolume); + lua_register(_luaContext, "soundGetVolume", apiSoundGetVolume); + lua_register(_luaContext, "soundFullStop", apiSoundFullStop); + + lua_register(_luaContext, "spriteDraw", apiSpriteDraw); + lua_register(_luaContext, "spriteGetHeight", apiSpriteGetHeight); + lua_register(_luaContext, "spriteGetWidth", apiSpriteGetWidth); + lua_register(_luaContext, "spriteLoad", apiSpriteLoad); + + lua_register(_luaContext, "vldpGetHeight", apiVldpGetHeight); + lua_register(_luaContext, "vldpGetPixel", apiVldpGetPixel); + lua_register(_luaContext, "vldpGetWidth", apiVldpGetWidth); + lua_register(_luaContext, "vldpSetVerbose", apiVldpVerbose); + + // by RDG2010 + lua_register(_luaContext, "keyboardGetMode", apiKeyboardGetMode); + lua_register(_luaContext, "keyboardSetMode", apiKeyboardSetMode); + lua_register(_luaContext, "mouseEnable", apiMouseEnable); + lua_register(_luaContext, "mouseDisable", apiMouseDisable); + lua_register(_luaContext, "mouseSetMode", apiMouseSetMode); + lua_register(_luaContext, "mouseHowMany", apiMouseHowMany); + lua_register(_luaContext, "discGetState", apiDiscGetState); + lua_register(_luaContext, "singeGetPauseFlag", apiSingeGetPauseFlag); + lua_register(_luaContext, "singeSetPauseFlag", apiSingeSetPauseFlag); + lua_register(_luaContext, "singeEnablePauseKey", apiSingeEnablePauseKey); + lua_register(_luaContext, "singeDisablePauseKey", apiSingeDisablePauseKey); + lua_register(_luaContext, "singeQuit", apiSingeQuit); + lua_register(_luaContext, "singeVersion", apiSingeVersion); + lua_register(_luaContext, "singeSetGameName", apiSingeSetGameName); + lua_register(_luaContext, "singeGetScriptPath", apiSingeGetScriptPath); + + // Open main video file + _videoHandle = videoLoad(_confVideoFile, _confDataDir, (bool)_confStretchVideo, _renderer); + if (_videoHandle < 0) utilDie("Unable to load video file: %s", _confVideoFile); + videoPlay(_videoHandle); + + // Create overlay texture + _overlay = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_TARGET, videoGetWidth(_videoHandle), videoGetHeight(_videoHandle)); + if (_overlay == NULL) utilDie("%s", SDL_GetError()); + if (_confStretchVideo) { + SDL_RenderSetLogicalSize(_renderer, videoGetWidth(_videoHandle), videoGetHeight(_videoHandle)); + } + + // Set volume + _effectsVolume = (int)((float)AUDIO_MAX_VOLUME * (float)_confVolumeNonVldp * (float)0.01); + Mix_Volume(-1, _effectsVolume * 2); + //***TODO*** Handle laser volume + + // Game Loop + while (_running) { + + // Event Loop + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + default: + //***TODO*** Process key + break; + } + break; + + case SDL_KEYUP: + switch (event.key.keysym.sym) { + case SDLK_ESCAPE: + _running = false; + break; + + default: + //***TODO*** Process key + break; + } + break; + + case SDL_QUIT: + _running = 0; + break; + } + } + + // Call game code + SDL_SetRenderTarget(_renderer, _overlay); + callLua("onOverlayUpdate", ">i", &intReturn); + if (intReturn == 1) { + refresh = true; + } + + // Update video + thisFrame = videoUpdate(_videoHandle, &videoTexture); + if ((thisFrame != lastFrame) && (thisFrame>= 0)) { + lastFrame = thisFrame; + refresh = true; + } + + // Update display + if (refresh) { + SDL_SetRenderTarget(_renderer, NULL); + SDL_RenderCopy(_renderer, videoTexture, NULL, NULL); + SDL_RenderPresent(_renderer); + refresh = false; + } + } + + // End game + callLua("onShutdown", ""); + + // Stop Lua + lua_close(_luaContext); + + // Free overlay + SDL_DestroyTexture(_overlay); + + // Unload fonts + HASH_ITER(hh, _fontList, font, fontTemp) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + HASH_DEL(_fontList, font); +#pragma GCC diagnostic pop + TTF_CloseFont(font->font); + free(font); + } + + // Unload sounds + HASH_ITER(hh, _soundList, sound, soundTemp) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + HASH_DEL(_soundList, sound); +#pragma GCC diagnostic pop + Mix_FreeChunk(sound->chunk); + free(sound); + } + + // Unload sprites + HASH_ITER(hh, _spriteList, sprite, spriteTemp) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + HASH_DEL(_spriteList, sprite); +#pragma GCC diagnostic pop + SDL_DestroyTexture(sprite->texture); + free(sprite); + } + + // Unload video + videoUnload(_videoHandle); +} diff --git a/singe/singe.h b/singe/singe.h index bf33d2415..35553468b 100644 --- a/singe/singe.h +++ b/singe/singe.h @@ -24,10 +24,19 @@ #define SINGE_H +#include + + +#define SINGE_VERSION 2.00 +#define VERSION_STRING "v2.00" +#define COPYRIGHT_END_YEAR "2020" + + // Command line options extern char *_confVideoFile; extern char *_confScriptFile; extern char *_confDataDir; +extern int _confStretchVideo; extern int _confNoMouse; extern int _confNoStats; extern int _confNoSound; @@ -40,4 +49,7 @@ extern int _confXResolution; extern int _confYResolution; +void singe(SDL_Window *window, SDL_Renderer *renderer); + + #endif // SINGE_H diff --git a/singe/videoPlayer.c b/singe/videoPlayer.c index b361ed501..7538bf72d 100644 --- a/singe/videoPlayer.c +++ b/singe/videoPlayer.c @@ -25,7 +25,6 @@ #include "thirdparty/uthash.h" -#include "common.h" #include "util.h" #include "videoPlayer.h" @@ -154,7 +153,40 @@ int videoIsPlaying(int playerIndex) { } -int videoLoad(char *filename, char *indexPath, SDL_Renderer *renderer) { +int videoGetFrame(int playerIndex) { + VideoPlayerT *v = NULL; + + // Get our player structure + HASH_FIND_INT(_videoPlayerHash, &playerIndex, v); + if (!v) utilDie("No video player at index %d in videoGetHeight.", playerIndex); + + return v->frame; +} + + +int videoGetHeight(int playerIndex) { + VideoPlayerT *v = NULL; + + // Get our player structure + HASH_FIND_INT(_videoPlayerHash, &playerIndex, v); + if (!v) utilDie("No video player at index %d in videoGetHeight.", playerIndex); + + return v->propFrame->EncodedHeight; +} + + +int videoGetWidth(int playerIndex) { + VideoPlayerT *v = NULL; + + // Get our player structure + HASH_FIND_INT(_videoPlayerHash, &playerIndex, v); + if (!v) utilDie("No video player at index %d in videoGetWidth.", playerIndex); + + return v->propFrame->EncodedWidth; +} + + +int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer) { char indexName[1024]; int pixelFormats[2]; int result = -1; @@ -232,10 +264,11 @@ int videoLoad(char *filename, char *indexPath, SDL_Renderer *renderer) { // Create video texture SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - v->videoTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STATIC, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight); + v->videoTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight); if (v->videoTexture == NULL) utilDie("%s", SDL_GetError()); - - SDL_RenderSetLogicalSize(renderer, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight); + if (!stretchVideo) { + SDL_RenderSetLogicalSize(renderer, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight); + } // Determine audio format switch (v->audioProps->SampleFormat) { diff --git a/singe/videoPlayer.h b/singe/videoPlayer.h index d3e0f4380..564ae1e70 100644 --- a/singe/videoPlayer.h +++ b/singe/videoPlayer.h @@ -26,10 +26,15 @@ #include +#include "common.h" + int videoInit(void); int videoIsPlaying(int playerIndex); -int videoLoad(char *filename, char *indexPath, SDL_Renderer *renderer); +int videoGetFrame(int playerIndex); +int videoGetHeight(int playerIndex); +int videoGetWidth(int playerIndex); +int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer); int videoPause(int playerIndex); int videoPlay(int playerIndex); int videoQuit(void);