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   \page vbo_rendering Vertex array and VBO rendering in Coin
35 
36   Coin 2.5 added improved support for OpenGL vertex array and VBO
37   rendering.  This might lead to major rendering performance
38   improvements compared to the old rendering code. The new rendering
39   code has been added for the SoIndexedFaceSet, SoVRMLIndexedFaceSet,
40   SoIndexedLineSet, SoVRMLIndexedLineSet, SoPointSet, SoFaceSet and
41   SoVRMLPointSet nodes.
42 
43   To take advantage of the improved performance vertex array and VBO
44   rendering yields, you'll need to organize your vertex data in a way
45   that makes it possible to render it with OpenGL vertex arrays.
46   OpenGL vertex array rendering does not support multiple index
47   arrays, so all your vertex data (coordinates, normals, colors and
48   texture coordinates) must use the same index array; or use OVERALL
49   binding. For the indexed nodes, this means that PER_VERTEX_INDEXED
50   and OVERALL are the only supported bindings for materials, normals
51   and texture coordinates. When PER_VERTEX_INDEXED binding is used,
52   the corresponding index field should by empty. This will signal the
53   shape to use the coordIndex field for indices. Below is an
54   example scene graph that will be rendered using vertex arrays:
55 
56   \verbatim
57 
58   NormalBinding { value PER_VERTEX_INDEXED }
59   Coordinate3 {
60     point [
61       0 0 0, # 0
62       1 0 0, # 1
63       2 0 0, # 2
64       0 1 0, # 3
65       1 1 0, # 4
66       2 1 0, # 5
67       0 2 0, # 6
68       1 2 0, # 7
69       2 2 0, # 8
70 
71       2 0  0, # 9
72       2 0 -1, # 10
73       2 1  0, # 11
74       2 1 -1, # 12
75       2 2  0, # 13
76       2 2 -1  # 14
77     ]
78   }
79   Normal {
80     vector [
81       0 0 1, # 0
82       0 0 1, # 1
83       0 0 1, # 2
84       0 0 1, # 3
85       0 0 1, # 4
86       0 0 1, # 5
87       0 0 1, # 6
88       0 0 1, # 7
89       0 0 1, # 8
90 
91       1 0 0,  # 9
92       1 0 0,  # 10
93       1 0 0,  # 11
94       1 0 0,  # 12
95       1 0 0,  # 13
96       1 0 0   # 14
97     ]
98   }
99 
100   IndexedFaceSet {
101     coordIndex [
102       0, 1, 4, 3, -1,
103       1, 2, 5, 4, -1,
104       3, 4, 7, 6, -1,
105       4, 5, 8, 7, -1,
106 
107       9, 10, 12, 11, -1,
108       11, 12, 14, 13, -1
109     ]
110     normalIndex [ ] # = use coordIndex
111   }
112   \endverbatim
113 
114   Please note that since only one index array can be used, it might
115   be necessary to supply duplicate normals and coordinates to meet this
116   requirement.
117 
118   Also, if normals are needed, you have to supply them. A shape
119   with autogenerated normals can't be rendered using vertex arrays
120   (since a single coordinate might get multiple normals).
121 
122   The PointSet nodes can always be rendered using vertex arrays since
123   these nodes haven't got index arrays, and the only bindings supported
124   are PER_VERTEX and OVERALL.
125 
126   If it's inconvenient to create vertex array ready scene graphs
127   directly from your application, it's also possible to use
128   SoReorganizeAction to reorganize the geometry before rendering.
129 */
130 
131 /*!
132   \class SoReorganizeAction Inventor/actions/SoReorganizeAction.h
133   \ingroup actions
134   \brief The SoReorganizeAction class reorganizes your scene graph to optimize traversal/rendering.
135 
136   Note. This is work-in-progress. pederb, 2005-04-05.
137 
138   The code below is an example of a program that applies an
139   SoReorganizeAction on a scene graph, converting all shapes into
140   shapes that can be rendered using vertex array or VBO rendering.
141 
142   \code
143 
144   #include <Inventor/SoDB.h>
145   #include <Inventor/nodes/SoSeparator.h>
146   #include <Inventor/nodes/SoCoordinate3.h>
147   #include <Inventor/nodes/SoCoordinate4.h>
148   #include <Inventor/nodes/SoNormal.h>
149   #include <Inventor/nodes/SoTextureCoordinate2.h>
150   #include <Inventor/nodes/SoSeparator.h>
151   #include <Inventor/actions/SoWriteAction.h>
152   #include <Inventor/actions/SoSearchAction.h>
153   #include <Inventor/errors/SoDebugError.h>
154   #include <Inventor/nodes/SoShapeHints.h>
155   #include <Inventor/SoInput.h>
156   #include <Inventor/SoOutput.h>
157   #include <Inventor/SoInteraction.h>
158   #include <Inventor/actions/SoReorganizeAction.h>
159   #include <cassert>
160   #include <cstdio>
161 
162   static void strip_node(SoType type, SoNode * root)
163   {
164     SoSearchAction sa;
165     sa.setType(type);
166     sa.setSearchingAll(TRUE);
167     sa.setInterest(SoSearchAction::ALL);
168     sa.apply(root);
169 
170     SoPathList & pl = sa.getPaths();
171     for (int i = 0; i < pl.getLength(); i++) {
172       SoFullPath * p = (SoFullPath*) pl[i];
173         if (p->getTail()->isOfType(type)) {
174           SoGroup * g = (SoGroup*) p->getNodeFromTail(1);
175           g->removeChild(p->getIndexFromTail(0));
176         }
177       }
178     sa.reset();
179   }
180 
181   int
182   main(int argc, char ** argv )
183   {
184     if (argc < 3) {
185       fprintf(stderr,"Usage: reorganize <infile> <outfile> [nostrip]\n");
186       return -1;
187     }
188 
189     SbBool strip = TRUE;
190     if (argc > 3) {
191       if (strcmp(argv[3], "nostrip") == 0) strip = FALSE;
192       else {
193         fprintf(stderr,"Usage: reorganize <infile> <outfile> [nostrip]\n");
194         return -1;
195       }
196     }
197 
198     SoDB::init();
199     SoInteraction::init();
200 
201     SoInput input;
202     SbBool ok = input.openFile(argv[1]);
203     if (!ok) {
204       fprintf(stderr,"Unable to open file.\n");
205       return -1;
206     }
207     SoSeparator * root = SoDB::readAll(&input);
208 
209     SbBool vrml1 = input.isFileVRML1();
210     SbBool vrml2 = input.isFileVRML2();
211 
212     if (vrml2) {
213       fprintf(stderr,"VRML2 not supported yet\n");
214       return -1;
215     }
216 
217     if (!root) {
218       fprintf(stderr,"Unable to read file.\n");
219       return -1;
220     }
221     root->ref();
222 
223     fprintf(stderr,"Applying SoReorganizeAction...");
224     SoReorganizeAction reorg;
225     reorg.apply(root);
226     fprintf(stderr,"done\n");
227 
228     SoOutput out;
229     if (out.openFile(argv[2])) {
230       if (strip) { // strip coord3, texcoord and normal nodes
231         fprintf(stderr,"stripping old nodes from scene graph\n");
232         strip_node(SoCoordinate3::getClassTypeId(), root);
233         strip_node(SoCoordinate4::getClassTypeId(), root);
234         strip_node(SoNormal::getClassTypeId(), root);
235         strip_node(SoTextureCoordinate2::getClassTypeId(), root);
236       }
237       fprintf(stderr,"writing target\n");
238       SoWriteAction wa(&out);
239       wa.apply(root);
240     }
241     root->unref();
242     return 0;
243   } // main()
244 
245   \endcode
246 
247   \since Coin 2.5
248 
249 */
250 
251 #include <Inventor/actions/SoReorganizeAction.h>
252 
253 #ifdef HAVE_CONFIG_H
254 #include "config.h"
255 #endif // HAVE_CONFIG_H
256 
257 #include <cstring>
258 #include <cassert>
259 
260 #include <Inventor/SbName.h>
261 #include <Inventor/actions/SoCallbackAction.h>
262 #include <Inventor/actions/SoSearchAction.h>
263 #include <Inventor/nodes/SoVertexShape.h>
264 #include <Inventor/nodes/SoNormal.h>
265 #include <Inventor/elements/SoLazyElement.h>
266 #include <Inventor/nodes/SoCoordinate3.h>
267 #include <Inventor/nodes/SoNormal.h>
268 #include <Inventor/nodes/SoIndexedFaceSet.h>
269 #include <Inventor/nodes/SoIndexedLineSet.h>
270 #include <Inventor/nodes/SoVertexProperty.h>
271 #include <Inventor/nodes/SoTextureCoordinate2.h>
272 #include <Inventor/nodes/SoGroup.h>
273 #include <Inventor/SoPrimitiveVertex.h>
274 #include <Inventor/SbViewportRegion.h>
275 #include <Inventor/elements/SoMultiTextureEnabledElement.h>
276 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
277 #include <Inventor/elements/SoShapeStyleElement.h>
278 #include <Inventor/elements/SoLightModelElement.h>
279 #include <Inventor/elements/SoNormalElement.h>
280 #include <Inventor/caches/SoPrimitiveVertexCache.h>
281 #include <Inventor/SbColor4f.h>
282 
283 #ifdef HAVE_VRML97
284 #include <Inventor/VRMLnodes/SoVRMLCoordinate.h>
285 #include <Inventor/VRMLnodes/SoVRMLTextureCoordinate.h>
286 #include <Inventor/VRMLnodes/SoVRMLNormal.h>
287 #include <Inventor/VRMLnodes/SoVRMLColor.h>
288 #include <Inventor/VRMLnodes/SoVRMLShape.h>
289 #include <Inventor/VRMLnodes/SoVRMLVertexShape.h>
290 #include <Inventor/VRMLnodes/SoVRMLIndexedFaceSet.h>
291 #include <Inventor/VRMLnodes/SoVRMLIndexedLineSet.h>
292 #endif // HAVE_VRML97
293 
294 #include "coindefs.h" // COIN_STUB()
295 #include "SbBasicP.h"
296 #include "actions/SoSubActionP.h"
297 
298 class SoReorganizeActionP {
299  public:
SoReorganizeActionP(void)300   SoReorganizeActionP(void)
301     : master(NULL),
302       gennormals(TRUE),
303       gentexcoords(TRUE),
304       gentristrips(FALSE),
305       genvp(FALSE),
306       matchidx(TRUE),
307       cbaction(SbViewportRegion(640, 480)),
308       pvcache(NULL)
309   {
310     cbaction.addTriangleCallback(SoVertexShape::getClassTypeId(), triangle_cb, this);
311     cbaction.addLineSegmentCallback(SoVertexShape::getClassTypeId(), line_segment_cb, this);
312 
313 #ifdef HAVE_VRML97
314     cbaction.addTriangleCallback(SoVRMLIndexedFaceSet::getClassTypeId(), triangle_cb, this);
315     cbaction.addLineSegmentCallback(SoVRMLIndexedLineSet::getClassTypeId(), line_segment_cb, this);
316 #endif // HAVE_VRML97
317 
318     cbaction.addPreCallback(SoVertexShape::getClassTypeId(),
319                             pre_shape_cb, this);
320     cbaction.addPostCallback(SoVertexShape::getClassTypeId(),
321                              post_shape_cb, this);
322 
323 #ifdef HAVE_VRML97
324     cbaction.addPreCallback(SoVRMLIndexedFaceSet::getClassTypeId(),
325                             pre_shape_cb, this);
326     cbaction.addPostCallback(SoVRMLIndexedFaceSet::getClassTypeId(),
327                              post_shape_cb, this);
328 
329 
330     cbaction.addPreCallback(SoVRMLIndexedLineSet::getClassTypeId(),
331                             pre_shape_cb, this);
332     cbaction.addPostCallback(SoVRMLIndexedLineSet::getClassTypeId(),
333                              post_shape_cb, this);
334 #endif // HAVE_VRML97
335 
336   }
337   SoReorganizeAction * master;
338   SbBool gennormals;
339   SbBool gentexcoords;
340   SbBool gentristrips;
341   SbBool genvp;
342   SbBool matchidx;
343   SbList <SbBool> needtexcoords;
344   int lastneeded;
345   int numtriangles;
346   int numlines;
347   int numpoints;
348   SbBool isvrml;
349 
350   SbBool didinit;
351   SbBool hastexture;
352   SbColor4f diffusecolor;
353   SbBool lighting;
354   SbBool normalsonstate;
355 
356   SoCallbackAction cbaction;
357   SoSearchAction sa;
358   SoPrimitiveVertexCache * pvcache;
359 
360   static SoCallbackAction::Response pre_shape_cb(void * userdata, SoCallbackAction * action, const SoNode * node);
361   static SoCallbackAction::Response post_shape_cb(void * userdata, SoCallbackAction * action, const SoNode * node);
362   static void triangle_cb(void * userdata, SoCallbackAction * action,
363                           const SoPrimitiveVertex * v1,
364                           const SoPrimitiveVertex * v2,
365                           const SoPrimitiveVertex * v3);
366 
367   static void line_segment_cb(void * userdata, SoCallbackAction * action,
368                               const SoPrimitiveVertex * v1,
369                               const SoPrimitiveVertex * v2);
370 
371   SbBool initShape(SoCallbackAction * action);
372   void replaceNode(SoFullPath * path);
373   void replaceIfs(SoFullPath * path);
374   void replaceVrmlIfs(SoFullPath * path);
375   void replaceIls(SoFullPath * path);
376   void replaceVrmlIls(SoFullPath * path);
377 
378   SoVertexProperty * createVertexProperty(const SbBool forlines);
379 };
380 
381 
382 #define PRIVATE(obj) obj->pimpl
383 
384 SO_ACTION_SOURCE(SoReorganizeAction);
385 
386 // Override from parent class.
387 void
initClass(void)388 SoReorganizeAction::initClass(void)
389 {
390   SO_ACTION_INTERNAL_INIT_CLASS(SoReorganizeAction, SoSimplifyAction);
391 }
392 
393 
394 /*!
395   A constructor.
396 */
397 
SoReorganizeAction(SoSimplifier * COIN_UNUSED_ARG (simplifier))398 SoReorganizeAction::SoReorganizeAction(SoSimplifier * COIN_UNUSED_ARG(simplifier))
399 {
400   PRIVATE(this)->master = this;
401   SO_ACTION_CONSTRUCTOR(SoReorganizeAction);
402 }
403 
404 /*!
405   The destructor.
406 */
407 
~SoReorganizeAction(void)408 SoReorganizeAction::~SoReorganizeAction(void)
409 {
410 }
411 
412 SoSeparator *
getSimplifiedSceneGraph(void) const413 SoReorganizeAction::getSimplifiedSceneGraph(void) const
414 {
415   return NULL;
416 }
417 
418 void
generateNormals(SbBool onoff)419 SoReorganizeAction::generateNormals(SbBool onoff)
420 {
421   PRIVATE(this)->gennormals = onoff;
422 }
423 
424 SbBool
areNormalGenerated(void) const425 SoReorganizeAction::areNormalGenerated(void) const
426 {
427   return PRIVATE(this)->gennormals;
428 }
429 
430 void
generateTriangleStrips(SbBool onoff)431 SoReorganizeAction::generateTriangleStrips(SbBool onoff)
432 {
433   PRIVATE(this)->gentristrips = onoff;
434 }
435 
436 SbBool
areTriangleStripGenerated(void) const437 SoReorganizeAction::areTriangleStripGenerated(void) const
438 {
439   return PRIVATE(this)->gentristrips;
440 }
441 
442 void
generateTexCoords(SbBool onoff)443 SoReorganizeAction::generateTexCoords(SbBool onoff)
444 {
445   PRIVATE(this)->gentexcoords = onoff;
446 }
447 
448 SbBool
areTexCoordsGenerated(void) const449 SoReorganizeAction::areTexCoordsGenerated(void) const
450 {
451   return PRIVATE(this)->gentexcoords;
452 }
453 
454 void
generateVPNodes(SbBool onoff)455 SoReorganizeAction::generateVPNodes(SbBool onoff)
456 {
457   PRIVATE(this)->genvp = onoff;
458 }
459 
460 SbBool
areVPNodesGenerated(void)461 SoReorganizeAction::areVPNodesGenerated(void)
462 {
463   return PRIVATE(this)->genvp;
464 }
465 
466 void
matchIndexArrays(SbBool onoff)467 SoReorganizeAction::matchIndexArrays(SbBool onoff)
468 {
469   PRIVATE(this)->matchidx = onoff;
470 }
471 
472 SbBool
areIndexArraysMatched(void) const473 SoReorganizeAction::areIndexArraysMatched(void) const
474 {
475   return PRIVATE(this)->matchidx;
476 }
477 
478 SoSimplifier *
getSimplifier(void) const479 SoReorganizeAction::getSimplifier(void) const
480 {
481   return NULL;
482 }
483 
484 void
apply(SoNode * root)485 SoReorganizeAction::apply(SoNode * root)
486 {
487   int i;
488   PRIVATE(this)->sa.setType(SoVertexShape::getClassTypeId());
489   PRIVATE(this)->sa.setSearchingAll(TRUE);
490   PRIVATE(this)->sa.setInterest(SoSearchAction::ALL);
491   PRIVATE(this)->sa.apply(root);
492   SoPathList & pl = PRIVATE(this)->sa.getPaths();
493   for (i = 0; i < pl.getLength(); i++) {
494     this->apply(pl[i]);
495   }
496   PRIVATE(this)->sa.reset();
497 
498 #ifdef HAVE_VRML97
499   PRIVATE(this)->sa.setType(SoVRMLIndexedFaceSet::getClassTypeId());
500   PRIVATE(this)->sa.setSearchingAll(TRUE);
501   PRIVATE(this)->sa.setInterest(SoSearchAction::ALL);
502   PRIVATE(this)->sa.apply(root);
503   SoPathList & pl2 = PRIVATE(this)->sa.getPaths();
504 
505   for (i = 0; i < pl2.getLength(); i++) {
506     this->apply(pl2[i]);
507   }
508   PRIVATE(this)->sa.reset();
509 
510   PRIVATE(this)->sa.setType(SoVRMLIndexedLineSet::getClassTypeId());
511   PRIVATE(this)->sa.setSearchingAll(TRUE);
512   PRIVATE(this)->sa.setInterest(SoSearchAction::ALL);
513   PRIVATE(this)->sa.apply(root);
514   SoPathList & pl3 = PRIVATE(this)->sa.getPaths();
515   for (i = 0; i < pl3.getLength(); i++) {
516     this->apply(pl3[i]);
517   }
518   PRIVATE(this)->sa.reset();
519 #endif // HAVE_VRML97
520 }
521 
522 void
apply(SoPath * path)523 SoReorganizeAction::apply(SoPath * path)
524 {
525   PRIVATE(this)->cbaction.apply(path);
526   PRIVATE(this)->replaceNode(reclassify_cast<SoFullPath *>(path));
527 }
528 
529 void
apply(const SoPathList & pathlist,SbBool COIN_UNUSED_ARG (obeysrules))530 SoReorganizeAction::apply(const SoPathList & pathlist, SbBool COIN_UNUSED_ARG(obeysrules))
531 {
532   for (int i = 0; i < pathlist.getLength(); i++) {
533     this->apply(pathlist[i]);
534   }
535 }
536 
537 void
startReport(const char * COIN_UNUSED_ARG (msg))538 SoReorganizeAction::startReport(const char * COIN_UNUSED_ARG(msg))
539 {
540   COIN_STUB();
541 }
542 
543 void
finishReport(void)544 SoReorganizeAction::finishReport(void)
545 {
546   COIN_STUB();
547 }
548 
549 // Documented in superclass.
550 void
beginTraversal(SoNode *)551 SoReorganizeAction::beginTraversal(SoNode * /* node */)
552 {
553   assert(0 && "should never get here");
554 }
555 
556 
557 SoCallbackAction::Response
pre_shape_cb(void * userdata,SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * node)558 SoReorganizeActionP::pre_shape_cb(void * userdata, SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * node)
559 {
560   SoReorganizeActionP * thisp = static_cast<SoReorganizeActionP *>(userdata);
561   thisp->didinit = FALSE;
562   thisp->isvrml = FALSE;
563 #ifdef HAVE_VRML97
564   thisp->isvrml = node->isOfType(SoVRMLGeometry::getClassTypeId());
565 #endif // HAVE_VRML97
566   thisp->numtriangles = 0;
567   thisp->numpoints = 0;
568   thisp->numlines = 0;
569   return SoCallbackAction::CONTINUE;
570 }
571 
572 SoCallbackAction::Response
post_shape_cb(void * COIN_UNUSED_ARG (userdata),SoCallbackAction * COIN_UNUSED_ARG (action),const SoNode * COIN_UNUSED_ARG (node))573 SoReorganizeActionP::post_shape_cb(void * COIN_UNUSED_ARG(userdata), SoCallbackAction * COIN_UNUSED_ARG(action), const SoNode * COIN_UNUSED_ARG(node))
574 {
575 #if 0 // debug
576   SoReorganizeActionP * thisp = (SoReorganizeActionP*) userdata;
577   fprintf(stderr,"shape: %s, numtri: %d, pvcache: %p\n",
578           node->getTypeId().getName().getString(),
579           thisp->numtriangles,
580           thisp->pvcache);
581 #endif // debug
582   return SoCallbackAction::CONTINUE;
583 }
584 
585 void
triangle_cb(void * userdata,SoCallbackAction * action,const SoPrimitiveVertex * v1,const SoPrimitiveVertex * v2,const SoPrimitiveVertex * v3)586 SoReorganizeActionP::triangle_cb(void * userdata, SoCallbackAction * action,
587                                  const SoPrimitiveVertex * v1,
588                                  const SoPrimitiveVertex * v2,
589                                  const SoPrimitiveVertex * v3)
590 {
591   SoReorganizeActionP * thisp = static_cast<SoReorganizeActionP *>(userdata);
592 
593   if (!thisp->didinit) {
594     if (thisp->initShape(action)) {
595       assert(thisp->pvcache == NULL);
596       thisp->pvcache = new SoPrimitiveVertexCache(action->getState());
597       thisp->pvcache->ref();
598     }
599   }
600 
601   thisp->numtriangles++;
602   if (thisp->pvcache) {
603     thisp->pvcache->addTriangle(v1, v2, v3);
604   }
605 }
606 
607 void
line_segment_cb(void * userdata,SoCallbackAction * action,const SoPrimitiveVertex * v1,const SoPrimitiveVertex * v2)608 SoReorganizeActionP::line_segment_cb(void * userdata, SoCallbackAction * action,
609                                      const SoPrimitiveVertex * v1,
610                                      const SoPrimitiveVertex * v2)
611 {
612   SoReorganizeActionP * thisp = static_cast<SoReorganizeActionP *>(userdata);
613 
614   if (!thisp->didinit) {
615     if (thisp->initShape(action)) {
616       assert(thisp->pvcache == NULL);
617       thisp->pvcache = new SoPrimitiveVertexCache(action->getState());
618       thisp->pvcache->ref();
619     }
620   }
621 
622   thisp->numlines++;
623   if (thisp->pvcache) {
624     thisp->pvcache->addLine(v1, v2);
625   }
626 }
627 
628 SbBool
initShape(SoCallbackAction * action)629 SoReorganizeActionP::initShape(SoCallbackAction * action)
630 {
631   this->didinit = TRUE;
632   SoState * state = action->getState();
633   SbBool canrenderasvertexarray = TRUE;
634 
635   unsigned int shapeflags = SoShapeStyleElement::get(state)->getFlags();
636 
637   this->lighting = SoLightModelElement::get(state) != SoLightModelElement::BASE_COLOR;
638   this->normalsonstate = SoNormalElement::getInstance(state)->getNum() > 0;
639 
640   SbBool texture0enabled =
641     SoMultiTextureEnabledElement::get(state,0) != FALSE;
642 
643   this->hastexture = texture0enabled;
644 
645   int lastenabled;
646   const SbBool * enabledunits =
647     SoMultiTextureEnabledElement::getEnabledUnits(state, lastenabled);
648 
649   this->needtexcoords.truncate(0);
650   this->needtexcoords.append(FALSE);
651 
652   if (shapeflags &
653       (SoShapeStyleElement::BUMPMAP|
654        SoShapeStyleElement::BBOXCMPLX|
655        SoShapeStyleElement::INVISIBLE|
656        SoShapeStyleElement::BIGIMAGE)) {
657     canrenderasvertexarray = FALSE;
658   }
659 
660   if (canrenderasvertexarray && texture0enabled) {
661     const SoMultiTextureCoordinateElement * celem =
662       static_cast<const SoMultiTextureCoordinateElement *>(SoMultiTextureCoordinateElement::getInstance(state));
663     switch (celem->getType()) {
664     case SoMultiTextureCoordinateElement::DEFAULT:
665     case SoMultiTextureCoordinateElement::EXPLICIT:
666       this->needtexcoords[0] = TRUE;
667       break;
668     case SoMultiTextureCoordinateElement::TEXGEN:
669       // don't need texcoords for unit0
670       break;
671     case SoMultiTextureCoordinateElement::FUNCTION:
672       this->needtexcoords[0] = TRUE;
673       break;
674     default:
675       canrenderasvertexarray = FALSE;
676       break;
677     }
678   }
679 
680   if (canrenderasvertexarray && enabledunits) {
681     const SoMultiTextureCoordinateElement * melem =
682       SoMultiTextureCoordinateElement::getInstance(state);
683     for (int i = 1; i <= lastenabled; i++) {
684       this->needtexcoords.append(FALSE);
685       if (enabledunits[i]) {
686         // FIXME: multitexturing is not supported yet, since it's not
687         // supported by SoVertexProperty. We might fix this later by
688         // inserting new nodes though. pederb, 2005-04-28
689         canrenderasvertexarray = FALSE;
690 
691         this->hastexture = TRUE;
692         switch (melem->getType(i)) {
693         case SoMultiTextureCoordinateElement::DEFAULT:
694         case SoMultiTextureCoordinateElement::EXPLICIT:
695           this->needtexcoords[i] = TRUE;
696           break;
697         case SoMultiTextureCoordinateElement::TEXGEN:
698           // don't need texcoords for unit i
699           break;
700         case SoMultiTextureCoordinateElement::FUNCTION:
701           this->needtexcoords[i] = TRUE;
702           break;
703         default:
704           canrenderasvertexarray = FALSE;
705           break;
706         }
707       }
708     }
709   }
710 
711   if (canrenderasvertexarray) {
712     SbColor diffuse = SoLazyElement::getDiffuse(state, 0);
713     float transp = SoLazyElement::getTransparency(state, 0);
714     this->diffusecolor = SbColor4f(diffuse, 1.0f - transp);
715   }
716   return canrenderasvertexarray;
717 }
718 
719 void
replaceNode(SoFullPath * path)720 SoReorganizeActionP::replaceNode(SoFullPath * path)
721 {
722   if (this->pvcache == NULL) return;
723   this->pvcache->fit(); // needed to do optimize-sort of data
724 
725   if (this->pvcache->getNumTriangleIndices()) {
726     if (this->isvrml) {
727       this->replaceVrmlIfs(path);
728     }
729     else {
730       this->replaceIfs(path);
731     }
732   }
733   else if (this->pvcache->getNumLineIndices()) {
734     if (this->isvrml) {
735       this->replaceVrmlIls(path);
736     }
737     else {
738       this->replaceIls(path);
739     }
740   }
741   this->pvcache->unref();
742   this->pvcache = NULL;
743 }
744 
745 SoVertexProperty *
createVertexProperty(const SbBool forlines)746 SoReorganizeActionP::createVertexProperty(const SbBool forlines)
747 {
748   SoVertexProperty * vp = new SoVertexProperty;
749   vp->ref();
750   SoVertexProperty::Binding nbind = SoVertexProperty::PER_VERTEX_INDEXED;
751 
752   if (!this->lighting ||
753       (forlines && !this->normalsonstate)) {
754     nbind = SoVertexProperty::OVERALL;
755   }
756   vp->normalBinding = nbind;
757 
758   int numv = this->pvcache->getNumVertices();
759 
760   if (this->hastexture) {
761     vp->texCoord.setNum(numv);
762     SbVec2f * dst = vp->texCoord.startEditing();
763     const SbVec4f * src = this->pvcache->getTexCoordArray();
764 
765     for (int i = 0; i < numv; i++) {
766       SbVec4f tmp = src[i];
767       if (tmp[3] != 0.0f) {
768         tmp[0] /= tmp[3];
769         tmp[1] /= tmp[3];
770       }
771       dst[i][0] = tmp[0];
772       dst[i][1] = tmp[1];
773     }
774     vp->texCoord.finishEditing();
775   }
776 
777   vp->vertex.setValues(0, numv,
778                        this->pvcache->getVertexArray());
779   if (nbind == SoVertexProperty::PER_VERTEX_INDEXED) {
780     vp->normal.setValues(0, numv,
781                          this->pvcache->getNormalArray());
782   }
783 
784   vp->materialBinding = SoVertexProperty::OVERALL;
785   vp->orderedRGBA = this->diffusecolor.getPackedValue();
786 
787   if (this->pvcache->colorPerVertex()) {
788     vp->materialBinding = SoVertexProperty::PER_VERTEX_INDEXED;
789     uint8_t * src = const_cast<uint8_t *>(this->pvcache->getColorArray());
790     vp->orderedRGBA.setNum(numv);
791     uint32_t * dst = vp->orderedRGBA.startEditing();
792     for (int i = 0; i < numv; i++) {
793       dst[i] = (src[0]<<24)|(src[1]<<16)|(src[2]<<8)|src[3];
794       src += 4;
795     }
796     vp->orderedRGBA.finishEditing();
797   }
798   vp->unrefNoDelete();
799   return vp;
800 }
801 
802 void
replaceIfs(SoFullPath * path)803 SoReorganizeActionP::replaceIfs(SoFullPath * path)
804 {
805   SoNode * parent = path->getNodeFromTail(1);
806   if (!parent->isOfType(SoGroup::getClassTypeId())) {
807     return;
808   }
809 
810   SoVertexProperty * vp = this->createVertexProperty(FALSE);
811   SoIndexedFaceSet * ifs = new SoIndexedFaceSet;
812   ifs->ref();
813   ifs->vertexProperty = vp;
814   ifs->normalIndex.setNum(0);
815   ifs->materialIndex.setNum(0);
816   ifs->textureCoordIndex.setNum(0);
817 
818   int numtri = this->pvcache->getNumTriangleIndices() / 3;
819   const GLint * indices = this->pvcache->getTriangleIndices();
820   ifs->coordIndex.setNum(numtri * 4);
821   int32_t * ptr = ifs->coordIndex.startEditing();
822 
823 
824   for (int i = 0; i < numtri; i++) {
825     *ptr++ = static_cast<int32_t>(indices[i*3]);
826     *ptr++ = static_cast<int32_t>(indices[i*3+1]);
827     *ptr++ = static_cast<int32_t>(indices[i*3+2]);
828     *ptr++ = -1;
829   }
830   ifs->coordIndex.finishEditing();
831 
832   int idx = path->getIndexFromTail(0);
833   path->pop();
834   SoGroup * g = coin_assert_cast<SoGroup *>(parent);
835   g->replaceChild(idx, ifs);
836   path->push(idx);
837   ifs->unrefNoDelete();
838 }
839 
840 void
replaceVrmlIfs(SoFullPath * path)841 SoReorganizeActionP::replaceVrmlIfs(SoFullPath * path)
842 {
843 #ifdef HAVE_VRML97
844   SoNode * parent = path->getNodeFromTail(1);
845   if (!parent->isOfType(SoGroup::getClassTypeId()) &&
846       !parent->isOfType(SoVRMLShape::getClassTypeId())) {
847     return;
848   }
849 
850   SoVRMLIndexedFaceSet * oldifs = coin_assert_cast<SoVRMLIndexedFaceSet *>(path->getTail());
851   assert(oldifs->isOfType(SoVRMLIndexedFaceSet::getClassTypeId()));
852   SoVRMLIndexedFaceSet * ifs = new SoVRMLIndexedFaceSet;
853   ifs->ref();
854   ifs->normalPerVertex = this->lighting;
855   ifs->colorPerVertex = this->pvcache->colorPerVertex();
856   ifs->ccw = oldifs->ccw;
857   ifs->solid = oldifs->solid;
858   ifs->creaseAngle = oldifs->creaseAngle;
859 
860   int numv = this->pvcache->getNumVertices();
861 
862   if (this->hastexture) {
863     SoVRMLTextureCoordinate * tc = new SoVRMLTextureCoordinate;
864     tc->point.setNum(numv);
865     SbVec2f * dst = tc->point.startEditing();
866     const SbVec4f * src = this->pvcache->getTexCoordArray();
867 
868     for (int i = 0; i < numv; i++) {
869       SbVec4f tmp = src[i];
870       if (tmp[3] != 0.0f) {
871         tmp[0] /= tmp[3];
872         tmp[1] /= tmp[3];
873       }
874       dst[i][0] = tmp[0];
875       dst[i][1] = tmp[1];
876     }
877     tc->point.finishEditing();
878     ifs->texCoord = tc;
879   }
880 
881   SoVRMLCoordinate * c = new SoVRMLCoordinate;
882   c->point.setValues(0, numv,
883                      this->pvcache->getVertexArray());
884   ifs->coord = c;
885 
886   if (this->lighting) {
887     SoVRMLNormal * norm = new SoVRMLNormal;
888     norm->vector.setValues(0, numv,
889                            this->pvcache->getNormalArray());
890     ifs->normal = norm;
891   }
892   if (this->pvcache->colorPerVertex()) {
893     SoVRMLColor * col = new SoVRMLColor;
894     col->color.setNum(numv);
895     uint8_t * src = const_cast<uint8_t *>(this->pvcache->getColorArray());
896     SbColor * dst = col->color.startEditing();
897     for (int i = 0; i < numv; i++) {
898       dst[i] = SbColor(src[0]/255.0f,
899                        src[1]/255.0f,
900                        src[2]/255.0f);
901       src += 4;
902     }
903     col->color.finishEditing();
904     ifs->color = col;
905   }
906 
907   ifs->normalIndex.setNum(0);
908   ifs->colorIndex.setNum(0);
909   ifs->texCoordIndex.setNum(0);
910 
911   int numtri = this->pvcache->getNumTriangleIndices() / 3;
912   const GLint * indices = this->pvcache->getTriangleIndices();
913   ifs->coordIndex.setNum(numtri * 4);
914   int32_t * ptr = ifs->coordIndex.startEditing();
915 
916   for (int i = 0; i < numtri; i++) {
917     *ptr++ = static_cast<int32_t>(indices[i*3]);
918     *ptr++ = static_cast<int32_t>(indices[i*3+1]);
919     *ptr++ = static_cast<int32_t>(indices[i*3+2]);
920     *ptr++ = -1;
921   }
922   ifs->coordIndex.finishEditing();
923 
924   int idx = path->getIndexFromTail(0);
925   path->pop();
926   if (parent->isOfType(SoGroup::getClassTypeId())) {
927     SoGroup * g = coin_assert_cast<SoGroup *>(parent);
928     g->replaceChild(idx, ifs);
929   }
930   else {
931     SoVRMLShape * shape = coin_assert_cast<SoVRMLShape *>(parent);
932     shape->geometry = ifs;
933   }
934   path->push(idx);
935   ifs->unrefNoDelete();
936 #endif // HAVE_VRML97
937 }
938 
939 void
replaceIls(SoFullPath * path)940 SoReorganizeActionP::replaceIls(SoFullPath * path)
941 {
942   SoNode * parent = path->getNodeFromTail(1);
943   if (!parent->isOfType(SoGroup::getClassTypeId())) {
944     return;
945   }
946 
947   SoVertexProperty * vp = this->createVertexProperty(TRUE);
948   SoIndexedLineSet * ils = new SoIndexedLineSet;
949   ils->ref();
950   ils->vertexProperty = vp;
951   ils->normalIndex.setNum(0);
952   ils->materialIndex.setNum(0);
953   ils->textureCoordIndex.setNum(0);
954 
955   int numlines = this->pvcache->getNumLineIndices() / 2;
956   const GLint * indices = this->pvcache->getLineIndices();
957   ils->coordIndex.setNum(numlines * 3);
958   int32_t * ptr = ils->coordIndex.startEditing();
959 
960   for (int i = 0; i < numlines; i++) {
961     *ptr++ = static_cast<int32_t>(indices[i*2]);
962     *ptr++ = static_cast<int32_t>(indices[i*2+1]);
963     *ptr++ = -1;
964   }
965   ils->coordIndex.finishEditing();
966 
967   int idx = path->getIndexFromTail(0);
968   path->pop();
969   SoGroup * g = coin_assert_cast<SoGroup *>(parent);
970   g->replaceChild(idx, ils);
971   path->push(idx);
972   ils->unrefNoDelete();
973 }
974 
975 void
replaceVrmlIls(SoFullPath * path)976 SoReorganizeActionP::replaceVrmlIls(SoFullPath * path)
977 {
978 #ifdef HAVE_VRML97
979   SoNode * parent = path->getNodeFromTail(1);
980   if (!parent->isOfType(SoGroup::getClassTypeId()) &&
981       !parent->isOfType(SoVRMLShape::getClassTypeId())) {
982     return;
983   }
984 
985   SoVRMLIndexedLineSet * ils = new SoVRMLIndexedLineSet;
986   ils->ref();
987 
988   int numv = this->pvcache->getNumVertices();
989   int numlines = this->pvcache->getNumLineIndices() / 2;
990   const GLint * indices = this->pvcache->getLineIndices();
991   ils->coordIndex.setNum(numlines * 3);
992   int32_t * ptr = ils->coordIndex.startEditing();
993 
994   for (int i = 0; i < numlines; i++) {
995     *ptr++ = static_cast<int32_t>(indices[i*2]);
996     *ptr++ = static_cast<int32_t>(indices[i*2+1]);
997     *ptr++ = -1;
998   }
999   ils->coordIndex.finishEditing();
1000 
1001   SoVRMLCoordinate * c = new SoVRMLCoordinate;
1002   c->point.setValues(0, numv,
1003                      this->pvcache->getVertexArray());
1004   ils->coord = c;
1005 
1006   if (this->pvcache->colorPerVertex()) {
1007     ils->colorPerVertex = TRUE;
1008     SoVRMLColor * col = new SoVRMLColor;
1009     col->color.setNum(numv);
1010     uint8_t * src = const_cast<uint8_t *>(this->pvcache->getColorArray());
1011     SbColor * dst = col->color.startEditing();
1012     for (int i = 0; i < numv; i++) {
1013       dst[i] = SbColor(src[0]/255.0f,
1014                        src[1]/255.0f,
1015                        src[2]/255.0f);
1016       src += 4;
1017     }
1018     col->color.finishEditing();
1019     ils->color = col;
1020   }
1021   ils->colorIndex.setNum(0);
1022 
1023   int idx = path->getIndexFromTail(0);
1024   path->pop();
1025   if (parent->isOfType(SoGroup::getClassTypeId())) {
1026     SoGroup * g = coin_assert_cast<SoGroup *>(parent);
1027     g->replaceChild(idx, ils);
1028   }
1029   else {
1030     SoVRMLShape * shape = coin_assert_cast<SoVRMLShape *>(parent);
1031     shape->geometry = ils;
1032   }
1033   path->push(idx);
1034   ils->unrefNoDelete();
1035 #endif // HAVE_VRML97
1036 }
1037 
1038 #undef PRIVATE
1039