| [4744] | 1 | /* | 
|---|
| [1853] | 2 |    orxonox - the future of 3D-vertical-scrollers | 
|---|
 | 3 |  | 
|---|
 | 4 |    Copyright (C) 2004 orx | 
|---|
 | 5 |  | 
|---|
 | 6 |    This program is free software; you can redistribute it and/or modify | 
|---|
 | 7 |    it under the terms of the GNU General Public License as published by | 
|---|
 | 8 |    the Free Software Foundation; either version 2, or (at your option) | 
|---|
 | 9 |    any later version. | 
|---|
| [1855] | 10 |  | 
|---|
 | 11 |    ### File Specific: | 
|---|
| [5261] | 12 |    main-programmer: Benjamin Grauer | 
|---|
| [1855] | 13 |    co-programmer: ... | 
|---|
| [1853] | 14 | */ | 
|---|
 | 15 |  | 
|---|
| [3955] | 16 | //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ | 
|---|
| [1853] | 17 |  | 
|---|
| [5261] | 18 | #include "shader.h" | 
|---|
| [1853] | 19 |  | 
|---|
| [5262] | 20 | #include "stdlibincl.h" | 
|---|
| [5273] | 21 | #include "compiler.h" | 
|---|
| [5262] | 22 | #include <stdio.h> | 
|---|
 | 23 | #include "debug.h" | 
|---|
| [5318] | 24 | #include "array.h" | 
|---|
| [5262] | 25 |  | 
|---|
| [5323] | 26 | #include "resource_manager.h" | 
|---|
| [5262] | 27 |  | 
|---|
| [5323] | 28 |  | 
|---|
| [5262] | 29 | #ifndef PARSELINELENGHT | 
|---|
 | 30 | #define PARSELINELENGHT     512       //!< how many chars to read at once | 
|---|
 | 31 | #endif | 
|---|
 | 32 |  | 
|---|
| [1856] | 33 | using namespace std; | 
|---|
| [1853] | 34 |  | 
|---|
| [1856] | 35 |  | 
|---|
| [3245] | 36 | /** | 
|---|
| [4838] | 37 |  * standard constructor | 
|---|
| [3245] | 38 | */ | 
|---|
| [5262] | 39 | Shader::Shader (const char* vertexShaderFile, const char* fragmentShaderFile) | 
|---|
| [3365] | 40 | { | 
|---|
| [5261] | 41 |    this->setClassID(CL_SHADER, "Shader"); | 
|---|
| [4320] | 42 |  | 
|---|
| [5261] | 43 |    this->fragmentShaderFile = NULL; | 
|---|
 | 44 |    this->vertexShaderFile = NULL; | 
|---|
 | 45 |    this->shaderProgram = 0; | 
|---|
 | 46 |    this->vertexShader = 0; | 
|---|
 | 47 |    this->fragmentShader = 0; | 
|---|
| [5262] | 48 |  | 
|---|
| [5263] | 49 |    if (GLEW_ARB_shader_objects && GLEW_ARB_shading_language_100) | 
|---|
| [5273] | 50 |      { | 
|---|
| [5320] | 51 |        GLint status = 0; | 
|---|
 | 52 |  | 
|---|
| [5273] | 53 |        this->shaderProgram = glCreateProgramObjectARB(); | 
|---|
| [5263] | 54 |  | 
|---|
| [5273] | 55 |        if (vertexShaderFile != NULL) | 
|---|
| [5285] | 56 |          this->loadShaderProgramm(SHADER_VERTEX, vertexShaderFile); | 
|---|
| [5273] | 57 |        if (fragmentShaderFile != NULL) | 
|---|
| [5285] | 58 |          this->loadShaderProgramm(SHADER_FRAGMENT, fragmentShaderFile); | 
|---|
| [5320] | 59 |        glLinkProgramARB(this->shaderProgram); | 
|---|
 | 60 |        // link error checking | 
|---|
 | 61 |        glGetObjectParameterivARB(this->shaderProgram, GL_OBJECT_LINK_STATUS_ARB, &status); | 
|---|
 | 62 |        if (status == GL_INVALID_VALUE || status == GL_INVALID_OPERATION) | 
|---|
 | 63 |          this->printError(this->shaderProgram); | 
|---|
 | 64 |     } | 
|---|
| [5273] | 65 |    else | 
|---|
 | 66 |      { | 
|---|
 | 67 |        PRINTF(2)("Shaders are not supported on your hardware\n"); | 
|---|
 | 68 |      } | 
|---|
| [3365] | 69 | } | 
|---|
| [1853] | 70 |  | 
|---|
 | 71 |  | 
