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