diff --git a/dev/cmake/Helpers.cmake b/dev/cmake/Helpers.cmake
index e9da4e6..7730539 100644
--- a/dev/cmake/Helpers.cmake
+++ b/dev/cmake/Helpers.cmake
@@ -125,7 +125,7 @@ function(add_example EXAMPLE_NAME)
${WAYLAND_EGL_LIBRARIES}
${WAYLAND_CURSOR_LIBRARIES}
${EGL_LIBRARIES}
- OpenGL::GL
+ OpenGL::OpenGL
PNG::PNG
Threads::Threads
)
diff --git a/dev/msvc/olcPGE3_BuildSH/olcPGE3_BuildSH.vcxproj b/dev/msvc/olcPGE3_BuildSH/olcPGE3_BuildSH.vcxproj
index cf6056b..f044f79 100644
--- a/dev/msvc/olcPGE3_BuildSH/olcPGE3_BuildSH.vcxproj
+++ b/dev/msvc/olcPGE3_BuildSH/olcPGE3_BuildSH.vcxproj
@@ -140,8 +140,8 @@
true
true
- false
- false
+ true
+ true
true
@@ -164,8 +164,8 @@
true
true
- true
- true
+ false
+ false
true
diff --git a/dev/src/draw.cpp b/dev/src/draw.cpp
index 86660a5..bd2e362 100644
--- a/dev/src/draw.cpp
+++ b/dev/src/draw.cpp
@@ -366,10 +366,26 @@ GPUTask olc::Draw::TaskDrawLine(const std::vector& vPoints, const olc
}
+GPUTask olc::Draw::TaskDrawPoints(const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint)
+{
+ GPUTask task;
+ task.structure = olc::Structure::Point;
+ task.vertexBuffer.resize(vPoints.size());
+ for (size_t i = 0; i < vPoints.size(); i++)
+ {
+ task.vertexBuffer[i] = { { vPoints[i].x, vPoints[i].y, 1.0f, 1.0f }, vColours[i],{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 } };
+ }
+ task.blendmode = blendMode;
+ task.tint = tint;
+ return task;
+}
+
GPUTask olc::Draw::TaskDrawPolygon(olc::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint)
{
- olc_IgnoreUnused(structure);
- return TaskDrawLine(vPoints, vColours, tint, false, true);
+ if (structure == olc::Structure::Point)
+ return TaskDrawPoints(vPoints, vColours, tint);
+ else
+ return TaskDrawLine(vPoints, vColours, tint, false, true);
}
GPUTask olc::Draw::TaskDrawPolygon(olc::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint)
@@ -918,7 +934,7 @@ const GPUTask& olc::Draw::TexturedPolygon(const olc::Structure structure, const
)));
}
-const GPUTask& olc::Draw::String(const olc::vf2d& pos, const std::string& text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
+const GPUTask& olc::Draw::String(const olc::vf2d& pos, std::string_view text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
{
PrepareTargetForHW();
@@ -949,7 +965,7 @@ const GPUTask& olc::Draw::String(const olc::vf2d& pos, const std::string& text,
return Batch(task);
}
-const GPUTask& olc::Draw::StringProp(const olc::vf2d& pos, const std::string& text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
+const GPUTask& olc::Draw::StringProp(const olc::vf2d& pos, std::string_view text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
{
PrepareTargetForHW();
@@ -979,7 +995,7 @@ const GPUTask& olc::Draw::StringProp(const olc::vf2d& pos, const std::string& te
return Batch(task);
}
-olc::vf2d olc::Draw::GetTextSize(const std::string& text, const bool bProportional, const olc::vf2d& scale, olc::Font& font)
+olc::vf2d olc::Draw::GetTextSize(std::string_view text, const bool bProportional, const olc::vf2d& scale, olc::Font& font)
{
olc::vf2d size = { 0, font.fLineHeight * scale.y };
olc::vf2d pos = { 0, font.fLineHeight * scale.y };
diff --git a/dev/src/draw.h b/dev/src/draw.h
index e082107..9b92460 100644
--- a/dev/src/draw.h
+++ b/dev/src/draw.h
@@ -778,7 +778,7 @@ namespace olc
// Draws a string at specified location in monospace font
const GPUTask& String(
const olc::vf2d& pos,
- const std::string& text,
+ std::string_view text,
const olc::Pixel col = olc::Colour::WHITE,
const olc::vf2d& scale = { 1.0f, 1.0f },
olc::Font& font = olc::fontClassicPGE);
@@ -786,14 +786,14 @@ namespace olc
// Draws a string at specified location in proportional font
const GPUTask& StringProp(
const olc::vf2d& pos,
- const std::string& text,
+ std::string_view text,
const olc::Pixel col = olc::Colour::WHITE,
const olc::vf2d& scale = { 1.0f, 1.0f },
olc::Font& font = olc::fontClassicPGE);
// Returns the bounding box size of a string in pixels
olc::vf2d GetTextSize(
- const std::string& text,
+ std::string_view text,
const bool bProportional = false,
const olc::vf2d& scale = { 1.0f, 1.0f },
olc::Font& font = olc::fontClassicPGE);
@@ -975,6 +975,11 @@ namespace olc
const olc::Pixel tint = olc::Colour::WHITE,
const bool constrain = true,
const bool looped = false);
+
+ GPUTask TaskDrawPoints(
+ const std::vector& vPoints,
+ const std::vector& vColours,
+ const olc::Pixel tint = olc::Colour::WHITE);
GPUTask TaskDrawPolygon(
olc::Structure structure,
diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp
index 5aea813..0ceec8a 100644
--- a/dev/src/gpu_opengl33.cpp
+++ b/dev/src/gpu_opengl33.cpp
@@ -76,6 +76,8 @@ out vec4 oCol;
R"(
void main()
{
+ gl_PointSize = 1.0; // Required for emscripten
+
if (pgeDrawType == 2) // 3D
{
gl_Position = pgeMVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);
diff --git a/dev/src/host_apple_macos.cpp b/dev/src/host_apple_macos.cpp
index a79b86a..eec3830 100644
--- a/dev/src/host_apple_macos.cpp
+++ b/dev/src/host_apple_macos.cpp
@@ -310,7 +310,8 @@ namespace olc::host {
if (!this->OnSystemThreadStart())
{
// PGE->OnContextStart() failed, or user aborted OnUserCreate()
- return;
+ StopSystem();
+
}
// Main system loop
@@ -346,6 +347,9 @@ namespace olc::host {
bool Host_Apple_MacOS::StopSystem()
{
+ // Clear any pending tasks/messages on the main thread
+ bSkipFrame = ExecutePendingMainThreadTasks();
+
dispatch_sync(dispatch_get_main_queue(), ^{
// clean up and close application
if (pMacOSOpenGLRenderer)
diff --git a/dev/src/image.cpp b/dev/src/image.cpp
index 4c48037..b54fa07 100644
--- a/dev/src/image.cpp
+++ b/dev/src/image.cpp
@@ -99,6 +99,11 @@ namespace olc
return region({ 0,0 }, this->Size()).flipH();
}
+ olc::ImageRegion Image::flipD()
+ {
+ return olc::ImageRegion(*this, { 0,0 }, { 0,1 }, { 1, 0 }, { 1,1 });
+ }
+
void Image::BindGPU()
{
onGPU = true;
diff --git a/dev/src/image.h b/dev/src/image.h
index 6cd93c2..0f57c0f 100644
--- a/dev/src/image.h
+++ b/dev/src/image.h
@@ -88,6 +88,7 @@ namespace olc
olc::ImageRegion region(const olc::vf2d& vTL, const olc::vf2d& vTR, const olc::vf2d& vBL, const olc::vf2d& vBR);
olc::ImageRegion flipV();
olc::ImageRegion flipH();
+ olc::ImageRegion flipD();
public: // Make friendly private later
void BindGPU();
diff --git a/examples/olcPGE3_Geometry2D.cpp b/examples/olcPGE3_Geometry2D.cpp
new file mode 100644
index 0000000..a7caf96
--- /dev/null
+++ b/examples/olcPGE3_Geometry2D.cpp
@@ -0,0 +1,446 @@
+#define OLC_PGE3_APPLICATION
+#include "olcPixelGameEngine3.h"
+
+#include "utilities/olcUTIL3_Geometry2D.h"
+
+#include
+
+
+using namespace olc::utils::geom2d;
+
+// INSTRUCTIONS
+// ~~~~~~~~~~~~
+//
+// A convoluted test file to make sure all the tests do what we think they do.
+// Drag shapes with left mouse button
+// Active Shape = GREEN
+// Overlapped Shapes = YELLOW
+// Contained Shapes = MAGENTA
+// Intersection Points = RED
+//
+// Cast Rays with right mouse button (like lasers pew pew)
+// Ray - DASHED CYAN
+
+// Still not sure why the STL doesn't have this...
+template
+struct overloads : Ts... { using Ts::operator()...; };
+
+template
+overloads(Ts...) -> overloads;
+
+class Example_Geometry2D : public olc::PixelGameEngine
+{
+public:
+ Example_Geometry2D()
+ {
+ // Name your application
+ sAppName = "Testing Geometry2D Utilities";
+ }
+
+ // So what's going on here? Why are we redefining these base types? Are they not included in the header?
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ //
+ // Yes they are, and they can be used as expected. The challenge starts if you want to have a container filled
+ // with different shapes. The shapes do not share a common base class. The utility library is not really intended
+ // to be used this way - instead it's expected the user keep track of which shapes are interacting with which and
+ // call the appropriate function. This "kinda" happens automatically at compile time as all the functions have
+ // exhaustive overrides to allow all the permutations of test.
+ //
+ // However for this test application I wanted a whole bunch of shapes the user can interact with. 'starfreakclone'
+ // reworked my explicit (and lengthy) functions of comparisons and tests into some clever template-fu as seen here.
+ //
+ // "NOTE!! NEED A TEMPLATE GURU - IM SURE THIS MESS CAN BE TIDIED UP" - javidx9
+ // "Never fear! We are here!" - starfreakclone, fux & eight&&
+
+ struct Point
+ {
+ olc::vf2d points[1]; // the point
+ };
+
+ struct Line
+ {
+ olc::vf2d points[2]; // start, end
+ };
+
+ struct Rect
+ {
+ olc::vf2d points[2]; // pos top left, pos bottom right
+ };
+
+ struct Circle
+ {
+ olc::vf2d points[2]; // center pos, pos on circumference
+ };
+
+ struct Triangle
+ {
+ olc::vf2d points[3]; // the three points
+ };
+
+ struct Ray
+ {
+ olc::vf2d points[2]; // origin, direction
+ };
+
+ // Create desired shapes using a sequence of points
+ static auto make_internal(const Point& p) { return p.points[0]; }
+ static auto make_internal(const Line& p) { return line{ p.points[0], p.points[1] }; }
+ static auto make_internal(const Rect& p) { return rect{ p.points[0], (p.points[1] - p.points[0]) }; }
+ static auto make_internal(const Circle& p) { return circle{ p.points[0], (p.points[1]-p.points[0]).mag() }; }
+ static auto make_internal(const Triangle& p) { return triangle{ p.points[0], p.points[1], p.points[2] }; }
+ static auto make_internal(const Ray& p) { return ray{ p.points[0], (p.points[1]-p.points[0]).norm() }; }
+
+ // The clever bit (and a bit new to me - jx9)
+ using ShapeWrap = std::variant;
+
+
+
+ bool CheckOverlaps(const ShapeWrap& s1, const ShapeWrap& s2)
+ {
+ const auto dispatch = overloads{
+ [](const auto& lhs, const auto& rhs)
+ {
+ return overlaps(make_internal(lhs), make_internal(rhs));
+ },
+
+ // Any combination of 'Ray' does not work because 'overlaps' is not implemented for it.
+ [](const Ray&, const auto&) { return false; },
+ [](const auto&, const Ray&) { return false; },
+ [](const Ray&, const Ray&) { return false; }
+ };
+
+ return std::visit(dispatch, s1, s2);
+ }
+
+ bool CheckContains(const ShapeWrap& s1, const ShapeWrap& s2)
+ {
+ const auto dispatch = overloads{
+ [](const auto& lhs, const auto& rhs)
+ {
+ return contains(make_internal(lhs), make_internal(rhs));
+ },
+ // Any combination of 'Ray' does not work because 'contains' is not implemented for it.
+ [](const Ray&, const auto&) { return false; },
+ [](const auto&, const Ray&) { return false; },
+ [](const Ray&, const Ray&) { return false; }
+ };
+
+ return std::visit(dispatch, s1, s2);
+ }
+
+ std::vector CheckIntersects(const ShapeWrap& s1, const ShapeWrap& s2)
+ {
+ const auto dispatch = overloads{
+ [](const auto& lhs, const auto& rhs)
+ {
+ return intersects(make_internal(lhs), make_internal(rhs));
+ },
+
+ // Any combination of 'Ray' does not work because 'intersects' is not implemented for it.
+ //[](const Ray&, const auto&) { return std::vector{}; }, - Ray Intersections are implemented - tut tut :P
+
+ // Ray vs Ray - needed explicitly because...
+ [](const Ray& lhs, const Ray& rhs)
+ {
+ return intersects(make_internal(lhs), make_internal(rhs));
+ },
+
+ // ...Shape vs Ray - Dont exist but this treats all f(x,ray) as invalid
+ [](const auto&, const Ray&) { return std::vector{}; },
+ };
+
+ return std::visit(dispatch, s1, s2);
+ }
+
+ std::optional> CheckReflect(const olc::utils::geom2d::ray& s1, const ShapeWrap& s2)
+ {
+ const auto dispatch = overloads{
+ [&](const auto& a) -> std::optional>
+ {
+ return reflect(s1, make_internal(a));
+ }
+ };
+
+ return std::visit(dispatch, s2);
+ }
+
+ olc::v_2d GetClosest(const olc::v_2d p, const ShapeWrap& s)
+ {
+ const auto dispatch = overloads{
+ [&](const auto& a) -> olc::v_2d
+ {
+ return closest(make_internal(a), p);
+ }
+ };
+
+ return std::visit(dispatch, s);
+ }
+
+ void draw_internal(const Point& x, const olc::Pixel col)
+ {
+ const auto p = make_internal(x);
+ draw.Pixel(p, col);
+ }
+
+ void draw_internal(const Line& x, const olc::Pixel col)
+ {
+ const auto l = make_internal(x);
+ draw.Line(l.start, l.end, col);
+ }
+
+ void draw_internal(const Rect& x, const olc::Pixel col)
+ {
+ const auto r = make_internal(x);
+ draw.Rect(r.pos, r.size, col);
+ }
+
+ void draw_internal(const Circle& x, const olc::Pixel col)
+ {
+ const auto c = make_internal(x);
+ draw.Circle(c.pos, int32_t(c.radius), col);
+ }
+
+ void draw_internal(const Triangle& x, const olc::Pixel col)
+ {
+ const auto t = make_internal(x);
+ draw.Triangle(t.pos[0], t.pos[1], t.pos[2], col);
+ }
+
+ void draw_internal(const Ray& x, const olc::Pixel col)
+ {
+ const auto t = make_internal(x);
+ draw.Line(t.origin, t.origin+t.direction * 1000.0f, col, 0xF0F0F0F0);
+ }
+
+ void DrawShape(const ShapeWrap& shape, const olc::Pixel col = olc::Colour::WHITE)
+ {
+ std::visit([&](const auto& x)
+ {
+ draw_internal(x, col);
+ }, shape);
+ }
+
+ std::vector vecShapes;
+
+ size_t nSelectedShapeIndex = -1;
+ olc::vi2d vOldMousePos;
+
+public:
+ bool OnUserCreate() override
+ {
+ vecShapes.push_back({ Point{ { { 250.0f, 10.0f } } } });
+
+ vecShapes.push_back({ Line{ { { 20.0f, 10.0f }, {50.0f, 70.0f} } } });
+ vecShapes.push_back({ Line{ { { 80.0f, 10.0f }, {10.0f, 20.0f} } } });
+
+ vecShapes.push_back({ Rect{ { { 80.0f, 10.0f }, {110.0f, 60.0f} } } });
+
+ vecShapes.push_back({ Circle{ { { 130.0f, 20.0f }, {170.0f, 20.0f} } } });
+ vecShapes.push_back({ Circle{ { { 330.0f, 300.0f }, {420.0f, 300.0f} } } });
+ vecShapes.push_back({ Circle{ { { 330.0f, 300.0f }, {400.0f, 300.0f} } } });
+
+ vecShapes.push_back({ Triangle{{ {50.0f, 100.0f}, {10.0f, 150.0f}, {90.0f, 150.0f}} }});
+ vecShapes.push_back({ Triangle{{ {350.0f, 200.0f}, {500.0f, 150.0f}, {450.0f, 400.0f}} }});
+
+ return true;
+ }
+
+ bool OnUserUpdate(float fElapsedTime) override
+ {
+ olc::hw::Button LeftClick = mouse.GetButton(0);
+ olc::hw::Button RightClick = mouse.GetButton(1);
+
+ draw.Clear(olc::Colour::VERY_DARK_BLUE);
+
+ olc::vf2d vMouseDelta = mouse.GetPosition() - vOldMousePos;
+ vOldMousePos = mouse.GetPosition();
+
+
+
+ if (LeftClick.bReleased)
+ nSelectedShapeIndex = -1;
+
+ // Check for mouse hovered shapes
+ ShapeWrap mouse{ Point{ vOldMousePos } };
+
+ if (nSelectedShapeIndex < vecShapes.size() && LeftClick.bHeld)
+ {
+ // Visit the selected shape and offset.
+ std::visit([&](auto& shape)
+ {
+ for (auto& p : shape.points)
+ {
+ p += vMouseDelta;
+ }
+ }, vecShapes[nSelectedShapeIndex]);
+ }
+
+ size_t nMouseIndex = 0;
+ for (const auto& shape : vecShapes)
+ {
+ const int shapeMargin = 5;
+ if (CheckContains(shape, mouse) || (GetClosest(vOldMousePos, shape) - vOldMousePos).mag() < shapeMargin)
+ {
+ break;
+ }
+
+ nMouseIndex++;
+ }
+
+ if (nMouseIndex < vecShapes.size() && LeftClick.bPressed)
+ nSelectedShapeIndex = nMouseIndex;
+
+ // Check Contains
+ std::vector vContains;
+ std::vector vOverlaps;
+ std::vector vIntersections;
+ if (nSelectedShapeIndex < vecShapes.size())
+ {
+ for (size_t i = 0; i < vecShapes.size(); i++)
+ {
+ if (i == nSelectedShapeIndex) continue; // No self check
+
+ const auto& vTargetShape = vecShapes[i];
+
+ const auto vPoints = CheckIntersects(vecShapes[nSelectedShapeIndex], vTargetShape);
+ vIntersections.insert(vIntersections.end(), vPoints.begin(), vPoints.end());
+
+ if(CheckContains(vecShapes[nSelectedShapeIndex], vTargetShape))
+ vContains.push_back(i);
+
+ if (CheckOverlaps(vecShapes[nSelectedShapeIndex], vTargetShape))
+ vOverlaps.push_back(i);
+ }
+ }
+
+
+ ShapeWrap ray1, ray2;
+
+
+
+ bool bRayMode = false;
+ if (RightClick.bHeld)
+ {
+ // Enable Ray Mode
+ bRayMode = true;
+
+ ray1 = { Ray{{ { 10.0f, 10.0f }, vOldMousePos} }};
+ ray2 = { Ray{{ { float(ScreenSize().x - 10), 10.0f }, vOldMousePos} }};
+
+
+ for (size_t i = 0; i < vecShapes.size(); i++)
+ {
+ const auto& vTargetShape = vecShapes[i];
+
+ const auto vPoints1 = CheckIntersects(ray1, vTargetShape);
+ vIntersections.insert(vIntersections.end(), vPoints1.begin(), vPoints1.end());
+
+ const auto vPoints2 = CheckIntersects(ray2, vTargetShape);
+ vIntersections.insert(vIntersections.end(), vPoints2.begin(), vPoints2.end());
+
+ }
+
+ const auto vPoints3 = CheckIntersects(ray2, ray1);
+ vIntersections.insert(vIntersections.end(), vPoints3.begin(), vPoints3.end());
+
+
+ }
+
+ // Draw All Shapes
+ for (const auto& shape : vecShapes)
+ DrawShape(shape);
+
+
+ // Draw Overlaps
+ for (const auto& shape_idx : vOverlaps)
+ DrawShape(vecShapes[shape_idx], olc::Colour::YELLOW);
+
+ // Draw Contains
+ for (const auto& shape_idx : vContains)
+ DrawShape(vecShapes[shape_idx], olc::Colour::MAGENTA);
+
+ // Draw Manipulated Shape
+ if (nSelectedShapeIndex < vecShapes.size())
+ DrawShape(vecShapes[nSelectedShapeIndex], olc::Colour::GREEN);
+ else if (nMouseIndex < vecShapes.size())
+ DrawShape(vecShapes[nMouseIndex], olc::Colour::DARK_GREEN);
+
+ // Draw Intersections
+ for (const auto& intersection : vIntersections)
+ draw.FilledCircle(intersection, 3, olc::Colour::RED);
+
+ if (bRayMode)
+ {
+ DrawShape(ray1, olc::Colour::CYAN);
+ DrawShape(ray2, olc::Colour::CYAN);
+ }
+
+ // Laser beam
+ ray ray_laser{ {10.0f, 300.0f}, {1.0f, 0.0f} };
+ bool ray_stop = false;
+ int nBounces = 100;
+ size_t last_hit_index = -1;
+
+
+ ray ray_reflected;
+
+ while (!ray_stop && nBounces > 0)
+ {
+ // Find closest
+ ray_stop = true;
+ size_t closest_hit_index = -1;
+ float fClosestDistance = 10000000.0f;
+
+ for (size_t i = 0; i < vecShapes.size(); i++)
+ {
+ // Dont check against origin shape
+ if (i == last_hit_index) continue;
+
+ const auto& vTargetShape = vecShapes[i];
+ auto hit = CheckReflect(ray_laser, vTargetShape);
+ if (hit.has_value())
+ {
+ float d = (ray_laser.origin - hit.value().origin).mag();
+ if (d < fClosestDistance)
+ {
+ fClosestDistance = d;
+ closest_hit_index = i;
+ ray_reflected = hit.value();
+ }
+ }
+ }
+
+ if (closest_hit_index != -1)
+ {
+ draw.Line(ray_laser.origin, ray_reflected.origin, olc::Pixel(rand() % 155 + 100, 0, 0));
+ ray_laser = ray_reflected;
+ ray_stop = false;
+ last_hit_index = closest_hit_index;
+ nBounces--;
+ }
+
+ if (ray_stop)
+ {
+ // Ray didnt hit anything
+ nBounces = 0;
+ draw.Line(ray_laser.origin, ray_laser.origin + ray_laser.direction * 1000.0f, olc::Pixel(rand() % 155 + 100, 0, 0));
+ }
+ }
+
+
+ return true;
+ }
+};
+
+int main()
+{
+ Example_Geometry2D demo;
+
+ olc::PGEConfig cfg;
+ cfg.vScreenSize = {512, 480};
+ cfg.vPixelSize = {2, 2};
+
+ if (demo.Construct(cfg))
+ demo.Start();
+ return 0;
+}
\ No newline at end of file
diff --git a/olcPixelGameEngine3.h b/olcPixelGameEngine3.h
index 3725ed0..6a4ad22 100644
--- a/olcPixelGameEngine3.h
+++ b/olcPixelGameEngine3.h
@@ -2385,6 +2385,7 @@ namespace olc
olc::ImageRegion region(const olc::vf2d& vTL, const olc::vf2d& vTR, const olc::vf2d& vBL, const olc::vf2d& vBR);
olc::ImageRegion flipV();
olc::ImageRegion flipH();
+ olc::ImageRegion flipD();
public: // Make friendly private later
void BindGPU();
@@ -3454,7 +3455,7 @@ namespace olc
// Draws a string at specified location in monospace font
const GPUTask& String(
const olc::vf2d& pos,
- const std::string& text,
+ std::string_view text,
const olc::Pixel col = olc::Colour::WHITE,
const olc::vf2d& scale = { 1.0f, 1.0f },
olc::Font& font = olc::fontClassicPGE);
@@ -3462,14 +3463,14 @@ namespace olc
// Draws a string at specified location in proportional font
const GPUTask& StringProp(
const olc::vf2d& pos,
- const std::string& text,
+ std::string_view text,
const olc::Pixel col = olc::Colour::WHITE,
const olc::vf2d& scale = { 1.0f, 1.0f },
olc::Font& font = olc::fontClassicPGE);
// Returns the bounding box size of a string in pixels
olc::vf2d GetTextSize(
- const std::string& text,
+ std::string_view text,
const bool bProportional = false,
const olc::vf2d& scale = { 1.0f, 1.0f },
olc::Font& font = olc::fontClassicPGE);
@@ -3651,6 +3652,11 @@ namespace olc
const olc::Pixel tint = olc::Colour::WHITE,
const bool constrain = true,
const bool looped = false);
+
+ GPUTask TaskDrawPoints(
+ const std::vector& vPoints,
+ const std::vector& vColours,
+ const olc::Pixel tint = olc::Colour::WHITE);
GPUTask TaskDrawPolygon(
olc::Structure structure,
@@ -11822,7 +11828,8 @@ namespace olc::host {
if (!this->OnSystemThreadStart())
{
// PGE->OnContextStart() failed, or user aborted OnUserCreate()
- return;
+ StopSystem();
+
}
// Main system loop
@@ -11858,6 +11865,9 @@ namespace olc::host {
bool Host_Apple_MacOS::StopSystem()
{
+ // Clear any pending tasks/messages on the main thread
+ bSkipFrame = ExecutePendingMainThreadTasks();
+
dispatch_sync(dispatch_get_main_queue(), ^{
// clean up and close application
if (pMacOSOpenGLRenderer)
@@ -16704,6 +16714,8 @@ out vec4 oCol;
R"(
void main()
{
+ gl_PointSize = 1.0; // Required for emscripten
+
if (pgeDrawType == 2) // 3D
{
gl_Position = pgeMVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);
@@ -18384,10 +18396,26 @@ GPUTask olc::Draw::TaskDrawLine(const std::vector& vPoints, const olc
}
+GPUTask olc::Draw::TaskDrawPoints(const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint)
+{
+ GPUTask task;
+ task.structure = olc::Structure::Point;
+ task.vertexBuffer.resize(vPoints.size());
+ for (size_t i = 0; i < vPoints.size(); i++)
+ {
+ task.vertexBuffer[i] = { { vPoints[i].x, vPoints[i].y, 1.0f, 1.0f }, vColours[i],{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 } };
+ }
+ task.blendmode = blendMode;
+ task.tint = tint;
+ return task;
+}
+
GPUTask olc::Draw::TaskDrawPolygon(olc::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint)
{
- olc_IgnoreUnused(structure);
- return TaskDrawLine(vPoints, vColours, tint, false, true);
+ if (structure == olc::Structure::Point)
+ return TaskDrawPoints(vPoints, vColours, tint);
+ else
+ return TaskDrawLine(vPoints, vColours, tint, false, true);
}
GPUTask olc::Draw::TaskDrawPolygon(olc::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint)
@@ -18936,7 +18964,7 @@ const GPUTask& olc::Draw::TexturedPolygon(const olc::Structure structure, const
)));
}
-const GPUTask& olc::Draw::String(const olc::vf2d& pos, const std::string& text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
+const GPUTask& olc::Draw::String(const olc::vf2d& pos, std::string_view text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
{
PrepareTargetForHW();
@@ -18967,7 +18995,7 @@ const GPUTask& olc::Draw::String(const olc::vf2d& pos, const std::string& text,
return Batch(task);
}
-const GPUTask& olc::Draw::StringProp(const olc::vf2d& pos, const std::string& text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
+const GPUTask& olc::Draw::StringProp(const olc::vf2d& pos, std::string_view text, const olc::Pixel col, const olc::vf2d& scale, olc::Font& font)
{
PrepareTargetForHW();
@@ -18997,7 +19025,7 @@ const GPUTask& olc::Draw::StringProp(const olc::vf2d& pos, const std::string& te
return Batch(task);
}
-olc::vf2d olc::Draw::GetTextSize(const std::string& text, const bool bProportional, const olc::vf2d& scale, olc::Font& font)
+olc::vf2d olc::Draw::GetTextSize(std::string_view text, const bool bProportional, const olc::vf2d& scale, olc::Font& font)
{
olc::vf2d size = { 0, font.fLineHeight * scale.y };
olc::vf2d pos = { 0, font.fLineHeight * scale.y };
@@ -20667,6 +20695,11 @@ namespace olc
return region({ 0,0 }, this->Size()).flipH();
}
+ olc::ImageRegion Image::flipD()
+ {
+ return olc::ImageRegion(*this, { 0,0 }, { 0,1 }, { 1, 0 }, { 1,1 });
+ }
+
void Image::BindGPU()
{
onGPU = true;
diff --git a/utilities/olcUTIL3_Geometry2D.h b/utilities/olcUTIL3_Geometry2D.h
index 400422c..f8899de 100644
--- a/utilities/olcUTIL3_Geometry2D.h
+++ b/utilities/olcUTIL3_Geometry2D.h
@@ -1073,8 +1073,8 @@ namespace olc::utils::geom2d
template
inline constexpr bool contains(const rect& r, const olc::v_2d& p)
{
- return !(p.x < r.pos.x || p.y < r.pos.y ||
- p.x >(r.pos.x + r.size.x) || p.y >(r.pos.y + r.size.y));
+ return !((p.x) < r.pos.x || (p.y) < r.pos.y ||
+ (p.x) > (r.pos.x + r.size.x) || (p.y) > (r.pos.y + r.size.y));
}
// contains(c,p)