diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index d969d78..7b24a29 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -2,7 +2,7 @@ olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.09 | + | OneLoneCoder Pixel Game Engine v2.10 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -28,7 +28,7 @@ License (OLC-3) ~~~~~~~~~~~~~~~ - Copyright 2018 - 2020 OneLoneCoder.com + Copyright 2018 - 2021 OneLoneCoder.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -113,7 +113,7 @@ 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 @@ -132,27 +132,27 @@ 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 - 200K YouTube followers, 80+ Patreons and 10K Discord server members who give me + 210K 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, + Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka, @Dragoneye, @Gorbit99 & @Mumflr Special thanks to those who bring gifts! GnarGnarHead.......Domina - Gorbit99...........Bastion, Ori & The Blind Forest, Terraria + Gorbit99...........Bastion, Ori & The Blind Forest, Terraria, Spelunky 2 Marti Morta........Gris Danicron...........Terraria - SaladinAkara.......Aseprite + SaladinAkara.......Aseprite, Inside AlterEgo...........Final Fantasy XII - The Zodiac Age - SlicEnDicE.........Noita + SlicEnDicE.........Noita, Inside 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 + David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020, 2021 2.01: Made renderer and platform static for multifile projects 2.02: Added Decal destructor, optimised Pixel constructor @@ -195,8 +195,22 @@ +Pixel Operators & Lerping +Filtered Decals - If you hate pixels, then erase this file +DrawStringProp(), GetTextSizeProp(), DrawStringPropDecal() - Draws non-monospaced font - - + 2.10: Fix PixelLerp() - oops my bad, lerped the wrong way :P + Fix "Shader" support for strings - thanks Megarev for crying about it + Fix GetTextSizeProp() - Height was just plain wrong... + +vec2d operator overloads (element wise *=, /=) + +vec2d comparison operators... :| yup... hmmmm... + +vec2d ceil(), floor(), min(), max() functions - surprising how often I do it manually + +DrawExplicitDecal(... uint32_t elements) - complete control over convex polygons and lines + +DrawPolygonDecal() - to keep Bispoo happy, required significant rewrite of EVERYTHING, but hey ho + +Complete rewrite of decal renderer + +OpenGL 3.3 Renderer (also supports Raspberry Pi) + +PGEX Break-In Hooks - with a push from Dandistine + +Wireframe Decal Mode - For debug overlays + + + !! 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 !! */ ////////////////////////////////////////////////////////////////////////////////////////// @@ -216,7 +230,7 @@ class Example : public olc::PixelGameEngine public: Example() { - // Name you application + // Name your application sAppName = "Example"; } @@ -271,42 +285,44 @@ int main() #include #include +#define PGE_VER 210 + // O------------------------------------------------------------------------------O // | COMPILER CONFIGURATION ODDITIES | // O------------------------------------------------------------------------------O #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__) || 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 +#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) @@ -317,30 +333,30 @@ int main() // 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 - #endif +#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 +#endif #endif // Renderer -#if !defined(OLC_GFX_OPENGL10) || !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) - #define OLC_GFX_OPENGL10 +#if !defined(OLC_GFX_OPENGL10) && !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) +#define OLC_GFX_OPENGL10 #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(_WIN32) +#define OLC_IMAGE_GDI +#endif +#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) +#define OLC_IMAGE_LIBPNG +#endif #endif @@ -348,49 +364,49 @@ int main() // | 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(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_ #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 +#define PGE_USE_CUSTOM_START +#if defined(__linux__) +#include +#include +#endif +#if defined(__APPLE__) +#include +#endif #endif @@ -456,7 +472,7 @@ namespace olc WHITE(255, 255, 255), BLACK(0, 0, 0), BLANK(0, 0, 0, 0); // Thanks to scripticuk and others for updating the key maps - // MOTE: The GLUT platform will need updating, open to contributions ;) + // NOTE: The GLUT platform will need updating, open to contributions ;) enum Key { NONE, @@ -492,6 +508,10 @@ namespace olc T mag2() const { return x * x + y * y; } v2d_generic norm() const { T r = 1 / mag(); return v2d_generic(x * r, y * r); } v2d_generic perp() const { return v2d_generic(-y, x); } + v2d_generic floor() const { return v2d_generic(std::floor(x), std::floor(y)); } + v2d_generic ceil() const { return v2d_generic(std::ceil(x), std::ceil(y)); } + v2d_generic max(const v2d_generic& v) const { return v2d_generic(std::max(x, v.x), std::max(y, v.y)); } + v2d_generic min(const v2d_generic& v) const { return v2d_generic(std::min(x, v.x), std::min(y, v.y)); } T dot(const v2d_generic& rhs) const { return this->x * rhs.x + this->y * rhs.y; } T cross(const v2d_generic& rhs) const { return this->x * rhs.y - this->y * rhs.x; } v2d_generic operator + (const v2d_generic& rhs) const { return v2d_generic(this->x + rhs.x, this->y + rhs.y); } @@ -504,6 +524,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 v2d_generic& rhs) { this->x *= rhs.x; this->y *= rhs.y; return *this; } + v2d_generic& operator /= (const v2d_generic& rhs) { this->x /= rhs.x; this->y /= rhs.y; 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); } @@ -518,17 +540,39 @@ 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); + } + 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); + } typedef v2d_generic vi2d; typedef v2d_generic vu2d; @@ -635,8 +679,10 @@ namespace olc { public: Decal(olc::Sprite* spr, bool filter = false); + Decal(const uint32_t nExistingTextureResource, olc::Sprite* spr); virtual ~Decal(); void Update(); + void UpdateSprite(); public: // But dont touch int32_t id = -1; @@ -651,6 +697,7 @@ namespace olc MULTIPLICATIVE, STENCIL, ILLUMINATE, + WIREFRAME, }; // O------------------------------------------------------------------------------O @@ -678,19 +725,12 @@ namespace olc struct DecalInstance { olc::Decal* decal = nullptr; - olc::vf2d pos[4] = { { 0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f} }; - olc::vf2d uv[4] = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; - float w[4] = { 1, 1, 1, 1 }; - olc::Pixel tint[4] = { olc::WHITE, olc::WHITE, olc::WHITE, olc::WHITE }; + std::vector pos; + std::vector uv; + std::vector w; + std::vector tint; olc::DecalMode mode = olc::DecalMode::NORMAL; - }; - - struct DecalTriangleInstance - { - olc::vf2d points[3]; - olc::vf2d texture[3]; - olc::Pixel colours[3]; - olc::Decal* decal = nullptr; + uint32_t points = 0; }; struct LayerDesc @@ -717,9 +757,10 @@ namespace olc virtual void PrepareDrawing() = 0; 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 DrawDecalQuad(const olc::DecalInstance& decal) = 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 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; virtual void ApplyTexture(uint32_t id) = 0; virtual void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) = 0; @@ -743,7 +784,9 @@ namespace olc static olc::PixelGameEngine* ptrPGE; }; - + class PGEX; + + static std::unique_ptr renderer; static std::unique_ptr platform; @@ -837,9 +880,9 @@ namespace olc Pixel::Mode GetPixelMode(); // Use a custom blend function void SetPixelMode(std::function pixelMode); - // Change the blend factor form between 0.0f to 1.0f; + // Change the blend factor from between 0.0f to 1.0f; void SetPixelBlend(float fBlend); - + public: // DRAWING ROUTINES @@ -867,7 +910,7 @@ namespace olc // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3) void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); void FillTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p = olc::WHITE); - // Draws an entire sprite at well location (x,y) + // Draws an entire sprite at location (x,y) void DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); void DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); // Draws an area of a sprite at location (x,y), where the @@ -883,7 +926,7 @@ namespace olc void DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); void DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); // Draws fully user controlled 4 vertices, pos(pixels), uv(pixels), colours - void DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col); + void DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements = 4); // Draws a decal with 4 arbitrary points, warping the texture to look "correct" void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint = olc::WHITE); void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint = olc::WHITE); @@ -902,7 +945,8 @@ namespace olc void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE); // Draws a corner shaded rectangle as a decal 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); @@ -922,7 +966,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 }; @@ -945,9 +989,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; @@ -997,7 +1041,14 @@ namespace olc // in case you are using them, but they will be removed. // olc::vf2d vSubPixelOffset = { 0.0f, 0.0f }; + public: // PGEX Stuff friend class PGEX; + void pgex_Register(olc::PGEX* pgex); + + private: + std::vector vExtensions; + + }; @@ -1008,6 +1059,15 @@ namespace olc class PGEX { friend class olc::PixelGameEngine; + public: + PGEX(); + + protected: + virtual void OnBeforeUserCreate(); + virtual void OnAfterUserCreate(); + virtual void OnBeforeUserUpdate(float &fElapsedTime); + virtual void OnAfterUserUpdate(float fElapsedTime); + protected: static PixelGameEngine* pge; }; @@ -1053,7 +1113,9 @@ 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) { @@ -1062,14 +1124,20 @@ 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 Pixel::operator * (const float i) const { float fR = std::min(255.0f, std::max(0.0f, float(r) * i)); @@ -1149,7 +1217,7 @@ namespace olc Pixel PixelLerp(const olc::Pixel& p1, const olc::Pixel& p2, float t) { - return (p1 * t) + p2 * (1.0f - t); + return (p2 * t) + p1 * (1.0f - t); } // O------------------------------------------------------------------------------O @@ -1234,13 +1302,19 @@ 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 { @@ -1298,7 +1372,9 @@ namespace olc } Pixel* Sprite::GetData() - { return pColData; } + { + return pColData; + } olc::rcode Sprite::LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack) @@ -1321,7 +1397,7 @@ namespace olc 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; + return spr; } // O------------------------------------------------------------------------------O @@ -1336,6 +1412,12 @@ namespace olc Update(); } + Decal::Decal(const uint32_t nExistingTextureResource, olc::Sprite* spr) + { + if (spr == nullptr) return; + id = nExistingTextureResource; + } + void Decal::Update() { if (sprite == nullptr) return; @@ -1344,6 +1426,13 @@ namespace olc renderer->UpdateTexture(id, sprite); } + void Decal::UpdateSprite() + { + if (sprite == nullptr) return; + renderer->ApplyTexture(id); + renderer->ReadTexture(id, sprite); + } + Decal::~Decal() { if (id != -1) @@ -1376,10 +1465,14 @@ 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 | @@ -1544,7 +1637,9 @@ 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) { @@ -1700,7 +1795,9 @@ namespace olc } std::vector& PixelGameEngine::GetLayers() - { return vLayers; } + { + return vLayers; + } uint32_t PixelGameEngine::CreateLayer() { @@ -1713,7 +1810,9 @@ namespace olc } Sprite* PixelGameEngine::GetDrawTarget() const - { return pDrawTarget; } + { + return pDrawTarget; + } int32_t PixelGameEngine::GetDrawTargetWidth() const { @@ -1732,49 +1831,79 @@ 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) @@ -2278,27 +2407,25 @@ namespace olc { olc::vf2d vScreenSpacePos = { - (pos.x * vInvScreenSize.x) * 2.0f - 1.0f, - ((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f + (std::floor(pos.x) * vInvScreenSize.x) * 2.0f - 1.0f, + ((std::floor(pos.y) * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; olc::vf2d vScreenSpaceDim = { - vScreenSpacePos.x + (2.0f * source_size.x * vInvScreenSize.x) * scale.x, - vScreenSpacePos.y - (2.0f * source_size.y * vInvScreenSize.y) * scale.y + vScreenSpacePos.x + (2.0f * std::ceil(source_size.x) * vInvScreenSize.x) * scale.x, + vScreenSpacePos.y - (2.0f * std::ceil(source_size.y) * vInvScreenSize.y) * scale.y }; - DecalInstance di; di.decal = decal; di.tint[0] = tint; - - di.pos[0] = { vScreenSpacePos.x, vScreenSpacePos.y }; - di.pos[1] = { vScreenSpacePos.x, vScreenSpaceDim.y }; - di.pos[2] = { vScreenSpaceDim.x, vScreenSpaceDim.y }; - di.pos[3] = { vScreenSpaceDim.x, vScreenSpacePos.y }; - + DecalInstance di; + di.points = 4; + di.decal = decal; + di.tint = { tint, tint, tint, tint }; + di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } }; olc::vf2d uvtl = source_pos * decal->vUVScale; olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale); - di.uv[0] = { uvtl.x, uvtl.y }; di.uv[1] = { uvtl.x, uvbr.y }; - di.uv[2] = { uvbr.x, uvbr.y }; di.uv[3] = { uvbr.x, uvtl.y }; + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; + di.w = { 1,1,1,1 }; di.mode = nDecalMode; vLayers[nTargetLayer].vecDecalInstance.push_back(di); } @@ -2307,27 +2434,25 @@ namespace olc { olc::vf2d vScreenSpacePos = { - (pos.x * vInvScreenSize.x) * 2.0f - 1.0f, - ((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f + (std::floor(pos.x) * vInvScreenSize.x) * 2.0f - 1.0f, + ((std::floor(pos.y) * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; olc::vf2d vScreenSpaceDim = { - vScreenSpacePos.x + (2.0f * size.x * vInvScreenSize.x), - vScreenSpacePos.y - (2.0f * size.y * vInvScreenSize.y) + vScreenSpacePos.x + (2.0f * std::ceil(size.x + 0.5f) * vInvScreenSize.x), + vScreenSpacePos.y - (2.0f * std::ceil(size.y + 0.5f) * vInvScreenSize.y) }; - DecalInstance di; di.decal = decal; di.tint[0] = tint; - - di.pos[0] = { vScreenSpacePos.x, vScreenSpacePos.y }; - di.pos[1] = { vScreenSpacePos.x, vScreenSpaceDim.y }; - di.pos[2] = { vScreenSpaceDim.x, vScreenSpaceDim.y }; - di.pos[3] = { vScreenSpaceDim.x, vScreenSpacePos.y }; - - olc::vf2d uvtl = source_pos * decal->vUVScale; - olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale); - di.uv[0] = { uvtl.x, uvtl.y }; di.uv[1] = { uvtl.x, uvbr.y }; - di.uv[2] = { uvbr.x, uvbr.y }; di.uv[3] = { uvbr.x, uvtl.y }; + DecalInstance di; + di.points = 4; + di.decal = decal; + di.tint = { tint, tint, tint, tint }; + di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } }; + olc::vf2d uvtl = (source_pos) * decal->vUVScale; + olc::vf2d uvbr = uvtl + ((source_size) * decal->vUVScale); + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; + di.w = { 1,1,1,1 }; di.mode = nDecalMode; vLayers[nTargetLayer].vecDecalInstance.push_back(di); } @@ -2337,8 +2462,8 @@ namespace olc { olc::vf2d vScreenSpacePos = { - (pos.x * vInvScreenSize.x) * 2.0f - 1.0f, - ((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f + (std::floor(pos.x) * vInvScreenSize.x) * 2.0f - 1.0f, + ((std::floor(pos.y) * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; olc::vf2d vScreenSpaceDim = @@ -2349,44 +2474,50 @@ namespace olc DecalInstance di; di.decal = decal; - di.tint[0] = tint; - di.pos[0] = { vScreenSpacePos.x, vScreenSpacePos.y }; - di.pos[1] = { vScreenSpacePos.x, vScreenSpaceDim.y }; - di.pos[2] = { vScreenSpaceDim.x, vScreenSpaceDim.y }; - di.pos[3] = { vScreenSpaceDim.x, vScreenSpacePos.y }; + di.points = 4; + di.tint = { tint, tint, tint, tint }; + di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } }; + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; + di.w = { 1, 1, 1, 1 }; di.mode = nDecalMode; vLayers[nTargetLayer].vecDecalInstance.push_back(di); } - void PixelGameEngine::DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& scale, const olc::Pixel& tint) + void PixelGameEngine::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements) { DecalInstance di; di.decal = decal; - di.tint[0] = tint; - di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale; - di.pos[1] = (olc::vf2d(0.0f, float(decal->sprite->height)) - center) * scale; - di.pos[2] = (olc::vf2d(float(decal->sprite->width), float(decal->sprite->height)) - center) * scale; - di.pos[3] = (olc::vf2d(float(decal->sprite->width), 0.0f) - center) * scale; - float c = cos(fAngle), s = sin(fAngle); - for (int i = 0; i < 4; i++) + di.pos.resize(elements); + di.uv.resize(elements); + di.w.resize(elements); + di.tint.resize(elements); + di.points = elements; + for (uint32_t i = 0; i < elements; i++) { - di.pos[i] = pos + olc::vf2d(di.pos[i].x * c - di.pos[i].y * s, di.pos[i].x * s + di.pos[i].y * c); - di.pos[i] = di.pos[i] * vInvScreenSize * 2.0f - olc::vf2d(1.0f, 1.0f); - di.pos[i].y *= -1.0f; + di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[i] = uv[i]; + di.tint[i] = col[i]; + di.w[i] = 1.0f; } di.mode = nDecalMode; vLayers[nTargetLayer].vecDecalInstance.push_back(di); } - void PixelGameEngine::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col) + void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint) { DecalInstance di; di.decal = decal; - for (int i = 0; i < 4; i++) + di.points = pos.size(); + di.pos.resize(di.points); + di.uv.resize(di.points); + di.w.resize(di.points); + di.tint.resize(di.points); + for (uint32_t i = 0; i < di.points; i++) { di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; di.uv[i] = uv[i]; - di.tint[i] = col[i]; + di.tint[i] = tint; + di.w[i] = 1.0f; } di.mode = nDecalMode; vLayers[nTargetLayer].vecDecalInstance.push_back(di); @@ -2397,7 +2528,7 @@ namespace olc std::array points = { { {pos}, {pos.x, pos.y + size.y}, {pos + size}, {pos.x + size.x, pos.y} } }; std::array uvs = { {{0,0},{0,0},{0,0},{0,0}} }; std::array cols = { {col, col, col, col} }; - DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data()); + DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 4); } void PixelGameEngine::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) @@ -2405,7 +2536,52 @@ namespace olc std::array points = { { {pos}, {pos.x, pos.y + size.y}, {pos + size}, {pos.x + size.x, pos.y} } }; std::array uvs = { {{0,0},{0,0},{0,0},{0,0}} }; std::array cols = { {colTL, colBL, colBR, colTR} }; - DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data()); + DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 4); + } + + //void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const olc::vf2d& pos, const std::vector& vPoints, const std::vector& vTexCoords, const float fAngle, const olc::vf2d& scale, const olc::Pixel& tint) + //{ + // DecalInstance di; + // di.decal = decal; + // di.points = vPoints.size(); + // di.pos.resize(di.points); + // di.uv.resize(di.points); + // di.w.resize(di.points); + // di.tint.resize(di.points); + // for (uint32_t i = 0; i < di.points; i++) + // { + // di.pos[i] = { (vPoints[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((vPoints[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + // di.uv[i] = vTexCoords[i]; + // di.tint[i] = tint; + // di.w[i] = 1.0f; + // } + // di.mode = nDecalMode; + // vLayers[nTargetLayer].vecDecalInstance.push_back(di); + //} + + void PixelGameEngine::DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& scale, const olc::Pixel& tint) + { + DecalInstance di; + di.decal = decal; + di.pos.resize(4); + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; + di.w = { 1, 1, 1, 1 }; + di.tint = { tint, tint, tint, tint }; + di.points = 4; + di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale; + di.pos[1] = (olc::vf2d(0.0f, float(decal->sprite->height)) - center) * scale; + di.pos[2] = (olc::vf2d(float(decal->sprite->width), float(decal->sprite->height)) - center) * scale; + di.pos[3] = (olc::vf2d(float(decal->sprite->width), 0.0f) - center) * scale; + float c = cos(fAngle), s = sin(fAngle); + for (int i = 0; i < 4; i++) + { + di.pos[i] = pos + olc::vf2d(di.pos[i].x * c - di.pos[i].y * s, di.pos[i].x * s + di.pos[i].y * c); + di.pos[i] = di.pos[i] * vInvScreenSize * 2.0f - olc::vf2d(1.0f, 1.0f); + di.pos[i].y *= -1.0f; + di.w[i] = 1; + } + di.mode = nDecalMode; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); } @@ -2413,7 +2589,10 @@ namespace olc { DecalInstance di; di.decal = decal; - di.tint[0] = tint; + di.points = 4; + di.tint = { tint, tint, tint, tint }; + di.w = { 1, 1, 1, 1 }; + di.pos.resize(4); di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale; di.pos[1] = (olc::vf2d(0.0f, source_size.y) - center) * scale; di.pos[2] = (olc::vf2d(source_size.x, source_size.y) - center) * scale; @@ -2428,8 +2607,7 @@ namespace olc olc::vf2d uvtl = source_pos * decal->vUVScale; olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale); - di.uv[0] = { uvtl.x, uvtl.y }; di.uv[1] = { uvtl.x, uvbr.y }; - di.uv[2] = { uvbr.x, uvbr.y }; di.uv[3] = { uvbr.x, uvtl.y }; + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; di.mode = nDecalMode; vLayers[nTargetLayer].vecDecalInstance.push_back(di); } @@ -2437,16 +2615,19 @@ namespace olc void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) { DecalInstance di; + di.points = 4; di.decal = decal; - di.tint[0] = tint; + di.tint = { tint, tint, tint, tint }; + di.w = { 1, 1, 1, 1 }; + di.pos.resize(4); + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; olc::vf2d center; float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y)); if (rd != 0) { olc::vf2d uvtl = source_pos * decal->vUVScale; olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale); - di.uv[0] = { uvtl.x, uvtl.y }; di.uv[1] = { uvtl.x, uvbr.y }; - di.uv[2] = { uvbr.x, uvbr.y }; di.uv[3] = { uvbr.x, uvtl.y }; + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; rd = 1.0f / rd; float rn = ((pos[3].x - pos[1].x) * (pos[0].y - pos[1].y) - (pos[3].y - pos[1].y) * (pos[0].x - pos[1].x)) * rd; @@ -2469,8 +2650,12 @@ namespace olc // Thanks Nathan Reed, a brilliant article explaining whats going on here // http://www.reedbeta.com/blog/quadrilateral-interpolation-part-1/ DecalInstance di; + di.points = 4; di.decal = decal; - di.tint[0] = tint; + di.tint = { tint, tint, tint, tint }; + di.w = { 1, 1, 1, 1 }; + di.pos.resize(4); + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; olc::vf2d center; float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y)); if (rd != 0) @@ -2574,8 +2759,11 @@ namespace olc int32_t sy = 0; Pixel::Mode m = nPixelMode; // Thanks @tucna, spotted bug with col.ALPHA :P - if (col.a != 255) SetPixelMode(Pixel::ALPHA); - else SetPixelMode(Pixel::MASK); + if (m != Pixel::CUSTOM) // Thanks @Megarev, required for "shaders" + { + if (col.a != 255) SetPixelMode(Pixel::ALPHA); + else SetPixelMode(Pixel::MASK); + } for (auto c : sText) { if (c == '\n') @@ -2615,7 +2803,7 @@ namespace olc olc::vi2d pos = { 0,1 }; for (auto c : s) { - if (c == '\n') { pos.y+=8; pos.x = 0; } + if (c == '\n') { pos.y += 1; pos.x = 0; } else pos.x += vFontSpacing[c - 32].y; size.x = std::max(size.x, pos.x); size.y = std::max(size.y, pos.y); @@ -2635,9 +2823,12 @@ namespace olc int32_t sx = 0; int32_t sy = 0; Pixel::Mode m = nPixelMode; - - if (col.a != 255) SetPixelMode(Pixel::ALPHA); - else SetPixelMode(Pixel::MASK); + + if (m != Pixel::CUSTOM) + { + if (col.a != 255) SetPixelMode(Pixel::ALPHA); + else SetPixelMode(Pixel::MASK); + } for (auto c : sText) { if (c == '\n') @@ -2672,10 +2863,14 @@ 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) { @@ -2695,13 +2890,19 @@ 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() @@ -2759,19 +2960,29 @@ 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() { @@ -2783,7 +2994,9 @@ namespace olc olc_PrepareEngine(); // Create user resources as part of this thread + for (auto& ext : vExtensions) ext->OnBeforeUserCreate(); if (!OnUserCreate()) bAtomActive = false; + for (auto& ext : vExtensions) ext->OnAfterUserCreate(); while (bAtomActive) { @@ -2868,9 +3081,10 @@ namespace olc // renderer->ClearBuffer(olc::BLACK, true); - // Handle Frame Update - if (!OnUserUpdate(fElapsedTime)) - bAtomActive = false; + // Handle Frame Update + for (auto& ext : vExtensions) ext->OnBeforeUserUpdate(fElapsedTime); + if (!OnUserUpdate(fElapsedTime)) bAtomActive = false; + for (auto& ext : vExtensions) ext->OnAfterUserUpdate(fElapsedTime); // Display Frame renderer->UpdateViewport(vViewPos, vViewSize); @@ -2879,6 +3093,7 @@ namespace olc // Layer 0 must always exist vLayers[0].bUpdate = true; vLayers[0].bShow = true; + SetDecalMode(DecalMode::NORMAL); renderer->PrepareDrawing(); for (auto layer = vLayers.rbegin(); layer != vLayers.rend(); ++layer) @@ -2898,7 +3113,7 @@ namespace olc // Display Decals in order for this layer for (auto& decal : layer->vecDecalInstance) - renderer->DrawDecalQuad(decal); + renderer->DrawDecal(decal); layer->vecDecalInstance.clear(); } else @@ -2977,6 +3192,19 @@ namespace olc } + void PixelGameEngine::pgex_Register(olc::PGEX* pgex) + { + if (std::find(vExtensions.begin(), vExtensions.end(), pgex) == vExtensions.end()) + vExtensions.push_back(pgex); + } + + + PGEX::PGEX() { pge->pgex_Register(this); } + void PGEX::OnBeforeUserCreate() {} + void PGEX::OnAfterUserCreate() {} + void PGEX::OnBeforeUserUpdate(float& fElapsedTime) {} + void PGEX::OnAfterUserUpdate(float fElapsedTime) {} + // Need a couple of statics as these are singleton instances // read from multiple locations std::atomic PixelGameEngine::bAtomActive{ false }; @@ -2997,39 +3225,39 @@ namespace olc // 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; +#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 +#include #endif #if defined(OLC_PLATFORM_X11) - namespace X11 - { - #include - } +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; +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 @@ -3055,7 +3283,7 @@ namespace olc public: void PrepareDevice() override - { + { #if defined(OLC_PLATFORM_GLUT) //glutInit has to be called with main() arguments, make fake ones int argc = 0; @@ -3134,11 +3362,11 @@ namespace olc mFullScreen = bFullScreen; if (!bVSYNC) { - #if defined(__APPLE__) +#if defined(__APPLE__) GLint sync = 0; CGLContextObj ctx = CGLGetCurrentContext(); if (ctx) CGLSetParameter(ctx, kCGLCPSwapInterval, &sync); - #endif +#endif } #else glEnable(GL_TEXTURE_2D); // Turn on texturing @@ -3183,7 +3411,8 @@ namespace olc void PrepareDrawing() override { glEnable(GL_BLEND); - SetDecalMode(olc::DecalMode::NORMAL); + nDecalMode = DecalMode::NORMAL; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void SetDecalMode(const olc::DecalMode& mode) @@ -3207,6 +3436,9 @@ namespace olc case olc::DecalMode::ILLUMINATE: glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); break; + case olc::DecalMode::WIREFRAME: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; } nDecalMode = mode; @@ -3228,35 +3460,27 @@ namespace olc glEnd(); } - void DrawDecalQuad(const olc::DecalInstance& decal) override + void DrawDecal(const olc::DecalInstance& decal) override { + SetDecalMode(decal.mode); + if (decal.decal == nullptr) - { - SetDecalMode(decal.mode); glBindTexture(GL_TEXTURE_2D, 0); - glBegin(GL_QUADS); - glColor4ub(decal.tint[0].r, decal.tint[0].g, decal.tint[0].b, decal.tint[0].a); - glTexCoord4f(decal.uv[0].x, decal.uv[0].y, 0.0f, decal.w[0]); glVertex2f(decal.pos[0].x, decal.pos[0].y); - glColor4ub(decal.tint[1].r, decal.tint[1].g, decal.tint[1].b, decal.tint[1].a); - glTexCoord4f(decal.uv[1].x, decal.uv[1].y, 0.0f, decal.w[1]); glVertex2f(decal.pos[1].x, decal.pos[1].y); - glColor4ub(decal.tint[2].r, decal.tint[2].g, decal.tint[2].b, decal.tint[2].a); - glTexCoord4f(decal.uv[2].x, decal.uv[2].y, 0.0f, decal.w[2]); glVertex2f(decal.pos[2].x, decal.pos[2].y); - glColor4ub(decal.tint[3].r, decal.tint[3].g, decal.tint[3].b, decal.tint[3].a); - glTexCoord4f(decal.uv[3].x, decal.uv[3].y, 0.0f, decal.w[3]); glVertex2f(decal.pos[3].x, decal.pos[3].y); - glEnd(); - } else - { - SetDecalMode(decal.mode); glBindTexture(GL_TEXTURE_2D, decal.decal->id); - glBegin(GL_QUADS); - glColor4ub(decal.tint[0].r, decal.tint[0].g, decal.tint[0].b, decal.tint[0].a); - glTexCoord4f(decal.uv[0].x, decal.uv[0].y, 0.0f, decal.w[0]); glVertex2f(decal.pos[0].x, decal.pos[0].y); - glTexCoord4f(decal.uv[1].x, decal.uv[1].y, 0.0f, decal.w[1]); glVertex2f(decal.pos[1].x, decal.pos[1].y); - glTexCoord4f(decal.uv[2].x, decal.uv[2].y, 0.0f, decal.w[2]); glVertex2f(decal.pos[2].x, decal.pos[2].y); - glTexCoord4f(decal.uv[3].x, decal.uv[3].y, 0.0f, decal.w[3]); glVertex2f(decal.pos[3].x, decal.pos[3].y); - glEnd(); + + if (nDecalMode == DecalMode::WIREFRAME) + glBegin(GL_LINE_LOOP); + else + glBegin(GL_TRIANGLE_FAN); + + for (uint32_t n = 0; n < decal.points; n++) + { + glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a); + glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]); + glVertex2f(decal.pos[n].x, decal.pos[n].y); } + glEnd(); } uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered) override @@ -3295,6 +3519,11 @@ namespace olc glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spr->width, spr->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); } + void ReadTexture(uint32_t id, olc::Sprite* spr) override + { + glReadPixels(0, 0, spr->width, spr->height, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); + } + void ApplyTexture(uint32_t id) override { glBindTexture(GL_TEXTURE_2D, id); @@ -3322,27 +3551,478 @@ namespace olc // | END RENDERER: OpenGL 1.0 (the original, the best...) | // O------------------------------------------------------------------------------O - - - // O------------------------------------------------------------------------------O -// | START IMAGE LOADER: GDI+, Windows Only, always exists, a little slow | +// | START RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) | // O------------------------------------------------------------------------------O -#if defined(OLC_IMAGE_GDI) - -#define min(a, b) ((a < b) ? a : b) -#define max(a, b) ((a > b) ? a : b) -#include -#include -#undef min -#undef max +#if defined(OLC_GFX_OPENGL33) +#if defined(OLC_PLATFORM_WINAPI) +#include +#include #if !defined(__MINGW32__) - #pragma comment(lib, "gdiplus.lib") - #pragma comment(lib, "Shlwapi.lib") +#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 -namespace olc +#if defined(__linux__) || defined(__FreeBSD__) +#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); +#endif + +#if defined(__APPLE__) +#define GL_SILENCE_DEPRECATION +#include +#include +#include +#endif + + +namespace olc +{ + typedef char GLchar; + typedef ptrdiff_t GLsizeiptr; + typedef GLuint CALLSTYLE locCreateShader_t(GLenum type); + typedef GLuint CALLSTYLE locCreateProgram_t(void); + typedef void CALLSTYLE locDeleteShader_t(GLuint shader); + typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); + typedef void CALLSTYLE locCompileShader_t(GLuint shader); + typedef void CALLSTYLE locLinkProgram_t(GLuint program); + typedef void CALLSTYLE locDeleteProgram_t(GLuint program); + typedef void CALLSTYLE locAttachShader_t(GLuint program, GLuint shader); + typedef void CALLSTYLE locBindBuffer_t(GLenum target, GLuint buffer); + typedef void CALLSTYLE locBufferData_t(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + typedef void CALLSTYLE locGenBuffers_t(GLsizei n, GLuint* buffers); + typedef void CALLSTYLE locVertexAttribPointer_t(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); + typedef void CALLSTYLE locEnableVertexAttribArray_t(GLuint index); + typedef void CALLSTYLE locUseProgram_t(GLuint program); + typedef void CALLSTYLE locBindVertexArray_t(GLuint array); + 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_GLUT) + bool mFullScreen = false; +#else + glDeviceContext_t glDeviceContext = 0; + glRenderContext_t glRenderContext = 0; +#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; + X11::XVisualInfo* olc_VisualInfo = nullptr; +#endif + + private: + locCreateShader_t* locCreateShader = nullptr; + locShaderSource_t* locShaderSource = nullptr; + locCompileShader_t* locCompileShader = nullptr; + locDeleteShader_t* locDeleteShader = nullptr; + locCreateProgram_t* locCreateProgram = nullptr; + locDeleteProgram_t* locDeleteProgram = nullptr; + locLinkProgram_t* locLinkProgram = nullptr; + locAttachShader_t* locAttachShader = nullptr; + locBindBuffer_t* locBindBuffer = nullptr; + locBufferData_t* locBufferData = nullptr; + locGenBuffers_t* locGenBuffers = nullptr; + locVertexAttribPointer_t* locVertexAttribPointer = nullptr; + locEnableVertexAttribArray_t* locEnableVertexAttribArray = nullptr; + locUseProgram_t* locUseProgram = nullptr; + locBindVertexArray_t* locBindVertexArray = nullptr; + locGenVertexArrays_t* locGenVertexArrays = nullptr; + locSwapInterval_t* locSwapInterval = nullptr; + locGetShaderInfoLog_t* locGetShaderInfoLog = nullptr; + + uint32_t m_nFS = 0; + uint32_t m_nVS = 0; + uint32_t m_nQuadShader = 0; + uint32_t m_vbQuad = 0; + uint32_t m_vaQuad = 0; + + struct locVertex + { + float pos[3]; + olc::vf2d tex; + olc::Pixel col; + }; + + locVertex pVertexMem[OLC_MAX_VERTS]; + + olc::Renderable rendBlankQuad; + + public: + void PrepareDevice() override + { +#if defined(OLC_PLATFORM_GLUT) + //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 + { + // Create OpenGL Context + +#if defined(OLC_PLATFORM_WINAPI) + // Create Device Context + glDeviceContext = GetDC((HWND)(params[0])); + PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + PFD_MAIN_PLANE, 0, 0, 0, 0 + }; + + int pf = 0; + if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return olc::FAIL; + SetPixelFormat(glDeviceContext, pf, &pfd); + + if (!(glRenderContext = wglCreateContext(glDeviceContext))) return olc::FAIL; + wglMakeCurrent(glDeviceContext, glRenderContext); + + // Set Vertical Sync + locSwapInterval = OGL_LOAD(locSwapInterval_t, "wglSwapIntervalEXT"); + if (locSwapInterval && !bVSYNC) locSwapInterval(0); + bSync = bVSYNC; +#endif + +#if defined(OLC_PLATFORM_X11) + using namespace X11; + // Linux has tighter coupling between OpenGL and X11, so we store + // various "platform" handles in the renderer + olc_Display = (X11::Display*)(params[0]); + olc_Window = (X11::Window*)(params[1]); + olc_VisualInfo = (X11::XVisualInfo*)(params[2]); + + glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE); + glXMakeCurrent(olc_Display, *olc_Window, glDeviceContext); + + XWindowAttributes gwa; + XGetWindowAttributes(olc_Display, *olc_Window, &gwa); + glViewport(0, 0, gwa.width, gwa.height); + + locSwapInterval = OGL_LOAD(locSwapInterval_t, "glXSwapIntervalEXT"); + + if (locSwapInterval == nullptr && !bVSYNC) + { + printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n"); + printf(" Don't worry though, things will still work, it's just the\n"); + printf(" frame rate will be capped to your monitors refresh rate - javidx9\n"); + } + + if (locSwapInterval != nullptr && !bVSYNC) + locSwapInterval(olc_Display, *olc_Window, 0); +#endif + +#if defined(OLC_PLATFORM_GLUT) + mFullScreen = bFullScreen; + if (!bVSYNC) + { +#if defined(__APPLE__) + GLint sync = 0; + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) CGLSetParameter(ctx, kCGLCPSwapInterval, &sync); +#endif + } +#else + glEnable(GL_TEXTURE_2D); // Turn on texturing + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); +#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"); + + // Load & Compile Quad Shader - assumes no errors + m_nFS = locCreateShader(0x8B30); + const GLchar* strFS = +#if defined(__arm__) + "#version 300 es\n" + "precision mediump float;" +#else + "#version 330 core\n" +#endif + "out vec4 pixel;\n""in vec2 oTex;\n" + "in vec4 oCol;\n""uniform sampler2D sprTex;\n""void main(){pixel = texture(sprTex, oTex) * oCol;}"; + locShaderSource(m_nFS, 1, &strFS, NULL); + locCompileShader(m_nFS); + + m_nVS = locCreateShader(0x8B31); + const GLchar* strVS = +#if defined(__arm__) + "#version 300 es\n" + "precision mediump float;" +#else + "#version 330 core\n" +#endif + "layout(location = 0) in vec3 aPos;\n""layout(location = 1) in vec2 aTex;\n" + "layout(location = 2) in vec4 aCol;\n""out vec2 oTex;\n""out vec4 oCol;\n" + "void main(){ float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex; oCol = aCol;}"; + locShaderSource(m_nVS, 1, &strVS, NULL); + locCompileShader(m_nVS); + + m_nQuadShader = locCreateProgram(); + locAttachShader(m_nQuadShader, m_nFS); + locAttachShader(m_nQuadShader, m_nVS); + locLinkProgram(m_nQuadShader); + + // Create Quad + locGenBuffers(1, &m_vbQuad); + locGenVertexArrays(1, &m_vaQuad); + locBindVertexArray(m_vaQuad); + locBindBuffer(0x8892, m_vbQuad); + + locVertex verts[OLC_MAX_VERTS]; + locBufferData(0x8892, sizeof(locVertex) * OLC_MAX_VERTS, verts, 0x88E0); + 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); + locBindBuffer(0x8892, 0); + locBindVertexArray(0); + + // Create blank texture for spriteless decals + rendBlankQuad.Create(1, 1); + rendBlankQuad.Sprite()->GetData()[0] = olc::WHITE; + rendBlankQuad.Decal()->Update(); + return olc::rcode::OK; + } + + olc::rcode DestroyDevice() override + { +#if defined(OLC_PLATFORM_WINAPI) + wglDeleteContext(glRenderContext); +#endif + +#if defined(OLC_PLATFORM_X11) + glXMakeCurrent(olc_Display, None, NULL); + glXDestroyContext(olc_Display, glDeviceContext); +#endif + +#if defined(OLC_PLATFORM_GLUT) + glutDestroyWindow(glutGetWindow()); +#endif + return olc::rcode::OK; + } + + void DisplayFrame() override + { +#if defined(OLC_PLATFORM_WINAPI) + SwapBuffers(glDeviceContext); + if (bSync) DwmFlush(); // Woooohooooooo!!!! SMOOOOOOOTH! +#endif + +#if defined(OLC_PLATFORM_X11) + X11::glXSwapBuffers(olc_Display, *olc_Window); +#endif + +#if defined(OLC_PLATFORM_GLUT) + glutSwapBuffers(); +#endif + } + + void PrepareDrawing() override + { + glEnable(GL_BLEND); + nDecalMode = DecalMode::NORMAL; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + locUseProgram(m_nQuadShader); + locBindVertexArray(m_vaQuad); + } + + void SetDecalMode(const olc::DecalMode& mode) + { + if (mode != nDecalMode) + { + switch (mode) + { + case olc::DecalMode::NORMAL: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; + case olc::DecalMode::ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; + case olc::DecalMode::MULTIPLICATIVE: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; + case olc::DecalMode::STENCIL: glBlendFunc(GL_ZERO, GL_SRC_ALPHA); break; + case olc::DecalMode::ILLUMINATE: glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); break; + case olc::DecalMode::WIREFRAME: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; + } + + nDecalMode = mode; + } + } + + void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) override + { + locBindBuffer(0x8892, m_vbQuad); + locVertex verts[4] = { + {{-1.0f, -1.0f, 1.0}, {0.0f * scale.x + offset.x, 1.0f * scale.y + offset.y}, tint}, + {{+1.0f, -1.0f, 1.0}, {1.0f * scale.x + offset.x, 1.0f * scale.y + offset.y}, tint}, + {{-1.0f, +1.0f, 1.0}, {0.0f * scale.x + offset.x, 0.0f * scale.y + offset.y}, tint}, + {{+1.0f, +1.0f, 1.0}, {1.0f * scale.x + offset.x, 0.0f * scale.y + offset.y}, tint}, + }; + + locBufferData(0x8892, sizeof(locVertex) * 4, verts, 0x88E0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + + void DrawDecal(const olc::DecalInstance& decal) override + { + SetDecalMode(decal.mode); + if (decal.decal == nullptr) + glBindTexture(GL_TEXTURE_2D, rendBlankQuad.Decal()->id); + else + glBindTexture(GL_TEXTURE_2D, decal.decal->id); + + locBindBuffer(0x8892, m_vbQuad); + + for (uint32_t i = 0; i < decal.points; i++) + pVertexMem[i] = { { decal.pos[i].x, decal.pos[i].y, decal.w[i] }, { decal.uv[i].x, decal.uv[i].y }, decal.tint[i] }; + + locBufferData(0x8892, sizeof(locVertex) * decal.points, pVertexMem, 0x88E0); + + if (nDecalMode == DecalMode::WIREFRAME) + glDrawArrays(GL_LINE_LOOP, 0, decal.points); + else + glDrawArrays(GL_TRIANGLE_FAN, 0, decal.points); + } + + uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered) override + { + UNUSED(width); + UNUSED(height); + uint32_t id = 0; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + + if (filtered) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + 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); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + return id; + } + + uint32_t DeleteTexture(const uint32_t id) override + { + glDeleteTextures(1, &id); + return id; + } + + 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()); + } + + void ReadTexture(uint32_t id, olc::Sprite* spr) override + { + glReadPixels(0, 0, spr->width, spr->height, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); + } + + void ApplyTexture(uint32_t id) override + { + glBindTexture(GL_TEXTURE_2D, id); + } + + void ClearBuffer(olc::Pixel p, bool bDepth) override + { + glClearColor(float(p.r) / 255.0f, float(p.g) / 255.0f, float(p.b) / 255.0f, float(p.a) / 255.0f); + glClear(GL_COLOR_BUFFER_BIT); + if (bDepth) glClear(GL_DEPTH_BUFFER_BIT); + } + + void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) override + { +#if defined(OLC_PLATFORM_GLUT) + if (!mFullScreen) glutReshapeWindow(size.x, size.y); +#else + glViewport(pos.x, pos.y, size.x, size.y); +#endif + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) | +// O------------------------------------------------------------------------------O + +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: GDI+, Windows Only, always exists, a little slow | +// O------------------------------------------------------------------------------O +#if defined(OLC_IMAGE_GDI) + +#define min(a, b) ((a < b) ? a : b) +#define max(a, b) ((a > b) ? a : b) +#include +#include +#include +#undef min +#undef max + +#if !defined(__MINGW32__) +#pragma comment(lib, "gdiplus.lib") +#pragma comment(lib, "Shlwapi.lib") +#endif + +namespace olc { // Thanks @MaGetzUb for this, which allows sprites to be defined // at construction, by initialising the GDI subsystem @@ -3350,11 +4030,18 @@ namespace olc { public: GDIPlusStartup() - { + { Gdiplus::GdiplusStartupInput startupInput; - ULONG_PTR token; - Gdiplus::GdiplusStartup(&token, &startupInput, NULL); - }; + GdiplusStartup(&token, &startupInput, NULL); + } + + ULONG_PTR token; + + ~GDIPlusStartup() + { + // Well, MarcusTU thought this was important :D + Gdiplus::GdiplusShutdown(token); + } } gdistartup; class ImageLoader_GDIPlus : public olc::ImageLoader @@ -3458,7 +4145,7 @@ namespace olc // clear out existing sprite if (spr->pColData != nullptr) delete[] spr->pColData; - + //////////////////////////////////////////////////////////////////////////// // Use libpng, Thanks to Guillaume Cottenceau // https://gist.github.com/niw/5963798 @@ -3604,7 +4291,7 @@ namespace olc 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; + delete[] bytes; return olc::rcode::OK; } @@ -3626,9 +4313,9 @@ namespace olc #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 @@ -3662,7 +4349,7 @@ namespace olc virtual olc::rcode ThreadCleanUp() override { - renderer->DestroyDevice(); + renderer->DestroyDevice(); PostMessage(olc_hWnd, WM_DESTROY, 0, 0); return olc::OK; } @@ -3852,13 +4539,20 @@ 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; } + { + XDestroyWindow(olc_Display, olc_Window); + return olc::rcode::OK; + } virtual olc::rcode ThreadStartUp() override - { return olc::rcode::OK; } + { + return olc::rcode::OK; + } virtual olc::rcode ThreadCleanUp() override { @@ -3987,7 +4681,9 @@ namespace olc } virtual olc::rcode StartSystemEventLoop() override - { return olc::OK; } + { + return olc::OK; + } virtual olc::rcode HandleSystemEvent() override {