more sdl2 fixes:

don't recreate window every scale / fullscreen change
better renderer handling, input scaling no longer needed even if window resizing is enabled
load/save window position (replaces old windows code to do this)
calculate initial mouse position on startup because sdl no longer does this for us
This commit is contained in:
jacob1
2018-04-22 22:14:06 -04:00
parent 802ec4d252
commit 7ac7eec6cf
5 changed files with 111 additions and 189 deletions

View File

@@ -4,5 +4,4 @@ void EngineProcess();
void ClipboardPush(ByteString text); void ClipboardPush(ByteString text);
ByteString ClipboardPull(); ByteString ClipboardPull();
int GetModifiers(); int GetModifiers();
bool LoadWindowPosition(int scale);
unsigned int GetTicks(); unsigned int GetTicks();

View File

@@ -67,6 +67,7 @@ SDL_Texture * sdl_texture;
int scale = 1; int scale = 1;
bool fullscreen = false; bool fullscreen = false;
void ClipboardPush(ByteString text) void ClipboardPush(ByteString text)
{ {
SDL_SetClipboardText(text.c_str()); SDL_SetClipboardText(text.c_str());
@@ -77,6 +78,43 @@ ByteString ClipboardPull()
return ByteString(SDL_GetClipboardText()); return ByteString(SDL_GetClipboardText());
} }
int GetModifiers()
{
return SDL_GetModState();
}
void LoadWindowPosition()
{
int savedWindowX = Client::Ref().GetPrefInteger("WindowX", INT_MAX);
int savedWindowY = Client::Ref().GetPrefInteger("WindowY", INT_MAX);
SDL_SetWindowPosition(sdl_window, savedWindowX, savedWindowY);
}
void SaveWindowPosition()
{
int x, y;
SDL_GetWindowPosition(sdl_window, &x, &y);
int borderTop, borderLeft;
SDL_GetWindowBordersSize(sdl_window, &borderTop, &borderLeft, nullptr, nullptr);
Client::Ref().SetPref("WindowX", x - borderLeft);
Client::Ref().SetPref("WindowY", y - borderTop);
}
void CalculateMousePosition(int *x, int *y)
{
int globalMx, globalMy;
SDL_GetGlobalMouseState(&globalMx, &globalMy);
int windowX, windowY;
SDL_GetWindowPosition(sdl_window, &windowX, &windowY);
if (x)
*x = (globalMx - windowX) / scale;
if (y)
*y = (globalMy - windowY) / scale;
}
#ifdef OGLI #ifdef OGLI
void blit() void blit()
{ {
@@ -86,7 +124,9 @@ void blit()
void blit(pixel * vid) void blit(pixel * vid)
{ {
SDL_UpdateTexture(sdl_texture, NULL, vid, WINDOWW * sizeof (Uint32)); SDL_UpdateTexture(sdl_texture, NULL, vid, WINDOWW * sizeof (Uint32));
SDL_RenderClear(sdl_renderer); // need to clear the renderer if there are black edges (fullscreen, or resizable window)
if (fullscreen)
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL); SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
SDL_RenderPresent(sdl_renderer); SDL_RenderPresent(sdl_renderer);
} }
@@ -134,6 +174,24 @@ int SDLOpen()
SendMessage(WindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hIconBig); SendMessage(WindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hIconBig);
#endif #endif
sdl_window = SDL_CreateWindow("The Powder Toy", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOWW * scale, WINDOWH * scale,
fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
SDL_RenderSetLogicalSize(sdl_renderer, WINDOWW, WINDOWH);
//Uncomment this to force fullscreen to an integer resolution
//SDL_RenderSetIntegerScale(sdl_renderer, SDL_TRUE);
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, WINDOWW, WINDOWH);
if (fullscreen)
SDL_RaiseWindow(sdl_window);
//Uncomment this to enable resizing
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
SDL_SetWindowResizable(sdl_window, SDL_TRUE);
#ifdef LIN
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom((void*)app_icon, 48, 48, 24, 144, 0x00FF0000, 0x0000FF00, 0x000000FF, 0);
SDL_SetWindowIcon(sdl_window, icon);
SDL_FreeSurface(icon);
#endif
atexit(SDL_Quit); atexit(SDL_Quit);
return 0; return 0;
@@ -141,30 +199,12 @@ int SDLOpen()
void SDLSetScreen(int newScale, bool newFullscreen) void SDLSetScreen(int newScale, bool newFullscreen)
{ {
SDL_DestroyTexture(sdl_texture);
SDL_DestroyRenderer(sdl_renderer);
SDL_DestroyWindow(sdl_window);
scale = newScale; scale = newScale;
fullscreen = newFullscreen; fullscreen = newFullscreen;
sdl_window = SDL_CreateWindow("The Powder Toy", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOWW * newScale, WINDOWH * newScale, SDL_SetWindowSize(sdl_window, WINDOWW * newScale, WINDOWH * newScale);
newFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); SDL_SetWindowFullscreen(sdl_window, newFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom((void*)app_icon, 48, 48, 24, 144, 0x00FF0000, 0x0000FF00, 0x000000FF, 0);
//SDL_WM_SetIcon(icon, (Uint8*)app_icon_bitmap);
SDL_SetWindowIcon(sdl_window, icon);
SDL_FreeSurface(icon);
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
if (newScale > 1)
SDL_RenderSetLogicalSize(sdl_renderer, WINDOWW, WINDOWH);
//SDL_RenderSetIntegerScale(sdl_renderer, SDL_TRUE);
if (newFullscreen) if (newFullscreen)
{
SDL_RaiseWindow(sdl_window); SDL_RaiseWindow(sdl_window);
//SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
}
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, WINDOWW, WINDOWH);
//SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
//SDL_SetWindowResizable(sdl_window, SDL_TRUE);
} }
unsigned int GetTicks() unsigned int GetTicks()
@@ -236,37 +276,9 @@ std::map<ByteString, ByteString> readArguments(int argc, char * argv[])
return arguments; return arguments;
} }
/*SDLKey MapNumpad(SDLKey key)
{
switch(key)
{
case SDLK_KP8:
return SDLK_UP;
case SDLK_KP2:
return SDLK_DOWN;
case SDLK_KP6:
return SDLK_RIGHT;
case SDLK_KP4:
return SDLK_LEFT;
case SDLK_KP7:
return SDLK_HOME;
case SDLK_KP1:
return SDLK_END;
case SDLK_KP_PERIOD:
return SDLK_DELETE;
case SDLK_KP0:
case SDLK_KP9:
case SDLK_KP3:
return SDLK_UNKNOWN;
default:
return key;
}
}*/
int elapsedTime = 0, currentTime = 0, lastTime = 0, currentFrame = 0; int elapsedTime = 0, currentTime = 0, lastTime = 0, currentFrame = 0;
unsigned int lastTick = 0; unsigned int lastTick = 0;
float fps = 0, delta = 1.0f; float fps = 0, delta = 1.0f;
float inputScaleH = 1.0f, inputScaleV = 1.0f;
ui::Engine * engine = NULL; ui::Engine * engine = NULL;
bool showDoubleScreenDialog = false; bool showDoubleScreenDialog = false;
float currentWidth, currentHeight; float currentWidth, currentHeight;
@@ -275,24 +287,11 @@ int mousex = 0, mousey = 0;
int mouseButton = 0; int mouseButton = 0;
bool mouseDown = false; bool mouseDown = false;
bool calculatedInitialMouse = false, delay = false;
bool hasMouseMoved = false;
void EventProcess(SDL_Event event) void EventProcess(SDL_Event event)
{ {
//inputScale= 1.0f;
/*if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
{
if (event.key.keysym.unicode==0)
{
// If unicode is zero, this could be a numpad key with numlock off, or numlock on and shift on (unicode is set to 0 by SDL or the OS in these circumstances. If numlock is on, unicode is the relevant digit character).
// For some unknown reason, event.key.keysym.mod seems to be unreliable on some computers (keysum.mod&KEY_MOD_NUM is opposite to the actual value), so check keysym.unicode instead.
// Note: unicode is always zero for SDL_KEYUP events, so this translation won't always work properly for keyup events.
SDLKey newKey = MapNumpad(event.key.keysym.sym);
if (newKey != event.key.keysym.sym)
{
event.key.keysym.sym = newKey;
event.key.keysym.unicode = 0;
}
}
}*/
switch (event.type) switch (event.type)
{ {
case SDL_QUIT: case SDL_QUIT:
@@ -321,26 +320,36 @@ void EventProcess(SDL_Event event)
y *= -1; y *= -1;
} }
bool positiveDir = y == 0 ? x > 0 : y > 0; bool positiveDir = y == 0 ? x > 0 : y > 0;
engine->onMouseWheel(event.motion.x * inputScaleH, event.motion.y * inputScaleV, positiveDir ? 1 : -1); engine->onMouseWheel(event.motion.x, event.motion.y, positiveDir ? 1 : -1);
break; break;
} }
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
mousex = event.motion.x * inputScaleH; mousex = event.motion.x;
mousey = event.motion.y * inputScaleV; mousey = event.motion.y;
engine->onMouseMove(mousex, mousey); engine->onMouseMove(mousex, mousey);
hasMouseMoved = true;
break; break;
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
mousex = event.motion.x * inputScaleH; // if mouse hasn't moved yet, sdl will send 0,0. We don't want that
mousey = event.motion.y * inputScaleV; if (hasMouseMoved)
{
mousex = event.motion.x;
mousey = event.motion.y;
}
mouseButton = event.button.button; mouseButton = event.button.button;
engine->onMouseClick(event.motion.x * inputScaleH, event.motion.y * inputScaleV, mouseButton); engine->onMouseClick(event.motion.x, event.motion.y, mouseButton);
mouseDown = true; mouseDown = true;
SDL_CaptureMouse(SDL_TRUE); SDL_CaptureMouse(SDL_TRUE);
break; break;
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
mousex = event.motion.x * inputScaleH; // if mouse hasn't moved yet, sdl will send 0,0. We don't want that
mousey = event.motion.y * inputScaleV; if (hasMouseMoved)
{
mousex = event.motion.x;
mousey = event.motion.y;
}
mouseButton = event.button.button; mouseButton = event.button.button;
engine->onMouseUnclick(mousex, mousey, mouseButton); engine->onMouseUnclick(mousex, mousey, mouseButton);
@@ -351,7 +360,18 @@ void EventProcess(SDL_Event event)
{ {
switch (event.window.event) switch (event.window.event)
{ {
case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SHOWN:
if (!calculatedInitialMouse)
{
//initial mouse coords, sdl won't tell us this if mouse hasn't moved
CalculateMousePosition(&mousex, &mousey);
engine->onMouseMove(mousex, mousey);
calculatedInitialMouse = true;
}
break;
// This event would be needed in certain glitchy cases of window resizing
// But for all currently tested cases, it isn't needed
/*case SDL_WINDOWEVENT_RESIZED:
{ {
float width = event.window.data1; float width = event.window.data1;
float height = event.window.data2; float height = event.window.data2;
@@ -364,7 +384,7 @@ void EventProcess(SDL_Event event)
inputScaleV = (float)WINDOWH * scale / currentHeight; inputScaleV = (float)WINDOWH * scale / currentHeight;
std::cout << "Changing input scale to " << inputScaleH << "x" << inputScaleV << std::endl; std::cout << "Changing input scale to " << inputScaleH << "x" << inputScaleV << std::endl;
break; break;
} }*/
// This would send a mouse up event when focus is lost // This would send a mouse up event when focus is lost
// Not even sdl itself will know when the mouse was released if it happens in another window // Not even sdl itself will know when the mouse was released if it happens in another window
// So it will ignore the next mouse down (after tpt is re-focused) and not send any events at all // So it will ignore the next mouse down (after tpt is re-focused) and not send any events at all
@@ -423,9 +443,9 @@ void EngineProcess()
} }
#ifdef OGLI #ifdef OGLI
blit(); blit();
#else #else
blit(engine->g->vid); blit(engine->g->vid);
#endif #endif
int frameTime = SDL_GetTicks() - frameStart; int frameTime = SDL_GetTicks() - frameStart;
@@ -457,92 +477,6 @@ void EngineProcess()
#endif #endif
} }
int GetModifiers()
{
return SDL_GetModState();
}
#ifdef WIN
// Returns true if the loaded position was set
// Returns false if something went wrong: SDL_GetWMInfo failed or the loaded position was invalid
bool LoadWindowPosition(int scale)
{
SDL_SysWMinfo sysInfo;
SDL_VERSION(&sysInfo.version);
if (SDL_GetWMInfo(&sysInfo) > 0)
{
int windowW = WINDOWW * scale;
int windowH = WINDOWH * scale;
int savedWindowX = Client::Ref().GetPrefInteger("WindowX", INT_MAX);
int savedWindowY = Client::Ref().GetPrefInteger("WindowY", INT_MAX);
// Center the window on the primary desktop by default
int newWindowX = (desktopWidth - windowW) / 2;
int newWindowY = (desktopHeight - windowH) / 2;
bool success = false;
if (savedWindowX != INT_MAX && savedWindowY != INT_MAX)
{
POINT windowPoints[] = {
{savedWindowX, savedWindowY}, // Top-left
{savedWindowX + windowW, savedWindowY + windowH} // Bottom-right
};
MONITORINFO monitor;
monitor.cbSize = sizeof(monitor);
if (GetMonitorInfo(MonitorFromPoint(windowPoints[0], MONITOR_DEFAULTTONEAREST), &monitor) != 0)
{
// Only use the saved window position if it lies inside the visible screen
if (PtInRect(&monitor.rcMonitor, windowPoints[0]) && PtInRect(&monitor.rcMonitor, windowPoints[1]))
{
newWindowX = savedWindowX;
newWindowY = savedWindowY;
success = true;
}
else
{
// Center the window on the nearest monitor
newWindowX = monitor.rcMonitor.left + (monitor.rcMonitor.right - monitor.rcMonitor.left - windowW) / 2;
newWindowY = monitor.rcMonitor.top + (monitor.rcMonitor.bottom - monitor.rcMonitor.top - windowH) / 2;
}
}
}
SetWindowPos(sysInfo.window, 0, newWindowX, newWindowY, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
// True if we didn't use the default, i.e. the position was valid
return success;
}
return false;
}
// Returns true if the window position was saved
bool SaveWindowPosition()
{
SDL_SysWMinfo sysInfo;
SDL_VERSION(&sysInfo.version);
if (SDL_GetWMInfo(&sysInfo) > 0)
{
WINDOWPLACEMENT placement;
placement.length = sizeof(placement);
GetWindowPlacement(sysInfo.window, &placement);
Client::Ref().SetPref("WindowX", (int)placement.rcNormalPosition.left);
Client::Ref().SetPref("WindowY", (int)placement.rcNormalPosition.top);
return true;
}
return false;
}
#endif
void BlueScreen(String detailMessage) void BlueScreen(String detailMessage)
{ {
ui::Engine * engine = &ui::Engine::Ref(); ui::Engine * engine = &ui::Engine::Ref();
@@ -619,23 +553,20 @@ int main(int argc, char * argv[])
chdir(arguments["ddir"].c_str()); chdir(arguments["ddir"].c_str());
#endif #endif
int tempScale = 1; scale = Client::Ref().GetPrefInteger("Scale", 1);
bool tempFullscreen = false; fullscreen = Client::Ref().GetPrefBool("Fullscreen", false);
tempScale = Client::Ref().GetPrefInteger("Scale", 1);
tempFullscreen = Client::Ref().GetPrefBool("Fullscreen", false);
if(arguments["kiosk"] == "true") if(arguments["kiosk"] == "true")
{ {
tempFullscreen = true; fullscreen = true;
Client::Ref().SetPref("Fullscreen", tempFullscreen); Client::Ref().SetPref("Fullscreen", fullscreen);
} }
if(arguments["scale"].length()) if(arguments["scale"].length())
{ {
tempScale = arguments["scale"].ToNumber<int>(); scale = arguments["scale"].ToNumber<int>();
Client::Ref().SetPref("Scale", tempScale); Client::Ref().SetPref("Scale", scale);
} }
ByteString proxyString = ""; ByteString proxyString = "";
@@ -660,21 +591,18 @@ int main(int argc, char * argv[])
Client::Ref().Initialise(proxyString); Client::Ref().Initialise(proxyString);
// TODO: maybe bind the maximum allowed scale to screen size somehow // TODO: maybe bind the maximum allowed scale to screen size somehow
if(tempScale < 1 || tempScale > 10) if(scale < 1 || scale > 10)
tempScale = 1; scale = 1;
SDLOpen(); SDLOpen();
// TODO: mabe make a nice loop that automagically finds the optimal scale // TODO: mabe make a nice loop that automagically finds the optimal scale
if (Client::Ref().IsFirstRun() && desktopWidth > WINDOWW*2+50 && desktopHeight > WINDOWH*2+50) if (Client::Ref().IsFirstRun() && desktopWidth > WINDOWW*2+50 && desktopHeight > WINDOWH*2+50)
{ {
tempScale = 2; scale = 2;
Client::Ref().SetPref("Scale", 2); Client::Ref().SetPref("Scale", 2);
showDoubleScreenDialog = true; showDoubleScreenDialog = true;
} }
#ifdef WIN LoadWindowPosition();
LoadWindowPosition(tempScale);
#endif
SDLSetScreen(tempScale, tempFullscreen);
#ifdef OGLI #ifdef OGLI
SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
@@ -811,15 +739,9 @@ int main(int argc, char * argv[])
engine->ShowWindow(new FontEditor(argv[1])); engine->ShowWindow(new FontEditor(argv[1]));
#endif #endif
//initial mouse coords
int sdl_x, sdl_y;
SDL_GetMouseState(&sdl_x, &sdl_y);
engine->onMouseMove(sdl_x * inputScaleH, sdl_y * inputScaleV);
EngineProcess(); EngineProcess();
#ifdef WIN
SaveWindowPosition(); SaveWindowPosition();
#endif
#if !defined(DEBUG) && !defined(_DEBUG) #if !defined(DEBUG) && !defined(_DEBUG)
} }

View File

@@ -52,7 +52,7 @@ void ConsoleView::DoKeyPress(int key, int scan, bool repeat, bool shift, bool ct
} }
} }
void ConsoleView::DoTextInput(std::string text) void ConsoleView::DoTextInput(String text)
{ {
if (text == "~") if (text == "~")
doClose = false; doClose = false;

View File

@@ -23,7 +23,7 @@ public:
void OnDraw() override; void OnDraw() override;
void OnTick(float dt) override; void OnTick(float dt) override;
void DoKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override; void DoKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
void DoTextInput(std::string text) override; void DoTextInput(String text) override;
void AttachController(ConsoleController * c_) { c = c_; } void AttachController(ConsoleController * c_) { c = c_; }
void NotifyPreviousCommandsChanged(ConsoleModel * sender); void NotifyPreviousCommandsChanged(ConsoleModel * sender);
void NotifyCurrentCommandChanged(ConsoleModel * sender); void NotifyCurrentCommandChanged(ConsoleModel * sender);

View File

@@ -92,7 +92,8 @@ void Engine::ConfirmExit()
void Engine::ShowWindow(Window * window) void Engine::ShowWindow(Window * window)
{ {
windowOpenState = 0; windowOpenState = 0;
ignoreEvents = true; if (state_)
ignoreEvents = true;
if(window->Position.X==-1) if(window->Position.X==-1)
{ {
window->Position.X = (width_-window->Size.X)/2; window->Position.X = (width_-window->Size.X)/2;