#include "MilkShapeModel.h" /* MS3D STRUCTURES */ // byte-align structures #ifdef _MSC_VER # pragma pack( push, packing ) # pragma pack( 1 ) # define PACK_STRUCT #elif defined( __GNUC__ ) # define PACK_STRUCT __attribute__((packed)) #else # error you must byte-align these structures with the appropriate compiler directives #endif typedef unsigned char byte; typedef unsigned short word; // File header struct MS3DHeader { char m_ID[10]; int m_version; } PACK_STRUCT; // Vertex information struct MS3DVertex { byte m_flags; float m_vertex[3]; char m_boneID; byte m_refCount; } PACK_STRUCT; // Triangle information struct MS3DTriangle { word m_flags; word m_vertexIndices[3]; float m_vertexNormals[3][3]; float m_s[3], m_t[3]; byte m_smoothingGroup; byte m_groupIndex; } PACK_STRUCT; // Material information struct MS3DMaterial { char m_name[32]; float m_ambient[4]; float m_diffuse[4]; float m_specular[4]; float m_emissive[4]; float m_shininess; // 0.0f - 128.0f float m_transparency; // 0.0f - 1.0f byte m_mode; // 0, 1, 2 is unused now char m_texture[128]; char m_alphamap[128]; } PACK_STRUCT; // Joint information struct MS3DJoint { byte m_flags; char m_name[32]; char m_parentName[32]; float m_rotation[3]; float m_translation[3]; word m_numRotationKeyframes; word m_numTranslationKeyframes; } PACK_STRUCT; // Keyframe data struct MS3DKeyframe { float m_time; float m_parameter[3]; } PACK_STRUCT; // Default alignment #ifdef _MSC_VER # pragma pack( pop, packing ) #endif #undef PACK_STRUCT MilkShapeModel::MilkShapeModel() { m_numMeshes = 0; m_pMeshes = NULL; m_numMaterials = 0; m_pMaterials = NULL; m_numTriangles = 0; m_pTriangles = NULL; m_numVertices = 0; m_pVertices = NULL; m_numJoints = 0; m_pJoints = NULL; } MilkShapeModel::~MilkShapeModel() { int i; for ( i = 0; i < m_numMeshes; i++ ) delete[] m_pMeshes[i].m_pTriangleIndices; for ( i = 0; i < m_numMaterials; i++ ) delete[] m_pMaterials[i].m_pTextureFilename; m_numMeshes = 0; if ( m_pMeshes != NULL ) { delete[] m_pMeshes; m_pMeshes = NULL; } m_numMaterials = 0; if ( m_pMaterials != NULL ) { delete[] m_pMaterials; m_pMaterials = NULL; } m_numTriangles = 0; if ( m_pTriangles != NULL ) { delete[] m_pTriangles; m_pTriangles = NULL; } m_numVertices = 0; if ( m_pVertices != NULL ) { delete[] m_pVertices; m_pVertices = NULL; } m_numJoints = 0; if (m_pJoints != NULL) { delete[] m_pJoints; m_pJoints = NULL; } } bool MilkShapeModel::load(const char* filename) { string file = "data/"; file.append(filename); ifstream inputFile(file.c_str(), ios::in | ios::binary); if (inputFile.fail()) { cout << "could not load model" << endl; return false; } else cout << "loaded model " << filename << " into buffer" << endl; // Check filesize inputFile.seekg(0, ios::end); long fileSize = inputFile.tellg(); inputFile.seekg(0, ios::beg); // Load complete file into buffer char* buffer = new char[fileSize]; inputFile.read(buffer, fileSize); inputFile.close(); // Check header information const char* pPtr = buffer; MS3DHeader *pHeader = (MS3DHeader *) pPtr; pPtr+=sizeof(MS3DHeader); if ( strncmp( pHeader->m_ID, "MS3D000000", 10 ) != 0 ) return false;// "Not A Valid Milkshape3D Model File." if ( pHeader->m_version < 3 || pHeader->m_version > 4 ) return false;// "Unhandled File Version. Only Milkshape3D Version 1.3 And 1.4 Is Supported." cout << "VERSION: " << pHeader->m_version << endl; // Load vertices int nVertices = *( word* )pPtr; m_numVertices = nVertices; m_pVertices = new Vertex[nVertices]; pPtr += sizeof( word ); int i; for ( i = 0; i < nVertices; i++ ) { MS3DVertex *pVertex = ( MS3DVertex* )pPtr; m_pVertices[i].m_boneID = pVertex->m_boneID; memcpy( m_pVertices[i].m_location, pVertex->m_vertex, sizeof( float )*3 ); pPtr += sizeof( MS3DVertex ); } // Load Triangles int nTriangles = *( word* )pPtr; m_numTriangles = nTriangles; m_pTriangles = new Triangle[nTriangles]; pPtr += sizeof( word ); for ( i = 0; i < nTriangles; i++ ) { MS3DTriangle *pTriangle = ( MS3DTriangle* )pPtr; int vertexIndices[3] = { pTriangle->m_vertexIndices[0], pTriangle->m_vertexIndices[1], pTriangle->m_vertexIndices[2] }; float t[3] = { 1.0f-pTriangle->m_t[0], 1.0f-pTriangle->m_t[1], 1.0f-pTriangle->m_t[2] }; memcpy( m_pTriangles[i].m_vertexNormals, pTriangle->m_vertexNormals, sizeof( float )*3*3 ); memcpy( m_pTriangles[i].m_s, pTriangle->m_s, sizeof( float )*3 ); memcpy( m_pTriangles[i].m_t, t, sizeof( float )*3 ); memcpy( m_pTriangles[i].m_vertexIndices, vertexIndices, sizeof( int )*3 ); pPtr += sizeof( MS3DTriangle ); } // Load Meshes int nGroups = *( word* )pPtr; m_numMeshes = nGroups; m_pMeshes = new Mesh[nGroups]; pPtr += sizeof( word ); for ( i = 0; i < nGroups; i++ ) { pPtr += sizeof( byte );// Flags pPtr += 32;// Name word nTriangles = *( word* )pPtr; pPtr += sizeof( word ); int *pTriangleIndices = new int[nTriangles]; for ( int j = 0; j < nTriangles; j++ ) { pTriangleIndices[j] = *( word* )pPtr; pPtr += sizeof( word ); } char materialIndex = *( char* )pPtr; pPtr += sizeof( char ); m_pMeshes[i].m_materialIndex = materialIndex; m_pMeshes[i].m_numTriangles = nTriangles; m_pMeshes[i].m_pTriangleIndices = pTriangleIndices; } // Load Materials int nMaterials = *( word* )pPtr; m_numMaterials = nMaterials; m_pMaterials = new Material[nMaterials]; pPtr += sizeof( word ); for ( i = 0; i < nMaterials; i++ ) { MS3DMaterial *pMaterial = ( MS3DMaterial* )pPtr; memcpy( m_pMaterials[i].m_ambient, pMaterial->m_ambient, sizeof( float )*4 ); memcpy( m_pMaterials[i].m_diffuse, pMaterial->m_diffuse, sizeof( float )*4 ); memcpy( m_pMaterials[i].m_specular, pMaterial->m_specular, sizeof( float )*4 ); memcpy( m_pMaterials[i].m_emissive, pMaterial->m_emissive, sizeof( float )*4 ); m_pMaterials[i].m_shininess = pMaterial->m_shininess; m_pMaterials[i].m_pTextureFilename = new char[strlen( pMaterial->m_texture )+1]; strcpy( m_pMaterials[i].m_pTextureFilename, pMaterial->m_texture ); pPtr += sizeof( MS3DMaterial ); } // Load AnimationFPS float foo = *( float* )pPtr; fAnimationFPS = foo; pPtr += sizeof(float); // Load currentTime float fAnim = *(float*)pPtr; fCurrentTime = fAnim; pPtr += sizeof(float); // Load total frames int tot = *(int*)pPtr; iTotalFrames = tot; pPtr += sizeof(int); // Load joints and keyframes int joints = *(word*)pPtr; m_numJoints = joints; m_pJoints = new Joint[m_numJoints]; pPtr += sizeof ( word ); for ( i = 0; i < m_numJoints; i++ ) { MS3DJoint *pJoint = ( MS3DJoint* )pPtr; m_pJoints[i].numKeyFramesRot = pJoint->m_numRotationKeyframes; m_pJoints[i].numKeyFramesTrans = pJoint->m_numTranslationKeyframes; memcpy(m_pJoints[i].name, pJoint->m_name, sizeof(char)*32); pPtr += sizeof( MS3DJoint ); m_pJoints[i].rotKeyframes = new RotKeyFrame[m_pJoints[i].numKeyFramesRot]; m_pJoints[i].posKeyframes = new PosKeyFrame[m_pJoints[i].numKeyFramesTrans]; for (int j = 0; j < m_pJoints[i].numKeyFramesRot; j++) { MS3DKeyframe *pKey = ( MS3DKeyframe*)pPtr; memcpy( m_pJoints[i].rotKeyframes[j].rotation, pKey->m_parameter, sizeof( float )*3 ); m_pJoints[i].rotKeyframes[j].time = pKey->m_time; pPtr += sizeof(MS3DKeyframe); } for (int j = 0; j < m_pJoints[i].numKeyFramesTrans; j++) { MS3DKeyframe *pKey = ( MS3DKeyframe*)pPtr; memcpy( m_pJoints[i].posKeyframes[j].position, pKey->m_parameter, sizeof( float )*3 ); m_pJoints[i].posKeyframes[j].time = pKey->m_time; pPtr += sizeof(MS3DKeyframe); } } reloadTextures(); delete [] buffer; return true; } void MilkShapeModel::draw() { GLboolean texEnabled = glIsEnabled( GL_TEXTURE_2D ); // Draw by group for ( int i = 0; i < m_numMeshes; i++ ) { int materialIndex = m_pMeshes[i].m_materialIndex; if ( materialIndex >= 0 ) { glMaterialfv( GL_FRONT, GL_AMBIENT, m_pMaterials[materialIndex].m_ambient ); glMaterialfv( GL_FRONT, GL_DIFFUSE, m_pMaterials[materialIndex].m_diffuse ); glMaterialfv( GL_FRONT, GL_SPECULAR, m_pMaterials[materialIndex].m_specular ); glMaterialfv( GL_FRONT, GL_EMISSION, m_pMaterials[materialIndex].m_emissive ); glMaterialf( GL_FRONT, GL_SHININESS, m_pMaterials[materialIndex].m_shininess ); if ( m_pMaterials[materialIndex].m_texture > 0 ) { glBindTexture( GL_TEXTURE_2D, m_pMaterials[materialIndex].m_texture ); glEnable( GL_TEXTURE_2D ); } else glDisable( GL_TEXTURE_2D ); } else { // Material properties? glDisable( GL_TEXTURE_2D ); } glBegin( GL_TRIANGLES ); { for ( int j = 0; j < m_pMeshes[i].m_numTriangles; j++ ) { int triangleIndex = m_pMeshes[i].m_pTriangleIndices[j]; const Triangle* pTri = &m_pTriangles[triangleIndex]; for ( int k = 0; k < 3; k++ ) { int index = pTri->m_vertexIndices[k]; glNormal3fv( pTri->m_vertexNormals[k] ); glTexCoord2f( pTri->m_s[k], pTri->m_t[k] ); glVertex3fv( m_pVertices[index].m_location ); } } } glEnd(); } if ( texEnabled ) glEnable( GL_TEXTURE_2D ); else glDisable( GL_TEXTURE_2D ); } void MilkShapeModel::SetupJoints() { } void MilkShapeModel::reloadTextures() { for ( int i = 0; i < m_numMaterials; i++ ) if ( strlen( m_pMaterials[i].m_pTextureFilename ) > 0 ) { string name = "data/"; name.append(m_pMaterials[i].m_pTextureFilename); Image *image = loadBMP(name.c_str()); image->outputData(); m_pMaterials[i].m_texture = loadTexture(image); delete image; } else m_pMaterials[i].m_texture = 0; } //Makes the image into a texture, and returns the id of the texture GLuint MilkShapeModel::loadTexture(Image *image) { GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->width, image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->pixels); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); return textureId; } void MilkShapeModel::outputData() { for (int i = 0; i < m_numMeshes; i++) { cout << "Mesh: " << i << " materialindex: " << m_pMeshes[i].m_materialIndex << endl; } cout << "Number of Materials: " << m_numMaterials << endl; for (int i = 0; i < m_numMaterials; i++) { cout << "Material: " << i << " textureID: " << m_pMaterials[i].m_texture; cout << " filename: " << m_pMaterials[i].m_pTextureFilename << endl; } for (int i = 0; i < m_numJoints; i++) cout << "joinname: " << m_pJoints[i].name << endl; }