Very small OpenGL wrapper (before moggle was there)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

280 lines
8.1 KiB

//
// shader.h
// J
//
// Created by Joshua Moerman on 7/01/11.
// Copyright 2011 Vadovas. All rights reserved.
//
13 years ago
#ifndef SHADER_H
#define SHADER_H
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <map>
#include <iterator>
#import "basic.h"
13 years ago
// TODO: do glValidateProgram, like in the OpenGL template (see bottom)
13 years ago
// TODO: add error checking at set_uniforms?
// TODO: use an uniform map? (benchmark first!)
// TODO: allow arrays is uniforms (now all counts are 1)
13 years ago
namespace J {
enum {
ATTRIB_VERTEX,
ATTRIB_COLOR,
NUM_ATTRIBUTES
};
13 years ago
class shader {
// NOTE: it could be hardcoded to use vertex_shader and fragment_shader.
13 years ago
typedef std::map<GLenum, GLuint> ShaderMap;
GLuint program;
ShaderMap shaders;
public:
// ***********
// constructor
13 years ago
shader(std::string vertex_shader_filename, std::string fragment_shader_filename) :
program(0), shaders() {
program = glCreateProgram();
if(program == 0) {
throw std::runtime_error("Program couldn't be created");
}
{ // vertex shader
// NOTE: C++03 mandates .c_str(), ugly, nothing to do about it...
std::ifstream vertex_shader(vertex_shader_filename.c_str());
if(!vertex_shader)
throw std::runtime_error(vertex_shader_filename + " couldn't be opened");
compile_shader(vertex_shader, GL_VERTEX_SHADER);
13 years ago
}
{ // fragment shader
std::ifstream fragment_shader(fragment_shader_filename.c_str());
if(!fragment_shader)
throw std::runtime_error(fragment_shader_filename + " couldn't be opened");
compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
13 years ago
}
{ // TODO: think of a nice way to implement this
// Bind attribute locations.
// This needs to be done prior to linking.
glBindAttribLocation(program, ATTRIB_VERTEX, "position");
glBindAttribLocation(program, ATTRIB_COLOR, "color");
}
13 years ago
link_program();
check_error();
13 years ago
}
~shader(){
begin();
for(ShaderMap::const_iterator i = shaders.begin(); i != shaders.end(); ++i){
ShaderMap::value_type const & it = *i;
GLuint shader = it.second;
glDetachShader(program, shader);
glDeleteShader(shader);
// NOTE: If a shader object to be deleted is attached to a program object, it will be flagged for deletion, but it will not be deleted until it is no longer attached to any program object
13 years ago
}
13 years ago
end();
glDeleteProgram(program);
13 years ago
}
// *****
// usage
13 years ago
void begin() {
glUseProgram(program);
}
void end() {
glUseProgram(0);
}
// ***************
// uniform setters
// float vectors (multiple values)
13 years ago
void set_uniform(char const* name, float x) const {
glUniform1f(glGetUniformLocation(program, name), x);
}
void set_uniform(char const* name, float x, float y) const {
glUniform2f(glGetUniformLocation(program, name), x, y);
}
void set_uniform(char const* name, float x, float y, float z) const {
glUniform3f(glGetUniformLocation(program, name), x, y, z);
}
void set_uniform(char const* name, float x, float y, float z, float w) const {
glUniform4f(glGetUniformLocation(program, name), x, y, z, w);
}
// integer vectors (multiple values)
13 years ago
void set_uniform(char const* name, int x) const {
glUniform1i(glGetUniformLocation(program, name), x);
}
void set_uniform(char const* name, int x, int y) const {
glUniform2i(glGetUniformLocation(program, name), x, y);
}
void set_uniform(char const* name, int x, int y, int z) const {
glUniform3i(glGetUniformLocation(program, name), x, y, z);
}
void set_uniform(char const* name, int x, int y, int z, int w) const {
glUniform4i(glGetUniformLocation(program, name), x, y, z, w);
}
// Float vectors (array)
void set_uniform(char const* name, const GLfloat (&value)[4]) const {
glUniform4fv(glGetUniformLocation(program, name), 1, value);
}
void set_uniform(char const* name, const GLfloat (&value)[3]) const {
glUniform3fv(glGetUniformLocation(program, name), 1, value);
}
void set_uniform(char const* name, const GLfloat (&value)[2]) const {
glUniform2fv(glGetUniformLocation(program, name), 1, value);
}
void set_uniform(char const* name, const GLfloat (&value)[1]) const {
glUniform1fv(glGetUniformLocation(program, name), 1, value);
}
// Integer vectors (array)
void set_uniform(char const* name, const GLint (&value)[4]) const {
glUniform4iv(glGetUniformLocation(program, name), 1, value);
}
void set_uniform(char const* name, const GLint (&value)[3]) const {
glUniform3iv(glGetUniformLocation(program, name), 1, value);
}
void set_uniform(char const* name, const GLint (&value)[2]) const {
glUniform2iv(glGetUniformLocation(program, name), 1, value);
}
void set_uniform(char const* name, const GLint (&value)[1]) const {
glUniform1iv(glGetUniformLocation(program, name), 1, value);
}
13 years ago
// matrices (in ES2 only square matrices)
void set_uniform(char const* name, const GLfloat (&value)[16], GLboolean trans = GL_FALSE) const {
13 years ago
glUniformMatrix4fv(glGetUniformLocation(program, name), 1, trans, value);
}
void set_uniform(char const* name, const GLfloat (&value)[9], GLboolean trans = GL_FALSE) const {
glUniformMatrix3fv(glGetUniformLocation(program, name), 1, trans, value);
13 years ago
}
void set_uniform(char const* name, const GLfloat (&value)[4], GLboolean trans = GL_FALSE) const {
glUniformMatrix2fv(glGetUniformLocation(program, name), 1, trans, value);
13 years ago
}
// textures (see todo above)
13 years ago
void set_texture(const char* name, GLenum target, GLuint tex, int textureLocation) const {
glActiveTexture(GL_TEXTURE0 + textureLocation);
glBindTexture(target, tex);
set_uniform(name, textureLocation);
}
// *********
// validator
void validate() {
#if defined(DEBUG)
GLint status;
glValidateProgram(program);
glGetProgramiv(program, GL_VALIDATE_STATUS, &status);
if(status == GL_FALSE){
std::cerr << "validator reports:" << std::endl;
show_log();
throw std::runtime_error("Program not valid");
}
#endif
}
13 years ago
private:
// *******************
// compiling / linking
void compile_shader(std::istream& file, GLenum type) {
13 years ago
// get the c-string, the shortest way (not fastest)
std::string buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
const char* sptr = buffer.c_str();
int ssize = buffer.size();
// create and compile shader
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &sptr, &ssize);
glCompileShader(shader);
check_compile_status(shader, buffer);
13 years ago
// put it in tha map
shaders[type] = shader;
}
void link_program() {
// attach all shaders
for(ShaderMap::const_iterator i = shaders.begin(); i != shaders.end(); ++i){
ShaderMap::value_type const & it = *i;
GLuint shader = it.second;
glAttachShader(program, shader);
}
// link
glLinkProgram(program);
check_link_status();
}
// ***************
// status checking
void check_compile_status(GLint shader, std::string source = "") {
#if defined(DEBUG)
GLint status = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE || shader == 0) {
std::cerr << "source:\n" << source << std::endl;
std::cerr << "shader reports:" << std::endl;
show_log();
throw std::runtime_error("Shader failed to compile");
}
#endif
}
void check_link_status() {
#if defined(DEBUG)
13 years ago
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if(status == GL_FALSE) {
std::cerr << "linker reports:" << std::endl;
show_log();
13 years ago
throw std::runtime_error("Shader failed to link");
}
#endif
}
void show_log(std::ostream& out = std::cerr) {
GLsizei infoLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength);
char* infoBuffer = new GLchar[infoLength];
glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer);
out << infoBuffer << std::endl;
delete [] infoBuffer;
}
13 years ago
};
} // namespace J
13 years ago
#endif // SHADER_H