123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- // Portions Copyright (c) 2014 James S Urquhart
- //
- // 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 "console/console.h"
- #include "io/fileStream.h"
- #include "game/resource.h"
- #include "game/version.h"
- #include "math/mRandom.h"
- #include "platformEmscripten/platformEmscripten.h"
- #include "platformEmscripten/EmscriptenConsole.h"
- #include "platform/event.h"
- #include "game/gameInterface.h"
- #include "platform/platform.h"
- #include "platform/platformAL.h"
- #include "platform/platformInput.h"
- #include "platform/platformVideo.h"
- #include "debug/profiler.h"
- #include "platformEmscripten/platformGL.h"
- #include "platformEmscripten/EmscriptenOGLVideo.h"
- #ifndef DEDICATED
- #include "platformEmscripten/EmscriptenInputManager.h"
- #endif
- #include <errno.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <unistd.h> // fork, execvp, chdir
- #include <time.h> // nanosleep
- #ifndef DEDICATED
- #include <SDL/SDL.h>
- #include <SDL/SDL_syswm.h>
- #include <SDL/SDL_version.h>
- extern bool InitOpenGL();
- extern void Cleanup(bool minimal=false);
- #endif
- extern "C"
- {
- extern U32 _EmscriptenGetDesktopHeight();
- extern U32 _EmscriptenGetDesktopWidth();
- extern U32 _EmscriptenGetDesktopBpp();
- }
- EmscriptenPlatState::EmscriptenPlatState()
- {
- captureDisplay = true;
- fadeWindows = true;
- backgrounded = false;
- minimized = false;
- quit = false;
- portrait = true;//-Mat Android is in portrait mode by default
- // start with something reasonable.
- fullscreen = true;
- osVersion = 0;
- dStrcpy(appWindowTitle, "Emscripten Torque Game Engine");
- // directory that contains main.cs . This will help us detect whether we are
- // running with the scripts in the bundle or not.
- mainDotCsDir = NULL;
- useRedirect = true;
- windowCreated = false;
- dedicated = false;
- printf("platstate init\n");
- }
- //------------------------------------------------------------------------------
- static void InitWindow(const Point2I &initialSize, const char *name)
- {
- gPlatState.windowSize = initialSize;
- gPlatState.setWindowTitle(name);
- }
- #ifndef DEDICATED
- //------------------------------------------------------------------------------
- static bool InitSDL()
- {
- if (SDL_Init(SDL_INIT_VIDEO) != 0)
- return false;
- atexit(SDL_Quit);
- SDL_SysWMinfo sysinfo;
- SDL_VERSION(&sysinfo.version);
- //if (SDL_GetWMInfo(&sysinfo) == 0)
- // return false;
- return true;
- }
- //------------------------------------------------------------------------------
- static void SetAppState()
- {
- U8 state = SDL_GetAppState();
- // if we're not active but we have appactive and inputfocus, set window
- // active and reactivate input
- if ((gPlatState.backgrounded || !Input::isActive()) &&
- state & SDL_APPACTIVE &&
- state & SDL_APPINPUTFOCUS)
- {
- gPlatState.backgrounded = false;
- Input::reactivate();
- Con::printf("Input activated by SetAppState");
- }
- // if we are active, but we don't have appactive or input focus,
- // deactivate input (if window not locked) and clear windowActive
- else if (!gPlatState.backgrounded &&
- !(state & SDL_APPACTIVE && state & SDL_APPINPUTFOCUS))
- {
- if (gPlatState.mouseLocked)
- Input::deactivate();
- gPlatState.backgrounded = true;
- Con::printf("Input deactivated by SetAppState");
- }
- }
- //------------------------------------------------------------------------------
- static S32 NumEventsPending()
- {
- static const int MaxEvents = 255;
- static SDL_Event events[MaxEvents];
- SDL_PumpEvents();
- #ifdef DUMMY_PLATFORM
- return 0;
- #else
- return SDL_PeepEvents(events, MaxEvents, SDL_PEEKEVENT, 0, SDL_LASTEVENT);
- #endif
- }
- //------------------------------------------------------------------------------
- static bool ProcessMessages()
- {
- #ifndef DUMMY_PLATFORM
- SDL_PumpEvents();
- // We're going to have to maintain our own list of events here, since the emscripten API
- // is a bit broken for our purposes...
- gPlatState.eventList.clear();
- gPlatState.eventList.reserve(255);
- SDL_Event e;
- while (SDL_PollEvent(&e))
- {
- gPlatState.eventList.push_back(e);
- }
- S32 numEvents = gPlatState.eventList.size();
- //if (numEvents > 0)
- // Con::printf("ProcessMessages: %i events pending", numEvents);
- if (numEvents == 0)
- return true;
- for (int i = 0; i < numEvents; ++i)
- {
- SDL_Event& event = gPlatState.eventList[i];
- //Con::printf("Event.type == %u", event.type);
- switch (event.type)
- {
- case SDL_QUIT:
- return false;
- break;
- case SDL_VIDEORESIZE:
- case SDL_VIDEOEXPOSE:
- Game->refreshWindow();
- break;
- case SDL_USEREVENT:
- Con::printf("User event handled");
- if (event.user.code == TORQUE_SETVIDEOMODE)
- {
- SetAppState();
- // SDL will send a motion event to restore the mouse position
- // on the new window. Ignore that if the window is locked.
- if (gPlatState.mouseLocked)
- {
- SDL_Event tempEvent;
- SDL_PeepEvents(&tempEvent, 1, SDL_GETEVENT, SDL_MOUSEMOTION,
- SDL_MOUSEMOTION);
- }
- }
- break;
- case SDL_ACTIVEEVENT:
- Con::printf("Active event");
- SetAppState();
- break;
- }
- }
- #endif
- return true;
- }
- //------------------------------------------------------------------------------
- // send a destroy window event to the window. assumes
- // window is created.
- void SendQuitEvent()
- {
- SDL_Event quitevent;
- quitevent.type = SDL_QUIT;
- SDL_PushEvent(&quitevent);
- }
- #endif // DEDICATED
- //------------------------------------------------------------------------------
- static inline void Sleep(int secs, int nanoSecs)
- {
- timespec sleeptime;
- sleeptime.tv_sec = secs;
- sleeptime.tv_nsec = nanoSecs;
- nanosleep(&sleeptime, NULL);
- }
- #ifndef DEDICATED
- struct AlertWinState
- {
- bool fullScreen;
- bool cursorHidden;
- bool inputGrabbed;
- };
- //------------------------------------------------------------------------------
- void DisplayErrorAlert(const char* errMsg, bool showSDLError)
- {
- char fullErrMsg[2048];
- dStrncpy(fullErrMsg, errMsg, sizeof(fullErrMsg));
-
- if (showSDLError)
- {
- const char* sdlerror = SDL_GetError();
- if (sdlerror != NULL && dStrlen(sdlerror) > 0)
- {
- dStrcat(fullErrMsg, " (Error: ");
- dStrcat(fullErrMsg, sdlerror);
- dStrcat(fullErrMsg, ")");
- }
- }
-
- Platform::AlertOK("Error", fullErrMsg);
- }
- //------------------------------------------------------------------------------
- static inline void AlertDisableVideo(AlertWinState& state)
- {
- state.fullScreen = Video::isFullScreen();
- state.cursorHidden = (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE);
- state.inputGrabbed = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON);
- if (state.fullScreen)
- SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
- if (state.cursorHidden)
- SDL_ShowCursor(SDL_ENABLE);
- if (state.inputGrabbed)
- SDL_WM_GrabInput(SDL_GRAB_OFF);
- }
- //------------------------------------------------------------------------------
- static inline void AlertEnableVideo(AlertWinState& state)
- {
- if (state.fullScreen)
- SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
- if (state.cursorHidden)
- SDL_ShowCursor(SDL_DISABLE);
- if (state.inputGrabbed)
- SDL_WM_GrabInput(SDL_GRAB_ON);
- }
- #endif // DEDICATED
- //------------------------------------------------------------------------------
- void Platform::setMouseLock(bool locked)
- {
- #ifndef DEDICATED
- gPlatState.mouseLocked = locked;
- UInputManager* uInputManager =
- dynamic_cast<UInputManager*>( Input::getManager() );
- if ( uInputManager && uInputManager->isEnabled() &&
- Input::isActive() )
- uInputManager->setWindowLocked(locked);
- #endif
- }
- //------------------------------------------------------------------------------
- void Platform::process()
- {
- PROFILE_START(XUX_PlatformProcess);
- if (gPlatState.windowCreated)
- {
- #ifndef DEDICATED
- // process window events
- PROFILE_START(XUX_ProcessMessages);
- bool quit = !ProcessMessages();
- PROFILE_END();
- if(quit)
- {
- // generate a quit event
- Event quitEvent;
- quitEvent.type = QuitEventType;
- Game->postEvent(quitEvent);
- }
- // process input events
- PROFILE_START(XUX_InputProcess);
- Input::process();
- PROFILE_END();
- // if we're not the foreground window, sleep for 1 ms
- if (gPlatState.backgrounded)
- Sleep(0, getBackgroundSleepTime() * 1000000);
- #endif
- }
- else
- {
- Sleep(0, getBackgroundSleepTime() * 1000000);
- }
- PROFILE_END();
- }
- //------------------------------------------------------------------------------
- const Point2I &Platform::getWindowSize()
- {
- return gPlatState.windowSize;
- }
- //------------------------------------------------------------------------------
- void Platform::setWindowSize( U32 newWidth, U32 newHeight )
- {
- gPlatState.windowSize = Point2I(newWidth, newHeight);
- }
- //------------------------------------------------------------------------------
- void Platform::minimizeWindow()
- {
- #ifndef DEDICATED
- if (gPlatState.windowCreated)
- SDL_WM_IconifyWindow();
- #endif
- }
- //------------------------------------------------------------------------------
- void Platform::restoreWindow()
- {
- }
- //------------------------------------------------------------------------------
- void Platform::shutdown()
- {
- Cleanup();
- }
- //------------------------------------------------------------------------------
- void Platform::init()
- {
- Con::printf("Platform::init");
- // Set the platform variable for the scripts
- Con::setVariable( "$platform", "x86UNIX" );
- Con::setVariable( "$platformUnixType", "emscripten" );
- EmscriptenConsole::create();
-
- #ifndef DEDICATED
- Con::printf("Dedicated == %i", gPlatState.dedicated);
- // if we're not dedicated do more initialization
- //if (!gPlatState.dedicated)
- {
- printf("Init non-dedicated\n");
- // init SDL
- if (!InitSDL())
- {
- Con::printf( " Unable to initialize SDL." );
- Platform::AlertOK("Error", "Unable to initialize SDL.");
- exit(1);
- }
- // initialize input
- Input::init();
- Con::printf( "Video Init:" );
- // initialize video
- Video::init();
- if ( Video::installDevice( OpenGLDevice::create() ) )
- Con::printf( " OpenGL display device detected." );
- else
- Con::printf( " OpenGL display device not detected." );
-
- Con::printf(" ");
- }
- #endif
- }
- //------------------------------------------------------------------------------
- void Platform::initWindow(const Point2I &initialSize, const char *name)
- {
- #ifndef DEDICATED
- // initialize window
- InitWindow(initialSize, name);
- if (!InitOpenGL()) {
- Con::printf( " Unable to init OpenGL window." );
- exit(1);
- }
- #endif
- }
- //------------------------------------------------------------------------------
- // Web browser function:
- //------------------------------------------------------------------------------
- bool Platform::openWebBrowser( const char* webAddress )
- {
- return false;
- }
- //------------------------------------------------------------------------------
- ConsoleFunction( getDesktopResolution, const char*, 1, 1,
- "getDesktopResolution()" )
- {
- if (!gPlatState.windowCreated)
- return "0 0 0";
- char buffer[256];
- char* returnString = Con::getReturnBuffer( dStrlen( buffer ) + 1 );
- Resolution res = Video::getDesktopResolution();
- dSprintf( buffer, sizeof( buffer ), "%d %d %d",
- res.w,
- res.h,
- res.bpp );
- dStrcpy( returnString, buffer );
- return( returnString );
- }
- //------------------------------------------------------------------------------
- // Silly Korean registry key checker:
- //------------------------------------------------------------------------------
- ConsoleFunction( isKoreanBuild, bool, 1, 1, "isKoreanBuild()" )
- {
- Con::printf("WARNING: isKoreanBuild() is unimplemented");
- return false;
- }
- //------------------------------------------------------------------------------
- void Platform::setWindowTitle( const char* title )
- {
- #ifndef DEDICATED
- gPlatState.setWindowTitle(title);
- SDL_WM_SetCaption(gPlatState.appWindowTitle, NULL);
- #endif
- }
- //------------------------------------------------------------------------------
- Resolution Video::getDesktopResolution()
- {
- Resolution Result;
- Result.h = _EmscriptenGetDesktopHeight();
- Result.w = _EmscriptenGetDesktopWidth();
- Result.bpp = _EmscriptenGetDesktopBpp();
- return Result;
- }
- //-----------------------------------------------------------------------------
- void Platform::outputDebugString( const char *string )
- {
- fprintf(stderr, "%s", string);
- fprintf(stderr, "\n" );
- fflush(stderr);
- }
|