From 7fd9f27c46c73a3f6fe59e587d3d1a2802b9884f Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Sun, 21 Mar 2021 18:58:45 +0000 Subject: [PATCH] PGE v2.15 - WASM --- olcPixelGameEngine.h | 1604 +++++++++++++++++++++++++++--------------- 1 file changed, 1019 insertions(+), 585 deletions(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index db074ee..c4d1bef 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -1,8 +1,9 @@ +#pragma region license_and_help /* olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.14 | + | OneLoneCoder Pixel Game Engine v2.15 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -67,6 +68,8 @@ Patreon: https://www.patreon.com/javidx9 Community: https://community.onelonecoder.com + + Compiling in Linux ~~~~~~~~~~~~~~~~~~ You will need a modern C++ compiler, so update yours! @@ -81,6 +84,7 @@ vblank_mode=0 ./YourProgName + Compiling in Code::Blocks on Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Well I wont judge you, but make sure your Code::Blocks installation @@ -98,6 +102,8 @@ Set these compiler options: -std=c++17 + + Compiling on Mac - EXPERIMENTAL! PROBABLY HAS BUGS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Yes yes, people use Macs for C++ programming! Who knew? Anyway, enough @@ -107,6 +113,18 @@ clang++ -arch x86_64 -std=c++17 -mmacosx-version-min=10.15 -Wall -framework OpenGL -framework GLUT -lpng YourSource.cpp -o YourProgName + + + Compiling with Emscripten (New & Experimental) + ~~~~~~~~~~~~~~~~~~~~~~~~~ + Emscripten compiler will turn your awesome C++ PixelGameEngine project into WASM! + This means you can run your application in teh browser, great for distributing + and submission in to jams and things! It's a bit new at the moment. + + em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 ./YourSource.cpp -o pge.html + + + Using stb_image.h ~~~~~~~~~~~~~~~~~ The PGE will load png images by default (with help from libpng on non-windows systems). @@ -119,6 +137,25 @@ Before including the olcPixelGameEngine.h header file. stb_image.h works on many systems and can be downloaded here: https://github.com/nothings/stb/blob/master/stb_image.h + + + Multiple cpp file projects? + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + As a single header solution, the OLC_PGE_APPLICATION definition is used to + insert the engine implementation at a project location of your choosing. + The simplest way to setup multifile projects is to create a file called + "olcPixelGameEngine.cpp" which includes the following: + + #define OLC_PGE_APPLICATION + #include "olcPixelGameEngine.h" + + That's all it should include. You can also include PGEX includes and + defines in here too. With this in place, you dont need to + #define OLC_PGE_APPLICATION anywhere, and can simply include this + header file as an when you need to. + + + Ports ~~~~~ olc::PixelGameEngine has been ported and tested with varying degrees of @@ -126,17 +163,19 @@ Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are interested in the details of these ports, come and visit the Discord! + + Thanks ~~~~~~ - I'd like to extend thanks to Bispoo, Eremiell, slavka, gurkanctn, Phantim, IProgramInCPP - JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice, dandistine - Ralakus, Gorbit99, raoul, joshinils, benedani, Moros1138, Alexio, SaladinAkara & MagetzUb - for advice, ideas and testing, and I'd like to extend my appreciation to the - 210K YouTube followers, 80+ Patreons and 10K Discord server members who give me + I'd like to extend thanks to Ian McKay, Bispoo, Eremiell, slavka, gurkanctn, Phantim, + IProgramInCPP, JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice, + dandistine, Ralakus, Gorbit99, raoul, joshinils, benedani, Moros1138, Alexio, SaladinAkara + & MagetzUb for advice, ideas and testing, and I'd like to extend my appreciation to the + 230K YouTube followers, 80+ Patreons and 10K Discord server members who give me the motivation to keep going with all this :D Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka, - @Dragoneye, @Gorbit99 & @Mumflr + @Dragoneye, @Gorbit99, @dandistine & @Mumflr Special thanks to those who bring gifts! GnarGnarHead.......Domina @@ -150,10 +189,16 @@ Special thanks to my Patreons too - I wont name you on here, but I've certainly enjoyed my tea and flapjacks :D + + Author ~~~~~~ David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020, 2021 +*/ +#pragma endregion +#pragma region version_history +/* 2.01: Made renderer and platform static for multifile projects 2.02: Added Decal destructor, optimised Pixel constructor 2.03: Added FreeBSD flags, Added DrawStringDecal() @@ -213,14 +258,23 @@ 2.14: Fix WIN32 Definition reshuffle Fix DrawPartialDecal() - messed up dimension during renderer experiment, didnt remove junk code, thanks Alexio Fix? Strange error regarding GDI+ Image Loader not knowing about COM, SDK change? + 2.15: Big Reformat + +WASM Platform (via Emscripten) - Big Thanks to OLC Community - See Platform for details + +Sample Mode for Decals + +Made olc_ConfigureSystem() accessible + +Added OLC_----_CUSTOM_EX for externalised platforms, renderers and image loaders + =Refactored olc::Sprite pixel data store + -Deprecating LoadFromPGESprFile() + -Deprecating SaveToPGESprFile() + Fix Pixel -= operator (thanks Au Lit) + !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! !! Volunteers willing to help appreciated, though PRs are manually integrated with credit !! */ +#pragma endregion -////////////////////////////////////////////////////////////////////////////////////////// - - +#pragma region hello_world_example // O------------------------------------------------------------------------------O // | Example "Hello World" Program (main.cpp) | // O------------------------------------------------------------------------------O @@ -265,10 +319,12 @@ int main() } */ +#pragma endregion #ifndef OLC_PGE_DEF #define OLC_PGE_DEF +#pragma region std_includes // O------------------------------------------------------------------------------O // | STANDARD INCLUDES | // O------------------------------------------------------------------------------O @@ -289,45 +345,42 @@ int main() #include #include #include +#pragma endregion -#define PGE_VER 214 +#define PGE_VER 215 // O------------------------------------------------------------------------------O // | COMPILER CONFIGURATION ODDITIES | // O------------------------------------------------------------------------------O +#pragma region compiler_config #define USE_EXPERIMENTAL_FS - #if defined(_WIN32) -#if _MSC_VER >= 1920 && _MSVC_LANG >= 201703L -#undef USE_EXPERIMENTAL_FS + #if _MSC_VER >= 1920 && _MSVC_LANG >= 201703L + #undef USE_EXPERIMENTAL_FS + #endif #endif -#endif - #if defined(__linux__) || defined(__MINGW32__) || defined(__EMSCRIPTEN__) || defined(__FreeBSD__) || defined(__APPLE__) -#if __cplusplus >= 201703L -#undef USE_EXPERIMENTAL_FS -#endif + #if __cplusplus >= 201703L + #undef USE_EXPERIMENTAL_FS + #endif #endif -#if defined(__APPLE__) -#define PGE_USE_CUSTOM_START -#endif #if defined(USE_EXPERIMENTAL_FS) || defined(FORCE_EXPERIMENTAL_FS) // C++14 -#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING -#include -namespace _gfs = std::experimental::filesystem::v1; + #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING + #include + namespace _gfs = std::experimental::filesystem::v1; #else // C++17 -#include -namespace _gfs = std::filesystem; + #include + namespace _gfs = std::filesystem; #endif #if defined(UNICODE) || defined(_UNICODE) -#define olcT(s) L##s + #define olcT(s) L##s #else -#define olcT(s) s + #define olcT(s) s #endif #define UNUSED(x) (void)(x) @@ -337,31 +390,50 @@ namespace _gfs = std::filesystem; // O------------------------------------------------------------------------------O // Platform -#if !defined(OLC_PLATFORM_WINAPI) && !defined(OLC_PLATFORM_X11) && !defined(OLC_PLATFORM_GLUT) -#if defined(_WIN32) -#define OLC_PLATFORM_WINAPI -#endif -#if defined(__linux__) || defined(__FreeBSD__) -#define OLC_PLATFORM_X11 -#endif -#if defined(__APPLE__) -#define OLC_PLATFORM_GLUT +#if !defined(OLC_PLATFORM_WINAPI) && !defined(OLC_PLATFORM_X11) && !defined(OLC_PLATFORM_GLUT) && !defined(OLC_PLATFORM_EMSCRIPTEN) + #if !defined(OLC_PLATFORM_CUSTOM_EX) + #if defined(_WIN32) + #define OLC_PLATFORM_WINAPI + #endif + #if defined(__linux__) || defined(__FreeBSD__) + #define OLC_PLATFORM_X11 + #endif + #if defined(__APPLE__) + #define GL_SILENCE_DEPRECATION + #define OLC_PLATFORM_GLUT + #endif + #if defined(__EMSCRIPTEN__) + #define OLC_PLATFORM_EMSCRIPTEN + #endif + #endif #endif + +// Start Situation +#if defined(OLC_PLATFORM_GLUT) || defined(OLC_PLATFORM_EMSCRIPTEN) + #define PGE_USE_CUSTOM_START #endif // Renderer #if !defined(OLC_GFX_OPENGL10) && !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) -#define OLC_GFX_OPENGL10 + #if !defined(OLC_GFX_CUSTOM_EX) + #if defined(OLC_PLATFORM_EMSCRIPTEN) + #define OLC_GFX_OPENGL33 + #else + #define OLC_GFX_OPENGL10 + #endif + #endif #endif // Image loader #if !defined(OLC_IMAGE_STB) && !defined(OLC_IMAGE_GDI) && !defined(OLC_IMAGE_LIBPNG) -#if defined(_WIN32) -#define OLC_IMAGE_GDI -#endif -#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) -#define OLC_IMAGE_LIBPNG -#endif + #if !defined(OLC_IMAGE_CUSTOM_EX) + #if defined(_WIN32) + #define OLC_IMAGE_GDI + #endif + #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__) + #define OLC_IMAGE_LIBPNG + #endif + #endif #endif @@ -369,55 +441,50 @@ namespace _gfs = std::filesystem; // | PLATFORM-SPECIFIC DEPENDENCIES | // O------------------------------------------------------------------------------O #if defined(OLC_PLATFORM_WINAPI) -#define _WINSOCKAPI_ // Thanks Cornchipss - -//#if !defined(WIN32_LEAN_AND_MEAN) // Removes something GDI requires -// #define WIN32_LEAN_AND_MEAN -//#endif -#if !defined(VC_EXTRALEAN) -#define VC_EXTRALEAN -#endif -#if !defined(NOMINMAX) -#define NOMINMAX -#endif - -// In Code::Blocks -#if !defined(_WIN32_WINNT) -#ifdef HAVE_MSMF -#define _WIN32_WINNT 0x0600 // Windows Vista -#else -#define _WIN32_WINNT 0x0500 // Windows 2000 -#endif -#endif - -#include - -#undef _WINSOCKAPI_ + #define _WINSOCKAPI_ // Thanks Cornchipss + #if !defined(VC_EXTRALEAN) + #define VC_EXTRALEAN + #endif + #if !defined(NOMINMAX) + #define NOMINMAX + #endif + + // In Code::Blocks + #if !defined(_WIN32_WINNT) + #ifdef HAVE_MSMF + #define _WIN32_WINNT 0x0600 // Windows Vista + #else + #define _WIN32_WINNT 0x0500 // Windows 2000 + #endif + #endif + + #include + #undef _WINSOCKAPI_ #endif #if defined(OLC_PLATFORM_X11) -namespace X11 -{ -#include -#include -} + namespace X11 + { + #include + #include + } #endif #if defined(OLC_PLATFORM_GLUT) -#define PGE_USE_CUSTOM_START -#if defined(__linux__) -#include -#include -#endif -#if defined(__APPLE__) -#include -#endif + #if defined(__linux__) + #include + #include + #endif + #if defined(__APPLE__) + #include + #endif #endif - +#pragma endregion // O------------------------------------------------------------------------------O // | olcPixelGameEngine INTERFACE DECLARATION | // O------------------------------------------------------------------------------O +#pragma region pge_declaration namespace olc { class PixelGameEngine; @@ -494,6 +561,17 @@ namespace olc CAPS_LOCK, ENUM_END }; + // O------------------------------------------------------------------------------O + // | olc::HWButton - Represents the state of a hardware button (mouse/key/joy) | + // O------------------------------------------------------------------------------O + struct HWButton + { + bool bPressed = false; // Set once during the frame the event occurs + bool bReleased = false; // Set once during the frame the event occurs + bool bHeld = false; // Set true for all frames between pressed and released events + }; + + // O------------------------------------------------------------------------------O @@ -545,39 +623,23 @@ namespace olc // Note: joshinils has some good suggestions here, but they are complicated to implement at this moment, // however they will appear in a future version of PGE template inline v2d_generic operator * (const float& lhs, const v2d_generic& rhs) - { - return v2d_generic((T)(lhs * (float)rhs.x), (T)(lhs * (float)rhs.y)); - } + { return v2d_generic((T)(lhs * (float)rhs.x), (T)(lhs * (float)rhs.y)); } template inline v2d_generic operator * (const double& lhs, const v2d_generic& rhs) - { - return v2d_generic((T)(lhs * (double)rhs.x), (T)(lhs * (double)rhs.y)); - } + { return v2d_generic((T)(lhs * (double)rhs.x), (T)(lhs * (double)rhs.y)); } template inline v2d_generic operator * (const int& lhs, const v2d_generic& rhs) - { - return v2d_generic((T)(lhs * (int)rhs.x), (T)(lhs * (int)rhs.y)); - } + { return v2d_generic((T)(lhs * (int)rhs.x), (T)(lhs * (int)rhs.y)); } template inline v2d_generic operator / (const float& lhs, const v2d_generic& rhs) - { - return v2d_generic((T)(lhs / (float)rhs.x), (T)(lhs / (float)rhs.y)); - } + { return v2d_generic((T)(lhs / (float)rhs.x), (T)(lhs / (float)rhs.y)); } template inline v2d_generic operator / (const double& lhs, const v2d_generic& rhs) - { - return v2d_generic((T)(lhs / (double)rhs.x), (T)(lhs / (double)rhs.y)); - } + { return v2d_generic((T)(lhs / (double)rhs.x), (T)(lhs / (double)rhs.y)); } template inline v2d_generic operator / (const int& lhs, const v2d_generic& rhs) - { - return v2d_generic((T)(lhs / (int)rhs.x), (T)(lhs / (int)rhs.y)); - } + { return v2d_generic((T)(lhs / (int)rhs.x), (T)(lhs / (int)rhs.y)); } // To stop dandistine crying... template inline bool operator < (const v2d_generic& lhs, const v2d_generic& rhs) - { - return lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x < rhs.x); - } + { return lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x < rhs.x); } template inline bool operator > (const v2d_generic& lhs, const v2d_generic& rhs) - { - return lhs.y > rhs.y || (lhs.y == rhs.y && lhs.x > rhs.x); - } + { return lhs.y > rhs.y || (lhs.y == rhs.y && lhs.x > rhs.x); } typedef v2d_generic vi2d; typedef v2d_generic vu2d; @@ -587,16 +649,7 @@ namespace olc - // O------------------------------------------------------------------------------O - // | olc::HWButton - Represents the state of a hardware button (mouse/key/joy) | - // O------------------------------------------------------------------------------O - struct HWButton - { - bool bPressed = false; // Set once during the frame the event occurs - bool bReleased = false; // Set once during the frame the event occurs - bool bHeld = false; // Set true for all frames between pressed and released events - }; - + // O------------------------------------------------------------------------------O @@ -671,7 +724,7 @@ namespace olc Pixel* GetData(); olc::Sprite* Duplicate(); olc::Sprite* Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize); - Pixel* pColData = nullptr; + std::vector pColData; Mode modeSample = Mode::NORMAL; static std::unique_ptr loader; @@ -683,7 +736,7 @@ namespace olc class Decal { public: - Decal(olc::Sprite* spr, bool filter = false); + Decal(olc::Sprite* spr, bool filter = false, bool clamp = true); Decal(const uint32_t nExistingTextureResource, olc::Sprite* spr); virtual ~Decal(); void Update(); @@ -712,8 +765,8 @@ namespace olc { public: Renderable() = default; - olc::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr, bool filter = false); - void Create(uint32_t width, uint32_t height, bool filter = false); + olc::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr, bool filter = false, bool clamp = true); + void Create(uint32_t width, uint32_t height, bool filter = false, bool clamp = true); olc::Decal* Decal() const; olc::Sprite* Sprite() const; @@ -763,7 +816,7 @@ namespace olc virtual void SetDecalMode(const olc::DecalMode& mode) = 0; virtual void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) = 0; virtual void DrawDecal(const olc::DecalInstance& decal) = 0; - virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false) = 0; + virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false, const bool clamp = true) = 0; virtual void UpdateTexture(uint32_t id, olc::Sprite* spr) = 0; virtual void ReadTexture(uint32_t id, olc::Sprite* spr) = 0; virtual uint32_t DeleteTexture(const uint32_t id) = 0; @@ -791,8 +844,7 @@ namespace olc class PGEX; - - + // The Static Twins (plus one) static std::unique_ptr renderer; static std::unique_ptr platform; static std::map mapKeys; @@ -922,6 +974,14 @@ namespace olc // selected area is (ox,oy) to (ox+w,oy+h) void DrawPartialSprite(int32_t x, int32_t y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); void DrawPartialSprite(const olc::vi2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); + // Draws a single line of text - traditional monospaced + void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + olc::vi2d GetTextSize(const std::string& s); + // Draws a single line of text - non-monospaced + void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + void DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + olc::vi2d GetTextSizeProp(const std::string& s); // Decal Quad functions void SetDecalMode(const olc::DecalMode& mode); @@ -952,16 +1012,7 @@ namespace olc void GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR); // Draws an arbitrary convex textured polygon using GPU void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint = olc::WHITE); - // Draws a single line of text - traditional monospaced - void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); - void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); - olc::vi2d GetTextSize(const std::string& s); - - // Draws a single line of text - non-monospaced - void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); - void DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); - olc::vi2d GetTextSizeProp(const std::string& s); - + // Clears entire draw target to Pixel void Clear(Pixel p); // Clears the rendering back buffer @@ -973,7 +1024,7 @@ namespace olc std::string sAppName; private: // Inner mysterious workings - Sprite* pDrawTarget = nullptr; + Sprite* pDrawTarget = nullptr; Pixel::Mode nPixelMode = Pixel::NORMAL; float fBlendFactor = 1.0f; olc::vi2d vScreenSize = { 256, 240 }; @@ -996,9 +1047,9 @@ namespace olc float fFrameTimer = 1.0f; float fLastElapsed = 0.0f; int nFrameCount = 0; - Sprite* fontSprite = nullptr; - Decal* fontDecal = nullptr; - Sprite* pDefaultDrawTarget = nullptr; + Sprite* fontSprite = nullptr; + Decal* fontDecal = nullptr; + Sprite* pDefaultDrawTarget = nullptr; std::vector vLayers; uint8_t nTargetLayer = 0; uint32_t nLastFPS = 0; @@ -1021,9 +1072,6 @@ namespace olc // The main engine thread void EngineThread(); - // At the very end of this file, chooses which - // components to compile - void olc_ConfigureSystem(); // If anything sets this flag to false, the engine // "should" shut down gracefully @@ -1043,6 +1091,12 @@ namespace olc void olc_UpdateMouseFocus(bool state); void olc_UpdateKeyFocus(bool state); void olc_Terminate(); + void olc_Reanimate(); + bool olc_IsRunning(); + + // At the very end of this file, chooses which + // components to compile + virtual void olc_ConfigureSystem(); // NOTE: Items Here are to be deprecated, I have left them in for now // in case you are using them, but they will be removed. @@ -1054,8 +1108,6 @@ namespace olc private: std::vector vExtensions; - - }; @@ -1080,28 +1132,9 @@ namespace olc }; } -#endif // OLC_PGE_DEF +#pragma endregion - - - -/* - Object Oriented Mode - ~~~~~~~~~~~~~~~~~~~~ - - If the olcPixelGameEngine.h is called from several sources it can cause - multiple definitions of objects. To prevent this, ONLY ONE of the pathways - to including this file must have OLC_PGE_APPLICATION defined before it. This prevents - the definitions being duplicated. - - If all else fails, create a file called "olcPixelGameEngine.cpp" with the following - two lines. Then you can just #include "olcPixelGameEngine.h" as normal without worrying - about defining things. Dont forget to include that cpp file as part of your build! - - #define OLC_PGE_APPLICATION - #include "olcPixelGameEngine.h" - -*/ +#endif // OLC_PGE_DEF // O------------------------------------------------------------------------------O @@ -1114,36 +1147,26 @@ namespace olc // | olcPixelGameEngine INTERFACE IMPLEMENTATION (CORE) | // | Note: The core implementation is platform independent | // O------------------------------------------------------------------------------O +#pragma region pge_implementation namespace olc { // O------------------------------------------------------------------------------O // | olc::Pixel IMPLEMENTATION | // O------------------------------------------------------------------------------O Pixel::Pixel() - { - r = 0; g = 0; b = 0; a = nDefaultAlpha; - } + { r = 0; g = 0; b = 0; a = nDefaultAlpha; } Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) - { - n = red | (green << 8) | (blue << 16) | (alpha << 24); - } // Thanks jarekpelczar - + { n = red | (green << 8) | (blue << 16) | (alpha << 24); } // Thanks jarekpelczar Pixel::Pixel(uint32_t p) - { - n = p; - } + { n = p; } bool Pixel::operator==(const Pixel& p) const - { - return n == p.n; - } + { return n == p.n; } bool Pixel::operator!=(const Pixel& p) const - { - return n != p.n; - } + { return n != p.n; } Pixel Pixel::operator * (const float i) const { @@ -1201,11 +1224,11 @@ namespace olc return *this; } - Pixel& Pixel::operator -= (const Pixel& p) + Pixel& Pixel::operator -= (const Pixel& p) // Thanks Au Lit { - this->r = uint8_t(std::min(255, std::max(0, int(r) + int(p.r)))); - this->g = uint8_t(std::min(255, std::max(0, int(g) + int(p.g)))); - this->b = uint8_t(std::min(255, std::max(0, int(b) + int(p.b)))); + this->r = uint8_t(std::min(255, std::max(0, int(r) - int(p.r)))); + this->g = uint8_t(std::min(255, std::max(0, int(g) - int(p.g)))); + this->b = uint8_t(std::min(255, std::max(0, int(b) - int(p.b)))); return *this; } @@ -1218,110 +1241,92 @@ namespace olc } Pixel PixelF(float red, float green, float blue, float alpha) - { - return Pixel(uint8_t(red * 255.0f), uint8_t(green * 255.0f), uint8_t(blue * 255.0f), uint8_t(alpha * 255.0f)); - } + { return Pixel(uint8_t(red * 255.0f), uint8_t(green * 255.0f), uint8_t(blue * 255.0f), uint8_t(alpha * 255.0f)); } Pixel PixelLerp(const olc::Pixel& p1, const olc::Pixel& p2, float t) - { - return (p2 * t) + p1 * (1.0f - t); - } + { return (p2 * t) + p1 * (1.0f - t); } // O------------------------------------------------------------------------------O // | olc::Sprite IMPLEMENTATION | // O------------------------------------------------------------------------------O Sprite::Sprite() - { - pColData = nullptr; width = 0; height = 0; - } + { width = 0; height = 0; } Sprite::Sprite(const std::string& sImageFile, olc::ResourcePack* pack) - { - LoadFromFile(sImageFile, pack); - } + { LoadFromFile(sImageFile, pack); } Sprite::Sprite(int32_t w, int32_t h) - { - if (pColData) delete[] pColData; + { width = w; height = h; - pColData = new Pixel[width * height]; - for (int32_t i = 0; i < width * height; i++) - pColData[i] = Pixel(); + pColData.resize(width * height); + pColData.resize(width * height, nDefaultPixel); } Sprite::~Sprite() - { - if (pColData) delete[] pColData; - } - - - olc::rcode Sprite::LoadFromPGESprFile(const std::string& sImageFile, olc::ResourcePack* pack) - { - if (pColData) delete[] pColData; - auto ReadData = [&](std::istream& is) - { - is.read((char*)&width, sizeof(int32_t)); - is.read((char*)&height, sizeof(int32_t)); - pColData = new Pixel[width * height]; - is.read((char*)pColData, (size_t)width * (size_t)height * sizeof(uint32_t)); - }; - - // These are essentially Memory Surfaces represented by olc::Sprite - // which load very fast, but are completely uncompressed - if (pack == nullptr) - { - std::ifstream ifs; - ifs.open(sImageFile, std::ifstream::binary); - if (ifs.is_open()) - { - ReadData(ifs); - return olc::OK; - } - else - return olc::FAIL; - } - else - { - ResourceBuffer rb = pack->GetFileBuffer(sImageFile); - std::istream is(&rb); - ReadData(is); - return olc::OK; - } - return olc::FAIL; - } - - olc::rcode Sprite::SaveToPGESprFile(const std::string& sImageFile) - { - if (pColData == nullptr) return olc::FAIL; - - std::ofstream ofs; - ofs.open(sImageFile, std::ifstream::binary); - if (ofs.is_open()) - { - ofs.write((char*)&width, sizeof(int32_t)); - ofs.write((char*)&height, sizeof(int32_t)); - ofs.write((char*)pColData, (size_t)width * (size_t)height * sizeof(uint32_t)); - ofs.close(); - return olc::OK; - } - - return olc::FAIL; - } + { pColData.clear(); } + + // To Be Deprecated + //olc::rcode Sprite::LoadFromPGESprFile(const std::string& sImageFile, olc::ResourcePack* pack) + //{ + // if (pColData) delete[] pColData; + // auto ReadData = [&](std::istream& is) + // { + // is.read((char*)&width, sizeof(int32_t)); + // is.read((char*)&height, sizeof(int32_t)); + // pColData = new Pixel[width * height]; + // is.read((char*)pColData, (size_t)width * (size_t)height * sizeof(uint32_t)); + // }; + + // // These are essentially Memory Surfaces represented by olc::Sprite + // // which load very fast, but are completely uncompressed + // if (pack == nullptr) + // { + // std::ifstream ifs; + // ifs.open(sImageFile, std::ifstream::binary); + // if (ifs.is_open()) + // { + // ReadData(ifs); + // return olc::OK; + // } + // else + // return olc::FAIL; + // } + // else + // { + // ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + // std::istream is(&rb); + // ReadData(is); + // return olc::OK; + // } + // return olc::FAIL; + //} + + //olc::rcode Sprite::SaveToPGESprFile(const std::string& sImageFile) + //{ + // if (pColData == nullptr) return olc::FAIL; + + // std::ofstream ofs; + // ofs.open(sImageFile, std::ifstream::binary); + // if (ofs.is_open()) + // { + // ofs.write((char*)&width, sizeof(int32_t)); + // ofs.write((char*)&height, sizeof(int32_t)); + // ofs.write((char*)pColData, std::streamsize(width) * std::streamsize(height) * sizeof(uint32_t)); + // ofs.close(); + // return olc::OK; + // } + + // return olc::FAIL; + //} void Sprite::SetSampleMode(olc::Sprite::Mode mode) - { - modeSample = mode; - } + { modeSample = mode; } Pixel Sprite::GetPixel(const olc::vi2d& a) const - { - return GetPixel(a.x, a.y); - } + { return GetPixel(a.x, a.y); } bool Sprite::SetPixel(const olc::vi2d& a, Pixel p) - { - return SetPixel(a.x, a.y, p); - } + { return SetPixel(a.x, a.y, p); } Pixel Sprite::GetPixel(int32_t x, int32_t y) const { @@ -1379,9 +1384,7 @@ namespace olc } Pixel* Sprite::GetData() - { - return pColData; - } + { return pColData.data(); } olc::rcode Sprite::LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack) @@ -1408,14 +1411,14 @@ namespace olc } // O------------------------------------------------------------------------------O - // | olc::Decal IMPLEMENTATION | + // | olc::Decal IMPLEMENTATION | // O------------------------------------------------------------------------------O - Decal::Decal(olc::Sprite* spr, bool filter) + Decal::Decal(olc::Sprite* spr, bool filter, bool clamp) { id = -1; if (spr == nullptr) return; sprite = spr; - id = renderer->CreateTexture(sprite->width, sprite->height, filter); + id = renderer->CreateTexture(sprite->width, sprite->height, filter, clamp); Update(); } @@ -1449,18 +1452,18 @@ namespace olc } } - void Renderable::Create(uint32_t width, uint32_t height, bool filter) + void Renderable::Create(uint32_t width, uint32_t height, bool filter, bool clamp) { pSprite = std::make_unique(width, height); - pDecal = std::make_unique(pSprite.get(), filter); + pDecal = std::make_unique(pSprite.get(), filter, clamp); } - olc::rcode Renderable::Load(const std::string& sFile, ResourcePack* pack, bool filter) + olc::rcode Renderable::Load(const std::string& sFile, ResourcePack* pack, bool filter, bool clamp) { pSprite = std::make_unique(); if (pSprite->LoadFromFile(sFile, pack) == olc::rcode::OK) { - pDecal = std::make_unique(pSprite.get(), filter); + pDecal = std::make_unique(pSprite.get(), filter, clamp); return olc::rcode::OK; } else @@ -1472,14 +1475,10 @@ namespace olc } olc::Decal* Renderable::Decal() const - { - return pDecal.get(); - } + { return pDecal.get(); } olc::Sprite* Renderable::Sprite() const - { - return pSprite.get(); - } + { return pSprite.get(); } // O------------------------------------------------------------------------------O // | olc::ResourcePack IMPLEMENTATION | @@ -1535,11 +1534,7 @@ namespace olc pos += size; }; - auto get = [&read]() -> int { - char c; - read(&c, 1); - return c; - }; + auto get = [&read]() -> int { char c; read(&c, 1); return c; }; // 2) Read Map uint32_t nMapEntries = 0; @@ -1639,14 +1634,10 @@ namespace olc } ResourceBuffer ResourcePack::GetFileBuffer(const std::string& sFile) - { - return ResourceBuffer(baseFile, mapFiles[sFile].nOffset, mapFiles[sFile].nSize); - } + { return ResourceBuffer(baseFile, mapFiles[sFile].nOffset, mapFiles[sFile].nSize); } bool ResourcePack::Loaded() - { - return baseFile.is_open(); - } + { return baseFile.is_open(); } std::vector ResourcePack::scramble(const std::vector& data, const std::string& key) { @@ -1694,8 +1685,6 @@ namespace olc if (vPixelSize.x <= 0 || vPixelSize.y <= 0 || vScreenSize.x <= 0 || vScreenSize.y <= 0) return olc::FAIL; - - return olc::OK; } @@ -1711,7 +1700,6 @@ namespace olc layer.bUpdate = true; } SetDrawTarget(nullptr); - renderer->ClearBuffer(olc::BLACK, true); renderer->DisplayFrame(); renderer->ClearBuffer(olc::BLACK, true); @@ -1767,44 +1755,28 @@ namespace olc } void PixelGameEngine::EnableLayer(uint8_t layer, bool b) - { - if (layer < vLayers.size()) vLayers[layer].bShow = b; - } + { if (layer < vLayers.size()) vLayers[layer].bShow = b; } void PixelGameEngine::SetLayerOffset(uint8_t layer, const olc::vf2d& offset) - { - SetLayerOffset(layer, offset.x, offset.y); - } + { SetLayerOffset(layer, offset.x, offset.y); } void PixelGameEngine::SetLayerOffset(uint8_t layer, float x, float y) - { - if (layer < vLayers.size()) vLayers[layer].vOffset = { x, y }; - } + { if (layer < vLayers.size()) vLayers[layer].vOffset = { x, y }; } void PixelGameEngine::SetLayerScale(uint8_t layer, const olc::vf2d& scale) - { - SetLayerScale(layer, scale.x, scale.y); - } + { SetLayerScale(layer, scale.x, scale.y); } void PixelGameEngine::SetLayerScale(uint8_t layer, float x, float y) - { - if (layer < vLayers.size()) vLayers[layer].vScale = { x, y }; - } + { if (layer < vLayers.size()) vLayers[layer].vScale = { x, y }; } void PixelGameEngine::SetLayerTint(uint8_t layer, const olc::Pixel& tint) - { - if (layer < vLayers.size()) vLayers[layer].tint = tint; - } + { if (layer < vLayers.size()) vLayers[layer].tint = tint; } void PixelGameEngine::SetLayerCustomRenderFunction(uint8_t layer, std::function f) - { - if (layer < vLayers.size()) vLayers[layer].funcHook = f; - } + { if (layer < vLayers.size()) vLayers[layer].funcHook = f; } std::vector& PixelGameEngine::GetLayers() - { - return vLayers; - } + { return vLayers; } uint32_t PixelGameEngine::CreateLayer() { @@ -1817,9 +1789,7 @@ namespace olc } Sprite* PixelGameEngine::GetDrawTarget() const - { - return pDrawTarget; - } + { return pDrawTarget; } int32_t PixelGameEngine::GetDrawTargetWidth() const { @@ -1838,85 +1808,52 @@ namespace olc } uint32_t PixelGameEngine::GetFPS() const - { - return nLastFPS; - } + { return nLastFPS; } bool PixelGameEngine::IsFocused() const - { - return bHasInputFocus; - } + { return bHasInputFocus; } HWButton PixelGameEngine::GetKey(Key k) const - { - return pKeyboardState[k]; - } + { return pKeyboardState[k]; } HWButton PixelGameEngine::GetMouse(uint32_t b) const - { - return pMouseState[b]; - } + { return pMouseState[b]; } int32_t PixelGameEngine::GetMouseX() const - { - return vMousePos.x; - } + { return vMousePos.x; } int32_t PixelGameEngine::GetMouseY() const - { - return vMousePos.y; - } + { return vMousePos.y; } const olc::vi2d& PixelGameEngine::GetMousePos() const - { - return vMousePos; - } + { return vMousePos; } int32_t PixelGameEngine::GetMouseWheel() const - { - return nMouseWheelDelta; - } + { return nMouseWheelDelta; } int32_t PixelGameEngine::ScreenWidth() const - { - return vScreenSize.x; - } + { return vScreenSize.x; } int32_t PixelGameEngine::ScreenHeight() const - { - return vScreenSize.y; - } + { return vScreenSize.y; } float PixelGameEngine::GetElapsedTime() const - { - return fLastElapsed; - } + { return fLastElapsed; } const olc::vi2d& PixelGameEngine::GetWindowSize() const - { - return vWindowSize; - } + { return vWindowSize; } const olc::vi2d& PixelGameEngine::GetPixelSize() const - { - return vPixelSize; - } + { return vPixelSize; } const olc::vi2d& PixelGameEngine::GetScreenPixelSize() const - { - return vScreenPixelSize; - } + { return vScreenPixelSize; } const olc::vi2d& PixelGameEngine::GetWindowMouse() const - { - return vMouseWindowPos; - } - + { return vMouseWindowPos; } bool PixelGameEngine::Draw(const olc::vi2d& pos, Pixel p) - { - return Draw(pos.x, pos.y, p); - } + { return Draw(pos.x, pos.y, p); } // This is it, the critical function that plots a pixel bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p) @@ -1955,9 +1892,7 @@ namespace olc void PixelGameEngine::DrawLine(const olc::vi2d& pos1, const olc::vi2d& pos2, Pixel p, uint32_t pattern) - { - DrawLine(pos1.x, pos1.y, pos2.x, pos2.y, p, pattern); - } + { DrawLine(pos1.x, pos1.y, pos2.x, pos2.y, p, pattern); } void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p, uint32_t pattern) { @@ -2039,9 +1974,7 @@ namespace olc } void PixelGameEngine::DrawCircle(const olc::vi2d& pos, int32_t radius, Pixel p, uint8_t mask) - { - DrawCircle(pos.x, pos.y, radius, p, mask); - } + { DrawCircle(pos.x, pos.y, radius, p, mask); } void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask) { // Thanks to IanM-Matrix1 #PR121 @@ -2080,9 +2013,7 @@ namespace olc } void PixelGameEngine::FillCircle(const olc::vi2d& pos, int32_t radius, Pixel p) - { - FillCircle(pos.x, pos.y, radius, p); - } + { FillCircle(pos.x, pos.y, radius, p); } void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p) { // Thanks to IanM-Matrix1 #PR121 @@ -2124,9 +2055,7 @@ namespace olc } void PixelGameEngine::DrawRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p) - { - DrawRect(pos.x, pos.y, size.x, size.y, p); - } + { DrawRect(pos.x, pos.y, size.x, size.y, p); } void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) { @@ -2144,19 +2073,13 @@ namespace olc } void PixelGameEngine::ClearBuffer(Pixel p, bool bDepth) - { - renderer->ClearBuffer(p, bDepth); - } + { renderer->ClearBuffer(p, bDepth); } olc::Sprite* PixelGameEngine::GetFontSprite() - { - return fontSprite; - } + { return fontSprite; } void PixelGameEngine::FillRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p) - { - FillRect(pos.x, pos.y, size.x, size.y, p); - } + { FillRect(pos.x, pos.y, size.x, size.y, p); } void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) { @@ -2179,9 +2102,7 @@ namespace olc } void PixelGameEngine::DrawTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p) - { - DrawTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); - } + { DrawTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); } void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) { @@ -2191,9 +2112,7 @@ namespace olc } void PixelGameEngine::FillTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p) - { - FillTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); - } + { FillTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); } // https://www.avrfreaks.net/sites/default/files/triangles.c void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) @@ -2271,7 +2190,6 @@ namespace olc t2x += t2xp; y += 1; if (y == y2) break; - } next: // Second half @@ -2333,9 +2251,7 @@ namespace olc } void PixelGameEngine::DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale, uint8_t flip) - { - DrawSprite(pos.x, pos.y, sprite, scale, flip); - } + { DrawSprite(pos.x, pos.y, sprite, scale, flip); } void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale, uint8_t flip) { @@ -2372,9 +2288,7 @@ namespace olc } void PixelGameEngine::DrawPartialSprite(const olc::vi2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, uint32_t scale, uint8_t flip) - { - DrawPartialSprite(pos.x, pos.y, sprite, sourcepos.x, sourcepos.y, size.x, size.y, scale, flip); - } + { DrawPartialSprite(pos.x, pos.y, sprite, sourcepos.x, sourcepos.y, size.x, size.y, scale, flip); } void PixelGameEngine::DrawPartialSprite(int32_t x, int32_t y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale, uint8_t flip) { @@ -2411,9 +2325,7 @@ namespace olc } void PixelGameEngine::SetDecalMode(const olc::DecalMode& mode) - { - nDecalMode = mode; - } + { nDecalMode = mode; } void PixelGameEngine::DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale, const olc::Pixel& tint) { @@ -2669,24 +2581,16 @@ namespace olc } void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::Pixel& tint) - { - DrawWarpedDecal(decal, pos.data(), tint); - } + { DrawWarpedDecal(decal, pos.data(), tint); } void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint) - { - DrawWarpedDecal(decal, &pos[0], tint); - } + { DrawWarpedDecal(decal, &pos[0], tint); } void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) - { - DrawPartialWarpedDecal(decal, pos.data(), source_pos, source_size, tint); - } + { DrawPartialWarpedDecal(decal, pos.data(), source_pos, source_size, tint); } void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) - { - DrawPartialWarpedDecal(decal, &pos[0], source_pos, source_size, tint); - } + { DrawPartialWarpedDecal(decal, &pos[0], source_pos, source_size, tint); } void PixelGameEngine::DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale) { @@ -2741,9 +2645,7 @@ namespace olc } void PixelGameEngine::DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale) - { - DrawString(pos.x, pos.y, sText, col, scale); - } + { DrawString(pos.x, pos.y, sText, col, scale); } void PixelGameEngine::DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col, uint32_t scale) { @@ -2806,9 +2708,7 @@ namespace olc } void PixelGameEngine::DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale) - { - DrawStringProp(pos.x, pos.y, sText, col, scale); - } + { DrawStringProp(pos.x, pos.y, sText, col, scale); } void PixelGameEngine::DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col, uint32_t scale) { @@ -2855,14 +2755,10 @@ namespace olc } void PixelGameEngine::SetPixelMode(Pixel::Mode m) - { - nPixelMode = m; - } + { nPixelMode = m; } Pixel::Mode PixelGameEngine::GetPixelMode() - { - return nPixelMode; - } + { return nPixelMode; } void PixelGameEngine::SetPixelMode(std::function pixelMode) { @@ -2882,21 +2778,14 @@ namespace olc // they are not overwritten bool PixelGameEngine::OnUserCreate() - { - return false; - } + { return false; } bool PixelGameEngine::OnUserUpdate(float fElapsedTime) - { - UNUSED(fElapsedTime); return false; - } + { UNUSED(fElapsedTime); return false; } bool PixelGameEngine::OnUserDestroy() - { - return true; - } - ////////////////////////////////////////////////////////////////// - + { return true; } + void PixelGameEngine::olc_UpdateViewport() { int32_t ww = vScreenSize.x * vPixelSize.x; @@ -2930,9 +2819,7 @@ namespace olc } void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta) - { - nMouseWheelDeltaCache += delta; - } + { nMouseWheelDeltaCache += delta; } void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y) { @@ -2952,29 +2839,25 @@ namespace olc } void PixelGameEngine::olc_UpdateMouseState(int32_t button, bool state) - { - pMouseNewState[button] = state; - } + { pMouseNewState[button] = state; } void PixelGameEngine::olc_UpdateKeyState(int32_t key, bool state) - { - pKeyNewState[key] = state; - } + { pKeyNewState[key] = state; } void PixelGameEngine::olc_UpdateMouseFocus(bool state) - { - bHasMouseFocus = state; - } + { bHasMouseFocus = state; } void PixelGameEngine::olc_UpdateKeyFocus(bool state) - { - bHasInputFocus = state; - } + { bHasInputFocus = state; } + + void PixelGameEngine::olc_Reanimate() + { bAtomActive = true; } + + bool PixelGameEngine::olc_IsRunning() + { return bAtomActive; } void PixelGameEngine::olc_Terminate() - { - bAtomActive = false; - } + { bAtomActive = false; } void PixelGameEngine::EngineThread() { @@ -3205,51 +3088,50 @@ namespace olc olc::PixelGameEngine* olc::Renderer::ptrPGE = nullptr; std::unique_ptr olc::Sprite::loader = nullptr; }; - - +#pragma endregion // O------------------------------------------------------------------------------O -// | olcPixelGameEngine PLATFORM SPECIFIC IMPLEMENTATIONS | +// | olcPixelGameEngine Renderers - the draw-y bits | // O------------------------------------------------------------------------------O +#pragma region renderer_ogl10 // O------------------------------------------------------------------------------O // | START RENDERER: OpenGL 1.0 (the original, the best...) | // O------------------------------------------------------------------------------O #if defined(OLC_GFX_OPENGL10) -#if defined(OLC_PLATFORM_WINAPI) -#include -#include -#if !defined(__MINGW32__) -#pragma comment(lib, "Dwmapi.lib") -#endif -typedef BOOL(WINAPI wglSwapInterval_t) (int interval); -static wglSwapInterval_t* wglSwapInterval = nullptr; -typedef HDC glDeviceContext_t; -typedef HGLRC glRenderContext_t; +#if defined(OLC_PLATFORM_WINAPI) + #include + #include + #if !defined(__MINGW32__) + #pragma comment(lib, "Dwmapi.lib") + #endif + typedef BOOL(WINAPI wglSwapInterval_t) (int interval); + static wglSwapInterval_t* wglSwapInterval = nullptr; + typedef HDC glDeviceContext_t; + typedef HGLRC glRenderContext_t; #endif #if defined(__linux__) || defined(__FreeBSD__) -#include -#endif - -#if defined(OLC_PLATFORM_X11) -namespace X11 -{ -#include -} + #include +#endif -typedef int(glSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); -static glSwapInterval_t* glSwapIntervalEXT; -typedef X11::GLXContext glDeviceContext_t; -typedef X11::GLXContext glRenderContext_t; +#if defined(OLC_PLATFORM_X11) + namespace X11 + { + #include + } + typedef int(glSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); + static glSwapInterval_t* glSwapIntervalEXT; + typedef X11::GLXContext glDeviceContext_t; + typedef X11::GLXContext glRenderContext_t; #endif #if defined(__APPLE__) -#define GL_SILENCE_DEPRECATION -#include -#include -#include + #define GL_SILENCE_DEPRECATION + #include + #include + #include #endif namespace olc @@ -3281,15 +3163,11 @@ namespace olc int argc = 0; char* argv[1] = { (char*)"" }; glutInit(&argc, argv); - glutInitWindowPosition(0, 0); glutInitWindowSize(512, 512); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); - // Creates the window and the OpenGL context for it glutCreateWindow("OneLoneCoder.com - Pixel Game Engine"); - glEnable(GL_TEXTURE_2D); // Turn on texturing glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); #endif @@ -3475,7 +3353,7 @@ namespace olc glEnd(); } - uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered) override + uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered, const bool clamp) override { UNUSED(width); UNUSED(height); @@ -3493,8 +3371,17 @@ namespace olc glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + if (clamp) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); return id; } @@ -3542,48 +3429,61 @@ namespace olc // O------------------------------------------------------------------------------O // | END RENDERER: OpenGL 1.0 (the original, the best...) | // O------------------------------------------------------------------------------O +#pragma endregion +#pragma region renderer_ogl33 // O------------------------------------------------------------------------------O // | START RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) | // O------------------------------------------------------------------------------O #if defined(OLC_GFX_OPENGL33) -#if defined(OLC_PLATFORM_WINAPI) -#include -#include -#if !defined(__MINGW32__) -#pragma comment(lib, "Dwmapi.lib") -#endif -typedef void __stdcall locSwapInterval_t(GLsizei n); -typedef HDC glDeviceContext_t; -typedef HGLRC glRenderContext_t; -#define CALLSTYLE __stdcall -#define OGL_LOAD(t, n) (t*)wglGetProcAddress(n) +#if defined(OLC_PLATFORM_WINAPI) + #include + #include + #if !defined(__MINGW32__) + #pragma comment(lib, "Dwmapi.lib") + #endif + typedef void __stdcall locSwapInterval_t(GLsizei n); + typedef HDC glDeviceContext_t; + typedef HGLRC glRenderContext_t; + #define CALLSTYLE __stdcall + #define OGL_LOAD(t, n) (t*)wglGetProcAddress(#n) #endif #if defined(__linux__) || defined(__FreeBSD__) -#include + #include #endif #if defined(OLC_PLATFORM_X11) -namespace X11 -{ -#include -} -typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); -typedef X11::GLXContext glDeviceContext_t; -typedef X11::GLXContext glRenderContext_t; -#define CALLSTYLE -#define OGL_LOAD(t, n) (t*)glXGetProcAddress((unsigned char*)n); + namespace X11 + { + #include + } + typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); + typedef X11::GLXContext glDeviceContext_t; + typedef X11::GLXContext glRenderContext_t; + #define CALLSTYLE + #define OGL_LOAD(t, n) (t*)glXGetProcAddress((unsigned char*)#n); #endif #if defined(__APPLE__) -#define GL_SILENCE_DEPRECATION -#include -#include -#include + #define GL_SILENCE_DEPRECATION + #include + #include + #include #endif +#if defined(OLC_PLATFORM_EMSCRIPTEN) + #include + #include + #define GL_GLEXT_PROTOTYPES + #include + #include + #define CALLSTYLE + typedef EGLBoolean(locSwapInterval_t)(EGLDisplay display, EGLint interval); + #define GL_CLAMP GL_CLAMP_TO_EDGE + #define OGL_LOAD(t, n) n; +#endif namespace olc { @@ -3592,7 +3492,11 @@ namespace olc typedef GLuint CALLSTYLE locCreateShader_t(GLenum type); typedef GLuint CALLSTYLE locCreateProgram_t(void); typedef void CALLSTYLE locDeleteShader_t(GLuint shader); +#if defined(OLC_PLATFORM_EMSCRIPTEN) + typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); +#else typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); +#endif typedef void CALLSTYLE locCompileShader_t(GLuint shader); typedef void CALLSTYLE locLinkProgram_t(GLuint program); typedef void CALLSTYLE locDeleteProgram_t(GLuint program); @@ -3607,23 +3511,28 @@ namespace olc typedef void CALLSTYLE locGenVertexArrays_t(GLsizei n, GLuint* arrays); typedef void CALLSTYLE locGetShaderInfoLog_t(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); - - constexpr size_t OLC_MAX_VERTS = 128; class Renderer_OGL33 : public olc::Renderer { private: +#if defined(OLC_PLATFORM_EMSCRIPTEN) + EGLDisplay olc_Display; + EGLConfig olc_Config; + EGLContext olc_Context; + EGLSurface olc_Surface; +#endif + #if defined(OLC_PLATFORM_GLUT) bool mFullScreen = false; #else + #if !defined(OLC_PLATFORM_EMSCRIPTEN) glDeviceContext_t glDeviceContext = 0; glRenderContext_t glRenderContext = 0; + #endif #endif - bool bSync = false; olc::DecalMode nDecalMode = olc::DecalMode(-1); // Thanks Gusgo & Bispoo - #if defined(OLC_PLATFORM_X11) X11::Display* olc_Display = nullptr; X11::Window* olc_Window = nullptr; @@ -3675,15 +3584,11 @@ namespace olc int argc = 0; char* argv[1] = { (char*)"" }; glutInit(&argc, argv); - glutInitWindowPosition(0, 0); glutInitWindowSize(512, 512); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); - // Creates the window and the OpenGL context for it glutCreateWindow("OneLoneCoder.com - Pixel Game Engine"); - glEnable(GL_TEXTURE_2D); // Turn on texturing glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); #endif @@ -3692,7 +3597,6 @@ namespace olc olc::rcode CreateDevice(std::vector params, bool bFullScreen, bool bVSYNC) override { // Create OpenGL Context - #if defined(OLC_PLATFORM_WINAPI) // Create Device Context glDeviceContext = GetDC((HWND)(params[0])); @@ -3745,6 +3649,24 @@ namespace olc locSwapInterval(olc_Display, *olc_Window, 0); #endif +#if defined(OLC_PLATFORM_EMSCRIPTEN) + EGLint const attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; + EGLint const context_config[] = { EGL_CONTEXT_CLIENT_VERSION , 2, EGL_NONE }; + EGLint num_config; + + olc_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(olc_Display, nullptr, nullptr); + eglChooseConfig(olc_Display, attribute_list, &olc_Config, 1, &num_config); + + /* create an EGL rendering context */ + olc_Context = eglCreateContext(olc_Display, olc_Config, EGL_NO_CONTEXT, context_config); + olc_Surface = eglCreateWindowSurface(olc_Display, olc_Config, NULL, nullptr); + eglMakeCurrent(olc_Display, olc_Surface, olc_Surface, olc_Context); + //eglSwapInterval is currently a NOP, plement anyways in case it becomes supported + locSwapInterval = &eglSwapInterval; + locSwapInterval(olc_Display, bVSYNC ? 1 : 0); +#endif + #if defined(OLC_PLATFORM_GLUT) mFullScreen = bFullScreen; if (!bVSYNC) @@ -3756,32 +3678,39 @@ namespace olc #endif } #else + #if !defined(OLC_PLATFORM_EMSCRIPTEN) glEnable(GL_TEXTURE_2D); // Turn on texturing glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + #endif #endif // Load External OpenGL Functions - locCreateShader = OGL_LOAD(locCreateShader_t, "glCreateShader"); - locCompileShader = OGL_LOAD(locCompileShader_t, "glCompileShader"); - locShaderSource = OGL_LOAD(locShaderSource_t, "glShaderSource"); - locDeleteShader = OGL_LOAD(locDeleteShader_t, "glDeleteShader"); - locCreateProgram = OGL_LOAD(locCreateProgram_t, "glCreateProgram"); - locDeleteProgram = OGL_LOAD(locDeleteProgram_t, "glDeleteProgram"); - locLinkProgram = OGL_LOAD(locLinkProgram_t, "glLinkProgram"); - locAttachShader = OGL_LOAD(locAttachShader_t, "glAttachShader"); - locBindBuffer = OGL_LOAD(locBindBuffer_t, "glBindBuffer"); - locBufferData = OGL_LOAD(locBufferData_t, "glBufferData"); - locGenBuffers = OGL_LOAD(locGenBuffers_t, "glGenBuffers"); - locVertexAttribPointer = OGL_LOAD(locVertexAttribPointer_t, "glVertexAttribPointer"); - locEnableVertexAttribArray = OGL_LOAD(locEnableVertexAttribArray_t, "glEnableVertexAttribArray"); - locUseProgram = OGL_LOAD(locUseProgram_t, "glUseProgram"); - locBindVertexArray = OGL_LOAD(locBindVertexArray_t, "glBindVertexArray"); - locGenVertexArrays = OGL_LOAD(locGenVertexArrays_t, "glGenVertexArrays"); - locGetShaderInfoLog = OGL_LOAD(locGetShaderInfoLog_t, "glGetShaderInfoLog"); + locCreateShader = OGL_LOAD(locCreateShader_t, glCreateShader); + locCompileShader = OGL_LOAD(locCompileShader_t, glCompileShader); + locShaderSource = OGL_LOAD(locShaderSource_t, glShaderSource); + locDeleteShader = OGL_LOAD(locDeleteShader_t, glDeleteShader); + locCreateProgram = OGL_LOAD(locCreateProgram_t, glCreateProgram); + locDeleteProgram = OGL_LOAD(locDeleteProgram_t, glDeleteProgram); + locLinkProgram = OGL_LOAD(locLinkProgram_t, glLinkProgram); + locAttachShader = OGL_LOAD(locAttachShader_t, glAttachShader); + locBindBuffer = OGL_LOAD(locBindBuffer_t, glBindBuffer); + locBufferData = OGL_LOAD(locBufferData_t, glBufferData); + locGenBuffers = OGL_LOAD(locGenBuffers_t, glGenBuffers); + locVertexAttribPointer = OGL_LOAD(locVertexAttribPointer_t, glVertexAttribPointer); + locEnableVertexAttribArray = OGL_LOAD(locEnableVertexAttribArray_t, glEnableVertexAttribArray); + locUseProgram = OGL_LOAD(locUseProgram_t, glUseProgram); + locGetShaderInfoLog = OGL_LOAD(locGetShaderInfoLog_t, glGetShaderInfoLog); +#if !defined(OLC_PLATFORM_EMSCRIPTEN) + locBindVertexArray = OGL_LOAD(locBindVertexArray_t, glBindVertexArray); + locGenVertexArrays = OGL_LOAD(locGenVertexArrays_t, glGenVertexArrays); +#else + locBindVertexArray = glBindVertexArrayOES; + locGenVertexArrays = glGenVertexArraysOES; +#endif // Load & Compile Quad Shader - assumes no errors m_nFS = locCreateShader(0x8B30); const GLchar* strFS = -#if defined(__arm__) +#if defined(__arm__) || defined(OLC_PLATFORM_EMSCRIPTEN) "#version 300 es\n" "precision mediump float;" #else @@ -3794,7 +3723,7 @@ namespace olc m_nVS = locCreateShader(0x8B31); const GLchar* strVS = -#if defined(__arm__) +#if defined(__arm__) || defined(OLC_PLATFORM_EMSCRIPTEN) "#version 300 es\n" "precision mediump float;" #else @@ -3846,6 +3775,16 @@ namespace olc #if defined(OLC_PLATFORM_GLUT) glutDestroyWindow(glutGetWindow()); #endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + eglMakeCurrent(olc_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(olc_Display, olc_Context); + eglDestroySurface(olc_Display, olc_Surface); + eglTerminate(olc_Display); + olc_Display = EGL_NO_DISPLAY; + olc_Surface = EGL_NO_SURFACE; + olc_Context = EGL_NO_CONTEXT; +#endif return olc::rcode::OK; } @@ -3863,6 +3802,10 @@ namespace olc #if defined(OLC_PLATFORM_GLUT) glutSwapBuffers(); #endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + eglSwapBuffers(olc_Display, olc_Surface); +#endif } void PrepareDrawing() override @@ -3872,9 +3815,15 @@ namespace olc glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); locUseProgram(m_nQuadShader); locBindVertexArray(m_vaQuad); + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + locVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(locVertex), 0); locEnableVertexAttribArray(0); + locVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(locVertex), (void*)(3 * sizeof(float))); locEnableVertexAttribArray(1); + locVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(locVertex), (void*)(5 * sizeof(float))); locEnableVertexAttribArray(2); +#endif } - void SetDecalMode(const olc::DecalMode& mode) + void SetDecalMode(const olc::DecalMode& mode) override { if (mode != nDecalMode) { @@ -3927,7 +3876,7 @@ namespace olc glDrawArrays(GL_TRIANGLE_FAN, 0, decal.points); } - uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered) override + uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered, const bool clamp) override { UNUSED(width); UNUSED(height); @@ -3946,9 +3895,19 @@ namespace olc glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + if (clamp) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } +#if !defined(OLC_PLATFORM_EMSCRIPTEN) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#endif return id; } @@ -3995,7 +3954,13 @@ namespace olc // O------------------------------------------------------------------------------O // | END RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) | // O------------------------------------------------------------------------------O +#pragma endregion +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine Image loaders | +// O------------------------------------------------------------------------------O + +#pragma region image_gdi // O------------------------------------------------------------------------------O // | START IMAGE LOADER: GDI+, Windows Only, always exists, a little slow | // O------------------------------------------------------------------------------O @@ -4006,17 +3971,17 @@ namespace olc #include #include #if defined(__MINGW32__) // Thanks Gusgo & Dandistine, but c'mon mingw!! wtf?! -#include + #include #else -#include + #include #endif #include #undef min #undef max #if !defined(__MINGW32__) -#pragma comment(lib, "gdiplus.lib") -#pragma comment(lib, "Shlwapi.lib") + #pragma comment(lib, "gdiplus.lib") + #pragma comment(lib, "Shlwapi.lib") #endif namespace olc @@ -4067,7 +4032,7 @@ namespace olc olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override { // clear out existing sprite - if (spr->pColData != nullptr) delete[] spr->pColData; + spr->pColData.clear(); // Open file UNUSED(pack); @@ -4090,7 +4055,8 @@ namespace olc if (bmp->GetLastStatus() != Gdiplus::Ok) return olc::rcode::FAIL; spr->width = bmp->GetWidth(); spr->height = bmp->GetHeight(); - spr->pColData = new Pixel[spr->width * spr->height]; + + spr->pColData.resize(spr->width * spr->height); for (int y = 0; y < spr->height; y++) for (int x = 0; x < spr->width; x++) @@ -4113,10 +4079,9 @@ namespace olc // O------------------------------------------------------------------------------O // | END IMAGE LOADER: GDI+ | // O------------------------------------------------------------------------------O +#pragma endregion - - - +#pragma region image_libpng // O------------------------------------------------------------------------------O // | START IMAGE LOADER: libpng, default on linux, requires -lpng (libpng-dev) | // O------------------------------------------------------------------------------O @@ -4141,7 +4106,7 @@ namespace olc UNUSED(pack); // clear out existing sprite - if (spr->pColData != nullptr) delete[] spr->pColData; + spr->pColData.clear(); //////////////////////////////////////////////////////////////////////////// // Use libpng, Thanks to Guillaume Cottenceau @@ -4177,7 +4142,7 @@ namespace olc png_read_image(png, row_pointers); //////////////////////////////////////////////////////////////////////////// // Create sprite array - spr->pColData = new Pixel[spr->width * spr->height]; + spr->pColData.resize(spr->width * spr->height); // Iterate through image rows, converting into sprite format for (int y = 0; y < spr->height; y++) { @@ -4224,7 +4189,7 @@ namespace olc fail_load: spr->width = 0; spr->height = 0; - spr->pColData = nullptr; + spr->pColData.clear(); return olc::rcode::FAIL; } @@ -4238,10 +4203,9 @@ namespace olc // O------------------------------------------------------------------------------O // | END IMAGE LOADER: | // O------------------------------------------------------------------------------O +#pragma endregion - - - +#pragma region image_stb // O------------------------------------------------------------------------------O // | START IMAGE LOADER: stb_image.h, all systems, very fast | // O------------------------------------------------------------------------------O @@ -4268,7 +4232,7 @@ namespace olc { UNUSED(pack); // clear out existing sprite - if (spr->pColData != nullptr) delete[] spr->pColData; + spr->pColData.clear(); // Open file stbi_uc* bytes = nullptr; int w = 0, h = 0, cmp = 0; @@ -4286,8 +4250,8 @@ namespace olc if (!bytes) return olc::rcode::FAIL; spr->width = w; spr->height = h; - spr->pColData = new Pixel[spr->width * spr->height]; - std::memcpy(spr->pColData, bytes, spr->width * spr->height * 4); + spr->pColData.resize(spr->width * spr->height); + std::memcpy(spr->pColData.data(), bytes, spr->width * spr->height * 4); delete[] bytes; return olc::rcode::OK; } @@ -4302,17 +4266,22 @@ namespace olc // O------------------------------------------------------------------------------O // | START IMAGE LOADER: stb_image.h | // O------------------------------------------------------------------------------O +#pragma endregion +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine Platforms | +// O------------------------------------------------------------------------------O +#pragma region platform_windows // O------------------------------------------------------------------------------O // | START PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 | // O------------------------------------------------------------------------------O #if defined(OLC_PLATFORM_WINAPI) #if defined(_WIN32) && !defined(__MINGW32__) -#pragma comment(lib, "user32.lib") // Visual Studio Only -#pragma comment(lib, "gdi32.lib") // For other Windows Compilers please add -#pragma comment(lib, "opengl32.lib") // these libs to your linker input + #pragma comment(lib, "user32.lib") // Visual Studio Only + #pragma comment(lib, "gdi32.lib") // For other Windows Compilers please add + #pragma comment(lib, "opengl32.lib") // these libs to your linker input #endif namespace olc @@ -4513,11 +4482,9 @@ namespace olc // O------------------------------------------------------------------------------O // | END PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 | // O------------------------------------------------------------------------------O +#pragma endregion - - - - +#pragma region platform_linux // O------------------------------------------------------------------------------O // | START PLATFORM: LINUX | // O------------------------------------------------------------------------------O @@ -4766,10 +4733,9 @@ namespace olc // O------------------------------------------------------------------------------O // | END PLATFORM: LINUX | // O------------------------------------------------------------------------------O +#pragma endregion - - - +#pragma region platform_glut // O------------------------------------------------------------------------------O // | START PLATFORM: GLUT (used to make it simple for Apple) | // O------------------------------------------------------------------------------O @@ -5027,9 +4993,459 @@ namespace olc { // O------------------------------------------------------------------------------O // | END PLATFORM: GLUT | // O------------------------------------------------------------------------------O +#pragma endregion + + +#pragma region platform_emscripten +// O------------------------------------------------------------------------------O +// | START PLATFORM: Emscripten - Totally Game Changing... | +// O------------------------------------------------------------------------------O + +// +// Firstly a big mega thank you to members of the OLC Community for sorting this +// out. Making a browser compatible version has been a priority for quite some +// time, but I lacked the expertise to do it. This awesome feature is possible +// because a group of former strangers got together and formed friendships over +// their shared passion for code. If anything demonstrates how powerful helping +// each other can be, it's this. - Javidx9 + +// Emscripten Platform: MaGetzUb, Moros1138, Slavka, Dandistine, Gorbit99, Bispoo +// also: Ishidex, Gusgo99, SlicEnDicE, Alexio + + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + +#include +#include + +extern "C" +{ + EMSCRIPTEN_KEEPALIVE inline int olc_OnPageUnload() + { olc::platform->ApplicationCleanUp(); return 0; } +} + +namespace olc +{ + class Platform_Emscripten : public olc::Platform + { + public: + + virtual olc::rcode ApplicationStartUp() override + { return olc::rcode::OK; } + + virtual olc::rcode ApplicationCleanUp() override + { ThreadCleanUp(); return olc::rcode::OK; } + + virtual olc::rcode ThreadStartUp() override + { return olc::rcode::OK; } + + virtual olc::rcode ThreadCleanUp() override + { renderer->DestroyDevice(); return olc::OK; } + + virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override + { + if (renderer->CreateDevice({}, bFullScreen, bEnableVSYNC) == olc::rcode::OK) + { + renderer->UpdateViewport(vViewPos, vViewSize); + return olc::rcode::OK; + } + else + return olc::rcode::FAIL; + } + + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override + { + emscripten_set_canvas_element_size("#canvas", vWindowSize.x, vWindowSize.y); + + mapKeys[DOM_PK_UNKNOWN] = Key::NONE; + mapKeys[DOM_PK_A] = Key::A; mapKeys[DOM_PK_B] = Key::B; mapKeys[DOM_PK_C] = Key::C; mapKeys[DOM_PK_D] = Key::D; + mapKeys[DOM_PK_E] = Key::E; mapKeys[DOM_PK_F] = Key::F; mapKeys[DOM_PK_G] = Key::G; mapKeys[DOM_PK_H] = Key::H; + mapKeys[DOM_PK_I] = Key::I; mapKeys[DOM_PK_J] = Key::J; mapKeys[DOM_PK_K] = Key::K; mapKeys[DOM_PK_L] = Key::L; + mapKeys[DOM_PK_M] = Key::M; mapKeys[DOM_PK_N] = Key::N; mapKeys[DOM_PK_O] = Key::O; mapKeys[DOM_PK_P] = Key::P; + mapKeys[DOM_PK_Q] = Key::Q; mapKeys[DOM_PK_R] = Key::R; mapKeys[DOM_PK_S] = Key::S; mapKeys[DOM_PK_T] = Key::T; + mapKeys[DOM_PK_U] = Key::U; mapKeys[DOM_PK_V] = Key::V; mapKeys[DOM_PK_W] = Key::W; mapKeys[DOM_PK_X] = Key::X; + mapKeys[DOM_PK_Y] = Key::Y; mapKeys[DOM_PK_Z] = Key::Z; + mapKeys[DOM_PK_0] = Key::K0; mapKeys[DOM_PK_1] = Key::K1; mapKeys[DOM_PK_2] = Key::K2; + mapKeys[DOM_PK_3] = Key::K3; mapKeys[DOM_PK_4] = Key::K4; mapKeys[DOM_PK_5] = Key::K5; + mapKeys[DOM_PK_6] = Key::K6; mapKeys[DOM_PK_7] = Key::K7; mapKeys[DOM_PK_8] = Key::K8; + mapKeys[DOM_PK_9] = Key::K9; + mapKeys[DOM_PK_F1] = Key::F1; mapKeys[DOM_PK_F2] = Key::F2; mapKeys[DOM_PK_F3] = Key::F3; mapKeys[DOM_PK_F4] = Key::F4; + mapKeys[DOM_PK_F5] = Key::F5; mapKeys[DOM_PK_F6] = Key::F6; mapKeys[DOM_PK_F7] = Key::F7; mapKeys[DOM_PK_F8] = Key::F8; + mapKeys[DOM_PK_F9] = Key::F9; mapKeys[DOM_PK_F10] = Key::F10; mapKeys[DOM_PK_F11] = Key::F11; mapKeys[DOM_PK_F12] = Key::F12; + mapKeys[DOM_PK_ARROW_UP] = Key::UP; mapKeys[DOM_PK_ARROW_DOWN] = Key::DOWN; + mapKeys[DOM_PK_ARROW_LEFT] = Key::LEFT; mapKeys[DOM_PK_ARROW_RIGHT] = Key::RIGHT; + mapKeys[DOM_PK_SPACE] = Key::SPACE; mapKeys[DOM_PK_TAB] = Key::TAB; + mapKeys[DOM_PK_SHIFT_LEFT] = Key::SHIFT; mapKeys[DOM_PK_SHIFT_RIGHT] = Key::SHIFT; + mapKeys[DOM_PK_CONTROL_LEFT] = Key::CTRL; mapKeys[DOM_PK_CONTROL_RIGHT] = Key::CTRL; + mapKeys[DOM_PK_INSERT] = Key::INS; mapKeys[DOM_PK_DELETE] = Key::DEL; mapKeys[DOM_PK_HOME] = Key::HOME; + mapKeys[DOM_PK_END] = Key::END; mapKeys[DOM_PK_PAGE_UP] = Key::PGUP; mapKeys[DOM_PK_PAGE_DOWN] = Key::PGDN; + mapKeys[DOM_PK_BACKSPACE] = Key::BACK; mapKeys[DOM_PK_ESCAPE] = Key::ESCAPE; + mapKeys[DOM_PK_ENTER] = Key::ENTER; mapKeys[DOM_PK_NUMPAD_EQUAL] = Key::EQUALS; + mapKeys[DOM_PK_NUMPAD_ENTER] = Key::ENTER; mapKeys[DOM_PK_PAUSE] = Key::PAUSE; + mapKeys[DOM_PK_SCROLL_LOCK] = Key::SCROLL; + mapKeys[DOM_PK_NUMPAD_0] = Key::NP0; mapKeys[DOM_PK_NUMPAD_1] = Key::NP1; mapKeys[DOM_PK_NUMPAD_2] = Key::NP2; + mapKeys[DOM_PK_NUMPAD_3] = Key::NP3; mapKeys[DOM_PK_NUMPAD_4] = Key::NP4; mapKeys[DOM_PK_NUMPAD_5] = Key::NP5; + mapKeys[DOM_PK_NUMPAD_6] = Key::NP6; mapKeys[DOM_PK_NUMPAD_7] = Key::NP7; mapKeys[DOM_PK_NUMPAD_8] = Key::NP8; + mapKeys[DOM_PK_NUMPAD_9] = Key::NP9; + mapKeys[DOM_PK_NUMPAD_MULTIPLY] = Key::NP_MUL; mapKeys[DOM_PK_NUMPAD_DIVIDE] = Key::NP_DIV; + mapKeys[DOM_PK_NUMPAD_ADD] = Key::NP_ADD; mapKeys[DOM_PK_NUMPAD_SUBTRACT] = Key::NP_SUB; + mapKeys[DOM_PK_NUMPAD_DECIMAL] = Key::NP_DECIMAL; + mapKeys[DOM_PK_PERIOD] = Key::PERIOD; mapKeys[DOM_PK_EQUAL] = Key::EQUALS; + mapKeys[DOM_PK_COMMA] = Key::COMMA; mapKeys[DOM_PK_MINUS] = Key::MINUS; + 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; + + // Keyboard Callbacks + emscripten_set_keydown_callback("#canvas", 0, 1, keyboard_callback); + emscripten_set_keyup_callback("#canvas", 0, 1, keyboard_callback); + + // Mouse Callbacks + emscripten_set_wheel_callback("#canvas", 0, 1, wheel_callback); + emscripten_set_mousedown_callback("#canvas", 0, 1, mouse_callback); + emscripten_set_mouseup_callback("#canvas", 0, 1, mouse_callback); + emscripten_set_mousemove_callback("#canvas", 0, 1, mouse_callback); + + // Touch Callbacks + emscripten_set_touchstart_callback("#canvas", 0, 1, touch_callback); + emscripten_set_touchmove_callback("#canvas", 0, 1, touch_callback); + emscripten_set_touchend_callback("#canvas", 0, 1, touch_callback); + + // Canvas Focus Callbacks + 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. + + + // Fullscreen and Resize Observers + EM_ASM({ + + // cache for reuse + Module._olc_EmscriptenShellCss = "width: 100%; height: 70vh; margin-left: auto; margin-right: auto;"; + + // width / height = aspect ratio + Module._olc_WindowAspectRatio = $0 / $1; + Module.canvas.parentNode.addEventListener("resize", (e) => { + + if (e.defaultPrevented) { e.stopPropagation(); return; } + var viewWidth = e.detail.width; + var viewHeight = e.detail.width / Module._olc_WindowAspectRatio; + if (viewHeight > e.detail.height) + { + viewHeight = e.detail.height; + viewWidth = e.detail.height * Module._olc_WindowAspectRatio; + } + + if (Module.canvas.parentNode.className == 'emscripten_border') + Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss + " width: " + viewWidth.toString() + "px; height: " + viewHeight.toString() + "px;"; + + Module.canvas.setAttribute("width", viewWidth); + Module.canvas.setAttribute("height", viewHeight); + + if (document.fullscreenElement != null) + { + var top = (e.detail.height - viewHeight) / 2; + var left = (e.detail.width - viewWidth) / 2; + Module.canvas.style.position = "fixed"; + Module.canvas.style.top = top.toString() + "px"; + Module.canvas.style.left = left.toString() + "px"; + Module.canvas.style.width = ""; + Module.canvas.style.height = ""; + } + + // trigger PGE update + Module._olc_PGE_UpdateWindowSize(viewWidth, viewHeight); + // this is really only needed when enter/exiting fullscreen + Module.canvas.focus(); + // prevent this event from ever affecting the document beyond this element + e.stopPropagation(); + }); + + // helper function to prevent repeating the same code everywhere + Module._olc_ResizeCanvas = () => + { + // yes, we still have to wait, sigh.. + setTimeout(() => + { + // if default template, stretch width as well + if (Module.canvas.parentNode.className == 'emscripten_border') + Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss; + + // override it's styling so we can get it's stretched size + Module.canvas.style.cssText = "width: 100%; height: 100%; outline: none;"; + + // setup custom resize event + var resizeEvent = new CustomEvent('resize', + { + detail: { + width: Module.canvas.clientWidth, + height : Module.canvas.clientHeight + }, + bubbles : true, + cancelable : true + }); + + // trigger custom resize event on canvas element + Module.canvas.dispatchEvent(resizeEvent); + }, 50); + }; + + + // Disable Refresh Gesture on mobile + document.body.style.cssText += " overscroll-behavior-y: contain;"; + + if (Module.canvas.parentNode.className == 'emscripten_border') + { + // force body to have no margin in emscripten's minimal shell + document.body.style.margin = "0"; + Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss; + } + + Module._olc_ResizeCanvas(); + + // observe and react to resizing of the container element + var resizeObserver = new ResizeObserver((entries) => {Module._olc_ResizeCanvas();}).observe(Module.canvas.parentNode); + + // observe and react to changes that occur when entering/exiting fullscreen + var mutationObserver = new MutationObserver((mutationsList, observer) => + { + // a change has occurred, let's check them out! + for (var i = 0; i < mutationsList.length; i++) + { + // cycle through all of the newly added elements + for (var j = 0; j < mutationsList[i].addedNodes.length; j++) + { + // if this element is a our canvas, trigger resize + if (mutationsList[i].addedNodes[j].id == 'canvas') + Module._olc_ResizeCanvas(); + } + } + }).observe(Module.canvas.parentNode, + { + attributes: false, + childList : true, + subtree : false + }); + + // add resize listener on window + window.addEventListener("resize", (e) => { Module._olc_ResizeCanvas(); }); + + }, 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) + { + if (eventType == EMSCRIPTEN_EVENT_BLUR) + { + ptrPGE->olc_UpdateKeyFocus(false); + ptrPGE->olc_UpdateMouseFocus(false); + } + else if (eventType == EMSCRIPTEN_EVENT_FOCUS) + { + ptrPGE->olc_UpdateKeyFocus(true); + ptrPGE->olc_UpdateMouseFocus(true); + } + + return 0; + } + + //TY Moros + static EM_BOOL keyboard_callback(int eventType, const EmscriptenKeyboardEvent* e, void* userData) + { + if (eventType == EMSCRIPTEN_EVENT_KEYDOWN) + ptrPGE->olc_UpdateKeyState(mapKeys[emscripten_compute_dom_pk_code(e->code)], true); + + // THANK GOD!! for this compute function. And thanks Dandistine for pointing it out! + if (eventType == EMSCRIPTEN_EVENT_KEYUP) + ptrPGE->olc_UpdateKeyState(mapKeys[emscripten_compute_dom_pk_code(e->code)], false); + + //Consume keyboard events so that keys like F1 and F5 don't do weird things + return EM_TRUE; + } + + //TY Moros + static EM_BOOL wheel_callback(int eventType, const EmscriptenWheelEvent* e, void* userData) + { + if (eventType == EMSCRIPTEN_EVENT_WHEEL) + ptrPGE->olc_UpdateMouseWheel(-1 * e->deltaY); + + return EM_TRUE; + } + + //TY Bispoo + static EM_BOOL touch_callback(int eventType, const EmscriptenTouchEvent* e, void* userData) + { + // Move + if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) + { + ptrPGE->olc_UpdateMouse(e->touches->targetX, e->touches->targetY); + } + + // Start + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) + { + ptrPGE->olc_UpdateMouse(e->touches->targetX, e->touches->targetY); + ptrPGE->olc_UpdateMouseState(0, true); + } + + // End + if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) + { + ptrPGE->olc_UpdateMouseState(0, false); + } + + return EM_TRUE; + } + + //TY Moros + static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent* e, void* userData) + { + //Mouse Movement + if (eventType == EMSCRIPTEN_EVENT_MOUSEMOVE) + ptrPGE->olc_UpdateMouse(e->targetX, e->targetY); + + + //Mouse button press + if (e->button == 0) // left click + { + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) + ptrPGE->olc_UpdateMouseState(0, true); + else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP) + ptrPGE->olc_UpdateMouseState(0, false); + } + + if (e->button == 2) // right click + { + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) + ptrPGE->olc_UpdateMouseState(1, true); + else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP) + ptrPGE->olc_UpdateMouseState(1, false); + + } + + if (e->button == 1) // middle click + { + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) + ptrPGE->olc_UpdateMouseState(2, true); + else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP) + ptrPGE->olc_UpdateMouseState(2, false); + + //at the moment only middle mouse needs to consume events. + return EM_TRUE; + } + + return EM_FALSE; + } + + virtual olc::rcode SetWindowTitle(const std::string& s) override + { emscripten_set_window_title(s.c_str()); return olc::OK; } + + virtual olc::rcode StartSystemEventLoop() override + { return olc::OK; } + + virtual olc::rcode HandleSystemEvent() override + { return olc::OK; } + + static void MainLoop() + { + olc::Platform::ptrPGE->olc_CoreUpdate(); + if (!ptrPGE->olc_IsRunning()) + { + if (ptrPGE->OnUserDestroy()) + { + emscripten_cancel_main_loop(); + platform->ApplicationCleanUp(); + } + else + { + ptrPGE->olc_Reanimate(); + } + } + } + }; + + //Emscripten needs a special Start function + //Much of this is usually done in EngineThread, but that isn't used here + olc::rcode PixelGameEngine::Start() + { + if (platform->ApplicationStartUp() != olc::OK) return olc::FAIL; + + // Construct the window + if (platform->CreateWindowPane({ 30,30 }, vWindowSize, bFullScreen) != olc::OK) return olc::FAIL; + olc_UpdateWindowSize(vWindowSize.x, vWindowSize.y); + + // Some implementations may form an event loop here + if (platform->ThreadStartUp() == olc::FAIL) return olc::FAIL; + + // Do engine context specific initialisation + olc_PrepareEngine(); + + // Consider the "thread" started + bAtomActive = true; + + // Create user resources as part of this thread + for (auto& ext : vExtensions) ext->OnBeforeUserCreate(); + if (!OnUserCreate()) bAtomActive = false; + for (auto& ext : vExtensions) ext->OnAfterUserCreate(); + + platform->StartSystemEventLoop(); + + //This causes a heap memory corruption in Emscripten for some reason + //Platform_Emscripten::bActiveRef = &bAtomActive; + emscripten_set_main_loop(&Platform_Emscripten::MainLoop, 0, 1); + + // Wait for thread to be exited + if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL; + return olc::OK; + } +} + +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 | +// O------------------------------------------------------------------------------O +#pragma endregion +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine Auto-Configuration | +// O------------------------------------------------------------------------------O +#pragma region pge_config namespace olc { void PixelGameEngine::olc_ConfigureSystem() @@ -5047,6 +5463,10 @@ namespace olc olc::Sprite::loader = std::make_unique(); #endif +#if defined(OLC_IMAGE_CUSTOM_EX) + olc::Sprite::loader = std::make_unique(); +#endif + @@ -5062,6 +5482,14 @@ namespace olc platform = std::make_unique(); #endif +#if defined(OLC_PLATFORM_EMSCRIPTEN) + platform = std::make_unique(); +#endif + +#if defined(OLC_PLATFORM_CUSTOM_EX) + platform = std::make_unique(); +#endif + #if defined(OLC_GFX_OPENGL10) @@ -5084,13 +5512,19 @@ namespace olc renderer = std::make_unique(); #endif +#if defined(OLC_GFX_CUSTOM_EX) + renderer = std::make_unique(); +#endif + // Associate components with PGE instance platform->ptrPGE = this; renderer->ptrPGE = this; } } -#endif // End olc namespace +#pragma endregion + +#endif // End OLC_PGE_APPLICATION // O------------------------------------------------------------------------------O // | END OF OLC_PGE_APPLICATION |