From: Jerome St-Louis Date: Sat, 10 Oct 2015 02:25:20 +0000 (-0400) Subject: ecere: Initial Emscripten support X-Git-Tag: 0.44.15~168 X-Git-Url: https://ecere.com/cgi-bin/gitweb.cgi?p=sdk;a=commitdiff_plain;h=26a4c51498aecb302708c345c323cd10ccf3fd6b ecere: Initial Emscripten support - Mekano, Chess and UWClone working reasonably well --- diff --git a/ecere/ecere.epj b/ecere/ecere.epj index 8a3dbea..6b89c69 100644 --- a/ecere/ecere.epj +++ b/ecere/ecere.epj @@ -780,12 +780,6 @@ if distributed with the Ecere SDK Windows installer. } } ] - }, - { - "Name" : "Emscripten", - "Options" : { - "ExcludeFromBuild" : true - } } ] }, @@ -800,17 +794,7 @@ if distributed with the Ecere SDK Windows installer. } ] }, - { - "FileName" : "PNGFormat.ec", - "Configurations" : [ - { - "Name" : "Emscripten", - "Options" : { - "ExcludeFromBuild" : true - } - } - ] - }, + "PNGFormat.ec", { "FileName" : "RGBFormat.ec", "Configurations" : [ @@ -998,6 +982,18 @@ if distributed with the Ecere SDK Windows installer. "Options" : { "ExcludeFromBuild" : false } + }, + { + "Name" : "Static", + "Options" : { + "ExcludeFromBuild" : false + } + }, + { + "Name" : "Emscripten", + "Options" : { + "ExcludeFromBuild" : false + } } ] }, @@ -1039,6 +1035,18 @@ if distributed with the Ecere SDK Windows installer. "Options" : { "ExcludeFromBuild" : false } + }, + { + "Name" : "Static", + "Options" : { + "ExcludeFromBuild" : false + } + }, + { + "Name" : "Emscripten", + "Options" : { + "ExcludeFromBuild" : false + } } ] }, @@ -1092,6 +1100,18 @@ if distributed with the Ecere SDK Windows installer. "Options" : { "ExcludeFromBuild" : false } + }, + { + "Name" : "Static", + "Options" : { + "ExcludeFromBuild" : false + } + }, + { + "Name" : "Emscripten", + "Options" : { + "ExcludeFromBuild" : false + } } ] }, @@ -1189,6 +1209,12 @@ if distributed with the Ecere SDK Windows installer. "Options" : { "ExcludeFromBuild" : false } + }, + { + "Name" : "Static", + "Options" : { + "ExcludeFromBuild" : false + } } ] }, @@ -1914,6 +1940,17 @@ if distributed with the Ecere SDK Windows installer. } } ] + }, + { + "Name" : "Emscripten", + "Platforms" : [ + { + "Name" : "linux", + "Options" : { + "ExcludeFromBuild" : true + } + } + ] } ] } @@ -2105,6 +2142,17 @@ if distributed with the Ecere SDK Windows installer. } } ] + }, + { + "Name" : "Emscripten", + "Platforms" : [ + { + "Name" : "linux", + "Options" : { + "ExcludeFromBuild" : true + } + } + ] } ] }, @@ -2250,6 +2298,17 @@ if distributed with the Ecere SDK Windows installer. } } ] + }, + { + "Name" : "Emscripten", + "Platforms" : [ + { + "Name" : "linux", + "Options" : { + "ExcludeFromBuild" : true + } + } + ] } ] }, @@ -2274,7 +2333,8 @@ if distributed with the Ecere SDK Windows installer. } } ] - } + }, + "test_html5.c" ], "Options" : { "ExcludeFromBuild" : true diff --git a/ecere/src/com/String.ec b/ecere/src/com/String.ec index 0f1c6fe..a789316 100644 --- a/ecere/src/com/String.ec +++ b/ecere/src/com/String.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace sys; #define set _set @@ -10,7 +12,7 @@ default: #include #include #if !defined(ECERE_BOOTSTRAP) // quick fix for now -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #define String _String #include diff --git a/ecere/src/com/instance.c b/ecere/src/com/instance.c index 1d63806..7ae555d 100644 --- a/ecere/src/com/instance.c +++ b/ecere/src/com/instance.c @@ -1,3 +1,5 @@ +#define _Noreturn + #include #include #include @@ -24,7 +26,7 @@ #undef bool #endif -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #define UNICODE #include @@ -54,14 +56,14 @@ typedef unsigned long long uint64; __declspec(dllexport) int isblank(int c) { return c == '\t' || c == ' '; } #endif -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) intptr_t stdinHandle, stdoutHandle; int osfStdin, osfStdout; FILE * fStdIn, * fStdOut; #endif FILE *eC_stdin(void) { -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) if(!fStdIn) { stdinHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE); @@ -137,7 +139,7 @@ extern struct __ecereNameSpace__ecere__com__Instance * __thisModule; typedef enum { unknown, win32, tux, apple } Platform; -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) Platform runtimePlatform = win32; #elif defined(__APPLE__) Platform runtimePlatform = apple; @@ -190,7 +192,7 @@ static bool DualPipe_GetLine(FILE * p, char *s, int max) bool Instance_LocateModule(const char * name, char * fileName) { -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) HMODULE hModule = null; if(name && name[0]) { @@ -404,11 +406,11 @@ bool Instance_LocateModule(const char * name, char * fileName) void Instance_COM_Initialize(int argc, char ** argv, char ** parsedCommand, int * argcPtr, const char *** argvPtr) { -#if !defined(__WIN32__) && !defined(__EMSCRIPTEN__) && !defined(ECERE_BOOTSTRAP) +#if !defined(__WIN32__) && !defined(ECERE_BOOTSTRAP) // Disable stdout buffering on Unix setvbuf(stdout, null, _IONBF, 0); #endif -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) *parsedCommand = UTF16toUTF8(GetCommandLineW()); *argvPtr = eSystem_New0(sizeof(char *) * 512); *argcPtr = Tokenize(*parsedCommand, 512,(void*)(char **)(*argvPtr), forArgsPassing); @@ -454,7 +456,7 @@ void * Instance_Module_Load(const char * libLocation, const char * name, void ** *Load = null; *Unload = null; -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) strcpy(fileName, name); GetExtension(fileName, extension); if(!extension[0]) @@ -571,7 +573,7 @@ void * Instance_Module_Load(const char * libLocation, const char * name, void ** void Instance_Module_Free(void * library) { -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) if(library) FreeLibrary(library); #elif (defined(__unix__) || defined(__APPLE__)) && !defined(__EMSCRIPTEN__) diff --git a/ecere/src/com/instance.ec b/ecere/src/com/instance.ec index c3627b0..097b732 100644 --- a/ecere/src/com/instance.ec +++ b/ecere/src/com/instance.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace com; // #define DISABLE_MEMMGR @@ -26,6 +28,10 @@ import "Mutex" #endif #endif +#if defined(__EMSCRIPTEN__) +#define GetCurrentThreadID() 0 +#endif + // #define MEMINFO /* #ifdef MEMINFO @@ -1454,7 +1460,7 @@ static void * _malloc(unsigned int size) void * pointer; -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Wait(); #endif @@ -1481,7 +1487,9 @@ static void * _malloc(unsigned int size) printf(" %s\n", stack.frames[c]); memoryErrorsCount++; +#if !defined(__EMSCRIPTEN__) memMutex.Release(); +#endif return null; } @@ -1496,7 +1504,7 @@ static void * _malloc(unsigned int size) } #endif -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Release(); #endif @@ -1519,7 +1527,7 @@ static void * _calloc(int n, unsigned int size) #else void * pointer; -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Wait(); #endif @@ -1544,7 +1552,9 @@ static void * _calloc(int n, unsigned int size) if(stack.frames[c]) printf(" %s\n", stack.frames[c]); memoryErrorsCount++; +#if !defined(__EMSCRIPTEN__) memMutex.Release(); +#endif return null; } @@ -1561,7 +1571,7 @@ static void * _calloc(int n, unsigned int size) } #endif -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Release(); #endif @@ -1585,7 +1595,7 @@ static void * _realloc(void * pointer, unsigned int size) #else if(!size) { _free(pointer); return null; } -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Wait(); #endif @@ -1627,7 +1637,9 @@ static void * _realloc(void * pointer, unsigned int size) if(stack.frames[c]) printf(" %s\n", stack.frames[c]); memoryErrorsCount++; +#if !defined(__EMSCRIPTEN__) memMutex.Release(); +#endif return null; } memset(pointer, 0xAB, REDZONE); @@ -1675,7 +1687,7 @@ static void * _realloc(void * pointer, unsigned int size) pointer = realloc(pointer, size); #endif -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Release(); #endif return pointer ? ((byte *)pointer + REDZONE) : null; @@ -1696,7 +1708,7 @@ static void * _crealloc(void * pointer, unsigned int size) #else if(!size) { _free(pointer); return null; } -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Wait(); #endif @@ -1738,7 +1750,9 @@ static void * _crealloc(void * pointer, unsigned int size) if(stack.frames[c]) printf(" %s\n", stack.frames[c]); memoryErrorsCount++; +#if !defined(__EMSCRIPTEN__) memMutex.Release(); +#endif return null; } memset(pointer, 0xAB, REDZONE); @@ -1786,7 +1800,7 @@ static void * _crealloc(void * pointer, unsigned int size) pointer = crealloc(pointer, size); #endif -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) memMutex.Release(); #endif return pointer ? ((byte *)pointer + REDZONE) : null; @@ -1800,7 +1814,7 @@ static void _free(void * pointer) #if defined(DISABLE_MEMMGR) && !defined(MEMINFO) free(pointer); #else -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) if(memMutex != pointer) memMutex.Wait(); #endif @@ -1910,7 +1924,7 @@ static void _free(void * pointer) free(pointer); #endif -#if !defined(ECERE_BOOTSTRAP) +#if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__) if(memMutex != pointer) memMutex.Release(); #endif @@ -3461,7 +3475,7 @@ static void CopyTemplateArg(ClassTemplateParameter param, ClassTemplateArgument switch(param.type) { case type: - arg.dataTypeString = CopyString(arg.dataTypeString); + arg.dataTypeString = CopyString(arg.dataTypeString); break; case expression: @@ -4613,7 +4627,9 @@ public dllexport void * eInstance_New(Class _class) #ifdef MEMINFO #undef malloc +#if !defined(__EMSCRIPTEN__) memMutex.Wait(); +#endif //allocateClass = _class; allocateClass = malloc(strlen(_class.name)+1); allocateInternal = _class.module == __thisModule; @@ -4646,8 +4662,10 @@ public dllexport void * eInstance_New(Class _class) } #ifdef MEMINFO allocateClass = null; +#if !defined(__EMSCRIPTEN__) memMutex.Release(); #endif +#endif #if !defined(MEMINFO) && defined(MEMTRACKING) { @@ -7372,7 +7390,9 @@ public void queryMemInfo(char * string) blocksByClass.Free(); sizeByClass.Free(); +#if !defined(__EMSCRIPTEN__) memMutex.Wait(); +#endif for(p = 0; pools && p < NUM_POOLS; p++) { BlockPool * pool = &pools[p]; @@ -7384,7 +7404,9 @@ public void queryMemInfo(char * string) sizeByClass[c] += block.size; } } +#if !defined(__EMSCRIPTEN__) memMutex.Release(); +#endif //for(c : blocksByClass) { diff --git a/ecere/src/gfx/bitmaps/JPEGFormat.ec b/ecere/src/gfx/bitmaps/JPEGFormat.ec index 963398f..8e17ff9 100644 --- a/ecere/src/gfx/bitmaps/JPEGFormat.ec +++ b/ecere/src/gfx/bitmaps/JPEGFormat.ec @@ -1,5 +1,6 @@ namespace gfx::bitmaps; +#define _Noreturn import "Display" #include diff --git a/ecere/src/gfx/bitmaps/PNGFormat.ec b/ecere/src/gfx/bitmaps/PNGFormat.ec index 95e596e..ce39a50 100644 --- a/ecere/src/gfx/bitmaps/PNGFormat.ec +++ b/ecere/src/gfx/bitmaps/PNGFormat.ec @@ -1,8 +1,8 @@ namespace gfx::bitmaps; -import "Display" +#define _Noreturn -#if !defined(__EMSCRIPTEN__) +import "Display" #define uint _uint #include "png.h" @@ -309,5 +309,3 @@ class PNGFormat : BitmapFormat return result; } } - -#endif // !defined(__EMSCRIPTEN__) diff --git a/ecere/src/gfx/drivers/LFBDisplayDriver.ec b/ecere/src/gfx/drivers/LFBDisplayDriver.ec index 831c16e..89a45d3 100644 --- a/ecere/src/gfx/drivers/LFBDisplayDriver.ec +++ b/ecere/src/gfx/drivers/LFBDisplayDriver.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace gfx::drivers; #ifdef __MSC__ diff --git a/ecere/src/gfx/drivers/XDisplayDriver.ec b/ecere/src/gfx/drivers/XDisplayDriver.ec index 1ec9a01..b18503c 100644 --- a/ecere/src/gfx/drivers/XDisplayDriver.ec +++ b/ecere/src/gfx/drivers/XDisplayDriver.ec @@ -5,7 +5,7 @@ namespace gfx::drivers; import "instance" -#if (defined(__unix__) || defined(__APPLE__)) && !defined(ECERE_MINIGLX) && !defined(__EMSCRIPTEN__) +#if (defined(__unix__) || defined(__APPLE__)) && !defined(ECERE_MINIGLX) default: @@ -25,10 +25,8 @@ default: #include #include -#if !defined(__EMSCRIPTEN__) #include #include -#endif #include #include #include diff --git a/ecere/src/gui/GuiApplication.ec b/ecere/src/gui/GuiApplication.ec index bb7fd95..6792305 100644 --- a/ecere/src/gui/GuiApplication.ec +++ b/ecere/src/gui/GuiApplication.ec @@ -1,7 +1,10 @@ +#define _Noreturn + namespace gui; #ifdef __EMSCRIPTEN__ #include +#include #endif #ifdef __EMSCRIPTEN__ @@ -472,7 +475,11 @@ public class GuiApplication : Application desktop.Update(null); } // When does the desktop have a display in not fullscreen mode? +#if defined(__EMSCRIPTEN__) + if(true) +#else if(!fullScreenMode && !modeSwitching) +#endif desktop.UpdateDisplay(); desktop.display.Unlock(); } @@ -687,6 +694,23 @@ public: { Window window; +#ifdef __EMSCRIPTEN__ + { + int w = 0, h = 0; + double dw = 0, dh = 0; + + emscripten_get_element_css_size(0, &dw, &dh); + w = (int)dw, h = (int)dh; + if(w && h) + { + emscripten_set_canvas_size(w, h); + guiApp.desktop.ExternalPosition(0,0, w, h); + if(guiApp.desktop.display && guiApp.desktop.display.displaySystem) + guiApp.desktop.display.Resize(w, h); + } + } +#endif + if(Init()) { if(desktop) @@ -707,13 +731,14 @@ public: } #ifdef __EMSCRIPTEN__ - emscripten_set_main_loop(emscripten_main_loop_callback, 1/*60*/, 1); + emscripten_set_main_loop(emscripten_main_loop_callback, 0 /*60*/, 1); #endif if(desktop) { int terminated = 0; incref desktop; + ProcessInput(true); while(desktop && interfaceDriver) { @@ -857,7 +882,11 @@ public: if(interfaceDriver) { +#if defined(__EMSCRIPTEN__) + if(true) +#else if(fullScreenMode && desktop.display) +#endif { #if !defined(__EMSCRIPTEN__) desktop.mutex.Wait(); @@ -1237,6 +1266,19 @@ public: (!refreshRate || refreshRate == fbRefreshRate) && (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName)))) result = true; +#if defined(__EMSCRIPTEN__) + else if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) && + fullScreen != fbFullScreen && + (!resolution || resolution == fbResolution) && + (!colorDepth || colorDepth == fbColorDepth) && + (!refreshRate || refreshRate == fbRefreshRate) && + (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName)))) + { + if(inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode)) + this.fullScreen = fullScreen; + result = true; + } +#endif else if(inter) { bool wasFullScreen = fullScreenMode; @@ -1529,6 +1571,7 @@ public: { set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); } }; + property Window acquiredWindow { get { return acquiredWindow; } }; }; #ifdef __EMSCRIPTEN__ diff --git a/ecere/src/gui/Window.ec b/ecere/src/gui/Window.ec index c7b3927..7e1986e 100644 --- a/ecere/src/gui/Window.ec +++ b/ecere/src/gui/Window.ec @@ -833,7 +833,9 @@ private: x -= rootWindow.clientStart.x; y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0); } +#if !defined(__EMSCRIPTEN__) if(!guiApp.fullScreenMode || is3D) +#endif { x -= rootWindow.absPosition.x; y -= rootWindow.absPosition.y; @@ -1820,7 +1822,11 @@ private: if(display && !display.flags.memBackBuffer && changeRootWindow) guiApp.interfaceDriver.PositionRootWindow(this, x, y, w, h, windowMoved, windowResized); //realResized); - if(!guiApp.fullScreenMode && this != guiApp.desktop && (windowResized || windowMoved)) + if( +#if !defined(__EMSCRIPTEN__) + !guiApp.fullScreenMode && +#endif + this != guiApp.desktop && (windowResized || windowMoved)) for(child = parent.children.first; child && child != this; child = child.next) if(child.rootWindow) guiApp.interfaceDriver.UpdateRootWindow(child.rootWindow); @@ -3810,7 +3816,10 @@ private: if(activateParent && parent && !parent.active /*parent != parent.parent.activeChild*/) parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap); } - else if(!guiApp.fullScreenMode) + else +#if !defined(__EMSCRIPTEN__) + if(!guiApp.fullScreenMode) +#endif { Window modalRoot = FindModal(); if(!modalRoot) modalRoot = this; @@ -4959,8 +4968,12 @@ private: Window child; // Setup relationship with outside world (bb root || !bb) +#if defined(__EMSCRIPTEN__) + if(this == guiApp.desktop) +#else if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver)) +#endif { rootWindow = this; if(!tempExtents) @@ -4992,7 +5005,11 @@ private: bool result = false; Window child; +#if defined(__EMSCRIPTEN__) + if(this == guiApp.desktop) +#else if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver)))) +#endif { subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver); DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null; @@ -5098,7 +5115,11 @@ private: } } - if(guiApp.fullScreenMode || this != guiApp.desktop) + if( +#if !defined(__EMSCRIPTEN__) + guiApp.fullScreenMode || +#endif + this != guiApp.desktop) { SetWindowMinimum(&skinMinSize.w, &skinMinSize.h); if(display) @@ -6026,7 +6047,7 @@ private: public bool AcquireInput(bool acquired) { bool result = true; - if(acquiredInput != acquired) + if((guiApp.acquiredWindow && acquiredInput) != acquired) { if(active || (!visible && creationActivation == activate)) result = AcquireInputEx(acquired); @@ -6059,7 +6080,11 @@ private: { if(guiApp.driver != null) { +#if !defined(__EMSCRIPTEN__) if(guiApp.fullScreenMode && guiApp.desktop.display) +#else + if(true) +#endif { #if !defined(__EMSCRIPTEN__) guiApp.desktop.mutex.Wait(); @@ -7988,16 +8013,23 @@ public: bool MenuWindowWindows(MenuItem selection, Modifiers mods) { - WindowList dialog { master = this }; - Window document = (Window)(intptr)dialog.Modal(); - if(document) + WindowList { - if(activeChild.state == maximized) - document.SetState(maximized, false, mods); - else if(document.state == minimized) - document.SetState(normal, false, mods); - document.Activate(); - } + master = this; isModal = true; + + void NotifyDestroyed(Window window, DialogResult result) + { + Window document = (Window)(intptr)result; + if(document) + { + if(activeChild.state == maximized) + document.SetState(maximized, false, 0); + else if(document.state == minimized) + document.SetState(normal, false, 0); + document.Activate(); + } + } + }.Create(); return true; } diff --git a/ecere/src/gui/drivers/AndroidInterface.ec b/ecere/src/gui/drivers/AndroidInterface.ec index 304ff49..4f2725a 100644 --- a/ecere/src/gui/drivers/AndroidInterface.ec +++ b/ecere/src/gui/drivers/AndroidInterface.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace gui::drivers; import "Window" diff --git a/ecere/src/gui/drivers/EmscriptenInterface.ec b/ecere/src/gui/drivers/EmscriptenInterface.ec index 9df8751..6cf6af1 100644 --- a/ecere/src/gui/drivers/EmscriptenInterface.ec +++ b/ecere/src/gui/drivers/EmscriptenInterface.ec @@ -21,62 +21,468 @@ public import "ecere" #define property _property #define uint _uint -//#include -#include -#include +#include +#include #undef property #undef uint +default: +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown; +extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp; + +private: + +static Point lastMouse; + +static inline const char *emscripten_event_type_to_string(int eventType) { + const char *events[] = { "(invalid)", "(none)", "keypress", "keydown", "keyup", "click", "mousedown", "mouseup", "dblclick", "mousemove", "wheel", "resize", + "scroll", "blur", "focus", "focusin", "focusout", "deviceorientation", "devicemotion", "orientationchange", "fullscreenchange", "pointerlockchange", + "visibilitychange", "touchstart", "touchend", "touchmove", "touchcancel", "gamepadconnected", "gamepaddisconnected", "beforeunload", + "batterychargingchange", "batterylevelchange", "webglcontextlost", "webglcontextrestored", "mouseenter", "mouseleave", "mouseover", "mouseout", "(invalid)" }; + ++eventType; + if (eventType < 0) eventType = 0; + if (eventType >= sizeof(events)/sizeof(events[0])) eventType = sizeof(events)/sizeof(events[0])-1; + return events[eventType]; +} + +static int mouseButtons; +static int movementX, movementY; + +static bool isFullScreen; + +static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent *e, void *userData) +{ + Window window = guiApp.desktop; + Modifiers mods { }; + int methodID; + + switch(eventType) + { + case EMSCRIPTEN_EVENT_MOUSEMOVE: + lastMouse = { e->canvasX, e->canvasY }; + window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, + e->canvasX, e->canvasY, &mods, false, true); + movementX += e->movementX; + movementY += e->movementY; + break; + case EMSCRIPTEN_EVENT_MOUSEDOWN: + // PrintLn("EMSCRIPTEN_EVENT_MOUSEDOWN!"); + methodID = + e->button == 0 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown : + e->button == 2 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown : + __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown; + window.MouseMessage(methodID, e->canvasX, e->canvasY, &mods, false, true); + if(e->button == 0) + mouseButtons |= 1; + else if(e->button == 2) + mouseButtons |= 2; + else + mouseButtons |= 4; + break; + case EMSCRIPTEN_EVENT_MOUSEUP: + methodID = + e->button == 0 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp : + e->button == 2 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp : + __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp; + window.MouseMessage(methodID, e->canvasX, e->canvasY, &mods, false, true); + if(e->button == 0) + mouseButtons &= ~1; + else if(e->button == 2) + mouseButtons &= ~2; + else + mouseButtons &= ~4; + break; + case EMSCRIPTEN_EVENT_DBLCLICK: + methodID = + e->button == 0 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick : + e->button == 2 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick : + __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick; + window.MouseMessage(methodID, e->canvasX, e->canvasY, &mods, false, true); + break; + } + +/* + printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, movement: (%ld,%ld), canvas: (%ld,%ld)\n", + emscripten_event_type_to_string(eventType), e->screenX, e->screenY, e->clientX, e->clientY, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", + e->button, e->buttons, e->movementX, e->movementY, e->canvasX, e->canvasY); +*/ + return 0; +} + +static EM_BOOL wheel_callback(int eventType, const EmscriptenWheelEvent *e, void *userData) +{ + Window window = guiApp.desktop; + window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, + e->deltaY < 0 ? wheelUp : wheelDown, 0); + /* + printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, canvas: (%ld,%ld), delta:(%g,%g,%g), deltaMode:%lu\n", + emscripten_event_type_to_string(eventType), e->mouse.screenX, e->mouse.screenY, e->mouse.clientX, e->mouse.clientY, + e->mouse.ctrlKey ? " CTRL" : "", e->mouse.shiftKey ? " SHIFT" : "", e->mouse.altKey ? " ALT" : "", e->mouse.metaKey ? " META" : "", + e->mouse.button, e->mouse.buttons, e->mouse.canvasX, e->mouse.canvasY, + (float)e->deltaX, (float)e->deltaY, (float)e->deltaZ, e->deltaMode); + */ + return 0; +} +static bool keyStatus[KeyCode]; + +EM_BOOL pointerlockchange_callback(int eventType, const EmscriptenPointerlockChangeEvent *e, void *userData) +{ + if(!e->isActive) + { + if(guiApp.acquiredWindow) + { + guiApp.acquiredWindow.acquiredInput = false; + guiApp.acquiredWindow = null; + } + } + else + { + Window w = guiApp.desktop; + if(w && w.children.first) w = w.children.first; + guiApp.acquiredWindow = w; + guiApp.acquiredWindow.acquiredInput = true; + } +/* + printf("%s, isActive: %d, pointerlock element nodeName: \"%s\", id: \"%s\"\n", + emscripten_event_type_to_string(eventType), e->isActive, e->nodeName, e->id); +*/ + movementX = 0; + movementY = 0; + return 0; +} + +EM_BOOL fullscreenchange_callback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData) +{ + int w = 0, h = 0; + double dw = 0, dh = 0; + isFullScreen = (bool)e->isFullscreen; + *&guiApp.fullScreen = isFullScreen; + + emscripten_get_element_css_size(0, &dw, &dh); + w = (int)dw, h = (int)dh; + if(w && h) + { + emscripten_set_canvas_size(w, h); + guiApp.desktop.ExternalPosition(0,0, w, h); + if(guiApp.desktop.display && guiApp.desktop.display.displaySystem) + guiApp.desktop.display.Resize(w, h); + } + movementX = 0; + movementY = 0; + return 0; +} + +// The event handler functions can return 1 to suppress the event and disable the default action. That calls event.preventDefault(); +// Returning 0 signals that the event was not consumed by the code, and will allow the event to pass on and bubble up normally. +EM_BOOL key_callback(int eventType, const EmscriptenKeyboardEvent *e, void *userData) +{ + Window window = guiApp.desktop; + Key key = 0; + switch(e->keyCode) + { + case 8: key = backSpace; break; + case 9: key = tab; break; + case 13: key = enter; break; + case 16: key = shift; break; + case 17: key = control; break; + case 18: key = alt; break; + case 19: key = pause; break; + case 20: key = capsLock; break; + case 27: key = escape; break; + case 32: key = space; break; + case 33: key = pageUp; break; + case 34: key = pageDown; break; + case 35: key = end; break; + case 36: key = home; break; + case 37: key = left; break; + case 38: key = up; break; + case 39: key = right; break; + case 40: key = down; break; + case 44: key = printScreen; break; + case 45: key = insert; break; + case 46: key = del; break; + case 48: key = k0; break; + case 49: key = k1; break; + case 50: key = k2; break; + case 51: key = k3; break; + case 52: key = k4; break; + case 53: key = k5; break; + case 54: key = k6; break; + case 55: key = k7; break; + case 56: key = k8; break; + case 57: key = k9; break; + case 65: key = a; break; + case 66: key = b; break; + case 67: key = c; break; + case 68: key = d; break; + case 69: key = KeyCode::e; break; + case 70: key = f; break; + case 71: key = g; break; + case 72: key = h; break; + case 73: key = i; break; + case 74: key = j; break; + case 75: key = k; break; + case 76: key = l; break; + case 77: key = m; break; + case 78: key = n; break; + case 79: key = o; break; + case 80: key = p; break; + case 81: key = q; break; + case 82: key = r; break; + case 83: key = s; break; + case 84: key = t; break; + case 85: key = u; break; + case 86: key = v; break; + case 87: key = w; break; + case 88: key = x; break; + case 89: key = y; break; + case 90: key = z; break; + // case 91: key = start; break; + // case 93: key = context; break; + case 112: key = f1; break; + case 113: key = f2; break; + case 114: key = f3; break; + case 115: key = f4; break; + case 116: key = f5; break; + case 117: key = f6; break; + case 118: key = f7; break; + case 119: key = f8; break; + case 120: key = f9; break; + case 121: key = f10; break; + case 122: key = f11; break; + case 123: key = f12; break; + case 144: key = numLock; break; + case 125: key = scrollLock; break; + case 188: key = comma; break; + case 190: key = period; break; + case 191: key = slash; break; + case 192: key = tilde; break; + case 219: key = leftBracket; break; // also corresponds to the Win Key (Start) in older versions of Opera. + case 220: key = backSlash; break; + case 221: key = rightBracket; break; + case 222: key = quote; break; + + /*case 173: */case 181: key = mute; break; // FF: 181 + case 174: case 182: key = volumeDown; break; // FF: 182 + case 175: case 183: key = volumeDown; break; // FF: 183 + case 186: case 59: key = semicolon; break; // FF: 59 + case 187: case 61: key = equal; break; // FF: 61 + case 189: case 173: key = minus; break; // FF: 61 + + case 96: key = keyPad0; break; + //case 45: key = keyPadInsert; break; + + case 97: key = keyPad1; break; + //case 35: key = keyPadEnd; break; + + case 98: key = keyPad2; break; + //case 40: key = keyPadDown; break; + + case 99: key = keyPad3; break; + //case 34: key = keyPadPageDown; break; + + case 100: key = keyPad4; break; + //case 37: key = keyPadLeft; break; + + case 101: key = keyPad5; break; + case 12: key = keyPad5; break; + + case 102: key = keyPad6; break; + //case 39: key = keyPadRight; break; + + case 103: key = keyPad7; break; + //case 36: key = keyPadHome; break; + + case 104: key = keyPad8; break; + //case 38: key = keyPadUp; break; + + case 105: key = keyPad9; break; + //case 33: key = keyPadPageUp; break; + + case 106: key = keyPadStar; break; + case 107: key = keyPadPlus; break; + case 109: key = keyPadMinus; break; + + case 110: key = keyPadDelete; break; + //case 46: key = keyPadDelete; break; + + case 11: key = keyPadSlash; break; + } + + key.alt = (bool)e->altKey; + key.shift = (bool)e->shiftKey; + key.ctrl = (bool)e->ctrlKey; +/* + printf("%s, key: \"%s\", code: \"%s\", location: %lu,%s%s%s%s repeat: %d, locale: \"%s\", char: \"%s\", charCode: %lu, keyCode: %lu, which: %lu\n", + emscripten_event_type_to_string(eventType), e->key, e->code, e->location, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", + e->repeat, e->locale, e->charValue, e->charCode, e->keyCode, e->which); +*/ + if(key) + { + switch(eventType) + { + case EMSCRIPTEN_EVENT_KEYDOWN: + //PrintLn("Setting ", key, " to down"); + keyStatus[key] = true; + window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, key, (unichar)e->charCode); + break; + case EMSCRIPTEN_EVENT_KEYUP: + //PrintLn("Setting ", key, " to false"); + keyStatus[key] = false; + window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, (unichar)e->charCode); + break; + } + } + + /* + if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && (!strcmp(e->key, "f") || e->which == 102)) { + EmscriptenFullscreenChangeEvent fsce; + EMSCRIPTEN_RESULT ret = emscripten_get_fullscreen_status(&fsce); + TEST_RESULT(emscripten_get_fullscreen_status); + if (!fsce.isFullscreen) { + printf("Requesting fullscreen..\n"); + ret = emscripten_request_fullscreen(0, 1); + TEST_RESULT(emscripten_request_fullscreen); + } else { + printf("Exiting fullscreen..\n"); + ret = emscripten_exit_fullscreen(); + TEST_RESULT(emscripten_exit_fullscreen); + ret = emscripten_get_fullscreen_status(&fsce); + TEST_RESULT(emscripten_get_fullscreen_status); + if (fsce.isFullscreen) { + fprintf(stderr, "Fullscreen exit did not work!\n"); + } + } + } + + if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && (!strcmp(e->key, "p") || e->which == 112)) { + EmscriptenPointerlockChangeEvent plce; + EMSCRIPTEN_RESULT ret = emscripten_get_pointerlock_status(&plce); + TEST_RESULT(emscripten_get_pointerlock_status); + if (!plce.isActive) { + printf("Requesting pointer lock..\n"); + ret = emscripten_request_pointerlock(0, 1); + TEST_RESULT(emscripten_request_pointerlock); + } else { + printf("Exiting pointer lock..\n"); + ret = emscripten_exit_pointerlock(); + TEST_RESULT(emscripten_exit_pointerlock); + ret = emscripten_get_pointerlock_status(&plce); + TEST_RESULT(emscripten_get_pointerlock_status); + if (plce.isActive) { + fprintf(stderr, "Pointer lock exit did not work!\n"); + } + } + } + */ + + return 0; +} + +static EM_BOOL uievent_callback(int eventType, const EmscriptenUiEvent *e, void *userData) +{ + switch(eventType) + { + case EMSCRIPTEN_EVENT_RESIZE: + //case EMSCRIPTEN_EVENT_SCROLL: + { + int w = 0, h = 0; + double dw = 0, dh = 0; + emscripten_get_element_css_size(0, &dw, &dh); + w = (int)dw, h = (int)dh; + if(w && h) + { + emscripten_set_canvas_size(w, h); + guiApp.desktop.ExternalPosition(0,0, w, h); + if(guiApp.desktop.display && guiApp.desktop.display.displaySystem) + guiApp.desktop.display.Resize(w, h); + } + //PrintLn("EMSCRIPTEN_EVENT_RESIZE: ", w, " x ", h); + break; + } + } + /* + printf("%s, detail: %ld, document.body.client size: (%d,%d), window.inner size: (%d,%d), scrollPos: (%d, %d)\n", + emscripten_event_type_to_string(eventType), e->detail, e->documentBodyClientWidth, e->documentBodyClientHeight, + e->windowInnerWidth, e->windowInnerHeight, e->scrollTop, e->scrollLeft); + */ + return 0; +} class EmscriptenInterface : Interface { class_property(name) = "Emscripten"; - // --- User Interface System --- bool ::Initialize() { - sflnprintf("class(EmscriptenInterface) ::Initialize [STUB!]\n"); - guiApp.desktop.ExternalPosition(0,0, 640, 480); + emscripten_set_resize_callback(0, 0, 1, uievent_callback); + //emscripten_set_scroll_callback(0, 0, 1, uievent_callback); + emscripten_set_click_callback(0, 0, 1, mouse_callback); + emscripten_set_mousedown_callback(0, 0, 1, mouse_callback); + emscripten_set_mouseup_callback(0, 0, 1, mouse_callback); + emscripten_set_dblclick_callback(0, 0, 1, mouse_callback); + emscripten_set_mousemove_callback(0, 0, 1, mouse_callback); + emscripten_set_wheel_callback(0, 0, 1, wheel_callback); + emscripten_set_keypress_callback(0, 0, 1, key_callback); + emscripten_set_keydown_callback(0, 0, 1, key_callback); + emscripten_set_keyup_callback(0, 0, 1, key_callback); + emscripten_set_pointerlockchange_callback(0, 0, 1, pointerlockchange_callback); + emscripten_set_fullscreenchange_callback(0, 0, 1, fullscreenchange_callback); + /*emscripten_set_mouseenter_callback(0, 0, 1, mouse_callback); + emscripten_set_mouseleave_callback(0, 0, 1, mouse_callback);*/ return true; } void ::Terminate() { - sflnprintf("class(EmscriptenInterface) ::Terminate [STUB!]\n"); + } bool ::ProcessInput(bool processAll) { - sflnprintf("class(EmscriptenInterface) ::ProcessInput [STUB!]\n"); + return false; } void ::Wait() { - sflnprintf("class(EmscriptenInterface) ::Wait [STUB!]\n"); + } void ::Lock(Window window) { - sflnprintf("class(EmscriptenInterface) ::Lock [STUB!]\n"); + } void ::Unlock(Window window) { - sflnprintf("class(EmscriptenInterface) ::Unlock [STUB!]\n"); + } void ::SetTimerResolution(uint hertz) { - sflnprintf("class(EmscriptenInterface) ::SetTimerResolution [STUB!] Implement high resolution timer here\n"); + } const char ** ::GraphicsDrivers(int * numDrivers) { - //sflnprintf("class(EmscriptenInterface) ::GraphicsDrivers [STUB!]\n"); static const char *graphicsDrivers[] = { "OpenGL" }; *numDrivers = sizeof(graphicsDrivers) / sizeof(char *); return (const char **)graphicsDrivers; @@ -85,18 +491,20 @@ class EmscriptenInterface : Interface void ::EnsureFullScreen(bool * fullScreen) { - sflnprintf("class(EmscriptenInterface) ::EnsureFullScreen [STUB!]\n"); - *fullScreen = true; + } void ::GetCurrentMode(bool * fullScreen, Resolution * resolution, PixelFormat * colorDepth, int * refreshRate) { - sflnprintf("class(EmscriptenInterface) ::GetCurrentMode [STUB!]\n"); + *fullScreen = isFullScreen; } bool ::ScreenMode(bool fullScreen, Resolution resolution, PixelFormat colorDepth, int refreshRate, bool * textMode) { - sflnprintf("class(EmscriptenInterface) ::ScreenMode [STUB!]\n"); + if(fullScreen) + emscripten_request_fullscreen(0, 1); + else + emscripten_exit_fullscreen(); return true; } @@ -105,13 +513,13 @@ class EmscriptenInterface : Interface void * ::CreateRootWindow(Window window) { - sflnprintf("class(EmscriptenInterface) ::CreateRootWindow [STUB!]\n"); + return null; } void ::DestroyRootWindow(Window window) { - sflnprintf("class(EmscriptenInterface) ::DestroyRootWindow [STUB!]\n"); + } @@ -119,47 +527,47 @@ class EmscriptenInterface : Interface void ::SetRootWindowCaption(Window window, const char * name) { - sflnprintf("class(EmscriptenInterface) ::SetRootWindowCaption [STUB!]\n"); + } void ::PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize) { - sflnprintf("class(EmscriptenInterface) ::Stub [STUB!]\n"); + } void ::OffsetWindow(Window window, int * x, int * y) { - sflnprintf("class(EmscriptenInterface) ::OffsetWindow [STUB!]\n"); + } void ::UpdateRootWindow(Window window) { - sflnprintf("class(EmscriptenInterface) ::UpdateRootWindow [STUB!]\n"); + } void ::SetRootWindowState(Window window, WindowState state, bool visible) { - sflnprintf("class(EmscriptenInterface) ::SetRootWindowState [STUB!]\n"); + } void ::ActivateRootWindow(Window window) { - sflnprintf("class(EmscriptenInterface) ::ActivateRootWindow [STUB!]\n"); + } void ::OrderRootWindow(Window window, bool topMost) { - sflnprintf("class(EmscriptenInterface) ::OrderRootWindow [STUB!]\n"); + } void ::SetRootWindowColor(Window window) { - sflnprintf("class(EmscriptenInterface) ::SetRootWindowColor [STUB!]\n"); + } void ::FlashRootWindow(Window window) { - sflnprintf("class(EmscriptenInterface) ::FlashRootWindow [STUB!]\n"); + } @@ -167,12 +575,12 @@ class EmscriptenInterface : Interface void ::StartMoving(Window window, int x, int y, bool fromKeyBoard) { - sflnprintf("class(EmscriptenInterface) ::StartMoving [STUB!]\n"); + } void ::StopMoving(Window window) { - sflnprintf("class(EmscriptenInterface) ::StopMoving [STUB!]\n"); + } @@ -180,22 +588,23 @@ class EmscriptenInterface : Interface void ::GetMousePosition(int *x, int *y) { - sflnprintf("class(EmscriptenInterface) ::GetMousePosition [STUB!]\n"); + *x = lastMouse.x; + *y = lastMouse.y; } void ::SetMousePosition(int x, int y) { - sflnprintf("class(EmscriptenInterface) ::SetMousePosition [STUB!]\n"); + } void ::SetMouseRange(Window window, Box box) { - sflnprintf("class(EmscriptenInterface) ::SetMouseRange [STUB!]\n"); + } void ::SetMouseCapture(Window window) { - sflnprintf("class(EmscriptenInterface) ::SetMouseCapture [STUB!]\n"); + } @@ -203,7 +612,7 @@ class EmscriptenInterface : Interface void ::SetMouseCursor(Window window, SystemCursor cursor) { - sflnprintf("class(EmscriptenInterface) ::SetMouseCursor [STUB!]\n"); + } @@ -211,7 +620,7 @@ class EmscriptenInterface : Interface void ::SetCaret(int caretX, int caretY, int size) { - sflnprintf("class(EmscriptenInterface) ::SetCaret [STUB!]\n"); + } @@ -219,30 +628,30 @@ class EmscriptenInterface : Interface void ::ClearClipboard() { - sflnprintf("class(EmscriptenInterface) ::ClearClipboard [STUB!]\n"); + } bool ::AllocateClipboard(ClipBoard clipBoard, uint size) { - sflnprintf("class(EmscriptenInterface) ::AllocateClipboard [STUB!]\n"); + return false; } bool ::SaveClipboard(ClipBoard clipBoard) { - sflnprintf("class(EmscriptenInterface) ::SaveClipboard [STUB!]\n"); + return false; } bool ::LoadClipboard(ClipBoard clipBoard) { - sflnprintf("class(EmscriptenInterface) ::LoadClipboard [STUB!]\n"); + return false; } void ::UnloadClipboard(ClipBoard clipBoard) { - sflnprintf("class(EmscriptenInterface) ::UnloadClipboard [STUB!]\n"); + } @@ -250,37 +659,44 @@ class EmscriptenInterface : Interface bool ::AcquireInput(Window window, bool state) { - sflnprintf("class(EmscriptenInterface) ::AcquireInput [STUB!]\n"); - return false; + if(state) + emscripten_request_pointerlock(0, 1); + else + emscripten_exit_pointerlock(); + + movementX = 0; + movementY = 0; + return true; } bool ::GetMouseState(MouseButtons * buttons, int * x, int * y) { - sflnprintf("class(EmscriptenInterface) ::GetMouseState [STUB!]\n"); - return false; + if(buttons) *buttons = { left = mouseButtons & 1, right = (mouseButtons & 2) ? true : false, middle = (mouseButtons & 4) ? true : false }; + if(x) { *x = movementX; movementX = 0; } + if(y) { *y = movementY; movementY = 0; } + + return true; } bool ::GetJoystickState(int device, Joystick joystick) { - sflnprintf("class(EmscriptenInterface) ::GetJoystickState [STUB!]\n"); + return false; } bool ::GetKeyState(Key key) { - sflnprintf("class(EmscriptenInterface) ::GetKeyState [STUB!]\n"); - return false; + return keyStatus[key]; } bool ::SetIcon(Window window, BitmapResource icon) { - sflnprintf("class(EmscriptenInterface) ::SetIcon [STUB!]\n"); + return false; } void ::GetScreenArea(Window window, Box box) { - sflnprintf("class(EmscriptenInterface) ::GetScreenArea [STUB!]\n"); } } diff --git a/ecere/src/gui/drivers/NCursesInterface.ec b/ecere/src/gui/drivers/NCursesInterface.ec index a20a7cf..ad34f44 100644 --- a/ecere/src/gui/drivers/NCursesInterface.ec +++ b/ecere/src/gui/drivers/NCursesInterface.ec @@ -1,8 +1,10 @@ +#define _Noreturn + namespace gui::drivers; import "instance" -#if (defined(__unix__) || defined(__APPLE__)) && !defined(__DOS__) && !defined(__EMSCRIPTEN__) +#if (defined(__unix__) || defined(__APPLE__)) && !defined(__DOS__) #undef __BLOCKS__ #define DBLCLICK_DELAY 0.3 // seconds diff --git a/ecere/src/gui/drivers/XInterface.ec b/ecere/src/gui/drivers/XInterface.ec index 428677f..13c166a 100644 --- a/ecere/src/gui/drivers/XInterface.ec +++ b/ecere/src/gui/drivers/XInterface.ec @@ -1,3 +1,4 @@ +#define _Noreturn namespace gui::drivers; import "instance" @@ -5,7 +6,7 @@ import "instance" import "OpenGLDisplayDriver" #endif -#if (defined(__unix__) || defined(__APPLE__)) && !defined(ECERE_MINIGLX) && !defined(__EMSCRIPTEN__) +#if (defined(__unix__) || defined(__APPLE__)) && !defined(ECERE_MINIGLX) #undef __BLOCKS__ default: diff --git a/ecere/src/net/Service.ec b/ecere/src/net/Service.ec index fb28e93..686fb68 100644 --- a/ecere/src/net/Service.ec +++ b/ecere/src/net/Service.ec @@ -1,3 +1,5 @@ +#define _Noreturn + #ifdef __statement #undef __statement #endif diff --git a/ecere/src/net/Socket.ec b/ecere/src/net/Socket.ec index 6292783..aec0562 100644 --- a/ecere/src/net/Socket.ec +++ b/ecere/src/net/Socket.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace net; #include diff --git a/ecere/src/net/dcom.ec b/ecere/src/net/dcom.ec index 3603854..a2b4366 100644 --- a/ecere/src/net/dcom.ec +++ b/ecere/src/net/dcom.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace net; #if defined(__WIN32__) diff --git a/ecere/src/net/network.ec b/ecere/src/net/network.ec index 568c223..e355df9 100644 --- a/ecere/src/net/network.ec +++ b/ecere/src/net/network.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace net; #ifndef ECERE_NONET diff --git a/ecere/src/sys/DualPipe.c b/ecere/src/sys/DualPipe.c index 466ccb7..c9eba7c 100644 --- a/ecere/src/sys/DualPipe.c +++ b/ecere/src/sys/DualPipe.c @@ -1,3 +1,5 @@ +#define _Noreturn + #if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #define UNICODE diff --git a/ecere/src/sys/EARArchive.ec b/ecere/src/sys/EARArchive.ec index 9e867db..a45267d 100644 --- a/ecere/src/sys/EARArchive.ec +++ b/ecere/src/sys/EARArchive.ec @@ -51,7 +51,12 @@ static File EAROpenArchive(const char * archive, EARHeader header) name = ((SubModule)__thisModule.application.modules.first).next.module.name; #endif - if(LocateModule(name, moduleName)) +#if defined(__EMSCRIPTEN__) + if(!name[0]) + f = FileOpen("resources.ear", read); +#endif + + if(!f && LocateModule(name, moduleName)) f = FileOpen(moduleName, read); } else @@ -1429,6 +1434,21 @@ class EARFileSystem : FileSystem result = EARGetEntry(f, entry, fileName, null); delete f; } + #ifdef ECERE_STATIC + if(!f && archive[0] == ':') + { + f = EAROpenArchive(":", &header); + if(f) + { + EAREntry entry { }; + char fn[MAX_LOCATION]; + strcpy(fn, archive + 1); + PathCat(fn, fileName); + result = EARGetEntry(f, entry, fn, null); + } + delete f; + } + #endif return result; } diff --git a/ecere/src/sys/File.c b/ecere/src/sys/File.c index 8bdb0c1..26cced2 100644 --- a/ecere/src/sys/File.c +++ b/ecere/src/sys/File.c @@ -1,4 +1,7 @@ +#define _Noreturn + #undef __BLOCKS__ + #include #include #include diff --git a/ecere/src/sys/File.ec b/ecere/src/sys/File.ec index 2a73e02..34da1f7 100644 --- a/ecere/src/sys/File.ec +++ b/ecere/src/sys/File.ec @@ -1,5 +1,7 @@ namespace sys; +#define _Noreturn + default: #define set _set #define uint _uint diff --git a/ecere/src/sys/Mutex.ec b/ecere/src/sys/Mutex.ec index ba212df..84f167e 100644 --- a/ecere/src/sys/Mutex.ec +++ b/ecere/src/sys/Mutex.ec @@ -1,3 +1,5 @@ +#define _Noreturn + #if defined(__ANDROID__) #include @@ -14,7 +16,7 @@ namespace sys; #define uint _uint #define set _set #define String _String -#if defined(__WIN32__) && !defined(__EMSCRIPTEN__) +#if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #include #else diff --git a/ecere/src/sys/Semaphore.ec b/ecere/src/sys/Semaphore.ec index b7e5c7c..6d582cc 100644 --- a/ecere/src/sys/Semaphore.ec +++ b/ecere/src/sys/Semaphore.ec @@ -1,3 +1,5 @@ +#define _Noreturn + default: #include private: diff --git a/ecere/src/sys/System.c b/ecere/src/sys/System.c index 1ef03a8..66cd65c 100644 --- a/ecere/src/sys/System.c +++ b/ecere/src/sys/System.c @@ -1,3 +1,5 @@ +#define _Noreturn + #include #include #include diff --git a/ecere/src/sys/System.ec b/ecere/src/sys/System.ec index 1b7bcd8..67b2e82 100644 --- a/ecere/src/sys/System.ec +++ b/ecere/src/sys/System.ec @@ -1,5 +1,7 @@ namespace sys; +#define _Noreturn + #if defined(ECERE_BOOTSTRAP) #undef __WIN32__ #undef __unix__ diff --git a/ecere/src/sys/Thread.ec b/ecere/src/sys/Thread.ec index ae2478b..b04144c 100644 --- a/ecere/src/sys/Thread.ec +++ b/ecere/src/sys/Thread.ec @@ -1,3 +1,5 @@ +#define _Noreturn + namespace sys; #define set _set @@ -12,7 +14,7 @@ namespace sys; #undef Thread #else #include -#ifndef __ANDROID__ +#if !defined(__ANDROID__) #include #endif #endif diff --git a/ecere/src/sys/Time.ec b/ecere/src/sys/Time.ec index 51bed63..2688df1 100644 --- a/ecere/src/sys/Time.ec +++ b/ecere/src/sys/Time.ec @@ -1,5 +1,7 @@ namespace sys; +#define _Noreturn + #define set _set #define Date _Date #define uint _uint diff --git a/samples/games/chess/chess.epj b/samples/games/chess/chess.epj index ca9d5b6..628d05a 100644 --- a/samples/games/chess/chess.epj +++ b/samples/games/chess/chess.epj @@ -52,6 +52,28 @@ "adb shell am start -a android.intent.action.MAIN -n com.ecere.$(MODULE)/android.app.NativeActivity" ] } + }, + { + "Name" : "Emscripten", + "Options" : { + "Optimization" : "Speed", + "PreprocessorDefinitions" : [ + "ECERE_STATIC", + "CHESS_NONET" + ], + "TargetFileName" : "chess.html", + "Libraries" : [ + "ecereStatic", + "z", + "freetype", + "jpeg", + "png" + ], + "LibraryDirs" : [ + "../../../ecere/obj/emscripten.linux.emscripten" + ], + "FastMath" : true + } } ], "Files" : [ @@ -105,6 +127,204 @@ ], "ResourcesPath" : "res", "Resources" : [ + { + "Folder" : "ecere", + "Files" : [ + { + "Folder" : "actions", + "Files" : [ + "../../../ecere/res/actions/clean.png", + "../../../ecere/res/actions/docNew.png", + "../../../ecere/res/actions/docSave.png", + "../../../ecere/res/actions/editFind.png", + "../../../ecere/res/actions/folderNew.png", + "../../../ecere/res/actions/goDown.png", + "../../../ecere/res/actions/goHome.png", + "../../../ecere/res/actions/goNext.png", + "../../../ecere/res/actions/goPrevious.png", + "../../../ecere/res/actions/goUp.png", + "../../../ecere/res/actions/listAdd.png", + "../../../ecere/res/actions/listRemove.png", + "../../../ecere/res/actions/viewRefresh.png", + "../../../ecere/res/actions/windowNew.png" + ] + }, + { + "Folder" : "aqua", + "Files" : [ + "../../../ecere/res/aqua/back.png", + "../../../ecere/res/aqua/down.png", + "../../../ecere/res/aqua/downLeft.png", + "../../../ecere/res/aqua/downMiddle.png", + "../../../ecere/res/aqua/downRight.png", + "../../../ecere/res/aqua/sDown.png", + "../../../ecere/res/aqua/sUp.png", + "../../../ecere/res/aqua/up.png", + "../../../ecere/res/aqua/upLeft.png", + "../../../ecere/res/aqua/upMiddle.png", + "../../../ecere/res/aqua/upRight.png" + ] + }, + { + "Folder" : "constructs", + "Files" : [ + "../../../ecere/res/constructs/class.png", + "../../../ecere/res/constructs/data.png", + "../../../ecere/res/constructs/dataPrivate.png", + "../../../ecere/res/constructs/dataType.png", + "../../../ecere/res/constructs/enum.png", + "../../../ecere/res/constructs/enumValue.png", + "../../../ecere/res/constructs/event.png", + "../../../ecere/res/constructs/library.png", + "../../../ecere/res/constructs/method.png", + "../../../ecere/res/constructs/methodPrivate.png", + "../../../ecere/res/constructs/namespace.png", + "../../../ecere/res/constructs/property.png", + "../../../ecere/res/constructs/propertyPrivate.png" + ] + }, + { + "Folder" : "controls", + "Files" : [ + "../../../ecere/res/controls/button.png", + "../../../ecere/res/controls/calendar.png", + "../../../ecere/res/controls/checkBox.png", + "../../../ecere/res/controls/dataBox.png", + "../../../ecere/res/controls/dropBox.png", + "../../../ecere/res/controls/editBox.png", + "../../../ecere/res/controls/groupBox.png", + "../../../ecere/res/controls/label.png", + "../../../ecere/res/controls/listBox.png", + "../../../ecere/res/controls/menu.png", + "../../../ecere/res/controls/optionBox.png", + "../../../ecere/res/controls/progressBar.png", + "../../../ecere/res/controls/scrollBarHorizontal.png", + "../../../ecere/res/controls/scrollBarVertical.png", + "../../../ecere/res/controls/statusBar.png" + ] + }, + { + "Folder" : "cursors", + "Files" : [ + "../../../ecere/res/cursors/arrow.png", + "../../../ecere/res/cursors/cross.png", + "../../../ecere/res/cursors/iBeam.png", + "../../../ecere/res/cursors/move.png", + "../../../ecere/res/cursors/sizeEastWest.png", + "../../../ecere/res/cursors/sizeNortEastSouthWest.png", + "../../../ecere/res/cursors/sizeNorthSouth.png", + "../../../ecere/res/cursors/sizeNortWestSouthEast.png" + ] + }, + { + "Folder" : "devices", + "Files" : [ + "../../../ecere/res/devices/computer.png", + "../../../ecere/res/devices/driveHardDisk.png", + "../../../ecere/res/devices/driveRemovableMedia.png", + "../../../ecere/res/devices/mediaFloppy.png", + "../../../ecere/res/devices/mediaOptical.png" + ] + }, + { + "Folder" : "elements", + "Files" : [ + "../../../ecere/res/elements/areaClose.png", + "../../../ecere/res/elements/areaMaximize.png", + "../../../ecere/res/elements/areaMinimize.png", + "../../../ecere/res/elements/areaRestore.png", + "../../../ecere/res/elements/arrowDown.png", + "../../../ecere/res/elements/arrowLeft.png", + "../../../ecere/res/elements/arrowRight.png", + "../../../ecere/res/elements/arrowUp.png", + "../../../ecere/res/elements/checkBox.png", + "../../../ecere/res/elements/checkBoxChecked.png", + "../../../ecere/res/elements/checkBoxDisabled.png", + "../../../ecere/res/elements/checkBoxDisabledChecked.png", + "../../../ecere/res/elements/optionBoxDisabled.png", + "../../../ecere/res/elements/optionBoxDisabledSelected.png", + "../../../ecere/res/elements/optionBoxDown.png", + "../../../ecere/res/elements/optionBoxSelectedDown.png", + "../../../ecere/res/elements/optionBoxSelectedUp.png", + "../../../ecere/res/elements/optionBoxUp.png", + "../../../ecere/res/elements/orderAscending.png", + "../../../ecere/res/elements/orderCategorized.png", + "../../../ecere/res/elements/orderDescending.png" + ] + }, + { + "Folder" : "emblems", + "Files" : [ + "../../../ecere/res/emblems/unreadable.png" + ] + }, + { + "Folder" : "mimeTypes", + "Files" : [ + "../../../ecere/res/mimeTypes/brokenFile.png", + "../../../ecere/res/mimeTypes/file.png", + "../../../ecere/res/mimeTypes/image.png", + "../../../ecere/res/mimeTypes/package.png", + "../../../ecere/res/mimeTypes/packageOpticalDisc.png", + "../../../ecere/res/mimeTypes/packageSoftware.png", + "../../../ecere/res/mimeTypes/text.png", + "../../../ecere/res/mimeTypes/textC++Header.png", + "../../../ecere/res/mimeTypes/textC++Source.png", + "../../../ecere/res/mimeTypes/textCHeader.png", + "../../../ecere/res/mimeTypes/textCSource.png", + "../../../ecere/res/mimeTypes/textEcereHeader.png", + "../../../ecere/res/mimeTypes/textEcereProject.png", + "../../../ecere/res/mimeTypes/textEcereSource.png", + "../../../ecere/res/mimeTypes/textEcereWorkspace.png", + "../../../ecere/res/mimeTypes/textHyperTextMarkup.png" + ] + }, + { + "Folder" : "places", + "Files" : [ + "../../../ecere/res/places/brokenFolder.png", + "../../../ecere/res/places/driveRemote.png", + "../../../ecere/res/places/folder.png", + "../../../ecere/res/places/folderRemote.png", + "../../../ecere/res/places/networkServer.png", + "../../../ecere/res/places/networkWorkgroup.png" + ] + }, + { + "Folder" : "status", + "Files" : [ + "../../../ecere/res/status/audioVolumeHigh.png", + "../../../ecere/res/status/folderOpen.png" + ] + }, + { + "Folder" : "unicode", + "Files" : [ + "../../../ecere/res/unicode/derivedGeneralCategoryStripped.txt" + ] + }, + { + "Folder" : "shaders", + "Files" : [ + "../../../ecere/src/gfx/drivers/gl3/fixed.frag", + "../../../ecere/src/gfx/drivers/gl3/fixed.vertex" + ] + }, + "C:/Windows/Fonts/tahoma.ttf", + "C:/Windows/Fonts/tahomabd.ttf" + ], + "Options" : { + "ExcludeFromBuild" : true + }, + "Configurations" : [ + { + "Name" : "Emscripten", + "Options" : { + "ExcludeFromBuild" : false + } + } + ] + }, "aboutPic.jpg", "blackBishop.png", "blackKing.png", diff --git a/samples/games/chess/src/about.ec b/samples/games/chess/src/about.ec index 8301ee6..e2ec35c 100644 --- a/samples/games/chess/src/about.ec +++ b/samples/games/chess/src/about.ec @@ -22,9 +22,9 @@ class AboutChess : Window void OnRedraw(Surface surface) { - surface.WriteTextf(200, 30, "Copyright (c) 1996-2005"); - surface.WriteTextf(200, 50, " Jerome Jacovella-St-Louis"); + surface.WriteTextf(200, 30, "Copyright (c) 1996-2015"); + surface.WriteTextf(200, 50, " Jérôme Jacovella-St-Louis"); surface.WriteTextf(200, 70, "Models Copyright (c) 2004"); - surface.WriteTextf(200, 90, " Gaetan Loyer"); + surface.WriteTextf(200, 90, " Gaétan Loyer"); } } diff --git a/samples/games/chess/src/ai.ec b/samples/games/chess/src/ai.ec index 4fc87d9..1fa159b 100644 --- a/samples/games/chess/src/ai.ec +++ b/samples/games/chess/src/ai.ec @@ -358,9 +358,15 @@ class AIThread : Thread void Play() { abortAI = false; +#if defined(__EMSCRIPTEN__) + Main(); + chess.MakeMove(aiMove.x1, aiMove.y1, aiMove.x2, aiMove.y2, aiMove.promotion); + aiMoveResult = false; +#else app.UpdateDisplay(); Create(); aiTimer.Start(); +#endif } void Abort() diff --git a/samples/games/chess/src/chess.ec b/samples/games/chess/src/chess.ec index 19bc3f1..07c8215 100644 --- a/samples/games/chess/src/chess.ec +++ b/samples/games/chess/src/chess.ec @@ -55,6 +55,9 @@ class ChessApp : GuiApplication } } +enum GameAction { newAIGame, newLocalGame, endGame, close, connect, host, stop }; + + #ifdef HIGH_DPI define stateWidth = 300; define turnWidth = 150; @@ -66,17 +69,20 @@ define turnWidth = 100; class Chess : Window { background = gray, hasMenuBar = true, hasStatusBar = true, + fullRender = true; text = APPNAME, -#ifndef __ANDROID__ +#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) hasClose = true, hasMaximize = true, hasMinimize = true, borderStyle = sizable, #endif anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 }; bool hosting, local, ai; +#ifndef CHESS_NONET Socket sockets[Player]; ChessService service { port = CHESS_PORT, chess = this }; +#endif MenuItem * driverItems; @@ -139,7 +145,7 @@ class Chess : Window bool NotifySelect(MenuItem selection, Modifiers mods) { - if(EndGame()) + if(EndGame(newAIGame)) { ai = true; chessState.gameRunning = true; @@ -162,7 +168,7 @@ class Chess : Window gameMenu, "New Local Game\tCtrl+L", l, ctrlL; bool NotifySelect(MenuItem selection, Modifiers mods) { - if(EndGame()) + if(EndGame(newLocalGame)) { local = true; chessState.gameRunning = true; @@ -180,24 +186,25 @@ class Chess : Window gameMenu, "End Game", e; bool NotifySelect(MenuItem selection, Modifiers mods) { - EndGame(); + EndGame(endGame); return true; } }; MenuItem { gameMenu, "Exit\tAlt+F4", x, NotifySelect = MenuFileExit }; +#ifndef CHESS_NONET // Network Menu MenuItem connectItem { networkMenu, "Connect...", c; bool NotifySelect(MenuItem selection, Modifiers mods) { - if(EndGame()) + if(EndGame(connect)) { hosting = false; service.Stop(); - ConnectDialog { master = this }.Modal(); + ConnectDialog { master = this, isModal = true }.Create(); } return true; } @@ -213,7 +220,7 @@ class Chess : Window networkMenu, "Host", h; bool NotifySelect(MenuItem selection, Modifiers mods) { - if(EndGame()) + if(EndGame(host)) { if(service.Start()) { @@ -230,7 +237,7 @@ class Chess : Window networkMenu, "Stop Hosting", s; bool NotifySelect(MenuItem selection, Modifiers mods) { - if(EndGame()) + if(EndGame(stop)) { hosting = false; service.Stop(); @@ -239,6 +246,7 @@ class Chess : Window return true; } }; +#endif // View Menu MenuItem fullScreenItem @@ -272,31 +280,19 @@ class Chess : Window helpMenu, "About...\tF1", a, f1; bool NotifySelect(MenuItem selection, Modifiers mods) { - AboutChess { master = this }.Modal(); + AboutChess { master = this, isModal = true }.Create(); return true; } }; - // --- Chess Utilities --- - bool MakeMove(int x1, int y1, int x2, int y2, PieceType promotion) + int cx1, cy1, cx2, cy2; + + bool DoMove(int x1, int y1, int x2, int y2, PieceType promotion) { bool valid = false; - PieceType type = chessState.board[y1][x1].type; Player player = chessState.board[y1][x1].player; - // Pawn Promotion - if(type == Pawn && y2 == ((player == White) ? 7 : 0)) - { - if(chessState.isLocalPlayer[chessState.turn] && - IsMoveValid(x1,y1,x2,y2, chessState, null, true)) - { - chess2D.Update(null); - chess3D.Update(null); - promotion = (PieceType)Promotion { master = this }.Modal(); - } - } - if(StateMakeMove(chessState, x1,y1,x2,y2, promotion, true, null)) { valid = true; @@ -313,7 +309,9 @@ class Chess : Window y2 = (byte)y2, promotion = promotion }; +#ifndef CHESS_NONET sockets[player^(Player)1].Send((byte *)&packet, sizeof(ChessPacket)); +#endif } if(player == Black) @@ -373,6 +371,44 @@ class Chess : Window return valid; } + // --- Chess Utilities --- + bool MakeMove(int x1, int y1, int x2, int y2, PieceType promotion) + { + bool valid = false; + + PieceType type = chessState.board[y1][x1].type; + Player player = chessState.board[y1][x1].player; + + // Pawn Promotion + if(type == Pawn && y2 == ((player == White) ? 7 : 0)) + { + valid = true; + if(chessState.isLocalPlayer[chessState.turn] && + (valid = IsMoveValid(x1,y1,x2,y2, chessState, null, true))) + { + valid = false; + cx1 = x1, cy1 = y1, cx2 = x2, cy2 = y2; + chess2D.Update(null); + chess3D.Update(null); + promotion = (PieceType)Promotion + { + master = this; + isModal = true; + + void Chess::NotifyDestroyed(Window promotionDlg, DialogResult r) + { + DoMove(cx1, cy1, cx2, cy2, (PieceType)r); + if(ai) + aiThread.Play(); + } + }.Create(); + } + } + else + valid = DoMove(x1, y1, x2, y2, promotion); + return valid; + } + void ProcessUserMove(int x1, int y1, int x2, int y2) { if(MakeMove(x1, y1, x2, y2, 0)) @@ -566,10 +602,12 @@ class Chess : Window void EnableMenus() { +#ifndef CHESS_NONET stopItem.disabled = !hosting; disconnectItem.disabled = !sockets[SERVER_COLOR] && !sockets[CLIENT_COLOR]; - endGameItem.disabled = !chessState.gameRunning; hostItem.disabled = hosting; +#endif + endGameItem.disabled = !chessState.gameRunning; } void SetDriver() @@ -604,20 +642,16 @@ class Chess : Window return true; } - bool EndGame() + void DoEndGame(GameAction action) { - if(chessState.gameRunning && - (chessState.state == Normal || chessState.state == Check)) - { - if(MessageBox { type = okCancel, contents = "Quit current game?", - master = this, text = "ECERE Chess" }.Modal() == cancel) - return false; - } +#ifndef CHESS_NONET if(sockets[SERVER_COLOR]) sockets[SERVER_COLOR].Disconnect(0); else if(sockets[CLIENT_COLOR]) sockets[CLIENT_COLOR].Disconnect(0); - else if(local || ai) + else +#endif + if(local || ai) { if(ai) aiThread.Abort(); local = ai = false; @@ -628,21 +662,53 @@ class Chess : Window turnField.text = ""; stateField.text = ""; + switch(action) + { + case newAIGame: aiItem.NotifySelect(this, aiItem, 0); break; + case newLocalGame: localItem.NotifySelect(this, localItem, 0); break; + } + } + + GameAction nextAction; + + bool EndGame(GameAction action) + { + if(chessState.gameRunning && + (chessState.state == Normal || chessState.state == Check)) + { + nextAction = action; + MessageBox + { + type = okCancel, contents = "Quit current game?", + master = this, text = "ECERE Chess"; + isModal = true; + + void Chess::NotifyDestroyed(Window msgBox, DialogResult result) + { + if(result != cancel) + DoEndGame(nextAction); + } + }.Create(); + return false; + } return true; } bool OnClose(bool parentClosing) { - return EndGame(); + return EndGame(close); } void OnDestroy() { +#ifndef CHESS_NONET delete sockets[Black]; delete sockets[White]; +#endif delete driverItems; } +#ifndef CHESS_NONET void Connect(const char * address) { ChessSocket socket { chess = this }; @@ -655,9 +721,11 @@ class Chess : Window chessState.isLocalPlayer[SERVER_COLOR] = false; } } +#endif } // --- Chess Communications --- +#ifndef CHESS_NONET class ChessSocket : Socket { Chess chess; @@ -740,3 +808,4 @@ class ChessService : Service } } } +#endif diff --git a/samples/games/chess/src/chess3D.ec b/samples/games/chess/src/chess3D.ec index 838531b..cbf89db 100644 --- a/samples/games/chess/src/chess3D.ec +++ b/samples/games/chess/src/chess3D.ec @@ -385,8 +385,7 @@ class Chess3D : Window void OnRedraw(Surface surface) { - //surface.SetBackground(white); - surface.Clear(colorAndDepth); + surface.Clear(depthBuffer); camera.Update(); display.antiAlias = antiAlias; diff --git a/samples/games/chess/src/connect.ec b/samples/games/chess/src/connect.ec index 9c97efb..a560b9d 100644 --- a/samples/games/chess/src/connect.ec +++ b/samples/games/chess/src/connect.ec @@ -1,5 +1,6 @@ import "chess.ec" +#ifndef CHESS_NONET class ConnectDialog : Window { minClientSize = Size { 300, 100 }; @@ -36,3 +37,4 @@ class ConnectDialog : Window line.text = "localhost" }; } +#endif diff --git a/samples/guiAndGfx/mekano/mekano.epj b/samples/guiAndGfx/mekano/mekano.epj index ab8c3f3..47662a1 100644 --- a/samples/guiAndGfx/mekano/mekano.epj +++ b/samples/guiAndGfx/mekano/mekano.epj @@ -71,6 +71,27 @@ } } ] + }, + { + "Name" : "Emscripten", + "Options" : { + "Optimization" : "Speed", + "PreprocessorDefinitions" : [ + "IMPORT_STATIC=static" + ], + "TargetFileName" : "mekano.html", + "Libraries" : [ + "ecereStatic", + "z", + "freetype", + "png", + "jpeg" + ], + "LibraryDirs" : [ + "../../../ecere/obj/emscripten.linux.emscripten" + ], + "FastMath" : true + } } ], "Files" : [ diff --git a/samples/guiAndGfx/mekano/mekanosimulation.ec b/samples/guiAndGfx/mekano/mekanosimulation.ec index 8bc4adc..106972e 100644 --- a/samples/guiAndGfx/mekano/mekanosimulation.ec +++ b/samples/guiAndGfx/mekano/mekanosimulation.ec @@ -1,6 +1,6 @@ import "mekanodisplay" -class MekanoSimulation +class MekanoSimulation : struct { private: List m_Objects { }; diff --git a/samples/guiAndGfx/mekano/mekanownd.ec b/samples/guiAndGfx/mekano/mekanownd.ec index e2c553b..1d65386 100644 --- a/samples/guiAndGfx/mekano/mekanownd.ec +++ b/samples/guiAndGfx/mekano/mekanownd.ec @@ -25,9 +25,13 @@ private: public: caption = "Mekano"; +#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) + anchor = { 0, 0, 0, 0 }; +#else + clientSize = { 640, 480 }; hasMaximize = true, hasMinimize = true, hasClose = true; borderStyle = sizable; - clientSize = { 640, 480 }; +#endif background = slateGray; BitmapResource bg { ":ecere.bmp", window = this };