diff --git a/J.xcodeproj/project.pbxproj b/J.xcodeproj/project.pbxproj index 5245606..2b8eae5 100644 --- a/J.xcodeproj/project.pbxproj +++ b/J.xcodeproj/project.pbxproj @@ -8,15 +8,21 @@ /* Begin PBXBuildFile section */ 42681369140A321800CBF943 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42681368140A321800CBF943 /* Foundation.framework */; }; - 4268136F140A321800CBF943 /* J.m in Sources */ = {isa = PBXBuildFile; fileRef = 4268136E140A321800CBF943 /* J.m */; }; + 4268136F140A321800CBF943 /* J.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4268136E140A321800CBF943 /* J.mm */; }; + 42ED6A6B140A380000402F76 /* fbo.h in Headers */ = {isa = PBXBuildFile; fileRef = 42ED6A68140A380000402F76 /* fbo.h */; }; + 42ED6A6C140A380000402F76 /* shader.h in Headers */ = {isa = PBXBuildFile; fileRef = 42ED6A69140A380000402F76 /* shader.h */; }; + 42ED6A6D140A380000402F76 /* to_string.h in Headers */ = {isa = PBXBuildFile; fileRef = 42ED6A6A140A380000402F76 /* to_string.h */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 42681365140A321800CBF943 /* libJ.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libJ.a; sourceTree = BUILT_PRODUCTS_DIR; }; 42681368140A321800CBF943 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 4268136C140A321800CBF943 /* J-Prefix.pch */ = {isa = PBXFileReference; path = "J-Prefix.pch"; sourceTree = ""; }; - 4268136D140A321800CBF943 /* J.h */ = {isa = PBXFileReference; path = J.h; sourceTree = ""; }; - 4268136E140A321800CBF943 /* J.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = J.m; sourceTree = ""; }; + 4268136C140A321800CBF943 /* J-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "J-Prefix.pch"; sourceTree = ""; }; + 4268136D140A321800CBF943 /* J.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = J.h; sourceTree = ""; }; + 4268136E140A321800CBF943 /* J.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = J.mm; sourceTree = ""; }; + 42ED6A68140A380000402F76 /* fbo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fbo.h; sourceTree = ""; }; + 42ED6A69140A380000402F76 /* shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shader.h; sourceTree = ""; }; + 42ED6A6A140A380000402F76 /* to_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = to_string.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,8 +65,11 @@ 4268136A140A321800CBF943 /* J */ = { isa = PBXGroup; children = ( + 42ED6A68140A380000402F76 /* fbo.h */, + 42ED6A69140A380000402F76 /* shader.h */, + 42ED6A6A140A380000402F76 /* to_string.h */, 4268136D140A321800CBF943 /* J.h */, - 4268136E140A321800CBF943 /* J.m */, + 4268136E140A321800CBF943 /* J.mm */, 4268136B140A321800CBF943 /* Supporting Files */, ); path = J; @@ -81,6 +90,9 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 42ED6A6B140A380000402F76 /* fbo.h in Headers */, + 42ED6A6C140A380000402F76 /* shader.h in Headers */, + 42ED6A6D140A380000402F76 /* to_string.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -134,7 +146,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4268136F140A321800CBF943 /* J.m in Sources */, + 4268136F140A321800CBF943 /* J.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -224,6 +236,7 @@ 42681374140A321800CBF943 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/J/J.h b/J/J.h index 4815c3d..79978e8 100644 --- a/J/J.h +++ b/J/J.h @@ -7,6 +7,9 @@ // #import +#import "shader.h" +#import "fbo.h" +#import "to_string.h" @interface J : NSObject diff --git a/J/J.mm b/J/J.mm new file mode 100644 index 0000000..d707e75 --- /dev/null +++ b/J/J.mm @@ -0,0 +1,23 @@ +// +// J.m +// J +// +// Created by Joshua Moerman on 8/28/11. +// Copyright 2011 Vadovas. All rights reserved. +// + +#import "J.h" + +@implementation J + +- (id)init +{ + self = [super init]; + if (self) { + // Initialization code here. + } + + return self; +} + +@end diff --git a/J/fbo.h b/J/fbo.h new file mode 100644 index 0000000..0698303 --- /dev/null +++ b/J/fbo.h @@ -0,0 +1,138 @@ +#ifndef FBO_H +#define FBO_H + +#include +#include +#include + +#include "to_string.h" + +#import +#import + +// TODO: more error checking in debug build. +// TODO: make texture class? for easier switching between linear/nearest interpolation for example + +class fbo { +public: + typedef std::map RenderbuffersMap; + + int width, height; + GLuint fbo_number; + RenderbuffersMap renderbuffers; + GLuint texture_id; + +public: + fbo(int width, int height) : width(width), height(height), fbo_number(0), renderbuffers(), texture_id(0) { + glGenFramebuffers(1, &fbo_number); + bind(); + + // generate texture + glGenTextures(1, &texture_id); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0); + + // attach depth + create_attach_renderbuffer(GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); + + // attach stencil + //create_attach_renderbuffer(GL_STENCIL_INDEX, GL_STENCIL_ATTACHMENT); + + check_status(); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + unbind(); + } + ~fbo() { + end(); + + glDeleteFramebuffers(1, &fbo_number); + + for(RenderbuffersMap::const_iterator i = renderbuffers.begin(); i != renderbuffers.end(); ++i){ + RenderbuffersMap::value_type const & it = *i; + glDeleteFramebuffers(1, &it.second); + } + + glDeleteTextures(1, &texture_id); + } + + void begin(){ + bind(); + // FIXME: this should be done, but also switching back should be done... + //glPushAttrib(GL_VIEWPORT); + //glViewport(0, 0, width, height); + + // NOTE: commented out, because we don't want fbo's to nest. + /*GLint savedFramebuffer = -1; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer); + std::cout << "sfb: " << savedFramebuffer << ", fbo: " << fbo_number << std::endl;*/ + } + + void end(){ + unbind(); + // FIXME: switch back to previous viewport. + //glPopAttrib(); + } + +private: + void bind(){ + glBindFramebuffer(GL_FRAMEBUFFER, fbo_number); + + GLenum status = glGetError(); + if(status != GL_NO_ERROR) + throw std::runtime_error("i has error" + std::to_string(status) + "with fbo: " + std::to_string(fbo_number)); + } + + void unbind(){ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + void create_attach_renderbuffer(GLenum format, GLenum attachment_point) { + GLuint buffer; + glGenRenderbuffers(1, &buffer); + glBindRenderbuffer(GL_RENDERBUFFER, buffer); + glRenderbufferStorage(GL_RENDERBUFFER, format, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_point, GL_RENDERBUFFER, buffer); + + renderbuffers[format] = buffer; + } + + void check_status() { + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + switch(status) { + case GL_FRAMEBUFFER_COMPLETE: + std::cout << "FRAMEBUFFER_COMPLETE - OK" << std::endl; + return; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + std::cout << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT" << std::endl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + std::cout << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" << std::endl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + std::cout << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS" << std::endl; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + std::cout << "FRAMEBUFFER_UNSUPPORTED" << std::endl; + break; + default: + std::cout << "UNKNOWN FRAMEBUFFER ERROR" << std::endl; + break; + } + //throw std::runtime_error("I will not continu.."); + } + + void check_error(){ + GLenum status = glGetError(); + if(status != GL_NO_ERROR){ + throw std::runtime_error("GL Error: " + std::to_string(status)); + } + } + +}; + +#endif // FBO_H diff --git a/J/shader.h b/J/shader.h new file mode 100644 index 0000000..fe005b5 --- /dev/null +++ b/J/shader.h @@ -0,0 +1,186 @@ +#ifndef SHADER_H +#define SHADER_H + +#include +#include +#include +#include +#include + +#import +#import + +// TODO: do glValidateProgram, like in the OpenGL template +// TODO: add error checking at set_uniforms? + +class shader { + typedef std::map 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); + } + + 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); + } + + 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(file)), std::istreambuf_iterator()); + 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 + } + +}; + +#endif // SHADER_H diff --git a/J/to_string.h b/J/to_string.h new file mode 100644 index 0000000..7266a82 --- /dev/null +++ b/J/to_string.h @@ -0,0 +1,27 @@ +// +// to_string.h +// OpenGLTemplate +// +// Created by Joshua Moerman on 8/18/11. +// Copyright 2011 Vadovas. All rights reserved. +// + +#ifndef OpenGLTemplate_to_string_h +#define OpenGLTemplate_to_string_h + +#include +#include + +// NOTE: workaround for the std::to_string in C++11 +namespace std { + +template +std::string to_string(T const & x){ + std::stringstream ss; + ss << x; + return ss.str(); +} + +} // end namespace std + +#endif // OpenGLTemplate_to_string_h