Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cstdio>
- #include <fstream>
- #include <assert.h>
- #include <iostream>
- #include <OpenGL/gl.h>
- #include <GLUT/glut.h>
- #include "Milkshape.h"
- #include "Quaternion.h"
- #include "LodePng.h"
- #include "Interpolator.h"
- // http://web.archive.org/web/20050305044436/http://rsn.gamedev.net/tutorials/ms3danim.asp
- using std::ifstream;
- using std::cout;
- #define READ1(x) input.read((char*)&(x), 1)
- #define READ2(x) input.read((char*)&(x), 2)
- #define READ4(x) input.read((char*)&(x), 4)
- #define READ6(x) input.read((char*)&(x), 6)
- #define READ10(x) input.read((char*)&(x), 10)
- #define READ12(x) input.read((char*)&(x), 12)
- #define READ16(x) input.read((char*)&(x), 16)
- #define READ32(x) input.read((char*)&(x), 32)
- #define READ36(x) input.read((char*)&(x), 36)
- #define READ128(x) input.read((char*)&(x), 128)
- MS3D::~MS3D() {
- glBindTexture(GL_TEXTURE_2D, 0);
- for (int i = 0; i < int(m_nNumMaterials); ++i) {
- if (m_vMaterials[0].textureId != -1)
- glDeleteTextures(1, (unsigned int*)&m_vMaterials[0].textureId);
- if (m_vMaterials[0].alphaMapId != -1)
- glDeleteTextures(1, (unsigned int*)&m_vMaterials[0].alphaMapId);
- }
- }
- MS3D::MS3D(const char* filePath) {
- memset(&m_tHeader, 0, sizeof(MS3DHeader));
- ifstream input; input.open(filePath, std::ios::in | std::ios::binary);
- READ10(m_tHeader.identification[0]);
- READ4(m_tHeader.version);
- READ2(m_nNumVerts);
- m_vVerts.reserve(m_nNumVerts);
- MS3DVertex dummyVertex;
- for (int i = 0; i < int(m_nNumVerts); ++i) {
- m_vVerts.push_back(dummyVertex);
- MS3DVertex& vertex = m_vVerts[i];
- READ1(vertex.flags);
- READ12(vertex.position[0]);
- READ1(vertex.boneId);
- READ1(vertex.referenceCount);
- }
- READ2(m_nNumTriangles);
- m_vTriangles.reserve(m_nNumTriangles);
- MS3DFace dummyTriangle;
- for (int i = 0; i < int(m_nNumTriangles); ++i) {
- m_vTriangles.push_back(dummyTriangle);
- MS3DFace& triangle = m_vTriangles[i];
- READ2(triangle.flags);
- READ6(triangle.vertexIndices[0]);
- READ12(triangle.vertexNormals[0][0]);
- READ12(triangle.vertexNormals[1][0]);
- READ12(triangle.vertexNormals[2][0]);
- READ12(triangle.s[0]);
- READ12(triangle.t[0]);
- READ1(triangle.smoothingGroup);
- READ1(triangle.groupIndex);
- }
- READ2(m_nNumGroups);
- m_vSubmeshes.reserve(m_nNumGroups);
- MS3DGroup dummyGroup;
- for (int i = 0; i < int(m_nNumGroups); ++i) {
- m_vSubmeshes.push_back(dummyGroup);
- MS3DGroup& group = m_vSubmeshes[i];
- READ1(group.flags);
- memset(group.name, 0, 32);
- READ32(group.name[0]);
- READ2(group.numTriangles);
- group.triangleIndices.reserve(group.numTriangles);
- for (int j = 0; j < int(group.numTriangles); ++j) {
- group.triangleIndices.push_back(0);
- READ2(group.triangleIndices[j]);
- }
- READ1(group.materialId);
- }
- READ2(m_nNumMaterials);
- m_vMaterials.reserve(m_nNumMaterials);
- MS3DMaterial dummyMaterial;
- for (int i = 0; i < int(m_nNumMaterials); ++i) {
- m_vMaterials.push_back(dummyMaterial);
- MS3DMaterial& material = m_vMaterials[i];
- memset(material.name, 0, 32);
- READ32(material.name[0]);
- READ16(material.ambient[0]);
- READ16(material.diffuse[0]);
- READ16(material.specular[0]);
- READ16(material.emissive[0]);
- READ4(material.shininess);
- READ4(material.transparency);
- READ1(material.mode);
- memset(material.texture, 0, 128);
- READ128(material.texture[0]);
- memset(material.alphaMap, 0, 128);
- READ128(material.alphaMap[0]);
- material.textureId = -1;
- if (material.texture[0] != 0)
- material.textureId = LoadTexture(material.texture);
- material.alphaMapId = -1;
- if (material.alphaMap[0] != 0)
- material.alphaMapId = LoadTexture(material.alphaMap);
- }
- READ4(m_nFPS);
- m_nFPSReciprocal = 1.0f / m_nFPS;
- READ4(m_nCurTime);
- READ4(m_nNumFrames);
- READ2(m_nNumJoints);
- m_vJoints.reserve(m_nNumJoints);
- MS3DJoint dummyJoint;
- MS3DFrame dummyFrame;
- MS3DRotationFrame dummyRotation;
- MS3DTranslationFrame dummyTranslation;
- for (int i = 0; i < int(m_nNumJoints); ++i) {
- m_vJoints.push_back(dummyJoint);
- MS3DJoint& joint = m_vJoints[i];
- READ1(joint.flags);
- memset(joint.name, 0, 32);
- READ32(joint.name[0]);
- memset(joint.parentName, 0, 32);
- READ32(joint.parentName[0]);
- READ12(joint.rotation[0]);
- READ12(joint.translation[0]);
- READ2(joint.numRotationFrames);
- READ2(joint.numTranslationFrames);
- joint.rawRotationFrames.reserve(joint.numRotationFrames);
- joint.rawTranslationFrames.reserve(joint.numTranslationFrames);
- for (int j = 0; j < joint.numRotationFrames; ++j) {
- joint.rawRotationFrames.push_back(dummyFrame);
- READ4(joint.rawRotationFrames[j].time);
- READ12(joint.rawRotationFrames[j].data[0]);
- }
- for (int j = 0; j < joint.numTranslationFrames; ++j) {
- joint.rawTranslationFrames.push_back(dummyFrame);
- READ4(joint.rawTranslationFrames[j].time);
- READ12(joint.rawTranslationFrames[j].data[0]);
- }
- }
- PrepareBones();
- input.close();
- m_nCurTime = 0.0f;
- }
- void MS3D::PrepareBones() {
- // Assign each bone a parent
- for (int i = 0; i < int(m_nNumJoints); ++i) {
- MS3DJoint& joint = m_vJoints[i];
- joint.parentId = -1;
- char buffer[33]; memset(buffer, 0, 33);
- memcpy(buffer, joint.name, 32);
- if (buffer[0] != '\0') {
- memcpy(buffer, joint.parentName, 32);
- string parent = buffer; string thisJoint;
- for (int j = 0; j < int(m_nNumJoints); ++j) {
- memset(buffer, 0, 33);
- memcpy(buffer, m_vJoints[j].name, 32);
- thisJoint = buffer;
- if (thisJoint == parent) {
- joint.parentId = j;
- break;
- }
- }
- }
- if (joint.parentId == -1) {
- log << "Found \"root\" joint\n";
- }
- }
- // Find the absolute (world position) for each bone
- for (int i = 0; i < int(m_nNumJoints); ++i) {
- MS3DJoint& joint = m_vJoints[i];
- Matrix localTransform = BuildMatrix(ToRotation(joint.rotation), ToTranslation(joint.translation));
- if (joint.parentId == -1) {
- joint.finalTransform = localTransform;
- } else {
- joint.finalTransform = m_vJoints[joint.parentId].finalTransform * localTransform;
- }
- }
- // Multiply every vertex (position) by the inverse of the world position of the bones
- for (int i = 0; i < int(m_nNumVerts); ++i) {
- MS3DVertex& vertex = m_vVerts[i];
- Vector vertexPosition(vertex.position[0], vertex.position[1], vertex.position[2]);
- vertexPosition.w = 1.0f;
- if (vertex.boneId != -1) {
- Matrix invFinalTransform = m_vJoints[vertex.boneId].finalTransform.Inverse();
- vertexPosition = invFinalTransform * vertexPosition;
- }
- vertex.position[0] = vertexPosition.x;
- vertex.position[1] = vertexPosition.y;
- vertex.position[2] = vertexPosition.z;
- }
- // Multiply every vertex (normal) by the inverse of the world position of the bones
- for (int i = 0; i < int(m_nNumTriangles); ++i) {
- MS3DFace& triangle = m_vTriangles[i];
- for (int j = 0; j < 3; ++j) {
- Vector vertexNormal(triangle.vertexNormals[j][0], triangle.vertexNormals[j][1], triangle.vertexNormals[j][2]);
- vertexNormal.w = 0.0f;
- if (m_vVerts[triangle.vertexIndices[j]].boneId != -1) {
- Matrix invFinalTransform = m_vJoints[m_vVerts[triangle.vertexIndices[j]].boneId].finalTransform.Inverse();
- vertexNormal = invFinalTransform * vertexNormal;
- }
- triangle.vertexNormals[j][0] = vertexNormal.x;
- triangle.vertexNormals[j][1] = vertexNormal.y;
- triangle.vertexNormals[j][2] = vertexNormal.z;
- }
- }
- }
- void MS3D::RenderAnimated() {
- glColor3f(1.0f, 1.0f, 1.0f);
- for (int i = 0; i < int(m_nNumGroups); ++i) {
- MS3DGroup& submesh = m_vSubmeshes[i];
- MS3DMaterial& material = m_vMaterials[submesh.materialId];
- glBindTexture(GL_TEXTURE_2D, material.textureId);
- glBegin(GL_TRIANGLES);
- for (int j = 0; j < submesh.numTriangles; ++j) {
- MS3DFace& triangle = m_vTriangles[submesh.triangleIndices[j]];
- for (int k = 0; k < 3; ++k) {
- glTexCoord2f(triangle.s[k], triangle.t[k]);
- Vector vertexNormal(triangle.vertexNormals[k][0], triangle.vertexNormals[k][1], triangle.vertexNormals[k][2]);
- Vector vertexPosition(m_vVerts[triangle.vertexIndices[k]].position[0], m_vVerts[triangle.vertexIndices[k]].position[1], m_vVerts[triangle.vertexIndices[k]].position[2]);
- if (m_vVerts[triangle.vertexIndices[k]].boneId != -1) {
- Matrix finalTransform = m_vJoints[m_vVerts[triangle.vertexIndices[k]].boneId].finalTransform;
- vertexPosition.w = 1.0f; vertexNormal.w = 0.0f;
- vertexPosition = finalTransform * vertexPosition;
- vertexNormal = finalTransform * vertexNormal;
- vertexNormal.Normalize();
- }
- glNormal3f(vertexNormal.x, vertexNormal.y, vertexNormal.z);
- glVertex3f(vertexPosition.x, vertexPosition.y, vertexPosition.z);
- }
- }
- glEnd();
- }
- }
- void MS3D::UpdateAnimation(float deltaTime) {
- // Update animation time
- if (m_nCurTime > m_nNumFrames * m_nFPSReciprocal) m_nCurTime = 0.0f;
- else m_nCurTime += deltaTime * 0.5f;
- // Loop trough each joint to set the animation data
- for (int i = 0; i < int(m_nNumJoints); ++i) {
- MS3DJoint& joint = m_vJoints[i];
- Matrix localTransform = BuildMatrix(ToRotation(joint.rotation), ToTranslation(joint.translation));
- // Will be using this to build the final matrix
- Vector animatedTranslation; Quaternion animatedRotation;
- // If there are no frames to animate, just stop
- if (joint.numRotationFrames == 0 && joint.numTranslationFrames == 0 )
- continue;
- // Find the translation frame number
- int frame = 0;
- while (frame < joint.numTranslationFrames &&
- joint.rawTranslationFrames[frame].time < m_nCurTime) ++frame;
- if (frame > joint.numTranslationFrames) frame = joint.numTranslationFrames;
- // Interpolate translation
- if (frame == 0) { // No prev frame
- animatedTranslation = ToTranslation(joint.rawTranslationFrames[0].data);
- } else if (frame == joint.numTranslationFrames) { // No "this" frame
- animatedTranslation = ToTranslation(joint.rawTranslationFrames[frame - 1].data);
- } else { // Do the actual interpolation
- MS3DFrame& curFrame = joint.rawTranslationFrames[frame];
- MS3DFrame& prevFrame = joint.rawTranslationFrames[frame - 1];
- float timeDelta = curFrame.time - prevFrame.time;
- float interpValue = (float)((m_nCurTime - prevFrame.time) / timeDelta);
- animatedTranslation = Lerp(ToTranslation(prevFrame.data), ToTranslation(curFrame.data), interpValue);
- }
- // Find the rotation frame
- frame = 0;
- while (frame < joint.numRotationFrames &&
- joint.rawRotationFrames[frame].time < m_nCurTime) ++frame;
- if (frame > joint.numRotationFrames) frame = joint.numRotationFrames;
- // Interpolate rotation
- if (frame == 0) { // No prev frame
- animatedRotation = ToRotation(joint.rawRotationFrames[0].data);
- } else if (frame == joint.numRotationFrames) { // No "this" frame
- animatedRotation = ToRotation(joint.rawRotationFrames[frame - 1].data);
- } else { // Do actual interpolation
- MS3DFrame& curFrame = joint.rawRotationFrames[frame];
- MS3DFrame& prevFrame = joint.rawRotationFrames[frame - 1];
- float timeDelta = curFrame.time - prevFrame.time;
- float interpValue = (float)((m_nCurTime - prevFrame.time) / timeDelta);
- animatedRotation = Slerp(ToRotation(prevFrame.data), ToRotation(curFrame.data), interpValue);
- }
- // Animate the bone in local space
- Matrix animationTransform = BuildMatrix(animatedRotation, animatedTranslation);
- localTransform = localTransform * animationTransform;
- if (joint.parentId == -1) {
- joint.finalTransform = localTransform;
- } else {
- joint.finalTransform = m_vJoints[joint.parentId].finalTransform * localTransform;
- }
- }
- }
- Matrix BuildMatrix(const Quaternion& rot, const Vector& trans) {
- Quaternion q = rot;
- Matrix m = Matrix::Translation(trans.x, trans.y, trans.z);
- m.SetRotation(q.ToMatrix());
- return m;
- }
- Vector ToTranslation(float* f) {
- Vector v(f[0], f[1], f[2]);
- v.w = 1.0f;
- return v;
- }
- Quaternion ToRotation(float* f) {
- Quaternion q;
- q.Euler(f[0], f[1], f[2]);
- q.Normalize();
- return q;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement