nkeynes@635: /** nkeynes@636: * $Id$ nkeynes@635: * nkeynes@635: * GL-based support functions nkeynes@635: * nkeynes@635: * Copyright (c) 2005 Nathan Keynes. nkeynes@635: * nkeynes@635: * This program is free software; you can redistribute it and/or modify nkeynes@635: * it under the terms of the GNU General Public License as published by nkeynes@635: * the Free Software Foundation; either version 2 of the License, or nkeynes@635: * (at your option) any later version. nkeynes@635: * nkeynes@635: * This program is distributed in the hope that it will be useful, nkeynes@635: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@635: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@635: * GNU General Public License for more details. nkeynes@635: */ nkeynes@736: nkeynes@645: #include nkeynes@1129: #include nkeynes@687: #include nkeynes@635: #include "pvr2/glutil.h" nkeynes@635: nkeynes@667: gboolean isGLSecondaryColorSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_EXT_secondary_color"); nkeynes@667: } nkeynes@667: nkeynes@667: gboolean isGLVertexBufferSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_ARB_vertex_buffer_object"); nkeynes@667: } nkeynes@667: nkeynes@667: gboolean isGLPixelBufferSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_ARB_pixel_buffer_object"); nkeynes@667: } nkeynes@667: nkeynes@667: gboolean isGLMirroredTextureSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_ARB_texture_mirrored_repeat"); nkeynes@667: } nkeynes@667: nkeynes@1140: /** nkeynes@1140: * Check if there's at least 2 texture units nkeynes@1140: */ nkeynes@1140: gboolean isGLMultitextureSupported() nkeynes@1140: { nkeynes@1140: if( !isGLExtensionSupported("GL_ARB_multitexture") ) nkeynes@1140: return FALSE; nkeynes@1140: int units = 0; nkeynes@1140: glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &units); nkeynes@1140: return units >= 2; nkeynes@1140: } nkeynes@1140: nkeynes@1134: gboolean isGLVertexRangeSupported() nkeynes@1134: { nkeynes@1134: return isGLExtensionSupported("GL_APPLE_vertex_array_range") || nkeynes@1134: isGLExtensionSupported("GL_NV_vertex_array_range"); nkeynes@1134: } nkeynes@1134: nkeynes@635: /** nkeynes@635: * Test if a specific extension is supported. From opengl.org nkeynes@635: * @param extension extension name to check for nkeynes@635: * @return TRUE if supported, otherwise FALSE. nkeynes@635: */ nkeynes@635: gboolean isGLExtensionSupported( const char *extension ) nkeynes@635: { nkeynes@635: const GLubyte *extensions = NULL; nkeynes@635: const GLubyte *start; nkeynes@635: GLubyte *where, *terminator; nkeynes@635: nkeynes@635: /* Extension names should not have spaces. */ nkeynes@635: where = (GLubyte *) strchr(extension, ' '); nkeynes@635: if (where || *extension == '\0') nkeynes@736: return 0; nkeynes@635: extensions = glGetString(GL_EXTENSIONS); nkeynes@645: if( extensions == NULL ) { nkeynes@736: /* No GL available, so we're pretty sure the extension isn't nkeynes@736: * available either. */ nkeynes@736: return FALSE; nkeynes@645: } nkeynes@635: /* It takes a bit of care to be fool-proof about parsing the nkeynes@635: OpenGL extensions string. Don't be fooled by sub-strings, nkeynes@635: etc. */ nkeynes@635: start = extensions; nkeynes@635: for (;;) { nkeynes@736: where = (GLubyte *) strstr((const char *) start, extension); nkeynes@736: if (!where) nkeynes@736: break; nkeynes@736: terminator = where + strlen(extension); nkeynes@736: if (where == start || *(where - 1) == ' ') nkeynes@736: if (*terminator == ' ' || *terminator == '\0') nkeynes@736: return TRUE; nkeynes@736: start = terminator; nkeynes@635: } nkeynes@635: return FALSE; nkeynes@635: } nkeynes@687: nkeynes@1129: int compare_charp( const void *a, const void *b ) nkeynes@1129: { nkeynes@1129: const char **ca = (const char **)a; nkeynes@1129: const char **cb = (const char **)b; nkeynes@1129: return strcmp(*ca, *cb); nkeynes@1129: } nkeynes@1129: nkeynes@1134: #define DEFAULT_TERMINAL_COLUMNS 80 nkeynes@1134: #define DEFAULT_COLUMN_WIDTH 34 nkeynes@1134: nkeynes@1134: /** nkeynes@1134: * Format a GL extension list (or other space-separated string) nicely, and nkeynes@1134: * print to the given output stream. nkeynes@1134: */ nkeynes@1134: nkeynes@1134: void fprint_extensions( FILE *out, const char *extensions ) nkeynes@687: { nkeynes@1134: unsigned int i, j, count, maxlen = DEFAULT_COLUMN_WIDTH, columns, per_column, terminal_columns; nkeynes@1134: const char *terminal_columns_str = getenv("COLUMNS"); nkeynes@1134: if( terminal_columns_str == NULL || (terminal_columns = strtol(terminal_columns_str,0,10)) == 0 ) nkeynes@1134: terminal_columns = DEFAULT_TERMINAL_COLUMNS; nkeynes@1129: nkeynes@1134: if( extensions == NULL || extensions[0] == '\0' ) nkeynes@1134: return; nkeynes@1134: nkeynes@1134: gchar *ext_dup = g_strdup(extensions); nkeynes@1134: gchar **ext_split = g_strsplit(g_strstrip(extensions), " ", 0); nkeynes@1134: for( count = 0; ext_split[count] != NULL; count++ ) { nkeynes@1134: unsigned len = strlen(ext_split[count]); nkeynes@1134: if( len > maxlen ) nkeynes@1134: maxlen = len; nkeynes@1134: } nkeynes@1134: nkeynes@1134: columns = terminal_columns / (maxlen+2); nkeynes@1134: if( columns == 0 ) nkeynes@1134: columns = 1; nkeynes@1134: per_column = (count+columns-1) / columns; nkeynes@1129: nkeynes@1129: qsort(ext_split, count, sizeof(gchar *), compare_charp); nkeynes@736: nkeynes@1134: for( i=0; iprint_info ) { nkeynes@1134: fprintf( out, "\n"); nkeynes@1134: display_driver->print_info(out); nkeynes@687: } nkeynes@687: } nkeynes@1150: nkeynes@1150: gboolean gl_check_error(const char *context) nkeynes@1150: { nkeynes@1150: GLint err = glGetError(); nkeynes@1150: if( err != 0 ) { nkeynes@1150: const char *s; nkeynes@1150: switch( err ) { nkeynes@1150: case GL_INVALID_ENUM: s = "Invalid enum"; break; nkeynes@1150: case GL_INVALID_VALUE: s = "Invalid value"; break; nkeynes@1150: case GL_INVALID_OPERATION: s = "Invalid operation"; break; nkeynes@1150: case GL_STACK_OVERFLOW: s = "Stack overflow"; break; nkeynes@1150: case GL_STACK_UNDERFLOW: s = "Stack underflow"; break; nkeynes@1150: case GL_OUT_OF_MEMORY: s = "Out of memory"; break; nkeynes@1150: default: s = "Unknown error"; break; nkeynes@1150: } nkeynes@1150: if( context ) { nkeynes@1150: WARN( "%s: GL error: %x (%s)\n", context, err, s ); nkeynes@1150: } else { nkeynes@1150: WARN( "GL error: %x (%s)\n", err, s ); nkeynes@1150: } nkeynes@1159: return FALSE; nkeynes@1150: } nkeynes@1159: return TRUE; nkeynes@1150: }