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 SoSphere SoSphere.h Inventor/nodes/SoSphere.h
40 \brief The SoSphere class is for rendering sphere shapes.
41
42 \ingroup nodes
43
44 Renders a sphere with the size given by the SoSphere::radius
45 field. The sphere is rendered with the current material, texture and
46 drawstyle settings (if any, otherwise the default settings are
47 used).
48
49 The SoSphere node class is provided as a convenient abstraction for
50 the application programmer to use "complex" shapes of this type
51 without having to do the tessellation to polygons and other
52 low-level programming herself.
53
54 A good trick for rendering ellipsoidal 3D shapes is to use an
55 SoSphere prefixed with an SoScale transformation to "flatten" it
56 along one or more of the principal axes. (Ie use for instance an
57 SoScale node with SoScale::scaleFactor equal to [1, 1, 0.1] to
58 flatten it along the Z direction.)
59
60 A sphere is visualized by the underlying rendering system by first
61 tessellating the conceptual sphere into a set of polygons. To
62 control the trade-off between an as much as possible correct visual
63 appearance of the sphere versus fast rendering, use an SoComplexity
64 node to influence the number of polygons generated from the
65 tessellation process. (The higher the complexity value, the more
66 polygons will be generated, the more \e rounded the sphere will
67 look.) Set the SoComplexity::value field to what you believe would
68 be a good trade-off between correctness and speed for your
69 particular application.
70
71 <b>FILE FORMAT/DEFAULTS:</b>
72 \code
73 Sphere {
74 radius 1
75 }
76 \endcode
77
78 \sa SoCone, SoCylinder, SoCube
79 */
80
81 #include <Inventor/nodes/SoSphere.h>
82 #include "coindefs.h"
83
84 #include <Inventor/SbSphere.h>
85 #include <Inventor/SoPickedPoint.h>
86 #include <Inventor/actions/SoGLRenderAction.h>
87 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
88 #include <Inventor/actions/SoRayPickAction.h>
89 #include <Inventor/bundles/SoMaterialBundle.h>
90 #include <Inventor/elements/SoGLMultiTextureEnabledElement.h>
91 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
92 #include <Inventor/misc/SoState.h>
93
94 #include "nodes/SoSubNodeP.h"
95 #include "rendering/SoGL.h"
96 #include "misc/SoGenerate.h"
97 #include "misc/SoPick.h"
98
99 /*!
100 \var SoSFFloat SoSphere::radius
101
102 Radius of sphere. Default value is 1.0.
103 */
104
105 #define SPHERE_NUM_SLICES 30.0f
106 #define SPHERE_NUM_STACKS 30.0f
107
108 // *************************************************************************
109
110 SO_NODE_SOURCE(SoSphere);
111
112 /*!
113 Constructor.
114 */
SoSphere(void)115 SoSphere::SoSphere(void)
116 {
117 SO_NODE_INTERNAL_CONSTRUCTOR(SoSphere);
118
119 SO_NODE_ADD_FIELD(radius, (1.0f));
120 }
121
122 /*!
123 Destructor.
124 */
~SoSphere()125 SoSphere::~SoSphere()
126 {
127 }
128
129 // Documented in superclass.
130 void
initClass(void)131 SoSphere::initClass(void)
132 {
133 SO_NODE_INTERNAL_INIT_CLASS(SoSphere, SO_FROM_INVENTOR_1|SoNode::VRML1);
134 }
135
136 // Documented in superclass.
137 void
GLRender(SoGLRenderAction * action)138 SoSphere::GLRender(SoGLRenderAction * action)
139 {
140 if (!this->shouldGLRender(action)) return;
141
142 SoState * state = action->getState();
143
144 SoMaterialBundle mb(action);
145 mb.sendFirst();
146
147 SbBool doTextures = FALSE;
148 SbBool do3DTextures = FALSE;
149 if (SoGLMultiTextureEnabledElement::get(state, 0)) {
150 doTextures = TRUE;
151 if (SoGLMultiTextureEnabledElement::getMode(state,0) ==
152 SoMultiTextureEnabledElement::TEXTURE3D) {
153 do3DTextures = TRUE;
154 }
155 }
156
157 SbBool sendNormals = !mb.isColorOnly() ||
158 (SoMultiTextureCoordinateElement::getType(state) == SoMultiTextureCoordinateElement::FUNCTION);
159
160 float complexity = SbClamp(this->getComplexityValue(action), 0.0f, 1.0f);
161
162 unsigned int flags = 0;
163 if (sendNormals) flags |= SOGL_NEED_NORMALS;
164 if (doTextures) flags |= SOGL_NEED_TEXCOORDS;
165 else if (do3DTextures) flags |= SOGL_NEED_3DTEXCOORDS;
166
167 sogl_render_sphere(this->radius.getValue(),
168 (int)(SPHERE_NUM_SLICES * complexity),
169 (int)(SPHERE_NUM_STACKS * complexity),
170 &mb,
171 flags, state);
172 }
173
174 // Documented in superclass.
175 void
computeBBox(SoAction * COIN_UNUSED_ARG (action),SbBox3f & box,SbVec3f & center)176 SoSphere::computeBBox(SoAction * COIN_UNUSED_ARG(action), SbBox3f & box, SbVec3f & center)
177 {
178 float r = this->radius.getValue();
179
180 // Allow negative values.
181 if (r < 0.0f) r = -r;
182
183 box.setBounds(SbVec3f(-r, -r, -r), SbVec3f(r, r, r));
184 center.setValue(0.0f, 0.0f, 0.0f);
185 }
186
187 // Documented in superclass.
188 void
rayPick(SoRayPickAction * action)189 SoSphere::rayPick(SoRayPickAction *action)
190 {
191 if (!shouldRayPick(action)) return;
192
193 sopick_pick_sphere(this->radius.getValue(),
194 action);
195 }
196
197 // Documented in superclass.
198 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)199 SoSphere::getPrimitiveCount(SoGetPrimitiveCountAction * action)
200 {
201 if (!this->shouldPrimitiveCount(action)) return;
202
203 float complexity = this->getComplexityValue(action);
204 action->addNumTriangles((int)(complexity*2.0f*SPHERE_NUM_SLICES*(SPHERE_NUM_STACKS-1)));
205 }
206
207 // Documented in superclass.
208 void
generatePrimitives(SoAction * action)209 SoSphere::generatePrimitives(SoAction * action)
210 {
211 float complexity = this->getComplexityValue(action);
212
213 sogen_generate_sphere(this->radius.getValue(),
214 (int)(SPHERE_NUM_SLICES * complexity),
215 (int)(SPHERE_NUM_STACKS * complexity),
216 this,
217 action);
218 }
219
220 #undef SPHERE_NUM_SLICES
221 #undef SPHERE_NUM_STACKS
222