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)