begin animation support for xfile

This commit is contained in:
David Rose 2004-10-03 02:54:27 +00:00
parent 99d7222df4
commit 9d564e2470
11 changed files with 1177 additions and 66 deletions

View File

@ -20,12 +20,16 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx
#define SOURCES \
config_xfile.h xFileFace.h xFileMaker.h xFileMaterial.h \
config_xfile.h \
xFileAnimationSet.h \
xFileFace.h xFileMaker.h xFileMaterial.h \
xFileMesh.h xFileNormal.h xFileTemplates.h \
xFileToEggConverter.h xFileVertex.h
#define INCLUDED_SOURCES \
config_xfile.cxx xFileFace.cxx xFileMaker.cxx xFileMaterial.cxx \
config_xfile.cxx \
xFileAnimationSet.cxx \
xFileFace.cxx xFileMaker.cxx xFileMaterial.cxx \
xFileMesh.cxx xFileNormal.cxx xFileTemplates.cxx \
xFileToEggConverter.cxx xFileVertex.cxx

View File

@ -0,0 +1,167 @@
// Filename: xFileAnimationSet.cxx
// Created by: drose (02Oct04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "xFileAnimationSet.h"
#include "xFileToEggConverter.h"
#include "eggGroup.h"
#include "eggTable.h"
#include "eggData.h"
#include "eggXfmSAnim.h"
#include "dcast.h"
////////////////////////////////////////////////////////////////////
// Function: XFileAnimationSet::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
XFileAnimationSet::
XFileAnimationSet() {
}
////////////////////////////////////////////////////////////////////
// Function: XFileAnimationSet::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
XFileAnimationSet::
~XFileAnimationSet() {
}
////////////////////////////////////////////////////////////////////
// Function: XFileAnimationSet::create_hierarchy
// Access: Public
// Description: Sets up the hierarchy of EggTables corresponding to
// this AnimationSet.
////////////////////////////////////////////////////////////////////
bool XFileAnimationSet::
create_hierarchy(XFileToEggConverter *converter) {
// Egg animation tables start off with one Table entry, enclosing a
// Bundle entry.
EggTable *table = new EggTable(get_name());
converter->get_egg_data().add_child(table);
EggTable *bundle = new EggTable(converter->_char_name);
table->add_child(bundle);
bundle->set_table_type(EggTable::TT_bundle);
// Then the Bundle contains a "<skeleton>" entry, which begins the
// animation table hierarchy.
EggTable *skeleton = new EggTable("<skeleton>");
bundle->add_child(skeleton);
// Fill in the rest of the hierarchy with empty tables.
mirror_table(converter->get_dart_node(), skeleton);
// Now populate those empty tables with the frame data.
JointData::const_iterator ji;
for (ji = _joint_data.begin(); ji != _joint_data.end(); ++ji) {
const string &joint_name = (*ji).first;
const FrameData &table = (*ji).second;
EggXfmSAnim *anim_table = get_table(joint_name);
if (anim_table == (EggXfmSAnim *)NULL) {
xfile_cat.warning()
<< "Frame " << joint_name << ", named by animation data, not defined.\n";
} else {
// If we have animation data, apply it.
FrameData::const_iterator fi;
for (fi = table.begin(); fi != table.end(); ++fi) {
anim_table->add_data(*fi);
}
anim_table->optimize();
}
}
// Put some data in the empty tables also.
Tables::iterator ti;
for (ti = _tables.begin(); ti != _tables.end(); ++ti) {
const string &joint_name = (*ti).first;
EggXfmSAnim *anim_table = (*ti).second._table;
EggGroup *joint = (*ti).second._joint;
if (anim_table->empty() && joint != (EggGroup *)NULL) {
// If there's no animation data, assign the rest transform.
anim_table->add_data(joint->get_transform());
}
anim_table->optimize();
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileAnimationSet::get_table
// Access: Public
// Description: Returns the table associated with the indicated joint
// name.
////////////////////////////////////////////////////////////////////
EggXfmSAnim *XFileAnimationSet::
get_table(const string &joint_name) const {
Tables::const_iterator ti;
ti = _tables.find(joint_name);
if (ti != _tables.end()) {
return (*ti).second._table;
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: XFileAnimationSet::create_frame_data
// Access: Public
// Description: Returns a reference to a new FrameData table
// corresponding to the indicated joint.
////////////////////////////////////////////////////////////////////
XFileAnimationSet::FrameData &XFileAnimationSet::
create_frame_data(const string &joint_name) {
return _joint_data[joint_name];
}
////////////////////////////////////////////////////////////////////
// Function: XFileAnimationSet::mirror_table
// Access: Private
// Description: Builds up a new set of EggTable nodes, as a
// mirror of the existing set of EggGroup (joint)
// nodes, and saves each new table in the _tables
// record.
////////////////////////////////////////////////////////////////////
void XFileAnimationSet::
mirror_table(EggGroup *model_node, EggTable *anim_node) {
EggGroupNode::iterator gi;
for (gi = model_node->begin(); gi != model_node->end(); ++gi) {
EggNode *child = (*gi);
if (child->is_of_type(EggGroup::get_class_type())) {
EggGroup *group = DCAST(EggGroup, child);
if (group->get_group_type() == EggGroup::GT_joint) {
// When we come to a <Joint>, create a new Table for it.
EggTable *new_table = new EggTable(group->get_name());
anim_node->add_child(new_table);
EggXfmSAnim *xform = new EggXfmSAnim("xform");
new_table->add_child(xform);
TablePair &table_pair = _tables[group->get_name()];
table_pair._table = xform;
table_pair._joint = group;
// Now recurse.
mirror_table(group, new_table);
} else {
// If we come to an ordinary <Group>, skip past it.
mirror_table(group, anim_node);
}
}
}
}

View File

@ -0,0 +1,69 @@
// Filename: xFileAnimationSet.h
// Created by: drose (02Oct04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef XFILEANIMATIONSET_H
#define XFILEANIMATIONSET_H
#include "pandatoolbase.h"
#include "pmap.h"
#include "pvector.h"
#include "luse.h"
#include "namable.h"
class XFileToEggConverter;
class EggGroup;
class EggTable;
class EggXfmSAnim;
////////////////////////////////////////////////////////////////////
// Class : XFileAnimationSet
// Description : This represents a tree of EggTables, corresponding to
// Animation entries in the X file. There is one
// EggTable for each joint in the character's joint
// set, and the whole tree is structured as a
// mirror of the joint set.
////////////////////////////////////////////////////////////////////
class XFileAnimationSet : public Namable {
public:
XFileAnimationSet();
~XFileAnimationSet();
bool create_hierarchy(XFileToEggConverter *converter);
EggXfmSAnim *get_table(const string &joint_name) const;
typedef pvector<LMatrix4d> FrameData;
FrameData &create_frame_data(const string &joint_name);
private:
void mirror_table(EggGroup *model_node, EggTable *anim_node);
typedef pmap<string, FrameData> JointData;
JointData _joint_data;
class TablePair {
public:
EggGroup *_joint;
EggXfmSAnim *_table;
};
typedef pmap<string, TablePair> Tables;
Tables _tables;
};
#endif

View File

@ -21,6 +21,7 @@
#include "xFileVertex.h"
#include "xFileNormal.h"
#include "xFileMaterial.h"
#include "config_xfile.h"
#include "eggVertexPool.h"
#include "eggVertex.h"
@ -38,6 +39,7 @@ XFileMesh(CoordinateSystem cs) : _cs(cs) {
_has_colors = false;
_has_uvs = false;
_has_materials = false;
_egg_parent = NULL;
}
////////////////////////////////////////////////////////////////////
@ -251,30 +253,41 @@ add_material(XFileMaterial *material) {
return next_index;
}
////////////////////////////////////////////////////////////////////
// Function: XFileMesh::set_egg_parent
// Access: Public
// Description: Specifies the egg node that will eventually be the
// parent of this mesh, when create_polygons() is later
// called.
////////////////////////////////////////////////////////////////////
void XFileMesh::
set_egg_parent(EggGroupNode *egg_parent) {
// We actually put the mesh under its own group.
EggGroup *egg_group = new EggGroup(get_name());
egg_parent->add_child(egg_group);
_egg_parent = egg_group;
}
////////////////////////////////////////////////////////////////////
// Function: XFileMesh::create_polygons
// Access: Public
// Description: Creates a slew of EggPolygons according to the faces
// in the mesh, and adds them to the indicated parent
// node.
// in the mesh, and adds them to the
// previously-indicated parent node.
////////////////////////////////////////////////////////////////////
bool XFileMesh::
create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
if (has_name()) {
// Put a named mesh within its own group.
EggGroup *egg_group = new EggGroup(get_name());
egg_parent->add_child(egg_group);
egg_parent = egg_group;
}
create_polygons(XFileToEggConverter *converter) {
nassertr(_egg_parent != (EggGroupNode *)NULL, false);
EggVertexPool *vpool = new EggVertexPool(get_name());
egg_parent->add_child(vpool);
_egg_parent->add_child(vpool);
Faces::const_iterator fi;
for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
XFileFace *face = (*fi);
EggPolygon *egg_poly = new EggPolygon;
egg_parent->add_child(egg_poly);
_egg_parent->add_child(egg_poly);
// Set up the vertices for the polygon.
XFileFace::Vertices::reverse_iterator vi;
@ -282,7 +295,8 @@ create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
int vertex_index = (*vi)._vertex_index;
int normal_index = (*vi)._normal_index;
if (vertex_index < 0 || vertex_index >= (int)_vertices.size()) {
nout << "Vertex index out of range in Mesh.\n";
xfile_cat.error()
<< "Vertex index out of range in Mesh.\n";
return false;
}
XFileVertex *vertex = _vertices[vertex_index];
@ -294,6 +308,7 @@ create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
// Create a temporary EggVertex before adding it to the pool.
EggVertex temp_vtx;
temp_vtx.set_external_index(vertex_index);
temp_vtx.set_pos(LCAST(double, vertex->_point));
if (vertex->_has_color) {
temp_vtx.set_color(vertex->_color);
@ -311,7 +326,7 @@ create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
// Transform the vertex into the appropriate (global) coordinate
// space.
temp_vtx.transform(egg_parent->get_node_to_vertex());
temp_vtx.transform(_egg_parent->get_node_to_vertex());
// Now get a real EggVertex matching our template.
EggVertex *egg_vtx = vpool->create_unique_vertex(temp_vtx);
@ -326,11 +341,32 @@ create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
}
}
// Now go through all of the vertices and skin them up.
EggVertexPool::iterator vi;
for (vi = vpool->begin(); vi != vpool->end(); ++vi) {
EggVertex *egg_vtx = (*vi);
int vertex_index = egg_vtx->get_external_index();
SkinWeights::const_iterator swi;
for (swi = _skin_weights.begin(); swi != _skin_weights.end(); ++swi) {
const SkinWeightsData &data = (*swi);
WeightMap::const_iterator wmi = data._weight_map.find(vertex_index);
if (wmi != data._weight_map.end()) {
EggGroup *joint = converter->find_joint(data._joint_name,
data._matrix_offset);
if (joint != (EggGroup *)NULL) {
double weight = (*wmi).second;
joint->ref_vertex(egg_vtx, weight);
}
}
}
}
if (!has_normals()) {
// If we don't have explicit normals, make some up, per the DX
// spec. Since the DX spec doesn't mention anything about a
// crease angle, we should be as generous as possible.
egg_parent->recompute_vertex_normals(180.0, _cs);
_egg_parent->recompute_vertex_normals(180.0, _cs);
}
return true;
@ -574,7 +610,8 @@ read_mesh_data(const Datagram &raw_data) {
}
if (di.get_remaining_size() != 0) {
nout << "Ignoring " << di.get_remaining_size() << " trailing Mesh.\n";
xfile_cat.warning()
<< "Ignoring " << di.get_remaining_size() << " trailing Mesh.\n";
}
return true;
@ -604,7 +641,8 @@ read_normal_data(const Datagram &raw_data) {
int num_faces = di.get_int32();
if (num_faces != _faces.size()) {
nout << "Incorrect number of faces in MeshNormals.\n";
xfile_cat.error()
<< "Incorrect number of faces in MeshNormals.\n";
return false;
}
@ -612,7 +650,8 @@ read_normal_data(const Datagram &raw_data) {
XFileFace *face = _faces[i];
int num_vertices = di.get_int32();
if (num_vertices != face->_vertices.size()) {
nout << "Incorrect number of vertices for face in MeshNormals.\n";
xfile_cat.error()
<< "Incorrect number of vertices for face in MeshNormals.\n";
return false;
}
for (int j = 0; j < num_vertices; j++) {
@ -621,8 +660,9 @@ read_normal_data(const Datagram &raw_data) {
}
if (di.get_remaining_size() != 0) {
nout << "Ignoring " << di.get_remaining_size()
<< " trailing MeshNormals.\n";
xfile_cat.warning()
<< "Ignoring " << di.get_remaining_size()
<< " trailing MeshNormals.\n";
}
return true;
@ -643,7 +683,8 @@ read_color_data(const Datagram &raw_data) {
for (i = 0; i < num_colors; i++) {
unsigned int vertex_index = di.get_int32();
if (vertex_index < 0 || vertex_index >= _vertices.size()) {
nout << "Vertex index out of range in MeshVertexColors.\n";
xfile_cat.error()
<< "Vertex index out of range in MeshVertexColors.\n";
return false;
}
XFileVertex *vertex = _vertices[vertex_index];
@ -655,8 +696,9 @@ read_color_data(const Datagram &raw_data) {
}
if (di.get_remaining_size() != 0) {
nout << "Ignoring " << di.get_remaining_size()
<< " trailing MeshVertexColors.\n";
xfile_cat.warning()
<< "Ignoring " << di.get_remaining_size()
<< " trailing MeshVertexColors.\n";
}
return true;
@ -674,7 +716,8 @@ read_uv_data(const Datagram &raw_data) {
int num_vertices = di.get_int32();
if (num_vertices != _vertices.size()) {
nout << "Wrong number of vertices in MeshTextureCoords.\n";
xfile_cat.error()
<< "Wrong number of vertices in MeshTextureCoords.\n";
return false;
}
@ -687,13 +730,62 @@ read_uv_data(const Datagram &raw_data) {
}
if (di.get_remaining_size() != 0) {
nout << "Ignoring " << di.get_remaining_size()
<< " trailing MeshTextureCoords.\n";
xfile_cat.warning()
<< "Ignoring " << di.get_remaining_size()
<< " trailing MeshTextureCoords.\n";
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileMesh::read_skin_weights_data
// Access: Public
// Description: Fills the structure based on the raw data from the
// SkinWeights template.
////////////////////////////////////////////////////////////////////
bool XFileMesh::
read_skin_weights_data(const Datagram &raw_data) {
DatagramIterator di(raw_data);
// Create a new SkinWeightsData record for the table. We'll need
// this data later when we create the vertices.
_skin_weights.push_back(SkinWeightsData());
SkinWeightsData &data = _skin_weights.back();
// The DX system encodes a pointer to a character string in four
// bytes within the stream. Weird, in a Microsofty sort of way.
data._joint_name = (const char *)di.get_uint32();
int num_weights = di.get_int32();
vector_int vindices;
vindices.reserve(num_weights);
// Unpack the list of vertices first
int i;
for (i = 0; i < num_weights; i++) {
int vindex = di.get_int32();
if (vindex < 0 || vindex > (int)_vertices.size()) {
xfile_cat.error()
<< "Illegal vertex index " << vindex << " in SkinWeights.\n";
return false;
}
vindices.push_back(vindex);
}
// Then unpack the weight for each vertex.
for (i = 0; i < num_weights; i++) {
float weight = di.get_float32();
data._weight_map[vindices[i]] = weight;
}
// Finally, read the matrix offset.
data._matrix_offset.read_datagram(di);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileMesh::read_material_list_data
// Access: Public
@ -708,7 +800,8 @@ read_material_list_data(const Datagram &raw_data) {
unsigned int num_faces = di.get_int32();
if (num_faces > _faces.size()) {
nout << "Too many faces in MaterialList.\n";
xfile_cat.error()
<< "Too many faces in MaterialList.\n";
return false;
}
@ -730,8 +823,9 @@ read_material_list_data(const Datagram &raw_data) {
}
if (di.get_remaining_size() != 0) {
nout << "Ignoring " << di.get_remaining_size()
<< " trailing MeshMaterialList.\n";
xfile_cat.warning()
<< "Ignoring " << di.get_remaining_size()
<< " trailing MeshMaterialList.\n";
}
return true;

View File

@ -58,8 +58,9 @@ public:
int add_normal(XFileNormal *normal);
int add_material(XFileMaterial *material);
bool create_polygons(EggGroupNode *egg_parent,
XFileToEggConverter *converter);
void set_egg_parent(EggGroupNode *egg_parent);
bool create_polygons(XFileToEggConverter *converter);
bool has_normals() const;
bool has_colors() const;
@ -79,6 +80,7 @@ public:
bool read_normal_data(const Datagram &raw_data);
bool read_color_data(const Datagram &raw_data);
bool read_uv_data(const Datagram &raw_data);
bool read_skin_weights_data(const Datagram &raw_data);
bool read_material_list_data(const Datagram &raw_data);
private:
@ -94,6 +96,17 @@ private:
Materials _materials;
Faces _faces;
typedef pmap<int, float> WeightMap;
class SkinWeightsData {
public:
string _joint_name;
WeightMap _weight_map;
LMatrix4f _matrix_offset;
};
typedef pvector<SkinWeightsData> SkinWeights;
SkinWeights _skin_weights;
typedef pmap<XFileVertex *, int, IndirectCompareTo<XFileVertex> > UniqueVertices;
typedef pmap<XFileNormal *, int, IndirectCompareTo<XFileNormal> > UniqueNormals;
typedef pmap<XFileMaterial *, int, IndirectCompareTo<XFileMaterial> > UniqueMaterials;
@ -105,6 +118,8 @@ private:
bool _has_colors;
bool _has_uvs;
bool _has_materials;
EggGroupNode *_egg_parent;
};
#endif

View File

@ -20,15 +20,38 @@
#include "xFileMesh.h"
#include "xFileMaterial.h"
#include "xFileTemplates.h"
#include "xFileAnimationSet.h"
#include "config_xfile.h"
#include "eggData.h"
#include "eggGroup.h"
#include "eggXfmSAnim.h"
#include "eggGroupUniquifier.h"
#include "datagram.h"
#include "eggMaterialCollection.h"
#include "eggTextureCollection.h"
#include "dcast.h"
#define MY_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID DECLSPEC_SELECTANY name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
// These are defined in d3dx9mesh.h, which we may not have available
// (so far, Panda is only dependent on dx8 API's).
#ifndef DXFILEOBJ_XSkinMeshHeader
// {3CF169CE-FF7C-44ab-93C0-F78F62D172E2}
MY_DEFINE_GUID(DXFILEOBJ_XSkinMeshHeader,
0x3cf169ce, 0xff7c, 0x44ab, 0x93, 0xc0, 0xf7, 0x8f, 0x62, 0xd1, 0x72, 0xe2);
#endif
#ifndef DXFILEOBJ_SkinWeights
// {6F0D123B-BAD2-4167-A0D0-80224F25FABB}
MY_DEFINE_GUID(DXFILEOBJ_SkinWeights,
0x6f0d123b, 0xbad2, 0x4167, 0xa0, 0xd0, 0x80, 0x22, 0x4f, 0x25, 0xfa, 0xbb);
#endif
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::Constructor
// Access: Public
@ -36,8 +59,10 @@
////////////////////////////////////////////////////////////////////
XFileToEggConverter::
XFileToEggConverter() {
_make_char = false;
_dx_file = NULL;
_dx_file_enum = NULL;
_dart_node = NULL;
}
////////////////////////////////////////////////////////////////////
@ -47,10 +72,12 @@ XFileToEggConverter() {
////////////////////////////////////////////////////////////////////
XFileToEggConverter::
XFileToEggConverter(const XFileToEggConverter &copy) :
SomethingToEggConverter(copy)
SomethingToEggConverter(copy),
_make_char(copy._make_char)
{
_dx_file = NULL;
_dx_file_enum = NULL;
_dart_node = NULL;
}
////////////////////////////////////////////////////////////////////
@ -138,7 +165,25 @@ convert_file(const Filename &filename) {
_egg_data->set_coordinate_system(CS_yup_left);
}
return get_toplevel();
if (!get_toplevel()) {
return false;
}
if (!create_polygons()) {
return false;
}
if (_make_char) {
// Now make sure that each joint has a unique name.
EggGroupUniquifier uniquifier;
uniquifier.uniquify(_dart_node);
}
if (!create_hierarchy()) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
@ -157,6 +202,37 @@ close() {
_dx_file->Release();
_dx_file = NULL;
}
// Clean up all the other stuff.
Meshes::const_iterator mi;
for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
delete (*mi);
}
_meshes.clear();
for (mi = _toplevel_meshes.begin(); mi != _toplevel_meshes.end(); ++mi) {
delete (*mi);
}
_toplevel_meshes.clear();
AnimationSets::const_iterator asi;
for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
delete (*asi);
}
_animation_sets.clear();
_joints.clear();
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::get_dart_node
// Access: Public
// Description: Returns the root of the joint hierarchy, if
// _make_char is true, or NULL otherwise.
////////////////////////////////////////////////////////////////////
EggGroup *XFileToEggConverter::
get_dart_node() const {
return _dart_node;
}
////////////////////////////////////////////////////////////////////
@ -183,6 +259,98 @@ create_unique_material(const EggMaterial &copy) {
return _materials.create_unique_material(copy, ~EggMaterial::E_mref_name);
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::find_joint (one parameter)
// Access: Public
// Description: This is called by set_animation_frame, for
// the purposes of building the frame data for the
// animation--it needs to know the original rest frame
// transform.
////////////////////////////////////////////////////////////////////
EggGroup *XFileToEggConverter::
find_joint(const string &joint_name) {
Joints::iterator ji;
ji = _joints.find(joint_name);
if (ji != _joints.end()) {
JointDef &joint_def = (*ji).second;
if (joint_def._node == (EggGroup *)NULL) {
// An invalid joint detected earlier.
return NULL;
}
return joint_def._node;
}
// Joint name is unknown. Issue a warning, then insert NULL into
// the table so we don't get the same warning again with the next
// polygon.
if (_make_char) {
xfile_cat.warning()
<< "Joint name " << joint_name << " in animation data is undefined.\n";
}
_joints[joint_name]._node = NULL;
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::find_joint (two parameters)
// Access: Public
// Description: This is called by XFileMesh::create_polygons(), for
// the purposes of applying skinning to vertices. It
// searches for the joint matching the indicated name,
// and returns it, possibly creating a new joint if the
// requested matrix_offset demands it. Returns NULL if
// the joint name is unknown.
////////////////////////////////////////////////////////////////////
EggGroup *XFileToEggConverter::
find_joint(const string &joint_name, const LMatrix4f &matrix_offset) {
return find_joint(joint_name);
/*
Joints::iterator ji;
ji = _joints.find(joint_name);
if (ji != _joints.end()) {
JointDef &joint_def = (*ji).second;
if (joint_def._node == (EggGroup *)NULL) {
// An invalid joint detected earlier.
return NULL;
}
OffsetJoints::iterator oji = joint_def._offsets.find(matrix_offset);
if (oji != joint_def._offsets.end()) {
// We've previously created a joint for this matrix, so just
// reuse it.
return (*oji).second;
}
if (!joint_def._offsets.empty()) {
const LMatrix4f &mat = (*joint_def._offsets.begin()).first;
}
// We need to create a new joint for this matrix.
EggGroup *new_joint = new EggGroup("synth");
joint_def._node->add_child(new_joint);
new_joint->set_group_type(EggGroup::GT_joint);
new_joint->set_transform(LCAST(double, matrix_offset));
joint_def._offsets[matrix_offset] = new_joint;
return new_joint;
}
// Joint name is unknown. Issue a warning, then insert NULL into
// the table so we don't get the same warning again with the next
// polygon.
if (_make_char) {
xfile_cat.warning()
<< "Joint name " << joint_name << " in animation data is undefined.\n";
}
_joints[joint_name]._node = NULL;
return NULL;
*/
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::get_toplevel
// Access: Private
@ -195,13 +363,22 @@ get_toplevel() {
HRESULT hr;
LPDIRECTXFILEDATA obj;
PT(EggGroup) egg_toplevel = new EggGroup;
bool any_frames = false;
EggGroupNode *egg_parent = _egg_data;
// If we are converting an animatable model, make an extra node to
// represent the root of the hierarchy.
if (_make_char) {
_dart_node = new EggGroup(_char_name);
egg_parent->add_child(_dart_node);
_dart_node->set_dart_type(EggGroup::DT_default);
egg_parent = _dart_node;
}
_any_frames = false;
hr = _dx_file_enum->GetNextDataObject(&obj);
while (hr == DXFILE_OK) {
if (!convert_toplevel_object(obj, _egg_data,
egg_toplevel, any_frames)) {
if (!convert_toplevel_object(obj, egg_parent)) {
return false;
}
hr = _dx_file_enum->GetNextDataObject(&obj);
@ -213,13 +390,6 @@ get_toplevel() {
return false;
}
if (!any_frames) {
// If the file contained no frames at all, then all of the meshes
// that appeared at the toplevel were meant to be directly
// included.
_egg_data->steal_children(*egg_toplevel);
}
return true;
}
@ -230,8 +400,7 @@ get_toplevel() {
// any Frames, to the appropriate egg structures.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
EggGroupNode *egg_toplevel, bool &any_frames) {
convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
HRESULT hr;
// Determine what type of data object we have.
@ -251,7 +420,7 @@ convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
// referenced below.
} else if (*type == TID_D3DRMFrame) {
any_frames = true;
_any_frames = true;
if (!convert_frame(obj, egg_parent)) {
return false;
}
@ -261,12 +430,17 @@ convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
return false;
}
} else if (*type == TID_D3DRMAnimationSet) {
if (!convert_animation_set(obj)) {
return false;
}
} else if (*type == TID_D3DRMMesh) {
// Assume a Mesh at the toplevel is just present to define a
// reference that will be included below. Convert it into the
// egg_toplevel group, where it will be ignored unless there are
// _toplevel_meshes set, where it will be ignored unless there are
// no frames at all in the file.
if (!convert_mesh(obj, egg_toplevel)) {
if (!convert_mesh(obj, egg_parent, true)) {
return false;
}
@ -352,7 +526,7 @@ convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
}
} else if (*type == TID_D3DRMMesh) {
if (!convert_mesh(obj, egg_parent)) {
if (!convert_mesh(obj, egg_parent, false)) {
return false;
}
@ -381,6 +555,24 @@ convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
EggGroup *group = new EggGroup(name);
egg_parent->add_child(group);
if (_make_char) {
group->set_group_type(EggGroup::GT_joint);
if (name.empty()) {
// Make up a name for this unnamed joint.
group->set_name("unnamed");
} else {
JointDef joint_def;
joint_def._node = group;
bool inserted = _joints.insert(Joints::value_type(name, joint_def)).second;
if (!inserted) {
xfile_cat.warning()
<< "Nonunique Frame name " << name
<< " encountered; animation will be ambiguous.\n";
}
}
}
// Now walk through the children of the frame.
LPDIRECTXFILEOBJECT child_obj;
@ -434,6 +626,398 @@ convert_transform(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_animation_set
// Access: Private
// Description: Begins an AnimationSet. This is the root of one
// particular animation (table of frames per joint) to
// be applied to the model within this file.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_animation_set(LPDIRECTXFILEDATA obj) {
HRESULT hr;
XFileAnimationSet *animation_set = new XFileAnimationSet();
animation_set->set_name(get_object_name(obj));
// Now walk through the children of the set; each one animates a
// different joint.
LPDIRECTXFILEOBJECT child_obj;
hr = obj->GetNextObject(&child_obj);
while (hr == DXFILE_OK) {
if (!convert_animation_set_object(child_obj, *animation_set)) {
return false;
}
hr = obj->GetNextObject(&child_obj);
}
if (hr != DXFILEERR_NOMOREOBJECTS) {
xfile_cat.error()
<< "Error extracting children of AnimationSet "
<< get_object_name(obj) << ".\n";
delete animation_set;
return false;
}
_animation_sets.push_back(animation_set);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_animation_set_object
// Access: Private
// Description: Converts the indicated object, a child of a
// AnimationSet.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_animation_set_object(LPDIRECTXFILEOBJECT obj,
XFileAnimationSet &animation_set) {
HRESULT hr;
LPDIRECTXFILEDATA data_obj;
LPDIRECTXFILEDATAREFERENCE ref_obj;
// See if the object is a data object.
hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
if (hr == DD_OK) {
// It is.
return convert_animation_set_data_object(data_obj, animation_set);
}
// Or maybe it's a reference to a previous object.
hr = obj->QueryInterface(IID_IDirectXFileDataReference, (void **)&ref_obj);
if (hr == DD_OK) {
// It is.
if (ref_obj->Resolve(&data_obj) == DXFILE_OK) {
return convert_animation_set_data_object(data_obj, animation_set);
}
}
// It isn't.
if (xfile_cat.is_debug()) {
xfile_cat.debug()
<< "Ignoring animation set object of unknown type: "
<< get_object_name(obj) << "\n";
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_animation_set_data_object
// Access: Private
// Description: Converts the indicated data object, a child of a
// AnimationSet.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_animation_set_data_object(LPDIRECTXFILEDATA obj, XFileAnimationSet &animation_set) {
HRESULT hr;
// Determine what type of data object we have.
const GUID *type;
hr = obj->GetType(&type);
if (hr != DXFILE_OK) {
xfile_cat.error()
<< "Unable to get type of template\n";
return false;
}
if (*type == TID_D3DRMAnimation) {
if (!convert_animation(obj, animation_set)) {
return false;
}
} else {
if (xfile_cat.is_debug()) {
xfile_cat.debug()
<< "Ignoring animation set data object of unknown type: "
<< get_object_name(obj) << "\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_animation
// Access: Private
// Description: Converts the indicated Animation template object.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_animation(LPDIRECTXFILEDATA obj, XFileAnimationSet &animation_set) {
HRESULT hr;
// Within an Animation template, we expect to find a reference to a
// frame, possibly an AnimationOptions object, and one or more
// AnimationKey objects.
LPDIRECTXFILEOBJECT child_obj;
// First, walk through the list of children, to find the one that is
// the frame reference. We need to know this up front so we know
// which table we should be building up.
string frame_name;
bool got_frame_name = false;
pvector<LPDIRECTXFILEOBJECT> children;
hr = obj->GetNextObject(&child_obj);
while (hr == DXFILE_OK) {
LPDIRECTXFILEDATAREFERENCE ref_obj;
if (child_obj->QueryInterface(IID_IDirectXFileDataReference, (void **)&ref_obj) == DD_OK) {
// Here's a reference!
LPDIRECTXFILEDATA data_obj;
if (ref_obj->Resolve(&data_obj) == DXFILE_OK) {
const GUID *type;
if (data_obj->GetType(&type) == DXFILE_OK) {
if (*type == TID_D3DRMFrame) {
// Ok, this one is a reference to a frame. Save the name.
frame_name = get_object_name(data_obj);
got_frame_name = true;
}
}
}
} else {
children.push_back(child_obj);
}
hr = obj->GetNextObject(&child_obj);
}
if (hr != DXFILEERR_NOMOREOBJECTS) {
xfile_cat.error()
<< "Error extracting children of Animation "
<< get_object_name(obj) << ".\n";
return false;
}
if (!got_frame_name) {
xfile_cat.error()
<< "Animation " << get_object_name(obj)
<< " includes no reference to a frame.\n";
return false;
}
FrameData &table = animation_set.create_frame_data(frame_name);
// Now go back again and get the actual data.
pvector<LPDIRECTXFILEOBJECT>::iterator ci;
for (ci = children.begin(); ci != children.end(); ++ci) {
if (!convert_animation_object((*ci), frame_name, table)) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_animation_object
// Access: Private
// Description: Converts the indicated object, a child of a
// Animation.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_animation_object(LPDIRECTXFILEOBJECT obj, const string &joint_name,
XFileToEggConverter::FrameData &table) {
HRESULT hr;
LPDIRECTXFILEDATA data_obj;
LPDIRECTXFILEDATAREFERENCE ref_obj;
// See if the object is a data object.
hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
if (hr == DD_OK) {
// It is.
return convert_animation_data_object(data_obj, joint_name, table);
}
// Or maybe it's a reference to a previous object.
hr = obj->QueryInterface(IID_IDirectXFileDataReference, (void **)&ref_obj);
if (hr == DD_OK) {
// It is.
if (ref_obj->Resolve(&data_obj) == DXFILE_OK) {
return convert_animation_data_object(data_obj, joint_name, table);
}
}
// It isn't.
if (xfile_cat.is_debug()) {
xfile_cat.debug()
<< "Ignoring animation set object of unknown type: "
<< get_object_name(obj) << "\n";
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_animation_data_object
// Access: Private
// Description: Converts the indicated data object, a child of a
// Animation.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_animation_data_object(LPDIRECTXFILEDATA obj, const string &joint_name,
XFileToEggConverter::FrameData &table) {
HRESULT hr;
// Determine what type of data object we have.
const GUID *type;
hr = obj->GetType(&type);
if (hr != DXFILE_OK) {
xfile_cat.error()
<< "Unable to get type of template\n";
return false;
}
if (*type == TID_D3DRMAnimationOptions) {
// Quietly ignore AnimationOptions.
} else if (*type == TID_D3DRMAnimationKey) {
if (!convert_animation_key(obj, joint_name, table)) {
return false;
}
} else {
if (xfile_cat.is_debug()) {
xfile_cat.debug()
<< "Ignoring animation set data object of unknown type: "
<< get_object_name(obj) << "\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_animation_key
// Access: Private
// Description: Converts the indicated AnimationKey template object.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_animation_key(LPDIRECTXFILEDATA obj, const string &joint_name,
XFileToEggConverter::FrameData &table) {
Datagram raw_data;
if (!get_data(obj, raw_data)) {
return false;
}
DatagramIterator di(raw_data);
int key_type = di.get_uint32();
int nkeys = di.get_uint32();
int last_time = 0;
for (int i = 0; i < nkeys; i++) {
int time = di.get_uint32();
int nvalues = di.get_uint32();
pvector<float> values;
values.reserve(nvalues);
for (int j = 0; j < nvalues; j++) {
float value = di.get_float32();
values.push_back(value);
}
while (last_time <= time) {
if (!set_animation_frame(joint_name, table, last_time, key_type,
&values[0], nvalues)) {
return false;
}
last_time++;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::set_animation_frame
// Access: Private
// Description: Sets a single frame of the animation data.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
set_animation_frame(const string &joint_name,
XFileToEggConverter::FrameData &table, int frame,
int key_type, const float *values, int nvalues) {
LMatrix4d mat;
// Pad out the table by duplicating the last row as necessary.
if ((int)table.size() <= frame) {
if (table.empty()) {
// Get the initial transform from the joint's rest transform.
EggGroup *joint = find_joint(joint_name);
if (joint != (EggGroup *)NULL) {
mat = joint->get_transform();
} else {
mat = LMatrix4d::ident_mat();
}
} else {
// Get the initial transform from the last frame of animation.
mat = table.back();
}
table.push_back(mat);
while ((int)table.size() <= frame) {
table.push_back(mat);
}
} else {
mat = table.back();
}
// Now modify the last row in the table.
switch (key_type) {
/*
case 0:
// Key type 0: rotation
break;
*/
/*
case 1:
// Key type 1: scale
break;
*/
case 2:
// Key type 2: position
if (nvalues != 3) {
xfile_cat.error()
<< "Incorrect number of values in animation table: "
<< nvalues << " for position data.\n";
return false;
}
mat.set_row(3, LVecBase3d(values[0], values[1], values[2]));
break;
/*
case 3:
// Key type 3: ????
break;
*/
case 4:
// Key type 4: full matrix
if (nvalues != 16) {
xfile_cat.error()
<< "Incorrect number of values in animation table: "
<< nvalues << " for matrix data.\n";
return false;
}
mat.set(values[0], values[1], values[2], values[3],
values[4], values[5], values[6], values[7],
values[8], values[9], values[10], values[11],
values[12], values[13], values[14], values[15]);
break;
default:
xfile_cat.error()
<< "Unsupported key type " << key_type << " in animation table.\n";
return false;
}
table.back() = mat;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_mesh
// Access: Private
@ -441,7 +1025,8 @@ convert_transform(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
// structures.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
bool is_toplevel) {
HRESULT hr;
Datagram raw_data;
@ -449,9 +1034,12 @@ convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
return false;
}
XFileMesh mesh(_egg_data->get_coordinate_system());
mesh.set_name(get_object_name(obj));
if (!mesh.read_mesh_data(raw_data)) {
XFileMesh *mesh = new XFileMesh(_egg_data->get_coordinate_system());
mesh->set_name(get_object_name(obj));
mesh->set_egg_parent(egg_parent);
if (!mesh->read_mesh_data(raw_data)) {
delete mesh;
return false;
}
@ -460,7 +1048,7 @@ convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
hr = obj->GetNextObject(&child_obj);
while (hr == DXFILE_OK) {
if (!convert_mesh_object(child_obj, mesh)) {
if (!convert_mesh_object(child_obj, *mesh)) {
return false;
}
hr = obj->GetNextObject(&child_obj);
@ -470,11 +1058,14 @@ convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
xfile_cat.error()
<< "Error extracting children of mesh " << get_object_name(obj)
<< ".\n";
delete mesh;
return false;
}
if (!mesh.create_polygons(egg_parent, this)) {
return false;
if (is_toplevel) {
_toplevel_meshes.push_back(mesh);
} else {
_meshes.push_back(mesh);
}
return true;
@ -556,6 +1147,14 @@ convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
return false;
}
} else if (*type == DXFILEOBJ_XSkinMeshHeader) {
// Quietly ignore a skin mesh header.
} else if (*type == DXFILEOBJ_SkinWeights) {
if (!convert_skin_weights(obj, mesh)) {
return false;
}
} else {
if (xfile_cat.is_debug()) {
xfile_cat.debug()
@ -627,6 +1226,26 @@ convert_mesh_uvs(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_skin_weights
// Access: Private
// Description: Converts the indicated SkinWeights template
// object.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
convert_skin_weights(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
Datagram raw_data;
if (!get_data(obj, raw_data)) {
return false;
}
if (!mesh.read_skin_weights_data(raw_data)) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::convert_mesh_material_list
// Access: Private
@ -874,6 +1493,67 @@ convert_texture(LPDIRECTXFILEDATA obj, XFileMaterial &material) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::create_polygons
// Access: Private
// Description: Creates all the polygons associated with
// previously-saved meshes.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
create_polygons() {
bool okflag = true;
Meshes::const_iterator mi;
for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
if (!(*mi)->create_polygons(this)) {
okflag = false;
}
delete (*mi);
}
_meshes.clear();
for (mi = _toplevel_meshes.begin(); mi != _toplevel_meshes.end(); ++mi) {
if (!_any_frames) {
if (!(*mi)->create_polygons(this)) {
okflag = false;
}
}
delete (*mi);
}
_toplevel_meshes.clear();
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::create_hierarchy
// Access: Private
// Description: Creates the animation table hierarchies for the
// previously-saved animation sets.
////////////////////////////////////////////////////////////////////
bool XFileToEggConverter::
create_hierarchy() {
bool okflag = true;
if (!_make_char && !_animation_sets.empty()) {
xfile_cat.warning()
<< "Ignoring animation data without -a.\n";
}
AnimationSets::const_iterator asi;
for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
if (_make_char) {
if (!(*asi)->create_hierarchy(this)) {
okflag = false;
}
}
delete (*asi);
}
_animation_sets.clear();
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: XFileToEggConverter::get_object_name
// Access: Private

View File

@ -20,9 +20,13 @@
#define XFILETOEGGCONVERTER_H
#include "pandatoolbase.h"
#include "xFileAnimationSet.h"
#include "somethingToEggConverter.h"
#include "eggTextureCollection.h"
#include "eggMaterialCollection.h"
#include "pvector.h"
#include "pmap.h"
#include "luse.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@ -31,10 +35,11 @@
#include <rmxfguid.h>
#undef WIN32_LEAN_AND_MEAN
class EggGroupNode;
class Datagram;
class XFileMesh;
class XFileMaterial;
class EggGroup;
class EggGroupNode;
class EggTexture;
class EggMaterial;
@ -56,24 +61,53 @@ public:
virtual bool convert_file(const Filename &filename);
void close();
EggGroup *get_dart_node() const;
EggTexture *create_unique_texture(const EggTexture &copy);
EggMaterial *create_unique_material(const EggMaterial &copy);
EggGroup *find_joint(const string &joint_name);
EggGroup *find_joint(const string &joint_name,
const LMatrix4f &matrix_offset);
public:
bool _make_char;
string _char_name;
private:
typedef XFileAnimationSet::FrameData FrameData;
bool get_toplevel();
bool convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
EggGroupNode *egg_toplevel, bool &any_frames);
bool convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
bool convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent);
bool convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
bool convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
bool convert_transform(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
bool convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
bool convert_animation_set(LPDIRECTXFILEDATA obj);
bool convert_animation_set_object(LPDIRECTXFILEOBJECT obj,
XFileAnimationSet &animation_set);
bool convert_animation_set_data_object(LPDIRECTXFILEDATA obj,
XFileAnimationSet &animation_set);
bool convert_animation(LPDIRECTXFILEDATA obj,
XFileAnimationSet &animation_set);
bool convert_animation_object(LPDIRECTXFILEOBJECT obj,
const string &joint_name, FrameData &table);
bool convert_animation_data_object(LPDIRECTXFILEDATA obj,
const string &joint_name,
FrameData &table);
bool convert_animation_key(LPDIRECTXFILEDATA obj, const string &joint_name,
FrameData &table);
bool set_animation_frame(const string &joint_name, FrameData &table,
int frame, int key_type,
const float *values, int nvalues);
bool convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
bool is_toplevel);
bool convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh);
bool convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
bool convert_mesh_normals(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
bool convert_mesh_colors(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
bool convert_mesh_uvs(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
bool convert_skin_weights(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
bool convert_mesh_material_list(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
bool convert_material_list_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh);
bool convert_material_list_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
@ -82,12 +116,42 @@ private:
bool convert_material_data_object(LPDIRECTXFILEDATA obj, XFileMaterial &material);
bool convert_texture(LPDIRECTXFILEDATA obj, XFileMaterial &material);
bool create_polygons();
bool create_hierarchy();
string get_object_name(LPDIRECTXFILEOBJECT obj);
bool get_data(LPDIRECTXFILEDATA obj, Datagram &raw_data);
LPDIRECTXFILE _dx_file;
LPDIRECTXFILEENUMOBJECT _dx_file_enum;
bool _any_frames;
typedef pvector<XFileMesh *> Meshes;
Meshes _meshes;
Meshes _toplevel_meshes;
typedef pvector<XFileAnimationSet *> AnimationSets;
AnimationSets _animation_sets;
typedef pmap<LMatrix4f, EggGroup *> OffsetJoints;
// A joint definition consists of the pointer to the EggGroup that
// represents the actual joint, plus a table of synthetic joints
// that were created for each animation set's offset matrix (we need
// to create a different joint to apply each unique offset matrix in
// an animation set).
class JointDef {
public:
EggGroup *_node;
OffsetJoints _offsets;
};
typedef pmap<string, JointDef> Joints;
Joints _joints;
EggGroup *_dart_node;
EggTextureCollection _textures;
EggMaterialCollection _materials;
};

View File

@ -1,5 +1,6 @@
#include "config_xfile.cxx"
#include "xFileAnimationSet.cxx"
#include "xFileFace.cxx"
#include "xFileMaker.cxx"
#include "xFileMaterial.cxx"

View File

@ -33,7 +33,7 @@ EggToX() : EggToSomething("DirectX", ".x", true, false) {
("This program reads an Egg file and outputs an equivalent, "
"or nearly equivalent, DirectX-style .x file. Only simple "
"hierarchy and polygon meshes are supported; advanced features "
"like LOD's, decals, and characters cannot be supported.");
"like LOD's, decals, and animation or skinning are not supported.");
add_option
("m", "", 0,

View File

@ -36,9 +36,19 @@ XFileToEgg() :
add_transform_options();
set_program_description
("This program converts DirectX retained-mode (.x) files to egg. This "
"is a simple converter that only supports basic polygons, materials, "
"and textures, in a hierarchy; animation is not supported at this time.");
("This program converts DirectX retained-mode (.x) files to egg. "
"Polygon meshes, materials, and textures, as well as skeleton "
"animation and skinning data, are supported. All animations "
"found in the source .x file are written together into the same "
"egg file.");
add_option
("a", "name", 0,
"Convert as an animatable model, converting Frames into Joints. This "
"should be specified for a model which is intended to be animated. The "
"default is to convert the model as a normal static model, which is "
"usually more optimal if animation is not required.",
&XFileToEgg::dispatch_string, &_make_char, &_char_name);
redescribe_option
("cs",
@ -60,6 +70,9 @@ run() {
XFileToEggConverter converter;
converter.set_egg_data(&_data, false);
converter._make_char = _make_char;
converter._char_name = _char_name;
// Copy in the path and animation parameters.
apply_parameters(converter);

View File

@ -35,6 +35,10 @@ public:
XFileToEgg();
void run();
public:
bool _make_char;
string _char_name;
};
#endif