1 /*******************************************************************************
\r
2 * Copyright 2011 See AUTHORS file.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
15 ******************************************************************************/
17 package com.badlogic.gdx.graphics.g3d.utils;
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.graphics.Color;
21 import com.badlogic.gdx.graphics.GL10;
22 import com.badlogic.gdx.graphics.Mesh;
23 import com.badlogic.gdx.graphics.VertexAttribute;
24 import com.badlogic.gdx.graphics.VertexAttributes;
25 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
26 import com.badlogic.gdx.graphics.g3d.Model;
27 import com.badlogic.gdx.graphics.g3d.model.MeshPart;
28 import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder.VertexInfo;
29 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
30 import com.badlogic.gdx.math.MathUtils;
31 import com.badlogic.gdx.math.Matrix4;
32 import com.badlogic.gdx.math.Vector2;
33 import com.badlogic.gdx.math.Vector3;
34 import com.badlogic.gdx.utils.Array;
35 import com.badlogic.gdx.utils.FloatArray;
36 import com.badlogic.gdx.utils.GdxRuntimeException;
37 import com.badlogic.gdx.utils.Pool;
38 import com.badlogic.gdx.utils.Pool.Poolable;
39 import com.badlogic.gdx.utils.ShortArray;
41 /** Class to construct a mesh, optionally splitting it into one or more mesh parts.
42 * Before you can call any other method you must call {@link #begin(VertexAttributes)} or {@link #begin(VertexAttributes, int)}.
43 * To use mesh parts you must call {@link #part(String, int)} before you start building the part.
44 * The MeshPart itself is only valid after the call to {@link #end()}.
46 public class MeshBuilder implements MeshPartBuilder {
47 private final VertexInfo vertTmp1 = new VertexInfo();
48 private final VertexInfo vertTmp2 = new VertexInfo();
49 private final VertexInfo vertTmp3 = new VertexInfo();
50 private final VertexInfo vertTmp4 = new VertexInfo();
51 private final VertexInfo vertTmp5 = new VertexInfo();
52 private final VertexInfo vertTmp6 = new VertexInfo();
53 private final VertexInfo vertTmp7 = new VertexInfo();
54 private final VertexInfo vertTmp8 = new VertexInfo();
56 private final Matrix4 matTmp1 = new Matrix4();
58 private final Vector3 tempV1 = new Vector3();
59 private final Vector3 tempV2 = new Vector3();
60 private final Vector3 tempV3 = new Vector3();
61 private final Vector3 tempV4 = new Vector3();
62 private final Vector3 tempV5 = new Vector3();
63 private final Vector3 tempV6 = new Vector3();
64 private final Vector3 tempV7 = new Vector3();
65 private final Vector3 tempV8 = new Vector3();
67 /** The vertex attributes of the resulting mesh */
68 private VertexAttributes attributes;
69 /** The vertices to construct, no size checking is done */
70 private FloatArray vertices = new FloatArray();
71 /** The indices to construct, no size checking is done */
72 private ShortArray indices = new ShortArray();
73 /** The size (in number of floats) of each vertex */
75 /** The current vertex index, used for indexing */
77 /** The offset in the indices array when begin() was called, used to define a meshpart. */
79 /** The offset within an vertex to position */
80 private int posOffset;
81 /** The size (in number of floats) of the position attribute */
83 /** The offset within an vertex to normal, or -1 if not available */
84 private int norOffset;
85 /** The offset within an vertex to color, or -1 if not available */
86 private int colOffset;
87 /** The size (in number of floats) of the color attribute */
89 /** The offset within an vertex to packed color, or -1 if not available */
91 /** The offset within an vertex to texture coordinates, or -1 if not available */
93 /** The meshpart currently being created */
94 private MeshPart part;
95 /** The parts created between begin and end */
96 private Array<MeshPart> parts = new Array<MeshPart>();
97 /** The color used if no vertex color is specified. */
98 private final Color color = new Color();
99 /** Whether to apply the default color. */
100 private boolean colorSet;
101 /** The current primitiveType */
102 private int primitiveType;
103 // FIXME makes this configurable
104 private float uMin = 0, uMax = 1, vMin = 0, vMax = 1;
105 private float[] vertex;
107 /** @param usage bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage},
108 * only Position, Color, Normal and TextureCoordinates is supported. */
109 public static VertexAttributes createAttributes(long usage) {
110 final Array<VertexAttribute> attrs = new Array<VertexAttribute>();
111 if ((usage & Usage.Position) == Usage.Position)
112 attrs.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE));
113 if ((usage & Usage.Color) == Usage.Color)
114 attrs.add(new VertexAttribute(Usage.Color, 4, ShaderProgram.COLOR_ATTRIBUTE));
115 if ((usage & Usage.Normal) == Usage.Normal)
116 attrs.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE));
117 if ((usage & Usage.TextureCoordinates) == Usage.TextureCoordinates)
118 attrs.add(new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE+"0"));
119 final VertexAttribute attributes[] = new VertexAttribute[attrs.size];
120 for (int i = 0; i < attributes.length; i++)
121 attributes[i] = attrs.get(i);
122 return new VertexAttributes(attributes);
125 /** Begin building a mesh. Call {@link #part(String, int)} to start a {@link MeshPart}.
126 * @param attributes bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage},
127 * only Position, Color, Normal and TextureCoordinates is supported. */
128 public void begin(final long attributes) {
129 begin(createAttributes(attributes), 0);
132 /** Begin building a mesh. Call {@link #part(String, int)} to start a {@link MeshPart}. */
133 public void begin(final VertexAttributes attributes) {
134 begin(attributes, 0);
137 /** Begin building a mesh.
138 * @param attributes bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage},
139 * only Position, Color, Normal and TextureCoordinates is supported. */
140 public void begin(final long attributes, int primitiveType) {
141 begin(createAttributes(attributes), primitiveType);
144 /** Begin building a mesh */
145 public void begin(final VertexAttributes attributes, int primitiveType) {
146 if (this.attributes != null)
147 throw new RuntimeException("Call end() first");
148 this.attributes = attributes;
149 this.vertices.clear();
150 this.indices.clear();
155 this.stride = attributes.vertexSize / 4;
156 this.vertex = new float[stride];
157 VertexAttribute a = attributes.findByUsage(Usage.Position);
159 throw new GdxRuntimeException("Cannot build mesh without position attribute");
160 posOffset = a.offset / 4;
161 posSize = a.numComponents;
162 a = attributes.findByUsage(Usage.Normal);
163 norOffset = a == null ? -1 : a.offset / 4;
164 a = attributes.findByUsage(Usage.Color);
165 colOffset = a == null ? -1 : a.offset / 4;
166 colSize = a == null ? 0 : a.numComponents;
167 a = attributes.findByUsage(Usage.ColorPacked);
168 cpOffset = a == null ? -1 : a.offset / 4;
169 a = attributes.findByUsage(Usage.TextureCoordinates);
170 uvOffset = a == null ? -1 : a.offset / 4;
172 this.primitiveType = primitiveType;
175 private void endpart() {
177 part.indexOffset = istart;
178 part.numVertices = indices.size - istart;
179 istart = indices.size;
184 /** Starts a new MeshPart. The mesh part is not usable until end() is called */
185 public MeshPart part(final String id, int primitiveType) {
186 if (this.attributes == null)
187 throw new RuntimeException("Call begin() first");
190 part = new MeshPart();
192 this.primitiveType = part.primitiveType = primitiveType;
200 /** End building the mesh and returns the mesh */
202 if (this.attributes == null)
203 throw new RuntimeException("Call begin() first");
206 final Mesh mesh = new Mesh(true, vertices.size, indices.size, attributes);
207 mesh.setVertices(vertices.items, 0, vertices.size);
208 mesh.setIndices(indices.items, 0, indices.size);
210 for (MeshPart p : parts)
222 public VertexAttributes getAttributes() {
227 public MeshPart getMeshPart() {
231 private final static Pool<Vector3> vectorPool = new Pool<Vector3>() {
233 protected Vector3 newObject () {
234 return new Vector3();
238 private final static Array<Vector3> vectorArray = new Array<Vector3>();
240 private Vector3 tmp(float x, float y, float z) {
241 final Vector3 result = vectorPool.obtain().set(x, y, z);
242 vectorArray.add(result);
246 private Vector3 tmp(Vector3 copyFrom) {
247 return tmp(copyFrom.x, copyFrom.y, copyFrom.z);
250 private void cleanup() {
251 vectorPool.freeAll(vectorArray);
256 public void setColor(float r, float g, float b, float a) {
257 color.set(r, g, b, a);
262 public void setColor(final Color color) {
263 if ((colorSet = color != null)==true)
264 this.color.set(color);
268 public void setUVRange(float u1, float v1, float u2, float v2) {
275 /** Increases the size of the backing vertices array to accommodate the specified number of additional vertices.
276 * Useful before adding many vertices to avoid multiple backing array resizes.
277 * @param numVertices The number of vertices you are about to add */
278 public void ensureVertices(int numVertices) {
279 vertices.ensureCapacity(vertex.length * numVertices);
282 /** Increases the size of the backing indices array to accommodate the specified number of additional indices.
283 * Useful before adding many indices to avoid multiple backing array resizes.
284 * @param numIndices The number of indices you are about to add */
285 public void ensureIndices(int numIndices) {
286 indices.ensureCapacity(numIndices);
289 /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
290 * vertices and indices. Useful before adding many vertices and indices to avoid multiple backing array resizes.
291 * @param numVertices The number of vertices you are about to add
292 * @param numIndices The number of indices you are about to add */
293 public void ensureCapacity(int numVertices, int numIndices) {
294 ensureVertices(numVertices);
295 ensureIndices(numIndices);
298 /** Increases the size of the backing indices array to accommodate the specified number of additional triangles.
299 * Useful before adding many triangles to avoid multiple backing array resizes.
300 * @param numTriangles The number of triangles you are about to add */
301 public void ensureTriangleIndices(int numTriangles) {
302 if (primitiveType == GL10.GL_LINES)
303 ensureIndices(6 * numTriangles);
304 else // GL_TRIANGLES || GL_POINTS
305 ensureIndices(3 * numTriangles);
308 /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
309 * vertices and triangles. Useful before adding many triangles to avoid multiple backing array resizes.
310 * @param numVertices The number of vertices you are about to add
311 * @param numTriangles The number of triangles you are about to add */
312 public void ensureTriangles(int numVertices, int numTriangles) {
313 ensureVertices(numVertices);
314 ensureTriangleIndices(numTriangles);
317 /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
318 * vertices and triangles. Useful before adding many triangles to avoid multiple backing array resizes.
319 * Assumes each triangles adds 3 vertices.
320 * @param numTriangles The number of triangles you are about to add */
321 public void ensureTriangles(int numTriangles) {
322 ensureTriangles(3 * numTriangles, numTriangles);
325 /** Increases the size of the backing indices array to accommodate the specified number of additional rectangles.
326 * Useful before adding many rectangles to avoid multiple backing array resizes.
327 * @param numRectangles The number of rectangles you are about to add */
328 public void ensureRectangleIndices(int numRectangles) {
329 if (primitiveType == GL10.GL_POINTS)
330 ensureIndices(4 * numRectangles);
331 else if (primitiveType == GL10.GL_LINES)
332 ensureIndices(8 * numRectangles);
334 ensureIndices(6 * numRectangles);
337 /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
338 * vertices and rectangles. Useful before adding many rectangles to avoid multiple backing array resizes.
339 * @param numVertices The number of vertices you are about to add
340 * @param numRectangles The number of rectangles you are about to add */
341 public void ensureRectangles(int numVertices, int numRectangles) {
342 ensureVertices(numVertices);
343 ensureRectangleIndices(numRectangles);
346 /** Increases the size of the backing vertices and indices arrays to accommodate the specified number of additional
347 * vertices and rectangles. Useful before adding many rectangles to avoid multiple backing array resizes.
348 * Assumes each rectangles adds 4 vertices
349 * @param numRectangles The number of rectangles you are about to add */
350 public void ensureRectangles(int numRectangles) {
351 ensureRectangles(4 * numRectangles, numRectangles);
355 public short vertex(Vector3 pos, Vector3 nor, Color col, Vector2 uv) {
356 if (vindex >= Short.MAX_VALUE)
357 throw new GdxRuntimeException("Too many vertices used");
358 if (col == null && colorSet)
361 vertex[posOffset ] = pos.x;
362 if (posSize > 1) vertex[posOffset+1] = pos.y;
363 if (posSize > 2) vertex[posOffset+2] = pos.z;
365 if (nor != null && norOffset >= 0) {
366 vertex[norOffset ] = nor.x;
367 vertex[norOffset+1] = nor.y;
368 vertex[norOffset+2] = nor.z;
371 if (colOffset >= 0) {
372 vertex[colOffset ] = col.r;
373 vertex[colOffset+1] = col.g;
374 vertex[colOffset+2] = col.b;
375 if (colSize > 3) vertex[colOffset+3] = col.a;
376 } else if (cpOffset > 0)
377 vertex[cpOffset] = col.toFloatBits(); // FIXME cache packed color?
379 if (uv != null && uvOffset >= 0) {
380 vertex[uvOffset ] = uv.x;
381 vertex[uvOffset+1] = uv.y;
383 vertices.addAll(vertex);
384 return (short)(vindex++);
388 public short lastIndex() {
389 return (short)(vindex-1);
393 public short vertex(final float... values) {
394 vertices.addAll(values);
395 vindex += values.length / stride;
396 return (short)(vindex-1);
400 public short vertex(final VertexInfo info) {
401 return vertex(info.hasPosition ? info.position : null, info.hasNormal ? info.normal : null,
402 info.hasColor ? info.color : null, info.hasUV ? info.uv : null);
406 public void index(final short value) {
411 public void index(final short value1, final short value2) {
418 public void index(final short value1, final short value2, final short value3) {
426 public void index(final short value1, final short value2, final short value3, final short value4) {
435 public void index(short value1, short value2, short value3, short value4, short value5, short value6) {
446 public void index(short value1, short value2, short value3, short value4, short value5, short value6, short value7, short value8) {
459 public void line(short index1, short index2) {
460 if (primitiveType != GL10.GL_LINES)
461 throw new GdxRuntimeException("Incorrect primitive type");
462 index(index1, index2);
466 public void line(VertexInfo p1, VertexInfo p2) {
468 line(vertex(p1), vertex(p2));
472 public void line(Vector3 p1, Vector3 p2) {
473 line(vertTmp1.set(p1, null, null, null), vertTmp2.set(p2, null, null, null));
477 public void line(float x1, float y1, float z1, float x2, float y2, float z2) {
478 line(vertTmp1.set(null, null, null, null).setPos(x1, y1, z1), vertTmp2.set(null, null, null, null).setPos(x2, y2, z2));
482 public void line(Vector3 p1, Color c1, Vector3 p2, Color c2) {
483 line(vertTmp1.set(p1, null, c1, null), vertTmp2.set(p2, null, c2, null));
487 public void triangle(short index1, short index2, short index3) {
488 if (primitiveType == GL10.GL_TRIANGLES || primitiveType == GL10.GL_POINTS) {
489 index(index1, index2, index3);
490 } else if (primitiveType == GL10.GL_LINES) {
491 index(index1, index2, index2, index3, index3, index1);
493 throw new GdxRuntimeException("Incorrect primitive type");
497 public void triangle(VertexInfo p1, VertexInfo p2, VertexInfo p3) {
499 triangle(vertex(p1), vertex(p2), vertex(p3));
503 public void triangle(Vector3 p1, Vector3 p2, Vector3 p3) {
504 triangle(vertTmp1.set(p1, null, null, null), vertTmp2.set(p2, null, null, null), vertTmp3.set(p3, null, null, null));
508 public void triangle(Vector3 p1, Color c1, Vector3 p2, Color c2, Vector3 p3, Color c3) {
509 triangle(vertTmp1.set(p1, null, c1, null), vertTmp2.set(p2, null, c2, null), vertTmp3.set(p3, null, c3, null));
513 public void rect(short corner00, short corner10, short corner11, short corner01) {
514 if (primitiveType == GL10.GL_TRIANGLES) {
515 index(corner00, corner10, corner11, corner11, corner01, corner00);
516 } else if (primitiveType == GL10.GL_LINES) {
517 index(corner00, corner10, corner10, corner11, corner11, corner01, corner01, corner00);
518 } else if (primitiveType == GL10.GL_POINTS) {
519 index(corner00, corner10, corner11, corner01);
521 throw new GdxRuntimeException("Incorrect primitive type");
525 public void rect(VertexInfo corner00, VertexInfo corner10, VertexInfo corner11, VertexInfo corner01) {
527 rect(vertex(corner00), vertex(corner10), vertex(corner11), vertex(corner01));
531 public void rect(Vector3 corner00, Vector3 corner10, Vector3 corner11, Vector3 corner01, Vector3 normal) {
532 rect(vertTmp1.set(corner00, normal, null, null).setUV(uMin,vMin),
533 vertTmp2.set(corner10, normal, null, null).setUV(uMax,vMin),
534 vertTmp3.set(corner11, normal, null, null).setUV(uMax,vMax),
535 vertTmp4.set(corner01, normal, null, null).setUV(uMin,vMax));
539 public void rect(float x00, float y00, float z00, float x10, float y10, float z10, float x11, float y11, float z11, float x01, float y01, float z01, float normalX, float normalY, float normalZ) {
540 rect(vertTmp1.set(null, null, null, null).setPos(x00,y00,z00).setNor(normalX,normalY,normalZ).setUV(uMin,vMin),
541 vertTmp2.set(null, null, null, null).setPos(x10,y10,z10).setNor(normalX,normalY,normalZ).setUV(uMax,vMin),
542 vertTmp3.set(null, null, null, null).setPos(x11,y11,z11).setNor(normalX,normalY,normalZ).setUV(uMax,vMax),
543 vertTmp4.set(null, null, null, null).setPos(x01,y01,z01).setNor(normalX,normalY,normalZ).setUV(uMin,vMax));
547 public void patch(VertexInfo corner00, VertexInfo corner10, VertexInfo corner11, VertexInfo corner01, int divisionsU, int divisionsV) {
548 ensureRectangles((divisionsV + 1) * (divisionsU + 1), divisionsV * divisionsU);
549 for (int u = 0; u <= divisionsU; u++) {
550 final float alphaU = (float)u / (float)divisionsU;
551 vertTmp5.set(corner00).lerp(corner10, alphaU);
552 vertTmp6.set(corner01).lerp(corner11, alphaU);
553 for (int v = 0; v <= divisionsV; v++) {
554 final short idx = vertex(vertTmp7.set(vertTmp5).lerp(vertTmp6, (float)v / (float)divisionsV));
556 rect((short)(idx-divisionsV-2), (short)(idx-1), idx, (short)(idx-divisionsV-1));
562 public void patch(Vector3 corner00, Vector3 corner10, Vector3 corner11, Vector3 corner01, Vector3 normal, int divisionsU, int divisionsV) {
563 patch(vertTmp1.set(corner00, normal, null, null).setUV(uMin,vMin),
564 vertTmp2.set(corner10, normal, null, null).setUV(uMax,vMin),
565 vertTmp3.set(corner11, normal, null, null).setUV(uMax,vMax),
566 vertTmp4.set(corner01, normal, null, null).setUV(uMin,vMax),
567 divisionsU, divisionsV);
570 public void patch(float x00, float y00, float z00, float x10, float y10, float z10, float x11, float y11, float z11, float x01, float y01, float z01, float normalX, float normalY, float normalZ, int divisionsU, int divisionsV) {
571 patch(vertTmp1.set(null).setPos(x00, y00, z00).setNor(normalX, normalY, normalZ).setUV(uMin,vMin),
572 vertTmp2.set(null).setPos(x10, y10, z10).setNor(normalX, normalY, normalZ).setUV(uMax,vMin),
573 vertTmp3.set(null).setPos(x11, y11, z11).setNor(normalX, normalY, normalZ).setUV(uMax,vMax),
574 vertTmp4.set(null).setPos(x01, y01, z01).setNor(normalX, normalY, normalZ).setUV(uMin,vMax),
575 divisionsU, divisionsV);
579 public void box(VertexInfo corner000, VertexInfo corner010, VertexInfo corner100, VertexInfo corner110,
580 VertexInfo corner001, VertexInfo corner011, VertexInfo corner101, VertexInfo corner111) {
582 final short i000 = vertex(corner000);
583 final short i100 = vertex(corner100);
584 final short i110 = vertex(corner110);
585 final short i010 = vertex(corner010);
586 final short i001 = vertex(corner001);
587 final short i101 = vertex(corner101);
588 final short i111 = vertex(corner111);
589 final short i011 = vertex(corner011);
591 if (primitiveType == GL10.GL_LINES) {
593 rect(i000, i100, i110, i010);
594 rect(i101, i001, i011, i111);
595 index(i000, i001, i010, i011, i110, i111, i100, i101);
596 } else if (primitiveType != GL10.GL_POINTS) {
597 ensureRectangleIndices(2);
598 rect(i000, i100, i110, i010);
599 rect(i101, i001, i011, i111);
600 } else { // GL10.GL_TRIANGLES
601 ensureRectangleIndices(6);
602 rect(i000, i100, i110, i010);
603 rect(i101, i001, i011, i111);
604 rect(i000, i010, i011, i001);
605 rect(i101, i111, i110, i100);
606 rect(i101, i100, i000, i001);
607 rect(i110, i111, i011, i010);
612 public void box(Vector3 corner000, Vector3 corner010, Vector3 corner100, Vector3 corner110,
613 Vector3 corner001, Vector3 corner011, Vector3 corner101, Vector3 corner111) {
614 if (norOffset < 0 && uvOffset < 0) {
615 box(vertTmp1.set(corner000, null, null, null), vertTmp2.set(corner010, null, null, null),
616 vertTmp3.set(corner100, null, null, null), vertTmp4.set(corner110, null, null, null),
617 vertTmp5.set(corner001, null, null, null), vertTmp6.set(corner011, null, null, null),
618 vertTmp7.set(corner101, null, null, null), vertTmp8.set(corner111, null, null, null));
621 Vector3 nor = tempV1.set(corner000).lerp(corner110, 0.5f).sub(tempV2.set(corner001).lerp(corner111, 0.5f)).nor();
622 rect(corner000, corner010, corner110, corner100, nor);
623 rect(corner011, corner001, corner101, corner111, nor.scl(-1));
624 nor = tempV1.set(corner000).lerp(corner101, 0.5f).sub(tempV2.set(corner010).lerp(corner111, 0.5f)).nor();
625 rect(corner001, corner000, corner100, corner101, nor);
626 rect(corner010, corner011, corner111, corner110, nor.scl(-1));
627 nor = tempV1.set(corner000).lerp(corner011, 0.5f).sub(tempV2.set(corner100).lerp(corner111, 0.5f)).nor();
628 rect(corner001, corner011, corner010, corner000, nor);
629 rect(corner100, corner110, corner111, corner101, nor.scl(-1));
634 public void box(Matrix4 transform) {
635 box(tmp(-0.5f,-0.5f,-0.5f).mul(transform),tmp(-0.5f,0.5f,-0.5f).mul(transform),tmp(0.5f,-0.5f,-0.5f).mul(transform),tmp(0.5f,0.5f,-0.5f).mul(transform),
636 tmp(-0.5f,-0.5f,0.5f).mul(transform),tmp(-0.5f,0.5f,0.5f).mul(transform),tmp(0.5f,-0.5f,0.5f).mul(transform),tmp(0.5f,0.5f,0.5f).mul(transform));
641 public void box(float width, float height, float depth) {
642 box(matTmp1.setToScaling(width, height, depth));
646 public void box(float x, float y, float z, float width, float height, float depth) {
647 box(matTmp1.setToScaling(width, height, depth).trn(x, y, z));
651 public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ) {
652 circle(radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, 0f, 360f);
656 public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal) {
657 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z);
661 public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal) {
662 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z);
666 public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ) {
667 circle(radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, 0f, 360f);
671 public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float angleFrom, float angleTo) {
672 ellipse(radius * 2f, radius * 2f, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, angleFrom, angleTo);
676 public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal, float angleFrom, float angleTo) {
677 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, angleFrom, angleTo);
681 public void circle(float radius, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal, float angleFrom, float angleTo) {
682 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z, angleFrom, angleTo);
686 public void circle(float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ, float angleFrom, float angleTo) {
687 ellipse(radius*2, radius*2, 0, 0, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, angleFrom, angleTo);
691 public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ) {
\r
692 ellipse(width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, 0f, 360f);
\r
696 public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal) {
\r
697 ellipse(width, height, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z);
\r
701 public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal) {
\r
702 ellipse(width, height, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z);
\r
706 public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ) {
\r
707 ellipse(width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, 0f, 360f);
\r
711 public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float angleFrom, float angleTo) {
\r
712 ellipse(width, height, 0f, 0f, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, angleFrom, angleTo);
\r
716 public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal, float angleFrom, float angleTo) {
\r
717 ellipse(width, height, 0f, 0f, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, angleFrom, angleTo);
\r
721 public void ellipse(float width, float height, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, final Vector3 binormal, float angleFrom, float angleTo) {
\r
722 ellipse(width, height, 0f, 0f, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z, angleFrom, angleTo);
\r
726 public void ellipse(float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ, float angleFrom, float angleTo) {
\r
727 ellipse(width, height, 0f, 0f, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, angleFrom, angleTo);
\r
731 public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, Vector3 center, Vector3 normal) {
732 ellipse(width, height, innerWidth, innerHeight, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, 0f, 360f);
736 public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ) {
737 ellipse(width, height, innerWidth, innerHeight, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, 0f, 360f);
741 public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float angleFrom, float angleTo) {
\r
742 tempV1.set(normalX, normalY, normalZ).crs(0, 0, 1);
743 tempV2.set(normalX, normalY, normalZ).crs(0, 1, 0);
744 if (tempV2.len2() > tempV1.len2())
746 tempV2.set(tempV1.nor()).crs(normalX, normalY, normalZ).nor();
747 ellipse(width, height, innerWidth, innerHeight, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tempV1.x, tempV1.y, tempV1.z, tempV2.x, tempV2.y, tempV2.z, angleFrom, angleTo);
751 public void ellipse(float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ, float angleFrom, float angleTo) {
752 if(innerWidth <= 0 || innerHeight <= 0) {
753 ensureTriangles(divisions + 2, divisions);
755 else if (innerWidth == width && innerHeight == height){
756 ensureVertices(divisions + 1);
757 ensureIndices(divisions + 1);
758 if(primitiveType != GL10.GL_LINES)
759 throw new GdxRuntimeException("Incorrect primitive type : expect GL_LINES because innerWidth == width && innerHeight == height");
762 ensureRectangles((divisions + 1)*2, divisions + 1);
765 final float ao = MathUtils.degreesToRadians * angleFrom;
766 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
767 final Vector3 sxEx = tempV1.set(tangentX, tangentY, tangentZ).scl(width * 0.5f);
768 final Vector3 syEx = tempV2.set(binormalX, binormalY, binormalZ).scl(height * 0.5f);
769 final Vector3 sxIn = tempV3.set(tangentX, tangentY, tangentZ).scl(innerWidth * 0.5f);
770 final Vector3 syIn = tempV4.set(binormalX, binormalY, binormalZ).scl(innerHeight * 0.5f);
771 VertexInfo currIn = vertTmp3.set(null, null, null, null);
772 currIn.hasUV = currIn.hasPosition = currIn.hasNormal = true;
\r
773 currIn.uv.set(.5f, .5f);
774 currIn.position.set(centerX, centerY, centerZ);
775 currIn.normal.set(normalX, normalY, normalZ);
776 VertexInfo currEx = vertTmp4.set(null, null, null, null);
777 currEx.hasUV = currEx.hasPosition = currEx.hasNormal = true;
\r
778 currEx.uv.set(.5f, .5f);
779 currEx.position.set(centerX, centerY, centerZ);
780 currEx.normal.set(normalX, normalY, normalZ);
781 final short center = vertex(currEx);
783 final float us = 0.5f * (innerWidth / width);
\r
784 final float vs = 0.5f * (innerHeight / height);
785 for (int i = 0; i <= divisions; i++) {
786 angle = ao + step * i;
787 final float x = MathUtils.cos(angle);
788 final float y = MathUtils.sin(angle);
789 currEx.position.set(centerX, centerY, centerZ).add(sxEx.x*x+syEx.x*y, sxEx.y*x+syEx.y*y, sxEx.z*x+syEx.z*y);
790 currEx.uv.set(.5f + .5f * x, .5f + .5f * y);
793 if(innerWidth <= 0f || innerHeight <= 0f) {
795 triangle((short)(vindex - 1), (short)(vindex - 2), center);
797 else if (innerWidth == width && innerHeight == height){
799 line((short)(vindex - 1), (short)(vindex - 2));
802 currIn.position.set(centerX, centerY, centerZ).add(sxIn.x*x+syIn.x*y, sxIn.y*x+syIn.y*y, sxIn.z*x+syIn.z*y);
803 currIn.uv.set(.5f + us * x, .5f + vs * y);
807 rect((short)(vindex - 1), (short)(vindex - 2),(short)(vindex - 4), (short)(vindex - 3));
813 public void cylinder(float width, float height, float depth, int divisions) {
814 cylinder(width, height, depth, divisions, 0, 360);
818 public void cylinder(float width, float height, float depth, int divisions, float angleFrom, float angleTo) {
819 cylinder(width, height, depth, divisions, angleFrom, angleTo, true);
822 /** Add a cylinder */
823 public void cylinder(float width, float height, float depth, int divisions, float angleFrom, float angleTo, boolean close) {
824 // FIXME create better cylinder method (- axis on which to create the cylinder (matrix?))
825 final float hw = width * 0.5f;
826 final float hh = height * 0.5f;
827 final float hd = depth * 0.5f;
828 final float ao = MathUtils.degreesToRadians * angleFrom;
829 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
830 final float us = 1f / divisions;
833 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
834 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
835 VertexInfo curr2 = vertTmp4.set(null, null, null, null);
836 curr2.hasUV = curr2.hasPosition = curr2.hasNormal = true;
838 ensureRectangles(2 * (divisions + 1), divisions);
839 for (int i = 0; i <= divisions; i++) {
840 angle = ao + step * i;
842 curr1.position.set(MathUtils.cos(angle) * hw, 0f, MathUtils.sin(angle) * hd);
843 curr1.normal.set(curr1.position).nor();
844 curr1.position.y = -hh;
846 curr2.position.set(curr1.position);
847 curr2.normal.set(curr1.normal);
848 curr2.position.y = hh;
853 rect((short)(vindex-3), (short)(vindex-1), (short)(vindex-2), (short)(vindex-4)); // FIXME don't duplicate lines and points
856 ellipse(width, depth, 0, 0, divisions, 0, hh, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, angleFrom, angleTo);
857 ellipse(width, depth, 0, 0, divisions, 0, -hh, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 180f-angleTo, 180f-angleFrom);
862 public void cone(float width, float height, float depth, int divisions) {
863 cone(width, height, depth, divisions, 0, 360);
867 public void cone(float width, float height, float depth, int divisions, float angleFrom, float angleTo) {
868 // FIXME create better cylinder method (- axis on which to create the cone (matrix?))
869 ensureTriangles(divisions + 2, divisions);
871 final float hw = width * 0.5f;
872 final float hh = height * 0.5f;
873 final float hd = depth * 0.5f;
874 final float ao = MathUtils.degreesToRadians * angleFrom;
875 final float step = (MathUtils.degreesToRadians * (angleTo - angleFrom)) / divisions;
876 final float us = 1f / divisions;
879 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
880 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
881 VertexInfo curr2 = vertTmp4.set(null, null, null, null).setPos(0,hh,0).setNor(0,1,0).setUV(0.5f, 0);
882 final int base = vertex(curr2);
883 for (int i = 0; i <= divisions; i++) {
884 angle = ao + step * i;
886 curr1.position.set(MathUtils.cos(angle) * hw, 0f, MathUtils.sin(angle) * hd);
887 curr1.normal.set(curr1.position).nor();
888 curr1.position.y = -hh;
893 triangle((short)base, (short)(vindex-1), (short)(vindex-2)); // FIXME don't duplicate lines and points
895 ellipse(width, depth, 0, 0, divisions, 0, -hh, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 180f-angleTo, 180f-angleFrom);
899 public void sphere(float width, float height, float depth, int divisionsU, int divisionsV) {
900 sphere(width, height, depth, divisionsU, divisionsV, 0, 360, 0, 180);
904 public void sphere(final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV) {
905 sphere(transform, width, height, depth, divisionsU, divisionsV, 0, 360, 0, 180);
909 public void sphere(float width, float height, float depth, int divisionsU, int divisionsV, float angleUFrom, float angleUTo, float angleVFrom, float angleVTo) {
910 sphere(matTmp1.idt(), width, height, depth, divisionsU, divisionsV, angleUFrom, angleUTo, angleVFrom, angleVTo);
914 public void sphere(final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV, float angleUFrom, float angleUTo, float angleVFrom, float angleVTo) {
915 // FIXME create better sphere method (- only one vertex for each pole, - position)
916 final float hw = width * 0.5f;
917 final float hh = height * 0.5f;
918 final float hd = depth * 0.5f;
919 final float auo = MathUtils.degreesToRadians * angleUFrom;
920 final float stepU = (MathUtils.degreesToRadians * (angleUTo - angleUFrom)) / divisionsU;
921 final float avo = MathUtils.degreesToRadians * angleVFrom;
922 final float stepV = (MathUtils.degreesToRadians * (angleVTo - angleVFrom)) / divisionsV;
923 final float us = 1f / divisionsU;
924 final float vs = 1f / divisionsV;
929 VertexInfo curr1 = vertTmp3.set(null, null, null, null);
930 curr1.hasUV = curr1.hasPosition = curr1.hasNormal = true;
932 ensureRectangles((divisionsV + 1) * (divisionsU + 1), divisionsV * divisionsU);
933 for (int iv = 0; iv <= divisionsV; iv++) {
934 angleV = avo + stepV * iv;
936 final float t = MathUtils.sin(angleV);
937 final float h = MathUtils.cos(angleV) * hh;
938 for (int iu = 0; iu <= divisionsU; iu++) {
939 angleU = auo + stepU * iu;
941 curr1.position.set(MathUtils.cos(angleU) * hw * t, h, MathUtils.sin(angleU) * hd * t).mul(transform);
942 curr1.normal.set(curr1.position).nor();
945 if ((iv > 0) && (iu > 0)) // FIXME don't duplicate lines and points
946 rect((short)(vindex-1), (short)(vindex-2), (short)(vindex-(divisionsU+3)), (short)(vindex-(divisionsU+2)));
952 public void capsule(float radius, float height, int divisions) {
953 if (height < 2f * radius)
954 throw new GdxRuntimeException("Height must be at least twice the radius");
955 final float d = 2f * radius;
956 cylinder(d, height - d, d, divisions, 0, 360, false);
957 sphere(matTmp1.setToTranslation(0, .5f*(height-d), 0), d, d, d, divisions, divisions, 0, 360, 0, 90);
958 sphere(matTmp1.setToTranslation(0, -.5f*(height-d), 0), d, d, d, divisions, divisions, 0, 360, 90, 180);