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