Files
BlitzNext/Runtime/blitz3d/loader_x.cpp
T
Michael Fabian 'Xaymar' Dirks 2196cb8419 runtime: Formatting
2019-01-18 17:04:17 +01:00

433 lines
11 KiB
C++

#include "loader_x.hpp"
#include "animation.hpp"
#include "meshmodel.hpp"
#include "pivot.hpp"
#include "std.hpp"
#include <windows.h>
//#include <dxfile.h>
#include <d3d9types.h>
#include <d3dx9xof.h>
#include <rmxfguid.h>
#include <rmxftmpl.h>
#include "../gxruntime/GraphicsRuntime.hpp"
extern gxRuntime* gx_runtime;
static map<string, MeshModel*> 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<string, MeshModel*>::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<Brush>& 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<FaceX> faces;
vector<Brush> 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;
}