1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SoToVRMLAction SoToVRMLAction.h Inventor/actions/SoToVRMLAction.h
35   \brief The SoToVRMLAction class builds a new scene graph using only VRML 1.0 nodes.
36 
37   \ingroup actions
38 
39   This action is used for converting a scene graph of VRML2/VRML97
40   nodes to a new scene graph using only VRML1 compatible nodes.
41 
42   A current limitation of this action is that nodes specific for
43   Inventor / Coin (ie neither VRML1 or VRML97 compatible nodes) is not
44   attempted converted, they are just ignored.
45 
46   \sa SoToVRML2Action
47 
48   \since Coin 2.0
49   \since TGS Inventor 2.5
50 */
51 
52 #include <Inventor/actions/SoToVRMLAction.h>
53 
54 #include <cstdio>
55 #include <cstdlib>
56 #include <cstring>
57 
58 #ifdef HAVE_CONFIG_H
59 #include "config.h"
60 #endif // HAVE_CONFIG_H
61 
62 #include <Inventor/SbName.h>
63 #include <Inventor/actions/SoCallbackAction.h>
64 #include <Inventor/actions/SoSearchAction.h>
65 #include <Inventor/SoDB.h>
66 #include <Inventor/nodes/SoNodes.h>
67 #include <Inventor/SoInput.h>
68 #include <Inventor/SoOutput.h>
69 #include <Inventor/SbBSPTree.h>
70 #include <Inventor/actions/SoCallbackAction.h>
71 #include <Inventor/actions/SoSearchAction.h>
72 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
73 #include <Inventor/SbViewportRegion.h>
74 #include <Inventor/nodes/SoTransform.h>
75 #include <Inventor/actions/SoWriteAction.h>
76 #include <Inventor/lists/SbList.h>
77 #include <Inventor/SoPrimitiveVertex.h>
78 #include <Inventor/lists/SoPathList.h>
79 #include <Inventor/lists/SoNodeList.h>
80 
81 #ifdef HAVE_NODEKITS
82 #include <Inventor/nodekits/SoBaseKit.h>
83 #endif // HAVE_NODEKITS
84 
85 #ifdef HAVE_VRML97
86 #include <Inventor/VRMLnodes/SoVRMLNodes.h>
87 #include <Inventor/VRMLnodes/SoVRML.h>
88 #endif // HAVE_VRML97
89 
90 #include "actions/SoSubActionP.h"
91 #include "coindefs.h"
92 #include "SbBasicP.h"
93 
94 // FIXME: currently only VRML2-nodes to VRML1-nodes is
95 // supported. Inventor/Coin specific nodes must also be supported
96 // (they are just ignored for now). It's quite easy to add support new
97 // nodes though. pederb, 2002-07-17
98 
99 
100 // helper function needed to copy the name of a node
tovrml_new_node(SoNode * newnode,const SoNode * oldnode)101 static SoNode * tovrml_new_node(SoNode * newnode, const SoNode * oldnode)
102 {
103   const SbName name = oldnode->getName();
104   if (name != SbName::empty()) newnode->setName(name);
105   return newnode;
106 }
107 
108 // We use SoType::createInstance() instead of simply new'ing to make
109 // an instance, as this makes SoType::overrideType() influence the
110 // conversion process.
111 
112 #define NEW_NODE(_type_, _oldnode_) \
113         coin_assert_cast<_type_*>(tovrml_new_node(static_cast<SoNode *>(_type_::getClassTypeId().createInstance()), \
114                                   _oldnode_))
115 
116 // *************************************************************************
117 
118 SO_ACTION_SOURCE(SoToVRMLAction);
119 
120 // *************************************************************************
121 
122 class SoToVRMLActionP {
123 public:
SoToVRMLActionP(void)124   SoToVRMLActionP(void)
125     : master(NULL)
126   {
127     this->expandsofile = FALSE;
128     this->urlname = "";
129     this->writetexcoords = FALSE;
130     this->expandtexture2node = FALSE;
131     // FIXME: don't know if this is correct default value. 20020705 mortene.
132     this->keepunknownnodes = TRUE;
133     this->convertinlinenodes = TRUE;
134     this->conditionalconversion = FALSE;
135     // FIXME: don't know if this is correct default value. 20020705 mortene.
136     this->isverbose = FALSE;
137 
138     this->nodefuse = FALSE; // for optimizing bad scene graphs
139 
140     this->bsptree = NULL;
141     this->bsptreetex = NULL;
142     this->bsptreenormal = NULL;
143     this->coordidx = NULL;
144     this->normalidx = NULL;
145     this->texidx = NULL;
146     this->coloridx = NULL;
147     this->vrmlpath = NULL;
148     this->vrmlroot = NULL;
149   }
150 
init(void)151   void init(void) {
152     if (this->vrmlpath) {
153       this->vrmlpath->unref();
154     }
155     this->vrmlpath = reclassify_cast<SoFullPath *>(new SoPath);
156     this->vrmlpath->ref();
157 
158     if (this->vrmlroot) {
159       this->vrmlroot->unref();
160     }
161     this->vrmlroot = new SoSeparator;
162     this->vrmlroot->ref();
163     this->vrmlpath->setHead(this->vrmlroot);
164   }
165 
166   SoToVRMLAction * master;
167   SbBool expandsofile;
168   SbString urlname;
169   SbBool writetexcoords;
170   SbBool expandtexture2node;
171   SbBool keepunknownnodes;
172   SbBool convertinlinenodes;
173   SbBool conditionalconversion;
174   SbBool isverbose;
175   SbBool nodefuse;
176   SoCallbackAction cbaction;
177   SoSearchAction searchaction;
178   SoFullPath * vrmlpath;
179   SoSeparator * vrmlroot;
180 
181   SbBSPTree * bsptree;
182   SbBSPTree * bsptreetex;
183   SbBSPTree * bsptreenormal;
184 
185   SbList <int32_t> * coordidx;
186   SbList <int32_t> * normalidx;
187   SbList <int32_t> * texidx;
188   SbList <int32_t> * coloridx;
189 
190   static SoCallbackAction::Response pop_cb(void *, SoCallbackAction *, const SoNode *);
191   static SoCallbackAction::Response push_cb(void *, SoCallbackAction *, const SoNode *);
192   static SoCallbackAction::Response post_primitives_cb(void *, SoCallbackAction *, const SoNode *);
193   static void triangle_cb(void * userdata, SoCallbackAction * action,
194                           const SoPrimitiveVertex * v1,
195                           const SoPrimitiveVertex * v2,
196                           const SoPrimitiveVertex * v3);
197   static SoCallbackAction::Response unsupported_cb(void *, SoCallbackAction *, const SoNode *);
198   SoNode * search_for_node(SoNode * root, const SbName & name, const SoType & type);
199   SoGroup * get_current_tail(void);
200   SoMaterial * find_or_create_material(void);
201   void init_gen(const SbBool color);
202 
203 #ifdef HAVE_VRML97
204   static SoCallbackAction::Response vrmlshape_cb(void *, SoCallbackAction *, const SoNode *);
205   static SoCallbackAction::Response vrmltransform_cb(void *, SoCallbackAction *, const SoNode *);
206   static SoCallbackAction::Response vrmldirlight_cb(void *, SoCallbackAction *, const SoNode *);
207   static SoCallbackAction::Response vrmlpointlight_cb(void *, SoCallbackAction *, const SoNode *);
208   static SoCallbackAction::Response vrmlspotlight_cb(void *, SoCallbackAction *, const SoNode *);
209   static SoCallbackAction::Response vrmlpixeltex_cb(void *, SoCallbackAction *, const SoNode *);
210   static SoCallbackAction::Response vrmlimagetex_cb(void *, SoCallbackAction *, const SoNode *);
211   static SoCallbackAction::Response vrmllod_cb(void *, SoCallbackAction *, const SoNode *);
212   static SoCallbackAction::Response vrmlmaterial_cb(void *, SoCallbackAction *, const SoNode *);
213   static SoCallbackAction::Response vrmlswitch_cb(void *, SoCallbackAction *, const SoNode *);
214   static SoCallbackAction::Response vrmltextransform_cb(void *, SoCallbackAction *, const SoNode *);
215   static SoCallbackAction::Response vrmlviewpoint_cb(void *, SoCallbackAction *, const SoNode *);
216   static SoCallbackAction::Response vrmlbox_cb(void *, SoCallbackAction *, const SoNode *);
217   static SoCallbackAction::Response vrmlcone_cb(void *, SoCallbackAction *, const SoNode *);
218   static SoCallbackAction::Response vrmlcylinder_cb(void *, SoCallbackAction *, const SoNode *);
219   static SoCallbackAction::Response vrmlifs_cb(void *, SoCallbackAction *, const SoNode *);
220   static SoCallbackAction::Response vrmlils_cb(void *, SoCallbackAction *, const SoNode *);
221   static SoCallbackAction::Response vrmlpointset_cb(void *, SoCallbackAction *, const SoNode *);
222   static SoCallbackAction::Response vrmlsphere_cb(void *, SoCallbackAction *, const SoNode *);
223 
224   static SoCallbackAction::Response vrmlelevation_cb(void *, SoCallbackAction *, const SoNode *);
225   static SoCallbackAction::Response vrmlextrusion_cb(void *, SoCallbackAction *, const SoNode *);
226 #endif // HAVE_VRML97
227 };
228 
229 
230 
231 #define PRIVATE(obj) ((obj)->pimpl)
232 #define PUBLIC(obj) ((obj)->master)
233 #define THISP(p) (static_cast<SoToVRMLActionP *>(p))
234 
235 // *************************************************************************
236 
237 // Overridden from parent class.
238 void
initClass(void)239 SoToVRMLAction::initClass(void)
240 {
241   SO_ACTION_INTERNAL_INIT_CLASS(SoToVRMLAction, SoAction);
242 }
243 
244 
245 /*!
246   Constructor.
247 */
248 
SoToVRMLAction(void)249 SoToVRMLAction::SoToVRMLAction(void)
250 {
251   PRIVATE(this)->master = this;
252 
253 #define ADD_PRE_CB(_node_, _cb_) \
254   PRIVATE(this)->cbaction.addPreCallback(_node_::getClassTypeId(), SoToVRMLActionP::_cb_, &PRIVATE(this).get())
255 #define ADD_POST_CB(_node_, _cb_) \
256   PRIVATE(this)->cbaction.addPostCallback(_node_::getClassTypeId(), SoToVRMLActionP::_cb_, &PRIVATE(this).get())
257 #define ADD_UNSUPPORTED(_node_) \
258   PRIVATE(this)->cbaction.addPreCallback(_node_::getClassTypeId(), SoToVRMLActionP::unsupported_cb, &PRIVATE(this).get())
259 
260 #ifdef HAVE_VRML97
261   ADD_PRE_CB(SoVRMLShape, vrmlshape_cb);
262   ADD_POST_CB(SoVRMLShape, pop_cb);
263   ADD_PRE_CB(SoVRMLGroup, push_cb);
264   ADD_POST_CB(SoVRMLGroup, pop_cb);
265   ADD_PRE_CB(SoVRMLTransform, vrmltransform_cb);
266   ADD_POST_CB(SoVRMLTransform, pop_cb);
267   ADD_PRE_CB(SoVRMLDirectionalLight, vrmldirlight_cb);
268   ADD_PRE_CB(SoVRMLPointLight, vrmlpointlight_cb);
269   ADD_PRE_CB(SoVRMLSpotLight, vrmlspotlight_cb);
270   ADD_PRE_CB(SoVRMLPixelTexture, vrmlpixeltex_cb);
271   ADD_PRE_CB(SoVRMLImageTexture, vrmlimagetex_cb);
272   ADD_PRE_CB(SoVRMLLOD, vrmllod_cb);
273   ADD_POST_CB(SoVRMLLOD, pop_cb);
274   ADD_PRE_CB(SoVRMLMaterial, vrmlmaterial_cb);
275   ADD_PRE_CB(SoVRMLSwitch, vrmlswitch_cb);
276   ADD_POST_CB(SoVRMLSwitch, pop_cb);
277   ADD_PRE_CB(SoVRMLTextureTransform, vrmltextransform_cb);
278   ADD_PRE_CB(SoVRMLViewpoint, vrmlviewpoint_cb);
279 
280   // misc geometry nodes
281   ADD_PRE_CB(SoVRMLBox, vrmlbox_cb);
282   ADD_PRE_CB(SoVRMLCone, vrmlcone_cb);
283   ADD_PRE_CB(SoVRMLCylinder, vrmlcylinder_cb);
284   ADD_PRE_CB(SoVRMLIndexedFaceSet, vrmlifs_cb);
285   ADD_PRE_CB(SoVRMLIndexedLineSet, vrmlils_cb);
286   ADD_PRE_CB(SoVRMLSphere, vrmlsphere_cb);
287 
288   // unsupported node
289   ADD_UNSUPPORTED(SoVRMLInline);  // convert to WWWInline
290   ADD_UNSUPPORTED(SoVRMLMovieTexture);
291   ADD_UNSUPPORTED(SoVRMLAnchor); // convert to WWWAnchor
292   ADD_UNSUPPORTED(SoVRMLAudioClip);
293   ADD_UNSUPPORTED(SoVRMLBackground);
294   ADD_UNSUPPORTED(SoVRMLCylinderSensor);
295   ADD_UNSUPPORTED(SoVRMLColorInterpolator);
296   ADD_UNSUPPORTED(SoVRMLCoordinateInterpolator);
297   ADD_UNSUPPORTED(SoVRMLFog);
298   ADD_UNSUPPORTED(SoVRMLFontStyle);
299   ADD_UNSUPPORTED(SoVRMLNavigationInfo);
300   ADD_UNSUPPORTED(SoVRMLNormalInterpolator);
301   ADD_UNSUPPORTED(SoVRMLPositionInterpolator);
302   ADD_UNSUPPORTED(SoVRMLProximitySensor);
303   ADD_UNSUPPORTED(SoVRMLScalarInterpolator);
304   ADD_UNSUPPORTED(SoVRMLScript);
305   ADD_UNSUPPORTED(SoVRMLSound);
306   ADD_UNSUPPORTED(SoVRMLSphereSensor);
307   ADD_UNSUPPORTED(SoVRMLText);
308   ADD_UNSUPPORTED(SoVRMLTimeSensor);
309   ADD_UNSUPPORTED(SoVRMLTouchSensor);
310   ADD_UNSUPPORTED(SoVRMLVisibilitySensor);
311   ADD_UNSUPPORTED(SoVRMLWorldInfo);  // convert to Info
312 
313   // these are converted to IndexedFaceSet
314   ADD_PRE_CB(SoVRMLExtrusion, vrmlextrusion_cb);
315   ADD_POST_CB(SoVRMLExtrusion, post_primitives_cb);
316   ADD_PRE_CB(SoVRMLElevationGrid, vrmlelevation_cb);
317   ADD_POST_CB(SoVRMLElevationGrid, post_primitives_cb);
318   PRIVATE(this)->cbaction.addTriangleCallback(SoVRMLElevationGrid::getClassTypeId(),
319                                               SoToVRMLActionP::triangle_cb, &PRIVATE(this).get());
320   PRIVATE(this)->cbaction.addTriangleCallback(SoVRMLExtrusion::getClassTypeId(),
321                                               SoToVRMLActionP::triangle_cb, &PRIVATE(this).get());
322 #endif // HAVE_VRML97
323 
324 #undef ADD_PRE_CB
325 #undef ADD_POST_CB
326 #undef ADD_UNSUPPORTED
327 }
328 
329 /*!
330   The destructor.
331 */
332 
~SoToVRMLAction(void)333 SoToVRMLAction::~SoToVRMLAction(void)
334 {
335   if (PRIVATE(this)->vrmlpath) {
336     PRIVATE(this)->vrmlpath->unref();
337   }
338   if (PRIVATE(this)->vrmlroot) {
339     PRIVATE(this)->vrmlroot->unref();
340   }
341 }
342 
343 // Documented in superclass.
344 void
apply(SoNode * root)345 SoToVRMLAction::apply(SoNode * root)
346 {
347   PRIVATE(this)->init();
348   PRIVATE(this)->cbaction.apply(root);
349 }
350 
351 // Documented in superclass.
352 void
apply(SoPath * path)353 SoToVRMLAction::apply(SoPath * path)
354 {
355   PRIVATE(this)->init();
356   PRIVATE(this)->cbaction.apply(path);
357 }
358 
359 // Documented in superclass.
360 void
apply(const SoPathList & pathlist,SbBool obeysrules)361 SoToVRMLAction::apply(const SoPathList & pathlist, SbBool obeysrules)
362 {
363   PRIVATE(this)->init();
364   PRIVATE(this)->cbaction.apply(pathlist, obeysrules);
365 }
366 
367 // Documented in superclass.
368 void
beginTraversal(SoNode * COIN_UNUSED_ARG (node))369 SoToVRMLAction::beginTraversal(SoNode * COIN_UNUSED_ARG(node))
370 {
371   assert(0 && "should never get here");
372 }
373 
374 SoNode *
getVRMLSceneGraph(void) const375 SoToVRMLAction::getVRMLSceneGraph(void) const
376 {
377   return PRIVATE(this)->vrmlroot;
378 }
379 
380 void
expandSoFile(SbBool flag)381 SoToVRMLAction::expandSoFile(SbBool flag)
382 {
383   PRIVATE(this)->expandsofile = flag;
384 }
385 
386 SbBool
areSoFileExpanded(void) const387 SoToVRMLAction::areSoFileExpanded(void) const
388 {
389   return PRIVATE(this)->expandsofile;
390 }
391 
392 void
setUrlName(const SbString name)393 SoToVRMLAction::setUrlName(const SbString name)
394 {
395   PRIVATE(this)->urlname = name;
396 }
397 
398 SbString
getUrlName(void) const399 SoToVRMLAction::getUrlName(void) const
400 {
401   return PRIVATE(this)->urlname;
402 }
403 
404 void
writeTexCoords(SbBool flag)405 SoToVRMLAction::writeTexCoords(SbBool flag)
406 {
407   PRIVATE(this)->writetexcoords = flag;
408 }
409 
410 SbBool
areTexCoordWritten(void) const411 SoToVRMLAction::areTexCoordWritten(void) const
412 {
413   return PRIVATE(this)->writetexcoords;
414 }
415 
416 void
expandTexture2Node(SbBool flag)417 SoToVRMLAction::expandTexture2Node(SbBool flag)
418 {
419   PRIVATE(this)->expandtexture2node = flag;
420 }
421 
422 SbBool
areTexture2NodeExpanded(void) const423 SoToVRMLAction::areTexture2NodeExpanded(void) const
424 {
425   return PRIVATE(this)->expandtexture2node;
426 }
427 
428 void
keepUnknownNodes(SbBool flag)429 SoToVRMLAction::keepUnknownNodes(SbBool flag)
430 {
431   PRIVATE(this)->keepunknownnodes = flag;
432 }
433 
434 SbBool
areUnknownNodeKept(void) const435 SoToVRMLAction::areUnknownNodeKept(void) const
436 {
437   return PRIVATE(this)->keepunknownnodes;
438 }
439 
440 void
convertInlineNodes(SbBool flag)441 SoToVRMLAction::convertInlineNodes(SbBool flag)
442 {
443   PRIVATE(this)->convertinlinenodes = flag;
444 }
445 
446 SbBool
doConvertInlineNodes(void) const447 SoToVRMLAction::doConvertInlineNodes(void) const
448 {
449   return PRIVATE(this)->convertinlinenodes;
450 }
451 
452 void
conditionalConversion(SbBool flag)453 SoToVRMLAction::conditionalConversion(SbBool flag)
454 {
455   PRIVATE(this)->conditionalconversion = flag;
456 }
457 
458 SbBool
doConditionalConversion(void) const459 SoToVRMLAction::doConditionalConversion(void) const
460 {
461   return PRIVATE(this)->conditionalconversion;
462 }
463 
464 void
setVerbosity(SbBool flag)465 SoToVRMLAction::setVerbosity(SbBool flag)
466 {
467   PRIVATE(this)->isverbose = flag;
468 }
469 
470 SbBool
isVerbose(void) const471 SoToVRMLAction::isVerbose(void) const
472 {
473   return PRIVATE(this)->isverbose;
474 }
475 
476 SoNode *
search_for_node(SoNode * root,const SbName & name,const SoType & type)477 SoToVRMLActionP::search_for_node(SoNode * root, const SbName & name, const SoType & type)
478 {
479   SoNodeList mylist;
480   if (name == SbName::empty()) return NULL;
481 
482   mylist.truncate(0);
483   int num = SoNode::getByName(name, mylist);
484   int cnt = 0;
485   SoNode * retnode = NULL;
486   for (int i = 0; i < num; i++) {
487     SoNode * node = mylist[i];
488     if (node->getTypeId() == type) {
489       retnode = node;
490       cnt++;
491     }
492   }
493 
494   // if there is only one node with that name, return it
495   if (retnode && cnt == 1) return retnode;
496   if (!retnode) return NULL;
497 
498   this->searchaction.setSearchingAll(TRUE);
499   this->searchaction.setName(name);
500   this->searchaction.setType(type);
501   this->searchaction.setInterest(SoSearchAction::LAST);
502   this->searchaction.setFind(SoSearchAction::TYPE|SoSearchAction::NAME);
503 
504 #ifdef HAVE_NODEKITS
505   SbBool old = SoBaseKit::isSearchingChildren();
506   SoBaseKit::setSearchingChildren(TRUE);
507 #endif // HAVE_NODEKITS
508 
509   this->searchaction.apply(root);
510   SoNode * tail = NULL;
511   SoFullPath * path = reclassify_cast<SoFullPath*>(this->searchaction.getPath());
512   if (path) {
513     tail = path->getTail();
514   }
515   this->searchaction.reset();
516 #ifdef HAVE_NODEKITS
517   SoBaseKit::setSearchingChildren(old);
518 #endif // HAVE_NODEKITS
519   return tail;
520 }
521 
522 SoGroup *
get_current_tail(void)523 SoToVRMLActionP::get_current_tail(void)
524 {
525   SoNode * node = this->vrmlpath->getTail();
526   assert(node->isOfType(SoGroup::getClassTypeId()));
527   return coin_assert_cast<SoGroup*>(node);
528 }
529 
530 SoMaterial *
find_or_create_material(void)531 SoToVRMLActionP::find_or_create_material(void)
532 {
533   SoMaterial * mat = NULL;
534   SoGroup * tail = this->get_current_tail();
535 
536   int num = tail->getNumChildren();
537   while (--num >= 0 && mat == NULL) {
538     SoNode * node = tail->getChild(num);
539     if (node->isOfType(SoMaterial::getClassTypeId())) {
540       mat = coin_assert_cast<SoMaterial*>(node);
541     }
542   }
543   if (mat == NULL) {
544     mat = new SoMaterial;
545     tail->addChild(mat);
546   }
547   return mat;
548 }
549 
550 SoCallbackAction::Response
push_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)551 SoToVRMLActionP::push_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
552 {
553   SoToVRMLActionP * thisp = THISP(closure);
554 
555   SoSeparator * newsep = NEW_NODE(SoSeparator, node);
556   SoGroup * prevgroup = THISP(closure)->get_current_tail();
557   prevgroup->addChild(newsep);
558   thisp->vrmlpath->append(newsep);
559   return SoCallbackAction::CONTINUE;
560 }
561 
562 SoCallbackAction::Response
pop_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * COIN_UNUSED_ARG (node))563 SoToVRMLActionP::pop_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * COIN_UNUSED_ARG(node))
564 {
565   THISP(closure)->vrmlpath->pop();
566   return SoCallbackAction::CONTINUE;
567 }
568 
569 SoCallbackAction::Response
unsupported_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)570 SoToVRMLActionP::unsupported_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
571 {
572   SoInfo * info = NEW_NODE(SoInfo, node);
573   SbString str;
574   str.sprintf("Unsupported node: %s",
575               node->getTypeId().getName().getString());
576   info->string = str;
577   THISP(closure)->get_current_tail()->addChild(info);
578   return SoCallbackAction::CONTINUE;
579 }
580 
581 void
init_gen(const SbBool color)582 SoToVRMLActionP::init_gen(const SbBool color)
583 {
584   SbBool dotex = FALSE;
585   SoGroup * tail = this->get_current_tail();
586   const int n = tail->getNumChildren();
587   for (int i = 0; i < n; i++) {
588     if (tail->getChild(i)->isOfType(SoTexture2::getClassTypeId())) {
589       dotex = TRUE;
590       break;
591     }
592   }
593 
594   this->bsptree = new SbBSPTree;
595   if (dotex) this->bsptreetex = new SbBSPTree;
596   this->bsptreenormal = new SbBSPTree;
597 
598   this->coordidx = new SbList <int32_t>;
599   this->normalidx = new SbList <int32_t>;
600   if (dotex) this->texidx = new SbList <int32_t>;
601   if (color) this->coloridx = new SbList <int32_t>;
602 }
603 
604 SoCallbackAction::Response
post_primitives_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)605 SoToVRMLActionP::post_primitives_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
606 {
607   SoToVRMLActionP * thisp = THISP(closure);
608 
609   int n;
610   SoGroup * tail = thisp->get_current_tail();
611   SoCoordinate3 * coord = new SoCoordinate3;
612   coord->point.setValues(0, thisp->bsptree->numPoints(),
613                          thisp->bsptree->getPointsArrayPtr());
614   tail->addChild(coord);
615 
616   SoIndexedFaceSet * ifs = NEW_NODE(SoIndexedFaceSet, node);
617   SoNormal * normal = new SoNormal;
618   normal->vector.setValues(0, thisp->bsptreenormal->numPoints(),
619                            thisp->bsptreenormal->getPointsArrayPtr());
620   tail->addChild(normal);
621 
622   ifs->coordIndex.setValues(0, thisp->coordidx->getLength(),
623                             thisp->coordidx->getArrayPtr());
624   ifs->normalIndex.setValues(0, thisp->normalidx->getLength(),
625                              thisp->normalidx->getArrayPtr());
626   if (thisp->texidx) {
627     SoTextureCoordinate2 * tex = new SoTextureCoordinate2;
628     ifs->textureCoordIndex.setValues(0, thisp->texidx->getLength(),
629                                      thisp->texidx->getArrayPtr());
630     tail->addChild(tex);
631     n = thisp->bsptreetex->numPoints();
632     tex->point.setNum(n);
633     SbVec2f * ptr = tex->point.startEditing();
634     for (int i = 0; i < n; i++) {
635       SbVec3f p = thisp->bsptreetex->getPoint(i);
636       ptr[i] = SbVec2f(p[0], p[1]);
637     }
638     tex->point.finishEditing();
639   }
640 
641   if (thisp->coloridx) {
642     SoMaterialBinding * bind = new SoMaterialBinding;
643     bind->value = SoMaterialBinding::PER_VERTEX_INDEXED;
644     tail->addChild(bind);
645     ifs->materialIndex.setValues(0, thisp->coloridx->getLength(),
646                                  thisp->coloridx->getArrayPtr());
647   }
648 
649   tail->addChild(ifs);
650 
651   delete thisp->bsptree; thisp->bsptree = NULL;
652   delete thisp->bsptreetex; thisp->bsptreetex = NULL;
653   delete thisp->bsptreenormal; thisp->bsptreenormal = NULL;
654 
655   delete thisp->coordidx; thisp->coordidx = NULL;
656   delete thisp->normalidx; thisp->normalidx = NULL;
657   delete thisp->texidx; thisp->texidx = NULL;
658   delete thisp->coloridx; thisp->coloridx = NULL;
659 
660   return SoCallbackAction::CONTINUE;
661 }
662 
663 void
triangle_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoPrimitiveVertex * v1,const SoPrimitiveVertex * v2,const SoPrimitiveVertex * v3)664 SoToVRMLActionP::triangle_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action),
665                              const SoPrimitiveVertex * v1,
666                              const SoPrimitiveVertex * v2,
667                              const SoPrimitiveVertex * v3)
668 {
669   SoToVRMLActionP * thisp = THISP(closure);
670   assert(thisp->bsptree);
671   assert(thisp->bsptreenormal);
672 
673   SoPrimitiveVertex const * const arr[3] = {v1, v2, v3};
674   for (int i = 0; i < 3; i++) {
675     const SoPrimitiveVertex * v = arr[i];
676     thisp->coordidx->append(thisp->bsptree->addPoint(v->getPoint()));
677     thisp->normalidx->append(thisp->bsptreenormal->addPoint(v->getNormal()));
678     if (thisp->texidx) {
679       assert(thisp->bsptreetex);
680       const SbVec4f & tc = v->getTextureCoords();
681       thisp->texidx->append(thisp->bsptreetex->addPoint(SbVec3f(tc[0], tc[1], 0.0f)));
682     }
683     if (thisp->coloridx) thisp->coloridx->append(v->getMaterialIndex());
684   }
685   thisp->coordidx->append(-1);
686   thisp->normalidx->append(-1);
687   if (thisp->texidx) thisp->texidx->append(-1);
688   if (thisp->coloridx) thisp->coloridx->append(-1);
689 }
690 
691 #ifdef HAVE_VRML97
692 
693 SoCallbackAction::Response
vrmlshape_cb(void * closure,SoCallbackAction * action,const SoNode * node)694 SoToVRMLActionP::vrmlshape_cb(void * closure, SoCallbackAction * action, const SoNode * node)
695 {
696   push_cb(closure, action, node);
697   return SoCallbackAction::CONTINUE;
698 }
699 
700 SoCallbackAction::Response
vrmltransform_cb(void * closure,SoCallbackAction * action,const SoNode * node)701 SoToVRMLActionP::vrmltransform_cb(void * closure, SoCallbackAction * action, const SoNode * node)
702 {
703   push_cb(closure, action, node);
704   const SoVRMLTransform * oldt = coin_assert_cast<const SoVRMLTransform *>(node);
705   SoTransform * newt = NEW_NODE(SoTransform, node);
706 
707   newt->translation = oldt->translation.getValue();
708   newt->rotation = oldt->rotation.getValue();
709   newt->scaleFactor = oldt->scale.getValue();
710   newt->scaleOrientation = oldt->scaleOrientation.getValue();
711   newt->center = oldt->center.getValue();
712   THISP(closure)->get_current_tail()->addChild(newt);
713   return SoCallbackAction::CONTINUE;
714 }
715 
716 SoCallbackAction::Response
vrmldirlight_cb(void * closure,SoCallbackAction * action,const SoNode * node)717 SoToVRMLActionP::vrmldirlight_cb(void * closure, SoCallbackAction * action, const SoNode * node)
718 {
719   return unsupported_cb(closure, action, node);
720 }
721 
722 SoCallbackAction::Response
vrmlpointlight_cb(void * closure,SoCallbackAction * action,const SoNode * node)723 SoToVRMLActionP::vrmlpointlight_cb(void * closure, SoCallbackAction * action, const SoNode * node)
724 {
725   return unsupported_cb(closure, action, node);
726 }
727 
728 SoCallbackAction::Response
vrmlspotlight_cb(void * closure,SoCallbackAction * action,const SoNode * node)729 SoToVRMLActionP::vrmlspotlight_cb(void * closure, SoCallbackAction * action, const SoNode * node)
730 {
731   return unsupported_cb(closure, action, node);
732 }
733 
734 SoCallbackAction::Response
vrmlpixeltex_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)735 SoToVRMLActionP::vrmlpixeltex_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
736 {
737   SoTexture2 * tex = NEW_NODE(SoTexture2, node);
738   const SoVRMLPixelTexture * oldtex = coin_assert_cast<const SoVRMLPixelTexture*>(node);
739   SbVec2s size;
740   int nc;
741   const unsigned char * bytes = oldtex->image.getValue(size, nc);
742   tex->image.setValue(size, nc, bytes);
743   THISP(closure)->get_current_tail()->addChild(tex);
744   return SoCallbackAction::CONTINUE;
745 }
746 
747 SoCallbackAction::Response
vrmlimagetex_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)748 SoToVRMLActionP::vrmlimagetex_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
749 {
750   SoTexture2 * tex = NEW_NODE(SoTexture2, node);
751   const SoVRMLImageTexture * oldtex = coin_assert_cast<const SoVRMLImageTexture*>(node);
752   if (oldtex->url.getNum()) {
753     tex->filename = oldtex->url[0];
754   }
755   THISP(closure)->get_current_tail()->addChild(tex);
756   return SoCallbackAction::CONTINUE;
757 }
758 
759 SoCallbackAction::Response
vrmllod_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)760 SoToVRMLActionP::vrmllod_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
761 {
762   SoLOD * lod = NEW_NODE(SoLOD, node);
763   const SoVRMLLOD * oldlod = coin_assert_cast<const SoVRMLLOD*>(node);
764   lod->center = oldlod->center.getValue();
765   lod->range.setValues(0, oldlod->range.getNum(),
766                        oldlod->range.getValues(0));
767   THISP(closure)->get_current_tail()->addChild(lod);
768   THISP(closure)->vrmlpath->append(lod);
769   return SoCallbackAction::CONTINUE;
770 }
771 
772 SoCallbackAction::Response
vrmlmaterial_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)773 SoToVRMLActionP::vrmlmaterial_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
774 {
775   SoMaterial * mat = NEW_NODE(SoMaterial, node);
776   const SoVRMLMaterial * oldmat = coin_assert_cast<const SoVRMLMaterial *>(node);
777   SbColor diffuse = oldmat->diffuseColor.getValue();
778   mat->diffuseColor = diffuse;
779   diffuse *= oldmat->ambientIntensity.getValue();
780   mat->ambientColor = diffuse;
781 
782   mat->emissiveColor = oldmat->emissiveColor.getValue();
783   mat->specularColor = oldmat->specularColor.getValue();
784   mat->shininess = oldmat->shininess.getValue();
785   mat->transparency = oldmat->transparency.getValue();
786 
787   THISP(closure)->get_current_tail()->addChild(mat);
788   return SoCallbackAction::CONTINUE;
789 }
790 
791 SoCallbackAction::Response
vrmlswitch_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)792 SoToVRMLActionP::vrmlswitch_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
793 {
794   SoSwitch * sw = NEW_NODE(SoSwitch, node);
795   const SoVRMLSwitch * oldsw = coin_assert_cast<const SoVRMLSwitch *>(node);
796   sw->whichChild = oldsw->whichChoice.getValue();
797   THISP(closure)->get_current_tail()->addChild(sw);
798   THISP(closure)->vrmlpath->append(sw);
799   return SoCallbackAction::CONTINUE;
800 }
801 
802 SoCallbackAction::Response
vrmltextransform_cb(void * closure,SoCallbackAction * action,const SoNode * node)803 SoToVRMLActionP::vrmltextransform_cb(void * closure, SoCallbackAction * action, const SoNode * node)
804 {
805   return unsupported_cb(closure, action, node);
806 }
807 
808 SoCallbackAction::Response
vrmlviewpoint_cb(void * closure,SoCallbackAction * action,const SoNode * node)809 SoToVRMLActionP::vrmlviewpoint_cb(void * closure, SoCallbackAction * action, const SoNode * node)
810 {
811   return unsupported_cb(closure, action, node);
812 }
813 
814 SoCallbackAction::Response
vrmlbox_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)815 SoToVRMLActionP::vrmlbox_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
816 {
817   SoCube * cube = NEW_NODE(SoCube, node);
818   const SoVRMLBox * box = coin_assert_cast<const SoVRMLBox *>(node);
819   cube->width = box->size.getValue()[0];
820   cube->height = box->size.getValue()[1];
821   cube->depth = box->size.getValue()[2];
822   THISP(closure)->get_current_tail()->addChild(cube);
823   return SoCallbackAction::CONTINUE;
824 }
825 
826 SoCallbackAction::Response
vrmlcone_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)827 SoToVRMLActionP::vrmlcone_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
828 {
829   SoCone * cone = NEW_NODE(SoCone, node);
830   const SoVRMLCone * oldcone = coin_assert_cast<const SoVRMLCone *>(node);
831   cone->bottomRadius = oldcone->bottomRadius.getValue();
832   cone->height = oldcone->height.getValue();
833 
834   int parts = 0;
835   if (oldcone->bottom.getValue()) parts |= SoCone::BOTTOM;
836   if (oldcone->side.getValue()) parts |= SoCone::SIDES;
837   cone->parts = static_cast<SoCone::Part>(parts);
838   THISP(closure)->get_current_tail()->addChild(cone);
839   return SoCallbackAction::CONTINUE;
840 }
841 
842 SoCallbackAction::Response
vrmlcylinder_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)843 SoToVRMLActionP::vrmlcylinder_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
844 {
845   SoCylinder * cyl = NEW_NODE(SoCylinder, node);
846   const SoVRMLCylinder * oldcyl = coin_assert_cast<const SoVRMLCylinder*>(node);
847   cyl->radius = oldcyl->radius.getValue();
848   cyl->height = oldcyl->height.getValue();
849   int parts = 0;
850   if (oldcyl->side.getValue()) parts |= SoCylinder::SIDES;
851   if (oldcyl->top.getValue()) parts |= SoCylinder::TOP;
852   if (oldcyl->bottom.getValue()) parts |= SoCylinder::BOTTOM;
853   cyl->parts = static_cast<SoCylinder::Part>(parts);
854   THISP(closure)->get_current_tail()->addChild(cyl);
855   return SoCallbackAction::CONTINUE;
856 }
857 
858 SoCallbackAction::Response
vrmlifs_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)859 SoToVRMLActionP::vrmlifs_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
860 {
861   const SoVRMLIndexedFaceSet * oldifs = coin_assert_cast<const SoVRMLIndexedFaceSet *>(node);
862 
863   if (oldifs->coordIndex.getNum() == 0 ||
864       oldifs->coordIndex[0] < 0)
865     return SoCallbackAction::CONTINUE;
866 
867   SoToVRMLActionP * thisp = THISP(closure);
868 
869   SoIndexedFaceSet * ifs = NEW_NODE(SoIndexedFaceSet, node);
870 
871   SoVRMLColor * color = coin_assert_cast<SoVRMLColor*>(oldifs->color.getValue());
872   SoVRMLCoordinate * coord = coin_assert_cast<SoVRMLCoordinate *>(oldifs->coord.getValue());
873   SoVRMLNormal * normal = coin_assert_cast<SoVRMLNormal *>(oldifs->normal.getValue());
874   SoVRMLTextureCoordinate * texcoord = coin_assert_cast<SoVRMLTextureCoordinate*>(oldifs->texCoord.getValue());
875 
876   SoShapeHints * sh = new SoShapeHints;
877   sh->creaseAngle = oldifs->creaseAngle.getValue();
878   sh->vertexOrdering = oldifs->ccw.getValue() ?
879     SoShapeHints::COUNTERCLOCKWISE : SoShapeHints::CLOCKWISE;
880   sh->shapeType = oldifs->solid.getValue() ?
881     SoShapeHints::SOLID : SoShapeHints::UNKNOWN_SHAPE_TYPE;
882   sh->faceType = oldifs->convex.getValue() ?
883     SoShapeHints::CONVEX : SoShapeHints::UNKNOWN_FACE_TYPE;
884 
885   SoGroup * tail = thisp->get_current_tail();
886   tail->addChild(sh);
887 
888   if (coord) {
889     SbName name = coord->getName();
890     SoCoordinate3 * newcoord = coin_assert_cast<SoCoordinate3*>(
891       thisp->search_for_node(thisp->vrmlpath->getHead(),
892                              name,
893                              SoCoordinate3::getClassTypeId()));
894     if (!newcoord) {
895       newcoord = new SoCoordinate3;
896       newcoord->setName(name);
897       newcoord->point.setValues(0, coord->point.getNum(),
898                                 coord->point.getValues(0));
899     }
900     tail->addChild(newcoord);
901   }
902 
903   if (normal) {
904     if (oldifs->normalPerVertex.getValue() != TRUE) {
905       SoNormalBinding * bind = new SoNormalBinding;
906       if (oldifs->normalIndex.getNum()) {
907         bind->value = SoMaterialBinding::PER_FACE_INDEXED;
908       }
909       else bind->value = SoMaterialBinding::PER_FACE;
910       tail->addChild(bind);
911     }
912     SbName name = normal->getName();
913     SoNormal * newnormal =
914       coin_assert_cast<SoNormal*>(thisp->search_for_node(thisp->vrmlpath->getHead(),
915                                          name,
916                                          SoNormal::getClassTypeId())
917                               );
918     if (!newnormal) {
919       newnormal = new SoNormal;
920       newnormal->setName(name);
921       newnormal->vector.setValues(0, normal->vector.getNum(),
922                                   normal->vector.getValues(0));
923     }
924     tail->addChild(newnormal);
925   }
926   if (color) {
927     SoMaterialBinding * bind = new SoMaterialBinding;
928     if (oldifs->colorPerVertex.getValue()) {
929       bind->value = SoMaterialBinding::PER_VERTEX_INDEXED;
930     }
931     else {
932       if (oldifs->colorIndex.getNum()) {
933         bind->value = SoMaterialBinding::PER_FACE_INDEXED;
934       }
935       else {
936         bind->value = SoMaterialBinding::PER_FACE;
937       }
938       tail->addChild(bind);
939     }
940 
941     SoMaterial * mat = thisp->find_or_create_material();
942     mat->diffuseColor.setValues(0, color->color.getNum(),
943                                 color->color.getValues(0));
944   }
945   if (texcoord) {
946     SbName name = texcoord->getName();
947     SoTextureCoordinate2 * newtc = coin_assert_cast<SoTextureCoordinate2*>(
948       thisp->search_for_node(thisp->vrmlpath->getHead(),
949                              name,
950                              SoTextureCoordinate2::getClassTypeId())
951       );
952     if (!newtc) {
953       newtc = new SoTextureCoordinate2;
954       newtc->setName(name);
955       newtc->point.setValues(0, texcoord->point.getNum(),
956                              texcoord->point.getValues(0));
957     }
958     tail->addChild(newtc);
959   }
960 
961   ifs->coordIndex.setValues(0, oldifs->coordIndex.getNum(),
962                             oldifs->coordIndex.getValues(0));
963   if (oldifs->texCoordIndex.getNum()) {
964     ifs->textureCoordIndex.setValues(0, oldifs->texCoordIndex.getNum(),
965                                      oldifs->texCoordIndex.getValues(0));
966   }
967   if (oldifs->colorIndex.getNum()) {
968     ifs->materialIndex.setValues(0, oldifs->colorIndex.getNum(),
969                                  oldifs->colorIndex.getValues(0));
970   }
971   if (oldifs->normalIndex.getNum()) {
972     ifs->normalIndex.setValues(0, oldifs->normalIndex.getNum(),
973                                oldifs->normalIndex.getValues(0));
974   }
975   tail->addChild(ifs);
976   return SoCallbackAction::CONTINUE;
977 }
978 
979 SoCallbackAction::Response
vrmlils_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)980 SoToVRMLActionP::vrmlils_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
981 {
982   SoToVRMLActionP * thisp = THISP(closure);
983 
984   const SoVRMLIndexedLineSet * oldils = coin_assert_cast<const SoVRMLIndexedLineSet*>(node);
985 
986   if (oldils->coordIndex.getNum() == 0 ||
987       oldils->coordIndex[0] < 0) return SoCallbackAction::CONTINUE;
988 
989   SoIndexedLineSet * ils = NEW_NODE(SoIndexedLineSet, node);
990 
991   SoVRMLColor * color = coin_assert_cast<SoVRMLColor *>(oldils->color.getValue());
992   SoVRMLCoordinate * coord = coin_assert_cast<SoVRMLCoordinate *>(oldils->coord.getValue());
993   SoGroup * tail = thisp->get_current_tail();
994 
995   SoCoordinate3 * newcoord = NULL;
996 
997   if (coord) {
998     if (thisp->nodefuse) {
999       newcoord = new SoCoordinate3;
1000     }
1001     else {
1002       SbName name = coord->getName();
1003       newcoord = coin_assert_cast<SoCoordinate3*>(
1004         thisp->search_for_node(thisp->vrmlpath->getHead(),
1005                                name,
1006                                SoCoordinate3::getClassTypeId()));
1007       if (!newcoord) {
1008         newcoord = new SoCoordinate3;
1009         newcoord->setName(name);
1010         newcoord->point.setValues(0, coord->point.getNum(),
1011                                   coord->point.getValues(0));
1012       }
1013     }
1014     tail->addChild(newcoord);
1015   }
1016 
1017   if (color) {
1018     SoMaterialBinding * bind = new SoMaterialBinding;
1019     if (oldils->colorPerVertex.getValue()) {
1020       bind->value = SoMaterialBinding::PER_VERTEX_INDEXED;
1021     }
1022     else {
1023       if (oldils->colorIndex.getNum()) {
1024         bind->value = SoMaterialBinding::PER_FACE_INDEXED;
1025       }
1026       else {
1027         bind->value = SoMaterialBinding::PER_FACE;
1028       }
1029       tail->addChild(bind);
1030     }
1031 
1032     SoMaterial * mat = thisp->find_or_create_material();
1033     mat->diffuseColor.setValues(0, color->color.getNum(),
1034                                 color->color.getValues(0));
1035   }
1036 
1037   if (thisp->nodefuse && coord) {
1038     SbBSPTree bsp;
1039     int n = oldils->coordIndex.getNum();
1040     const int32_t * src = oldils->coordIndex.getValues(0);
1041 
1042     const SbVec3f * c = coord->point.getValues(0);
1043 
1044     ils->coordIndex.setNum(n);
1045     int32_t * dst = ils->coordIndex.startEditing();
1046 
1047     for (int i = 0; i < n; i++) {
1048       int idx = src[i];
1049       if (idx >= 0) {
1050         dst[i] = bsp.addPoint(c[idx]);
1051       }
1052       else dst[i] = -1;
1053     }
1054     ils->coordIndex.finishEditing();
1055     newcoord->point.setValues(0, bsp.numPoints(),
1056                               bsp.getPointsArrayPtr());
1057 
1058   }
1059   else {
1060     ils->coordIndex.setValues(0, oldils->coordIndex.getNum(),
1061                               oldils->coordIndex.getValues(0));
1062   }
1063   if (oldils->colorIndex.getNum()) {
1064     ils->materialIndex.setValues(0, oldils->colorIndex.getNum(),
1065                                  oldils->colorIndex.getValues(0));
1066   }
1067   tail->addChild(ils);
1068   return SoCallbackAction::CONTINUE;
1069 }
1070 
1071 SoCallbackAction::Response
vrmlpointset_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)1072 SoToVRMLActionP::vrmlpointset_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
1073 {
1074   SoToVRMLActionP * thisp = THISP(closure);
1075 
1076   const SoVRMLPointSet * oldps = coin_assert_cast<const SoVRMLPointSet*>(node);
1077 
1078   SoPointSet * ps = NEW_NODE(SoPointSet, node);
1079   SoGroup * tail = thisp->get_current_tail();
1080 
1081   SoVRMLColor * color = coin_assert_cast<SoVRMLColor*>(oldps->color.getValue());
1082   SoVRMLCoordinate * coord = coin_assert_cast<SoVRMLCoordinate*>(oldps->coord.getValue());
1083 
1084   if (coord) {
1085     SbName name = coord->getName();
1086     SoCoordinate3 * newcoord = coin_assert_cast<SoCoordinate3 *> (
1087       thisp->search_for_node(thisp->vrmlpath->getHead(),
1088                              name,
1089                              SoCoordinate3::getClassTypeId())
1090       );
1091     if (!newcoord) {
1092       newcoord = new SoCoordinate3;
1093       newcoord->setName(name);
1094       newcoord->point.setValues(0, coord->point.getNum(),
1095                                 coord->point.getValues(0));
1096     }
1097     tail->addChild(newcoord);
1098   }
1099 
1100   if (color) {
1101     SoMaterial * mat = thisp->find_or_create_material();
1102     mat->diffuseColor.setValues(0, color->color.getNum(),
1103                                 color->color.getValues(0));
1104   }
1105 
1106   tail->addChild(ps);
1107   return SoCallbackAction::CONTINUE;
1108 }
1109 
1110 SoCallbackAction::Response
vrmlsphere_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)1111 SoToVRMLActionP::vrmlsphere_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
1112 {
1113   SoSphere * sphere = NEW_NODE(SoSphere, node);
1114   const SoVRMLSphere * oldsphere = coin_assert_cast<const SoVRMLSphere *>(node);
1115   sphere->radius = oldsphere->radius.getValue();
1116   THISP(closure)->get_current_tail()->addChild(sphere);
1117   return SoCallbackAction::CONTINUE;
1118 }
1119 
1120 SoCallbackAction::Response
vrmlelevation_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)1121 SoToVRMLActionP::vrmlelevation_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
1122 {
1123   SoToVRMLActionP * thisp = THISP(closure);
1124 
1125   SoGroup * tail = thisp->get_current_tail();
1126 
1127   const SoVRMLElevationGrid * grid = coin_assert_cast<const SoVRMLElevationGrid*>(node);
1128   SoShapeHints * sh = new SoShapeHints;
1129   sh->creaseAngle = grid->creaseAngle.getValue();
1130   sh->vertexOrdering = grid->ccw.getValue() ?
1131     SoShapeHints::COUNTERCLOCKWISE : SoShapeHints::CLOCKWISE;
1132   sh->shapeType = grid->solid.getValue() ?
1133     SoShapeHints::SOLID : SoShapeHints::UNKNOWN_SHAPE_TYPE;
1134   sh->faceType = SoShapeHints::CONVEX;
1135   tail->addChild(sh);
1136 
1137   SoVRMLColor * color = coin_assert_cast<SoVRMLColor *>(grid->color.getValue());
1138 
1139   if (color) {
1140     SoMaterial * mat = thisp->find_or_create_material();
1141     mat->diffuseColor.setValues(0, color->color.getNum(),
1142                                 color->color.getValues(0));
1143   }
1144 
1145   thisp->init_gen(color != NULL);
1146   return SoCallbackAction::CONTINUE;
1147 }
1148 
1149 SoCallbackAction::Response
vrmlextrusion_cb(void * closure,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)1150 SoToVRMLActionP::vrmlextrusion_cb(void * closure, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
1151 {
1152   SoToVRMLActionP * thisp = THISP(closure);
1153 
1154   SoGroup * tail = thisp->get_current_tail();
1155 
1156   const SoVRMLExtrusion * ext = coin_assert_cast<const SoVRMLExtrusion*>(node);
1157   SoShapeHints * sh = new SoShapeHints;
1158   sh->creaseAngle = ext->creaseAngle.getValue();
1159   sh->vertexOrdering = ext->ccw.getValue() ?
1160     SoShapeHints::COUNTERCLOCKWISE : SoShapeHints::CLOCKWISE;
1161   sh->shapeType = ext->solid.getValue() ?
1162     SoShapeHints::SOLID : SoShapeHints::UNKNOWN_SHAPE_TYPE;
1163   sh->faceType = ext->convex.getValue() ?
1164     SoShapeHints::CONVEX : SoShapeHints::UNKNOWN_FACE_TYPE;
1165   tail->addChild(sh);
1166 
1167   thisp->init_gen(FALSE);
1168   return SoCallbackAction::CONTINUE;
1169 }
1170 
1171 #endif // HAVE_VRML97
1172 
1173 #undef NEW_NODE
1174 #undef PRIVATE
1175 #undef PUBLIC
1176 #undef THISP
1177