Panda3D

vrmlToEggConverter.cxx

00001 // Filename: vrmlToEggConverter.cxx
00002 // Created by:  drose (01Oct04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "vrmlToEggConverter.h"
00016 #include "vrmlAppearance.h"
00017 #include "indexedFaceSet.h"
00018 #include "vrmlNodeType.h"
00019 #include "parse_vrml.h"
00020 #include "vrmlParser.h"
00021 #include "eggGroupNode.h"
00022 #include "eggGroup.h"
00023 #include "eggData.h"
00024 #include "deg_2_rad.h"
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: VRMLToEggConverter::Constructor
00028 //       Access: Public
00029 //  Description:
00030 ////////////////////////////////////////////////////////////////////
00031 VRMLToEggConverter::
00032 VRMLToEggConverter() {
00033 }
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: VRMLToEggConverter::Copy Constructor
00037 //       Access: Public
00038 //  Description:
00039 ////////////////////////////////////////////////////////////////////
00040 VRMLToEggConverter::
00041 VRMLToEggConverter(const VRMLToEggConverter &copy) :
00042   SomethingToEggConverter(copy)
00043 {
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: VRMLToEggConverter::Destructor
00048 //       Access: Public
00049 //  Description:
00050 ////////////////////////////////////////////////////////////////////
00051 VRMLToEggConverter::
00052 ~VRMLToEggConverter() {
00053 }
00054 
00055 ////////////////////////////////////////////////////////////////////
00056 //     Function: VRMLToEggConverter::make_copy
00057 //       Access: Public, Virtual
00058 //  Description: Allocates and returns a new copy of the converter.
00059 ////////////////////////////////////////////////////////////////////
00060 SomethingToEggConverter *VRMLToEggConverter::
00061 make_copy() {
00062   return new VRMLToEggConverter(*this);
00063 }
00064 
00065 
00066 ////////////////////////////////////////////////////////////////////
00067 //     Function: VRMLToEggConverter::get_name
00068 //       Access: Public, Virtual
00069 //  Description: Returns the English name of the file type this
00070 //               converter supports.
00071 ////////////////////////////////////////////////////////////////////
00072 string VRMLToEggConverter::
00073 get_name() const {
00074   return "VRML";
00075 }
00076 
00077 ////////////////////////////////////////////////////////////////////
00078 //     Function: VRMLToEggConverter::get_extension
00079 //       Access: Public, Virtual
00080 //  Description: Returns the common extension of the file type this
00081 //               converter supports.
00082 ////////////////////////////////////////////////////////////////////
00083 string VRMLToEggConverter::
00084 get_extension() const {
00085   return "wrl";
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: VRMLToEggConverter::supports_compressed
00090 //       Access: Published, Virtual
00091 //  Description: Returns true if this file type can transparently load
00092 //               compressed files (with a .pz extension), false
00093 //               otherwise.
00094 ////////////////////////////////////////////////////////////////////
00095 bool VRMLToEggConverter::
00096 supports_compressed() const {
00097   return true;
00098 }
00099 
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: VRMLToEggConverter::convert_file
00102 //       Access: Public, Virtual
00103 //  Description: Handles the reading of the input file and converting
00104 //               it to egg.  Returns true if successful, false
00105 //               otherwise.
00106 ////////////////////////////////////////////////////////////////////
00107 bool VRMLToEggConverter::
00108 convert_file(const Filename &filename) {
00109   clear_error();
00110 
00111   VrmlScene *scene = parse_vrml(filename);
00112   if (scene == (VrmlScene *)NULL) {
00113     return false;
00114   }
00115 
00116   if (_egg_data->get_coordinate_system() == CS_default) {
00117     _egg_data->set_coordinate_system(CS_yup_right);
00118   }
00119 
00120   // First, resolve all the DEF/USE references, and count the number
00121   // of times each node is USEd.
00122   Nodes nodes;
00123   VrmlScene::iterator si;
00124   for (si = scene->begin(); si != scene->end(); ++si) {
00125     get_all_defs((*si)._node, nodes);
00126   }
00127 
00128   // Now go through the hierarchy again, and this time actually
00129   // build the egg structure.
00130   VrmlScene::const_iterator csi;
00131   for (csi = scene->begin(); csi != scene->end(); ++csi) {
00132     vrml_node((*csi)._node, get_egg_data(), LMatrix4d::ident_mat());
00133   }
00134 
00135   return !had_error();
00136 }
00137 
00138 ////////////////////////////////////////////////////////////////////
00139 //     Function: VRMLToEggConverter::get_all_defs
00140 //       Access: Private
00141 //  Description: Makes a first pass through the VRML hierarchy,
00142 //               identifying all nodes marked with a DEF code, and
00143 //               also counting the times each one is referenced by
00144 //               USE.  Later, we'll need this information: if a node
00145 //               is referenced at least once, we need to define it as
00146 //               an instance node.
00147 ////////////////////////////////////////////////////////////////////
00148 void VRMLToEggConverter::
00149 get_all_defs(SFNodeRef &vrml, VRMLToEggConverter::Nodes &nodes) {
00150   Nodes::iterator ni;
00151   
00152   switch (vrml._type) {
00153   case SFNodeRef::T_def:
00154     // If this is a node definition, add it to the map.
00155     nassertv(vrml._name != NULL);
00156     nassertv(vrml._p != NULL);
00157     /*
00158       This happens too often to bother yelling about it.
00159     ni = nodes.find(vrml._name);
00160     if (ni != nodes.end()) {
00161       cerr << "Warning: node name " << vrml._name 
00162            << " appears multiple times.\n";
00163     }
00164     */
00165     nodes[vrml._name] = vrml._p;
00166     break;
00167 
00168   case SFNodeRef::T_use:
00169     // If it's a reference, resolve it.
00170     nassertv(vrml._name != NULL);
00171     ni = nodes.find(vrml._name);
00172     if (ni == nodes.end()) {
00173       cerr << "Unknown node reference: " << vrml._name << "\n";
00174     } else {
00175       // Increment the use count of the node.
00176       (*ni).second->_use_count++;
00177 
00178       // Store the pointer itself in the reference, so we don't have
00179       // to do this again later.
00180       vrml._p = (*ni).second;
00181     }
00182     return;
00183 
00184   default:
00185     break;
00186   }
00187 
00188   VrmlNode *node = vrml._p;
00189   if (node != NULL) {
00190     VrmlNode::Fields::iterator fi;
00191     for (fi = node->_fields.begin(); fi != node->_fields.end(); ++fi) {
00192       if ((*fi)._type->type == SFNODE) {
00193         get_all_defs((*fi)._value._sfnode, nodes);
00194       } else if ((*fi)._type->type == MFNODE) {
00195         MFArray *children = (*fi)._value._mf;
00196         MFArray::iterator ci;
00197         for (ci = children->begin(); ci != children->end(); ++ci) {
00198           get_all_defs((*ci)._sfnode, nodes);
00199         }
00200       }
00201     }
00202   }
00203 }
00204 
00205 ////////////////////////////////////////////////////////////////////
00206 //     Function: VRMLToEggConverter::vrml_node
00207 //       Access: Public
00208 //  Description: Processes a single VRML node, converting it to egg
00209 //               and adding it to the egg file, if appropriate, or
00210 //               doing whatever else should be done.
00211 ////////////////////////////////////////////////////////////////////
00212 void VRMLToEggConverter::
00213 vrml_node(const SFNodeRef &vrml, EggGroupNode *egg, 
00214           const LMatrix4d &net_transform) {
00215   const VrmlNode *node = vrml._p;
00216   if (node != NULL) {
00217     // Now add it to the egg file at this point.
00218     if (strcmp(node->_type->getName(), "Group") == 0) {
00219       vrml_grouping_node(vrml, egg, net_transform, 
00220                          &VRMLToEggConverter::vrml_group);
00221     } else if (strcmp(node->_type->getName(), "Transform") == 0) {
00222       vrml_grouping_node(vrml, egg, net_transform, 
00223                          &VRMLToEggConverter::vrml_transform);
00224     } else if (strcmp(node->_type->getName(), "Shape") == 0) {
00225       vrml_grouping_node(vrml, egg, net_transform, 
00226                          &VRMLToEggConverter::vrml_shape);
00227     }
00228   }
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: VRMLToEggConverter::vrml_grouping_node
00233 //       Access: Public
00234 //  Description: Begins initial processing of a grouping-type node;
00235 //               that is, any node (like Group, Transform, or Shape)
00236 //               that maps to a <Group> or <Instance> in egg.  This
00237 //               create the group and does any instance-munging
00238 //               necessary, then calls the indicated method with the
00239 //               new parameters.
00240 ////////////////////////////////////////////////////////////////////
00241 void VRMLToEggConverter::
00242 vrml_grouping_node(const SFNodeRef &vrml, EggGroupNode *egg,
00243                    const LMatrix4d &net_transform,
00244                    void (VRMLToEggConverter::*process_func)
00245                    (const VrmlNode *node, EggGroup *group,
00246                     const LMatrix4d &net_transform)) {
00247   const VrmlNode *node = vrml._p;
00248   nassertv(node != NULL);
00249   string name;
00250   if (vrml._name != NULL) {
00251     name = vrml._name;
00252   }
00253 
00254   /*
00255     The following code fragment was used in the old DWD-style egg
00256     library.  Currently, the Panda egg library doesn't support
00257     instance references, so we deal with VRML instances by copying.
00258 
00259   if (vrml._type == SFNodeRef::T_use) {
00260     // If this is an instancing reference, just add the reference and
00261     // return; no need for further processing on the node.
00262     Instances::const_iterator fi = _instances.find(node);
00263     assert(fi != _instances.end());
00264     EggInstance *inst = _data.CreateInstance(egg);
00265     inst->AddGroupRef((*fi).second);
00266     return;
00267   }
00268     */
00269 
00270   PT(EggGroup) group = new EggGroup(name);
00271   egg->add_child(group);
00272 
00273   LMatrix4d next_transform = net_transform;
00274 
00275   if (node->_use_count > 0) {
00276     // If this node is referenced one or more times later in the file,
00277     // we must make it an instance node.
00278     group->set_group_type(EggGroup::GT_instance);
00279     next_transform = LMatrix4d::ident_mat();
00280 
00281     // And define the instance for future references.
00282     //    _instances[node] = group;
00283   }
00284 
00285   (this->*process_func)(node, group, next_transform);
00286 }
00287 
00288 
00289 ////////////////////////////////////////////////////////////////////
00290 //     Function: VRMLToEggConverter::vrml_group
00291 //       Access: Public
00292 //  Description: Creates an Egg group corresponding to the VRML group.
00293 ////////////////////////////////////////////////////////////////////
00294 void VRMLToEggConverter::
00295 vrml_group(const VrmlNode *node, EggGroup *group,
00296            const LMatrix4d &net_transform) {
00297   const MFArray *children = node->get_value("children")._mf;
00298   MFArray::const_iterator ci;
00299   for (ci = children->begin(); ci != children->end(); ++ci) {
00300     vrml_node((*ci)._sfnode, group, net_transform);
00301   }
00302 }
00303 
00304 ////////////////////////////////////////////////////////////////////
00305 //     Function: VRMLToEggConverter::vrml_transform
00306 //       Access: Public
00307 //  Description: Creates an Egg group with a transform corresponding
00308 //               to the VRML group.
00309 ////////////////////////////////////////////////////////////////////
00310 void VRMLToEggConverter::
00311 vrml_transform(const VrmlNode *node, EggGroup *group,
00312                const LMatrix4d &net_transform) {
00313   const double *scale = node->get_value("scale")._sfvec;
00314   const double *rotation = node->get_value("rotation")._sfvec;
00315   const double *translation = node->get_value("translation")._sfvec;
00316 
00317   const double *center = node->get_value("center")._sfvec;
00318   const double *o = node->get_value("scaleOrientation")._sfvec;
00319 
00320   LMatrix4d local_transform = LMatrix4d::ident_mat();
00321 
00322   bool any_transform = false;
00323 
00324   if (scale[0] != 1.0 || scale[1] != 1.0 || scale[2] != 1.0) {
00325     any_transform = true;
00326     if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
00327       local_transform *=
00328         LMatrix4d::translate_mat(-center[0], -center[1], -center[2]);
00329 
00330       if (o[3] != 0.0) {
00331         local_transform *= 
00332           LMatrix4d::rotate_mat(rad_2_deg(-o[3]), LVector3d(o[0], o[1], o[2]));
00333         local_transform *=
00334           LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
00335         local_transform *= 
00336           LMatrix4d::rotate_mat(rad_2_deg(o[3]), LVector3d(o[0], o[1], o[2]));
00337 
00338       } else {
00339         local_transform *=
00340           LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
00341       }
00342       local_transform *= 
00343         LMatrix4d::translate_mat(center[0], center[1], center[2]);
00344 
00345     } else {
00346       if (o[3] != 0.0) {
00347         local_transform *= 
00348           LMatrix4d::rotate_mat(rad_2_deg(-o[3]), LVector3d(o[0], o[1], o[2]));
00349         local_transform *=
00350           LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
00351         local_transform *= 
00352           LMatrix4d::rotate_mat(rad_2_deg(o[3]), LVector3d(o[0], o[1], o[2]));
00353 
00354       } else {
00355         local_transform *=
00356           LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
00357       }
00358     }      
00359   }
00360 
00361   if (rotation[3] != 0.0) {
00362     any_transform = true;
00363     if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
00364       local_transform *= 
00365         LMatrix4d::translate_mat(-center[0], -center[1], -center[2]);
00366       local_transform *= 
00367         LMatrix4d::rotate_mat(rad_2_deg(rotation[3]),
00368                               LVector3d(rotation[0], rotation[1], rotation[2]));
00369       local_transform *=
00370         LMatrix4d::translate_mat(center[0], center[1], center[2]);
00371 
00372     } else {
00373       local_transform *=
00374         LMatrix4d::rotate_mat(rad_2_deg(rotation[3]),
00375                               LVector3d(rotation[0], rotation[1], rotation[2]));
00376     }
00377   }
00378 
00379   if (translation[0] != 0.0 ||
00380       translation[1] != 0.0 ||
00381       translation[2] != 0.0) {
00382     any_transform = true;
00383     local_transform *=
00384       LMatrix4d::translate_mat(translation[0], translation[1], translation[2]);
00385   }
00386 
00387   if (any_transform) {
00388     group->set_transform3d(local_transform);
00389   }
00390 
00391   LMatrix4d next_transform = local_transform * net_transform;
00392 
00393   const MFArray *children = node->get_value("children")._mf;
00394   MFArray::const_iterator ci;
00395   for (ci = children->begin(); ci != children->end(); ++ci) {
00396     vrml_node((*ci)._sfnode, group, next_transform);
00397   }
00398 }
00399 
00400 ////////////////////////////////////////////////////////////////////
00401 //     Function: VRMLToEggConverter::vrml_shape
00402 //       Access: Public
00403 //  Description: Creates an Egg group corresponding a VRML shape.
00404 //               This will probably contain a vertex pool and a number
00405 //               of polygons.
00406 ////////////////////////////////////////////////////////////////////
00407 void VRMLToEggConverter::
00408 vrml_shape(const VrmlNode *node, EggGroup *group,
00409            const LMatrix4d &net_transform) {
00410   const VrmlNode *geometry = node->get_value("geometry")._sfnode._p;
00411 
00412   if (geometry != NULL) {
00413     VRMLAppearance appearance(node->get_value("appearance")._sfnode._p);
00414 
00415     if (strcmp(geometry->_type->getName(), "IndexedFaceSet") == 0) {
00416       IndexedFaceSet ifs(geometry, appearance);
00417       ifs.convert_to_egg(group, net_transform);
00418     } else {
00419       cerr << "Ignoring " << geometry->_type->getName() << "\n";
00420     }
00421   }
00422 }
 All Classes Functions Variables Enumerations