Panda3D
Loading...
Searching...
No Matches
vrmlToEggConverter.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file vrmlToEggConverter.cxx
10 * @author drose
11 * @date 2004-10-01
12 */
13
14#include "vrmlToEggConverter.h"
15#include "vrmlAppearance.h"
16#include "indexedFaceSet.h"
17#include "vrmlNodeType.h"
18#include "parse_vrml.h"
19#include "vrmlParser.h"
20#include "eggGroupNode.h"
21#include "eggGroup.h"
22#include "eggData.h"
23#include "deg_2_rad.h"
24
25/**
26 *
27 */
28VRMLToEggConverter::
29VRMLToEggConverter() {
30}
31
32/**
33 *
34 */
35VRMLToEggConverter::
36VRMLToEggConverter(const VRMLToEggConverter &copy) :
38{
39}
40
41/**
42 *
43 */
44VRMLToEggConverter::
45~VRMLToEggConverter() {
46}
47
48/**
49 * Allocates and returns a new copy of the converter.
50 */
55
56
57/**
58 * Returns the English name of the file type this converter supports.
59 */
61get_name() const {
62 return "VRML";
63}
64
65/**
66 * Returns the common extension of the file type this converter supports.
67 */
69get_extension() const {
70 return "wrl";
71}
72
73/**
74 * Returns true if this file type can transparently load compressed files
75 * (with a .pz extension), false otherwise.
76 */
78supports_compressed() const {
79 return true;
80}
81
82/**
83 * Handles the reading of the input file and converting it to egg. Returns
84 * true if successful, false otherwise.
85 */
87convert_file(const Filename &filename) {
89
90 VrmlScene *scene = parse_vrml(filename);
91 if (scene == nullptr) {
92 return false;
93 }
94
95 if (_egg_data->get_coordinate_system() == CS_default) {
96 _egg_data->set_coordinate_system(CS_yup_right);
97 }
98
99 // First, resolve all the DEFUSE references, and count the number of times
100 // each node is USEd.
101 Nodes nodes;
102 VrmlScene::iterator si;
103 for (si = scene->begin(); si != scene->end(); ++si) {
104 get_all_defs((*si)._node, nodes);
105 }
106
107 // Now go through the hierarchy again, and this time actually build the egg
108 // structure.
109 VrmlScene::const_iterator csi;
110 for (csi = scene->begin(); csi != scene->end(); ++csi) {
111 vrml_node((*csi)._node, get_egg_data(), LMatrix4d::ident_mat());
112 }
113
114 return !had_error();
115}
116
117/**
118 * Makes a first pass through the VRML hierarchy, identifying all nodes marked
119 * with a DEF code, and also counting the times each one is referenced by USE.
120 * Later, we'll need this information: if a node is referenced at least once,
121 * we need to define it as an instance node.
122 */
123void VRMLToEggConverter::
124get_all_defs(SFNodeRef &vrml, VRMLToEggConverter::Nodes &nodes) {
125 Nodes::iterator ni;
126
127 switch (vrml._type) {
128 case SFNodeRef::T_def:
129 // If this is a node definition, add it to the map.
130 nassertv(vrml._name != nullptr);
131 nassertv(vrml._p != nullptr);
132 /*
133 This happens too often to bother yelling about it.
134 ni = nodes.find(vrml._name);
135 if (ni != nodes.end()) {
136 cerr << "Warning: node name " << vrml._name
137 << " appears multiple times.\n";
138 }
139 */
140 nodes[vrml._name] = vrml._p;
141 break;
142
143 case SFNodeRef::T_use:
144 // If it's a reference, resolve it.
145 nassertv(vrml._name != nullptr);
146 ni = nodes.find(vrml._name);
147 if (ni == nodes.end()) {
148 std::cerr << "Unknown node reference: " << vrml._name << "\n";
149 } else {
150 // Increment the use count of the node.
151 (*ni).second->_use_count++;
152
153 // Store the pointer itself in the reference, so we don't have to do
154 // this again later.
155 vrml._p = (*ni).second;
156 }
157 return;
158
159 default:
160 break;
161 }
162
163 VrmlNode *node = vrml._p;
164 if (node != nullptr) {
165 VrmlNode::Fields::iterator fi;
166 for (fi = node->_fields.begin(); fi != node->_fields.end(); ++fi) {
167 if ((*fi)._type->type == SFNODE) {
168 get_all_defs((*fi)._value._sfnode, nodes);
169 } else if ((*fi)._type->type == MFNODE) {
170 MFArray *children = (*fi)._value._mf;
171 MFArray::iterator ci;
172 for (ci = children->begin(); ci != children->end(); ++ci) {
173 get_all_defs((*ci)._sfnode, nodes);
174 }
175 }
176 }
177 }
178}
179
180/**
181 * Processes a single VRML node, converting it to egg and adding it to the egg
182 * file, if appropriate, or doing whatever else should be done.
183 */
184void VRMLToEggConverter::
185vrml_node(const SFNodeRef &vrml, EggGroupNode *egg,
186 const LMatrix4d &net_transform) {
187 const VrmlNode *node = vrml._p;
188 if (node != nullptr) {
189 // Now add it to the egg file at this point.
190 if (strcmp(node->_type->getName(), "Group") == 0) {
191 vrml_grouping_node(vrml, egg, net_transform,
192 &VRMLToEggConverter::vrml_group);
193 } else if (strcmp(node->_type->getName(), "Transform") == 0) {
194 vrml_grouping_node(vrml, egg, net_transform,
195 &VRMLToEggConverter::vrml_transform);
196 } else if (strcmp(node->_type->getName(), "Shape") == 0) {
197 vrml_grouping_node(vrml, egg, net_transform,
198 &VRMLToEggConverter::vrml_shape);
199 }
200 }
201}
202
203/**
204 * Begins initial processing of a grouping-type node; that is, any node (like
205 * Group, Transform, or Shape) that maps to a <Group> or <Instance> in egg.
206 * This create the group and does any instance-munging necessary, then calls
207 * the indicated method with the new parameters.
208 */
209void VRMLToEggConverter::
210vrml_grouping_node(const SFNodeRef &vrml, EggGroupNode *egg,
211 const LMatrix4d &net_transform,
212 void (VRMLToEggConverter::*process_func)
213 (const VrmlNode *node, EggGroup *group,
214 const LMatrix4d &net_transform)) {
215 const VrmlNode *node = vrml._p;
216 nassertv(node != nullptr);
217 std::string name;
218 if (vrml._name != nullptr) {
219 name = vrml._name;
220 }
221
222 /*
223 The following code fragment was used in the old DWD-style egg
224 library. Currently, the Panda egg library doesn't support
225 instance references, so we deal with VRML instances by copying.
226
227 if (vrml._type == SFNodeRef::T_use) {
228 // If this is an instancing reference, just add the reference and return;
229 // no need for further processing on the node.
230 Instances::const_iterator fi = _instances.find(node);
231 assert(fi != _instances.end());
232 EggInstance *inst = _data.CreateInstance(egg);
233 inst->AddGroupRef((*fi).second);
234 return;
235 }
236 */
237
238 PT(EggGroup) group = new EggGroup(name);
239 egg->add_child(group);
240
241 LMatrix4d next_transform = net_transform;
242
243 if (node->_use_count > 0) {
244 // If this node is referenced one or more times later in the file, we must
245 // make it an instance node.
246 group->set_group_type(EggGroup::GT_instance);
247 next_transform = LMatrix4d::ident_mat();
248
249 // And define the instance for future references. _instances[node] =
250 // group;
251 }
252
253 (this->*process_func)(node, group, next_transform);
254}
255
256
257/**
258 * Creates an Egg group corresponding to the VRML group.
259 */
260void VRMLToEggConverter::
261vrml_group(const VrmlNode *node, EggGroup *group,
262 const LMatrix4d &net_transform) {
263 const MFArray *children = node->get_value("children")._mf;
264 MFArray::const_iterator ci;
265 for (ci = children->begin(); ci != children->end(); ++ci) {
266 vrml_node((*ci)._sfnode, group, net_transform);
267 }
268}
269
270/**
271 * Creates an Egg group with a transform corresponding to the VRML group.
272 */
273void VRMLToEggConverter::
274vrml_transform(const VrmlNode *node, EggGroup *group,
275 const LMatrix4d &net_transform) {
276 const double *scale = node->get_value("scale")._sfvec;
277 const double *rotation = node->get_value("rotation")._sfvec;
278 const double *translation = node->get_value("translation")._sfvec;
279
280 const double *center = node->get_value("center")._sfvec;
281 const double *o = node->get_value("scaleOrientation")._sfvec;
282
283 LMatrix4d local_transform = LMatrix4d::ident_mat();
284
285 bool any_transform = false;
286
287 if (scale[0] != 1.0 || scale[1] != 1.0 || scale[2] != 1.0) {
288 any_transform = true;
289 if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
290 local_transform *=
291 LMatrix4d::translate_mat(-center[0], -center[1], -center[2]);
292
293 if (o[3] != 0.0) {
294 local_transform *=
295 LMatrix4d::rotate_mat(rad_2_deg(-o[3]), LVector3d(o[0], o[1], o[2]));
296 local_transform *=
297 LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
298 local_transform *=
299 LMatrix4d::rotate_mat(rad_2_deg(o[3]), LVector3d(o[0], o[1], o[2]));
300
301 } else {
302 local_transform *=
303 LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
304 }
305 local_transform *=
306 LMatrix4d::translate_mat(center[0], center[1], center[2]);
307
308 } else {
309 if (o[3] != 0.0) {
310 local_transform *=
311 LMatrix4d::rotate_mat(rad_2_deg(-o[3]), LVector3d(o[0], o[1], o[2]));
312 local_transform *=
313 LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
314 local_transform *=
315 LMatrix4d::rotate_mat(rad_2_deg(o[3]), LVector3d(o[0], o[1], o[2]));
316
317 } else {
318 local_transform *=
319 LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
320 }
321 }
322 }
323
324 if (rotation[3] != 0.0) {
325 any_transform = true;
326 if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
327 local_transform *=
328 LMatrix4d::translate_mat(-center[0], -center[1], -center[2]);
329 local_transform *=
330 LMatrix4d::rotate_mat(rad_2_deg(rotation[3]),
331 LVector3d(rotation[0], rotation[1], rotation[2]));
332 local_transform *=
333 LMatrix4d::translate_mat(center[0], center[1], center[2]);
334
335 } else {
336 local_transform *=
337 LMatrix4d::rotate_mat(rad_2_deg(rotation[3]),
338 LVector3d(rotation[0], rotation[1], rotation[2]));
339 }
340 }
341
342 if (translation[0] != 0.0 ||
343 translation[1] != 0.0 ||
344 translation[2] != 0.0) {
345 any_transform = true;
346 local_transform *=
347 LMatrix4d::translate_mat(translation[0], translation[1], translation[2]);
348 }
349
350 if (any_transform) {
351 group->set_transform3d(local_transform);
352 }
353
354 LMatrix4d next_transform = local_transform * net_transform;
355
356 const MFArray *children = node->get_value("children")._mf;
357 MFArray::const_iterator ci;
358 for (ci = children->begin(); ci != children->end(); ++ci) {
359 vrml_node((*ci)._sfnode, group, next_transform);
360 }
361}
362
363/**
364 * Creates an Egg group corresponding a VRML shape. This will probably
365 * contain a vertex pool and a number of polygons.
366 */
367void VRMLToEggConverter::
368vrml_shape(const VrmlNode *node, EggGroup *group,
369 const LMatrix4d &net_transform) {
370 const VrmlNode *geometry = node->get_value("geometry")._sfnode._p;
371
372 if (geometry != nullptr) {
373 VRMLAppearance appearance(node->get_value("appearance")._sfnode._p);
374
375 if (strcmp(geometry->_type->getName(), "IndexedFaceSet") == 0) {
376 IndexedFaceSet ifs(geometry, appearance);
377 ifs.convert_to_egg(group, net_transform);
378 } else {
379 std::cerr << "Ignoring " << geometry->_type->getName() << "\n";
380 }
381 }
382}
A base class for nodes in the hierarchy that are not leaf nodes.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition eggGroup.h:34
void set_transform3d(const LMatrix4d &mat)
Sets the overall transform as a 4x4 matrix.
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
Decodes the vertices and faces in a VRML indexed face set, and creates the corresponding egg geometry...
This is a base class for a family of converter classes that manage a conversion from some file type t...
bool had_error() const
Returns true if an error was detected during the conversion process (unless _allow_errors is true),...
EggData * get_egg_data()
Returns the EggData structure.
void clear_error()
Resets the error flag to the no-error state.
This class supervises the construction of an EggData structure from a VRML file.
virtual std::string get_name() const
Returns the English name of the file type this converter supports.
virtual SomethingToEggConverter * make_copy()
Allocates and returns a new copy of the converter.
virtual std::string get_extension() const
Returns the common extension of the file type this converter supports.
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension),...
virtual bool convert_file(const Filename &filename)
Handles the reading of the input file and converting it to egg.
This is our own Panda specialization on the default STL map.
Definition pmap.h:49
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
VrmlScene * parse_vrml(Filename filename)
Reads the named VRML file and returns a corresponding VrmlScene, or NULL if there is a parse error.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.