diff --git a/examples/TEST_Patches.cpp b/examples/TEST_Patches.cpp new file mode 100644 index 00000000..76190a2f --- /dev/null +++ b/examples/TEST_Patches.cpp @@ -0,0 +1,128 @@ +/* + Example file for Patch Experiments + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2025 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions or derivations of source code must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce + the above copyright notice. This list of conditions and the following + disclaimer must be reproduced in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + + Author + ~~~~~~ + David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024, 2025 + +*/ + + +#define OLC_PGE_APPLICATION +#include + + + +class TEST_Patches : public olc::PixelGameEngine +{ +public: + TEST_Patches() + { + sAppName = "Testing Patches"; + } + + std::unique_ptr pSprite; + std::unique_ptr pDecal; + +public: + bool OnUserCreate() override + { + pSprite = std::make_unique("./assets/DirectionalSolids.png"); + pDecal = std::make_unique(pSprite.get()); + return true; + } + + + bool OnUserUpdate(float fElapsedTime) override + { + + Clear(olc::TANGERINE); + DrawSprite({ 10,10 }, pSprite.get()); + + /*DrawSprite( + olc::vf2d(GetMousePos()), + pSprite->Patch({ 16, 0 }, { 16, 16 }), + { -30.0f, -30.0f }); + + DrawSprite( + olc::vf2d(GetMousePos()), + pSprite->Patch({ 0.25f, 0.5f }, { 0.5f, 0.0f }, { 0.75f, 0.5f }, { 0.5f, 1.0f }), + { 100.0f, 100.0f }); + + DrawSprite( + olc::vf2d(GetMousePos()), + *pSprite, + { 50.0f, -50.0f });*/ + + + + DrawDecal( + olc::vf2d(GetMousePos()), + pDecal->Patch({ 16, 0 }, { 16, 16 }), + { -30.0f, -30.0f }); + + DrawDecal( + olc::vf2d(GetMousePos()), + pDecal->Patch({ 0.25f, 0.5f }, { 0.5f, 0.0f }, { 0.75f, 0.5f }, { 0.5f, 1.0f }), + { 100.0f, 100.0f }); + + DrawDecal( + olc::vf2d(GetMousePos()), + *pDecal, + { 320.0f, -180.0f }); + + DrawLine({ 0,0 }, GetScreenSize(), olc::TANGERINE); + + return true; + } +}; + +int main() +{ + TEST_Patches demo; + if (demo.Construct(1280, 720, 1, 1, false, false)) + demo.Start(); + return 0; +} \ No newline at end of file diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index cf4c13d7..f4dbb2ac 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -357,7 +357,10 @@ Updated Geometry2D to support non-segment line intersections +olcUTIL_Hardware3D.h file v1.01 NOTICE OF DEPRECATION! olc::DecalInstance is to be removed and replaced by olc::GPUTask - 2.30: + 2.30: Experimental "Patches" - Pass image resources to drawing functions using intermediate placeholders + +SpritePatch + +DecalPatch + +Added the Colour "Orange" cos some internet rando made me laugh about it :D !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! @@ -932,6 +935,8 @@ namespace olc { class PixelGameEngine; class Sprite; + struct SpritePatch; + struct DecalPatch; // Pixel Game Engine Advanced Configuration constexpr uint8_t nMouseButtons = 5; @@ -989,7 +994,7 @@ namespace olc CYAN(0, 255, 255), DARK_CYAN(0, 128, 128), VERY_DARK_CYAN(0, 64, 64), BLUE(0, 0, 255), DARK_BLUE(0, 0, 128), VERY_DARK_BLUE(0, 0, 64), MAGENTA(255, 0, 255), DARK_MAGENTA(128, 0, 128), VERY_DARK_MAGENTA(64, 0, 64), - WHITE(255, 255, 255), BLACK(0, 0, 0), BLANK(0, 0, 0, 0); + WHITE(255, 255, 255), BLACK(0, 0, 0), BLANK(0, 0, 0, 0), TANGERINE(255, 165, 0); #endif // Thanks to scripticuk and others for updating the key maps // NOTE: The GLUT platform will need updating, open to contributions ;) @@ -1104,9 +1109,20 @@ namespace olc std::vector pColData; Mode modeSample = Mode::NORMAL; + operator olc::SpritePatch(); + olc::SpritePatch Patch(const olc::vi2d& pos, const olc::vi2d& size); + olc::SpritePatch Patch(const olc::vf2d& pBL, const olc::vf2d& pTL, const olc::vf2d& pTR, const olc::vf2d& pBR); + static std::unique_ptr loader; }; + struct SpritePatch + { + olc::Sprite* sprite; + std::array coords; + }; + + // O------------------------------------------------------------------------------O // | olc::Decal - A GPU resident storage of an olc::Sprite | // O------------------------------------------------------------------------------O @@ -1119,12 +1135,23 @@ namespace olc void Update(); void UpdateSprite(); + operator olc::DecalPatch(); + olc::DecalPatch Patch(const olc::vi2d& pos, const olc::vi2d& size); + olc::DecalPatch Patch(const olc::vf2d& pBL, const olc::vf2d& pTL, const olc::vf2d& pTR, const olc::vf2d& pBR); + + public: // But dont touch int32_t id = -1; olc::Sprite* sprite = nullptr; olc::vf2d vUVScale = { 1.0f, 1.0f }; }; + struct DecalPatch + { + olc::Decal* decal; + std::array coords; + }; + enum class DecalMode { NORMAL, @@ -1488,6 +1515,11 @@ namespace olc // Clip a line segment to visible area bool ClipLineToScreen(olc::vi2d& in_p1, olc::vi2d& in_p2); + + // Patches + void DrawSprite(const olc::vf2d& pos, const SpritePatch& patch, const olc::vf2d& scale = { 1.0f, 1.0f }); + void DrawDecal(const olc::vf2d& pos, const DecalPatch& patch, const olc::vf2d& scale = { 1.0f, 1.0f }); + // Dont allow PGE to mark layers as dirty, so pixel graphics don't update void EnablePixelTransfer(const bool bEnable = true); @@ -2089,6 +2121,34 @@ namespace olc return { width, height }; } + + olc::Sprite::operator olc::SpritePatch() + { + return Patch({ 0,0 }, Size()); + } + + SpritePatch olc::Sprite::Patch(const olc::vi2d& pos, const olc::vi2d& size) + { + SpritePatch patch; + patch.sprite = this; + patch.coords[0] = olc::vf2d(pos.x, pos.y + size.y) / olc::vf2d(Size()); + patch.coords[1] = olc::vf2d(pos) / olc::vf2d(Size()); + patch.coords[2] = olc::vf2d(pos.x + size.x, pos.y) / olc::vf2d(Size()); + patch.coords[3] = olc::vf2d(pos + size) / olc::vf2d(Size()); + return patch; + } + + SpritePatch olc::Sprite::Patch(const olc::vf2d& pBL, const olc::vf2d& pTL, const olc::vf2d& pTR, const olc::vf2d& pBR) + { + SpritePatch patch; + patch.sprite = this; + patch.coords[0] = pBL; + patch.coords[1] = pTL; + patch.coords[2] = pTR; + patch.coords[3] = pBR; + return patch; + } + // O------------------------------------------------------------------------------O // | olc::Decal IMPLEMENTATION | // O------------------------------------------------------------------------------O @@ -2163,6 +2223,33 @@ namespace olc return pSprite.get(); } + olc::Decal::operator olc::DecalPatch() + { + return Patch({ 0,0 }, this->sprite->Size()); + } + + DecalPatch olc::Decal::Patch(const olc::vi2d& pos, const olc::vi2d& size) + { + DecalPatch patch; + patch.decal = this; + patch.coords[0] = olc::vf2d(pos.x, pos.y + size.y) / olc::vf2d(this->sprite->Size()); + patch.coords[1] = olc::vf2d(pos) / olc::vf2d(this->sprite->Size()); + patch.coords[2] = olc::vf2d(pos.x + size.x, pos.y) / olc::vf2d(this->sprite->Size()); + patch.coords[3] = olc::vf2d(pos + size) / olc::vf2d(this->sprite->Size()); + return patch; + } + + DecalPatch olc::Decal::Patch(const olc::vf2d& pBL, const olc::vf2d& pTL, const olc::vf2d& pTR, const olc::vf2d& pBR) + { + DecalPatch patch; + patch.decal = this; + patch.coords[0] = pBL; + patch.coords[1] = pTL; + patch.coords[2] = pTR; + patch.coords[3] = pBR; + return patch; + } + // O------------------------------------------------------------------------------O // | olc::ResourcePack IMPLEMENTATION | // O------------------------------------------------------------------------------O @@ -3303,6 +3390,53 @@ namespace olc } } + + void PixelGameEngine::DrawSprite(const olc::vf2d& pos, const SpritePatch& patch, const olc::vf2d& scale) + { + std::vector transformed(4); + transformed = { + (patch.coords[0] - patch.coords[1]) * patch.sprite->Size() * scale + pos, + pos, + (patch.coords[2] - patch.coords[1]) * patch.sprite->Size() * scale + pos, + (patch.coords[3] - patch.coords[1]) * patch.sprite->Size() * scale + pos + } ; + + std::vector verts = + { + olc::vf2d{pos.x, pos.y + scale.y}, + pos, + olc::vf2d{pos.x + scale.x, pos.y}, + olc::vf2d{pos + scale} + }; + + std::vector uv(patch.coords.begin(), patch.coords.end()); + + FillTexturedPolygon(verts, uv, { olc::WHITE, olc::WHITE , olc::WHITE , olc::WHITE }, patch.sprite, olc::DecalStructure::FAN); + } + + void PixelGameEngine::DrawDecal(const olc::vf2d& pos, const DecalPatch& patch, const olc::vf2d& scale) + { + std::vector transformed(4); + transformed = { + (patch.coords[0] - patch.coords[1]) * patch.decal->sprite->Size() * scale + pos, + pos, + (patch.coords[2] - patch.coords[1]) * patch.decal->sprite->Size() * scale + pos, + (patch.coords[3] - patch.coords[1]) * patch.decal->sprite->Size() * scale + pos + }; + + std::vector verts = + { + olc::vf2d{pos.x, pos.y + scale.y}, + pos, + olc::vf2d{pos.x + scale.x, pos.y}, + olc::vf2d{pos + scale} + }; + + std::vector uv(patch.coords.begin(), patch.coords.end()); + + DrawPolygonDecal(patch.decal, verts, uv, { olc::WHITE, olc::WHITE , olc::WHITE , olc::WHITE }); + } + void PixelGameEngine::SetDecalMode(const olc::DecalMode& mode) { nDecalMode = mode;