nkeynes@635 | 1 | /**
|
nkeynes@635 | 2 | * $Id$
|
nkeynes@635 | 3 | *
|
nkeynes@635 | 4 | * GLSL shader loader/unloader. Current version assumes there's exactly
|
nkeynes@635 | 5 | * 1 shader program that's used globally. This may turn out not to be the
|
nkeynes@635 | 6 | * most efficient approach.
|
nkeynes@635 | 7 | *
|
nkeynes@635 | 8 | * Copyright (c) 2007 Nathan Keynes.
|
nkeynes@635 | 9 | *
|
nkeynes@635 | 10 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@635 | 11 | * it under the terms of the GNU General Public License as published by
|
nkeynes@635 | 12 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@635 | 13 | * (at your option) any later version.
|
nkeynes@635 | 14 | *
|
nkeynes@635 | 15 | * This program is distributed in the hope that it will be useful,
|
nkeynes@635 | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@635 | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@635 | 18 | * GNU General Public License for more details.
|
nkeynes@635 | 19 | */
|
nkeynes@635 | 20 |
|
nkeynes@635 | 21 | #define GL_GLEXT_PROTOTYPES 1
|
nkeynes@635 | 22 |
|
nkeynes@635 | 23 | #include "lxdream.h"
|
nkeynes@635 | 24 | #include "display.h"
|
nkeynes@635 | 25 | #include "pvr2/glutil.h"
|
nkeynes@635 | 26 |
|
nkeynes@635 | 27 | #define MAX_ERROR_BUF 4096
|
nkeynes@635 | 28 |
|
nkeynes@635 | 29 | gboolean glsl_is_supported()
|
nkeynes@635 | 30 | {
|
nkeynes@635 | 31 | return isGLExtensionSupported("GL_ARB_fragment_shader") &&
|
nkeynes@635 | 32 | isGLExtensionSupported("GL_ARB_vertex_shader") &&
|
nkeynes@635 | 33 | isGLExtensionSupported("GL_ARB_shading_language_100");
|
nkeynes@635 | 34 | }
|
nkeynes@635 | 35 |
|
nkeynes@635 | 36 | #ifdef GL_ARB_shader_objects
|
nkeynes@635 | 37 | static GLhandleARB glsl_program = 0, glsl_vert_shader = 0, glsl_frag_shader = 0;
|
nkeynes@635 | 38 |
|
nkeynes@635 | 39 | void glsl_print_error( char *msg, GLhandleARB obj )
|
nkeynes@635 | 40 | {
|
nkeynes@635 | 41 | char buf[MAX_ERROR_BUF];
|
nkeynes@635 | 42 | GLsizei length;
|
nkeynes@635 | 43 | glGetInfoLogARB( obj, sizeof(buf), &length, buf );
|
nkeynes@635 | 44 | ERROR( "%s: %s", msg, buf );
|
nkeynes@635 | 45 | }
|
nkeynes@635 | 46 |
|
nkeynes@635 | 47 | gboolean glsl_check_shader_error( char *msg, GLhandleARB obj )
|
nkeynes@635 | 48 | {
|
nkeynes@635 | 49 | GLint value;
|
nkeynes@635 | 50 |
|
nkeynes@635 | 51 | glGetObjectParameterivARB(obj, GL_OBJECT_COMPILE_STATUS_ARB, &value);
|
nkeynes@635 | 52 | if( value == 0 ) {
|
nkeynes@635 | 53 | glsl_print_error(msg, obj);
|
nkeynes@635 | 54 | return FALSE;
|
nkeynes@635 | 55 | }
|
nkeynes@635 | 56 | return TRUE;
|
nkeynes@635 | 57 | }
|
nkeynes@635 | 58 |
|
nkeynes@635 | 59 | gboolean glsl_check_program_error( char *msg, GLhandleARB obj )
|
nkeynes@635 | 60 | {
|
nkeynes@635 | 61 | if( glGetError() != GL_NO_ERROR ) {
|
nkeynes@635 | 62 | glsl_print_error(msg, obj);
|
nkeynes@635 | 63 | }
|
nkeynes@635 | 64 | return TRUE;
|
nkeynes@635 | 65 | }
|
nkeynes@635 | 66 |
|
nkeynes@635 | 67 |
|
nkeynes@635 | 68 | gboolean glsl_load_shaders( const char *vertex_src, const char *fragment_src )
|
nkeynes@635 | 69 | {
|
nkeynes@635 | 70 | gboolean vsok = TRUE, fsok = TRUE, pok = FALSE;
|
nkeynes@635 | 71 |
|
nkeynes@635 | 72 | if( vertex_src == NULL && fragment_src == NULL ) {
|
nkeynes@635 | 73 | return TRUE; // nothing to do
|
nkeynes@635 | 74 | }
|
nkeynes@635 | 75 |
|
nkeynes@635 | 76 | glsl_program = glCreateProgramObjectARB();
|
nkeynes@635 | 77 |
|
nkeynes@635 | 78 | if( vertex_src != NULL ) {
|
nkeynes@635 | 79 | glsl_vert_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
|
nkeynes@635 | 80 | glShaderSourceARB( glsl_vert_shader, 1, &vertex_src, NULL );
|
nkeynes@635 | 81 | glCompileShaderARB(glsl_vert_shader);
|
nkeynes@635 | 82 | vsok = glsl_check_shader_error("Failed to compile vertex shader", glsl_vert_shader);
|
nkeynes@635 | 83 | }
|
nkeynes@635 | 84 | if( fragment_src != NULL ) {
|
nkeynes@635 | 85 | glsl_frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
|
nkeynes@635 | 86 | glShaderSourceARB( glsl_frag_shader, 1, &fragment_src, NULL );
|
nkeynes@635 | 87 | glCompileShaderARB(glsl_frag_shader);
|
nkeynes@635 | 88 | fsok = glsl_check_shader_error("Failed to compile fragment shader", glsl_frag_shader);
|
nkeynes@635 | 89 | }
|
nkeynes@635 | 90 |
|
nkeynes@635 | 91 | if( vsok && fsok ) {
|
nkeynes@635 | 92 | if( vertex_src != NULL ) {
|
nkeynes@635 | 93 | glAttachObjectARB(glsl_program, glsl_vert_shader);
|
nkeynes@635 | 94 | }
|
nkeynes@635 | 95 | if( fragment_src != NULL ) {
|
nkeynes@635 | 96 | glAttachObjectARB(glsl_program, glsl_frag_shader);
|
nkeynes@635 | 97 | }
|
nkeynes@635 | 98 | glLinkProgramARB(glsl_program);
|
nkeynes@635 | 99 | pok = glsl_check_program_error( "Failed to link shader program", glsl_program );
|
nkeynes@635 | 100 | }
|
nkeynes@635 | 101 | if( pok ) {
|
nkeynes@635 | 102 | glUseProgramObjectARB(glsl_program);
|
nkeynes@635 | 103 | pok = glsl_check_program_error( "Failed to apply shader program", glsl_program );
|
nkeynes@635 | 104 | } else {
|
nkeynes@635 | 105 | glsl_unload_shaders();
|
nkeynes@635 | 106 | }
|
nkeynes@635 | 107 | return pok;
|
nkeynes@635 | 108 | }
|
nkeynes@635 | 109 |
|
nkeynes@635 | 110 | void glsl_enable_shader(gboolean en)
|
nkeynes@635 | 111 | {
|
nkeynes@635 | 112 | if( glsl_program != 0 ) {
|
nkeynes@635 | 113 | if( en ) {
|
nkeynes@635 | 114 | glUseProgramObjectARB(glsl_program);
|
nkeynes@635 | 115 | } else {
|
nkeynes@635 | 116 | glUseProgramObjectARB(0);
|
nkeynes@635 | 117 | }
|
nkeynes@635 | 118 | }
|
nkeynes@635 | 119 | }
|
nkeynes@635 | 120 |
|
nkeynes@635 | 121 | void glsl_unload_shaders(void)
|
nkeynes@635 | 122 | {
|
nkeynes@635 | 123 | glUseProgramObjectARB(0);
|
nkeynes@635 | 124 | glDetachObjectARB(glsl_program, glsl_vert_shader);
|
nkeynes@635 | 125 | glDetachObjectARB(glsl_program, glsl_frag_shader);
|
nkeynes@635 | 126 | glDeleteObjectARB(glsl_program);
|
nkeynes@635 | 127 | glDeleteObjectARB(glsl_vert_shader);
|
nkeynes@635 | 128 | glDeleteObjectARB(glsl_frag_shader);
|
nkeynes@635 | 129 | }
|
nkeynes@635 | 130 |
|
nkeynes@656 | 131 | #elif HAVE_OPENGL_SHADER
|
nkeynes@635 | 132 | static GLuint glsl_program = 0, glsl_vert_shader = 0, glsl_frag_shader = 0;
|
nkeynes@635 | 133 |
|
nkeynes@635 | 134 | gboolean glsl_check_shader_error( char *msg, GLuint shader )
|
nkeynes@635 | 135 | {
|
nkeynes@635 | 136 | GLint value;
|
nkeynes@635 | 137 |
|
nkeynes@635 | 138 | glGetShaderiv( shader, GL_COMPILE_STATUS, &value );
|
nkeynes@635 | 139 | if( value == 0 ) {
|
nkeynes@635 | 140 | char buf[MAX_ERROR_BUF];
|
nkeynes@635 | 141 | GLsizei length;
|
nkeynes@635 | 142 | glGetShaderInfoLog( shader, sizeof(buf), &length, buf );
|
nkeynes@635 | 143 | ERROR( "%s: %s", msg, buf );
|
nkeynes@635 | 144 | return FALSE;
|
nkeynes@635 | 145 | }
|
nkeynes@635 | 146 | return TRUE;
|
nkeynes@635 | 147 | }
|
nkeynes@635 | 148 | gboolean glsl_check_program_error( char *msg, GLuint program )
|
nkeynes@635 | 149 | {
|
nkeynes@635 | 150 | if( glGetError() != GL_NO_ERROR ) {
|
nkeynes@635 | 151 | char buf[MAX_ERROR_BUF];
|
nkeynes@635 | 152 | GLsizei length;
|
nkeynes@635 | 153 | glGetProgramInfoLog( program, sizeof(buf), &length, buf );
|
nkeynes@635 | 154 | ERROR( "%s: %s", msg, buf );
|
nkeynes@635 | 155 | return FALSE;
|
nkeynes@635 | 156 | }
|
nkeynes@635 | 157 | return TRUE;
|
nkeynes@635 | 158 | }
|
nkeynes@635 | 159 |
|
nkeynes@635 | 160 | gboolean glsl_load_shaders( const char *vertex_src, const char *fragment_src )
|
nkeynes@635 | 161 | {
|
nkeynes@635 | 162 | gboolean vsok = TRUE, fsok = TRUE, pok = FALSE;
|
nkeynes@635 | 163 |
|
nkeynes@635 | 164 | if( vertex_src == NULL && fragment_src == NULL ) {
|
nkeynes@635 | 165 | return TRUE;
|
nkeynes@635 | 166 | }
|
nkeynes@635 | 167 |
|
nkeynes@635 | 168 | glsl_program = glCreateProgram();
|
nkeynes@635 | 169 |
|
nkeynes@635 | 170 | if( vertex_src != NULL ) {
|
nkeynes@635 | 171 | glsl_vert_shader = glCreateShader(GL_VERTEX_SHADER);
|
nkeynes@635 | 172 | glShaderSource( glsl_vert_shader, 1, &vertex_src, NULL );
|
nkeynes@635 | 173 | glCompileShader(glsl_vert_shader);
|
nkeynes@635 | 174 | vsok = glsl_check_shader_error( "Failed to compile vertex shader", glsl_vert_shader );
|
nkeynes@635 | 175 | }
|
nkeynes@635 | 176 | if( fragment_src != NULL ) {
|
nkeynes@635 | 177 | glsl_frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
nkeynes@635 | 178 | glShaderSource( glsl_frag_shader, 1, &fragment_src, NULL );
|
nkeynes@635 | 179 | glCompileShader(glsl_frag_shader);
|
nkeynes@635 | 180 | fsok = glsl_check_shader_error( "Failed to compile fragment shader", glsl_frag_shader );
|
nkeynes@635 | 181 | }
|
nkeynes@635 | 182 |
|
nkeynes@635 | 183 | if( vsok && fsok ) {
|
nkeynes@635 | 184 | if( vertex_src != NULL ) {
|
nkeynes@635 | 185 | glAttachShader(glsl_program, glsl_vert_shader);
|
nkeynes@635 | 186 | }
|
nkeynes@635 | 187 | if( fragment_src != NULL ) {
|
nkeynes@635 | 188 | glAttachShader(glsl_program, glsl_frag_shader);
|
nkeynes@635 | 189 | }
|
nkeynes@635 | 190 | glLinkProgram(glsl_program);
|
nkeynes@635 | 191 | pok = glsl_check_program_error( "Failed to link shader program", glsl_program );
|
nkeynes@635 | 192 | }
|
nkeynes@635 | 193 |
|
nkeynes@635 | 194 | if( pok ) {
|
nkeynes@635 | 195 | glUseProgram(glsl_program);
|
nkeynes@635 | 196 | } else {
|
nkeynes@635 | 197 | glsl_unload_shaders();
|
nkeynes@635 | 198 | }
|
nkeynes@635 | 199 | return pok;
|
nkeynes@635 | 200 | }
|
nkeynes@635 | 201 |
|
nkeynes@635 | 202 |
|
nkeynes@635 | 203 | void glsl_enable_shader(gboolean en)
|
nkeynes@635 | 204 | {
|
nkeynes@635 | 205 | if( glsl_program != 0 ) {
|
nkeynes@635 | 206 | if( en ) {
|
nkeynes@635 | 207 | glUseProgram(glsl_program);
|
nkeynes@635 | 208 | } else {
|
nkeynes@635 | 209 | glUseProgram(0);
|
nkeynes@635 | 210 | }
|
nkeynes@635 | 211 | }
|
nkeynes@635 | 212 | }
|
nkeynes@635 | 213 |
|
nkeynes@635 | 214 | void glsl_unload_shaders(void)
|
nkeynes@635 | 215 | {
|
nkeynes@635 | 216 | glUseProgram(0);
|
nkeynes@635 | 217 | glDetachShader(glsl_program, glsl_vert_shader);
|
nkeynes@635 | 218 | glDetachShader(glsl_program, glsl_frag_shader);
|
nkeynes@635 | 219 | glDeleteProgram(glsl_program);
|
nkeynes@635 | 220 | glDeleteShader(glsl_vert_shader);
|
nkeynes@635 | 221 | glDeleteShader(glsl_frag_shader);
|
nkeynes@635 | 222 | }
|
nkeynes@656 | 223 |
|
nkeynes@656 | 224 | #else
|
nkeynes@656 | 225 | gboolean glsl_load_shaders( const char *vertex_src, const char *fragment_src )
|
nkeynes@656 | 226 | {
|
nkeynes@656 | 227 | return FALSE;
|
nkeynes@656 | 228 | }
|
nkeynes@656 | 229 |
|
nkeynes@656 | 230 | void glsl_unload_shaders()
|
nkeynes@656 | 231 | {
|
nkeynes@656 | 232 | }
|
nkeynes@656 | 233 |
|
nkeynes@635 | 234 | #endif
|