I've already constructed a 15x15 grid of cubes with glutSolidCube(). Then i have a menu handler in which when I click "Start Game", loads the texture I used to all of the cubes, calling a custom glutSolidCube and having glTexCoord2d before each declaration of vertices, cause we can't have textures on the latter I think. For uploading the texture from an image, I'm using a STB_IMAGE_IMPLEMENTATION implementation having also a header file included. The function loadTextureFromFile(const char *filename) does the loading part.
How can I upload more textures (I want 2 more, in the same loadTextureFromFile() function preferably) and how to handle each texture with the glTexCoord2d()?
Here's my entire code:
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h> // openGL header
#include <GL/glu.h> // glut header
#include <GL/glut.h> // glut header
#define STB_IMAGE_IMPLEMENTATION
/////////////////////////////////////Textures==============================================/////////////////////////////////////
#include "stb_image.h"
GLuint texture; //the array for our texture
void loadTextureFromFile(const char *filename)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
//glShadeModel(GL_FLAT);
//glEnable(GL_DEPTH_TEST);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// set the texture wrapping/filtering options (on the currently bound texture object)
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load and generate the texture
int width, height, nrChannels;
unsigned char *data = stbi_load("paper.bmp", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
//glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
}
void FreeTexture(GLuint texture)
{
glDeleteTextures(1, &texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void
drawBox(GLfloat size, GLenum type)
{
static GLfloat n[6][3] =
{
{-1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{1.0, 0.0, 0.0},
{0.0, -1.0, 0.0},
{0.0, 0.0, 1.0},
{0.0, 0.0, -1.0}
};
static GLint faces[6][4] =
{
{0, 1, 2, 3},
{3, 2, 6, 7},
{7, 6, 5, 4},
{4, 5, 1, 0},
{5, 6, 2, 1},
{7, 4, 0, 3}
};
GLfloat v[8][3];
GLint i;
v[0][0] = v[1][0] = v[2][0] = v[3][0] = -size / 2;
v[4][0] = v[5][0] = v[6][0] = v[7][0] = size / 2;
v[0][1] = v[1][1] = v[4][1] = v[5][1] = -size / 2;
v[2][1] = v[3][1] = v[6][1] = v[7][1] = size / 2;
v[0][2] = v[3][2] = v[4][2] = v[7][2] = -size / 2;
v[1][2] = v[2][2] = v[5][2] = v[6][2] = size / 2;
for (i = 5; i >= 0; i--) {
glBegin(type);
glNormal3fv(&n[i][0]);
glTexCoord2d(0.0,0.0);
glVertex3fv(&v[faces[i][0]][0]);
glTexCoord2d(0.0,1.0);
glVertex3fv(&v[faces[i][1]][0]);
glTexCoord2d(1.0,1.0);
glVertex3fv(&v[faces[i][2]][0]);
glTexCoord2d(1.0,0.0);
glVertex3fv(&v[faces[i][3]][0]);
glEnd();
}
}
void APIENTRY
myglutSolidCube(GLdouble size)
{
drawBox(size, GL_QUADS);
}
//int red_color[]={255,0,0};
//int blue_colot[]={0,0,255};
//////////////////////////////=========MENU============/////////////
enum MENU_TYPE //menu options-values
{
MENU_START,
MENU_EXIT,
};
//create the menu - Prototype
void my_createmenu(void);
// Menu handling function declaration - Prototype
void menu(int);
void init()
{ //for 3d lighting
glEnable(GL_DEPTH_TEST); //depth test
glEnable(GL_LIGHTING); //enable light from a single source
glEnable(GL_LIGHT0); //enable white light , diffuse and specular components
glEnable(GL_COLOR_MATERIAL); //track the current color
}
void display()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Black and opaque
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//define the projection matrix just once and use the modelview matrix all other times
glMatrixMode(GL_PROJECTION); //Applies subsequent matrix operations to the projection matrix stack
glLoadIdentity();//Reset
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport); //The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height
double aspect = (double)viewport[2] / (double)viewport[3]; // y/width would be 1.0
gluPerspective(60,aspect, 1, 100); //using perspective projection
//gluOrtho2D(0.0,600.0,-60.0,600.0);
glMatrixMode(GL_MODELVIEW); //for trasformations - Applies subsequent matrix operations to the texture matrix stack
glLoadIdentity();
// move back a bit for viewer , cause of gluPerspective
glTranslatef( 0, 0, -35 );
float e=0,f=0;
//construct the grid with reference the central cube
for(int i=0;i<8;i++) {
for(int j=0;j<8;j++) {
glPushMatrix();
glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
glColor3ub(245, 245, 220); //Beige
glutSolidCube(2.25);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
glColor3ub(245, 245, 220); //Beige
glutSolidCube(2.25);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
glColor3ub(245, 245, 220); //Beige
glutSolidCube(2.25);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
glColor3ub(245, 245, 220); //Beige
glutSolidCube(2.25);
glPopMatrix();
f += -2.63;
}
f=0;
e+=2.63;
}
glutSwapBuffers(); //implicit glFlush
}
//for the second part of program
void display_game()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Black and opaque
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//define the projection matrix just once and use the modelview matrix all other times
glMatrixMode(GL_PROJECTION); //Applies subsequent matrix operations to the projection matrix stack
glLoadIdentity();//Reset
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport); //The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height
double aspect = (double)viewport[2] / (double)viewport[3]; // y/width would be 1.0
gluPerspective(60,aspect, 1, 100); //using perspective projection
//glOrtho(0.0f, 600.0f, 600.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW); //for trasformations - Applies subsequent matrix operations to the texture matrix stack
glLoadIdentity();
// move back a bit for viewer , cause of gluPerspective
glTranslatef( 0, 0, -35 );
float e=0,f=0;
glEnable(GL_TEXTURE_2D);
//construct the grid with reference the central cube
for(int i=0;i<8;i++) {
for(int j=0;j<8;j++) {
glPushMatrix();
glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
//glColor3ub(245, 245, 220); //Beige
//glColor3ub( rand()%255,rand()%255, rand()%255 );
myglutSolidCube(2.25);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
//glColor3ub( rand()%255,rand()%255, rand()%255 );
myglutSolidCube(2.25);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
myglutSolidCube(2.25);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
myglutSolidCube(2.25);
glPopMatrix();
f += -2.63;
}
f=0;
e+=2.63;
}
//SEED to some constant value for 2nd part of the program. If it is not used , cubes would change color in runtime
//srand(0x98765432);
glutSwapBuffers(); //implicit glFlush
glDisable(GL_TEXTURE_2D);
}
void reshape(GLsizei width, GLsizei height) {
// GLsizei for non-negative integer // Compute aspect ratio of the new window
if (height == 0) height = 1; // To prevent divide by 0
GLfloat aspect = (GLfloat)width / (GLfloat)height; // Set the viewport to cover the new window
glViewport(0, 0, width, height); // Set the aspect ratio of the clipping volume glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity(); // Reset // Enable perspective projection with fovy, aspect, zNear and zFar
gluPerspective(45.0f, aspect, 0.1f, 100.0f);
}
void timer(int extra)
{
glutPostRedisplay();
glutTimerFunc(16, timer, 0);
}
void mouseEscape( int button, int state, int x, int y )
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN &&button==MENU_EXIT)
{
int windowID = glutCreateWindow("CUBES");
glutDestroyWindow(windowID);
exit(0);
}
glutPostRedisplay();
}
//for loading the texture
const char* filename = "salt_on_spoon.bmp";
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(600,600);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE| GLUT_MULTISAMPLE);
glEnable(GL_MULTISAMPLE); //anti-alliasing
glutCreateWindow("CUBES");
//create and handle the menu
my_createmenu();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutTimerFunc(0, timer, 0);
init();
//glEnable(GL_TEXTURE_2D); //for texture
//glutMouseFunc(mouseEscape);
//glutKeyboardFunc(keyEscape);
//Load our texture
//loadTextureFromFile(filename);
glutMainLoop();
//Free our texture
//FreeTexture(texture);
return 0;
}
//create the menu-entries
void my_createmenu(void) {
// Create a menu
glutCreateMenu(menu);
// Add menu items
glutAddMenuEntry("Start Game", MENU_START);
glutAddMenuEntry("Exit", MENU_EXIT);
// Associate a mouse button with menu
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
// Menu handling function-what to do in each value
void menu(int item)
{
switch (item)
{
case MENU_START: {
//glEnable(GL_TEXTURE_2D); //for texture
//Load our texture
loadTextureFromFile(filename);
glutDisplayFunc(display_game);
}
break;
case MENU_EXIT:
{
int windowID = glutCreateWindow("CUBES"); //exit game
glutDestroyWindow(windowID);
exit(0);
}
break;
default:
{ /* Nothing */ }
break;
}
glutPostRedisplay();
return;
}
I'm doing the texture loading part in the menu function. How will I be able to handle three textures? The ultimate goal is to make a rand call also for the three textures to be rendered on the cubes.
I also have two pictures: 1st: when the program begins:
2nd: after clicking "Star Game" where you can see the texture rendered in all of the cubes:
The goal is for more 2 types of textures and all of them render in random cubes.
You can create more than 1 texture object.
glBindTexture binds a named texture to a texturing target, that is a global state. glTexImage2D specify a two-dimensional texture image for the texture, which is currently bound to the specified target. glTexParameter set parameter to the texture object.
I recommend to write a function which loads a texture form a file to a given texture object (name id):
void loadTextureFromFile(const char *filename, unsigned int texture)
{
glBindTexture(GL_TEXTURE_2D, texture);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load and generate the texture
int width, height, nrChannels;
unsigned char *data = stbi_load(filename, &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, data);
//glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
}
const char* filename1 = "salt_on_spoon.bmp";
const char* filename2 = ...;
const char* filename3 = ...;
unsigned int tob[3];
int main(int argc, char **argv)
{
// [...]
glGenTextures(3, &tob[0]);
loadTextureFromFile(filename1, tob[0]);
loadTextureFromFile(filename2, tob[1]);
loadTextureFromFile(filename3, tob[2]);
// [...]
}
When two-dimensional texturing is enabled, then the image of the texture object, which is currently bound to the target GL_TEXTURE_2D is wrapped on the mesh.
You've to bind the proper texture object, before you draw the geometry. e.g:
for(int i=0;i<8;i++) {
for(int j=0;j<8;j++) {
glBindTexture(GL_TEXTURE_2D, tob[0]);
glPushMatrix();
glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
myglutSolidCube(2.25);
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, tob[1]);
glPushMatrix();
glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
myglutSolidCube(2.25);
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, tob[2]);
glPushMatrix();
glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
myglutSolidCube(2.25);
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, tob[0]);
glPushMatrix();
glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up
glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
myglutSolidCube(2.25);
glPopMatrix();
f += -2.63;
}
f=0;
e+=2.63;
}
Note, the distribution of the textures is just an example. You've to ensure that unsigned int tob[3]; is declared before, in global namespace.
Related
I have created a rotating wired sphere. I have done textures to a cube but sphere seems to be a problem.
I want to add world map as a texture to this sphere. Any suggestions?
#include <iostream>
#include <stdlib.h>
#include <GL/glut.h>
#include <thread>
#include <chrono>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
using namespace std;
GLuint texture;
int start = 1;
GLfloat xRotated, yRotated, zRotated;
GLdouble radius = 1;
void init() {
glOrtho(-1000 / 2, 1000 / 2, -1000 / 2, 1000 / 2, -500, 500);
}
GLuint glInitTexture(char* filename)
{
GLuint t = 0;
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
unsigned char* data = stbi_load(filename, &width, &height, &nrChannels, 0);
glGenTextures(1, &t);
glBindTexture(GL_TEXTURE_2D, t);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
//unsigned char data[] = { 255, 0, 0, 255 };
if (data)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
else
std::cout << "fail";
return t;
}
void drawImage(GLuint file, float x, float y, float w, float h)
{
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glPushMatrix();
//glTranslatef(x, y, 0.0);
//glRotatef(angle, 0.0, 0.0, 1.0);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, file);
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -4.5);
glRotatef(yRotated, 0.0, 1.0, 0.0);
glEnable(GL_TEXTURE_2D);
GLUquadric *qobj = gluNewQuadric();
gluQuadricTexture(qobj, GL_TRUE);
gluSphere(qobj, radius, 20, 20);
gluDeleteQuadric(qobj);
glDisable(GL_TEXTURE_2D);
glFlush();
yRotated += 0.01;
//glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
//Plots points of both graphs together
//Displays map on screen
void drawMap() {
std::cout << "\nDraw map\n";
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
const double w = glutGet(GLUT_WINDOW_WIDTH);
const double h = glutGet(GLUT_WINDOW_HEIGHT);
gluPerspective(90.0, w / h, 0.1, 1000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -15);
for (int i = 0; i < 10000; i++) {
glClear(GL_DEPTH_BUFFER_BIT);
drawImage(texture, 0, 0, 100, 200);
//std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
glutSwapBuffers();
glEnd();
glFlush();
}
void render()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
//glFlush();
glPointSize(5);
glColor3f(1, 1, 1);
glBegin(GL_LINES);
glVertex3f(-450, -450, 10);
glVertex3f(-450, -250, 10);
glEnd();
glBegin(GL_LINES);
glVertex3f(-450, -450, 10);
glVertex3f(-250, -450, 10);
glEnd();
drawMap();
//plotPoints();
glFlush();
}
void Kbevent(unsigned char key, int x, int y) {
if (key == 's') {
start = start % 2;
glutPostRedisplay();
}
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(1560, 810);
glutCreateWindow("Applying Textures");
init();
xRotated = yRotated = zRotated = 30.0;
xRotated = 33;
yRotated = 40;
char fn[] = "map.jpg";
texture = glInitTexture(fn);
glutDisplayFunc(render);
//glutReshapeFunc(reshapeFunc);
//glutIdleFunc(idleFunc);
glutKeyboardFunc(Kbevent);
glutMainLoop();
return 0;
}
The problem with applying a 2D texture is that when you wrap a 2D texture onto a sphere, the top and bottom area of the sphere, the texture looks squeezed.
I suggest to use gluSphere and gluQuadricTexture rather than glutSolidSphere. e.g:
glEnable(GL_TEXTURE_2D);
GLUquadric *qobj = gluNewQuadric();
gluQuadricTexture(qobj, GL_TRUE);
gluSphere(qobj, radius, 20, 20);
gluDeleteQuadric(qobj);
glDisable(GL_TEXTURE_2D);
For an continuously rotation, you have increment the rotation angle and to continuously update the window (glutPostRedisplay). e.g.:
void redisplayFunc(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -4.5);
glRotatef(yRotated, 0.0, 1.0, 0.0);
glEnable(GL_TEXTURE_2D);
GLUquadric *qobj = gluNewQuadric();
gluQuadricTexture(qobj, GL_TRUE);
gluSphere(qobj, radius, 20, 20);
gluDeleteQuadric(qobj);
glDisable(GL_TEXTURE_2D);
glFlush();
yRotated += 1;
glutPostRedisplay();
}
I am new to OpenGL. I have the following code that I am using from a tutorial I followed, what it does is render a tile map. It does this successfully but my problem now is that I want to add a moveable object onto the window however it is not appearing.
#include "stdafx.h"
#include <string>
#include <windows.h>
#include <iostream>
#include <conio.h>
#include <sstream>
#include <math.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include "GL/freeglut.h"
#pragma comment(lib, "OpenGL32.lib")
// window size and update rate (60 fps)
int width = 700;
int height = 700;
int interval = 1000 / 60;
// ball
float ball_pos_x = width / 2;
float ball_pos_y = height / 2;
float ball_dir_x = -1.0f;
float ball_dir_y = 0.0f;
int ball_width = 20;
int ball_height = 20;
int ball_speed = 5;
GLuint texture; //the array for our texture
GLuint texture2; //the array for our second texture
void keyboard() {
if (GetAsyncKeyState(VK_LEFT)) ball_pos_x -= ball_speed;
if (GetAsyncKeyState(VK_RIGHT)) ball_pos_x += ball_speed;
if (GetAsyncKeyState(VK_UP)) ball_pos_y += ball_speed;
if (GetAsyncKeyState(VK_DOWN)) ball_pos_y -= ball_speed;
}
int cMap[30][30] = { //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},
};
void drawRect(float x, float y, float width, float height) {
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x + width, y);
glVertex2f(x + width, y + height);
glVertex2f(x, y + height);
glEnd();
}
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 draw() {
// clear (has to be done at the beginning)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // ToDo: draw our scene
// draw ball
drawRect(ball_pos_x - ball_width / 2, ball_pos_y - ball_height / 2, ball_width, ball_height);
glEnable( GL_TEXTURE_2D );
glTranslatef(-5, 4, -20); //translate back a bit to view the map correctly
drawTiles(); //draw our tiles
// swap buffers (has to be done at the end)
glutSwapBuffers();
}
void UpdatePlayer(){
// hit by right racket?
if (ball_pos_x < ball_pos_x + ball_width &&
ball_pos_x > enemy_pos_x &&
ball_pos_y < enemy_pos_y + enemy_height &&
ball_pos_y > enemy_pos_y) {
ball_pos_x = ball_pos_x;
ball_pos_y = ball_pos_y;
}
}
void update(int value) { // Call update() again in 'interval' milliseconds
// input handling
keyboard();
UpdatePlayer();
glutTimerFunc(interval, update, 0);
// Redisplay frame
glutPostRedisplay();
}
void enable2D(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, width, 0.0f, height, 0.0f, 1.0f);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
}
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 _tmain(int argc, char** argv)
{
// initialize opengl (via glut)
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(width, height); glutCreateWindow("noobtuts.com Pong");
// Register callback functions
glutDisplayFunc(draw);
glutIdleFunc (draw);
glutReshapeFunc (reshape);
glutTimerFunc(interval, update, 0);
// setup scene to 2d mode and set draw color to white
enable2D(width, height);
glColor3f(1.0f, 1.0f, 1.0f);
//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;
}
If I was to comment out in the main...
glutIdleFunc (draw);
glutReshapeFunc (reshape);
The tile map will disappear and my moveable square is visible and works...I just can't implement the two together successfully. Again i'm completely new to this so apologise if I am doing something really stupid Any ideas where I am going wrong?
Are you sure you want to draw the tile map with a perspective projection? It seems to me that you should be using an orthographic projection for both the tile map and the ball.
Change your reshape function to simply call enable2D(w, h). Then change your drawTiles function to draw using screen coordinates instead. That should work.
Some additional notes:
Don't forget to disable texturing when drawing your ball (you don't seem to be setting any texture for it, so it will just render with the last texture set).
You could also disable depth testing with glDisable(GL_DEPTH_TEST) since you don't really need it (and use glVertex2f for drawing the tile map instead of glVertex3f)
I started with opengl texturing and everything was working well. Now I am trying to load a bmp and make white part transparent using glEnable(GL_BLEND); and glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
This is my source code:
float kSpeedForw=0.0f;
GLuint texture[1];
CCamera g_Camera;
GLfloat xrot = 0;
GLfloat yrot = 0;
GLfloat zrot = 0;
bool g_bFullScreen = true;
HWND g_hWnd;
RECT g_rRect;
HDC g_hDC;
HGLRC g_hRC;
HINSTANCE g_hInstance;
float jump = -0.1;
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f };
void Init(HWND hWnd)
{
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); // Position The Light
glEnable(GL_LIGHT1); // Enable Light One
glColor4f(1.0f, 1.0f, 1.0f, 0.5); // Full Brightness. 50% Alpha
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
g_hWnd = hWnd;
GetClientRect(g_hWnd, &g_rRect);
InitializeOpenGL(g_rRect.right, g_rRect.bottom);
g_Camera.PositionCamera(0, 1.5f, 6, 0, 1.5f, 5, 0, 1, 0);
ShowCursor(false);
}
GLuint LoadTexture(const char * filename)
{
glEnable(GL_TEXTURE_2D);
GLuint texture;
int width, height;
unsigned char * data;
FILE * file;
file = fopen(filename, "rb");
if (file == NULL) return 0;
if (filename=="Data/weed.bmp"){
width = 200;
height = 200;
}
if (filename == "Data/gun.bmp"){
width = 300;
height = 300;
}
data = (unsigned char *)malloc(width * height * 3);
fread(data, width * height * 3, 1, file);
fclose(file);
for (int i = 0; i < width * height; ++i)
{
int index = i * 3;
unsigned char B, R;
B = data[index];
R = data[index + 2];
data[index] = R;
data[index + 2] = B;
}
if (filename == "Data/weed.bmp"){
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
free(data);
}
if (filename == "Data/gun.bmp"){
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3,width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
return texture;
}
WPARAM MainLoop() // main function
{
MSG msg;
Init(g_hWnd);
glClearColor(0, 0, 255, 0);
while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if (LockFrameRate(60))
{
g_Camera.SetViewByMouse();
kSpeedForw = 0;
if (jump > -0.1)jump-=0.01;
CheckForMovement();
g_Camera.MoveCamera(kSpeedForw, jump);
RenderScene();
}
}
DeInit();
return(msg.wParam);
}
void RenderScene()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glDisable(GL_BLEND);
glEnable(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(g_Camera.m_vPosition.x, g_Camera.m_vPosition.y, g_Camera.m_vPosition.z,
g_Camera.m_vView.x, g_Camera.m_vView.y, g_Camera.m_vView.z,
g_Camera.m_vUpVector.x, g_Camera.m_vUpVector.y, g_Camera.m_vUpVector.z);
GLuint texture;
texture = LoadTexture("Data/weed.bmp");
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
float i = 0;
glColor3f(1,1,1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-10 + i / 5, 0, 10 - i / 5);
glTexCoord2f(50.0f, 0.0f);
glVertex3f(-10 + i / 5, 0, -10 + i / 5);
glTexCoord2f(50.0f, 50.0f);
glVertex3f(10 - i / 5, 0, -10 + i / 5);
glTexCoord2f(0.0f, 50.0f);
glVertex3f(10 - i / 5, 0, 10 - i / 5);
glEnd();
////////////////////////////////////////////////////////////HUD
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SMOOTH);
glEnable(GL_BLEND); // Turn Blending On
int vPort[4];
glGetIntegerv(GL_VIEWPORT, vPort);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
GLuint ruka;
ruka = LoadTexture("Data/gun.bmp");
glBindTexture(GL_TEXTURE_2D, ruka);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0, 0);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(450,0);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(450,450);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0,450);
glEnd();
SwapBuffers(g_hDC);
}
The code works well for loading and rendering the platform(weed.bmp) and it also loads and renders gun fine. But big part of gun.bmp is white. I was hoping to get that part transparent. I was also hoping to add more HUD features, which would also need to be partly transparent.
My gun.bmp file: https://drive.google.com/file/d/0BxxlNcAI0eh9cHZGd1ZfMTFwYmM/view?usp=sharing
If you know a solution of this problem please post it. Thanks
You load image as GL_RGB, you want GL_RGBA to have an alpha channel.
Also, you need a 32 bits Bitmap (8 bits/channel × 4 channels = 32 bits).
I am having difficulty getting a offscreen rendered texture to to be displayed. I have checked round the web and other questions and am clearly missing something.
I am new to OpenGL so may well be making some naive errors. It is part of a routine to add post processing using a shader to modify the firestor/secondlife viewer project to an equifisheye projection. My test code is based around the GLEW and GLUT framework using OpenGL 1.3 as the viewer is designed to run on older platforms.
The approach is:
set up and initialise the FBO, Render buffers and textures to draw to.
initilise various default settings for drawing the glutCube and glutTeapot :)
The display function
a) using the default framebuffer draws a rotating cube (works fine)
b) the texture is then drawn to
OUTPUT: all black and not the rotating cube.
My code is:
GLuint buffer_fbo;
GLuint bufferColtexture;
GLuint depthBuffer_rb;
typedef struct {
int width;
int height;
char* title;
float field_of_view_angle;
float z_near;
float z_far;
} glutWindow;
glutWindow win;
//
void ShutDown(void)
{
glDeleteFramebuffersEXT(1, &buffer_fbo);
glDeleteRenderbuffersEXT(1, &depthBuffer_rb);
glDeleteTextures(1,&bufferColtexture);
}
float g_potrotation = 0;
float g_potrotation_speed = 0.2f;
float xrot =0;
float yrot = 0;
float zrot = 0;
GLenum g_Drawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT };
void setupFBO(void)
{
// *********** set up scene FBO including dept buffers and their textures ****************
glGenFramebuffersEXT(1, &buffer_fbo);
// set up render buffers for depth info
glGenRenderbuffersEXT(1, &depthBuffer_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, win.width, win.height);
// Genrate texture to render to
glGenTextures(1, &bufferColtexture);
glBindTexture(GL_TEXTURE_2D, bufferColtexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, win.width, win.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// attach texture to render to to fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer_fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, bufferColtexture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBuffer_rb);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // check frame buffer
if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
printf("FRAMEBUFFER status error %i \n",status);
exit(1);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // bind back to default
}
void initialise()
{
setupFBO();
// select projection matrix
glMatrixMode(GL_PROJECTION);
// set the viewport
glViewport(0, 0, win.width, win.height);
// set matrix mode
glMatrixMode(GL_PROJECTION);
// reset projection matrix
glLoadIdentity();
GLfloat aspect = (GLfloat) win.width / win.height;
// set up a perspective projection matrix
gluPerspective(win.field_of_view_angle, aspect, win.z_near, win.z_far);
// specify which matrix is the current matrix
glMatrixMode(GL_MODELVIEW);
glShadeModel( GL_SMOOTH );
// specify the clear value for the depth buffer
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LEQUAL );
// specify implementation-specific hints
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
GLfloat amb_light[] = { 0.1, 0.1, 0.1, 1.0 };
GLfloat diffuse[] = { 0.6, 0.6, 0.6, 1 };
GLfloat specular[] = { 0.7, 0.7, 0.3, 1 };
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, amb_light );
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
glEnable( GL_LIGHT0 );
glEnable( GL_COLOR_MATERIAL );
glShadeModel( GL_SMOOTH );
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glDepthFunc( GL_LEQUAL );
glEnable( GL_DEPTH_TEST );
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glClearColor(0.5, 0.5, 0.5, 1.0);
}
void drawquad(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glDisable(GL_LIGHTING); // This was the cause of the problem, disable lighting worked!
glLoadIdentity(); // Reset The View
glTranslatef(0.0f,0.0f,-5.0f);
glTranslatef(0.0f,0.0f,-5.0f);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
glBindTexture(GL_TEXTURE_2D, bufferColtexture);
glBegin(GL_QUADS);
// Front Face
glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
glEnd();
xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
glEnable(GL_LIGHTING); // now reenabling the lighting. after adding to fix code.
}
void display(void)
{
// set red background
// draw to fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
// Clear Screen and Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
// set drawing a rotating cube as per default
glLoadIdentity();
// Define a viewing transformation
gluLookAt( 3,1,0, 0,0,0, 0,1,0);
// Push and pop the current matrix stack.
// This causes that translations and rotations on this matrix wont influence others.
glPushMatrix();
glColor3f(0,1,0);
glTranslatef(0,0,0);
glRotatef(g_potrotation,0,1,0);
glRotatef(90,0,1,0);
// Draw the solid cube
glutSolidCube(1);
glPopMatrix();
// draw teapot to fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer_fbo);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,depthBuffer_rb);
// Clear Screen and Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// Define a viewing transformation
gluLookAt( 4,2,0, 0,0,0, 0,1,0);
// Push and pop the current matrix stack.
// This causes that translations and rotations on this matrix wont influence others.
glPushMatrix();
glColor3f(1,0,0);
glTranslatef(0,0,0);
glRotatef(g_potrotation,0,1,0);
glRotatef(90,0,1,0);
// Draw the teapot
glutSolidTeapot(1);
glPopMatrix();
g_potrotation += g_potrotation_speed;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); // reset to default Frame and Render buffer
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,0);
drawquad();
glutSwapBuffers();
}
// informs OpenGL that window size has changed.
void reshape(int width, int height)
{
}
void idle(void)
{
glutPostRedisplay();
}
int checkglewOK()
{
if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
printf("Ready for GLSL\n");
else {
printf("Not totally ready :( \n");
exit(1);
};
}
void keyboard (unsigned char key, int mousePositionX, int mousePositionY)
{
switch (key)
{
case KEY_ESCAPE:
exit (0);
break;
default:
break;
}
}
int main(int argc, char** argv)
{
// set window values
win.width = 640;
win.height = 480;
win.title = "Shader Test";
win.field_of_view_angle = 45;
win.z_near = 1.0f;
win.z_far = 500.0f;
////////////////////////////////////////////////////////
// Initialise and Create Window
////////////////////////////////////////////////////////
glutInit(&argc, argv);
// set modes RGB-Alpha, doble bufferedd (prevent flickering)
// has a depth buffer to ensure that 3D object overlp OK
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); // set display mode
// define window size
glutInitWindowSize(win.width, win.height);
glutCreateWindow(win.title); // create the window
glewInit(); // Glew Init occurs after Create Window !!!
checkglewOK();
glutDisplayFunc(display); // register display function
//glutReshapeFunc(reshape); // register resize function
glutIdleFunc(idle); // register idel function
glutKeyboardFunc(keyboard);
initialise();
glutMainLoop(); // run glut main loop
ShutDown();
return EXIT_SUCCESS;
}
I'm currently trying to implement in OpenGL image processing algorithms.
I would like to successively use several shaders in order to perform several filters (Sobel Gaussian,...).
I understood that to do this I had to render to texture thanks to a FBO. I read a lot of things about that, and wrote a code. But I'm not getting the result I expected.
For the moment, I'm just trying to use two shaders. So, I have an original image which is the input of my first shader. Then, I want to render the output of the shader to a texture which will then be the input of my second shader (ping-pong technique). And finally, I want to display the output of the second shader.
But as result, I'm getting the original image.
My code is the following:
/******************** Shaders Function *******************************/
void setupShaders(char *vert, char *frag, GLuint p) {
GLuint v, f;
char *vs = NULL,*fs = NULL;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead(vert);
fs = textFileRead(frag);
const char * ff = fs;
const char * vv = vs;
glShaderSource(v, 1, &vv, NULL);
glShaderSource(f, 1, &ff, NULL);
free(vs);free(fs);
glCompileShader(v);
glCompileShader(f);
p = glCreateProgram();
glAttachShader(p,f);
glAttachShader(p,v);
glLinkProgram(p);
glUseProgram(p);
}
/******************** Texture Function ***********************************/
void setupTexture(void) {
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_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
/******************** Quad Drawing Function ******************************/
void ShaderDraw(void){
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, height, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(width, height, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(width, height, 0.0);
glEnd();
}
/******************** Initialization Function ***************************/
void init(void)
{
//Checking GLSL
glewInit();
if (glewIsSupported("GL_VERSION_2_0"))
printf("Ready for OpenGL 2.0\n");
else {
printf("OpenGL 2.0 not supported\n");
exit(1);
}
// Init
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
}
/******************** Display Function **********************************/
void display(void)
{
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-4.0, -4.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-4.0, 4.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(4.0, 4.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(4.0, -4.0, 0.0);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
}
/******************** Reshape Function *********************************/
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -7.0);
}
/******************** Main Function *************************************/
int main(int argc, char** argv)
{
// Glut Initialisation
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
// Window Generation
glutInitWindowSize(1000,800);
glutInitWindowPosition(100, 100);
glutCreateWindow("Night Vision");
// Initialisation Function
init();
// Downloading Image
data = cLoadBitmap("lena.bmp", &height, &width);
checkGLErrors ("Downloading Image");
int read_tex = 0;
int write_tex = 1;
// Generating Texture
glEnable(GL_TEXTURE_2D);
glGenTextures(2, texImg);
// Init Texture0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texImg[read_tex]);
setupTexture();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
checkGLErrors ("InitTexture0");
// Init Texture1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texImg[write_tex]);
setupTexture();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
checkGLErrors ("InitTexture1");
// Setup Framebuffer Object
GLuint fb;
glGenFramebuffersEXT(1, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
checkGLErrors ("Framebuffer->fb");
GLenum att_point[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
glBindTexture(GL_TEXTURE_2D, texImg[read_tex]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[read_tex], GL_TEXTURE_2D, texImg[read_tex], 0);
glBindTexture(GL_TEXTURE_2D, texImg[write_tex]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[write_tex], GL_TEXTURE_2D, texImg[write_tex], 0);
checkFramebufferStatus();
//set the write texture as output buffer for the shader
glDrawBuffer(att_point[write_tex]);
// create, init and enable the shader
setupShaders("filter.vert", "sobel_filter_3.frag", p1);
checkGLErrors ("Shaders 1");
// attach the input texture(read texture) to the first texture unit
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texImg[read_tex]);
GLuint texLoc;
texLoc = glGetUniformLocation(p1,"tex");
glUniform1i(texLoc, 0);
// draw a square with the texture on it so to perform the computation
ShaderDraw();
// swap the buffers
read_tex = 1;
write_tex = 0;
// Delete program 1
glDeleteProgram(p1);
// set the write texture as output buffer for the shader
glDrawBuffer(att_point[write_tex]);
// create, init and enable the shaders
setupShaders("filter.vert", "gaussian7.frag", p2);
checkGLErrors ("Shaders 2");
// attach the input texture(read texture) to the first texture unit
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texImg[read_tex]);
texLoc = glGetUniformLocation(p2,"tex");
glUniform1i(texLoc, 0);
// draw a square with the texture on it so to perform the computation
ShaderDraw();
// Delete program 2 & disable the FBO
glDeleteProgram(p2);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glUseProgram(0);
// Bind the texture to display
glBindTexture(GL_TEXTURE_2D,texImg[0]);
// Glut Functions: Display, Reshape, Keyboard
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
// Calling Main
glutMainLoop();
return 0;
}
Does someone have an idea of what is wrong???
You are trying to simultaneously use the FBO as render source and render target. Afaik you cannot do that - if you want to use a texture bound to an FBO as render source, you need to unbind the FBO (either by calling glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); or by binding another FBO).
It looks like you are trying to save memory that way by using your start texture as the FBO's color buffer there. I am not sure whether this is possible as well.
So you may want try to create two FBOs, each with a single color buffer, and swap the entire FBOs, and start with rendering your texture to the first FBO. Also, don't use your start texture as a color buffer for an FBO, but create a separate color buffer for each FBO instead.
You also don't need to bind a texture to a texture unit before attaching it to an FBO.