ref: 2247f4c8984d43c50550fbd4444e2eed321007d2
parent: 108c333ecdfd8287e12f39f858347db64d33f2f7
author: Olav Sørensen <[email protected]>
date: Thu Apr 2 17:59:03 EDT 2020
Pushed v1.16 code - The mouse system has been rewritten so that we don't need to do mouse capturing while interacting with GUI widgets, which could be buggy sometimes. - The different Disk Op. item paths (mod./instr./smp./pat./trk.) now behave exactly like real FT2. I.e. if they haven't been initialized before, they will be set to the current working directory. - Scrollbar thumbs are now limited to minimum 9 pixels in length/height, to prevent them from being difficult to click on.
--- a/src/ft2_diskop.c
+++ b/src/ft2_diskop.c
@@ -75,7 +75,7 @@
static char *modTmpFName, *insTmpFName, *smpTmpFName, *patTmpFName, *trkTmpFName;
static char *modTmpFNameUTF8; // for window title
static uint8_t FReq_Item;
-static bool FReq_ShowAllFiles;
+static bool FReq_ShowAllFiles, modPathSet, insPathSet, smpPathSet, patPathSet, trkPathSet;
static int32_t FReq_EntrySelected = -1, FReq_FileCount, FReq_DirPos, lastMouseY;
static UNICHAR *FReq_CurPathU, *FReq_ModCurPathU, *FReq_InsCurPathU, *FReq_SmpCurPathU, *FReq_PatCurPathU, *FReq_TrkCurPathU;
static DirRec *FReq_Buffer;
@@ -176,20 +176,70 @@
UNICHAR pathU[PATH_MAX + 2];
#endif
+ UNICHAR_GETCWD(FReq_ModCurPathU, PATH_MAX);
+
// the UNICHAR paths are already zeroed out
#ifdef _WIN32
- if (config.modulesPath[0] != '\0') MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.modulesPath, -1, FReq_ModCurPathU, 80);
- if (config.instrPath[0] != '\0') MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.instrPath, -1, FReq_InsCurPathU, 80);
- if (config.samplesPath[0] != '\0') MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.samplesPath, -1, FReq_SmpCurPathU, 80);
- if (config.patternsPath[0] != '\0') MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.patternsPath, -1, FReq_PatCurPathU, 80);
- if (config.tracksPath[0] != '\0') MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.tracksPath, -1, FReq_TrkCurPathU, 80);
+ if (config.modulesPath[0] != '\0')
+ {
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.modulesPath, -1, FReq_ModCurPathU, 80);
+ modPathSet = true;
+ }
+
+ if (config.instrPath[0] != '\0')
+ {
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.instrPath, -1, FReq_InsCurPathU, 80);
+ insPathSet = true;
+ }
+
+ if (config.samplesPath[0] != '\0')
+ {
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.samplesPath, -1, FReq_SmpCurPathU, 80);
+ smpPathSet = true;
+ }
+
+ if (config.patternsPath[0] != '\0')
+ {
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.patternsPath, -1, FReq_PatCurPathU, 80);
+ patPathSet = true;
+ }
+
+ if (config.tracksPath[0] != '\0')
+ {
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.tracksPath, -1, FReq_TrkCurPathU, 80);
+ trkPathSet = true;
+ }
#else
- if (config.modulesPath[0] != '\0') strncpy(FReq_ModCurPathU, config.modulesPath, 80);
- if (config.instrPath[0] != '\0') strncpy(FReq_InsCurPathU, config.instrPath, 80);
- if (config.samplesPath[0] != '\0') strncpy(FReq_SmpCurPathU, config.samplesPath, 80);
- if (config.patternsPath[0] != '\0') strncpy(FReq_PatCurPathU, config.patternsPath, 80);
- if (config.tracksPath[0] != '\0') strncpy(FReq_TrkCurPathU, config.tracksPath, 80);
+ if (config.modulesPath[0] != '\0')
+ {
+ strncpy(FReq_ModCurPathU, config.modulesPath, 80);
+ modPathSet = true;
+ }
+
+ if (config.instrPath[0] != '\0')
+ {
+ strncpy(FReq_InsCurPathU, config.instrPath, 80);
+ insPathSet = true;
+ }
+
+ if (config.samplesPath[0] != '\0')
+ {
+ strncpy(FReq_SmpCurPathU, config.samplesPath, 80);
+ smpPathSet = true;
+ }
+
+ if (config.patternsPath[0] != '\0')
+ {
+ strncpy(FReq_PatCurPathU, config.patternsPath, 80);
+ patPathSet = true;
+ }
+
+ if (config.tracksPath[0] != '\0')
+ {
+ strncpy(FReq_TrkCurPathU, config.tracksPath, 80);
+ trkPathSet = true;
+ }
#endif
// set initial path to user directory
@@ -200,16 +250,12 @@
UNICHAR_CHDIR(getenv("HOME"));
#endif
- // if present in config, set custom "modules" path
- if (UNICHAR_CHDIR(FReq_ModCurPathU) != 0)
+ // if we couldn't set present in config, set custom "modules" path
+ if (modPathSet && UNICHAR_CHDIR(FReq_ModCurPathU) != 0)
+ {
UNICHAR_GETCWD(FReq_ModCurPathU, PATH_MAX);
-
- if (UNICHAR_CHDIR(FReq_InsCurPathU) != 0) UNICHAR_STRCPY(FReq_InsCurPathU, FReq_ModCurPathU);
- if (UNICHAR_CHDIR(FReq_SmpCurPathU) != 0) UNICHAR_STRCPY(FReq_SmpCurPathU, FReq_ModCurPathU);
- if (UNICHAR_CHDIR(FReq_PatCurPathU) != 0) UNICHAR_STRCPY(FReq_PatCurPathU, FReq_ModCurPathU);
- if (UNICHAR_CHDIR(FReq_TrkCurPathU) != 0) UNICHAR_STRCPY(FReq_TrkCurPathU, FReq_ModCurPathU);
-
- UNICHAR_CHDIR(FReq_ModCurPathU); // set back after testing
+ modPathSet = true;
+ }
}
static void freeDirRecBuffer(void)
@@ -1969,7 +2015,7 @@
return true;
}
-void startDiskOpFillThread(void)
+void diskOp_StartDirReadThread(void)
{
editor.diskOpReadDone = false;
@@ -2076,11 +2122,69 @@
FReq_Item = item;
switch (FReq_Item)
{
- default: case DISKOP_ITEM_MODULE: FReq_FileName = modTmpFName; FReq_CurPathU = FReq_ModCurPathU; break;
- case DISKOP_ITEM_INSTR: FReq_FileName = insTmpFName; FReq_CurPathU = FReq_InsCurPathU; break;
- case DISKOP_ITEM_SAMPLE: FReq_FileName = smpTmpFName; FReq_CurPathU = FReq_SmpCurPathU; break;
- case DISKOP_ITEM_PATTERN: FReq_FileName = patTmpFName; FReq_CurPathU = FReq_PatCurPathU; break;
- case DISKOP_ITEM_TRACK: FReq_FileName = trkTmpFName; FReq_CurPathU = FReq_TrkCurPathU; break;
+ default:
+ case DISKOP_ITEM_MODULE:
+ {
+ FReq_FileName = modTmpFName;
+ FReq_CurPathU = FReq_ModCurPathU;
+ }
+ break;
+
+ case DISKOP_ITEM_INSTR:
+ {
+ FReq_FileName = insTmpFName;
+
+ if (!insPathSet)
+ {
+ UNICHAR_STRCPY(FReq_InsCurPathU, FReq_CurPathU);
+ insPathSet = true;
+ }
+
+ FReq_CurPathU = FReq_InsCurPathU;
+ }
+ break;
+
+ case DISKOP_ITEM_SAMPLE:
+ {
+ FReq_FileName = smpTmpFName;
+
+ if (!smpPathSet)
+ {
+ UNICHAR_STRCPY(FReq_SmpCurPathU, FReq_CurPathU);
+ smpPathSet = true;
+ }
+
+ FReq_CurPathU = FReq_SmpCurPathU;
+ }
+ break;
+
+ case DISKOP_ITEM_PATTERN:
+ {
+ FReq_FileName = patTmpFName;
+
+ if (!patPathSet)
+ {
+ UNICHAR_STRCPY(FReq_SmpCurPathU, FReq_CurPathU);
+ patPathSet = true;
+ }
+
+ FReq_CurPathU = FReq_PatCurPathU;
+ }
+ break;
+
+ case DISKOP_ITEM_TRACK:
+ {
+ FReq_FileName = trkTmpFName;
+
+ if (!trkPathSet)
+ {
+ UNICHAR_STRCPY(FReq_TrkCurPathU, FReq_CurPathU);
+ trkPathSet = true;
+ }
+
+ FReq_CurPathU = FReq_TrkCurPathU;
+ }
+ break;
}
pathLen = (int32_t)UNICHAR_STRLEN(FReq_CurPathU);
@@ -2189,7 +2293,7 @@
if (editor.diskOpReadOnOpen)
{
editor.diskOpReadOnOpen = false;
- startDiskOpFillThread();
+ diskOp_StartDirReadThread();
}
}
--- a/src/ft2_diskop.h
+++ b/src/ft2_diskop.h
@@ -40,7 +40,7 @@
int32_t getExtOffset(char *s, int32_t stringLen); // get byte offset of file extension (last '.')
bool testDiskOpMouseDown(bool mouseHeldDown);
void testDiskOpMouseRelease(void);
-void startDiskOpFillThread(void);
+void diskOp_StartDirReadThread(void);
void diskOp_DrawDirectory(void);
void showDiskOpScreen(void);
void hideDiskOpScreen(void);
--- a/src/ft2_events.c
+++ b/src/ft2_events.c
@@ -152,7 +152,7 @@
if (editor.diskOpReadDir)
{
editor.diskOpReadDir = false;
- startDiskOpFillThread();
+ diskOp_StartDirReadThread();
}
if (editor.diskOpReadDone)
@@ -407,14 +407,23 @@
while (SDL_PollEvent(&event))
{
- if (video.vsync60HzPresent)
+ if (event.type == SDL_WINDOWEVENT)
{
- /* if we minimize the window and vsync is present, vsync is temporarily turned off.
- ** recalc waitVBL() vars so that it can sleep properly in said mode. */
- if (event.type == SDL_WINDOWEVENT &&
- (event.window.event == SDL_WINDOWEVENT_MINIMIZED || event.window.event == SDL_WINDOWEVENT_FOCUS_LOST))
+ if (event.window.event == SDL_WINDOWEVENT_HIDDEN)
+ video.windowHidden = true;
+ else if (event.window.event == SDL_WINDOWEVENT_SHOWN)
+ video.windowHidden = false;
+
+ if (video.vsync60HzPresent)
{
- setupWaitVBL();
+ /* if we minimize the window and vsync is present, vsync is temporarily turned off.
+ ** recalc waitVBL() vars so that it can sleep properly in said mode.
+ */
+ if (event.window.event == SDL_WINDOWEVENT_MINIMIZED ||
+ event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
+ {
+ setupWaitVBL();
+ }
}
}
--- a/src/ft2_header.h
+++ b/src/ft2_header.h
@@ -12,7 +12,7 @@
#endif
#include "ft2_replayer.h"
-#define PROG_VER_STR "1.15"
+#define PROG_VER_STR "1.16"
// do NOT change these! It will only mess things up...
--- a/src/ft2_inst_ed.c
+++ b/src/ft2_inst_ed.c
@@ -3146,7 +3146,7 @@
ins->vibDepth = ih.vibDepth;
ins->vibRate = ih.vibRate;
ins->fadeOut = ih.fadeOut;
- ins->midiOn = (ih.midiOn > 0) ? true : false;
+ ins->midiOn = (ih.midiOn == 1) ? true : false;
ins->midiChannel = ih.midiChannel;
ins->midiProgram = ih.midiProgram;
ins->midiBend = ih.midiBend;
--- a/src/ft2_module_loader.c
+++ b/src/ft2_module_loader.c
@@ -622,17 +622,7 @@
s = &instrTmp[1+a]->samp[0];
s->len = 2 * SWAP16(h_MOD31.instr[a].len);
-
- s->pek = NULL;
- s->origPek = (int8_t *)malloc(s->len + LOOP_FIX_LEN);
- if (s->origPek == NULL)
- {
- showMsg(0, "System message", "Not enough memory!");
- goto modLoadError;
- }
- s->pek = s->origPek + SMP_DAT_OFFSET;
-
if (modFormat != FORMAT_HMNT) // most of "His Master's Noisetracker" songs have junk sample names, so let's not load them
memcpy(s->name, songTmp.instrName[1+a], 22);
@@ -655,11 +645,11 @@
s->repL = 2;
// in The Ultimate SoundTracker, sample loop start is in bytes, not words
- if (mightBeSTK)
+ if (modFormat == FORMAT_STK)
s->repS >>= 1;
// fix for poorly converted STK (< v2.5) -> PT/NT modules (FIXME: Worth keeping or not?)
- if (!mightBeSTK && s->repL > 2 && s->repS+s->repL > s->len)
+ if (modFormat != FORMAT_STK && s->repL > 2 && s->repS+s->repL > s->len)
{
if ((s->repS>>1)+s->repL <= s->len)
s->repS >>= 1;
@@ -692,6 +682,16 @@
s->repS = 0;
}
+ s->pek = NULL;
+ s->origPek = (int8_t *)malloc(s->len + LOOP_FIX_LEN);
+ if (s->origPek == NULL)
+ {
+ showMsg(0, "System message", "Not enough memory!");
+ goto modLoadError;
+ }
+
+ s->pek = s->origPek + SMP_DAT_OFFSET;
+
int32_t bytesRead = (int32_t)fread(s->pek, 1, s->len, f);
if (bytesRead < s->len)
{
@@ -737,7 +737,7 @@
static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool fromExternalThread)
{
uint8_t typ, tempo;
- int16_t i, j, k, ai, ap, tmp;
+ int16_t i, j, k, ap, tmp;
uint16_t a;
tonTyp *ton;
sampleTyp *s;
@@ -899,7 +899,6 @@
}
}
- ai = 31;
for (i = 0; i < 31; i++)
{
// trim off spaces at end of name
@@ -1010,7 +1009,6 @@
static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread)
{
int8_t *tmpSmp;
- bool illegalUxx;
uint8_t ha[2048];
uint8_t alastnfo[32], alastefx[32], alastvibnfo[32], s3mLastGInstr[32];
uint8_t typ;
@@ -1129,8 +1127,6 @@
// *** PATTERNS ***
- illegalUxx = false;
-
k = 0;
for (i = 0; i < ap; i++)
{
@@ -2012,7 +2008,7 @@
ins->vibDepth = ih.vibDepth;
ins->vibRate = ih.vibRate;
ins->fadeOut = ih.fadeOut;
- ins->midiOn = (ih.midiOn > 0) ? true : false;
+ ins->midiOn = (ih.midiOn == 1) ? true : false;
ins->midiChannel = ih.midiChannel;
ins->midiProgram = ih.midiProgram;
ins->midiBend = ih.midiBend;
--- a/src/ft2_mouse.c
+++ b/src/ft2_mouse.c
@@ -59,9 +59,9 @@
const uint8_t *cursorsSrc = bmp.mouseCursors;
switch (config.mouseType)
{
- case MOUSE_IDLE_SHAPE_NICE: cursorsSrc += 0 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
- case MOUSE_IDLE_SHAPE_UGLY: cursorsSrc += 1 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
- case MOUSE_IDLE_SHAPE_AWFUL: cursorsSrc += 2 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_SHAPE_NICE: cursorsSrc += 0 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_SHAPE_UGLY: cursorsSrc += 1 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_SHAPE_AWFUL: cursorsSrc += 2 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
case MOUSE_IDLE_SHAPE_USABLE: cursorsSrc += 3 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
default: break;
}
@@ -68,7 +68,9 @@
for (uint32_t i = 0; i < NUM_CURSORS; i++)
{
- SDL_Surface *surface = SDL_CreateRGBSurface(0, MOUSE_CURSOR_W*video.yScale, MOUSE_CURSOR_H*video.yScale, 32, 0, 0, 0, 0);
+ int32_t scaleFactor = video.yScale;
+
+ SDL_Surface *surface = SDL_CreateRGBSurface(0, MOUSE_CURSOR_W*scaleFactor, MOUSE_CURSOR_H*scaleFactor, 32, 0, 0, 0, 0);
if (surface == NULL)
{
freeMouseCursors();
@@ -104,10 +106,10 @@
// blit upscaled cursor to surface
for (uint32_t y = 0; y < MOUSE_CURSOR_H; y++)
{
- uint32_t *outX = &dstPixels32[(y * video.yScale) * surface->w];
- for (uint32_t yScale = 0; yScale < video.yScale; yScale++)
+ uint32_t *outX = &dstPixels32[(y * scaleFactor) * surface->w];
+ for (int32_t yScale = 0; yScale < scaleFactor; yScale++)
{
- for (uint32_t x = 0; x < MOUSE_CURSOR_W; x++)
+ for (int32_t x = 0; x < MOUSE_CURSOR_W; x++)
{
uint8_t srcPix = srcPixels8[(y * MOUSE_CURSOR_W) + x];
if (srcPix != PAL_TRANSPR)
@@ -118,7 +120,7 @@
else if (srcPix == PAL_BCKGRND)
pixel = border;
- for (uint32_t xScale = 0; xScale < video.yScale; xScale++)
+ for (int32_t xScale = 0; xScale < scaleFactor; xScale++)
outX[xScale] = pixel;
}
@@ -163,13 +165,13 @@
{
if (video.fullscreen)
{
- mouse.setPosX = video.displayW / 2;
- mouse.setPosY = video.displayH / 2;
+ mouse.setPosX = video.displayW >> 1;
+ mouse.setPosY = video.displayH >> 1;
}
else
{
- mouse.setPosX = video.renderW / 2;
- mouse.setPosY = video.renderH / 2;
+ mouse.setPosX = video.renderW >> 1;
+ mouse.setPosY = video.renderH >> 1;
}
mouse.setPosFlag = true;
@@ -242,11 +244,11 @@
gfxPtr = &bmp.mouseCursors[mouseModeGfxOffs];
switch (shape)
{
- case MOUSE_IDLE_SHAPE_NICE: gfxPtr += 0 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
- case MOUSE_IDLE_SHAPE_UGLY: gfxPtr += 1 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
- case MOUSE_IDLE_SHAPE_AWFUL: gfxPtr += 2 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
- case MOUSE_IDLE_SHAPE_USABLE: gfxPtr += 3 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
- case MOUSE_IDLE_TEXT_EDIT: gfxPtr += 12 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_SHAPE_NICE: gfxPtr += 0 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_SHAPE_UGLY: gfxPtr += 1 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_SHAPE_AWFUL: gfxPtr += 2 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_SHAPE_USABLE: gfxPtr += 3 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
+ case MOUSE_IDLE_TEXT_EDIT: gfxPtr += 12 * (MOUSE_CURSOR_W * MOUSE_CURSOR_H); break;
default: return;
}
}
@@ -284,7 +286,7 @@
static void changeCursorIfOverTextBoxes(void)
{
- int16_t i, mx, my;
+ int32_t i, mx, my;
textBox_t *t;
mouse.mouseOverTextBox = false;
@@ -542,11 +544,6 @@
void mouseButtonUpHandler(uint8_t mouseButton)
{
-#ifndef __APPLE__
- if (!video.fullscreen) // release mouse button trap
- SDL_SetWindowGrab(video.window, SDL_FALSE);
-#endif
-
if (mouseButton == SDL_BUTTON_LEFT)
{
mouse.leftButtonPressed = false;
@@ -569,7 +566,6 @@
mouse.rightButtonPressed = false;
mouse.rightButtonReleased = true;
-
if (editor.editSampleFlag)
{
// right mouse button released after hand-editing sample data
@@ -582,9 +578,9 @@
writeSample(true);
setSongModifiedFlag();
+
editor.editSampleFlag = false;
}
-
}
mouse.firstTimePressingButton = false;
@@ -611,9 +607,9 @@
testRadioButtonMouseRelease();
// revert "delete/rename" mouse modes (disk op.)
- if (mouse.lastUsedObjectID != PB_DISKOP_DELETE && mouse.lastUsedObjectID != PB_DISKOP_RENAME)
+ if (mouse.mode != MOUSE_MODE_NORMAL)
{
- if (mouse.mode != MOUSE_MODE_NORMAL)
+ if (mouse.lastUsedObjectID != PB_DISKOP_DELETE && mouse.lastUsedObjectID != PB_DISKOP_RENAME)
setMouseMode(MOUSE_MODE_NORMAL);
}
@@ -623,11 +619,6 @@
void mouseButtonDownHandler(uint8_t mouseButton)
{
-#ifndef __APPLE__
- if (!video.fullscreen) // trap mouse pointer while holding down left and/or right button
- SDL_SetWindowGrab(video.window, SDL_TRUE);
-#endif
-
// if already holding left button and clicking right, don't do mouse down handling
if (mouseButton == SDL_BUTTON_RIGHT && mouse.leftButtonPressed)
{
@@ -691,7 +682,7 @@
if (mouse.lastUsedObjectType != OBJECT_PUSHBUTTON && mouse.lastUsedObjectID != OBJECT_ID_NONE)
return;
- // kludge #3
+ // kludge #3 :(
if (!mouse.rightButtonPressed)
mouse.lastUsedObjectID = OBJECT_ID_NONE;
@@ -698,27 +689,28 @@
// check if we pressed a GUI object
/* test objects like this - clickable things *never* overlap, so no need to test all
- ** other objects if we clicked on one already */
+ ** other objects if we clicked on one already
+ */
testInstrSwitcherMouseDown(); // kludge: allow right click to both change ins. and edit text
- if (testTextBoxMouseDown()) return;
- if (testPushButtonMouseDown()) return;
- if (testCheckBoxMouseDown()) return;
- if (testScrollBarMouseDown()) return;
+ if (testTextBoxMouseDown()) return;
+ if (testPushButtonMouseDown()) return;
+ if (testCheckBoxMouseDown()) return;
+ if (testScrollBarMouseDown()) return;
if (testRadioButtonMouseDown()) return;
- // from this point, we don't need to test more widgets if a system request box is shown
+ // at this point, we don't need to test more widgets if a system request is shown
if (editor.ui.sysReqShown)
return;
if (testInstrVolEnvMouseDown(false)) return;
if (testInstrPanEnvMouseDown(false)) return;
- if (testDiskOpMouseDown(false)) return;
- if (testPianoKeysMouseDown(false)) return;
- if (testSamplerDataMouseDown()) return;
- if (testPatternDataMouseDown()) return;
- if (testScopesMouseDown()) return;
+ if (testDiskOpMouseDown(false)) return;
+ if (testPianoKeysMouseDown(false)) return;
+ if (testSamplerDataMouseDown()) return;
+ if (testPatternDataMouseDown()) return;
+ if (testScopesMouseDown()) return;
if (testAudioDeviceListsMouseDown()) return;
#ifdef HAS_MIDI
@@ -737,11 +729,11 @@
{
switch (mouse.lastUsedObjectType)
{
- case OBJECT_PUSHBUTTON: handlePushButtonsWhileMouseDown(); break;
+ case OBJECT_PUSHBUTTON: handlePushButtonsWhileMouseDown(); break;
case OBJECT_RADIOBUTTON: handleRadioButtonsWhileMouseDown(); break;
- case OBJECT_CHECKBOX: handleCheckBoxesWhileMouseDown(); break;
- case OBJECT_SCROLLBAR: handleScrollBarsWhileMouseDown(); break;
- case OBJECT_TEXTBOX: handleTextBoxWhileMouseDown(); break;
+ case OBJECT_CHECKBOX: handleCheckBoxesWhileMouseDown(); break;
+ case OBJECT_SCROLLBAR: handleScrollBarsWhileMouseDown(); break;
+ case OBJECT_TEXTBOX: handleTextBoxWhileMouseDown(); break;
default: break;
}
}
@@ -750,16 +742,28 @@
// test non-standard GUI elements
switch (mouse.lastUsedObjectType)
{
- case OBJECT_INSTRSWITCH: testInstrSwitcherMouseDown(); break;
- case OBJECT_PATTERNMARK: handlePatternDataMouseDown(true); break;
- case OBJECT_DISKOPLIST: testDiskOpMouseDown(true); break;
- case OBJECT_SMPDATA: handleSampleDataMouseDown(true); break;
- case OBJECT_PIANO: testPianoKeysMouseDown(true); break;
- case OBJECT_INSVOLENV: testInstrVolEnvMouseDown(true); break;
- case OBJECT_INSPANENV: testInstrPanEnvMouseDown(true); break;
+ case OBJECT_INSTRSWITCH: testInstrSwitcherMouseDown(); break;
+ case OBJECT_PATTERNMARK: handlePatternDataMouseDown(true); break;
+ case OBJECT_DISKOPLIST: testDiskOpMouseDown(true); break;
+ case OBJECT_SMPDATA: handleSampleDataMouseDown(true); break;
+ case OBJECT_PIANO: testPianoKeysMouseDown(true); break;
+ case OBJECT_INSVOLENV: testInstrVolEnvMouseDown(true); break;
+ case OBJECT_INSPANENV: testInstrPanEnvMouseDown(true); break;
default: break;
}
}
+
+ /* Hack to send "mouse button up" events if we released the mouse button(s)
+ ** outside of the window...
+ */
+ if (mouse.x < 0 || mouse.x >= SCREEN_W || mouse.y < 0 || mouse.y >= SCREEN_H)
+ {
+ if (mouse.leftButtonPressed && !(mouse.buttonState & SDL_BUTTON_LMASK))
+ sendMouseButtonUpEvent(SDL_BUTTON_LEFT);
+
+ if (mouse.rightButtonPressed && !(mouse.buttonState & SDL_BUTTON_RMASK))
+ sendMouseButtonUpEvent(SDL_BUTTON_RIGHT);
+ }
}
}
@@ -769,88 +773,102 @@
if (video.renderH > 0.0) video.dMouseYMul = (double)SCREEN_H / video.renderH;
}
+void sendMouseButtonUpEvent(uint8_t button)
+{
+ SDL_Event event;
+
+ memset(&event, 0, sizeof (event));
+
+ event.type = SDL_MOUSEBUTTONUP;
+ event.button.button = button;
+
+ SDL_PushEvent(&event);
+}
+
void readMouseXY(void)
{
- int16_t x, y;
- int32_t mx, my;
+ int32_t mx, my, windowX, windowY;
if (mouse.setPosFlag)
{
- mouse.setPosFlag = false;
-
- if (SDL_GetWindowFlags(video.window) & SDL_WINDOW_SHOWN)
+ if (!video.windowHidden)
SDL_WarpMouseInWindow(video.window, mouse.setPosX, mouse.setPosY);
+ mouse.setPosFlag = false;
return;
}
- SDL_PumpEvents(); // gathers all pending input from devices into the event queue (less mouse lag)
- SDL_GetMouseState(&mx, &my);
+ mouse.buttonState = SDL_GetGlobalMouseState(&mx, &my);
- /* in centered fullscreen mode, trap the mouse inside the framed image
- ** and subtract the coords to match the OS mouse position (fixes touch from touchscreens) */
- if (video.fullscreen && !(config.windowFlags & FILTERING))
+ if (video.fullscreen)
{
- if (mx < video.renderX)
- {
- mx = video.renderX;
- SDL_WarpMouseInWindow(video.window, mx, my);
- }
- else if (mx >= video.renderX+video.renderW)
- {
- mx = (video.renderX + video.renderW) - 1;
- SDL_WarpMouseInWindow(video.window, mx, my);
- }
+ /* If fullscreen without filtering mode, translate coords and warp mouse
+ ** inside the render space.
+ ** Fullscreen + filtering mode takes up 100% of the screen area used, so no
+ ** need to translate coords in that mode.
+ */
- if (my < video.renderY)
+ if (!(config.windowFlags & FILTERING))
{
- my = video.renderY;
- SDL_WarpMouseInWindow(video.window, mx, my);
- }
- else if (my >= video.renderY+video.renderH)
- {
- my = (video.renderY + video.renderH) - 1;
- SDL_WarpMouseInWindow(video.window, mx, my);
- }
+ if (!(config.specialFlags2 & HARDWARE_MOUSE))
+ {
+ bool warpMouse = false;
- mx -= video.renderX;
- my -= video.renderY;
+ if (mx < video.renderX)
+ {
+ mx = video.renderX;
+ warpMouse = true;
+ }
+ else if (mx >= video.renderX+video.renderW)
+ {
+ mx = (video.renderX + video.renderW) - 1;
+ warpMouse = true;
+ }
+
+ if (my < video.renderY)
+ {
+ my = video.renderY;
+ warpMouse = true;
+ }
+ else if (my >= video.renderY+video.renderH)
+ {
+ my = (video.renderY + video.renderH) - 1;
+ warpMouse = true;
+ }
+
+ if (warpMouse)
+ SDL_WarpMouseInWindow(video.window, mx, my);
+ }
+
+ // convert fullscreen coords to window (centered image) coords
+ mx -= video.renderX;
+ my -= video.renderY;
+ }
}
+ else
+ {
+ // convert desktop coords to window coords
- if (mx < 0) mx = 0;
- if (my < 0) mx = 0;
+ // (a call to this function is really fast in windowed mode)
+ SDL_GetWindowPosition(video.window, &windowX, &windowY);
+ mx -= windowX;
+ my -= windowY;
+ }
+
// multiply coords by video upscaling factors (don't round)
- mx = (int32_t)(mx * video.dMouseXMul);
- my = (int32_t)(my * video.dMouseYMul);
+ mouse.x = (int32_t)(mx * video.dMouseXMul);
+ mouse.y = (int32_t)(my * video.dMouseYMul);
- if (mx >= SCREEN_W) mx = SCREEN_W - 1;
- if (my >= SCREEN_H) my = SCREEN_H - 1;
-
if (config.specialFlags2 & HARDWARE_MOUSE)
{
- // hardware mouse (OS)
- mouse.x = (int16_t)mx;
- mouse.y = (int16_t)my;
+ // hardware mouse mode (OS)
hideSprite(SPRITE_MOUSE_POINTER);
}
else
{
- // software mouse (FT2 mouse)
- x = (int16_t)mx;
- y = (int16_t)my;
-
- mouse.x = x;
- mouse.y = y;
-
- // for text editing cursor (do this after clamp)
- x += mouse.xBias;
- y += mouse.yBias;
-
- if (x < 0) x = 0;
- if (y < 0) y = 0;
-
- setSpritePos(SPRITE_MOUSE_POINTER, x, y);
+ // software mouse mode (FT2 mouse)
+ setSpritePos(SPRITE_MOUSE_POINTER, mouse.x + mouse.xBias, mouse.y + mouse.yBias);
}
changeCursorIfOverTextBoxes();
--- a/src/ft2_mouse.h
+++ b/src/ft2_mouse.h
@@ -19,9 +19,10 @@
bool leftButtonPressed, rightButtonPressed, leftButtonReleased, rightButtonReleased;
bool firstTimePressingButton, mouseOverTextBox;
int8_t buttonCounter, mode;
- int16_t lastUsedObjectID, lastUsedObjectType, lastEditBox, x, y, lastX, lastY, xBias, yBias;
- int16_t lastScrollX, lastScrollXTmp, lastScrollY, saveMouseX, saveMouseY;
- int32_t setPosX, setPosY;
+ int16_t lastUsedObjectID, lastUsedObjectType, lastEditBox;
+ int32_t x, y, lastX, lastY, xBias, yBias, setPosX, setPosY;
+ int32_t lastScrollX, lastScrollXTmp, lastScrollY, saveMouseX, saveMouseY;
+ uint32_t buttonState;
} mouse;
// do not change these!
@@ -30,6 +31,7 @@
#define MOUSE_GLASS_ANI_FRAMES 22
#define MOUSE_CLOCK_ANI_FRAMES 5
+void sendMouseButtonUpEvent(uint8_t button);
void freeMouseCursors(void);
bool createMouseCursors(void);
void setMousePosToCenter(void);
--- a/src/ft2_sample_ed.c
+++ b/src/ft2_sample_ed.c
@@ -1440,7 +1440,7 @@
smpEd_Rx2 = smpEd_ScrPos + smpEd_ViewSize;
}
-static void zoomSampleDataIn(int32_t step, int16_t x)
+static void zoomSampleDataIn(int32_t step, int32_t x)
{
int32_t tmp32, minViewSize;
int64_t newScrPos64;
@@ -1482,7 +1482,7 @@
updateScrPos();
}
-static void zoomSampleDataOut(int32_t step, int16_t x)
+static void zoomSampleDataOut(int32_t step, int32_t x)
{
int32_t tmp32;
int64_t newViewSize64;
--- a/src/ft2_sample_ed_features.c
+++ b/src/ft2_sample_ed_features.c
@@ -43,11 +43,6 @@
editor.ui.sysReqShown = true;
editor.ui.sysReqEnterPressed = false;
-#ifndef __APPLE__
- if (!video.fullscreen) // release mouse button trap
- SDL_SetWindowGrab(video.window, SDL_FALSE);
-#endif
-
unstuckLastUsedGUIElement();
SDL_EventState(SDL_DROPFILE, SDL_DISABLE);
}
--- a/src/ft2_scrollbars.c
+++ b/src/ft2_scrollbars.c
@@ -20,6 +20,12 @@
#include "ft2_video.h"
#include "ft2_palette.h"
+/* Prevent the scrollbar thumbs from being so small that
+** it's difficult to use them. In units of pixels.
+** Shouldn't be higher than 9!
+*/
+#define MIN_THUMB_LENGTH 9
+
scrollBar_t scrollBars[NUM_SCROLLBARS] =
{
// ------ RESERVED SCROLLBARS ------
@@ -168,7 +174,9 @@
static void setScrollBarThumbCoords(uint16_t scrollBarID)
{
- int16_t tmp16, thumbX, thumbY, thumbW, thumbH, scrollEnd;
+ int16_t thumbX, thumbY, thumbW, thumbH, scrollEnd, realThumbLength;
+ int32_t tmp32, length, end;
+ double dTmp;
scrollBar_t *scrollBar;
assert(scrollBarID < NUM_SCROLLBARS);
@@ -196,11 +204,18 @@
if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
{
- thumbW = 15;
+ realThumbLength = 15;
+
+ thumbW = realThumbLength;
+ if (thumbW < MIN_THUMB_LENGTH)
+ thumbW = MIN_THUMB_LENGTH;
+
if (scrollBar->end > 0)
{
- tmp16 = (int16_t)round(((scrollBar->w - thumbW) / (double)scrollBar->end) * scrollBar->pos);
- thumbX = scrollBar->x + tmp16;
+ length = scrollBar->w - realThumbLength;
+ dTmp = (length / (double)scrollBar->end) * scrollBar->pos;
+ tmp32 = (int32_t)(dTmp + 0.5);
+ thumbX = (int16_t)(scrollBar->x + tmp32);
}
else
{
@@ -211,18 +226,27 @@
{
if (scrollBar->end > 0)
{
- tmp16 = (int16_t)round((scrollBar->w / (double)scrollBar->end) * scrollBar->page);
- thumbW = CLAMP(tmp16, 1, scrollBar->w);
+ dTmp = (scrollBar->w / (double)scrollBar->end) * scrollBar->page;
+ tmp32 = (int32_t)(dTmp + 0.5);
+ realThumbLength = (int16_t)CLAMP(tmp32, 1, scrollBar->w);
}
else
{
- thumbW = 1;
+ realThumbLength = 1;
}
+ thumbW = realThumbLength;
+ if (thumbW < MIN_THUMB_LENGTH)
+ thumbW = MIN_THUMB_LENGTH;
+
if (scrollBar->end > scrollBar->page)
{
- tmp16 = (int16_t)round(((scrollBar->w - thumbW) / (double)(scrollBar->end - scrollBar->page)) * scrollBar->pos);
- thumbX = scrollBar->x + tmp16;
+ length = scrollBar->w - thumbW;
+ end = scrollBar->end - scrollBar->page;
+
+ dTmp = (length / (double)end) * scrollBar->pos;
+ tmp32 = (int32_t)(dTmp + 0.5);
+ thumbX = (int16_t)(scrollBar->x + tmp32);
}
else
{
@@ -231,7 +255,7 @@
}
// prevent scrollbar thumb coords from being outside of the scrollbar area
- thumbX = CLAMP(thumbX, scrollBar->x, scrollEnd - 1);
+ thumbX = CLAMP(thumbX, scrollBar->x, scrollEnd-1);
if (thumbX+thumbW > scrollEnd)
thumbW = scrollEnd - thumbX;
}
@@ -245,18 +269,27 @@
if (scrollBar->end > 0)
{
- tmp16 = (int16_t)round((scrollBar->h / (double)scrollBar->end) * scrollBar->page);
- thumbH = CLAMP(tmp16, 1, scrollBar->h);
+ dTmp = (scrollBar->h / (double)scrollBar->end) * scrollBar->page;
+ tmp32 = (int32_t)(dTmp + 0.5);
+ realThumbLength = (int16_t)CLAMP(tmp32, MIN_THUMB_LENGTH, scrollBar->h);
}
else
{
- thumbH = 1;
+ realThumbLength = 1;
}
+ thumbH = realThumbLength;
+ if (thumbW < MIN_THUMB_LENGTH)
+ thumbW = MIN_THUMB_LENGTH;
+
if (scrollBar->end > scrollBar->page)
{
- tmp16 = (int16_t)round(((scrollBar->h - thumbH) / (double)(scrollBar->end - scrollBar->page)) * scrollBar->pos);
- thumbY = scrollBar->y + tmp16;
+ length = scrollBar->h - thumbH;
+ end = scrollBar->end - scrollBar->page;
+
+ dTmp = (length / (double)end) * scrollBar->pos;
+ tmp32 = (int32_t)(dTmp + 0.5);
+ thumbY = (int16_t)(scrollBar->y + tmp32);
}
else
{
@@ -270,6 +303,7 @@
}
// set values now
+ scrollBar->realThumbLength = realThumbLength;
scrollBar->thumbX = thumbX;
scrollBar->thumbY = thumbY;
scrollBar->thumbW = thumbW;
@@ -463,7 +497,7 @@
bool testScrollBarMouseDown(void)
{
uint16_t start, end;
- int32_t scrollPos;
+ int32_t scrollPos, length;
double dTmp;
scrollBar_t *scrollBar;
@@ -506,18 +540,26 @@
}
else
{
- mouse.saveMouseX = (int16_t)round(scrollBar->thumbW / 2.0);
+ mouse.saveMouseX = scrollBar->thumbW >> 1;
scrollPos = mouse.lastScrollX - scrollBar->x - mouse.saveMouseX;
if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
- scrollPos = (int32_t)round(scrollPos * (scrollBar->w / (double)(scrollBar->w - 15)));
+ {
+ dTmp = scrollPos * (scrollBar->w / (double)(scrollBar->w - scrollBar->thumbW));
+ scrollPos = (int32_t)(dTmp + 0.5);
+ }
+ assert(scrollBar->w > 0);
scrollPos = CLAMP(scrollPos, 0, scrollBar->w);
- assert(scrollBar->w > 0);
+ length = scrollBar->w + (scrollBar->realThumbLength - scrollBar->thumbW);
+ if (length < 1)
+ length = 1;
- dTmp = round(((double)scrollPos * scrollBar->end) / scrollBar->w);
- setScrollBarPos(mouse.lastUsedObjectID, (int32_t)dTmp, true);
+ dTmp = ((double)scrollPos * scrollBar->end) / length;
+ scrollPos = (int32_t)(dTmp + 0.5);
+
+ setScrollBarPos(mouse.lastUsedObjectID, scrollPos, true);
}
}
else
@@ -529,15 +571,21 @@
}
else
{
- mouse.saveMouseY = (int16_t)(scrollBar->thumbH / 2.0); // truncate here
+ mouse.saveMouseY = scrollBar->thumbH >> 1;
scrollPos = mouse.lastScrollY - scrollBar->y - mouse.saveMouseY;
- scrollPos = CLAMP(scrollPos, 0, scrollBar->h);
assert(scrollBar->h > 0);
+ scrollPos = CLAMP(scrollPos, 0, scrollBar->h);
- dTmp = round(((double)scrollPos * scrollBar->end) / scrollBar->h);
- setScrollBarPos(mouse.lastUsedObjectID, (int32_t)dTmp, true);
+ length = scrollBar->h + (scrollBar->realThumbLength - scrollBar->thumbW);
+ if (length < 1)
+ length = 1;
+
+ dTmp = ((double)scrollPos * scrollBar->end) / length;
+ scrollPos = (int32_t)(dTmp + 0.5);
+
+ setScrollBarPos(mouse.lastUsedObjectID, scrollPos, true);
}
}
@@ -575,7 +623,7 @@
void handleScrollBarsWhileMouseDown(void)
{
- int16_t scrollX, scrollY;
+ int32_t scrollX, scrollY, length;
double dTmp;
scrollBar_t *scrollBar;
@@ -594,16 +642,22 @@
if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
{
assert(scrollBar->w >= 16);
- scrollX = (int16_t)round(scrollX * (scrollBar->w / (double)(scrollBar->w - 15)));
+ dTmp = scrollX * (scrollBar->w / (double)(scrollBar->w - scrollBar->thumbW));
+ scrollX = (int32_t)(dTmp + 0.5);
}
+ assert(scrollBar->w > 0);
scrollX = CLAMP(scrollX, 0, scrollBar->w);
- assert(scrollBar->w > 0);
+ length = scrollBar->w + (scrollBar->realThumbLength - scrollBar->thumbW);
+ if (length < 1)
+ length = 1;
- dTmp = round(((double)scrollX * scrollBar->end) / scrollBar->w);
- setScrollBarPos(mouse.lastUsedObjectID, (int32_t)dTmp, true);
+ dTmp = ((double)scrollX * scrollBar->end) / length;
+ scrollX = (int32_t)(dTmp + 0.5);
+ setScrollBarPos(mouse.lastUsedObjectID, scrollX, true);
+
if (mouse.lastUsedObjectID != OBJECT_ID_NONE) // this can change in the callback in setScrollBarPos()
drawScrollBar(mouse.lastUsedObjectID);
}
@@ -617,10 +671,14 @@
scrollY = mouse.lastScrollY - mouse.saveMouseY - scrollBar->y;
scrollY = CLAMP(scrollY, 0, scrollBar->h);
- assert(scrollBar->h > 0);
+ length = scrollBar->h + (scrollBar->realThumbLength - scrollBar->thumbH);
+ if (length < 1)
+ length = 1;
- dTmp = round(((double)scrollY * scrollBar->end) / scrollBar->h);
- setScrollBarPos(mouse.lastUsedObjectID, (int32_t)dTmp, true);
+ dTmp = ((double)scrollY * scrollBar->end) / length;
+ scrollY = (int32_t)(dTmp + 0.5);
+
+ setScrollBarPos(mouse.lastUsedObjectID, scrollY, true);
if (mouse.lastUsedObjectID != OBJECT_ID_NONE) // this can change in the callback in setScrollBarPos()
drawScrollBar(mouse.lastUsedObjectID);
--- a/src/ft2_scrollbars.h
+++ b/src/ft2_scrollbars.h
@@ -76,7 +76,7 @@
uint8_t state;
uint32_t pos, page, end;
uint32_t oldPos, oldPage, oldEnd;
- uint16_t thumbX, thumbY, thumbW, thumbH;
+ uint16_t thumbX, thumbY, thumbW, thumbH, realThumbLength;
} scrollBar_t;
void drawScrollBar(uint16_t scrollBarID);
--- a/src/ft2_sysreqs.c
+++ b/src/ft2_sysreqs.c
@@ -161,11 +161,6 @@
pushButton_t *p;
checkBox_t *c;
-#ifndef __APPLE__
- if (!video.fullscreen) // release mouse button trap
- SDL_SetWindowGrab(video.window, SDL_FALSE);
-#endif
-
if (editor.editTextFlag)
exitTextEditing();
@@ -410,11 +405,6 @@
okBox(0, "System message", "Not enough memory!");
return 0;
}
-
-#ifndef __APPLE__
- if (!video.fullscreen) // release mouse button trap
- SDL_SetWindowGrab(video.window, SDL_FALSE);
-#endif
SDL_EventState(SDL_DROPFILE, SDL_DISABLE);
--- a/src/ft2_textboxes.c
+++ b/src/ft2_textboxes.c
@@ -63,7 +63,8 @@
};
static int16_t markX1, markX2;
-static uint16_t oldCursorPos, oldMouseX;
+static uint16_t oldCursorPos;
+static int32_t oldMouseX;
static void moveTextCursorLeft(int16_t i, bool updateTextBox);
static void moveTextCursorRight(int16_t i, bool updateTextBox);
--- a/src/ft2_video.c
+++ b/src/ft2_video.c
@@ -376,7 +376,7 @@
return true;
}
-void changeSpriteData(uint8_t sprite, const uint8_t *data)
+void changeSpriteData(int32_t sprite, const uint8_t *data)
{
sprites[sprite].data = data;
memset(sprites[sprite].refreshBuffer, 0, sprites[sprite].w * sprites[sprite].h * sizeof (int32_t));
@@ -384,7 +384,7 @@
void freeSprites(void)
{
- for (uint32_t i = 0; i < SPRITE_NUM; i++)
+ for (int32_t i = 0; i < SPRITE_NUM; i++)
{
if (sprites[i].refreshBuffer != NULL)
{
@@ -404,18 +404,18 @@
changeSpriteData(SPRITE_RIGHT_LOOP_PIN, clicked ? &bmp.loopPins[3*(154*16)] : &bmp.loopPins[2*(154*16)]);
}
-int32_t getSpritePosX(uint8_t sprite)
+int32_t getSpritePosX(int32_t sprite)
{
return sprites[sprite].x;
}
-void setSpritePos(uint8_t sprite, int16_t x, int16_t y)
+void setSpritePos(int32_t sprite, int32_t x, int32_t y)
{
- sprites[sprite].newX = x;
- sprites[sprite].newY = y;
+ sprites[sprite].newX = (int16_t)x;
+ sprites[sprite].newY = (int16_t)y;
}
-void hideSprite(uint8_t sprite)
+void hideSprite(int32_t sprite)
{
sprites[sprite].newX = SCREEN_W;
}
@@ -423,7 +423,7 @@
void eraseSprites(void)
{
int8_t i;
- register int32_t x, y, sw, sh, srcPitch, dstPitch;
+ int32_t sx, sy, x, y, sw, sh, srcPitch, dstPitch;
const uint32_t *src32;
uint32_t *dst32;
sprite_t *s;
@@ -431,28 +431,36 @@
for (i = SPRITE_NUM-1; i >= 0; i--) // erasing must be done in reverse order
{
s = &sprites[i];
- if (s->x >= SCREEN_W) // sprite is hidden, don't erase
+ if (s->x >= SCREEN_W || s->y >= SCREEN_H) // sprite is hidden, don't draw nor fill clear buffer
continue;
- assert(s->y >= 0 && s->refreshBuffer != NULL);
+ assert(s->refreshBuffer != NULL);
sw = s->w;
sh = s->h;
- x = s->x;
- y = s->y;
+ sx = s->x;
+ sy = s->y;
- // if x is negative, adjust variables (can only happen on loop pins in smp. ed.)
- if (x < 0)
+ // if x is negative, adjust variables
+ if (sx < 0)
{
- sw += x; // subtraction
- x = 0;
+ sw += sx; // subtraction
+ sx = 0;
}
+ // if y is negative, adjust variables
+ if (sy < 0)
+ {
+ sh += sy; // subtraction
+ sy = 0;
+ }
+
src32 = s->refreshBuffer;
- dst32 = &video.frameBuffer[(y * SCREEN_W) + x];
+ dst32 = &video.frameBuffer[(sy * SCREEN_W) + sx];
- if (y+sh >= SCREEN_H) sh = SCREEN_H - y;
- if (x+sw >= SCREEN_W) sw = SCREEN_W - x;
+ // handle x/y clipping
+ if (sx+sw >= SCREEN_W) sw = SCREEN_W - sx;
+ if (sy+sh >= SCREEN_H) sh = SCREEN_H - sy;
srcPitch = s->w - sw;
dstPitch = SCREEN_W - sw;
@@ -471,7 +479,7 @@
void renderSprites(void)
{
const uint8_t *src8;
- register int32_t x, y, sw, sh, srcPitch, dstPitch;
+ int32_t sx, sy, x, y, sw, sh, srcPitch, dstPitch;
uint32_t i, *clr32, *dst32, windowFlags;
sprite_t *s;
@@ -495,20 +503,42 @@
s->x = s->newX;
s->y = s->newY;
- if (s->x >= SCREEN_W) // sprite is hidden, don't draw nor fill clear buffer
+ if (s->x >= SCREEN_W || s->y >= SCREEN_H) // sprite is hidden, don't draw nor fill clear buffer
continue;
- assert(s->x >= 0 && s->y >= 0 && s->data != NULL && s->refreshBuffer != NULL);
+ assert(s->data != NULL && s->refreshBuffer != NULL);
sw = s->w;
sh = s->h;
+ sx = s->x;
+ sy = s->y;
src8 = s->data;
- dst32 = &video.frameBuffer[(s->y * SCREEN_W) + s->x];
+
+ // if x is negative, adjust variables
+ if (sx < 0)
+ {
+ sw += sx; // subtraction
+ src8 -= sx; // addition
+ sx = 0;
+ }
+
+ // if y is negative, adjust variables
+ if (sy < 0)
+ {
+ sh += sy; // subtraction
+ src8 += (-sy * s->w); // addition
+ sy = 0;
+ }
+
+ if (sw <= 0 || sh <= 0) // sprite is hidden, don't draw nor fill clear buffer
+ continue;
+
+ dst32 = &video.frameBuffer[(sy * SCREEN_W) + sx];
clr32 = s->refreshBuffer;
- // handle xy clipping
- if (s->y+sh >= SCREEN_H) sh = SCREEN_H - s->y;
- if (s->x+sw >= SCREEN_W) sw = SCREEN_W - s->x;
+ // handle x/y clipping
+ if (sx+sw >= SCREEN_W) sw = SCREEN_W - sx;
+ if (sy+sh >= SCREEN_H) sh = SCREEN_H - sy;
srcPitch = s->w - sw;
dstPitch = SCREEN_W - sw;
@@ -570,8 +600,7 @@
{
uint8_t pal;
const uint8_t *src8;
- int32_t sx;
- register int32_t x, y, sw, sh, srcPitch, dstPitch;
+ int32_t sx, x, y, sw, sh, srcPitch, dstPitch;
uint32_t *clr32, *dst32;
sprite_t *s;
@@ -604,7 +633,7 @@
dst32 = &video.frameBuffer[(s->y * SCREEN_W) + sx];
// handle x clipping
- if (s->x+sw >= SCREEN_W) sw = SCREEN_W - s->x;
+ if (sx+sw >= SCREEN_W) sw = SCREEN_W - sx;
srcPitch = s->w - sw;
dstPitch = SCREEN_W - sw;
@@ -663,7 +692,7 @@
dst32 = &video.frameBuffer[(s->y * SCREEN_W) + sx];
// handle x clipping
- if (s->x+sw >= SCREEN_W) sw = SCREEN_W - s->x;
+ if (sx+sw >= SCREEN_W) sw = SCREEN_W - sx;
srcPitch = s->w - sw;
dstPitch = SCREEN_W - sw;
--- a/src/ft2_video.h
+++ b/src/ft2_video.h
@@ -27,7 +27,7 @@
SDL_Window *window;
double dMonitorRefreshRate, dMouseXMul, dMouseYMul;
uint8_t upscaleFactor;
- bool vsync60HzPresent;
+ bool vsync60HzPresent, windowHidden;
int32_t renderX, renderY, renderW, renderH, displayW, displayH;
uint32_t *frameBufferUnaligned;
SDL_Renderer *renderer;
@@ -56,15 +56,15 @@
void closeVideo(void);
void setLeftLoopPinState(bool clicked);
void setRightLoopPinState(bool clicked);
-int32_t getSpritePosX(uint8_t sprite);
+int32_t getSpritePosX(int32_t sprite);
void eraseSprites(void);
void renderLoopPins(void);
void renderSprites(void);
bool setupSprites(void);
void freeSprites(void);
-void setSpritePos(uint8_t sprite, int16_t x, int16_t y);
-void changeSpriteData(uint8_t sprite, const uint8_t *data);
-void hideSprite(uint8_t sprite);
+void setSpritePos(int32_t sprite, int32_t x, int32_t y);
+void changeSpriteData(int32_t sprite, const uint8_t *data);
+void hideSprite(int32_t sprite);
void handleRedrawing(void);
void enterFullscreen(void);
void leaveFullScreen(void);