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