It is working as it should

Co-authored-by: sigonasr2 <sigonasr2@gmail.com>
master
sigonasr2 2 years ago
parent 32caf354e2
commit adc4e42d34
  1. BIN
      C++ProjectTemplate
  2. 1024
      geom2d.h
  3. 191
      main.cpp
  4. 328
      quadtree.h
  5. 735
      transformedView.h

Binary file not shown.

1024
geom2d.h

File diff suppressed because it is too large Load Diff

@ -1,20 +1,193 @@
#include <memory>
/*
Quirky Quad Trees Part #1 - Static Quad Tree Implementation
"War... huh... What is it good for? Absolutely nothin..." - javidx9
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.
Video:
~~~~~~
https://youtu.be/ASAowY6yJII
Pan & Zoom with middle mouse, TAB to switch between methods
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
Author
~~~~~~
David Barr, aka javidx9, <EFBFBD>OneLoneCoder 2019, 2020, 2021, 2022
*/
#define OLC_PGE_APPLICATION
#include "pixelGameEngine.h"
using namespace olc;
#define OLC_PGEX_TRANSFORMEDVIEW
#include "transformedView.h"
struct MyStruct{
int val=4;
friend std::ostream&operator<<(std::ostream&os,MyStruct&rhs){
printf("Called\n");
return os;
#include "quadtree.h"
// The Example!
class Example_StaticQuadTree : public olc::PixelGameEngine
{
public:
Example_StaticQuadTree()
{
sAppName = "Static QuadTree";
}
protected:
olc::TransformedView tv;
// An example object of something in 2D space
struct SomeObjectWithArea
{
olc::vf2d vPos;
olc::vf2d vVel;
olc::vf2d vSize;
olc::Pixel colour;
};
// A regular list of the objects
std::list<SomeObjectWithArea> vecObjects;
// An equivalent quad tree of the objects
olc::utils::QuadTreeContainer<SomeObjectWithArea> treeObjects;
// The "length" of one side of the "world" the objects reside in
float fArea = 100000.0f;
bool bUseQuadTree = true;
public:
bool OnUserCreate() override
{
// Transform View - enables Pan & Zoom
tv.Initialise({ ScreenWidth(), ScreenHeight() });
// Create the tree, and size it to the world
treeObjects.resize(olc::utils::geom2d::rect<float>({ 0.0f, 0.0f }, { fArea, fArea }));
// Dirty random float generator
auto rand_float = [](const float a, const float b)
{
return float(rand()) / float(RAND_MAX) * (b - a) + a;
};
// Create 1,000,000 objects, push into both containers (so 2,000,000 I suppose :P )
for (int i = 0; i < 1000000; i++)
{
SomeObjectWithArea ob;
ob.vPos = { rand_float(0.0f, fArea), rand_float(0.0f, fArea) };
ob.vSize = { rand_float(0.1f, 100.0f), rand_float(0.1f, 100.0f) };
ob.colour = olc::Pixel(rand() % 256, rand() % 256, rand() % 256);
treeObjects.insert(ob, olc::utils::geom2d::rect(ob.vPos, ob.vSize));
vecObjects.push_back(ob);
}
return true;
}
bool OnUserUpdate(float fElapsedTime) override
{
// Tab switches between modes
if (GetKey(olc::Key::TAB).bPressed)
bUseQuadTree = !bUseQuadTree;
tv.HandlePanAndZoom();
// Get rectangle that equates to screen in world space
olc::utils::geom2d::rect rScreen = { tv.GetWorldTL(), tv.GetWorldBR() - tv.GetWorldTL() };
size_t nObjectCount = 0;
if (bUseQuadTree)
{
// QUAD TREE MODE
auto tpStart = std::chrono::system_clock::now();
// Use search function to return list of pointers to objects in that area
for (const auto& object : treeObjects.search(rScreen))
{
tv.FillRectDecal(object->item.vPos, object->item.vSize, object->item.colour);
nObjectCount++;
}
std::chrono::duration<float> duration = std::chrono::system_clock::now() - tpStart;
std::string sOutput = "Quadtree " + std::to_string(nObjectCount) + "/" + std::to_string(vecObjects.size()) + " in " + std::to_string(duration.count());
DrawStringDecal({ 4, 4 }, sOutput, olc::BLACK, { 4.0f, 8.0f });
DrawStringDecal({ 2, 2 }, sOutput, olc::WHITE, { 4.0f, 8.0f });
}
else
{
// LINEAR SEARCH MODE
auto tpStart = std::chrono::system_clock::now();
// Blindly check all objects to see if they overlap with screen
for (const auto& object : vecObjects)
{
if (olc::utils::geom2d::overlaps(rScreen,olc::utils::geom2d::rect<float>{ object.vPos, object.vSize }))
{
tv.FillRectDecal(object.vPos, object.vSize, object.colour);
nObjectCount++;
}
}
std::chrono::duration<float> duration = std::chrono::system_clock::now() - tpStart;
std::string sOutput = "Linear " + std::to_string(nObjectCount) + "/" + std::to_string(vecObjects.size()) + " in " + std::to_string(duration.count());
DrawStringDecal({ 4, 4 }, sOutput, olc::BLACK, { 4.0f, 8.0f });
DrawStringDecal({ 2, 2 }, sOutput, olc::WHITE, { 4.0f, 8.0f });
}
return true;
}
};
int main()
{
MyStruct*st=new MyStruct({5});
std::cout<<*st<<std::endl;
Example_StaticQuadTree demo;
if (demo.Construct(1280, 960, 1, 1, false, false))
demo.Start();
return 0;
}

@ -0,0 +1,328 @@
/*
OneLoneCoder - QuadTree v1.00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A Dynamic Quad-Tree implementation to store objects in a 2D space
with a fast retrieval.
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, <EFBFBD>OneLoneCoder 2019, 2020, 2021, 2022
*/
#pragma once
#include "pixelGameEngine.h"
#include "geom2d.h"
namespace olc::utils
{
template <typename T, typename CTYPE = float>
struct QuadTreeItemLocation
{
typename std::list<std::pair<geom2d::rect<CTYPE>, T>>* container = nullptr;
typename std::list<std::pair<geom2d::rect<CTYPE>, T>>::iterator iterator;
};
template <typename pT, typename CTYPE = float>
class DynamicQuadTree
{
public:
DynamicQuadTree(const geom2d::rect<CTYPE>& size, const size_t nDepth = 0, const size_t nMaxDepth = 8)
{
m_depth = nDepth;
m_rect = size;
m_maxdepth = nMaxDepth;
resize(m_rect);
}
// Insert a region into this area
QuadTreeItemLocation<pT> insert(const pT item, const geom2d::rect<CTYPE>& itemsize)
{
for (int i = 0; i < 4; i++)
{
if (geom2d::contains(m_rChild[i], itemsize))
{
// Have we reached depth limit?
if (m_depth + 1 < m_maxdepth)
{
// No, so does child exist?
if (!m_pChild[i])
{
// No, so create it
m_pChild[i] = std::make_shared<DynamicQuadTree<pT>>(m_rChild[i], m_depth + 1, m_maxdepth);
}
// Yes, so add item to it
return m_pChild[i]->insert(item, itemsize);
}
}
}
// It didnt fit, so item must belong to this geom2d::rect<CTYPE>
m_pItems.push_back({ itemsize, item });
return { &m_pItems, std::prev(m_pItems.end()) };
}
void relocate(pT item, const geom2d::rect<CTYPE>& rArea)
{
// Remove it
remove(item);
// Reinsert it with new location
insert(item, rArea);
}
size_t size() const
{
size_t nCount = m_pItems.size();
for (int i = 0; i < 4; i++)
if (m_pChild[i]) nCount += m_pChild[i]->size();
return nCount;
}
void search(const geom2d::rect<CTYPE>& rArea, std::list<pT>& listItems) const
{
// First, check for items belonging to this area, add them to the list
// if there is overlap
for (const auto& p : m_pItems)
{
if (geom2d::overlaps(rArea,p.first))
listItems.push_back(p.second);
}
// Second, recurse through children and see if they can
// add to the list
for (int i = 0; i < 4; i++)
{
if (m_pChild[i])
{
// If child is entirely contained within area, recursively
// add all of its children, no need to check boundaries
if (geom2d::contains(rArea,m_rChild[i]))
m_pChild[i]->items(listItems);
// If child overlaps with search area then checks need
// to be made
else if (geom2d::overlaps(m_rChild[i],rArea))
m_pChild[i]->search(rArea, listItems);
}
}
}
void items(std::list<pT>& listItems) const
{
// No questions asked, just return child items
for (const auto& p : m_pItems)
listItems.push_back(p.second);
for (int i = 0; i < 4; i++)
if (m_pChild[i]) m_pChild[i]->items(listItems);
}
void clear()
{
m_pItems.clear();
for (int i = 0; i < 4; i++)
{
if (m_pChild[i])
m_pChild[i]->clear();
else
m_pChild[i].reset();
}
}
void resize(const geom2d::rect<CTYPE>& rArea)
{
clear();
m_rect = rArea;
olc::v2d_generic<CTYPE> vChildSize = m_rect.size / CTYPE(2);
m_rChild =
{
geom2d::rect<CTYPE>(m_rect.pos, vChildSize),
geom2d::rect<CTYPE>({m_rect.pos.x + vChildSize.x, m_rect.pos.y}, vChildSize),
geom2d::rect<CTYPE>({m_rect.pos.x, m_rect.pos.y + vChildSize.y}, vChildSize),
geom2d::rect<CTYPE>(m_rect.pos + vChildSize, vChildSize)
};
}
const geom2d::rect<CTYPE>& area()
{
return m_rect;
}
protected:
size_t m_depth = 0;
size_t m_maxdepth = 8;
// Area of this quadnode
geom2d::rect<CTYPE> m_rect;
// 4 child areas of this quadnode
std::array<geom2d::rect<CTYPE>, 4> m_rChild{};
// 4 potential children of this quadnode
std::array<std::shared_ptr<DynamicQuadTree<pT>>, 4> m_pChild{};
// Items which belong to this quadnode
std::list<std::pair<geom2d::rect<CTYPE>, pT>> m_pItems;
};
template<typename T, typename CTYPE = float>
struct QuadTreeItem
{
// The item Itself
T item;
// A "locator" to the container/iterator that points to this item's iterator in the
// top level list - phew
QuadTreeItemLocation<typename std::list<QuadTreeItem<T, CTYPE>>::iterator> pItem;
};
template <typename T, typename CTYPE = float>
class QuadTreeContainer
{
using IQuadtreeContainer = std::list<QuadTreeItem<T, CTYPE>>;
public:
QuadTreeContainer(const geom2d::rect<CTYPE>& size = { {0.0f, 0.0f}, { 100.0f, 100.0f } }, const size_t nDepth = 0, const size_t nMaxDepth = 8) : root(size, nDepth, nMaxDepth)
{
}
// Sets the spatial coverage area of teh quadtree
void resize(const geom2d::rect<CTYPE>& rArea)
{
root.resize(rArea);
}
// Inserts an item into the quadtree
void insert(const T& item, const geom2d::rect<CTYPE>& itemsize)
{
QuadTreeItem<T> newItem;
newItem.item = item;
// Item i stored in container
m_allItems.emplace_back(newItem);
// Pointer/Area of item is stored in geom2d::rect<CTYPE> tree
m_allItems.back().pItem = root.insert(std::prev(m_allItems.end()), itemsize);
}
// Returns a std::list of pointers to items within the search area
std::list<typename IQuadtreeContainer::iterator> search(const geom2d::rect<CTYPE>& rArea) const
{
std::list<typename IQuadtreeContainer::iterator> listItemPointers;
root.search(rArea, listItemPointers);
return listItemPointers;
}
void remove(typename IQuadtreeContainer::iterator& item)
{
// Iterator points to a QuadTreeItem
item->pItem.container->erase(item->pItem.iterator);
// Remove actual item from container
m_allItems.erase(item);
}
void relocate(typename IQuadtreeContainer::iterator& item, const geom2d::rect<CTYPE>& itemsize)
{
// Remove pointer to item from whichever container its stored in
item->pItem.container->erase(item->pItem.iterator);
// Update the items pointer by reinsertion into geom2d::rect<CTYPE> tree
item->pItem = root.insert(item, itemsize);
}
typename IQuadtreeContainer::iterator begin()
{
return m_allItems.begin();
}
typename IQuadtreeContainer::iterator end()
{
return m_allItems.end();
}
typename IQuadtreeContainer::const_iterator cbegin()
{
return m_allItems.cbegin();
}
typename IQuadtreeContainer::const_iterator cend()
{
return m_allItems.cend();
}
size_t size() const
{
return root.size();
}
void clear()
{
root.clear();
}
const geom2d::rect<CTYPE>& area()
{
return root.area();
}
protected:
DynamicQuadTree<typename IQuadtreeContainer::iterator> root;
IQuadtreeContainer m_allItems;
};
}

@ -0,0 +1,735 @@
/*
olcPGEX_TransformedView.h
+-------------------------------------------------------------+
| OneLoneCoder Pixel Game Engine Extension |
| Transformed View v1.07 |
+-------------------------------------------------------------+
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, <EFBFBD>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()
*/
#pragma once
#ifndef OLC_PGEX_TRANSFORMEDVIEW_H
#define OLC_PGEX_TRANSFORMEDVIEW_H
#include "pixelGameEngine.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<olc::vf2d, 4>& 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<olc::vf2d, 4>& 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<olc::vf2d>& pos, const std::vector<olc::vf2d>& 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<olc::vf2d>&pos, const std::vector<olc::vf2d>&uv, const std::vector<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<olc::vf2d> 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<olc::vf2d, 4> 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<olc::vf2d, 4>& 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<olc::vf2d, 4> 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<olc::vf2d, 4>& 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<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const olc::Pixel tint)
{
std::vector<olc::vf2d> 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<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel> &tint)
{
std::vector<olc::vf2d> vTransformed(pos.size());
for (uint32_t n = 0; n < pos.size(); n++)
vTransformed[n] = WorldToScreen(pos[n]);
pge->DrawPolygonDecal(decal, vTransformed, uv, 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
Loading…
Cancel
Save