156 lines
4.6 KiB
C++
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, ¶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);
|
|
}
|