OSDN Git Service

Small changes to MeshBuilder
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / graphics / g3d / utils / MeshBuilder.java
1 /*******************************************************************************\r
2  * Copyright 2011 See AUTHORS file.\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  * \r
8  *   http://www.apache.org/licenses/LICENSE-2.0\r
9  * \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  ******************************************************************************/
16
17 package com.badlogic.gdx.graphics.g3d.utils;
18
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.graphics.Color;
21 import com.badlogic.gdx.graphics.GL10;
22 import com.badlogic.gdx.graphics.Mesh;
23 import com.badlogic.gdx.graphics.VertexAttribute;
24 import com.badlogic.gdx.graphics.VertexAttributes;
25 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
26 import com.badlogic.gdx.graphics.g3d.Model;
27 import com.badlogic.gdx.graphics.g3d.model.MeshPart;
28 import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder.VertexInfo;
29 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
30 import com.badlogic.gdx.math.MathUtils;
31 import com.badlogic.gdx.math.Matrix4;
32 import com.badlogic.gdx.math.Vector2;
33 import com.badlogic.gdx.math.Vector3;
34 import com.badlogic.gdx.utils.Array;
35 import com.badlogic.gdx.utils.FloatArray;
36 import com.badlogic.gdx.utils.GdxRuntimeException;
37 import com.badlogic.gdx.utils.Pool;
38 import com.badlogic.gdx.utils.Pool.Poolable;
39 import com.badlogic.gdx.utils.ShortArray;
40
41 /** Class to construct a mesh, optionally splitting it into one or more mesh parts.
42  * Before you can call any other method you must call {@link #begin(VertexAttributes)} or {@link #begin(VertexAttributes, int)}. 
43  * To use mesh parts you must call {@link #part(String, int)} before you start building the part.
44  * The MeshPart itself is only valid after the call to {@link #end()}.
45  * @author Xoppa */
46 public class MeshBuilder implements MeshPartBuilder {
47         private final VertexInfo vertTmp1 = new VertexInfo();
48         private final VertexInfo vertTmp2 = new VertexInfo();
49         private final VertexInfo vertTmp3 = new VertexInfo();
50         private final VertexInfo vertTmp4 = new VertexInfo();
51         private final VertexInfo vertTmp5 = new VertexInfo();
52         private final VertexInfo vertTmp6 = new VertexInfo();
53         private final VertexInfo vertTmp7 = new VertexInfo();
54         private final VertexInfo vertTmp8 = new VertexInfo();
55         
56         private final Matrix4 matTmp1 = new Matrix4();
57         
58         private final Vector3 tempV1 = new Vector3();
59         private final Vector3 tempV2 = new Vector3();
60         private final Vector3 tempV3 = new Vector3();
61         private final Vector3 tempV4 = new Vector3();
62         private final Vector3 tempV5 = new Vector3();
63         private final Vector3 tempV6 = new Vector3();
64         private final Vector3 tempV7 = new Vector3();
65         private final Vector3 tempV8 = new Vector3();
66         
67         /** The vertex attributes of the resulting mesh */ 
68         private VertexAttributes attributes;
69         /** The vertices to construct, no size checking is done */
70         private FloatArray vertices = new FloatArray();
71         /** The indices to construct, no size checking is done */
72         private ShortArray indices = new ShortArray();
73         /** The size (in number of floats) of each vertex */
74         private int stride;
75         /** The current vertex index, used for indexing */
76         private short vindex;
77         /** The offset in the indices array when begin() was called, used to define a meshpart. */
78         private int istart;
79         /** The offset within an vertex to position */
80         private int posOffset;
81         /** The size (in number of floats) of the position attribute */
82         private int posSize;
83         /** The offset within an vertex to normal, or -1 if not available */
84         private int norOffset;
85         /** The offset within an vertex to color, or -1 if not available */
86         private int colOffset;
87         /** The size (in number of floats) of the color attribute */
88         private int colSize;
89         /** The offset within an vertex to packed color, or -1 if not available */
90         private int cpOffset;
91         /** The offset within an vertex to texture coordinates, or -1 if not available */
92         private int uvOffset;
93         /** The meshpart currently being created */
94         private MeshPart part;
95         /** The parts created between begin and end */
96         private Array<MeshPart> parts = new Array<MeshPart>();
97         /** The color used if no vertex color is specified. */
98         private final Color color = new Color();
99         /** Whether to apply the default color. */
100         private boolean colorSet;
101         /** The current primitiveType */
102         private int primitiveType;
103         // FIXME makes this configurable
104         private float uMin = 0, uMax = 1, vMin = 0, vMax = 1;
105         private float[] vertex;
106         
107         /** @param usage bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage}, 
108          * only Position, Color, Normal and TextureCoordinates is supported. */
109         public static VertexAttributes createAttributes(long usage) {
110                 final Array<VertexAttribute> attrs = new Array<VertexAttribute>();
111                 if ((usage & Usage.Position) == Usage.Position)
112                         attrs.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE));
113                 if ((usage & Usage.Color) == Usage.Color)
114                         attrs.add(new VertexAttribute(Usage.Color, 4, ShaderProgram.COLOR_ATTRIBUTE));
115                 if ((usage & Usage.Normal) == Usage.Normal)
116                         attrs.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE));
117                 if ((usage & Usage.TextureCoordinates) == Usage.TextureCoordinates)
118                         attrs.add(new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE+"0"));
119                 final VertexAttribute attributes[] = new VertexAttribute[attrs.size];
120                 for (int i = 0; i < attributes.length; i++)
121                         attributes[i] = attrs.get(i);
122                 return new VertexAttributes(attributes);
123         }
124         
125         /** Begin building a mesh. Call {@link #part(String, int)} to start a {@link MeshPart}.
126          * @param attributes bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage}, 
127          * only Position, Color, Normal and TextureCoordinates is supported. */
128         public void begin(final long attributes) {
129                 begin(createAttributes(attributes), 0);
130         }
131         
132         /** Begin building a mesh. Call {@link #part(String, int)} to start a {@link MeshPart}. */
133         public void begin(final VertexAttributes attributes) {
134                 begin(attributes, 0);
135         }
136         
137         /** Begin building a mesh.
138          * @param attributes bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage}, 
139          * only Position, Color, Normal and TextureCoordinates is supported. */
140         public void begin(final long attributes, int primitiveType) {
141                 begin(createAttributes(attributes), primitiveType);
142         }
143         
144         /** Begin building a mesh */
145         public void begin(final VertexAttributes attributes, int primitiveType) {
146                 if (this.attributes != null)
147                         throw new RuntimeException("Call end() first");
148                 this.attributes = attributes;
149                 this.vertices.clear();
150                 this.indices.clear();
151                 this.parts.clear();
152                 this.vindex = 0;
153                 this.istart = 0;
154                 this.part = null;
155                 this.stride = attributes.vertexSize / 4;
156                 this.vertex = new float[stride];
157                 VertexAttribute a = attributes.findByUsage(Usage.Position);
158                 if (a == null)
159                         throw new GdxRuntimeException("Cannot build mesh without position attribute");
160                 posOffset = a.offset / 4;
161                 posSize = a.numComponents;
162                 a = attributes.findByUsage(Usage.Normal);
163                 norOffset = a == null ? -1 : a.offset / 4;
164                 a = attributes.findByUsage(Usage.Color);
165                 colOffset = a == null ? -1 : a.offset / 4;
166                 colSize = a == null ? 0 : a.numComponents;
167                 a = attributes.findByUsage(Usage.ColorPacked);
168                 cpOffset = a == null ? -1 : a.offset / 4;
169                 a = attributes.findByUsage(Usage.TextureCoordinates);
170                 uvOffset = a == null ? -1 : a.offset / 4;
171                 setColor(null);
172                 this.primitiveType = primitiveType;
173         }
174         
175         private void endpart() {
176                 if (part != null) {
177                         part.indexOffset = istart;
178                         part.numVertices = indices.size - istart;
179                         istart = indices.size;
180                         part = null;
181                 }
182         }
183         
184         /** Starts a new MeshPart. The mesh part is not usable until end() is called */
185         public MeshPart part(final String id, int primitiveType) {
186                 if (this.attributes == null)
187                         throw new RuntimeException("Call begin() first");
188                 endpart();
189                 
190                 part = new MeshPart();
191                 part.id = id;
192                 this.primitiveType = part.primitiveType = primitiveType;
193                 parts.add(part);
194                 
195                 setColor(null);
196                 
197                 return part;
198         }
199         
200         /** End building the mesh and returns the mesh */
201         public Mesh end() {
202                 if (this.attributes == null)
203                         throw new RuntimeException("Call begin() first");
204                 endpart();
205                 
206                 final Mesh mesh = new Mesh(true, vertices.size, indices.size, attributes);
207                 mesh.setVertices(vertices.items, 0, vertices.size);
208                 mesh.setIndices(indices.items, 0, indices.size);
209                 
210                 for (MeshPart p : parts)
211                         p.mesh = mesh;
212                 parts.clear();
213                 
214                 attributes = null;
215                 vertices.clear();
216                 indices.clear();
217                 
218                 return mesh;
219         }
220         
221         @Override
222         public VertexAttributes getAttributes() {
223                 return attributes;
224         }
225         
226         @Override
227         public MeshPart getMeshPart() {
228                 return part;
229         }
230         
231         private final static Pool<Vector3> vectorPool = new Pool<Vector3>() {
232                 @Override
233                 protected Vector3 newObject () {
234                         return new Vector3();
235                 }
236         };
237         
238         private final static Array<Vector3> vectorArray = new Array<Vector3>();
239         
240         private Vector3 tmp(float x, float y, float z) {
241                 final Vector3 result = vectorPool.obtain().set(x, y, z);
242                 vectorArray.add(result);
243                 return result;
244         }
245         
246         private Vector3 tmp(Vector3 copyFrom) {
247                 return tmp(copyFrom.x, copyFrom.y, copyFrom.z);
248         }
249         
250         private void cleanup() {
251                 vectorPool.freeAll(vectorArray);
252                 vectorArray.clear();
253         }
254         
255         @Override
256         public void setColor(float r, float g, float b, float a) {
257                 color.set(r, g, b, a);
258                 colorSet = true;
259         }
260         
261         @Override
262         public void setColor(final Color color) {
263                 if ((colorSet = color != null)==true)
264                         this.color.set(color);
265         }
266         
267         @Override
268         public void setUVRange(float u1, float v1, float u2, float v2) {
269                 uMin = u1;
270                 vMin = v1;
271                 uMax = u2;
272                 vMax = v2;
273         }
274         
275         /** Increases the size of the backing vertices array to accommodate the specified number of additional vertices. 
276          * Useful before adding many vertices to avoid multiple backing array resizes.
277          * @param numVertices The number of vertices you are about to add */
278         public void ensureVertices(int numVertices) {
279                 vertices.ensureCapacity(vertex.length * numVertices);
280         }
281         
282         /** Increases the size of the backing indices array to accommodate the specified number of additional indices. 
283          * Useful before adding many indices to avoid multiple backing array resizes.
284          * @param numIndices The number of indices you are about to add */
285         public void ensureIndices(int numIndices) {
286                 indices.ensureCapacity(numIndices);
287         }
288         
289         /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
290          * vertices and indices. Useful before adding many vertices and indices to avoid multiple backing array resizes.
291          * @param numVertices The number of vertices you are about to add
292          * @param numIndices The number of indices you are about to add */
293         public void ensureCapacity(int numVertices, int numIndices) {
294                 ensureVertices(numVertices);
295                 ensureIndices(numIndices);
296         }
297         
298         /** Increases the size of the backing indices array to accommodate the specified number of additional triangles. 
299          * Useful before adding many triangles to avoid multiple backing array resizes.
300          * @param numTriangles The number of triangles you are about to add */
301         public void ensureTriangleIndices(int numTriangles) {
302                 if (primitiveType == GL10.GL_LINES)
303                         ensureIndices(6 * numTriangles);
304                 else // GL_TRIANGLES || GL_POINTS
305                         ensureIndices(3 * numTriangles);
306         }
307         
308         /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
309          * vertices and triangles. Useful before adding many triangles to avoid multiple backing array resizes.
310          * @param numVertices The number of vertices you are about to add
311          * @param numTriangles The number of triangles you are about to add */
312         public void ensureTriangles(int numVertices, int numTriangles) {
313                 ensureVertices(numVertices);
314                 ensureTriangleIndices(numTriangles);
315         }
316         
317         /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
318          * vertices and triangles. Useful before adding many triangles to avoid multiple backing array resizes.
319          * Assumes each triangles adds 3 vertices.
320          * @param numTriangles The number of triangles you are about to add */
321         public void ensureTriangles(int numTriangles) {
322                 ensureTriangles(3 * numTriangles, numTriangles);
323         }
324         
325         /** Increases the size of the backing indices array to accommodate the specified number of additional rectangles. 
326          * Useful before adding many rectangles to avoid multiple backing array resizes.
327          * @param numRectangles The number of rectangles you are about to add */
328         public void ensureRectangleIndices(int numRectangles) {
329                 if (primitiveType == GL10.GL_POINTS) 
330                         ensureIndices(4 * numRectangles);
331                 else if (primitiveType == GL10.GL_LINES) 
332                         ensureIndices(8 * numRectangles);
333                 else // GL_TRIANGLES
334                         ensureIndices(6 * numRectangles);
335         }
336         
337         /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
338          * vertices and rectangles. Useful before adding many rectangles to avoid multiple backing array resizes.
339          * @param numVertices The number of vertices you are about to add
340          * @param numRectangles The number of rectangles you are about to add */
341         public void ensureRectangles(int numVertices, int numRectangles) {
342                 ensureVertices(numVertices);
343                 ensureRectangleIndices(numRectangles);
344         }
345         
346         /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
347          * vertices and rectangles. Useful before adding many rectangles to avoid multiple backing array resizes.
348          * Assumes each rectangles adds 4 vertices
349          * @param numRectangles The number of rectangles you are about to add */
350         public void ensureRectangles(int numRectangles) {
351                 ensureRectangles(4 * numRectangles, numRectangles);
352         }
353         
354         @Override
355         public short vertex(Vector3 pos, Vector3 nor, Color col, Vector2 uv) {
356                 if (vindex >= Short.MAX_VALUE)
357                         throw new GdxRuntimeException("Too many vertices used");
358                 if (col == null && colorSet)
359                         col = color;
360                 if (pos != null) {
361                         vertex[posOffset  ] = pos.x;
362                         if (posSize > 1) vertex[posOffset+1] = pos.y;
363                         if (posSize > 2) vertex[posOffset+2] = pos.z;
364                 }
365                 if (nor != null && norOffset >= 0) {
366                         vertex[norOffset  ] = nor.x;
367                         vertex[norOffset+1] = nor.y;
368                         vertex[norOffset+2] = nor.z;
369                 }
370                 if (col != null) {
371                         if (colOffset >= 0) {
372                                 vertex[colOffset  ] = col.r;
373                                 vertex[colOffset+1] = col.g;
374                                 vertex[colOffset+2] = col.b;
375                                 if (colSize > 3) vertex[colOffset+3] = col.a;
376                         } else if (cpOffset > 0)
377                                 vertex[cpOffset] = col.toFloatBits(); // FIXME cache packed color?
378                 }
379                 if (uv != null && uvOffset >= 0) {
380                         vertex[uvOffset  ] = uv.x;
381                         vertex[uvOffset+1] = uv.y;
382                 }
383                 vertices.addAll(vertex);
384                 return (short)(vindex++);
385         }
386         
387         @Override
388         public short lastIndex() {
389                 return (short)(vindex-1);
390         }
391
392         @Override
393         public short vertex(final float... values) {
394                 vertices.addAll(values);
395                 vindex += values.length / stride;
396                 return (short)(vindex-1);
397         }
398         
399         @Override
400         public short vertex(final VertexInfo info) {
401                 return vertex(info.hasPosition ? info.position : null, info.hasNormal ? info.normal : null, 
402                         info.hasColor ? info.color : null, info.hasUV ? info.uv : null);
403         }
404         
405         @Override
406         public void index(final short value) {
407                 indices.add(value);
408         }
409         
410         @Override
411         public void index(final short value1, final short value2) {
412                 ensureIndices(2);
413                 indices.add(value1);
414                 indices.add(value2);
415         }
416         
417         @Override
418         public void index(final short value1, final short value2, final short value3) {
419                 ensureIndices(3);
420                 indices.add(value1);
421                 indices.add(value2);
422                 indices.add(value3);
423         }
424         
425         @Override
426         public void index(final short value1, final short value2, final short value3, final short value4) {
427                 ensureIndices(4);
428                 indices.add(value1);
429                 indices.add(value2);
430                 indices.add(value3);
431                 indices.add(value4);
432         }
433         
434         @Override
435         public void index(short value1, short value2, short value3, short value4, short value5, short value6) {
436                 ensureIndices(6);
437                 indices.add(value1);
438                 indices.add(value2);
439                 indices.add(value3);
440                 indices.add(value4);
441                 indices.add(value5);
442                 indices.add(value6);
443         }
444
445         @Override
446         public void index(short value1, short value2, short value3, short value4, short value5, short value6, short value7, short value8) {
447                 ensureIndices(8);
448                 indices.add(value1);
449                 indices.add(value2);
450                 indices.add(value3);
451                 indices.add(value4);
452                 indices.add(value5);
453                 indices.add(value6);
454                 indices.add(value7);
455                 indices.add(value8);
456         }
457         
458         @Override
459         public void line(short index1, short index2) {
460                 if (primitiveType != GL10.GL_LINES)
461                         throw new GdxRuntimeException("Incorrect primitive type");
462                 index(index1, index2);
463         }
464         
465         @Override
466         public void line(VertexInfo p1, VertexInfo p2) {
467                 ensureVertices(2);
468                 line(vertex(p1), vertex(p2));
469         }
470
471         @Override
472         public void line(Vector3 p1, Vector3 p2) {
473                 line(vertTmp1.set(p1, null, null, null), vertTmp2.set(p2, null, null, null));
474         }
475         
476         @Override
477         public void line(float x1, float y1, float z1, float x2, float y2, float z2) {
478                 line(vertTmp1.set(null, null, null, null).setPos(x1, y1, z1), vertTmp2.set(null, null, null, null).setPos(x2, y2, z2));
479         }
480
481         @Override
482         public void line(Vector3 p1, Color c1, Vector3 p2, Color c2) {
483                 line(vertTmp1.set(p1, null, c1, null), vertTmp2.set(p2, null, c2, null));
484         }
485         
486         @Override
487         public void triangle(short index1, short index2, short index3) {
488                 if (primitiveType == GL10.GL_TRIANGLES || primitiveType == GL10.GL_POINTS) {
489                         index(index1, index2, index3);
490                 } else if (primitiveType == GL10.GL_LINES) {
491                         index(index1, index2, index2, index3, index3, index1);
492                 } else
493                         throw new GdxRuntimeException("Incorrect primitive type");
494         }
495
496         @Override
497         public void triangle(VertexInfo p1, VertexInfo p2, VertexInfo p3) {
498                 ensureVertices(3);
499                 triangle(vertex(p1), vertex(p2), vertex(p3));
500         }
501         
502         @Override
503         public void triangle(Vector3 p1, Vector3 p2, Vector3 p3) {
504                 triangle(vertTmp1.set(p1, null, null, null), vertTmp2.set(p2, null, null, null), vertTmp3.set(p3, null, null, null));
505         }
506         
507         @Override
508         public void triangle(Vector3 p1, Color c1, Vector3 p2, Color c2, Vector3 p3, Color c3) {
509                 triangle(vertTmp1.set(p1, null, c1, null), vertTmp2.set(p2, null, c2, null), vertTmp3.set(p3, null, c3, null));
510         }
511         
512         @Override
513         public void rect(short corner00, short corner10, short corner11, short corner01) {
514                 if (primitiveType == GL10.GL_TRIANGLES) {
515                         index(corner00, corner10, corner11, corner11, corner01, corner00);
516                 } else if (primitiveType == GL10.GL_LINES) {
517                         index(corner00, corner10, corner10, corner11, corner11, corner01, corner01, corner00);
518                 } else if (primitiveType == GL10.GL_POINTS) {
519                         index(corner00, corner10, corner11, corner01);
520                 } else
521                         throw new GdxRuntimeException("Incorrect primitive type");
522         }
523         
524         @Override
525         public void rect(VertexInfo corner00, VertexInfo corner10, VertexInfo corner11, VertexInfo corner01) {
526                 ensureVertices(4);
527                 rect(vertex(corner00), vertex(corner10), vertex(corner11), vertex(corner01));
528         }
529         
530         @Override
531         public void rect(Vector3 corner00, Vector3 corner10, Vector3 corner11, Vector3 corner01, Vector3 normal) {
532                 rect(vertTmp1.set(corner00, normal, null, null).setUV(uMin,vMin),
533                         vertTmp2.set(corner10, normal, null, null).setUV(uMax,vMin),
534                         vertTmp3.set(corner11, normal, null, null).setUV(uMax,vMax),
535                         vertTmp4.set(corner01, normal, null, null).setUV(uMin,vMax));
536         }
537         
538         @Override
539         public void rect(float x00, float y00, float z00, float x10, float y10, float z10, float x11, float y11, float z11, float x01, float y01, float z01, float normalX, float normalY, float normalZ) {
540                 rect(vertTmp1.set(null, null, null, null).setPos(x00,y00,z00).setNor(normalX,normalY,normalZ).setUV(uMin,vMin),
541                         vertTmp2.set(null, null, null, null).setPos(x10,y10,z10).setNor(normalX,normalY,normalZ).setUV(uMax,vMin),
542                         vertTmp3.set(null, null, null, null).setPos(x11,y11,z11).setNor(normalX,normalY,normalZ).setUV(uMax,vMax),
543                         vertTmp4.set(null, null, null, null).setPos(x01,y01,z01).setNor(normalX,normalY,normalZ).setUV(uMin,vMax));
544         }
545         
546         @Override
547         public void patch(VertexInfo corner00, VertexInfo corner10, VertexInfo corner11, VertexInfo corner01, int divisionsU, int divisionsV) {
548                 ensureRectangles((divisionsV + 1) * (divisionsU + 1), divisionsV * divisionsU);
549                 for (int u = 0; u <= divisionsU; u++) {
550                         final float alphaU = (float)u / (float)divisionsU; 
551                         vertTmp5.set(corner00).lerp(corner10, alphaU);
552                         vertTmp6.set(corner01).lerp(corner11, alphaU);
553                         for (int v = 0; v <= divisionsV; v++) {
554                                 final short idx = vertex(vertTmp7.set(vertTmp5).lerp(vertTmp6, (float)v / (float)divisionsV));
555                                 if (u > 0 && v > 0)
556                                         rect((short)(idx-divisionsV-2), (short)(idx-1), idx, (short)(idx-divisionsV-1));
557                         }
558                 }
559         }
560         
561         @Override
562         public void patch(Vector3 corner00, Vector3 corner10, Vector3 corner11, Vector3 corner01, Vector3 normal, int divisionsU, int divisionsV) {
563                 patch(vertTmp1.set(corner00, normal, null, null).setUV(uMin,vMin),
564                         vertTmp2.set(corner10, normal, null, null).setUV(uMax,vMin),
565                         vertTmp3.set(corner11, normal, null, null).setUV(uMax,vMax),
566                         vertTmp4.set(corner01, normal, null, null).setUV(uMin,vMax),
567                         divisionsU, divisionsV);
568         }
569         
570         public void patch(float x00, float y00, float z00, float x10, float y10, float z10, float x11, float y11, float z11, float x01, float y01, float z01, float normalX, float normalY, float normalZ, int divisionsU, int divisionsV) {
571                 patch(vertTmp1.set(null).setPos(x00, y00, z00).setNor(normalX, normalY, normalZ).setUV(uMin,vMin),
572                         vertTmp2.set(null).setPos(x10, y10, z10).setNor(normalX, normalY, normalZ).setUV(uMax,vMin),
573                         vertTmp3.set(null).setPos(x11, y11, z11).setNor(normalX, normalY, normalZ).setUV(uMax,vMax),
574                         vertTmp4.set(null).setPos(x01, y01, z01).setNor(normalX, normalY, normalZ).setUV(uMin,vMax),
575                         divisionsU, divisionsV);
576         }
577         
578         @Override
579         public void box(VertexInfo corner000, VertexInfo corner010, VertexInfo corner100, VertexInfo corner110,
580                                                 VertexInfo corner001, VertexInfo corner011, VertexInfo corner101, VertexInfo corner111) {
581                 ensureVertices(8);
582                 final short i000 = vertex(corner000);
583                 final short i100 = vertex(corner100);
584                 final short i110 = vertex(corner110);
585                 final short i010 = vertex(corner010);
586                 final short i001 = vertex(corner001);
587                 final short i101 = vertex(corner101);
588                 final short i111 = vertex(corner111);
589                 final short i011 = vertex(corner011);
590                 
591                 if (primitiveType == GL10.GL_LINES) {
592                         ensureIndices(24);
593                         rect(i000, i100, i110, i010);
594                         rect(i101, i001, i011, i111);
595                         index(i000, i001, i010, i011, i110, i111, i100, i101);
596                 } else if (primitiveType != GL10.GL_POINTS) {
597                         ensureRectangleIndices(2);
598                         rect(i000, i100, i110, i010);
599                         rect(i101, i001, i011, i111);
600                 } else { // GL10.GL_TRIANGLES
601                         ensureRectangleIndices(6);
602                         rect(i000, i100, i110, i010);
603                         rect(i101, i001, i011, i111);
604                         rect(i000, i010, i011, i001);
605                         rect(i101, i111, i110, i100);
606                         rect(i101, i100, i000, i001);
607                         rect(i110, i111, i011, i010);
608                 }
609         }
610         
611         @Override
612         public void box(Vector3 corner000, Vector3 corner010, Vector3 corner100, Vector3 corner110,
613                                                 Vector3 corner001, Vector3 corner011, Vector3 corner101, Vector3 corner111) {
614                 if (norOffset < 0 && uvOffset < 0) {
615                         box(vertTmp1.set(corner000, null, null, null), vertTmp2.set(corner010, null, null, null),
616                                 vertTmp3.set(corner100, null, null, null), vertTmp4.set(corner110, null, null, null),
617                                 vertTmp5.set(corner001, null, null, null), vertTmp6.set(corner011, null, null, null),
618                                 vertTmp7.set(corner101, null, null, null), vertTmp8.set(corner111, null, null, null));
619                 } else {
620                         ensureRectangles(6);
621                         Vector3 nor = tempV1.set(corner000).lerp(corner110, 0.5f).sub(tempV2.set(corner001).lerp(corner111, 0.5f)).nor();
622                         rect(corner000, corner010, corner110, corner100, nor);
623                         rect(corner011, corner001, corner101, corner111, nor.scl(-1));
624                         nor = tempV1.set(corner000).lerp(corner101, 0.5f).sub(tempV2.set(corner010).lerp(corner111, 0.5f)).nor();
625                         rect(corner001, corner000, corner100, corner101, nor);
626                         rect(corner010, corner011, corner111, corner110, nor.scl(-1));
627                         nor = tempV1.set(corner000).lerp(corner011, 0.5f).sub(tempV2.set(corner100).lerp(corner111, 0.5f)).nor();
628                         rect(corner001, corner011, corner010, corner000, nor);
629                         rect(corner100, corner110, corner111, corner101, nor.scl(-1));
630                 }
631         }
632         
633         @Override
634         public void box(Matrix4 transform) {
635                 box(tmp(-0.5f,-0.5f,-0.5f).mul(transform),tmp(-0.5f,0.5f,-0.5f).mul(transform),tmp(0.5f,-0.5f,-0.5f).mul(transform),tmp(0.5f,0.5f,-0.5f).mul(transform),
636                         tmp(-0.5f,-0.5f,0.5f).mul(transform),tmp(-0.5f,0.5f,0.5f).mul(transform),tmp(0.5f,-0.5f,0.5f).mul(transform),tmp(0.5f,0.5f,0.5f).mul(transform));
637                 cleanup();
638         }
639
640         @Override
641         public void box(float width, float height, float depth) {
642                 box(matTmp1.setToScaling(width, height, depth));
643         }
644         
645         @Override
646         public void box(float x, float y, float z, float width, float height, float depth) {
647                 box(matTmp1.setToScaling(width, height, depth).trn(x, y, z));
648         }
649         
650         @Override
651         public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ) {
652                 circle(radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, 0f, 360f);
653         }
654
655         @Override
656         public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal) {
657                 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z);
658         }
659
660         @Override
661         public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal) {
662                 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z);
663         }
664         
665         @Override
666         public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ) {
667                 circle(radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, 0f, 360f);               
668         }
669         
670         @Override
671         public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float angleFrom, float angleTo) {
672                 ellipse(radius * 2f, radius * 2f, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, angleFrom, angleTo);
673         }
674
675         @Override
676         public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal, float angleFrom, float angleTo) {
677                 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, angleFrom, angleTo);
678         }
679         
680         @Override
681         public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal, float angleFrom, float angleTo) {
682                 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z, angleFrom, angleTo);
683         }
684
685         @Override
686         public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ, float angleFrom, float angleTo) {
687                 ellipse(radius*2, radius*2, 0, 0, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, angleFrom, angleTo);
688         }\r
689         \r
690         @Override\r
691         public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ) {\r
692                 ellipse(width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, 0f, 360f);\r
693         }\r
694 \r
695         @Override\r
696         public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal) {\r
697                 ellipse(width, height, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z);\r
698         }\r
699 \r
700         @Override\r
701         public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal) {\r
702                 ellipse(width, height, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z);\r
703         }\r
704         \r
705         @Override\r
706         public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ) {\r
707                 ellipse(width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, 0f, 360f);               \r
708         }\r
709         \r
710         @Override\r
711         public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float angleFrom, float angleTo) {\r
712                 ellipse(width, height, 0f, 0f, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, angleFrom, angleTo);\r
713         }\r
714 \r
715         @Override\r
716         public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal, float angleFrom, float angleTo) {\r
717                 ellipse(width, height, 0f, 0f, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, angleFrom, angleTo);\r
718         }\r
719         \r
720         @Override\r
721         public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal, float angleFrom, float angleTo) {\r
722                 ellipse(width, height, 0f, 0f, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z, angleFrom, angleTo);\r
723         }\r
724 \r
725         @Override\r
726         public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ, float angleFrom, float angleTo) {\r
727                 ellipse(width, height, 0f, 0f, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, angleFrom, angleTo);\r
728         }\r
729         
730         @Override
731         public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, Vector3 center, Vector3 normal) {
732                 ellipse(width, height, innerWidth, innerHeight, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, 0f, 360f);
733         }
734
735         @Override
736         public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ) {
737                 ellipse(width, height, innerWidth, innerHeight, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, 0f, 360f);
738         }
739                 
740         @Override
741         public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float angleFrom, float angleTo) {\r
742                 tempV1.set(normalX, normalY, normalZ).crs(0, 0, 1);
743                 tempV2.set(normalX, normalY, normalZ).crs(0, 1, 0);
744                 if (tempV2.len2() > tempV1.len2())
745                         tempV1.set(tempV2);
746                 tempV2.set(tempV1.nor()).crs(normalX, normalY, normalZ).nor();
747                 ellipse(width, height, innerWidth, innerHeight, divisions, centerX, centerY, centerZ, normalX, normalY,  normalZ, tempV1.x, tempV1.y, tempV1.z, tempV2.x, tempV2.y, tempV2.z, angleFrom, angleTo);
748         }
749         
750         @Override
751         public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ, float angleFrom, float angleTo) {
752                 if(innerWidth <= 0 || innerHeight <= 0) {                                       
753                         ensureTriangles(divisions + 2, divisions);
754                 }
755                 else if (innerWidth == width && innerHeight == height){
756                         ensureVertices(divisions + 1);
757                         ensureIndices(divisions + 1);
758                         if(primitiveType != GL10.GL_LINES)
759                                 throw new GdxRuntimeException("Incorrect primitive type : expect GL_LINES because innerWidth == width && innerHeight == height");
760                 }
761                 else {
762                         ensureRectangles((divisions + 1)*2, divisions + 1);
763                 }
764                 
765                 final float ao = MathUtils.degreesToRadians * angleFrom;
766                 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
767                 final Vector3 sxEx = tempV1.set(tangentX, tangentY, tangentZ).scl(width * 0.5f);
768                 final Vector3 syEx = tempV2.set(binormalX, binormalY, binormalZ).scl(height * 0.5f);
769                 final Vector3 sxIn = tempV3.set(tangentX, tangentY, tangentZ).scl(innerWidth * 0.5f);
770                 final Vector3 syIn = tempV4.set(binormalX, binormalY, binormalZ).scl(innerHeight * 0.5f);
771                 VertexInfo currIn = vertTmp3.set(null, null, null, null);
772                 currIn.hasUV = currIn.hasPosition = currIn.hasNormal = true;\r
773                 currIn.uv.set(.5f, .5f);
774                 currIn.position.set(centerX, centerY, centerZ);
775                 currIn.normal.set(normalX, normalY, normalZ);   
776                 VertexInfo currEx = vertTmp4.set(null, null, null, null);
777                 currEx.hasUV = currEx.hasPosition = currEx.hasNormal = true;\r
778                 currEx.uv.set(.5f, .5f);
779                 currEx.position.set(centerX, centerY, centerZ);
780                 currEx.normal.set(normalX, normalY, normalZ);
781                 final short center = vertex(currEx);
782                 float angle = 0f;\r
783                 final float us = 0.5f * (innerWidth / width);\r
784                 final float vs = 0.5f * (innerHeight / height);
785                 for (int i = 0; i <= divisions; i++) {
786                         angle = ao + step * i;
787                         final float x = MathUtils.cos(angle);
788                         final float y = MathUtils.sin(angle);
789                         currEx.position.set(centerX, centerY, centerZ).add(sxEx.x*x+syEx.x*y, sxEx.y*x+syEx.y*y, sxEx.z*x+syEx.z*y);
790                         currEx.uv.set(.5f + .5f * x, .5f + .5f * y);                            
791                         vertex(currEx);
792                         
793                         if(innerWidth <= 0f || innerHeight <= 0f)       {                                       
794                                 if (i != 0)
795                                         triangle((short)(vindex - 1), (short)(vindex - 2), center);
796                         }
797                         else if (innerWidth == width && innerHeight == height){
798                                 if (i != 0)
799                                         line((short)(vindex - 1), (short)(vindex - 2));
800                         }
801                         else {
802                                 currIn.position.set(centerX, centerY, centerZ).add(sxIn.x*x+syIn.x*y, sxIn.y*x+syIn.y*y, sxIn.z*x+syIn.z*y);
803                                 currIn.uv.set(.5f + us * x, .5f + vs * y);                              
804                                 vertex(currIn);
805                                 
806                                 if( i != 0)
807                                         rect((short)(vindex - 1), (short)(vindex - 2),(short)(vindex - 4), (short)(vindex - 3));
808                         }
809                 }
810         }
811         
812         @Override
813         public void cylinder(float width, float height, float depth, int divisions) {
814                 cylinder(width, height, depth, divisions, 0, 360);
815         }
816         
817         @Override
818         public void cylinder(float width, float height, float depth, int divisions, float angleFrom, float angleTo) {
819                 cylinder(width, height, depth, divisions, angleFrom, angleTo, true);
820         }
821         
822         /** Add a cylinder */
823         public void cylinder(float width, float height, float depth, int divisions, float angleFrom, float angleTo, boolean close) {
824                 // FIXME create better cylinder method (- axis on which to create the cylinder (matrix?))
825                 final float hw = width * 0.5f;
826                 final float hh = height * 0.5f;
827                 final float hd = depth * 0.5f;
828                 final float ao = MathUtils.degreesToRadians * angleFrom;
829                 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
830                 final float us = 1f / divisions;
831                 float u = 0f;
832                 float angle = 0f;
833                 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
834                 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
835                 VertexInfo curr2 = vertTmp4.set(null, null, null, null);
836                 curr2.hasUV = curr2.hasPosition = curr2.hasNormal = true;
837                 
838                 ensureRectangles(2 * (divisions + 1), divisions);
839                 for (int i = 0; i <= divisions; i++) {
840                         angle = ao + step * i;
841                         u = 1f - us * i;
842                         curr1.position.set(MathUtils.cos(angle) * hw, 0f, MathUtils.sin(angle) * hd);
843                         curr1.normal.set(curr1.position).nor();
844                         curr1.position.y = -hh;
845                         curr1.uv.set(u, 1);
846                         curr2.position.set(curr1.position);
847                         curr2.normal.set(curr1.normal);
848                         curr2.position.y = hh;
849                         curr2.uv.set(u, 0);
850                         vertex(curr1);
851                         vertex(curr2);
852                         if (i != 0)
853                                 rect((short)(vindex-3), (short)(vindex-1), (short)(vindex-2), (short)(vindex-4)); // FIXME don't duplicate lines and points
854                 }
855                 if (close) {
856                         ellipse(width, depth, 0, 0, divisions, 0, hh, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, angleFrom, angleTo);
857                         ellipse(width, depth, 0, 0, divisions, 0, -hh, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 180f-angleTo, 180f-angleFrom);
858                 }
859         }
860         
861         @Override
862         public void cone(float width, float height, float depth, int divisions) {
863                 cone(width, height, depth, divisions, 0, 360);
864         }
865         
866         @Override
867         public void cone(float width, float height, float depth, int divisions, float angleFrom, float angleTo) {
868                 // FIXME create better cylinder method (- axis on which to create the cone (matrix?))
869                 ensureTriangles(divisions + 2, divisions);
870                 
871                 final float hw = width * 0.5f;
872                 final float hh = height * 0.5f;
873                 final float hd = depth * 0.5f;
874                 final float ao = MathUtils.degreesToRadians * angleFrom;
875                 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
876                 final float us = 1f / divisions;
877                 float u = 0f;
878                 float angle = 0f;               
879                 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
880                 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
881                 VertexInfo curr2 = vertTmp4.set(null, null, null, null).setPos(0,hh,0).setNor(0,1,0).setUV(0.5f, 0);
882                 final int base = vertex(curr2);
883                 for (int i = 0; i <= divisions; i++) {
884                         angle = ao + step * i;
885                         u = 1f - us * i;
886                         curr1.position.set(MathUtils.cos(angle) * hw, 0f, MathUtils.sin(angle) * hd);
887                         curr1.normal.set(curr1.position).nor();
888                         curr1.position.y = -hh;
889                         curr1.uv.set(u, 1);
890                         vertex(curr1);
891                         if (i == 0)
892                                 continue;
893                         triangle((short)base, (short)(vindex-1), (short)(vindex-2)); // FIXME don't duplicate lines and points
894                 }
895                 ellipse(width, depth, 0, 0, divisions, 0, -hh, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 180f-angleTo, 180f-angleFrom);
896         }
897         
898         @Override
899         public void sphere(float width, float height, float depth, int divisionsU, int divisionsV) {
900                 sphere(width, height, depth, divisionsU, divisionsV, 0, 360, 0, 180);
901         }
902         
903         @Override
904         public void sphere(final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV) {
905                 sphere(transform, width, height, depth, divisionsU, divisionsV, 0, 360, 0, 180);
906         }
907
908         @Override
909         public void sphere(float width, float height, float depth, int divisionsU, int divisionsV, float angleUFrom, float angleUTo, float angleVFrom, float angleVTo) {
910                 sphere(matTmp1.idt(), width, height, depth, divisionsU, divisionsV, angleUFrom, angleUTo, angleVFrom, angleVTo);
911         }
912
913         @Override
914         public void sphere(final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV, float angleUFrom, float angleUTo, float angleVFrom, float angleVTo) {
915                 // FIXME create better sphere method (- only one vertex for each pole, - position)
916                 final float hw = width * 0.5f;
917                 final float hh = height * 0.5f;
918                 final float hd = depth * 0.5f;
919                 final float auo = MathUtils.degreesToRadians * angleUFrom;
920                 final float stepU = (MathUtils.degreesToRadians * (angleUTo - angleUFrom)) / divisionsU;
921                 final float avo = MathUtils.degreesToRadians * angleVFrom;
922                 final float stepV = (MathUtils.degreesToRadians * (angleVTo - angleVFrom)) / divisionsV;
923                 final float us = 1f / divisionsU;
924                 final float vs = 1f / divisionsV;
925                 float u = 0f;
926                 float v = 0f;
927                 float angleU = 0f;
928                 float angleV = 0f;
929                 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
930                 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
931                 
932                 ensureRectangles((divisionsV + 1) * (divisionsU + 1), divisionsV * divisionsU);
933                 for (int iv = 0; iv <= divisionsV; iv++) {
934                         angleV = avo + stepV * iv;
935                         v = vs * iv;
936                         final float t = MathUtils.sin(angleV);
937                         final float h = MathUtils.cos(angleV) * hh;
938                         for (int iu = 0; iu <= divisionsU; iu++) {
939                                 angleU = auo + stepU * iu;
940                                 u = 1f - us * iu;
941                                 curr1.position.set(MathUtils.cos(angleU) * hw * t, h, MathUtils.sin(angleU) * hd * t).mul(transform);
942                                 curr1.normal.set(curr1.position).nor();
943                                 curr1.uv.set(u, v);
944                                 vertex(curr1);
945                                 if ((iv > 0) && (iu > 0)) // FIXME don't duplicate lines and points
946                                         rect((short)(vindex-1), (short)(vindex-2), (short)(vindex-(divisionsU+3)), (short)(vindex-(divisionsU+2))); 
947                         }
948                 }
949         }
950         
951         @Override
952         public void capsule(float radius, float height, int divisions) {
953                 if (height < 2f * radius)
954                         throw new GdxRuntimeException("Height must be at least twice the radius");
955                 final float d = 2f * radius;
956                 cylinder(d, height - d, d, divisions, 0, 360, false);
957                 sphere(matTmp1.setToTranslation(0, .5f*(height-d), 0), d, d, d, divisions, divisions, 0, 360, 0, 90);
958                 sphere(matTmp1.setToTranslation(0, -.5f*(height-d), 0), d, d, d, divisions, divisions, 0, 360, 90, 180);
959         }
960 }