+#define GLCHECK(_w) {_w; dumpError(#_w);}
+
+void print_log(GLuint obj)
+{
+ int infologLength = 0;
+ int maxLength;
+
+ if(glIsShader(obj))
+ glGetShaderiv(obj,GL_INFO_LOG_LENGTH,&maxLength);
+ else
+ glGetProgramiv(obj,GL_INFO_LOG_LENGTH,&maxLength);
+
+ char infoLog[maxLength];
+
+ if (glIsShader(obj))
+ glGetShaderInfoLog(obj, maxLength, &infologLength, infoLog);
+ else
+ glGetProgramInfoLog(obj, maxLength, &infologLength, infoLog);
+
+ if (infologLength > 0)
+ printf("%s\n",infoLog);
+}
+/* Global */
+GLuint fbo, fbo_texture, rbo_depth;
+//GLuint vbo_fbo_vertices;
+
+static void
+gl_offscreenInit(
+ int screen_width,
+ int screen_height)
+{
+ /* init_resources */
+ /* Create back-buffer, used for post-processing */
+
+ /* Texture */
+ GLCHECK(glActiveTexture(GL_TEXTURE0));
+ glGenTextures(1, &fbo_texture);
+ glBindTexture(GL_TEXTURE_2D, fbo_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ /* Depth buffer */
+ GLCHECK(glGenRenderbuffers(1, &rbo_depth));
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
+ screen_height);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ /* Framebuffer to link everything together */
+ GLCHECK(glGenFramebuffers(1, &fbo));
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ fbo_texture, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, rbo_depth);
+
+ GLenum status;
+ if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER))
+ != GL_FRAMEBUFFER_COMPLETE) {
+ fprintf(stderr, "glCheckFramebufferStatus: error %d", (int)status);
+ return ;
+ }
+#if 0
+ // Set the list of draw buffers.
+ GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0};
+ glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+}
+
+void
+gl_offscreenReshape(
+ int screen_width,
+ int screen_height)
+{
+// Rescale FBO and RBO as well
+ glBindTexture(GL_TEXTURE_2D, fbo_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
+ screen_height);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+// glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+// glViewport(0, 0, screen_width, screen_height);
+// glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void gl_offscreenFree()
+{
+ /* free_resources */
+ glDeleteRenderbuffers(1, &rbo_depth);
+ glDeleteTextures(1, &fbo_texture);
+ glDeleteFramebuffers(1, &fbo);
+// glDeleteBuffers(1, &vbo_fbo_vertices);
+}
+
+GLuint program_postproc = 0, uniform_fbo_texture;
+
+static GLuint create_shader(const char * fname, GLuint pid)
+{
+ const GLchar * buf;
+
+ FILE *f = fopen(fname, "r");
+ if (!f) {
+ perror(fname);
+ return 0;
+ }
+ fseek(f, 0, SEEK_END);
+ long fs = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ /*
+ * need to insert a header since there is nothing to detect the version number
+ * reliably without it, and __VERSION__ returns idiocy
+ */
+ char head[128];
+ sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
+ const int header = strlen(head);
+ buf = malloc(header + fs + 1);
+ memcpy((void*)buf, head, header);
+ fread((void*)buf + header, 1, fs, f);
+ ((char*)buf)[header + fs] = 0;
+ fclose(f);
+
+ GLuint vs = glCreateShader(pid);
+ glShaderSource(vs, 1, &buf, NULL);
+ glCompileShader(vs);
+ dumpError("glCompileShader");
+ print_log(vs);
+ free((void*)buf);
+ return vs;
+}
+
+
+int gl_ppProgram()
+{
+ int vs, fs;
+ int link_ok, validate_ok;
+ /* init_resources */
+ /* Post-processing */
+ if ((vs = create_shader("gfx/postproc.vs", GL_VERTEX_SHADER)) == 0)
+ return 0;
+ if ((fs = create_shader("gfx/postproc.fs", GL_FRAGMENT_SHADER)) == 0)
+ return 0;
+
+ program_postproc = glCreateProgram();
+ glAttachShader(program_postproc, vs);
+ glAttachShader(program_postproc, fs);
+ glLinkProgram(program_postproc);
+ glGetProgramiv(program_postproc, GL_LINK_STATUS, &link_ok);
+ if (!link_ok) {
+ fprintf(stderr, "glLinkProgram:");
+ goto error;
+ }
+ glValidateProgram(program_postproc);
+ glGetProgramiv(program_postproc, GL_VALIDATE_STATUS, &validate_ok);
+ if (!validate_ok) {
+ fprintf(stderr, "glValidateProgram:");
+ goto error;
+ }
+
+ char * uniform_name = "m_Texture";
+ uniform_fbo_texture = glGetUniformLocation(program_postproc, uniform_name);
+ if (uniform_fbo_texture == -1) {
+ fprintf(stderr, "Could not bind uniform %s\n", uniform_name);
+ goto error;
+ }
+ return 0;
+error:
+ print_log(program_postproc);
+ glDeleteProgram(program_postproc);
+ program_postproc = 0;
+ return -1;
+}
+
+void
+gl_ppFree()
+{
+ if (program_postproc)
+ glDeleteProgram(program_postproc);
+ program_postproc = 0;
+}
+
+static void
+_gl_reshape_cb(int w, int h)
+{
+ _w = w;
+ _h = h;
+
+ glViewport(0, 0, _w, _h);
+ gl_offscreenReshape(_w, _h);
+ glutPostRedisplay();
+}
+