Tools.cc 10.9 KB
Newer Older
1 2 3 4 5
/***********************************************************************
 * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/
Robert Menzel's avatar
Robert Menzel committed
6

Robert Menzel's avatar
Robert Menzel committed
7
#include <ACGL/ACGL.hh>
Robert Menzel's avatar
Robert Menzel committed
8
#include <ACGL/OpenGL/Tools.hh>
9
#include <ACGL/Utils/FileHelpers.hh>
10
#include <ACGL/OpenGL/glloaders/extensions.hh>
11 12 13
#include <ACGL/OpenGL/Debug.hh>
#include <sstream>
using namespace std;
Robert Menzel's avatar
Robert Menzel committed
14 15

namespace ACGL{
Robert Menzel's avatar
Robert Menzel committed
16
namespace OpenGL{
Robert Menzel's avatar
Robert Menzel committed
17

18 19 20 21 22 23 24 25 26 27 28 29
GLuint g_ACGL_defaultFramebuffer = 0;

void setDefaultFramebuffer( GLuint _id )
{
    g_ACGL_defaultFramebuffer = _id;
}

void bindDefaultFramebuffer()
{
    glBindFramebuffer( GL_FRAMEBUFFER, g_ACGL_defaultFramebuffer );
}

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
#if (ACGL_OPENGL_VERSION >= 30)
bool doesSupportExtension( const char *_extensionName )
{
    // move beginning of the extension string by 3 chars if the requested extension name does not include the mandatory "GL_"
    // move by 0 (don't move) otherwise:
    size_t pointerOffset = (strncmp(_extensionName, "GL_", 3) == 0)?0:3;
    GLint n = 0;
    glGetIntegerv(GL_NUM_EXTENSIONS, &n);
    for (GLint i = 0; i < n; i++)
    {
        const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
        extension += pointerOffset;
        if (strcmp(extension, _extensionName) == 0) return true;
    }
    return false;
}
#endif

48 49 50 51 52 53 54 55 56 57
GLfloat ACGL_MAX_TEXTURE_MAX_ANISOTROPY = -1.0f;
void initRuntimeDependentLimits()
{
    if ( ACGL_EXT_texture_filter_anisotrophic() ) {
        glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &ACGL_MAX_TEXTURE_MAX_ANISOTROPY );
    } else {
        ACGL_MAX_TEXTURE_MAX_ANISOTROPY = 0.0f;
    }
}

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
//! returns the size in bytes of the common gl types named by there GLenums.
GLint getGLTypeSize ( GLenum _type )
{
    switch(_type)
    {
        case GL_BYTE:           return sizeof(GLbyte);
        case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);
        case GL_SHORT:          return sizeof(GLshort);
        case GL_UNSIGNED_SHORT: return sizeof(GLushort);
        case GL_INT:            return sizeof(GLint);
        case GL_UNSIGNED_INT:   return sizeof(GLuint);
        case GL_FLOAT:          return sizeof(GLfloat);
#ifndef ACGL_OPENGL_ES
        case GL_DOUBLE:         return sizeof(GLdouble);
#endif

        //case GL_INT64_NV:       return sizeof(GLint64);
        //case GL_UNSIGNED_INT64_NV: return sizeof(GLuint64);
        //case GL_HALF_FLOAT:     return sizeof(GLhalf);
        case GL_FIXED:          return 4; // fixed are packed in a 32bit int (see 2.1.2 of the spec.)
    }
    return 0;
}

GLuint getNumberOfChannels( GLenum _format )
{
    // GLES formats:
    if (_format == GL_ALPHA || _format == GL_DEPTH_COMPONENT) return 1;
    if (_format == GL_RGB)  return 3;
    if (_format == GL_RGBA) return 4;
#ifdef ACGL_OPENGL_CORE_PROFILE
    // removed from core:
    if (_format == GL_LUMINANCE)  return 1;
    if (_format == GL_LUMINANCE_ALPHA)  return 2;
#endif

#ifndef ACGL_OPENGL_ES
    // additional desktop formats:
    if ( _format == GL_R8I  || _format == GL_R16I  || _format == GL_R32I
                        || _format == GL_R8UI || _format == GL_R16UI || _format == GL_R32UI
                                              || _format == GL_R16F  || _format == GL_R32F )   return 1;
    if (_format == GL_RED_INTEGER || _format == GL_GREEN_INTEGER || _format == GL_BLUE_INTEGER ) return 1;

    if (_format == GL_RG || _format == GL_RG8I  || _format == GL_RG16I  || _format == GL_RG32I
                         || _format == GL_RG8UI || _format == GL_RG16UI || _format == GL_RG32UI
                                                || _format == GL_RG16F  || _format == GL_RG32F )   return 2;
    if (_format == GL_RG_INTEGER ) return 2;

    if (_format == GL_RGB8I  || _format == GL_RGB16I  || _format == GL_RGB32I
                          || _format == GL_RGB8UI || _format == GL_RGB16UI || _format == GL_RGB32UI
                                                  || _format == GL_RGB16F  || _format == GL_RGB32F )   return 3;
    if (_format == GL_BGR  || _format == GL_RGB_INTEGER  || _format == GL_BGR_INTEGER)  return 3;

    if ( _format == GL_RGBA8I  || _format == GL_RGBA16I  || _format == GL_RGBA32I
                           || _format == GL_RGBA8UI || _format == GL_RGBA16UI || _format == GL_RGBA32UI
                                                    || _format == GL_RGBA16F  || _format == GL_RGBA32F )   return 4;
    if (_format == GL_BGRA || _format == GL_RGBA_INTEGER || _format == GL_BGRA_INTEGER) return 4;
#endif

    return 1; // unknown number of channels, assume 1
}

120 121 122 123
//
// This is a "private" function that should not be called from outside of this file.
//
// glGetIntegerv(GL_MAJOR_VERSION... and glGetIntegerv(GL_MINOR_VERSION... are great, but
124
// require OpenGL 3.0 and are not supported on ES 2 :-( so the VERSION string has to get parsed...
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
//
// OpenGL spec:
// The VERSION ... strings are laid out as follows:
// <version number><space><vendor-specific information>
//
// OpenGL ES spec:
// The VERSION string is laid out as follows:
// "OpenGL ES N.M vendor-specific information"
//
// both specs:
// The version number is either of the form major_number.minor_number or
// major_number.minor_number.release_number, where the numbers all have one or more digits.
//
uint32_t privateGetOpenGLVersion( int _type )
{
    static uint32_t OGLminor   = 0;
    static uint32_t OGLmajor   = 0;
    static uint32_t OGLversion = 0;

    if (OGLversion == 0) {
        // calculate the version numbers once:
        // NOTE: similar to GLEW we assume here, that the minor and major numbers
        //       only have one digit. We also ignore release numbers. This will fail e.g. for OpenGL 10.0
        const GLubyte* versionString;
        versionString = glGetString(GL_VERSION);

Robert Menzel's avatar
Robert Menzel committed
151 152 153 154
        if (versionString == NULL) {
            ACGL::Utils::error() << "cannot get OpenGL version" << std::endl;
            return 0;
        }
155 156 157 158 159 160
        int positionOfFirstDot = 0;
        while ((versionString[positionOfFirstDot] != '\0') && (versionString[positionOfFirstDot] != '.')) ++positionOfFirstDot;

        OGLmajor = versionString[positionOfFirstDot-1] - '0';
        OGLminor = versionString[positionOfFirstDot+1] - '0';

161 162
        if (OGLmajor > 9) OGLmajor = 0;
        if (OGLminor > 9) OGLminor = 0;
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

        OGLversion = OGLmajor*10 + OGLminor;
    }
    switch (_type) {
        case 0: return OGLminor;
        case 1: return OGLmajor;
        default: return OGLversion;
    };
}

uint32_t getOpenGLMinorVersionNumber()
{
    return privateGetOpenGLVersion( 0 );
}

uint32_t getOpenGLMajorVersionNumber()
{
    return privateGetOpenGLVersion( 1 );
}

uint32_t getOpenGLVersionNumber()
{
    return privateGetOpenGLVersion( 2 );
}

188 189 190 191 192
bool doesSupportGeometryShader()
{
#ifdef ACGL_OPENGL_ES
    return false;
#else
193
    return (ACGL_EXT_geometry_shader4() || ACGL_ARB_geometry_shader4() || (getOpenGLVersionNumber() >= 32));
194 195 196 197 198 199 200 201
#endif
}

bool doesSupportTessellationShader()
{
#ifdef ACGL_OPENGL_ES
    return false;
#else
202
    return ( ACGL_ARB_tessellation_shader() || (getOpenGLVersionNumber() >= 40));
203 204 205
#endif
}

206 207 208 209 210
bool doesSupportComputeShader()
{
#ifdef ACGL_OPENGL_ES
    return false;
#else
211
    return ( ACGL_ARB_compute_shader() || (getOpenGLVersionNumber() >= 43));
212 213 214 215 216 217
#endif
}


GLenum getShaderTypeByFileEnding( const std::string _fileName, bool _ignoreUnsupportedShaderTypes )
{
218
    std::string fileEnding = ACGL::Utils::StringHelpers::getFileEnding( _fileName );
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
    if( fileEnding.size() == 0 ) return GL_INVALID_ENUM;

    GLenum foundType = GL_INVALID_ENUM;

    // guess the shader type:
    for (unsigned int ending = 0; ending < sizeof(sShaderEndings) / sizeof(ShaderEndings); ++ending)
    {
        if ( fileEnding == sShaderEndings[ending].ending )
        {
            foundType = sShaderEndings[ending].type;
            break;
        }
    }

    if (_ignoreUnsupportedShaderTypes) {
        if (foundType == GL_GEOMETRY_SHADER        && !doesSupportGeometryShader()    ) return GL_INVALID_ENUM;
        if (foundType == GL_TESS_CONTROL_SHADER    && !doesSupportTessellationShader()) return GL_INVALID_ENUM;
        if (foundType == GL_TESS_EVALUATION_SHADER && !doesSupportTessellationShader()) return GL_INVALID_ENUM;
        if (foundType == GL_COMPUTE_SHADER         && !doesSupportComputeShader()     ) return GL_INVALID_ENUM;
    }

    return foundType;
}

const GLubyte* acglShaderTypeString( GLenum _shaderType )
{
    if      (_shaderType == GL_VERTEX_SHADER)          { return (GLubyte*) "vertex shader"; }
    else if (_shaderType == GL_TESS_CONTROL_SHADER)    { return (GLubyte*) "tessellation control shader"; }
    else if (_shaderType == GL_TESS_EVALUATION_SHADER) { return (GLubyte*) "tessellation evaluation shader"; }
    else if (_shaderType == GL_GEOMETRY_SHADER)        { return (GLubyte*) "geometry shader"; }
    else if (_shaderType == GL_FRAGMENT_SHADER)        { return (GLubyte*) "fragment shader"; }
    else if (_shaderType == GL_COMPUTE_SHADER)         { return (GLubyte*) "compute shader"; }
    else {
        return (GLubyte*) "unknown shader type";
    }
}

256
const GLubyte* acglErrorString( GLenum _errorCode )
Robert Menzel's avatar
Robert Menzel committed
257
{
Robert Menzel's avatar
Robert Menzel committed
258 259
    // no gluErrorString on iOS, problems on visual studio...
    // Only 3.2+ Core and ES 2.0+ errors belong here:
260 261
    if      (_errorCode == GL_INVALID_ENUM)                  { return (GLubyte*) "GL_INVALID_ENUM"; }
    else if (_errorCode == GL_INVALID_VALUE)                 { return (GLubyte*) "GL_INVALID_VALUE"; }
Robert Menzel's avatar
Robert Menzel committed
262
    else if (_errorCode == GL_INVALID_OPERATION)             { return (GLubyte*) "GL_INVALID_OPERATION"; }
263
    else if (_errorCode == GL_INVALID_FRAMEBUFFER_OPERATION) { return (GLubyte*) "GL_INVALID_FRAMEBUFFER_OPERATION"; }
Robert Menzel's avatar
Robert Menzel committed
264
    else if (_errorCode == GL_OUT_OF_MEMORY)                 { return (GLubyte*) "GL_OUT_OF_MEMORY"; }
265
    else if (_errorCode == GL_NO_ERROR)                      { return (GLubyte*) "GL_NO_ERROR"; }
Robert Menzel's avatar
Robert Menzel committed
266
    else {
267
        return (GLubyte*) "unknown error";
Robert Menzel's avatar
Robert Menzel committed
268 269 270 271 272 273 274
    }
}



GLenum openGLError_( const char *_fileName, const unsigned long _lineNumber )
{
275 276 277 278 279 280
    GLenum currentError = glGetError();
    GLenum lastError    = currentError;

    // OpenGL does not forbit the implementation to stack up more than one error code
    // so we have to check those in a loop:
    while ( currentError != GL_NO_ERROR ) {
281
        ACGL::Utils::error() << "GL error in file " << _fileName << ":" << _lineNumber << " - " << acglErrorString( currentError ) << std::endl;
282

283 284 285
        //stringstream sstream (stringstream::in | stringstream::out);
        //sstream << acglErrorString( currentError ) << " in file " << _fileName << ":" << _lineNumber;
        //acglDebugMessageInsert( GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, currentError, GL_DEBUG_SEVERITY_HIGH, -1, sstream.str().c_str() );
286

287 288
        lastError    = currentError;
        currentError = glGetError();
Robert Menzel's avatar
Robert Menzel committed
289 290
    }

291
    return lastError; // returns the last real error (in case there was at least one!)
Robert Menzel's avatar
Robert Menzel committed
292 293 294
}


Robert Menzel's avatar
Robert Menzel committed
295
} // OpenGL
Robert Menzel's avatar
Robert Menzel committed
296 297
} // ACGL