/* ================================================================ Program ---------------- This file defines our Program class. This class is responsible for loading, creating, and compiling OpenGL programs. ================================================================ */ #include "Program.hpp" #include "Log.hpp" #include "fio.hpp" #include #include // ostringstream #include // oor /* ======== Constructors and Destructors ======== */ Program::Program() { program = 0; } Program::~Program() { doClean(); } /* ======== Compilation and Linking ======== */ // add given shader to Program. During doCompile(), it is compiled and attached to the program int Program::addShader(const char *file, GLenum type) { // Load in our shader file char *buffer = NULL; size_t length = asset_fileToMem(file, &buffer); buffer[length] = '\0'; if (buffer == NULL) { LOG(LOG_ERROR) << FUNC_NAME << ": Could not open \"" << file << "\" for reading"; return 1; } // Create our shader GLuint shader = glCreateShader(type); if (shader == 0) { LOG(LOG_ERROR) << FUNC_NAME << ": Could not create shader for " << file; return 2; } // Load GLSL program into OpenGL const char *c_str = buffer; glShaderSource(shader, 1, &c_str, NULL); // Push the shader and its type onto the appropriate vectors shader_prog.push_back(shader); shader_type.push_back(type); free(buffer); return 0; } int Program::doCompile() { int params = -1; // param return for error checking char log[2048]; // log for OpenGL info logs int len = 0; // length of logs // Let's first create our program program = glCreateProgram(); // Now we compile our shaders size_t i; for (i = 0; i < shader_prog.size(); i++) { GLuint shader = shader_prog.at(i); glCompileShader(shader); // Let's check for errors glGetShaderiv(shader, GL_COMPILE_STATUS, ¶ms); if (params == GL_FALSE) { glGetShaderInfoLog(shader, 2048, &len, log); LOG(LOG_ERROR) << FUNC_NAME << ": shader \'" << shader << "\' failed to compile!\n" << log; return 1; } glAttachShader(program, shader); LOG(LOG_INFO) << FUNC_NAME << ": shader \'" << shader << "\' built and attached to " << program; } // Let's link the program glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, ¶ms); if (params != GL_TRUE) { glGetProgramInfoLog(program, 2048, &len, log); LOG(LOG_ERROR) << FUNC_NAME << ": failed to link program " << program << "\n" << log; return 1; } LOG(LOG_INFO) << FUNC_NAME << ": program " << program << " successfully built"; return 0; } GLuint Program::getProgram() { return program; } /* ======== (De)Activation ======== */ // int Program::activate() { glUseProgram(program); size_t i; for (i = 0; i < shader_textures.size(); i++) { glActiveTexture(GL_TEXTURE0 + shader_textures[i].index); glBindTexture(GL_TEXTURE_2D, shader_textures[i].texture); glUniform1i(shader_textures[i].location, shader_textures[i].index); } return 0; } int Program::deactivate() { // TODO: deactivate textures size_t i; for (i = 0; i < shader_textures.size(); i++) { // ?? FIXME } return 0; } /* ======== Cleaning ======== */ int Program::doClean() { // TODO: glDetachShader // TODO: glDeleteProgram return 0; } /* ======== Variable interfaces ======== */ // Textures can be "inserted" into a Program via the following function. The texture index position corresponds to an OpenGL texture position as well as the GLSL uniform that matches "tex"+"1-99" (e.g., "tex1"). int Program::attachTexture(GLuint index, GLuint texture) { if (texture == 0) return 1; std::ostringstream texture_str; texture_str << "tex" << index; Texture tex; tex.index = index; tex.texture = texture; tex.location = glGetUniformLocation(program, texture_str.str().c_str()); // Insert it onto the textures record for later usage shader_textures.insert(shader_textures.begin()+index, tex); return 0; } int Program::setTexture(GLuint index, GLuint texture) { try { shader_textures.at(index).texture = texture; } catch (const std::out_of_range& oor) { LOG(LOG_WARNING) << FUNC_NAME << ": " << oor.what(); return 1; } return 0; } GLuint Program::getUniform(const char *name) { return 0; } // VARIABLE Program::Variable::Variable(VariableType type_) { data_type = type_; type = UNDEF; location = 0; data = NULL; length = 0; switch(data_type) { case TEXTURE: length = sizeof(GLuint); data = (char*)malloc(length); (*data) = (GLuint)0; break; case INT: break; } } Program::Variable::~Variable() { if (data != NULL) free(data); }