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