|---|
| [3245] | 72 | /** | 
|---|
| [4838] | 73 |  * standard deconstructor | 
|---|
| [5318] | 74 |  */ | 
|---|
| [5261] | 75 | Shader::~Shader () | 
|---|
| [3543] | 76 | { | 
|---|
| [5322] | 77 |   if (this->shaderProgram == glGetHandleARB(GL_PROGRAM_OBJECT_ARB)) | 
|---|
| [5318] | 78 |     Shader::deactivateShader(); | 
|---|
 | 79 |  | 
|---|
| [3543] | 80 |   // delete what has to be deleted here | 
|---|
| [5262] | 81 |   this->deleteProgram(SHADER_VERTEX); | 
|---|
 | 82 |   this->deleteProgram(SHADER_FRAGMENT); | 
|---|
| [5263] | 83 |  | 
|---|
| [5273] | 84 |   if (this->fragmentShader != 0) | 
|---|
| [5322] | 85 |   { | 
|---|
 | 86 |     glDetachObjectARB(this->shaderProgram, this->fragmentShader); | 
|---|
| [5273] | 87 |     glDeleteObjectARB(this->fragmentShader); | 
|---|
| [5322] | 88 |   } | 
|---|
| [5273] | 89 |   if (this->vertexShader != 0) | 
|---|
| [5322] | 90 |   { | 
|---|
 | 91 |     glDetachObjectARB(this->shaderProgram, this->vertexShader); | 
|---|
| [5273] | 92 |     glDeleteObjectARB(this->vertexShader); | 
|---|
| [5322] | 93 |   } | 
|---|
| [5273] | 94 |   if (this->shaderProgram != 0) | 
|---|
| [5321] | 95 |   { | 
|---|
 | 96 |     GLint status = 0; | 
|---|
| [5322] | 97 |     //glLinkProgramARB(this->shaderProgram); | 
|---|
| [5273] | 98 |     glDeleteObjectARB(this->shaderProgram); | 
|---|
| [5321] | 99 |        // link error checking | 
|---|
 | 100 |     glGetObjectParameterivARB(this->shaderProgram, GL_OBJECT_DELETE_STATUS_ARB, &status); | 
|---|
 | 101 |     if (status == GL_INVALID_VALUE || status == GL_INVALID_OPERATION) | 
|---|
 | 102 |       this->printError(this->shaderProgram); | 
|---|
 | 103 |   } | 
|---|
| [3543] | 104 | } | 
|---|
| [5261] | 105 |  | 
|---|
| [5323] | 106 | Shader* Shader::getShader(const char* vertexShaderFile, const char* fragmentShaderFile) | 
|---|
 | 107 | { | 
|---|
| [6645] | 108 |   return (Shader*)ResourceManager::getInstance()->load(vertexShaderFile, SHADER,  RP_LEVEL, fragmentShaderFile); | 
|---|
| [5323] | 109 | } | 
|---|
 | 110 |  | 
|---|
 | 111 | bool Shader::unload(Shader* shader) | 
|---|
 | 112 | { | 
|---|
 | 113 |   return ResourceManager::getInstance()->unload(shader); | 
|---|
 | 114 | } | 
|---|
 | 115 |  | 
