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 SoMultiTextureCoordinateElement Inventor/elements/SoMultiTextureCoordinateElement.h
35   \brief The SoMultiTextureCoordinateElement class is yet to be documented.
36 
37   \ingroup elements
38 
39   FIXME: write doc.
40 
41   \COIN_CLASS_EXTENSION
42 
43   \since Coin 2.2
44 */
45 
46 #include "coindefs.h"
47 #include "SbBasicP.h"
48 
49 /*! \file SoMultiTextureCoordinateElement.h */
50 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
51 #include <Inventor/elements/SoGLVBOElement.h>
52 #include <Inventor/nodes/SoNode.h>
53 #include <Inventor/lists/SbList.h>
54 #include <cassert>
55 
56 #define PRIVATE(obj) obj->pimpl
57 
UnitData()58 SoMultiTextureCoordinateElement::UnitData::UnitData()
59   : nodeid(0),
60     whatKind(DEFAULT),
61     funcCB(NULL),
62     funcCBData(NULL),
63     numCoords(0),
64     coords2(NULL),
65     coords3(NULL),
66     coords4(NULL),
67     coordsDimension(2)
68 {
69 }
70 
UnitData(const UnitData & org)71 SoMultiTextureCoordinateElement::UnitData::UnitData(const UnitData & org)
72   : nodeid(org.nodeid),
73     whatKind(org.whatKind),
74     funcCB(org.funcCB),
75     funcCBData(org.funcCBData),
76     numCoords(org.numCoords),
77     coords2(org.coords2),
78     coords3(org.coords3),
79     coords4(org.coords4),
80     coordsDimension(org.coordsDimension)
81 {
82 }
83 
84 class SoMultiTextureCoordinateElementP {
85 public:
86   mutable SbList<SoMultiTextureCoordinateElement::UnitData> unitdata;
87 
ensureCapacity(int units) const88   void ensureCapacity(int units) const {
89     for (int i = this->unitdata.getLength(); i <= units; i++) {
90       this->unitdata.append(SoMultiTextureCoordinateElement::UnitData());
91     }
92   }
93 };
94 
95 SO_ELEMENT_CUSTOM_CONSTRUCTOR_SOURCE(SoMultiTextureCoordinateElement);
96 
97 /*!
98   This static method initializes static data for the
99   SoMultiTextureCoordinateElement class.
100 */
101 
102 void
initClass()103 SoMultiTextureCoordinateElement::initClass()
104 {
105   SO_ELEMENT_INIT_CLASS(SoMultiTextureCoordinateElement, inherited);
106 }
107 
108 
109 /*!
110   The constructor.
111 */
SoMultiTextureCoordinateElement(void)112 SoMultiTextureCoordinateElement::SoMultiTextureCoordinateElement(void)
113 {
114   PRIVATE(this) = new SoMultiTextureCoordinateElementP;
115 
116   this->setTypeId(SoMultiTextureCoordinateElement::classTypeId);
117   this->setStackIndex(SoMultiTextureCoordinateElement::classStackIndex);
118 }
119 
120 /*!
121   The destructor.
122 */
123 
~SoMultiTextureCoordinateElement()124 SoMultiTextureCoordinateElement::~SoMultiTextureCoordinateElement()
125 {
126   delete PRIVATE(this);
127 }
128 
129 //! FIXME: write doc.
130 
131 void
setDefault(SoState * const state,SoNode * const COIN_UNUSED_ARG (node),const int unit)132 SoMultiTextureCoordinateElement::setDefault(SoState * const state,
133                                             SoNode * const COIN_UNUSED_ARG(node),
134                                             const int unit)
135 {
136   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
137     SoGLVBOElement::setTexCoordVBO(state, unit, NULL);
138   }
139   SoMultiTextureCoordinateElement * element =
140     coin_assert_cast<SoMultiTextureCoordinateElement *>
141     (SoElement::getElement(state, classStackIndex));
142 
143   PRIVATE(element)->ensureCapacity(unit);
144   UnitData & ud = PRIVATE(element)->unitdata[unit];
145   ud.nodeid = 0;
146   ud.whatKind = DEFAULT;
147   ud.numCoords = 0;
148 }
149 
150 //! FIXME: write doc.
151 
152 void
setFunction(SoState * const state,SoNode * const node,const int unit,SoTextureCoordinateFunctionCB * const func,void * const userdata)153 SoMultiTextureCoordinateElement::setFunction(SoState * const state,
154                                              SoNode * const node,
155                                              const int unit,
156                                              SoTextureCoordinateFunctionCB * const func,
157                                              void * const userdata)
158 {
159   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
160     SoGLVBOElement::setTexCoordVBO(state, unit, NULL);
161   }
162 
163   SoMultiTextureCoordinateElement * element =
164     coin_assert_cast<SoMultiTextureCoordinateElement *>
165     (SoElement::getElement(state, classStackIndex));
166 
167   PRIVATE(element)->ensureCapacity(unit);
168   UnitData & ud = PRIVATE(element)->unitdata[unit];
169 
170   ud.nodeid = node->getNodeId();
171   ud.funcCB = func;
172   ud.funcCBData = userdata;
173   ud.whatKind = FUNCTION;
174   ud.coords2 = NULL;
175   ud.coords3 = NULL;
176   ud.coords4 = NULL;
177   ud.numCoords = 0;
178 }
179 
180 //! FIXME: write doc.
181 
182 void
set2(SoState * const state,SoNode * const node,const int unit,const int32_t numCoords,const SbVec2f * const coords)183 SoMultiTextureCoordinateElement::set2(SoState * const state,
184                                       SoNode * const node,
185                                       const int unit,
186                                       const int32_t numCoords,
187                                       const SbVec2f * const coords)
188 {
189   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
190     SoGLVBOElement::setTexCoordVBO(state, unit, NULL);
191   }
192   SoMultiTextureCoordinateElement * element = coin_assert_cast<SoMultiTextureCoordinateElement *>
193     (
194      SoElement::getElement(state, classStackIndex)
195      );
196 
197   PRIVATE(element)->ensureCapacity(unit);
198   UnitData & ud = PRIVATE(element)->unitdata[unit];
199 
200   ud.nodeid = node->getNodeId();
201   ud.coordsDimension = 2;
202   ud.numCoords = numCoords;
203   ud.coords2 = coords;
204   ud.coords3 = NULL;
205   ud.coords4 = NULL;
206   ud.whatKind = EXPLICIT;
207 }
208 
209 /*!
210   FIXME: write doc.
211 */
212 void
set3(SoState * const state,SoNode * const node,const int unit,const int32_t numCoords,const SbVec3f * const coords)213 SoMultiTextureCoordinateElement::set3(SoState * const state,
214                                       SoNode * const node,
215                                       const int unit,
216                                       const int32_t numCoords,
217                                       const SbVec3f * const coords)
218 {
219   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
220     SoGLVBOElement::setTexCoordVBO(state, unit, NULL);
221   }
222   SoMultiTextureCoordinateElement * element =
223     coin_assert_cast<SoMultiTextureCoordinateElement *>
224     (
225      SoElement::getElement(state, classStackIndex)
226      );
227 
228   PRIVATE(element)->ensureCapacity(unit);
229   UnitData & ud = PRIVATE(element)->unitdata[unit];
230 
231   ud.nodeid = node->getNodeId();
232   ud.coordsDimension = 3;
233   ud.numCoords = numCoords;
234   ud.coords2 = NULL;
235   ud.coords3 = coords;
236   ud.coords4 = NULL;
237   ud.whatKind = EXPLICIT;
238 }
239 
240 //! FIXME: write doc.
241 
242 void
set4(SoState * const state,SoNode * const node,const int unit,const int32_t numCoords,const SbVec4f * const coords)243 SoMultiTextureCoordinateElement::set4(SoState * const state,
244                                       SoNode * const node,
245                                       const int unit,
246                                       const int32_t numCoords,
247                                       const SbVec4f * const coords)
248 {
249   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
250     SoGLVBOElement::setTexCoordVBO(state, unit, NULL);
251   }
252   SoMultiTextureCoordinateElement * element =
253     coin_assert_cast<SoMultiTextureCoordinateElement *>
254     (
255      SoElement::getElement(state, classStackIndex)
256      );
257 
258   PRIVATE(element)->ensureCapacity(unit);
259   UnitData & ud = PRIVATE(element)->unitdata[unit];
260 
261   ud.nodeid = node->getNodeId();
262   ud.coordsDimension = 4;
263   ud.numCoords = numCoords;
264   ud.coords2 = NULL;
265   ud.coords3 = NULL;
266   ud.coords4 = coords;
267   ud.whatKind = EXPLICIT;
268 }
269 
270 //! FIXME: write doc.
271 
272 const SoMultiTextureCoordinateElement *
getInstance(SoState * const state)273 SoMultiTextureCoordinateElement::getInstance(SoState * const state)
274 {
275   return coin_safe_cast<const SoMultiTextureCoordinateElement *>
276     (getConstElement(state, classStackIndex));
277 }
278 
279 /*!
280   This method returns texture coordinate for the given point and normal.
281   The coordinate is returned as a 4D vector where the r and q coordinates
282   may be set to 0 and 1 respecively depending on what texture coordinate
283   dimension we're using.
284 
285   This method should only be used if the CoordType is FUNCTION.
286 */
287 
288 const SbVec4f &
get(const int unit,const SbVec3f & point,const SbVec3f & normal) const289 SoMultiTextureCoordinateElement::get(const int unit,
290                                      const SbVec3f & point,
291                                      const SbVec3f & normal) const
292 {
293   assert(unit < PRIVATE(this)->unitdata.getLength());
294   const UnitData & ud = PRIVATE(this)->unitdata[unit];
295 
296   assert((ud.whatKind == FUNCTION ||
297           ud.whatKind == TEXGEN) && ud.funcCB);
298   return (*(ud.funcCB))(ud.funcCBData, point, normal);
299 }
300 
301 //! FIXME: write doc.
302 
303 const SbVec2f &
get2(const int unit,const int index) const304 SoMultiTextureCoordinateElement::get2(const int unit, const int index) const
305 {
306   assert(unit < PRIVATE(this)->unitdata.getLength());
307   const UnitData & ud = PRIVATE(this)->unitdata[unit];
308 
309   assert(index >= 0 && index < ud.numCoords);
310   assert(ud.whatKind == EXPLICIT);
311   if (ud.coordsDimension == 2) {
312     return ud.coords2[index];
313   }
314   else {
315     // need an instance we can write to
316     SoMultiTextureCoordinateElement * elem = const_cast<SoMultiTextureCoordinateElement *>(this);
317 
318     if (ud.coordsDimension == 4) {
319       float tmp = ud.coords4[index][3];
320       float to2D = tmp == 0.0f ? 1.0f : 1.0f / tmp;
321 
322       elem->convert2.setValue(ud.coords4[index][0] * to2D,
323                               ud.coords4[index][1] * to2D);
324     }
325     else { // coordsDimension == 3
326       elem->convert2.setValue(ud.coords3[index][0],
327                               ud.coords3[index][1]);
328     }
329     return this->convert2;
330   }
331 }
332 
333 /*!
334   FIXME: write doc.
335 
336 */
337 const SbVec3f &
get3(const int unit,const int index) const338 SoMultiTextureCoordinateElement::get3(const int unit, const int index) const
339 {
340   assert(unit < PRIVATE(this)->unitdata.getLength());
341   const UnitData & ud = PRIVATE(this)->unitdata[unit];
342 
343   assert(index >= 0 && index < ud.numCoords);
344   assert(ud.whatKind == EXPLICIT);
345   if (ud.coordsDimension == 3) {
346     return ud.coords3[index];
347   }
348   else {
349     // need an instance we can write to
350     SoMultiTextureCoordinateElement * elem =
351       const_cast<SoMultiTextureCoordinateElement *>(this);
352 
353     if (ud.coordsDimension==2) {
354       elem->convert3.setValue(ud.coords2[index][0],
355                               ud.coords2[index][1],
356                               0.0f);
357     }
358     else { // this->coordsDimension==4
359       ud.coords4[index].getReal(elem->convert3);
360     }
361     return this->convert3;
362   }
363 }
364 
365 //!  FIXME: write doc.
366 
367 const SbVec4f &
get4(const int unit,const int index) const368 SoMultiTextureCoordinateElement::get4(const int unit, const int index) const
369 {
370   assert(unit < PRIVATE(this)->unitdata.getLength());
371   const UnitData & ud = PRIVATE(this)->unitdata[unit];
372 
373   assert(index >= 0 && index < ud.numCoords);
374   assert(ud.whatKind == EXPLICIT);
375   if (ud.coordsDimension==4) {
376     return ud.coords4[index];
377   }
378   else {
379     // need an instance we can write to
380     SoMultiTextureCoordinateElement * elem =
381       const_cast<SoMultiTextureCoordinateElement *>(this);
382     if (ud.coordsDimension == 2) {
383       elem->convert4.setValue(ud.coords2[index][0],
384                               ud.coords2[index][1],
385                               0.0f,
386                               1.0f);
387     }
388     else { // this->coordsDimension==3
389       elem->convert4.setValue(ud.coords3[index][0],
390                               ud.coords3[index][1],
391                               ud.coords3[index][2],
392                               1.0f);
393     }
394     return this->convert4;
395   }
396 }
397 
398 /*!
399   This method is used by shapes.  Three return values are possible.
400 
401   DEFAULT means that the shapes should generate their own texture coordinates.
402 
403   EXPLICIT means that discrete texture coordinates are stored, and should be
404   fetched with get2(), get3() or get4().
405 
406   FUNCTION means that get(point, normal) must be used to generate texture
407   coordinates.
408 */
409 
410 SoMultiTextureCoordinateElement::CoordType
getType(SoState * const state,const int unit)411 SoMultiTextureCoordinateElement::getType(SoState * const state, const int unit)
412 {
413   const SoMultiTextureCoordinateElement * element =
414     coin_assert_cast<const SoMultiTextureCoordinateElement *>
415     (getConstElement(state, classStackIndex));
416   return element->getType(unit);
417 }
418 
419 //! FIXME: write doc.
420 
421 // side effect, will increase array size
422 SoMultiTextureCoordinateElement::CoordType
getType(const int unit) const423 SoMultiTextureCoordinateElement::getType(const int unit) const
424 {
425   PRIVATE(this)->ensureCapacity(unit);
426   const UnitData & ud = PRIVATE(this)->unitdata[unit];
427   return ud.whatKind;
428 }
429 
430 //! FIXME: write doc.
431 
432 void
init(SoState * state)433 SoMultiTextureCoordinateElement::init(SoState * state)
434 {
435   inherited::init(state);
436   PRIVATE(this)->unitdata.truncate(0);
437 }
438 
439 //! FIXME: write doc.
440 
441 //$ EXPORT INLINE
442 int32_t
getNum(const int unit) const443 SoMultiTextureCoordinateElement::getNum(const int unit) const
444 {
445   PRIVATE(this)->ensureCapacity(unit);
446   const UnitData & ud = PRIVATE(this)->unitdata[unit];
447   return ud.numCoords;
448 }
449 
450 //! FIXME: write doc. (for backwards compability. Use getDimension() instead).
451 
452 //$ EXPORT INLINE
453 SbBool
is2D(const int unit) const454 SoMultiTextureCoordinateElement::is2D(const int unit) const
455 {
456   assert(unit < PRIVATE(this)->unitdata.getLength());
457   const UnitData & ud = PRIVATE(this)->unitdata[unit];
458   return (ud.coordsDimension==2);
459 }
460 
461 /*!
462   FIXME: write doc.
463 */
464 int32_t
getDimension(const int unit) const465 SoMultiTextureCoordinateElement::getDimension(const int unit) const
466 {
467   assert(unit < PRIVATE(this)->unitdata.getLength());
468   const UnitData & ud = PRIVATE(this)->unitdata[unit];
469   return ud.coordsDimension;
470 }
471 
472 /*!
473   Returns a pointer to the 2D texture coordinate array. This method is not
474   part of the OIV API.
475 */
476 const SbVec2f *
getArrayPtr2(const int unit) const477 SoMultiTextureCoordinateElement::getArrayPtr2(const int unit) const
478 {
479   assert(unit < PRIVATE(this)->unitdata.getLength());
480   const UnitData & ud = PRIVATE(this)->unitdata[unit];
481   return ud.coords2;
482 }
483 
484 /*!
485   Returns a pointer to the 3D texture coordinate array.
486 
487 */
488 const SbVec3f *
getArrayPtr3(const int unit) const489 SoMultiTextureCoordinateElement::getArrayPtr3(const int unit) const
490 {
491   assert(unit < PRIVATE(this)->unitdata.getLength());
492   const UnitData & ud = PRIVATE(this)->unitdata[unit];
493   return ud.coords3;
494 }
495 
496 /*!
497   Returns a pointer to the 4D texture coordinate array. This method is not
498   part of the OIV API.
499 */
500 const SbVec4f *
getArrayPtr4(const int unit) const501 SoMultiTextureCoordinateElement::getArrayPtr4(const int unit) const
502 {
503   assert(unit < PRIVATE(this)->unitdata.getLength());
504   const UnitData & ud = PRIVATE(this)->unitdata[unit];
505   return ud.coords4;
506 }
507 
508 void
push(SoState * COIN_UNUSED_ARG (state))509 SoMultiTextureCoordinateElement::push(SoState * COIN_UNUSED_ARG(state))
510 {
511   SoMultiTextureCoordinateElement * prev =
512     coin_assert_cast<SoMultiTextureCoordinateElement *>
513     (this->getNextInStack());
514 
515   PRIVATE(this)->unitdata = PRIVATE(prev)->unitdata;
516 }
517 
518 SbBool
matches(const SoElement * elem) const519 SoMultiTextureCoordinateElement::matches(const SoElement * elem) const
520 {
521   const SoMultiTextureCoordinateElement * e =
522     coin_assert_cast<const SoMultiTextureCoordinateElement *>(elem);
523   if (PRIVATE(e)->unitdata.getLength() != PRIVATE(this)->unitdata.getLength()) return FALSE;
524 
525   for (int i = 0; i < PRIVATE(this)->unitdata.getLength(); i++) {
526     if (PRIVATE(e)->unitdata[i].nodeid != PRIVATE(this)->unitdata[i].nodeid) {
527       return FALSE;
528     }
529   }
530   return TRUE;
531 }
532 
533 SoElement *
copyMatchInfo(void) const534 SoMultiTextureCoordinateElement::copyMatchInfo(void) const
535 {
536   SoMultiTextureCoordinateElement * elem =
537     static_cast<SoMultiTextureCoordinateElement *>(getTypeId().createInstance());
538   PRIVATE(elem)->unitdata = PRIVATE(this)->unitdata;
539   return elem;
540 }
541 
542 /*!
543   Returns the per-unit data for this element.
544 */
545 SoMultiTextureCoordinateElement::UnitData &
getUnitData(const int unit)546 SoMultiTextureCoordinateElement::getUnitData(const int unit)
547 {
548   assert(unit < PRIVATE(this)->unitdata.getLength());
549   return PRIVATE(this)->unitdata[unit];
550 }
551 
552 const SoMultiTextureCoordinateElement::UnitData &
getUnitData(const int unit) const553 SoMultiTextureCoordinateElement::getUnitData(const int unit) const
554 {
555   assert(unit < PRIVATE(this)->unitdata.getLength());
556   return PRIVATE(this)->unitdata[unit];
557 }
558 
559 int
getMaxUnits() const560 SoMultiTextureCoordinateElement::getMaxUnits() const
561 {
562   return PRIVATE(this)->unitdata.getLength();
563 }
564 
565 #undef PRIVATE
566