#include "loader_x.hpp" #include "animation.hpp" #include "meshmodel.hpp" #include "pivot.hpp" #include "std.hpp" #include //#include #include #include #include #include #include "../gxruntime/GraphicsRuntime.hpp" extern gxRuntime* gx_runtime; static map frames_map; static int anim_len; static bool conv, flip_tris; static Transform conv_tform; static bool collapse, animonly; static void parseAnimKey(ID3DXFileData* fileData, MeshModel* e) { DWORD sz; int* data; if (fileData->GetData(0, &sz, (void**)&data) < 0) return; int type = *data++; int cnt = *data++; Animation anim = e->getAnimation(); for (int k = 0; k < cnt; ++k) { int time = *data++; int n = *data++; if (time > anim_len) anim_len = time; switch (type) { case 0: if (n == 4) { Quat rot = *(Quat*)data; if (conv) { if (fabs(rot.w) < 1 - FLT_EPSILON) { rot.normalize(); //quat-to-axis/angle float half = acosf(rot.w); if (flip_tris) half = -half; rot = Quat(cosf(half), (conv_tform.m * rot.v).normalized() * sinf(half)); } else rot = Quat(); } anim.setRotationKey(time, rot); } break; case 1: if (n == 3) { Vector scl = *(Vector*)data; if (conv) scl = conv_tform.m * scl; scl.x = fabs(scl.x); scl.y = fabs(scl.y); scl.z = fabs(scl.z); anim.setScaleKey(time, scl); } break; case 2: if (n == 3) { Vector pos = *(Vector*)data; if (conv) pos = conv_tform * pos; anim.setPositionKey(time, pos); } break; } data += n; } e->setAnimation(anim); } static void parseAnim(ID3DXFileData* fileData) { const GUID* guid; IDirectXFileObject* childObj; IDirectXFileData* childData; IDirectXFileDataReference* childRef; MeshModel* frame = 0; //find the frame reference for (; fileData->GetNextObject(&childObj) >= 0; childObj->Release()) { if (childObj->QueryInterface(IID_IDirectXFileDataReference, (void**)&childRef) >= 0) { if (childRef->Resolve(&childData) >= 0) { if (childData->GetType(&guid) >= 0) { if (*guid == TID_D3DRMFrame) { char name[80]; DWORD len = 80; if (childData->GetName(name, &len) >= 0) { map::iterator it = frames_map.find(name); if (it != frames_map.end()) frame = it->second; } } } childData->Release(); } childRef->Release(); } else if (frame && childObj->QueryInterface(IID_IDirectXFileData, (void**)&childData) >= 0) { if (childData->GetType(&guid) >= 0) { if (*guid == TID_D3DRMAnimationKey) { parseAnimKey(childData, frame); } } childData->Release(); } } } static void parseAnimSet(IDirectXFileData* fileData) { const GUID* guid; IDirectXFileObject* childObj; IDirectXFileData* childData; for (; fileData->GetNextObject(&childObj) >= 0; childObj->Release()) { if (childObj->QueryInterface(IID_IDirectXFileData, (void**)&childData) < 0) continue; if (childData->GetType(&guid) >= 0) { if (*guid == TID_D3DRMAnimation) { parseAnim(childData); } } childData->Release(); } } static Brush parseMaterial(IDirectXFileData* fileData) { const GUID* guid; IDirectXFileObject* childObj; IDirectXFileData* childData; Brush brush; DWORD sz; float* data; if (fileData->GetData(0, &sz, (void**)&data) < 0) return brush; brush.setColor(Vector(data[0], data[1], data[2])); if (data[3]) brush.setAlpha(data[3]); for (; fileData->GetNextObject(&childObj) >= 0; childObj->Release()) { if (childObj->QueryInterface(IID_IDirectXFileData, (void**)&childData) < 0) continue; if (childData->GetType(&guid) >= 0) { if (*guid == TID_D3DRMTextureFilename) { DWORD sz; char** data; if (childData->GetData(0, &sz, (void**)&data) >= 0) { brush.setTexture(0, Texture(*data, 0), 0); brush.setColor(Vector(1, 1, 1)); } } } childData->Release(); } return brush; } static void parseMaterialList(IDirectXFileData* fileData, vector& mats) { const GUID* guid; IDirectXFileObject* childObj; IDirectXFileData* childData; IDirectXFileDataReference* childRef; //iterate through child objects... for (; fileData->GetNextObject(&childObj) >= 0; childObj->Release()) { if (childObj->QueryInterface(IID_IDirectXFileData, (void**)&childData) >= 0) { if (childData->GetType(&guid) >= 0) { if (*guid == TID_D3DRMMaterial) { mats.push_back(parseMaterial(childData)); } } childData->Release(); } else if (childObj->QueryInterface(IID_IDirectXFileDataReference, (void**)&childRef) >= 0) { if (childRef->Resolve(&childData) >= 0) { if (childData->GetType(&guid) >= 0) { if (*guid == TID_D3DRMMaterial) { mats.push_back(parseMaterial(childData)); } } childData->Release(); } childRef->Release(); } } } struct FaceX { int *data, mat_index; FaceX(int* d) : data(d), mat_index(0) {} }; static void parseMesh(IDirectXFileData* fileData, MeshModel* mesh) { const GUID* guid; IDirectXFileObject* childObj; IDirectXFileData* childData; DWORD sz; int* data; if (fileData->GetData(0, &sz, (void**)&data) < 0) return; //stuff... vector faces; vector mats; MeshLoader::beginMesh(); //setup vertices int num_verts = *data++; int k; for (k = 0; k < num_verts; ++k) { Surface::Vertex v; v.coords = *(Vector*)data; if (conv) v.coords = conv_tform * v.coords; v.color = 0xffffffff; //Vector(1,1,1); MeshLoader::addVertex(v); data += 3; } //setup faces int num_faces = *data++; for (k = 0; k < num_faces; ++k) { faces.push_back(FaceX(data)); data += *data + 1; } bool normals = false; //get material and texture info for (; fileData->GetNextObject(&childObj) >= 0; childObj->Release()) { if (childObj->QueryInterface(IID_IDirectXFileData, (void**)&childData) < 0) continue; if (childData->GetType(&guid) >= 0) { DWORD sz; int* data; if (childData->GetData(0, &sz, (void**)&data) >= 0) { if (*guid == TID_D3DRMMeshMaterialList) { int num_mats = *data++; int num_faces = *data++; for (int k = 0; k < num_faces; ++k) { faces[k].mat_index = *data++; } parseMaterialList(childData, mats); } else if (*guid == TID_D3DRMMeshTextureCoords) { int num_coords = *data++; if (num_coords == num_verts) { float* coords = (float*)data; for (int k = 0; k < num_coords; ++k) { Surface::Vertex& v = MeshLoader::refVertex(k); float tu = *coords++; float tv = *coords++; v.tex_coords[0][0] = v.tex_coords[1][0] = tu; v.tex_coords[0][1] = v.tex_coords[1][1] = tv; } } } else if (*guid == TID_D3DRMMeshVertexColors) { int num_colors = *data++; if (num_colors == num_verts) { for (int k = 0; k < num_colors; ++k) { Surface::Vertex& v = MeshLoader::refVertex(*data++); float* t = (float*)data; v.color = 0xff000000 | (int(t[0] * 255) << 16) | (int(t[1] * 255) << 8) | int(t[2] * 255); // v.color=Vector( t[0],t[1],t[2] ); data += 4; } } } else if (*guid == TID_D3DRMMeshNormals) { int num_normals = *data++; if (num_normals == num_verts) { Matrix co = conv_tform.m.cofactor(); for (int k = 0; k < num_normals; ++k) { Surface::Vertex& v = MeshLoader::refVertex(k); v.normal = (co * *(Vector*)data).normalized(); data += 3; } normals = true; } } } } childData->Release(); } if (!mats.size()) mats.push_back(Brush()); for (size_t k = 0; k < faces.size(); ++k) { const FaceX& f = faces[k]; int* data = f.data; int cnt = *data++; if (cnt < 3) continue; int tri[3]; tri[0] = data[0]; for (int j = 2; j < cnt; ++j) { tri[1] = data[j - 1 + flip_tris]; tri[2] = data[j - flip_tris]; MeshLoader::addTriangle(tri, mats[f.mat_index]); } } MeshLoader::endMesh(mesh); if (!normals) mesh->updateNormals(); } static MeshModel* parseFrame(IDirectXFileData* fileData) { MeshModel* e = new MeshModel(); const GUID* guid; IDirectXFileObject* childObj; IDirectXFileData* childData; char name[80]; DWORD len = 80; if (fileData->GetName(name, &len) < 0) return e; e->SetName(name); frames_map[name] = e; //iterate through child objects... for (; fileData->GetNextObject(&childObj) >= 0; childObj->Release()) { if (childObj->QueryInterface(IID_IDirectXFileData, (void**)&childData) < 0) continue; if (childData->GetType(&guid) >= 0) { if (*guid == TID_D3DRMFrameTransformMatrix) { DWORD size; D3DMATRIX* data; if (childData->GetData(0, &size, (void**)&data) >= 0) { Transform tform = Transform(Matrix(Vector(data->_11, data->_12, data->_13), Vector(data->_21, data->_22, data->_23), Vector(data->_31, data->_32, data->_33)), Vector(data->_41, data->_42, data->_43)); if (conv) tform = conv_tform * tform * -conv_tform; e->SetLocalTransform(tform); } } else if (*guid == TID_D3DRMMesh) { if (!animonly) parseMesh(childData, e); } else if (*guid == TID_D3DRMFrame) { MeshModel* t = parseFrame(childData); t->SetParent(e); } } childData->Release(); } return e; } static MeshModel* parseFile(const string& file) { const GUID* guid; IDirectXFile* xfile; IDirectXFileData* fileData; IDirectXFileEnumObject* enumObj; if (DirectXFileCreate(&xfile) < 0) return 0; if (xfile->RegisterTemplates((VOID*)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES) < 0) { xfile->Release(); return 0; } if (xfile->CreateEnumObject((void*)file.c_str(), DXFILELOAD_FROMFILE, &enumObj) < 0) { xfile->Release(); return 0; } anim_len = 0; MeshModel* e = new MeshModel(); for (; enumObj->GetNextDataObject(&fileData) >= 0; fileData->Release()) { if (fileData->GetType(&guid) < 0) continue; if (*guid == TID_D3DRMMesh) { if (!animonly) parseMesh(fileData, e); } else if (*guid == TID_D3DRMFrame) { MeshModel* t = parseFrame(fileData); t->SetParent(e); } else if (*guid == TID_D3DRMAnimationSet) { if (!collapse) parseAnimSet(fileData); } } if (!collapse) { e->setAnimator(new Animator(e, anim_len)); } enumObj->Release(); xfile->Release(); return e; } MeshModel* Loader_X::load(const string& filename, const Transform& t, int hint) { conv_tform = t; conv = flip_tris = false; if (conv_tform != Transform()) { conv = true; if (conv_tform.m.i.cross(conv_tform.m.j).dot(conv_tform.m.k) < 0) flip_tris = true; } collapse = !!(hint & MeshLoader::HINT_COLLAPSE); animonly = !!(hint & MeshLoader::HINT_ANIMONLY); MeshModel* e = parseFile(filename); frames_map.clear(); return e; }