OSDN Git Service

Various, mostly meshbuilder ensure size
[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                 ensureTriangles(divisions + 2, divisions);
677                 
678                 final float ao = MathUtils.degreesToRadians * angleFrom;
679                 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
680                 final Vector3 sx = tempV1.set(tangentX, tangentY, tangentZ).scl(width * 0.5f);
681                 final Vector3 sy = tempV2.set(binormalX, binormalY, binormalZ).scl(height * 0.5f);
682                 VertexInfo curr = vertTmp3.set(null, null, null, null);
683                 curr.hasUV = curr.hasPosition = curr.hasNormal = true;
684                 curr.uv.set(.5f, .5f);
685                 curr.position.set(centerX, centerY, centerZ);
686                 curr.normal.set(normalX, normalY, normalZ);     
687                 final short center = vertex(curr);
688                 float angle = 0f;
689                 for (int i = 0; i <= divisions; i++) {
690                         angle = ao + step * i;
691                         final float x = MathUtils.cos(angle);
692                         final float y = MathUtils.sin(angle);
693                         curr.uv.set(.5f + .5f * x, .5f + .5f * y);
694                         curr.position.set(centerX, centerY, centerZ).add(sx.x*x+sy.x*y, sx.y*x+sy.y*y, sx.z*x+sy.z*y);
695                         vertex(curr);
696                         if (i != 0)
697                                 triangle((short)(vindex - 1), (short)(vindex - 2), center);
698                 }
699         }
700         
701         @Override
702         public void cylinder(float width, float height, float depth, int divisions) {
703                 cylinder(width, height, depth, divisions, 0, 360);
704         }
705         
706         @Override
707         public void cylinder(float width, float height, float depth, int divisions, float angleFrom, float angleTo) {
708                 cylinder(width, height, depth, divisions, angleFrom, angleTo, true);
709         }
710         
711         /** Add a cylinder */
712         public void cylinder(float width, float height, float depth, int divisions, float angleFrom, float angleTo, boolean close) {
713                 // FIXME create better cylinder method (- axis on which to create the cylinder (matrix?))
714                 final float hw = width * 0.5f;
715                 final float hh = height * 0.5f;
716                 final float hd = depth * 0.5f;
717                 final float ao = MathUtils.degreesToRadians * angleFrom;
718                 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
719                 final float us = 1f / divisions;
720                 float u = 0f;
721                 float angle = 0f;
722                 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
723                 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
724                 VertexInfo curr2 = vertTmp4.set(null, null, null, null);
725                 curr2.hasUV = curr2.hasPosition = curr2.hasNormal = true;
726                 
727                 ensureRectangles(2 * (divisions + 1), divisions);
728                 for (int i = 0; i <= divisions; i++) {
729                         angle = ao + step * i;
730                         u = 1f - us * i;
731                         curr1.position.set(MathUtils.cos(angle) * hw, 0f, MathUtils.sin(angle) * hd);
732                         curr1.normal.set(curr1.position).nor();
733                         curr1.position.y = -hh;
734                         curr1.uv.set(u, 1);
735                         curr2.position.set(curr1.position);
736                         curr2.normal.set(curr1.normal);
737                         curr2.position.y = hh;
738                         curr2.uv.set(u, 0);
739                         vertex(curr1);
740                         vertex(curr2);
741                         if (i != 0)
742                                 rect((short)(vindex-3), (short)(vindex-1), (short)(vindex-2), (short)(vindex-4)); // FIXME don't duplicate lines and points
743                 }
744                 if (close) {
745                         circle(width, depth, 0, hh, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, divisions, angleFrom, angleTo);
746                         circle(width, depth, 0, -hh, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, divisions, 180f-angleTo, 180f-angleFrom);
747                 }
748         }
749         
750         @Override
751         public void cone(float width, float height, float depth, int divisions) {
752                 cone(width, height, depth, divisions, 0, 360);
753         }
754         
755         @Override
756         public void cone(float width, float height, float depth, int divisions, float angleFrom, float angleTo) {
757                 // FIXME create better cylinder method (- axis on which to create the cone (matrix?))
758                 ensureTriangles(divisions + 2, divisions);
759                 
760                 final float hw = width * 0.5f;
761                 final float hh = height * 0.5f;
762                 final float hd = depth * 0.5f;
763                 final float ao = MathUtils.degreesToRadians * angleFrom;
764                 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
765                 final float us = 1f / divisions;
766                 float u = 0f;
767                 float angle = 0f;               
768                 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
769                 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
770                 VertexInfo curr2 = vertTmp4.set(null, null, null, null).setPos(0,hh,0).setNor(0,1,0).setUV(0.5f, 0);
771                 final int base = vertex(curr2);
772                 for (int i = 0; i <= divisions; i++) {
773                         angle = ao + step * i;
774                         u = 1f - us * i;
775                         curr1.position.set(MathUtils.cos(angle) * hw, 0f, MathUtils.sin(angle) * hd);
776                         curr1.normal.set(curr1.position).nor();
777                         curr1.position.y = -hh;
778                         curr1.uv.set(u, 1);
779                         vertex(curr1);
780                         if (i == 0)
781                                 continue;
782                         triangle((short)base, (short)(vindex-1), (short)(vindex-2)); // FIXME don't duplicate lines and points
783                 }
784                 circle(width, depth, 0, -hh, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, divisions, 180f-angleTo, 180f-angleFrom);
785         }
786         
787         @Override
788         public void sphere(float width, float height, float depth, int divisionsU, int divisionsV) {
789                 sphere(width, height, depth, divisionsU, divisionsV, 0, 360, 0, 180);
790         }
791         
792         @Override
793         public void sphere(final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV) {
794                 sphere(transform, width, height, depth, divisionsU, divisionsV, 0, 360, 0, 180);
795         }
796
797         @Override
798         public void sphere(float width, float height, float depth, int divisionsU, int divisionsV, float angleUFrom, float angleUTo, float angleVFrom, float angleVTo) {
799                 sphere(matTmp1.idt(), width, height, depth, divisionsU, divisionsV, angleUFrom, angleUTo, angleVFrom, angleVTo);
800         }
801
802         @Override
803         public void sphere(final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV, float angleUFrom, float angleUTo, float angleVFrom, float angleVTo) {
804                 // FIXME create better sphere method (- only one vertex for each pole, - position)
805                 final float hw = width * 0.5f;
806                 final float hh = height * 0.5f;
807                 final float hd = depth * 0.5f;
808                 final float auo = MathUtils.degreesToRadians * angleUFrom;
809                 final float stepU = (MathUtils.degreesToRadians * (angleUTo - angleUFrom)) / divisionsU;
810                 final float avo = MathUtils.degreesToRadians * angleVFrom;
811                 final float stepV = (MathUtils.degreesToRadians * (angleVTo - angleVFrom)) / divisionsV;
812                 final float us = 1f / divisionsU;
813                 final float vs = 1f / divisionsV;
814                 float u = 0f;
815                 float v = 0f;
816                 float angleU = 0f;
817                 float angleV = 0f;
818                 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
819                 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
820                 
821                 ensureRectangles((divisionsV + 1) * (divisionsU + 1), divisionsV * divisionsU);
822                 for (int iv = 0; iv <= divisionsV; iv++) {
823                         angleV = avo + stepV * iv;
824                         v = vs * iv;
825                         final float t = MathUtils.sin(angleV);
826                         final float h = MathUtils.cos(angleV) * hh;
827                         for (int iu = 0; iu <= divisionsU; iu++) {
828                                 angleU = auo + stepU * iu;
829                                 u = 1f - us * iu;
830                                 curr1.position.set(MathUtils.cos(angleU) * hw * t, h, MathUtils.sin(angleU) * hd * t).mul(transform);
831                                 curr1.normal.set(curr1.position).nor();
832                                 curr1.uv.set(u, v);
833                                 vertex(curr1);
834                                 if ((iv > 0) && (iu > 0)) // FIXME don't duplicate lines and points
835                                         rect((short)(vindex-1), (short)(vindex-2), (short)(vindex-(divisionsU+3)), (short)(vindex-(divisionsU+2))); 
836                         }
837                 }
838         }
839         
840         @Override
841         public void capsule(float radius, float height, int divisions) {
842                 if (height < 2f * radius)
843                         throw new GdxRuntimeException("Height must be at least twice the radius");
844                 final float d = 2f * radius;
845                 cylinder(d, height - d, d, divisions, 0, 360, false);
846                 sphere(matTmp1.setToTranslation(0, .5f*(height-d), 0), d, d, d, divisions, divisions, 0, 360, 0, 90);
847                 sphere(matTmp1.setToTranslation(0, -.5f*(height-d), 0), d, d, d, divisions, divisions, 0, 360, 90, 180);
848         }
849 }