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 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif // HAVE_CONFIG_H
36 
37 #ifdef HAVE_VRML97
38 
39 /*!
40   \class SoVRMLPointSet SoVRMLPointSet.h Inventor/VRMLnodes/SoVRMLPointSet.h
41   \brief The SoVRMLPointSet class is used to represent a set of 3D points.
42 
43   \ingroup VRMLnodes
44 
45   \WEB3DCOPYRIGHT
46 
47   \verbatim
48   PointSet {
49     exposedField  SFNode  color      NULL
50     exposedField  SFNode  coord      NULL
51   }
52   \endverbatim
53 
54   The PointSet node specifies a set of 3D points, in the local
55   coordinate system, with associated colours at each point. The coord
56   field specifies a SoVRMLCoordinate node (or instance of a Coordinate
57   node). The results are undefined if the coord field specifies any
58   other type of node. PointSet uses the coordinates in order. If the
59   coord field is NULL, the point set is considered empty.  PointSet
60   nodes are not lit, not texture-mapped, nor do they participate in
61   collision detection. The size of each point is implementation-
62   dependent.  If the color field is not NULL, it shall specify a
63   SoVRMLColor node that contains at least the number of points
64   contained in the coord node. The results are undefined if the color
65   field specifies any other type of node. Colours shall be applied to
66   each point in order. The results are undefined if the number of
67   values in the Color node is less than the number of values specified
68   in the Coordinate node.  If the color field is NULL and there is a
69   SoVRMLMaterial node defined for the SoVRMLAppearance node affecting
70   this PointSet node, the emissiveColor of the Material node shall be
71   used to draw the points. More details on lighting equations can be
72   found in 4.14, Lighting model
73   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.14>).
74 
75 */
76 
77 #include <Inventor/VRMLnodes/SoVRMLPointSet.h>
78 
79 #include <Inventor/VRMLnodes/SoVRMLMacros.h>
80 #include <Inventor/VRMLnodes/SoVRMLCoordinate.h>
81 #include <Inventor/misc/SoState.h>
82 #include <Inventor/misc/SoGLDriverDatabase.h>
83 #include <Inventor/bundles/SoTextureCoordinateBundle.h>
84 #include <Inventor/SoPrimitiveVertex.h>
85 
86 #include <Inventor/actions/SoGLRenderAction.h>
87 #include <Inventor/system/gl.h>
88 
89 #include <Inventor/nodes/SoVertexProperty.h>
90 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
91 #include <Inventor/actions/SoGetBoundingBoxAction.h>
92 #include <Inventor/elements/SoGLCoordinateElement.h>
93 #include <Inventor/elements/SoMultiTextureEnabledElement.h>
94 #include <Inventor/elements/SoNormalBindingElement.h>
95 #include <Inventor/elements/SoMaterialBindingElement.h>
96 #include <Inventor/elements/SoGLLazyElement.h>
97 #include <Inventor/bundles/SoMaterialBundle.h>
98 #include <Inventor/caches/SoNormalCache.h>
99 #include <Inventor/details/SoPointDetail.h>
100 #include <Inventor/caches/SoBoundingBoxCache.h>
101 #include <Inventor/SbColor.h>
102 #include <Inventor/SbColor4f.h>
103 #include <Inventor/elements/SoOverrideElement.h>
104 #include <Inventor/elements/SoMaterialBindingElement.h>
105 #include <Inventor/elements/SoGLVBOElement.h>
106 #include <Inventor/elements/SoGLLazyElement.h>
107 #if COIN_DEBUG
108 #include <Inventor/errors/SoDebugError.h>
109 #endif // COIN_DEBUG
110 
111 #include "nodes/SoSubNodeP.h"
112 #include "rendering/SoGL.h"
113 #include "rendering/SoVBO.h"
114 
115 static SbBool
is_material_per_vertex(SoVRMLPointSet * ps,SoState * state)116 is_material_per_vertex(SoVRMLPointSet * ps, SoState * state)
117 {
118   if (SoOverrideElement::getMaterialBindingOverride(state)) {
119     if (SoMaterialBindingElement::get(state) !=
120         SoMaterialBindingElement::OVERALL) return TRUE;
121     return FALSE;
122   }
123   return ps->color.getValue() != NULL;
124 }
125 
126 SO_NODE_SOURCE(SoVRMLPointSet);
127 
128 // Doc in parent
129 void
initClass(void)130 SoVRMLPointSet::initClass(void)
131 {
132   SO_NODE_INTERNAL_INIT_CLASS(SoVRMLPointSet, SO_VRML97_NODE_TYPE);
133 }
134 
135 /*!
136   Constructor.
137 */
SoVRMLPointSet(void)138 SoVRMLPointSet::SoVRMLPointSet(void)
139 {
140   SO_VRMLNODE_INTERNAL_CONSTRUCTOR(SoVRMLPointSet);
141 }
142 
143 /*!
144   Destructor.
145 */
~SoVRMLPointSet()146 SoVRMLPointSet::~SoVRMLPointSet()
147 {
148 }
149 
150 // Doc in parent
151 void
GLRender(SoGLRenderAction * action)152 SoVRMLPointSet::GLRender(SoGLRenderAction * action)
153 {
154   SoState * state = action->getState();
155 
156   SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
157   SoMultiTextureEnabledElement::disableAll(state);
158 
159   SoVRMLVertexPoint::GLRender(action);
160 
161   if (!this->shouldGLRender(action)) return;
162 
163   const SoCoordinateElement * coords;
164   coords = SoCoordinateElement::getInstance(state);
165 
166   SoMaterialBundle mb(action);
167 
168   SbBool matpervertex = is_material_per_vertex(this, state);
169   if (!matpervertex) {
170     const SbColor & col = SoLazyElement::getEmissive(state);
171     SbColor4f c(col[0], col[1], col[2], 1.0f);
172     SoGLLazyElement::sendPackedDiffuse(state, c.getPackedValue());
173   }
174   else {
175     mb.sendFirst();
176   }
177 
178   const cc_glglue * glue = sogl_glue_instance(state);
179 
180   const int numpts = coords->getNum();
181   const uint32_t contextid = action->getCacheContext();
182 
183   // no point setting up OpenGL for vertex arrays for fewer than 20 points
184   SbBool dova =
185     SoVBO::shouldRenderAsVertexArrays(state, contextid, numpts) &&
186     SoGLDriverDatabase::isSupported(glue, SO_GL_VERTEX_ARRAY);
187 
188   if (dova && matpervertex) {
189     const SoGLVBOElement * vboelem = SoGLVBOElement::getInstance(state);
190     if (vboelem->getColorVBO() == NULL) {
191       dova = FALSE;
192       // we might be able to do VA-rendering, but need to check the
193       // diffuse color type first.
194       SoGLLazyElement * lelem = (SoGLLazyElement*) SoLazyElement::getInstance(state);
195       if (!lelem->isPacked() && lelem->getNumTransparencies() <= 1) {
196         dova = TRUE;
197       }
198     }
199   }
200   SbBool didrenderasvbo = FALSE;
201   if (dova) {
202     SbBool vbo = this->startVertexArray(action,
203                                         coords,
204                                         NULL,
205                                         FALSE,
206                                         matpervertex);
207     didrenderasvbo = vbo;
208     cc_glglue_glDrawArrays(glue, GL_POINTS, 0, numpts);
209     this->finishVertexArray(action, vbo,
210                             FALSE,
211                             FALSE,
212                             matpervertex);
213   }
214   else {
215     sogl_render_pointset((SoGLCoordinateElement*) coords,
216                          NULL,
217                          matpervertex ? &mb : NULL,
218                          NULL,
219                          numpts, 0);
220   }
221 
222   // send approx number of points for autocache handling
223   sogl_autocache_update(state, numpts, didrenderasvbo);
224 }
225 
226 // Doc in parent
227 void
getBoundingBox(SoGetBoundingBoxAction * action)228 SoVRMLPointSet::getBoundingBox(SoGetBoundingBoxAction * action)
229 {
230   inherited::getBoundingBox(action);
231   // notify open (if any) bbox caches about points in this shape
232   SoBoundingBoxCache::setHasLinesOrPoints(action->getState());
233 }
234 
235 // Doc in parent
236 void
generatePrimitives(SoAction * action)237 SoVRMLPointSet::generatePrimitives(SoAction * action)
238 {
239   SoVRMLCoordinate * coordnode = (SoVRMLCoordinate*) this->coord.getValue();
240   if (!coordnode || coordnode->point.getNum() == 0) return;
241   const SbVec3f * coords = coordnode->point.getValues(0);
242 
243   SoPrimitiveVertex vertex;
244   SoPointDetail pointDetail;
245   vertex.setDetail(&pointDetail);
246 
247   int32_t numpts = coordnode->point.getNum();
248 
249   int matnr = 0;
250   int idx = 0;
251 
252   SbBool matpervertex = is_material_per_vertex(this, action->getState());
253 
254   this->beginShape(action, SoShape::POINTS);
255   for (int i = 0; i < numpts; i++) {
256     if (matpervertex) {
257       pointDetail.setMaterialIndex(matnr);
258       vertex.setMaterialIndex(matnr++);
259     }
260     pointDetail.setCoordinateIndex(idx);
261     vertex.setPoint(coords[idx++]);
262     this->shapeVertex(&vertex);
263   }
264   this->endShape();
265 }
266 
267 #endif // HAVE_VRML97
268