Torque3D/Engine/source/windowManager/sdl/sdlWindowMgr.cpp
marauder2k7 ce36ea6c0b Revert "SDL.h"
This reverts commit ec5624f890.
2023-07-25 07:03:32 +01:00

590 lines
16 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "windowManager/sdl/sdlWindowMgr.h"
#include "platformSDL/sdlInputManager.h"
#include "platform/platformVolume.h"
#include "core/util/path.h"
#include "gfx/gfxDevice.h"
#include "core/util/journal/process.h"
#include "core/strings/unicode.h"
#include "gfx/bitmap/gBitmap.h"
#include "SDL.h"
// ------------------------------------------------------------------------
void sdl_CloseSplashWindow(void* hinst);
#ifdef TORQUE_SDL
PlatformWindowManager * CreatePlatformWindowManager()
{
return new PlatformWindowManagerSDL();
}
#endif
// ------------------------------------------------------------------------
PlatformWindowManagerSDL::PlatformWindowManagerSDL()
{
// Register in the process list.
mOnProcessSignalSlot.setDelegate( this, &PlatformWindowManagerSDL::_process );
Process::notify( mOnProcessSignalSlot, PROCESS_INPUT_ORDER );
// Init our list of allocated windows.
mWindowListHead = NULL;
// By default, we have no parent window.
mParentWindow = NULL;
mCurtainWindow = NULL;
mDisplayWindow = true;
mOffscreenRender = false;
mInputState = KeyboardInputState::NONE;
}
PlatformWindowManagerSDL::~PlatformWindowManagerSDL()
{
// Kill all our windows first.
while(mWindowListHead)
// The destructors update the list, so this works just fine.
delete mWindowListHead;
}
RectI PlatformWindowManagerSDL::getPrimaryDesktopArea()
{
// Primary is monitor 0
return getMonitorRect(0);
}
Point2I PlatformWindowManagerSDL::getDesktopResolution()
{
SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(0, &mode);
// Return Resolution
return Point2I(mode.w, mode.h);
}
S32 PlatformWindowManagerSDL::getDesktopBitDepth()
{
// Return Bits per Pixel
SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(0, &mode);
int bbp;
unsigned int r,g,b,a;
SDL_PixelFormatEnumToMasks(mode.format, &bbp, &r, &g, &b, &a);
return bbp;
}
S32 PlatformWindowManagerSDL::findFirstMatchingMonitor(const char* name)
{
S32 count = SDL_GetNumVideoDisplays();
for (U32 index = 0; index < count; ++index)
{
if (dStrstr(name, SDL_GetDisplayName(index)) == name)
return index;
}
return 0;
}
U32 PlatformWindowManagerSDL::getMonitorCount()
{
S32 monitorCount = SDL_GetNumVideoDisplays();
if (monitorCount < 0)
{
Con::errorf("SDL_GetNumVideoDisplays() failed: %s", SDL_GetError());
monitorCount = 0;
}
return (U32)monitorCount;
}
const char* PlatformWindowManagerSDL::getMonitorName(U32 index)
{
const char* monitorName = SDL_GetDisplayName(index);
if (monitorName == NULL)
Con::errorf("SDL_GetDisplayName() failed: %s", SDL_GetError());
return monitorName;
}
RectI PlatformWindowManagerSDL::getMonitorRect(U32 index)
{
SDL_Rect sdlRect;
if (0 != SDL_GetDisplayBounds(index, &sdlRect))
{
Con::errorf("SDL_GetDisplayBounds() failed: %s", SDL_GetError());
return RectI(0, 0, 0, 0);
}
return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
}
RectI PlatformWindowManagerSDL::getMonitorUsableRect(U32 index)
{
SDL_Rect sdlRect;
if (0 != SDL_GetDisplayUsableBounds(index, &sdlRect))
{
Con::errorf("SDL_GetDisplayUsableBounds() failed: %s", SDL_GetError());
return RectI(0, 0, 0, 0);
}
return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
}
U32 PlatformWindowManagerSDL::getMonitorModeCount(U32 monitorIndex)
{
S32 modeCount = SDL_GetNumDisplayModes(monitorIndex);
if (modeCount < 0)
{
Con::errorf("SDL_GetNumDisplayModes(%d) failed: %s", monitorIndex, SDL_GetError());
modeCount = 0;
}
return (U32)modeCount;
}
const String PlatformWindowManagerSDL::getMonitorMode(U32 monitorIndex, U32 modeIndex)
{
SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
if (SDL_GetDisplayMode(monitorIndex, modeIndex, &mode) != 0)
{
Con::errorf("SDL_GetDisplayMode(%d, %d) failed: %s", monitorIndex, modeIndex, SDL_GetError());
return String::EmptyString;
}
GFXVideoMode vm;
vm.resolution.set(mode.w, mode.h);
vm.refreshRate = mode.refresh_rate;
vm.bitDepth = 32;
vm.antialiasLevel = 0;
vm.fullScreen = false;
vm.wideScreen = false;
return vm.toString();
}
const String PlatformWindowManagerSDL::getMonitorDesktopMode(U32 monitorIndex)
{
SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
if (SDL_GetDesktopDisplayMode(monitorIndex, &mode) != 0)
{
Con::errorf("SDL_GetDesktopDisplayMode(%d) failed: %s", monitorIndex, SDL_GetError());
return String::EmptyString;
}
GFXVideoMode vm;
vm.resolution.set(mode.w, mode.h);
vm.refreshRate = mode.refresh_rate;
int bbp;
unsigned int r, g, b, a;
SDL_PixelFormatEnumToMasks(mode.format, &bbp, &r, &g, &b, &a);
vm.bitDepth = bbp;
vm.antialiasLevel = 0;
vm.fullScreen = false;
vm.wideScreen = ((mode.w / 16) * 9) == mode.h;
return vm.toString();
}
void PlatformWindowManagerSDL::getMonitorRegions(Vector<RectI> &regions)
{
SDL_Rect sdlRect;
S32 monitorCount = SDL_GetNumVideoDisplays();
for (S32 index = 0; index < monitorCount; ++index)
{
if (0 == SDL_GetDisplayBounds(index, &sdlRect))
regions.push_back(RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h));
}
}
void PlatformWindowManagerSDL::getWindows(VectorPtr<PlatformWindow*> &windows)
{
PlatformWindowSDL *win = mWindowListHead;
while(win)
{
windows.push_back(win);
win = win->mNextWindow;
}
}
PlatformWindow *PlatformWindowManagerSDL::createWindow(GFXDevice *device, const GFXVideoMode &mode)
{
// Do the allocation.
PlatformWindowSDL *window = new PlatformWindowSDL();
U32 windowFlags = /*SDL_WINDOW_SHOWN |*/ SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN;
if(GFX->getAdapterType() == OpenGL)
windowFlags |= SDL_WINDOW_OPENGL;
window->mWindowHandle = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, mode.resolution.x, mode.resolution.y, windowFlags );
window->mWindowId = SDL_GetWindowID( window->mWindowHandle );
window->mOwningManager = this;
mWindowMap[ window->mWindowId ] = window;
//Now, fetch our window icon, if any
Torque::Path iconPath = Torque::Path(Con::getVariable( "$Core::windowIcon" ));
if (iconPath.getExtension() == String("bmp"))
{
Con::errorf("Unable to use bmp format images for the window icon. Please use a different format.");
}
else
{
Resource<GBitmap> img = GBitmap::load(iconPath);
if (img != NULL)
{
U32 pitch;
U32 width = img->getWidth();
bool hasAlpha = img->getHasTransparency();
U32 depth;
if (hasAlpha)
{
pitch = 4 * width;
depth = 32;
}
else
{
pitch = 3 * width;
depth = 24;
}
Uint32 rmask, gmask, bmask, amask;
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
S32 shift = hasAlpha ? 8 : 0;
rmask = 0xff000000 >> shift;
gmask = 0x00ff0000 >> shift;
bmask = 0x0000ff00 >> shift;
amask = 0x000000ff >> shift;
}
else
{
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = hasAlpha ? 0xff000000 : 0;
}
SDL_Surface* iconSurface = SDL_CreateRGBSurfaceFrom(img->getAddress(0, 0), img->getWidth(), img->getHeight(), depth, pitch, rmask, gmask, bmask, amask);
SDL_SetWindowIcon(window->mWindowHandle, iconSurface);
SDL_FreeSurface(iconSurface);
}
}
if(device)
{
window->mDevice = device;
window->mTarget = device->allocWindowTarget(window);
AssertISV(window->mTarget, "PlatformWindowManagerSDL::createWindow - failed to get a window target back from the device.");
}
else
{
Con::warnf("PlatformWindowManagerSDL::createWindow - created a window with no device!");
}
//Set it up for drag-n-drop events
#ifdef TORQUE_TOOLS
SDL_EventState(SDL_DROPBEGIN, SDL_ENABLE);
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
SDL_EventState(SDL_DROPCOMPLETE, SDL_ENABLE);
#endif
linkWindow(window);
SDL_SetWindowMinimumSize(window->mWindowHandle, Con::getIntVariable("$Video::minimumXResolution", 1024),
Con::getIntVariable("$Video::minimumYResolution", 720));
return window;
}
void PlatformWindowManagerSDL::setParentWindow(void* newParent)
{
}
void* PlatformWindowManagerSDL::getParentWindow()
{
return NULL;
}
void PlatformWindowManagerSDL::_process()
{
SDL_Event evt;
while( SDL_PollEvent(&evt) )
{
if (evt.type >= SDL_JOYAXISMOTION && evt.type <= SDL_CONTROLLERDEVICEREMAPPED)
{
SDLInputManager* mgr = static_cast<SDLInputManager*>(Input::getManager());
if (mgr)
mgr->processEvent(evt);
continue;
}
switch(evt.type)
{
case SDL_QUIT:
{
PlatformWindowSDL *window = static_cast<PlatformWindowSDL*>( getFirstWindow() );
if(window)
window->appEvent.trigger( window->getWindowId(), WindowClose );
break;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
PlatformWindowSDL *window = mWindowMap[evt.key.windowID];
if(window)
window->_processSDLEvent(evt);
break;
}
case SDL_MOUSEWHEEL:
{
PlatformWindowSDL *window = mWindowMap[evt.wheel.windowID];
if (window)
window->_processSDLEvent(evt);
break;
}
case SDL_MOUSEMOTION:
{
PlatformWindowSDL *window = mWindowMap[evt.motion.windowID];
if(window)
window->_processSDLEvent(evt);
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
PlatformWindowSDL *window = mWindowMap[evt.button.windowID];
if(window)
window->_processSDLEvent(evt);
break;
}
case SDL_TEXTINPUT:
{
PlatformWindowSDL *window = mWindowMap[evt.text.windowID];
if(window)
window->_processSDLEvent(evt);
break;
}
case SDL_WINDOWEVENT:
{
PlatformWindowSDL *window = mWindowMap[evt.window.windowID];
if(window)
window->_processSDLEvent(evt);
break;
}
case(SDL_DROPBEGIN):
{
if (!Con::isFunction("onDropBegin"))
break;
Con::executef("onDropBegin");
}
case (SDL_DROPFILE):
{
// In case if dropped file
if (!Con::isFunction("onDropFile"))
break;
char* fileName = evt.drop.file;
if (!Platform::isDirectory(fileName) && !Platform::isFile(fileName))
break;
Con::executef("onDropFile", StringTable->insert(fileName));
SDL_free(fileName); // Free dropped_filedir memory
break;
}
case(SDL_DROPCOMPLETE):
{
if (Con::isFunction("onDropEnd"))
Con::executef("onDropEnd");
break;
}
default:
{
#ifdef TORQUE_DEBUG
Con::warnf("Unhandled SDL input event: 0x%04x", evt.type);
#endif
}
}
}
// After the event loop is processed, we can now see if we have to notify
// SDL that we want text based events. This fixes a bug where text based
// events would be generated while key presses would still be happening.
// See KeyboardInputState for further documentation.
if (mInputState != KeyboardInputState::NONE)
{
// Update text mode toggling.
if (mInputState == KeyboardInputState::TEXT_INPUT)
SDL_StartTextInput();
else
SDL_StopTextInput();
// Done until we need to update it again.
mInputState = KeyboardInputState::NONE;
}
}
PlatformWindow * PlatformWindowManagerSDL::getWindowById( WindowId id )
{
// Walk the list and find the matching id, if any.
PlatformWindowSDL *win = mWindowListHead;
while(win)
{
if(win->getWindowId() == id)
return win;
win = win->mNextWindow;
}
return NULL;
}
PlatformWindow * PlatformWindowManagerSDL::getFirstWindow()
{
return mWindowListHead != NULL ? mWindowListHead : NULL;
}
PlatformWindow* PlatformWindowManagerSDL::getFocusedWindow()
{
PlatformWindowSDL* window = mWindowListHead;
while( window )
{
if( window->isFocused() )
return window;
window = window->mNextWindow;
}
return NULL;
}
void PlatformWindowManagerSDL::linkWindow( PlatformWindowSDL *w )
{
w->mNextWindow = mWindowListHead;
mWindowListHead = w;
}
void PlatformWindowManagerSDL::unlinkWindow( PlatformWindowSDL *w )
{
PlatformWindowSDL **walk = &mWindowListHead;
while(*walk)
{
if(*walk != w)
{
// Advance to next item in list.
walk = &(*walk)->mNextWindow;
continue;
}
// Got a match - unlink and return.
*walk = (*walk)->mNextWindow;
return;
}
}
void PlatformWindowManagerSDL::_processCmdLineArgs( const S32 argc, const char **argv )
{
// TODO SDL
}
void PlatformWindowManagerSDL::lowerCurtain()
{
if(mCurtainWindow)
return;
// TODO SDL
}
void PlatformWindowManagerSDL::raiseCurtain()
{
if(!mCurtainWindow)
return;
// TODO SDL
}
void PlatformWindowManagerSDL::updateSDLTextInputState(KeyboardInputState state)
{
// Force update state. This will respond at the end of the event loop.
mInputState = state;
}
void Platform::openFolder(const char* path )
{
AssertFatal(0, "Not Implemented");
}
void Platform::openFile(const char* path )
{
AssertFatal(0, "Not Implemented");
}
//------------------------------------------------------------------------------
namespace GL
{
void gglPerformBinds();
}
void InitWindowingSystem()
{
}
AFTER_MODULE_INIT(gfx)
{
#if !defined(TORQUE_DEDICATED)
int res = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE);
AssertFatal(res != -1, avar("SDL error:%s", SDL_GetError()));
// By default, SDL enables text input. We disable it on initialization, and
// we will enable it whenever the time is right.
SDL_StopTextInput();
#endif
}