/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ #include "shader.h" #include "array.h" #include "stdlibincl.h" #include #include "debug.h" #ifndef PARSELINELENGHT #define PARSELINELENGHT 512 //!< how many chars to read at once #endif using namespace std; /** * standard constructor */ Shader::Shader (const char* vertexShaderFile, const char* fragmentShaderFile) { this->setClassID(CL_SHADER, "Shader"); this->fragmentShaderFile = NULL; this->vertexShaderFile = NULL; this->fragmentShaderSource = NULL; this->vertexShaderSource = NULL; this->fragmentShaderLengths = NULL; this->vertexShaderLenghts = NULL; this->shaderProgram = 0; this->vertexShader = 0; this->fragmentShader = 0; if (GLEW_ARB_shader_objects && GLEW_ARB_shading_language_100) this->shaderProgram = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); if (vertexShaderFile != NULL) this->loadShaderProgramm(SHADER_VERTEX, vertexShaderFile); if (fragmentShaderFile != NULL) this->loadShaderProgramm(SHADER_FRAGMENT, fragmentShaderFile); glLinkProgramARB(this->shaderProgram); this->printError(this->shaderProgram); } /** * standard deconstructor */ Shader::~Shader () { // delete what has to be deleted here this->deleteProgram(SHADER_VERTEX); this->deleteProgram(SHADER_FRAGMENT); glDeleteObjectARB(this->shaderProgram); } bool Shader::loadShaderProgramm(SHADER_TYPE type, const char* fileName) { if (type != SHADER_VERTEX && type != SHADER_FRAGMENT) return false; this->deleteProgram(type); FILE* stream; //< The stream we use to read the file. if( (stream = fopen (fileName, "r")) == NULL) { PRINTF(1)("Shader could not open %s\n", fileName); return false; } Array* program = new Array; Array* lengths = new Array; if (type == SHADER_VERTEX) { this->vertexShaderFile = new char[strlen(fileName)+1]; strcpy(this->vertexShaderFile, fileName); this->vertexShaderSource = program; this->vertexShaderLenghts = lengths; } else { this->fragmentShaderFile = new char[strlen(fileName)+1]; strcpy(this->fragmentShaderFile, fileName); this->fragmentShaderSource = program; this->fragmentShaderLengths = lengths; } char lineBuffer[PARSELINELENGHT]; char* addString; while( !feof( stream)) { // get next line fgets (lineBuffer, PARSELINELENGHT, stream); // if (strchr(lineBuffer, '\n')) // { // addString = new char[strlen(lineBuffer)]; // strncpy(addString, lineBuffer, strlen (lineBuffer)-1); // addString[strlen(lineBuffer)-1] ='\0'; // } // else { addString = new char[strlen(lineBuffer)+1]; strcpy(addString, lineBuffer); } program->addEntry(addString); lengths->addEntry(strlen(addString)); } fclose(stream); program->finalizeArray(); lengths->finalizeArray(); if (type == SHADER_VERTEX && GLEW_ARB_vertex_shader) { this->vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); glShaderSourceARB(this->vertexShader, program->getCount(), (const GLcharARB**)program->getArray(), lengths->getArray()); glCompileShaderARB(this->vertexShader); glAttachObjectARB(this->shaderProgram, this->vertexShader); this->printError(this->vertexShader); } if (type == SHADER_FRAGMENT && GLEW_ARB_fragment_shader) { this->fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); glShaderSourceARB(this->fragmentShader, program->getCount(), (const GLcharARB**)program->getArray(), lengths->getArray()); glCompileShaderARB(this->fragmentShader); glAttachObjectARB(this->shaderProgram, this->fragmentShader); this->printError(this->fragmentShader); } } bool Shader::activateShader() { glUseProgramObjectARB(this->shaderProgram); } void Shader::deleteProgram(SHADER_TYPE type) { Array* deleteArray = NULL; if (type == SHADER_VERTEX) { deleteArray = this->vertexShaderSource; this->vertexShaderSource = NULL; delete this->vertexShaderLenghts; this->vertexShaderLenghts = NULL; delete[] this->vertexShaderFile; this->vertexShaderFile = NULL; glDeleteObjectARB(this->vertexShader); this->vertexShader = 0; } else if (type == SHADER_FRAGMENT) { deleteArray = this->fragmentShaderSource; delete this->fragmentShaderLengths; this->fragmentShaderLengths = NULL; this->fragmentShaderSource = NULL; delete[] this->fragmentShaderFile; this->fragmentShaderFile = NULL; glDeleteObjectARB(this->fragmentShader); this->fragmentShader = 0; } else return; if (deleteArray == NULL) return; else { deleteArray->finalizeArray(); for (unsigned int i = 0; i < deleteArray->getCount(); i++) { delete[] deleteArray->getEntry(i); } delete deleteArray; } } void Shader::printError(GLenum program) { GLint length = 5000; // glGetObjectParameterARBfiv(program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); char* text = new char[length+1]; glGetInfoLogARB(program, length, &length, text); printf("%s\n", text); delete[] text; } void Shader::debug() const { PRINT(3)("Shader info: (SHADER: %d)\n", this->shaderProgram); if (this->vertexShader != 0) { PRINT(3)("VertexShaderProgramm: number=%d, file='%s'\n", this->vertexShader, this->vertexShaderFile); if (this->vertexShaderSource != NULL) for (unsigned int i = 0; i < this->vertexShaderSource->getCount(); i++) PRINT(3)("%d: %s\n", i, this->vertexShaderSource->getEntry(i)); } if (this->fragmentShader != 0) { PRINT(3)("FragmentShaderProgramm: number=%d, file='%s'\n", this->fragmentShader, this->fragmentShaderFile); if (this->fragmentShaderSource != NULL) for (unsigned int i = 0; i < this->fragmentShaderSource->getCount(); i++) PRINT(3)("%d: %s\n", i, this->fragmentShaderSource->getEntry(i)); } }