1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.graphics.g3d.utils; 18 19 import com.badlogic.gdx.graphics.Color; 20 import com.badlogic.gdx.graphics.GL20; 21 import com.badlogic.gdx.graphics.Mesh; 22 import com.badlogic.gdx.graphics.VertexAttribute; 23 import com.badlogic.gdx.graphics.VertexAttributes; 24 import com.badlogic.gdx.graphics.VertexAttributes.Usage; 25 import com.badlogic.gdx.graphics.g2d.TextureRegion; 26 import com.badlogic.gdx.graphics.g3d.model.MeshPart; 27 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.ArrowShapeBuilder; 28 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.BoxShapeBuilder; 29 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.CapsuleShapeBuilder; 30 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.ConeShapeBuilder; 31 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.CylinderShapeBuilder; 32 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.EllipseShapeBuilder; 33 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.PatchShapeBuilder; 34 import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.SphereShapeBuilder; 35 import com.badlogic.gdx.graphics.glutils.ShaderProgram; 36 import com.badlogic.gdx.math.MathUtils; 37 import com.badlogic.gdx.math.Matrix3; 38 import com.badlogic.gdx.math.Matrix4; 39 import com.badlogic.gdx.math.Vector2; 40 import com.badlogic.gdx.math.Vector3; 41 import com.badlogic.gdx.math.collision.BoundingBox; 42 import com.badlogic.gdx.utils.Array; 43 import com.badlogic.gdx.utils.FloatArray; 44 import com.badlogic.gdx.utils.GdxRuntimeException; 45 import com.badlogic.gdx.utils.IntIntMap; 46 import com.badlogic.gdx.utils.NumberUtils; 47 import com.badlogic.gdx.utils.Pool; 48 import com.badlogic.gdx.utils.ShortArray; 49 50 /** Class to construct a mesh, optionally splitting it into one or more mesh parts. Before you can call any other method you must 51 * call {@link #begin(VertexAttributes)} or {@link #begin(VertexAttributes, int)}. To use mesh parts you must call 52 * {@link #part(String, int)} before you start building the part. The MeshPart itself is only valid after the call to 53 * {@link #end()}. 54 * @author Xoppa */ 55 public class MeshBuilder implements MeshPartBuilder { 56 private final static ShortArray tmpIndices = new ShortArray(); 57 private final static FloatArray tmpVertices = new FloatArray(); 58 59 private final VertexInfo vertTmp1 = new VertexInfo(); 60 private final VertexInfo vertTmp2 = new VertexInfo(); 61 private final VertexInfo vertTmp3 = new VertexInfo(); 62 private final VertexInfo vertTmp4 = new VertexInfo(); 63 64 private final Color tempC1 = new Color(); 65 66 /** The vertex attributes of the resulting mesh */ 67 private VertexAttributes attributes; 68 /** The vertices to construct, no size checking is done */ 69 private FloatArray vertices = new FloatArray(); 70 /** The indices to construct, no size checking is done */ 71 private ShortArray indices = new ShortArray(); 72 /** The size (in number of floats) of each vertex */ 73 private int stride; 74 /** The current vertex index, used for indexing */ 75 private short vindex; 76 /** The offset in the indices array when begin() was called, used to define a meshpart. */ 77 private int istart; 78 /** The offset within an vertex to position */ 79 private int posOffset; 80 /** The size (in number of floats) of the position attribute */ 81 private int posSize; 82 /** The offset within an vertex to normal, or -1 if not available */ 83 private int norOffset; 84 /** The offset within a vertex to binormal, or -1 if not available */ 85 private int biNorOffset; 86 /** The offset within a vertex to tangent, or -1 if not available */ 87 private int tangentOffset; 88 /** The offset within an vertex to color, or -1 if not available */ 89 private int colOffset; 90 /** The size (in number of floats) of the color attribute */ 91 private int colSize; 92 /** The offset within an vertex to packed color, or -1 if not available */ 93 private int cpOffset; 94 /** The offset within an vertex to texture coordinates, or -1 if not available */ 95 private int uvOffset; 96 /** The meshpart currently being created */ 97 private MeshPart part; 98 /** The parts created between begin and end */ 99 private Array<MeshPart> parts = new Array<MeshPart>(); 100 /** The color used if no vertex color is specified. */ 101 private final Color color = new Color(Color.WHITE); 102 private boolean hasColor = false; 103 /** The current primitiveType */ 104 private int primitiveType; 105 /** The UV range used when building */ 106 private float uOffset = 0f, uScale = 1f, vOffset = 0f, vScale = 1f; 107 private boolean hasUVTransform = false; 108 private float[] vertex; 109 110 private boolean vertexTransformationEnabled = false; 111 private final Matrix4 positionTransform = new Matrix4(); 112 private final Matrix3 normalTransform = new Matrix3(); 113 private final BoundingBox bounds = new BoundingBox(); 114 115 /** @param usage bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage}, only Position, Color, Normal and 116 * TextureCoordinates is supported. */ 117 public static VertexAttributes createAttributes (long usage) { 118 final Array<VertexAttribute> attrs = new Array<VertexAttribute>(); 119 if ((usage & Usage.Position) == Usage.Position) 120 attrs.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE)); 121 if ((usage & Usage.ColorUnpacked) == Usage.ColorUnpacked) 122 attrs.add(new VertexAttribute(Usage.ColorUnpacked, 4, ShaderProgram.COLOR_ATTRIBUTE)); 123 if ((usage & Usage.ColorPacked) == Usage.ColorPacked) 124 attrs.add(new VertexAttribute(Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE)); 125 if ((usage & Usage.Normal) == Usage.Normal) 126 attrs.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE)); 127 if ((usage & Usage.TextureCoordinates) == Usage.TextureCoordinates) 128 attrs.add(new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE + "0")); 129 final VertexAttribute attributes[] = new VertexAttribute[attrs.size]; 130 for (int i = 0; i < attributes.length; i++) 131 attributes[i] = attrs.get(i); 132 return new VertexAttributes(attributes); 133 } 134 135 /** Begin building a mesh. Call {@link #part(String, int)} to start a {@link MeshPart}. 136 * @param attributes bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage}, only Position, Color, Normal 137 * and TextureCoordinates is supported. */ 138 public void begin (final long attributes) { 139 begin(createAttributes(attributes), -1); 140 } 141 142 /** Begin building a mesh. Call {@link #part(String, int)} to start a {@link MeshPart}. */ 143 public void begin (final VertexAttributes attributes) { 144 begin(attributes, -1); 145 } 146 147 /** Begin building a mesh. 148 * @param attributes bitwise mask of the {@link com.badlogic.gdx.graphics.VertexAttributes.Usage}, only Position, Color, Normal 149 * and TextureCoordinates is supported. */ 150 public void begin (final long attributes, int primitiveType) { 151 begin(createAttributes(attributes), primitiveType); 152 } 153 154 /** Begin building a mesh */ 155 public void begin (final VertexAttributes attributes, int primitiveType) { 156 if (this.attributes != null) throw new RuntimeException("Call end() first"); 157 this.attributes = attributes; 158 this.vertices.clear(); 159 this.indices.clear(); 160 this.parts.clear(); 161 this.vindex = 0; 162 this.lastIndex = -1; 163 this.istart = 0; 164 this.part = null; 165 this.stride = attributes.vertexSize / 4; 166 if (this.vertex == null || this.vertex.length < stride) this.vertex = new float[stride]; 167 VertexAttribute a = attributes.findByUsage(Usage.Position); 168 if (a == null) throw new GdxRuntimeException("Cannot build mesh without position attribute"); 169 posOffset = a.offset / 4; 170 posSize = a.numComponents; 171 a = attributes.findByUsage(Usage.Normal); 172 norOffset = a == null ? -1 : a.offset / 4; 173 a = attributes.findByUsage(Usage.BiNormal); 174 biNorOffset = a == null ? -1 : a.offset / 4; 175 a = attributes.findByUsage(Usage.Tangent); 176 tangentOffset = a == null ? -1 : a.offset / 4; 177 a = attributes.findByUsage(Usage.ColorUnpacked); 178 colOffset = a == null ? -1 : a.offset / 4; 179 colSize = a == null ? 0 : a.numComponents; 180 a = attributes.findByUsage(Usage.ColorPacked); 181 cpOffset = a == null ? -1 : a.offset / 4; 182 a = attributes.findByUsage(Usage.TextureCoordinates); 183 uvOffset = a == null ? -1 : a.offset / 4; 184 setColor(null); 185 setVertexTransform(null); 186 setUVRange(null); 187 this.primitiveType = primitiveType; 188 bounds.inf(); 189 } 190 191 private void endpart () { 192 if (part != null) { 193 bounds.getCenter(part.center); 194 bounds.getDimensions(part.halfExtents).scl(0.5f); 195 part.radius = part.halfExtents.len(); 196 bounds.inf(); 197 part.offset = istart; 198 part.size = indices.size - istart; 199 istart = indices.size; 200 part = null; 201 } 202 } 203 204 /** Starts a new MeshPart. The mesh part is not usable until end() is called. This will reset the current color and vertex 205 * transformation. 206 * @see #part(String, int, MeshPart) */ 207 public MeshPart part (final String id, int primitiveType) { 208 return part(id, primitiveType, new MeshPart()); 209 } 210 211 /** Starts a new MeshPart. The mesh part is not usable until end() is called. This will reset the current color and vertex 212 * transformation. 213 * @param id The id (name) of the part 214 * @param primitiveType e.g. {@link GL20#GL_TRIANGLES} or {@link GL20#GL_LINES} 215 * @param meshPart The part to receive the result */ 216 public MeshPart part (final String id, final int primitiveType, MeshPart meshPart) { 217 if (this.attributes == null) throw new RuntimeException("Call begin() first"); 218 endpart(); 219 220 part = meshPart; 221 part.id = id; 222 this.primitiveType = part.primitiveType = primitiveType; 223 parts.add(part); 224 225 setColor(null); 226 setVertexTransform(null); 227 setUVRange(null); 228 229 return part; 230 } 231 232 /** End building the mesh and returns the mesh 233 * @param mesh The mesh to receive the built vertices and indices, must have the same attributes and must be big enough to hold 234 * the data, any existing data will be overwritten. */ 235 public Mesh end (Mesh mesh) { 236 endpart(); 237 238 if (attributes == null) throw new GdxRuntimeException("Call begin() first"); 239 if (!attributes.equals(mesh.getVertexAttributes())) throw new GdxRuntimeException("Mesh attributes don't match"); 240 if ((mesh.getMaxVertices() * stride) < vertices.size) 241 throw new GdxRuntimeException("Mesh can't hold enough vertices: " + mesh.getMaxVertices() + " * " + stride + " < " 242 + vertices.size); 243 if (mesh.getMaxIndices() < indices.size) 244 throw new GdxRuntimeException("Mesh can't hold enough indices: " + mesh.getMaxIndices() + " < " + indices.size); 245 246 mesh.setVertices(vertices.items, 0, vertices.size); 247 mesh.setIndices(indices.items, 0, indices.size); 248 249 for (MeshPart p : parts) 250 p.mesh = mesh; 251 parts.clear(); 252 253 attributes = null; 254 vertices.clear(); 255 indices.clear(); 256 257 return mesh; 258 } 259 260 /** End building the mesh and returns the mesh */ 261 public Mesh end () { 262 return end(new Mesh(true, vertices.size / stride, indices.size, attributes)); 263 } 264 265 /** Clears the data being built up until now, including the vertices, indices and all parts. Must be called in between the call 266 * to #begin and #end. Any builder calls made from the last call to #begin up until now are practically discarded. The state 267 * (e.g. UV region, color, vertex transform) will remain unchanged. */ 268 public void clear () { 269 this.vertices.clear(); 270 this.indices.clear(); 271 this.parts.clear(); 272 this.vindex = 0; 273 this.lastIndex = -1; 274 this.istart = 0; 275 this.part = null; 276 } 277 278 /** @return the size in number of floats of one vertex, multiply by four to get the size in bytes. */ 279 public int getFloatsPerVertex () { 280 return stride; 281 } 282 283 /** @return The number of vertices built up until now, only valid in between the call to begin() and end(). */ 284 public int getNumVertices () { 285 return vertices.size / stride; 286 } 287 288 /** Get a copy of the vertices built so far. 289 * @param out The float array to receive the copy of the vertices, must be at least `destOffset` + {@link #getNumVertices()} * 290 * {@link #getFloatsPerVertex()} in size. 291 * @param destOffset The offset (number of floats) in the out array where to start copying */ 292 public void getVertices (float[] out, int destOffset) { 293 if (attributes == null) throw new GdxRuntimeException("Must be called in between #begin and #end"); 294 if ((destOffset < 0) || (destOffset > out.length - vertices.size)) 295 throw new GdxRuntimeException("Array to small or offset out of range"); 296 System.arraycopy(vertices.items, 0, out, destOffset, vertices.size); 297 } 298 299 /** Provides direct access to the vertices array being built, use with care. The size of the array might be bigger, do not rely 300 * on the length of the array. Instead use {@link #getFloatsPerVertex()} * {@link #getNumVertices()} to calculate the usable 301 * size of the array. Must be called in between the call to #begin and #end. */ 302 protected float[] getVertices () { 303 return vertices.items; 304 } 305 306 /** @return The number of indices built up until now, only valid in between the call to begin() and end(). */ 307 public int getNumIndices () { 308 return indices.size; 309 } 310 311 /** Get a copy of the indices built so far. 312 * @param out The short array to receive the copy of the indices, must be at least `destOffset` + {@link #getNumIndices()} in 313 * size. 314 * @param destOffset The offset (number of shorts) in the out array where to start copying */ 315 public void getIndices (short[] out, int destOffset) { 316 if (attributes == null) throw new GdxRuntimeException("Must be called in between #begin and #end"); 317 if ((destOffset < 0) || (destOffset > out.length - indices.size)) 318 throw new GdxRuntimeException("Array to small or offset out of range"); 319 System.arraycopy(indices.items, 0, out, destOffset, indices.size); 320 } 321 322 /** Provides direct access to the indices array being built, use with care. The size of the array might be bigger, do not rely 323 * on the length of the array. Instead use {@link #getNumIndices()} to calculate the usable size of the array. Must be called 324 * in between the call to #begin and #end. */ 325 protected short[] getIndices () { 326 return indices.items; 327 } 328 329 @Override 330 public VertexAttributes getAttributes () { 331 return attributes; 332 } 333 334 @Override 335 public MeshPart getMeshPart () { 336 return part; 337 } 338 339 @Override 340 public int getPrimitiveType () { 341 return primitiveType; 342 } 343 344 @Override 345 public void setColor (float r, float g, float b, float a) { 346 color.set(r, g, b, a); 347 hasColor = !color.equals(Color.WHITE); 348 } 349 350 @Override 351 public void setColor (final Color color) { 352 this.color.set(!(hasColor = (color != null)) ? Color.WHITE : color); 353 } 354 355 @Override 356 public void setUVRange (float u1, float v1, float u2, float v2) { 357 uOffset = u1; 358 vOffset = v1; 359 uScale = u2 - u1; 360 vScale = v2 - v1; 361 hasUVTransform = !(MathUtils.isZero(u1) && MathUtils.isZero(v1) && MathUtils.isEqual(u2, 1f) && MathUtils.isEqual(v2, 1f)); 362 } 363 364 @Override 365 public void setUVRange (TextureRegion region) { 366 if (!(hasUVTransform = (region != null))) { 367 uOffset = vOffset = 0f; 368 uScale = vScale = 1f; 369 } else 370 setUVRange(region.getU(), region.getV(), region.getU2(), region.getV2()); 371 } 372 373 @Override 374 public Matrix4 getVertexTransform (Matrix4 out) { 375 return out.set(positionTransform); 376 } 377 378 @Override 379 public void setVertexTransform (Matrix4 transform) { 380 if ((vertexTransformationEnabled = (transform != null)) == true) { 381 positionTransform.set(transform); 382 normalTransform.set(transform).inv().transpose(); 383 } else { 384 positionTransform.idt(); 385 normalTransform.idt(); 386 } 387 } 388 389 @Override 390 public boolean isVertexTransformationEnabled () { 391 return vertexTransformationEnabled; 392 } 393 394 @Override 395 public void setVertexTransformationEnabled (boolean enabled) { 396 vertexTransformationEnabled = enabled; 397 } 398 399 @Override 400 public void ensureVertices (int numVertices) { 401 vertices.ensureCapacity(stride * numVertices); 402 } 403 404 @Override 405 public void ensureIndices (int numIndices) { 406 indices.ensureCapacity(numIndices); 407 } 408 409 @Override 410 public void ensureCapacity (int numVertices, int numIndices) { 411 ensureVertices(numVertices); 412 ensureIndices(numIndices); 413 } 414 415 @Override 416 public void ensureTriangleIndices (int numTriangles) { 417 if (primitiveType == GL20.GL_LINES) 418 ensureIndices(6 * numTriangles); 419 else if (primitiveType == GL20.GL_TRIANGLES || primitiveType == GL20.GL_POINTS) 420 ensureIndices(3 * numTriangles); 421 else 422 throw new GdxRuntimeException("Incorrect primtive type"); 423 } 424 425 /** @deprecated use {@link #ensureVertices(int)} followed by {@link #ensureTriangleIndices(int)} instead. */ 426 @Deprecated 427 public void ensureTriangles (int numVertices, int numTriangles) { 428 ensureVertices(numVertices); 429 ensureTriangleIndices(numTriangles); 430 } 431 432 /** @deprecated use {@link #ensureVertices(int)} followed by {@link #ensureTriangleIndices(int)} instead. */ 433 @Deprecated 434 public void ensureTriangles (int numTriangles) { 435 ensureVertices(3 * numTriangles); 436 ensureTriangleIndices(numTriangles); 437 } 438 439 @Override 440 public void ensureRectangleIndices (int numRectangles) { 441 if (primitiveType == GL20.GL_POINTS) 442 ensureIndices(4 * numRectangles); 443 else if (primitiveType == GL20.GL_LINES) 444 ensureIndices(8 * numRectangles); 445 else 446 // GL_TRIANGLES 447 ensureIndices(6 * numRectangles); 448 } 449 450 /** @deprecated use {@link #ensureVertices(int)} followed by {@link #ensureRectangleIndices(int)} instead. */ 451 @Deprecated 452 public void ensureRectangles (int numVertices, int numRectangles) { 453 ensureVertices(numVertices); 454 ensureRectangleIndices(numRectangles); 455 } 456 457 /** @deprecated use {@link #ensureVertices(int)} followed by {@link #ensureRectangleIndices(int)} instead. */ 458 public void ensureRectangles (int numRectangles) { 459 ensureVertices(4 * numRectangles); 460 ensureRectangleIndices(numRectangles); 461 } 462 463 private short lastIndex = -1; 464 465 @Override 466 public short lastIndex () { 467 return lastIndex; 468 } 469 470 private final static Vector3 vTmp = new Vector3(); 471 472 private final static void transformPosition (final float[] values, final int offset, final int size, Matrix4 transform) { 473 if (size > 2) { 474 vTmp.set(values[offset], values[offset + 1], values[offset + 2]).mul(transform); 475 values[offset] = vTmp.x; 476 values[offset + 1] = vTmp.y; 477 values[offset + 2] = vTmp.z; 478 } else if (size > 1) { 479 vTmp.set(values[offset], values[offset + 1], 0).mul(transform); 480 values[offset] = vTmp.x; 481 values[offset + 1] = vTmp.y; 482 } else 483 values[offset] = vTmp.set(values[offset], 0, 0).mul(transform).x; 484 } 485 486 private final static void transformNormal (final float[] values, final int offset, final int size, Matrix3 transform) { 487 if (size > 2) { 488 vTmp.set(values[offset], values[offset + 1], values[offset + 2]).mul(transform).nor(); 489 values[offset] = vTmp.x; 490 values[offset + 1] = vTmp.y; 491 values[offset + 2] = vTmp.z; 492 } else if (size > 1) { 493 vTmp.set(values[offset], values[offset + 1], 0).mul(transform).nor(); 494 values[offset] = vTmp.x; 495 values[offset + 1] = vTmp.y; 496 } else 497 values[offset] = vTmp.set(values[offset], 0, 0).mul(transform).nor().x; 498 } 499 500 private final void addVertex (final float[] values, final int offset) { 501 final int o = vertices.size; 502 vertices.addAll(values, offset, stride); 503 lastIndex = (short)(vindex++); 504 505 if (vertexTransformationEnabled) { 506 transformPosition(vertices.items, o + posOffset, posSize, positionTransform); 507 if (norOffset >= 0) transformNormal(vertices.items, o + norOffset, 3, normalTransform); 508 if (biNorOffset >= 0) transformNormal(vertices.items, o + biNorOffset, 3, normalTransform); 509 if (tangentOffset >= 0) transformNormal(vertices.items, o + tangentOffset, 3, normalTransform); 510 } 511 512 final float x = vertices.items[o + posOffset]; 513 final float y = (posSize > 1) ? vertices.items[o + posOffset + 1] : 0f; 514 final float z = (posSize > 2) ? vertices.items[o + posOffset + 2] : 0f; 515 bounds.ext(x, y, z); 516 517 if (hasColor) { 518 if (colOffset >= 0) { 519 vertices.items[o + colOffset] *= color.r; 520 vertices.items[o + colOffset + 1] *= color.g; 521 vertices.items[o + colOffset + 2] *= color.b; 522 if (colSize > 3) vertices.items[o + colOffset + 3] *= color.a; 523 } else if (cpOffset >= 0) { 524 vertices.items[o + cpOffset] = tempC1.set(NumberUtils.floatToIntColor(vertices.items[o + cpOffset])).mul(color) 525 .toFloatBits(); 526 } 527 } 528 529 if (hasUVTransform && uvOffset >= 0) { 530 vertices.items[o + uvOffset] = uOffset + uScale * vertices.items[o + uvOffset]; 531 vertices.items[o + uvOffset + 1] = vOffset + vScale * vertices.items[o + uvOffset + 1]; 532 } 533 } 534 535 private final Vector3 tmpNormal = new Vector3(); 536 537 @Override 538 public short vertex (Vector3 pos, Vector3 nor, Color col, Vector2 uv) { 539 if (vindex >= Short.MAX_VALUE) throw new GdxRuntimeException("Too many vertices used"); 540 541 vertex[posOffset] = pos.x; 542 if (posSize > 1) vertex[posOffset + 1] = pos.y; 543 if (posSize > 2) vertex[posOffset + 2] = pos.z; 544 545 if (norOffset >= 0) { 546 if (nor == null) nor = tmpNormal.set(pos).nor(); 547 vertex[norOffset] = nor.x; 548 vertex[norOffset + 1] = nor.y; 549 vertex[norOffset + 2] = nor.z; 550 } 551 552 if (colOffset >= 0) { 553 if (col == null) col = Color.WHITE; 554 vertex[colOffset] = col.r; 555 vertex[colOffset + 1] = col.g; 556 vertex[colOffset + 2] = col.b; 557 if (colSize > 3) vertex[colOffset + 3] = col.a; 558 } else if (cpOffset > 0) { 559 if (col == null) col = Color.WHITE; 560 vertex[cpOffset] = col.toFloatBits(); // FIXME cache packed color? 561 } 562 563 if (uv != null && uvOffset >= 0) { 564 vertex[uvOffset] = uv.x; 565 vertex[uvOffset + 1] = uv.y; 566 } 567 568 addVertex(vertex, 0); 569 return lastIndex; 570 } 571 572 @Override 573 public short vertex (final float... values) { 574 final int n = values.length - stride; 575 for (int i = 0; i <= n; i += stride) 576 addVertex(values, i); 577 return lastIndex; 578 } 579 580 @Override 581 public short vertex (final VertexInfo info) { 582 return vertex(info.hasPosition ? info.position : null, info.hasNormal ? info.normal : null, info.hasColor ? info.color 583 : null, info.hasUV ? info.uv : null); 584 } 585 586 @Override 587 public void index (final short value) { 588 indices.add(value); 589 } 590 591 @Override 592 public void index (final short value1, final short value2) { 593 ensureIndices(2); 594 indices.add(value1); 595 indices.add(value2); 596 } 597 598 @Override 599 public void index (final short value1, final short value2, final short value3) { 600 ensureIndices(3); 601 indices.add(value1); 602 indices.add(value2); 603 indices.add(value3); 604 } 605 606 @Override 607 public void index (final short value1, final short value2, final short value3, final short value4) { 608 ensureIndices(4); 609 indices.add(value1); 610 indices.add(value2); 611 indices.add(value3); 612 indices.add(value4); 613 } 614 615 @Override 616 public void index (short value1, short value2, short value3, short value4, short value5, short value6) { 617 ensureIndices(6); 618 indices.add(value1); 619 indices.add(value2); 620 indices.add(value3); 621 indices.add(value4); 622 indices.add(value5); 623 indices.add(value6); 624 } 625 626 @Override 627 public void index (short value1, short value2, short value3, short value4, short value5, short value6, short value7, 628 short value8) { 629 ensureIndices(8); 630 indices.add(value1); 631 indices.add(value2); 632 indices.add(value3); 633 indices.add(value4); 634 indices.add(value5); 635 indices.add(value6); 636 indices.add(value7); 637 indices.add(value8); 638 } 639 640 @Override 641 public void line (short index1, short index2) { 642 if (primitiveType != GL20.GL_LINES) throw new GdxRuntimeException("Incorrect primitive type"); 643 index(index1, index2); 644 } 645 646 @Override 647 public void line (VertexInfo p1, VertexInfo p2) { 648 ensureVertices(2); 649 line(vertex(p1), vertex(p2)); 650 } 651 652 @Override 653 public void line (Vector3 p1, Vector3 p2) { 654 line(vertTmp1.set(p1, null, null, null), vertTmp2.set(p2, null, null, null)); 655 } 656 657 @Override 658 public void line (float x1, float y1, float z1, float x2, float y2, float z2) { 659 line(vertTmp1.set(null, null, null, null).setPos(x1, y1, z1), vertTmp2.set(null, null, null, null).setPos(x2, y2, z2)); 660 } 661 662 @Override 663 public void line (Vector3 p1, Color c1, Vector3 p2, Color c2) { 664 line(vertTmp1.set(p1, null, c1, null), vertTmp2.set(p2, null, c2, null)); 665 } 666 667 @Override 668 public void triangle (short index1, short index2, short index3) { 669 if (primitiveType == GL20.GL_TRIANGLES || primitiveType == GL20.GL_POINTS) { 670 index(index1, index2, index3); 671 } else if (primitiveType == GL20.GL_LINES) { 672 index(index1, index2, index2, index3, index3, index1); 673 } else 674 throw new GdxRuntimeException("Incorrect primitive type"); 675 } 676 677 @Override 678 public void triangle (VertexInfo p1, VertexInfo p2, VertexInfo p3) { 679 ensureVertices(3); 680 triangle(vertex(p1), vertex(p2), vertex(p3)); 681 } 682 683 @Override 684 public void triangle (Vector3 p1, Vector3 p2, Vector3 p3) { 685 triangle(vertTmp1.set(p1, null, null, null), vertTmp2.set(p2, null, null, null), vertTmp3.set(p3, null, null, null)); 686 } 687 688 @Override 689 public void triangle (Vector3 p1, Color c1, Vector3 p2, Color c2, Vector3 p3, Color c3) { 690 triangle(vertTmp1.set(p1, null, c1, null), vertTmp2.set(p2, null, c2, null), vertTmp3.set(p3, null, c3, null)); 691 } 692 693 @Override 694 public void rect (short corner00, short corner10, short corner11, short corner01) { 695 if (primitiveType == GL20.GL_TRIANGLES) { 696 index(corner00, corner10, corner11, corner11, corner01, corner00); 697 } else if (primitiveType == GL20.GL_LINES) { 698 index(corner00, corner10, corner10, corner11, corner11, corner01, corner01, corner00); 699 } else if (primitiveType == GL20.GL_POINTS) { 700 index(corner00, corner10, corner11, corner01); 701 } else 702 throw new GdxRuntimeException("Incorrect primitive type"); 703 } 704 705 @Override 706 public void rect (VertexInfo corner00, VertexInfo corner10, VertexInfo corner11, VertexInfo corner01) { 707 ensureVertices(4); 708 rect(vertex(corner00), vertex(corner10), vertex(corner11), vertex(corner01)); 709 } 710 711 @Override 712 public void rect (Vector3 corner00, Vector3 corner10, Vector3 corner11, Vector3 corner01, Vector3 normal) { 713 rect(vertTmp1.set(corner00, normal, null, null).setUV(0f, 1f), vertTmp2.set(corner10, normal, null, null).setUV(1f, 1f), 714 vertTmp3.set(corner11, normal, null, null).setUV(1f, 0f), vertTmp4.set(corner01, normal, null, null).setUV(0f, 0f)); 715 } 716 717 @Override 718 public void rect (float x00, float y00, float z00, float x10, float y10, float z10, float x11, float y11, float z11, 719 float x01, float y01, float z01, float normalX, float normalY, float normalZ) { 720 rect(vertTmp1.set(null, null, null, null).setPos(x00, y00, z00).setNor(normalX, normalY, normalZ).setUV(0f, 1f), vertTmp2 721 .set(null, null, null, null).setPos(x10, y10, z10).setNor(normalX, normalY, normalZ).setUV(1f, 1f), 722 vertTmp3.set(null, null, null, null).setPos(x11, y11, z11).setNor(normalX, normalY, normalZ).setUV(1f, 0f), vertTmp4 723 .set(null, null, null, null).setPos(x01, y01, z01).setNor(normalX, normalY, normalZ).setUV(0f, 0f)); 724 } 725 726 @Override 727 public void addMesh (Mesh mesh) { 728 addMesh(mesh, 0, mesh.getNumIndices()); 729 } 730 731 @Override 732 public void addMesh (MeshPart meshpart) { 733 if (meshpart.primitiveType != primitiveType) throw new GdxRuntimeException("Primitive type doesn't match"); 734 addMesh(meshpart.mesh, meshpart.offset, meshpart.size); 735 } 736 737 @Override 738 public void addMesh (Mesh mesh, int indexOffset, int numIndices) { 739 if (!attributes.equals(mesh.getVertexAttributes())) throw new GdxRuntimeException("Vertex attributes do not match"); 740 if (numIndices <= 0) return; // silently ignore an empty mesh part 741 742 // FIXME don't triple copy, instead move the copy to jni 743 int numFloats = mesh.getNumVertices() * stride; 744 tmpVertices.clear(); 745 tmpVertices.ensureCapacity(numFloats); 746 tmpVertices.size = numFloats; 747 mesh.getVertices(tmpVertices.items); 748 749 tmpIndices.clear(); 750 tmpIndices.ensureCapacity(numIndices); 751 tmpIndices.size = numIndices; 752 mesh.getIndices(indexOffset, numIndices, tmpIndices.items, 0); 753 754 addMesh(tmpVertices.items, tmpIndices.items, 0, numIndices); 755 } 756 757 private static IntIntMap indicesMap = null; 758 759 @Override 760 public void addMesh (float[] vertices, short[] indices, int indexOffset, int numIndices) { 761 if (indicesMap == null) 762 indicesMap = new IntIntMap(numIndices); 763 else { 764 indicesMap.clear(); 765 indicesMap.ensureCapacity(numIndices); 766 } 767 ensureIndices(numIndices); 768 final int numVertices = vertices.length / stride; 769 ensureVertices(numVertices < numIndices ? numVertices : numIndices); 770 for (int i = 0; i < numIndices; i++) { 771 final int sidx = indices[indexOffset + i]; 772 int didx = indicesMap.get(sidx, -1); 773 if (didx < 0) { 774 addVertex(vertices, sidx * stride); 775 indicesMap.put(sidx, didx = lastIndex); 776 } 777 index((short)didx); 778 } 779 } 780 781 @Override 782 public void addMesh (float[] vertices, short[] indices) { 783 final short offset = (short)(lastIndex + 1); 784 785 final int numVertices = vertices.length / stride; 786 ensureVertices(numVertices); 787 for (int v = 0; v < vertices.length; v += stride) 788 addVertex(vertices, v); 789 790 ensureIndices(indices.length); 791 for (int i = 0; i < indices.length; ++i) 792 index((short)(indices[i] + offset)); 793 } 794 795 796 // TODO: The following methods are deprecated and will be removed in a future release 797 798 @Override 799 @Deprecated 800 public void patch (VertexInfo corner00, VertexInfo corner10, VertexInfo corner11, VertexInfo corner01, int divisionsU, 801 int divisionsV) { 802 PatchShapeBuilder.build(this, corner00, corner10, corner11, corner01, divisionsU, divisionsV); 803 } 804 805 @Override 806 @Deprecated 807 public void patch (Vector3 corner00, Vector3 corner10, Vector3 corner11, Vector3 corner01, Vector3 normal, int divisionsU, 808 int divisionsV) { 809 PatchShapeBuilder.build(this, corner00, corner10, corner11, corner01, normal, divisionsU, divisionsV); 810 } 811 812 @Override 813 @Deprecated 814 public void patch (float x00, float y00, float z00, float x10, float y10, float z10, float x11, float y11, float z11, 815 float x01, float y01, float z01, float normalX, float normalY, float normalZ, int divisionsU, int divisionsV) { 816 PatchShapeBuilder.build(this, x00, y00, z00, x10, y10, z10, x11, y11, z11, x01, y01, z01, normalX, normalY, normalZ, divisionsU, divisionsV); 817 } 818 819 @Override 820 @Deprecated 821 public void box (VertexInfo corner000, VertexInfo corner010, VertexInfo corner100, VertexInfo corner110, VertexInfo corner001, 822 VertexInfo corner011, VertexInfo corner101, VertexInfo corner111) { 823 BoxShapeBuilder.build(this, corner000, corner010, corner100, corner110, corner001, corner011, corner101, corner111); 824 } 825 826 @Override 827 @Deprecated 828 public void box (Vector3 corner000, Vector3 corner010, Vector3 corner100, Vector3 corner110, Vector3 corner001, 829 Vector3 corner011, Vector3 corner101, Vector3 corner111) { 830 BoxShapeBuilder.build(this, corner000, corner010, corner100, corner110, corner001, corner011, corner101, corner111); 831 } 832 833 @Override 834 @Deprecated 835 public void box (Matrix4 transform) { 836 BoxShapeBuilder.build(this, transform); 837 } 838 839 @Override 840 @Deprecated 841 public void box (float width, float height, float depth) { 842 BoxShapeBuilder.build(this, width, height, depth); 843 } 844 845 @Override 846 @Deprecated 847 public void box (float x, float y, float z, float width, float height, float depth) { 848 BoxShapeBuilder.build(this, x, y, z, width, height, depth); 849 } 850 851 @Override 852 @Deprecated 853 public void circle (float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, 854 float normalZ) { 855 EllipseShapeBuilder.build(this, radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ); 856 } 857 858 @Override 859 @Deprecated 860 public void circle (float radius, int divisions, final Vector3 center, final Vector3 normal) { 861 EllipseShapeBuilder.build(this, radius, divisions, center, normal); 862 } 863 864 @Override 865 @Deprecated 866 public void circle (float radius, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, 867 final Vector3 binormal) { 868 EllipseShapeBuilder.build(this, radius, divisions, center, normal, tangent, binormal); 869 } 870 871 @Override 872 @Deprecated 873 public void circle (float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, 874 float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ) { 875 EllipseShapeBuilder.build(this, radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, 876 tangentY, tangentZ, binormalX, binormalY, binormalZ); 877 } 878 879 @Override 880 @Deprecated 881 public void circle (float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, 882 float normalZ, float angleFrom, float angleTo) { 883 EllipseShapeBuilder 884 .build(this, radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, angleFrom, angleTo); 885 } 886 887 @Override 888 @Deprecated 889 public void circle (float radius, int divisions, final Vector3 center, final Vector3 normal, float angleFrom, float angleTo) { 890 EllipseShapeBuilder.build(this, radius, divisions, center, normal, angleFrom, angleTo); 891 } 892 893 @Override 894 @Deprecated 895 public void circle (float radius, int divisions, final Vector3 center, final Vector3 normal, final Vector3 tangent, 896 final Vector3 binormal, float angleFrom, float angleTo) { 897 circle(radius, divisions, center.x, center.y, center.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, 898 binormal.x, binormal.y, binormal.z, angleFrom, angleTo); 899 } 900 901 @Override 902 @Deprecated 903 public void circle (float radius, int divisions, float centerX, float centerY, float centerZ, float normalX, float normalY, 904 float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, float binormalZ, 905 float angleFrom, float angleTo) { 906 EllipseShapeBuilder.build(this, radius, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, 907 tangentY, tangentZ, binormalX, binormalY, binormalZ, angleFrom, angleTo); 908 } 909 910 @Override 911 @Deprecated 912 public void ellipse (float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, 913 float normalY, float normalZ) { 914 EllipseShapeBuilder.build(this, width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ); 915 } 916 917 @Override 918 @Deprecated 919 public void ellipse (float width, float height, int divisions, final Vector3 center, final Vector3 normal) { 920 EllipseShapeBuilder.build(this, width, height, divisions, center, normal); 921 } 922 923 @Override 924 @Deprecated 925 public void ellipse (float width, float height, int divisions, final Vector3 center, final Vector3 normal, 926 final Vector3 tangent, final Vector3 binormal) { 927 EllipseShapeBuilder.build(this, width, height, divisions, center, normal, tangent, binormal); 928 } 929 930 @Override 931 @Deprecated 932 public void ellipse (float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, 933 float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, 934 float binormalZ) { 935 EllipseShapeBuilder.build(this, width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, 936 tangentY, tangentZ, binormalX, binormalY, binormalZ); 937 } 938 939 @Override 940 @Deprecated 941 public void ellipse (float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, 942 float normalY, float normalZ, float angleFrom, float angleTo) { 943 EllipseShapeBuilder.build(this, width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, angleFrom, 944 angleTo); 945 } 946 947 @Override 948 @Deprecated 949 public void ellipse (float width, float height, int divisions, final Vector3 center, final Vector3 normal, float angleFrom, 950 float angleTo) { 951 EllipseShapeBuilder.build(this, width, height, divisions, center, normal, angleFrom, angleTo); 952 } 953 954 @Override 955 @Deprecated 956 public void ellipse (float width, float height, int divisions, final Vector3 center, final Vector3 normal, 957 final Vector3 tangent, final Vector3 binormal, float angleFrom, float angleTo) { 958 EllipseShapeBuilder.build(this, width, height, divisions, center, normal, tangent, binormal, angleFrom, angleTo); 959 } 960 961 @Override 962 @Deprecated 963 public void ellipse (float width, float height, int divisions, float centerX, float centerY, float centerZ, float normalX, 964 float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, float binormalX, float binormalY, 965 float binormalZ, float angleFrom, float angleTo) { 966 EllipseShapeBuilder.build(this, width, height, divisions, centerX, centerY, centerZ, normalX, normalY, normalZ, tangentX, 967 tangentY, tangentZ, binormalX, binormalY, binormalZ, angleFrom, angleTo); 968 } 969 970 @Override 971 @Deprecated 972 public void ellipse (float width, float height, float innerWidth, float innerHeight, int divisions, Vector3 center, 973 Vector3 normal) { 974 EllipseShapeBuilder.build(this, width, height, innerWidth, innerHeight, divisions, center, normal); 975 } 976 977 @Override 978 @Deprecated 979 public void ellipse (float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, 980 float centerY, float centerZ, float normalX, float normalY, float normalZ) { 981 EllipseShapeBuilder.build(this, width, height, innerWidth, innerHeight, divisions, centerX, centerY, centerZ, normalX, 982 normalY, normalZ); 983 } 984 985 @Override 986 @Deprecated 987 public void ellipse (float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, 988 float centerY, float centerZ, float normalX, float normalY, float normalZ, float angleFrom, float angleTo) { 989 EllipseShapeBuilder.build(this, width, height, innerWidth, innerHeight, divisions, centerX, centerY, centerZ, normalX, 990 normalY, normalZ, angleFrom, angleTo); 991 } 992 993 @Override 994 @Deprecated 995 public void ellipse (float width, float height, float innerWidth, float innerHeight, int divisions, float centerX, 996 float centerY, float centerZ, float normalX, float normalY, float normalZ, float tangentX, float tangentY, float tangentZ, 997 float binormalX, float binormalY, float binormalZ, float angleFrom, float angleTo) { 998 EllipseShapeBuilder.build(this, width, height, innerWidth, innerHeight, divisions, centerX, centerY, centerZ, normalX, 999 normalY, normalZ, tangentX, tangentY, tangentZ, binormalX, binormalY, binormalZ, angleFrom, angleTo); 1000 } 1001 1002 @Override 1003 @Deprecated 1004 public void cylinder (float width, float height, float depth, int divisions) { 1005 CylinderShapeBuilder.build(this, width, height, depth, divisions); 1006 } 1007 1008 @Override 1009 @Deprecated 1010 public void cylinder (float width, float height, float depth, int divisions, float angleFrom, float angleTo) { 1011 CylinderShapeBuilder.build(this, width, height, depth, divisions, angleFrom, angleTo); 1012 } 1013 1014 @Override 1015 @Deprecated 1016 public void cylinder (float width, float height, float depth, int divisions, float angleFrom, float angleTo, boolean close) { 1017 CylinderShapeBuilder.build(this, width, height, depth, divisions, angleFrom, angleTo, close); 1018 } 1019 1020 @Override 1021 @Deprecated 1022 public void cone (float width, float height, float depth, int divisions) { 1023 cone(width, height, depth, divisions, 0, 360); 1024 } 1025 1026 @Override 1027 @Deprecated 1028 public void cone (float width, float height, float depth, int divisions, float angleFrom, float angleTo) { 1029 ConeShapeBuilder.build(this, width, height, depth, divisions, angleFrom, angleTo); 1030 } 1031 1032 @Override 1033 @Deprecated 1034 public void sphere (float width, float height, float depth, int divisionsU, int divisionsV) { 1035 SphereShapeBuilder.build(this, width, height, depth, divisionsU, divisionsV); 1036 } 1037 1038 @Override 1039 @Deprecated 1040 public void sphere (final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV) { 1041 SphereShapeBuilder.build(this, transform, width, height, depth, divisionsU, divisionsV); 1042 } 1043 1044 @Override 1045 @Deprecated 1046 public void sphere (float width, float height, float depth, int divisionsU, int divisionsV, float angleUFrom, float angleUTo, 1047 float angleVFrom, float angleVTo) { 1048 SphereShapeBuilder.build(this, width, height, depth, divisionsU, divisionsV, angleUFrom, angleUTo, angleVFrom, angleVTo); 1049 } 1050 1051 @Override 1052 @Deprecated 1053 public void sphere (final Matrix4 transform, float width, float height, float depth, int divisionsU, int divisionsV, 1054 float angleUFrom, float angleUTo, float angleVFrom, float angleVTo) { 1055 SphereShapeBuilder.build(this, transform, width, height, depth, divisionsU, divisionsV, angleUFrom, angleUTo, angleVFrom, 1056 angleVTo); 1057 } 1058 1059 @Override 1060 @Deprecated 1061 public void capsule (float radius, float height, int divisions) { 1062 CapsuleShapeBuilder.build(this, radius, height, divisions); 1063 } 1064 1065 @Override 1066 @Deprecated 1067 public void arrow (float x1, float y1, float z1, float x2, float y2, float z2, float capLength, float stemThickness, 1068 int divisions) { 1069 ArrowShapeBuilder.build(this, x1, y1, z1, x2, y2, z2, capLength, stemThickness, divisions); 1070 } 1071 } 1072