OSDN Git Service

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