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 SoCube SoCube.h Inventor/nodes/SoCube.h
40   \brief The SoCube class is for rendering cubes.
41 
42   \ingroup nodes
43 
44   Insert a cube shape into the scenegraph. The cube is rendered with
45   the current material, texture and drawstyle settings (if any,
46   otherwise the default settings are used).
47 
48   (Strictly speaking, as you can have different width, height and
49   depth values for the "cube", instances of this class actually
50   represents \e boxes.)
51 
52   The SoCube node class is provided as a convenient abstraction for
53   the application programmer to use "complex" shapes of this type
54   without having to do the calculation and book-keeping of the polygon
55   sides and other low-level programming herself.
56 
57   <b>FILE FORMAT/DEFAULTS:</b>
58   \code
59     Cube {
60         width 2
61         height 2
62         depth 2
63     }
64   \endcode
65 
66   \sa SoCylinder, SoSphere, SoCone
67 */
68 
69 #include <Inventor/nodes/SoCube.h>
70 #include "coindefs.h"
71 
72 #include <Inventor/SbPlane.h>
73 #include <Inventor/SoPickedPoint.h>
74 #include <Inventor/actions/SoGLRenderAction.h>
75 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
76 #include <Inventor/actions/SoRayPickAction.h>
77 #include <Inventor/bundles/SoMaterialBundle.h>
78 #include <Inventor/details/SoCubeDetail.h>
79 #include <Inventor/elements/SoDrawStyleElement.h>
80 #include <Inventor/elements/SoGLMultiTextureEnabledElement.h>
81 #include <Inventor/elements/SoMaterialBindingElement.h>
82 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
83 #include <Inventor/misc/SoState.h>
84 
85 #include "nodes/SoSubNodeP.h"
86 #include "rendering/SoGL.h"
87 #include "misc/SoGenerate.h"
88 #include "misc/SoPick.h"
89 
90 /*!
91   \var SoSFFloat SoCube::width
92   X axis dimension of cube, defaults to 2.0.
93 */
94 /*!
95   \var SoSFFloat SoCube::height
96   Y axis dimension of cube, defaults to 2.0.
97 */
98 /*!
99   \var SoSFFloat SoCube::depth
100   Z axis dimension of cube, defaults to 2.0.
101 */
102 
103 
104 // *************************************************************************
105 
106 SO_NODE_SOURCE(SoCube);
107 
108 /*!
109   Constructor.
110 */
SoCube(void)111 SoCube::SoCube(void)
112 {
113   SO_NODE_INTERNAL_CONSTRUCTOR(SoCube);
114 
115   SO_NODE_ADD_FIELD(width, (2.0f));
116   SO_NODE_ADD_FIELD(height, (2.0f));
117   SO_NODE_ADD_FIELD(depth, (2.0f));
118 }
119 
120 /*!
121   Destructor.
122 */
~SoCube()123 SoCube::~SoCube()
124 {
125 }
126 
127 // Doc in parent.
128 void
initClass(void)129 SoCube::initClass(void)
130 {
131   SO_NODE_INTERNAL_INIT_CLASS(SoCube, SO_FROM_INVENTOR_1|SoNode::VRML1);
132 }
133 
134 // Doc in parent.
135 void
GLRender(SoGLRenderAction * action)136 SoCube::GLRender(SoGLRenderAction * action)
137 {
138   if (!this->shouldGLRender(action)) return;
139   SoState * state = action->getState();
140 
141   SoMaterialBindingElement::Binding binding =
142     SoMaterialBindingElement::get(state);
143 
144   SbBool materialPerPart =
145     (binding == SoMaterialBindingElement::PER_PART ||
146      binding == SoMaterialBindingElement::PER_PART_INDEXED ||
147      binding == SoMaterialBindingElement::PER_FACE ||
148      binding == SoMaterialBindingElement::PER_FACE_INDEXED);
149 
150   SbBool doTextures = FALSE;
151   SbBool do3DTextures = FALSE;
152   if (SoGLMultiTextureEnabledElement::get(state, 0)) {
153     doTextures = TRUE;
154     if (SoGLMultiTextureEnabledElement::getMode(state,0) ==
155         SoMultiTextureEnabledElement::TEXTURE3D) {
156       do3DTextures = TRUE;
157     }
158   }
159 
160   SoMaterialBundle mb(action);
161   mb.sendFirst();
162 
163   SbBool sendNormals = !mb.isColorOnly() ||
164     (SoMultiTextureCoordinateElement::getType(state) == SoMultiTextureCoordinateElement::FUNCTION);
165 
166   unsigned int flags = 0;
167   if (materialPerPart) flags |= SOGL_MATERIAL_PER_PART;
168   if (doTextures) {
169     switch (SoMultiTextureEnabledElement::getMode(state, 0)) {
170     default:
171       flags |= SOGL_NEED_TEXCOORDS;
172       break;
173     case SoMultiTextureEnabledElement::CUBEMAP:
174       flags |= SOGL_NEED_3DTEXCOORDS;
175       break;
176     }
177   }
178   else if (do3DTextures) flags |= SOGL_NEED_3DTEXCOORDS;
179   if (sendNormals) flags |= SOGL_NEED_NORMALS;
180 
181   sogl_render_cube(width.getValue(),
182                    height.getValue(),
183                    depth.getValue(),
184                    &mb,
185                    flags, state);
186 }
187 
188 // Doc in parent.
189 void
generatePrimitives(SoAction * action)190 SoCube::generatePrimitives(SoAction * action)
191 {
192   SoMaterialBindingElement::Binding binding =
193     SoMaterialBindingElement::get(action->getState());
194 
195   SbBool materialPerPart =
196     (binding == SoMaterialBindingElement::PER_PART ||
197      binding == SoMaterialBindingElement::PER_PART_INDEXED ||
198      binding == SoMaterialBindingElement::PER_FACE ||
199      binding == SoMaterialBindingElement::PER_FACE_INDEXED);
200 
201   unsigned int flags = 0;
202   if (materialPerPart) flags |= SOGEN_MATERIAL_PER_PART;
203   sogen_generate_cube(this->width.getValue(),
204                       this->height.getValue(),
205                       this->depth.getValue(),
206                       flags,
207                       this,
208                       action);
209 }
210 
211 // Doc in parent.
212 void
computeBBox(SoAction * COIN_UNUSED_ARG (action),SbBox3f & box,SbVec3f & center)213 SoCube::computeBBox(SoAction * COIN_UNUSED_ARG(action), SbBox3f & box, SbVec3f & center)
214 {
215   center.setValue(0.0f, 0.0f, 0.0f);
216   float w, h, d;
217   this->getHalfSize(w, h, d);
218 
219   // Allow negative values.
220   if (w < 0.0f) w = -w;
221   if (h < 0.0f) h = -h;
222   if (d < 0.0f) d = -d;
223 
224   box.setBounds(-w, -h, -d, w, h, d);
225 }
226 
227 // Doc in parent.
228 void
rayPick(SoRayPickAction * action)229 SoCube::rayPick(SoRayPickAction * action)
230 {
231   if (!shouldRayPick(action)) return;
232 
233   SoMaterialBindingElement::Binding binding =
234     SoMaterialBindingElement::get(action->getState());
235 
236   SbBool materialPerPart =
237     (binding == SoMaterialBindingElement::PER_PART ||
238      binding == SoMaterialBindingElement::PER_PART_INDEXED);
239 
240   sopick_pick_cube(this->width.getValue(),
241                    this->height.getValue(),
242                    this->depth.getValue(),
243                    materialPerPart ? SOPICK_MATERIAL_PER_PART : 0,
244                    this, action);
245 }
246 
247 // Convenience function for finding half the size of the box.
248 void
getHalfSize(float & w,float & h,float & d)249 SoCube::getHalfSize(float & w, float & h, float & d)
250 {
251   w = (this->width.isIgnored() ? 1.0f :
252        this->width.getValue() * 0.5f);
253   h = (this->height.isIgnored() ? 1.0f :
254        this->height.getValue() * 0.5f);
255   d = (this->depth.isIgnored() ? 1.0f :
256        this->depth.getValue() * 0.5f);
257 }
258 
259 // Doc from parent.
260 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)261 SoCube::getPrimitiveCount(SoGetPrimitiveCountAction * action)
262 {
263   if (!this->shouldPrimitiveCount(action)) return;
264 
265   action->addNumTriangles(12);
266 }
267