Here is my unit test:
[b]
#include <iostream>
#include <cassert>
#include<GL/glew.h>
#include<GL/glut.h>
#include<GL/glext.h>
#include "textfile.h"
using namespace std;
float angle = 0.0;
int in_tex = 0;
int out_tex = 1;
int iter = 20;
// texture handle for ping pong
GLuint tex[2];
unsigned char* data;
// initial texture
GLuint init_tex;
int width = 512;
int height = 128;
// fbo handle
GLuint fbo;
GLenum att_point[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
// shader variables
GLuint v, f, p1, p2, f2;
char *vs,*fs,*fs2;
static bool
checkFBOErrors()
{
unsigned fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
std::cout << "error creating fbo, framebufferstatus is not complete:" << std::endl;
std::string error;
switch (fbo_status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error.assign("GL_FRAMEBUFFER_UNSUPPORTED_EXT");break;
}
std::cout << "error: " << error << std::endl;
return false;
}
}
//
//
// shader program
void setShaders()
{
// v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
f2 = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
// vs = textFileRead("toon.vert");
fs = textFileRead("toon.frag");
fs2 = textFileRead("toon2.frag");
const char * ff = fs;
const char * ff2 = fs2;
// const char * vv = vs;
// glShaderSourceARB(v, 1, &vv,NULL);
glShaderSourceARB(f, 1, &ff,NULL);
glShaderSourceARB(f2, 1, &ff2,NULL);
// free(vs);
free(fs); free(fs2);
// glCompileShaderARB(v);
glCompileShaderARB(f);
glCompileShaderARB(f2);
p1 = glCreateProgramObjectARB();
glAttachObjectARB(p1,f);
// glAttachObjectARB(p1,v);
glLinkProgramARB(p1);
p2 = glCreateProgramObjectARB();
glAttachObjectARB(p2,f2);
// glAttachObjectARB(p2,v);
glLinkProgramARB(p2);
}
void InitGLExtensions()
{
// Init GLEW
if (glewInit() != GLEW_OK)
{
cout << "Error: Can't initialize GLEW" << endl;
exit(-1);
}
else
{
cout<<"GLEW IS INITIALIZED OK!!"<<endl;
}
if (!GLEW_EXT_framebuffer_object)
{
cout << "Error: EXT_framebuffer_object is not supported." << endl;
exit(-1);
}
else
cout<<"FRAME BUFFER OBJECT IS INITIALIZED OK!!"<<endl;
}
void initTextures()
{
// allocate texture name
glGenTextures(1, &init_tex);
//
// generate test 8 bit image
//
data = (unsigned char*) malloc(width * height *sizeof(unsigned char));
// init texture info
for(int row = 0; row < height; row++)
{
for( int col = 0; col < width; col++ )
{
int pos = row*width + col;
if( row % 32==0 || col % 32==0)
{
data[pos] = 255;
}
else data[pos] = 0;
}
}
glBindTexture(GL_TEXTURE_2D, init_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR/*GL_NEAREST*/ );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/* GL_NEAREST*/);
/*
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
*/
//free(data);
}
// create FBO and two textures used for Ping Pong
// attach these two textures to FBO
void InitFBO()
{
// Create FBO
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
// Initialize ping pong texture 1, bind to fbo
glGenTextures(1, &tex[0]);
glBindTexture(GL_TEXTURE_2D, tex[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
// Attach Texture to Framebuffer Color Buffer
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[in_tex], GL_TEXTURE_2D, tex[in_tex], 0);
checkFBOErrors();
// Initialize ping pong texture 2, bind to fbo
glGenTextures(1, &tex[1]);
glBindTexture(GL_TEXTURE_2D, tex[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
// Attach Texture to Framebuffer Color Buffer
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[out_tex], GL_TEXTURE_2D, tex[out_tex], 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
void ReleaseFBO()
{
glDeleteFramebuffersEXT(1, &fbo);
}
void changeSize(int w, int h) {
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;
float ratio = 1.0* w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-width/2, width/2, -height/2, height/2);
// Set the viewport to be the entire window
//glViewport(0, 0, w, h);
// Set the correct perspective.
//gluPerspective(45,ratio,1,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, w, h);
/*
gluLookAt(0.0,0.0,0.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
*/
}
void shaderDraw()
{
glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-width/2, -height/2, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f( width/2, -height/2, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f( width/2, height/2, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-width/2, height/2, 0.0f);
glEnd();
}
// render to buffer
// Do ping pong once: two passes, do convolution along X direction and Y direction
void rendertoBuffer(void)
{
glUseProgramObjectARB(p1);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
//glPushAttrib(GL_VIEWPORT_BIT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-width/2, width/2, -height/2, height/2);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
// bind input texture and draw
glBindTexture(GL_TEXTURE_2D, init_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
// first draw
shaderDraw();
// now we have the render buffer textures
for( int i = 0; i < iter; i++ )
{
// set the draw destination
glDrawBuffer( att_point[out_tex] );
// bind textureIN to smoo_text for shaders
glActiveTexture(GL_TEXTURE0);
int myTexture = glGetUniformLocationARB(p1, "smoo_text");
glUniform1iARB(myTexture, 0);
glBindTexture(GL_TEXTURE_2D, tex[in_tex]);
int textID = glGetUniformLocationARB(p1, "tex_id");
shaderDraw();
// swap in/out index
if( in_tex )
{
in_tex = 0;
out_tex = 1;
glUniform1iARB(textID, out_tex);
}
else
{
in_tex = 1;
out_tex = 0;
glUniform1iARB(textID, out_tex);
}
}
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
//cout<< __FILE__ << __LINE__ <<" IN RENDER TO BUFFER STAGE "<<endl;
glUseProgramObjectARB(0);
}
void renderScene(void)
{
//rendertoBuffer();
glUseProgramObjectARB(p2);
glClearColor(0.0f, 0.0f,0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//
// bind textureIN to smoo_text for shaders
glActiveTexture(GL_TEXTURE1);
//glEnable(GL_TEXTURE_2D);
int myTexture = glGetUniformLocationARB(p2, "imag_text");
glBindTexture(GL_TEXTURE_2D, tex[out_tex]);
glUniform1iARB( myTexture, 1);
//
// draw to screen
shaderDraw();
glDisable(GL_TEXTURE_2D);
glutSwapBuffers();
glUseProgramObjectARB(0);
//cout<<__FILE__<<" "<<__LINE__<<" IN RENDER SCENE"<<endl;
}
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 27)
exit(0);
}
void updateInteration( int key, int x, int y)
{
if( key == GLUT_KEY_PAGE_UP )
{
iter ++;
}
if( key == GLUT_KEY_PAGE_DOWN && iter > 0)
{
iter --;
}
cout<< __FILE__<<" "<<__LINE__<<" current iteration "<< iter<<endl;
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(320,320);
glutCreateWindow("Lighthouse 3D - GLUT Tutorial");
InitGLExtensions();
InitFBO();
initTextures();
setShaders();
rendertoBuffer();
glutReshapeFunc(changeSize);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
//adding here the setting of keyboard processing
glutKeyboardFunc(processNormalKeys);
glutSpecialFunc(updateInteration);
glutMainLoop();
return 0;
}
[/b]
[/b][/QUOTE]