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 /*!
34   \class SoTextureCoordinateEnvironment SoTextureCoordinateEnvironment.h Inventor/nodes/SoTextureCoordinateEnvironment.h
35   \brief The SoTextureCoordinateEnvironment class generates texture coordinates by projecting onto a surrounding texture.
36 
37   \ingroup nodes
38 
39   The texture specifying the enviroment will be mapped around the
40   scenegraph below this node using a sphere. The texture will be mapped
41   onto the scenegraph taking camera position into account. This will
42   lead to an object reflecting its enviroment.
43 
44   Here is a scenegraph example showing how enviroment mapping can be
45   applied to an object:
46 
47   \code
48   #Inventor V2.1 ascii
49 
50   Separator {
51 
52     Texture2 {
53       filename "ocean.jpg" # the environment, in this case ocean
54     }
55     TextureCoordinateEnvironment {}
56 
57     Cube {} # the environmentally mapped object
58   }
59   \endcode
60 
61   <b>FILE FORMAT/DEFAULTS:</b>
62   \code
63     TextureCoordinateEnvironment {
64     }
65   \endcode
66 */
67 
68 // *************************************************************************
69 
70 // FIXME: Can this somehow relate to 3D textures? (kintel 20020203)
71 
72 #include <Inventor/nodes/SoTextureCoordinateEnvironment.h>
73 
74 #include <cstdlib>
75 #include <cfloat>
76 
77 #ifdef HAVE_CONFIG_H
78 #include <config.h>
79 #endif // HAVE_CONFIG_H
80 
81 #include <Inventor/SbVec3f.h>
82 #include <Inventor/actions/SoGLRenderAction.h>
83 #include <Inventor/elements/SoGLMultiTextureCoordinateElement.h>
84 #include <Inventor/elements/SoModelMatrixElement.h>
85 #include <Inventor/elements/SoTextureUnitElement.h>
86 #include <Inventor/elements/SoGLCacheContextElement.h>
87 #include <Inventor/system/gl.h>
88 #include <Inventor/C/glue/gl.h>
89 
90 #include "tidbitsp.h"
91 #include "nodes/SoSubNodeP.h"
92 
93 // *************************************************************************
94 
95 class SoTextureCoordinateEnvironmentP {
96 public:
97   static SbVec4f * dummy_texcoords;
98   static void cleanup_func(void);
99 };
100 
101 SbVec4f * SoTextureCoordinateEnvironmentP::dummy_texcoords = NULL;
102 
103 void
cleanup_func(void)104 SoTextureCoordinateEnvironmentP::cleanup_func(void)
105 {
106   delete SoTextureCoordinateEnvironmentP::dummy_texcoords;
107 }
108 
109 // *************************************************************************
110 
111 SO_NODE_SOURCE(SoTextureCoordinateEnvironment);
112 
113 /*!
114   Constructor.
115 */
SoTextureCoordinateEnvironment()116 SoTextureCoordinateEnvironment::SoTextureCoordinateEnvironment()
117 {
118   SO_NODE_INTERNAL_CONSTRUCTOR(SoTextureCoordinateEnvironment);
119 }
120 
121 /*!
122   Destructor.
123 */
~SoTextureCoordinateEnvironment()124 SoTextureCoordinateEnvironment::~SoTextureCoordinateEnvironment()
125 {
126 }
127 
128 // doc in super
129 void
initClass(void)130 SoTextureCoordinateEnvironment::initClass(void)
131 {
132   SO_NODE_INTERNAL_INIT_CLASS(SoTextureCoordinateEnvironment, SO_FROM_INVENTOR_1);
133 
134   SoTextureCoordinateEnvironmentP::dummy_texcoords = new SbVec4f(0.0f, 0.0f, 0.0f, 1.0f);
135   coin_atexit((coin_atexit_f *)SoTextureCoordinateEnvironmentP::cleanup_func, CC_ATEXIT_NORMAL);
136 }
137 
138 // generates texture coordinates for GLRender, callback and pick actions
139 const SbVec4f &
generate(void * userdata,const SbVec3f &,const SbVec3f & n)140 SoTextureCoordinateEnvironment::generate(void *userdata,
141                                          const SbVec3f & /* p */,
142                                          const SbVec3f &n)
143 {
144   //
145   // from formula in the Red Book
146   //
147 
148   SoState *state = (SoState*)userdata;
149   SbVec3f wn; // normal in world (eye) coordinates
150   SoModelMatrixElement::get(state).multDirMatrix(n, wn);
151   SbVec3f u = n;
152 
153   u.normalize();
154   wn.normalize();
155 
156   // reflection vector
157   SbVec3f r = u - SbVec3f(2.0f*wn[0]*wn[0]*u[0],
158                           2.0f*wn[1]*wn[1]*u[1],
159                           2.0f*wn[2]*wn[2]*u[2]);
160   r.normalize();
161 
162   float tmp = 1.0f + r[2];
163   float m = 2.0f * (float)sqrt(r[0]*r[0] + r[1]*r[1] + tmp*tmp);
164 
165   // in case an empty normal was supplied
166   if (fabs(m) <= FLT_EPSILON) m = 1.0f;
167 
168   (*SoTextureCoordinateEnvironmentP::dummy_texcoords)[0] = r[0] / m + 0.5f;
169   (*SoTextureCoordinateEnvironmentP::dummy_texcoords)[1] = r[1] / m + 0.5f;
170   return *SoTextureCoordinateEnvironmentP::dummy_texcoords;
171 }
172 
173 // doc from parent
174 void
doAction(SoAction * action)175 SoTextureCoordinateEnvironment::doAction(SoAction * action)
176 {
177   SoState * state = action->getState();
178   int unit = SoTextureUnitElement::get(state);
179   SoMultiTextureCoordinateElement::setFunction(action->getState(), this, unit,
180                                                generate,
181                                                action->getState());
182 }
183 
184 // doc from parent
185 void
GLRender(SoGLRenderAction * action)186 SoTextureCoordinateEnvironment::GLRender(SoGLRenderAction * action)
187 {
188   SoState * state = action->getState();
189   int unit = SoTextureUnitElement::get(state);
190   const cc_glglue * glue = cc_glglue_instance(SoGLCacheContextElement::get(state));
191   int maxunits = cc_glglue_max_texture_units(glue);
192   if (unit < maxunits) {
193     SoMultiTextureCoordinateElement::setFunction(action->getState(), this,
194                                                  unit,
195                                                  generate,
196                                                  action->getState());
197     SoGLMultiTextureCoordinateElement::setTexGen(action->getState(),
198                                                  this, unit, handleTexgen,
199                                                  NULL,
200                                                  generate,
201                                                  action->getState());
202   }
203 }
204 
205 // doc from parent
206 void
callback(SoCallbackAction * action)207 SoTextureCoordinateEnvironment::callback(SoCallbackAction * action)
208 {
209   SoTextureCoordinateEnvironment::doAction((SoAction *)action);
210 }
211 
212 // doc from parent
213 void
pick(SoPickAction * action)214 SoTextureCoordinateEnvironment::pick(SoPickAction * action)
215 {
216   SoTextureCoordinateEnvironment::doAction((SoAction *)action);
217 }
218 
219 void
handleTexgen(void *)220 SoTextureCoordinateEnvironment::handleTexgen(void * /* data */)
221 {
222 #if 0 // from red book
223   glTexGenfv(GL_S, GL_SPHERE_MAP, 0);
224   glTexGenfv(GL_T, GL_SPHERE_MAP, 0);
225 #else // from siggraph 96
226   glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
227   glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
228 #endif
229 
230   // supply dummy plane for R and Q so that texture generation works
231   // properly
232   glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
233   glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
234 
235   float plane[4];
236   plane[0] = 0.0f;
237   plane[1] = 0.0f;
238   plane[2] = 0.0f;
239   plane[3] = 1.0f;
240   glTexGenfv(GL_R, GL_OBJECT_PLANE, plane);
241   glTexGenfv(GL_Q, GL_OBJECT_PLANE, plane);
242 }
243