open_toontown_panda3d/pandatool/src/xfile/xFileNode.cxx

582 lines
20 KiB
C++

// Filename: xFileNode.cxx
// Created by: drose (03Oct04)
//
////////////////////////////////////////////////////////////////////
//
// 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 "xFileNode.h"
#include "windowsGuid.h"
#include "xFile.h"
#include "xLexerDefs.h"
#include "xFileParseData.h"
#include "xFile.h"
#include "xFileDataNodeTemplate.h"
#include "filename.h"
TypeHandle XFileNode::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: XFileNode::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
XFileNode::
XFileNode(XFile *x_file, const string &name) :
Namable(make_nice_name(name)),
_x_file(x_file)
{
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
XFileNode::
~XFileNode() {
clear();
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::find_child
// Access: Public
// Description: Returns the child with the indicated name, if any, or
// NULL if none.
////////////////////////////////////////////////////////////////////
XFileNode *XFileNode::
find_child(const string &name) const {
ChildrenByName::const_iterator ni;
ni = _children_by_name.find(name);
if (ni != _children_by_name.end()) {
return get_child((*ni).second);
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::find_child_index
// Access: Public
// Description: Returns the index number of the child with the
// indicated name, if any, or -1 if none.
////////////////////////////////////////////////////////////////////
int XFileNode::
find_child_index(const string &name) const {
ChildrenByName::const_iterator ni;
ni = _children_by_name.find(name);
if (ni != _children_by_name.end()) {
return (*ni).second;
}
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::find_child_index
// Access: Public
// Description: Returns the index number of the indicated child,
// or -1 if none.
////////////////////////////////////////////////////////////////////
int XFileNode::
find_child_index(const XFileNode *child) const {
for (int i = 0; i < (int)_children.size(); i++) {
if (_children[i] == child) {
return i;
}
}
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::find_descendent
// Access: Public
// Description: Returns the first child or descendent found with the
// indicated name after a depth-first search, if any, or
// NULL if none.
////////////////////////////////////////////////////////////////////
XFileNode *XFileNode::
find_descendent(const string &name) const {
XFileNode *child = find_child(name);
if (child != (XFileNode *)NULL) {
return child;
}
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
XFileNode *child = (*ci)->find_descendent(name);
if (child != (XFileNode *)NULL){
return child;
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::has_guid
// Access: Public, Virtual
// Description: Returns true if this node has a GUID associated.
////////////////////////////////////////////////////////////////////
bool XFileNode::
has_guid() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::get_guid
// Access: Public, Virtual
// Description: If has_guid() returned true, returns the particular
// GUID associated with this node.
////////////////////////////////////////////////////////////////////
const WindowsGuid &XFileNode::
get_guid() const {
static WindowsGuid empty;
return empty;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::is_template_def
// Access: Public, Virtual
// Description: Returns true if this node represents the definition
// of some template. This is the template definition,
// not an actual data object that represents an instance
// of the template. If the file strictly uses standard
// templates, the presence of template definitions is
// optional.
//
// If this returns true, the node must be of type
// XFileTemplate.
////////////////////////////////////////////////////////////////////
bool XFileNode::
is_template_def() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::is_reference
// Access: Public, Virtual
// Description: Returns true if this node represents an indirect
// reference to an object defined previously in the
// file. References are generally transparent, so in
// most cases you never need to call this, unless you
// actually need to differentiate between references and
// instances; you can simply use the reference node as
// if it were itself the object it references.
//
// If this returns true, the node must be of type
// XFileDataNodeReference.
////////////////////////////////////////////////////////////////////
bool XFileNode::
is_reference() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::is_object
// Access: Public, Virtual
// Description: Returns true if this node represents a data object
// that is the instance of some template, or false
// otherwise. This also returns true for references to
// objects (which are generally treated just like the
// objects themselves).
//
// If this returns true, the node must be of type
// XFileDataNode (it is either an XFileDataNodeTemplate
// or an XFileDataNodeReference).
////////////////////////////////////////////////////////////////////
bool XFileNode::
is_object() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::is_standard_object
// Access: Public, Virtual
// Description: Returns true if this node represents an instance of
// the standard template with the indicated name, or
// false otherwise. This returns also returns true for
// references to standard objects.
//
// If this returns true, the node must be of type
// XFileDataNode (it is either an XFileDataNodeTemplate
// or an XFileDataNodeReference).
////////////////////////////////////////////////////////////////////
bool XFileNode::
is_standard_object(const string &template_name) const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_child
// Access: Public
// Description: Adds the indicated node as a child of this node.
////////////////////////////////////////////////////////////////////
void XFileNode::
add_child(XFileNode *node) {
if (node->has_name()) {
_children_by_name[node->get_name()] = (int)_children.size();
}
if (node->has_guid()) {
_x_file->_nodes_by_guid[node->get_guid()] = node;
}
if (node->is_of_type(XFileDataNode::get_class_type())) {
_objects.push_back(DCAST(XFileDataNode, node));
}
_children.push_back(node);
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::clear
// Access: Public, Virtual
// Description: Removes all children from the node, and otherwise
// resets it to its initial state.
////////////////////////////////////////////////////////////////////
void XFileNode::
clear() {
_children.clear();
_objects.clear();
_children_by_name.clear();
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::write_text
// Access: Public, Virtual
// Description: Writes a suitable representation of this node to an
// .x file in text mode.
////////////////////////////////////////////////////////////////////
void XFileNode::
write_text(ostream &out, int indent_level) const {
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
(*ci)->write_text(out, indent_level);
}
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::repack_data
// Access: Public, Virtual
// Description: This is called on the template that defines an
// object, once the data for the object has been parsed.
// It is responsible for identifying which component of
// the template owns each data element, and packing the
// data elements appropriately back into the object.
//
// It returns true on success, or false on an error
// (e.g. not enough data elements, mismatched data
// type).
////////////////////////////////////////////////////////////////////
bool XFileNode::
repack_data(XFileDataObject *object,
const XFileParseDataList &parse_data_list,
XFileNode::PrevData &prev_data,
size_t &index, size_t &sub_index) const {
// This method should be specialized for data types that actually
// consume a data element. Here in the base class, it just walks
// through its children, asking each one to pull off the appropriate
// number of data elements.
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
if (!(*ci)->repack_data(object, parse_data_list,
prev_data, index, sub_index)) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::fill_zero_data
// Access: Public, Virtual
// Description: This is similar to repack_data(), except it is used
// to fill the initial values for a newly-created
// template object to zero.
////////////////////////////////////////////////////////////////////
bool XFileNode::
fill_zero_data(XFileDataObject *object) const {
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
if (!(*ci)->fill_zero_data(object)) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::matches
// Access: Public, Virtual
// Description: Returns true if the node, particularly a template
// node, is structurally equivalent to the other node
// (which must be of the same type). This checks data
// element types, but does not compare data element
// names.
////////////////////////////////////////////////////////////////////
bool XFileNode::
matches(const XFileNode *other) const {
if (other->get_type() != get_type()) {
return false;
}
if (other->get_num_children() != get_num_children()) {
return false;
}
for (int i = 0; i < get_num_children(); i++) {
if (!get_child(i)->matches(other->get_child(i))) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_Mesh
// Access: Public
// Description: Creates a new Mesh instance, as a child of this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_Mesh(const string &name) {
XFileTemplate *xtemplate = XFile::find_standard_template("Mesh");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_MeshNormals
// Access: Public
// Description: Creates a new MeshNormals instance, as a child of
// this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_MeshNormals(const string &name) {
XFileTemplate *xtemplate = XFile::find_standard_template("MeshNormals");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_MeshVertexColors
// Access: Public
// Description: Creates a new MeshVertexColors instance, as a child of
// this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_MeshVertexColors(const string &name) {
XFileTemplate *xtemplate = XFile::find_standard_template("MeshVertexColors");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_MeshTextureCoords
// Access: Public
// Description: Creates a new MeshTextureCoords instance, as a child of
// this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_MeshTextureCoords(const string &name) {
XFileTemplate *xtemplate = XFile::find_standard_template("MeshTextureCoords");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_MeshMaterialList
// Access: Public
// Description: Creates a new MeshMaterialList instance, as a child of
// this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_MeshMaterialList(const string &name) {
XFileTemplate *xtemplate = XFile::find_standard_template("MeshMaterialList");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_Material
// Access: Public
// Description: Creates a new Material instance, as a child of
// this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_Material(const string &name, const Colorf &face_color,
double power, const RGBColorf &specular_color,
const RGBColorf &emissive_color) {
XFileTemplate *xtemplate = XFile::find_standard_template("Material");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
(*node)["faceColor"]["red"] = face_color[0];
(*node)["faceColor"]["green"] = face_color[1];
(*node)["faceColor"]["blue"] = face_color[2];
(*node)["faceColor"]["alpha"] = face_color[3];
(*node)["power"] = power;
(*node)["specularColor"]["red"] = specular_color[0];
(*node)["specularColor"]["green"] = specular_color[1];
(*node)["specularColor"]["blue"] = specular_color[2];
(*node)["emissiveColor"]["red"] = emissive_color[0];
(*node)["emissiveColor"]["green"] = emissive_color[1];
(*node)["emissiveColor"]["blue"] = emissive_color[2];
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_TextureFilename
// Access: Public
// Description: Creates a new TextureFilename instance, as a child of
// this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_TextureFilename(const string &name, const Filename &filename) {
XFileTemplate *xtemplate = XFile::find_standard_template("TextureFilename");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
(*node)["filename"] = filename.to_os_specific();
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_Frame
// Access: Public
// Description: Creates a new Frame instance, as a child of this
// node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_Frame(const string &name) {
XFileTemplate *xtemplate = XFile::find_standard_template("Frame");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
add_child(node);
node->zero_fill();
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::add_FrameTransformMatrix
// Access: Public
// Description: Creates a new FrameTransformMatrix instance, as a
// child of this node.
////////////////////////////////////////////////////////////////////
XFileDataNode *XFileNode::
add_FrameTransformMatrix(const LMatrix4d &mat) {
XFileTemplate *xtemplate =
XFile::find_standard_template("FrameTransformMatrix");
nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
XFileDataNodeTemplate *node =
new XFileDataNodeTemplate(get_x_file(), "", xtemplate);
add_child(node);
node->zero_fill();
XFileDataObject &xmat = (*node)["frameMatrix"]["matrix"];
xmat[0] = mat(0, 0);
xmat[1] = mat(0, 1);
xmat[2] = mat(0, 2);
xmat[3] = mat(0, 3);
xmat[4] = mat(1, 0);
xmat[5] = mat(1, 1);
xmat[6] = mat(1, 2);
xmat[7] = mat(1, 3);
xmat[8] = mat(2, 0);
xmat[9] = mat(2, 1);
xmat[10] = mat(2, 2);
xmat[11] = mat(2, 3);
xmat[12] = mat(3, 0);
xmat[13] = mat(3, 1);
xmat[14] = mat(3, 2);
xmat[15] = mat(3, 3);
return node;
}
////////////////////////////////////////////////////////////////////
// Function: XFileNode::make_nice_name
// Access: Protected, Static
// Description: Transforms the indicated egg name to a name that is
// acceptable for a node in the X File format.
////////////////////////////////////////////////////////////////////
string XFileNode::
make_nice_name(const string &str) {
string result;
string::const_iterator si;
for (si = str.begin(); si != str.end(); ++si) {
if (isalnum(*si)) {
result += (*si);
} else {
switch (*si) {
case '-':
result += (*si);
break;
default:
result += "_";
}
}
}
if (!str.empty() && isdigit(str[0])) {
// If the name begins with a digit, we must make it begin with
// something else, like for instance an underscore.
result = '_' + result;
}
return result;
}