Flickering 2D Texture using GLUT and C - c

I'm trying my hand at making a chip8 emulator using just plain C. I got most of the opcodes set so I just need to work on the display. I decided on using GLUT for the display since it appeared quick setup. The main idea is to display the chip8 sprites onto the 2D texture. I got it to display some digits though some opcode execution but it's flickering. I'm using double buffering since from what I read it's the best way to make sure something is ready to be displayed but I'm still getting flickering. Any ideas on what can cause it?
Here's all the code for OpenGL and GLUT for the display.
int main(int argc, char * argv[]) {
// if(argc < 2){
// printf("Usage: %s <bin file>\n", argv[0]);
// exit(0);
// }
//initialize chip 8
chip8_Init();
//load file if exists
chip8_load("test6.bin");
//setup graphics
glutInit(&argc, argv);
glutInitWindowSize(display_width, display_height);
glutInitWindowPosition(320, 320);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
glutCreateWindow("Chip8 GL");
setupTexture();
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
glutKeyboardFunc(chip8_keypad);
glutKeyboardUpFunc(chip8_keypadUp);
glutMainLoop();
return 0;
}
void setupTexture(){
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
//set texture parameters
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_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
//update texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
screenData);
}
void updateTexture(){ //display()
//update pixels
for (int i = 0; i < SCREEN_HEIGHT; i++) {
for (int j = 0; j < SCREEN_WIDTH; j++) {
if(chip8.gfx[(i * SCREEN_WIDTH)+j] == 0){
screenData[i][j][0] = 0;
screenData[i][j][1] = 0;
screenData[i][j][2] = 0;
}
else{
screenData[i][j][0] = 255;
screenData[i][j][1] = 255;
screenData[i][j][2] = 255;
}
}
}
//update texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
screenData);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, texName);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2d(0.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex2d(display_width, 0.0);
glTexCoord2f(1.0, 1.0); glVertex2d(display_width, display_height);
glTexCoord2f(0.0, 1.0); glVertex2d(0.0, display_height);
glEnd();
glutSwapBuffers();
}
void renderScene(){
chip8_emulateCycle();
if(drawFlag == 1){
updateTexture();
drawFlag = 0;
}
}
void changeSize(int w, int h){
glClearColor(0.0f, 0.0f, 0.5f, 0.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, w, h);
// Resize quad
display_width = w;
display_height = h;
}
Edit: I might have figured it out. In the draw opcode, it uses XOR. So when the draw command for the first time the sprite is displayed and when called again it disappears and so on so forth.

My opengl is very dusty, but I saw some points in your code:
You should enable GL_TEXTURE_2D before initialize it:
void setupTexture()
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* enable texturing */
glEnable(GL_TEXTURE_2D);
/* create texture */
glGenTextures(1, &texName);
/* select texture */
glBindTexture(GL_TEXTURE_2D, texName);
/* select behavior */
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
/* ... */
}
You should select the texture before modifying it
void updateTexture(){
/* update pixels */
/* ... */
/*select texture */
glBindTexture(GL_TEXTURE_2D, texName);
/*update texture */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
screenData);
/* clear screen */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* draw texture */
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2d(0.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex2d(display_width, 0.0);
glTexCoord2f(1.0, 1.0); glVertex2d(display_width, display_height);
glTexCoord2f(0.0, 1.0); glVertex2d(0.0, display_height);
glEnd();
glutSwapBuffers();
}
Moreover, you may test for the result of called functions, by using glGetError():
void check_for_error(void)
{
GLenum err = glGetError();
if (GL_NO_ERROR != err)
{
fprintf("Error %d\n", err);
exit(EXIT_FAILURE);
}
}
Said that, I don't know the data inside chip8.gfx[], may be they are not as you expect.

Related

How to switch between textures/framebuffers on keypress using GLUT?

