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 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif // HAVE_CONFIG_H
36
37 #ifdef HAVE_VRML97
38
39 /*!
40 \class SoVRMLPixelTexture SoVRMLPixelTexture.h Inventor/VRMLnodes/SoVRMLPixelTexture.h
41 \brief The SoVRMLPixelTexture class is used for mapping a texture image onto geometry..
42
43 \ingroup VRMLnodes
44
45 \WEB3DCOPYRIGHT
46
47 \verbatim
48 PixelTexture {
49 exposedField SFImage image 0 0 0 # see SoSFImage
50 field SFBool repeatS TRUE
51 field SFBool repeatT TRUE
52 }
53 \endverbatim
54
55 The PixelTexture node defines a 2D image-based texture map as an
56 explicit array of pixel values (image field) and parameters
57 controlling tiling repetition of the texture onto geometry. Texture
58 maps are defined in a 2D coordinate system (s, t) that ranges from
59 0.0 to 1.0 in both directions. The bottom edge of the pixel image
60 corresponds to the S-axis of the texture map, and left edge of the
61 pixel image corresponds to the T-axis of the texture map. The
62 lower-left pixel of the pixel image corresponds to s=0.0, t=0.0, and
63 the top-right pixel of the image corresponds to s = 1.0, t = 1.0.
64 See 4.6.11, Texture maps
65 (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.6.11>),
66 for a general description of texture
67 maps. Figure 6.13 depicts an example PixelTexture.
68
69 <center>
70 <img src="http://www.web3d.org/documents/specifications/14772/V2.0/Images/PixelTexture.gif">
71 Figure 6.13 -- PixelTexture node
72 </center>
73
74 See 4.14, Lighting model
75 (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.14>),
76 for a description of how the texture values interact with the
77 appearance of the geometry. SoSFImage, describes the
78 specification of an image. The repeatS and repeatT fields specify
79 how the texture wraps in the S and T directions. If repeatS is TRUE
80 (the default), the texture map is repeated outside the 0-to-1
81 texture coordinate range in the S direction so that it fills the
82 shape. If repeatS is FALSE, the texture coordinates are clamped in
83 the S direction to lie within the 0.0 to 1.0 range. The repeatT
84 field is analogous to the repeatS field.
85
86 */
87
88 /*!
89 SoSFImage SoVRMLPixelTexture::image
90 The image data.
91 */
92
93 #include <Inventor/VRMLnodes/SoVRMLPixelTexture.h>
94
95 #include <cassert>
96 #include <cstddef>
97
98 #include <Inventor/VRMLnodes/SoVRMLMacros.h>
99 #include <Inventor/SoInput.h>
100 #include <Inventor/actions/SoCallbackAction.h>
101 #include <Inventor/actions/SoRayPickAction.h>
102 #include <Inventor/actions/SoGLRenderAction.h>
103 #include <Inventor/elements/SoGLMultiTextureEnabledElement.h>
104 #include <Inventor/elements/SoGLMultiTextureImageElement.h>
105 #include <Inventor/elements/SoTextureQualityElement.h>
106 #include <Inventor/elements/SoTextureOverrideElement.h>
107 #include <Inventor/elements/SoTextureUnitElement.h>
108 #include <Inventor/elements/SoCacheElement.h>
109 #include <Inventor/errors/SoReadError.h>
110 #include <Inventor/misc/SoGLBigImage.h>
111 #include <Inventor/sensors/SoFieldSensor.h>
112 #include <Inventor/errors/SoDebugError.h>
113 #include <Inventor/SbImage.h>
114 #ifdef HAVE_THREADS
115 #include <Inventor/threads/SbMutex.h>
116 #endif // HAVE_THREADS
117
118 #include "nodes/SoSubNodeP.h"
119 #include "elements/SoTextureScalePolicyElement.h"
120
121 // *************************************************************************
122
123 class SoVRMLPixelTextureP {
124 public:
125 SoGLImage * glimage;
126 SbBool glimagevalid;
127 int readstatus;
128
129 #ifdef COIN_THREADSAFE
130 SbMutex glimagemutex;
lock_glimage(void)131 void lock_glimage(void) { this->glimagemutex.lock(); }
unlock_glimage(void)132 void unlock_glimage(void) { this->glimagemutex.unlock(); }
133 #else // !COIN_THREADSAFE
lock_glimage(void)134 void lock_glimage(void) { }
unlock_glimage(void)135 void unlock_glimage(void) { }
136 #endif // !COIN_THREADSAFE
137 };
138
139 // *************************************************************************
140
141 SO_NODE_SOURCE(SoVRMLPixelTexture);
142
143 // *************************************************************************
144
145 // Doc in parent
146 void
initClass(void)147 SoVRMLPixelTexture::initClass(void)
148 {
149 SO_NODE_INTERNAL_INIT_CLASS(SoVRMLPixelTexture, SO_VRML97_NODE_TYPE);
150
151 SoType type = SoVRMLPixelTexture::getClassTypeId();
152 SoRayPickAction::addMethod(type, SoNode::rayPickS);
153 }
154
155 #define PRIVATE(obj) ((obj)->pimpl)
156
157 /*!
158 Constructor.
159 */
SoVRMLPixelTexture(void)160 SoVRMLPixelTexture::SoVRMLPixelTexture(void)
161 {
162 PRIVATE(this) = new SoVRMLPixelTextureP;
163
164 SO_VRMLNODE_INTERNAL_CONSTRUCTOR(SoVRMLPixelTexture);
165
166 SO_VRMLNODE_ADD_EXPOSED_FIELD(image, (SbVec2s(0,0), 0, NULL));
167
168 PRIVATE(this)->glimage = NULL;
169 PRIVATE(this)->glimagevalid = FALSE;
170 PRIVATE(this)->readstatus = 1;
171 }
172
173 /*!
174 Destructor.
175 */
~SoVRMLPixelTexture()176 SoVRMLPixelTexture::~SoVRMLPixelTexture()
177 {
178 if (PRIVATE(this)->glimage) PRIVATE(this)->glimage->unref(NULL);
179 delete PRIVATE(this);
180 }
181
182 static SoGLImage::Wrap
pixeltexture_translate_wrap(const SbBool repeat)183 pixeltexture_translate_wrap(const SbBool repeat)
184 {
185 if (repeat) return SoGLImage::REPEAT;
186 return SoGLImage::CLAMP_TO_EDGE;
187 }
188
189 // Doc in parent
190 void
doAction(SoAction * action)191 SoVRMLPixelTexture::doAction(SoAction * action)
192 {
193 SoState * state = action->getState();
194 int unit = SoTextureUnitElement::get(state);
195
196 if (SoTextureOverrideElement::getImageOverride(state) && (unit == 0))
197 return;
198
199 int nc;
200 SbVec2s size;
201 const unsigned char * bytes = this->image.getValue(size, nc);
202
203 if (size == SbVec2s(0, 0)) {
204 SoMultiTextureEnabledElement::set(state, this, unit, FALSE);
205 }
206 else {
207 SoMultiTextureImageElement::set(state, this, unit,
208 size, nc, bytes,
209 (this->repeatS.getValue() ?
210 SoMultiTextureImageElement::REPEAT :
211 SoMultiTextureImageElement::CLAMP_TO_BORDER),
212 (this->repeatT.getValue() ?
213 SoMultiTextureImageElement::REPEAT :
214 SoMultiTextureImageElement::CLAMP_TO_BORDER),
215 SoMultiTextureImageElement::MODULATE,
216 SbColor(1.0f, 1.0f, 1.0f));
217 SoMultiTextureEnabledElement::set(state, this, unit, TRUE);
218 }
219 if (this->isOverride() && (unit == 0)) {
220 SoTextureOverrideElement::setImageOverride(state, TRUE);
221 }
222 }
223
224 void
rayPick(SoRayPickAction * action)225 SoVRMLPixelTexture::rayPick(SoRayPickAction * action)
226 {
227 SoVRMLPixelTexture::doAction(action);
228 }
229
230 // Doc in parent
231 void
GLRender(SoGLRenderAction * action)232 SoVRMLPixelTexture::GLRender(SoGLRenderAction * action)
233 {
234 SoState * state = action->getState();
235 int unit = SoTextureUnitElement::get(state);
236
237 if (SoTextureOverrideElement::getImageOverride(state) && (unit == 0))
238 return;
239
240 float quality = SoTextureQualityElement::get(state);
241
242 PRIVATE(this)->lock_glimage();
243
244 if (!PRIVATE(this)->glimagevalid) {
245 int nc;
246 SbVec2s size;
247 const unsigned char * bytes =
248 this->image.getValue(size, nc);
249 SoTextureScalePolicyElement::Policy scalepolicy =
250 SoTextureScalePolicyElement::get(state);
251 SbBool needbig = (scalepolicy == SoTextureScalePolicyElement::FRACTURE);
252
253 if (needbig &&
254 (PRIVATE(this)->glimage == NULL ||
255 PRIVATE(this)->glimage->getTypeId() != SoGLBigImage::getClassTypeId())) {
256 if (PRIVATE(this)->glimage) PRIVATE(this)->glimage->unref(state);
257 PRIVATE(this)->glimage = new SoGLBigImage();
258 }
259 else if (!needbig &&
260 (PRIVATE(this)->glimage == NULL ||
261 PRIVATE(this)->glimage->getTypeId() != SoGLImage::getClassTypeId())) {
262 if (PRIVATE(this)->glimage) PRIVATE(this)->glimage->unref(state);
263 PRIVATE(this)->glimage = new SoGLImage();
264 }
265
266 if (scalepolicy == SoTextureScalePolicyElement::SCALE_DOWN) {
267 PRIVATE(this)->glimage->setFlags(PRIVATE(this)->glimage->getFlags()|SoGLImage::SCALE_DOWN);
268 }
269
270 if (bytes && size != SbVec2s(0,0)) {
271 PRIVATE(this)->glimage->setData(bytes, size, nc,
272 pixeltexture_translate_wrap(this->repeatS.getValue()),
273 pixeltexture_translate_wrap(this->repeatT.getValue()),
274 quality);
275 PRIVATE(this)->glimagevalid = TRUE;
276 // don't cache while creating a texture object
277 SoCacheElement::setInvalid(TRUE);
278 if (state->isCacheOpen()) {
279 SoCacheElement::invalidate(state);
280 }
281 }
282 }
283
284 PRIVATE(this)->unlock_glimage();
285
286 SoGLMultiTextureImageElement::set(state, this, unit,
287 PRIVATE(this)->glimagevalid ? PRIVATE(this)->glimage : NULL,
288 SoMultiTextureImageElement::MODULATE,
289 SbColor(1.0f, 1.0f, 1.0f));
290
291 SoGLMultiTextureEnabledElement::set(state,
292 this, unit, PRIVATE(this)->glimagevalid &&
293 quality > 0.0f);
294
295 if (this->isOverride() && (unit == 0)) {
296 SoTextureOverrideElement::setImageOverride(state, TRUE);
297 }
298 }
299
300 // doc in parent
301 void
callback(SoCallbackAction * action)302 SoVRMLPixelTexture::callback(SoCallbackAction * action)
303 {
304 SoVRMLPixelTexture::doAction(action);
305 }
306
307 // doc in parent
308 SbBool
readInstance(SoInput * in,unsigned short flags)309 SoVRMLPixelTexture::readInstance(SoInput * in,
310 unsigned short flags)
311 {
312 PRIVATE(this)->glimagevalid = FALSE;
313 return inherited::readInstance(in, flags);
314 }
315
316 /*!
317 Overloaded to detect when fields change.
318 */
319 void
notify(SoNotList * list)320 SoVRMLPixelTexture::notify(SoNotList * list)
321 {
322 PRIVATE(this)->glimagevalid = FALSE;
323 SoNode::notify(list);
324 }
325
326 #undef PRIVATE
327
328 #endif // HAVE_VRML97
329