Panda3D
|
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 ©) : 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 }