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 SoIndexedLineSet SoIndexedLineSet.h Inventor/nodes/SoIndexedLineSet.h
35 \brief The SoIndexedLineSet class is used to render and otherwise represent indexed lines.
36
37 \ingroup nodes
38
39 The indexed counterpart of SoLineSet. Lines can specified using
40 indices for coordinates, normals, materials and texture coordinates.
41
42 If no normals are supplied on the stack (or in the vertexProperty
43 field), the lines will be rendered with lighting disabled.
44
45 For more information about line sets, see documentation in
46 SoLineSet. For more information about indexed shapes, see
47 documentation in SoIndexedShape and SoIndexedFaceSet.
48
49 <b>FILE FORMAT/DEFAULTS:</b>
50 \code
51 IndexedLineSet {
52 vertexProperty NULL
53 coordIndex 0
54 materialIndex -1
55 normalIndex -1
56 textureCoordIndex -1
57 }
58 \endcode
59
60 */
61
62 #include <Inventor/nodes/SoIndexedLineSet.h>
63
64 #include <cassert>
65
66 #ifdef HAVE_CONFIG_H
67 #include <config.h>
68 #endif // HAVE_CONFIG_H
69
70 #include <Inventor/SoPrimitiveVertex.h>
71 #include <Inventor/caches/SoNormalCache.h>
72 #include <Inventor/misc/SoState.h>
73 #include <Inventor/bundles/SoMaterialBundle.h>
74 #include <Inventor/actions/SoGLRenderAction.h>
75 #include <Inventor/actions/SoGetBoundingBoxAction.h>
76 #include <Inventor/system/gl.h>
77 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
78 #include <Inventor/elements/SoNormalBindingElement.h>
79 #include <Inventor/elements/SoMaterialBindingElement.h>
80 #include <Inventor/elements/SoCoordinateElement.h>
81 #include <Inventor/elements/SoGLShapeHintsElement.h>
82 #include <Inventor/elements/SoTextureCoordinateBindingElement.h>
83 #include <Inventor/elements/SoDrawStyleElement.h>
84 #include <Inventor/elements/SoGLCoordinateElement.h>
85 #include <Inventor/elements/SoGLLazyElement.h>
86 #include <Inventor/elements/SoGLCacheContextElement.h>
87 #include <Inventor/elements/SoGLVBOElement.h>
88 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
89 #include <Inventor/elements/SoMultiTextureEnabledElement.h>
90 #include <Inventor/bundles/SoTextureCoordinateBundle.h>
91 #include <Inventor/details/SoLineDetail.h>
92 #include <Inventor/caches/SoBoundingBoxCache.h>
93 #include <Inventor/misc/SoGLDriverDatabase.h>
94
95 #if COIN_DEBUG
96 #include <Inventor/errors/SoDebugError.h>
97 #endif // COIN_DEBUG
98
99 #include "nodes/SoSubNodeP.h"
100 #include "rendering/SoGL.h"
101 #include "rendering/SoVertexArrayIndexer.h"
102 #include "rendering/SoVBO.h"
103
104
105 SO_NODE_SOURCE(SoIndexedLineSet);
106
107
108 #define PRIVATE(obj) obj->pimpl
109 #define LOCK_VAINDEXER(obj) SoBase::staticDataLock()
110 #define UNLOCK_VAINDEXER(obj) SoBase::staticDataUnlock()
111
112 class SoIndexedLineSetP {
113 public:
114 SoVertexArrayIndexer * vaindexer;
115 };
116
117 /*!
118 Constructor.
119 */
SoIndexedLineSet()120 SoIndexedLineSet::SoIndexedLineSet()
121 {
122 PRIVATE(this) = new SoIndexedLineSetP;
123 PRIVATE(this)->vaindexer = NULL;
124
125 SO_NODE_INTERNAL_CONSTRUCTOR(SoIndexedLineSet);
126 }
127
128 /*!
129 Destructor.
130 */
~SoIndexedLineSet()131 SoIndexedLineSet::~SoIndexedLineSet()
132 {
133 delete PRIVATE(this)->vaindexer;
134 delete PRIVATE(this);
135 }
136
137 // doc from parent
138 void
initClass(void)139 SoIndexedLineSet::initClass(void)
140 {
141 SO_NODE_INTERNAL_INIT_CLASS(SoIndexedLineSet, SO_FROM_INVENTOR_1|SoNode::VRML1);
142 }
143
144 //
145 // translates current normal binding into the internal Binding enum
146 //
147 SoIndexedLineSet::Binding
findNormalBinding(SoState * state)148 SoIndexedLineSet::findNormalBinding(SoState * state)
149 {
150 Binding binding = PER_VERTEX_INDEXED;
151
152 SoNormalBindingElement::Binding normbind =
153 (SoNormalBindingElement::Binding) SoNormalBindingElement::get(state);
154
155 switch (normbind) {
156 case SoNormalBindingElement::OVERALL:
157 binding = OVERALL;
158 break;
159 case SoNormalBindingElement::PER_VERTEX:
160 binding = PER_VERTEX;
161 break;
162 case SoNormalBindingElement::PER_VERTEX_INDEXED:
163 binding = PER_VERTEX_INDEXED;
164 break;
165 case SoNormalBindingElement::PER_PART:
166 binding = PER_SEGMENT;
167 break;
168 case SoNormalBindingElement::PER_PART_INDEXED:
169 binding = PER_SEGMENT_INDEXED;
170 break;
171 case SoNormalBindingElement::PER_FACE:
172 binding = PER_LINE;
173 break;
174 case SoNormalBindingElement::PER_FACE_INDEXED:
175 binding = PER_LINE_INDEXED;
176 break;
177 default:
178 #if COIN_DEBUG
179 SoDebugError::postWarning("SoIndexedLineSet::findNormalBinding",
180 "unknown normal binding setting");
181 #endif // COIN_DEBUG
182 break;
183 }
184
185 return binding;
186 }
187
188 //
189 // translates current material binding into the internal Binding enum
190 //
191 SoIndexedLineSet::Binding
findMaterialBinding(SoState * state)192 SoIndexedLineSet::findMaterialBinding(SoState * state)
193 {
194 Binding binding = OVERALL;
195
196 SoMaterialBindingElement::Binding matbind =
197 (SoMaterialBindingElement::Binding) SoMaterialBindingElement::get(state);
198
199 switch (matbind) {
200 case SoNormalBindingElement::OVERALL:
201 binding = OVERALL;
202 break;
203 case SoNormalBindingElement::PER_VERTEX:
204 binding = PER_VERTEX;
205 break;
206 case SoNormalBindingElement::PER_VERTEX_INDEXED:
207 binding = PER_VERTEX_INDEXED;
208 break;
209 case SoNormalBindingElement::PER_PART:
210 binding = PER_SEGMENT;
211 break;
212 case SoNormalBindingElement::PER_PART_INDEXED:
213 binding = PER_SEGMENT_INDEXED;
214 break;
215 case SoNormalBindingElement::PER_FACE:
216 binding = PER_LINE;
217 break;
218 case SoNormalBindingElement::PER_FACE_INDEXED:
219 binding = PER_LINE_INDEXED;
220 break;
221 default:
222 #if COIN_DEBUG
223 SoDebugError::postWarning("SoIndexedFaceSet::findNormalBinding",
224 "unknown normal binding setting");
225 #endif // COIN_DEBUG
226 break;
227 }
228
229 return binding;
230 }
231
232
233 // doc from parent
234 void
GLRender(SoGLRenderAction * action)235 SoIndexedLineSet::GLRender(SoGLRenderAction * action)
236 {
237 if (this->coordIndex.getNum() < 2) return;
238 SoState * state = action->getState();
239
240 if (!this->shouldGLRender(action)) return;
241
242 SbBool didpush = FALSE;
243
244 if (this->vertexProperty.getValue()) {
245 state->push();
246 didpush = TRUE;
247 this->vertexProperty.getValue()->GLRender(action);
248 }
249
250 SoMaterialBundle mb(action);
251 SoTextureCoordinateBundle tb(action, TRUE, FALSE);
252 SbBool doTextures = tb.needCoordinates();
253
254 const SoCoordinateElement * coords;
255 const SbVec3f * normals;
256 const int32_t * cindices;
257 int numindices;
258 const int32_t * nindices;
259 const int32_t * tindices;
260 const int32_t * mindices;
261 SbBool normalCacheUsed;
262
263 SbBool sendNormals = !mb.isColorOnly() || tb.isFunction();
264
265 getVertexData(state, coords, normals, cindices,
266 nindices, tindices, mindices, numindices,
267 sendNormals, normalCacheUsed);
268
269 if (sendNormals && normals == NULL) {
270 if (!didpush) {
271 state->push();
272 didpush = TRUE;
273 }
274 sendNormals = FALSE;
275 SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
276 }
277
278 Binding mbind = this->findMaterialBinding(state);
279 Binding nbind = this->findNormalBinding(state);
280
281 if (this->getNodeType() == SoNode::VRML1) {
282 // For VRML1, PER_VERTEX means per vertex in shape, not PER_VERTEX
283 // on the state.
284 if (mbind == PER_VERTEX) {
285 mbind = PER_VERTEX_INDEXED;
286 mindices = cindices;
287 }
288 if (nbind == PER_VERTEX) {
289 nbind = PER_VERTEX_INDEXED;
290 nindices = cindices;
291 }
292 }
293
294 if (doTextures) {
295 if (SoTextureCoordinateBindingElement::get(state) ==
296 SoTextureCoordinateBindingElement::PER_VERTEX) {
297 tindices = NULL; // just in case
298 }
299 else if (tindices == NULL) {
300 tindices = cindices;
301 }
302 }
303
304 mb.sendFirst(); // make sure we have the correct material
305
306 if (!sendNormals) nbind = OVERALL;
307 else if (nbind == OVERALL) {
308 glNormal3fv((const GLfloat *)normals);
309 }
310
311 SbBool drawPoints =
312 SoDrawStyleElement::get(state) == SoDrawStyleElement::POINTS;
313
314 const uint32_t contextid = action->getCacheContext();
315 SoGLLazyElement * lelem = NULL;
316
317 SbBool dova =
318 !drawPoints &&
319 SoVBO::shouldRenderAsVertexArrays(state, contextid, numindices) &&
320 ((nbind == OVERALL) || ((nbind == PER_VERTEX_INDEXED) && ((nindices == cindices) || (nindices == NULL)))) &&
321 (!doTextures || (tindices == cindices)) &&
322 ((mbind == OVERALL) || ((mbind == PER_VERTEX_INDEXED) && ((mindices == cindices) || (mindices == NULL)))) &&
323 SoGLDriverDatabase::isSupported(sogl_glue_instance(state), SO_GL_VERTEX_ARRAY);
324
325 const SoGLVBOElement * vboelem = SoGLVBOElement::getInstance(state);
326 SoVBO * colorvbo = NULL;
327
328 if (dova && (mbind != OVERALL)) {
329 dova = FALSE;
330 if ((mbind == PER_VERTEX_INDEXED) && ((mindices == cindices) || (mindices == NULL))) {
331 lelem = (SoGLLazyElement*) SoLazyElement::getInstance(state);
332 colorvbo = vboelem->getColorVBO();
333 if (colorvbo) dova = TRUE;
334 else {
335 // we might be able to do VA-rendering, but need to check the
336 // diffuse color type first.
337 if (!lelem->isPacked() && lelem->getNumTransparencies() <= 1) {
338 dova = TRUE;
339 }
340 }
341 }
342 }
343 SbBool didrenderasvbo = FALSE;
344 if (dova) {
345 SbBool dovbo = this->startVertexArray(action,
346 coords,
347 nbind != OVERALL ? normals : NULL,
348 doTextures,
349 mbind != OVERALL);
350 didrenderasvbo = dovbo;
351 LOCK_VAINDEXER(this);
352 if (PRIVATE(this)->vaindexer == NULL) {
353 SoVertexArrayIndexer * indexer = new SoVertexArrayIndexer;
354
355 int i = 0;
356 while (i < numindices) {
357 int cnt = 0;
358 while (i + cnt < numindices && cindices[i+cnt] >= 0) cnt++;
359 if (cnt >= 2) {
360 for (int j = 1; j < cnt;j++) {
361 indexer->addLine(cindices[i+j-1],
362 cindices[i+j]);
363 }
364 }
365 i += cnt + 1;
366 }
367 indexer->close();
368 if (indexer->getNumVertices()) {
369 PRIVATE(this)->vaindexer = indexer;
370 }
371 else {
372 delete indexer;
373 }
374 #if 0
375 fprintf(stderr,"XXX: ILS create VertexArrayIndexer: %d\n", indexer->getNumVertices());
376 #endif
377 }
378
379 if (PRIVATE(this)->vaindexer) {
380 PRIVATE(this)->vaindexer->render(sogl_glue_instance(state), dovbo, contextid);
381 }
382 UNLOCK_VAINDEXER(this);
383
384 this->finishVertexArray(action,
385 dovbo,
386 nbind != OVERALL,
387 doTextures,
388 mbind != OVERALL);
389 }
390 else {
391 sogl_render_lineset((SoGLCoordinateElement*)coords,
392 cindices,
393 numindices,
394 normals,
395 nindices,
396 &mb,
397 mindices,
398 &tb,
399 tindices,
400 (int)nbind,
401 (int)mbind,
402 doTextures ? 1 : 0,
403 drawPoints ? 1 : 0);
404 }
405
406 if (didpush) {
407 state->pop();
408 }
409 // send approx number of lines for autocache handling
410 sogl_autocache_update(state, this->coordIndex.getNum() / 2, didrenderasvbo);
411 }
412
413 // Documented in superclass.
414 SbBool
generateDefaultNormals(SoState *,SoNormalBundle *)415 SoIndexedLineSet::generateDefaultNormals(SoState *, SoNormalBundle *)
416 {
417 return FALSE;
418 }
419
420 // Documented in superclass.
421 SbBool
generateDefaultNormals(SoState * COIN_UNUSED_ARG (state),SoNormalCache * nc)422 SoIndexedLineSet::generateDefaultNormals(SoState * COIN_UNUSED_ARG(state), SoNormalCache * nc)
423 {
424 // not possible to generate normals for IndexedLineSet
425 nc->set(0, NULL);
426 return TRUE;
427 }
428
429 // doc from parent
430 void
getBoundingBox(SoGetBoundingBoxAction * action)431 SoIndexedLineSet::getBoundingBox(SoGetBoundingBoxAction * action)
432 {
433 inherited::getBoundingBox(action);
434 // notify open (if any) bbox caches about lines in this shape
435 SoBoundingBoxCache::setHasLinesOrPoints(action->getState());
436 }
437
438 // doc from parent
439 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)440 SoIndexedLineSet::getPrimitiveCount(SoGetPrimitiveCountAction *action)
441 {
442 if (!this->shouldPrimitiveCount(action)) return;
443
444 int n = this->coordIndex.getNum();
445 if (n < 2) return;
446
447 if (action->canApproximateCount()) {
448 action->addNumLines(n/3);
449 }
450 else {
451 const int32_t * ptr = coordIndex.getValues(0);
452 const int32_t * endptr = ptr + n;
453 int cnt = 0;
454 int add = 0;
455 while (ptr < endptr) {
456 if (*ptr++ >= 0) cnt++;
457 else {
458 add += cnt-1;
459 cnt = 0;
460 }
461 }
462 // in case index array wasn't terminated by a -1
463 if (cnt >= 2) add += cnt-1;
464 action->addNumLines(add);
465 }
466 }
467
468 // doc from parent
469 void
generatePrimitives(SoAction * action)470 SoIndexedLineSet::generatePrimitives(SoAction *action)
471 {
472 if (this->coordIndex.getNum() < 2) return;
473
474 SoState * state = action->getState();
475
476 if (this->vertexProperty.getValue()) {
477 state->push();
478 this->vertexProperty.getValue()->doAction(action);
479 }
480
481 Binding mbind = this->findMaterialBinding(state);
482 Binding nbind = this->findNormalBinding(state);
483
484 const SoCoordinateElement * coords;
485 const SbVec3f * normals;
486 const int32_t * cindices;
487 int numindices;
488 const int32_t * normindices;
489 const int32_t * texindices;
490 const int32_t * matindices;
491 SbBool doTextures;
492 SbBool sendNormals = TRUE;
493 SbBool normalCacheUsed;
494
495 getVertexData(state, coords, normals, cindices,
496 normindices, texindices, matindices, numindices,
497 sendNormals, normalCacheUsed);
498
499 if (normals == NULL) {
500 sendNormals = FALSE;
501 nbind = OVERALL;
502 }
503
504 if (this->getNodeType() == SoNode::VRML1) {
505 // For VRML1, PER_VERTEX means per vertex in shape, not PER_VERTEX
506 // on the state.
507 if (mbind == PER_VERTEX) {
508 mbind = PER_VERTEX_INDEXED;
509 matindices = cindices;
510 }
511 if (nbind == PER_VERTEX) {
512 nbind = PER_VERTEX_INDEXED;
513 normindices = cindices;
514 }
515 }
516
517 SoTextureCoordinateBundle tb(action, FALSE, FALSE);
518 doTextures = tb.needCoordinates();
519
520 if (doTextures) {
521 if (SoTextureCoordinateBindingElement::get(state) ==
522 SoTextureCoordinateBindingElement::PER_VERTEX) {
523 texindices = NULL; // just in case
524 }
525 else if (texindices == NULL) {
526 texindices = cindices;
527 }
528 }
529
530 if (mbind == PER_VERTEX_INDEXED && matindices == NULL) {
531 matindices = cindices;
532 }
533 if (nbind == PER_VERTEX_INDEXED && normindices == NULL) {
534 normindices = cindices;
535 }
536 if (mbind == PER_VERTEX || mbind == PER_LINE || mbind == PER_SEGMENT) {
537 matindices = NULL;
538 }
539 if (nbind == PER_VERTEX || nbind == PER_LINE || nbind == PER_SEGMENT) {
540 normindices = NULL;
541 }
542
543 if (nbind == OVERALL) normindices = NULL;
544 if (mbind == OVERALL) matindices = NULL;
545
546 int matnr = 0;
547 int normnr = 0;
548 int texidx = 0;
549 int32_t i;
550 const int32_t *end = cindices + numindices;
551
552 SoPrimitiveVertex vertex;
553 SoPointDetail pointDetail;
554 SoLineDetail lineDetail;
555
556 vertex.setDetail(&pointDetail);
557
558 SbVec3f dummynormal(0.0f, 0.0f, 1.0f);
559 const SbVec3f *currnormal = &dummynormal;
560 if (normals) currnormal = normals;
561
562 if (nbind == OVERALL) {
563 vertex.setNormal(*currnormal);
564 }
565
566 if (mbind == PER_SEGMENT || mbind == PER_SEGMENT_INDEXED ||
567 nbind == PER_SEGMENT || nbind == PER_SEGMENT_INDEXED) {
568 int previ;
569 SbBool matPerPolyline = mbind == PER_LINE || mbind == PER_LINE_INDEXED;
570 SbBool normPerPolyline = nbind == PER_LINE || nbind == PER_LINE_INDEXED;
571
572 this->beginShape(action, SoShape::LINES, &lineDetail);
573
574 while (cindices + 1 < end) { // need at least two vertices
575 previ = *cindices++;
576
577 if (matPerPolyline || mbind >= PER_VERTEX) {
578 if (matindices) vertex.setMaterialIndex(*matindices++);
579 else vertex.setMaterialIndex(matnr++);
580 pointDetail.setMaterialIndex(vertex.getMaterialIndex());
581 }
582 if (normPerPolyline || nbind >= PER_VERTEX) {
583 if (normindices) {
584 pointDetail.setNormalIndex(*normindices);
585 currnormal = &normals[*normindices++];
586 }
587 else {
588 pointDetail.setNormalIndex(normnr);
589 currnormal = &normals[normnr++];
590 }
591 vertex.setNormal(*currnormal);
592 }
593 if (doTextures) {
594 if (tb.isFunction()) {
595 vertex.setTextureCoords(tb.get(coords->get3(previ), *currnormal));
596 }
597 else {
598 pointDetail.setTextureCoordIndex(texindices?*texindices:texidx);
599 vertex.setTextureCoords(tb.get(texindices?*texindices++:texidx++));
600 }
601 }
602
603 while (cindices < end && (i = *cindices++) >= 0) {
604 if (mbind == PER_SEGMENT || mbind == PER_SEGMENT_INDEXED) {
605 if (matindices) vertex.setMaterialIndex(*matindices++);
606 else vertex.setMaterialIndex(matnr++);
607 pointDetail.setMaterialIndex(vertex.getMaterialIndex());
608 }
609 if (nbind == PER_SEGMENT || nbind == PER_SEGMENT_INDEXED) {
610 if (normindices) {
611 pointDetail.setNormalIndex(*normindices);
612 currnormal = &normals[*normindices++];
613 }
614 else {
615 pointDetail.setNormalIndex(normnr);
616 currnormal = &normals[normnr++];
617 }
618 vertex.setNormal(*currnormal);
619 }
620 pointDetail.setCoordinateIndex(previ);
621 vertex.setPoint(coords->get3(previ));
622 this->shapeVertex(&vertex);
623
624 if (mbind >= PER_VERTEX) {
625 if (matindices) vertex.setMaterialIndex(*matindices++);
626 else vertex.setMaterialIndex(matnr++);
627 pointDetail.setMaterialIndex(vertex.getMaterialIndex());
628 }
629 if (nbind >= PER_VERTEX) {
630 if (normindices) {
631 pointDetail.setNormalIndex(*normindices);
632 currnormal = &normals[*normindices++];
633 }
634 else {
635 pointDetail.setNormalIndex(normnr);
636 currnormal = &normals[normnr++];
637 }
638 vertex.setNormal(*currnormal);
639 }
640 if (doTextures) {
641 if (tb.isFunction()) {
642 vertex.setTextureCoords(tb.get(coords->get3(i), *currnormal));
643 }
644 else {
645 pointDetail.setTextureCoordIndex(texindices?*texindices:texidx);
646 vertex.setTextureCoords(tb.get(texindices?*texindices++:texidx++));
647 }
648 }
649 pointDetail.setCoordinateIndex(i);
650 vertex.setPoint(coords->get3(i));
651 this->shapeVertex(&vertex);
652 lineDetail.incPartIndex();
653 previ = i;
654 }
655 lineDetail.incLineIndex();
656 if (mbind == PER_VERTEX_INDEXED) matindices++;
657 if (nbind == PER_VERTEX_INDEXED) normindices++;
658 if (doTextures && texindices) texindices++;
659 }
660 this->endShape();
661 return;
662 }
663
664 while (cindices + 1 < end) { // need at least two vertices
665 this->beginShape(action, LINE_STRIP, &lineDetail);
666 i = *cindices++;
667 assert(i >= 0);
668 if (matindices) {
669 pointDetail.setMaterialIndex(*matindices);
670 vertex.setMaterialIndex(*matindices++);
671 }
672 else if (mbind != OVERALL) {
673 pointDetail.setMaterialIndex(matnr);
674 vertex.setMaterialIndex(matnr++);
675 }
676 if (normindices) {
677 pointDetail.setNormalIndex(*normindices);
678 currnormal = &normals[*normindices++];
679 }
680 else if (nbind != OVERALL) {
681 pointDetail.setNormalIndex(normnr);
682 currnormal = &normals[normnr++];
683 }
684 vertex.setNormal(*currnormal);
685 if (doTextures) {
686 if (tb.isFunction()) {
687 vertex.setTextureCoords(tb.get(coords->get3(i), *currnormal));
688 }
689 else {
690 pointDetail.setTextureCoordIndex(texindices?*texindices:texidx);
691 vertex.setTextureCoords(tb.get(texindices?*texindices++:texidx++));
692 }
693 }
694 pointDetail.setCoordinateIndex(i);
695 vertex.setPoint(coords->get3(i));
696 this->shapeVertex(&vertex);
697
698 i = *cindices++;
699 assert(i >= 0);
700 if (mbind >= PER_VERTEX) {
701 if (matindices) vertex.setMaterialIndex(*matindices++);
702 else vertex.setMaterialIndex(matnr++);
703 pointDetail.setMaterialIndex(vertex.getMaterialIndex());
704 }
705 if (nbind >= PER_VERTEX) {
706 if (normindices) {
707 pointDetail.setNormalIndex(*normindices);
708 currnormal = &normals[*normindices++];
709 }
710 else {
711 pointDetail.setNormalIndex(normnr);
712 currnormal = &normals[normnr++];
713 }
714 vertex.setNormal(*currnormal);
715 }
716 if (doTextures) {
717 if (tb.isFunction()) {
718 vertex.setTextureCoords(tb.get(coords->get3(i), *currnormal));
719 }
720 else {
721 pointDetail.setTextureCoordIndex(texindices?*texindices:texidx);
722 vertex.setTextureCoords(tb.get(texindices?*texindices++:texidx++));
723 }
724 }
725 pointDetail.setCoordinateIndex(i);
726 vertex.setPoint(coords->get3(i));
727 this->shapeVertex(&vertex);
728 lineDetail.incPartIndex();
729
730 while (cindices < end && (i = *cindices++) >= 0) {
731 assert(cindices <= end);
732 if (mbind >= PER_VERTEX) {
733 if (matindices) vertex.setMaterialIndex(*matindices++);
734 else vertex.setMaterialIndex(matnr++);
735 pointDetail.setMaterialIndex(vertex.getMaterialIndex());
736 }
737 if (nbind >= PER_VERTEX) {
738 if (normindices) {
739 pointDetail.setNormalIndex(*normindices);
740 currnormal = &normals[*normindices++];
741 }
742 else {
743 pointDetail.setNormalIndex(normnr);
744 currnormal = &normals[normnr++];
745 }
746 vertex.setNormal(*currnormal);
747 }
748 if (doTextures) {
749 if (tb.isFunction()) {
750 vertex.setTextureCoords(tb.get(coords->get3(i), *currnormal));
751 }
752 else {
753 pointDetail.setTextureCoordIndex(texindices?*texindices:texidx);
754 vertex.setTextureCoords(tb.get(texindices?*texindices++:texidx++));
755 }
756 }
757 pointDetail.setCoordinateIndex(i);
758 vertex.setPoint(coords->get3(i));
759 this->shapeVertex(&vertex);
760 lineDetail.incPartIndex();
761 }
762 this->endShape(); // end of line strip
763 if (mbind == PER_VERTEX_INDEXED) matindices++;
764 if (nbind == PER_VERTEX_INDEXED) normindices++;
765 if (doTextures && texindices) texindices++;
766 lineDetail.incLineIndex();
767 }
768
769 if (this->vertexProperty.getValue()) {
770 state->pop();
771 }
772 }
773
774 void
notify(SoNotList * list)775 SoIndexedLineSet::notify(SoNotList * list)
776 {
777 SoField *f = list->getLastField();
778 if (f == &this->coordIndex) {
779 LOCK_VAINDEXER(this);
780 delete PRIVATE(this)->vaindexer;
781 PRIVATE(this)->vaindexer = NULL;
782 UNLOCK_VAINDEXER(this);
783 }
784 inherited::notify(list);
785 }
786
787
788 #undef LOCK_VAINDEXER
789 #undef PRIVATE
790 #undef UNLOCK_VAINDEXER
791