1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#pragma once
22
23// LOVE
24#include "common/config.h"
25#include "common/Vector.h"
26#include "graphics/vertex.h"
27
28// C++
29#include <vector>
30#include <string.h>
31
32namespace love
33{
34namespace graphics
35{
36
37class Graphics;
38
39/**
40 * Abstract base class for a chain of segments.
41 * @author Matthias Richter
42 **/
43class Polyline
44{
45public:
46
47 Polyline(vertex::TriangleIndexMode mode = vertex::TriangleIndexMode::STRIP)
48 : vertices(nullptr)
49 , overdraw(nullptr)
50 , vertex_count(0)
51 , overdraw_vertex_count(0)
52 , triangle_mode(mode)
53 , overdraw_vertex_start(0)
54 {}
55
56 virtual ~Polyline();
57
58 /**
59 * @param vertices Vertices defining the core line segments
60 * @param count Number of vertices
61 * @param size_hint Expected number of vertices of the rendering sleeve around the core line.
62 * @param halfwidth linewidth / 2.
63 * @param pixel_size Dimension of one pixel on the screen in world coordinates.
64 * @param draw_overdraw Fake antialias the line.
65 */
66 void render(const Vector2 *vertices, size_t count, size_t size_hint, float halfwidth, float pixel_size, bool draw_overdraw);
67
68 /** Draws the line on the screen
69 */
70 void draw(love::graphics::Graphics *gfx);
71
72protected:
73
74 virtual void calc_overdraw_vertex_count(bool is_looping);
75 virtual void render_overdraw(const std::vector<Vector2> &normals, float pixel_size, bool is_looping);
76 virtual void fill_color_array(Color32 constant_color, Color32 *colors, int count);
77
78 /** Calculate line boundary points.
79 *
80 * @param[out] anchors Anchor points defining the core line.
81 * @param[out] normals Normals defining the edge of the sleeve.
82 * @param[in,out] segment Direction of segment pq (updated to the segment qr).
83 * @param[in,out] segmentLength Length of segment pq (updated to the segment qr).
84 * @param[in,out] segmentNormal Normal on the segment pq (updated to the segment qr).
85 * @param[in] pointA Current point on the line (q).
86 * @param[in] pointB Next point on the line (r).
87 * @param[in] halfWidth Half line width (see Polyline.render()).
88 */
89 virtual void renderEdge(std::vector<Vector2> &anchors, std::vector<Vector2> &normals,
90 Vector2 &segment, float &segmentLength, Vector2 &segmentNormal,
91 const Vector2 &pointA, const Vector2 &pointB, float halfWidth) = 0;
92
93 Vector2 *vertices;
94 Vector2 *overdraw;
95 size_t vertex_count;
96 size_t overdraw_vertex_count;
97 vertex::TriangleIndexMode triangle_mode;
98 size_t overdraw_vertex_start;
99
100}; // Polyline
101
102
103/**
104 * A Polyline whose segments are not connected.
105 * @author Matthias Richter
106 */
107class NoneJoinPolyline : public Polyline
108{
109public:
110
111 NoneJoinPolyline()
112 : Polyline(vertex::TriangleIndexMode::QUADS)
113 {}
114
115 void render(const Vector2 *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw)
116 {
117 Polyline::render(vertices, count, 4 * count - 4, halfwidth, pixel_size, draw_overdraw);
118
119 // discard the first and last two vertices. (these are redundant)
120 for (size_t i = 0; i < vertex_count - 4; ++i)
121 this->vertices[i] = this->vertices[i+2];
122
123 // The last quad is now garbage, so zero it out to make sure it doesn't
124 // get rasterized. These vertices are in between the core line vertices
125 // and the overdraw vertices in the combined vertex array, so they still
126 // get "rendered" since we draw everything with one draw call.
127 memset(&this->vertices[vertex_count - 4], 0, sizeof(love::Vector2) * 4);
128
129 vertex_count -= 4;
130 }
131
132protected:
133
134 void calc_overdraw_vertex_count(bool is_looping) override;
135 void render_overdraw(const std::vector<Vector2> &normals, float pixel_size, bool is_looping) override;
136 void fill_color_array(Color32 constant_color, Color32 *colors, int count) override;
137 void renderEdge(std::vector<Vector2> &anchors, std::vector<Vector2> &normals,
138 Vector2 &s, float &len_s, Vector2 &ns, const Vector2 &q,
139 const Vector2 &r, float hw) override;
140
141}; // NoneJoinPolyline
142
143
144/**
145 * A Polyline whose segments are connected by a sharp edge.
146 * @author Matthias Richter
147 */
148class MiterJoinPolyline : public Polyline
149{
150public:
151
152 void render(const Vector2 *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw)
153 {
154 Polyline::render(vertices, count, 2 * count, halfwidth, pixel_size, draw_overdraw);
155 }
156
157protected:
158
159 void renderEdge(std::vector<Vector2> &anchors, std::vector<Vector2> &normals,
160 Vector2 &s, float &len_s, Vector2 &ns, const Vector2 &q,
161 const Vector2 &r, float hw) override;
162
163}; // MiterJoinPolyline
164
165
166/**
167 * A Polyline whose segments are connected by a flat edge.
168 * @author Matthias Richter
169 */
170class BevelJoinPolyline : public Polyline
171{
172public:
173
174 void render(const Vector2 *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw)
175 {
176 Polyline::render(vertices, count, 4 * count - 4, halfwidth, pixel_size, draw_overdraw);
177 }
178
179protected:
180
181 void renderEdge(std::vector<Vector2> &anchors, std::vector<Vector2> &normals,
182 Vector2 &s, float &len_s, Vector2 &ns, const Vector2 &q,
183 const Vector2 &r, float hw) override;
184
185}; // BevelJoinPolyline
186
187} // graphics
188} // love
189