/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.badlogic.gdx.graphics.g3d.utils.shapebuilders; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g3d.Renderable; import com.badlogic.gdx.graphics.g3d.RenderableProvider; import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.FlushablePool; /** RenderableShapeBuilder builds various properties of a renderable. * @author realitix */ public class RenderableShapeBuilder extends BaseShapeBuilder { private static class RenderablePool extends FlushablePool<Renderable> { public RenderablePool () { super(); } @Override protected Renderable newObject () { return new Renderable(); } @Override public Renderable obtain () { Renderable renderable = super.obtain(); renderable.environment = null; renderable.material = null; renderable.meshPart.set("", null, 0, 0, 0); renderable.shader = null; renderable.userData = null; return renderable; } } private static short[] indices; private static float[] vertices; private final static RenderablePool renderablesPool = new RenderablePool(); private final static Array<Renderable> renderables = new Array<Renderable>(); private static final int FLOAT_BYTES = 4; /** Builds normal, tangent and binormal of a RenderableProvider with default colors (normal blue, tangent red, binormal green). * @param builder * @param renderableProvider * @param vectorSize Size of the normal vector */ public static void buildNormals (MeshPartBuilder builder, RenderableProvider renderableProvider, float vectorSize) { buildNormals(builder, renderableProvider, vectorSize, tmpColor0.set(0, 0, 1, 1), tmpColor1.set(1, 0, 0, 1), tmpColor2.set(0, 1, 0, 1)); } /** Builds normal, tangent and binormal of a RenderableProvider. * @param builder * @param renderableProvider * @param vectorSize Size of the normal vector * @param normalColor Normal vector's color * @param tangentColor Tangent vector's color * @param binormalColor Binormal vector's color */ public static void buildNormals (MeshPartBuilder builder, RenderableProvider renderableProvider, float vectorSize, Color normalColor, Color tangentColor, Color binormalColor) { renderableProvider.getRenderables(renderables, renderablesPool); for (Renderable renderable : renderables) { buildNormals(builder, renderable, vectorSize, normalColor, tangentColor, binormalColor); } renderablesPool.flush(); renderables.clear(); } /** Builds normal, tangent and binormal of a Renderable. * @param builder * @param renderable * @param vectorSize Size of the normal vector * @param normalColor Normal vector's color * @param tangentColor Tangent vector's color * @param binormalColor Binormal vector's color */ public static void buildNormals (MeshPartBuilder builder, Renderable renderable, float vectorSize, Color normalColor, Color tangentColor, Color binormalColor) { Mesh mesh = renderable.meshPart.mesh; // Position int positionOffset = -1; if (mesh.getVertexAttribute(Usage.Position) != null) positionOffset = mesh.getVertexAttribute(Usage.Position).offset / FLOAT_BYTES; // Normal int normalOffset = -1; if (mesh.getVertexAttribute(Usage.Normal) != null) normalOffset = mesh.getVertexAttribute(Usage.Normal).offset / FLOAT_BYTES; // Tangent int tangentOffset = -1; if (mesh.getVertexAttribute(Usage.Tangent) != null) tangentOffset = mesh.getVertexAttribute(Usage.Tangent).offset / FLOAT_BYTES; // Binormal int binormalOffset = -1; if (mesh.getVertexAttribute(Usage.BiNormal) != null) binormalOffset = mesh.getVertexAttribute(Usage.BiNormal).offset / FLOAT_BYTES; int attributesSize = mesh.getVertexSize() / FLOAT_BYTES; int verticesOffset = 0; int verticesQuantity = 0; if (mesh.getNumIndices() > 0) { // Get min vertice to max vertice in indices array ensureIndicesCapacity(mesh.getNumIndices()); mesh.getIndices(renderable.meshPart.offset, renderable.meshPart.size, indices, 0); short minVertice = minVerticeInIndices(); short maxVertice = maxVerticeInIndices(); verticesOffset = minVertice; verticesQuantity = maxVertice - minVertice; } else { verticesOffset = renderable.meshPart.offset; verticesQuantity = renderable.meshPart.size; } ensureVerticesCapacity(verticesQuantity * attributesSize); mesh.getVertices(verticesOffset * attributesSize, verticesQuantity * attributesSize, vertices, 0); for (int i = verticesOffset; i < verticesQuantity; i++) { int id = i * attributesSize; // Vertex position tmpV0.set(vertices[id + positionOffset], vertices[id + positionOffset + 1], vertices[id + positionOffset + 2]); // Vertex normal, tangent, binormal if (normalOffset != -1) { tmpV1.set(vertices[id + normalOffset], vertices[id + normalOffset + 1], vertices[id + normalOffset + 2]); tmpV2.set(tmpV0).add(tmpV1.scl(vectorSize)); } if (tangentOffset != -1) { tmpV3.set(vertices[id + tangentOffset], vertices[id + tangentOffset + 1], vertices[id + tangentOffset + 2]); tmpV4.set(tmpV0).add(tmpV3.scl(vectorSize)); } if (binormalOffset != -1) { tmpV5.set(vertices[id + binormalOffset], vertices[id + binormalOffset + 1], vertices[id + binormalOffset + 2]); tmpV6.set(tmpV0).add(tmpV5.scl(vectorSize)); } // World transform tmpV0.mul(renderable.worldTransform); tmpV2.mul(renderable.worldTransform); tmpV4.mul(renderable.worldTransform); tmpV6.mul(renderable.worldTransform); // Draws normal, tangent, binormal if (normalOffset != -1) { builder.setColor(normalColor); builder.line(tmpV0, tmpV2); } if (tangentOffset != -1) { builder.setColor(tangentColor); builder.line(tmpV0, tmpV4); } if (binormalOffset != -1) { builder.setColor(binormalColor); builder.line(tmpV0, tmpV6); } } } private static void ensureVerticesCapacity (int capacity) { if (vertices == null || vertices.length < capacity) vertices = new float[capacity]; } private static void ensureIndicesCapacity (int capacity) { if (indices == null || indices.length < capacity) indices = new short[capacity]; } private static short minVerticeInIndices () { short min = (short)32767; for (int i = 0; i < indices.length; i++) if (indices[i] < min) min = indices[i]; return min; } private static short maxVerticeInIndices () { short max = (short)-32768; for (int i = 0; i < indices.length; i++) if (indices[i] > max) max = indices[i]; return max; } }