I have two buffers with .rgb images loaded. Original image is stored in frame_buffer and second one is stored in temp_buffer. I want to switch between those two images in GLUT window, when user press a button, how can I extend my code to do this?
typedef struct pixel{
GLbyte r;
GLbyte g;
GLbyte b;
}Pixel;
Pixel frame_buffer[WIDTH][HEIGHT]; //original image
Pixel temp_buffer[WIDTH][HEIGHT]; //embossed image
GLuint texture;
int window_id;
void keyboardFunction(unsigned char button, int x, int y){
switch(button){
case 'S':
case 's':
// WHEN USER PRESS 'S', NEW IMAGE FROM temp_buffer IS
// LOADED, HOW CAN I DO THIS?
break;
default:
break;
}
glutPostRedisplay();
}
// Initialize OpenGL state
void init() {
// Texture setup
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// Other
glClearColor(0, 0, 0, 0);
gluOrtho2D(-1, 1, -1, 1);
glLoadIdentity();
glColor3f(1, 1, 1);
loadInputFromUser();
emboss();
}
void display() {
// Copy frame_buffer to texture memory
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, frame_buffer);
// Clear screen buffer
glClear(GL_COLOR_BUFFER_BIT);
// Render a quad
glBegin(GL_QUADS);
glTexCoord2f(1, 0); glVertex2f(1, 1);
glTexCoord2f(1, 1); glVertex2f(1, -1);
glTexCoord2f(0, 1); glVertex2f(-1, -1);
glTexCoord2f(0, 0); glVertex2f(-1, 1);
glEnd();
// Display result
glFlush();
//glutPostRedisplay();
glutSwapBuffers();
}
// Main entry function
int main(int argc, char **argv) {
// Init GLUT
glutInit(&argc, argv);
glutInitWindowPosition(-1, -1);
glutInitWindowSize(WIDTH, HEIGHT);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutCreateWindow("Convolution Filter");
// Set up OpenGL state
init();
// Run the control loop
glutDisplayFunc(display);
glutKeyboardFunc(keyboardFunction);
glutReshapeFunc(changeViewPoint);
GLenum err = glewInit();
if (GLEW_OK != err){
fprintf(stderr, "GLEW error");
return 1;
}
glutMainLoop();
return EXIT_SUCCESS;
}
original image stored in frame_buffer
image filtered with emboss stored in temp_buffer (yeah I know its not perfect :D )
I want to switch between them with keybutton.
Edit the following snippets:
Pixel frame_buffer[WIDTH][HEIGHT]; //original image
Pixel temp_buffer[WIDTH][HEIGHT]; //embossed image
int which_image = 0;
...
case 'S':
case 's':
which_image ^= 1;
break;
...
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, which_image == 0 ? frame_buffer : temp_buffer);
...
glFlush();
glutPostRedisplay();
glutSwapBuffers();
That being said, you currently upload the texture (glTexImage2D) for each frame drawn. You should rather upload it only once during startup and each time it changes.

OpenGL C++ order for using a vertex buffer and a texture buffer