|---|
| [5317] | 116 | Shader* Shader::storedShader = NULL; | 
|---|
| [5261] | 117 |  | 
|---|
| [5317] | 118 |  | 
|---|
| [5261] | 119 | bool Shader::loadShaderProgramm(SHADER_TYPE type, const char* fileName) | 
|---|
 | 120 | { | 
|---|
| [5319] | 121 |   GLhandleARB shader = 0; | 
|---|
| [5285] | 122 |  | 
|---|
| [5262] | 123 |   if (type != SHADER_VERTEX && type != SHADER_FRAGMENT) | 
|---|
| [5261] | 124 |     return false; | 
|---|
| [5262] | 125 |   this->deleteProgram(type); | 
|---|
| [5261] | 126 |  | 
|---|
 | 127 |  | 
|---|
| [5390] | 128 |   tArray<char*>* program = fileReadArray(fileName); | 
|---|
| [5271] | 129 |   if (program == NULL) | 
|---|
 | 130 |     return false; | 
|---|
| [5318] | 131 |  | 
|---|
| [5266] | 132 |   if (type == SHADER_VERTEX && GLEW_ARB_vertex_shader) | 
|---|
| [5262] | 133 |   { | 
|---|
 | 134 |     this->vertexShaderFile = new char[strlen(fileName)+1]; | 
|---|
 | 135 |     strcpy(this->vertexShaderFile, fileName); | 
|---|
 | 136 |  | 
|---|
| [5269] | 137 |     shader = this->vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); | 
|---|
| [5263] | 138 |   } | 
|---|
| [5262] | 139 |  | 
|---|
| [5263] | 140 |   if (type == SHADER_FRAGMENT && GLEW_ARB_fragment_shader) | 
|---|
 | 141 |   { | 
|---|
| [5266] | 142 |     this->fragmentShaderFile = new char[strlen(fileName)+1]; | 
|---|
 | 143 |     strcpy(this->fragmentShaderFile, fileName); | 
|---|
 | 144 |  | 
|---|
| [5269] | 145 |     shader = this->fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); | 
|---|
| [5263] | 146 |   } | 
|---|
| [5273] | 147 |  | 
|---|
 | 148 |   if (shader != 0) | 
|---|
| [5319] | 149 |   { | 
|---|
| [5320] | 150 |     GLint status = 0; | 
|---|
| [5321] | 151 |     glShaderSourceARB(shader, program->getCount(), (const char**)program->getArray(), NULL); | 
|---|
| [5320] | 152 |     glCompileShaderARB(shader); | 
|---|
 | 153 |     // checking on error. | 
|---|
 | 154 |     glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); | 
|---|
 | 155 |     if (status == GL_INVALID_VALUE || status == GL_INVALID_OPERATION) | 
|---|
 | 156 |       this->printError(shader); | 
|---|
 | 157 |     else | 
|---|
 | 158 |       glAttachObjectARB(this->shaderProgram, shader); | 
|---|
| [5319] | 159 |   } | 
|---|
 | 160 |   for (unsigned int i=0; i< program->getCount(); i++) | 
|---|
 | 161 |     delete[] program->getArray()[i]; | 
|---|
 | 162 |   delete program; | 
|---|
| [5261] | 163 | } | 
|---|
 | 164 |  | 
|---|
| [5266] | 165 | char* Shader::fileRead(const char* fileName) | 
|---|
| [5261] | 166 | { | 
|---|
| [5266] | 167 |   FILE* fileHandle; | 
|---|
 | 168 |   char* content = NULL; | 
|---|
 | 169 |  | 
|---|
 | 170 |   int count = 0; | 
|---|
 | 171 |  | 
|---|
| [5271] | 172 |   if (fileName == NULL) | 
|---|
 | 173 |     return NULL; | 
|---|
| [5266] | 174 |  | 
|---|
| [5271] | 175 |   fileHandle = fopen(fileName, "rt"); | 
|---|
| [5266] | 176 |  | 
|---|
| [5271] | 177 |   if (fileHandle == NULL) | 
|---|
 | 178 |     return NULL; | 
|---|
 | 179 |   fseek(fileHandle, 0, SEEK_END); | 
|---|
 | 180 |   count = ftell(fileHandle); | 
|---|
 | 181 |   rewind(fileHandle); | 
|---|
 | 182 |   if (count > 0) { | 
|---|
 | 183 |      content = new char[count+1]; | 
|---|
 | 184 |      count = fread(content, sizeof(char), count, fileHandle); | 
|---|
 | 185 |      content[count] = '\0'; | 
|---|
 | 186 |    } | 
|---|
 | 187 |    fclose(fileHandle); | 
|---|
 | 188 |  return content; | 
|---|
| [5266] | 189 | } | 
|---|
 | 190 |  | 
