/* * Copyright 2012 Benjamin Glatzel <benjamin.glatzel@me.com> * * 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 org.terasology.rendering.primitives; import gnu.trove.iterator.TIntIterator; import gnu.trove.list.TFloatList; import gnu.trove.list.TIntList; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL15; import org.terasology.asset.Asset; import org.terasology.asset.AssetUri; import org.terasology.logic.manager.VertexBufferObjectManager; import java.nio.FloatBuffer; import java.nio.IntBuffer; import static org.lwjgl.opengl.GL11.*; // TODO: Store mesh information in Mesh class in a usable format, for public class Mesh implements Asset { private static final int VERTEX_SIZE = 3; private static final int TEX_COORD_0_SIZE = 2; private static final int TEX_COORD_1_SIZE = 3; private static final int COLOR_SIZE = 4; private static final int NORMAL_SIZE = 3; public static Mesh buildMesh(AssetUri uri, TFloatList vertices, TFloatList texCoord0, TFloatList texCoord1, TFloatList normals, TFloatList colors, TIntList indices) { Mesh mesh = buildMesh(vertices, texCoord0, texCoord1, normals, colors, indices); mesh.uri = uri; return mesh; } public static Mesh buildMesh(TFloatList vertices, TFloatList texCoord0, TFloatList texCoord1, TFloatList normals, TFloatList colors, TIntList indices) { int vertexCount = vertices.size() / VERTEX_SIZE; boolean hasTexCoord0 = texCoord0 != null && texCoord0.size() / TEX_COORD_0_SIZE == vertexCount; boolean hasTexCoord1 = texCoord1 != null && texCoord1.size() / TEX_COORD_1_SIZE == vertexCount; boolean hasNormals = normals != null && normals.size() / NORMAL_SIZE == vertexCount; boolean hasColors = colors != null && colors.size() / COLOR_SIZE == vertexCount; int vertSize = VERTEX_SIZE + (hasTexCoord0 ? TEX_COORD_0_SIZE : 0) + (hasTexCoord1 ? TEX_COORD_1_SIZE : 0) + (hasNormals ? NORMAL_SIZE : 0) + (hasColors ? COLOR_SIZE : 0); FloatBuffer vertexBuffer = createVertexBuffer(vertices, texCoord0, texCoord1, normals, colors, vertexCount, hasTexCoord0, hasTexCoord1, hasNormals, hasColors, vertSize); IntBuffer indexBuffer = BufferUtils.createIntBuffer(indices.size()); TIntIterator iterator = indices.iterator(); while (iterator.hasNext()) { indexBuffer.put(iterator.next()); } indexBuffer.flip(); Mesh mesh = new Mesh(); mesh.vboVertexBuffer = VertexBufferObjectManager.getInstance().getVboId(); mesh.vboIndexBuffer = VertexBufferObjectManager.getInstance().getVboId(); mesh.indexCount = indices.size(); VertexBufferObjectManager.getInstance().bufferVboData(mesh.vboVertexBuffer, vertexBuffer, GL15.GL_STATIC_DRAW); VertexBufferObjectManager.getInstance().bufferVboElementData(mesh.vboIndexBuffer, indexBuffer, GL15.GL_STATIC_DRAW); mesh.stride = vertSize * 4; mesh.vertexOffset = 0; int offset = VERTEX_SIZE; if (hasTexCoord0) { mesh.hasTexCoord0 = hasTexCoord0; mesh.texCoord0Offset = 4 * offset; offset += TEX_COORD_0_SIZE; } if (hasTexCoord1) { mesh.hasTexCoord1 = hasTexCoord1; mesh.texCoord1Offset = 4 * offset; offset += TEX_COORD_1_SIZE; } if (hasNormals) { mesh.hasNormal = hasNormals; mesh.normalOffset = 4 * offset; offset += NORMAL_SIZE; } if (hasColors) { mesh.hasColor = hasColors; mesh.colorOffset = 4 * offset; offset += COLOR_SIZE; } return mesh; } private static FloatBuffer createVertexBuffer(TFloatList vertices, TFloatList texcoord0, TFloatList texcoord1, TFloatList normals, TFloatList colors, int vertexCount, boolean hasTexCoord0, boolean hasTexCoord1, boolean hasNormal, boolean hasColor, int vertSize) { FloatBuffer vertexBuffer; vertexBuffer = BufferUtils.createFloatBuffer(vertSize * vertexCount); int texCoord0Size = (hasTexCoord0) ? TEX_COORD_0_SIZE : 0; int texCoord1Size = (hasTexCoord1) ? TEX_COORD_1_SIZE : 0; int normalSize = (hasNormal) ? NORMAL_SIZE : 0; int colorSize = (hasColor) ? COLOR_SIZE : 0; int uv1 = 0, uv2 = 0, n = 0, c = 0; for (int v = 0; v < vertices.size(); v += 3) { vertexBuffer.put(vertices.get(v)).put(vertices.get(v + 1)).put(vertices.get(v + 2)); for (int i = 0; i < texCoord0Size; ++i) { vertexBuffer.put(texcoord0.get(uv1 + i)); } for (int i = 0; i < texCoord1Size; ++i) { vertexBuffer.put(texcoord1.get(uv2 + i)); } for (int i = 0; i < normalSize; ++i) { vertexBuffer.put(normals.get(n + i)); } for (int i = 0; i < colorSize; ++i) { vertexBuffer.put(colors.get(c + i)); } uv1 += texCoord0Size; uv2 += texCoord1Size; n += normalSize; c += colorSize; } vertexBuffer.flip(); return vertexBuffer; } private Mesh() { } private AssetUri uri = new AssetUri(""); private int stride; private int vertexOffset; private int texCoord0Offset; private int texCoord1Offset; private int colorOffset; private int normalOffset; private boolean hasTexCoord0 = false; private boolean hasTexCoord1 = false; private boolean hasColor = false; private boolean hasNormal = false; private int vboVertexBuffer; private int vboIndexBuffer; private int indexCount; @Override public AssetUri getURI() { return uri; } public void render() { glEnableClientState(GL_VERTEX_ARRAY); if (hasTexCoord0 || hasTexCoord1) glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (hasColor) glEnableClientState(GL_COLOR_ARRAY); if (hasNormal) glEnableClientState(GL_NORMAL_ARRAY); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexBuffer); GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboIndexBuffer); glVertexPointer(VERTEX_SIZE, GL11.GL_FLOAT, stride, vertexOffset); if (hasTexCoord0) { GL13.glClientActiveTexture(GL13.GL_TEXTURE0); glTexCoordPointer(TEX_COORD_0_SIZE, GL11.GL_FLOAT, stride, texCoord0Offset); } if (hasTexCoord1) { GL13.glClientActiveTexture(GL13.GL_TEXTURE1); glTexCoordPointer(TEX_COORD_1_SIZE, GL11.GL_FLOAT, stride, texCoord1Offset); } if (hasColor) glColorPointer(COLOR_SIZE, GL11.GL_FLOAT, stride, colorOffset); if (hasNormal) glNormalPointer(GL11.GL_FLOAT, stride, normalOffset); GL12.glDrawRangeElements(GL11.GL_TRIANGLES, 0, indexCount, indexCount, GL_UNSIGNED_INT, 0); if (hasNormal) glDisableClientState(GL_NORMAL_ARRAY); if (hasColor) glDisableClientState(GL_COLOR_ARRAY); if (hasTexCoord0 || hasTexCoord1) glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); } }