I'm having issues loading a texture onto my triangle strips. I'm following Anton Gerdelan's tutorial, and after failing with my main program, I went back to the basics and just tried to make a plain square and put his texture on it (the skull and crossbones).
I completely copy and pasted code from his "Hello Triangle" page, which worked, but once trying to fit in code from his texture tutorial above (and changing the triangle to a square), all I'm getting is a big white square with no texture.
I've checked the status of my shaders with glGetShaderiv() and they returned positive, I checked the image I loaded to see if the pixel data was sensible, so I believe my error is in declaring my VBOs, or the order/parameters in which I'm using them.
Here's the complete code which I copied, which compiles fine in Visual Studio 2013, except the output isn't what is expected.
I am using the static libraries of GLEW and GLFW, along with the STBI Image header
#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GL/glfw3.h> // GLFW helper library
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
const char* vertex_shader =
"#version 400\n"
"in vec3 vp;"
"layout (location=1) in vec2 vt; // per-vertex texture co-ords"
"out vec2 texture_coordinates; "
"void main () {"
" gl_Position = vec4 (vp, 1.0);"
" texture_coordinates = vt; "
"}";
const char* fragment_shader =
"#version 400\n"
"in vec2 texture_coordinates;"
"uniform sampler2D basic_texture;"
"out vec4 frag_colour;"
"void main () {"
"vec4 texel = texture(basic_texture, texture_coordinates);"
"frag_colour = texel; "
"}";
float points[] = {
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f
};
float texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0
};
GLFWwindow* window;
unsigned int vt_vbo;
unsigned int tex = 0;
GLuint vao = 0;
GLuint vbo = 0;
GLuint shader_programme;
void initializeGL(){
// start GL context and O/S window using the GLFW helper library
if (!glfwInit()) {
printf("ERROR: could not start GLFW3\n");
return;
}
window = glfwCreateWindow(640, 480, "Texture Test", NULL, NULL);
if (!window) {
printf("ERROR: could not open window with GLFW3\n");
glfwTerminate();
return;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// get version info
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
const GLubyte* version = glGetString(GL_VERSION); // version as a string
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n", version);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
}
void startShaders(){
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
shader_programme = glCreateProgram();
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
GLint vsstat;
glGetShaderiv(vs, GL_COMPILE_STATUS, &vsstat);
GLint fsstat;
glGetShaderiv(fs, GL_COMPILE_STATUS, &fsstat);
printf("%i\n%i\n", vsstat, fsstat);
}
void loadImage(){
int x, y, n;
int force_channels = 4;
unsigned char* image_data = stbi_load("skulluvmap.png", &x, &y, &n, force_channels);
if (!image_data) {
printf("ERROR: could not load %s\n", "skulluvmap.png");
}
int width_in_bytes = x * 4;
unsigned char *top = NULL;
unsigned char *bottom = NULL;
unsigned char temp = 0;
int half_height = y / 2;
for (int row = 0; row < half_height; row++) {
top = image_data + row * width_in_bytes;
bottom = image_data + (y - row - 1) * width_in_bytes;
for (int col = 0; col < width_in_bytes; col++) {
temp = *top;
*top = *bottom;
*bottom = temp;
top++;
bottom++;
}
}
printf("first 4 bytes are: %i %i %i %i\n",
image_data[0], image_data[1], image_data[2], image_data[3]
);
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void generateBuffers(){
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0); // don't forget this!
glGenBuffers(1, &vt_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), texcoords, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1); // don't forget this!
}
void mainLoop(){
while (!glfwWindowShouldClose(window)) {
// wipe the drawing surface clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int tex_loc = glGetUniformLocation(shader_programme, "basic_texture");
glUseProgram(shader_programme);
glUniform1i(tex_loc, 0); // use active texture 0
// draw points 0-4 from the currently bound VAO with current in-use shader
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// update other events like input handling
glfwPollEvents();
// put the stuff we've been drawing onto the display
glfwSwapBuffers(window);
}
}
int main() {
initializeGL();
startShaders();
loadImage();
generateBuffers();
mainLoop();
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
You're misusing your second buffer which is supposed to be the buffer with texcoords. So what you really want to achieve is having a pair of texture coordinates for every vertex. It means that you texcoords array should in fact store 4 pairs because you have 4 triples in the points array. So that's the first fix. You probably want it to look like:
float texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0, 0.0,
1.0, 1.0,
};
Then in the generateBuffers, your vt_vbo is wrong. The data should be passed this way:
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), texcoords, GL_STATIC_DRAW);
because you only want to pass 8 values there. 2 texcoords for each vertex.
Edit:
This however, doesn't fully explain why your texture doesn't appear at all. I primarily thought that there might be a problem with your texcoords pointer but it doesn't seem to be the case.

glClear: RAM usage slighty increasing

