From ed537c4f6a15905d1839bc69959c1c7bd1a33c4d Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 28 Sep 2019 18:34:56 -0300 Subject: [PATCH] lines can render more than 65k vertices (resolves issue #1356). --- src/modules/graphics/Polyline.cpp | 76 ++++++++++++++++++++----------- src/modules/graphics/Polyline.h | 26 +++++------ 2 files changed, 63 insertions(+), 39 deletions(-) diff --git a/src/modules/graphics/Polyline.cpp b/src/modules/graphics/Polyline.cpp index ac85f13b0..3bff531b4 100644 --- a/src/modules/graphics/Polyline.cpp +++ b/src/modules/graphics/Polyline.cpp @@ -367,39 +367,63 @@ Polyline::~Polyline() void Polyline::draw(love::graphics::Graphics *gfx) { - int total_vertex_count = (int) vertex_count; - if (overdraw) - total_vertex_count = (int) (overdraw_vertex_start + overdraw_vertex_count); - const Matrix4 &t = gfx->getTransform(); bool is2D = t.isAffine2DTransform(); - - Graphics::StreamDrawCommand cmd; - cmd.formats[0] = vertex::getSinglePositionFormat(is2D); - cmd.formats[1] = vertex::CommonFormat::RGBAub; - cmd.indexMode = triangle_mode; - cmd.vertexCount = total_vertex_count; - - Graphics::StreamVertexData data = gfx->requestStreamDraw(cmd); - - if (is2D) - t.transformXY((Vector2 *) data.stream[0], vertices, total_vertex_count); - else - t.transformXY0((Vector3 *) data.stream[0], vertices, total_vertex_count); - Color32 curcolor = toColor32(gfx->getColor()); - Color32 *colordata = (Color32 *) data.stream[1]; - for (int i = 0; i < (int) vertex_count; i++) - colordata[i] = curcolor; + int overdraw_start = (int) overdraw_vertex_start; + int overdraw_count = (int) overdraw_vertex_count; + int total_vertex_count = (int) vertex_count; if (overdraw) - fill_color_array(curcolor, colordata + overdraw_vertex_start); + total_vertex_count = overdraw_start + overdraw_count; + + // love's automatic batching can only deal with < 65k vertices per draw. + // uint16_max - 3 is evenly divisible by 6 (needed for quads mode). + int maxvertices = LOVE_UINT16_MAX - 3; + + int advance = maxvertices; + if (triangle_mode == vertex::TriangleIndexMode::STRIP) + advance -= 2; + + for (int vertex_start = 0; vertex_start < total_vertex_count; vertex_start += advance) + { + const Vector2 *verts = vertices + vertex_start; + + Graphics::StreamDrawCommand cmd; + cmd.formats[0] = vertex::getSinglePositionFormat(is2D); + cmd.formats[1] = vertex::CommonFormat::RGBAub; + cmd.indexMode = triangle_mode; + cmd.vertexCount = std::min(maxvertices, total_vertex_count - vertex_start); + + Graphics::StreamVertexData data = gfx->requestStreamDraw(cmd); + + if (is2D) + t.transformXY((Vector2 *) data.stream[0], verts, cmd.vertexCount); + else + t.transformXY0((Vector3 *) data.stream[0], verts, cmd.vertexCount); + + Color32 *colordata = (Color32 *) data.stream[1]; + + // Constant vertex color up to the overdraw vertices. + for (int i = 0; i < std::min(cmd.vertexCount, (int) vertex_count - vertex_start); i++) + colordata[i] = curcolor; + + int colorcount = 0; + if (overdraw) + colorcount = std::min(cmd.vertexCount, overdraw_count - (vertex_start - overdraw_start)); + + if (colorcount > 0) + { + Color32 *colors = colordata + std::max(0, (overdraw_start - vertex_start)); + fill_color_array(curcolor, colors, colorcount); + } + } } -void Polyline::fill_color_array(Color32 constant_color, Color32 *colors) +void Polyline::fill_color_array(Color32 constant_color, Color32 *colors, int count) { - for (size_t i = 0; i < overdraw_vertex_count; ++i) + for (int i = 0; i < count; ++i) { Color32 c = constant_color; c.a *= (i+1) % 2; // avoids branching. equiv to if (i%2 == 1) c.a = 0; @@ -407,9 +431,9 @@ void Polyline::fill_color_array(Color32 constant_color, Color32 *colors) } } -void NoneJoinPolyline::fill_color_array(Color32 constant_color, Color32 *colors) +void NoneJoinPolyline::fill_color_array(Color32 constant_color, Color32 *colors, int count) { - for (size_t i = 0; i < overdraw_vertex_count; ++i) + for (int i = 0; i < count; ++i) { Color32 c = constant_color; c.a *= (i & 3) < 2; // if (i % 4 == 2 || i % 4 == 3) c.a = 0 diff --git a/src/modules/graphics/Polyline.h b/src/modules/graphics/Polyline.h index b9dacb633..82d29f1c7 100644 --- a/src/modules/graphics/Polyline.h +++ b/src/modules/graphics/Polyline.h @@ -73,7 +73,7 @@ protected: virtual void calc_overdraw_vertex_count(bool is_looping); virtual void render_overdraw(const std::vector &normals, float pixel_size, bool is_looping); - virtual void fill_color_array(Color32 constant_color, Color32 *colors); + virtual void fill_color_array(Color32 constant_color, Color32 *colors, int count); /** Calculate line boundary points. * @@ -131,12 +131,12 @@ public: protected: - virtual void calc_overdraw_vertex_count(bool is_looping); - virtual void render_overdraw(const std::vector &normals, float pixel_size, bool is_looping); - virtual void fill_color_array(Color32 constant_color, Color32 *colors); - virtual void renderEdge(std::vector &anchors, std::vector &normals, - Vector2 &s, float &len_s, Vector2 &ns, - const Vector2 &q, const Vector2 &r, float hw); + void calc_overdraw_vertex_count(bool is_looping) override; + void render_overdraw(const std::vector &normals, float pixel_size, bool is_looping) override; + void fill_color_array(Color32 constant_color, Color32 *colors, int count) override; + void renderEdge(std::vector &anchors, std::vector &normals, + Vector2 &s, float &len_s, Vector2 &ns, const Vector2 &q, + const Vector2 &r, float hw) override; }; // NoneJoinPolyline @@ -156,9 +156,9 @@ public: protected: - virtual void renderEdge(std::vector &anchors, std::vector &normals, - Vector2 &s, float &len_s, Vector2 &ns, - const Vector2 &q, const Vector2 &r, float hw); + void renderEdge(std::vector &anchors, std::vector &normals, + Vector2 &s, float &len_s, Vector2 &ns, const Vector2 &q, + const Vector2 &r, float hw) override; }; // MiterJoinPolyline @@ -178,9 +178,9 @@ public: protected: - virtual void renderEdge(std::vector &anchors, std::vector &normals, - Vector2 &s, float &len_s, Vector2 &ns, - const Vector2 &q, const Vector2 &r, float hw); + void renderEdge(std::vector &anchors, std::vector &normals, + Vector2 &s, float &len_s, Vector2 &ns, const Vector2 &q, + const Vector2 &r, float hw) override; }; // BevelJoinPolyline