From 070d768e99c0a6fe8e9ef44e0f0485a900d70310 Mon Sep 17 00:00:00 2001 From: Modanung Date: Sat, 27 Feb 2021 21:23:10 +0100 Subject: [PATCH 1/3] Added Emscripten shell --- .gitignore | 1 + CMake/Modules/DryCommon.cmake | 10 +- Source/Dry/CMakeLists.txt | 4 + Source/Dry/Graphics/OpenGL/OGLGraphics.cpp | 75 +++++ Source/Dry/Graphics/OpenGL/OGLIndexBuffer.cpp | 3 + .../Dry/Graphics/OpenGL/OGLRenderSurface.cpp | 3 + .../Dry/Graphics/OpenGL/OGLShaderProgram.cpp | 3 + .../Graphics/OpenGL/OGLShaderVariation.cpp | 3 + Source/Dry/Graphics/OpenGL/OGLTexture2D.cpp | 3 + .../Dry/Graphics/OpenGL/OGLTexture2DArray.cpp | 3 + Source/Dry/Graphics/OpenGL/OGLTexture3D.cpp | 3 + Source/Dry/Graphics/OpenGL/OGLTextureCube.cpp | 3 + .../Dry/Graphics/OpenGL/OGLVertexBuffer.cpp | 3 + Source/Dry/Input/Input.cpp | 95 +++++- Source/Dry/UI/UI.cpp | 35 ++- Source/Dry/UI/UI.h | 5 + bin/shell.html | 288 ++++++++++++++++++ 17 files changed, 511 insertions(+), 29 deletions(-) create mode 100644 bin/shell.html diff --git a/.gitignore b/.gitignore index 1981c7f..1a42be8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Output directories /bin/* +!/bin/shell.html !/bin/**/ !/bin/*.bat !/bin/*.sh diff --git a/CMake/Modules/DryCommon.cmake b/CMake/Modules/DryCommon.cmake index e1472df..85fda1e 100644 --- a/CMake/Modules/DryCommon.cmake +++ b/CMake/Modules/DryCommon.cmake @@ -632,8 +632,8 @@ else () if (WEB) if (EMSCRIPTEN) # Emscripten-specific setup - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-warn-absolute-paths -Wno-unknown-warning-option") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-warn-absolute-paths -Wno-unknown-warning-option") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-warn-absolute-paths -Wno-unknown-warning-option --bind") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-warn-absolute-paths -Wno-unknown-warning-option --bind") if (DRY_THREADING) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_PTHREADS=1") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_PTHREADS=1") @@ -1042,13 +1042,15 @@ macro (add_html_shell) set (HTML_SHELL ${ARGN}) else () # Create Dry custom HTML shell that also embeds our own project logo - if (NOT EXISTS ${CMAKE_BINARY_DIR}/Source/shell.html) + if (NOT EXISTS ${CMAKE_SOURCE_DIR}/bin/shell.html) file (READ ${EMSCRIPTEN_ROOT_PATH}/src/shell.html HTML_SHELL) string (REPLACE "" "\n\n" HTML_SHELL "${HTML_SHELL}") # Stringify to preserve semicolons string (REPLACE "" "\n\n\"link\n" HTML_SHELL "${HTML_SHELL}") file (WRITE ${CMAKE_BINARY_DIR}/Source/shell.html "${HTML_SHELL}") + set (HTML_SHELL ${CMAKE_BINARY_DIR}/Source/shell.html) + else () + set (HTML_SHELL ${CMAKE_SOURCE_DIR}/bin/shell.html) endif () - set (HTML_SHELL ${CMAKE_BINARY_DIR}/Source/shell.html) endif () list (APPEND SOURCE_FILES ${HTML_SHELL}) set_source_files_properties (${HTML_SHELL} PROPERTIES EMCC_OPTION shell-file) diff --git a/Source/Dry/CMakeLists.txt b/Source/Dry/CMakeLists.txt index cc0a286..8d81518 100644 --- a/Source/Dry/CMakeLists.txt +++ b/Source/Dry/CMakeLists.txt @@ -102,6 +102,10 @@ if (DRY_HASH_DEBUG) add_definitions (-DDRY_HASH_DEBUG) endif () +if (EXISTS ${CMAKE_SOURCE_DIR}/bin/shell.html) + add_definitions (-DDRY_CUSTOM_SHELL) +endif() + # Define source files foreach (DIR IK Navigation Network Physics 2D WebP) string (TOUPPER DRY_${DIR} OPT) diff --git a/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp b/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp index e730e89..e352d9a 100644 --- a/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp @@ -53,6 +53,12 @@ #endif #ifdef __EMSCRIPTEN__ +#include "../../Input/Input.h" +#include "../../UI/Cursor.h" +#include "../../UI/UI.h" +#include +#include + // Emscripten provides even all GL extension functions via static linking. However there is // no GLES2-specific extension header at the moment to include instanced rendering declarations, // so declare them manually from GLES3 gl2ext.h. Emscripten will provide these when linking final output. @@ -62,6 +68,75 @@ extern "C" GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor); } + +// Helper functions to support emscripten canvas resolution change +static const Dry::Context *appContext; + +static void JSCanvasSize(int width, int height, bool fullscreen, float scale) +{ + DRY_LOGINFOF("JSCanvasSize: width=%d height=%d fullscreen=%d ui scale=%f", width, height, fullscreen, scale); + + using namespace Dry; + + if (appContext) + { + bool uiCursorVisible = false; + bool systemCursorVisible = false; + MouseMode mouseMode{}; + + // Detect current system pointer state + Input* input = appContext->GetSubsystem(); + if (input) + { + systemCursorVisible = input->IsMouseVisible(); + mouseMode = input->GetMouseMode(); + } + + UI* ui = appContext->GetSubsystem(); + if (ui) + { + ui->SetScale(scale); + + // Detect current UI pointer state + Cursor* cursor = ui->GetCursor(); + if (cursor) + uiCursorVisible = cursor->IsVisible(); + } + + // Apply new resolution + appContext->GetSubsystem()->SetMode(width, height); + + // Reset the pointer state as it was before resolution change + if (input) + { + if (uiCursorVisible) + input->SetMouseVisible(false); + else + input->SetMouseVisible(systemCursorVisible); + + input->SetMouseMode(mouseMode); + } + + if (ui) + { + Cursor* cursor = ui->GetCursor(); + if (cursor) + { + cursor->SetVisible(uiCursorVisible); + + IntVector2 pos = input->GetMousePosition(); + pos = ui->ConvertSystemToUI(pos); + + cursor->SetPosition(pos); + } + } + } +} + +using namespace emscripten; +EMSCRIPTEN_BINDINGS(Module) { + function("JSCanvasSize", &JSCanvasSize); +} #endif #ifdef _WIN32 diff --git a/Source/Dry/Graphics/OpenGL/OGLIndexBuffer.cpp b/Source/Dry/Graphics/OpenGL/OGLIndexBuffer.cpp index c6c7c77..f991d9e 100644 --- a/Source/Dry/Graphics/OpenGL/OGLIndexBuffer.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLIndexBuffer.cpp @@ -35,6 +35,9 @@ namespace Dry void IndexBuffer::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteBuffers(1, &object_.name_); + GPUObject::OnDeviceLost(); } diff --git a/Source/Dry/Graphics/OpenGL/OGLRenderSurface.cpp b/Source/Dry/Graphics/OpenGL/OGLRenderSurface.cpp index 41ae9ba..6d9958d 100644 --- a/Source/Dry/Graphics/OpenGL/OGLRenderSurface.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLRenderSurface.cpp @@ -103,6 +103,9 @@ void RenderSurface::OnDeviceLost() // Clean up also from non-active FBOs graphics->CleanupRenderSurface(this); + if (renderBuffer_ && !graphics->IsDeviceLost()) + glDeleteRenderbuffersEXT(1, &renderBuffer_); + renderBuffer_ = 0; } diff --git a/Source/Dry/Graphics/OpenGL/OGLShaderProgram.cpp b/Source/Dry/Graphics/OpenGL/OGLShaderProgram.cpp index 8f737f9..0a15146 100644 --- a/Source/Dry/Graphics/OpenGL/OGLShaderProgram.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLShaderProgram.cpp @@ -74,6 +74,9 @@ ShaderProgram::~ShaderProgram() void ShaderProgram::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteProgram(object_.name_); + GPUObject::OnDeviceLost(); if (graphics_ && graphics_->GetShaderProgram() == this) diff --git a/Source/Dry/Graphics/OpenGL/OGLShaderVariation.cpp b/Source/Dry/Graphics/OpenGL/OGLShaderVariation.cpp index 6e6cd33..ca00590 100644 --- a/Source/Dry/Graphics/OpenGL/OGLShaderVariation.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLShaderVariation.cpp @@ -49,6 +49,9 @@ const char* ShaderVariation::elementSemanticNames[] = void ShaderVariation::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteShader(object_.name_); + GPUObject::OnDeviceLost(); compilerOutput_.Clear(); diff --git a/Source/Dry/Graphics/OpenGL/OGLTexture2D.cpp b/Source/Dry/Graphics/OpenGL/OGLTexture2D.cpp index 47728cd..d128c90 100644 --- a/Source/Dry/Graphics/OpenGL/OGLTexture2D.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLTexture2D.cpp @@ -41,6 +41,9 @@ namespace Dry void Texture2D::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteTextures(1, &object_.name_); + GPUObject::OnDeviceLost(); if (renderSurface_) diff --git a/Source/Dry/Graphics/OpenGL/OGLTexture2DArray.cpp b/Source/Dry/Graphics/OpenGL/OGLTexture2DArray.cpp index cfb92c1..a7c8730 100644 --- a/Source/Dry/Graphics/OpenGL/OGLTexture2DArray.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLTexture2DArray.cpp @@ -45,6 +45,9 @@ namespace Dry void Texture2DArray::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteTextures(1, &object_.name_); + GPUObject::OnDeviceLost(); if (renderSurface_) diff --git a/Source/Dry/Graphics/OpenGL/OGLTexture3D.cpp b/Source/Dry/Graphics/OpenGL/OGLTexture3D.cpp index 51333dc..fb2e084 100644 --- a/Source/Dry/Graphics/OpenGL/OGLTexture3D.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLTexture3D.cpp @@ -41,6 +41,9 @@ namespace Dry void Texture3D::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteTextures(1, &object_.name_); + GPUObject::OnDeviceLost(); } diff --git a/Source/Dry/Graphics/OpenGL/OGLTextureCube.cpp b/Source/Dry/Graphics/OpenGL/OGLTextureCube.cpp index cf9c119..0ab2eda 100644 --- a/Source/Dry/Graphics/OpenGL/OGLTextureCube.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLTextureCube.cpp @@ -45,6 +45,9 @@ namespace Dry void TextureCube::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteTextures(1, &object_.name_); + GPUObject::OnDeviceLost(); for (auto& renderSurface : renderSurfaces_) diff --git a/Source/Dry/Graphics/OpenGL/OGLVertexBuffer.cpp b/Source/Dry/Graphics/OpenGL/OGLVertexBuffer.cpp index 5400885..902e4ae 100644 --- a/Source/Dry/Graphics/OpenGL/OGLVertexBuffer.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLVertexBuffer.cpp @@ -34,6 +34,9 @@ namespace Dry void VertexBuffer::OnDeviceLost() { + if (object_.name_ && !graphics_->IsDeviceLost()) + glDeleteBuffers(1, &object_.name_); + GPUObject::OnDeviceLost(); } diff --git a/Source/Dry/Input/Input.cpp b/Source/Dry/Input/Input.cpp index d602dee..8b629c8 100644 --- a/Source/Dry/Input/Input.cpp +++ b/Source/Dry/Input/Input.cpp @@ -47,6 +47,8 @@ #ifdef __EMSCRIPTEN__ #include +#include +#include #endif #include "../DebugNew.h" @@ -109,6 +111,8 @@ public: /// Static callback method for Pointer Lock API. Handles change in Pointer Lock state and sends events for mouse mode change. static EM_BOOL HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData); + /// Static callback method for Pointer Lock API for the custom shell implementation + static void HandleCustomPointerLockChange(bool pointerLocked); /// Static callback method for tracking focus change events. static EM_BOOL HandleFocusChange(int eventType, const EmscriptenFocusEvent* keyEvent, void* userData); /// Static callback method for suppressing mouse jump. @@ -126,7 +130,7 @@ public: private: /// Instance of Input subsystem that constructed this instance. - Input* inputInst_; + static Input* inputInst_; /// The mouse mode being requested for pointer-lock. static MouseMode requestedMouseMode_; /// Flag indicating whether to suppress the next mouse mode change event. @@ -138,18 +142,21 @@ private: static bool invalidatedSuppressMouseModeEvent_; }; +Input* EmscriptenInput::inputInst_ = nullptr; bool EmscriptenInput::suppressMouseModeEvent_ = false; MouseMode EmscriptenInput::requestedMouseMode_ = MM_INVALID; bool EmscriptenInput::invalidatedSuppressMouseModeEvent_ = false; MouseMode EmscriptenInput::invalidatedRequestedMouseMode_ = MM_INVALID; -EmscriptenInput::EmscriptenInput(Input* inputInst) : - inputInst_(inputInst) +EmscriptenInput::EmscriptenInput(Input* inputInst) { + inputInst_ = inputInst; auto* vInputInst = (void*)inputInst; +#ifndef DRY_CUSTOM_SHELL // Handle pointer lock emscripten_set_pointerlockchange_callback(NULL, vInputInst, false, EmscriptenInput::HandlePointerLockChange); +#endif // Handle mouse events to prevent mouse jumps emscripten_set_mousedown_callback(NULL, vInputInst, true, EmscriptenInput::HandleMouseJump); @@ -167,7 +174,13 @@ void EmscriptenInput::RequestPointerLock(MouseMode mode, bool suppressEvent) { requestedMouseMode_ = mode; suppressMouseModeEvent_ = suppressEvent; +#ifdef DRY_CUSTOM_SHELL + EM_ASM({ + Module.RequestPointerLock(); + }); +#else emscripten_request_pointerlock(NULL, true); +#endif } void EmscriptenInput::ExitPointerLock(bool suppressEvent) @@ -183,8 +196,16 @@ void EmscriptenInput::ExitPointerLock(bool suppressEvent) if (inputInst_->IsMouseLocked()) { inputInst_->emscriptenExitingPointerLock_ = true; +#ifndef DRY_CUSTOM_SHELL emscripten_exit_pointerlock(); +#endif } + +#ifdef DRY_CUSTOM_SHELL + EM_ASM({ + Module.ExitPointerLock(); + }); +#endif } bool EmscriptenInput::IsVisible() @@ -198,6 +219,51 @@ bool EmscriptenInput::IsVisible() return true; } +void EmscriptenInput::HandleCustomPointerLockChange(bool pointerLocked) +{ + bool invalid = false; + const bool suppress = suppressMouseModeEvent_; + if (requestedMouseMode_ == MM_INVALID && invalidatedRequestedMouseMode_ != MM_INVALID) + { + invalid = true; + requestedMouseMode_ = invalidatedRequestedMouseMode_; + suppressMouseModeEvent_ = invalidatedSuppressMouseModeEvent_; + invalidatedRequestedMouseMode_ = MM_INVALID; + invalidatedSuppressMouseModeEvent_ = false; + } + + if (pointerLocked) + { + // Pointer Lock is now active + inputInst_->emscriptenPointerLock_ = true; + inputInst_->emscriptenEnteredPointerLock_ = true; + inputInst_->SetMouseModeEmscriptenFinal(requestedMouseMode_, suppressMouseModeEvent_); + } + else + { + // Pointer Lock is now inactive + inputInst_->emscriptenPointerLock_ = false; + + if (inputInst_->mouseMode_ == MM_RELATIVE) + inputInst_->SetMouseModeEmscriptenFinal(MM_FREE, suppressMouseModeEvent_); + else if (inputInst_->mouseMode_ == MM_ABSOLUTE) + inputInst_->SetMouseModeEmscriptenFinal(MM_ABSOLUTE, suppressMouseModeEvent_); + + inputInst_->emscriptenExitingPointerLock_ = false; + } + + requestedMouseMode_ = MM_INVALID; + suppressMouseModeEvent_ = false; + + invalidatedRequestedMouseMode_ = MM_INVALID; + invalidatedSuppressMouseModeEvent_ = false; +} + +using namespace emscripten; +EMSCRIPTEN_BINDINGS(Module) { + function("JSPointerLockChange", &EmscriptenInput::HandleCustomPointerLockChange); +} + EM_BOOL EmscriptenInput::HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData) { auto* const inputInst = (Input*)userData; @@ -338,14 +404,14 @@ void JoystickState::Initialize(unsigned numButtons, unsigned numAxes, unsigned n void JoystickState::Reset() { - for (unsigned i{ 0 }; i < buttons_.Size(); ++i) + for (unsigned i = 0; i < buttons_.Size(); ++i) { buttons_[i] = false; buttonPress_[i] = false; } - for (unsigned i{ 0 }; i < axes_.Size(); ++i) + for (unsigned i = 0; i < axes_.Size(); ++i) axes_[i] = 0.0f; - for (unsigned i{ 0 }; i < hats_.Size(); ++i) + for (unsigned i = 0; i < hats_.Size(); ++i) hats_[i] = HAT_CENTER; } @@ -381,7 +447,7 @@ Input::Input(Context* context) : { context_->RequireSDL(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); - for (int i{ 0 }; i < TOUCHID_MAX; i++) + for (int i = 0; i < TOUCHID_MAX; i++) availableTouchIDs_.Push(i); SubscribeToEvent(E_SCREENMODE, DRY_HANDLER(Input, HandleScreenMode)); @@ -594,7 +660,7 @@ void Input::SetMouseVisible(bool enable, bool suppressEvent) if (mouseMode_ == MM_ABSOLUTE) SetMouseModeAbsolute(SDL_TRUE); #else - if (mouseMode_ == MM_ABSOLUTE && !emscriptenPointerLock_) + if (mouseMode_ == MM_ABSOLUTE && !emscriptenPointerLock_ || !enable) emscriptenInput_->RequestPointerLock(MM_ABSOLUTE, suppressEvent); #endif SDL_ShowCursor(SDL_FALSE); @@ -633,7 +699,7 @@ void Input::SetMouseVisible(bool enable, bool suppressEvent) } } #else - if (mouseMode_ == MM_ABSOLUTE && emscriptenPointerLock_) + if (mouseMode_ == MM_ABSOLUTE && emscriptenPointerLock_ || enable) emscriptenInput_->ExitPointerLock(suppressEvent); #endif } @@ -777,6 +843,7 @@ void Input::SetMouseModeEmscripten(MouseMode mode, bool suppressEvent) if (emscriptenPointerLock_) { SetMouseVisibleEmscripten(false, suppressEvent); + } else { @@ -1097,14 +1164,14 @@ SDL_JoystickID Input::AddScreenJoystick(XMLFile* layoutFile, XMLFile* styleFile) else if (keyBinding.Length() == 4) { keyBindings.Resize(4); // e.g.: "WSAD" - for (unsigned i{ 0 }; i < 4; ++i) + for (unsigned i = 0; i < 4; ++i) keyBindings[i] = keyBinding.Substring(i, 1); } if (keyBindings.Size() == 4) { PopulateKeyBindingMap(keyBindingMap); - for (unsigned j{ 0 }; j < 4; ++j) + for (unsigned j = 0; j < 4; ++j) { if (keyBindings[j].Length() == 1) mappedKeyBinding[j] = keyBindings[j][0]; @@ -1561,7 +1628,7 @@ void Input::ResetJoysticks() // Open each detected joystick automatically on startup auto size = static_cast(SDL_NumJoysticks()); - for (unsigned i{ 0 }; i < size; ++i) + for (unsigned i = 0; i < size; ++i) OpenJoystick(i); } @@ -1575,7 +1642,7 @@ void Input::ResetInputAccumulation() mouseMoveWheel_ = 0; for (HashMap::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i) { - for (unsigned j{ 0 }; j < i->second_.buttonPress_.Size(); ++j) + for (unsigned j = 0; j < i->second_.buttonPress_.Size(); ++j) i->second_.buttonPress_[j] = false; } @@ -1673,7 +1740,7 @@ void Input::ResetTouches() touches_.Clear(); touchIDMap_.Clear(); availableTouchIDs_.Clear(); - for (int i{ 0 }; i < TOUCHID_MAX; i++) + for (int i = 0; i < TOUCHID_MAX; i++) availableTouchIDs_.Push(i); } diff --git a/Source/Dry/UI/UI.cpp b/Source/Dry/UI/UI.cpp index 15098c0..26d1597 100644 --- a/Source/Dry/UI/UI.cpp +++ b/Source/Dry/UI/UI.cpp @@ -766,9 +766,22 @@ void UI::SetCustomSize(int width, int height) ResizeRootElement(); } +IntVector2 UI::ConvertSystemToUI(const IntVector2& pos) const +{ + return VectorFloorToInt(static_cast(pos) / GetScale()); +} + +IntVector2 UI::ConvertUIToSystem(const IntVector2& pos) const +{ + return VectorFloorToInt(static_cast(pos) * GetScale()); +} + IntVector2 UI::GetCursorPosition() const { - return cursor_ ? cursor_->GetPosition() : GetSubsystem()->GetMousePosition(); + if (cursor_) + return cursor_->GetPosition(); + + return ConvertSystemToUI(GetSubsystem()->GetMousePosition()); } UIElement* UI::GetElementAt(const IntVector2& position, bool enabledOnly, IntVector2* elementScreenPosition) const @@ -1787,24 +1800,24 @@ void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData) qualifiers_ = QualifierFlags(eventData[P_QUALIFIERS].GetUInt()); usingTouchInput_ = false; - auto* input = GetSubsystem(); - const IntVector2& rootSize = rootElement_->GetSize(); - const IntVector2& rootPos = rootElement_->GetPosition(); + auto* input{ GetSubsystem() }; + const IntVector2& rootSize{ rootElement_->GetSize() }; + const IntVector2& rootPos{ rootElement_->GetPosition() }; - IntVector2 DeltaP = IntVector2(eventData[P_DX].GetInt(), eventData[P_DY].GetInt()); + const IntVector2 mouseDeltaPos{ eventData[P_DX].GetInt(), eventData[P_DY].GetInt() }; + const IntVector2 mousePos{ eventData[P_X].GetInt(), eventData[P_Y].GetInt() }; if (cursor_) { if (!input->IsMouseVisible()) { if (!input->IsMouseLocked()) - cursor_->SetPosition(IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt())); + cursor_->SetPosition(ConvertSystemToUI(mousePos)); else if (cursor_->IsVisible()) { // Relative mouse motion: move cursor only when visible - IntVector2 pos = cursor_->GetPosition(); - pos.x_ += eventData[P_DX].GetInt(); - pos.y_ += eventData[P_DY].GetInt(); + IntVector2 pos{ cursor_->GetPosition() }; + pos += ConvertSystemToUI(mouseDeltaPos); pos.x_ = Clamp(pos.x_, rootPos.x_, rootPos.x_ + rootSize.x_ - 1); pos.y_ = Clamp(pos.y_, rootPos.y_, rootPos.y_ + rootSize.y_ - 1); cursor_->SetPosition(pos); @@ -1813,7 +1826,7 @@ void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData) else { // Absolute mouse motion: move always - cursor_->SetPosition(IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt())); + cursor_->SetPosition(ConvertSystemToUI(mousePos)); } } @@ -1821,7 +1834,7 @@ void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData) bool cursorVisible; GetCursorPositionAndVisible(cursorPos, cursorVisible); - ProcessMove(cursorPos, DeltaP, mouseButtons_, qualifiers_, cursor_, cursorVisible); + ProcessMove(cursorPos, mouseDeltaPos, mouseButtons_, qualifiers_, cursor_, cursorVisible); } void UI::HandleMouseWheel(StringHash eventType, VariantMap& eventData) diff --git a/Source/Dry/UI/UI.h b/Source/Dry/UI/UI.h index 38858c5..ea8bd90 100644 --- a/Source/Dry/UI/UI.h +++ b/Source/Dry/UI/UI.h @@ -131,6 +131,11 @@ public: /// Set custom size of the root element. void SetCustomSize(int width, int height); + /// Convert system mouse position (or offset) to scaled UI position (or offset). + IntVector2 ConvertSystemToUI(const IntVector2& pos) const; + /// Convert scaled UI position (or offset) to system mouse position (or offset). + IntVector2 ConvertUIToSystem(const IntVector2& pos) const; + /// Return root UI element. UIElement* GetRoot() const { return rootElement_; } /// Return root modal element. diff --git a/bin/shell.html b/bin/shell.html new file mode 100644 index 0000000..8cd1624 --- /dev/null +++ b/bin/shell.html @@ -0,0 +1,288 @@ + + + + + + Dry + + + +
+
Downloading...
+ +
+ + + + {{{ SCRIPT }}} + + -- GitLab From c4041456f4485ef835007967d30cb45240be4267 Mon Sep 17 00:00:00 2001 From: Modanung Date: Sat, 27 Feb 2021 22:05:01 +0100 Subject: [PATCH 2/3] Modified shell style --- bin/shell.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/shell.html b/bin/shell.html index 8cd1624..b19693c 100644 --- a/bin/shell.html +++ b/bin/shell.html @@ -1,5 +1,5 @@ - + @@ -23,6 +23,10 @@ text-align: center; } + #status { + color: #5e7732; + } + #fullscreen-button { position: absolute; width: 2em; @@ -47,7 +51,7 @@ left: 0; width: 100%; height: 100%; - background-color: #000; + background-color: black; border: 1px solid #000000; border: none; cursor: default !important; -- GitLab From 685e3c0f546d9c44ae5a4cc10a23fe6c70a7e93c Mon Sep 17 00:00:00 2001 From: Modanung Date: Sun, 28 Feb 2021 13:57:08 +0100 Subject: [PATCH 3/3] Hid fullscreen button in Chrome --- Source/Dry/Graphics/OpenGL/OGLGraphics.cpp | 4 ++++ Source/Dry/UI/LineEdit.cpp | 11 ++++++++++- bin/shell.html | 9 +++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp b/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp index e352d9a..f869c71 100644 --- a/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp +++ b/Source/Dry/Graphics/OpenGL/OGLGraphics.cpp @@ -317,6 +317,10 @@ Graphics::Graphics(Context* context) : // Register Graphics library object factories RegisterGraphicsLibrary(context_); + +#ifdef __EMSCRIPTEN__ + appContext = context_; +#endif } Graphics::~Graphics() diff --git a/Source/Dry/UI/LineEdit.cpp b/Source/Dry/UI/LineEdit.cpp index e6b0b42..271ab13 100644 --- a/Source/Dry/UI/LineEdit.cpp +++ b/Source/Dry/UI/LineEdit.cpp @@ -564,10 +564,19 @@ bool LineEdit::FilterImplicitAttributes(XMLElement& dest) const void LineEdit::UpdateText() { - unsigned utf8Length = line_.LengthUTF8(); + unsigned utf8Length{ line_.LengthUTF8() }; + + // If maxLength_ nonzero, truncate line to enforce length + if (maxLength_ && utf8Length > maxLength_) + { + line_ = line_.SubstringUTF8(0, maxLength_); + utf8Length = maxLength_; + } if (!echoCharacter_) + { text_->SetText(line_); + } else { String echoText; diff --git a/bin/shell.html b/bin/shell.html index b19693c..7f82da9 100644 --- a/bin/shell.html +++ b/bin/shell.html @@ -158,7 +158,9 @@ // Enter the fullscreen mode function enterFullscreen(show) { - if (show === undefined) show = !isFullScreen(); + if (show === undefined) + show = !isFullScreen(); + if (show) { if (canvasElement.requestFullscreen) canvasElement.requestFullscreen(); else if (canvasElement.webkitRequestFullScreen) canvasElement.webkitRequestFullScreen(); @@ -193,7 +195,10 @@ // App is ready to launch, make canvas and fullscreen button visible function ready() { document.getElementById('canvas').style.display = 'block'; - document.getElementById('fullscreen-button').style.display = 'block'; + + if(!window.chrome) { + document.getElementById('fullscreen-button').style.display = 'block'; + } if (document.hidden) { unlockPointer(); -- GitLab