com.badlogic.gdx.graphics.g3d.md2.MD2Loader.java Source code

Java tutorial

Introduction

Here is the source code for com.badlogic.gdx.graphics.g3d.md2.MD2Loader.java

Source

package com.badlogic.gdx.graphics.g3d.md2;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.model.keyframe.Keyframe;
import com.badlogic.gdx.graphics.g3d.model.keyframe.KeyframedAnimation;
import com.badlogic.gdx.graphics.g3d.model.keyframe.KeyframedModel;
import com.badlogic.gdx.graphics.g3d.model.keyframe.SubMesh;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.LittleEndianInputStream;

public class MD2Loader {

    public KeyframedModel load(FileHandle fileHandle) {
        InputStream in = fileHandle.read();
        try {
            return load(in);
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                }
            ;
        }
    }

    public KeyframedModel load(InputStream in) {
        try {
            byte[] bytes = loadBytes(new BufferedInputStream(in));
            MD2Header header = loadHeader(bytes);
            float[] texCoords = loadTexCoords(header, bytes);
            Array<MD2Frame> frames = loadFrames(header, bytes);
            short[] triangles = loadTriangles(header, bytes);
            return buildModel(header, triangles, frames, texCoords);
        } catch (IOException e) {
            throw new GdxRuntimeException("Couldn't load MD2 model", e);
        }
    }

    private KeyframedModel buildModel(MD2Header header, short[] triangles, Array<MD2Frame> frames,
            float[] texCoords) {
        SubMesh subMesh = new SubMesh();
        KeyframedAnimation animation = new KeyframedAnimation();
        animation.duration = frames.size * 0.2f;
        animation.keyframes = new Keyframe[frames.size];

        for (int i = 0; i < frames.size; i++) {
            MD2Frame frame = frames.get(i);
            final float[] frameVertices = frame.vertices;

            Keyframe keyFrame = new Keyframe();
            keyFrame.timeStamp = 0;
            keyFrame.vertices = new float[header.numTris * 15];

            for (int j = 0, idx = 0, idx2 = 0; j < header.numTris; j++) {
                int v1 = triangles[idx2++] * 3;
                int v2 = triangles[idx2++] * 3;
                int v3 = triangles[idx2++] * 3;
                int t1 = triangles[idx2++] * 2;
                int t2 = triangles[idx2++] * 2;
                int t3 = triangles[idx2++] * 2;

                keyFrame.vertices[idx++] = frameVertices[v1];
                keyFrame.vertices[idx++] = frameVertices[v1 + 1];
                keyFrame.vertices[idx++] = frameVertices[v1 + 2];
                keyFrame.vertices[idx++] = texCoords[t1];
                keyFrame.vertices[idx++] = texCoords[t1 + 1];

                keyFrame.vertices[idx++] = frameVertices[v2];
                keyFrame.vertices[idx++] = frameVertices[v2 + 1];
                keyFrame.vertices[idx++] = frameVertices[v2 + 2];
                keyFrame.vertices[idx++] = texCoords[t2];
                keyFrame.vertices[idx++] = texCoords[t2 + 1];

                keyFrame.vertices[idx++] = frameVertices[v3];
                keyFrame.vertices[idx++] = frameVertices[v3 + 1];
                keyFrame.vertices[idx++] = frameVertices[v3 + 2];
                keyFrame.vertices[idx++] = texCoords[t3];
                keyFrame.vertices[idx++] = texCoords[t3 + 1];

                animation.keyframes[i] = keyFrame;
            }
        }
        subMesh.mesh = new Mesh(false, header.numTris * 3, 0, new VertexAttribute(Usage.Position, 3, "a_pos"),
                new VertexAttribute(Usage.TextureCoordinates, 2, "a_tex0"));
        subMesh.animations.put("all", animation);
        KeyframedModel model = new KeyframedModel();
        model.subMeshes = new SubMesh[] { subMesh };
        return model;
    }

    public MD2Header loadHeader(byte[] bytes) throws IOException {
        MD2Header header = new MD2Header();
        LittleEndianInputStream in = new LittleEndianInputStream(new ByteArrayInputStream(bytes));
        header.ident = in.readInt();
        header.version = in.readInt();
        header.skinWidth = in.readInt();
        header.skinHeight = in.readInt();
        header.frameSize = in.readInt();
        header.numSkins = in.readInt();
        header.numVertices = in.readInt();
        header.numSt = in.readInt();
        header.numTris = in.readInt();
        header.numGlcmds = in.readInt();
        header.numFrames = in.readInt();
        header.offsetSkins = in.readInt();
        header.offsetSt = in.readInt();
        header.offsetTris = in.readInt();
        header.offsetFrames = in.readInt();
        header.offsetGlcmds = in.readInt();
        header.offsetEnd = in.readInt();
        in.close();
        return header;
    }

    public float[] loadTexCoords(MD2Header header, byte[] bytes) throws IOException {
        float[] texCoords = new float[2 * header.numSt];
        LittleEndianInputStream in = new LittleEndianInputStream(new ByteArrayInputStream(bytes));
        in.skipBytes(header.offsetSt);
        float invWidth = 1.0f / header.skinWidth;
        float invHeight = 1.0f / header.skinHeight;
        for (int idx = 0; idx < 2 * header.numSt; idx += 2) {
            texCoords[idx] = in.readShort() * invWidth;
            texCoords[idx + 1] = in.readShort() * invHeight;
        }
        in.close();
        return texCoords;
    }

    public Array<MD2Frame> loadFrames(MD2Header header, byte[] bytes) throws IOException {
        Array<MD2Frame> frames = new Array<MD2Frame>();
        LittleEndianInputStream in = new LittleEndianInputStream(new ByteArrayInputStream(bytes));
        in.skip(header.offsetFrames);
        byte[] name = new byte[16];
        for (int i = 0; i < header.numFrames; i++) {
            MD2Frame frame = new MD2Frame();
            frame.vertices = new float[3 * header.numVertices];
            float scaleX = in.readFloat();
            float scaleY = in.readFloat();
            float scaleZ = in.readFloat();
            float tranX = in.readFloat();
            float tranY = in.readFloat();
            float tranZ = in.readFloat();
            in.read(name);
            frame.name = new String(name);
            for (int j = 0, idx = 0; j < header.numVertices; j++) {
                float x = in.read(), y = in.read(), z = in.read();
                frame.vertices[idx++] = x * scaleX + tranX;
                frame.vertices[idx++] = z * scaleZ + tranZ;
                frame.vertices[idx++] = y * scaleY + tranY;
                in.read();
            }
            frames.add(frame);
        }
        in.close();
        return frames;
    }

    public short[] loadTriangles(MD2Header header, byte[] bytes) throws IOException {
        short[] triangles = new short[6 * header.numTris];
        LittleEndianInputStream in = new LittleEndianInputStream(new ByteArrayInputStream(bytes));
        in.skip(header.offsetTris);
        for (int i = 0, idx = 0; i < header.numTris; i++) {
            triangles[idx++] = in.readShort();
            triangles[idx++] = in.readShort();
            triangles[idx++] = in.readShort();
            triangles[idx++] = in.readShort();
            triangles[idx++] = in.readShort();
            triangles[idx++] = in.readShort();
        }
        return triangles;
    }

    public byte[] loadBytes(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];

        int readBytes = 0;
        while ((readBytes = in.read(buffer)) > 0) {
            out.write(buffer, 0, readBytes);
        }

        out.close();
        return out.toByteArray();
    }
}