Updated TransformedView to 1.05

pull/272/head
Javidx9 3 years ago committed by GitHub
parent 7a20524ae4
commit ccedd4ecf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 150
      Extensions/olcPGEX_TransformedView.h

@ -3,7 +3,7 @@
+-------------------------------------------------------------+ +-------------------------------------------------------------+
| OneLoneCoder Pixel Game Engine Extension | | OneLoneCoder Pixel Game Engine Extension |
| Transformed View v1.01 | | Transformed View v1.05 |
+-------------------------------------------------------------+ +-------------------------------------------------------------+
NOTE: UNDER ACTIVE DEVELOPMENT - THERE ARE BUGS/GLITCHES NOTE: UNDER ACTIVE DEVELOPMENT - THERE ARE BUGS/GLITCHES
@ -18,7 +18,7 @@
License (OLC-3) License (OLC-3)
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
Copyright 2018 - 2021 OneLoneCoder.com Copyright 2018 - 2022 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@ -59,11 +59,17 @@
Author Author
~~~~~~ ~~~~~~
David Barr, aka javidx9, ©OneLoneCoder 2019, 2020, 2021 David Barr, aka javidx9, ©OneLoneCoder 2019, 2020, 2021, 2022
Revisions: Revisions:
1.00: Initial Release 1.00: Initial Release
1.01: DrawLine bug fix, thanks Fern 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
*/ */
#pragma once #pragma once
@ -91,19 +97,19 @@ namespace olc
olc::vf2d GetWorldBR() const; olc::vf2d GetWorldBR() const;
olc::vf2d GetWorldVisibleArea() const; olc::vf2d GetWorldVisibleArea() const;
void ZoomAtScreenPos(const float fDeltaZoom, const olc::vi2d& vPos); void ZoomAtScreenPos(const float fDeltaZoom, const olc::vi2d& vPos);
void SetZoom(const float fZoom, const olc::vi2d& vPos); void SetZoom(const float fZoom, const olc::vf2d& vPos);
void StartPan(const olc::vi2d& vPos); void StartPan(const olc::vi2d& vPos);
void UpdatePan(const olc::vi2d& vPos); void UpdatePan(const olc::vi2d& vPos);
void EndPan(const olc::vi2d& vPos); void EndPan(const olc::vi2d& vPos);
const olc::vf2d& GetWorldOffset() const; const olc::vf2d& GetWorldOffset() const;
const olc::vf2d& GetWorldScale() const; const olc::vf2d& GetWorldScale() const;
virtual olc::vi2d WorldToScreen(const olc::vf2d& vWorldPos) const; virtual olc::vf2d WorldToScreen(const olc::vf2d& vWorldPos) const;
virtual olc::vf2d ScreenToWorld(const olc::vi2d& vScreenPos) const; virtual olc::vf2d ScreenToWorld(const olc::vf2d& vScreenPos) const;
virtual olc::vf2d ScaleToWorld(const olc::vi2d& vScreenSize) const; virtual olc::vf2d ScaleToWorld(const olc::vf2d& vScreenSize) const;
virtual olc::vi2d ScaleToScreen(const olc::vf2d& vWorldSize) const; virtual olc::vf2d ScaleToScreen(const olc::vf2d& vWorldSize) const;
virtual bool IsPointVisible(const olc::vf2d& vPos) const; virtual bool IsPointVisible(const olc::vf2d& vPos) const;
virtual bool IsRectVisible(const olc::vf2d& vPos, const olc::vf2d& vSize) 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: protected:
olc::vf2d m_vWorldOffset = { 0.0f, 0.0f }; olc::vf2d m_vWorldOffset = { 0.0f, 0.0f };
olc::vf2d m_vWorldScale = { 1.0f, 1.0f }; olc::vf2d m_vWorldScale = { 1.0f, 1.0f };
@ -176,6 +182,18 @@ namespace olc
void GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR); 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 // 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 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
}; };
@ -186,21 +204,12 @@ namespace olc
TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize); TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize);
public: public:
void SetRangeX(const bool bRanged, const int32_t nMin = 0, const int32_t nMax = 0);
void SetRangeY(const bool bRanged, const int32_t nMin = 0, const int32_t nMax = 0);
olc::vi2d GetTopLeftTile() const; olc::vi2d GetTopLeftTile() const;
olc::vi2d GetBottomRightTile() const; olc::vi2d GetBottomRightTile() const;
olc::vi2d GetVisibleTiles() const; olc::vi2d GetVisibleTiles() const;
olc::vi2d GetTileUnderScreenPos(const olc::vi2d& vPos) const; olc::vi2d GetTileUnderScreenPos(const olc::vi2d& vPos) const;
const olc::vi2d GetTileOffset() const; const olc::vi2d GetTileOffset() const;
private:
bool m_bRangedX = false;
int32_t m_nMinRangeX = 0;
int32_t m_nMaxRangeX = 0;
bool m_bRangedY = false;
int32_t m_nMinRangeY = 0;
int32_t m_nMaxRangeY = 0;
}; };
} }
@ -240,7 +249,7 @@ namespace olc
olc::vf2d TransformedView::GetWorldTL() const olc::vf2d TransformedView::GetWorldTL() const
{ {
return ScreenToWorld({ 0,0 }); return TransformedView::ScreenToWorld({ 0,0 });
} }
olc::vf2d TransformedView::GetWorldBR() const olc::vf2d TransformedView::GetWorldBR() const
@ -261,7 +270,7 @@ namespace olc
m_vWorldOffset += vOffsetBeforeZoom - vOffsetAfterZoom; m_vWorldOffset += vOffsetBeforeZoom - vOffsetAfterZoom;
} }
void TransformedView::SetZoom(const float fZoom, const olc::vi2d& vPos) void TransformedView::SetZoom(const float fZoom, const olc::vf2d& vPos)
{ {
olc::vf2d vOffsetBeforeZoom = ScreenToWorld(vPos); olc::vf2d vOffsetBeforeZoom = ScreenToWorld(vPos);
m_vWorldScale = { fZoom, fZoom }; m_vWorldScale = { fZoom, fZoom };
@ -300,27 +309,28 @@ namespace olc
return m_vWorldScale; return m_vWorldScale;
} }
olc::vi2d TransformedView::WorldToScreen(const olc::vf2d& vWorldPos) const olc::vf2d TransformedView::WorldToScreen(const olc::vf2d& vWorldPos) const
{ {
olc::vf2d vFloat = ((vWorldPos - m_vWorldOffset) * m_vWorldScale); olc::vf2d vFloat = ((vWorldPos - m_vWorldOffset) * m_vWorldScale);
vFloat = { std::floor(vFloat.x), std::floor(vFloat.y) }; //vFloat = { std::floor(vFloat.x + 0.5f), std::floor(vFloat.y + 0.5f) };
return vFloat; return vFloat;
} }
olc::vf2d TransformedView::ScreenToWorld(const olc::vi2d& vScreenPos) const olc::vf2d TransformedView::ScreenToWorld(const olc::vf2d& vScreenPos) const
{ {
return (olc::vf2d(vScreenPos) / m_vWorldScale) + m_vWorldOffset; return (olc::vf2d(vScreenPos) / m_vWorldScale) + m_vWorldOffset;
} }
olc::vf2d TransformedView::ScaleToWorld(const olc::vi2d& vScreenSize) const olc::vf2d TransformedView::ScaleToWorld(const olc::vf2d& vScreenSize) const
{ {
return (olc::vf2d(vScreenSize) / m_vWorldScale); return (olc::vf2d(vScreenSize) / m_vWorldScale);
} }
olc::vi2d TransformedView::ScaleToScreen(const olc::vf2d& vWorldSize) const olc::vf2d TransformedView::ScaleToScreen(const olc::vf2d& vWorldSize) const
{ {
olc::vf2d vFloat = vWorldSize * m_vWorldScale; //olc::vf2d vFloat = (vWorldSize * m_vWorldScale) + olc::vf2d(0.5f, 0.5f);
return vFloat.floor(); //return vFloat.floor();
return (vWorldSize * m_vWorldScale);
} }
bool TransformedView::IsPointVisible(const olc::vf2d & vPos) const bool TransformedView::IsPointVisible(const olc::vf2d & vPos) const
@ -336,6 +346,23 @@ namespace olc
return (vScreenPos.x < 0 + m_vViewArea.x && vScreenPos.x + vScreenSize.x > 0 && vScreenPos.y < m_vViewArea.y&& vScreenPos.y + vScreenSize.y > 0); 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) bool TransformedView::Draw(float x, float y, olc::Pixel p)
{ {
return Draw({ x, y }, p); return Draw({ x, y }, p);
@ -348,7 +375,7 @@ namespace olc
void TransformedView::DrawLine(float x1, float y1, float x2, float y2, olc::Pixel p, uint32_t pattern) void TransformedView::DrawLine(float x1, float y1, float x2, float y2, olc::Pixel p, uint32_t pattern)
{ {
DrawLine({ x1, y1 }, { x2, y2 }, p, pattern); DrawLine({ x1, y2 }, { x2, y2 }, p, pattern);
} }
void TransformedView::DrawLine(const olc::vf2d & pos1, const olc::vf2d & pos2, olc::Pixel p, uint32_t pattern) void TransformedView::DrawLine(const olc::vf2d & pos1, const olc::vf2d & pos2, olc::Pixel p, uint32_t pattern)
@ -427,13 +454,20 @@ namespace olc
if (IsRectVisible(pos, vSpriteSize * scale)) if (IsRectVisible(pos, vSpriteSize * scale))
{ {
olc::vf2d vSpriteScaledSize = vSpriteSize * m_vRecipPixel * m_vWorldScale * scale; olc::vf2d vSpriteScaledSize = vSpriteSize * m_vRecipPixel * m_vWorldScale * scale;
olc::vi2d vPixel, vStart = WorldToScreen(pos), vEnd = vSpriteScaledSize + vStart; 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; olc::vf2d vPixelStep = 1.0f / vSpriteScaledSize;
for (vPixel.y = vStart.y; vPixel.y < vEnd.y; vPixel.y++)
for (vPixel.y = vScreenPixelStart.y; vPixel.y < vScreenPixelEnd.y; vPixel.y++)
{ {
for (vPixel.x = vStart.x; vPixel.x < vEnd.x; vPixel.x++) for (vPixel.x = vScreenPixelStart.x; vPixel.x < vScreenPixelEnd.x; vPixel.x++)
{ {
olc::vf2d vSample = olc::vf2d(vPixel - vStart) * vPixelStep; olc::vf2d vSample = olc::vf2d(vPixel - vSpritePixelStart) * vPixelStep;
pge->Draw(vPixel, sprite->Sample(vSample.x, vSample.y)); pge->Draw(vPixel, sprite->Sample(vSample.x, vSample.y));
} }
} }
@ -592,6 +626,11 @@ namespace olc
pge->FillRectDecal(WorldToScreen(pos), (size * m_vWorldScale).ceil(), col); pge->FillRectDecal(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) 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); pge->GradientFillRectDecal(WorldToScreen(pos), size * m_vWorldScale, colTL, colBL, colBR, colTR);
@ -605,29 +644,50 @@ namespace olc
pge->DrawPolygonDecal(decal, vTransformed, uv, tint); 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);
}
TileTransformedView::TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize) #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)
{ {
Initialise(vViewArea, vTileSize); 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 TileTransformedView::SetRangeX(const bool bRanged, const int32_t nMin, const int32_t nMax) 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)
{ {
m_bRangedX = bRanged; shade.DrawPartialDecal(WorldToScreen(pos), size * m_vWorldScale * m_vRecipPixel, decal, source_pos, source_size, tint);
m_nMinRangeX = nMin;
m_nMaxRangeX = nMax;
} }
void TileTransformedView::SetRangeY(const bool bRanged, const int32_t nMin, const int32_t nMax) #endif
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
TileTransformedView::TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize)
{ {
m_bRangedY = bRanged; Initialise(vViewArea, vTileSize);
m_nMinRangeY = nMin;
m_nMaxRangeY = nMax;
} }
olc::vi2d TileTransformedView::GetTopLeftTile() const olc::vi2d TileTransformedView::GetTopLeftTile() const
{ {
return ScreenToWorld({ 0,0 }).floor(); return ScreenToWorld({ 0,0 }).floor();

Loading…
Cancel
Save