diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index 434c83b..468e85d 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -2,7 +2,7 @@ olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.07 | + | OneLoneCoder Pixel Game Engine v2.08 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -94,10 +94,31 @@ https://solarianprogrammer.com/2019/11/16/install-codeblocks-gcc-windows-build-c-cpp-fortran-programs/ Add these libraries to "Linker Options": - user32 gdi32 opengl32 gdiplus Shlwapi stdc++fs + user32 gdi32 opengl32 gdiplus Shlwapi dwmapi stdc++fs 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 + arguing, thanks to Mumflr the PGE is now supported on Mac. Now I know nothing + about Mac, so if you need support, I suggest checking out the instructions + here: https://github.com/MumflrFumperdink/olcPGEMac + + clang++ -arch x86_64 -std=c++17 -mmacosx-version-min=10.15 -Wall -framework OpenGL -framework GLUT -lpng YourSource.cpp -o YourProgName + + Using stb_image.h + ~~~~~~~~~~~~~~~~~ + The PGE will load png images by default (with help from libpng on non-windows systems). + However, the excellent "stb_image.h" can be used instead, supporting a variety of + image formats, and has no library dependence - something we like at OLC studios ;) + To use stb_image.h, make sure it's in your code base, and simply: + + #define OLC_IMAGE_STB + + 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 + Ports ~~~~~ olc::PixelGameEngine has been ported and tested with varying degrees of @@ -114,7 +135,8 @@ 174K YouTube followers, 70+ Patreons and 8K Discord server members who give me the motivation to keep going with all this :D - Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka, @Dragoneye & @Gorbit99 + Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka, + @Dragoneye, @Gorbit99 & @Mumflr Special thanks to those who bring gifts! GnarGnarHead.......Domina @@ -155,6 +177,16 @@ +Added comparator operators for olc::vectors +Added DestroyWindow() on windows platforms for serial PGE launches +Added GetMousePos() to stop TarriestPython whinging + 2.08: Fix SetScreenSize() aspect ratio pre-calculation + Fix DrawExplicitDecal() - stupid oversight with multiple decals + Disabled olc::Sprite copy constructor + +olc::Sprite Duplicate() - produces a new clone of the sprite + +olc::Sprite Duplicate(pos, size) - produces a new sprite from the region defined + +Unary operators for vectors + +More pedant mollification - Thanks TheLandfill + +ImageLoader modules - user selectable image handling core, gdi+, libpng, stb_image + +Mac Support via GLUT - thanks Mumflr! + */ ////////////////////////////////////////////////////////////////////////////////////////// @@ -235,47 +267,68 @@ int main() #define USE_EXPERIMENTAL_FS #if defined(_WIN32) -#if _MSC_VER >= 1920 && _MSVC_LANG >= 201703L -#undef USE_EXPERIMENTAL_FS -#endif + #if _MSC_VER >= 1920 && _MSVC_LANG >= 201703L + #undef USE_EXPERIMENTAL_FS + #endif #endif -#if defined(__linux__) || defined(__MINGW32__) || defined(__EMSCRIPTEN__) || defined(__FreeBSD__) -#if __cplusplus >= 201703L -#undef USE_EXPERIMENTAL_FS +#if defined(__linux__) || defined(__MINGW32__) || defined(__EMSCRIPTEN__) || defined(__FreeBSD__) || defined(__APPLE__) + #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 -#else -#define olcT(s) s + #define olcT(s) L##s + #else + #define olcT(s) s #endif #define UNUSED(x) (void)(x) - #if !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) -#define OLC_GFX_OPENGL10 + #define OLC_GFX_OPENGL10 #endif +#if defined(_WIN32) + #if defined(OLC_IMAGE_STB) + #define PGE_ILOADER_STB + #else + #define PGE_ILOADER_GDI + #endif +#endif + +#if defined(__linux__) || defined(__APPLE__) + #if defined(OLC_IMAGE_STB) + #define PGE_ILOADER_STB + #else + #define PGE_ILOADER_LIBPNG + #endif +#endif + + // O------------------------------------------------------------------------------O // | olcPixelGameEngine INTERFACE DECLARATION | // O------------------------------------------------------------------------------O namespace olc { class PixelGameEngine; + class Sprite; // Pixel Game Engine Advanced Configuration constexpr uint8_t nMouseButtons = 5; @@ -283,8 +336,6 @@ namespace olc constexpr uint32_t nDefaultPixel = (nDefaultAlpha << 24); enum rcode { FAIL = 0, OK = 1, NO_FILE = -1 }; - - // O------------------------------------------------------------------------------O // | olc::Pixel - Represents a 32-Bit RGBA colour | // O------------------------------------------------------------------------------O @@ -346,9 +397,10 @@ namespace olc { T x = 0; T y = 0; - v2d_generic() : x(0), y(0) { } - v2d_generic(T _x, T _y) : x(_x), y(_y) { } - v2d_generic(const v2d_generic& v) : x(v.x), y(v.y) { } + v2d_generic() : x(0), y(0) {} + v2d_generic(T _x, T _y) : x(_x), y(_y) {} + v2d_generic(const v2d_generic& v) : x(v.x), y(v.y) {} + v2d_generic& operator=(const v2d_generic& v) = default; T mag() { return T(std::sqrt(x * x + y * y)); } T mag2() { return x * x + y * y; } v2d_generic norm() { T r = 1 / mag(); return v2d_generic(x * r, y * r); } @@ -365,6 +417,8 @@ namespace olc v2d_generic& operator -= (const v2d_generic& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; } v2d_generic& operator *= (const T& rhs) { this->x *= rhs; this->y *= rhs; return *this; } v2d_generic& operator /= (const T& rhs) { this->x /= rhs; this->y /= rhs; return *this; } + v2d_generic operator + () const { return { +x, +y }; } + v2d_generic operator - () const { return { -x, -y }; } bool operator == (const v2d_generic& rhs) const { return (this->x == rhs.x && this->y == rhs.y); } bool operator != (const v2d_generic& rhs) const { return (this->x != rhs.x || this->y != rhs.y); } const std::string str() const { return std::string("(") + std::to_string(this->x) + "," + std::to_string(this->y) + ")"; } @@ -377,29 +431,17 @@ 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)); } typedef v2d_generic vi2d; typedef v2d_generic vu2d; @@ -449,6 +491,15 @@ namespace olc }; + class ImageLoader + { + public: + ImageLoader() = default; + virtual ~ImageLoader() = default; + virtual olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) = 0; + virtual olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) = 0; + }; + // O------------------------------------------------------------------------------O // | olc::Sprite - An image represented by a 2D array of olc::Pixel | @@ -459,6 +510,7 @@ namespace olc Sprite(); Sprite(const std::string& sImageFile, olc::ResourcePack* pack = nullptr); Sprite(int32_t w, int32_t h); + Sprite(const olc::Sprite&) = delete; ~Sprite(); public: @@ -481,8 +533,12 @@ namespace olc Pixel Sample(float x, float y) const; Pixel SampleBL(float u, float v) const; Pixel* GetData(); + olc::Sprite* Duplicate(); + olc::Sprite* Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize); Pixel* pColData = nullptr; Mode modeSample = Mode::NORMAL; + + static std::unique_ptr loader; }; // O------------------------------------------------------------------------------O @@ -508,6 +564,7 @@ namespace olc { public: Renderable() = default; + virtual ~Renderable() = default; olc::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr); void Create(uint32_t width, uint32_t height); olc::Decal* Decal() const; @@ -556,6 +613,7 @@ namespace olc class Renderer { public: + virtual ~Renderer() = default; virtual void PrepareDevice() = 0; virtual olc::rcode CreateDevice(std::vector params, bool bFullScreen, bool bVSYNC) = 0; virtual olc::rcode DestroyDevice() = 0; @@ -575,6 +633,7 @@ namespace olc class Platform { public: + virtual ~Platform() = default; virtual olc::rcode ApplicationStartUp() = 0; virtual olc::rcode ApplicationCleanUp() = 0; virtual olc::rcode ThreadStartUp() = 0; @@ -587,6 +646,8 @@ namespace olc static olc::PixelGameEngine* ptrPGE; }; + + static std::unique_ptr renderer; static std::unique_ptr platform; static std::map mapKeys; @@ -614,17 +675,17 @@ namespace olc public: // Hardware Interfaces // Returns true if window is currently in focus - bool IsFocused(); + bool IsFocused() const; // Get the state of a specific keyboard button - HWButton GetKey(Key k); + HWButton GetKey(Key k) const; // Get the state of a specific mouse button - HWButton GetMouse(uint32_t b); + HWButton GetMouse(uint32_t b) const; // Get Mouse X coordinate in "pixel" space int32_t GetMouseX() const; // Get Mouse Y coordinate in "pixel" space int32_t GetMouseY() const; // Get Mouse Wheel Delta - int32_t GetMouseWheel(); + int32_t GetMouseWheel() const; // Get the mouse in window space const olc::vi2d& GetWindowMouse() const; // Gets the mouse as a vector to keep Tarriest happy @@ -632,24 +693,24 @@ namespace olc public: // Utility // Returns the width of the screen in "pixels" - int32_t ScreenWidth(); + int32_t ScreenWidth() const; // Returns the height of the screen in "pixels" - int32_t ScreenHeight(); + int32_t ScreenHeight() const; // Returns the width of the currently selected drawing target in "pixels" - int32_t GetDrawTargetWidth(); + int32_t GetDrawTargetWidth() const; // Returns the height of the currently selected drawing target in "pixels" - int32_t GetDrawTargetHeight(); + int32_t GetDrawTargetHeight() const; // Returns the currently active draw target - olc::Sprite* GetDrawTarget(); + olc::Sprite* GetDrawTarget() const; // Resize the primary screen sprite void SetScreenSize(int w, int h); // Specify which Sprite should be the target of drawing functions, use nullptr // to specify the primary screen void SetDrawTarget(Sprite* target); // Gets the current Frames Per Second - uint32_t GetFPS(); + uint32_t GetFPS() const; // Gets last update of elapsed time - const float GetElapsedTime() const; + float GetElapsedTime() const; // Gets Actual Window size const olc::vi2d& GetWindowSize() const; // Gets pixel scale @@ -681,9 +742,7 @@ namespace olc void SetPixelMode(std::function pixelMode); // Change the blend factor form between 0.0f to 1.0f; void SetPixelBlend(float fBlend); - // Offset texels by sub-pixel amount (advanced, do not use) - [[deprecated]] - void SetSubPixelOffset(float ox, float oy); + public: // DRAWING ROUTINES @@ -785,9 +844,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; @@ -796,14 +855,14 @@ namespace olc std::chrono::time_point m_tp1, m_tp2; // State of keyboard - bool pKeyNewState[256]{ 0 }; - bool pKeyOldState[256]{ 0 }; - HWButton pKeyboardState[256]{ 0 }; + bool pKeyNewState[256] = { 0 }; + bool pKeyOldState[256] = { 0 }; + HWButton pKeyboardState[256] = { 0 }; // State of mouse - bool pMouseNewState[nMouseButtons]{ 0 }; - bool pMouseOldState[nMouseButtons]{ 0 }; - HWButton pMouseState[nMouseButtons]{ 0 }; + bool pMouseNewState[nMouseButtons] = { 0 }; + bool pMouseOldState[nMouseButtons] = { 0 }; + HWButton pMouseState[nMouseButtons] = { 0 }; // The main engine thread void EngineThread(); @@ -891,9 +950,7 @@ namespace olc // | 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) { @@ -902,19 +959,13 @@ namespace olc 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 PixelF(float red, float green, float blue, float alpha) { @@ -1003,19 +1054,13 @@ namespace olc } 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 { @@ -1073,10 +1118,31 @@ namespace olc } Pixel* Sprite::GetData() + { return pColData; } + + + olc::rcode Sprite::LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack) { - return pColData; + UNUSED(pack); + return loader->LoadImageResource(this, sImageFile, pack); } + olc::Sprite* Sprite::Duplicate() + { + olc::Sprite* spr = new olc::Sprite(width, height); + std::memcpy(spr->GetData(), GetData(), width * height * sizeof(olc::Pixel)); + spr->modeSample = modeSample; + return spr; + } + + olc::Sprite* Sprite::Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize) + { + olc::Sprite* spr = new olc::Sprite(vSize.x, vSize.y); + for (int y = 0; y < vSize.y; y++) + for (int x = 0; x < vSize.x; x++) + spr->SetPixel(x, y, GetPixel(vPos.x + x, vPos.y + y)); + return spr; + } // O------------------------------------------------------------------------------O // | olc::Decal IMPLEMENTATION | @@ -1130,14 +1196,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 | @@ -1302,9 +1364,7 @@ namespace olc } bool ResourcePack::Loaded() - { - return baseFile.is_open(); - } + { return baseFile.is_open(); } std::vector ResourcePack::scramble(const std::vector& data, const std::string& key) { @@ -1361,6 +1421,7 @@ namespace olc void PixelGameEngine::SetScreenSize(int w, int h) { vScreenSize = { w, h }; + vInvScreenSize = { 1.0f / float(w), 1.0f / float(h) }; for (auto& layer : vLayers) { delete layer.pDrawTarget; // Erase existing layer sprites @@ -1459,9 +1520,7 @@ namespace olc } std::vector& PixelGameEngine::GetLayers() - { - return vLayers; - } + { return vLayers; } uint32_t PixelGameEngine::CreateLayer() { @@ -1473,12 +1532,10 @@ namespace olc return uint32_t(vLayers.size()) - 1; } - Sprite* PixelGameEngine::GetDrawTarget() - { - return pDrawTarget; - } + Sprite* PixelGameEngine::GetDrawTarget() const + { return pDrawTarget; } - int32_t PixelGameEngine::GetDrawTargetWidth() + int32_t PixelGameEngine::GetDrawTargetWidth() const { if (pDrawTarget) return pDrawTarget->width; @@ -1486,7 +1543,7 @@ namespace olc return 0; } - int32_t PixelGameEngine::GetDrawTargetHeight() + int32_t PixelGameEngine::GetDrawTargetHeight() const { if (pDrawTarget) return pDrawTarget->height; @@ -1494,90 +1551,50 @@ namespace olc return 0; } - uint32_t PixelGameEngine::GetFPS() - { - return nLastFPS; - } + uint32_t PixelGameEngine::GetFPS() const + { return nLastFPS; } - bool PixelGameEngine::IsFocused() - { - return bHasInputFocus; - } + bool PixelGameEngine::IsFocused() const + { return bHasInputFocus; } - HWButton PixelGameEngine::GetKey(Key k) - { - return pKeyboardState[k]; - } + HWButton PixelGameEngine::GetKey(Key k) const + { return pKeyboardState[k]; } - HWButton PixelGameEngine::GetMouse(uint32_t b) - { - return pMouseState[b]; - } + HWButton PixelGameEngine::GetMouse(uint32_t b) const + { 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() - { - return nMouseWheelDelta; - } + int32_t PixelGameEngine::GetMouseWheel() const + { return nMouseWheelDelta; } - int32_t PixelGameEngine::ScreenWidth() - { - return vScreenSize.x; - } + int32_t PixelGameEngine::ScreenWidth() const + { return vScreenSize.x; } - int32_t PixelGameEngine::ScreenHeight() - { - return vScreenSize.y; - } + int32_t PixelGameEngine::ScreenHeight() const + { return vScreenSize.y; } - const float PixelGameEngine::GetElapsedTime() const - { - return fLastElapsed; - } + float PixelGameEngine::GetElapsedTime() const + { 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) @@ -1620,11 +1637,6 @@ namespace olc return false; } - void PixelGameEngine::SetSubPixelOffset(float ox, float oy) - { - //vSubPixelOffset.x = ox * vPixel.x; - //vSubPixelOffset.y = oy * vPixel.y; - } void PixelGameEngine::DrawLine(const olc::vi2d& pos1, const olc::vi2d& pos2, Pixel p, uint32_t pattern) { @@ -2180,6 +2192,7 @@ namespace olc void PixelGameEngine::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col) { DecalInstance di; + di.decal = decal; for (int i = 0; i < 4; i++) { di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; @@ -2386,14 +2399,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) { @@ -2413,19 +2422,13 @@ 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() @@ -2483,29 +2486,19 @@ 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_Terminate() - { - bAtomActive = false; - } + { bAtomActive = false; } void PixelGameEngine::EngineThread() { @@ -2706,6 +2699,7 @@ namespace olc olc::PixelGameEngine* olc::PGEX::pge = nullptr; olc::PixelGameEngine* olc::Platform::ptrPGE = nullptr; olc::PixelGameEngine* olc::Renderer::ptrPGE = nullptr; + std::unique_ptr olc::Sprite::loader = nullptr; }; @@ -2718,29 +2712,38 @@ namespace olc // | START RENDERER: OpenGL 1.0 (the original, the best...) | // O------------------------------------------------------------------------------O #if defined(OLC_GFX_OPENGL10) -#if defined(_WIN32) -#include -#include -#include -typedef BOOL(WINAPI wglSwapInterval_t) (int interval); -static wglSwapInterval_t* wglSwapInterval = nullptr; -typedef HDC glDeviceContext_t; -typedef HGLRC glRenderContext_t; + #if defined(_WIN32) + #include + #include + #include + #pragma comment(lib, "Dwmapi.lib") + 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 -namespace X11 -{ -#include -#include -#include -} -#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; + #include + namespace X11 + { + #include + #include + #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 + #include #endif namespace olc @@ -2748,8 +2751,13 @@ namespace olc class Renderer_OGL10 : public olc::Renderer { private: +#if defined(__APPLE__) + bool mFullScreen = false; +#else glDeviceContext_t glDeviceContext = 0; glRenderContext_t glRenderContext = 0; +#endif + bool bSync = false; #if defined(__linux__) || defined(__FreeBSD__) @@ -2760,7 +2768,25 @@ namespace olc public: void PrepareDevice() override - { } + { +#if defined(__APPLE__) + //glutInit has to be called with main() arguments, make fake ones + 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 + } olc::rcode CreateDevice(std::vector params, bool bFullScreen, bool bVSYNC) override { @@ -2817,8 +2843,18 @@ namespace olc glSwapIntervalEXT(olc_Display, *olc_Window, 0); #endif +#if defined(__APPLE__) + mFullScreen = bFullScreen; + if (!bVSYNC) + { + GLint sync = 0; + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) CGLSetParameter(ctx, kCGLCPSwapInterval, &sync); + } +#else glEnable(GL_TEXTURE_2D); // Turn on texturing glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); +#endif return olc::rcode::OK; } @@ -2832,6 +2868,10 @@ namespace olc glXMakeCurrent(olc_Display, None, NULL); glXDestroyContext(olc_Display, glDeviceContext); #endif + +#if defined(__APPLE__) + glutDestroyWindow(glutGetWindow()); +#endif return olc::rcode::OK; } @@ -2845,6 +2885,10 @@ namespace olc #if defined(__linux__) || defined(__FreeBSD__) X11::glXSwapBuffers(olc_Display, *olc_Window); #endif + +#if defined(__APPLE__) + glutSwapBuffers(); +#endif } void PrepareDrawing() override @@ -2899,6 +2943,8 @@ namespace olc uint32_t CreateTexture(const uint32_t width, const uint32_t height) override { + UNUSED(width); + UNUSED(height); uint32_t id = 0; glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); @@ -2918,6 +2964,7 @@ namespace olc void UpdateTexture(uint32_t id, olc::Sprite* spr) override { + UNUSED(id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spr->width, spr->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); } @@ -2935,7 +2982,11 @@ namespace olc void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) override { +#if defined(__APPLE__) + if (!mFullScreen) glutReshapeWindow(size.x, size.y); +#else glViewport(pos.x, pos.y, size.x, size.y); +#endif } }; } @@ -2945,30 +2996,12 @@ namespace olc // O------------------------------------------------------------------------------O + // O------------------------------------------------------------------------------O -// | START PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 | +// | START IMAGE LOADER: GDI+, Windows Only, always exists, a little slow | // O------------------------------------------------------------------------------O -#if defined(_WIN32) +#if defined(PGE_ILOADER_GDI) #if !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, "gdiplus.lib") -#pragma comment(lib, "Shlwapi.lib") -#pragma comment(lib, "Dwmapi.lib") -#else - // 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 -#endif - -// Include WinAPI -#if !defined(NOMINMAX) #define NOMINMAX #endif #define VC_EXTRALEAN @@ -2976,29 +3009,11 @@ namespace olc #include #include #include -#include +#pragma comment(lib, "gdiplus.lib") +#pragma comment(lib, "Shlwapi.lib") namespace olc { - // Little utility function to convert from char to wchar in Windows environments - // depending upon how the compiler is configured. This should not be necessary - // on linux platforms - std::wstring ConvertS2W(std::string s) - { -#ifdef __MINGW32__ - wchar_t* buffer = new wchar_t[s.length() + 1]; - mbstowcs(buffer, s.c_str(), s.length()); - buffer[s.length()] = L'\0'; -#else - int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); - wchar_t* buffer = new wchar_t[count]; - MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); -#endif - std::wstring w(buffer); - delete[] buffer; - return w; - } - // Thanks @MaGetzUb for this, which allows sprites to be defined // at construction, by initialising the GDI subsystem static class GDIPlusStartup @@ -3012,13 +3027,328 @@ namespace olc }; } gdistartup; + class ImageLoader_GDIPlus : public olc::ImageLoader + { + private: + std::wstring ConvertS2W(std::string s) + { +#ifdef __MINGW32__ + wchar_t* buffer = new wchar_t[s.length() + 1]; + mbstowcs(buffer, s.c_str(), s.length()); + buffer[s.length()] = L'\0'; +#else + int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + wchar_t* buffer = new wchar_t[count]; + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); +#endif + std::wstring w(buffer); + delete[] buffer; + return w; + } + + public: + ImageLoader_GDIPlus() : ImageLoader() + {} + + olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override + { + // Check file exists + if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE; + + // It does, so clear out existing sprite + if (spr->pColData != nullptr) delete[] spr->pColData; + + // Open file + UNUSED(pack); + Gdiplus::Bitmap* bmp = nullptr; + if (pack != nullptr) + { + // Load sprite from input stream + ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + bmp = Gdiplus::Bitmap::FromStream(SHCreateMemStream((BYTE*)rb.vMemory.data(), UINT(rb.vMemory.size()))); + } + else + { + // Load sprite from file + bmp = Gdiplus::Bitmap::FromFile(ConvertS2W(sImageFile).c_str()); + } + + 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]; + + for (int y = 0; y < spr->height; y++) + for (int x = 0; x < spr->width; x++) + { + Gdiplus::Color c; + bmp->GetPixel(x, y, &c); + spr->SetPixel(x, y, olc::Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha())); + } + delete bmp; + return olc::rcode::OK; + } + + olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override + { + return olc::rcode::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END IMAGE LOADER: GDI+ | +// O------------------------------------------------------------------------------O + + + + +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: libpng, default on linux, requires -lpng (libpng-dev) | +// O------------------------------------------------------------------------------O +#if defined(PGE_ILOADER_LIBPNG) +#include +namespace olc +{ + void pngReadStream(png_structp pngPtr, png_bytep data, png_size_t length) + { + png_voidp a = png_get_io_ptr(pngPtr); + ((std::istream*)a)->read((char*)data, length); + } + + class ImageLoader_LibPNG : public olc::ImageLoader + { + public: + ImageLoader_LibPNG() : ImageLoader() + {} + + olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override + { + UNUSED(pack); + + // Check file exists + if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE; + + // It does, so clear out existing sprite + if (spr->pColData != nullptr) delete[] spr->pColData; + + + //////////////////////////////////////////////////////////////////////////// + // Use libpng, Thanks to Guillaume Cottenceau + // https://gist.github.com/niw/5963798 + // Also reading png from streams + // http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/ + png_structp png; + png_infop info; + + auto loadPNG = [&]() + { + png_read_info(png, info); + png_byte color_type; + png_byte bit_depth; + png_bytep* row_pointers; + spr->width = png_get_image_width(png, info); + spr->height = png_get_image_height(png, info); + color_type = png_get_color_type(png, info); + bit_depth = png_get_bit_depth(png, info); + if (bit_depth == 16) png_set_strip_16(png); + if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); + if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); + if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) + png_set_filler(png, 0xFF, PNG_FILLER_AFTER); + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + png_read_update_info(png, info); + row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * spr->height); + for (int y = 0; y < spr->height; y++) { + row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); + } + png_read_image(png, row_pointers); + //////////////////////////////////////////////////////////////////////////// + // Create sprite array + spr->pColData = new Pixel[spr->width * spr->height]; + // Iterate through image rows, converting into sprite format + for (int y = 0; y < spr->height; y++) + { + png_bytep row = row_pointers[y]; + for (int x = 0; x < spr->width; x++) + { + png_bytep px = &(row[x * 4]); + spr->SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3])); + } + } + + for (int y = 0; y < spr->height; y++) // Thanks maksym33 + free(row_pointers[y]); + free(row_pointers); + png_destroy_read_struct(&png, &info, nullptr); + }; + png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png) goto fail_load; + + info = png_create_info_struct(png); + if (!info) goto fail_load; + + if (setjmp(png_jmpbuf(png))) goto fail_load; + + if (pack == nullptr) + { + FILE* f = fopen(sImageFile.c_str(), "rb"); + if (!f) return olc::rcode::NO_FILE; + png_init_io(png, f); + loadPNG(); + fclose(f); + } + else + { + ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + std::istream is(&rb); + png_set_read_fn(png, (png_voidp)&is, pngReadStream); + loadPNG(); + } + + return olc::rcode::OK; + + fail_load: + spr->width = 0; + spr->height = 0; + spr->pColData = nullptr; + return olc::rcode::FAIL; + } + + olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override + { + return olc::rcode::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END IMAGE LOADER: | +// O------------------------------------------------------------------------------O + + + + +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: stb_image.h, all systems, very fast | +// O------------------------------------------------------------------------------O +// Thanks to Sean Barrett - https://github.com/nothings/stb/blob/master/stb_image.h +// MIT License - Copyright(c) 2017 Sean Barrett + +// Note you need to download the above file into your project folder, and +// #define OLC_IMAGE_STB +// #define OLC_PGE_APPLICATION +// #include "olcPixelGameEngine.h" + +#if defined(PGE_ILOADER_STB) +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +namespace olc +{ + class ImageLoader_STB : public olc::ImageLoader + { + public: + ImageLoader_STB() : ImageLoader() + {} + + olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override + { + UNUSED(pack); + + // Check file exists + if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE; + + // It does, so clear out existing sprite + if (spr->pColData != nullptr) delete[] spr->pColData; + + // Open file + stbi_uc* bytes = nullptr; + int w = 0, h = 0, cmp = 0; + if (pack != nullptr) + { + ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + bytes = stbi_load_from_memory((unsigned char*)rb.vMemory.data(), rb.vMemory.size(), &w, &h, &cmp, 4); + } + else + { + bytes = stbi_load(sImageFile.c_str(), &w, &h, &cmp, 4); + } + + 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); + delete[] bytes; + return olc::rcode::OK; + } + + olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override + { + return olc::rcode::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: stb_image.h | +// O------------------------------------------------------------------------------O + + +// O------------------------------------------------------------------------------O +// | START PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 | +// O------------------------------------------------------------------------------O +#if defined(_WIN32) +#if !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 + +#else + // 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 +#endif + +// Include WinAPI +#if !defined(__MINGW32__) +#define NOMINMAX +#endif +#define VC_EXTRALEAN +#define WIN32_LEAN_AND_MEAN +#include + +namespace olc +{ class Platform_Windows : public olc::Platform { private: HWND olc_hWnd = nullptr; std::wstring wsAppName; + std::wstring ConvertS2W(std::string s) + { +#ifdef __MINGW32__ + wchar_t* buffer = new wchar_t[s.length() + 1]; + mbstowcs(buffer, s.c_str(), s.length()); + buffer[s.length()] = L'\0'; +#else + int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + wchar_t* buffer = new wchar_t[count]; + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); +#endif + std::wstring w(buffer); + delete[] buffer; + return w; + } + public: virtual olc::rcode ApplicationStartUp() override { return olc::rcode::OK; } virtual olc::rcode ApplicationCleanUp() override { return olc::rcode::OK; } @@ -3171,39 +3501,6 @@ namespace olc return DefWindowProc(hWnd, uMsg, wParam, lParam); } }; - - // On Windows load images using GDI+ library - olc::rcode Sprite::LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack) - { - UNUSED(pack); - Gdiplus::Bitmap* bmp = nullptr; - if (pack != nullptr) - { - // Load sprite from input stream - ResourceBuffer rb = pack->GetFileBuffer(sImageFile); - bmp = Gdiplus::Bitmap::FromStream(SHCreateMemStream((BYTE*)rb.vMemory.data(), UINT(rb.vMemory.size()))); - } - else - { - // Load sprite from file - bmp = Gdiplus::Bitmap::FromFile(ConvertS2W(sImageFile).c_str()); - } - - if (bmp->GetLastStatus() != Gdiplus::Ok) return olc::NO_FILE; - width = bmp->GetWidth(); - height = bmp->GetHeight(); - pColData = new Pixel[width * height]; - - for (int y = 0; y < height; y++) - for (int x = 0; x < width; x++) - { - Gdiplus::Color c; - bmp->GetPixel(x, y, &c); - SetPixel(x, y, olc::Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha())); - } - delete bmp; - return olc::OK; - } } #endif // O------------------------------------------------------------------------------O @@ -3232,19 +3529,13 @@ namespace olc public: virtual olc::rcode ApplicationStartUp() override - { - return olc::rcode::OK; - } + { return olc::rcode::OK; } virtual olc::rcode ApplicationCleanUp() override - { - return olc::rcode::OK; - } + { return olc::rcode::OK; } virtual olc::rcode ThreadStartUp() override - { - return olc::rcode::OK; - } + { return olc::rcode::OK; } virtual olc::rcode ThreadCleanUp() override { @@ -3358,9 +3649,7 @@ namespace olc } virtual olc::rcode StartSystemEventLoop() override - { - return olc::OK; - } + { return olc::OK; } virtual olc::rcode HandleSystemEvent() override { @@ -3441,115 +3730,293 @@ namespace olc return olc::OK; } }; +} +#endif +// O------------------------------------------------------------------------------O +// | END PLATFORM: LINUX | +// O------------------------------------------------------------------------------O - void pngReadStream(png_structp pngPtr, png_bytep data, png_size_t length) - { - png_voidp a = png_get_io_ptr(pngPtr); - ((std::istream*)a)->read((char*)data, length); - } - olc::rcode Sprite::LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack) + + +// O------------------------------------------------------------------------------O +// | START PLATFORM: GLUT (used to make it simple for Apple) | +// O------------------------------------------------------------------------------O +// +// VERY IMPORTANT!!! The Apple port was originally created by @Mumflr (discord) +// and the repo for the development of this project can be found here: +// https://github.com/MumflrFumperdink/olcPGEMac which contains maccy goodness +// and support on how to setup your build environment. +// +// "MASSIVE MASSIVE THANKS TO MUMFLR" - Javidx9 +#if defined(__APPLE__) +namespace olc { + + class Platform_GLUT : public olc::Platform { - UNUSED(pack); - //////////////////////////////////////////////////////////////////////////// - // Use libpng, Thanks to Guillaume Cottenceau - // https://gist.github.com/niw/5963798 - - // Also reading png from streams - // http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/ - - png_structp png; - png_infop info; - - auto loadPNG = [&]() - { - png_read_info(png, info); - png_byte color_type; - png_byte bit_depth; - png_bytep* row_pointers; - width = png_get_image_width(png, info); - height = png_get_image_height(png, info); - color_type = png_get_color_type(png, info); - bit_depth = png_get_bit_depth(png, info); - if (bit_depth == 16) png_set_strip_16(png); - if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); - if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_PALETTE) - png_set_filler(png, 0xFF, PNG_FILLER_AFTER); - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - png_read_update_info(png, info); - row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); - for (int y = 0; y < height; y++) { - row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); + public: + static std::atomic* bActiveRef; + + virtual olc::rcode ApplicationStartUp() override { + return olc::rcode::OK; + } + + virtual olc::rcode ApplicationCleanUp() override + { + 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; } - png_read_image(png, row_pointers); - //////////////////////////////////////////////////////////////////////////// - // Create sprite array - pColData = new Pixel[width * height]; - // Iterate through image rows, converting into sprite format - for (int y = 0; y < height; y++) + else + return olc::rcode::FAIL; + } + + static void ExitMainLoop() { + if (!ptrPGE->OnUserDestroy()) { + *bActiveRef = true; + return; + } + platform->ThreadCleanUp(); + platform->ApplicationCleanUp(); + exit(0); + } + + static void ThreadFunct() { + if (!*bActiveRef) { + ExitMainLoop(); + return; + } + glutPostRedisplay(); + } + + static void DrawFunct() { + ptrPGE->olc_CoreUpdate(); + } + + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override + { + renderer->PrepareDevice(); + + + if (bFullScreen) { - png_bytep row = row_pointers[y]; - for (int x = 0; x < width; x++) - { - png_bytep px = &(row[x * 4]); - SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3])); - } + vWindowSize.x = glutGet(GLUT_SCREEN_WIDTH); + vWindowSize.y = glutGet(GLUT_SCREEN_HEIGHT); + glutFullScreen(); } - for (int y = 0; y < height; y++) // Thanks maksym33 - free(row_pointers[y]); - free(row_pointers); - png_destroy_read_struct(&png, &info, nullptr); - }; + if (vWindowSize.x > glutGet(GLUT_SCREEN_WIDTH) || vWindowSize.y > glutGet(GLUT_SCREEN_HEIGHT)) { + perror("ERROR: The specified window dimensions do not fit on your screen\n"); + return olc::FAIL; + } - png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png) goto fail_load; + // Create Keyboard Mapping + mapKeys[0x00] = Key::NONE; + mapKeys['A'] = Key::A; mapKeys['B'] = Key::B; mapKeys['C'] = Key::C; mapKeys['D'] = Key::D; mapKeys['E'] = Key::E; + mapKeys['F'] = Key::F; mapKeys['G'] = Key::G; mapKeys['H'] = Key::H; mapKeys['I'] = Key::I; mapKeys['J'] = Key::J; + mapKeys['K'] = Key::K; mapKeys['L'] = Key::L; mapKeys['M'] = Key::M; mapKeys['N'] = Key::N; mapKeys['O'] = Key::O; + mapKeys['P'] = Key::P; mapKeys['Q'] = Key::Q; mapKeys['R'] = Key::R; mapKeys['S'] = Key::S; mapKeys['T'] = Key::T; + mapKeys['U'] = Key::U; mapKeys['V'] = Key::V; mapKeys['W'] = Key::W; mapKeys['X'] = Key::X; mapKeys['Y'] = Key::Y; + mapKeys['Z'] = Key::Z; + + mapKeys[GLUT_KEY_F1] = Key::F1; mapKeys[GLUT_KEY_F2] = Key::F2; mapKeys[GLUT_KEY_F3] = Key::F3; mapKeys[GLUT_KEY_F4] = Key::F4; + mapKeys[GLUT_KEY_F5] = Key::F5; mapKeys[GLUT_KEY_F6] = Key::F6; mapKeys[GLUT_KEY_F7] = Key::F7; mapKeys[GLUT_KEY_F8] = Key::F8; + mapKeys[GLUT_KEY_F9] = Key::F9; mapKeys[GLUT_KEY_F10] = Key::F10; mapKeys[GLUT_KEY_F11] = Key::F11; mapKeys[GLUT_KEY_F12] = Key::F12; + + mapKeys[GLUT_KEY_DOWN] = Key::DOWN; mapKeys[GLUT_KEY_LEFT] = Key::LEFT; mapKeys[GLUT_KEY_RIGHT] = Key::RIGHT; mapKeys[GLUT_KEY_UP] = Key::UP; + mapKeys[13] = Key::ENTER; + + mapKeys[127] = Key::BACK; mapKeys[27] = Key::ESCAPE; + mapKeys[9] = Key::TAB; mapKeys[GLUT_KEY_HOME] = Key::HOME; + mapKeys[GLUT_KEY_END] = Key::END; mapKeys[GLUT_KEY_PAGE_UP] = Key::PGUP; mapKeys[GLUT_KEY_PAGE_DOWN] = Key::PGDN; mapKeys[GLUT_KEY_INSERT] = Key::INS; + mapKeys[32] = Key::SPACE; mapKeys[46] = Key::PERIOD; + + mapKeys[48] = Key::K0; mapKeys[49] = Key::K1; mapKeys[50] = Key::K2; mapKeys[51] = Key::K3; mapKeys[52] = Key::K4; + mapKeys[53] = Key::K5; mapKeys[54] = Key::K6; mapKeys[55] = Key::K7; mapKeys[56] = Key::K8; mapKeys[57] = Key::K9; + + glutKeyboardFunc([](unsigned char key, int x, int y) -> void { + switch (glutGetModifiers()) { + case 0: //This is when there are no modifiers + if ('a' <= key && key <= 'z') key -= 32; + break; + case GLUT_ACTIVE_SHIFT: + ptrPGE->olc_UpdateKeyState(Key::SHIFT, true); + break; + case GLUT_ACTIVE_CTRL: + if ('a' <= key && key <= 'z') key -= 32; + ptrPGE->olc_UpdateKeyState(Key::CTRL, true); + break; + case GLUT_ACTIVE_ALT: + if ('a' <= key && key <= 'z') key -= 32; + break; + } - info = png_create_info_struct(png); - if (!info) goto fail_load; + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], true); + }); + + glutKeyboardUpFunc([](unsigned char key, int x, int y) -> void { + switch (glutGetModifiers()) { + case 0: //This is when there are no modifiers + if ('a' <= key && key <= 'z') key -= 32; + break; + case GLUT_ACTIVE_SHIFT: + ptrPGE->olc_UpdateKeyState(Key::SHIFT, false); + break; + case GLUT_ACTIVE_CTRL: + if ('a' <= key && key <= 'z') key -= 32; + ptrPGE->olc_UpdateKeyState(Key::CTRL, false); + break; + case GLUT_ACTIVE_ALT: + if ('a' <= key && key <= 'z') key -= 32; + //No ALT in PGE + break; + } - if (setjmp(png_jmpbuf(png))) goto fail_load; + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], false); + }); + + //Special keys + glutSpecialFunc([](int key, int x, int y) -> void { + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], true); + }); + + glutSpecialUpFunc([](int key, int x, int y) -> void { + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], false); + }); + + glutMouseFunc([](int button, int state, int x, int y) -> void { + switch (button) { + case GLUT_LEFT_BUTTON: + if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(0, false); + else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(0, true); + break; + case GLUT_MIDDLE_BUTTON: + if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(2, false); + else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(2, true); + break; + case GLUT_RIGHT_BUTTON: + if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(1, false); + else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(1, true); + break; + } + }); - if (pack == nullptr) + auto mouseMoveCall = [](int x, int y) -> void { + ptrPGE->olc_UpdateMouse(x, y); + }; + + glutMotionFunc(mouseMoveCall); + glutPassiveMotionFunc(mouseMoveCall); + + glutEntryFunc([](int state) -> void { + if (state == GLUT_ENTERED) ptrPGE->olc_UpdateKeyFocus(true); + else if (state == GLUT_LEFT) ptrPGE->olc_UpdateKeyFocus(false); + }); + + glutDisplayFunc(DrawFunct); + glutIdleFunc(ThreadFunct); + + return olc::OK; + } + + virtual olc::rcode SetWindowTitle(const std::string& s) override { - FILE* f = fopen(sImageFile.c_str(), "rb"); - if (!f) return olc::NO_FILE; - png_init_io(png, f); - loadPNG(); - fclose(f); + glutSetWindowTitle(s.c_str()); + return olc::OK; } - else + + virtual olc::rcode StartSystemEventLoop() override { + glutMainLoop(); + return olc::OK; + } + + virtual olc::rcode HandleSystemEvent() override { - ResourceBuffer rb = pack->GetFileBuffer(sImageFile); - std::istream is(&rb); - png_set_read_fn(png, (png_voidp)&is, pngReadStream); - loadPNG(); + return olc::OK; } + }; - return olc::OK; + std::atomic* Platform_GLUT::bActiveRef{ nullptr }; - fail_load: - width = 0; - height = 0; - pColData = nullptr; - return olc::FAIL; + //Custom Start + 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); + + + if (platform->ThreadStartUp() == olc::FAIL) return olc::FAIL; + + olc_PrepareEngine(); + + if (!OnUserCreate()) return olc::FAIL; + + Platform_GLUT::bActiveRef = &bAtomActive; + + glutWMCloseFunc(Platform_GLUT::ExitMainLoop); + + bAtomActive = true; + + platform->StartSystemEventLoop(); + + //This code will not even be run but why not + if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL; + + return olc::OK; } } + #endif // O------------------------------------------------------------------------------O -// | END PLATFORM: LINUX | +// | END PLATFORM: GLUT | // O------------------------------------------------------------------------------O + + namespace olc { void PixelGameEngine::olc_ConfigureSystem() { + +#if defined(PGE_ILOADER_GDI) + olc::Sprite::loader = std::make_unique(); +#endif + +#if defined(PGE_ILOADER_LIBPNG) + olc::Sprite::loader = std::make_unique(); +#endif + +#if defined(PGE_ILOADER_STB) + olc::Sprite::loader = std::make_unique(); +#endif + + + + #if defined(_WIN32) platform = std::make_unique(); #endif @@ -3558,6 +4025,12 @@ namespace olc platform = std::make_unique(); #endif +#if defined(__APPLE__) + platform = std::make_unique(); +#endif + + + #if defined(OLC_GFX_OPENGL10) renderer = std::make_unique(); #endif @@ -3570,7 +4043,7 @@ namespace olc renderer = std::make_unique(); #endif - //// Associate components with PGE instance + // Associate components with PGE instance platform->ptrPGE = this; renderer->ptrPGE = this; }