From 0bdfb62d60557d2faebc87ca845723497832000c Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Thu, 3 Jun 2021 20:57:15 +0100 Subject: [PATCH] PGE v2.16 FIX Emscripten JS formatting in VS IDE (thanks Moros) +"Headless" Mode +DrawLineDecal() +Mouse Button Constants +Move Constructor for olc::Renderable +Polar/Cartesian conversion for v2d_generic +DrawRotatedStringDecal()/DrawRotatedStringPropDecal() (thanks Oso-Grande/Sopadeoso (PR #209)) =Using olc::Renderable for layer surface +Major Mac and GLUT Update (thanks Mumflr) --- olcPixelGameEngine.h | 275 +++++++++++++++++++++++++++---------------- 1 file changed, 173 insertions(+), 102 deletions(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index c4d1bef8..48a9be57 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -3,7 +3,7 @@ olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.15 | + | OneLoneCoder Pixel Game Engine v2.16 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -111,7 +111,8 @@ 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 + clang++ -arch x86_64 -std=c++17 -mmacosx-version-min=10.15 -Wall -framework OpenGL + -framework GLUT -framework Carbon -lpng YourSource.cpp -o YourProgName @@ -179,10 +180,10 @@ Special thanks to those who bring gifts! GnarGnarHead.......Domina - Gorbit99...........Bastion, Ori & The Blind Forest, Terraria, Spelunky 2 + Gorbit99...........Bastion, Ori & The Blind Forest, Terraria, Spelunky 2, Skully Marti Morta........Gris Danicron...........Terraria - SaladinAkara.......Aseprite, Inside + SaladinAkara.......Aseprite, Inside, Quern: Undying Thoughts, Outer Wilds AlterEgo...........Final Fantasy XII - The Zodiac Age SlicEnDicE.........Noita, Inside @@ -267,6 +268,16 @@ -Deprecating LoadFromPGESprFile() -Deprecating SaveToPGESprFile() Fix Pixel -= operator (thanks Au Lit) + 2.16: FIX Emscripten JS formatting in VS IDE (thanks Moros) + +"Headless" Mode + +DrawLineDecal() + +Mouse Button Constants + +Move Constructor for olc::Renderable + +Polar/Cartesian conversion for v2d_generic + +DrawRotatedStringDecal()/DrawRotatedStringPropDecal() (thanks Oso-Grande/Sopadeoso (PR #209)) + =Using olc::Renderable for layer surface + +Major Mac and GLUT Update (thanks Mumflr) + !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! @@ -347,7 +358,7 @@ int main() #include #pragma endregion -#define PGE_VER 215 +#define PGE_VER 216 // O------------------------------------------------------------------------------O // | COMPILER CONFIGURATION ODDITIES | @@ -440,6 +451,7 @@ int main() // O------------------------------------------------------------------------------O // | PLATFORM-SPECIFIC DEPENDENCIES | // O------------------------------------------------------------------------------O +#if !defined(OLC_PGE_HEADLESS) #if defined(OLC_PLATFORM_WINAPI) #define _WINSOCKAPI_ // Thanks Cornchipss #if !defined(VC_EXTRALEAN) @@ -477,8 +489,11 @@ int main() #endif #if defined(__APPLE__) #include + #include + #include #endif #endif +#endif #pragma endregion // O------------------------------------------------------------------------------O @@ -561,6 +576,13 @@ namespace olc CAPS_LOCK, ENUM_END }; + namespace Mouse + { + static constexpr int32_t LEFT = 0; + static constexpr int32_t RIGHT = 1; + static constexpr int32_t MIDDLE = 2; + }; + // O------------------------------------------------------------------------------O // | olc::HWButton - Represents the state of a hardware button (mouse/key/joy) | // O------------------------------------------------------------------------------O @@ -595,6 +617,8 @@ namespace olc 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)); } + v2d_generic cart() { return { std::cos(y) * x, std::sin(y) * x }; } + v2d_generic polar() { return { mag(), std::atan2(y, x) }; } 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); } @@ -704,8 +728,6 @@ namespace olc public: olc::rcode LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack = nullptr); - olc::rcode LoadFromPGESprFile(const std::string& sImageFile, olc::ResourcePack* pack = nullptr); - olc::rcode SaveToPGESprFile(const std::string& sImageFile); public: int32_t width = 0; @@ -764,7 +786,9 @@ namespace olc class Renderable { public: - Renderable() = default; + Renderable() = default; + Renderable(Renderable&& r) : pSprite(std::move(r.pSprite)), pDecal(std::move(r.pDecal)) {} + Renderable(const Renderable&) = delete; olc::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr, bool filter = false, bool clamp = true); void Create(uint32_t width, uint32_t height, bool filter = false, bool clamp = true); olc::Decal* Decal() const; @@ -797,7 +821,7 @@ namespace olc olc::vf2d vScale = { 1, 1 }; bool bShow = false; bool bUpdate = false; - olc::Sprite* pDrawTarget = nullptr; + olc::Renderable pDrawTarget; uint32_t nResID = 0; std::vector vecDecalInstance; olc::Pixel tint = olc::WHITE; @@ -1012,7 +1036,10 @@ namespace olc void GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR); // Draws an arbitrary convex textured polygon using GPU void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint = olc::WHITE); - + // Draws a line in Decal Space + void DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p = olc::WHITE); + void DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + void DrawRotatedStringPropDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); // Clears entire draw target to Pixel void Clear(Pixel p); // Clears the rendering back buffer @@ -1024,7 +1051,7 @@ namespace olc std::string sAppName; private: // Inner mysterious workings - Sprite* pDrawTarget = nullptr; + olc::Sprite* pDrawTarget = nullptr; Pixel::Mode nPixelMode = Pixel::NORMAL; float fBlendFactor = 1.0f; olc::vi2d vScreenSize = { 256, 240 }; @@ -1049,7 +1076,6 @@ namespace olc int nFrameCount = 0; Sprite* fontSprite = nullptr; Decal* fontDecal = nullptr; - Sprite* pDefaultDrawTarget = nullptr; std::vector vLayers; uint8_t nTargetLayer = 0; uint32_t nLastFPS = 0; @@ -1265,60 +1291,6 @@ namespace olc Sprite::~Sprite() { pColData.clear(); } - // To Be Deprecated - //olc::rcode Sprite::LoadFromPGESprFile(const std::string& sImageFile, olc::ResourcePack* pack) - //{ - // if (pColData) delete[] pColData; - // auto ReadData = [&](std::istream& is) - // { - // is.read((char*)&width, sizeof(int32_t)); - // is.read((char*)&height, sizeof(int32_t)); - // pColData = new Pixel[width * height]; - // is.read((char*)pColData, (size_t)width * (size_t)height * sizeof(uint32_t)); - // }; - - // // These are essentially Memory Surfaces represented by olc::Sprite - // // which load very fast, but are completely uncompressed - // if (pack == nullptr) - // { - // std::ifstream ifs; - // ifs.open(sImageFile, std::ifstream::binary); - // if (ifs.is_open()) - // { - // ReadData(ifs); - // return olc::OK; - // } - // else - // return olc::FAIL; - // } - // else - // { - // ResourceBuffer rb = pack->GetFileBuffer(sImageFile); - // std::istream is(&rb); - // ReadData(is); - // return olc::OK; - // } - // return olc::FAIL; - //} - - //olc::rcode Sprite::SaveToPGESprFile(const std::string& sImageFile) - //{ - // if (pColData == nullptr) return olc::FAIL; - - // std::ofstream ofs; - // ofs.open(sImageFile, std::ifstream::binary); - // if (ofs.is_open()) - // { - // ofs.write((char*)&width, sizeof(int32_t)); - // ofs.write((char*)&height, sizeof(int32_t)); - // ofs.write((char*)pColData, std::streamsize(width) * std::streamsize(height) * sizeof(uint32_t)); - // ofs.close(); - // return olc::OK; - // } - - // return olc::FAIL; - //} - void Sprite::SetSampleMode(olc::Sprite::Mode mode) { modeSample = mode; } @@ -1695,8 +1667,7 @@ namespace olc vInvScreenSize = { 1.0f / float(w), 1.0f / float(h) }; for (auto& layer : vLayers) { - delete layer.pDrawTarget; // Erase existing layer sprites - layer.pDrawTarget = new Sprite(vScreenSize.x, vScreenSize.y); + layer.pDrawTarget.Create(vScreenSize.x, vScreenSize.y); layer.bUpdate = true; } SetDrawTarget(nullptr); @@ -1740,7 +1711,7 @@ namespace olc else { nTargetLayer = 0; - pDrawTarget = vLayers[0].pDrawTarget; + pDrawTarget = vLayers[0].pDrawTarget.Sprite(); } } @@ -1748,7 +1719,7 @@ namespace olc { if (layer < vLayers.size()) { - pDrawTarget = vLayers[layer].pDrawTarget; + pDrawTarget = vLayers[layer].pDrawTarget.Sprite(); vLayers[layer].bUpdate = true; nTargetLayer = layer; } @@ -1781,10 +1752,8 @@ namespace olc uint32_t PixelGameEngine::CreateLayer() { LayerDesc ld; - ld.pDrawTarget = new olc::Sprite(vScreenSize.x, vScreenSize.y); - ld.nResID = renderer->CreateTexture(vScreenSize.x, vScreenSize.y); - renderer->UpdateTexture(ld.nResID, ld.pDrawTarget); - vLayers.push_back(ld); + ld.pDrawTarget.Create(vScreenSize.x, vScreenSize.y); + vLayers.push_back(std::move(ld)); return uint32_t(vLayers.size()) - 1; } @@ -2447,6 +2416,27 @@ namespace olc vLayers[nTargetLayer].vecDecalInstance.push_back(di); } + void PixelGameEngine::DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p) + { + DecalInstance di; + di.decal = nullptr; + di.points = uint32_t(2); + di.pos.resize(di.points); + di.uv.resize(di.points); + di.w.resize(di.points); + di.tint.resize(di.points); + di.pos[0] = { (pos1.x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos1.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[0] = { 0.0f, 0.0f }; + di.tint[0] = p; + di.w[0] = 1.0f; + di.pos[1] = { (pos2.x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos2.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[1] = { 0.0f, 0.0f }; + di.tint[1] = p; + di.w[1] = 1.0f; + di.mode = olc::DecalMode::WIREFRAME; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + void PixelGameEngine::FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) { std::array points = { { {pos}, {pos.x, pos.y + size.y}, {pos + size}, {pos.x + size.x, pos.y} } }; @@ -2629,6 +2619,44 @@ namespace olc } } } + // Thanks Oso-Grande/Sopadeoso For these awesom and stupidly clever Text Rotation routines... duh XD + void PixelGameEngine::DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center, const Pixel col, const olc::vf2d& scale) + { + olc::vf2d spos = center; + for (auto c : sText) + { + if (c == '\n') + { + spos.x = center.x; spos.y -= 8.0f; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialRotatedDecal(pos, fontDecal, fAngle, spos, { float(ox) * 8.0f, float(oy) * 8.0f }, { 8.0f, 8.0f }, scale, col); + spos.x -= 8.0f; + } + } + } + + void PixelGameEngine::DrawRotatedStringPropDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center, const Pixel col, const olc::vf2d& scale) + { + olc::vf2d spos = center; + for (auto c : sText) + { + if (c == '\n') + { + spos.x = center.x; spos.y -= 8.0f; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialRotatedDecal(pos, fontDecal, fAngle, spos, { float(ox) * 8.0f + float(vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(vFontSpacing[c - 32].y), 8.0f }, scale, col); + spos.x -= float(vFontSpacing[c - 32].y); + } + } + } olc::vi2d PixelGameEngine::GetTextSize(const std::string& s) { @@ -2977,10 +3005,10 @@ namespace olc { if (layer->funcHook == nullptr) { - renderer->ApplyTexture(layer->nResID); + renderer->ApplyTexture(layer->pDrawTarget.Decal()->id); if (layer->bUpdate) { - renderer->UpdateTexture(layer->nResID, layer->pDrawTarget); + layer->pDrawTarget.Decal()->Update(); layer->bUpdate = false; } @@ -3094,6 +3122,8 @@ namespace olc // | olcPixelGameEngine Renderers - the draw-y bits | // O------------------------------------------------------------------------------O +#if !defined(OLC_PGE_HEADLESS) + #pragma region renderer_ogl10 // O------------------------------------------------------------------------------O // | START RENDERER: OpenGL 1.0 (the original, the best...) | @@ -3417,11 +3447,7 @@ namespace olc 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 } }; } @@ -3942,11 +3968,7 @@ namespace olc 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 } }; } @@ -4795,7 +4817,43 @@ namespace olc { exit(0); } +#if defined(__APPLE__) + static void scrollWheelUpdate(id selff, SEL _sel, id theEvent) { + static const SEL deltaYSel = sel_registerName("deltaY"); + + double deltaY = ((double (*)(id, SEL))objc_msgSend_fpret)(theEvent, deltaYSel); + + for (int i = 0; i < abs(deltaY); i++) { + if (deltaY > 0) { + ptrPGE->olc_UpdateMouseWheel(-1); + } + else if (deltaY < 0) { + ptrPGE->olc_UpdateMouseWheel(1); + } + } + } +#endif static void ThreadFunct() { +#if defined(__APPLE__) + static bool hasEnabledCocoa = false; + if (!hasEnabledCocoa) { + // Objective-C Wizardry + Class NSApplicationClass = objc_getClass("NSApplication"); + + // NSApp = [NSApplication sharedApplication] + SEL sharedApplicationSel = sel_registerName("sharedApplication"); + id NSApp = ((id(*)(Class, SEL))objc_msgSend)(NSApplicationClass, sharedApplicationSel); + // window = [NSApp mainWindow] + SEL mainWindowSel = sel_registerName("mainWindow"); + id window = ((id(*)(id, SEL))objc_msgSend)(NSApp, mainWindowSel); + + // [window setStyleMask: NSWindowStyleMaskClosable | ~NSWindowStyleMaskResizable] + SEL setStyleMaskSel = sel_registerName("setStyleMask:"); + ((void (*)(id, SEL, NSUInteger))objc_msgSend)(window, setStyleMaskSel, 7); + + hasEnabledCocoa = true; + } +#endif if (!*bActiveRef) { ExitMainLoop(); return; @@ -4809,8 +4867,15 @@ namespace olc { virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override { - renderer->PrepareDevice(); +#if defined(__APPLE__) + Class GLUTViewClass = objc_getClass("GLUTView"); + SEL scrollWheelSel = sel_registerName("scrollWheel:"); + bool resultAddMethod = class_addMethod(GLUTViewClass, scrollWheelSel, (IMP)scrollWheelUpdate, "v@:@"); + assert(resultAddMethod); +#endif + + renderer->PrepareDevice(); if (bFullScreen) { @@ -4818,10 +4883,14 @@ namespace olc { vWindowSize.y = glutGet(GLUT_SCREEN_HEIGHT); glutFullScreen(); } - - 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; + else + { + 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; + } + glutReshapeWindow(vWindowSize.x, vWindowSize.y - 1); } // Create Keyboard Mapping @@ -4967,19 +5036,12 @@ namespace olc { 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 @@ -5140,7 +5202,7 @@ namespace olc // width / height = aspect ratio Module._olc_WindowAspectRatio = $0 / $1; - Module.canvas.parentNode.addEventListener("resize", (e) => { + Module.canvas.parentNode.addEventListener("resize", function(e) { if (e.defaultPrevented) { e.stopPropagation(); return; } var viewWidth = e.detail.width; @@ -5177,10 +5239,10 @@ namespace olc }); // helper function to prevent repeating the same code everywhere - Module._olc_ResizeCanvas = () => + Module._olc_ResizeCanvas = function() { // yes, we still have to wait, sigh.. - setTimeout(() => + setTimeout(function() { // if default template, stretch width as well if (Module.canvas.parentNode.className == 'emscripten_border') @@ -5219,10 +5281,10 @@ namespace olc Module._olc_ResizeCanvas(); // observe and react to resizing of the container element - var resizeObserver = new ResizeObserver((entries) => {Module._olc_ResizeCanvas();}).observe(Module.canvas.parentNode); + var resizeObserver = new ResizeObserver(function(entries) {Module._olc_ResizeCanvas();}).observe(Module.canvas.parentNode); // observe and react to changes that occur when entering/exiting fullscreen - var mutationObserver = new MutationObserver((mutationsList, observer) => + var mutationObserver = new MutationObserver(function(mutationsList, observer) { // a change has occurred, let's check them out! for (var i = 0; i < mutationsList.length; i++) @@ -5243,7 +5305,7 @@ namespace olc }); // add resize listener on window - window.addEventListener("resize", (e) => { Module._olc_ResizeCanvas(); }); + window.addEventListener("resize", function(e) { Module._olc_ResizeCanvas(); }); }, vWindowSize.x, vWindowSize.y); // Fullscreen and Resize Observers #pragma warning restore format @@ -5442,6 +5504,8 @@ extern "C" #pragma endregion +#endif // Headless + // O------------------------------------------------------------------------------O // | olcPixelGameEngine Auto-Configuration | // O------------------------------------------------------------------------------O @@ -5451,6 +5515,8 @@ namespace olc void PixelGameEngine::olc_ConfigureSystem() { +#if !defined(OLC_PGE_HEADLESS) + #if defined(OLC_IMAGE_GDI) olc::Sprite::loader = std::make_unique(); #endif @@ -5519,6 +5585,11 @@ namespace olc // Associate components with PGE instance platform->ptrPGE = this; renderer->ptrPGE = this; +#else + olc::Sprite::loader = nullptr; + platform = nullptr; + renderer = nullptr; +#endif } }