Developer Documentation
Loading...
Searching...
No Matches
globjects.cc
1/*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42#include <ACG/GL/acg_glew.hh>
43#include <ACG/GL/globjects.hh>
44#include <ACG/GL/GLFormatInfo.hh>
45#include <ACG/ShaderUtils/GLSLShader.hh>
46#include <ACG/Utils/ImageConversion.hh>
47
48#include <QImage>
49#if QT_VERSION_MAJOR < 6
50 #include <QGLWidget>
51#else
52 #include <QtOpenGLWidgets/QOpenGLWidget>
53#endif
54
55namespace ACG {
56
57
58//-----------------------------------------------------------------------------
59
60Texture::Texture( GLenum tgt, GLenum _unit )
61 : target(tgt), unit(_unit), valid(false), texture(0u), internalFormat_(0)
62{
63}
64
65void Texture::bindAsImage(GLuint _index, GLenum _access)
66{
67#if defined(GL_ARB_shader_image_load_store)
68 if (is_valid())
69 glBindImageTexture(_index, id(), 0, GL_FALSE, 0, _access, getInternalFormat());
70 else
71 std::cerr << "Texture::bindAsImage - error: texture not initialized!" << std::endl;
72#else
73 std::cerr << "Texture::bindAsImage - glBindImageTexture symbol not loaded!" << std::endl;
74#endif
75}
76
77
78GLint Texture::getInternalFormat()
79{
80 if (!internalFormat_)
81 {
82 bind();
83 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat_);
84 }
85
86 return internalFormat_;
87}
88//
89// bool Texture::clear( float _color )
90// {
91// #ifdef GL_ARB_clear_texture
92// if (supportsClearTexture() && texture)
93// {
94// glClearTexImage(texture, 0, GL_R32F, GL_FLOAT, &_color);
95// return true;
96// }
97// #endif
98// return false;
99// }
100//
101// bool Texture::clear( const ACG::Vec2f& _color )
102// {
103// #ifdef GL_ARB_clear_texture
104// if (supportsClearTexture() && texture)
105// {
106// glClearTexImage(texture, 0, GL_RG32F, GL_FLOAT, _color.data());
107// return true;
108// }
109// #endif
110// return false;
111// }
112//
113// bool Texture::clear( const ACG::Vec3f& _color )
114// {
115// #ifdef GL_ARB_clear_texture
116// if (supportsClearTexture() && texture)
117// {
118// glClearTexImage(texture, 0, GL_RGB32F, GL_FLOAT, _color.data());
119// return true;
120// }
121// #endif
122// return false;
123// }
124
125bool Texture::clear( const ACG::Vec4f& _color )
126{
127#ifdef GL_ARB_clear_texture
128 if (supportsClearTexture() && texture)
129 {
130 glClearTexImage(texture, 0, GL_RGBA, GL_FLOAT, _color.data());
131 return true;
132 }
133#endif
134 return false;
135}
136
137bool Texture::clear( const ACG::Vec4ui& _color )
138{
139#ifdef GL_ARB_clear_texture
140 if (supportsClearTexture() && texture)
141 {
142 glClearTexImage(texture, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, _color.data());
143 return true;
144 }
145#endif
146 return false;
147}
148
149bool Texture::clear( const ACG::Vec4i& _color )
150{
151#ifdef GL_ARB_clear_texture
152 if (supportsClearTexture() && texture)
153 {
154 glClearTexImage(texture, 0, GL_RGBA_INTEGER, GL_INT, _color.data());
155 return true;
156 }
157#endif
158 return false;
159}
160
161bool Texture::supportsImageLoadStore()
162{
163 static int status = -1;
164
165 if (status < 0)
166 {
167#if defined(GL_ARB_shader_image_load_store)
168 // core in version 4.2
169 status = checkExtensionSupported("ARB_shader_image_load_store") || openGLVersion(4,2);
170#else
171 // symbol missing, install latest glew version
172 status = 0;
173#endif
174 }
175
176 return status > 0;
177}
178
179
180bool Texture::supportsTextureBuffer()
181{
182 static int status = -1;
183
184 if (status < 0)
185 {
186 // core in version 3.0
187 status = checkExtensionSupported("EXT_texture_buffer") || openGLVersion(3,1);
188 }
189
190 return status > 0;
191}
192
193
194bool Texture::supportsClearTexture()
195{
196 static int status = -1;
197
198 if (status < 0)
199 {
200#if defined(GL_ARB_clear_texture)
201 status = checkExtensionSupported("ARB_clear_texture");
202#else
203 // symbol missing, install latest glew version
204 status = 0;
205#endif
206 }
207
208 return status > 0;
209}
210
211bool Texture::supportsGenerateMipmap()
212{
213 static int status = -1;
214
215 if (status < 0)
216 {
217#if defined(GL_SGIS_generate_mipmap)
218 status = checkExtensionSupported("GL_SGIS_generate_mipmap");
219#else
220 // symbol missing, install latest glew version
221 status = 0;
222#endif
223 }
224
225 return status > 0;
226}
227
228//-----------------------------------------------------------------------------
229
230
231Texture1D::Texture1D( GLenum unit ) : Texture(GL_TEXTURE_1D, unit),
232 width_(0),
233 format_(0), type_(0)
234{}
235
236void Texture1D::setData(GLint _level,
237 GLint _internalFormat,
238 GLsizei _width,
239 GLenum _format,
240 GLenum _type,
241 const GLvoid* _data) {
242
243 bind();
244
245 glTexImage1D(GL_TEXTURE_1D, _level, _internalFormat, _width, 0, _format, _type, _data);
246
247 width_ = _width;
248 internalFormat_ = _internalFormat;
249 format_ = _format;
250 type_ = _type;
251}
252
253
254void Texture1D::setStorage( GLsizei _levels, GLenum _internalFormat, GLsizei _width ) {
255#ifdef GL_ARB_texture_storage
256 bind();
257 glTexStorage1D(GL_TEXTURE_1D, _levels, _internalFormat, _width);
258
259 width_ = _width;
260 internalFormat_ = _internalFormat;
261
262 GLFormatInfo finfo(_internalFormat);
263 format_ = finfo.format();
264 type_ = finfo.type();
265#endif // GL_ARB_texture_storage
266}
267
268
269bool Texture1D::getData( GLint _level, void* _dst ) {
270 if (is_valid()) {
271 GLint curTex = 0;
272 glGetIntegerv(GL_TEXTURE_BINDING_1D, &curTex);
273
274 bind();
275 glGetTexImage(GL_TEXTURE_1D, _level, format_, type_, _dst);
276
277 glBindTexture(GL_TEXTURE_1D, curTex);
278
279 return true;
280 }
281 return false;
282}
283
284bool Texture1D::getData( GLint _level, std::vector<char>& _dst ) {
285 if (is_valid()) {
286
287 GLFormatInfo finfo(internalFormat_);
288
289 if (finfo.isValid()) {
290 size_t bufSize = finfo.elemSize() * width_;
291
292 if (_dst.size() < bufSize)
293 _dst.resize(bufSize);
294
295 if (!_dst.empty())
296 return getData(_level, &_dst[0]);
297 }
298 }
299 return false;
300}
301
302
303
304
305
306//-----------------------------------------------------------------------------
307
308Texture2D::Texture2D(GLenum unit)
309 : Texture(GL_TEXTURE_2D, unit),
310 width_(0), height_(0),
311 format_(0), type_(0),
312 buildMipsCPU_(false)
313{}
314
315//-----------------------------------------------------------------------------
316
317bool Texture2D::autogenerateMipMaps()
318{
319 if(openGLVersion(3,0))
320 {
321 // From OpenGL 3.0, glGenerateMipmap is supported and we should use that
322 // but glGenerateMipmap must be called AFTER the data was uploaded.
323 return false;
324 }
325
326#ifdef GL_SGIS_generate_mipmap
327 if (supportsGenerateMipmap())
328 {
329 parameter(GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
330 return true;
331 }
332#endif
333 // hardware accelerated generation is not available, fall back to software implementation
334 buildMipsCPU_ = true;
335 return false;
336}
337
338//-----------------------------------------------------------------------------
339
340void Texture2D::disableAutogenerateMipMaps()
341{
342#ifdef GL_SGIS_generate_mipmap
343 if (supportsGenerateMipmap())
344 parameter(GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
345#endif
346 buildMipsCPU_ = false;
347}
348
349//-----------------------------------------------------------------------------
350
351void Texture2D::setData(GLint _level,
352 GLint _internalFormat,
353 GLsizei _width,
354 GLsizei _height,
355 GLenum _format,
356 GLenum _type,
357 const GLvoid* _data,
358 bool _mipmaps) {
359
360 if (getUnit() == GL_NONE)
361 setUnit(GL_TEXTURE0);
362
363 bind();
364
365 if (buildMipsCPU_ && _level == 0)
366 buildMipMaps(_internalFormat, _width, _height, _format, _type, _data);
367 else
368 glTexImage2D(GL_TEXTURE_2D, _level, _internalFormat, _width, _height, 0, _format, _type, _data);
369
370 // If mip maps should not be built on cpu and the OpenGL version is high enough, we go the default way
371 if(_mipmaps && !buildMipsCPU_ && openGLVersion(3,0))
372 glGenerateMipmap(GL_TEXTURE_2D);
373
374 width_ = _width;
375 height_ = _height;
376 internalFormat_ = _internalFormat;
377 format_ = _format;
378 type_ = _type;
379}
380
381
382void Texture2D::setStorage( GLsizei _levels, GLenum _internalFormat, GLsizei _width, GLsizei _height ) {
383#ifdef GL_ARB_texture_storage
384 bind();
385 glTexStorage2D(GL_TEXTURE_2D, _levels, _internalFormat, _width, _height);
386
387 width_ = _width;
388 height_ = _height;
389 internalFormat_ = _internalFormat;
390
391 GLFormatInfo finfo(_internalFormat);
392 format_ = finfo.format();
393 type_ = finfo.type();
394#endif // GL_ARB_texture_storage
395}
396
397
398bool Texture2D::getData( GLint _level, void* _dst ) {
399 if (is_valid()) {
400 GLint curTex = 0;
401 glGetIntegerv(GL_TEXTURE_BINDING_2D, &curTex);
402
403 bind();
404 glGetTexImage(GL_TEXTURE_2D, _level, format_, type_, _dst);
405
406 glBindTexture(GL_TEXTURE_2D, curTex);
407
408 return true;
409 }
410 return false;
411}
412
413bool Texture2D::getData( GLint _level, std::vector<char>& _dst ) {
414 if (is_valid()) {
415
416 GLFormatInfo finfo(internalFormat_);
417
418 if (finfo.isValid()) {
419 size_t bufSize = finfo.elemSize() * width_ * height_;
420
421 if (_dst.size() < bufSize)
422 _dst.resize(bufSize);
423
424 if (!_dst.empty())
425 return getData(_level, &_dst[0]);
426 }
427 }
428 return false;
429}
430
431template<class T>
432void Texture2D_buildMipMaps_DataInterpreter(Vec4f* _dst, int _numChannels, int _srcOffset, const void* _src)
433{
434 const T* dataT = static_cast<const T*>(_src);
435
436 for (int i = 0; i < _numChannels; ++i)
437 (*_dst)[i] = float(dataT[_srcOffset + i]);
438}
439
440void Texture2D::buildMipMaps( GLenum _internalfmt,
441 GLint _width,
442 GLint _height,
443 GLenum _format,
444 GLenum _type,
445 const void* _data )
446{
447// gluBuild2DMipmaps(_target, _internalfmt, _width, _height, _format, _type, _data);
448// return;
449//
450 if (_data)
451 {
452 GLFormatInfo finfo(_internalfmt);
453
454 if (finfo.isValid() && (finfo.isFloat() || finfo.isNormalized()))
455 {
456 int numChannels = finfo.channelCount();
457
458
459 // avoid quantization error for smaller mipmaps
460 // -> treat image data as floats instead of normalized ubytes
461
462
463 // compute number of mipmaps
464
465 Vec2i curSize = Vec2i(_width, _height);
466
467 std::vector<int> mipMemsize(1, 0);
468 std::vector<Vec2i> mipSize(1, curSize);
469 // mipmap count is usually a small number, so push_back() shouldn't be problematic
470 mipMemsize.reserve(16);
471 mipSize.reserve(16);
472
473 int numMips = 1; // first level
474
475 // downscale width and height by 2 until 1x1 texture
476 while (curSize[0] > 1 || curSize[1] > 1)
477 {
478 for (int k = 0; k < 2; ++k)
479 curSize[k] = std::max(1, curSize[k] >> 1);
480
481 // tex dimension
482 mipSize.push_back(curSize);
483
484 // size in bytes
485 int numPixels = curSize[0] * curSize[1];
486 mipMemsize.push_back(numPixels * numChannels * 4);
487
488 ++numMips;
489 }
490
491 // compute size in bytes required for the complete mipmap chain starting at level 1
492 std::vector<int> mipOffset; // offset in bytes
493 mipOffset.reserve(16);
494 int totalMemSize = 0;
495 for (int mipID = 0; mipID < numMips; ++mipID)
496 {
497 mipOffset.push_back(totalMemSize);
498 totalMemSize += mipMemsize[mipID];
499 }
500
501
502 // alloc memory block for the mipmaps
503 std::vector<float> mipData(totalMemSize / 4);
504
505 // downsample
506 for (int mipID = 1; mipID < numMips; ++mipID)
507 {
508 Vec2i srcSize = mipSize[mipID-1];
509 Vec2i dstSize = mipSize[mipID];
510
511 int srcOffset = mipOffset[mipID-1];
512 int dstOffset = mipOffset[mipID];
513
514 int dstNumPixels = dstSize[0] * dstSize[1];
515
516 // loop is parallelizable, but synchronization overhead is too high
517// #ifdef USE_OPENMP
518// #pragma omp parallel for
519// #endif // USE_OPENMP
520 for (int dstPixel = 0; dstPixel < dstNumPixels; ++dstPixel)
521 {
522 int x = dstPixel % dstSize[0];
523 int y = dstPixel / dstSize[0];
524
525 Vec4f pixelData[4];
526
527 Vec2i srcPixelPos[4] =
528 {
529 Vec2i(x * 2, y * 2), Vec2i(x * 2 + 1, y * 2),
530 Vec2i(x * 2, y * 2 + 1), Vec2i(x * 2 + 1, y * 2 + 1)
531 };
532
533 Vec4f avgColor = Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
534
535 // load the four source pixels
536 for (int srcPixel = 0; srcPixel < 4; ++srcPixel)
537 {
538 // init with black
539 pixelData[srcPixel] = Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
540
541 // clamp pixel position
542 srcPixelPos[srcPixel][0] = std::min(srcPixelPos[srcPixel][0], srcSize[0] - 1);
543 srcPixelPos[srcPixel][1] = std::min(srcPixelPos[srcPixel][1], srcSize[1] - 1);
544
545 // linear position of 2d pixel pos, row-major
546 int srcPixelPosLinear = srcSize[0] * srcPixelPos[srcPixel][1] + srcPixelPos[srcPixel][0];
547
548 // interpret pixel of the input image based on type
549 if (mipID == 1)
550 {
551 switch ( _type )
552 {
553 case GL_DOUBLE: Texture2D_buildMipMaps_DataInterpreter<double>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data); break;
554 case GL_FLOAT: Texture2D_buildMipMaps_DataInterpreter<float>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data); break;
555 case GL_INT: Texture2D_buildMipMaps_DataInterpreter<int>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data); break;
556 case GL_UNSIGNED_INT: Texture2D_buildMipMaps_DataInterpreter<unsigned int>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data); break;
557 case GL_SHORT: Texture2D_buildMipMaps_DataInterpreter<short>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data); break;
558 case GL_UNSIGNED_SHORT: Texture2D_buildMipMaps_DataInterpreter<unsigned short>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data); break;
559 case GL_BYTE:
560 {
561 Texture2D_buildMipMaps_DataInterpreter<char>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data);
562
563 if (finfo.isNormalized())
564 pixelData[srcPixel] /= 127.0f;
565 } break;
566 case GL_UNSIGNED_BYTE:
567 {
568 Texture2D_buildMipMaps_DataInterpreter<unsigned char>(pixelData + srcPixel, numChannels, srcPixelPosLinear * numChannels, _data);
569
570 if (finfo.isNormalized())
571 pixelData[srcPixel] /= 255.0f;
572 } break;
573
574 default: std::cerr << "MipMaps: unknown data type: " << _type << std::endl;
575 }
576 }
577 else
578 {
579 // load from previously computed mipmap
580
581 for (int c = 0; c < numChannels; ++c)
582 pixelData[srcPixel][c] = mipData[srcOffset/4 + srcPixelPosLinear * numChannels + c];
583 }
584
585 avgColor += pixelData[srcPixel];
586 }
587
588 avgColor *= 0.25f;
589
590 // store average of the source pixels
591 int dstPixelPosLinear = y * dstSize[0] + x;
592 for (int c = 0; c < numChannels; ++c)
593 mipData[dstOffset / 4 + dstPixelPosLinear * numChannels + c] = avgColor[c];
594 }
595
596 }
597
598
599 // upload mipmaps to gpu
600
601 for (int mipID = 0; mipID < numMips; ++mipID)
602 {
603 // inpute image at level 0
604 const void* mipDataPtr = _data;
605 GLenum mipDataType = _type;
606
607 if (mipID > 0)
608 {
609 // downsampled image at lower levels
610 // these are stored as float textures in memory
611 // glTexImage2D converts float data to the requested internal format
612 mipDataPtr = &mipData[mipOffset[mipID] / 4];
613 mipDataType = GL_FLOAT;
614 }
615
616 glTexImage2D(getTarget(), mipID, _internalfmt, mipSize[mipID][0], mipSize[mipID][1], 0, _format, mipDataType, mipDataPtr);
617 }
618 }
619 }
620}
621
622
623bool Texture2D::loadFromFile( const std::string& _filename, GLenum _minFilter, GLenum _magFilter )
624{
625 bool success = false;
626
627 const int numMipmapEnums = 4;
628 GLenum mipmapEnums[numMipmapEnums] = {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR};
629 bool mipmaps = false;
630
631 for (int i = 0; i < numMipmapEnums; ++i)
632 mipmaps = mipmaps || _minFilter == mipmapEnums[i];
633
634 if (!_filename.empty())
635 {
636 bind();
637
638 QImage qtex;
639
640 if (qtex.load(_filename.c_str()))
641 {
642 success = true;
643
644 if (mipmaps)
645 autogenerateMipMaps();
646
647 QImage gltex = ACG::Util::convertToGLFormat(qtex);
648
649 setData(0, GL_RGBA, gltex.width(), gltex.height(), GL_RGBA, GL_UNSIGNED_BYTE, gltex.bits(), mipmaps);
650 }
651
652 }
653
654 if (success)
655 {
656 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _minFilter);
657 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _magFilter);
658 }
659
660 return success;
661}
662
663
664void Texture2D::loadRandom( GLint _internalFormat, GLsizei _width, GLsizei _height )
665{
666 ACG::GLFormatInfo finfo(_internalFormat);
667
668 if (finfo.isValid() && _width && _height)
669 {
670 int n = _width * _height * finfo.channelCount();
671
672 GLvoid* dataPtr = 0;
673
674 std::vector<float> randF;
675 std::vector<int> randI;
676
677 GLenum gltype = 0;
678
679 if (finfo.isFloat() || finfo.isNormalized())
680 {
681 randF.resize(n);
682
683 bool isSigned = finfo.isInt();
684
685 for (int i = 0; i < n; ++i)
686 {
687 float r = float(rand()) / float(RAND_MAX);
688
689 if (isSigned)
690 r = r * 2.0f - 1.0f;
691
692 randF[i] = r;
693 }
694
695 dataPtr = &randF[0];
696 gltype = GL_FLOAT;
697 }
698 else
699 {
700 randI.resize(n);
701
702 for (int i = 0; i < n; ++i)
703 randI[i] = rand();
704
705 dataPtr = &randI[0];
706 gltype = GL_INT;
707 }
708
709 bind();
710 setData(0, _internalFormat, _width, _height, finfo.format(), gltype, dataPtr);
711 }
712}
713
714bool Texture2D::checkTextureMem( GLenum _internalFormat, GLsizei _width, GLsizei _height, GLenum _format)
715{
716 GLuint t = 0;
717 glGenTextures(1, &t);
718
719 bool res = false;
720
721 if (t)
722 {
723 GLint savedTex = 0;
724 glGetIntegerv(GL_TEXTURE_BINDING_2D, &savedTex);
725
726
727 glBindTexture(GL_TEXTURE_2D, t);
728 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, _internalFormat, _width, _height, 0, _format, GL_FLOAT, 0);
729
730 GLint w = 0;
731 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
732 if (w)
733 res = true;
734
735 glBindTexture(GL_TEXTURE_2D, savedTex);
736 glDeleteTextures(1, &t);
737 }
738
739 return res;
740}
741
742//-----------------------------------------------------------------------------
743
744#if defined(GL_VERSION_1_5)
745
746void VertexBufferObject::del() {
747 if (valid)
748 glDeleteBuffers(1, &vbo);
749 valid = false;
750}
751
752void VertexBufferObject::upload(
753 GLsizeiptr size, const GLvoid* data, GLenum usage) {
754
755 if (!valid)
756 gen();
757
758 bind();
759
760 glBufferData(target, size, data, usage);
761}
762
763void VertexBufferObject::uploadSubData(
764 GLuint _offset, GLuint _size, const GLvoid* _data ) {
765
766 glBufferSubData(target, _offset, _size, _data);
767}
768
769void VertexBufferObject::gen() {
770 glGenBuffers(1, &vbo);
771 if(vbo > 0u)
772 valid = true;
773}
774
775int VertexBufferObject::size() {
776 bind();
777 int bufsize = 0;
778 glGetBufferParameteriv(target, GL_BUFFER_SIZE, &bufsize);
779 return bufsize;
780}
781
782#endif
783
784
785//-----------------------------------------------------------------------------
786
787TextureBuffer::TextureBuffer(GLenum u)
788 :
789Texture(GL_TEXTURE_BUFFER, u),
790 bufferSize_(0), buffer_(0), usage_(0), fmt_(0) {
791}
792
793
794TextureBuffer::~TextureBuffer() {
795 if (buffer_)
796 glDeleteBuffers(1, &buffer_);
797}
798
799void TextureBuffer::setBufferData(
800 size_t _size, const void* _data, GLenum _internalFormat, GLenum _usage) {
801 if (supportsTextureBuffer()) {
802 // setup buffer object
803 if (!buffer_)
804 glGenBuffers(1, &buffer_);
805
806 glBindBuffer(GL_TEXTURE_BUFFER, buffer_);
807 glBufferData(GL_TEXTURE_BUFFER, static_cast<GLsizei>(_size), _data, _usage);
808
809 usage_ = _usage;
810 fmt_ = _internalFormat;
811
812 // bind buffer to texture
813 if (getUnit() == GL_NONE)
814 setUnit(GL_TEXTURE0);
815
816 bind();
817
818 glTexBuffer(GL_TEXTURE_BUFFER, _internalFormat, buffer_);
819
820 bufferSize_ = _size;
821 }
822 else
823 std::cerr << "TextureBuffer::setData - gpu does not support buffer textures!" << std::endl;
824}
825
826bool TextureBuffer::getBufferData(void* _dst) {
828{
829 if (buffer_) {
830 glBindBuffer(GL_TEXTURE_BUFFER, buffer_);
831 glGetBufferSubData(GL_TEXTURE_BUFFER, 0, bufferSize_, _dst);
832 return true;
833 }
834 else
835 std::cerr << "TextureBuffer::getBufferData - gpu does not support buffer textures!" << std::endl;
836}else{
837 std::cerr << "TextureBuffer::getBufferData - currently only in core profile available!" << std::endl;
838}
839 return false;
840}
841
842bool TextureBuffer::getBufferData(std::vector<char>& _dst) {
843 if (_dst.size() < size_t(bufferSize_))
844 _dst.resize(bufferSize_);
845
846 if (!_dst.empty())
847 return getBufferData(&_dst[0]);
848
849 return false;
850}
851
852
853
854//-----------------------------------------------------------------------------
855
856
857#if defined(GL_NV_vertex_program) || defined(GL_NV_fragment_program)
858
859void ProgramBaseNV::bind() {
860 if (!valid)
861 gen();
862 glBindProgramARB(target, program);
863}
864
865void ProgramBaseNV::unbind() {
866 glBindProgramARB(target, 0);
867}
868
869bool ProgramBaseNV::load(const char* prog_text) {
870 int size = int(strlen(prog_text));
871 if (!valid)
872 gen();
873 glLoadProgramNV(target, program, size, (const GLubyte *) prog_text);
874 GLint errpos;
875 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_NV, &errpos);
876 if (errpos != -1) {
877 fprintf(stderr, "\nprogram error:\n");
878 int bgn = std::max(0, errpos - 10), end = std::min(size, bgn + 30);
879 for (int i = bgn; i < end; ++i)
880 fputc(prog_text[i], stderr);
881 fputc('\n', stderr);
882 return false;
883 }
884 return true;
885}
886
887
888void ProgramBaseNV::gen() {
889 glGenProgramsARB(1, &program);
890 valid = true;
891}
892
893void ProgramBaseNV::del() {
894 if (valid)
895 glDeleteProgramsARB(1, &program);
896 valid = false;
897}
898
899#endif
900
901#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program)
902
903void ProgramBaseARB::bind() {
904 if (!valid)
905 gen();
906 glBindProgramARB(target, program);
907}
908void ProgramBaseARB::unbind() {
909 glBindProgramARB(target, 0);
910}
911
912bool ProgramBaseARB::load(const char* prog_text) {
913 int size = int(strlen(prog_text));
914 if (!valid)
915 gen();
916 bind();
917 glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, size, prog_text);
918 GLint errpos;
919 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errpos);
920 if (errpos != -1) {
921 fprintf(stderr, "\nprogram error:\n");
922 int bgn = std::max(0, errpos - 10), end = std::min(size, bgn + 30);
923 for (int i = bgn; i < end; ++i)
924 fputc(prog_text[i], stderr);
925 fputc('\n', stderr);
926 return false;
927 }
928 return true;
929}
930
931void ProgramBaseARB::gen() {
932 glGenProgramsARB(1, &program);
933 valid = true;
934}
935void ProgramBaseARB::del() {
936 if (valid)
937 glDeleteProgramsARB(1, &program);
938 valid = false;
939}
940
941#endif // GL_ARB_vertex_program
942
943
944//-----------------------------------------------------------------------------
945
946// support state unknown : -1
947int VertexArrayObject::supportStatus_ = -1;
948
949VertexArrayObject::VertexArrayObject()
950 : id_(0)
951{
952}
953
954VertexArrayObject::~VertexArrayObject()
955{
956#ifdef GL_ARB_vertex_array_object
957 if (id_)
958 glDeleteVertexArrays(1, &id_);
959#endif
960}
961
962
963void VertexArrayObject::bind()
964{
965#ifdef GL_ARB_vertex_array_object
966 if (!id_)
967 init();
968
969 if (id_)
970 glBindVertexArray(id_);
971#endif
972}
973
974void VertexArrayObject::unbind()
975{
976#ifdef GL_ARB_vertex_array_object
977 glBindVertexArray(0);
978#endif
979}
980
981void VertexArrayObject::init()
982{
983#ifdef GL_ARB_vertex_array_object
984 if (id_)
985 glDeleteVertexArrays(1, &id_);
986
987 glGenVertexArrays(1, &id_);
988#endif
989}
990
991bool VertexArrayObject::isSupported()
992{
993#ifndef GL_ARB_vertex_array_object
994 // missing definition in gl header!
995 supportStatus_ = 0;
996#else
997
998 if (supportStatus_ < 0)
999 supportStatus_ = checkExtensionSupported("GL_ARB_vertex_array_object") ? 1 : 0;
1000 if( openGLVersion(3,2) )
1001 return true;
1002#endif
1003
1004 return supportStatus_ > 0;
1005}
1006
1007
1008
1009//-----------------------------------------------------------------------------
1010
1011
1012
1013// support state unknown : -1
1014int AtomicCounter::supportStatus_ = -1;
1015
1016AtomicCounter::AtomicCounter(int _numCounters)
1017 : numCounters_(_numCounters), buffer_(0)
1018{
1019}
1020
1021AtomicCounter::~AtomicCounter()
1022{
1023 if (buffer_)
1024 glDeleteBuffers(1, &buffer_);
1025}
1026
1027void AtomicCounter::init()
1028{
1029 // check support and initialize
1030#ifdef GL_ARB_shader_atomic_counters
1031 if (isSupported() && numCounters_ > 0)
1032 {
1033 glGenBuffers(1, &buffer_);
1034 bind();
1035 glBufferData(GL_ATOMIC_COUNTER_BUFFER, numCounters_ * sizeof(unsigned int), 0, GL_DYNAMIC_COPY);
1036 unbind();
1037 }
1038#endif
1039
1040 if (!isValid())
1041 std::cerr << "atomic counter failed to initialize!" << std::endl;
1042}
1043
1044void AtomicCounter::bind()
1045{
1046#ifdef GL_ARB_shader_atomic_counters
1047 // implicit initialization
1048 if (!isValid())
1049 init();
1050
1051 if (isValid())
1052 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1053#endif
1054}
1055
1056void AtomicCounter::bind(GLuint _index)
1057{
1058#ifdef GL_ARB_shader_atomic_counters
1059 // implicit initialization
1060 if (!isValid())
1061 init();
1062
1063 if (isValid())
1064 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, _index, buffer_);
1065#endif
1066}
1067
1068void AtomicCounter::unbind()
1069{
1070#ifdef GL_ARB_shader_atomic_counters
1071 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1072#endif
1073}
1074
1075void AtomicCounter::set(unsigned int _value)
1076{
1077#ifdef GL_ARB_shader_atomic_counters
1078 // implicit initialization
1079 bind();
1080
1081 if (isValid())
1082 {
1083 const size_t bufSize = numCounters_ * sizeof(unsigned int);
1084 // unsigned int* bufData = new unsigned int[numCounters_];
1085 // memset(bufData, int(_value), bufSize);
1086 //
1087 // glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, bufSize, bufData);
1088 // delete [] bufData;
1089
1090 void* bufPtr = glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, bufSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
1091 memset(bufPtr, int(_value), bufSize);
1092 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1093
1094 unbind();
1095 }
1096#endif
1097}
1098
1099void AtomicCounter::get(unsigned int* _out)
1100{
1101#ifdef GL_ARB_shader_atomic_counters
1102 if (isValid())
1103 {
1104 bind();
1105
1106 const size_t bufSize = numCounters_ * sizeof(unsigned int);
1107
1108 // doesnt work, driver crash on ati:
1109 // glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, bufSize, _out);
1110
1111 void* bufPtr = glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, bufSize, GL_MAP_READ_BIT);
1112 memcpy(_out, bufPtr, bufSize);
1113 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1114
1115 unbind();
1116 }
1117#endif
1118}
1119
1120bool AtomicCounter::isSupported()
1121{
1122#ifndef GL_ARB_shader_atomic_counters
1123 // missing definition in gl header!
1124 supportStatus_ = 0;
1125#else
1126
1127 if (supportStatus_ < 0)
1128 supportStatus_ = checkExtensionSupported("GL_ARB_shader_atomic_counters") ? 1 : 0;
1129#endif
1130
1131 return supportStatus_ > 0;
1132}
1133
1134bool AtomicCounter::isValid() const
1135{
1136 return buffer_ && numCounters_ > 0;
1137}
1138
1139//-----------------------------------------------------------------------------
1140
1141QueryObject::QueryObject(GLenum _type)
1142 : id_(0), state_(-1), type_(_type)
1143{
1144
1145}
1146
1147QueryObject::~QueryObject()
1148{
1149 if (id_)
1150 glDeleteQueries(1, &id_);
1151}
1152
1153void QueryObject::begin()
1154{
1155 if (!id_)
1156 glGenQueries(1, &id_);
1157
1158 glBeginQuery(type_, id_);
1159 state_ = 0;
1160}
1161
1162void QueryObject::end()
1163{
1164 if (!state_)
1165 {
1166 glEndQuery(type_);
1167 state_ = 1;
1168 }
1169}
1170
1171bool QueryObject::available() const
1172{
1173 GLint r = GL_FALSE;
1174 if (state_ > 0)
1175 glGetQueryObjectiv(id_, GL_QUERY_RESULT_AVAILABLE, &r);
1176 return r != GL_FALSE;
1177}
1178
1179GLuint QueryObject::result() const
1180{
1181 GLuint r = 0xffffffff;
1182 if (state_ > 0)
1183 glGetQueryObjectuiv(id_, GL_QUERY_RESULT, &r);
1184 return r;
1185}
1186
1187
1188//-----------------------------------------------------------------------------
1189
1190int QueryCounter::supportStatus_ = -1;
1191
1192QueryCounter::QueryCounter()
1193 : state_(-1)
1194{
1195 queryObjects_[0] = queryObjects_[1] = 0;
1196}
1197
1198QueryCounter::~QueryCounter()
1199{
1200 if (queryObjects_[0])
1201 glDeleteQueries(2, queryObjects_);
1202}
1203
1204
1205void QueryCounter::restart()
1206{
1207#ifdef GL_ARB_timer_query
1208 if (isSupported())
1209 {
1210 state_ = 0;
1211
1212 if (!queryObjects_[0])
1213 glGenQueries(2, queryObjects_);
1214
1215 glQueryCounter(queryObjects_[0], GL_TIMESTAMP);
1216 }
1217#endif
1218}
1219
1220void QueryCounter::stop()
1221{
1222#ifdef GL_ARB_timer_query
1223 if (state_ == 0)
1224 {
1225 glQueryCounter(queryObjects_[1], GL_TIMESTAMP);
1226 ++state_;
1227 }
1228#endif
1229}
1230
1232{
1233 GLuint64 timing = 0;
1234#ifdef GL_ARB_timer_query
1235 stop();
1236
1237 if (state_ == 1)
1238 {
1239 GLint available = 0;
1240 while (!available)
1241 glGetQueryObjectiv(queryObjects_[1], GL_QUERY_RESULT_AVAILABLE, &available);
1242
1243 GLuint64 timeStart;
1244 glGetQueryObjectui64v(queryObjects_[0], GL_QUERY_RESULT, &timeStart);
1245 glGetQueryObjectui64v(queryObjects_[1], GL_QUERY_RESULT, &timing);
1246 timing -= timeStart;
1247 }
1248#endif
1249 return timing;
1250}
1251
1253{
1254 return elapsedNs() / 1000;
1255}
1256
1258{
1259 GLuint64 ms = elapsedMs();
1260
1261 return float(ms) / 1000.0f;
1262}
1263
1265{
1266#ifndef GL_ARB_timer_query
1267 // missing definition in gl header!
1268 supportStatus_ = 0;
1269#else
1270
1271 if (supportStatus_ < 0)
1272 supportStatus_ = checkExtensionSupported("GL_ARB_timer_query") || openGLVersion(3,2) ? 1 : 0;
1273#endif
1274
1275 return supportStatus_ > 0;
1276}
1277
1278
1279//-----------------------------------------------------------------------------
1280
1281
1282// support state unknown : -1
1283int UniformBufferObject::supportStatus_ = -1;
1284int UniformBufferObject::maxBlockSize_ = -1;
1285int UniformBufferObject::maxBindings_ = -1;
1286int UniformBufferObject::maxCombinedShaderBlocks_ = -1;
1287int UniformBufferObject::offsetAlignment_ = -1;
1288
1289UniformBufferObject::UniformBufferObject()
1290 : VertexBufferObject(
1291#ifndef GL_ARB_uniform_buffer_object
1292 GL_NONE
1293#else
1294 GL_UNIFORM_BUFFER
1295#endif
1296 ),
1297 data_(0)
1298{
1299}
1300
1301UniformBufferObject::~UniformBufferObject()
1302{
1303}
1304
1305void UniformBufferObject::bind( GLuint _index )
1306{
1307#ifdef GL_ARB_uniform_buffer_object
1308 glBindBufferBase(GL_UNIFORM_BUFFER, _index, id());
1309#endif
1310}
1311
1312
1313bool UniformBufferObject::isSupported()
1314{
1315#ifndef GL_ARB_uniform_buffer_object
1316 // missing definition in gl header!
1317 supportStatus_ = 0;
1318#else
1319
1320 if (supportStatus_ < 0)
1321 supportStatus_ = checkExtensionSupported("GL_ARB_uniform_buffer_object") ? 1 : 0;
1322#endif
1323
1324 return supportStatus_ > 0;
1325}
1326
1327void UniformBufferObject::queryCaps()
1328{
1329#ifdef GL_ARB_uniform_buffer_object
1330 if (isSupported())
1331 {
1332 glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxBindings_);
1333 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxBlockSize_);
1334 glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &maxCombinedShaderBlocks_);
1335 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offsetAlignment_);
1336 }
1337#endif
1338}
1339
1340int UniformBufferObject::getMaxBindings()
1341{
1342 if (maxBindings_ < 0)
1343 queryCaps();
1344
1345 return maxBindings_;
1346}
1347
1348int UniformBufferObject::getMaxBlocksize()
1349{
1350 if (maxBlockSize_ < 0)
1351 queryCaps();
1352
1353 return maxBlockSize_;
1354}
1355
1356int UniformBufferObject::getMaxCombinedShaderBlocks()
1357{
1358 if (maxCombinedShaderBlocks_ < 0)
1359 queryCaps();
1360
1361 return maxCombinedShaderBlocks_;
1362}
1363
1364int UniformBufferObject::getOffsetAlignment()
1365{
1366 if (offsetAlignment_ < 0)
1367 queryCaps();
1368
1369 return offsetAlignment_;
1370}
1371
1372void UniformBufferObject::setUniformData( GLSL::Program* _prog, const char* _bufferName, const char* _uniformName, const void* _data, int _datasize, bool _delay )
1373{
1374 if (_prog && _bufferName && _uniformName && _data)
1375 {
1376 GLuint idx = _prog->getUniformBlockIndex(_bufferName);
1377
1378 if (idx != GL_INVALID_INDEX)
1379 {
1380 size_t bufsize = size_t(_prog->getUniformBlockSize(idx));
1381
1382 if (data_.size() != bufsize)
1383 data_.resize(bufsize, 0);
1384
1385 int offset = -1;
1386 _prog->getUniformBlockOffsets(1, &_uniformName, &offset);
1387
1388 if (offset >= 0)
1389 {
1390 memcpy(&data_[offset], _data, _datasize);
1391
1392 if (!_delay)
1393 {
1394 VertexBufferObject::bind();
1395
1396 if (size() != int(bufsize))
1397 VertexBufferObject::upload(bufsize, &data_[0], GL_DYNAMIC_DRAW);
1398 else
1399 uploadSubData(offset, _datasize, _data);
1400 }
1401 }
1402 }
1403 }
1404}
1405
1406void UniformBufferObject::upload()
1407{
1408 if (!data_.empty())
1409 {
1410 VertexBufferObject::bind();
1411
1412 VertexBufferObject::upload(data_.size(), &data_[0], GL_DYNAMIC_DRAW);
1413 }
1414}
1415
1416
1417//-----------------------------------------------------------------------------
1418
1419
1420
1421// support state unknown : -1
1422int ShaderStorageBufferObject::supportStatus_ = -1;
1423int ShaderStorageBufferObject::maxBlockSize_ = -1;
1424int ShaderStorageBufferObject::maxBindings_ = -1;
1425int ShaderStorageBufferObject::maxCombinedShaderBlocks_ = -1;
1426
1427ShaderStorageBufferObject::ShaderStorageBufferObject()
1428 : VertexBufferObject(
1429#ifndef GL_ARB_shader_storage_buffer_object
1430 GL_NONE
1431#else
1432 GL_SHADER_STORAGE_BUFFER
1433#endif
1434 )
1435{
1436}
1437
1438ShaderStorageBufferObject::~ShaderStorageBufferObject()
1439{
1440}
1441
1442void ShaderStorageBufferObject::bind( GLuint _index )
1443{
1444#ifdef GL_ARB_shader_storage_buffer_object
1445 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, _index, id());
1446#endif
1447}
1448
1449bool ShaderStorageBufferObject::isSupported()
1450{
1451#ifndef GL_ARB_shader_storage_buffer_object
1452 // missing definition in gl header!
1453 supportStatus_ = 0;
1454#else
1455
1456 if (supportStatus_ < 0)
1457 supportStatus_ = checkExtensionSupported("GL_ARB_shader_storage_buffer_object") ? 1 : 0;
1458#endif
1459
1460 return supportStatus_ > 0;
1461}
1462
1463void ShaderStorageBufferObject::queryCaps()
1464{
1465#ifdef GL_ARB_shader_storage_buffer_object
1466 if (isSupported())
1467 {
1468 glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxBindings_);
1469 glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxBlockSize_);
1470 glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxCombinedShaderBlocks_);
1471 }
1472#endif
1473}
1474
1475int ShaderStorageBufferObject::getMaxBindings()
1476{
1477 if (maxBindings_ < 0)
1478 queryCaps();
1479
1480 return maxBindings_;
1481}
1482
1483int ShaderStorageBufferObject::getMaxBlocksize()
1484{
1485 if (maxBlockSize_ < 0)
1486 queryCaps();
1487
1488 return maxBlockSize_;
1489}
1490
1491int ShaderStorageBufferObject::getMaxCombinedShaderBlocks()
1492{
1493 if (maxCombinedShaderBlocks_ < 0)
1494 queryCaps();
1495
1496 return maxCombinedShaderBlocks_;
1497}
1498
1499
1500
1501
1502
1503} /* namespace ACG */
float elapsedSecs()
elapsed gpu time in seconds
GLuint64 elapsedMs()
elapsed gpu time in millisecs
GLuint64 elapsedNs()
elapsed gpu time since restart() in nanosecs
static bool isSupported()
check hw support
GLSL program class.
void getUniformBlockOffsets(int _numUniforms, const char **_names, int *_outOffsets)
Get offsets of uniforms in a uniform buffer.
int getUniformBlockSize(GLuint _index)
Get size in bytes of a uniform buffer.
GLuint getUniformBlockIndex(const char *_name)
Get location of the specified uniform buffer.
Scalar * data()
access to Scalar array
Definition Vector11T.hh:201
Namespace providing different geometric functions concerning angles.
bool checkExtensionSupported(const std::string &_extension)
Definition gl.cc:107
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition gl.cc:129
VectorT< signed int, 2 > Vec2i
Definition VectorT.hh:98
bool compatibilityProfile()
get opengl core profile setting
Definition gl.cc:171
bool bind(osg::GeometryPtr &_geo, Mesh &_mesh)
Definition bindT.hh:101