diff --git a/Crawler/Crawler.vcxproj b/Crawler/Crawler.vcxproj
index a5bf9133..9c6368ef 100644
--- a/Crawler/Crawler.vcxproj
+++ b/Crawler/Crawler.vcxproj
@@ -17,7 +17,6 @@
Release
x64
-
16.0
@@ -53,27 +52,24 @@
true
Unicode
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Level3
@@ -108,6 +104,7 @@
true
_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
+ stdcpp17
Console
@@ -122,6 +119,7 @@
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
+ stdcpp17
Console
@@ -130,9 +128,16 @@
true
-
-
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/Crawler/Crawler.vcxproj.filters b/Crawler/Crawler.vcxproj.filters
index a8a65633..ea59ed75 100644
--- a/Crawler/Crawler.vcxproj.filters
+++ b/Crawler/Crawler.vcxproj.filters
@@ -14,4 +14,23 @@
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
\ No newline at end of file
diff --git a/Crawler/assets/nico-warrior.png b/Crawler/assets/nico-warrior.png
new file mode 100644
index 00000000..03428b2e
Binary files /dev/null and b/Crawler/assets/nico-warrior.png differ
diff --git a/Crawler/assets/nico-warrior.xcf b/Crawler/assets/nico-warrior.xcf
new file mode 100644
index 00000000..361693c7
Binary files /dev/null and b/Crawler/assets/nico-warrior.xcf differ
diff --git a/Crawler/assets/slime.png b/Crawler/assets/slime.png
new file mode 100644
index 00000000..8c9a2063
Binary files /dev/null and b/Crawler/assets/slime.png differ
diff --git a/Crawler/main.cpp b/Crawler/main.cpp
new file mode 100644
index 00000000..44f7ec6d
--- /dev/null
+++ b/Crawler/main.cpp
@@ -0,0 +1,83 @@
+#define OLC_PGE_APPLICATION
+#include "olcPixelGameEngine.h"
+#include "olcUTIL_Camera2D.h"
+#define OLC_PGEX_TRANSFORMEDVIEW
+#include "olcPGEX_TransformedView.h"
+
+using namespace olc;
+using namespace olc::utils;
+
+const vi2d WINDOW_SIZE={24*8,24*8};
+
+struct Player{
+ vf2d pos;
+ float moveSpd;
+ Player(){};
+ Player(vf2d pos,float moveSpd):
+ pos(pos),moveSpd(moveSpd){};
+};
+
+class Crawler : public olc::PixelGameEngine
+{
+ const vi2d WORLD_SIZE={64,64};
+ Camera2D camera;
+ TileTransformedView view;
+ Player player=Player{{},100};
+
+public:
+ Crawler()
+ {
+ sAppName = "Crawler Concept";
+ }
+
+public:
+ bool OnUserCreate() override
+ {
+ camera=Camera2D{WINDOW_SIZE};
+ camera.SetMode(olc::utils::Camera2D::Mode::LazyFollow);
+ camera.SetTarget(player.pos);
+ camera.SetWorldBoundary({0,0},WORLD_SIZE*24);
+ camera.EnableWorldBoundary(true);
+ view=TileTransformedView{GetScreenSize(),{1,1}};
+ return true;
+ }
+
+ bool OnUserUpdate(float fElapsedTime) override
+ {
+ if(GetKey(RIGHT).bHeld){
+ player.pos.x+=fElapsedTime*player.moveSpd;
+ }
+ if(GetKey(LEFT).bHeld){
+ player.pos.x-=fElapsedTime*player.moveSpd;
+ }
+ if(GetKey(UP).bHeld){
+ player.pos.y-=fElapsedTime*player.moveSpd;
+ }
+ if(GetKey(DOWN).bHeld){
+ player.pos.y+=fElapsedTime*player.moveSpd;
+ }
+
+ camera.Update(fElapsedTime);
+ view.SetWorldOffset(camera.GetViewPosition());
+ //view.HandlePanAndZoom();
+ // called once per frame
+ Clear(BLACK);
+ for (int x = view.GetTopLeftTile().x/24; x <= view.GetBottomRightTile().x/24; x++){
+ for (int y = view.GetTopLeftTile().y/24; y <= view.GetBottomRightTile().y/24; y++){
+ view.DrawRect(vi2d{x,y}*24,{24,24},DARK_GREY);
+ }
+ }
+ view.DrawCircle(player.pos,8);
+ return true;
+ }
+};
+
+
+int main()
+{
+ Crawler demo;
+ if (demo.Construct(WINDOW_SIZE.x, WINDOW_SIZE.y, 4, 4))
+ demo.Start();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/Crawler/olcPGEX_TransformedView.h b/Crawler/olcPGEX_TransformedView.h
new file mode 100644
index 00000000..bfc48823
--- /dev/null
+++ b/Crawler/olcPGEX_TransformedView.h
@@ -0,0 +1,746 @@
+/*
+olcPGEX_TransformedView.h
+
++-------------------------------------------------------------+
+| OneLoneCoder Pixel Game Engine Extension |
+| Transformed View v1.08 |
++-------------------------------------------------------------+
+
+NOTE: UNDER ACTIVE DEVELOPMENT - THERE ARE BUGS/GLITCHES
+
+What is this?
+~~~~~~~~~~~~~
+This extension provides drawing routines that are compatible with
+changeable world and screen spaces. For example you can pan and
+zoom, and all PGE drawing routines will automatically adopt the current
+world scales and offsets.
+
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2018 - 2022 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
+
+Revisions:
+1.00: Initial Release
+1.01: Fix for rounding error when scaling to screen
+1.02: Added DrawLineDecal for convenience
+1.03: Removed std::floor from WorldToScreen()
+Added HandlePanAndZoom(...) convenience function
+Removed unused "range" facility in TileTransformView
+1.04: Added DrawPolygonDecal() for arbitrary polygons
+1.05: Clipped DrawSprite() to visible area, massive performance increase
+1.06: Fixed error in DrawLine() - Thanks CraisyDaisyRecords (& Fern)!
+1.07: +DrawRectDecal()
++GetPGE()
+1.08: +DrawPolygonDecal() with tint overload, akin to PGE
+*/
+
+#pragma once
+#ifndef OLC_PGEX_TRANSFORMEDVIEW_H
+#define OLC_PGEX_TRANSFORMEDVIEW_H
+
+#include "olcPixelGameEngine.h"
+
+
+
+namespace olc
+{
+ class TransformedView : public olc::PGEX
+ {
+ public:
+ TransformedView() = default;
+ virtual void Initialise(const olc::vi2d& vViewArea, const olc::vf2d& vPixelScale = { 1.0f, 1.0f });
+
+ olc::PixelGameEngine* GetPGE();
+
+ public:
+ void SetWorldOffset(const olc::vf2d& vOffset);
+ void MoveWorldOffset(const olc::vf2d& vDeltaOffset);
+ void SetWorldScale(const olc::vf2d& vScale);
+ void SetViewArea(const olc::vi2d& vViewArea);
+ olc::vf2d GetWorldTL() const;
+ olc::vf2d GetWorldBR() const;
+ olc::vf2d GetWorldVisibleArea() const;
+ void ZoomAtScreenPos(const float fDeltaZoom, const olc::vi2d& vPos);
+ void SetZoom(const float fZoom, const olc::vf2d& vPos);
+ void StartPan(const olc::vi2d& vPos);
+ void UpdatePan(const olc::vi2d& vPos);
+ void EndPan(const olc::vi2d& vPos);
+ const olc::vf2d& GetWorldOffset() const;
+ const olc::vf2d& GetWorldScale() const;
+ virtual olc::vf2d WorldToScreen(const olc::vf2d& vWorldPos) const;
+ virtual olc::vf2d ScreenToWorld(const olc::vf2d& vScreenPos) const;
+ virtual olc::vf2d ScaleToWorld(const olc::vf2d& vScreenSize) const;
+ virtual olc::vf2d ScaleToScreen(const olc::vf2d& vWorldSize) const;
+ virtual bool IsPointVisible(const olc::vf2d& vPos) const;
+ virtual bool IsRectVisible(const olc::vf2d& vPos, const olc::vf2d& vSize) const;
+ virtual void HandlePanAndZoom(const int nMouseButton = 2, const float fZoomRate = 0.1f, const bool bPan = true, const bool bZoom = true);
+ protected:
+ olc::vf2d m_vWorldOffset = { 0.0f, 0.0f };
+ olc::vf2d m_vWorldScale = { 1.0f, 1.0f };
+ olc::vf2d m_vRecipPixel = { 1.0f, 1.0f };
+ olc::vf2d m_vPixelScale = { 1.0f, 1.0f };
+ bool m_bPanning = false;
+ olc::vf2d m_vStartPan = { 0.0f, 0.0f };
+ olc::vi2d m_vViewArea;
+
+ public: // Hopefully, these should look familiar!
+ // Plots a single point
+ virtual bool Draw(float x, float y, olc::Pixel p = olc::WHITE);
+ bool Draw(const olc::vf2d& pos, olc::Pixel p = olc::WHITE);
+ // Draws a line from (x1,y1) to (x2,y2)
+ void DrawLine(float x1, float y1, float x2, float y2, olc::Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF);
+ void DrawLine(const olc::vf2d& pos1, const olc::vf2d& pos2, olc::Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF);
+ // Draws a circle located at (x,y) with radius
+ void DrawCircle(float x, float y, float radius, olc::Pixel p = olc::WHITE, uint8_t mask = 0xFF);
+ void DrawCircle(const olc::vf2d& pos, float radius, olc::Pixel p = olc::WHITE, uint8_t mask = 0xFF);
+ // Fills a circle located at (x,y) with radius
+ void FillCircle(float x, float y, float radius, olc::Pixel p = olc::WHITE);
+ void FillCircle(const olc::vf2d& pos, float radius, olc::Pixel p = olc::WHITE);
+ // Draws a rectangle at (x,y) to (x+w,y+h)
+ void DrawRect(float x, float y, float w, float h, olc::Pixel p = olc::WHITE);
+ void DrawRect(const olc::vf2d& pos, const olc::vf2d& size, olc::Pixel p = olc::WHITE);
+ // Fills a rectangle at (x,y) to (x+w,y+h)
+ void FillRect(float x, float y, float w, float h, olc::Pixel p = olc::WHITE);
+ void FillRect(const olc::vf2d& pos, const olc::vf2d& size, olc::Pixel p = olc::WHITE);
+ // Draws a triangle between points (x1,y1), (x2,y2) and (x3,y3)
+ void DrawTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p = olc::WHITE);
+ void DrawTriangle(const olc::vf2d& pos1, const olc::vf2d& pos2, const olc::vf2d& pos3, olc::Pixel p = olc::WHITE);
+ // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3)
+ void FillTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p = olc::WHITE);
+ void FillTriangle(const olc::vf2d& pos1, const olc::vf2d& pos2, const olc::vf2d& pos3, olc::Pixel p = olc::WHITE);
+ // Draws an entire sprite at location (x,y)
+ void DrawSprite(float x, float y, olc::Sprite* sprite, float scalex = 1, float scaley = 1, uint8_t flip = olc::Sprite::NONE);
+ void DrawSprite(const olc::vf2d& pos, olc::Sprite* sprite, const olc::vf2d& scale = { 1.0f, 1.0f }, uint8_t flip = olc::Sprite::NONE);
+ // Draws an area of a sprite at location (x,y), where the
+ // selected area is (ox,oy) to (ox+w,oy+h)
+ void DrawPartialSprite(float x, float y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, float scalex = 1, float scaley = 1, uint8_t flip = olc::Sprite::NONE);
+ void DrawPartialSprite(const olc::vf2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, const olc::vf2d& scale = { 1.0f, 1.0f }, uint8_t flip = olc::Sprite::NONE);
+ void DrawString(float x, float y, const std::string& sText, Pixel col, const olc::vf2d& scale);
+ void DrawString(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale);
+
+
+ // Draws a whole decal, with optional scale and tinting
+ void DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE);
+ // Draws a region of a decal, with optional scale and tinting
+ 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, 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);
+ void DrawWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::Pixel& tint = olc::WHITE);
+ //// As above, but you can specify a region of a decal source sprite
+ void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
+ void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
+ void DrawPartialWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
+ //// Draws a decal rotated to specified angle, wit point of rotation offset
+ void DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE);
+ void DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE);
+ // Draws a multiline string as a decal, with tiniting and scaling
+ void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
+ void DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
+ // Draws a single shaded filled rectangle as a decal
+ void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE);
+ void DrawRectDecal(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);
+ void DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p = olc::WHITE);
+ void DrawPolygonDecal(olc::Decal* decal, const std::vector&pos, const std::vector&uv, const std::vector &tint);
+ void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector& colours, const olc::Pixel tint);
+
+
+#if defined(OLC_PGEX_SHADER)
+ // Shader Specific
+ void DrawDecal(olc::Shade& shader, const olc::vf2d & pos, olc::Decal * decal, const olc::vf2d & scale = { 1.0f,1.0f }, const olc::Pixel & tint = olc::WHITE);
+ void DrawPartialDecal(olc::Shade& shader, 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(olc::Shade& shader, 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);
+#endif
+
+
+
+ };
+
+ class TileTransformedView : public TransformedView
+ {
+ public:
+ TileTransformedView() = default;
+ TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize);
+
+ public:
+ olc::vi2d GetTopLeftTile() const;
+ olc::vi2d GetBottomRightTile() const;
+ olc::vi2d GetVisibleTiles() const;
+ olc::vi2d GetTileUnderScreenPos(const olc::vi2d& vPos) const;
+ const olc::vi2d GetTileOffset() const;
+
+ };
+}
+
+#ifdef OLC_PGEX_TRANSFORMEDVIEW
+#undef OLC_PGEX_TRANSFORMEDVIEW
+
+namespace olc
+{
+ olc::PixelGameEngine* TransformedView::GetPGE()
+ {
+ return pge;
+ }
+
+ void TransformedView::Initialise(const olc::vi2d& vViewArea, const olc::vf2d& vPixelScale)
+ {
+ SetViewArea(vViewArea);
+ SetWorldScale(vPixelScale);
+ m_vPixelScale = vPixelScale;
+ m_vRecipPixel = 1.0f / m_vPixelScale;
+ }
+
+ void TransformedView::SetWorldOffset(const olc::vf2d& vOffset)
+ {
+ m_vWorldOffset = vOffset;
+ }
+
+ void TransformedView::MoveWorldOffset(const olc::vf2d& vDeltaOffset)
+ {
+ m_vWorldOffset += vDeltaOffset;
+ }
+
+ void TransformedView::SetWorldScale(const olc::vf2d& vScale)
+ {
+ m_vWorldScale = vScale;
+ }
+
+ void TransformedView::SetViewArea(const olc::vi2d& vViewArea)
+ {
+ m_vViewArea = vViewArea;
+ }
+
+ olc::vf2d TransformedView::GetWorldTL() const
+ {
+ return TransformedView::ScreenToWorld({ 0,0 });
+ }
+
+ olc::vf2d TransformedView::GetWorldBR() const
+ {
+ return TransformedView::ScreenToWorld(m_vViewArea);
+ }
+
+ olc::vf2d TransformedView::GetWorldVisibleArea() const
+ {
+ return GetWorldBR() - GetWorldTL();
+ }
+
+ void TransformedView::ZoomAtScreenPos(const float fDeltaZoom, const olc::vi2d& vPos)
+ {
+ olc::vf2d vOffsetBeforeZoom = ScreenToWorld(vPos);
+ m_vWorldScale *= fDeltaZoom;
+ olc::vf2d vOffsetAfterZoom = ScreenToWorld(vPos);
+ m_vWorldOffset += vOffsetBeforeZoom - vOffsetAfterZoom;
+ }
+
+ void TransformedView::SetZoom(const float fZoom, const olc::vf2d& vPos)
+ {
+ olc::vf2d vOffsetBeforeZoom = ScreenToWorld(vPos);
+ m_vWorldScale = { fZoom, fZoom };
+ olc::vf2d vOffsetAfterZoom = ScreenToWorld(vPos);
+ m_vWorldOffset += vOffsetBeforeZoom - vOffsetAfterZoom;
+ }
+
+ void TransformedView::StartPan(const olc::vi2d& vPos)
+ {
+ m_bPanning = true;
+ m_vStartPan = olc::vf2d(vPos);
+ }
+
+ void TransformedView::UpdatePan(const olc::vi2d& vPos)
+ {
+ if (m_bPanning)
+ {
+ m_vWorldOffset -= (olc::vf2d(vPos) - m_vStartPan) / m_vWorldScale;
+ m_vStartPan = olc::vf2d(vPos);
+ }
+ }
+
+ void TransformedView::EndPan(const olc::vi2d& vPos)
+ {
+ UpdatePan(vPos);
+ m_bPanning = false;
+ }
+
+ const olc::vf2d& TransformedView::GetWorldOffset() const
+ {
+ return m_vWorldOffset;
+ }
+
+ const olc::vf2d& TransformedView::GetWorldScale() const
+ {
+ return m_vWorldScale;
+ }
+
+ olc::vf2d TransformedView::WorldToScreen(const olc::vf2d& vWorldPos) const
+ {
+ olc::vf2d vFloat = ((vWorldPos - m_vWorldOffset) * m_vWorldScale);
+ //vFloat = { std::floor(vFloat.x + 0.5f), std::floor(vFloat.y + 0.5f) };
+ return vFloat;
+ }
+
+ olc::vf2d TransformedView::ScreenToWorld(const olc::vf2d& vScreenPos) const
+ {
+ return (olc::vf2d(vScreenPos) / m_vWorldScale) + m_vWorldOffset;
+ }
+
+ olc::vf2d TransformedView::ScaleToWorld(const olc::vf2d& vScreenSize) const
+ {
+ return (olc::vf2d(vScreenSize) / m_vWorldScale);
+ }
+
+ olc::vf2d TransformedView::ScaleToScreen(const olc::vf2d& vWorldSize) const
+ {
+ //olc::vf2d vFloat = (vWorldSize * m_vWorldScale) + olc::vf2d(0.5f, 0.5f);
+ //return vFloat.floor();
+ return (vWorldSize * m_vWorldScale);
+ }
+
+ bool TransformedView::IsPointVisible(const olc::vf2d & vPos) const
+ {
+ olc::vi2d vScreen = WorldToScreen(vPos);
+ return vScreen.x >= 0 && vScreen.x < m_vViewArea.x&& vScreen.y >= 0 && vScreen.y < m_vViewArea.y;
+ }
+
+ bool TransformedView::IsRectVisible(const olc::vf2d& vPos, const olc::vf2d& vSize) const
+ {
+ olc::vi2d vScreenPos = WorldToScreen(vPos);
+ olc::vi2d vScreenSize = vSize * m_vWorldScale;
+ return (vScreenPos.x < 0 + m_vViewArea.x && vScreenPos.x + vScreenSize.x > 0 && vScreenPos.y < m_vViewArea.y&& vScreenPos.y + vScreenSize.y > 0);
+ }
+
+ void TransformedView::HandlePanAndZoom(const int nMouseButton, const float fZoomRate, const bool bPan, const bool bZoom)
+ {
+ const auto& vMousePos = pge->GetMousePos();
+ if (bPan)
+ {
+ if (pge->GetMouse(nMouseButton).bPressed) StartPan(vMousePos);
+ if (pge->GetMouse(nMouseButton).bHeld) UpdatePan(vMousePos);
+ if (pge->GetMouse(nMouseButton).bReleased) EndPan(vMousePos);
+ }
+
+ if (bZoom)
+ {
+ if (pge->GetMouseWheel() > 0) ZoomAtScreenPos(1.0f + fZoomRate, vMousePos);
+ if (pge->GetMouseWheel() < 0) ZoomAtScreenPos(1.0f - fZoomRate, vMousePos);
+ }
+ }
+
+ bool TransformedView::Draw(float x, float y, olc::Pixel p)
+ {
+ return Draw({ x, y }, p);
+ }
+
+ bool TransformedView::Draw(const olc::vf2d & pos, olc::Pixel p)
+ {
+ return pge->Draw(WorldToScreen(pos), p);
+ }
+
+ void TransformedView::DrawLine(float x1, float y1, float x2, float y2, olc::Pixel p, uint32_t pattern)
+ {
+ DrawLine({ x1, y1 }, { x2, y2 }, p, pattern);
+ }
+
+ void TransformedView::DrawLine(const olc::vf2d & pos1, const olc::vf2d & pos2, olc::Pixel p, uint32_t pattern)
+ {
+ pge->DrawLine(WorldToScreen(pos1), WorldToScreen(pos2), p, pattern);
+ }
+
+ void TransformedView::DrawCircle(float x, float y, float radius, olc::Pixel p, uint8_t mask)
+ {
+ DrawCircle({ x,y }, radius, p, mask);
+ }
+
+ void TransformedView::DrawCircle(const olc::vf2d & pos, float radius, olc::Pixel p, uint8_t mask)
+ {
+ pge->DrawCircle(WorldToScreen(pos), int32_t(radius * m_vWorldScale.x), p, mask);
+ }
+
+ void TransformedView::FillCircle(float x, float y, float radius, olc::Pixel p)
+ {
+ FillCircle({ x,y }, radius, p);
+ }
+
+ void TransformedView::FillCircle(const olc::vf2d & pos, float radius, olc::Pixel p)
+ {
+ pge->FillCircle(WorldToScreen(pos), int32_t(radius * m_vWorldScale.x), p);
+ }
+
+ void TransformedView::DrawRect(float x, float y, float w, float h, olc::Pixel p)
+ {
+ DrawRect({ x, y }, { w, h }, p);
+ }
+
+ void TransformedView::DrawRect(const olc::vf2d & pos, const olc::vf2d & size, olc::Pixel p)
+ {
+ pge->DrawRect(WorldToScreen(pos), ((size * m_vWorldScale) + olc::vf2d(0.5f, 0.5f)).floor(), p);
+ }
+
+ void TransformedView::FillRect(float x, float y, float w, float h, olc::Pixel p)
+ {
+ FillRect({ x, y }, { w, h }, p);
+ }
+
+ void TransformedView::FillRect(const olc::vf2d & pos, const olc::vf2d & size, olc::Pixel p)
+ {
+ pge->FillRect(WorldToScreen(pos), size * m_vWorldScale, p);
+ }
+
+ void TransformedView::DrawTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p)
+ {
+ DrawTriangle({ x1, y1 }, { x2, y2 }, { x3, y3 }, p);
+ }
+
+ void TransformedView::DrawTriangle(const olc::vf2d & pos1, const olc::vf2d & pos2, const olc::vf2d & pos3, olc::Pixel p)
+ {
+ pge->DrawTriangle(WorldToScreen(pos1), WorldToScreen(pos2), WorldToScreen(pos3), p);
+ }
+
+ void TransformedView::FillTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p)
+ {
+ FillTriangle({ x1, y1 }, { x2, y2 }, { x3, y3 }, p);
+ }
+
+ void TransformedView::FillTriangle(const olc::vf2d & pos1, const olc::vf2d & pos2, const olc::vf2d & pos3, olc::Pixel p)
+ {
+ pge->FillTriangle(WorldToScreen(pos1), WorldToScreen(pos2), WorldToScreen(pos3), p);
+ }
+
+ void TransformedView::DrawSprite(float x, float y, olc::Sprite* sprite, float scalex, float scaley, uint8_t flip)
+ {
+ DrawSprite({ x, y }, sprite, { scalex, scaley }, flip);
+ }
+
+ void TransformedView::DrawSprite(const olc::vf2d & pos, olc::Sprite * sprite, const olc::vf2d & scale, uint8_t flip)
+ {
+ olc::vf2d vSpriteSize = olc::vf2d(float(sprite->width), float(sprite->height));
+ if (IsRectVisible(pos, vSpriteSize * scale))
+ {
+ olc::vf2d vSpriteScaledSize = vSpriteSize * m_vRecipPixel * m_vWorldScale * scale;
+ olc::vi2d vPixel;
+ olc::vi2d vSpritePixelStart = WorldToScreen(pos);
+ olc::vi2d vSpritePixelEnd = WorldToScreen((vSpriteSize * scale) + pos);
+
+ olc::vi2d vScreenPixelStart = (vSpritePixelStart).max({0,0});
+ olc::vi2d vScreenPixelEnd = (vSpritePixelEnd).min({ pge->ScreenWidth(),pge->ScreenHeight() });
+
+ olc::vf2d vPixelStep = 1.0f / vSpriteScaledSize;
+
+ for (vPixel.y = vScreenPixelStart.y; vPixel.y < vScreenPixelEnd.y; vPixel.y++)
+ {
+ for (vPixel.x = vScreenPixelStart.x; vPixel.x < vScreenPixelEnd.x; vPixel.x++)
+ {
+ olc::vf2d vSample = olc::vf2d(vPixel - vSpritePixelStart) * vPixelStep;
+ pge->Draw(vPixel, sprite->Sample(vSample.x, vSample.y));
+ }
+ }
+ }
+ }
+
+
+ void TransformedView::DrawPartialSprite(float x, float y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, float scalex, float scaley, uint8_t flip)
+ {
+ DrawPartialSprite({ x,y }, sprite, { ox,oy }, { w, h }, { scalex, scaley }, flip);
+ }
+
+ void TransformedView::DrawPartialSprite(const olc::vf2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, const olc::vf2d& scale, uint8_t flip)
+ {
+ olc::vf2d vSpriteSize = size;
+ if (IsRectVisible(pos, size * scale))
+ {
+ olc::vf2d vSpriteScaledSize = olc::vf2d(size) * m_vRecipPixel * m_vWorldScale * scale;
+ olc::vf2d vSpritePixelStep = 1.0f / olc::vf2d(float(sprite->width), float(sprite->height));
+ olc::vi2d vPixel, vStart = WorldToScreen(pos), vEnd = vSpriteScaledSize + vStart;
+ olc::vf2d vScreenPixelStep = 1.0f / vSpriteScaledSize;
+
+ for (vPixel.y = vStart.y; vPixel.y < vEnd.y; vPixel.y++)
+ {
+ for (vPixel.x = vStart.x; vPixel.x < vEnd.x; vPixel.x++)
+ {
+ olc::vf2d vSample = ((olc::vf2d(vPixel - vStart) * vScreenPixelStep) * size * vSpritePixelStep) + olc::vf2d(sourcepos) * vSpritePixelStep;
+ pge->Draw(vPixel, sprite->Sample(vSample.x, vSample.y));
+ }
+ }
+ }
+ }
+
+ void TransformedView::DrawString(float x, float y, const std::string& sText, Pixel col, const olc::vf2d& scale)
+ {
+ DrawString({ x, y }, sText, col, scale);
+ }
+
+ void TransformedView::DrawString(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale)
+ {
+ olc::vf2d vOffset = { 0.0f, 0.0f };
+ Pixel::Mode m = pge->GetPixelMode();
+
+ auto StringPlot = [&col](const int x, const int y, const olc::Pixel& pSource, const olc::Pixel& pDest)
+ {
+ return pSource.r > 1 ? col : pDest;
+ };
+
+ pge->SetPixelMode(StringPlot);
+
+ for (auto c : sText)
+ {
+ if (c == '\n')
+ {
+ vOffset.x = 0.0f; vOffset.y += 8.0f * m_vRecipPixel.y * scale.y;
+ }
+ else
+ {
+ int32_t ox = ((c - 32) % 16) * 8;
+ int32_t oy = ((c - 32) / 16) * 8;
+ DrawPartialSprite(pos + vOffset, pge->GetFontSprite(), { ox, oy }, { 8, 8 }, scale);
+ vOffset.x += 8.0f * m_vRecipPixel.x * scale.x;
+ }
+ }
+ pge->SetPixelMode(m);
+ }
+
+
+ void TransformedView::DrawDecal(const olc::vf2d & pos, olc::Decal * decal, const olc::vf2d & scale, const olc::Pixel & tint)
+ {
+ pge->DrawDecal(WorldToScreen(pos), decal, scale * m_vWorldScale * m_vRecipPixel, tint);
+ }
+
+ void TransformedView::DrawPartialDecal(const olc::vf2d & pos, olc::Decal * decal, const olc::vf2d & source_pos, const olc::vf2d & source_size, const olc::vf2d & scale, const olc::Pixel & tint)
+ {
+ pge->DrawPartialDecal(WorldToScreen(pos), decal, source_pos, source_size, scale * m_vWorldScale * m_vRecipPixel, tint);
+ }
+
+ void TransformedView::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)
+ {
+ pge->DrawPartialDecal(WorldToScreen(pos), size * m_vWorldScale * m_vRecipPixel, decal, source_pos, source_size, tint);
+ }
+
+ void TransformedView::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements)
+ {
+ std::vector vTransformed(elements);
+ for (uint32_t n = 0; n < elements; n++)
+ vTransformed[n] = WorldToScreen(pos[n]);
+ pge->DrawExplicitDecal(decal, vTransformed.data(), uv, col, elements);
+ }
+
+ void TransformedView::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint)
+ {
+ std::array vTransformed =
+ { {
+ WorldToScreen(pos[0]), WorldToScreen(pos[1]),
+ WorldToScreen(pos[2]), WorldToScreen(pos[3]),
+ } };
+
+ pge->DrawWarpedDecal(decal, vTransformed, tint);
+ }
+
+ void TransformedView::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint)
+ {
+ DrawWarpedDecal(decal, &pos[0], tint);
+ }
+
+ void TransformedView::DrawWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::Pixel& tint)
+ {
+ DrawWarpedDecal(decal, pos.data(), tint);
+ }
+
+ void TransformedView::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
+ {
+ DrawPartialWarpedDecal(decal, &pos[0], source_pos, source_size, tint);
+ }
+
+ void TransformedView::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
+ {
+ std::array vTransformed =
+ { {
+ WorldToScreen(pos[0]), WorldToScreen(pos[1]),
+ WorldToScreen(pos[2]), WorldToScreen(pos[3]),
+ } };
+
+ pge->DrawPartialWarpedDecal(decal, vTransformed, source_pos, source_size, tint);
+ }
+
+ void TransformedView::DrawPartialWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
+ {
+ DrawPartialWarpedDecal(decal, pos.data(), source_pos, source_size, tint);
+ }
+
+ void TransformedView::DrawRotatedDecal(const olc::vf2d & pos, olc::Decal * decal, const float fAngle, const olc::vf2d & center, const olc::vf2d & scale, const olc::Pixel & tint)
+ {
+ pge->DrawRotatedDecal(WorldToScreen(pos), decal, fAngle, center, scale * m_vWorldScale * m_vRecipPixel, tint);
+ }
+
+ void TransformedView::DrawPartialRotatedDecal(const olc::vf2d & pos, olc::Decal * decal, const float fAngle, const olc::vf2d & center, const olc::vf2d & source_pos, const olc::vf2d & source_size, const olc::vf2d & scale, const olc::Pixel & tint)
+ {
+ pge->DrawPartialRotatedDecal(WorldToScreen(pos), decal, fAngle, center, source_pos, source_size, scale * m_vWorldScale * m_vRecipPixel, tint);
+ }
+
+ void TransformedView::DrawStringDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::vf2d & scale)
+ {
+ pge->DrawStringDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel);
+ }
+
+ void TransformedView::DrawStringPropDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::vf2d & scale )
+ {
+ pge->DrawStringPropDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel);
+ }
+
+ void TransformedView::FillRectDecal(const olc::vf2d & pos, const olc::vf2d & size, const olc::Pixel col)
+ {
+ pge->FillRectDecal(WorldToScreen(pos), (size * m_vWorldScale).ceil(), col);
+ }
+
+ void TransformedView::DrawRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col)
+ {
+ pge->DrawRectDecal(WorldToScreen(pos), (size * m_vWorldScale).ceil(), col);
+ }
+
+ void TransformedView::DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p)
+ {
+ pge->DrawLineDecal(WorldToScreen(pos1), WorldToScreen(pos2), p);
+ }
+
+ void TransformedView::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)
+ {
+ pge->GradientFillRectDecal(WorldToScreen(pos), size * m_vWorldScale, colTL, colBL, colBR, colTR);
+ }
+
+ void TransformedView::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint)
+ {
+ std::vector vTransformed(pos.size());
+ for (uint32_t n = 0; n < pos.size(); n++)
+ vTransformed[n] = WorldToScreen(pos[n]);
+ pge->DrawPolygonDecal(decal, vTransformed, uv, tint);
+ }
+
+ void TransformedView::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector &tint)
+ {
+ std::vector vTransformed(pos.size());
+ for (uint32_t n = 0; n < pos.size(); n++)
+ vTransformed[n] = WorldToScreen(pos[n]);
+ pge->DrawPolygonDecal(decal, vTransformed, uv, tint);
+ }
+
+ void TransformedView::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector& colours, const olc::Pixel tint)
+ {
+ std::vector vTransformed(pos.size());
+ for (uint32_t n = 0; n < pos.size(); n++)
+ vTransformed[n] = WorldToScreen(pos[n]);
+ pge->DrawPolygonDecal(decal, vTransformed, uv, colours, tint);
+ }
+
+
+
+#if defined (OLC_PGEX_SHADER)
+
+ void TransformedView::DrawDecal(olc::Shade &shade, const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale, const olc::Pixel& tint)
+ {
+ shade.DrawDecal(WorldToScreen(pos), decal, scale * m_vWorldScale * m_vRecipPixel, tint);
+ }
+
+ void TransformedView::DrawPartialDecal(olc::Shade& shade, const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale, const olc::Pixel& tint)
+ {
+ shade.DrawPartialDecal(WorldToScreen(pos), decal, source_pos, source_size, scale * m_vWorldScale * m_vRecipPixel, tint);
+ }
+
+ void TransformedView::DrawPartialDecal(olc::Shade& shade, 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)
+ {
+ shade.DrawPartialDecal(WorldToScreen(pos), size * m_vWorldScale * m_vRecipPixel, decal, source_pos, source_size, tint);
+ }
+
+#endif
+
+
+
+
+
+
+
+ /////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////
+
+
+ TileTransformedView::TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize)
+ {
+ Initialise(vViewArea, vTileSize);
+ }
+
+
+ olc::vi2d TileTransformedView::GetTopLeftTile() const
+ {
+ return ScreenToWorld({ 0,0 }).floor();
+ }
+
+ olc::vi2d TileTransformedView::GetBottomRightTile() const
+ {
+ return ScreenToWorld(m_vViewArea).ceil();
+ }
+
+ olc::vi2d TileTransformedView::GetVisibleTiles() const
+ {
+ return GetBottomRightTile() - GetTopLeftTile();
+ }
+
+ olc::vi2d TileTransformedView::GetTileUnderScreenPos(const olc::vi2d& vPos) const
+ {
+ return ScreenToWorld(vPos).floor();
+ }
+
+ const olc::vi2d TileTransformedView::GetTileOffset() const
+ {
+ return { int32_t((m_vWorldOffset.x - std::floor(m_vWorldOffset.x)) * m_vWorldScale.x),
+ int32_t((m_vWorldOffset.y - std::floor(m_vWorldOffset.y)) * m_vWorldScale.y) };
+ }
+}
+
+#endif
+#endif
\ No newline at end of file
diff --git a/Crawler/olcPixelGameEngine.h b/Crawler/olcPixelGameEngine.h
new file mode 100644
index 00000000..e6d3a9d2
--- /dev/null
+++ b/Crawler/olcPixelGameEngine.h
@@ -0,0 +1,6695 @@
+#pragma region license_and_help
+/*
+olcPixelGameEngine.h
+
++-------------------------------------------------------------+
+| OneLoneCoder Pixel Game Engine v2.23 |
+| "What do you need? Pixels... Lots of Pixels..." - javidx9 |
++-------------------------------------------------------------+
+
+What is this?
+~~~~~~~~~~~~~
+olc::PixelGameEngine is a single file, cross platform graphics and userinput
+framework used for games, visualisations, algorithm exploration and learning.
+It was developed by YouTuber "javidx9" as an assistive tool for many of his
+videos. The goal of this project is to provide high speed graphics with
+minimal project setup complexity, to encourage new programmers, younger people,
+and anyone else that wants to make fun things.
+
+However, olc::PixelGameEngine is not a toy! It is a powerful and fast utility
+capable of delivering high resolution, high speed, high quality applications
+which behave the same way regardless of the operating system or platform.
+
+This file provides the core utility set of the olc::PixelGameEngine, including
+window creation, keyboard/mouse input, main game thread, timing, pixel drawing
+routines, image/sprite loading and drawing routines, and a bunch of utility
+types to make rapid development of games/visualisations possible.
+
+
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2018 - 2022 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
+https://www.youtube.com/javidx9extra
+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
+Patreon: https://www.patreon.com/javidx9
+Community: https://community.onelonecoder.com
+
+
+
+Compiling in Linux
+~~~~~~~~~~~~~~~~~~
+You will need a modern C++ compiler, so update yours!
+To compile use the command:
+
+g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng -lstdc++fs -std=c++17
+
+On some Linux configurations, the frame rate is locked to the refresh
+rate of the monitor. This engine tries to unlock it but may not be
+able to, in which case try launching your program like this:
+
+vblank_mode=0 ./YourProgName
+
+
+
+Compiling in Code::Blocks on Windows
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Well I wont judge you, but make sure your Code::Blocks installation
+is really up to date - you may even consider updating your C++ toolchain
+to use MinGW32-W64.
+
+Guide for installing recent GCC for Windows:
+https://www.msys2.org/
+Guide for configuring code::blocks:
+https://solarianprogrammer.com/2019/11/05/install-gcc-windows/
+https://solarianprogrammer.com/2019/11/16/install-codeblocks-gcc-windows-build-c-cpp-fortran-programs/
+
+Add these libraries to "Linker Options":
+user32 gdi32 opengl32 gdiplus Shlwapi dwmapi stdc++fs
+
+Set these compiler options: -std=c++17
+
+
+
+Compiling on Mac - EXPERIMENTAL! PROBABLY HAS BUGS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Yes yes, people use Macs for C++ programming! Who knew? Anyway, enough
+arguing, thanks to Mumflr the PGE is now supported on Mac. Now I know nothing
+about Mac, so if you need support, I suggest checking out the instructions
+here: https://github.com/MumflrFumperdink/olcPGEMac
+
+clang++ -arch x86_64 -std=c++17 -mmacosx-version-min=10.15 -Wall -framework OpenGL
+-framework GLUT -framework Carbon -lpng YourSource.cpp -o YourProgName
+
+
+
+Compiling with Emscripten (New & Experimental)
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Emscripten compiler will turn your awesome C++ PixelGameEngine project into WASM!
+This means you can run your application in teh browser, great for distributing
+and submission in to jams and things! It's a bit new at the moment.
+
+em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 ./YourSource.cpp -o pge.html
+
+
+
+Using stb_image.h
+~~~~~~~~~~~~~~~~~
+The PGE will load png images by default (with help from libpng on non-windows systems).
+However, the excellent "stb_image.h" can be used instead, supporting a variety of
+image formats, and has no library dependence - something we like at OLC studios ;)
+To use stb_image.h, make sure it's in your code base, and simply:
+
+#define OLC_IMAGE_STB
+
+Before including the olcPixelGameEngine.h header file. stb_image.h works on many systems
+and can be downloaded here: https://github.com/nothings/stb/blob/master/stb_image.h
+
+
+
+Multiple cpp file projects?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+As a single header solution, the OLC_PGE_APPLICATION definition is used to
+insert the engine implementation at a project location of your choosing.
+The simplest way to setup multifile projects is to create a file called
+"olcPixelGameEngine.cpp" which includes the following:
+
+#define OLC_PGE_APPLICATION
+#include "olcPixelGameEngine.h"
+
+That's all it should include. You can also include PGEX includes and
+defines in here too. With this in place, you dont need to
+#define OLC_PGE_APPLICATION anywhere, and can simply include this
+header file as an when you need to.
+
+
+
+Ports
+~~~~~
+olc::PixelGameEngine has been ported and tested with varying degrees of
+success to: WinXP, Win7, Win8, Win10, Various Linux, Raspberry Pi,
+Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are
+interested in the details of these ports, come and visit the Discord!
+
+
+
+Thanks
+~~~~~~
+I'd like to extend thanks to Ian McKay, Bispoo, Eremiell, slavka, Kwizatz77, gurkanctn, Phantim,
+IProgramInCPP, JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice,
+dandistine, Ralakus, Gorbit99, raoul, joshinils, benedani, Moros1138, Alexio, SaladinAkara
+& MagetzUb for advice, ideas and testing, and I'd like to extend my appreciation to the
+250K YouTube followers, 80+ Patreons, 4.8K Twitch followers and 10K Discord server members
+who give me the motivation to keep going with all this :D
+
+Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka,
+@Dragoneye, @Gorbit99, @dandistine & @Mumflr
+
+Special thanks to those who bring gifts!
+GnarGnarHead.......Domina
+Gorbit99...........Bastion, Ori & The Blind Forest, Terraria, Spelunky 2, Skully
+Marti Morta........Gris
+Danicron...........Terraria
+SaladinAkara.......Aseprite, Inside, Quern: Undying Thoughts, Outer Wilds
+AlterEgo...........Final Fantasy XII - The Zodiac Age
+SlicEnDicE.........Noita, Inside
+TGD................Voucher Gift
+Dragoneye..........Lucas Arts Adventure Game Pack
+Anonymous Pirate...Return To Monkey Island
+
+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, (c) OneLoneCoder 2018, 2019, 2020, 2021, 2022
+*/
+#pragma endregion
+
+#pragma region version_history
+/*
+2.01: Made renderer and platform static for multifile projects
+2.02: Added Decal destructor, optimised Pixel constructor
+2.03: Added FreeBSD flags, Added DrawStringDecal()
+2.04: Windows Full-Screen bug fixed
+2.05: +DrawPartialWarpedDecal() - draws a warped decal from a subset image
++DrawPartialRotatedDecal() - draws a rotated decal from a subset image
+2.06: +GetTextSize() - returns area occupied by multiline string
++GetWindowSize() - returns actual window size
++GetElapsedTime() - returns last calculated fElapsedTime
++GetWindowMouse() - returns actual mouse location in window
++DrawExplicitDecal() - bow-chikka-bow-bow
++DrawPartialDecal(pos, size) - draws a partial decal to specified area
++FillRectDecal() - draws a flat shaded rectangle as a decal
++GradientFillRectDecal() - draws a rectangle, with unique colour corners
++Modified DrawCircle() & FillCircle() - Thanks IanM-Matrix1 (#PR121)
++Gone someway to appeasing pedants
+2.07: +GetPixelSize() - returns user specified pixel size
++GetScreenPixelSize() - returns actual size in monitor pixels
++Pixel Cohesion Mode (flag in Construct()) - disallows arbitrary window scaling
++Working VSYNC in Windows windowed application - now much smoother
++Added string conversion for olc::vectors
++Added comparator operators for olc::vectors
++Added DestroyWindow() on windows platforms for serial PGE launches
++Added GetMousePos() to stop TarriestPython whinging
+2.08: Fix SetScreenSize() aspect ratio pre-calculation
+Fix DrawExplicitDecal() - stupid oversight with multiple decals
+Disabled olc::Sprite copy constructor
++olc::Sprite Duplicate() - produces a new clone of the sprite
++olc::Sprite Duplicate(pos, size) - produces a new sprite from the region defined
++Unary operators for vectors
++More pedant mollification - Thanks TheLandfill
++ImageLoader modules - user selectable image handling core, gdi+, libpng, stb_image
++Mac Support via GLUT - thanks Mumflr!
+2.09: Fix olc::Renderable Image load error - Thanks MaGetzUb & Zij-IT for finding and moaning about it
+Fix file rejection in image loaders when using resource packs
+Tidied Compiler defines per platform - Thanks slavka
++Pedant fixes, const correctness in parts
++DecalModes - Normal, Additive, Multiplicative blend modes
++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
+2.11: Made PGEX hooks optional - (provide true to super constructor)
+2.12: Fix for MinGW compiler non-compliance :( - why is its sdk structure different?? why???
+2.13: +GetFontSprite() - allows access to font data
+2.14: Fix WIN32 Definition reshuffle
+Fix DrawPartialDecal() - messed up dimension during renderer experiment, didnt remove junk code, thanks Alexio
+Fix? Strange error regarding GDI+ Image Loader not knowing about COM, SDK change?
+2.15: Big Reformat
++WASM Platform (via Emscripten) - Big Thanks to OLC Community - See Platform for details
++Sample Mode for Decals
++Made olc_ConfigureSystem() accessible
++Added OLC_----_CUSTOM_EX for externalised platforms, renderers and image loaders
+=Refactored olc::Sprite pixel data store
+-Deprecating LoadFromPGESprFile()
+-Deprecating SaveToPGESprFile()
+Fix Pixel -= operator (thanks Au Lit)
+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)
+2.17: +Clipping for DrawLine() functions
++Reintroduced sub-pixel decals
++Modified DrawPartialDecal() to quantise and correctly sample from tile atlasses
++olc::Sprite::GetPixel() - Clamp Mode
+2.18: +Option to not "dirty" layers with SetDrawTarget() - Thanks TerasKasi!
+=Detection for Mac M1, fix for scroll wheel interrogation - Thanks ruarq!
+2.19: Textual Input(of)course Edition!
+=Built in font is now olc::Renderable
++EnablePixelTransfer() - Gate if layer content transfers occur (speedup in decal only apps)
++TextEntryEnable() - Enables/Disables text entry mode
++TextEntryGetString() - Gets the current accumulated string in text entry mode
++TextEntryGetCursor() - Gets the current cursor position in text entry mode
++IsTextEntryEnabled() - Returns true if text entry mode is activated
++OnTextEntryComplete() - Override is called when user presses "ENTER" in text entry mode
++Potential for regional keyboard mappings - needs volunteers to do this
++ConsoleShow() - Opens built in command console
++ConsoleClear() - Clears built in command console output
++ConsoleOut() - Stream strings to command console output
++ConsoleCaptureStdOut() - Capture std::cout by redirecting to built-in console
++OnConsoleCommand() - Override is called when command is entered into built in console
+2.20: +DrawRectDecal() - Keeps OneSketchyGuy quiet
++GetScreenSize()
++olc::Sprite::Size() - returns size of sprite in vector format
+2.21: Emscripten Overhaul - Thanks Moros!
++DrawPolygonDecal() tint overload, can now tint a polygon accounting for vertex colours
++Multiplicative Pixel overload
++v2d_generic clamp()
++v2d_generic lerp()
++GetDroppedFiles() - returns files dropped onto engine window for that frame (MSW only)
++GetDroppedFilesPoint() - returns location of dropped files (MSW only)
++Exposed OpenGL33 Loader interface so the typedefs can be shared with PGEX & user
++Fix OGL33 DecalStructure types - wow, how did that one get missed?? lol
++FillTexturedTriangle() - Software rasterizes a textured, coloured, triangle
++FillTexturedPolygon() - Hijacks DecalStructure for configuration
++olc::vf2d arguments for Sprite::Sample() functions
+2.22: = Fix typo on dragged file buffers for unicode builds
+2.23: Fixed Emscripten host sizing errors - Thanks Moros
+Fixed v2d_generic.clamp() function
+
+!! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !!
+!! Volunteers willing to help appreciated, though PRs are manually integrated with credit !!
+*/
+#pragma endregion
+
+#pragma region hello_world_example
+// O------------------------------------------------------------------------------O
+// | Example "Hello World" Program (main.cpp) |
+// O------------------------------------------------------------------------------O
+/*
+
+#define OLC_PGE_APPLICATION
+#include "olcPixelGameEngine.h"
+
+// Override base class with your custom functionality
+class Example : public olc::PixelGameEngine
+{
+public:
+Example()
+{
+// Name your application
+sAppName = "Example";
+}
+
+public:
+bool OnUserCreate() override
+{
+// Called once at the start, so create things here
+return true;
+}
+
+bool OnUserUpdate(float fElapsedTime) override
+{
+// Called once per frame, draws random coloured pixels
+for (int x = 0; x < ScreenWidth(); x++)
+for (int y = 0; y < ScreenHeight(); y++)
+Draw(x, y, olc::Pixel(rand() % 256, rand() % 256, rand() % 256));
+return true;
+}
+};
+
+int main()
+{
+Example demo;
+if (demo.Construct(256, 240, 4, 4))
+demo.Start();
+return 0;
+}
+
+*/
+#pragma endregion
+
+#ifndef OLC_PGE_DEF
+#define OLC_PGE_DEF
+
+#pragma region std_includes
+// O------------------------------------------------------------------------------O
+// | STANDARD INCLUDES |
+// O------------------------------------------------------------------------------O
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include