org.terasology.rendering.opengl.OpenGLSkeletalMesh.java Source code

Java tutorial

Introduction

Here is the source code for org.terasology.rendering.opengl.OpenGLSkeletalMesh.java

Source

/*
 * Copyright 2013 MovingBlocks
 *
 * 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.opengl;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL15;
import org.terasology.asset.AbstractAsset;
import org.terasology.asset.AssetUri;
import org.terasology.engine.subsystem.lwjgl.GLBufferPool;
import org.terasology.rendering.VertexBufferObjectUtil;
import org.terasology.rendering.assets.skeletalmesh.Bone;
import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh;
import org.terasology.rendering.assets.skeletalmesh.SkeletalMeshData;

import javax.vecmath.Quat4f;
import javax.vecmath.Vector2f;
import javax.vecmath.Vector3f;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Collection;
import java.util.List;

import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL11.GL_NORMAL_ARRAY;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_COORD_ARRAY;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
import static org.lwjgl.opengl.GL11.GL_VERTEX_ARRAY;
import static org.lwjgl.opengl.GL11.glDisableClientState;
import static org.lwjgl.opengl.GL11.glEnableClientState;
import static org.lwjgl.opengl.GL11.glNormalPointer;
import static org.lwjgl.opengl.GL11.glTexCoordPointer;
import static org.lwjgl.opengl.GL11.glVertexPointer;

/**
 * @author Immortius
 */
public class OpenGLSkeletalMesh extends AbstractAsset<SkeletalMeshData> implements SkeletalMesh {

    private static final int TEX_COORD_SIZE = 2;
    private static final int VECTOR3_SIZE = 3;
    private static final int STRIDE = 24;
    private static final int NORMAL_OFFSET = VECTOR3_SIZE * 4;

    private SkeletalMeshData data;

    private int vboPosNormBuffer;
    private int vboUVBuffer;
    private int vboIndexBuffer;

    private GLBufferPool bufferPool;

    public OpenGLSkeletalMesh(AssetUri uri, SkeletalMeshData data, GLBufferPool bufferPool) {
        super(uri);
        this.bufferPool = bufferPool;
        reload(data);
    }

    @Override
    public void reload(SkeletalMeshData newData) {
        this.data = newData;

        if (vboPosNormBuffer == 0) {
            vboPosNormBuffer = bufferPool.get(getURI().toSimpleString());
        }

        IntBuffer indexBuffer = BufferUtils.createIntBuffer(newData.getIndices().size());
        indexBuffer.put(newData.getIndices().toArray());
        indexBuffer.flip();
        if (vboIndexBuffer == 0) {
            vboIndexBuffer = bufferPool.get(getURI().toSimpleString());
        }
        VertexBufferObjectUtil.bufferVboElementData(vboIndexBuffer, indexBuffer, GL15.GL_STATIC_DRAW);

        FloatBuffer uvBuffer = BufferUtils.createFloatBuffer(newData.getUVs().size() * 2);
        for (Vector2f uv : newData.getUVs()) {
            uvBuffer.put(uv.x);
            uvBuffer.put(uv.y);
        }
        uvBuffer.flip();

        if (vboUVBuffer == 0) {
            vboUVBuffer = bufferPool.get(getURI().toSimpleString());
        }
        VertexBufferObjectUtil.bufferVboData(vboUVBuffer, uvBuffer, GL15.GL_STATIC_DRAW);
    }

    @Override
    public void dispose() {
        if (vboIndexBuffer != 0) {
            bufferPool.dispose(vboIndexBuffer);
            vboIndexBuffer = 0;
        }
        if (vboPosNormBuffer != 0) {
            bufferPool.dispose(vboPosNormBuffer);
            vboPosNormBuffer = 0;
        }
        if (vboUVBuffer != 0) {
            bufferPool.dispose(vboUVBuffer);
            vboUVBuffer = 0;
        }
    }

    @Override
    public boolean isDisposed() {
        return vboPosNormBuffer == 0 && vboUVBuffer == 0 && vboIndexBuffer == 0;
    }

    public void preRender() {
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboUVBuffer);
        GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
        glTexCoordPointer(2, GL11.GL_FLOAT, TEX_COORD_SIZE * 4, 0);

        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboIndexBuffer);
    }

    public void postRender() {
        glDisableClientState(GL_NORMAL_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
    }

    public void doRender(List<Vector3f> verts, List<Vector3f> normals) {
        FloatBuffer vertBuffer = BufferUtils.createFloatBuffer(verts.size() * 6);
        for (int i = 0; i < verts.size(); ++i) {
            Vector3f vert = verts.get(i);
            vertBuffer.put(vert.x);
            vertBuffer.put(vert.y);
            vertBuffer.put(vert.z);
            Vector3f norm = normals.get(i);
            vertBuffer.put(norm.x);
            vertBuffer.put(norm.y);
            vertBuffer.put(norm.z);
        }
        vertBuffer.flip();
        VertexBufferObjectUtil.bufferVboData(vboPosNormBuffer, vertBuffer, GL15.GL_DYNAMIC_DRAW);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboPosNormBuffer);
        glVertexPointer(VECTOR3_SIZE, GL_FLOAT, STRIDE, 0);
        glNormalPointer(GL_FLOAT, STRIDE, NORMAL_OFFSET);

        GL11.glDrawElements(GL11.GL_TRIANGLES, data.getIndices().size(), GL_UNSIGNED_INT, 0);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    }

    public void render() {
        preRender();
        doRender(data.getBindPoseVertexPositions(), data.getBindPoseVertexNormals());
        postRender();
    }

    public void render(List<Vector3f> bonePositions, List<Quat4f> boneRotations) {
        preRender();
        doRender(data.getVertexPositions(bonePositions, boneRotations),
                data.getVertexNormals(bonePositions, boneRotations));
        postRender();
    }

    @Override
    public int getVertexCount() {
        return data.getVertexCount();
    }

    @Override
    public Collection<Bone> getBones() {
        return data.getBones();
    }

    @Override
    public Bone getBone(String boneName) {
        return data.getBone(boneName);
    }
}