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 // This is an internal class with utility functions we use when
34 // playing around with OpenGL.
35 
36 // *************************************************************************
37 
38 #include "rendering/SoGL.h"
39 #include "coindefs.h"
40 
41 #include <cassert>
42 #include <cstdio>
43 #include <cstring>
44 
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif // HAVE_CONFIG_H
48 
49 #include <Inventor/C/tidbits.h>
50 #include <Inventor/SoOffscreenRenderer.h>
51 #include <Inventor/actions/SoGLRenderAction.h>
52 #include <Inventor/bundles/SoMaterialBundle.h>
53 #include <Inventor/bundles/SoTextureCoordinateBundle.h>
54 #include <Inventor/bundles/SoVertexAttributeBundle.h>
55 #include <Inventor/elements/SoCacheElement.h>
56 #include <Inventor/elements/SoComplexityElement.h>
57 #include <Inventor/elements/SoComplexityTypeElement.h>
58 #include <Inventor/elements/SoCoordinateElement.h>
59 #include <Inventor/elements/SoGLCacheContextElement.h>
60 #include <Inventor/elements/SoGLCoordinateElement.h>
61 #include <Inventor/elements/SoGLMultiTextureEnabledElement.h>
62 #include <Inventor/elements/SoGLMultiTextureImageElement.h>
63 #include <Inventor/elements/SoModelMatrixElement.h>
64 #include <Inventor/elements/SoMultiTextureEnabledElement.h>
65 #include <Inventor/elements/SoProfileElement.h>
66 #include <Inventor/elements/SoShapeStyleElement.h>
67 #include <Inventor/elements/SoProjectionMatrixElement.h>
68 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
69 #include <Inventor/elements/SoViewingMatrixElement.h>
70 #include <Inventor/elements/SoViewportRegionElement.h>
71 #include <Inventor/errors/SoDebugError.h>
72 #include <Inventor/lists/SbList.h>
73 #include <Inventor/nodes/SoCallback.h>
74 #include <Inventor/nodes/SoProfile.h>
75 #include <Inventor/nodes/SoShape.h>
76 #include <Inventor/system/gl.h>
77 #include <Inventor/threads/SbStorage.h>
78 
79 #include "glue/GLUWrapper.h"
80 #include "tidbitsp.h"
81 #include "glue/glp.h"
82 
83 // *************************************************************************
84 
85 // Convenience function for access to OpenGL wrapper from an SoState
86 // pointer.
87 const cc_glglue *
sogl_glue_instance(const SoState * state)88 sogl_glue_instance(const SoState * state)
89 {
90   SoGLRenderAction * action = (SoGLRenderAction *)state->getAction();
91   // FIXME: disabled until we figure out why this doesn't work on some
92   // Linux systems (gcc 3.2 systems, it seems). pederb, 2003-11-24
93 #if 0
94   assert(action->isOfType(SoGLRenderAction::getClassTypeId()) &&
95          "must have state from SoGLRenderAction to get hold of GL wrapper");
96   return cc_glglue_instance(action->getCacheContext());
97 #else // disabled
98   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
99     return cc_glglue_instance(action->getCacheContext());
100   }
101   static int didwarn = 0;
102   if (!didwarn) {
103     didwarn = 1;
104     SoDebugError::postWarning("sogl_glue_instance",
105                               "Wrong action type detected. Please report this to <coin-support@sim.no>, "
106                               "and include information about your system (compiler, Linux version, etc.");
107   }
108   // just return some cc_glglue instance. It usually doesn't matter
109   // that much unless multiple contexts on multiple displays are used.
110   return cc_glglue_instance(1);
111 #endif // workaround version
112 }
113 
114 
115 // generate a 3d circle in the x-z plane
116 static void
sogl_generate_3d_circle(SbVec3f * coords,const int num,const float radius,const float y)117 sogl_generate_3d_circle(SbVec3f *coords, const int num, const float radius, const float y)
118 {
119   float delta = 2.0f*float(M_PI)/float(num);
120   float angle = 0.0f;
121   for (int i = 0; i < num; i++) {
122     coords[i][0] = -float(sin(angle)) * radius;
123     coords[i][1] = y;
124     coords[i][2] = -float(cos(angle)) * radius;
125     angle += delta;
126   }
127 }
128 
129 // generate a 2d circle
130 static void
sogl_generate_2d_circle(SbVec2f * coords,const int num,const float radius)131 sogl_generate_2d_circle(SbVec2f *coords, const int num, const float radius)
132 {
133   float delta = 2.0f*float(M_PI)/float(num);
134   float angle = 0.0f;
135   for (int i = 0; i < num; i++) {
136     coords[i][0] = -float(sin(angle)) * radius;
137     coords[i][1] = -float(cos(angle)) * radius;
138     angle += delta;
139   }
140 }
141 
142 void
sogl_render_cone(const float radius,const float height,const int numslices,SoMaterialBundle * const material,const unsigned int flagsin,SoState * state)143 sogl_render_cone(const float radius,
144                  const float height,
145                  const int numslices,
146                  SoMaterialBundle * const material,
147                  const unsigned int flagsin,
148                  SoState * state)
149 {
150   const SbBool * unitenabled = NULL;
151   int maxunit = 0;
152   const cc_glglue * glue = NULL;
153 
154   int flags = flagsin;
155 
156   if (state) {
157     unitenabled =
158       SoMultiTextureEnabledElement::getEnabledUnits(state, maxunit);
159     if (unitenabled) {
160       glue = sogl_glue_instance(state);
161       flags |= SOGL_NEED_MULTITEXCOORDS;
162     }
163     else maxunit = -1;
164   }
165 
166   int i,u;
167   // use a limit of 128 to avoid allocating memory each time
168   // a cone is drawn
169   int slices = numslices;
170   if (slices > 128) slices = 128;
171   if (slices < 4) slices = 4;
172 
173   float h2 = height * 0.5f;
174 
175   // put coordinates on the stack
176   SbVec3f coords[129];
177   SbVec3f normals[130];
178   SbVec2f texcoords[129];
179 
180   sogl_generate_3d_circle(coords, slices, radius, -h2);
181   coords[slices] = coords[0];
182   if (flags & (SOGL_NEED_TEXCOORDS|SOGL_NEED_3DTEXCOORDS|SOGL_NEED_MULTITEXCOORDS)) {
183     sogl_generate_2d_circle(texcoords, slices, 0.5f);
184     texcoords[slices] = texcoords[0];
185   }
186 
187   if (flags & SOGL_NEED_NORMALS) {
188     double a = atan(height/radius);
189     sogl_generate_3d_circle(normals, slices, float(sin(a)), float(cos(a)));
190     normals[slices] = normals[0];
191     normals[slices+1] = normals[1];
192   }
193 
194   int matnr = 0;
195 
196   // FIXME: the texture coordinate generation for cone sides is of
197   // sub-par quality. The textures comes out looking "skewed" and
198   // "compressed". 20010926 mortene.
199 
200   if (flags & SOGL_RENDER_SIDE) {
201     glBegin(GL_TRIANGLES);
202     i = 0;
203 
204     float t = 1.0;
205     float delta = 1.0f / slices;
206 
207     while (i < slices) {
208       if (flags & SOGL_NEED_TEXCOORDS) {
209         glTexCoord2f(t - delta*0.5f, 1.0f);
210       }
211       else if (flags & SOGL_NEED_3DTEXCOORDS) {
212         glTexCoord3f(0.5f, 1.0f, 0.5f);
213       }
214       if (flags & SOGL_NEED_NORMALS) {
215         SbVec3f n = (normals[i] + normals[i+1])*0.5f;
216         glNormal3f(n[0], n[1], n[2]);
217       }
218       if (flags & SOGL_NEED_MULTITEXCOORDS) {
219         for (u = 1; u <= maxunit; u++) {
220           if (unitenabled[u]) {
221             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
222                                         t - delta*0.5f, 1.0f);
223           }
224         }
225       }
226 
227       glVertex3f(0.0f, h2, 0.0f);
228       if (flags & SOGL_NEED_TEXCOORDS) {
229         glTexCoord2f(t, 0.0f);
230       }
231       else if (flags & SOGL_NEED_3DTEXCOORDS) {
232         glTexCoord3f(texcoords[i][0]+0.5f, 0.0f, texcoords[i][1]+0.5f);
233       }
234       if (flags & SOGL_NEED_NORMALS) {
235         glNormal3fv((const GLfloat*)&normals[i]);
236       }
237       if (flags & SOGL_NEED_MULTITEXCOORDS) {
238         for (u = 1; u <= maxunit; u++) {
239           if (unitenabled[u]) {
240             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
241                                         t, 0.0f);
242           }
243         }
244       }
245       glVertex3fv((const GLfloat*)&coords[i]);
246 
247       if (flags & SOGL_NEED_TEXCOORDS) {
248         glTexCoord2f(t - delta, 0.0f);
249       }
250       else if (flags & SOGL_NEED_3DTEXCOORDS) {
251         glTexCoord3f(texcoords[i+1][0]+0.5f, 0.0f, texcoords[i+1][1]+0.5f);
252       }
253       if (flags & SOGL_NEED_NORMALS) {
254         glNormal3fv((const GLfloat*)&normals[i+1]);
255       }
256       if (flags & SOGL_NEED_MULTITEXCOORDS) {
257         for (u = 1; u <= maxunit; u++) {
258           if (unitenabled[u]) {
259             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
260                                         t - delta, 0.0f);
261           }
262         }
263       }
264       glVertex3fv((const GLfloat*)&coords[i+1]);
265 
266       i++;
267       t -= delta;
268     }
269 
270     matnr++;
271     glEnd();
272   }
273 
274   if (flags & SOGL_RENDER_BOTTOM) {
275     if (flags & SOGL_MATERIAL_PER_PART) {
276       material->send(matnr, TRUE);
277     }
278 
279     glBegin(GL_TRIANGLE_FAN);
280     glNormal3f(0.0f, -1.0f, 0.0f);
281     for (i = slices-1; i >= 0; i--) {
282       if (flags & SOGL_NEED_TEXCOORDS) {
283         glTexCoord2f(texcoords[i][0]+0.5f, texcoords[i][1]+0.5f);
284       }
285       else if (flags & SOGL_NEED_3DTEXCOORDS) {
286         glTexCoord3f(texcoords[i][0]+0.5f, 0.0f, texcoords[i][1]+0.5f);
287       }
288       if (flags & SOGL_NEED_MULTITEXCOORDS) {
289         for (u = 1; u <= maxunit; u++) {
290           if (unitenabled[u]) {
291             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
292                                         texcoords[i][0]+0.5f, texcoords[i][1]+0.5f);
293           }
294         }
295       }
296 
297       glVertex3fv((const GLfloat*)&coords[i]);
298     }
299     glEnd();
300   }
301   if (state && (SoComplexityTypeElement::get(state) ==
302                 SoComplexityTypeElement::OBJECT_SPACE)) {
303     // encourage auto caching for object space
304     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DO_AUTO_CACHE);
305     SoGLCacheContextElement::incNumShapes(state);
306   }
307   else {
308     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
309   }
310 }
311 
312 void
sogl_render_cylinder(const float radius,const float height,const int numslices,SoMaterialBundle * const material,const unsigned int flagsin,SoState * state)313 sogl_render_cylinder(const float radius,
314                      const float height,
315                      const int numslices,
316                      SoMaterialBundle * const material,
317                      const unsigned int flagsin,
318                      SoState * state)
319 {
320   const SbBool * unitenabled = NULL;
321   int maxunit = 0;
322   const cc_glglue * glue = NULL;
323 
324   int flags = flagsin;
325 
326   if (state) {
327     unitenabled =
328       SoMultiTextureEnabledElement::getEnabledUnits(state, maxunit);
329     if (unitenabled) {
330       glue = sogl_glue_instance(state);
331       flags |= SOGL_NEED_MULTITEXCOORDS;
332     }
333     else maxunit = -1;
334   }
335 
336   int i, u;
337   int slices = numslices;
338   if (slices > 128) slices = 128;
339   if (slices < 4) slices = 4;
340 
341   float h2 = height * 0.5f;
342 
343   SbVec3f coords[129];
344   SbVec3f normals[130];
345   SbVec2f texcoords[129];
346 
347   sogl_generate_3d_circle(coords, slices, radius, -h2);
348   coords[slices] = coords[0];
349   if (flags & SOGL_NEED_3DTEXCOORDS ||
350       (flags & SOGL_NEED_TEXCOORDS &&
351        flags & (SOGL_RENDER_BOTTOM | SOGL_RENDER_TOP))) {
352     sogl_generate_2d_circle(texcoords, slices, 0.5f);
353     texcoords[slices] = texcoords[0];
354   }
355 
356   if (flags & SOGL_NEED_NORMALS) {
357     sogl_generate_3d_circle(normals, slices, 1.0f, 0.0f);
358     normals[slices] = normals[0];
359     normals[slices+1] = normals[1];
360   }
361 
362   int matnr = 0;
363 
364   if (flags & SOGL_RENDER_SIDE) {
365     glBegin(GL_QUAD_STRIP);
366     i = 0;
367 
368     float t = 0.0;
369     float inc = 1.0f / slices;
370 
371     while (i <= slices) {
372       if (flags & SOGL_NEED_TEXCOORDS) {
373         glTexCoord2f(t, 1.0f);
374       }
375       else if (flags & SOGL_NEED_3DTEXCOORDS) {
376         glTexCoord3f(texcoords[i][0]+0.5f, 1.0f, 1.0f - texcoords[i][1]-0.5f);
377       }
378       if (flags & SOGL_NEED_NORMALS) {
379         glNormal3fv((const GLfloat*)&normals[i]);
380       }
381       if (flags & SOGL_NEED_MULTITEXCOORDS) {
382         for (u = 1; u <= maxunit; u++) {
383           if (unitenabled[u]) {
384             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
385                                         t, 1.0f);
386           }
387         }
388       }
389 
390       SbVec3f c = coords[i];
391       glVertex3f(c[0], h2, c[2]);
392       if (flags & SOGL_NEED_TEXCOORDS) {
393         glTexCoord2f(t, 0.0f);
394       }
395       else if (flags & SOGL_NEED_3DTEXCOORDS) {
396         glTexCoord3f(texcoords[i][0]+0.5f, 0.0f, 1.0f - texcoords[i][1]-0.5f);
397       }
398       if (flags & SOGL_NEED_MULTITEXCOORDS) {
399         for (u = 1; u <= maxunit; u++) {
400           if (unitenabled[u]) {
401             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
402                                         t, 0.0f);
403           }
404         }
405       }
406       glVertex3f(c[0], c[1], c[2]);
407       i++;
408       t += inc;
409     }
410 
411     matnr++;
412     glEnd();
413   }
414 
415   if ((flags & (SOGL_NEED_TEXCOORDS|SOGL_NEED_3DTEXCOORDS|SOGL_NEED_MULTITEXCOORDS)) &&
416       (flags & (SOGL_RENDER_BOTTOM | SOGL_RENDER_TOP))) {
417     sogl_generate_2d_circle(texcoords, slices, 0.5f);
418     texcoords[slices] = texcoords[0];
419   }
420 
421   if (flags & SOGL_RENDER_TOP) {
422     if (flags & SOGL_MATERIAL_PER_PART) {
423       material->send(matnr, TRUE);
424     }
425     glBegin(GL_TRIANGLE_FAN);
426     glNormal3f(0.0f, 1.0f, 0.0f);
427 
428     for (i = 0; i < slices; i++) {
429       if (flags & SOGL_NEED_TEXCOORDS) {
430         glTexCoord2f(texcoords[i][0]+0.5f, 1.0f - texcoords[i][1]-0.5f);
431       }
432       else if (flags & SOGL_NEED_3DTEXCOORDS) {
433         glTexCoord3f(texcoords[i][0]+0.5f, 1.0f, 1.0f - texcoords[i][1]-0.5f);
434       }
435       if (flags & SOGL_NEED_MULTITEXCOORDS) {
436         for (u = 1; u <= maxunit; u++) {
437           if (unitenabled[u]) {
438             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
439                                        texcoords[i][0]+0.5f, 1.0f - texcoords[i][1]-0.5f);
440           }
441         }
442       }
443       const SbVec3f &c = coords[i];
444       glVertex3f(c[0], h2, c[2]);
445     }
446     glEnd();
447     matnr++;
448   }
449   if (flags & SOGL_RENDER_BOTTOM) {
450     if (flags & SOGL_MATERIAL_PER_PART) {
451       material->send(matnr, TRUE);
452     }
453     glBegin(GL_TRIANGLE_FAN);
454     glNormal3f(0.0f, -1.0f, 0.0f);
455 
456     for (i = slices-1; i >= 0; i--) {
457       if (flags & SOGL_NEED_TEXCOORDS) {
458         glTexCoord2f(texcoords[i][0]+0.5f, texcoords[i][1]+0.5f);
459       }
460       else if (flags & SOGL_NEED_3DTEXCOORDS) {
461         glTexCoord3f(texcoords[i][0]+0.5f, 0.0f, 1.0f - texcoords[i][1]-0.5f);
462       }
463       if (flags & SOGL_NEED_MULTITEXCOORDS) {
464         for (u = 1; u <= maxunit; u++) {
465           if (unitenabled[u]) {
466             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
467                                         texcoords[i][0]+0.5f, texcoords[i][1]+0.5f);
468           }
469         }
470       }
471       glVertex3fv((const GLfloat*)&coords[i]);
472     }
473     glEnd();
474   }
475   if (state && (SoComplexityTypeElement::get(state) ==
476                 SoComplexityTypeElement::OBJECT_SPACE)) {
477     // encourage auto caching for object space
478     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DO_AUTO_CACHE);
479     SoGLCacheContextElement::incNumShapes(state);
480   }
481   else {
482     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
483   }
484 }
485 
486 void
sogl_render_sphere(const float radius,const int numstacks,const int numslices,SoMaterialBundle * const,const unsigned int flagsin,SoState * state)487 sogl_render_sphere(const float radius,
488                    const int numstacks,
489                    const int numslices,
490                    SoMaterialBundle * const /* material */,
491                    const unsigned int flagsin,
492                    SoState * state)
493 {
494   const SbBool * unitenabled = NULL;
495   int maxunit = 0;
496   const cc_glglue * glue = NULL;
497 
498   unsigned int flags = flagsin;
499 
500   if (state && (flags & SOGL_NEED_TEXCOORDS)) {
501     unitenabled =
502       SoMultiTextureEnabledElement::getEnabledUnits(state, maxunit);
503     if (unitenabled) {
504       glue = sogl_glue_instance(state);
505       flags |= SOGL_NEED_MULTITEXCOORDS;
506     }
507     else maxunit = -1;
508   }
509 
510   int stacks = numstacks;
511   int slices = numslices;
512 
513   if (stacks < 3) stacks = 3;
514   if (slices < 4) slices = 4;
515 
516   if (slices > 128) slices = 128;
517 
518   // used to cache last stack's data
519   SbVec3f coords[129];
520   SbVec3f normals[129];
521   float S[129];
522   SbVec3f texcoords[129];
523 
524   int i, j, u;
525   float rho;
526   float drho;
527   float theta;
528   float dtheta;
529   float tc, ts;
530   SbVec3f tmp;
531 
532   drho = float(M_PI) / (float) (stacks-1);
533   dtheta = 2.0f * float(M_PI) / (float) slices;
534 
535   float currs = 0.0f;
536   float incs = 1.0f / (float)slices;
537   rho = drho;
538   theta = 0.0f;
539   tc = (float) cos(rho);
540   ts = - (float) sin(rho);
541   tmp.setValue(0.0f,
542                tc,
543                ts);
544   normals[0] = tmp;
545   texcoords[0] = tmp/2 + SbVec3f(0.5f,0.5f,0.5f);
546   tmp *= radius;
547   coords[0] = tmp;
548   S[0] = currs;
549   float dT = 1.0f / (float) (stacks-1);
550   float T = 1.0f - dT;
551 
552   glBegin(GL_TRIANGLES);
553 
554   for (j = 1; j <= slices; j++) {
555     glNormal3f(0.0f, 1.0f, 0.0f);
556     if (flags & SOGL_NEED_TEXCOORDS) {
557       glTexCoord2f(currs + 0.5f * incs, 1.0f);
558     }
559     else if (flags & SOGL_NEED_3DTEXCOORDS) {
560       glTexCoord3f(0.5f, 1.0f, 0.5f);
561     }
562     if (flags & SOGL_NEED_MULTITEXCOORDS) {
563       for (u = 1; u <= maxunit; u++) {
564         if (unitenabled[u]) {
565           cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
566                                       currs + 0.5f * incs, 1.0f);
567         }
568       }
569     }
570     glVertex3f(0.0f, radius, 0.0f);
571 
572     glNormal3fv((const GLfloat*) &normals[j-1]);
573     if (flags & SOGL_NEED_TEXCOORDS) {
574       glTexCoord2f(currs, T);
575     }
576     else if (flags & SOGL_NEED_3DTEXCOORDS) {
577       glTexCoord3fv((const GLfloat*) &texcoords[j-1]);
578     }
579     if (flags & SOGL_NEED_MULTITEXCOORDS) {
580       for (u = 1; u <= maxunit; u++) {
581         if (unitenabled[u]) {
582           cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
583                                       currs, T);
584         }
585       }
586     }
587 
588     glVertex3fv((const GLfloat*) &coords[j-1]);
589 
590     currs += incs;
591     theta += dtheta;
592     tmp.setValue(float(sin(theta))*ts,
593                  tc,
594                  float(cos(theta))*ts);
595 
596     normals[j] = tmp;
597     glNormal3fv((const GLfloat*)&normals[j]);
598     if (flags & SOGL_NEED_TEXCOORDS) {
599       S[j] = currs;
600       glTexCoord2f(currs, T);
601     }
602     else if (flags & SOGL_NEED_3DTEXCOORDS) {
603       texcoords[j] = tmp/2 + SbVec3f(0.5f,0.5f,0.5f);
604       glTexCoord3fv((const GLfloat*) &texcoords[j]);
605     }
606     if (flags & SOGL_NEED_MULTITEXCOORDS) {
607       for (u = 1; u <= maxunit; u++) {
608         if (unitenabled[u]) {
609           cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
610                                       currs, T);
611         }
612       }
613     }
614     tmp *= radius;
615     coords[j] = tmp;
616     glVertex3fv((const GLfloat*)&coords[j]);
617   }
618   glEnd(); // GL_TRIANGLES
619 
620   rho += drho;
621 
622   for (i = 2; i < stacks-1; i++) {
623     tc = (float)cos(rho);
624     ts = - (float) sin(rho);
625     glBegin(GL_QUAD_STRIP);
626     theta = 0.0f;
627     for (j = 0; j <= slices; j++) {
628       if (flags & SOGL_NEED_TEXCOORDS) {
629         glTexCoord2f(S[j], T);
630       }
631       else if (flags & SOGL_NEED_3DTEXCOORDS) {
632         glTexCoord3fv((const GLfloat*) &texcoords[j]);
633       }
634       if (flags & SOGL_NEED_MULTITEXCOORDS) {
635         for (u = 1; u <= maxunit; u++) {
636           if (unitenabled[u]) {
637             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
638                                         S[j], T);
639           }
640         }
641       }
642       glNormal3fv((const GLfloat*)&normals[j]);
643       glVertex3fv((const GLfloat*)&coords[j]);
644 
645       tmp.setValue(float(sin(theta))*ts,
646                    tc,
647                    float(cos(theta))*ts);
648       if (flags & SOGL_NEED_TEXCOORDS) {
649         glTexCoord2f(S[j], T - dT);
650       }
651       else if (flags & SOGL_NEED_3DTEXCOORDS) {
652         texcoords[j] = tmp/2 + SbVec3f(0.5f,0.5f,0.5f);
653         glTexCoord3fv((const GLfloat*) &texcoords[j]);
654       }
655       if (flags & SOGL_NEED_MULTITEXCOORDS) {
656         for (u = 1; u <= maxunit; u++) {
657           if (unitenabled[u]) {
658             cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
659                                         S[j], T - dT);
660           }
661         }
662       }
663       normals[j] = tmp;
664       glNormal3f(tmp[0], tmp[1], tmp[2]);
665       tmp *= radius;
666       glVertex3f(tmp[0], tmp[1], tmp[2]);
667       coords[j] = tmp;
668       theta += dtheta;
669     }
670     glEnd(); // GL_QUAD_STRIP
671     rho += drho;
672     T -= dT;
673   }
674 
675   glBegin(GL_TRIANGLES);
676   for (j = 0; j < slices; j++) {
677     if (flags & SOGL_NEED_TEXCOORDS) {
678       glTexCoord2f(S[j], T);
679     }
680     else if (flags & SOGL_NEED_3DTEXCOORDS) {
681       glTexCoord3fv((const GLfloat*) &texcoords[j]);
682     }
683     if (flags & SOGL_NEED_MULTITEXCOORDS) {
684       for (u = 1; u <= maxunit; u++) {
685         if (unitenabled[u]) {
686           cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
687                                       S[j], T);
688         }
689       }
690     }
691     glNormal3fv((const GLfloat*)&normals[j]);
692     glVertex3fv((const GLfloat*)&coords[j]);
693 
694     if (flags & SOGL_NEED_TEXCOORDS) {
695       glTexCoord2f(S[j]+incs*0.5f, 0.0f);
696     }
697     else if (flags & SOGL_NEED_3DTEXCOORDS) {
698       glTexCoord3f(0.5f, 0.0f, 0.5f);
699     }
700     if (flags & SOGL_NEED_MULTITEXCOORDS) {
701       for (u = 1; u <= maxunit; u++) {
702         if (unitenabled[u]) {
703           cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
704                                       S[j]+incs*0.5f, 0.0f);
705         }
706       }
707     }
708     glNormal3f(0.0f, -1.0f, 0.0f);
709     glVertex3f(0.0f, -radius, 0.0f);
710 
711     if (flags & SOGL_NEED_TEXCOORDS) {
712       glTexCoord2f(S[j+1], T);
713     }
714     else if (flags & SOGL_NEED_3DTEXCOORDS) {
715       glTexCoord3fv((const GLfloat*) &texcoords[j+1]);
716     }
717     if (flags & SOGL_NEED_MULTITEXCOORDS) {
718       for (u = 1; u <= maxunit; u++) {
719         if (unitenabled[u]) {
720           cc_glglue_glMultiTexCoord2f(glue, (GLenum) (GL_TEXTURE0 + u),
721                                       S[j+1], T);
722         }
723       }
724     }
725     glNormal3fv((const GLfloat*)&normals[j+1]);
726     glVertex3fv((const GLfloat*)&coords[j+1]);
727   }
728   glEnd(); // GL_TRIANGLES
729 
730   if (state && (SoComplexityTypeElement::get(state) ==
731                 SoComplexityTypeElement::OBJECT_SPACE)) {
732     // encourage auto caching for object space
733     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DO_AUTO_CACHE);
734     SoGLCacheContextElement::incNumShapes(state);
735   }
736   else {
737     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
738   }
739 }
740 
741 //
742 // the 12 triangles in the cube
743 //
744 static int sogl_cube_vindices[] =
745 {
746   0, 1, 3, 2,
747   5, 4, 6, 7,
748   1, 5, 7, 3,
749   4, 0, 2, 6,
750   4, 5, 1, 0,
751   2, 3, 7, 6
752 };
753 
754 static float sogl_cube_texcoords[] =
755 {
756   1.0f, 1.0f,
757   0.0f, 1.0f,
758   0.0f, 0.0f,
759   1.0f, 0.0f
760 };
761 
762 static float sogl_cube_3dtexcoords[][3] =
763 {
764   {1.0f, 1.0f, 1.0f},
765   {1.0f, 1.0f, 0.0f},
766   {1.0f, 0.0f, 1.0f},
767   {1.0f, 0.0f, 0.0f},
768   {0.0f, 1.0f, 1.0f},
769   {0.0f, 1.0f, 0.0f},
770   {0.0f, 0.0f, 1.0f},
771   {0.0f, 0.0f, 0.0f}
772 };
773 
774 static float sogl_cube_normals[] =
775 {
776   0.0f, 0.0f, 1.0f,
777   0.0f, 0.0f, -1.0f,
778   -1.0f, 0.0f, 0.0f,
779   1.0f, 0.0f, 0.0f,
780   0.0f, 1.0f, 0.0f,
781   0.0f, -1.0f, 0.0f
782 };
783 
784 static void
sogl_generate_cube_vertices(SbVec3f * varray,const float w,const float h,const float d)785 sogl_generate_cube_vertices(SbVec3f *varray,
786                        const float w,
787                        const float h,
788                        const float d)
789 {
790   for (int i = 0; i < 8; i++) {
791     varray[i].setValue((i&1) ? -w : w,
792                        (i&2) ? -h : h,
793                        (i&4) ? -d : d);
794   }
795 }
796 
797 
798 void
sogl_render_cube(const float width,const float height,const float depth,SoMaterialBundle * const material,const unsigned int flagsin,SoState * state)799 sogl_render_cube(const float width,
800                  const float height,
801                  const float depth,
802                  SoMaterialBundle * const material,
803                  const unsigned int flagsin,
804                  SoState * state)
805 {
806   const SbBool * unitenabled = NULL;
807   int maxunit = 0;
808   const cc_glglue * glue = NULL;
809 
810   int flags = flagsin;
811 
812   if (state) {
813     unitenabled =
814       SoMultiTextureEnabledElement::getEnabledUnits(state, maxunit);
815     if (unitenabled) {
816       glue = sogl_glue_instance(state);
817       flags |= SOGL_NEED_MULTITEXCOORDS;
818     }
819     else maxunit = -1;
820   }
821 
822 
823   SbVec3f varray[8];
824   sogl_generate_cube_vertices(varray,
825                          width * 0.5f,
826                          height * 0.5f,
827                          depth * 0.5f);
828   glBegin(GL_QUADS);
829   int *iptr = sogl_cube_vindices;
830   int u;
831 
832   for (int i = 0; i < 6; i++) { // 6 quads
833     if (flags & SOGL_NEED_NORMALS)
834       glNormal3fv((const GLfloat*)&sogl_cube_normals[i*3]);
835     if (flags & SOGL_MATERIAL_PER_PART)
836       material->send(i, TRUE);
837     for (int j = 0; j < 4; j++) {
838       if (flags & SOGL_NEED_3DTEXCOORDS) {
839         glTexCoord3fv(sogl_cube_3dtexcoords[*iptr]);
840       }
841       else if (flags & SOGL_NEED_TEXCOORDS) {
842         glTexCoord2fv(&sogl_cube_texcoords[j<<1]);
843       }
844       if (flags & SOGL_NEED_MULTITEXCOORDS) {
845         for (u = 1; u <= maxunit; u++) {
846           if (unitenabled[u]) {
847             cc_glglue_glMultiTexCoord2fv(glue, (GLenum) (GL_TEXTURE0 + u),
848                                          &sogl_cube_texcoords[j<<1]);
849           }
850         }
851       }
852       glVertex3fv((const GLfloat*)&varray[*iptr++]);
853     }
854   }
855   glEnd();
856 
857   if (state) {
858     // always encourage auto caching for cubes
859     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DO_AUTO_CACHE);
860     SoGLCacheContextElement::incNumShapes(state);
861   }
862 }
863 
864 // **************************************************************************
865 
866 #if !defined(NO_LINESET_RENDER)
867 
868 namespace { namespace SoGL { namespace IndexedLineSet {
869 
870   enum AttributeBinding {
871     OVERALL = 0,
872     PER_SEGMENT = 1,
873     PER_SEGMENT_INDEXED = 2,
874     PER_LINE = 3,
875     PER_LINE_INDEXED = 4,
876     PER_VERTEX = 5,
877     PER_VERTEX_INDEXED = 6
878   };
879 
880   template < int NormalBinding,
881              int MaterialBinding,
882              int TexturingEnabled >
GLRender(const SoGLCoordinateElement * coords,const int32_t * indices,int num_vertexindices,const SbVec3f * normals,const int32_t * normindices,SoMaterialBundle * const materials,const int32_t * matindices,const SoTextureCoordinateBundle * const texcoords,const int32_t * texindices,const int drawAsPoints)883   static void GLRender(const SoGLCoordinateElement * coords,
884                        const int32_t *indices,
885                        int num_vertexindices,
886                        const SbVec3f *normals,
887                        const int32_t *normindices,
888                        SoMaterialBundle *const materials,
889                        const int32_t *matindices,
890                        const SoTextureCoordinateBundle * const texcoords,
891                        const int32_t *texindices,
892                        const int drawAsPoints)
893   {
894     const SbVec3f * coords3d = NULL;
895     const SbVec4f * coords4d = NULL;
896     const SbBool is3d = coords->is3D();
897     if (is3d) {
898       coords3d = coords->getArrayPtr3();
899     }
900     else {
901       coords4d = coords->getArrayPtr4();
902     }
903     int numcoords = coords->getNum();
904 
905     // This is the same code as in SoGLCoordinateElement::send().
906     // It is inlined here for speed (~15% speed increase).
907 #define SEND_VERTEX(_idx_) \
908     if (is3d) glVertex3fv((const GLfloat*) (coords3d + _idx_)); \
909     else glVertex4fv((const GLfloat*) (coords4d + _idx_));
910 
911     if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
912       if (matindices == NULL) matindices = indices;
913     }
914     if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
915       if (normindices == NULL) normindices = indices;
916     }
917 
918     int matnr = 0;
919     int texidx = 0;
920     int32_t i;
921     const int32_t *end = indices + num_vertexindices;
922 
923     SbVec3f dummynormal(0.0f, 0.0f, 1.0f);
924     const SbVec3f *currnormal = &dummynormal;
925     if (normals) currnormal = normals;
926     if ((AttributeBinding)MaterialBinding == OVERALL) {
927       glNormal3fv((const GLfloat*)currnormal);
928     }
929 
930     if ((AttributeBinding)MaterialBinding == PER_SEGMENT ||
931         (AttributeBinding)MaterialBinding == PER_SEGMENT_INDEXED ||
932         (AttributeBinding)NormalBinding == PER_SEGMENT ||
933         (AttributeBinding)NormalBinding == PER_SEGMENT_INDEXED) {
934       int previ;
935 
936       if (drawAsPoints)
937         glBegin(GL_POINTS);
938       else
939         glBegin(GL_LINES);
940 
941       while (indices < end) {
942         previ = *indices++;
943 
944         // Variable used for counting errors and make sure not a bunch of
945         // errormessages flood the screen.
946         static uint32_t current_errors = 0;
947 
948         // This test is for robustness upon buggy data sets
949         if (previ < 0 || previ >= numcoords) {
950           if (current_errors < 1) {
951             SoDebugError::postWarning("[indexedlineset]::GLRender", "Erroneous coordinate "
952                                       "index: %d (Should be within [0, %d]). Aborting "
953                                       "rendering. This message will be shown once, but "
954                                       "there might be more errors", previ, numcoords - 1);
955           }
956 
957           current_errors++;
958           glEnd();
959           return;
960         }
961 
962         if ((AttributeBinding)MaterialBinding == PER_LINE ||
963             (AttributeBinding)MaterialBinding == PER_VERTEX) {
964           materials->send(matnr++, TRUE);
965         } else if ((AttributeBinding)MaterialBinding == PER_LINE_INDEXED ||
966                    (AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
967           materials->send(*matindices++, TRUE);
968         }
969 
970         if ((AttributeBinding)NormalBinding == PER_LINE ||
971             (AttributeBinding)NormalBinding == PER_VERTEX) {
972           currnormal = normals++;
973           glNormal3fv((const GLfloat*) currnormal);
974         } else if ((AttributeBinding)NormalBinding == PER_LINE_INDEXED ||
975                    (AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
976           currnormal = &normals[*normindices++];
977           glNormal3fv((const GLfloat*) currnormal);
978         }
979         if (TexturingEnabled == TRUE) {
980           texcoords->send(texindices ? *texindices++ : texidx++,coords->get3(previ), *currnormal);
981         }
982         i = (indices < end) ? *indices++ : -1;
983         while (i >= 0) {
984           // For robustness upon buggy data sets
985           if (i >= numcoords) {
986             if (current_errors < 1) {
987               SoDebugError::postWarning("[indexedlineset]::GLRender", "Erroneous coordinate "
988                                         "index: %d (Should be within [0, %d]). Aborting "
989                                         "rendering. This message will be shown once, but "
990                                         "there might be more errors", i, numcoords - 1);
991             }
992             current_errors++;
993             break;
994           }
995 
996           if ((AttributeBinding)MaterialBinding == PER_SEGMENT) {
997             materials->send(matnr++, TRUE);
998           } else if ((AttributeBinding)MaterialBinding == PER_SEGMENT_INDEXED) {
999             materials->send(*matindices++, TRUE);
1000           }
1001 
1002           if ((AttributeBinding)NormalBinding == PER_SEGMENT) {
1003             currnormal = normals++;
1004             glNormal3fv((const GLfloat*) currnormal);
1005           } else if ((AttributeBinding)NormalBinding == PER_SEGMENT_INDEXED) {
1006             currnormal = &normals[*normindices++];
1007             glNormal3fv((const GLfloat*)currnormal);
1008           }
1009           SEND_VERTEX(previ);
1010 
1011           if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1012             materials->send(matnr++, TRUE);
1013           } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1014             materials->send(*matindices++, TRUE);
1015           }
1016           if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1017             currnormal = normals++;
1018             glNormal3fv((const GLfloat*)currnormal);
1019           } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1020             currnormal = &normals[*normindices++];
1021             glNormal3fv((const GLfloat*)currnormal);
1022           }
1023           if (TexturingEnabled == TRUE) {
1024             texcoords->send(texindices ? *texindices++ : texidx++, coords->get3(i), *currnormal);
1025           }
1026           SEND_VERTEX(i);
1027           previ = i;
1028           i = indices < end ? *indices++ : -1;
1029         }
1030         if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1031           matindices++;
1032         }
1033         if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1034           normindices++;
1035         }
1036         if (TexturingEnabled == TRUE) {
1037           if (texindices) texindices++;
1038         }
1039       }
1040       glEnd();
1041 
1042     } else { // no per_segment binding code below
1043 
1044       if (drawAsPoints)
1045         glBegin(GL_POINTS);
1046 
1047       while (indices < end) {
1048         if (!drawAsPoints)
1049           glBegin(GL_LINE_STRIP);
1050 
1051         i = *indices++;
1052 
1053         // Variable used for counting errors and make sure not a bunch of
1054         // errormessages flood the screen.
1055         static uint32_t current_errors = 0;
1056 
1057         // This test is for robustness upon buggy data sets
1058         if (i < 0 || i >= numcoords) {
1059           if (current_errors < 1) {
1060             SoDebugError::postWarning("[indexedlineset]::GLRender", "Erroneous coordinate "
1061                                       "index: %d (Should be within [0, %d]). Aborting "
1062                                       "rendering. This message will be shown once, but "
1063                                       "there might be more errors", i, numcoords - 1);
1064           }
1065 
1066           current_errors++;
1067           glEnd();
1068           return;
1069         }
1070 
1071         if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED ||
1072             (AttributeBinding)MaterialBinding == PER_LINE_INDEXED) {
1073           materials->send(*matindices++, TRUE);
1074         } else if ((AttributeBinding)MaterialBinding == PER_VERTEX ||
1075                    (AttributeBinding)MaterialBinding == PER_LINE) {
1076           materials->send(matnr++, TRUE);
1077         }
1078 
1079         if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED ||
1080             (AttributeBinding)NormalBinding == PER_LINE_INDEXED) {
1081           currnormal = &normals[*normindices++];
1082           glNormal3fv((const GLfloat*) currnormal);
1083         } else if ((AttributeBinding)NormalBinding == PER_VERTEX ||
1084                    (AttributeBinding)NormalBinding == PER_LINE) {
1085           currnormal = normals++;
1086           glNormal3fv((const GLfloat*) currnormal);
1087         }
1088         if (TexturingEnabled == TRUE) {
1089           texcoords->send(texindices ? *texindices++ : texidx++, coords->get3(i), *currnormal);
1090         }
1091 
1092         SEND_VERTEX(i);
1093         i = indices < end ? *indices++ : -1;
1094         while (i >= 0) {
1095           // For robustness upon buggy data sets
1096           if (i >= numcoords) {
1097             if (current_errors < 1) {
1098               SoDebugError::postWarning("[indexedlineset]::GLRender", "Erroneous coordinate "
1099                                         "index: %d (Should be within [0, %d]). Aborting "
1100                                         "rendering. This message will be shown once, but "
1101                                         "there might be more errors", i, numcoords - 1);
1102             }
1103             current_errors++;
1104             break;
1105           }
1106 
1107           if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1108             materials->send(matnr++, TRUE);
1109           } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1110             materials->send(*matindices++, TRUE);
1111           }
1112 
1113           if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1114             currnormal = normals++;
1115             glNormal3fv((const GLfloat*) currnormal);
1116           } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1117             currnormal = &normals[*normindices++];
1118             glNormal3fv((const GLfloat*) currnormal);
1119           }
1120           if (TexturingEnabled == TRUE) {
1121             texcoords->send(texindices ? *texindices++ : texidx++, coords->get3(i), *currnormal);
1122           }
1123 
1124           SEND_VERTEX(i);
1125           i = indices < end ? *indices++ : -1;
1126         }
1127         if (!drawAsPoints)
1128           glEnd(); // end of line strip
1129 
1130         if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1131           matindices++;
1132         }
1133         if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1134           normindices++;
1135         }
1136         if (TexturingEnabled == TRUE) {
1137           if (texindices) texindices++;
1138         }
1139       }
1140       if (drawAsPoints)
1141         glEnd();
1142     }
1143   }
1144 
1145 } } } // namespace
1146 
1147 #define SOGL_INDEXEDLINESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, texturing, args) \
1148   SoGL::IndexedLineSet::GLRender<normalbinding, materialbinding, texturing> args
1149 
1150 #define SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, materialbinding, texturing, args) \
1151   if (texturing) { \
1152     SOGL_INDEXEDLINESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, TRUE, args); \
1153   } else { \
1154     SOGL_INDEXEDLINESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, FALSE, args); \
1155   }
1156 
1157 #define SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(normalbinding, materialbinding, texturing, args) \
1158   switch (materialbinding) { \
1159   case SoGL::IndexedLineSet::OVERALL: \
1160     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::IndexedLineSet::OVERALL, texturing, args); \
1161     break; \
1162   case SoGL::IndexedLineSet::PER_SEGMENT: \
1163     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::IndexedLineSet::PER_SEGMENT, texturing, args); \
1164     break; \
1165   case SoGL::IndexedLineSet::PER_SEGMENT_INDEXED: \
1166     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::IndexedLineSet::PER_SEGMENT_INDEXED, texturing, args); \
1167     break; \
1168   case SoGL::IndexedLineSet::PER_LINE: \
1169     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::IndexedLineSet::PER_LINE, texturing, args); \
1170     break; \
1171   case SoGL::IndexedLineSet::PER_LINE_INDEXED: \
1172     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::IndexedLineSet::PER_LINE_INDEXED, texturing, args); \
1173     break; \
1174   case SoGL::IndexedLineSet::PER_VERTEX: \
1175     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::IndexedLineSet::PER_VERTEX, texturing, args); \
1176     break; \
1177   case SoGL::IndexedLineSet::PER_VERTEX_INDEXED: \
1178     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::IndexedLineSet::PER_VERTEX_INDEXED, texturing, args); \
1179     break; \
1180   default: \
1181     assert(!"invalid material binding argument"); \
1182   }
1183 
1184 #define SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG1(normalbinding, materialbinding, texturing, args) \
1185   switch (normalbinding) { \
1186   case SoGL::IndexedLineSet::OVERALL: \
1187     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(SoGL::IndexedLineSet::OVERALL, materialbinding, texturing, args); \
1188     break; \
1189   case SoGL::IndexedLineSet::PER_SEGMENT: \
1190     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(SoGL::IndexedLineSet::PER_SEGMENT, materialbinding, texturing, args); \
1191     break; \
1192   case SoGL::IndexedLineSet::PER_SEGMENT_INDEXED: \
1193     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(SoGL::IndexedLineSet::PER_SEGMENT_INDEXED, materialbinding, texturing, args); \
1194     break; \
1195   case SoGL::IndexedLineSet::PER_LINE: \
1196     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(SoGL::IndexedLineSet::PER_LINE, materialbinding, texturing, args); \
1197     break; \
1198   case SoGL::IndexedLineSet::PER_LINE_INDEXED: \
1199     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(SoGL::IndexedLineSet::PER_LINE_INDEXED, materialbinding, texturing, args); \
1200     break; \
1201   case SoGL::IndexedLineSet::PER_VERTEX: \
1202     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(SoGL::IndexedLineSet::PER_VERTEX, materialbinding, texturing, args); \
1203     break; \
1204   case SoGL::IndexedLineSet::PER_VERTEX_INDEXED: \
1205     SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2(SoGL::IndexedLineSet::PER_VERTEX_INDEXED, materialbinding, texturing, args); \
1206     break; \
1207   default: \
1208     assert(!"invalid normal binding argument"); \
1209   }
1210 
1211 #define SOGL_INDEXEDLINESET_GLRENDER(normalbinding, materialbinding, texturing, args) \
1212   SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG1(normalbinding, materialbinding, texturing, args)
1213 
1214 void
sogl_render_lineset(const SoGLCoordinateElement * const coords,const int32_t * cindices,int numindices,const SbVec3f * normals,const int32_t * nindices,SoMaterialBundle * const mb,const int32_t * mindices,const SoTextureCoordinateBundle * const tb,const int32_t * tindices,int nbind,int mbind,const int texture,const int drawAsPoints)1215 sogl_render_lineset(const SoGLCoordinateElement * const coords,
1216                     const int32_t *cindices,
1217                     int numindices,
1218                     const SbVec3f *normals,
1219                     const int32_t *nindices,
1220                     SoMaterialBundle *const mb,
1221                     const int32_t *mindices,
1222                     const SoTextureCoordinateBundle * const tb,
1223                     const int32_t *tindices,
1224                     int nbind,
1225                     int mbind,
1226                     const int texture,
1227                     const int drawAsPoints)
1228 {
1229 
1230   SOGL_INDEXEDLINESET_GLRENDER(nbind, mbind, texture, (coords,
1231                                                        cindices,
1232                                                        numindices,
1233                                                        normals,
1234                                                        nindices,
1235                                                        mb,
1236                                                        mindices,
1237                                                        tb,
1238                                                        tindices,
1239                                                        drawAsPoints));
1240 }
1241 
1242 #undef SOGL_INDEXEDLINESET_GLRENDER_CALL_FUNC
1243 #undef SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG1
1244 #undef SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG2
1245 #undef SOGL_INDEXEDLINESET_GLRENDER_RESOLVE_ARG3
1246 #undef SOGL_INDEXEDLINESET_GLRENDER
1247 
1248 #endif // !NO_LINESET_RENDER
1249 
1250 // **************************************************************************
1251 
1252 #if !defined(NO_FACESET_RENDER)
1253 
1254 namespace { namespace SoGL { namespace FaceSet {
1255 
1256   enum AttributeBinding {
1257     OVERALL = 0,
1258     PER_FACE = 1,
1259     PER_FACE_INDEXED = 2,
1260     PER_VERTEX = 3,
1261     PER_VERTEX_INDEXED = 4
1262   };
1263 
1264   template < int NormalBinding,
1265              int MaterialBinding,
1266              int VertexAttributeBinding >
GLRender(const SoGLCoordinateElement * const vertexlist,const int32_t * vertexindices,int numindices,const SbVec3f * normals,const int32_t * normalindices,SoMaterialBundle * materials,const int32_t * matindices,const SoTextureCoordinateBundle * const texcoords,const int32_t * texindices,SoVertexAttributeBundle * const attribs,const int dotexture,const int doattribs)1267   static void GLRender(const SoGLCoordinateElement * const vertexlist,
1268                      const int32_t *vertexindices,
1269                      int numindices,
1270                      const SbVec3f *normals,
1271                      const int32_t *normalindices,
1272                      SoMaterialBundle *materials,
1273                      const int32_t *matindices,
1274                      const SoTextureCoordinateBundle * const texcoords,
1275                      const int32_t *texindices,
1276                        SoVertexAttributeBundle * const attribs,
1277                        const int dotexture,
1278                        const int doattribs)
1279   {
1280 
1281     // just in case someone forgot
1282     if (matindices == NULL) matindices = vertexindices;
1283     if (normalindices == NULL) normalindices = vertexindices;
1284 
1285     int texidx = 0;
1286 
1287     const SbVec3f * coords3d = NULL;
1288     const SbVec4f * coords4d = NULL;
1289     const SbBool is3d = vertexlist->is3D();
1290     if (is3d) {
1291       coords3d = vertexlist->getArrayPtr3();
1292     }
1293     else {
1294       coords4d = vertexlist->getArrayPtr4();
1295     }
1296 
1297     // This is the same code as in SoGLCoordinateElement::send().
1298     // It is inlined here for speed (~15% speed increase).
1299 #define SEND_VERTEX(_idx_)                                           \
1300     if (is3d) glVertex3fv((const GLfloat*) (coords3d + _idx_));             \
1301     else glVertex4fv((const GLfloat*) (coords4d + _idx_));
1302 
1303     int mode = GL_POLYGON; // ...to save a test
1304     int newmode;
1305     const int32_t *viptr = vertexindices;
1306     const int32_t *vistartptr = vertexindices;
1307     const int32_t *viendptr = viptr + numindices;
1308     int32_t v1, v2, v3, v4, v5 = 0; // v5 init unnecessary, but kills a compiler warning.
1309     int numverts = vertexlist->getNum();
1310 
1311     SbVec3f dummynormal(0,0,1);
1312     const SbVec3f * currnormal = &dummynormal;
1313     if ((AttributeBinding)NormalBinding == PER_VERTEX ||
1314        (AttributeBinding)NormalBinding == PER_FACE ||
1315        (AttributeBinding)NormalBinding == PER_VERTEX_INDEXED ||
1316        (AttributeBinding)NormalBinding == PER_FACE_INDEXED ||
1317        dotexture) {
1318       if (normals) currnormal = normals;
1319     }
1320 
1321     int matnr = 0;
1322     int attribnr = 0;
1323 
1324     if (doattribs && (AttributeBinding)VertexAttributeBinding == OVERALL) {
1325       attribs->send(0);
1326     }
1327 
1328     while (viptr + 2 < viendptr) {
1329       v1 = *viptr++;
1330       v2 = *viptr++;
1331       v3 = *viptr++;
1332 
1333       // Variable used for counting errors and make sure not a
1334       // bunch of errormessages flood the screen.
1335       static uint32_t current_errors = 0;
1336 
1337       // This test is for robustness upon buggy data sets
1338       if (v1 < 0 || v2 < 0 || v3 < 0 ||
1339           v1 >= numverts || v2 >= numverts || v3 >= numverts) {
1340 
1341         if (current_errors < 1) {
1342           SoDebugError::postWarning("[faceset]::GLRender", "Erroneous polygon detected. "
1343                                     "Ignoring (offset: %d, [%d %d %d]). Should be within "
1344                                     " [0, %d] This message will only be shown once, but "
1345                                     "more errors might be present",
1346                                     viptr - vistartptr - 3, v1, v2, v3, numverts - 1);
1347         }
1348         current_errors++;
1349         break;
1350       }
1351       v4 = viptr < viendptr ? *viptr++ : -1;
1352       if (v4  < 0) newmode = GL_TRIANGLES;
1353       // This test for numverts is for robustness upon buggy data sets
1354       else if (v4 >= numverts) {
1355         newmode = GL_TRIANGLES;
1356 
1357         if (current_errors < 1) {
1358           SoDebugError::postWarning("[faceset]::GLRender", "Erroneous polygon detected. "
1359                                     "(offset: %d, [%d %d %d %d]). Should be within "
1360                                     " [0, %d] This message will only be shown once, but "
1361                                     "more errors might be present",
1362                                     viptr - vistartptr - 4, v1, v2, v3, v4, numverts - 1);
1363         }
1364         current_errors++;
1365       }
1366       else {
1367         v5 = viptr < viendptr ? *viptr++ : -1;
1368         if (v5 < 0) newmode = GL_QUADS;
1369         // This test for numverts is for robustness upon buggy data sets
1370         else if (v5 >= numverts) {
1371           newmode = GL_QUADS;
1372 
1373           if (current_errors < 1) {
1374             SoDebugError::postWarning("[faceset]::GLRender", "Erroneous polygon detected. "
1375                                       "(offset: %d, [%d %d %d %d %d]). Should be within "
1376                                       " [0, %d] This message will only be shown once, but "
1377                                       "more errors might be present",
1378                                       viptr - vistartptr - 5, v1, v2, v3, v4, v5, numverts - 1);
1379           }
1380           current_errors++;
1381         }
1382         else newmode = GL_POLYGON;
1383       }
1384       if (newmode != mode) {
1385         if (mode != GL_POLYGON) glEnd();
1386         mode = newmode;
1387         glBegin((GLenum) mode);
1388       }
1389       else if (mode == GL_POLYGON) glBegin(GL_POLYGON);
1390 
1391       /* vertex 1 *********************************************************/
1392       if ((AttributeBinding)MaterialBinding == PER_VERTEX ||
1393           (AttributeBinding)MaterialBinding == PER_FACE) {
1394         materials->send(matnr++, TRUE);
1395       } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED ||
1396                  (AttributeBinding)MaterialBinding == PER_FACE_INDEXED) {
1397         materials->send(*matindices++, TRUE);
1398       }
1399 
1400       if ((AttributeBinding)NormalBinding == PER_VERTEX ||
1401           (AttributeBinding)NormalBinding == PER_FACE) {
1402         currnormal = normals++;
1403         glNormal3fv((const GLfloat*)currnormal);
1404       } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED ||
1405                  (AttributeBinding)NormalBinding == PER_FACE_INDEXED) {
1406         currnormal = &normals[*normalindices++];
1407         glNormal3fv((const GLfloat*)currnormal);
1408       }
1409 
1410       if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX) {
1411        attribs->send(attribnr++);
1412       } else if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX_INDEXED) {
1413         attribs->send(*vertexindices++);
1414       }
1415 
1416       if (dotexture) {
1417         texcoords->send(texindices ? *texindices++ : texidx++,
1418                         vertexlist->get3(v1),
1419                         *currnormal);
1420       }
1421 
1422       SEND_VERTEX(v1);
1423 
1424       /* vertex 2 *********************************************************/
1425       if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1426         materials->send(matnr++, TRUE);
1427       } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1428         materials->send(*matindices++, TRUE);
1429       }
1430 
1431       // nvidia color-per-face-bug workaround
1432       if ((AttributeBinding)MaterialBinding == PER_FACE) {
1433         materials->send(matnr-1, TRUE);
1434       } else if ((AttributeBinding)MaterialBinding == PER_FACE_INDEXED) {
1435         materials->send(matindices[-1], TRUE);
1436       }
1437 
1438       if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1439         currnormal = normals++;
1440         glNormal3fv((const GLfloat*)currnormal);
1441       } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1442         currnormal = &normals[*normalindices++];
1443         glNormal3fv((const GLfloat*)currnormal);
1444       }
1445 
1446       if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX) {
1447        attribs->send(attribnr++);
1448       } else if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX_INDEXED) {
1449         attribs->send(*vertexindices++);
1450       }
1451 
1452       if (dotexture) {
1453         texcoords->send(texindices ? *texindices++ : texidx++,
1454                         vertexlist->get3(v2),
1455                         *currnormal);
1456       }
1457 
1458       SEND_VERTEX(v2);
1459 
1460       /* vertex 3 *********************************************************/
1461       if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1462         materials->send(matnr++, TRUE);
1463       } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1464         materials->send(*matindices++, TRUE);
1465       }
1466 
1467       // nvidia color-per-face-bug workaround
1468       if ((AttributeBinding)MaterialBinding == PER_FACE) {
1469         materials->send(matnr-1, TRUE);
1470       } else if ((AttributeBinding)MaterialBinding == PER_FACE_INDEXED) {
1471         materials->send(matindices[-1], TRUE);
1472       }
1473 
1474       if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1475         currnormal = normals++;
1476         glNormal3fv((const GLfloat*)currnormal);
1477       } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1478         currnormal = &normals[*normalindices++];
1479         glNormal3fv((const GLfloat*)currnormal);
1480       }
1481 
1482       if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX) {
1483        attribs->send(attribnr++);
1484       } else if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX_INDEXED) {
1485         attribs->send(*vertexindices++);
1486       }
1487 
1488       if (dotexture) {
1489         texcoords->send(texindices ? *texindices++ : texidx++,
1490                         vertexlist->get3(v3),
1491                         *currnormal);
1492       }
1493 
1494       SEND_VERTEX(v3);
1495 
1496       if (mode != GL_TRIANGLES) {
1497         /* vertex 4 (quad or polygon)**************************************/
1498         if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1499           materials->send(matnr++, TRUE);
1500         } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1501           materials->send(*matindices++, TRUE);
1502         }
1503 
1504         // nvidia color-per-face-bug workaround
1505         if ((AttributeBinding)MaterialBinding == PER_FACE) {
1506           materials->send(matnr-1, TRUE);
1507         } else if ((AttributeBinding)MaterialBinding == PER_FACE_INDEXED) {
1508           materials->send(matindices[-1], TRUE);
1509         }
1510 
1511         if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1512           currnormal = normals++;
1513           glNormal3fv((const GLfloat*)currnormal);
1514         } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1515           currnormal = &normals[*normalindices++];
1516           glNormal3fv((const GLfloat*)currnormal);
1517         }
1518 
1519         if (dotexture) {
1520           texcoords->send(texindices ? *texindices++ : texidx++,
1521                           vertexlist->get3(v4),
1522                           *currnormal);
1523         }
1524 
1525         if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX) {
1526           attribs->send(attribnr++);
1527         }
1528         else if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX_INDEXED) {
1529           attribs->send(*vertexindices++);
1530         }
1531         SEND_VERTEX(v4);
1532 
1533         if (mode == GL_POLYGON) {
1534           /* vertex 5 (polygon) ********************************************/
1535           if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1536             materials->send(matnr++, TRUE);
1537           } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1538             materials->send(*matindices++, TRUE);
1539           }
1540 
1541           // nvidia color-per-face-bug workaround
1542           if ((AttributeBinding)MaterialBinding == PER_FACE) {
1543             materials->send(matnr-1, TRUE);
1544           } else if ((AttributeBinding)MaterialBinding == PER_FACE_INDEXED) {
1545             materials->send(matindices[-1], TRUE);
1546           }
1547 
1548           if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1549             currnormal = normals++;
1550             glNormal3fv((const GLfloat*)currnormal);
1551           } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1552             currnormal = &normals[*normalindices++];
1553             glNormal3fv((const GLfloat*)currnormal);
1554           }
1555 
1556           if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX) {
1557             attribs->send(attribnr++);
1558           } else if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX_INDEXED) {
1559             attribs->send(*vertexindices++);
1560           }
1561 
1562           if (dotexture) {
1563             texcoords->send(texindices ? *texindices++ : texidx++,
1564                             vertexlist->get3(v5),
1565                             *currnormal);
1566 
1567           }
1568 
1569           SEND_VERTEX(v5);
1570 
1571           v1 = viptr < viendptr ? *viptr++ : -1;
1572           while (v1 >= 0) {
1573             // For robustness upon buggy data sets
1574             if (v1 >= numverts) {
1575               if (current_errors < 1) {
1576                 SoDebugError::postWarning("[faceset]::GLRender", "Erroneous polygon detected. "
1577                                           "(offset: %d, [... %d]). Should be within "
1578                                           "[0, %d] This message will only be shown once, but "
1579                                           "more errors might be present",
1580                                           viptr - vistartptr - 1, v1, numverts - 1);
1581               }
1582               current_errors++;
1583               break;
1584             }
1585 
1586             /* vertex 6-n (polygon) *****************************************/
1587             if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1588               materials->send(matnr++, TRUE);
1589             } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1590               materials->send(*matindices++, TRUE);
1591             }
1592 
1593             // nvidia color-per-face-bug workaround
1594             if ((AttributeBinding)MaterialBinding == PER_FACE) {
1595               materials->send(matnr-1, TRUE);
1596             } else if ((AttributeBinding)MaterialBinding == PER_FACE_INDEXED) {
1597               materials->send(matindices[-1], TRUE);
1598             }
1599 
1600             if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1601               currnormal = normals++;
1602               glNormal3fv((const GLfloat*)currnormal);
1603             } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1604               currnormal = &normals[*normalindices++];
1605               glNormal3fv((const GLfloat*)currnormal);
1606             }
1607 
1608             if (dotexture) {
1609               texcoords->send(texindices ? *texindices++ : texidx++,
1610                               vertexlist->get3(v1),
1611                               *currnormal);
1612             }
1613 
1614             if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX) {
1615               attribs->send(attribnr++);
1616             } else if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX_INDEXED) {
1617               attribs->send(*vertexindices++);
1618             }
1619             SEND_VERTEX(v1);
1620 
1621             v1 = viptr < viendptr ? *viptr++ : -1;
1622           }
1623           glEnd(); /* draw polygon */
1624         }
1625       }
1626 
1627       if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1628         matindices++;
1629       }
1630       if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1631         normalindices++;
1632       }
1633       if ((AttributeBinding)VertexAttributeBinding == PER_VERTEX_INDEXED) {
1634         vertexindices++;
1635       }
1636 
1637       if (dotexture) {
1638         if (texindices) texindices++;
1639       }
1640     }
1641     // check if triangle or quad
1642     if (mode != GL_POLYGON) glEnd();
1643   }
1644 
1645 } } } // namespace
1646 
1647 #define SOGL_FACESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, vertexattributebinding, args) \
1648   SoGL::FaceSet::GLRender<normalbinding, materialbinding, vertexattributebinding> args
1649 
1650 #define SOGL_FACESET_GLRENDER_RESOLVE_ARG3(normalbinding, materialbinding, vertexattributebinding, args) \
1651   switch (vertexattributebinding) { \
1652   case SoGL::FaceSet::OVERALL: \
1653     SOGL_FACESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, SoGL::FaceSet::OVERALL, args); \
1654     break; \
1655   case SoGL::FaceSet::PER_FACE: \
1656     SOGL_FACESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, SoGL::FaceSet::OVERALL, args); \
1657     break; \
1658   case SoGL::FaceSet::PER_FACE_INDEXED: \
1659     SOGL_FACESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, SoGL::FaceSet::OVERALL, args); \
1660     break; \
1661   case SoGL::FaceSet::PER_VERTEX: \
1662     SOGL_FACESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, SoGL::FaceSet::PER_VERTEX, args); \
1663     break; \
1664   case SoGL::FaceSet::PER_VERTEX_INDEXED: \
1665     SOGL_FACESET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, SoGL::FaceSet::PER_VERTEX_INDEXED, args); \
1666     break; \
1667   default: \
1668     assert(!"invalid vertex attribute binding argument"); \
1669   }
1670 
1671 #define SOGL_FACESET_GLRENDER_RESOLVE_ARG2(normalbinding, materialbinding, vertexattributebinding, args) \
1672   switch (materialbinding) { \
1673   case SoGL::FaceSet::OVERALL: \
1674     SOGL_FACESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::FaceSet::OVERALL, vertexattributebinding, args); \
1675     break; \
1676   case SoGL::FaceSet::PER_FACE: \
1677     SOGL_FACESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::FaceSet::PER_FACE, vertexattributebinding, args); \
1678     break; \
1679   case SoGL::FaceSet::PER_FACE_INDEXED: \
1680     SOGL_FACESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::FaceSet::PER_FACE_INDEXED, vertexattributebinding, args); \
1681     break; \
1682   case SoGL::FaceSet::PER_VERTEX: \
1683     SOGL_FACESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::FaceSet::PER_VERTEX, vertexattributebinding, args); \
1684     break; \
1685   case SoGL::FaceSet::PER_VERTEX_INDEXED: \
1686     SOGL_FACESET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::FaceSet::PER_VERTEX_INDEXED, vertexattributebinding, args); \
1687     break; \
1688   default: \
1689     assert(!"invalid material binding argument"); \
1690   }
1691 
1692 #define SOGL_FACESET_GLRENDER_RESOLVE_ARG1(normalbinding, materialbinding, vertexattributebinding, args) \
1693   switch (normalbinding) { \
1694   case SoGL::FaceSet::OVERALL: \
1695     SOGL_FACESET_GLRENDER_RESOLVE_ARG2(SoGL::FaceSet::OVERALL, materialbinding, vertexattributebinding, args); \
1696     break; \
1697   case SoGL::FaceSet::PER_FACE: \
1698     SOGL_FACESET_GLRENDER_RESOLVE_ARG2(SoGL::FaceSet::PER_FACE, materialbinding, vertexattributebinding, args); \
1699     break; \
1700   case SoGL::FaceSet::PER_FACE_INDEXED: \
1701     SOGL_FACESET_GLRENDER_RESOLVE_ARG2(SoGL::FaceSet::PER_FACE_INDEXED, materialbinding, vertexattributebinding, args); \
1702     break; \
1703   case SoGL::FaceSet::PER_VERTEX: \
1704     SOGL_FACESET_GLRENDER_RESOLVE_ARG2(SoGL::FaceSet::PER_VERTEX, materialbinding, vertexattributebinding, args); \
1705     break; \
1706   case SoGL::FaceSet::PER_VERTEX_INDEXED: \
1707     SOGL_FACESET_GLRENDER_RESOLVE_ARG2(SoGL::FaceSet::PER_VERTEX_INDEXED, materialbinding, vertexattributebinding, args); \
1708     break; \
1709   default: \
1710     assert(!"invalid normal binding argument"); \
1711   }
1712 
1713 #define SOGL_FACESET_GLRENDER(normalbinding, materialbinding, vertexattributebinding, args) \
1714   SOGL_FACESET_GLRENDER_RESOLVE_ARG1(normalbinding, materialbinding, vertexattributebinding, args)
1715 
1716 
1717 void
sogl_render_faceset(const SoGLCoordinateElement * const vertexlist,const int32_t * vertexindices,int num_vertexindices,const SbVec3f * normals,const int32_t * normindices,SoMaterialBundle * const materials,const int32_t * matindices,SoTextureCoordinateBundle * const texcoords,const int32_t * texindices,SoVertexAttributeBundle * const attribs,const int nbind,const int mbind,const int attribbind,const int dotexture,const int doattribs)1718 sogl_render_faceset(const SoGLCoordinateElement * const vertexlist,
1719                     const int32_t *vertexindices,
1720                     int num_vertexindices,
1721                     const SbVec3f *normals,
1722                     const int32_t *normindices,
1723                     SoMaterialBundle *const materials,
1724                     const int32_t *matindices,
1725                     SoTextureCoordinateBundle * const texcoords,
1726                     const int32_t *texindices,
1727                     SoVertexAttributeBundle * const attribs,
1728                     const int nbind,
1729                     const int mbind,
1730                     const int attribbind,
1731                     const int dotexture,
1732                     const int doattribs)
1733 {
1734   SOGL_FACESET_GLRENDER(nbind, mbind, attribbind, (vertexlist,
1735                                                    vertexindices,
1736                                                    num_vertexindices,
1737                                                    normals,
1738                                                    normindices,
1739                                                    materials,
1740                                                    matindices,
1741                                                    texcoords,
1742                                                    texindices,
1743                                                    attribs,
1744                                                    dotexture,
1745                                                    doattribs));
1746 }
1747 
1748 #undef SOGL_FACESET_GLRENDER
1749 #undef SOGL_FACESET_GLRENDER_RESOLVE_ARG1
1750 #undef SOGL_FACESET_GLRENDER_RESOLVE_ARG2
1751 #undef SOGL_FACESET_GLRENDER_RESOLVE_ARG3
1752 #undef SOGL_FACESET_GLRENDER_RESOLVE_ARG4
1753 #undef SOGL_FACESET_GLRENDER_CALL_FUNC
1754 
1755 #endif // !NO_FACESET_RENDER
1756 
1757 // **************************************************************************
1758 
1759 //typedef void sogl_render_faceset_func(const SoGLCoordinateElement * const coords,
1760 //                                      const int32_t *vertexindices,
1761 //                                      int num_vertexindices,
1762 //                                      const SbVec3f *normals,
1763 //                                      const int32_t *normindices,
1764 //                                      SoMaterialBundle *materials,
1765 //                                      const int32_t *matindices,
1766 //                                      const SoTextureCoordinateBundle * const texcoords,
1767 //                                      const int32_t *texindices);
1768 
1769 #if !defined(NO_TRISTRIPSET_RENDER)
1770 
1771 namespace { namespace SoGL { namespace TriStripSet {
1772 
1773   enum AttributeBinding {
1774     OVERALL = 0,
1775     PER_STRIP = 1,
1776     PER_STRIP_INDEXED = 2,
1777     PER_TRIANGLE = 3,
1778     PER_TRIANGLE_INDEXED = 4,
1779     PER_VERTEX = 5,
1780     PER_VERTEX_INDEXED = 6
1781   };
1782 
1783   template < int NormalBinding,
1784              int MaterialBinding,
1785              int TexturingEnabled >
GLRender(const SoGLCoordinateElement * const vertexlist,const int32_t * vertexindices,int numindices,const SbVec3f * normals,const int32_t * normalindices,SoMaterialBundle * materials,const int32_t * matindices,const SoTextureCoordinateBundle * const texcoords,const int32_t * texindices)1786   static void GLRender(const SoGLCoordinateElement * const vertexlist,
1787                        const int32_t *vertexindices,
1788                        int numindices,
1789                        const SbVec3f *normals,
1790                        const int32_t *normalindices,
1791                        SoMaterialBundle *materials,
1792                        const int32_t *matindices,
1793                        const SoTextureCoordinateBundle * const texcoords,
1794                        const int32_t *texindices)
1795   {
1796 
1797     // just in case someone forgot...
1798     if (matindices == NULL) matindices = vertexindices;
1799     if (normalindices == NULL) normalindices = vertexindices;
1800 
1801     int texidx = 0;
1802     const int32_t *viptr = vertexindices;
1803     const int32_t *vistartptr = vertexindices;
1804     const int32_t *viendptr = viptr + numindices;
1805     int32_t v1, v2, v3;
1806     int numverts = vertexlist->getNum();
1807 
1808     const SbVec3f * coords3d = NULL;
1809     const SbVec4f * coords4d = NULL;
1810     const SbBool is3d = vertexlist->is3D();
1811     if (is3d) {
1812       coords3d = vertexlist->getArrayPtr3();
1813     }
1814     else {
1815       coords4d = vertexlist->getArrayPtr4();
1816     }
1817 
1818     // This is the same code as in SoGLCoordinateElement::send().
1819     // It is inlined here for speed (~15% speed increase).
1820 #define SEND_VERTEX_TRISTRIP(_idx_) \
1821     if (is3d) glVertex3fv((const GLfloat*) (coords3d + _idx_)); \
1822     else glVertex4fv((const GLfloat*) (coords4d + _idx_));
1823 
1824     if ((AttributeBinding)NormalBinding == PER_VERTEX ||
1825         (AttributeBinding)NormalBinding == PER_TRIANGLE ||
1826         (AttributeBinding)NormalBinding == PER_STRIP ||
1827         (AttributeBinding)NormalBinding == PER_VERTEX_INDEXED ||
1828         (AttributeBinding)NormalBinding == PER_TRIANGLE_INDEXED ||
1829         (AttributeBinding)NormalBinding == PER_STRIP_INDEXED) {
1830       assert(normals && "Aborting rendering of tristrip; got NULL normals");
1831     }
1832 
1833     SbVec3f dummynormal(0.0f, 0.0f, 1.0f);
1834     const SbVec3f *currnormal = &dummynormal;
1835 
1836     if ((AttributeBinding)NormalBinding == PER_VERTEX ||
1837         (AttributeBinding)NormalBinding == PER_TRIANGLE ||
1838         (AttributeBinding)NormalBinding == PER_STRIP ||
1839         (AttributeBinding)NormalBinding == PER_VERTEX_INDEXED ||
1840         (AttributeBinding)NormalBinding == PER_TRIANGLE_INDEXED ||
1841         (AttributeBinding)NormalBinding == PER_STRIP_INDEXED ||
1842         TexturingEnabled == TRUE) {
1843       if (normals) currnormal = normals;
1844     }
1845 
1846     int matnr = 0;
1847 
1848     while (viptr + 2 < viendptr) {
1849       v1 = *viptr++;
1850       v2 = *viptr++;
1851       v3 = *viptr++;
1852 
1853       // This should be here to prevent illegal polygons from being rendered
1854       if (v1 < 0 || v2 < 0 || v3 < 0 ||
1855           v1 >= numverts || v2 >= numverts || v3 >= numverts) {
1856 
1857         static uint32_t current_errors = 0;
1858         if (current_errors < 1) {
1859           SoDebugError::postWarning("[tristrip]::GLRender", "Erroneous polygon detected. "
1860                                     "Ignoring (offset: %d, [%d %d %d]). Should be within "
1861                                     " [0, %d] This message will only be shown once, but "
1862                                     "more errors may be present",
1863                                     viptr - vistartptr - 3, v1, v2, v3, numverts - 1);
1864         }
1865 
1866         current_errors++;
1867         break;
1868       }
1869 
1870       glBegin(GL_TRIANGLE_STRIP);
1871 
1872       /* vertex 1 *********************************************************/
1873       if ((AttributeBinding)MaterialBinding == PER_VERTEX ||
1874           (AttributeBinding)MaterialBinding == PER_STRIP ||
1875           (AttributeBinding)MaterialBinding == PER_TRIANGLE) {
1876         materials->send(matnr++, TRUE);
1877       } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED ||
1878                  (AttributeBinding)MaterialBinding == PER_STRIP_INDEXED ||
1879                  (AttributeBinding)MaterialBinding == PER_TRIANGLE_INDEXED) {
1880         materials->send(*matindices++, TRUE);
1881       }
1882       if ((AttributeBinding)NormalBinding == PER_VERTEX ||
1883           (AttributeBinding)NormalBinding == PER_STRIP ||
1884           (AttributeBinding)NormalBinding == PER_TRIANGLE) {
1885         currnormal = normals++;
1886         glNormal3fv((const GLfloat*)currnormal);
1887       } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED ||
1888                  (AttributeBinding)NormalBinding == PER_TRIANGLE_INDEXED ||
1889                  (AttributeBinding)NormalBinding == PER_STRIP_INDEXED) {
1890         currnormal = &normals[*normalindices++];
1891         glNormal3fv((const GLfloat*)currnormal);
1892       }
1893       if (TexturingEnabled == TRUE) {
1894         texcoords->send(texindices ? *texindices++ : texidx++,
1895                         vertexlist->get3(v1),
1896                         *currnormal);
1897       }
1898       SEND_VERTEX_TRISTRIP(v1);
1899 
1900       /* vertex 2 *********************************************************/
1901       if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1902         materials->send(matnr++, TRUE);
1903       } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1904         materials->send(*matindices++, TRUE);
1905       }
1906 
1907       // needed for nvidia color-per-face-bug workaround
1908       if ((AttributeBinding)MaterialBinding == PER_TRIANGLE ||
1909           (AttributeBinding)MaterialBinding == PER_STRIP) {
1910         materials->send(matnr-1, TRUE);
1911       } else if ((AttributeBinding)MaterialBinding == PER_TRIANGLE_INDEXED ||
1912                  (AttributeBinding)MaterialBinding == PER_STRIP_INDEXED) {
1913         materials->send(matindices[-1], TRUE);
1914       }
1915       // end of nvidia workaround
1916 
1917       if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1918         currnormal = normals++;
1919         glNormal3fv((const GLfloat*)currnormal);
1920       } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1921         currnormal = &normals[*normalindices++];
1922         glNormal3fv((const GLfloat*)currnormal);
1923       }
1924       if (TexturingEnabled == TRUE) {
1925         texcoords->send(texindices ? *texindices++ : texidx++,
1926                         vertexlist->get3(v2),
1927                         *currnormal);
1928       }
1929       SEND_VERTEX_TRISTRIP(v2);
1930 
1931       /* vertex 3 *********************************************************/
1932       if ((AttributeBinding)MaterialBinding == PER_VERTEX) {
1933         materials->send(matnr++, TRUE);
1934       } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
1935         materials->send(*matindices++, TRUE);
1936       }
1937 
1938       // needed for nvidia color-per-face-bug workaround
1939       if ((AttributeBinding)MaterialBinding == PER_STRIP ||
1940           (AttributeBinding)MaterialBinding == PER_TRIANGLE) {
1941         materials->send(matnr-1, TRUE);
1942       } else if ((AttributeBinding)MaterialBinding == PER_TRIANGLE_INDEXED ||
1943                  (AttributeBinding)MaterialBinding == PER_STRIP_INDEXED) {
1944         materials->send(matindices[-1], TRUE);
1945       }
1946       // end of nvidia workaround
1947 
1948       if ((AttributeBinding)NormalBinding == PER_VERTEX) {
1949         currnormal = normals++;
1950         glNormal3fv((const GLfloat*)currnormal);
1951       } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
1952         currnormal = &normals[*normalindices++];
1953         glNormal3fv((const GLfloat*)currnormal);
1954       }
1955       if (TexturingEnabled == TRUE) {
1956         texcoords->send(texindices ? *texindices++ : texidx++,
1957                         vertexlist->get3(v3),
1958                         *currnormal);
1959       }
1960       SEND_VERTEX_TRISTRIP(v3);
1961 
1962       v1 = viptr < viendptr ? *viptr++ : -1;
1963       while (v1 >= 0) {
1964         if ((AttributeBinding)MaterialBinding == PER_VERTEX ||
1965             (AttributeBinding)MaterialBinding == PER_TRIANGLE) {
1966           materials->send(matnr++, TRUE);
1967         } else if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED ||
1968                    (AttributeBinding)MaterialBinding == PER_TRIANGLE_INDEXED) {
1969           materials->send(*matindices++, TRUE);
1970         }
1971 
1972         // needed for nvidia color-per-face-bug workaround
1973         if ((AttributeBinding)MaterialBinding == PER_STRIP) {
1974           materials->send(matnr-1, TRUE);
1975         } else if ((AttributeBinding)MaterialBinding == PER_STRIP_INDEXED) {
1976           materials->send(matindices[-1], TRUE);
1977         }
1978         // end of nvidia workaround
1979 
1980         if ((AttributeBinding)NormalBinding == PER_VERTEX ||
1981             (AttributeBinding)NormalBinding == PER_TRIANGLE) {
1982           currnormal = normals++;
1983           glNormal3fv((const GLfloat*)currnormal);
1984         } else if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED ||
1985                    (AttributeBinding)NormalBinding == PER_TRIANGLE_INDEXED) {
1986           currnormal = &normals[*normalindices++];
1987           glNormal3fv((const GLfloat*)currnormal);
1988         }
1989         if (TexturingEnabled == TRUE) {
1990           texcoords->send(texindices ? *texindices++ : texidx++,
1991                           vertexlist->get3(v1),
1992                           *currnormal);
1993         }
1994 
1995         SEND_VERTEX_TRISTRIP(v1);
1996         v1 = viptr < viendptr ? *viptr++ : -1;
1997       }
1998       glEnd(); // end of tristrip
1999 
2000       if ((AttributeBinding)MaterialBinding == PER_VERTEX_INDEXED) {
2001         matindices++;
2002       }
2003       if ((AttributeBinding)NormalBinding == PER_VERTEX_INDEXED) {
2004         normalindices++;
2005       }
2006       if (TexturingEnabled == TRUE) {
2007         if (texindices) texindices++;
2008       }
2009     }
2010   }
2011 
2012 } } } // namespace
2013 
2014 #define SOGL_TRISTRIPSET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, texturing, args) \
2015   SoGL::TriStripSet::GLRender<normalbinding, materialbinding, texturing> args
2016 
2017 #define SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, materialbinding, texturing, args) \
2018   if (texturing) { \
2019     SOGL_TRISTRIPSET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, TRUE, args); \
2020   } else { \
2021     SOGL_TRISTRIPSET_GLRENDER_CALL_FUNC(normalbinding, materialbinding, FALSE, args); \
2022   }
2023 
2024 #define SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(normalbinding, materialbinding, texturing, args) \
2025   switch (materialbinding) { \
2026   case SoGL::TriStripSet::OVERALL: \
2027     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::TriStripSet::OVERALL, texturing, args); \
2028     break; \
2029   case SoGL::TriStripSet::PER_STRIP: \
2030     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::TriStripSet::PER_STRIP, texturing, args); \
2031     break; \
2032   case SoGL::TriStripSet::PER_STRIP_INDEXED: \
2033     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::TriStripSet::PER_STRIP_INDEXED, texturing, args); \
2034     break; \
2035   case SoGL::TriStripSet::PER_TRIANGLE: \
2036     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::TriStripSet::PER_TRIANGLE, texturing, args); \
2037     break; \
2038   case SoGL::TriStripSet::PER_TRIANGLE_INDEXED: \
2039     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::TriStripSet::PER_TRIANGLE_INDEXED, texturing, args); \
2040     break; \
2041   case SoGL::IndexedLineSet::PER_VERTEX: \
2042     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::TriStripSet::PER_VERTEX, texturing, args); \
2043     break; \
2044   case SoGL::IndexedLineSet::PER_VERTEX_INDEXED: \
2045     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3(normalbinding, SoGL::TriStripSet::PER_VERTEX_INDEXED, texturing, args); \
2046     break; \
2047   default: \
2048     assert(!"invalid material binding argument"); \
2049   }
2050 
2051 #define SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG1(normalbinding, materialbinding, texturing, args) \
2052   switch (normalbinding) { \
2053   case SoGL::TriStripSet::OVERALL: \
2054     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(SoGL::TriStripSet::OVERALL, materialbinding, texturing, args); \
2055     break; \
2056   case SoGL::TriStripSet::PER_STRIP: \
2057     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(SoGL::TriStripSet::PER_STRIP, materialbinding, texturing, args); \
2058     break; \
2059   case SoGL::TriStripSet::PER_STRIP_INDEXED: \
2060     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(SoGL::TriStripSet::PER_STRIP_INDEXED, materialbinding, texturing, args); \
2061     break; \
2062   case SoGL::TriStripSet::PER_TRIANGLE: \
2063     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(SoGL::TriStripSet::PER_TRIANGLE, materialbinding, texturing, args); \
2064     break; \
2065   case SoGL::TriStripSet::PER_TRIANGLE_INDEXED: \
2066     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(SoGL::TriStripSet::PER_TRIANGLE_INDEXED, materialbinding, texturing, args); \
2067     break; \
2068   case SoGL::TriStripSet::PER_VERTEX: \
2069     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(SoGL::TriStripSet::PER_VERTEX, materialbinding, texturing, args); \
2070     break; \
2071   case SoGL::TriStripSet::PER_VERTEX_INDEXED: \
2072     SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2(SoGL::TriStripSet::PER_VERTEX_INDEXED, materialbinding, texturing, args); \
2073     break; \
2074   default: \
2075     assert(!"invalid normal binding argument"); \
2076   }
2077 
2078 #define SOGL_TRISTRIPSET_GLRENDER(normalbinding, materialbinding, texturing, args) \
2079   SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG1(normalbinding, materialbinding, texturing, args)
2080 
2081 void
sogl_render_tristrip(const SoGLCoordinateElement * const vertexlist,const int32_t * vertexindices,int num_vertexindices,const SbVec3f * normals,const int32_t * normindices,SoMaterialBundle * const materials,const int32_t * matindices,const SoTextureCoordinateBundle * const texcoords,const int32_t * texindices,const int nbind,const int mbind,const int texture)2082 sogl_render_tristrip(const SoGLCoordinateElement * const vertexlist,
2083                      const int32_t *vertexindices,
2084                      int num_vertexindices,
2085                      const SbVec3f *normals,
2086                      const int32_t *normindices,
2087                      SoMaterialBundle *const materials,
2088                      const int32_t *matindices,
2089                      const SoTextureCoordinateBundle * const texcoords,
2090                      const int32_t *texindices,
2091                      const int nbind,
2092                      const int mbind,
2093                      const int texture)
2094 {
2095   SOGL_TRISTRIPSET_GLRENDER(nbind, mbind, texture, (vertexlist,
2096                                                     vertexindices,
2097                                                     num_vertexindices,
2098                                                     normals,
2099                                                     normindices,
2100                                                     materials,
2101                                                     matindices,
2102                                                     texcoords,
2103                                                     texindices));
2104 }
2105 
2106 #undef SOGL_TRISTRIPSET_GLRENDER_CALL_FUNC
2107 #undef SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG1
2108 #undef SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG2
2109 #undef SOGL_TRISTRIPSET_GLRENDER_RESOLVE_ARG3
2110 #undef SOGL_TRISTRIPSET_GLRENDER
2111 
2112 #endif // !NO_TRISTRIPSET_RENDER
2113 
2114 
2115 // PointSet rendering
2116 // here we include the 8 variations directly...
2117 
2118 static void
sogl_render_pointset_m0n0t0(const SoGLCoordinateElement * coords,const SbVec3f * COIN_UNUSED_ARG (normals),SoMaterialBundle * COIN_UNUSED_ARG (mb),const SoTextureCoordinateBundle * COIN_UNUSED_ARG (tb),int32_t numpts,int32_t idx)2119 sogl_render_pointset_m0n0t0(const SoGLCoordinateElement * coords,
2120                             const SbVec3f * COIN_UNUSED_ARG(normals),
2121                             SoMaterialBundle * COIN_UNUSED_ARG(mb),
2122                             const SoTextureCoordinateBundle * COIN_UNUSED_ARG(tb),
2123                             int32_t numpts,
2124                             int32_t idx)
2125 {
2126   int i;
2127   const int unroll = numpts >> 2;
2128   const int rest = numpts & 3;
2129 
2130   // manually unroll this common loop
2131 
2132   glBegin(GL_POINTS);
2133   for (i = 0; i < unroll; i++) {
2134     coords->send(idx++);
2135     coords->send(idx++);
2136     coords->send(idx++);
2137     coords->send(idx++);
2138   }
2139   for (i = 0; i < rest; i++) {
2140     coords->send(idx++);
2141   }
2142   glEnd();
2143 }
2144 
2145 static void
sogl_render_pointset_m0n0t1(const SoGLCoordinateElement * coords,const SbVec3f * COIN_UNUSED_ARG (normals),SoMaterialBundle * COIN_UNUSED_ARG (mb),const SoTextureCoordinateBundle * tb,int32_t numpts,int32_t idx)2146 sogl_render_pointset_m0n0t1(const SoGLCoordinateElement * coords,
2147                             const SbVec3f * COIN_UNUSED_ARG(normals),
2148                             SoMaterialBundle * COIN_UNUSED_ARG(mb),
2149                             const SoTextureCoordinateBundle * tb,
2150                             int32_t numpts,
2151                             int32_t idx)
2152 {
2153   int texnr = 0;
2154   const SbVec3f currnormal(0.0f,0.0f,1.0f);
2155 
2156   glBegin(GL_POINTS);
2157   for (int i = 0; i < numpts; i++) {
2158     tb->send(texnr++, coords->get3(idx), currnormal);
2159     coords->send(idx++);
2160   }
2161   glEnd();
2162 }
2163 
2164 static void
sogl_render_pointset_m0n1t0(const SoGLCoordinateElement * coords,const SbVec3f * normals,SoMaterialBundle * COIN_UNUSED_ARG (mb),const SoTextureCoordinateBundle * COIN_UNUSED_ARG (tb),int32_t numpts,int32_t idx)2165 sogl_render_pointset_m0n1t0(const SoGLCoordinateElement * coords,
2166                             const SbVec3f * normals,
2167                             SoMaterialBundle * COIN_UNUSED_ARG(mb),
2168                             const SoTextureCoordinateBundle * COIN_UNUSED_ARG(tb),
2169                             int32_t numpts,
2170                             int32_t idx)
2171 {
2172   glBegin(GL_POINTS);
2173   for (int i = 0; i < numpts; i++) {
2174     glNormal3fv((const GLfloat*)normals++);
2175     coords->send(idx++);
2176   }
2177   glEnd();
2178 }
2179 
2180 static void
sogl_render_pointset_m0n1t1(const SoGLCoordinateElement * coords,const SbVec3f * normals,SoMaterialBundle * COIN_UNUSED_ARG (mb),const SoTextureCoordinateBundle * tb,int32_t numpts,int32_t idx)2181 sogl_render_pointset_m0n1t1(const SoGLCoordinateElement * coords,
2182                             const SbVec3f * normals,
2183                             SoMaterialBundle * COIN_UNUSED_ARG(mb),
2184                             const SoTextureCoordinateBundle * tb,
2185                             int32_t numpts,
2186                             int32_t idx)
2187 {
2188   int texnr = 0;
2189   const SbVec3f currnormal(0.0f,0.0f,1.0f);
2190 
2191   glBegin(GL_POINTS);
2192   for (int i = 0; i < numpts; i++) {
2193     glNormal3fv((const GLfloat*)normals++);
2194     tb->send(texnr++, coords->get3(idx), currnormal);
2195     coords->send(idx++);
2196   }
2197   glEnd();
2198 }
2199 
2200 static void
sogl_render_pointset_m1n0t0(const SoGLCoordinateElement * coords,const SbVec3f * COIN_UNUSED_ARG (normals),SoMaterialBundle * mb,const SoTextureCoordinateBundle * COIN_UNUSED_ARG (tb),int32_t numpts,int32_t idx)2201 sogl_render_pointset_m1n0t0(const SoGLCoordinateElement * coords,
2202                             const SbVec3f * COIN_UNUSED_ARG(normals),
2203                             SoMaterialBundle * mb,
2204                             const SoTextureCoordinateBundle * COIN_UNUSED_ARG(tb),
2205                             int32_t numpts,
2206                             int32_t idx)
2207 {
2208   int i;
2209   int matnr = 0;
2210   const int unroll = numpts >> 2;
2211   const int rest = numpts & 3;
2212 
2213   // manually unroll this common loop
2214 
2215   glBegin(GL_POINTS);
2216   for (i = 0; i < unroll; i++) {
2217     mb->send(matnr++, TRUE);
2218     coords->send(idx++);
2219     mb->send(matnr++, TRUE);
2220     coords->send(idx++);
2221     mb->send(matnr++, TRUE);
2222     coords->send(idx++);
2223     mb->send(matnr++, TRUE);
2224     coords->send(idx++);
2225   }
2226   for (i = 0; i < rest; i++) {
2227     mb->send(matnr++, TRUE);
2228     coords->send(idx++);
2229   }
2230   glEnd();
2231 }
2232 
2233 static void
sogl_render_pointset_m1n0t1(const SoGLCoordinateElement * coords,const SbVec3f * COIN_UNUSED_ARG (normals),SoMaterialBundle * mb,const SoTextureCoordinateBundle * tb,int32_t numpts,int32_t idx)2234 sogl_render_pointset_m1n0t1(const SoGLCoordinateElement * coords,
2235                             const SbVec3f * COIN_UNUSED_ARG(normals),
2236                             SoMaterialBundle * mb,
2237                             const SoTextureCoordinateBundle * tb,
2238                             int32_t numpts,
2239                             int32_t idx)
2240 {
2241   int matnr = 0;
2242   int texnr = 0;
2243   const SbVec3f currnormal(0.0f,0.0f,1.0f);
2244 
2245   glBegin(GL_POINTS);
2246   for (int i = 0; i < numpts; i++) {
2247     mb->send(matnr++, TRUE);
2248     tb->send(texnr++, coords->get3(idx), currnormal);
2249     coords->send(idx++);
2250   }
2251   glEnd();
2252 }
2253 
2254 static void
sogl_render_pointset_m1n1t0(const SoGLCoordinateElement * coords,const SbVec3f * normals,SoMaterialBundle * mb,const SoTextureCoordinateBundle * COIN_UNUSED_ARG (tb),int32_t numpts,int32_t idx)2255 sogl_render_pointset_m1n1t0(const SoGLCoordinateElement * coords,
2256                             const SbVec3f * normals,
2257                             SoMaterialBundle * mb,
2258                             const SoTextureCoordinateBundle * COIN_UNUSED_ARG(tb),
2259                             int32_t numpts,
2260                             int32_t idx)
2261 {
2262   int matnr = 0;
2263 
2264   glBegin(GL_POINTS);
2265   for (int i = 0; i < numpts; i++) {
2266     mb->send(matnr++, TRUE);
2267     glNormal3fv((const GLfloat*)normals++);
2268     coords->send(idx++);
2269   }
2270   glEnd();
2271 }
2272 
2273 static void
sogl_render_pointset_m1n1t1(const SoGLCoordinateElement * coords,const SbVec3f * normals,SoMaterialBundle * mb,const SoTextureCoordinateBundle * tb,int32_t numpts,int32_t idx)2274 sogl_render_pointset_m1n1t1(const SoGLCoordinateElement * coords,
2275                             const SbVec3f * normals,
2276                             SoMaterialBundle * mb,
2277                             const SoTextureCoordinateBundle * tb,
2278                             int32_t numpts,
2279                             int32_t idx)
2280 {
2281   int texnr = 0;
2282   int matnr = 0;
2283 
2284   glBegin(GL_POINTS);
2285   for (int i = 0; i < numpts; i++) {
2286     mb->send(matnr++, TRUE);
2287     tb->send(texnr++, coords->get3(idx), *normals);
2288     glNormal3fv((const GLfloat*)normals++);
2289     coords->send(idx++);
2290   }
2291   glEnd();
2292 }
2293 
2294 // ---
2295 
2296 typedef void sogl_render_pointset_func(const SoGLCoordinateElement * coords,
2297                                        const SbVec3f * normals,
2298                                        SoMaterialBundle * mb,
2299                                        const SoTextureCoordinateBundle * tb,
2300                                        int32_t numpts,
2301                                        int32_t idx);
2302 
2303 static sogl_render_pointset_func * sogl_render_pointset_funcs[8];
2304 
2305 void
sogl_render_pointset(const SoGLCoordinateElement * coords,const SbVec3f * normals,SoMaterialBundle * mb,const SoTextureCoordinateBundle * tb,int32_t numpts,int32_t idx)2306 sogl_render_pointset(const SoGLCoordinateElement * coords,
2307                      const SbVec3f * normals,
2308                      SoMaterialBundle * mb,
2309                      const SoTextureCoordinateBundle * tb,
2310                      int32_t numpts,
2311                      int32_t idx)
2312 {
2313   static int first = 1;
2314   if (first) {
2315     sogl_render_pointset_funcs[0] = sogl_render_pointset_m0n0t0;
2316     sogl_render_pointset_funcs[1] = sogl_render_pointset_m0n0t1;
2317     sogl_render_pointset_funcs[2] = sogl_render_pointset_m0n1t0;
2318     sogl_render_pointset_funcs[3] = sogl_render_pointset_m0n1t1;
2319     sogl_render_pointset_funcs[4] = sogl_render_pointset_m1n0t0;
2320     sogl_render_pointset_funcs[5] = sogl_render_pointset_m1n0t1;
2321     sogl_render_pointset_funcs[6] = sogl_render_pointset_m1n1t0;
2322     sogl_render_pointset_funcs[7] = sogl_render_pointset_m1n1t1;
2323     first = 0;
2324   }
2325 
2326   int mat = mb ? 1 : 0;
2327   int norm = normals ? 1 : 0;
2328   int tex = tb ? 1 : 0;
2329 
2330   sogl_render_pointset_funcs[ (mat << 2) | (norm << 1) | tex ]
2331     ( coords,
2332       normals,
2333       mb,
2334       tb,
2335       numpts,
2336       idx);
2337 }
2338 
2339 // Used by library code to decide whether or not to add extra
2340 // debugging checks for glGetError().
2341 SbBool
sogl_glerror_debugging(void)2342 sogl_glerror_debugging(void)
2343 {
2344   static int COIN_GLERROR_DEBUGGING = -1;
2345   if (COIN_GLERROR_DEBUGGING == -1) {
2346     const char * str = coin_getenv("COIN_GLERROR_DEBUGGING");
2347     COIN_GLERROR_DEBUGGING = str ? atoi(str) : 0;
2348   }
2349   return (COIN_GLERROR_DEBUGGING == 0) ? FALSE : TRUE;
2350 }
2351 
2352 static int SOGL_AUTOCACHE_REMOTE_MIN = 500000;
2353 static int SOGL_AUTOCACHE_REMOTE_MAX = 5000000;
2354 static int SOGL_AUTOCACHE_LOCAL_MIN = 100000;
2355 static int SOGL_AUTOCACHE_LOCAL_MAX = 1000000;
2356 static int SOGL_AUTOCACHE_VBO_LIMIT = 65536;
2357 
2358 /*!
2359   Called by each shape during rendering. Will enable/disable autocaching
2360   based on the number of primitives.
2361 */
2362 void
sogl_autocache_update(SoState * state,const int numprimitives,SbBool didusevbo)2363 sogl_autocache_update(SoState * state, const int numprimitives, SbBool didusevbo)
2364 {
2365   static SbBool didtestenv = FALSE;
2366   if (!didtestenv) {
2367     const char * env;
2368     env = coin_getenv("COIN_AUTOCACHE_REMOTE_MIN");
2369     if (env) {
2370       SOGL_AUTOCACHE_REMOTE_MIN = atoi(env);
2371     }
2372     env = coin_getenv("COIN_AUTOCACHE_REMOTE_MAX");
2373     if (env) {
2374       SOGL_AUTOCACHE_REMOTE_MAX = atoi(env);
2375     }
2376     env = coin_getenv("COIN_AUTOCACHE_LOCAL_MIN");
2377     if (env) {
2378       SOGL_AUTOCACHE_LOCAL_MIN = atoi(env);
2379     }
2380     env = coin_getenv("COIN_AUTOCACHE_LOCAL_MAX");
2381     if (env) {
2382       SOGL_AUTOCACHE_LOCAL_MAX = atoi(env);
2383     }
2384     env = coin_getenv("COIN_AUTOCACHE_VBO_LIMIT");
2385     if (env) {
2386       SOGL_AUTOCACHE_VBO_LIMIT = atoi(env);
2387     }
2388     didtestenv = TRUE;
2389   }
2390 
2391   int minval = SOGL_AUTOCACHE_LOCAL_MIN;
2392   int maxval = SOGL_AUTOCACHE_LOCAL_MAX;
2393   if (SoGLCacheContextElement::getIsRemoteRendering(state)) {
2394     minval = SOGL_AUTOCACHE_REMOTE_MIN;
2395     maxval = SOGL_AUTOCACHE_REMOTE_MAX;
2396   }
2397   if (numprimitives <= minval) {
2398     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DO_AUTO_CACHE);
2399   }
2400   else if (numprimitives >= maxval) {
2401     SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
2402   }
2403   SoGLCacheContextElement::incNumShapes(state);
2404 
2405   if (didusevbo) {
2406     // avoid creating caches when rendering large VBOs
2407     if (numprimitives > SOGL_AUTOCACHE_VBO_LIMIT) {
2408       SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
2409     }
2410   }
2411 }
2412 
2413 // **************************************************************************
2414 
2415 static SoOffscreenRenderer * offscreenrenderer = NULL;
2416 static SoCallback * offscreencallback = NULL;
2417 
offscreenrenderer_cleanup(void)2418 static void offscreenrenderer_cleanup(void)
2419 {
2420   offscreencallback->unref();
2421   delete offscreenrenderer;
2422   offscreenrenderer = NULL;
2423   offscreencallback = NULL;
2424 }
2425 
2426 // This is really obsoleted now that we have
2427 // cc_glglue_context_create_offscreen() et al in the OpenGL
2428 // wrapper. So don't use this function any more from within Coin.
2429 //
2430 // FIXME: must be kept around due to ABI & API compatibility reasons
2431 // for now, but should consider taking it out for the next major Coin
2432 // release.
2433 //
2434 // 20030519 mortene.
2435 //
2436 // SoGL API is private so this function can be taken out any time
2437 // 20090426 pederb
2438 
2439 void
sogl_offscreencontext_callback(void (* cb)(void *,SoAction *),void * closure)2440 sogl_offscreencontext_callback(void (*cb)(void *, SoAction*),
2441                                void * closure)
2442 {
2443   if (offscreenrenderer == NULL) {
2444     offscreenrenderer = new SoOffscreenRenderer(SbViewportRegion(32, 32));
2445     offscreencallback = new SoCallback;
2446     offscreencallback->ref();
2447     coin_atexit((coin_atexit_f*) offscreenrenderer_cleanup, CC_ATEXIT_NORMAL);
2448   }
2449   offscreencallback->setCallback(cb, closure);
2450   offscreenrenderer->render(offscreencallback);
2451 }
2452