I have a vertex/fragment shader that draws a rectangle performing many calculations based on a texture. (It blends pixels, modifies them, etc). The thing is that each rectangle and the pixels it contains will not change. I only move the entire rectangle(s) around and zoom them.
Is there any way to optimize the fragment shader since the rectangles do not really need to be recomputed?
So, if I understood you correctly you compute those rectangles once and then want to reuse them? This kind of task is solved by rendering to a texture and then use the generated textures further on.
Render to texture is easiest done through Framebuffer Objects.
EDIT: A simple example for using FBO to render to texture
// test_fbo_teapot.cpp
#include <GL/glew.h> // Uses GLEW for extension loading
#include <GL/glut.h> // Uses GLUT as framework
// Check those are on your system for compilation
// and if not please install them.
#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_DRAW_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_DRAW_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_DRAW_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 intermediary()
{
}
void final()
{
static float a=0, b=0, c=0;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0,0, width, height);
glClearColor(1,1,1,1);
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();
intermediary();
final();
glutSwapBuffers();
}
};
Related
I'm trying to render a frame captured on OpenCV using OpenGL (imshow is too slow), however I'm failing to update the texture with each new frame. I know I could use GPU on OpenCV but I just don't want to rebuild it, I also thought it should be pretty easy to render it on OpenGL.
The following is the code I'm working on - It should be pretty straight forward yet I don't know where I'm messing up.
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#include "opencv2/opencv.hpp"
using namespace cv;
void render();
void initFrame();
void createTexture();
GLuint textureId;
GLuint fb;
int width = 400;
int height = 400;
VideoCapture cap;
int main(int argc, char **argv)
{
cap.set(CV_CAP_PROP_FRAME_WIDTH, width);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, height);
if(!cap.open(0))
exit(-1);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(width, height);
glutCreateWindow("Test");
glutDisplayFunc(render);
glutIdleFunc(glutPostRedisplay);
createTexture();
initFrame();
glutMainLoop();
return 0;
}
void createTexture()
{
//create texture id
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, //Type of texture
0, //pyramid level (for mip-mapping) - 0: top level
GL_RGB, //Internal color format to convert to
width, //Image width
height, //Image height
0, //border width in pix (either 1 or 0)
GL_RGB, //Input image format
GL_UNSIGNED_BYTE,// Image data type
0 // image data
);
/*
else if(mat.channels() == 4)
{
glTexImage2D(GL_TEXTURE_2D, //Type of texture
0, //pyramid level (for mip-mapping) - 0: top level
GL_RGBA, //Internal color format to convert to
width, //Image width
height, //Image height
0, //border width in pix (either 1 or 0)
GL_RGBA, //Input image format
GL_UNSIGNED_BYTE,// Image data type
0 // image data
);
}
*/
//free(imgPtr);
//glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
}
void initFrame()
{
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
}
void render()
{
Mat frame;
cap >> frame;
if(frame.empty())
exit(-1);
glTexSubImage2D(textureId,
0,
0,
0,
frame.cols,
frame.rows,
GL_RGB,
GL_UNSIGNED_BYTE,
frame.ptr()
);
glBindTexture(GL_TEXTURE_2D,0);
glFlush();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
glBindFramebuffer(GL_FRAMEBUFFER,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
float cube[][2] = {
{-1, -1},
{ 1, -1},
{ 1, 1},
{-1, 1}
};
float textCor[][2] = {
{0,0},
{1,0},
{1,1},
{0,1}
};
unsigned int faces[] = {1,0,3,2};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 2*sizeof(float), &cube[0][0]);
glTexCoordPointer(2, GL_FLOAT, 2*sizeof(float), &textCor[0][0]);
glCullFace(GL_FRONT);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, faces);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,0);
glFlush();
glutSwapBuffers();
}
I am trying to wrap a texture on a quad.
All I see is a white rectangle:
To load the texture I used freeimage.
I need help in order to fix this very simple demo:
#include <GL/glut.h>
#include <GL/gl.h>
#include <FreeImage.h>
#include <stdio.h>
GLfloat coordinates[] =
{
-0.5, 0.5, 1,
-0.5, -0.5, 0,
0.5, -0.5, 0,
0.5, 0.5, 0
};
GLfloat texCoords[] =
{
0, 1,
0, 0,
1, 0,
1, 1
};
BYTE* data;
FIBITMAP* bitmap;
GLuint texture;
void initGlutCallbacks();
void initGL();
void onReshape(int w, int h);
void display();
FIBITMAP* loadTexture(const char* fileName);
int main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(512, 512);
glutInitWindowPosition(64, 64);
glutCreateWindow("arrays");
initGlutCallbacks();
initGL();
// texture
bitmap = loadTexture("rufol.png");
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
data = FreeImage_GetBits(bitmap);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0,
GL_RGBA8, GL_UNSIGNED_BYTE,
data
);
// enable arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// specifying data for the arrays
glVertexPointer
(
3, GL_FLOAT, 0, coordinates
);
glTexCoordPointer
(
2, GL_FLOAT, 0, texCoords
);
glutMainLoop();
}
void initGlutCallbacks(){
glutReshapeFunc(onReshape);
glutDisplayFunc(display);
}
void initGL(){
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0);
glEnable ( GL_TEXTURE_2D );
}
void onReshape(int w, int h){
}
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTexEnvf(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDrawArrays(GL_QUADS, 0, 4);
glFlush();
glutSwapBuffers();
}
FIBITMAP* loadTexture(const char* fileName){
FIBITMAP *bitmap = FreeImage_Load(FIF_PNG, "rufol.png");
if(bitmap == 0) printf("error loading the image\n");
FIBITMAP *fbitmap = FreeImage_ConvertTo32Bits(bitmap);
FreeImage_Unload(bitmap);
return fbitmap;
}
As you can see I am not even using perspective. Also lighting is not enabled(I don't know if it is required to display textures). I have tested a very similar code but using colors for each vertex instead of texture coordinates and it worked. So I think it might be something wrong when loading the image.
Have you tried using GL_RGBA instead of GL_RGBA8 as second parameter (format)?
I've previously asked how I might be able to display my colour buffer and also save it to disk, and the answer I got was that I should;
Render to a FBO and use glReadPixels() to slurp images out of that instead of the front buffer.
How can I generate a screenshot when glReadPixels is empty?
However, I've read a bit about framebuffers and am still totally confused, so I thought I would ask about how to do this on SO. My code does something like this:
/* Callback handler for window re-paint event */
void display()
{
glClear(GL_COLOR_BUFFER_BIT); //Clear the color buffer
glMatrixMode(GL_MODELVIEW); //To operate on the model-view matrix
// do some rendering
glFlush(); // display
}
when I want to save the image at any point, I run this:
std::unique_ptr<RGBA2D> GrabScreen()
{
//we get the width/height of the screen into this array
GLint screen[4];
//get the width/height of the window
glGetIntegerv(GL_VIEWPORT, screen);
GLint width = screen[2];
GLint height = screen[3];
std::unique_ptr<RGBA2D> pixels(new RGBA2D(height, width * 4));
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels->data());
return std::move(pixels);
}
Note that RGBA2D is a 2D eigen vector object (not important). This all works fine, except that it only saves the image if it is being displayed. I want to be able to run my program on a unix machine without a display. I want to render to an FBO. How do I do this?
Not hand-holding, but I can hopefully point you in the right direction.
You will use glGenFramebuffers and glBindFramebuffer to create and bind a Framebuffer Object (FBO).
Then you have a choice if you want to render to a texture or to a renderbuffer. For your purpose, either one will work. The renderbuffer is easier, IMHO. Use glGenRenderbuffers, glBindRenderbuffer and glRenderbufferStorage to set up your color renderbuffer.
Then you attach your color renderbuffer to the FBO, using glFramebufferRenderbuffer.
If you need a depth buffer, repeat the previous two steps to create and attach another renderbuffer used as the depth buffer for your FBO rendering.
Then do your rendering, and grab the frame with glReadPixels.
All these calls are documented in the man pages at www.opengl.org. If you search for the keywords and some of the function names, you should also be able to find some full code samples.
Recently I had a small discussion on the Wayland devel maillist where I wanted to demonstrate how FBOs don't get updated when the X-Server managing the GPU is not holding the VT. Anyway, for demonstration purposes I hacked a quick and dirty program from various sources I had around, that renders to an FBO in a loop and writes the created picture out to a file. It's not optimized for performance, but does what you're interested in, so I drop the source code here (note that the malloc for the readout buffer misses a paired free, so there's a nongrowing memory leak in there)
// framebuffer continuous dump demonstrator
//
// build:
// c++ -o test_fbo test_fbo.cpp -lm -lGL -lGLU -lglut -lGLEW
#include <GL/glew.h>
#include <GL/glut.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
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 *dumpbuf;
int dumpbuf_fd;
};
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_RGB8,
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_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
GLint red_bits, green_bits, blue_bits, alpha_bits;
glGetIntegerv(GL_RED_BITS, &red_bits);
glGetIntegerv(GL_GREEN_BITS, &green_bits);
glGetIntegerv(GL_BLUE_BITS, &blue_bits);
glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
fprintf(stderr, "FBO format R%dG%dB%dA%d\n",
(int)red_bits,
(int)green_bits,
(int)blue_bits,
(int)alpha_bits );
CHECK_FRAMEBUFFER_STATUS();
dumpbuf_fd = open("/tmp/fbodump.rgb", O_CREAT|O_SYNC|O_RDWR, S_IRUSR|S_IWUSR);
assert(-1 != dumpbuf_fd);
dumpbuf = malloc(fbo_width*fbo_height*3);
assert(dumpbuf);
}
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.);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0,0,fbo_width,fbo_height,GL_RGB,GL_UNSIGNED_BYTE,dumpbuf);
lseek(dumpbuf_fd, SEEK_SET, 0);
write(dumpbuf_fd, dumpbuf, fbo_width*fbo_height*3);
}
void intermediary()
{
}
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();
intermediary();
final();
glutSwapBuffers();
}
}
I'm trying implement tile mapping using openGL and C++.
I found this
tutorial/explanation which I thought was pretty good.
When I compile and run the code in visual studio 2010 it just opens a window and displays a white square.
Maybe my files aren't loading correctly. I've tried the .raw files the website uses as well as my own .png files.
#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
GLuint texture; //the array for our texture
GLuint texture2; //the array for our second texture
int cMap[10][10] = { //our map
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
//function to load the RAW file
GLuint LoadTexture( const char * filename, int width, int height )
{
GLuint texture;
unsigned char * data;
FILE * file;
//The following code will read in our RAW file
file = fopen( filename, “rb” );
if ( file == NULL ) return 0;
data = (unsigned char *)malloc( width * height * 3 );
fread( data, width * height * 3, 1, file );
fclose( file );
glGenTextures( 1, &texture )
glBindTexture( GL_TEXTURE_2D, texture );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
GL_MODULATE ); //set texture environment parameters
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR );
//Here we are setting the parameter to repeat the texture
instead of clamping the texture
//to the edge of our shape.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_REPEAT );
//Generate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, data);
free( data ); //free the texture
return texture; //return whether it was successfull
}
void FreeTexture( GLuint texture )
{
glDeleteTextures( 1, &texture );
}
void drawTiles (void) { //our function to draw the tiles
for (int i = 0; i < 10; i++) //loop through the height of the map
{
for (int j = 0; j < 10; j++) //loop through the width of the map
{
if (cMap[i][j] == 0) //if the map at this position contains a 0
{
glBindTexture( GL_TEXTURE_2D, texture ); //bind our grass texture to our shape
}
else //otherwise
{
glBindTexture( GL_TEXTURE_2D, texture2 ); //bind our dirt texture to our shape
}
glPushMatrix(); //push the matrix so that our translations only affect
this tile
glTranslatef(j, -i, 0); //translate the tile to where it should belong
glBegin (GL_QUADS); //begin drawing our quads
glTexCoord2d(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0); //with our vertices we have to assign a texcoord
glTexCoord2d(1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0); //so that our texture has some points to draw to
glTexCoord2d(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2d(0.0, 1.0);
glVertex3f(0.0, 1.0, 0.0);
glEnd();
glPopMatrix(); //pop the matrix
} //end first loop
} //end second loop
}
void display (void) {
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glEnable( GL_TEXTURE_2D );
glTranslatef(-5, 4, -20); //translate back a bit to view the map correctly
drawTiles(); //draw our tiles
glutSwapBuffers();
}
void reshape (int w, int h) {
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
glMatrixMode (GL_MODELVIEW);
}
int main (int argc, char **argv) {
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (“A basic OpenGL Window“);
glutDisplayFunc (display);
glutIdleFunc (display);
glutReshapeFunc (reshape);
//Load our texture
texture = LoadTexture(“texture.raw”, 256, 256);
texture2 = LoadTexture(“texture2.raw”, 256, 256);
glutMainLoop ();
//Free our texture
FreeTexture(texture);
FreeTexture(texture2);
return 0;
}
Make sure your working directory is what you're assuming it to be.
Or use absolute file names.
Otherwise fopen() will fail because it can't find the file.
I've got a fairly complicated scene with many GL_POINTS that I need to render. The scene will be largely static, so I'd like to render it to a Framebuffer Object and then only update that FBO when my scene actually changes. I'd then like to render the FBO to the screen each frame.
I've found examples that render an FBO into a texture. I've found examples that render an FBO into a RenderBuffer (still not quite sure what that is). I'm not sure what the steps are to achieve this. Do I need to render to a texture and the draw the texture to the screen?
Can you please enumerate the steps (ideally even in pseudocode or actual code) to render my scene to an FBO and then draw that FBO to the screen.
draw() is sufficient for a placeholder for my own drawing functions.
I provide a minimal FBO example just for this
Basically the steps are: Create FBO with depth renderbuffer and color texture attachment. To render to FBO unbind the target texture, bind FBO, render to FBO. Unbind FBO, bind texture, render.
#include <GL/glew.h>
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
void init();
void display();
int const fbo_width = 512;
int const fbo_height = 512;
GLuint fb, color, depth;
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutCreateWindow("FBO test");
glutDisplayFunc(display);
glutIdleFunc(glutPostRedisplay);
glewInit();
init();
glutMainLoop();
return 0;
}
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 */
fputs("Framebuffer Error\n", stderr);
exit(-1);
}
}
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_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
CHECK_FRAMEBUFFER_STATUS();
}
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;
const int win_width = glutGet(GLUT_WINDOW_WIDTH);
const int win_height = glutGet(GLUT_WINDOW_HEIGHT);
const float aspect = (float)win_width/(float)win_height;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0,0, win_width, win_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();
}
Here is alternative example which does not require textures:
// copy framebuffer
if(fboUsed)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboId);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT,
0, 0, screenWidth, screenHeight,
GL_COLOR_BUFFER_BIT,
GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
Replace variables in blit with your own.
Apperently frame buffer 0 is front buffer.
fboId is your frame buffer number.