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 // Note: the class documentation for the basic primitive shapes
34 // SoSphere, SoCylinder, SoCone and SoCube have many common, or at
35 // least close to common, paragraphs. If you make any changes, check
36 // those other shapes too, to see if your updates / fixes should be
37 // migrated. <mortene@sim.no>.
38 /*!
39 \class SoCone SoCone.h Inventor/nodes/SoCone.h
40 \brief The SoCone class is for rendering cone shapes.
41
42 \ingroup nodes
43
44 Insert a cone shape into the scenegraph. The cone is rendered with
45 the current material, texture and drawstyle settings (if any,
46 otherwise the default settings are used).
47
48 The SoCone node class is provided as a convenient abstraction for
49 the application programmer to use "complex" shapes of this type
50 without having to do the tessellation to polygons and other
51 low-level programming herself.
52
53 A cone is visualized by the underlying rendering system by first
54 tessellating the conceptual cone into a set of polygons. To control
55 the trade-off between an as much as possible correct visual
56 appearance of the cone versus fast rendering, use an SoComplexity
57 node to influence the number of polygons generated from the
58 tessellation process. (The higher the complexity value, the more
59 polygons will be generated, the more \e rounded the sides of the
60 cone will look.) Set the SoComplexity::value field to what you
61 believe would be a good trade-off between correctness and speed for
62 your particular application.
63
64 <b>FILE FORMAT/DEFAULTS:</b>
65 \code
66 Cone {
67 bottomRadius 1
68 height 2
69 parts (SIDES | BOTTOM)
70 }
71 \endcode
72
73 \sa SoCylinder, SoSphere, SoCube
74 */
75
76 #include <Inventor/nodes/SoCone.h>
77 #include "coindefs.h"
78
79 #include <cassert>
80 #include <cmath>
81
82 #include <Inventor/SbLine.h>
83 #include <Inventor/SbPlane.h>
84 #include <Inventor/SoPickedPoint.h>
85 #include <Inventor/actions/SoGLRenderAction.h>
86 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
87 #include <Inventor/actions/SoRayPickAction.h>
88 #include <Inventor/bundles/SoMaterialBundle.h>
89 #include <Inventor/details/SoConeDetail.h>
90 #include <Inventor/elements/SoMaterialBindingElement.h>
91 #include <Inventor/elements/SoGLMultiTextureEnabledElement.h>
92 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
93 #include <Inventor/misc/SoState.h>
94
95 #if COIN_DEBUG
96 #include <Inventor/errors/SoDebugError.h>
97 #endif // COIN_DEBUG
98
99 #include "nodes/SoSubNodeP.h"
100 #include "rendering/SoGL.h"
101 #include "misc/SoPick.h"
102 #include "misc/SoGenerate.h"
103
104 /*!
105 \enum SoCone::Part
106 Enumerates the various parts of the cone, for setting inclusion or
107 exclusion from the shape.
108 */
109
110 /*!
111 \var SoSFBitMask SoCone::parts
112 The parts to use for the cone shape. Defaults to SoCone::ALL.
113 */
114 /*!
115 \var SoSFFloat SoCone::bottomRadius
116 Radius of the cone's bottom disc. Default value is 1.0.
117 */
118 /*!
119 \var SoSFFloat SoCone::height
120 Height of cone. Default value is 2.0.
121 */
122
123 #define CONE_SIDE_NUMTRIS 40.0f
124
125 // *************************************************************************
126
127 SO_NODE_SOURCE(SoCone);
128
129 /*!
130 Constructor.
131 */
SoCone(void)132 SoCone::SoCone(void)
133 {
134 SO_NODE_INTERNAL_CONSTRUCTOR(SoCone);
135
136 SO_NODE_ADD_FIELD(bottomRadius, (1.0f));
137 SO_NODE_ADD_FIELD(height, (2.0f));
138 SO_NODE_ADD_FIELD(parts, (ALL));
139
140 SO_NODE_DEFINE_ENUM_VALUE(Part, SIDES);
141 SO_NODE_DEFINE_ENUM_VALUE(Part, BOTTOM);
142 SO_NODE_DEFINE_ENUM_VALUE(Part, ALL);
143 SO_NODE_SET_SF_ENUM_TYPE(parts, Part);
144 }
145
146 /*!
147 Destructor.
148 */
~SoCone()149 SoCone::~SoCone()
150 {
151 }
152
153
154 // Doc from parent.
155 void
initClass(void)156 SoCone::initClass(void)
157 {
158 SO_NODE_INTERNAL_INIT_CLASS(SoCone, SO_FROM_INVENTOR_1|SoNode::VRML1);
159 }
160
161 // Doc from parent.
162 void
computeBBox(SoAction * COIN_UNUSED_ARG (action),SbBox3f & box,SbVec3f & center)163 SoCone::computeBBox(SoAction * COIN_UNUSED_ARG(action), SbBox3f & box, SbVec3f & center)
164 {
165 float r = this->bottomRadius.getValue();
166 float h = this->height.getValue();
167
168 // Allow negative values.
169 if (h < 0.0f) h = -h;
170 if (r < 0.0f) r = -r;
171
172 float half_height = h/2.0f;
173
174 // The SIDES are present, so just find the middle point and enclose
175 // everything.
176 if (this->parts.getValue() & SoCone::SIDES) {
177 center.setValue(0.0f, 0.0f, 0.0f);
178 box.setBounds(SbVec3f(-r, -half_height, -r), SbVec3f(r, half_height, r));
179 }
180 // ..no SIDES, but we've still got the bottom (NB: OIV misses this case).
181 else if (this->parts.getValue() & SoCone::BOTTOM) {
182 center.setValue(0.0f, -half_height, 0.0f);
183 box.setBounds(SbVec3f(-r, -half_height, -r), SbVec3f(r, -half_height, r));
184 }
185 // ..no parts present. My confidence is shot -- I feel very small.
186 else {
187 center.setValue(0.0f, 0.0f, 0.0f);
188 box.setBounds(SbVec3f(0.0f, 0.0f, 0.0f), SbVec3f(0.0f, 0.0f, 0.0f));
189 }
190 }
191
192 // Doc from parent.
193 void
GLRender(SoGLRenderAction * action)194 SoCone::GLRender(SoGLRenderAction * action)
195 {
196 if (!shouldGLRender(action)) return;
197
198 SoState * state = action->getState();
199
200 SbBool doTextures = FALSE;
201 SbBool do3DTextures = FALSE;
202 if (SoGLMultiTextureEnabledElement::get(state, 0)) {
203 doTextures = TRUE;
204 if (SoGLMultiTextureEnabledElement::getMode(state,0) ==
205 SoMultiTextureEnabledElement::TEXTURE3D) {
206 do3DTextures = TRUE;
207 }
208 }
209 SoCone::Part p = (SoCone::Part) this->parts.getValue();
210
211 SoMaterialBundle mb(action);
212 SbBool sendNormals = !mb.isColorOnly() ||
213 (SoMultiTextureCoordinateElement::getType(state, 0) == SoMultiTextureCoordinateElement::FUNCTION);
214
215 unsigned int flags = 0;
216 if (doTextures) flags |= SOGL_NEED_TEXCOORDS;
217 else if (do3DTextures) flags |= SOGL_NEED_3DTEXCOORDS;
218 if (sendNormals) flags |= SOGL_NEED_NORMALS;
219 if (p & SoCone::SIDES) flags |= SOGL_RENDER_SIDE;
220 if (p & SoCone::BOTTOM) flags |= SOGL_RENDER_BOTTOM;
221
222 SoMaterialBindingElement::Binding bind =
223 SoMaterialBindingElement::get(state);
224 if (bind == SoMaterialBindingElement::PER_PART ||
225 bind == SoMaterialBindingElement::PER_PART_INDEXED)
226 flags |= SOGL_MATERIAL_PER_PART;
227
228 mb.sendFirst();
229
230 float complexity = this->getComplexityValue(action);
231
232 sogl_render_cone(this->bottomRadius.getValue(),
233 this->height.getValue(),
234 (int)(CONE_SIDE_NUMTRIS * complexity),
235 &mb,
236 flags, state);
237
238 #if COIN_DEBUG && 0 // debug
239 SoDebugError::postInfo("SoCone::GLRender", "end");
240 #endif // debug
241 }
242
243 /*!
244 Add a \a part to the cone.
245
246 \sa removePart(), hasPart()
247 */
248 void
addPart(SoCone::Part part)249 SoCone::addPart(SoCone::Part part)
250 {
251 if (this->hasPart(part)) {
252 #if COIN_DEBUG
253 SoDebugError::postWarning("SoCone::addPart", "part already set");
254 #endif // COIN_DEBUG
255 return;
256 }
257
258 this->parts.setValue(this->parts.getValue() | part);
259 }
260
261 /*!
262 Remove a \a part from the cone.
263
264 \sa addPart(), hasPart()
265 */
266 void
removePart(SoCone::Part part)267 SoCone::removePart(SoCone::Part part)
268 {
269 if (!this->hasPart(part)) {
270 #if COIN_DEBUG
271 SoDebugError::postWarning("SoCone::removePart", "part was not set");
272 #endif // COIN_DEBUG
273 return;
274 }
275
276 this->parts.setValue(this->parts.getValue() & ~part);
277 }
278
279 /*!
280 Returns \c TRUE if rendering of the given \a part is currently
281 turned on.
282
283 \sa addPart(), removePart()
284 */
285 SbBool
hasPart(SoCone::Part part) const286 SoCone::hasPart(SoCone::Part part) const
287 {
288 return (this->parts.getValue() & part) ? TRUE : FALSE;
289 }
290
291 // Doc from parent.
292 void
rayPick(SoRayPickAction * action)293 SoCone::rayPick(SoRayPickAction * action)
294 {
295 if (!this->shouldRayPick(action)) return;
296
297 SoCone::Part p = (SoCone::Part) this->parts.getValue();
298 unsigned int flags = 0;
299 if (p & SoCone::SIDES) flags |= SOPICK_SIDES;
300 if (p & SoCone::BOTTOM) flags |= SOPICK_BOTTOM;
301
302 SoMaterialBindingElement::Binding bind =
303 SoMaterialBindingElement::get(action->getState());
304 if (bind == SoMaterialBindingElement::PER_PART ||
305 bind == SoMaterialBindingElement::PER_PART_INDEXED)
306 flags |= SOPICK_MATERIAL_PER_PART;
307
308 sopick_pick_cone(this->bottomRadius.getValue(),
309 this->height.getValue(),
310 flags, this, action);
311 }
312
313 // Doc from parent.
314 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)315 SoCone::getPrimitiveCount(SoGetPrimitiveCountAction * action)
316 {
317 if (!this->shouldPrimitiveCount(action)) return;
318
319 float complexity = this->getComplexityValue(action);
320 int numtris = (int)(complexity * CONE_SIDE_NUMTRIS);
321
322 if (this->parts.getValue() & SoCone::BOTTOM) {
323 action->addNumTriangles(numtris-2);
324 }
325 if (this->parts.getValue() & SoCone::SIDES) {
326 action->addNumTriangles(numtris);
327 }
328 }
329
330 // Doc from parent.
331 void
generatePrimitives(SoAction * action)332 SoCone::generatePrimitives(SoAction * action)
333 {
334 SoCone::Part p = (SoCone::Part) this->parts.getValue();
335 unsigned int flags = 0;
336 if (p & SoCone::SIDES) flags |= SOGEN_GENERATE_SIDE;
337 if (p & SoCone::BOTTOM) flags |= SOGEN_GENERATE_BOTTOM;
338
339 SoMaterialBindingElement::Binding bind =
340 SoMaterialBindingElement::get(action->getState());
341 if (bind == SoMaterialBindingElement::PER_PART ||
342 bind == SoMaterialBindingElement::PER_PART_INDEXED)
343 flags |= SOGL_MATERIAL_PER_PART;
344
345 float complexity = this->getComplexityValue(action);
346
347 sogen_generate_cone(this->bottomRadius.getValue(),
348 this->height.getValue(),
349 (int)(CONE_SIDE_NUMTRIS * complexity),
350 flags,
351 this,
352 action);
353 }
354
355 #undef CONE_SIDE_NUMTRIS
356