271 lines
8.1 KiB
C++
271 lines
8.1 KiB
C++
// Filename: xFileMaker.cxx
|
|
// Created by: drose (19Jun01)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "xFileMaker.h"
|
|
#include "xFileMesh.h"
|
|
#include "xFileMaterial.h"
|
|
#include "config_xfile.h"
|
|
|
|
#include "pnotify.h"
|
|
#include "eggGroupNode.h"
|
|
#include "eggGroup.h"
|
|
#include "eggBin.h"
|
|
#include "eggPolysetMaker.h"
|
|
#include "eggVertexPool.h"
|
|
#include "eggVertex.h"
|
|
#include "eggPolygon.h"
|
|
#include "eggData.h"
|
|
#include "pvector.h"
|
|
#include "vector_int.h"
|
|
#include "string_utils.h"
|
|
#include "datagram.h"
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
XFileMaker::
|
|
XFileMaker() {
|
|
_mesh_index = 0;
|
|
_x_file = new XFile;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::Destructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
XFileMaker::
|
|
~XFileMaker() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::write
|
|
// Access: Public
|
|
// Description: Writes the .x file data to the indicated filename;
|
|
// returns true on success, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
write(const Filename &filename) {
|
|
return _x_file->write(filename);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::add_tree
|
|
// Access: Public
|
|
// Description: Adds the egg tree rooted at the indicated node to the
|
|
// X structure. This may be somewhat destructive of
|
|
// the egg tree. Returns true on success, false on
|
|
// failure.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
add_tree(EggData *egg_data) {
|
|
_meshes.clear();
|
|
|
|
// Now collect all the polygons together into polysets.
|
|
EggPolysetMaker pmaker;
|
|
pmaker.make_bins(egg_data);
|
|
|
|
// And now we're ready to traverse the egg hierarchy.
|
|
if (!recurse_nodes(egg_data, _x_file)) {
|
|
return false;
|
|
}
|
|
|
|
// Create X structures for all of the meshes we built up.
|
|
Meshes::iterator mi;
|
|
for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
|
|
if (!finalize_mesh((*mi).first, (*mi).second)) {
|
|
return false;
|
|
}
|
|
}
|
|
_meshes.clear();
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::add_node
|
|
// Access: Private
|
|
// Description: Adds the node to the DX structure, in whatever form
|
|
// it is supported.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
add_node(EggNode *egg_node, XFileNode *x_parent) {
|
|
if (egg_node->is_of_type(EggBin::get_class_type())) {
|
|
return add_bin(DCAST(EggBin, egg_node), x_parent);
|
|
|
|
} else if (egg_node->is_of_type(EggGroup::get_class_type())) {
|
|
return add_group(DCAST(EggGroup, egg_node), x_parent);
|
|
|
|
} else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
|
|
// A grouping node of some kind.
|
|
EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
|
|
|
|
if (xfile_one_mesh) {
|
|
// Don't create any additional frames representing the egg
|
|
// hierarchy.
|
|
if (!recurse_nodes(egg_group, x_parent)) {
|
|
return false;
|
|
}
|
|
|
|
} else {
|
|
// Create a Frame for each EggGroup.
|
|
XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
|
|
|
|
if (!recurse_nodes(egg_group, x_frame)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Some unsupported node type. Ignore it.
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::add_group
|
|
// Access: Private
|
|
// Description: Adds a frame for the indicated group node.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
add_group(EggGroup *egg_group, XFileNode *x_parent) {
|
|
if (xfile_one_mesh) {
|
|
// Don't create any additional frames representing the egg
|
|
// hierarchy.
|
|
if (!recurse_nodes(egg_group, x_parent)) {
|
|
return false;
|
|
}
|
|
|
|
} else {
|
|
// Create a frame for each EggGroup.
|
|
XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
|
|
|
|
// Set the transform on the frame, if we have one.
|
|
if (egg_group->has_transform()) {
|
|
x_frame->add_FrameTransformMatrix(egg_group->get_transform3d());
|
|
}
|
|
|
|
if (!recurse_nodes(egg_group, x_frame)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::add_bin
|
|
// Access: Private
|
|
// Description: Determines what kind of object needs to be added for
|
|
// the indicated bin node.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
add_bin(EggBin *egg_bin, XFileNode *x_parent) {
|
|
switch (egg_bin->get_bin_number()) {
|
|
case EggPolysetMaker::BN_polyset:
|
|
return add_polyset(egg_bin, x_parent);
|
|
}
|
|
|
|
xfile_cat.error()
|
|
<< "Unexpected bin type " << egg_bin->get_bin_number() << "\n";
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::add_polyset
|
|
// Access: Private
|
|
// Description: Adds a mesh object corresponding to the collection of
|
|
// polygons within the indicated bin.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
add_polyset(EggBin *egg_bin, XFileNode *x_parent) {
|
|
// Make sure that all our polygons are reasonable.
|
|
egg_bin->remove_invalid_primitives(true);
|
|
|
|
XFileMesh *mesh = get_mesh(x_parent);
|
|
|
|
EggGroupNode::iterator ci;
|
|
for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
|
|
EggPolygon *poly;
|
|
DCAST_INTO_R(poly, *ci, false);
|
|
|
|
mesh->add_polygon(poly);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::recurse_nodes
|
|
// Access: Private
|
|
// Description: Adds each child of the indicated Node as a child of
|
|
// the indicated DX object.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
recurse_nodes(EggGroupNode *egg_node, XFileNode *x_parent) {
|
|
EggGroupNode::iterator ci;
|
|
for (ci = egg_node->begin(); ci != egg_node->end(); ++ci) {
|
|
EggNode *child = (*ci);
|
|
if (!add_node(child, x_parent)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::get_mesh
|
|
// Access: Private
|
|
// Description: Returns a suitable XFileMesh object for creating
|
|
// meshes within the indicated x_parent object.
|
|
////////////////////////////////////////////////////////////////////
|
|
XFileMesh *XFileMaker::
|
|
get_mesh(XFileNode *x_parent) {
|
|
Meshes::iterator mi = _meshes.find(x_parent);
|
|
if (mi != _meshes.end()) {
|
|
// We've already started working on this x_parent before; use the
|
|
// same mesh object.
|
|
return (*mi).second;
|
|
}
|
|
|
|
// We haven't seen this x_parent before; create a new mesh object.
|
|
XFileMesh *mesh = new XFileMesh;
|
|
_meshes.insert(Meshes::value_type(x_parent, mesh));
|
|
return mesh;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFileMaker::finalize_mesh
|
|
// Access: Private
|
|
// Description: Creates the actual X structures corresponding to
|
|
// the indicated XFileMesh object.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFileMaker::
|
|
finalize_mesh(XFileNode *x_parent, XFileMesh *mesh) {
|
|
// Get a unique number for each mesh.
|
|
_mesh_index++;
|
|
string mesh_index = format_string(_mesh_index);
|
|
|
|
// Finally, create the Mesh object.
|
|
mesh->make_x_mesh(x_parent, mesh_index);
|
|
|
|
return true;
|
|
}
|