|---|
| [5318] | 191 |  | 
|---|
| [5390] | 192 | tArray<char*>* Shader::fileReadArray(const char* fileName) | 
|---|
| [5318] | 193 | { | 
|---|
 | 194 |   FILE*    stream;           //< The stream we use to read the file. | 
|---|
 | 195 |  | 
|---|
 | 196 |   if( (stream = fopen (fileName, "rt")) == NULL) | 
|---|
 | 197 |   { | 
|---|
 | 198 |     PRINTF(1)("Shader could not open %s\n", fileName); | 
|---|
 | 199 |     return NULL; | 
|---|
 | 200 |   } | 
|---|
| [5390] | 201 |   tArray<char*>* file = new tArray<char*>; | 
|---|
| [5318] | 202 |  | 
|---|
 | 203 |   char lineBuffer[PARSELINELENGHT]; | 
|---|
 | 204 |   char* addString; | 
|---|
 | 205 |   while(fgets (lineBuffer, PARSELINELENGHT, stream) != NULL) | 
|---|
 | 206 |   { | 
|---|
 | 207 |     addString = new char[strlen(lineBuffer)+1]; | 
|---|
 | 208 |     strcpy(addString, lineBuffer); | 
|---|
 | 209 |     file->addEntry(addString); | 
|---|
 | 210 |   } | 
|---|
 | 211 |   fclose(stream); | 
|---|
 | 212 |   file->finalizeArray(); | 
|---|
 | 213 |   return file; | 
|---|
 | 214 | } | 
|---|
 | 215 |  | 
|---|
 | 216 |  | 
|---|
 | 217 |  | 
|---|
| [5266] | 218 | void Shader::activateShader() | 
|---|
 | 219 | { | 
|---|
| [5273] | 220 |   if (likely (this->shaderProgram != 0)) | 
|---|
| [5317] | 221 |   { | 
|---|
| [5273] | 222 |     glUseProgramObjectARB(this->shaderProgram); | 
|---|
| [5317] | 223 |     Shader::storedShader = this; | 
|---|
 | 224 |   } | 
|---|
| [5261] | 225 | } | 
|---|
| [5262] | 226 |  | 
|---|
| [5266] | 227 | void Shader::deactivateShader() | 
|---|
 | 228 | { | 
|---|
| [5364] | 229 |  if (storedShader != NULL) | 
|---|
 | 230 |    glUseProgramObjectARB(0); | 
|---|
 | 231 |  Shader::storedShader = NULL; | 
|---|
| [5266] | 232 | } | 
|---|
| [5262] | 233 |  | 
|---|
| [5266] | 234 |  | 
|---|
| [5262] | 235 | void Shader::deleteProgram(SHADER_TYPE type) | 
|---|
 | 236 | { | 
|---|
| [5335] | 237 |   GLint status = 0; | 
|---|
| [5273] | 238 |   if (type == SHADER_VERTEX && this->vertexShader != 0) | 
|---|
| [5262] | 239 |   { | 
|---|
 | 240 |     delete[] this->vertexShaderFile; | 
|---|
 | 241 |     this->vertexShaderFile = NULL; | 
|---|
| [5321] | 242 |     glDetachObjectARB(this->shaderProgram, this->vertexShader); | 
|---|
| [5263] | 243 |     glDeleteObjectARB(this->vertexShader); | 
|---|
| [5320] | 244 |     glGetObjectParameterivARB(this->vertexShader, GL_OBJECT_DELETE_STATUS_ARB, &status); | 
|---|
 | 245 |     if (status == GL_INVALID_VALUE || status == GL_INVALID_OPERATION) | 
|---|
 | 246 |       Shader::printError(this->vertexShader); | 
|---|
| [5263] | 247 |     this->vertexShader = 0; | 
|---|
| [5262] | 248 |   } | 
|---|
| [5273] | 249 |   else if (type == SHADER_FRAGMENT && this->fragmentShader != 0) | 
|---|
| [5262] | 250 |   { | 
|---|
 | 251 |     delete[] this->fragmentShaderFile; | 
|---|
 | 252 |     this->fragmentShaderFile = NULL; | 
|---|
| [5321] | 253 |     glDetachObjectARB(this->shaderProgram, this->fragmentShader); | 
|---|
| [5263] | 254 |     glDeleteObjectARB(this->fragmentShader); | 
|---|
| [5320] | 255 |     glGetObjectParameterivARB(this->fragmentShader, GL_OBJECT_DELETE_STATUS_ARB, &status); | 
|---|
 | 256 |     if (status == GL_INVALID_VALUE || status == GL_INVALID_OPERATION) | 
|---|
 | 257 |       Shader::printError(this->fragmentShader); | 
|---|
| [5263] | 258 |     this->fragmentShader = 0; | 
|---|
| [5262] | 259 |   } | 
|---|
 | 260 |   else | 
|---|
 | 261 |     return; | 
|---|
 | 262 | } | 
