MS3D模型载入与演示(支持动画)

import java.io.InputStream;
import java.nio.FloatBuffer;
import java.util.Hashtable;
import java.util.Vector;

import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.opengl.GL11;
import org.tinder.studio.lwjgl.util.BinaryFileReader;
import org.tinder.studio.lwjgl.util.Bounding;
import org.tinder.studio.lwjgl.util.GLApp;
import org.tinder.studio.lwjgl.util.Matrix4f;
import org.tinder.studio.lwjgl.util.Vector3f;
import org.tinder.studio.lwjgl.util.Vector4f;

/**
 * 
 * 
 * @Author Micheal Hong
 * @Email [email protected]
 * @Version 2010-6-29下午10:33:28
 * 
 */
public class MS3DModel {

	MS3DHeader header;

	int numVertices;
	public MS3DVertex[] vertices;
	float vertex[];

	int numTriangles;
	MS3DTriangle[] triangles;

	int numMeshs;
	MS3DMesh[] meshs;

	int numMaterials;
	MS3DMaterial[] materials;

	int numJoints;
	MS3DJoint[] joints;

	long lastTime;
	int currentAnimation;
	float currentTime;
	int totalFrames;
	int endFrame;
	float animationFPS;
	boolean loop;
	boolean loopDone;
	Vector allAnimations;
	Hashtable allJoints;
	Vector rootJoints;
	String textureDirectory;
	
	Bounding bounding;

	/***************************************************************************************************************************************************************************************************
	 * MS3DModel () - Constructor
	 **************************************************************************************************************************************************************************************************/
	public MS3DModel(InputStream file,String textureDirectory) {
		this.allJoints = new Hashtable();
		this.rootJoints = new Vector();
		this.allAnimations = new Vector();
		this.currentAnimation = -1;
		this.loop = true;
		this.loopDone = false;
		this.textureDirectory=textureDirectory;
		this.loadModel(file);
		this.makeBounding();

	}

	/***************************************************************************************************************************************************************************************************
	 * loadModel() - Load a ms3d model and prepare it for rendering
	 **************************************************************************************************************************************************************************************************/
	protected void loadModel(InputStream file) {

		try {
			// Read the model file
			BinaryFileReader modelFile = new BinaryFileReader(file);

			// Read header
			this.header = new MS3DHeader(modelFile);
			if (!this.header.isValid())
				throw new Exception("Model header is invalid! Only versions 1.3 and 1.4 are supported!");

			// Read vertices
			this.numVertices = modelFile.readShort();
			this.vertices = new MS3DVertex[this.numVertices];
			this.vertex = new float[3 * numVertices];
			for (int i = 0; i < this.numVertices; i++) {
				this.vertices[i] = new MS3DVertex(modelFile);
				this.vertex[3 * i] = this.vertices[i].vertex.x;
				this.vertex[3 * i + 1] = this.vertices[i].vertex.y;
				this.vertex[3 * i + 2] = this.vertices[i].vertex.z;
			}

			// Triangles
			this.numTriangles = modelFile.readShort();
			this.triangles = new MS3DTriangle[this.numTriangles];
			for (int i = 0; i < this.numTriangles; i++)
				this.triangles[i] = new MS3DTriangle(modelFile);

			// Meshs
			this.numMeshs = modelFile.readShort();
			this.meshs = new MS3DMesh[this.numMeshs];
			for (int i = 0; i < this.numMeshs; i++)
				this.meshs[i] = new MS3DMesh(modelFile);

			// Materials
			this.numMaterials = modelFile.readShort();
			this.materials = new MS3DMaterial[this.numMaterials];
			for (int i = 0; i < this.numMaterials; i++)
				this.materials[i] = new MS3DMaterial(modelFile);

			// Keyframe data
			animationFPS = modelFile.readFloat();
			currentTime = (long) (modelFile.readFloat() * 1000);
			totalFrames = modelFile.readInt();

			// Joints
			numJoints = modelFile.readShort();
			this.joints = new MS3DJoint[numJoints];
			for (int i = 0; i < this.numJoints; i++) {
				this.joints[i] = new MS3DJoint(modelFile);
				addJoint(this.joints[i]);
			}

			// Load textures
			this.reloadTextures();

			this.makeBones();

			this.reset();

		} catch (Exception e) {
			Sys.alert("Error", "Failed to load model '" + file.toString()+ "'!\n\n" + e.getMessage());
			e.printStackTrace();
			System.exit(0);
		}

	}

