OpenGL framebuffer: может очистить его, но не может привлечь к нему
на Mac у меня есть настройка OpenGL, которая работает отлично, кроме фреймбуфферов - текстурирования и т. д. Так я знаю, что текстурирование включено, у меня есть действительный контекст и т. д. Все работает безупречно, пока я не попытаюсь создать framebuffer.
Я создал фреймбуффер с glGenFramebuffers, glBindFramebuffer и glFramebufferTexture2D, и glCheckFramebufferStatus возвращает GL_FRAMEBUFFER_COMPLETE. Если я затем позвоню glClear, а затем вызову glGetTexImage, полученные данные показывает, что glClear действовал на текстуры привязаны к фреймбуферу так как надо. Я могу установить glClearColor на все, что хочу, и glClear правильно устанавливает данные текстуры.
но на этом хорошие новости заканчиваются. Я не могу ничего нарисовать в фреймбуффер, использую ли я VBOs или glBegin/glEnd. Данные текстуры из текстуры привязаны к фреймбуферу не тронутое вызовов отрисовки (хотя результаты glClear все-таки появятся). Это все правда, даже если я позову. glFlush и glFinish перед вызовом glGetTexImage. Кроме того, glGetError не возвращает ошибок ни в одном из моих вызовов.
я опубликовал ниже пример кода, который я добавил в соответствующий момент в программе, чтобы попытаться работать над этой проблемой, если это даст кому-нибудь идею. (Это не включает вызов glClear, но я знаю из отдельного тестирования в тот же момент, что это работает нормально).
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbTexID, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
Debugger();
glEnable(GL_TEXTURE_2D);
glCullFace(GL_NONE);
glGenTextures(1,(GLuint*)&tex);
glBindTexture(GL_TEXTURE_2D,tex);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,1024,1024,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1024, 1024, 0, -5000, 5000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, 1024, 1024);
glColor4f(1,1,1,1);
glBegin(GL_TRIANGLES);
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(1024, 0);
glTexCoord2f(0, 1);
glVertex2f(0, 1024);
glEnd();
glFlush();
glFinish();
unsigned char *dd = new unsigned char[1024*1024*4];
glBindTexture(GL_TEXTURE_2D, fbTexID); //I've tried calling glBindFramebuffer(GL_FRAMEBUFFER,0) before this bind - makes no difference
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dd);
delete dd;
4 ответов
ваша текстура не работала, потому что она была связана! У тебя не может быть привязан текстурная работа на FBO в качестве rendertarget! Это то, что не очень документировано, но имеет смысл, когда вы думаете об этом Разработчикам драйверов также нужны некоторые гарантии, на случай, если вы сделаете что-то странное, как чтение и запись в одну и ту же текстуру одновременно
хорошо, ответил на мой собственный вопрос. Похоже, что текстуры можно создавать к поверхности, что буфер кадра рисует, должен быть создан после создается буфер кадров. Итак, это работает:
glGenFramebuffers...
glBindFramebuffer...
glGenTextures...
glBindTexture...
glTexParameterf etc.
glFramebufferTexture2D...
но это не:
glGenTextures...
glBindTexture...
glGenFramebuffers
glBindFramebuffer...
glFramebufferTexture2D...
Я не вижу этого нигде, и это кажется удивительным, но мой код перешел от не работы к работе, просто переместив генерацию текстуры.
Это тест FBO, который я написал некоторое время назад:
#include <GL/glew.h>
#include <GL/glut.h>
#include <cmath>
#include <iostream>
using namespace std;
namespace render
{
int width, height;
float aspect;
void init();
void reshape(int width, int height);
void display();
int const fbo_width = 512;
int const fbo_height = 512;
GLuint fb, color, depth;
};
void idle();
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutCreateWindow("FBO test");
glutDisplayFunc(render::display);
glutReshapeFunc(render::reshape);
glutIdleFunc(idle);
glewInit();
render::init();
glutMainLoop();
return 0;
}
void idle()
{
glutPostRedisplay();
}
void CHECK_FRAMEBUFFER_STATUS()
{
GLenum status;
status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE:
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
/* choose different formats */
break;
default:
/* programming error; will fail on all hardware */
throw "Framebuffer Error";
}
}
namespace render
{
float const light_dir[]={1,1,1,0};
float const light_color[]={1,0.95,0.9,1};
void init()
{
glGenFramebuffers(1, &fb);
glGenTextures(1, &color);
glGenRenderbuffers(1, &depth);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D( GL_TEXTURE_2D,
0,
GL_RGBA,
fbo_width, fbo_height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbo_width, fbo_height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
CHECK_FRAMEBUFFER_STATUS();
}
void reshape(int width, int height)
{
render::width=width;
render::height=height;
aspect=float(width)/float(height);
glutPostRedisplay();
}
void prepare()
{
static float a=0, b=0, c=0;
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0,0,fbo_width, fbo_height);
glClearColor(1,1,1,0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, 1, 1, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glLightfv(GL_LIGHT0, GL_POSITION, light_dir);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
glTranslatef(0,0,-5);
glRotatef(a, 1, 0, 0);
glRotatef(b, 0, 1, 0);
glRotatef(c, 0, 0, 1);
glutSolidTeapot(0.75);
a=fmod(a+0.1, 360.);
b=fmod(b+0.5, 360.);
c=fmod(c+0.25, 360.);
}
void final()
{
static float a=0, b=0, c=0;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0,0, width, height);
glClearColor(1.,1.,1.,0.);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, aspect, 1, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,-5);
glRotatef(b, 0, 1, 0);
b=fmod(b+0.5, 360.);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, color);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING);
float cube[][5]=
{
{-1, -1, -1, 0, 0},
{ 1, -1, -1, 1, 0},
{ 1, 1, -1, 1, 1},
{-1, 1, -1, 0, 1},
{-1, -1, 1, -1, 0},
{ 1, -1, 1, 0, 0},
{ 1, 1, 1, 0, 1},
{-1, 1, 1, -1, 1},
};
unsigned int faces[]=
{
0, 1, 2, 3,
1, 5, 6, 2,
5, 4, 7, 6,
4, 0, 3, 7,
3, 2, 6, 7,
4, 5, 1, 0
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 5*sizeof(float), &cube[0][0]);
glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), &cube[0][3]);
glCullFace(GL_BACK);
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);
glCullFace(GL_FRONT);
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void display()
{
prepare();
final();
glutSwapBuffers();
}
}
возможно, эта ссылка помогает
вот FBO "benchmark" я написал время назад. set_fbo_size()
имеет последовательность создания, которая работает для меня (TM).
/////////////////////////////////////////////////////////////////////////////
// INCLUDES /////////////////////////////////////////////////////////////////
#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
/////////////////////////////////////////////////////////////////////////////
// CLASSES //////////////////////////////////////////////////////////////////
// http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
class ExpAvg
{
public:
ExpAvg(float initial, unsigned int time_periods) : avg(initial), alpha(2.0f / ( time_periods + 1 )) {}
void Update(float nextval) { avg = alpha*nextval + (1.0f-alpha)*avg; }
float Get() { return avg; }
private:
float avg;
float alpha;
};
class gl2D
{
public:
gl2D() {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
gluOrtho2D(0, viewport[2], 0, viewport[3]);
glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
}
~gl2D() {
glMatrixMode(GL_PROJECTION); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glPopMatrix();
}
};
/////////////////////////////////////////////////////////////////////////////
// GLOBALS //////////////////////////////////////////////////////////////////
int screen_width = 1024;
int screen_height = 768;
int mouse_x, mouse_y;
bool mouse_left, mouse_right;
float camera_angle_x = 45;
float camera_angle_y = 45;
float camera_distance = 0;
int texture_width, texture_height;
GLuint tex, fbo, rbo; // object IDs
/////////////////////////////////////////////////////////////////////////////
// UTILITIES ////////////////////////////////////////////////////////////////
bool get_fbo_status()
{
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
cout << "Framebuffer complete." << endl; return true;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
cerr << "[ERROR] Attachment is NOT complete." << endl; return false;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
cerr << "[ERROR] No image is attached to FBO." << endl; return false;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
cerr << "[ERROR] Attached images have different dimensions." << endl; return false;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
cerr << "[ERROR] Color attached images have different internal formats." << endl; return false;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
cerr << "[ERROR] Draw buffer." << endl; return false;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
cerr << "[ERROR] Read buffer." << endl; return false;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
cerr << "[ERROR] Unsupported by FBO implementation." << endl; return false;
default:
cerr << "[ERROR] Unknow error." << endl; return false;
}
}
void gl_print(const char *str, int x, int y, void *font)
{
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING); // need to disable lighting for proper text color
glDisable(GL_TEXTURE_2D);
glRasterPos2i(x, y); // place text position
while(*str) glutBitmapCharacter(font, *str++);
glPopAttrib();
}
void textured_cube()
{
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
// face v0-v1-v2-v3
glNormal3f(0,0,1);
glTexCoord2f(1, 1); glVertex3f(1,1,1);
glTexCoord2f(0, 1); glVertex3f(-1,1,1);
glTexCoord2f(0, 0); glVertex3f(-1,-1,1);
glTexCoord2f(1, 0); glVertex3f(1,-1,1);
// face v0-v3-v4-v5
glNormal3f(1,0,0);
glTexCoord2f(0, 1); glVertex3f(1,1,1);
glTexCoord2f(0, 0); glVertex3f(1,-1,1);
glTexCoord2f(1, 0); glVertex3f(1,-1,-1);
glTexCoord2f(1, 1); glVertex3f(1,1,-1);
// face v0-v5-v6-v1
glNormal3f(0,1,0);
glTexCoord2f(1, 0); glVertex3f(1,1,1);
glTexCoord2f(1, 1); glVertex3f(1,1,-1);
glTexCoord2f(0, 1); glVertex3f(-1,1,-1);
glTexCoord2f(0, 0); glVertex3f(-1,1,1);
// face v1-v6-v7-v2
glNormal3f(-1,0,0);
glTexCoord2f(1, 1); glVertex3f(-1,1,1);
glTexCoord2f(0, 1); glVertex3f(-1,1,-1);
glTexCoord2f(0, 0); glVertex3f(-1,-1,-1);
glTexCoord2f(1, 0); glVertex3f(-1,-1,1);
// face v7-v4-v3-v2
glNormal3f(0,-1,0);
glTexCoord2f(0, 0); glVertex3f(-1,-1,-1);
glTexCoord2f(1, 0); glVertex3f(1,-1,-1);
glTexCoord2f(1, 1); glVertex3f(1,-1,1);
glTexCoord2f(0, 1); glVertex3f(-1,-1,1);
// face v4-v7-v6-v5
glNormal3f(0,0,-1);
glTexCoord2f(0, 0); glVertex3f(1,-1,-1);
glTexCoord2f(1, 0); glVertex3f(-1,-1,-1);
glTexCoord2f(1, 1); glVertex3f(-1,1,-1);
glTexCoord2f(0, 1); glVertex3f(1,1,-1);
glEnd();
}
bool set_fbo_size(int width, int height)
{
int max_size;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
if(width > max_size) return false;
if(height > max_size) return false;
texture_width = width; texture_height = height;
// create FBO
if(fbo) glDeleteFramebuffersEXT(1, &fbo);
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
// create and attach a new texture as the FBO's color buffer
if(tex) glDeleteTextures(1, &tex);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);
// create and attach a new depth buffer to currently bound FBO
if(rbo) glDeleteRenderbuffersEXT(1, &rbo);
glGenRenderbuffersEXT(1, &rbo);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
if( !get_fbo_status() ) exit(1);
return true;
}
/////////////////////////////////////////////////////////////////////////////
// GLUT CALLBACKS ///////////////////////////////////////////////////////////
void CB_Idle()
{
glutPostRedisplay();
}
void CB_Reshape(int width, int height)
{
screen_width = width;
screen_height = height;
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (float)(width)/height, 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void CB_Mouse(int button, int state, int x, int y)
{
mouse_x = x; mouse_y = y;
if(button == GLUT_LEFT_BUTTON)
mouse_left = (state == GLUT_DOWN);
else if(button == GLUT_RIGHT_BUTTON)
mouse_right = (state == GLUT_DOWN);
}
void CB_Motion(int x, int y)
{
if(mouse_left) {
camera_angle_y += (x - mouse_x);
camera_angle_x += (y - mouse_y);
mouse_x = x; mouse_y = y;
}
if(mouse_right) {
camera_distance += (y - mouse_y) * 0.2f;
mouse_y = y;
}
}
void CB_Keyboard(unsigned char key, int x, int y)
{
static int drawMode = 0;
static int tex_size = 0;
bool ret = false;
switch(key) {
case 27: // ESCAPE
exit(0);
break;
case ' ':
while(!ret) {
tex_size = (tex_size+1) % 7;
switch(tex_size) {
case 0: ret = set_fbo_size(128,128); break;
case 1: ret = set_fbo_size(256,256); break;
case 2: ret = set_fbo_size(512,512); break;
case 3: ret = set_fbo_size(1024,1024); break;
case 4: ret = set_fbo_size(2048,2048); break;
case 5: ret = set_fbo_size(4096,4096); break;
case 6: ret = set_fbo_size(8192,8192); break;
default: ; break;
}
}
break;
default:
break;
}
glutPostRedisplay();
}
void CB_Init()
{
GLenum err = glewInit();
if(GLEW_OK != err) {
cerr << "Error: " << glewGetErrorString(err) << endl;
exit(1);
}
if(!GLEW_EXT_framebuffer_object) {
cerr << "Requires EXT_framebuffer_object" << endl;
exit(1);
}
tex = fbo = rbo = 0;
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glClearColor(0, 0, 0, 0);
GLfloat lightKa[] = {.2f, .2f, .2f, 1.0f}; // ambient light
GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f}; // diffuse light
GLfloat lightKs[] = {1, 1, 1, 1}; // specular light
glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);
float lightPos[4] = {0, 0, 20, 1}; // positional light
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glEnable(GL_LIGHT0);
set_fbo_size(128, 128);
}
void CB_Exit()
{
glDeleteTextures(1, &tex);
glDeleteFramebuffersEXT(1, &fbo);
glDeleteRenderbuffersEXT(1, &rbo);
}
void CB_Display()
{
static ExpAvg ft_fbo(0, 19);
static ExpAvg ft_overall(0, 19);
int before = glutGet(GLUT_ELAPSED_TIME);
// compute rotation angle
const float ANGLE_SPEED = 90; // degree/s
float angle = ANGLE_SPEED * (glutGet(GLUT_ELAPSED_TIME) / 1000.0f);
// render using fbo /////////////////////////////////////////////
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // bind fbo
// adjust viewport and projection matrix to texture dimension
glViewport(0, 0, texture_width, texture_height);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(60.0f, (float)(texture_width)/texture_height, 1.0f, 100.0f);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
// clear buffer
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTranslatef(0,0,-3);
glPushMatrix();
glRotatef(angle*0.5f, 1, 0, 0);
glRotatef(angle, 0, 1, 0);
glRotatef(angle*0.7f, 0, 0, 1);
// set up teapot colors
float shininess = 15.0f;
float diffuseColor[3] = {0.929524f, 0.796542f, 0.178823f};
float specularColor[4] = {1.00000f, 0.980392f, 0.549020f, 1.0f};
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); // range 0 ~ 128
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularColor);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glColor3fv(diffuseColor);
glBindTexture(GL_TEXTURE_2D, 0);
glFrontFace(GL_CW);
glutSolidTeapot(1.0);
glFrontFace(GL_CCW);
glPopMatrix();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
glFinish();
ft_fbo.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );
// normal rendering ///////////////////////////////////
// back to normal viewport and projection matrix
glViewport(0, 0, screen_width, screen_height);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(60.0f, (float)(screen_width)/screen_height, 1.0f, 100.0f);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTranslatef(0,0,-4);
glPushMatrix();
glTranslatef(0, 0, camera_distance);
glRotatef(camera_angle_x, 1, 0, 0);
glRotatef(camera_angle_y, 0, 1, 0);
// draw a cube with the dynamic texture
glBindTexture(GL_TEXTURE_2D, tex);
textured_cube();
glPopMatrix();
{
gl2D two_dee; // set 2D mode
glDisable(GL_DEPTH_TEST);
stringstream ss;
glColor3f(1,1,0);
ss << fixed << setprecision(3);
int pos = 1;
ss.str(""); ss << "Texture size: " << texture_width << "x" << texture_height;
gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
ss.str(""); ss << "Overall frame time: " << ft_overall.Get() << " ms";
gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
ss.str(""); ss << " FBO frame time: " << ft_fbo.Get() << " ms";
gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
ss.str(""); ss << "Press space to change texture size; mouse moves/zooms cube";
gl_print(ss.str().c_str(), 10, 10, GLUT_BITMAP_8_BY_13);
glEnable(GL_DEPTH_TEST);
}
glutSwapBuffers();
ft_overall.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );
}
/////////////////////////////////////////////////////////////////////////////
// MAIN /////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(screen_width, screen_height);
glutInitWindowPosition(100, 100);
glutCreateWindow("FBO Test");
glutDisplayFunc(CB_Display);
glutIdleFunc(CB_Idle);
glutReshapeFunc(CB_Reshape);
glutKeyboardFunc(CB_Keyboard);
glutMouseFunc(CB_Mouse);
glutMotionFunc(CB_Motion);
atexit(CB_Exit);
CB_Init();
glutMainLoop();
return 0;
}