|---|
 | 263 |  | 
|---|
| [5264] | 264 |  | 
|---|
| [5319] | 265 | void Shader::printError(GLhandleARB program) | 
|---|
| [5264] | 266 | { | 
|---|
| [5273] | 267 |   if (program == 0) | 
|---|
 | 268 |     return; | 
|---|
 | 269 |  | 
|---|
| [5267] | 270 |   int infologLength = 0; | 
|---|
 | 271 |   int charsWritten  = 0; | 
|---|
 | 272 |   char *infoLog; | 
|---|
 | 273 |  | 
|---|
 | 274 |   glGetObjectParameterivARB(program, GL_OBJECT_INFO_LOG_LENGTH_ARB, | 
|---|
 | 275 |                             &infologLength); | 
|---|
 | 276 |  | 
|---|
 | 277 |   if (infologLength > 0) | 
|---|
 | 278 |   { | 
|---|
| [5283] | 279 |     infoLog = new char[infologLength+1]; | 
|---|
| [5267] | 280 |     glGetInfoLogARB(program, infologLength, &charsWritten, infoLog); | 
|---|
| [5269] | 281 |     printf("%s\n", infoLog); | 
|---|
| [5283] | 282 |     delete[] infoLog; | 
|---|
| [5267] | 283 |   } | 
|---|
| [5264] | 284 | } | 
|---|
 | 285 |  | 
|---|
| [5333] | 286 | bool Shader::checkShaderAbility() | 
|---|
 | 287 | { | 
|---|
 | 288 |   if (GLEW_ARB_shader_objects && | 
|---|
 | 289 |       GLEW_ARB_shading_language_100 && | 
|---|
 | 290 |       GLEW_ARB_vertex_shader && | 
|---|
 | 291 |       GLEW_ARB_fragment_shader) | 
|---|
 | 292 |     return true; | 
|---|
 | 293 |   else | 
|---|
 | 294 |     return false; | 
|---|
 | 295 | } | 
|---|
| [5264] | 296 |  | 
|---|
| [5262] | 297 | void Shader::debug() const | 
|---|
 | 298 | { | 
|---|
 | 299 |   PRINT(3)("Shader info: (SHADER: %d)\n", this->shaderProgram); | 
|---|
 | 300 |   if (this->vertexShader != 0) | 
|---|
 | 301 |   { | 
|---|
| [5266] | 302 | /*    PRINT(3)("VertexShaderProgramm: number=%d, file='%s'\n", this->vertexShader, this->vertexShaderFile); | 
|---|
| [5262] | 303 |     if (this->vertexShaderSource != NULL) | 
|---|
 | 304 |       for (unsigned int i = 0; i < this->vertexShaderSource->getCount(); i++) | 
|---|
 | 305 |         PRINT(3)("%d: %s\n", i, this->vertexShaderSource->getEntry(i)); | 
|---|
 | 306 |   } | 
|---|
 | 307 |   if (this->fragmentShader != 0) | 
|---|
 | 308 |   { | 
|---|
 | 309 |     PRINT(3)("FragmentShaderProgramm: number=%d, file='%s'\n", this->fragmentShader, this->fragmentShaderFile); | 
|---|
 | 310 |     if (this->fragmentShaderSource != NULL) | 
|---|
 | 311 |       for (unsigned int i = 0; i < this->fragmentShaderSource->getCount(); i++) | 
|---|
| [5266] | 312 |         PRINT(3)("%d: %s\n", i, this->fragmentShaderSource->getEntry(i));*/ | 
|---|
| [5262] | 313 |   } | 
|---|
 | 314 | } | 
|---|
 | 315 |  | 
|---|