📄 ms3d.cpp
字号:
/*
Milkshape 3D Model Loading Class by Jim Adams
Milkshape 3D .ms3d file format:
Header
# Vertices
Vertex data
# Faces
Face data
# Groups
Group data
# Materials
Material data
Animation FPS
CurrentTime
Total Frames
# Bones
Bone Data
*/
#include <windows.h>
#include <stdio.h>
#include "d3d8.h"
#include "d3dx8.h"
#include "texture.h"
#include "mesh.h"
#include "MS3D.h"
BOOL LoadMS3D(cMeshGroup *MeshGroup, char *Filename,
char *TexturePath, char *DefaultTexture,
IDirect3DDevice8 *pDevice, cTextureManager *pManager)
{
char *Names[2];
Names[0] = Filename;
Names[1] = Filename;
return LoadMS3D(MeshGroup, Filename, 1, (char**)&Names, TexturePath, DefaultTexture, pDevice, pManager);
}
BOOL LoadMS3D(cMeshGroup *MeshGroup, char *Filename,
DWORD NumAnimations, char **AnimFilenames,
char *TexturePath, char *DefaultTexture,
IDirect3DDevice8 *pDevice, cTextureManager *pManager)
{
FILE *fp;
sMS3DHeader Header;
DWORD i, j, k, Num, Pos, AnimPos;
unsigned short msNumVertices;
sMS3DVertex *msVertices = NULL;
sMeshVertex *Vertices;
unsigned short msNumFaces;
sMS3DFace *msFaces = NULL;
unsigned short *Indices;
unsigned short msNumGroups;
sMS3DGroup *msGroups = NULL;
unsigned short msNumMaterials;
sMS3DMaterial *msMaterials = NULL;
unsigned short msNumBones;
sMS3DBone *msBones = NULL;
float msAnimationFPS;
float msCurrentTime;
int msTotalFrames;
cMeshContainer *Mesh = NULL;
cAnimationContainer *Anim = NULL;
// Error checking
if(MeshGroup == NULL || Filename == NULL || pDevice == NULL || pManager == NULL)
return FALSE;
// Free a prior model
MeshGroup->Free();
// Assign mesh type
MeshGroup->m_Type = MESH_BONES;
// Assign device and texture manager
MeshGroup->m_Device = pDevice;
MeshGroup->m_Manager = pManager;
// Open file and read header
if((fp=fopen(Filename, "rb"))==NULL)
return FALSE;
fread(&Header, 1, sizeof(sMS3DHeader), fp);
// Make sure header is valid
if(memcmp(Header.Signature, "MS3D000000", 10)) {
fclose(fp);
return FALSE;
}
// Read data into some temporary buffers
// Read vertex data
fread(&msNumVertices, 1, sizeof(short), fp);
if(msNumVertices) {
msVertices = new sMS3DVertex[msNumVertices];
for(i=0;i<msNumVertices;i++) {
fread(&msVertices[i], 1, sizeof(sMS3DVertex), fp);
// Assign to bone # 0 if none assigned
if(msVertices[i].Bone == -1)
msVertices[i].Bone = 0;
}
}
// Read face data
fread(&msNumFaces, 1, sizeof(short), fp);
if(msNumFaces) {
msFaces = new sMS3DFace[msNumFaces];
for(i=0;i<msNumFaces;i++)
fread(&msFaces[i], 1, sizeof(sMS3DFace), fp);
}
// Read groups
fread(&msNumGroups, 1, sizeof(short), fp);
if(msNumGroups) {
msGroups = new sMS3DGroup[msNumGroups];
for(i=0;i<msNumGroups;i++) {
fread(&msGroups[i], 1, sizeof(msGroups[i].Header), fp);
if((Num = msGroups[i].Header.NumFaces)) {
msGroups[i].Indices = new unsigned short[Num];
for(j=0;j<Num;j++)
fread(&msGroups[i].Indices[j], 1, sizeof(short), fp);
}
fread(&msGroups[i].Material, 1, sizeof(char), fp);
// Change group material to 0 if none assigned (-1)
if(msGroups[i].Material == -1)
msGroups[i].Material = 0;
}
}
// Read materials, creating a default one if none in file
fread(&msNumMaterials, 1, sizeof(short), fp);
if(!msNumMaterials) {
// Create a single material and color it white
msNumMaterials = 1;
msMaterials = new sMS3DMaterial[1];
ZeroMemory(&msMaterials[0], sizeof(sMS3DMaterial));
msMaterials[0].Diffuse[0] = msMaterials[0].Diffuse[1] = msMaterials[0].Diffuse[2] = 1.0f;
// Set all groups to use material #0
// If there are no materials, set all groups to
// use material #0
if(msNumGroups) {
for(i=0;i<msNumGroups;i++)
msGroups[i].Material = 0;
}
} else {
// Read in all materials from file
msMaterials = new sMS3DMaterial[msNumMaterials];
for(i=0;i<msNumMaterials;i++)
fread(&msMaterials[i], 1, sizeof(sMS3DMaterial), fp);
}
// Record position of animation data in file (for loading animations)
AnimPos = ftell(fp);
// Read in FPS, current editor time, and # frames
fread(&msAnimationFPS, 1, sizeof(float), fp);
fread(&msCurrentTime, 1, sizeof(float), fp);
fread(&msTotalFrames, 1, sizeof(int), fp);
// Read in bones, skipping keyframe data
fread(&msNumBones, 1, sizeof(short), fp);
if(msNumBones) {
msBones = new sMS3DBone[msNumBones];
for(i=0;i<msNumBones;i++) {
fread(&msBones[i], 1, sizeof(msBones[i].Header), fp);
// Skip by position key frames
if((Num = msBones[i].Header.NumRotFrames))
fseek(fp, Num * sizeof(sMS3DKeyFrame), SEEK_CUR);
// Skip by animation key frames
if((Num=msBones[i].Header.NumPosFrames))
fseek(fp, Num * sizeof(sMS3DKeyFrame), SEEK_CUR);
}
}
// Close file
fclose(fp);
// At this point, the entire Milkshape 3D model is loaded
// in memory. You need to parse this data into a
// cMeshContainer object now.
// Create a single mesh to use
MeshGroup->m_NumMeshes = 1;
MeshGroup->m_Meshes = Mesh = new cMeshContainer();
// Name the mesh by clipping out mesh filename (without path and extension)
Mesh->m_Name = CleanMS3DName(Filename);
// Store mesh values ////////////////////////////////////
// Notice that the number of vertices is based on the number
// of faces. The reason being is that Milkshape 3D stores
// texture coordinates based on faces, so a single vertex
// may have multiple texture coordinates. Same goes for normals.
Mesh->m_NumVertices = (DWORD)msNumFaces * 3;
Mesh->m_NumFaces = (DWORD)msNumFaces;
Mesh->m_NumBones = (DWORD)msNumBones;
Mesh->m_NumMaterials = (DWORD)msNumMaterials;
// Create the bone hierarchy ////////////////////////////
if(Mesh->m_NumBones) {
Mesh->m_Bones = new cBoneHierarchy();
// Create each bone in the hierarchy
Mesh->m_Bones->m_Bones = new cBoneContainer[Mesh->m_NumBones]();
// Create the bone matrices
Mesh->m_Bones->m_matCombined = new D3DXMATRIX[Mesh->m_NumBones];
Mesh->m_Bones->m_matTransformations = new D3DXMATRIX[Mesh->m_NumBones];
Mesh->m_Bones->m_matInversed = new D3DXMATRIX[Mesh->m_NumBones];
for(i=0;i<Mesh->m_NumBones;i++) {
// Point bones to matrices
Mesh->m_Bones->m_Bones[i].m_matCombined = &Mesh->m_Bones->m_matCombined[i];
Mesh->m_Bones->m_Bones[i].m_matTransformation = &Mesh->m_Bones->m_matTransformations[i];
// Build the hierarchy
Mesh->m_Bones->m_Bones[i].m_Name = strdup(msBones[i].Header.Name);
for(j=0;j<Mesh->m_NumBones;j++) {
// Match parent
if(i != j && msBones[i].Header.Parent[0] && !stricmp(msBones[i].Header.Parent, msBones[j].Header.Name)) {
// i = current bone, j = parent bone
// Link sibling
Mesh->m_Bones->m_Bones[i].m_Sibling = Mesh->m_Bones->m_Bones[j].m_Child;
// Link child
Mesh->m_Bones->m_Bones[j].m_Child = &Mesh->m_Bones->m_Bones[i];
}
}
// Create default pose and store in transformation matrix
D3DXMATRIX matX, matY, matZ, matXYZ, matWorld;
D3DXMatrixRotationX(&matX, msBones[i].Header.Rotation[0]);
D3DXMatrixRotationY(&matY, msBones[i].Header.Rotation[1]);
D3DXMatrixRotationZ(&matZ, msBones[i].Header.Rotation[2]);
D3DXMatrixTranslation(&matXYZ,
msBones[i].Header.Position[0],
msBones[i].Header.Position[1],
msBones[i].Header.Position[2]);
D3DXMatrixMultiply(&matWorld, &matX, &matY);
D3DXMatrixMultiply(&matWorld, &matWorld, &matZ);
D3DXMatrixMultiply(&Mesh->m_Bones->m_matTransformations[i], &matWorld, &matXYZ);
}
// Since the mesh has been converted from right-handed
// to left-handed coordinates, the bones than also need
// to be flipped. Since the bones are based off
// transformation matrices, than the root bone matrix
// must be 'reflected' in order to be correct.
// To reflect a matrix, you need to construct a splitting
// plane that defines where to reflect.
D3DXPLANE planeReflect;
D3DXMATRIX matReflect;
D3DXPlaneFromPoints(&planeReflect,
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 0.0f, 1.0f),
&D3DXVECTOR3(0.0f, 1.0f, 1.0f));
D3DXMatrixReflect(&matReflect, &planeReflect);
D3DXMatrixMultiply(&Mesh->m_Bones->m_matTransformations[0],
&Mesh->m_Bones->m_matTransformations[0],
&matReflect);
// Update the bone hierarchy and store inversed matrices
Mesh->m_Bones->m_Bones[0].UpdateHierarchy();
// Inverse the combined matrices and store
for(i=0;i<Mesh->m_NumBones;i++)
D3DXMatrixInverse(&Mesh->m_Bones->m_matInversed[i], NULL, &Mesh->m_Bones->m_matCombined[i]);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -