1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2017 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5  *
6  * This software is provided 'as-is', without any express or implied warranty.
7  * In no event will the authors be held liable for any damages arising from the
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  */
24 
25 /**
26  * $(U VertexArray) is a very simple wrapper around a dynamic array of vertices
27  *and a primitives type.
28  *
29  * It inherits $(DRAWABLE_LINK), but unlike other drawables it is not
30  * transformable.
31  *
32  * Example:
33  * ---
34  * VertexArray lines(PrimitiveType.LineStrip, 4);
35  * lines[0].position = Vector2f(10, 0);
36  * lines[1].position = Vector2f(20, 0);
37  * lines[2].position = Vector2f(30, 5);
38  * lines[3].position = Vector2f(40, 2);
39  *
40  * window.draw(lines);
41  * ---
42  *
43  * See_Also:
44  * $(VERTEX_LINK)
45  */
46 module dsfml.graphics.vertexarray;
47 
48 import dsfml.graphics.vertex;
49 import dsfml.graphics.primitivetype;
50 import dsfml.graphics.rect;
51 import dsfml.graphics.drawable;
52 import dsfml.graphics.rendertarget;
53 import dsfml.graphics.renderstates;
54 
55 import dsfml.system.vector2;
56 
57 /**
58  * Define a set of one or more 2D primitives.
59  */
60 class VertexArray : Drawable
61 {
62     /**
63      * The type of primitive to draw.
64      *
65      * Can be any of the following:
66      * - Points
67      * - Lines
68      * - Triangles
69      * - Quads
70      *
71      * The default primitive type is Points.
72      */
73     PrimitiveType primitiveType;
74     private Vertex[] Vertices;
75 
76     /**
77      * Default constructor
78      *
79      * Creates an empty vertex array.
80      */
81     this()
82     {
83     }
84 
85     /**
86      * Construct the vertex array with a type and an initial number of vertices
87      *
88      * Params:
89      *  type        = Type of primitives
90      *  vertexCount = Initial number of vertices in the array
91      */
92     this(PrimitiveType type, uint vertexCount)
93     {
94         primitiveType = type;
95         Vertices = new Vertex[vertexCount];
96     }
97 
98     private this(PrimitiveType type, Vertex[] vertices)
99     {
100         primitiveType = type;
101         Vertices = vertices;
102     }
103 
104     /// Destructor.
105     ~this()
106     {
107         import dsfml.system.config;
108         mixin(destructorOutput);
109     }
110 
111     /**
112      * Compute the bounding rectangle of the vertex array.
113      *
114      * This function returns the axis-aligned rectangle that contains all the
115      * vertices of the array.
116      *
117      * Returns: Bounding rectangle of the vertex array.
118      */
119     FloatRect getBounds()
120     {
121         if (Vertices.length>0)
122         {
123             float left = Vertices[0].position.x;
124             float top = Vertices[0].position.y;
125             float right = Vertices[0].position.x;
126             float bottom = Vertices[0].position.y;
127 
128             for (size_t i = 1; i < Vertices.length; ++i)
129             {
130                 Vector2f position = Vertices[i].position;
131 
132                 // Update left and right
133                 if (position.x < left)
134                     left = position.x;
135                 else if (position.x > right)
136                     right = position.x;
137 
138                 // Update top and bottom
139                 if (position.y < top)
140                     top = position.y;
141                 else if (position.y > bottom)
142                     bottom = position.y;
143             }
144 
145             return FloatRect(left, top, right - left, bottom - top);
146         }
147         else
148         {
149             return FloatRect(0,0,0,0);
150         }
151     }
152 
153     /**
154      * Return the vertex count.
155      *
156      * Returns: Number of vertices in the array
157      */
158     uint getVertexCount()
159     {
160         import std.algorithm;
161         return cast(uint)min(uint.max, Vertices.length);
162     }
163 
164     /**
165      * Add a vertex to the array.
166      *
167      * Params:
168      * 		vertex	= Vertex to add.
169      */
170     void append(Vertex newVertex)
171     {
172         Vertices ~= newVertex;
173     }
174 
175     /**
176      * Clear the vertex array.
177      *
178      * This function removes all the vertices from the array. It doesn't
179      * deallocate the corresponding memory, so that adding new vertices after
180      * clearing doesn't involve reallocating all the memory.
181      */
182     void clear()
183     {
184         Vertices.length = 0;
185     }
186 
187     /**
188      * Draw the object to a render target.
189      *
190      * Params:
191      *  		renderTarget =	Render target to draw to
192      *  		renderStates =	Current render states
193      */
194     override void draw(RenderTarget renderTarget, RenderStates renderStates)
195     {
196         if(Vertices.length != 0)
197         {
198             renderTarget.draw(Vertices, primitiveType,renderStates);
199         }
200     }
201 
202     /**
203      * Resize the vertex array.
204      *
205      * If vertexCount is greater than the current size, the previous vertices
206      * are kept and new (default-constructed) vertices are added. If vertexCount
207      * is less than the current size, existing vertices are removed from the
208      * array.
209      *
210      * Params:
211      * 		vertexCount	= New size of the array (number of vertices).
212      */
213     void resize(uint length)
214     {
215         Vertices.length = length;
216     }
217 
218     /**
219      * Get a read-write access to a vertex by its index
220      *
221      * This function doesn't check index, it must be in range
222      * [0, getVertexCount() - 1]. The behavior is undefined otherwise.
223      *
224      * Params:
225      *  index = Index of the vertex to get
226      *
227      * Returns: Reference to the index-th vertex.
228      */
229     ref Vertex opIndex(size_t index)
230     {
231         return Vertices[index];
232     }
233 }
234 
235 unittest
236 {
237     version(DSFML_Unittest_Graphics)
238     {
239         import std.stdio;
240         import dsfml.graphics.texture;
241         import dsfml.graphics.rendertexture;
242         import dsfml.graphics.color;
243 
244         writeln("Unit test for VertexArray");
245 
246         auto texture = new Texture();
247 
248         assert(texture.loadFromFile("res/TestImage.png"));
249 
250 
251 
252         auto dimensions = FloatRect(0,0,texture.getSize().x,texture.getSize().y);
253 
254         auto vertexArray = new VertexArray(PrimitiveType.Quads, 0);
255 
256         //Creates a vertex array at position (0,0) the width and height of the loaded texture
257         vertexArray.append(Vertex(Vector2f(dimensions.left,dimensions.top), Color.Blue, Vector2f(dimensions.left,dimensions.top)));
258         vertexArray.append(Vertex(Vector2f(dimensions.left,dimensions.height), Color.Blue, Vector2f(dimensions.left,dimensions.height)));
259         vertexArray.append(Vertex(Vector2f(dimensions.width,dimensions.height), Color.Blue, Vector2f(dimensions.width,dimensions.height)));
260         vertexArray.append(Vertex(Vector2f(dimensions.width,dimensions.top), Color.Blue, Vector2f(dimensions.width,dimensions.top)));
261 
262 
263         auto renderStates = RenderStates(texture);
264 
265 
266         auto renderTexture = new RenderTexture();
267 
268         renderTexture.create(100,100);
269 
270         renderTexture.clear();
271 
272         //draw the VertexArray with the texture we loaded
273         renderTexture.draw(vertexArray, renderStates);
274 
275         renderTexture.display();
276 
277         writeln();
278     }
279 }