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