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.
 
 
 
 

229 lines
6.6 KiB

#ifndef SHADER_H
#define SHADER_H
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <map>
#include <iterator>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
// TODO: do glValidateProgram, like in the OpenGL template (see bottom)
// TODO: add error checking at set_uniforms?
// TODO: use an uniform map? (benchmark first!)
namespace J {
enum {
ATTRIB_VERTEX,
ATTRIB_COLOR,
NUM_ATTRIBUTES
};
class shader {
typedef std::map<GLenum, GLuint> ShaderMap;
GLuint program;
ShaderMap shaders;
public:
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");
read_shader(vertex_shader, GL_VERTEX_SHADER);
}
{ // 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");
read_shader(fragment_shader, GL_FRAGMENT_SHADER);
}
{ // 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");
}
link_program();
}
~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
}
glDeleteProgram(program);
end();
}
void begin() {
glUseProgram(program);
}
void end() {
glUseProgram(0);
}
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);
}
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);
}
// TODO: add support for other matrices (not only 4x4), in ES2 only square matrices
void set_matrix(char const* name, bool trans, const GLfloat* value) const {
glUniformMatrix4fv(glGetUniformLocation(program, name), 1, trans, value);
}
// TODO: add support for other vectors (not only length 4)
void set_uniform(char const* name, const GLfloat* value, GLsizei count = 1) const {
glUniform4fv(glGetUniformLocation(program, name), count, value);
}
// TODO: add support for other vectors (not only length 4)
void set_uniform(char const* name, const GLint* value, GLsizei count = 1) const {
glUniform4iv(glGetUniformLocation(program, name), count, value);
}
void set_texture(const char* name, GLenum target, GLuint tex, int textureLocation) const {
glActiveTexture(GL_TEXTURE0 + textureLocation);
glBindTexture(target, tex);
set_uniform(name, textureLocation);
}
private:
// FIXME: this also compiles, bad name
void read_shader(std::istream& file, GLenum type) {
// 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);
#if defined(DEBUG)
// check compile status
GLint status = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE || shader == 0) {
GLsizei infoLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
char* infoBuffer = new GLchar[infoLength];
glGetShaderInfoLog(shader, infoLength, &infoLength, infoBuffer);
std::cerr << "source:\n" << buffer << std::endl;
std::cerr << "shader reports:\n" << infoBuffer << std::endl;
delete [] infoBuffer;
throw std::runtime_error("Shader failed to compile");
}
#endif
// 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);
#if defined(DEBUG)
// check link status
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if(status == GL_FALSE) {
GLsizei infoLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength);
char* infoBuffer = new GLchar[infoLength];
glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer);
std::cerr << "linker reports:\n" << infoBuffer << std::endl;
delete [] infoBuffer;
throw std::runtime_error("Shader failed to link");
}
#endif
}
/*
// Validate program before drawing. This is a good check, but only really necessary in a debug build.
- (BOOL)validateProgram:(GLuint)prog
{
GLint logLength, status;
glValidateProgram(prog);
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(@"Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
if (status == 0)
return FALSE;
return TRUE;
}
*/
};
} // namespace J
#endif // SHADER_H