//
// code based on https://github.com/yasuohasegawa/OpenGL-Multipass-Shader-Sample
//
#include <GL/glew.h>
#include <GL/glut.h>
#include "ShaderTest.h"
#define TIMER_MS 25
#define CYCLE 1000.0f
#define APP_WIDTH 640
#define APP_HEIGHT 360
#define BLIT_TESTING_MODE 0
#define TEXTURES_COUNT 2
static GLuint _s_texBuffer[TEXTURES_COUNT] = {0, 0};
static GLuint _s_texBufferIndex = 0;
static GLuint _s_program1 = 0;
static GLuint _s_program2 = 0;
static GLuint _s_fb = 0;
static GLuint _s_texImage = 0;
static GLuint _s_frame = 0;
static enum eDrawMethod{
DRAW_QUAD,
DRAW_TRIANGLE_FAN,
DRAW_TRIANGLE_DUAL,
DRAW_TRIANGLE_STRIP,
DRAW_TRIANGLE_OVERSIZED
} _s_drawMethod = DRAW_QUAD;
void draw(){
if (_s_drawMethod == DRAW_QUAD){
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2i(0, 0);
glTexCoord2f(1.0, 0.0); glVertex2i(APP_WIDTH, 0);
glTexCoord2f(1.0, 1.0); glVertex2i(APP_WIDTH, APP_HEIGHT);
glTexCoord2f(0.0, 1.0); glVertex2i(0, APP_HEIGHT);
glEnd();
} else if (_s_drawMethod == DRAW_TRIANGLE_FAN) {
glBegin(GL_TRIANGLE_FAN);
glVertex2i(0, 0);
glVertex2i(0, APP_HEIGHT);
glVertex2i(APP_WIDTH, APP_HEIGHT);
glVertex2i(APP_WIDTH, 0);
glEnd();
// 1---2
// | / |
// 3---4
} else if (_s_drawMethod == DRAW_TRIANGLE_DUAL) {
glBegin(GL_TRIANGLES);
glVertex2i(0, APP_HEIGHT); // 1
glVertex2i(APP_WIDTH, APP_HEIGHT); // 2
glVertex2i(0, 0); // 3
glVertex2i(APP_WIDTH, 0); // 4
glVertex2i(0, 0); // 3
glVertex2i(APP_WIDTH, APP_HEIGHT); // 2
glEnd();
} else if (_s_drawMethod == DRAW_TRIANGLE_STRIP) {
glBegin(GL_TRIANGLE_STRIP);
glVertex2i(0, 0);
glVertex2i(APP_WIDTH, 0);
glVertex2i(0, APP_HEIGHT);
glVertex2i(APP_WIDTH, APP_HEIGHT);
glEnd();
} else if (_s_drawMethod == DRAW_TRIANGLE_OVERSIZED) {
glBegin(GL_TRIANGLES);
glVertex2i(0, 0);
glVertex2i(0, APP_HEIGHT);
glVertex2i(APP_WIDTH, APP_HEIGHT);
glEnd();
}
}
void init(){
glewInit();
_s_program1 = loadShader("./shaders/shader.vert","./shaders/ripples1_buffer.frag");
_s_program2 = loadShader("./shaders/shader.vert","./shaders/ripples1_image.frag");
// buffer textures
for (int i = 0; i < TEXTURES_COUNT; ++i){
glGenTextures(1, &_s_texBuffer[i]);
glBindTexture(GL_TEXTURE_2D, _s_texBuffer[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
}
// image/screen texture
glGenTextures(1, &_s_texImage);
glBindTexture(GL_TEXTURE_2D, _s_texImage);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// fbo
glGenFramebuffers(1, &_s_fb);
glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
for (int i = 0; i < TEXTURES_COUNT; ++i)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, _s_texBuffer[i], 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void render(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, APP_WIDTH, APP_HEIGHT);
glOrtho(0, APP_WIDTH, 0, APP_HEIGHT, -1, 1);
if (_s_drawMethod == DRAW_TRIANGLE_OVERSIZED){
glTranslatef(0.0, -APP_HEIGHT, 0.0);
glScalef(2.0, 2.0, 0.0);
}
// buffer
glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
glDrawBuffer(GL_COLOR_ATTACHMENT0 + _s_texBufferIndex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _s_texBuffer[_s_texBufferIndex ? 0 : 1]);
glUseProgram(_s_program1);
glUniform2f(glGetUniformLocation(_s_program1, "iViewportResolution"), (float) APP_WIDTH, (float) APP_HEIGHT);
glUniform1f(glGetUniformLocation(_s_program1, "iTime"), (float) glutGet(GLUT_ELAPSED_TIME) / CYCLE);
glUniform1i(glGetUniformLocation(_s_program1, "iFrame"), _s_frame++);
glUniform1i(glGetUniformLocation(_s_program1, "iChannel0"), 0);
draw();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// image / screen
// check for blit testing, rather than rendering to the image/screen texture
#if BLIT_TESTING_MODE
glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
glReadBuffer(GL_COLOR_ATTACHMENT0 + _s_texBufferIndex);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, APP_WIDTH, APP_HEIGHT, 0, 0, APP_WIDTH, APP_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#else
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _s_texBuffer[_s_texBufferIndex]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _s_texImage);
glUseProgram(_s_program2);
glUniform2f(glGetUniformLocation(_s_program2, "iViewportResolution"), (float) APP_WIDTH, (float) APP_HEIGHT);
glUniform1i(glGetUniformLocation(_s_program2, "iChannel0"), 0);
glUniform1i(glGetUniformLocation(_s_program2, "iChannel1"), 1);
draw();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
#endif
// update texture index (ping pong)
_s_texBufferIndex = _s_texBufferIndex ? 0 : 1;
glFlush();
}
void timer(int){
render();
glutTimerFunc(TIMER_MS, timer, 0);
}
void display(){}
int main(int argc, char *argv[]){
glutInit(&argc, argv);
glutInitWindowPosition(0, 0);
glutInitWindowSize(APP_WIDTH, APP_HEIGHT);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutTimerFunc(TIMER_MS, timer, 0);
init();
glutMainLoop();
return 0;
}