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