RtB/src/Program.cpp

156 lines
4.6 KiB
C++

/* ================================================================
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 <fstream>
#include <sstream> // ostringstream
#include <stdexcept> // 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, &params);
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, &params);
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);
}