Following is my little opengl program, just drawing a triangle. There is an glitch, the RAM is slightly increasing by about 10K per second the moment i add the glClear() function. Why is that so?
int screenwidth=537, screenheight=716;
GLFWwindow* window;
if (!glfwInit()) return -1;
window = glfwCreateWindow(screenwidth, screenheight, "Test", NULL, NULL);
if(!window){glfwTerminate(); return -1;}
glfwMakeContextCurrent(window);
//Setting up the OpenGL Context
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, screenwidth, screenheight, 0, 0, 1);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(1,0.9176f,0.1259f,1);
//The rendering loop
while (!glfwWindowShouldClose(window)){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLES);
glVertex2f(0, 0);
glVertex2f(.5f, .5f);
glVertex2f(0, .5f);
glEnd();
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){
glfwSetWindowShouldClose(window, GL_TRUE);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
Example: https://www.youtube.com/watch?v=MOxyaxuTsyI

opengl render to texture just see a black region

I am having some trouble in OpenGL, making a render to texture example work. At initialization, i generate a texture 'randtex' with random values of green and black. If i render this texture directly to the window (mapped into a quad) it works all well.
like this:
But if i render 'randtex' into another texture 'tex' which is attached to a framebuffer object, then rendering 'tex' on the screen just gives me a black image on the fbo's blue background and from what i know it should give me the original texture over the blue background. In other words, this is what i am getting
vertex shader for display only (display_shaderp).
#version 420
in vec4 pos;
in vec2 tex_coord;
out vec2 vtex_coord;
uniform mat4 projection;
uniform mat4 modelview;
void main(){
gl_Position = projection * modelview * pos;
vtex_coord = tex_coord;
}
fragment shader for display only (display_shaderp)
#version 420
in vec2 vtex_coord;
uniform sampler2D tex;
out vec4 color;
void main(){
color = texture2D(tex, vtex_coord);
//color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}
shader program compiles and links ok, i get no gl errors and framebuffer is complete without errors too.
This is the rendering code:
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, win_width, win_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (GLfloat)win_width / (GLfloat) win_height, 0.1f, 50.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslate3f(0.0f, 0.0f, -3.0f)
// render to texture
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0,0, win_width, win_height);
glClearColor(0.0, 0.0, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(fbo_shaderp);
GLfloat m_matrix[16], p_matrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, m_matrix);
glGetFloatv(GL_PROJECTION_MATRIX, p_matrix);
glUniformMatrix4fv(glGetUniformLocation(fbo_shaderp, "modelview"),1,GL_FALSE,m_matrix);
glUniformMatrix4fv(glGetUniformLocation(fbo_shaderp, "projection"),1,GL_FALSE,p_matrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, randtex);
glUniform1i(glGetUniformLocation(fbo_shaderp, "tex"), randtex);
GLuint _p = glGetAttribLocation(fbo_shaderp, "pos");
GLuint _t = glGetAttribLocation(fbo_shaderp, "tex_coord");
glVertexAttribPointer(_p, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
glVertexAttribPointer(_t, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(sizeof(float)*3));
glEnableVertexAttribArray(_p);
glEnableVertexAttribArray(_t);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// render to the window
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0,0, win_width, win_height);
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(display_shaderp);
glUniformMatrix4fv(glGetUniformLocation(display_shaderp,"modelview"),1,GL_FALSE,m_matrix);
glUniformMatrix4fv(glGetUniformLocation(display_shaderp,"projection"),1,GL_FALSE,p_matrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(glGetUniformLocation(display_shaderp, "tex"), 0);
GLuint _p = glGetAttribLocation(display_shaderp, "pos");
GLuint _t = glGetAttribLocation(display_shaderp, "tex_coord");
glVertexAttribPointer ( _p, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0 );
glVertexAttribPointer ( _t, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*) (sizeof(float) * 3) );
glEnableVertexAttribArray(_p);
glEnableVertexAttribArray(_t);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glUseProgram(0);
And the code to create textures and framebuffer
int i = 0;
// create a random texture 'randtex'
glGenTextures(1, &randtex);
glBindTexture(GL_TEXTURE_2D, randtex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// random data
GLubyte* data = (GLubyte *) malloc(width*height*4*sizeof(GLubyte));
GLubyte val;
for (i = 0; i < width * height * 4; i+=4){
if ((double)rand()/(double)RAND_MAX > 0.8)
val = 255;
else
val = 0;
data[i] = 0;
data[i+1] = val;
data[i+2] = 0;
data[i+3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,GL_UNSIGNED_BYTE, data);
// create an empty texture 'tex'
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,GL_UNSIGNED_BYTE, 0);
// create framebuffer and attach 'tex'
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, tex, 0);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
fprintf(stderr, "glCheckFramebufferStatus: error %p", status);
shaders for render to texture (fbo_shaderp)
render to texture vertex shader
in vec4 pos;
in vec2 tex_coord;
out vec2 vtex_coord;
uniform mat4 projection;
uniform mat4 modelview;
void main(){
gl_Position = projection * modelview * pos;
vtex_coord = tex_coord;
}
render to texture fragment shader
#version 420
in vec2 vtex_coord;
layout(location = 0) out vec4 color;
uniform sampler2D tex;
void main(){
color = texture2D(tex, vtex_coord);
//color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}
In this last shader, if i use the commented line to paint all white and comment out the
texture one, i do get a white image but also opengl error right after rendering to texture "OpenGL Error: invalid value", so this actually confuses me more.
glUniform1i(glGetUniformLocation(fbo_shaderp, "tex"), randtex);
You must not give the ID of the texture, but the slot you bind the texture to. So in your case, that should be
glUniform1i(glGetUniformLocation(fbo_shaderp, "tex"), 0);

Texture mapping in OpenGL (with SOIL)

I'm having trouble getting a texture loaded with SOIL to show up properly on this quad. In case it's not clear, I'm just writing up a little 2D sprite engine, and this is the rendering portion (needs a bit of optimization without a doubt). I haven't done any OpenGL in a couple months, and I'm admittedly quite rusty.
#include <OpenGL/OpenGL.h>
#include <GLUT/GLUT.h>
#include "SOIL.h"
#include <stdio.h>
GLuint linktex;
void drawSprite(GLint left, GLint right, GLint bottom, GLint top, GLuint texture){
//Draw clockwise
glColor3f(1.0, 1.0, 1.0);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glTexCoord2i(1,1); glVertex2i(right , top);
glTexCoord2i(1,0); glVertex2i(right , bottom);
glTexCoord2i(0,0); glVertex2i(left , bottom);
glTexCoord2i(0,1); glVertex2i(left , top);
glEnd();
}
void display(void){
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glOrtho(0.0, 240.0, 0.0, 160.0, -1.0, 1.0);
drawSprite(50, 82, 50, 82, linktex);
glFlush();
}
void reshape(int w, int h){
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
void init(){
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glFrontFace(GL_CW);
GLuint linktex = SOIL_load_OGL_texture(
"link.png",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_INVERT_Y
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
if( 0 == linktex )
{
printf( "SOIL loading error: '%s'\n", SOIL_last_result());
}
}
int main (int argc, char **argv) {
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE);
glutInitWindowSize (240, 160);
glutInitWindowPosition (100, 100);
glutCreateWindow ("Test");
glutDisplayFunc (display);
glutReshapeFunc (reshape);
glutMainLoop();
init();
return 0;
}
It looks like when you are loading the texture, you are assigning the id to a local variable linktex instead of the global you declared at the beginning of the file.
When you reference linktex in the void display(void); method, the texture is un-initialized.
Try changing your call to load the texture to :
// comment out the type declaration, to assign to the global instead of a local
/*GLuint*/ linktex = SOIL_load_OGL_texture(
"link.png",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_INVERT_Y
);

Resources