From d0165ec9a629bf6e91f6c2fe927fdd039d158ac4 Mon Sep 17 00:00:00 2001 From: Moros Smith Date: Mon, 11 Nov 2024 20:29:40 -0500 Subject: [PATCH 01/14] remove duplicate for PK_BACKSLASH --- olcPixelGameEngine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index 0d9e567b..43557fef 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -7010,7 +7010,7 @@ namespace olc mapKeys[DOM_PK_CAPS_LOCK] = Key::CAPS_LOCK; mapKeys[DOM_PK_SEMICOLON] = Key::OEM_1; mapKeys[DOM_PK_SLASH] = Key::OEM_2; mapKeys[DOM_PK_BACKQUOTE] = Key::OEM_3; mapKeys[DOM_PK_BRACKET_LEFT] = Key::OEM_4; mapKeys[DOM_PK_BACKSLASH] = Key::OEM_5; mapKeys[DOM_PK_BRACKET_RIGHT] = Key::OEM_6; - mapKeys[DOM_PK_QUOTE] = Key::OEM_7; mapKeys[DOM_PK_BACKSLASH] = Key::OEM_8; + mapKeys[DOM_PK_QUOTE] = Key::OEM_7; // Keyboard Callbacks emscripten_set_keydown_callback("#canvas", 0, 1, keyboard_callback); From c2c9f5036e1846bfa574d00af0b5e241eb860a88 Mon Sep 17 00:00:00 2001 From: Moros Smith Date: Mon, 11 Nov 2024 20:30:12 -0500 Subject: [PATCH 02/14] handle number pad state --- olcPixelGameEngine.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index 43557fef..18b21a30 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -7173,6 +7173,41 @@ namespace olc //TY Moros static EM_BOOL keyboard_callback(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { + // we maintain our own state for teh number pad, default true + static bool numPadActive = true; + + // THANK GOD!! for this compute function. And thanks Dandistine for pointing it out! + int pk_code = emscripten_compute_dom_pk_code(e->code); + + if(!numPadActive) + { + /** + * we need to react differently if the numlock is not + * active. this block ensures uniform behavior with + * windows and linux, MacOS is a lost cause due to GLUT. + */ + switch(pk_code) + { + case DOM_PK_NUMPAD_7: pk_code = DOM_PK_HOME; break; + case DOM_PK_NUMPAD_8: pk_code = DOM_PK_ARROW_UP; break; + case DOM_PK_NUMPAD_9: pk_code = DOM_PK_PAGE_UP; break; + case DOM_PK_NUMPAD_4: pk_code = DOM_PK_ARROW_LEFT; break; + case DOM_PK_NUMPAD_5: pk_code = DOM_PK_UNKNOWN; break; + case DOM_PK_NUMPAD_6: pk_code = DOM_PK_ARROW_RIGHT; break; + case DOM_PK_NUMPAD_1: pk_code = DOM_PK_END; break; + case DOM_PK_NUMPAD_2: pk_code = DOM_PK_ARROW_DOWN; break; + case DOM_PK_NUMPAD_3: pk_code = DOM_PK_PAGE_DOWN; break; + case DOM_PK_NUMPAD_0: pk_code = DOM_PK_INSERT; break; + case DOM_PK_NUMPAD_DECIMAL: pk_code = DOM_PK_DELETE; break; + default: + break; + } + } + // check for keydown + numlock and act appropriately + if (eventType == EMSCRIPTEN_EVENT_KEYDOWN && pk_code == DOM_PK_NUM_LOCK) + { + numPadActive = !numPadActive; + } if (eventType == EMSCRIPTEN_EVENT_KEYDOWN) ptrPGE->olc_UpdateKeyState(emscripten_compute_dom_pk_code(e->code), true); From 26f47772797b1cf53d70b7bcf88887fe46f51297 Mon Sep 17 00:00:00 2001 From: Moros Smith Date: Mon, 11 Nov 2024 20:30:49 -0500 Subject: [PATCH 03/14] pass the pk_code directly --- olcPixelGameEngine.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index 18b21a30..a50c540f 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -7203,17 +7203,18 @@ namespace olc break; } } + // check for keydown + numlock and act appropriately if (eventType == EMSCRIPTEN_EVENT_KEYDOWN && pk_code == DOM_PK_NUM_LOCK) { numPadActive = !numPadActive; } + if (eventType == EMSCRIPTEN_EVENT_KEYDOWN) - ptrPGE->olc_UpdateKeyState(emscripten_compute_dom_pk_code(e->code), true); + ptrPGE->olc_UpdateKeyState(pk_code, true); - // THANK GOD!! for this compute function. And thanks Dandistine for pointing it out! if (eventType == EMSCRIPTEN_EVENT_KEYUP) - ptrPGE->olc_UpdateKeyState(emscripten_compute_dom_pk_code(e->code), false); + ptrPGE->olc_UpdateKeyState(pk_code, false); //Consume keyboard events so that keys like F1 and F5 don't do weird things return EM_TRUE; From 177ce9c4428d3584118d60c1f7d4fe40156ac17d Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Tue, 22 Apr 2025 10:35:12 +0100 Subject: [PATCH 04/14] Stubbed 2.30 in develop --- olcPixelGameEngine.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index b64b4136..be197f11 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -3,7 +3,7 @@ olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.29 | + | OneLoneCoder Pixel Game Engine v2.30 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -357,6 +357,7 @@ Updated Geometry2D to support non-segment line intersections +olcUTIL_Hardware3D.h file v1.01 NOTICE OF DEPRECATION! olc::DecalInstance is to be removed and replaced by olc::GPUTask + 2.30: !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! @@ -437,7 +438,7 @@ int main() #include #pragma endregion -#define PGE_VER 229 +#define PGE_VER 230 // O------------------------------------------------------------------------------O // | COMPILER CONFIGURATION ODDITIES | From 22305848133b8e43731f2dcd4334372152ccd899 Mon Sep 17 00:00:00 2001 From: dandistine <> Date: Fri, 25 Apr 2025 19:45:25 -0500 Subject: [PATCH 05/14] Fix headless mode as it was missing two deleted renderer functions. --- olcPixelGameEngine.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index b64b4136..53cf692f 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -4973,6 +4973,8 @@ namespace olc virtual void SetDecalMode(const olc::DecalMode& mode) {} virtual void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) {} virtual void DrawDecal(const olc::DecalInstance& decal) {} + virtual void DoGPUTask(const olc::GPUTask& task) {} + virtual void Set3DProjection(const std::array& mat) {} virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false, const bool clamp = true) { return 1; }; virtual void UpdateTexture(uint32_t id, olc::Sprite* spr) {} virtual void ReadTexture(uint32_t id, olc::Sprite* spr) {} From 2114780ae74de93440595c02999e6884cb8fa361 Mon Sep 17 00:00:00 2001 From: dandistine <34634876+dandistine@users.noreply.github.com> Date: Fri, 2 May 2025 10:26:57 -0500 Subject: [PATCH 06/14] Fix javascript strict equality --- olcPixelGameEngine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index b64b4136..7fab1566 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -7641,7 +7641,7 @@ namespace olc // set up resize observer and fullscreenchange event handler var olc_Init = function() { - if (Module.olc_AspectRatio == = undefined) + if (Module.olc_AspectRatio === undefined) { setTimeout(function() { Module.olc_Init(); }, 50); return; From 818d5774d3c881190159b6a529620e07de2fc6e5 Mon Sep 17 00:00:00 2001 From: Moros Smith Date: Thu, 22 May 2025 22:23:15 -0400 Subject: [PATCH 07/14] template doesn't need to handle resizing anymore. all based on parent element styling --- olcExampleProgram.html | 7738 ++++++++++++++++++++++++++++++++ tools/wasm/basic_template.html | 78 +- 2 files changed, 7759 insertions(+), 57 deletions(-) create mode 100644 olcExampleProgram.html diff --git a/olcExampleProgram.html b/olcExampleProgram.html new file mode 100644 index 00000000..3aa46a72 --- /dev/null +++ b/olcExampleProgram.html @@ -0,0 +1,7738 @@ + + + + + + + + Emscripten-Generated Code + + + + + + + + + diff --git a/tools/wasm/basic_template.html b/tools/wasm/basic_template.html index e15b7abe..a3265fdb 100644 --- a/tools/wasm/basic_template.html +++ b/tools/wasm/basic_template.html @@ -7,70 +7,34 @@ Emscripten-Generated Code - - - + {{{ SCRIPT }}} From 2caca2a995a979bd4f2c34efaff43cefb354459a Mon Sep 17 00:00:00 2001 From: Moros Smith Date: Thu, 22 May 2025 22:24:22 -0400 Subject: [PATCH 08/14] replace error-prone javascript resize handling --- olcPixelGameEngine.h | 180 +++++++++++++------------------------------ 1 file changed, 52 insertions(+), 128 deletions(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index be197f11..3996d279 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -7560,128 +7560,16 @@ namespace olc emscripten_set_blur_callback("#canvas", 0, 1, focus_callback); emscripten_set_focus_callback("#canvas", 0, 1, focus_callback); -#pragma warning disable format - EM_ASM(window.onunload = Module._olc_OnPageUnload; ); - - // IMPORTANT! - Sorry About This... - // - // In order to handle certain browser based events, such as resizing and - // going to full screen, we have to effectively inject code into the container - // running the PGE. Yes, I vomited about 11 times too when the others were - // convincing me this is the future. Well, this isnt the future, and if it - // were to be, I want no part of what must be a miserable distopian free - // for all of anarchic code injection to get rudimentary events like "Resize()". - // - // Wake up people! Of course theres a spoon. There has to be to keep feeding - // the giant web baby. - - - EM_ASM({ - - // olc_ApsectRatio - // - // Used by olc_ResizeHandler to calculate the viewport from the - // dimensions of the canvas container's element. - Module.olc_AspectRatio = $0 / $1; - - // HACK ALERT! - // - // Here we assume any html shell that uses 3 or more instance of the class "emscripten" - // is using one of the default or minimal emscripten page layouts - Module.olc_AssumeDefaultShells = (document.querySelectorAll('.emscripten').length >= 3) ? true : false; - - // olc_ResizeHandler - // - // Used by olc_Init, and is called when a resize observer and fullscreenchange event is triggered. - var olc_ResizeHandler = function() - { - // are we in fullscreen mode? - let isFullscreen = (document.fullscreenElement != null); - - // get the width of the containing element - let width = (isFullscreen) ? window.innerWidth : Module.canvas.parentNode.clientWidth; - let height = (isFullscreen) ? window.innerHeight : Module.canvas.parentNode.clientHeight; - - // calculate the expected viewport size - let viewWidth = width; - let viewHeight = width / Module.olc_AspectRatio; - - // if we're taller than the containing element, recalculate based on height - if (viewHeight > height) - { - viewWidth = height * Module.olc_AspectRatio; - viewHeight = height; - } - - // ensure resulting viewport is in integer space - viewWidth = parseInt(viewWidth); - viewHeight = parseInt(viewHeight); - - setTimeout(function() - { - // if default shells, apply default styles - if (Module.olc_AssumeDefaultShells) - Module.canvas.parentNode.setAttribute('style', 'width: 100%; height: 70vh; margin-left: auto; margin-right: auto;'); - - // apply viewport dimensions to the canvas - Module.canvas.setAttribute('width', viewWidth); - Module.canvas.setAttribute('height', viewHeight); - Module.canvas.setAttribute('style', `width: ${viewWidth}px; height: ${viewHeight}px; `); - - // update the PGE window size - Module._olc_PGE_UpdateWindowSize(viewWidth, viewHeight); - - // force focus on our PGE canvas - Module.canvas.focus(); - }, 200); - }; - - - // olc_Init - // - // set up resize observer and fullscreenchange event handler - var olc_Init = function() - { - if (Module.olc_AspectRatio == = undefined) - { - setTimeout(function() { Module.olc_Init(); }, 50); - return; - } - - let resizeObserver = new ResizeObserver(function(entries) - { - Module.olc_ResizeHandler(); - }).observe(Module.canvas.parentNode); - - let mutationObserver = new MutationObserver(function(mutationsList, observer) - { - setTimeout(function() { Module.olc_ResizeHandler(); }, 200); - }).observe(Module.canvas.parentNode, { attributes: false, childList : true, subtree : false }); - - window.addEventListener('fullscreenchange', function(e) - { - setTimeout(function() { Module.olc_ResizeHandler(); }, 200); - }); - }; - - // set up hooks - Module.olc_ResizeHandler = (Module.olc_ResizeHandler != undefined) ? Module.olc_ResizeHandler : olc_ResizeHandler; - Module.olc_Init = (Module.olc_Init != undefined) ? Module.olc_Init : olc_Init; - - // run everything! - Module.olc_Init(); + // Canvas Resize Callbacks + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, resize_callback); + emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, fullscreen_change_callback); + + // trigger resize after a short pause + EM_ASM({ setTimeout(function() { window.dispatchEvent(new Event("resize")); }, 200); }); - }, vWindowSize.x, vWindowSize.y); // Fullscreen and Resize Observers -#pragma warning restore format return olc::rcode::OK; } - // Interface PGE's UpdateWindowSize, for use in Javascript - void UpdateWindowSize(int width, int height) - { - ptrPGE->olc_UpdateWindowSize(width, height); - } - //TY Gorbit static EM_BOOL focus_callback(int eventType, const EmscriptenFocusEvent* focusEvent, void* userData) { @@ -7699,6 +7587,52 @@ namespace olc return 0; } + //TY Moros + static EM_BOOL fullscreen_change_callback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData) + { + // trigger resize after a short pause + EM_ASM({ setTimeout(function() { window.dispatchEvent(new Event("resize")); }, 50); }); + return 0; + } + + //TY Moros + static EM_BOOL resize_callback(int eventType, const EmscriptenUiEvent *event, void *userData) + { + // HACK ALERT! + // + // Here we assume any html shell that uses 3 or more instance of the class "emscripten" + // is using one of the default or minimal emscripten page layouts + static bool assumeDefaultShell = EM_ASM_INT( return (document.querySelectorAll('.emscripten').length >= 3) ? 1 : 0; ); + static bool firstTry = false; + + // we to apply this style once + if(!firstTry && assumeDefaultShell) + { + EM_ASM({ Module.canvas.parentNode.setAttribute('style', 'width: 100%; height: 70vh; margin-left: auto; margin-right: auto;'); }); + firstTry = true; + } + + // get and keep the aspect ratio of the canvas + static double aspect = EM_ASM_DOUBLE( return Module.canvas.clientWidth; ) / EM_ASM_DOUBLE( return Module.canvas.clientHeight; ); + + double parentWidth = EM_ASM_DOUBLE( return (!!document.fullscreenElement) ? window.innerWidth : Module.canvas.parentElement.clientWidth; ); + double parentHeight = EM_ASM_DOUBLE( return (!!document.fullscreenElement) ? window.innerHeight : Module.canvas.parentElement.clientHeight; ); + + double width = parentWidth; + double height = parentWidth / aspect; + + if (height > parentHeight) + { + height = parentHeight; + width = height * aspect; + } + + // resize the canvas + emscripten_set_canvas_element_size("#canvas", static_cast(width), static_cast(height)); + ptrPGE->olc_UpdateWindowSize(static_cast(width), static_cast(height)); + return 0; + } + //TY Moros static EM_BOOL keyboard_callback(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { @@ -7857,16 +7791,6 @@ namespace olc } } -extern "C" -{ - EMSCRIPTEN_KEEPALIVE inline void olc_PGE_UpdateWindowSize(int width, int height) - { - emscripten_set_canvas_element_size("#canvas", width, height); - // Thanks slavka - ((olc::Platform_Emscripten*)olc::platform.get())->UpdateWindowSize(width, height); - } -} - #endif // O------------------------------------------------------------------------------O // | END PLATFORM: Emscripten | From fa8d7947969ad82321d9f4b6fedcc7d881bd841d Mon Sep 17 00:00:00 2001 From: Moros Smith Date: Thu, 22 May 2025 22:36:42 -0400 Subject: [PATCH 09/14] oops, we don't need this... --- olcExampleProgram.html | 7738 ---------------------------------------- 1 file changed, 7738 deletions(-) delete mode 100644 olcExampleProgram.html diff --git a/olcExampleProgram.html b/olcExampleProgram.html deleted file mode 100644 index 3aa46a72..00000000 --- a/olcExampleProgram.html +++ /dev/null @@ -1,7738 +0,0 @@ - - - - - - - - Emscripten-Generated Code - - - - - - - - - From 6057a505f85134691eeb6040523f45a8fd36cd79 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:15:39 +0100 Subject: [PATCH 10/14] gitignore faff --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index dd400cf0..7f12c4ff 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ /.vs /utilities/olcUTIL_AffineView.h /utilities/olcUTIL_Maths.h +/utilities/olcUTIL_GameMode.h +/utilities/olcUTIL_Sparkles.h From 1fb4660eed4a5aae4c71636c15b2cba25a6b518b Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:15:59 +0100 Subject: [PATCH 11/14] Updated Camera2D --- olcPixelGameEngine.h | 4 +++- utilities/olcUTIL_Animate2D.h | 25 +++++++++++++++++++++---- utilities/olcUTIL_Camera2D.h | 19 ++++++++++++++++--- utilities/olcUTIL_Hardware3D.h | 14 +++++++------- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index be197f11..730f0cba 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -4974,6 +4974,8 @@ namespace olc virtual void SetDecalMode(const olc::DecalMode& mode) {} virtual void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) {} virtual void DrawDecal(const olc::DecalInstance& decal) {} + virtual void DoGPUTask(const olc::GPUTask& task) {} + virtual void Set3DProjection(const std::array& mat) {} virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false, const bool clamp = true) { return 1; }; virtual void UpdateTexture(uint32_t id, olc::Sprite* spr) {} virtual void ReadTexture(uint32_t id, olc::Sprite* spr) {} @@ -7642,7 +7644,7 @@ namespace olc // set up resize observer and fullscreenchange event handler var olc_Init = function() { - if (Module.olc_AspectRatio == = undefined) + if (Module.olc_AspectRatio === undefined) { setTimeout(function() { Module.olc_Init(); }, 50); return; diff --git a/utilities/olcUTIL_Animate2D.h b/utilities/olcUTIL_Animate2D.h index a78415d7..d9283af6 100644 --- a/utilities/olcUTIL_Animate2D.h +++ b/utilities/olcUTIL_Animate2D.h @@ -111,10 +111,15 @@ namespace olc::utils::Animate2D public: // Constructs a sequence of frames with a duration and a traversal style inline FrameSequence(const float fFrameDuration = 0.1f, const Style nStyle = Style::Repeat) + { + SetFrameDuration(fFrameDuration); + m_nStyle = nStyle; + } + + inline void SetFrameDuration(const float fFrameDuration = 0.1f) { m_fFrameDuration = fFrameDuration; m_fFrameRate = 1.0f / m_fFrameDuration; - m_nStyle = nStyle; } // Adds a frame to this sequence @@ -126,7 +131,13 @@ namespace olc::utils::Animate2D // Returns a Frame Object for a given time into an animation inline const Frame& GetFrame(const float fTime) const { - return m_vFrames[ConvertTimeToFrame(fTime)]; + size_t frame = ConvertTimeToFrame(fTime); + return m_vFrames[frame]; + } + + inline const bool Complete(const float fTime) const + { + return std::abs(fTime - (m_vFrames.size() * m_fFrameDuration)) < 0.01f; } private: @@ -143,7 +154,10 @@ namespace olc::utils::Animate2D return size_t(fTime * m_fFrameRate) % m_vFrames.size(); break; case Style::OneShot: - return std::clamp(size_t(fTime * m_fFrameRate), size_t(0), m_vFrames.size() - 1); + { + size_t frame = std::clamp(size_t(fTime * m_fFrameRate), size_t(0), m_vFrames.size() - 1); + return frame; + } break; case Style::PingPong: { @@ -167,7 +181,8 @@ namespace olc::utils::Animate2D { private: size_t nIndex = 0; - float fTime = 0.0f; + float fTime = 0.0f; + bool bComplete = false; template friend class Animation; }; @@ -187,6 +202,7 @@ namespace olc::utils::Animate2D { state.fTime = 0.0f; state.nIndex = idx; + state.bComplete = false; return true; } @@ -197,6 +213,7 @@ namespace olc::utils::Animate2D inline void UpdateState(AnimationState& state, const float fElapsedTime) const { state.fTime += fElapsedTime; + state.bComplete = m_vSequences[state.nIndex].Complete(state.fTime); } public: diff --git a/utilities/olcUTIL_Camera2D.h b/utilities/olcUTIL_Camera2D.h index a482b78c..b9aed6b7 100644 --- a/utilities/olcUTIL_Camera2D.h +++ b/utilities/olcUTIL_Camera2D.h @@ -1,5 +1,5 @@ /* - OneLoneCoder - Camera2D v1.00 + OneLoneCoder - Camera2D v1.01 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A 2D world camera with various modes @@ -7,7 +7,7 @@ License (OLC-3) ~~~~~~~~~~~~~~~ - Copyright 2018 - 2022 OneLoneCoder.com + Copyright 2018 - 2025 OneLoneCoder.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -48,7 +48,12 @@ Author ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 + David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024, 2025 + + Version + ~~~~~~~ + + 1.01 +SlideScreens - Prompted by AtomizerZero */ @@ -67,6 +72,7 @@ namespace olc::utils EdgeMove, // Moves as target crosses boundary LazyFollow, // Lazily follows the target FixedScreens, // Moves statically between "screens" + SlideScreens, // MOves statically between "screens" but with a fast transition }; public: @@ -216,6 +222,13 @@ namespace olc::utils m_vPosition = olc::vf2d(olc::vi2d(GetTarget() / m_vScreenSize) * olc::vi2d(m_vScreenSize)) + (m_vViewSize * 0.5f); } break; + + case Mode::SlideScreens: + { + olc::vf2d vScreen = olc::vf2d(olc::vi2d(GetTarget() / m_vScreenSize) * olc::vi2d(m_vScreenSize)) + (m_vViewSize * 0.5f); + m_vPosition += (vScreen - m_vPosition) * m_fLazyFollowRate * 2.0f * fElapsedTime; + } + break; } // Make camera target the middle of the view diff --git a/utilities/olcUTIL_Hardware3D.h b/utilities/olcUTIL_Hardware3D.h index 6eb2a9bd..0ca7b6d1 100644 --- a/utilities/olcUTIL_Hardware3D.h +++ b/utilities/olcUTIL_Hardware3D.h @@ -1267,19 +1267,19 @@ namespace olc::utils::hw3d inline void TurnLeft(const float fSpeed) { fHeading += fSpeed; - if (fHeading >= std::numbers::pi * 2.0f) - fHeading -= std::numbers::pi * 2.0f; + if (fHeading >= float(std::numbers::pi) * 2.0f) + fHeading -= float(std::numbers::pi) * 2.0f; if (fHeading < 0) - fHeading += std::numbers::pi * 2.0f; + fHeading += float(std::numbers::pi) * 2.0f; } inline void TurnRight(const float fSpeed) { fHeading -= fSpeed; - if (fHeading >= std::numbers::pi * 2.0f) - fHeading -= std::numbers::pi * 2.0f; + if (fHeading >= float(std::numbers::pi) * 2.0f) + fHeading -= float(std::numbers::pi) * 2.0f; if(fHeading < 0) - fHeading += std::numbers::pi * 2.0f; + fHeading += float(std::numbers::pi) * 2.0f; } inline void SetHeading(const float fAngle) @@ -1294,7 +1294,7 @@ namespace olc::utils::hw3d } protected: - float fHeading = std::numbers::pi * 0.5; + float fHeading = float(std::numbers::pi) * 0.5; }; From 0b3ccd7423b429500c074934ccb776d24f23822c Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:30:38 +0100 Subject: [PATCH 12/14] Updated contribs & Camera2D Test --- contributions/README.md | 2 + examples/TEST_Camera2D.cpp | 348 +++++++++++++++++++++---------------- 2 files changed, 202 insertions(+), 148 deletions(-) diff --git a/contributions/README.md b/contributions/README.md index c600f20c..244c38cc 100644 --- a/contributions/README.md +++ b/contributions/README.md @@ -23,6 +23,8 @@ These source code contributions enhance the functionality of the olcPixelGameEng * https://github.com/Oso-Grande/olcPGEX_Font * Arc Drawing * https://github.com/AlterEgoIV/olcPGEX_Arc +* Audio/Video Playback + * https://github.com/Piratux/olcPGEX_Media ## MacOS Support * These will potentially be absorbed into main build diff --git a/examples/TEST_Camera2D.cpp b/examples/TEST_Camera2D.cpp index a253c6d9..7844c4ea 100644 --- a/examples/TEST_Camera2D.cpp +++ b/examples/TEST_Camera2D.cpp @@ -1,10 +1,13 @@ /* - Example file for olcUTIL_Camera2D.h + OneLoneCoder - Camera2D v1.01 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + A 2D world camera with various modes + License (OLC-3) ~~~~~~~~~~~~~~~ - Copyright 2018 - 2022 OneLoneCoder.com + Copyright 2018 - 2025 OneLoneCoder.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -45,175 +48,224 @@ Author ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 + David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024, 2025 + + Version + ~~~~~~~ + + 1.01 +SlideScreens - Prompted by AtomizerZero */ -#define OLC_PGE_APPLICATION +#pragma once + #include "olcPixelGameEngine.h" -#define OLC_PGEX_TRANSFORMEDVIEW -#include "extensions/olcPGEX_TransformedView.h" +namespace olc::utils +{ + class Camera2D + { + public: + enum class Mode : uint8_t + { + Simple, // No motion, just directly settable + EdgeMove, // Moves as target crosses boundary + LazyFollow, // Lazily follows the target + FixedScreens, // Moves statically between "screens" + SlideScreens, // MOves statically between "screens" but with a fast transition + }; + + public: + inline Camera2D() : m_pTarget(&m_vLocalTarget) {} + + // Construct a camera with a viewable area size, and an optional starting position + inline Camera2D(const olc::vf2d& vViewSize, const olc::vf2d& vViewPos = { 0.0f, 0.0f }) : m_pTarget(&m_vLocalTarget) + { + m_vViewSize = vViewSize; + m_vViewPos = vViewPos; + } -#include "utilities/olcUTIL_Camera2D.h" + // Set the operational mode of this camera + inline void SetMode(const Mode t) + { + m_nMode = t; + } -/* - To demonstrate the camera, we need a world. In this case its a simle tile - world of 80x75 tiles, and each tile is 32x32 screen pixels. + // Get the operational mode of this camera + inline Mode GetMode() const + { + return m_nMode; + } - A transformed view is used to navigate the world manually via the middle - mouse button in "free roam" mode, or controlled by the camera. + // Get the position of the target being tracked by this camera + inline const olc::vf2d& GetTarget() const + { + return *m_pTarget; + } - Specifically a Tile Transformed View is used, which means all units for - drawing and for the camera are specified in tile space, i.e. 1 tile is - 1x1 units (regardless of pixel size) + // Get the position of the cameras focus point + inline const olc::vf2d& GetPosition() const + { + return m_vPosition; + } - No assets are used for this application, so the world is constructed - out of coloured squares so you can see you are moving through it. + // Get the top left of teh cameras visible area in world space + inline const olc::vf2d& GetViewPosition() const + { + return m_vViewPos; + } - Pressing "TAB" key will swap between "free roam" and "play" modes. In - free roam mode, you can use middle mouse button to pan and zoom around - the world. The camera's visible area to the player is highlighted in red. - In play mode, the camera behaves as it would in a 2D game, depending upon - the selected mode. -*/ + // Get the camera's visible area + inline const olc::vf2d& GetViewSize() const + { + return m_vViewSize; + } -class TEST_Camera2D : public olc::PixelGameEngine -{ -public: - TEST_Camera2D() - { - sAppName = "Camera2D Utility Test"; - } + // Set tracked point via pointer + inline void SetTarget(olc::vf2d& vTarget) + { + m_pTarget = &vTarget; + } + + // Set tracked point via const ref - {10, 35} for example + inline void SetTarget(const olc::vf2d&& vTarget) + { + m_vLocalTarget = vTarget; + m_pTarget = &m_vLocalTarget; + } + + // Set world boundary rectangle + inline void SetWorldBoundary(const olc::vf2d& vPos, const olc::vf2d& vSize) + { + m_vWorldBoundaryPos = vPos; + m_vWorldBoundarySize = vSize; + } + + // Instruct camera to respect world boundaries + inline void EnableWorldBoundary(const bool bEnable) + { + m_bWorldBoundary = bEnable; + } + + // Are we using a world boundary? + inline bool IsWorldBoundaryEnabled() const + { + return m_bWorldBoundary; + } - // Transformed view object to make world offsetting simple - olc::TileTransformedView tv; + // Get the world boundary rectangle position + inline const olc::vf2d& GetWorldBoundaryPosition() const + { + return m_vWorldBoundaryPos; + } - // Conveninet constants to define tile map world - olc::vi2d m_vWorldSize = { 80, 75 }; - olc::vi2d m_vTileSize = { 32, 32 }; + // Get the world boundary rectangle size + inline const olc::vf2d& GetWorldBoundarySize() const + { + return m_vWorldBoundarySize; + } - // The camera! - olc::utils::Camera2D camera; + // Set the velocity at which the lazy follower reaches tracked point + inline void SetLazyFollowRate(const float fRate) + { + m_fLazyFollowRate = fRate; + } - // The point that represents the player, it is "tracked" - // by the camera - olc::vf2d vTrackedPoint; + // Get the velocity at which the lazy follower reaches tracked point + inline float GetLazyFollowRate() const + { + return m_fLazyFollowRate; + } - // Flag whether we are in "free roam" or "play" mode - bool bFreeRoam = false; + // Set distance from tracked point to start nudging screen + inline void SetEdgeTriggerDistance(const olc::vf2d& vEdge) + { + m_vEdgeTriggerDistance = vEdge; + } - // The world map, stored as a 1D array - std::vector vWorldMap; + // Return disance from tracked point that screen will nudge + inline const olc::vf2d& GetEdgeTriggerDistance() const + { + return m_vEdgeTriggerDistance; + } -public: - bool OnUserCreate() override - { - // Construct transform view - tv = olc::TileTransformedView(GetScreenSize(), m_vTileSize); - - // Construct Camera - vTrackedPoint = { 20.0f, 20.0f }; - camera = olc::utils::Camera2D(GetScreenSize() / m_vTileSize, vTrackedPoint); - - // Configure Camera - camera.SetTarget(vTrackedPoint); - camera.SetMode(olc::utils::Camera2D::Mode::Simple); - camera.SetWorldBoundary({ 0.0f, 0.0f }, m_vWorldSize); - camera.EnableWorldBoundary(true); - - // Create "tile map" world with just two tiles - vWorldMap.resize(m_vWorldSize.x * m_vWorldSize.y); - for (int i = 0; i < vWorldMap.size(); i++) - vWorldMap[i] = ((rand() % 20) == 1) ? 1 : 0; - - // Set background colour - Clear(olc::CYAN); - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // In free roam, middle mouse button pans & zooms - if (bFreeRoam) - tv.HandlePanAndZoom(); - - // Handle player "physics" in response to key presses - olc::vf2d vVel = { 0.0f, 0.0f }; - if (GetKey(olc::Key::W).bHeld) vVel += {0, -1}; - if (GetKey(olc::Key::S).bHeld) vVel += {0, +1}; - if (GetKey(olc::Key::A).bHeld) vVel += {-1, 0}; - if (GetKey(olc::Key::D).bHeld) vVel += {+1, 0}; - vTrackedPoint += vVel * 8.0f * fElapsedTime; - - // Switch between "free roam" and "play" mode with TAB key - if (GetKey(olc::Key::TAB).bPressed) - { - // Always setup camera to play mode when tab key pressed - tv.SetWorldOffset(camera.GetViewPosition()); - tv.SetWorldScale(m_vTileSize); - bFreeRoam = !bFreeRoam; - } - - // Switch camera mode in operation - if (GetKey(olc::Key::K1).bPressed) - camera.SetMode(olc::utils::Camera2D::Mode::Simple); - if (GetKey(olc::Key::K2).bPressed) - camera.SetMode(olc::utils::Camera2D::Mode::EdgeMove); - if (GetKey(olc::Key::K3).bPressed) - camera.SetMode(olc::utils::Camera2D::Mode::LazyFollow); - if (GetKey(olc::Key::K4).bPressed) - camera.SetMode(olc::utils::Camera2D::Mode::FixedScreens); - - // Update the camera, if teh tracked object remains visible, - // true is returned - bool bOnScreen = camera.Update(fElapsedTime); - - // In "play" mode, set the transformed view to that required by - // the camera - if (!bFreeRoam) - tv.SetWorldOffset(camera.GetViewPosition()); - - // Render "tile map", by getting visible tiles - olc::vi2d vTileTL = tv.GetTopLeftTile().max({ 0,0 }); - olc::vi2d vTileBR = tv.GetBottomRightTile().min(m_vWorldSize); - olc::vi2d vTile; - // Then looping through them and drawing them - for (vTile.y = vTileTL.y; vTile.y < vTileBR.y; vTile.y++) - for (vTile.x = vTileTL.x; vTile.x < vTileBR.x; vTile.x++) + // Update camera, animating if necessary, obeying world boundary rules + // returns true if target is visible + inline virtual bool Update(const float fElapsedTime) + { + switch (m_nMode) { - int idx = vTile.y * m_vWorldSize.x + vTile.x; - - if (vWorldMap[idx] == 0) - tv.FillRectDecal(vTile, { 1.0f, 1.0f }, olc::Pixel(40, 40, 40)); - - if (vWorldMap[idx] == 1) - tv.FillRectDecal(vTile, { 1.0f, 1.0f }, olc::Pixel(60, 60, 60)); + case Mode::Simple: + { + m_vPosition = GetTarget(); } + break; - // Draw the "player" as a 1x1 cell - tv.FillRectDecal(vTrackedPoint - olc::vf2d(0.5f, 0.5f), {1.0f, 1.0f}, olc::BLUE); + case Mode::EdgeMove: + { + olc::vf2d vOverlap = GetTarget() - m_vPosition; + if (vOverlap.x > m_vEdgeTriggerDistance.x) m_vPosition.x += vOverlap.x - m_vEdgeTriggerDistance.x; + if (vOverlap.x < -m_vEdgeTriggerDistance.x) m_vPosition.x += vOverlap.x + m_vEdgeTriggerDistance.x; + if (vOverlap.y > m_vEdgeTriggerDistance.y) m_vPosition.y += vOverlap.y - m_vEdgeTriggerDistance.y; + if (vOverlap.y < -m_vEdgeTriggerDistance.y) m_vPosition.y += vOverlap.y + m_vEdgeTriggerDistance.y; + } + break; - // Overlay with information - if (bFreeRoam) - { - tv.FillRectDecal(camera.GetViewPosition(), camera.GetViewSize(), olc::PixelF(1.0f, 0.0f, 0.0f, 0.5f)); - DrawStringPropDecal({ 2, 2 }, "TAB: Free Mode, M-Btn to Pan & Zoom", olc::YELLOW); - } - else - DrawStringPropDecal({ 2,2 }, "TAB: Play Mode", olc::YELLOW); + case Mode::LazyFollow: + { + m_vPosition += (GetTarget() - m_vPosition) * m_fLazyFollowRate * fElapsedTime; + } + break; - DrawStringPropDecal({ 2,12 }, "WASD : Move", olc::YELLOW); - DrawStringPropDecal({ 2,22 }, "CAMERA: 1) Simple 2) EdgeMove 3) LazyFollow 4) Screens", olc::YELLOW); - DrawStringPropDecal({ 2,42 }, vTrackedPoint.str(), olc::YELLOW); - return true; - } -}; + case Mode::FixedScreens: + { + m_vPosition = olc::vf2d(olc::vi2d(GetTarget() / m_vScreenSize) * olc::vi2d(m_vScreenSize)) + (m_vViewSize * 0.5f); + } + break; -int main() -{ - TEST_Camera2D demo; - if (demo.Construct(512, 480, 2, 2)) - demo.Start(); - return 0; + case Mode::SlideScreens: + { + olc::vf2d vScreen = olc::vf2d(olc::vi2d(GetTarget() / m_vScreenSize) * olc::vi2d(m_vScreenSize)) + (m_vViewSize * 0.5f); + m_vPosition += (vScreen - m_vPosition) * m_fLazyFollowRate * 2.0f * fElapsedTime; + } + break; + } + + // Make camera target the middle of the view + m_vViewPos = m_vPosition - (m_vViewSize * 0.5f); + + // Clamp to World Boundary (if in place) + if (m_bWorldBoundary) + { + m_vViewPos = m_vViewPos.max(m_vWorldBoundaryPos).min(m_vWorldBoundaryPos + m_vWorldBoundarySize - m_vViewSize); + } + + return GetTarget().x >= m_vViewPos.x && GetTarget().x < (m_vViewPos.x + m_vViewSize.x) && + GetTarget().y >= m_vViewPos.y && GetTarget().y < (m_vViewPos.y + m_vViewSize.y); + } + + protected: + // Position of camera focus point in the world + olc::vf2d m_vPosition; + // Rectangular size of camera viewing area + olc::vf2d m_vViewSize; + // Top left coordinate of camera viewing area + olc::vf2d m_vViewPos; + // Camera movement mode + Mode m_nMode = Mode::Simple; + + // Target Vector2D object camera should follow (either ref or ptr) + olc::vf2d* m_pTarget = nullptr; + olc::vf2d m_vLocalTarget; + + // World Boundary + bool m_bWorldBoundary = false; + olc::vf2d m_vWorldBoundaryPos = { 0.0f, 0.0f }; + olc::vf2d m_vWorldBoundarySize = { 256.0f, 240.0f }; + + // Mode specific + olc::vf2d m_vEdgeTriggerDistance = { 1.0f, 1.0f }; + float m_fLazyFollowRate = 4.0f; + olc::vi2d m_vScreenSize = { 16,15 }; + }; } \ No newline at end of file From fabe3e938e6f03de443e1a0e21d36e444f51c7b7 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:38:07 +0100 Subject: [PATCH 13/14] Bugfix from ya0guang #368 Related Work Items: #3 --- examples/TEST_Animate2D.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/TEST_Animate2D.cpp b/examples/TEST_Animate2D.cpp index 94197fa6..daa92daf 100644 --- a/examples/TEST_Animate2D.cpp +++ b/examples/TEST_Animate2D.cpp @@ -4,7 +4,7 @@ License (OLC-3) ~~~~~~~~~~~~~~~ - Copyright 2018 - 2022 OneLoneCoder.com + Copyright 2018 - 2025 OneLoneCoder.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -45,7 +45,10 @@ Author ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 + David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024, 2025 + + Version + 1.01 BugFix - Thanks ya0guang! */ @@ -240,7 +243,7 @@ class TEST_Animate2D : public olc::PixelGameEngine // If walk off screen, wrap around to other side if (dude.pos.x > ScreenWidth()) dude.pos.x -= ScreenWidth(); - if (dude.pos.y > ScreenHeight()) dude.pos.x -= ScreenHeight(); + if (dude.pos.y > ScreenHeight()) dude.pos.y -= ScreenHeight(); if (dude.pos.x < 0) dude.pos.x += ScreenWidth(); if (dude.pos.y < 0) dude.pos.y += ScreenHeight(); From a48249fa12763436ab81f222a845245a2a38a6af Mon Sep 17 00:00:00 2001 From: Gusgo99 Date: Wed, 11 Jun 2025 23:57:24 -0300 Subject: [PATCH 14/14] Removes call to std::unique_ptr::release that discards the returned pointer. This caused a leak when a Renderable which already has an image loaded tries to load an image, but fails to do so. --- olcPixelGameEngine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index cf4c13d7..84b32286 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -2147,7 +2147,6 @@ namespace olc } else { - pSprite.release(); pSprite = nullptr; return olc::rcode::NO_FILE; }