	public void addJoint(MS3DJoint joint) {
		allJoints.put(joint.name, joint);

		if (joint.parentName.equals(""))
			rootJoints.addElement(joint);
	}

	public Hashtable getJoints() {
		return allJoints;
	}

	/***************************************************************************************************************************************************************************************************
	 * reloadTextures() - Load the texture of each material
	 **************************************************************************************************************************************************************************************************/
	public void reloadTextures() {

		for (int i = 0; i < this.numMaterials; i++) {
			if (this.materials[i].textureID != 0)
				GL11.glDeleteTextures(BufferUtils.createIntBuffer(1).put(this.materials[i].textureID));
			else {
				try {
					this.materials[i].textureID = GLApp.makeTexture(this.textureDirectory+"/"+this.materials[i].texturemap);
				} catch (Exception e) {
					System.out.println("Failed to open texture file 'this.materials[i].texturemap'!");
				}
			}

		}
	}

	public void updateModel(long time) {
		// update the animation
		updateAnimation(time);

		boolean texturingEnabled = GL11.glIsEnabled(GL11.GL_TEXTURE_2D);

		// update the points
		for (int i = 0; i < numMeshs; i++) {
			if (this.meshs[i].materialIndex >= 0) {
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT,this.materials[this.meshs[i].materialIndex].ambient);
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_DIFFUSE,this.materials[this.meshs[i].materialIndex].diffuse);
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR,this.materials[this.meshs[i].materialIndex].specular);
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_EMISSION,this.materials[this.meshs[i].materialIndex].emissive);
				GL11.glMaterialf(GL11.GL_FRONT, GL11.GL_SHININESS,this.materials[this.meshs[i].materialIndex].shininess);

				if (this.materials[this.meshs[i].materialIndex].textureID > 0) {
					GL11.glBindTexture(GL11.GL_TEXTURE_2D,this.materials[this.meshs[i].materialIndex].textureID);
					GL11.glEnable(GL11.GL_TEXTURE_2D);
				} else {
					GL11.glDisable(GL11.GL_TEXTURE_2D);
				}
			} else {
				GL11.glDisable(GL11.GL_TEXTURE_2D);
			}
			float[] coords = new float[3];
			Vector4f temp = new Vector4f();
			Matrix4f matrix=null;
			GL11.glBegin(GL11.GL_TRIANGLES);
			for (int j = 0; j < meshs[i].numTriangles; j++) {

				for (int k = 0; k < 3; k++) {

					coords[0] = vertex[3 * triangles[meshs[i].triangleIndices[j]].vertexIndices[k]];
					coords[1] = vertex[3 * triangles[meshs[i].triangleIndices[j]].vertexIndices[k] + 1];
					coords[2] = vertex[3 * triangles[meshs[i].triangleIndices[j]].vertexIndices[k] + 2];

					if (vertices[triangles[meshs[i].triangleIndices[j]].vertexIndices[k]].boneID != -1) {
						matrix = joints[vertices[triangles[meshs[i].triangleIndices[j]].vertexIndices[k]].boneID].finalMatrix;

						temp.x = coords[0] * matrix.m00 + coords[1]
								* matrix.m10 + coords[2] * matrix.m20
								+ matrix.m30;
						temp.y = coords[0] * matrix.m01 + coords[1]
								* matrix.m11 + coords[2] * matrix.m21
								+ matrix.m31;
						temp.z = coords[0] * matrix.m02 + coords[1]
								* matrix.m12 + coords[2] * matrix.m22
								+ matrix.m32;
						temp.w = coords[0] * matrix.m03 + coords[1]
								* matrix.m13 + coords[2] * matrix.m23
								+ matrix.m33;

						GL11.glNormal3f(
										triangles[meshs[i].triangleIndices[j]].vertexNormals[0][0],
										triangles[meshs[i].triangleIndices[j]].vertexNormals[0][1],
										triangles[meshs[i].triangleIndices[j]].vertexNormals[0][2]);
						GL11.glTexCoord2f(
								triangles[meshs[i].triangleIndices[j]].s[k],
								triangles[meshs[i].triangleIndices[j]].t[k]);
						GL11.glVertex3f(temp.x, temp.y, temp.z);
					}

				}
			}
			GL11.glEnd();

		}

		// Reset texture state
		if (texturingEnabled)
			GL11.glEnable(GL11.GL_TEXTURE_2D);
		else
			GL11.glDisable(GL11.GL_TEXTURE_2D);

	}

	/***************************************************************************************************************************************************************************************************
	 * render() - Render this model
	 **************************************************************************************************************************************************************************************************/
	public void render() {

		// Save texture state
		boolean texturingEnabled = GL11.glIsEnabled(GL11.GL_TEXTURE_2D);

		// Render each mesh
		for (int m = 0; m < this.numMeshs; m++) {

			// Set texture for this mesh
			if (this.meshs[m].materialIndex >= 0) {
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT,this.materials[this.meshs[m].materialIndex].ambient);
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_DIFFUSE,this.materials[this.meshs[m].materialIndex].diffuse);
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR,this.materials[this.meshs[m].materialIndex].specular);
				GL11.glMaterial(GL11.GL_FRONT, GL11.GL_EMISSION,this.materials[this.meshs[m].materialIndex].emissive);
				GL11.glMaterialf(GL11.GL_FRONT, GL11.GL_SHININESS,this.materials[this.meshs[m].materialIndex].shininess);

				if (this.materials[this.meshs[m].materialIndex].textureID > 0) {
					GL11.glBindTexture(GL11.GL_TEXTURE_2D,this.materials[this.meshs[m].materialIndex].textureID);
					GL11.glEnable(GL11.GL_TEXTURE_2D);
				} else {
					GL11.glDisable(GL11.GL_TEXTURE_2D);
				}
			} else {
				GL11.glDisable(GL11.GL_TEXTURE_2D);
			}

			// Render each mesh
			GL11.glBegin(GL11.GL_TRIANGLES);
			{
				for (int t = 0; t < this.meshs[m].numTriangles; t++) {
					for (int v = 0; v < 3; v++) {
						GL11.glNormal3f(
										this.triangles[this.meshs[m].triangleIndices[t]].vertexNormals[v][0],
										this.triangles[this.meshs[m].triangleIndices[t]].vertexNormals[v][1],
										this.triangles[this.meshs[m].triangleIndices[t]].vertexNormals[v][2]);
						GL11.glTexCoord2f(
										this.triangles[this.meshs[m].triangleIndices[t]].s[v],
										this.triangles[this.meshs[m].triangleIndices[t]].t[v]);
						GL11.glVertex3f(
										this.vertices[this.triangles[this.meshs[m].triangleIndices[t]].vertexIndices[v]].vertex.x,
										this.vertices[this.triangles[this.meshs[m].triangleIndices[t]].vertexIndices[v]].vertex.y,
										this.vertices[this.triangles[this.meshs[m].triangleIndices[t]].vertexIndices[v]].vertex.z);
					}
				}
			}
			GL11.glEnd();

		}

		// Reset texture state
		if (texturingEnabled)
			GL11.glEnable(GL11.GL_TEXTURE_2D);
		else
			GL11.glDisable(GL11.GL_TEXTURE_2D);
	}

	public void reset() {
		for (int i = 0; i < numJoints; i++) {
			joints[i].currentRotationKeyframe = 0;
			joints[i].currentTranslationKeyframe = 0;
			joints[i].finalMatrix = new Matrix4f(joints[i].absoluteMatrix);
		}

		currentTime = 0;
		if (currentAnimation != -1) {
			MS3DAnimation ms3dAnimation = (MS3DAnimation) allAnimations.get(currentAnimation);
			currentTime += ms3dAnimation.startFrame * 1000.0 / animationFPS;
		}
		loopDone = false;
	}

	public void updateAnimation(long time) {

		currentTime += time - lastTime;
		lastTime = time;

		if (currentAnimation == -1) {
			endFrame = totalFrames;
		} else {
			MS3DAnimation ms3dAnimation = (MS3DAnimation) allAnimations.get(currentAnimation);
			endFrame = ms3dAnimation.endFrame;
		}

		if (currentTime >= (endFrame + 1) * 1000.0 / animationFPS) {
			if (loop) {
				reset();
			} else {
				currentTime = (long) ((endFrame + 1) * 1000.0 / animationFPS);
				loopDone = true;
			}
		}

		for (int i = 0; i < numJoints; i++) {
			Vector3f transVec = new Vector3f();
			Matrix4f transform = new Matrix4f();
			transform.setIdentity();

			short frame;
			MS3DJoint joint = joints[i];

			if (joint.numRotationKeyframes == 0
					&& joint.numTranslationKeyframes == 0) {
				joint.finalMatrix = new Matrix4f(joint.absoluteMatrix);
				continue;
			}

			frame = joint.currentTranslationKeyframe;
			while (frame < joint.numTranslationKeyframes
					&& joint.translationKeyframes[frame].time < currentTime) {
				frame++;
			}
			// System.out.println("frame:"+frame);
			joint.currentTranslationKeyframe = frame;

			if (frame == 0) {
				transVec.x = joint.translationKeyframes[0].x;
				transVec.y = joint.translationKeyframes[0].y;
				transVec.z = joint.translationKeyframes[0].z;
			} else if (frame == joint.numTranslationKeyframes) {
				transVec.x = joint.translationKeyframes[frame - 1].x;
				transVec.y = joint.translationKeyframes[frame - 1].y;
				transVec.z = joint.translationKeyframes[frame - 1].z;
			} else {
				MS3DKeyframe curFrame = joint.translationKeyframes[frame];
				MS3DKeyframe prevFrame = joint.translationKeyframes[frame - 1];

				float timeDelta = ((float) (curFrame.time - prevFrame.time));
				float interpValue = (float) ((currentTime - prevFrame.time) / (float) timeDelta);

				transVec.x = prevFrame.x + (curFrame.x - prevFrame.x) * interpValue;
				transVec.y = prevFrame.y + (curFrame.y - prevFrame.y) * interpValue;
				transVec.z = prevFrame.z + (curFrame.z - prevFrame.z) * interpValue;
			}

			//
			frame = joint.currentRotationKeyframe;

			while (frame < joint.numRotationKeyframes
					&& joint.rotationKeyframes[frame].time < currentTime) {
				frame++;
			}
			joint.currentRotationKeyframe = frame;

			if (frame == 0) {
				setRzRyRxRotationTranspose(transform,joint.rotationKeyframes[0].z,joint.rotationKeyframes[0].y,joint.rotationKeyframes[0].x);
			} else if (frame == joint.numRotationKeyframes) {
				setRzRyRxRotationTranspose(transform,joint.rotationKeyframes[frame - 1].z,joint.rotationKeyframes[frame - 1].y,joint.rotationKeyframes[frame - 1].x);
			} else {
				MS3DKeyframe curFrame = joint.rotationKeyframes[frame];
				MS3DKeyframe prevFrame = joint.rotationKeyframes[frame - 1];

				float timeDelta = ((float) (curFrame.time - prevFrame.time));
				float interpValue = (float) ((currentTime - prevFrame.time) / timeDelta);

				Vector3f rotVec = new Vector3f();

				rotVec.x = prevFrame.x + (curFrame.x - prevFrame.x) * interpValue;
				rotVec.y = prevFrame.y + (curFrame.y - prevFrame.y) * interpValue;
				rotVec.z = prevFrame.z + (curFrame.z - prevFrame.z) * interpValue;

				setRzRyRxRotationTranspose(transform, rotVec.z, rotVec.y, rotVec.x);

			}

			// Translation
			setTranslationTranspose(transform, transVec.x, transVec.y, transVec.z);

			Matrix4f relativeFinal = new Matrix4f();

			mulTransposeBothTanspose(relativeFinal, joint.relativeMatrix, transform);

			if (joint.parentName.equals("")) {

				joint.finalMatrix = relativeFinal;

			} else {

				MS3DJoint father = (MS3DJoint) allJoints.get(joint.parentName);

				joint.finalMatrix = new Matrix4f();

				mulTransposeBothTanspose(joint.finalMatrix, father.finalMatrix, relativeFinal);

			}

		}

	}

	public static void setRzRyRxRotationTranspose(Matrix4f matrix, float z, float y, float x) {
		if (matrix == null) {
			matrix = new Matrix4f();
			matrix.setIdentity();
		}

		double cosinusX = Math.cos(x);
		double sinusX = Math.sin(x);
		double cosinusY = Math.cos(y);
		double sinusY = Math.sin(y);
		double cosinusZ = Math.cos(z);
		double sinusZ = Math.sin(z);

		matrix.m00 = (float) (cosinusY * cosinusZ);
		matrix.m01 = (float) (cosinusY * sinusZ);
		matrix.m02 = (float) (-sinusY);
		// do not alter m03

		matrix.m10 = (float) (sinusX * sinusY * cosinusZ - cosinusX * sinusZ);
		matrix.m11 = (float) (sinusX * sinusY * sinusZ + cosinusX * cosinusZ);
		matrix.m12 = (float) (sinusX * cosinusY);
		// do not alter m13

		matrix.m20 = (float) (cosinusX * sinusY * cosinusZ + sinusX * sinusZ);
		matrix.m21 = (float) (cosinusX * sinusY * sinusZ - sinusX * cosinusZ);
		matrix.m22 = (float) (cosinusX * cosinusY);
		// do not alter m23

		// do not alter m30 - m33
	}

	public static void setTranslationTranspose(Matrix4f matrix, float x, float y, float z) {
		if (matrix == null) {
			matrix = new Matrix4f();
			matrix.setIdentity();
		}

		// do not alter m00 - m23
		matrix.m30 = x;
		matrix.m31 = y;
		matrix.m32 = z;

		matrix.m33 = 1.0f;

	}

	public static void mulTransposeBothTanspose(Matrix4f matrix, Matrix4f matrixA, Matrix4f matrixB) {
		if (matrix == null) {
			matrix = new Matrix4f();
		}

		matrix.m00 = matrixA.m00 * matrixB.m00 + matrixA.m10 * matrixB.m01
				+ matrixA.m20 * matrixB.m02;
		matrix.m01 = matrixA.m01 * matrixB.m00 + matrixA.m11 * matrixB.m01
				+ matrixA.m21 * matrixB.m02;
		matrix.m02 = matrixA.m02 * matrixB.m00 + matrixA.m12 * matrixB.m01
				+ matrixA.m22 * matrixB.m02;
		matrix.m03 = 0.0f;

		matrix.m10 = matrixA.m00 * matrixB.m10 + matrixA.m10 * matrixB.m11
				+ matrixA.m20 * matrixB.m12;
		matrix.m11 = matrixA.m01 * matrixB.m10 + matrixA.m11 * matrixB.m11
				+ matrixA.m21 * matrixB.m12;
		matrix.m12 = matrixA.m02 * matrixB.m10 + matrixA.m12 * matrixB.m11
				+ matrixA.m22 * matrixB.m12;
		matrix.m13 = 0.0f;

		matrix.m20 = matrixA.m00 * matrixB.m20 + matrixA.m10 * matrixB.m21
				+ matrixA.m20 * matrixB.m22;
		matrix.m21 = matrixA.m01 * matrixB.m20 + matrixA.m11 * matrixB.m21
				+ matrixA.m21 * matrixB.m22;
		matrix.m22 = matrixA.m02 * matrixB.m20 + matrixA.m12 * matrixB.m21
				+ matrixA.m22 * matrixB.m22;
		matrix.m23 = 0.0f;

		matrix.m30 = matrixA.m00 * matrixB.m30 + matrixA.m10 * matrixB.m31
				+ matrixA.m20 * matrixB.m32 + matrixA.m30;
		matrix.m31 = matrixA.m01 * matrixB.m30 + matrixA.m11 * matrixB.m31
				+ matrixA.m21 * matrixB.m32 + matrixA.m31;
		matrix.m32 = matrixA.m02 * matrixB.m30 + matrixA.m12 * matrixB.m31
				+ matrixA.m22 * matrixB.m32 + matrixA.m32;
		matrix.m33 = 1.0f;
	}

	public void addAnimation(MS3DAnimation ms3dAnimation) {
		allAnimations.addElement(ms3dAnimation);
	}

	public void deleteAnimations() {
		for (int i = 0; i < allAnimations.size(); i++) {
			allAnimations.remove(i);
		}
	}

	public int numberAnimations() {
		return allAnimations.size();
	}

	/**
	 * 初始化骨骼和绑定顶点
	 */
	private void makeBones() {
		MS3DJoint joint = null;
		MS3DVertex vertex = null;

		MS3DJoint father = null;

		// make the bone hierarchy
		for (int i = 0; i < numJoints; i++) {
			joint = joints[i];

			joint.relativeMatrix = new Matrix4f();

			// Rotation
			MS3DModel.setRzRyRxRotationTranspose(joint.relativeMatrix,joint.rotation[2], joint.rotation[1], joint.rotation[0]);

			// Translation
			MS3DModel.setTranslationTranspose(joint.relativeMatrix,joint.translation[0], joint.translation[1],joint.translation[2]);

			if (!joint.parentName.equals("")) {
				// 如果是子关节,那么将上一个节点的绝对矩阵乘上这个节点的变幻矩 阵就可以得到这个子节点的绝对矩阵了.
				father = (MS3DJoint) allJoints.get(joint.parentName);

				joint.absoluteMatrix = new Matrix4f();

				MS3DModel.mulTransposeBothTanspose(joint.absoluteMatrix,
						father.absoluteMatrix, joint.relativeMatrix);

			} else {
				// 如果是根关节那么它的绝对矩阵就是它的相对变换矩阵
				joint.absoluteMatrix = new Matrix4f(joint.relativeMatrix);

			}
		}

		// initialize the vertices
		for (int i = 0; i < numVertices; i++) {
			vertex = vertices[i];

			if (vertex.boneID != -1) {
				Matrix4f matrix = joints[vertex.boneID].absoluteMatrix;

				float x = vertex.vertex.x - matrix.m30;
				float y = vertex.vertex.y - matrix.m31;
				float z = vertex.vertex.z - matrix.m32;

				this.vertex[3 * i] = x * matrix.m00 + y * matrix.m01 + z * matrix.m02;
				this.vertex[3 * i + 1] = x * matrix.m10 + y * matrix.m11 + z * matrix.m12;
				this.vertex[3 * i + 2] = x * matrix.m20 + y * matrix.m21 + z * matrix.m22;

			}
		}

	}
	
	private void makeBounding()
	{
		float minX,minY,minZ,maxX,maxY,maxZ;
		minX=minY=minZ=maxX=maxY=maxZ=0;
		Vector3f vertex;
		for(int i=0;i maxX)
					maxX = vertex.x;

				if (vertex.y < minY)
					minY = vertex.y;
				else if (vertex.y > maxY)
					maxY = vertex.y;
				if (vertex.z < minZ)
					minZ = vertex.z;
				else if (vertex.z > maxZ)
					maxZ = vertex.z;

			}
		}
		this.bounding=new Bounding(minX, minY, minZ, maxX, maxY, maxZ);
	}

	/***************************************************************************************************************************************************************************************************
	 * Header of a ms3d file
	 **************************************************************************************************************************************************************************************************/
	private class MS3DHeader {

		/** Read the header */
		public MS3DHeader(BinaryFileReader modelFile) {

			this.ID = modelFile.readString(10);
			this.version = modelFile.readInt();
		}

		/** Check whether the header is valid */
		public boolean isValid() {

			if ((this.ID.equals("MS3D000000") && this.version >= 3 && this.version <= 4))
				return true;
			else
				return false;
		}

		String ID;
		int version;
	}

	/***************************************************************************************************************************************************************************************************
	 * Vertex as used in ms3d files
	 **************************************************************************************************************************************************************************************************/
	@SuppressWarnings("unused")
	private class MS3DVertex {

		/** Read a vertex */
		public MS3DVertex(BinaryFileReader modelFile) {

			this.flags = modelFile.readByte();
			this.vertex = new Vector3f(modelFile.readFloat(), modelFile.readFloat(), modelFile.readFloat());
			this.boneID = modelFile.readByte();
			this.refCount = modelFile.readByte();
		}

		Vector3f vertex;
		int boneID;
		int flags;
		int refCount;
	}

	/***************************************************************************************************************************************************************************************************
	 * Triangle as used in ms3d files
	 **************************************************************************************************************************************************************************************************/
	@SuppressWarnings("unused")
	private class MS3DTriangle {

		/** Read a triangle */
		public MS3DTriangle(BinaryFileReader modelFile) {

			this.flags = modelFile.readShort();
			this.vertexIndices[0] = modelFile.readShort();
			this.vertexIndices[1] = modelFile.readShort();
			this.vertexIndices[2] = modelFile.readShort();
			this.vertexNormals[0][0] = modelFile.readFloat();
			this.vertexNormals[0][1] = modelFile.readFloat();
			this.vertexNormals[0][2] = modelFile.readFloat();
			this.vertexNormals[1][0] = modelFile.readFloat();
			this.vertexNormals[1][1] = modelFile.readFloat();
			this.vertexNormals[1][2] = modelFile.readFloat();
			this.vertexNormals[2][0] = modelFile.readFloat();
			this.vertexNormals[2][1] = modelFile.readFloat();
			this.vertexNormals[2][2] = modelFile.readFloat();
			this.s[0] = modelFile.readFloat();
			this.s[1] = modelFile.readFloat();
			this.s[2] = modelFile.readFloat();
			this.t[0] = 1 - modelFile.readFloat();
			this.t[1] = 1 - modelFile.readFloat();
			this.t[2] = 1 - modelFile.readFloat();
			this.smoothingMesh = modelFile.readByte();
			this.meshIndex = modelFile.readByte();
		}

		int flags;
		int vertexIndices[] = new int[3];
		float[][] vertexNormals = new float[3][3];
		float[] s = new float[3];
		float[] t = new float[3];
		int smoothingMesh;
		int meshIndex;
	}

	/***************************************************************************************************************************************************************************************************
	 * Mesh to group triangles which use the same material
	 **************************************************************************************************************************************************************************************************/
	@SuppressWarnings("unused")
	private class MS3DMesh {

		// Read a mesh
		public MS3DMesh(BinaryFileReader modelFile) {

			this.flags = modelFile.readByte();
			this.name = modelFile.readString(32);
			this.numTriangles = modelFile.readShort();
			this.triangleIndices = new int[this.numTriangles];
			for (int i = 0; i < this.numTriangles; i++)
				this.triangleIndices[i] = modelFile.readShort();
			this.materialIndex = modelFile.readByte();
		}

		String name;
		int materialIndex;
		int numTriangles;
		int[] triangleIndices;
		int flags;
	}

	/***************************************************************************************************************************************************************************************************
	 * Material as used in ms3d files
	 **************************************************************************************************************************************************************************************************/
	@SuppressWarnings("unused")
	private class MS3DMaterial {

		// Read a material
		public MS3DMaterial(BinaryFileReader modelFile) {

			this.name = modelFile.readString(32);
			float[] ambientArray = new float[] { modelFile.readFloat(),modelFile.readFloat(), modelFile.readFloat(),modelFile.readFloat() };
			float[] diffuseArray = new float[] { modelFile.readFloat(),modelFile.readFloat(), modelFile.readFloat(),modelFile.readFloat() };
			float[] specularArray = new float[] { modelFile.readFloat(),modelFile.readFloat(), modelFile.readFloat(),modelFile.readFloat() };
			float[] emissiveArray = new float[] { modelFile.readFloat(),modelFile.readFloat(), modelFile.readFloat(),modelFile.readFloat() };
			this.shininess = modelFile.readFloat();
			this.transparency = modelFile.readFloat();
			this.mode = modelFile.readByte();
			this.texturemap = modelFile.readString(128);
			this.alphamap = modelFile.readString(128);

			// // Fix paths
			if (this.texturemap.startsWith("..\\"))
				this.texturemap = this.texturemap.substring(3);

			if (this.texturemap.startsWith(".\\"))
				this.texturemap = this.texturemap.substring(2);

			if (this.alphamap.startsWith("..\\"))
				this.alphamap = this.alphamap.substring(3);

			if (this.alphamap.startsWith(".\\"))
				this.alphamap = this.alphamap.substring(2);

			// Fill buffers
			this.ambient.put(ambientArray).flip();
			this.diffuse.put(diffuseArray).flip();
			this.specular.put(specularArray).flip();
			this.emissive.put(emissiveArray).flip();
		}

		String name;
		String texturemap;
		int textureID;
		String alphamap;
		FloatBuffer ambient = BufferUtils.createFloatBuffer(4);
		FloatBuffer diffuse = BufferUtils.createFloatBuffer(4);
		FloatBuffer specular = BufferUtils.createFloatBuffer(4);
		FloatBuffer emissive = BufferUtils.createFloatBuffer(4);
		float shininess;
		float transparency;
		int mode;
	}

	/***************************************************************************************************************************************************************************************************
	 * Joint information as used in ms3d files
	 **************************************************************************************************************************************************************************************************/
	@SuppressWarnings("unused")
	private class MS3DJoint {

		// Read Joint
		public MS3DJoint(BinaryFileReader modelFile) {
			this.flag = modelFile.readByte();
			this.name = modelFile.readString(32);
			System.out.print(name + ":");
			this.parentName = modelFile.readString(32);
			this.rotation[0] = modelFile.readFloat();
			this.rotation[1] = modelFile.readFloat();
			this.rotation[2] = modelFile.readFloat();
			this.translation[0] = modelFile.readFloat();
			this.translation[1] = modelFile.readFloat();
			this.translation[2] = modelFile.readFloat();
			this.numRotationKeyframes = modelFile.readShort();
			this.numTranslationKeyframes = modelFile.readShort();
			System.out.println(this.numRotationKeyframes + ","
					+ this.numTranslationKeyframes);

			this.rotationKeyframes = new MS3DKeyframe[numRotationKeyframes];
			for (int i = 0; i < this.numRotationKeyframes; i++)
				this.rotationKeyframes[i] = new MS3DKeyframe(modelFile);

			this.translationKeyframes = new MS3DKeyframe[numTranslationKeyframes];
			for (int i = 0; i < this.numTranslationKeyframes; i++)
				this.translationKeyframes[i] = new MS3DKeyframe(modelFile);

		}

		int flag;
		String name;
		String parentName;
		float[] rotation = new float[3];
		float[] translation = new float[3];
		int numRotationKeyframes;
		int numTranslationKeyframes;
		MS3DKeyframe[] rotationKeyframes;
		MS3DKeyframe[] translationKeyframes;

		Matrix4f absoluteMatrix;
		Matrix4f relativeMatrix;
		Matrix4f finalMatrix;
		short currentRotationKeyframe;
		short currentTranslationKeyframe;
	}

	/***************************************************************************************************************************************************************************************************
	 * Keyframe as used in ms3d files
	 **************************************************************************************************************************************************************************************************/
	private class MS3DKeyframe {

		// Read Keyframe
		public MS3DKeyframe(BinaryFileReader modelFile) {
			this.time = (long) (modelFile.readFloat() * 1000);
			this.x = modelFile.readFloat();
			this.y = modelFile.readFloat();
			this.z = modelFile.readFloat();
		}

		float time; // time in seconds
		float x, y, z;
	}

	@SuppressWarnings("unused")
	private class MS3DAnimation {

		short startFrame;
		short endFrame;

		public MS3DAnimation() {
			this.startFrame = 0;
			this.endFrame = 0;
		}

		/** Creates a new instance of MS3DAnimation */
		public MS3DAnimation(short startFrame, short endFrame) {
			this.startFrame = startFrame;
			this.endFrame = endFrame;
		}

		public MS3DAnimation(int startFrame, int endFrame) {
			this.startFrame = (short) startFrame;
			this.endFrame = (short) endFrame;
		}

	}

	public Bounding getBounding() {
		return bounding;
	}

	
}

演示效果如下:

MS3D模型载入与演示(支持动画)_第1张图片

你可能感兴趣的:(OpenGL)