1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12 */
13 #include <osg/GL>
14 #include <osg/GLU>
15
16 #include <osg/Image>
17 #include <osg/Notify>
18 #include <osg/io_utils>
19
20 #include <osg/Geode>
21 #include <osg/Geometry>
22 #include <osg/StateSet>
23 #include <osg/Texture1D>
24 #include <osg/Texture2D>
25 #include <osg/Texture3D>
26 #include <osg/Texture2DArray>
27 #include <osg/TextureCubeMap>
28 #include <osg/Light>
29
30 #include <algorithm>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include "dxtctool.h"
35
36 using namespace osg;
37 using namespace std;
38
operator ()(osg::StateAttribute * attr,osg::NodeVisitor * nv)39 void Image::UpdateCallback::operator () (osg::StateAttribute* attr, osg::NodeVisitor* nv)
40 {
41 osg::Texture* texture = attr ? attr->asTexture() : 0;
42
43 // OSG_NOTICE<<"ImageSequence::UpdateCallback::"<<texture<<std::endl;
44 if (texture)
45 {
46 for(unsigned int i=0; i<texture->getNumImages(); ++i)
47 {
48 texture->getImage(i)->update(nv);
49 }
50 }
51 }
52
DataIterator(const Image * image)53 Image::DataIterator::DataIterator(const Image* image):
54 _image(image),
55 _rowNum(0),
56 _imageNum(0),
57 _mipmapNum(0),
58 _currentPtr(0),
59 _currentSize(0)
60 {
61 assign();
62 }
63
DataIterator(const DataIterator & ri)64 Image::DataIterator::DataIterator(const DataIterator& ri):
65 _image(ri._image),
66 _rowNum(ri._rowNum),
67 _imageNum(ri._imageNum),
68 _mipmapNum(ri._mipmapNum),
69 _currentPtr(0),
70 _currentSize(0)
71 {
72 assign();
73 }
74
operator ++()75 void Image::DataIterator::operator ++ ()
76 {
77 if (!_image || _image->isDataContiguous())
78 {
79 // for contiguous image data we never need more than one block of data
80 _currentPtr = 0;
81 _currentSize = 0;
82 return;
83 }
84
85 if (_image->isMipmap())
86 {
87 // advance to next row
88 ++_rowNum;
89
90 if (_rowNum>=_image->t())
91 {
92 // moved over end of current image so move to next
93 _rowNum = 0;
94 ++_imageNum;
95
96 if (_imageNum>=_image->r())
97 {
98 // move to next mipmap
99 _imageNum = 0;
100 ++_mipmapNum;
101
102 if (_mipmapNum>=_image->getNumMipmapLevels())
103 {
104 _currentPtr = 0;
105 _currentSize = 0;
106 return;
107 }
108 }
109 }
110 }
111 else
112 {
113 // advance to next row
114 ++_rowNum;
115
116 if (_rowNum>=_image->t())
117 {
118 // moved over end of current image so move to next
119 _rowNum = 0;
120 ++_imageNum;
121
122 if (_imageNum>=_image->r())
123 {
124 // we've moved off the end of the osg::Image so reset to null
125 _currentPtr = 0;
126 _currentSize = 0;
127 return;
128 }
129 }
130 }
131
132 assign();
133 }
134
assign()135 void Image::DataIterator::assign()
136 {
137 //OSG_NOTICE<<"DataIterator::assign A"<<std::endl;
138 if (!_image)
139 {
140 _currentPtr = 0;
141 _currentSize = 0;
142 return;
143 }
144
145 //OSG_NOTICE<<"DataIterator::assign B"<<std::endl;
146
147 if (_image->isDataContiguous())
148 {
149 _currentPtr = _image->data();
150 _currentSize = _image->getTotalSizeInBytesIncludingMipmaps();
151
152 //OSG_NOTICE<<" _currentPtr="<<(void*)_currentPtr<<std::endl;
153 //OSG_NOTICE<<" _currentSize="<<_currentSize<<std::endl;
154
155 return;
156 }
157
158 //OSG_NOTICE<<"DataIterator::assign C"<<std::endl;
159
160 if (_image->isMipmap())
161 {
162 //OSG_NOTICE<<"DataIterator::assign D"<<std::endl;
163
164 if (_mipmapNum>=_image->getNumMipmapLevels())
165 {
166 _currentPtr = 0;
167 _currentSize = 0;
168 return;
169 }
170 const unsigned char* ptr = _image->getMipmapData(_mipmapNum);
171
172 int rowLength = _image->getRowLength()>>_mipmapNum;
173 if (rowLength==0) rowLength = 1;
174
175 int imageHeight = _image->t()>>_mipmapNum;
176 if (imageHeight==0) imageHeight = 1;
177
178 unsigned int rowWidthInBytes = Image::computeRowWidthInBytes(rowLength,_image->getPixelFormat(),_image->getDataType(),_image->getPacking());
179 unsigned int imageSizeInBytes = rowWidthInBytes*imageHeight;
180
181 _currentPtr = ptr + rowWidthInBytes*_rowNum + imageSizeInBytes*_imageNum;
182 _currentSize = rowWidthInBytes;
183 }
184 else
185 {
186 //OSG_NOTICE<<"DataIterator::assign E"<<std::endl;
187
188 if (_imageNum>=_image->r() || _rowNum>=_image->t())
189 {
190 _currentPtr = 0;
191 _currentSize = 0;
192 return;
193 }
194
195 //OSG_NOTICE<<"DataIterator::assign F"<<std::endl;
196
197 _currentPtr = _image->data(0, _rowNum, _imageNum);
198 _currentSize = _image->getRowSizeInBytes();
199 return;
200 }
201 }
202
203
Image()204 Image::Image()
205 :BufferData(),
206 _fileName(""),
207 _writeHint(NO_PREFERENCE),
208 _origin(BOTTOM_LEFT),
209 _s(0), _t(0), _r(0),
210 _rowLength(0),
211 _internalTextureFormat(0),
212 _pixelFormat(0),
213 _dataType(0),
214 _packing(4),
215 _pixelAspectRatio(1.0),
216 _allocationMode(USE_NEW_DELETE),
217 _data(0L),
218 _dimensionsChangedCallbacks()
219 {
220 setDataVariance(STATIC);
221 }
222
Image(const Image & image,const CopyOp & copyop)223 Image::Image(const Image& image,const CopyOp& copyop):
224 BufferData(image,copyop),
225 _fileName(image._fileName),
226 _writeHint(image._writeHint),
227 _origin(image._origin),
228 _s(image._s), _t(image._t), _r(image._r),
229 _rowLength(0),
230 _internalTextureFormat(image._internalTextureFormat),
231 _pixelFormat(image._pixelFormat),
232 _dataType(image._dataType),
233 _packing(image._packing),
234 _pixelAspectRatio(image._pixelAspectRatio),
235 _allocationMode(USE_NEW_DELETE),
236 _data(0L),
237 _mipmapData(image._mipmapData),
238 _dimensionsChangedCallbacks(image._dimensionsChangedCallbacks)
239 {
240 if (image._data)
241 {
242 unsigned int size = image.getTotalSizeInBytesIncludingMipmaps();
243 setData(new unsigned char [size],USE_NEW_DELETE);
244 if (unsigned char* dest_ptr = _data)
245 {
246 for(DataIterator itr(&image); itr.valid(); ++itr)
247 {
248 memcpy(dest_ptr, itr.data(), itr.size());
249 dest_ptr += itr.size();
250 }
251 }
252 else
253 {
254 OSG_WARN<<"Warning: Image::Image(const Image&, const CopyOp&) out of memory, no image copy made."<<std::endl;
255 }
256 }
257 }
258
~Image()259 Image::~Image()
260 {
261 deallocateData();
262 }
263
deallocateData()264 void Image::deallocateData()
265 {
266 if (_data) {
267 if (_allocationMode==USE_NEW_DELETE) delete [] _data;
268 else if (_allocationMode==USE_MALLOC_FREE) ::free(_data);
269 _data = 0;
270 }
271 }
272
compare(const Image & rhs) const273 int Image::compare(const Image& rhs) const
274 {
275 // if at least one filename is empty, then need to test buffer
276 // pointers because images could have been created on the fly
277 // and therefore we can't rely on file names to get an accurate
278 // comparison
279 if (getFileName().empty() || rhs.getFileName().empty())
280 {
281 if (_data<rhs._data) return -1;
282 if (_data>rhs._data) return 1;
283 }
284
285 // need to test against image contents here...
286 COMPARE_StateAttribute_Parameter(_s)
287 COMPARE_StateAttribute_Parameter(_t)
288 COMPARE_StateAttribute_Parameter(_internalTextureFormat)
289 COMPARE_StateAttribute_Parameter(_pixelFormat)
290 COMPARE_StateAttribute_Parameter(_dataType)
291 COMPARE_StateAttribute_Parameter(_packing)
292 COMPARE_StateAttribute_Parameter(_mipmapData)
293 COMPARE_StateAttribute_Parameter(_modifiedCount)
294
295 // same buffer + same parameters = same image
296 if ((_data || rhs._data) && (_data == rhs._data)) return 0;
297
298 // slowest comparison at the bottom!
299 COMPARE_StateAttribute_Parameter(getFileName())
300
301 return 0;
302 }
303
setFileName(const std::string & fileName)304 void Image::setFileName(const std::string& fileName)
305 {
306 _fileName = fileName;
307 }
308
setData(unsigned char * data,AllocationMode mode)309 void Image::setData(unsigned char* data, AllocationMode mode)
310 {
311 deallocateData();
312 _data = data;
313 _allocationMode = mode;
314 dirty();
315 }
316
317
isPackedType(GLenum type)318 bool Image::isPackedType(GLenum type)
319 {
320 switch(type)
321 {
322 case(GL_UNSIGNED_BYTE_3_3_2):
323 case(GL_UNSIGNED_BYTE_2_3_3_REV):
324 case(GL_UNSIGNED_SHORT_5_6_5):
325 case(GL_UNSIGNED_SHORT_5_6_5_REV):
326 case(GL_UNSIGNED_SHORT_4_4_4_4):
327 case(GL_UNSIGNED_SHORT_4_4_4_4_REV):
328 case(GL_UNSIGNED_SHORT_5_5_5_1):
329 case(GL_UNSIGNED_SHORT_1_5_5_5_REV):
330 case(GL_UNSIGNED_INT_8_8_8_8):
331 case(GL_UNSIGNED_INT_8_8_8_8_REV):
332 case(GL_UNSIGNED_INT_10_10_10_2):
333 case(GL_UNSIGNED_INT_2_10_10_10_REV): return true;
334 default: return false;
335 }
336 }
337
338
computePixelFormat(GLenum format)339 GLenum Image::computePixelFormat(GLenum format)
340 {
341 switch(format)
342 {
343 case(GL_ALPHA16F_ARB):
344 case(GL_ALPHA32F_ARB):
345 return GL_ALPHA;
346
347 case(GL_LUMINANCE16F_ARB):
348 case(GL_LUMINANCE32F_ARB):
349 return GL_LUMINANCE;
350
351 case(GL_INTENSITY16F_ARB):
352 case(GL_INTENSITY32F_ARB):
353 return GL_INTENSITY;
354
355 case(GL_LUMINANCE_ALPHA16F_ARB):
356 case(GL_LUMINANCE_ALPHA32F_ARB):
357 return GL_LUMINANCE_ALPHA;
358
359 case (GL_R16F):
360 case (GL_R32F):
361 case (GL_R8):
362 case (GL_R8_SNORM):
363 case (GL_R16):
364 case (GL_R16_SNORM):
365 return GL_RED;
366
367 case (GL_R8I):
368 case (GL_R8UI):
369 case (GL_R16I):
370 case (GL_R16UI):
371 case (GL_R32I):
372 case (GL_R32UI):
373 return GL_RED_INTEGER_EXT;
374
375 case (GL_RG16F):
376 case (GL_RG32F):
377 case (GL_RG8):
378 case (GL_RG8_SNORM):
379 case (GL_RG16):
380 case (GL_RG16_SNORM):
381 return GL_RG;
382
383 case (GL_RG8I):
384 case (GL_RG8UI):
385 case (GL_RG16I):
386 case (GL_RG16UI):
387 case (GL_RG32I):
388 case (GL_RG32UI):
389 return GL_RG_INTEGER;
390
391 case(GL_RGB32F_ARB):
392 case(GL_RGB16F_ARB):
393 case(GL_R3_G3_B2):
394 case(GL_RGB4):
395 case(GL_RGB5):
396 case(GL_RGB8):
397 case(GL_RGB8_SNORM):
398 case(GL_RGB10):
399 case(GL_RGB12):
400 case(GL_SRGB8):
401 return GL_RGB;
402
403 case(GL_RGBA8):
404 case(GL_RGBA16):
405 case(GL_RGBA32F_ARB):
406 case(GL_RGBA16F_ARB):
407 case(GL_RGBA8_SNORM):
408 case(GL_RGB10_A2):
409 case(GL_RGBA12):
410 case(GL_SRGB8_ALPHA8):
411 return GL_RGBA;
412
413 case(GL_ALPHA8I_EXT):
414 case(GL_ALPHA16I_EXT):
415 case(GL_ALPHA32I_EXT):
416 case(GL_ALPHA8UI_EXT):
417 case(GL_ALPHA16UI_EXT):
418 case(GL_ALPHA32UI_EXT):
419 return GL_ALPHA_INTEGER_EXT;
420
421 case(GL_LUMINANCE8I_EXT):
422 case(GL_LUMINANCE16I_EXT):
423 case(GL_LUMINANCE32I_EXT):
424 case(GL_LUMINANCE8UI_EXT):
425 case(GL_LUMINANCE16UI_EXT):
426 case(GL_LUMINANCE32UI_EXT):
427 return GL_LUMINANCE_INTEGER_EXT;
428
429 case(GL_INTENSITY8I_EXT):
430 case(GL_INTENSITY16I_EXT):
431 case(GL_INTENSITY32I_EXT):
432 case(GL_INTENSITY8UI_EXT):
433 case(GL_INTENSITY16UI_EXT):
434 case(GL_INTENSITY32UI_EXT):
435 OSG_WARN<<"Image::computePixelFormat("<<std::hex<<format<<std::dec<<") intensity pixel format is not correctly specified, so assume GL_LUMINANCE_INTEGER."<<std::endl;
436 return GL_LUMINANCE_INTEGER_EXT;
437
438 case(GL_LUMINANCE_ALPHA8I_EXT):
439 case(GL_LUMINANCE_ALPHA16I_EXT):
440 case(GL_LUMINANCE_ALPHA32I_EXT):
441 case(GL_LUMINANCE_ALPHA8UI_EXT):
442 case(GL_LUMINANCE_ALPHA16UI_EXT):
443 case(GL_LUMINANCE_ALPHA32UI_EXT):
444 return GL_LUMINANCE_ALPHA_INTEGER_EXT;
445
446 case(GL_RGB32I_EXT):
447 case(GL_RGB16I_EXT):
448 case(GL_RGB8I_EXT):
449 case(GL_RGB32UI_EXT):
450 case(GL_RGB16UI_EXT):
451 case(GL_RGB8UI_EXT):
452 return GL_RGB_INTEGER_EXT;
453
454 case(GL_RGBA32I_EXT):
455 case(GL_RGBA16I_EXT):
456 case(GL_RGBA8I_EXT):
457 case(GL_RGBA32UI_EXT):
458 case(GL_RGBA16UI_EXT):
459 case(GL_RGBA8UI_EXT):
460 return GL_RGBA_INTEGER_EXT;
461
462 case(GL_DEPTH_COMPONENT16):
463 case(GL_DEPTH_COMPONENT24):
464 case(GL_DEPTH_COMPONENT32):
465 case(GL_DEPTH_COMPONENT32F):
466 case(GL_DEPTH_COMPONENT32F_NV):
467 return GL_DEPTH_COMPONENT;
468
469 default:
470 return format;
471 }
472 }
473
computeFormatDataType(GLenum pixelFormat)474 GLenum Image::computeFormatDataType(GLenum pixelFormat)
475 {
476 switch (pixelFormat)
477 {
478 case GL_R32F:
479 case GL_RG32F:
480 case GL_LUMINANCE32F_ARB:
481 case GL_LUMINANCE16F_ARB:
482 case GL_LUMINANCE_ALPHA32F_ARB:
483 case GL_LUMINANCE_ALPHA16F_ARB:
484 case GL_RGB32F_ARB:
485 case GL_RGB16F_ARB:
486 case GL_RGBA32F_ARB:
487 case GL_RGBA16F_ARB: return GL_FLOAT;
488
489 case GL_RGBA32UI_EXT:
490 case GL_RGB32UI_EXT:
491 case GL_LUMINANCE32UI_EXT:
492 case GL_LUMINANCE_ALPHA32UI_EXT: return GL_UNSIGNED_INT;
493
494 case GL_RGB16UI_EXT:
495 case GL_RGBA16UI_EXT:
496 case GL_LUMINANCE16UI_EXT:
497 case GL_LUMINANCE_ALPHA16UI_EXT: return GL_UNSIGNED_SHORT;
498
499 case GL_RGBA8UI_EXT:
500 case GL_RGB8UI_EXT:
501 case GL_LUMINANCE8UI_EXT:
502 case GL_LUMINANCE_ALPHA8UI_EXT: return GL_UNSIGNED_BYTE;
503
504 case GL_RGBA32I_EXT:
505 case GL_RGB32I_EXT:
506 case GL_LUMINANCE32I_EXT:
507 case GL_LUMINANCE_ALPHA32I_EXT: return GL_INT;
508
509 case GL_RGBA16I_EXT:
510 case GL_RGB16I_EXT:
511 case GL_LUMINANCE16I_EXT:
512 case GL_LUMINANCE_ALPHA16I_EXT: return GL_SHORT;
513
514 case GL_RGB8I_EXT:
515 case GL_RGBA8I_EXT:
516 case GL_LUMINANCE8I_EXT:
517 case GL_LUMINANCE_ALPHA8I_EXT: return GL_BYTE;
518
519 case GL_RGBA:
520 case GL_RGB:
521 case GL_RED:
522 case GL_RG:
523 case GL_LUMINANCE:
524 case GL_LUMINANCE_ALPHA:
525 case GL_ALPHA: return GL_UNSIGNED_BYTE;
526
527 default:
528 {
529 OSG_WARN<<"error computeFormatType = "<<std::hex<<pixelFormat<<std::dec<<std::endl;
530 return 0;
531 }
532 }
533 }
534
computeNumComponents(GLenum pixelFormat)535 unsigned int Image::computeNumComponents(GLenum pixelFormat)
536 {
537 switch(pixelFormat)
538 {
539 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): return 3;
540 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): return 4;
541 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): return 4;
542 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): return 4;
543 case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT): return 1;
544 case(GL_COMPRESSED_RED_RGTC1_EXT): return 1;
545 case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): return 2;
546 case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): return 2;
547 case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): return 3;
548 case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): return 3;
549 case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): return 4;
550 case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): return 4;
551 case(GL_ETC1_RGB8_OES): return 3;
552 case(GL_COMPRESSED_RGB8_ETC2): return 3;
553 case(GL_COMPRESSED_SRGB8_ETC2): return 3;
554 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2): return 4;
555 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2): return 4;
556 case(GL_COMPRESSED_RGBA8_ETC2_EAC): return 4;
557 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC): return 4;
558 case(GL_COMPRESSED_R11_EAC): return 1;
559 case(GL_COMPRESSED_SIGNED_R11_EAC): return 1;
560 case(GL_COMPRESSED_RG11_EAC): return 2;
561 case(GL_COMPRESSED_SIGNED_RG11_EAC): return 2;
562 case(GL_COLOR_INDEX): return 1;
563 case(GL_STENCIL_INDEX): return 1;
564 case(GL_DEPTH_COMPONENT): return 1;
565 case(GL_DEPTH_COMPONENT16): return 1;
566 case(GL_DEPTH_COMPONENT24): return 1;
567 case(GL_DEPTH_COMPONENT32): return 1;
568 case(GL_DEPTH_COMPONENT32F): return 1;
569 case(GL_DEPTH_COMPONENT32F_NV): return 1;
570 case(GL_RED): return 1;
571 case(GL_GREEN): return 1;
572 case(GL_BLUE): return 1;
573 case(GL_ALPHA): return 1;
574 case(GL_ALPHA8I_EXT): return 1;
575 case(GL_ALPHA8UI_EXT): return 1;
576 case(GL_ALPHA16I_EXT): return 1;
577 case(GL_ALPHA16UI_EXT): return 1;
578 case(GL_ALPHA32I_EXT): return 1;
579 case(GL_ALPHA32UI_EXT): return 1;
580 case(GL_ALPHA16F_ARB): return 1;
581 case(GL_ALPHA32F_ARB): return 1;
582 case(GL_R16F): return 1;
583 case(GL_R32F): return 1;
584 case(GL_R8): return 1;
585 case(GL_R8_SNORM): return 1;
586 case(GL_R16): return 1;
587 case(GL_R16_SNORM): return 1;
588 case(GL_R8I): return 1;
589 case(GL_R8UI): return 1;
590 case(GL_R16I): return 1;
591 case(GL_R16UI): return 1;
592 case(GL_R32I): return 1;
593 case(GL_R32UI): return 1;
594 case(GL_RG): return 2;
595 case(GL_RG16F): return 2;
596 case(GL_RG32F): return 2;
597 case(GL_RG8): return 2;
598 case(GL_RG8_SNORM): return 2;
599 case(GL_RG16): return 2;
600 case(GL_RG16_SNORM): return 2;
601 case(GL_RG8I): return 2;
602 case(GL_RG8UI): return 2;
603 case(GL_RG16I): return 2;
604 case(GL_RG16UI): return 2;
605 case(GL_RG32I): return 2;
606 case(GL_RG32UI): return 2;
607 case(GL_RGB): return 3;
608 case(GL_BGR): return 3;
609 case(GL_RGB8I_EXT): return 3;
610 case(GL_RGB8UI_EXT): return 3;
611 case(GL_RGB16I_EXT): return 3;
612 case(GL_RGB16UI_EXT): return 3;
613 case(GL_RGB32I_EXT): return 3;
614 case(GL_RGB32UI_EXT): return 3;
615 case(GL_RGB16F_ARB): return 3;
616 case(GL_RGB32F_ARB): return 3;
617 case(GL_RGBA16F_ARB): return 4;
618 case(GL_RGBA32F_ARB): return 4;
619 case(GL_RGBA): return 4;
620 case(GL_BGRA): return 4;
621 case(GL_RGBA8): return 4;
622 case(GL_LUMINANCE): return 1;
623 case(GL_LUMINANCE4): return 1;
624 case(GL_LUMINANCE8): return 1;
625 case(GL_LUMINANCE12): return 1;
626 case(GL_LUMINANCE16): return 1;
627 case(GL_LUMINANCE8I_EXT): return 1;
628 case(GL_LUMINANCE8UI_EXT): return 1;
629 case(GL_LUMINANCE16I_EXT): return 1;
630 case(GL_LUMINANCE16UI_EXT): return 1;
631 case(GL_LUMINANCE32I_EXT): return 1;
632 case(GL_LUMINANCE32UI_EXT): return 1;
633 case(GL_LUMINANCE16F_ARB): return 1;
634 case(GL_LUMINANCE32F_ARB): return 1;
635 case(GL_LUMINANCE4_ALPHA4): return 2;
636 case(GL_LUMINANCE6_ALPHA2): return 2;
637 case(GL_LUMINANCE8_ALPHA8): return 2;
638 case(GL_LUMINANCE12_ALPHA4): return 2;
639 case(GL_LUMINANCE12_ALPHA12): return 2;
640 case(GL_LUMINANCE16_ALPHA16): return 2;
641 case(GL_INTENSITY): return 1;
642 case(GL_INTENSITY4): return 1;
643 case(GL_INTENSITY8): return 1;
644 case(GL_INTENSITY12): return 1;
645 case(GL_INTENSITY16): return 1;
646 case(GL_INTENSITY8UI_EXT): return 1;
647 case(GL_INTENSITY8I_EXT): return 1;
648 case(GL_INTENSITY16I_EXT): return 1;
649 case(GL_INTENSITY16UI_EXT): return 1;
650 case(GL_INTENSITY32I_EXT): return 1;
651 case(GL_INTENSITY32UI_EXT): return 1;
652 case(GL_INTENSITY16F_ARB): return 1;
653 case(GL_INTENSITY32F_ARB): return 1;
654 case(GL_LUMINANCE_ALPHA): return 2;
655 case(GL_LUMINANCE_ALPHA8I_EXT): return 2;
656 case(GL_LUMINANCE_ALPHA8UI_EXT): return 2;
657 case(GL_LUMINANCE_ALPHA16I_EXT): return 2;
658 case(GL_LUMINANCE_ALPHA16UI_EXT): return 2;
659 case(GL_LUMINANCE_ALPHA32I_EXT): return 2;
660 case(GL_LUMINANCE_ALPHA32UI_EXT): return 2;
661 case(GL_LUMINANCE_ALPHA16F_ARB): return 2;
662 case(GL_LUMINANCE_ALPHA32F_ARB): return 2;
663 case(GL_HILO_NV): return 2;
664 case(GL_DSDT_NV): return 2;
665 case(GL_DSDT_MAG_NV): return 3;
666 case(GL_DSDT_MAG_VIB_NV): return 4;
667 case(GL_RED_INTEGER_EXT): return 1;
668 case(GL_GREEN_INTEGER_EXT): return 1;
669 case(GL_BLUE_INTEGER_EXT): return 1;
670 case(GL_ALPHA_INTEGER_EXT): return 1;
671 case(GL_RGB_INTEGER_EXT): return 3;
672 case(GL_RGBA_INTEGER_EXT): return 4;
673 case(GL_BGR_INTEGER_EXT): return 3;
674 case(GL_BGRA_INTEGER_EXT): return 4;
675 case(GL_LUMINANCE_INTEGER_EXT): return 1;
676 case(GL_LUMINANCE_ALPHA_INTEGER_EXT): return 2;
677 case(GL_SRGB8) : return 3;
678 case(GL_SRGB8_ALPHA8) : return 4;
679 case (GL_COMPRESSED_RGBA_ASTC_4x4_KHR) : return 4;
680 case (GL_COMPRESSED_RGBA_ASTC_5x4_KHR) : return 4;
681 case (GL_COMPRESSED_RGBA_ASTC_5x5_KHR) : return 4;
682 case (GL_COMPRESSED_RGBA_ASTC_6x5_KHR) : return 4;
683 case (GL_COMPRESSED_RGBA_ASTC_6x6_KHR) : return 4;
684 case (GL_COMPRESSED_RGBA_ASTC_8x5_KHR) : return 4;
685 case (GL_COMPRESSED_RGBA_ASTC_8x6_KHR) : return 4;
686 case (GL_COMPRESSED_RGBA_ASTC_8x8_KHR) : return 4;
687 case (GL_COMPRESSED_RGBA_ASTC_10x5_KHR) : return 4;
688 case (GL_COMPRESSED_RGBA_ASTC_10x6_KHR) : return 4;
689 case (GL_COMPRESSED_RGBA_ASTC_10x8_KHR) : return 4;
690 case (GL_COMPRESSED_RGBA_ASTC_10x10_KHR) : return 4;
691 case (GL_COMPRESSED_RGBA_ASTC_12x10_KHR) : return 4;
692 case (GL_COMPRESSED_RGBA_ASTC_12x12_KHR) : return 4;
693 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) : return 4;
694 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) : return 4;
695 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) : return 4;
696 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) : return 4;
697 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) : return 4;
698 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) : return 4;
699 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) : return 4;
700 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) : return 4;
701 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) : return 4;
702 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) : return 4;
703 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) : return 4;
704 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) : return 4;
705 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) : return 4;
706 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) : return 4;
707 default:
708 {
709 OSG_WARN<<"error pixelFormat = "<<std::hex<<pixelFormat<<std::dec<<std::endl;
710 return 0;
711 }
712 }
713 }
714
715
computePixelSizeInBits(GLenum format,GLenum type)716 unsigned int Image::computePixelSizeInBits(GLenum format,GLenum type)
717 {
718
719 switch(format)
720 {
721 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): return 4;
722 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): return 4;
723 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): return 8;
724 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): return 8;
725 case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT): return 4;
726 case(GL_COMPRESSED_RED_RGTC1_EXT): return 4;
727 case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): return 8;
728 case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): return 8;
729 case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): return 4;
730 case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): return 2;
731 case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): return 4;
732 case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): return 2;
733 case(GL_ETC1_RGB8_OES): return 4;
734 case(GL_COMPRESSED_RGB8_ETC2): return 4;
735 case(GL_COMPRESSED_SRGB8_ETC2): return 4;
736 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2): return 4;
737 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2): return 4;
738 case(GL_COMPRESSED_RGBA8_ETC2_EAC): return 8;
739 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC): return 8;
740 case(GL_COMPRESSED_R11_EAC): return 4;
741 case(GL_COMPRESSED_SIGNED_R11_EAC): return 4;
742 case(GL_COMPRESSED_RG11_EAC): return 8;
743 case(GL_COMPRESSED_SIGNED_RG11_EAC): return 8;
744 default: break;
745 }
746
747 // note, haven't yet added proper handling of the ARB GL_COMPRESSRED_* pathways
748 // yet, no clear size for these since its probably implementation dependent
749 // which raises the question of how to actually query for these sizes...
750 // will need to revisit this issue, for now just report an error.
751 // this is possible a bit of mute point though as since the ARB compressed formats
752 // aren't yet used for storing images to disk, so its likely that users wont have
753 // osg::Image's for pixel formats set the ARB compressed formats, just using these
754 // compressed formats as internal texture modes. This is very much speculation though
755 // if get the below error then its time to revist this issue :-)
756 // Robert Osfield, Jan 2005.
757 switch(format)
758 {
759 case(GL_COMPRESSED_ALPHA):
760 case(GL_COMPRESSED_LUMINANCE):
761 case(GL_COMPRESSED_LUMINANCE_ALPHA):
762 case(GL_COMPRESSED_INTENSITY):
763 case(GL_COMPRESSED_RGB):
764 case(GL_COMPRESSED_RGBA):
765 OSG_WARN<<"Image::computePixelSizeInBits(format,type) : cannot compute correct size of compressed format ("<<format<<") returning 0."<<std::endl;
766 return 0;
767 default: break;
768 }
769 switch (format)
770 {//handle GL_KHR_texture_compression_astc_hdr
771 case (GL_COMPRESSED_RGBA_ASTC_4x4_KHR) :
772 case (GL_COMPRESSED_RGBA_ASTC_5x4_KHR) :
773 case (GL_COMPRESSED_RGBA_ASTC_5x5_KHR) :
774 case (GL_COMPRESSED_RGBA_ASTC_6x5_KHR) :
775 case (GL_COMPRESSED_RGBA_ASTC_6x6_KHR) :
776 case (GL_COMPRESSED_RGBA_ASTC_8x5_KHR) :
777 case (GL_COMPRESSED_RGBA_ASTC_8x6_KHR) :
778 case (GL_COMPRESSED_RGBA_ASTC_8x8_KHR) :
779 case (GL_COMPRESSED_RGBA_ASTC_10x5_KHR) :
780 case (GL_COMPRESSED_RGBA_ASTC_10x6_KHR) :
781 case (GL_COMPRESSED_RGBA_ASTC_10x8_KHR) :
782 case (GL_COMPRESSED_RGBA_ASTC_10x10_KHR) :
783 case (GL_COMPRESSED_RGBA_ASTC_12x10_KHR) :
784 case (GL_COMPRESSED_RGBA_ASTC_12x12_KHR) :
785 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) :
786 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) :
787 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) :
788 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) :
789 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) :
790 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) :
791 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) :
792 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) :
793 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) :
794 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) :
795 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) :
796 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) :
797 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) :
798 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) :
799 {
800 osg::Vec3i footprint = computeBlockFootprint(format);
801 unsigned int pixelsPerBlock = footprint.x() * footprint.y();
802 unsigned int bitsPerBlock = computeBlockSize(format, 0);//16 x 8 = 128
803 unsigned int bitsPerPixel = bitsPerBlock / pixelsPerBlock;
804 if (bitsPerBlock == bitsPerPixel * pixelsPerBlock) {
805 OSG_WARN << "Image::computePixelSizeInBits(format,type) : bits per pixel (" << bitsPerPixel << ") is not an integer for GL_KHR_texture_compression_astc_hdr sizes other than 4x4 and 8x8." << std::endl;
806 return bitsPerPixel;
807 } else {
808 OSG_WARN << "Image::computePixelSizeInBits(format,type) : bits per pixel (" << bitsPerBlock << "/" << pixelsPerBlock << ") is not an integer for GL_KHR_texture_compression_astc_hdr size" << footprint.x() << "x" << footprint.y() << "." << std::endl;
809 }
810 return 0;
811 }
812 default: break;
813 }
814
815 switch(format)
816 {
817 case(GL_LUMINANCE4): return 4;
818 case(GL_LUMINANCE8): return 8;
819 case(GL_LUMINANCE12): return 12;
820 case(GL_LUMINANCE16): return 16;
821 case(GL_LUMINANCE4_ALPHA4): return 8;
822 case(GL_LUMINANCE6_ALPHA2): return 8;
823 case(GL_LUMINANCE8_ALPHA8): return 16;
824 case(GL_LUMINANCE12_ALPHA4): return 16;
825 case(GL_LUMINANCE12_ALPHA12): return 24;
826 case(GL_LUMINANCE16_ALPHA16): return 32;
827 case(GL_INTENSITY4): return 4;
828 case(GL_INTENSITY8): return 8;
829 case(GL_INTENSITY12): return 12;
830 case(GL_INTENSITY16): return 16;
831 default: break;
832 }
833
834 switch(type)
835 {
836
837 case(GL_BITMAP): return computeNumComponents(format);
838
839 case(GL_BYTE):
840 case(GL_UNSIGNED_BYTE): return 8*computeNumComponents(format);
841
842 case(GL_HALF_FLOAT):
843 case(GL_SHORT):
844 case(GL_UNSIGNED_SHORT): return 16*computeNumComponents(format);
845
846 case(GL_INT):
847 case(GL_UNSIGNED_INT):
848 case(GL_FLOAT): return 32*computeNumComponents(format);
849
850
851 case(GL_UNSIGNED_BYTE_3_3_2):
852 case(GL_UNSIGNED_BYTE_2_3_3_REV): return 8;
853
854 case(GL_UNSIGNED_SHORT_5_6_5):
855 case(GL_UNSIGNED_SHORT_5_6_5_REV):
856 case(GL_UNSIGNED_SHORT_4_4_4_4):
857 case(GL_UNSIGNED_SHORT_4_4_4_4_REV):
858 case(GL_UNSIGNED_SHORT_5_5_5_1):
859 case(GL_UNSIGNED_SHORT_1_5_5_5_REV): return 16;
860
861 case(GL_UNSIGNED_INT_8_8_8_8):
862 case(GL_UNSIGNED_INT_8_8_8_8_REV):
863 case(GL_UNSIGNED_INT_10_10_10_2):
864 case(GL_UNSIGNED_INT_2_10_10_10_REV): return 32;
865 default:
866 {
867 OSG_WARN<<"error type = "<<type<<std::endl;
868 return 0;
869 }
870 }
871
872 }
873
computeBlockFootprint(GLenum pixelFormat)874 osg::Vec3i Image::computeBlockFootprint(GLenum pixelFormat)
875 {
876 switch (pixelFormat)
877 {
878 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT) :
879 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) :
880 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) :
881 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) :
882 return osg::Vec3i(4,4,4);//opengl 3d dxt: r value means (max)4 consecutive blocks in r direction packed into a slab.
883
884 case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT) :
885 case(GL_COMPRESSED_RED_RGTC1_EXT) :
886 case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT) :
887 case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT) :
888 case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG) :
889 case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG) :
890 case(GL_ETC1_RGB8_OES) :
891 case(GL_COMPRESSED_RGB8_ETC2) :
892 case(GL_COMPRESSED_SRGB8_ETC2) :
893 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) :
894 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) :
895 case(GL_COMPRESSED_RGBA8_ETC2_EAC) :
896 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) :
897 case(GL_COMPRESSED_R11_EAC) :
898 case(GL_COMPRESSED_SIGNED_R11_EAC) :
899 case(GL_COMPRESSED_RG11_EAC) :
900 case(GL_COMPRESSED_SIGNED_RG11_EAC) :
901 return osg::Vec3i(4, 4, 1);//not sure about r
902 case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG) :
903 case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG) :
904 return osg::Vec3i(8, 4, 1);//no 3d texture support in pvrtc at all
905 case (GL_COMPRESSED_RGBA_ASTC_4x4_KHR) : return osg::Vec3i(4, 4, 1);
906 case (GL_COMPRESSED_RGBA_ASTC_5x4_KHR) : return osg::Vec3i(5, 4, 1);
907 case (GL_COMPRESSED_RGBA_ASTC_5x5_KHR) : return osg::Vec3i(5, 5, 1);
908 case (GL_COMPRESSED_RGBA_ASTC_6x5_KHR) : return osg::Vec3i(6, 5, 1);
909 case (GL_COMPRESSED_RGBA_ASTC_6x6_KHR) : return osg::Vec3i(6, 6, 1);
910 case (GL_COMPRESSED_RGBA_ASTC_8x5_KHR) : return osg::Vec3i(8, 5, 1);
911 case (GL_COMPRESSED_RGBA_ASTC_8x6_KHR) : return osg::Vec3i(8, 6, 1);
912 case (GL_COMPRESSED_RGBA_ASTC_8x8_KHR) : return osg::Vec3i(8, 8, 1);
913 case (GL_COMPRESSED_RGBA_ASTC_10x5_KHR) : return osg::Vec3i(10, 5, 1);
914 case (GL_COMPRESSED_RGBA_ASTC_10x6_KHR) : return osg::Vec3i(10, 6, 1);
915 case (GL_COMPRESSED_RGBA_ASTC_10x8_KHR) : return osg::Vec3i(10, 8, 1);
916 case (GL_COMPRESSED_RGBA_ASTC_10x10_KHR) : return osg::Vec3i(10, 10, 1);
917 case (GL_COMPRESSED_RGBA_ASTC_12x10_KHR) : return osg::Vec3i(12, 10, 1);
918 case (GL_COMPRESSED_RGBA_ASTC_12x12_KHR) : return osg::Vec3i(12, 12, 1);
919 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) : return osg::Vec3i(4, 4, 1);
920 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) : return osg::Vec3i(5, 4, 1);
921 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) : return osg::Vec3i(5, 5, 1);
922 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) : return osg::Vec3i(6, 5, 1);
923 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) : return osg::Vec3i(6, 6, 1);
924 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) : return osg::Vec3i(8, 5, 1);
925 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) : return osg::Vec3i(8, 6, 1);
926 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) : return osg::Vec3i(8, 8, 1);
927 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) : return osg::Vec3i(10, 5, 1);
928 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) : return osg::Vec3i(10, 6, 1);
929 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) : return osg::Vec3i(10, 8, 1);
930 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) : return osg::Vec3i(10, 10, 1);
931 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) : return osg::Vec3i(12, 10, 1);
932 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) : return osg::Vec3i(12, 12, 1);
933
934 default:
935 break;
936 }
937 return osg::Vec3i(1,1,1);
938 }
939 //returns the max(size of a 2D block in bytes,packing)
computeBlockSize(GLenum pixelFormat,GLenum packing)940 unsigned int Image::computeBlockSize(GLenum pixelFormat, GLenum packing)
941 {
942 switch(pixelFormat)
943 {
944 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
945 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
946 return osg::maximum(8u,packing); // block size of 8
947 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
948 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
949 case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
950 case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
951 case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG):
952 case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
953 case(GL_ETC1_RGB8_OES):
954 return osg::maximum(16u,packing); // block size of 16
955 case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT):
956 case(GL_COMPRESSED_RED_RGTC1_EXT):
957 return osg::maximum(8u,packing); // block size of 8
958 break;
959 case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
960 case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
961 return osg::maximum(16u,packing); // block size of 16
962
963 case(GL_COMPRESSED_RGB8_ETC2):
964 case(GL_COMPRESSED_SRGB8_ETC2):
965 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2):
966 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2):
967 case(GL_COMPRESSED_R11_EAC):
968 case(GL_COMPRESSED_SIGNED_R11_EAC):
969 return osg::maximum(8u,packing); // block size of 8
970
971 case(GL_COMPRESSED_RGBA8_ETC2_EAC):
972 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC):
973 case(GL_COMPRESSED_RG11_EAC):
974 case(GL_COMPRESSED_SIGNED_RG11_EAC):
975 return osg::maximum(16u,packing); // block size of 16
976 case (GL_COMPRESSED_RGBA_ASTC_4x4_KHR) :
977 case (GL_COMPRESSED_RGBA_ASTC_5x4_KHR) :
978 case (GL_COMPRESSED_RGBA_ASTC_5x5_KHR) :
979 case (GL_COMPRESSED_RGBA_ASTC_6x5_KHR) :
980 case (GL_COMPRESSED_RGBA_ASTC_6x6_KHR) :
981 case (GL_COMPRESSED_RGBA_ASTC_8x5_KHR) :
982 case (GL_COMPRESSED_RGBA_ASTC_8x6_KHR) :
983 case (GL_COMPRESSED_RGBA_ASTC_8x8_KHR) :
984 case (GL_COMPRESSED_RGBA_ASTC_10x5_KHR) :
985 case (GL_COMPRESSED_RGBA_ASTC_10x6_KHR) :
986 case (GL_COMPRESSED_RGBA_ASTC_10x8_KHR) :
987 case (GL_COMPRESSED_RGBA_ASTC_10x10_KHR) :
988 case (GL_COMPRESSED_RGBA_ASTC_12x10_KHR) :
989 case (GL_COMPRESSED_RGBA_ASTC_12x12_KHR) :
990 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) :
991 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) :
992 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) :
993 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) :
994 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) :
995 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) :
996 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) :
997 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) :
998 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) :
999 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) :
1000 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) :
1001 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) :
1002 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) :
1003 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) :
1004 return osg::maximum(16u, packing); // block size of 16
1005 default:
1006 break;
1007 }
1008 return packing;
1009 }
1010
computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum type,int packing)1011 unsigned int Image::computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum type,int packing)
1012 {
1013 unsigned int pixelSize = computePixelSizeInBits(pixelFormat,type);
1014 int widthInBits = width*pixelSize;
1015 int packingInBits = packing!=0 ? packing*8 : 8;
1016 //OSG_INFO << "width="<<width<<" pixelSize="<<pixelSize<<" width in bit="<<widthInBits<<" packingInBits="<<packingInBits<<" widthInBits%packingInBits="<<widthInBits%packingInBits<<std::endl;
1017 return (widthInBits/packingInBits + ((widthInBits%packingInBits)?1:0))*packing;
1018 }
1019
computeImageSizeInBytes(int width,int height,int depth,GLenum pixelFormat,GLenum type,int packing,int slice_packing,int image_packing)1020 unsigned int Image::computeImageSizeInBytes(int width,int height, int depth, GLenum pixelFormat,GLenum type,int packing, int slice_packing, int image_packing)
1021 {
1022 if (width<=0 || height<=0 || depth<=0) return 0;
1023
1024 int blockSize = computeBlockSize(pixelFormat, 0);
1025 if (blockSize > 0) {
1026 osg::Vec3i footprint = computeBlockFootprint(pixelFormat);
1027 width = (width + footprint.x() - 1) / footprint.x();
1028 height = (height + footprint.y() - 1) / footprint.y();
1029 unsigned int size = blockSize * width;
1030 size = roudUpToMultiple(size, packing);
1031 size *= height;
1032 size = roudUpToMultiple(size, slice_packing);
1033 size *= depth;
1034 size = roudUpToMultiple(size, image_packing);
1035 return size;
1036 }
1037
1038 // compute size of one row
1039 unsigned int size = osg::Image::computeRowWidthInBytes( width, pixelFormat, type, packing );
1040
1041 // now compute size of slice
1042 size *= height;
1043 size += slice_packing - 1;
1044 size -= size % slice_packing;
1045
1046 // compute size of whole image
1047 size *= depth;
1048 size += image_packing - 1;
1049 size -= size % image_packing;
1050
1051 return osg::maximum( size, computeBlockSize(pixelFormat, packing) );
1052 }
1053
roudUpToMultiple(int s,int pack)1054 int Image::roudUpToMultiple(int s, int pack) {
1055 if (pack < 2) return s;
1056 s += pack - 1;
1057 s -= s % pack;
1058 return s;
1059 }
1060
computeNearestPowerOfTwo(int s,float bias)1061 int Image::computeNearestPowerOfTwo(int s,float bias)
1062 {
1063 if ((s & (s-1))!=0)
1064 {
1065 // it isn't so lets find the closest power of two.
1066 // yes, logf and powf are slow, but this code should
1067 // only be called during scene graph initialization,
1068 // if at all, so not critical in the greater scheme.
1069 float p2 = logf((float)s)/logf(2.0f);
1070 float rounded_p2 = floorf(p2+bias);
1071 s = (int)(powf(2.0f,rounded_p2));
1072 }
1073 return s;
1074 }
1075
computeNumberOfMipmapLevels(int s,int t,int r)1076 int Image::computeNumberOfMipmapLevels(int s,int t, int r)
1077 {
1078 int w = maximum(s, t);
1079 w = maximum(w, r);
1080
1081 int n = 0;
1082 while (w >>= 1)
1083 ++n;
1084 return n+1;
1085 }
1086
isCompressed() const1087 bool Image::isCompressed() const
1088 {
1089 switch(_pixelFormat)
1090 {
1091 case(GL_COMPRESSED_ALPHA_ARB):
1092 case(GL_COMPRESSED_INTENSITY_ARB):
1093 case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
1094 case(GL_COMPRESSED_LUMINANCE_ARB):
1095 case(GL_COMPRESSED_RGBA_ARB):
1096 case(GL_COMPRESSED_RGB_ARB):
1097 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
1098 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
1099 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
1100 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
1101 case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT):
1102 case(GL_COMPRESSED_RED_RGTC1_EXT):
1103 case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
1104 case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
1105 case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG):
1106 case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
1107 case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
1108 case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
1109 case(GL_ETC1_RGB8_OES):
1110 case(GL_COMPRESSED_RGB8_ETC2):
1111 case(GL_COMPRESSED_SRGB8_ETC2):
1112 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2):
1113 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2):
1114 case(GL_COMPRESSED_RGBA8_ETC2_EAC):
1115 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC):
1116 case(GL_COMPRESSED_R11_EAC):
1117 case(GL_COMPRESSED_SIGNED_R11_EAC):
1118 case(GL_COMPRESSED_RG11_EAC):
1119 case(GL_COMPRESSED_SIGNED_RG11_EAC):
1120 case (GL_COMPRESSED_RGBA_ASTC_4x4_KHR) :
1121 case (GL_COMPRESSED_RGBA_ASTC_5x4_KHR) :
1122 case (GL_COMPRESSED_RGBA_ASTC_5x5_KHR) :
1123 case (GL_COMPRESSED_RGBA_ASTC_6x5_KHR) :
1124 case (GL_COMPRESSED_RGBA_ASTC_6x6_KHR) :
1125 case (GL_COMPRESSED_RGBA_ASTC_8x5_KHR) :
1126 case (GL_COMPRESSED_RGBA_ASTC_8x6_KHR) :
1127 case (GL_COMPRESSED_RGBA_ASTC_8x8_KHR) :
1128 case (GL_COMPRESSED_RGBA_ASTC_10x5_KHR) :
1129 case (GL_COMPRESSED_RGBA_ASTC_10x6_KHR) :
1130 case (GL_COMPRESSED_RGBA_ASTC_10x8_KHR) :
1131 case (GL_COMPRESSED_RGBA_ASTC_10x10_KHR) :
1132 case (GL_COMPRESSED_RGBA_ASTC_12x10_KHR) :
1133 case (GL_COMPRESSED_RGBA_ASTC_12x12_KHR) :
1134 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) :
1135 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) :
1136 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) :
1137 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) :
1138 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) :
1139 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) :
1140 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) :
1141 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) :
1142 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) :
1143 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) :
1144 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) :
1145 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) :
1146 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) :
1147 case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) :
1148 return true;
1149 default:
1150 return false;
1151 }
1152 }
1153
getTotalSizeInBytesIncludingMipmaps() const1154 unsigned int Image::getTotalSizeInBytesIncludingMipmaps() const
1155 {
1156 if (_mipmapData.empty())
1157 {
1158 // no mips so just return size of main image
1159 return getTotalSizeInBytes();
1160 }
1161
1162 int s = _s;
1163 int t = _t;
1164 int r = _r;
1165 unsigned int totalSize = 0;
1166 for(unsigned int i=0;i<_mipmapData.size()+1;++i)
1167 {
1168 totalSize += computeImageSizeInBytes(s, t, r, _pixelFormat, _dataType, _packing);
1169
1170 s >>= 1;
1171 t >>= 1;
1172 r >>= 1;
1173
1174 if (s<1) s=1;
1175 if (t<1) t=1;
1176 if (r<1) r=1;
1177 }
1178
1179 return totalSize;
1180 }
1181
setRowLength(int length)1182 void Image::setRowLength(int length)
1183 {
1184 _rowLength = length;
1185 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
1186 if (length > 0)
1187 {
1188 OSG_WARN << "Image::setRowLength is not supported on this platform, ignoring" << std::endl;
1189 }
1190 #endif
1191
1192 }
1193
setInternalTextureFormat(GLint internalFormat)1194 void Image::setInternalTextureFormat(GLint internalFormat)
1195 {
1196 // won't do any sanity checking right now, leave it to
1197 // OpenGL to make the call.
1198 _internalTextureFormat = internalFormat;
1199 }
1200
setPixelFormat(GLenum pixelFormat)1201 void Image::setPixelFormat(GLenum pixelFormat)
1202 {
1203 _pixelFormat = pixelFormat;
1204 }
1205
setDataType(GLenum dataType)1206 void Image::setDataType(GLenum dataType)
1207 {
1208 if (_dataType==dataType) return; // do nothing if the same.
1209
1210 if (_dataType==0)
1211 {
1212 // setting the datatype for the first time
1213 _dataType = dataType;
1214 }
1215 else
1216 {
1217 OSG_WARN<<"Image::setDataType(..) - warning, attempt to reset the data type not permitted."<<std::endl;
1218 }
1219 }
1220
1221
allocateImage(int s,int t,int r,GLenum format,GLenum type,int packing)1222 void Image::allocateImage(int s,int t,int r,
1223 GLenum format,GLenum type,
1224 int packing)
1225 {
1226 _mipmapData.clear();
1227
1228 bool callback_needed(false);
1229
1230 unsigned int previousTotalSize = 0;
1231
1232 if (_data) previousTotalSize = computeRowWidthInBytes(_s,_pixelFormat,_dataType,_packing)*_t*_r;
1233
1234 unsigned int newTotalSize = computeRowWidthInBytes(s,format,type,packing)*t*r;
1235
1236 if (newTotalSize!=previousTotalSize)
1237 {
1238 if (newTotalSize)
1239 setData(new unsigned char [newTotalSize],USE_NEW_DELETE);
1240 else
1241 deallocateData(); // and sets it to NULL.
1242 }
1243
1244 if (_data)
1245 {
1246 callback_needed = (_s != s) || (_t != t) || (_r != r);
1247 _s = s;
1248 _t = t;
1249 _r = r;
1250 _pixelFormat = format;
1251 _dataType = type;
1252 _packing = packing;
1253 _rowLength = 0;
1254
1255 // preserve internalTextureFormat if already set, otherwise
1256 // use the pixelFormat as the source for the format.
1257 if (_internalTextureFormat==0) _internalTextureFormat = format;
1258 }
1259 else
1260 {
1261 callback_needed = (_s != 0) || (_t != 0) || (_r != 0);
1262
1263 // failed to allocate memory, for now, will simply set values to 0.
1264 _s = 0;
1265 _t = 0;
1266 _r = 0;
1267 _pixelFormat = 0;
1268 _dataType = 0;
1269 _packing = 0;
1270 _rowLength = 0;
1271
1272 // commenting out reset of _internalTextureFormat as we are changing
1273 // policy so that allocateImage honours previous settings of _internalTextureFormat.
1274 //_internalTextureFormat = 0;
1275 }
1276
1277 if (callback_needed)
1278 handleDimensionsChangedCallbacks();
1279
1280 dirty();
1281 }
1282
setImage(int s,int t,int r,GLint internalTextureFormat,GLenum format,GLenum type,unsigned char * data,AllocationMode mode,int packing,int rowLength)1283 void Image::setImage(int s,int t,int r,
1284 GLint internalTextureFormat,
1285 GLenum format,GLenum type,
1286 unsigned char *data,
1287 AllocationMode mode,
1288 int packing,
1289 int rowLength)
1290 {
1291 _mipmapData.clear();
1292
1293 bool callback_needed = (_s != s) || (_t != t) || (_r != r);
1294
1295 _s = s;
1296 _t = t;
1297 _r = r;
1298
1299 _internalTextureFormat = internalTextureFormat;
1300 _pixelFormat = format;
1301 _dataType = type;
1302
1303 setData(data,mode);
1304
1305 _packing = packing;
1306 _rowLength = rowLength;
1307
1308 dirty();
1309
1310 if (callback_needed)
1311 handleDimensionsChangedCallbacks();
1312
1313 }
1314
readPixels(int x,int y,int width,int height,GLenum format,GLenum type,int packing)1315 void Image::readPixels(int x,int y,int width,int height,
1316 GLenum format, GLenum type, int packing)
1317 {
1318 allocateImage(width,height,1,format,type, packing);
1319
1320 glPixelStorei(GL_PACK_ALIGNMENT,_packing);
1321 glPixelStorei(GL_PACK_ROW_LENGTH,_rowLength);
1322
1323 glReadPixels(x,y,width,height,format,type,_data);
1324 }
1325
1326
readImageFromCurrentTexture(unsigned int contextID,bool copyMipMapsIfAvailable,GLenum type,unsigned int face)1327 void Image::readImageFromCurrentTexture(unsigned int contextID, bool copyMipMapsIfAvailable, GLenum type, unsigned int face)
1328 {
1329 #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
1330 // OSG_NOTICE<<"Image::readImageFromCurrentTexture()"<<std::endl;
1331
1332 const osg::GLExtensions* extensions = osg::GLExtensions::Get(contextID,true);
1333
1334 GLboolean binding1D = GL_FALSE, binding2D = GL_FALSE, bindingRect = GL_FALSE, binding3D = GL_FALSE, binding2DArray = GL_FALSE, bindingCubeMap = GL_FALSE;
1335
1336 glGetBooleanv(GL_TEXTURE_BINDING_1D, &binding1D);
1337 glGetBooleanv(GL_TEXTURE_BINDING_2D, &binding2D);
1338 glGetBooleanv(GL_TEXTURE_BINDING_RECTANGLE, &bindingRect);
1339 glGetBooleanv(GL_TEXTURE_BINDING_3D, &binding3D);
1340 glGetBooleanv(GL_TEXTURE_BINDING_CUBE_MAP, &bindingCubeMap);
1341
1342 if (extensions->isTexture2DArraySupported)
1343 {
1344 glGetBooleanv(GL_TEXTURE_BINDING_2D_ARRAY, &binding2DArray);
1345 }
1346
1347 GLenum textureMode = binding1D ? GL_TEXTURE_1D : binding2D ? GL_TEXTURE_2D : bindingRect ? GL_TEXTURE_RECTANGLE : binding3D ? GL_TEXTURE_3D : binding2DArray ? GL_TEXTURE_2D_ARRAY : 0;
1348 if (bindingCubeMap)
1349 {
1350 switch (face)
1351 {
1352 case TextureCubeMap::POSITIVE_X:
1353 textureMode = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1354 break;
1355 case TextureCubeMap::NEGATIVE_X:
1356 textureMode = GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
1357 break;
1358 case TextureCubeMap::POSITIVE_Y:
1359 textureMode = GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
1360 break;
1361 case TextureCubeMap::NEGATIVE_Y:
1362 textureMode = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
1363 break;
1364 case TextureCubeMap::POSITIVE_Z:
1365 textureMode = GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
1366 break;
1367 case TextureCubeMap::NEGATIVE_Z:
1368 textureMode = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1369 break;
1370 }
1371 }
1372
1373 if (textureMode==0) return;
1374
1375 GLint internalformat;
1376 GLint width;
1377 GLint height;
1378 GLint depth;
1379 GLint packing;
1380 GLint rowLength;
1381
1382 GLint numMipMaps = 0;
1383 if (copyMipMapsIfAvailable)
1384 {
1385 for(;numMipMaps<20;++numMipMaps)
1386 {
1387 glGetTexLevelParameteriv(textureMode, numMipMaps, GL_TEXTURE_WIDTH, &width);
1388 glGetTexLevelParameteriv(textureMode, numMipMaps, GL_TEXTURE_HEIGHT, &height);
1389 glGetTexLevelParameteriv(textureMode, numMipMaps, GL_TEXTURE_DEPTH, &depth);
1390 // OSG_NOTICE<<" numMipMaps="<<numMipMaps<<" width="<<width<<" height="<<height<<" depth="<<depth<<std::endl;
1391 if (width==0 || height==0 || depth==0) break;
1392 }
1393 }
1394 else
1395 {
1396 numMipMaps = 1;
1397 }
1398
1399 // OSG_NOTICE<<"Image::readImageFromCurrentTexture() : numMipMaps = "<<numMipMaps<<std::endl;
1400
1401
1402 GLint compressed = 0;
1403
1404 if (textureMode==GL_TEXTURE_2D)
1405 {
1406 if (extensions->isCompressedTexImage2DSupported())
1407 {
1408 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed);
1409 }
1410 }
1411 else if (textureMode==GL_TEXTURE_3D)
1412 {
1413 if (extensions->isCompressedTexImage3DSupported())
1414 {
1415 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed);
1416 }
1417 }
1418 else if (textureMode==GL_TEXTURE_2D_ARRAY)
1419 {
1420 if (extensions->isCompressedTexImage3DSupported())
1421 {
1422 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed);
1423 }
1424 }
1425 else if(bindingCubeMap)
1426 {
1427 if (extensions->isCompressedTexImage2DSupported())
1428 {
1429 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed);
1430 }
1431 }
1432
1433
1434
1435 /* if the compression has been successful */
1436 if (compressed == GL_TRUE)
1437 {
1438
1439 MipmapDataType mipMapData;
1440
1441 unsigned int total_size = 0;
1442 GLint i;
1443 for(i=0;i<numMipMaps;++i)
1444 {
1445 if (i>0) mipMapData.push_back(total_size);
1446
1447 GLint compressed_size;
1448 glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &compressed_size);
1449
1450 total_size += compressed_size;
1451 }
1452
1453
1454 unsigned char* data = new unsigned char[total_size];
1455 if (!data)
1456 {
1457 OSG_WARN<<"Warning: Image::readImageFromCurrentTexture(..) out of memory, no image read."<<std::endl;
1458 return;
1459 }
1460
1461 deallocateData(); // and sets it to NULL.
1462
1463 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1464 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_WIDTH, &width);
1465 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_HEIGHT, &height);
1466 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_DEPTH, &depth);
1467 glGetIntegerv(GL_UNPACK_ALIGNMENT, &packing);
1468 glPixelStorei(GL_PACK_ALIGNMENT, packing);
1469 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowLength);
1470 glPixelStorei(GL_PACK_ROW_LENGTH, rowLength);
1471
1472 _data = data;
1473 _s = width;
1474 _t = height;
1475 _r = depth;
1476
1477 _pixelFormat = internalformat;
1478 _dataType = type;
1479 _internalTextureFormat = internalformat;
1480 _mipmapData = mipMapData;
1481 _allocationMode=USE_NEW_DELETE;
1482 _packing = packing;
1483 _rowLength = rowLength;
1484
1485 for(i=0;i<numMipMaps;++i)
1486 {
1487 extensions->glGetCompressedTexImage(textureMode, i, getMipmapData(i));
1488 }
1489
1490 dirty();
1491
1492 }
1493 else
1494 {
1495 MipmapDataType mipMapData;
1496
1497 // Get the internal texture format and packing value from OpenGL,
1498 // instead of using possibly outdated values from the class.
1499 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1500 glGetIntegerv(GL_UNPACK_ALIGNMENT, &packing);
1501 glPixelStorei(GL_PACK_ALIGNMENT, packing);
1502 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowLength);
1503 glPixelStorei(GL_PACK_ROW_LENGTH, rowLength);
1504
1505 unsigned int total_size = 0;
1506 GLint i;
1507 for(i=0;i<numMipMaps;++i)
1508 {
1509 if (i>0) mipMapData.push_back(total_size);
1510
1511 glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_WIDTH, &width);
1512 glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_HEIGHT, &height);
1513 glGetTexLevelParameteriv(textureMode, i, GL_TEXTURE_DEPTH, &depth);
1514
1515 unsigned int level_size = computeRowWidthInBytes(width,internalformat,type,packing)*height*depth;
1516
1517 total_size += level_size;
1518 }
1519
1520
1521 unsigned char* data = new unsigned char[total_size];
1522 if (!data)
1523 {
1524 OSG_WARN<<"Warning: Image::readImageFromCurrentTexture(..) out of memory, no image read."<<std::endl;
1525 return;
1526 }
1527
1528 deallocateData(); // and sets it to NULL.
1529
1530 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_WIDTH, &width);
1531 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_HEIGHT, &height);
1532 glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_DEPTH, &depth);
1533
1534 _data = data;
1535 _s = width;
1536 _t = height;
1537 _r = depth;
1538
1539 _pixelFormat = computePixelFormat(internalformat);
1540 _dataType = type;
1541 _internalTextureFormat = internalformat;
1542 _mipmapData = mipMapData;
1543 _allocationMode=USE_NEW_DELETE;
1544 _packing = packing;
1545 _rowLength = rowLength;
1546
1547 for(i=0;i<numMipMaps;++i)
1548 {
1549 glGetTexImage(textureMode,i,_pixelFormat,_dataType,getMipmapData(i));
1550 }
1551
1552 dirty();
1553 }
1554 #else
1555 OSG_NOTICE<<"Warning: Image::readImageFromCurrentTexture() not supported."<<std::endl;
1556 #endif
1557 }
1558
swap(osg::Image & rhs)1559 void Image::swap(osg::Image& rhs)
1560 {
1561 std::swap(_fileName, rhs._fileName);
1562 std::swap(_writeHint, rhs._writeHint);
1563
1564 std::swap(_origin, rhs._origin);
1565
1566 std::swap(_s, rhs._s); std::swap(_t, rhs._t); std::swap(_r, rhs._r);
1567 std::swap(_rowLength, rhs._rowLength);
1568 std::swap(_internalTextureFormat, rhs._internalTextureFormat);
1569 std::swap(_pixelFormat, rhs._pixelFormat);
1570 std::swap(_dataType, rhs._dataType);
1571 std::swap(_packing, rhs._packing);
1572 std::swap(_pixelAspectRatio, rhs._pixelAspectRatio);
1573
1574 std::swap(_allocationMode, rhs._allocationMode);
1575 std::swap(_data, rhs._data);
1576
1577 std::swap(_mipmapData, rhs._mipmapData);
1578
1579 std::swap(_bufferObject, rhs._bufferObject);
1580
1581 std::swap(_dimensionsChangedCallbacks, rhs._dimensionsChangedCallbacks);
1582 }
1583
1584
scaleImage(int s,int t,int r,GLenum newDataType)1585 void Image::scaleImage(int s,int t,int r, GLenum newDataType)
1586 {
1587 if (_s==s && _t==t && _r==r && _dataType==newDataType) return;
1588
1589 if (_data==NULL)
1590 {
1591 OSG_WARN << "Error Image::scaleImage() do not succeed : cannot scale NULL image."<<std::endl;
1592 return;
1593 }
1594
1595 if (_r!=1 || r!=1)
1596 {
1597 OSG_WARN << "Error Image::scaleImage() do not succeed : scaling of volumes not implemented."<<std::endl;
1598 return;
1599 }
1600
1601 unsigned int newTotalSize = computeRowWidthInBytes(s,_pixelFormat,newDataType,_packing)*t;
1602
1603 // need to sort out what size to really use...
1604 unsigned char* newData = new unsigned char [newTotalSize];
1605 if (!newData)
1606 {
1607 // should we throw an exception??? Just return for time being.
1608 OSG_FATAL << "Error Image::scaleImage() do not succeed : out of memory."<<newTotalSize<<std::endl;
1609 return;
1610 }
1611
1612 PixelStorageModes psm;
1613 psm.pack_alignment = _packing;
1614 psm.pack_row_length = _rowLength;
1615 psm.unpack_alignment = _packing;
1616
1617 GLint status = gluScaleImage(&psm, _pixelFormat,
1618 _s,
1619 _t,
1620 _dataType,
1621 _data,
1622 s,
1623 t,
1624 newDataType,
1625 newData);
1626
1627 if (status==0)
1628 {
1629
1630 // free old image.
1631 _s = s;
1632 _t = t;
1633 _rowLength = 0;
1634 _dataType = newDataType;
1635 setData(newData,USE_NEW_DELETE);
1636 }
1637 else
1638 {
1639 delete [] newData;
1640
1641 OSG_WARN << "Error Image::scaleImage() did not succeed : errorString = "<< gluErrorString((GLenum)status) << ". The rendering context may be invalid." << std::endl;
1642 }
1643
1644 dirty();
1645 }
1646
copySubImage(int s_offset,int t_offset,int r_offset,const osg::Image * source)1647 void Image::copySubImage(int s_offset, int t_offset, int r_offset, const osg::Image* source)
1648 {
1649 if (!source) return;
1650 if (s_offset<0 || t_offset<0 || r_offset<0)
1651 {
1652 OSG_WARN<<"Warning: negative offsets passed to Image::copySubImage(..) not supported, operation ignored."<<std::endl;
1653 return;
1654 }
1655
1656 if (!_data)
1657 {
1658 OSG_INFO<<"allocating image"<<endl;
1659 allocateImage(s_offset+source->s(),t_offset+source->t(),r_offset+source->r(),
1660 source->getPixelFormat(),source->getDataType(),
1661 source->getPacking());
1662 }
1663
1664 if (s_offset>=_s || t_offset>=_t || r_offset>=_r)
1665 {
1666 OSG_WARN<<"Warning: offsets passed to Image::copySubImage(..) outside destination image, operation ignored."<<std::endl;
1667 return;
1668 }
1669
1670
1671 if (_pixelFormat != source->getPixelFormat())
1672 {
1673 OSG_WARN<<"Warning: image with an incompatible pixel formats passed to Image::copySubImage(..), operation ignored."<<std::endl;
1674 return;
1675 }
1676
1677 unsigned char* data_destination = data(s_offset, t_offset, r_offset);
1678 if (isCompressed())
1679 {
1680 osg::Vec3i footprint = computeBlockFootprint(_pixelFormat);
1681 if (footprint.x() == 4 && footprint.y() == 4)
1682 {
1683 if ((source->s() & 0x3) || (source->t() & 0x3) || (s_offset & 0x3) || (t_offset & 0x3))
1684 {
1685 OSG_WARN << "Error Image::copySubImage() did not succeed : size " << source->s() << "x" << source->t() << " or offset " << s_offset<< "," << t_offset << " not multiple of 4." << std::endl;
1686 return;
1687 }
1688 }
1689 else
1690 {
1691 if ((source->s() % footprint.x()) || (source->t() % footprint.y()) || (s_offset % footprint.x()) || (t_offset% footprint.y()))
1692 {
1693 OSG_WARN << "Error Image::copySubImage() did not succeed : size " << source->s() << "x" << source->t() << " or offset " << s_offset << "," << t_offset << " not multiple of footprint " << footprint.x() << "x" << footprint.y() << std::endl;
1694 return;
1695 }
1696 }
1697 unsigned int rowWidthInBlocks = (_s + footprint.x() - 1) / footprint.x();
1698 unsigned int blockSize = computeBlockSize(_pixelFormat, 0);
1699 data_destination = _data + blockSize * (rowWidthInBlocks * (t_offset / footprint.y()) + (s_offset / footprint.x()));
1700 unsigned int copy_width = (osg::minimum(source->s(), _s - s_offset) + footprint.x() - 1) / footprint.x();
1701 unsigned int copy_height = (osg::minimum(source->t(), _t - t_offset) + footprint.y() - 1) / footprint.y();
1702 unsigned int dstRowStep = blockSize * rowWidthInBlocks;
1703 unsigned int srcRowStep = blockSize * ((source->_s + footprint.x() - 1) / footprint.x());
1704 const unsigned char* data_source = source->data(0, 0, 0);
1705 for (unsigned int row = 0; row < copy_height; row += 1) { //copy blocks in a row, footprint.y() rows at a time
1706 memcpy(data_destination, data_source, copy_width * blockSize);
1707 data_source += srcRowStep;
1708 data_destination += dstRowStep;
1709 }
1710 return;
1711 }
1712 PixelStorageModes psm;
1713 psm.pack_alignment = _packing;
1714 psm.pack_row_length = _rowLength!=0 ? _rowLength : _s;
1715 psm.unpack_alignment = source->getPacking();
1716 psm.unpack_row_length = source->getRowLength();
1717
1718 GLint status = gluScaleImage(&psm, _pixelFormat,
1719 source->s(),
1720 source->t(),
1721 source->getDataType(),
1722 source->data(),
1723 source->s(),
1724 source->t(),
1725 _dataType,
1726 data_destination);
1727
1728 if (status!=0)
1729 {
1730 OSG_WARN << "Error Image::scaleImage() did not succeed : errorString = "<< gluErrorString((GLenum)status) << ". The rendering context may be invalid." << std::endl;
1731 }
1732 }
1733
flipHorizontal()1734 void Image::flipHorizontal()
1735 {
1736 if (_data==NULL)
1737 {
1738 OSG_WARN << "Error Image::flipHorizontal() did not succeed : cannot flip NULL image."<<std::endl;
1739 return;
1740 }
1741
1742 unsigned int elemSize = getPixelSizeInBits()/8;
1743
1744 if (_mipmapData.empty())
1745 {
1746 unsigned int rowStepInBytes = getRowStepInBytes();
1747 unsigned int imageStepInBytes = getImageStepInBytes();
1748
1749 for(int r=0;r<_r;++r)
1750 {
1751 for (int t=0; t<_t; ++t)
1752 {
1753 unsigned char* rowData = _data + t*rowStepInBytes + r*imageStepInBytes;
1754 unsigned char* left = rowData ;
1755 unsigned char* right = rowData + ((_s-1)*getPixelSizeInBits())/8;
1756
1757 while (left < right)
1758 {
1759 char tmp[32]; // max elem size is four floats
1760 memcpy(tmp, left, elemSize);
1761 memcpy(left, right, elemSize);
1762 memcpy(right, tmp, elemSize);
1763 left += elemSize;
1764 right -= elemSize;
1765 }
1766 }
1767 }
1768 }
1769 else
1770 {
1771 OSG_WARN << "Error Image::flipHorizontal() did not succeed : cannot flip mipmapped image."<<std::endl;
1772 return;
1773 }
1774
1775 dirty();
1776 }
1777
flipImageVertical(unsigned char * top,unsigned char * bottom,unsigned int rowSize,unsigned int rowStep)1778 void flipImageVertical(unsigned char* top, unsigned char* bottom, unsigned int rowSize, unsigned int rowStep)
1779 {
1780 while(top<bottom)
1781 {
1782 unsigned char* t = top;
1783 unsigned char* b = bottom;
1784 for(unsigned int i=0;i<rowSize;++i, ++t,++b)
1785 {
1786 unsigned char temp=*t;
1787 *t = *b;
1788 *b = temp;
1789 }
1790 top += rowStep;
1791 bottom -= rowStep;
1792 }
1793 }
1794
1795
flipVertical()1796 void Image::flipVertical()
1797 {
1798 if (_data==NULL)
1799 {
1800 OSG_WARN << "Error Image::flipVertical() do not succeed : cannot flip NULL image."<<std::endl;
1801 return;
1802 }
1803
1804 if (!_mipmapData.empty() && _r>1)
1805 {
1806 OSG_WARN << "Error Image::flipVertical() do not succeed : flipping of mipmap 3d textures not yet supported."<<std::endl;
1807 return;
1808 }
1809
1810 unsigned int rowSize = getRowSizeInBytes();
1811 unsigned int rowStep = getRowStepInBytes();
1812
1813 const bool dxtc(dxtc_tool::isDXTC(_pixelFormat));
1814 if (_mipmapData.empty())
1815 {
1816 // no mipmaps,
1817 // so we can safely handle 3d textures
1818 for(int r=0;r<_r;++r)
1819 {
1820 if (dxtc)
1821 {
1822 if (!dxtc_tool::VerticalFlip(_s,_t,_pixelFormat,data(0,0,r)))
1823 {
1824 OSG_NOTICE << "Notice Image::flipVertical(): Vertical flip do not succeed" << std::endl;
1825 }
1826 }
1827 else
1828 {
1829 if (isCompressed()) OSG_NOTICE << "Notice Image::flipVertical(): image is compressed but normal v-flip is used" << std::endl;
1830 // its not a compressed image, so implement flip oursleves.
1831 unsigned char* top = data(0,0,r);
1832 unsigned char* bottom = top + (_t-1)*rowStep;
1833
1834 flipImageVertical(top, bottom, rowSize, rowStep);
1835 }
1836 }
1837 }
1838 else if (_r==1)
1839 {
1840 if (dxtc)
1841 {
1842 if (!dxtc_tool::VerticalFlip(_s,_t,_pixelFormat,_data))
1843 {
1844 OSG_NOTICE << "Notice Image::flipVertical(): Vertical flip do not succeed" << std::endl;
1845 }
1846 }
1847 else
1848 {
1849 if (isCompressed()) OSG_NOTICE << "Notice Image::flipVertical(): image is compressed but normal v-flip is used" << std::endl;
1850 // its not a compressed image, so implement flip oursleves.
1851 unsigned char* top = data(0,0,0);
1852 unsigned char* bottom = top + (_t-1)*rowStep;
1853
1854 flipImageVertical(top, bottom, rowSize, rowStep);
1855 }
1856
1857 int s = _s;
1858 int t = _t;
1859 //int r = _r;
1860
1861 for(unsigned int i=0;i<_mipmapData.size() && _mipmapData[i];++i)
1862 {
1863 s >>= 1;
1864 t >>= 1;
1865 if (s==0) s=1;
1866 if (t==0) t=1;
1867 if (dxtc)
1868 {
1869 if (!dxtc_tool::VerticalFlip(s,t,_pixelFormat,_data+_mipmapData[i]))
1870 {
1871 OSG_NOTICE << "Notice Image::flipVertical(): Vertical flip did not succeed" << std::endl;
1872 }
1873 }
1874 else
1875 {
1876 // it's not a compressed image, so implement flip ourselves.
1877 unsigned int mipRowSize = computeRowWidthInBytes(s, _pixelFormat, _dataType, _packing);
1878 unsigned int mipRowStep = mipRowSize;
1879 unsigned char* top = _data+_mipmapData[i];
1880 unsigned char* bottom = top + (t-1)*mipRowStep;
1881
1882 flipImageVertical(top, bottom, mipRowSize, mipRowStep);
1883 }
1884 }
1885 }
1886
1887 dirty();
1888 }
1889
flipDepth()1890 void Image::flipDepth()
1891 {
1892 if (_data==NULL)
1893 {
1894 OSG_WARN << "Error Image::flipVertical() do not succeed : cannot flip NULL image."<<std::endl;
1895 return;
1896 }
1897
1898 if (_r==1)
1899 {
1900 return;
1901 }
1902
1903 if (!_mipmapData.empty() && _r>1)
1904 {
1905 OSG_WARN << "Error Image::flipVertical() do not succeed : flipping of mipmap 3d textures not yet supported."<<std::endl;
1906 return;
1907 }
1908
1909 unsigned int sizeOfRow = getRowSizeInBytes();
1910
1911 int r_front = 0;
1912 int r_back = _r-1;
1913 for(; r_front<r_back; ++r_front,--r_back)
1914 {
1915 for(int row=0; row<_t; ++row)
1916 {
1917 unsigned char* front = data(0, row, r_front);
1918 unsigned char* back = data(0, row, r_back);
1919 for(unsigned int i=0; i<sizeOfRow; ++i, ++front, ++back)
1920 {
1921 std::swap(*front, *back);
1922 }
1923 }
1924 }
1925 }
1926
1927
ensureValidSizeForTexturing(GLint maxTextureSize)1928 void Image::ensureValidSizeForTexturing(GLint maxTextureSize)
1929 {
1930 int new_s = computeNearestPowerOfTwo(_s);
1931 int new_t = computeNearestPowerOfTwo(_t);
1932
1933 if (new_s>maxTextureSize) new_s = maxTextureSize;
1934 if (new_t>maxTextureSize) new_t = maxTextureSize;
1935
1936 if (new_s!=_s || new_t!=_t)
1937 {
1938 if (!_fileName.empty()) { OSG_NOTICE << "Scaling image '"<<_fileName<<"' from ("<<_s<<","<<_t<<") to ("<<new_s<<","<<new_t<<")"<<std::endl; }
1939 else { OSG_NOTICE << "Scaling image from ("<<_s<<","<<_t<<") to ("<<new_s<<","<<new_t<<")"<<std::endl; }
1940
1941 scaleImage(new_s,new_t,_r);
1942 }
1943 }
1944
supportsTextureSubloading() const1945 bool Image::supportsTextureSubloading() const
1946 {
1947 switch(_internalTextureFormat)
1948 {
1949 case GL_ETC1_RGB8_OES:
1950 case(GL_COMPRESSED_RGB8_ETC2):
1951 case(GL_COMPRESSED_SRGB8_ETC2):
1952 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2):
1953 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2):
1954 case(GL_COMPRESSED_RGBA8_ETC2_EAC):
1955 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC):
1956 case(GL_COMPRESSED_R11_EAC):
1957 case(GL_COMPRESSED_SIGNED_R11_EAC):
1958 case(GL_COMPRESSED_RG11_EAC):
1959 case(GL_COMPRESSED_SIGNED_RG11_EAC):
1960 return false;
1961 default:
1962 return true;
1963 }
1964 }
1965
1966
1967 template <typename T>
_findLowerAlphaValueInRow(unsigned int num,T * data,T value,unsigned int delta)1968 bool _findLowerAlphaValueInRow(unsigned int num, T* data,T value, unsigned int delta)
1969 {
1970 for(unsigned int i=0;i<num;++i)
1971 {
1972 if (*data<value) return true;
1973 data += delta;
1974 }
1975 return false;
1976 }
1977
1978 template <typename T>
_maskedFindLowerAlphaValueInRow(unsigned int num,T * data,T value,T mask,unsigned int delta)1979 bool _maskedFindLowerAlphaValueInRow(unsigned int num, T* data,T value, T mask, unsigned int delta)
1980 {
1981 for(unsigned int i=0;i<num;++i)
1982 {
1983 if ((*data & mask)<value) return true;
1984 data += delta;
1985 }
1986 return false;
1987 }
1988
isImageTranslucent() const1989 bool Image::isImageTranslucent() const
1990 {
1991 unsigned int offset = 0;
1992 unsigned int delta = 1;
1993 switch(_pixelFormat)
1994 {
1995 case(GL_ALPHA):
1996 offset = 0;
1997 delta = 1;
1998 break;
1999 case(GL_LUMINANCE_ALPHA):
2000 offset = 1;
2001 delta = 2;
2002 break;
2003 case(GL_RGBA):
2004 offset = 3;
2005 delta = 4;
2006 break;
2007 case(GL_BGRA):
2008 offset = 3;
2009 delta = 4;
2010 break;
2011 case(GL_RGB):
2012 return false;
2013 case(GL_BGR):
2014 return false;
2015 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
2016 return false;
2017 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
2018 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
2019 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
2020 return dxtc_tool::isCompressedImageTranslucent(_s, _t, _pixelFormat, _data);
2021 default:
2022 return false;
2023 }
2024
2025 for(int ir=0;ir<r();++ir)
2026 {
2027 for(int it=0;it<t();++it)
2028 {
2029 const unsigned char* d = data(0,it,ir);
2030 switch(_dataType)
2031 {
2032 case(GL_BYTE):
2033 if (_findLowerAlphaValueInRow(s(), (char*)d +offset, (char)127, delta))
2034 return true;
2035 break;
2036 case(GL_UNSIGNED_BYTE):
2037 if (_findLowerAlphaValueInRow(s(), (unsigned char*)d + offset, (unsigned char)255, delta))
2038 return true;
2039 break;
2040 case(GL_SHORT):
2041 if (_findLowerAlphaValueInRow(s(), (short*)d + offset, (short)32767, delta))
2042 return true;
2043 break;
2044 case(GL_UNSIGNED_SHORT):
2045 if (_findLowerAlphaValueInRow(s(), (unsigned short*)d + offset, (unsigned short)65535, delta))
2046 return true;
2047 break;
2048 case(GL_INT):
2049 if (_findLowerAlphaValueInRow(s(), (int*)d + offset, (int)2147483647, delta))
2050 return true;
2051 break;
2052 case(GL_UNSIGNED_INT):
2053 if (_findLowerAlphaValueInRow(s(), (unsigned int*)d + offset, 4294967295u, delta))
2054 return true;
2055 break;
2056 case(GL_FLOAT):
2057 if (_findLowerAlphaValueInRow(s(), (float*)d + offset, 1.0f, delta))
2058 return true;
2059 break;
2060 case(GL_UNSIGNED_SHORT_5_5_5_1):
2061 if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
2062 (unsigned short)0x0001,
2063 (unsigned short)0x0001, 1))
2064 return true;
2065 break;
2066 case(GL_UNSIGNED_SHORT_1_5_5_5_REV):
2067 if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
2068 (unsigned short)0x8000,
2069 (unsigned short)0x8000, 1))
2070 return true;
2071 break;
2072 case(GL_UNSIGNED_SHORT_4_4_4_4):
2073 if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
2074 (unsigned short)0x000f,
2075 (unsigned short)0x000f, 1))
2076 return true;
2077 break;
2078 case(GL_UNSIGNED_SHORT_4_4_4_4_REV):
2079 if (_maskedFindLowerAlphaValueInRow(s(), (unsigned short*)d,
2080 (unsigned short)0xf000,
2081 (unsigned short)0xf000, 1))
2082 return true;
2083 break;
2084 case(GL_UNSIGNED_INT_10_10_10_2):
2085 if (_maskedFindLowerAlphaValueInRow(s(), (unsigned int*)d,
2086 0x00000003u,
2087 0x00000003u, 1))
2088 return true;
2089 break;
2090 case(GL_UNSIGNED_INT_2_10_10_10_REV):
2091 if (_maskedFindLowerAlphaValueInRow(s(), (unsigned int*)d,
2092 0xc0000000u,
2093 0xc0000000u, 1))
2094 return true;
2095 break;
2096 case(GL_HALF_FLOAT):
2097 if (_findLowerAlphaValueInRow(s(), (unsigned short*)d + offset,
2098 (unsigned short)0x3c00, delta))
2099 return true;
2100 break;
2101 }
2102 }
2103 }
2104
2105 return false;
2106 }
2107
2108 ///////////////////////////////////////////////////////////////////////////////
2109
2110
createGeodeForImage(osg::Image * image)2111 Geode* osg::createGeodeForImage(osg::Image* image)
2112 {
2113 return createGeodeForImage(image,image->s(),image->t());
2114 }
2115
2116
2117 #include <osg/TextureRectangle>
2118
2119
createGeodeForImage(osg::Image * image,float s,float t)2120 Geode* osg::createGeodeForImage(osg::Image* image,float s,float t)
2121 {
2122 if (image)
2123 {
2124 if (s>0 && t>0)
2125 {
2126
2127 float y = 1.0;
2128 float x = y*(s/t);
2129
2130 float texcoord_y_b = (image->getOrigin() == osg::Image::BOTTOM_LEFT) ? 0.0f : 1.0f;
2131 float texcoord_y_t = (image->getOrigin() == osg::Image::BOTTOM_LEFT) ? 1.0f : 0.0f;
2132
2133 // set up the texture.
2134
2135 #if 0
2136 osg::TextureRectangle* texture = new osg::TextureRectangle;
2137 texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
2138 texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
2139 //texture->setResizeNonPowerOfTwoHint(false);
2140 float texcoord_x = image->s();
2141 texcoord_y_b *= image->t();
2142 texcoord_y_t *= image->t();
2143 #else
2144 osg::Texture2D* texture = new osg::Texture2D;
2145 texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
2146 texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
2147 texture->setResizeNonPowerOfTwoHint(false);
2148 float texcoord_x = 1.0f;
2149 #endif
2150 texture->setImage(image);
2151
2152 // set up the drawstate.
2153 osg::StateSet* dstate = new osg::StateSet;
2154 dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
2155 dstate->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
2156 dstate->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON);
2157
2158 // set up the geoset. unsigned int rowSize = computeRowWidthInBytes(s,_pixelFormat,_dataType,_packing);
2159
2160 Geometry* geom = new Geometry;
2161 geom->setStateSet(dstate);
2162
2163 Vec3Array* coords = new Vec3Array(4);
2164 (*coords)[0].set(-x,0.0f,y);
2165 (*coords)[1].set(-x,0.0f,-y);
2166 (*coords)[2].set(x,0.0f,-y);
2167 (*coords)[3].set(x,0.0f,y);
2168 geom->setVertexArray(coords);
2169
2170 Vec2Array* tcoords = new Vec2Array(4);
2171 (*tcoords)[0].set(0.0f*texcoord_x,texcoord_y_t);
2172 (*tcoords)[1].set(0.0f*texcoord_x,texcoord_y_b);
2173 (*tcoords)[2].set(1.0f*texcoord_x,texcoord_y_b);
2174 (*tcoords)[3].set(1.0f*texcoord_x,texcoord_y_t);
2175 geom->setTexCoordArray(0,tcoords);
2176
2177 osg::Vec4Array* colours = new osg::Vec4Array(1);
2178 (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
2179 geom->setColorArray(colours, osg::Array::BIND_OVERALL);
2180
2181 geom->addPrimitiveSet(new DrawArrays(PrimitiveSet::QUADS,0,4));
2182
2183 // set up the geode.
2184 osg::Geode* geode = new osg::Geode;
2185 geode->addDrawable(geom);
2186
2187 return geode;
2188
2189 }
2190 else
2191 {
2192 return NULL;
2193 }
2194 }
2195 else
2196 {
2197 return NULL;
2198 }
2199 }
2200
2201 template <typename T>
_readColor(GLenum pixelFormat,T * data,float scale)2202 Vec4 _readColor(GLenum pixelFormat, T* data,float scale)
2203 {
2204 switch(pixelFormat)
2205 {
2206 case(GL_DEPTH_COMPONENT): //intentionally fall through and execute the code for GL_LUMINANCE
2207 case(GL_LUMINANCE): { float l = float(*data++)*scale; return Vec4(l, l, l, 1.0f); }
2208 case(GL_ALPHA): { float a = float(*data++)*scale; return Vec4(1.0f, 1.0f, 1.0f, a); }
2209 case(GL_RED): { float r = float(*data++)*scale; return Vec4(r, 1.0f, 1.0f, 1.0f); }
2210 case(GL_RG): { float r = float(*data++)*scale; float g = float(*data++)*scale; return Vec4(r, g, 1.0f, 1.0f); }
2211 case(GL_LUMINANCE_ALPHA): { float l = float(*data++)*scale; float a = float(*data++)*scale; return Vec4(l,l,l,a); }
2212 case(GL_RGB): { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; return Vec4(r,g,b,1.0f); }
2213 case(GL_RGBA): { float r = float(*data++)*scale; float g = float(*data++)*scale; float b = float(*data++)*scale; float a = float(*data++)*scale; return Vec4(r,g,b,a); }
2214 case(GL_BGR): { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; return Vec4(r,g,b,1.0f); }
2215 case(GL_BGRA): { float b = float(*data++)*scale; float g = float(*data++)*scale; float r = float(*data++)*scale; float a = float(*data++)*scale; return Vec4(r,g,b,a); }
2216 }
2217 return Vec4(1.0f,1.0f,1.0f,1.0f);
2218 }
2219
getColor(unsigned int s,unsigned t,unsigned r) const2220 Vec4 Image::getColor(unsigned int s,unsigned t,unsigned r) const
2221 {
2222 if (isCompressed())
2223 {
2224 if (dxtc_tool::isDXTC(_pixelFormat)) {
2225 unsigned char color[4];
2226 if (dxtc_tool::CompressedImageGetColor(color, s, t, r, _s, _t, _r, _pixelFormat, _data)) {
2227 return Vec4(((float)color[0]) / 255.0f, ((float)color[1]) / 255.0f, ((float)color[2]) / 255.0f, ((float)color[3]) / 255.0f );
2228 }
2229 }
2230 }
2231 else
2232 {
2233 const unsigned char* ptr = data(s,t,r);
2234 switch(_dataType)
2235 {
2236 case(GL_BYTE): return _readColor(_pixelFormat, (char*)ptr, 1.0f/128.0f);
2237 case(GL_UNSIGNED_BYTE): return _readColor(_pixelFormat, (unsigned char*)ptr, 1.0f/255.0f);
2238 case(GL_SHORT): return _readColor(_pixelFormat, (short*)ptr, 1.0f/32768.0f);
2239 case(GL_UNSIGNED_SHORT): return _readColor(_pixelFormat, (unsigned short*)ptr, 1.0f/65535.0f);
2240 case(GL_INT): return _readColor(_pixelFormat, (int*)ptr, 1.0f/2147483648.0f);
2241 case(GL_UNSIGNED_INT): return _readColor(_pixelFormat, (unsigned int*)ptr, 1.0f/4294967295.0f);
2242 case(GL_FLOAT): return _readColor(_pixelFormat, (float*)ptr, 1.0f);
2243 case(GL_DOUBLE): return _readColor(_pixelFormat, (double*)ptr, 1.0f);
2244 }
2245 }
2246 return Vec4(1.0f,1.0f,1.0f,1.0f);
2247 }
2248
getColor(const Vec3 & texcoord) const2249 Vec4 Image::getColor(const Vec3& texcoord) const
2250 {
2251 unsigned int s = osg::clampTo(int(texcoord.x()*float(_s-1)), 0, _s-1);
2252 unsigned int t = osg::clampTo(int(texcoord.y()*float(_t-1)), 0, _t-1);
2253 unsigned int r = osg::clampTo(int(texcoord.z()*float(_r-1)), 0, _r-1);
2254 //OSG_NOTICE<<"getColor("<<texcoord<<")="<<getColor(s,t,r)<<std::endl;
2255 return getColor(s,t,r);
2256 }
2257
2258
2259 template <typename T>
_writeColor(GLenum pixelFormat,T * data,float scale,const Vec4 & c)2260 void _writeColor(GLenum pixelFormat, T* data, float scale, const Vec4& c)
2261 {
2262 switch(pixelFormat)
2263 {
2264 case(GL_DEPTH_COMPONENT): //intentionally fall through and execute the code for GL_LUMINANCE
2265 case(GL_LUMINANCE): { (*data++) = (T)(c[0] * scale); } break;
2266 case(GL_ALPHA): { (*data++) = (T)(c[3] * scale); } break;
2267 case(GL_LUMINANCE_ALPHA): { (*data++) = (T)(c[0] * scale); (*data++) = (T)(c[3] * scale); } break;
2268 case(GL_RGB): { (*data++) = (T)(c[0] *scale); (*data++) = (T)(c[1] *scale); (*data++) = (T)(c[2] *scale);} break;
2269 case(GL_RGBA): { (*data++) = (T)(c[0] *scale); (*data++) = (T)(c[1] *scale); (*data++) = (T)(c[2] *scale); (*data++) = (T)(c[3] *scale);} break;
2270 case(GL_BGR): { (*data++) = (T)(c[2] *scale); (*data++) = (T)(c[1] *scale); (*data++) = (T)(c[0] *scale);} break;
2271 case(GL_BGRA): { (*data++) = (T)(c[2] *scale); (*data++) = (T)(c[1] *scale); (*data++) = (T)(c[0] *scale); (*data++) = (T)(c[3] *scale);} break;
2272 }
2273
2274 }
2275
2276
setColor(const Vec4 & color,unsigned int s,unsigned int t,unsigned int r)2277 void Image::setColor( const Vec4& color, unsigned int s, unsigned int t/*=0*/, unsigned int r/*=0*/ )
2278 {
2279 unsigned char* ptr = data(s,t,r);
2280
2281 switch(getDataType())
2282 {
2283 case(GL_BYTE): return _writeColor(getPixelFormat(), (char*)ptr, 128.0f, color);
2284 case(GL_UNSIGNED_BYTE): return _writeColor(getPixelFormat(), (unsigned char*)ptr, 255.0f, color);
2285 case(GL_SHORT): return _writeColor(getPixelFormat(), (short*)ptr, 32768.0f, color);
2286 case(GL_UNSIGNED_SHORT): return _writeColor(getPixelFormat(), (unsigned short*)ptr, 65535.0f, color);
2287 case(GL_INT): return _writeColor(getPixelFormat(), (int*)ptr, 2147483648.0f, color);
2288 case(GL_UNSIGNED_INT): return _writeColor(getPixelFormat(), (unsigned int*)ptr, 4294967295.0f, color);
2289 case(GL_FLOAT): return _writeColor(getPixelFormat(), (float*)ptr, 1.0f, color);
2290 case(GL_DOUBLE): return _writeColor(getPixelFormat(), (double*)ptr, 1.0f, color);
2291 }
2292 }
2293
setColor(const Vec4 & color,const Vec3 & texcoord)2294 void Image::setColor( const Vec4& color, const Vec3& texcoord )
2295 {
2296 unsigned int s = osg::clampTo(int(texcoord.x()*float(_s-1)), 0, _s-1);
2297 unsigned int t = osg::clampTo(int(texcoord.y()*float(_t-1)), 0, _t-1);
2298 unsigned int r = osg::clampTo(int(texcoord.z()*float(_r-1)), 0, _r-1);
2299
2300 return setColor(color, s,t,r);
2301 }
2302
addDimensionsChangedCallback(DimensionsChangedCallback * cb)2303 void Image::addDimensionsChangedCallback(DimensionsChangedCallback* cb)
2304 {
2305 _dimensionsChangedCallbacks.push_back(cb);
2306 }
2307
removeDimensionsChangedCallback(DimensionsChangedCallback * cb)2308 void Image::removeDimensionsChangedCallback(DimensionsChangedCallback* cb)
2309 {
2310 DimensionsChangedCallbackVector::iterator itr = std::find(_dimensionsChangedCallbacks.begin(), _dimensionsChangedCallbacks.end(), cb);
2311 if (itr!=_dimensionsChangedCallbacks.end()) _dimensionsChangedCallbacks.erase(itr);
2312 }
2313