I can't repeat the texture using GL_TEXTURE_CUBE_MAP and GL_REPEAT - opengl

After two days of reading and trying, I was able to texture a cube with GL_TEXTURE_CUBE_MAP:
Textured Cube
Then I decided to make a parallelepiped from the cube, in which the corresponding texture is repeated on the long side. I get similar or worse results:
Poorly stretched texture
And I want to get such a result:
Repeated texture
Is it even possible?
Here is the essential part of the code:
void Create( void ) {
glGenTextures( 1, &id );
glBindTexture( GL_TEXTURE_CUBE_MAP, id );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
const RGB bk_cols[ ] = { {207,193,0}, {133,96,169}, {0,166,81}, {0,84,166}, {158,11,15}, {137,137,137} };
const char letters[ ] = { 'x', 'y', 'z' };
RGB* rgb = new RGB[ 16 * 16 + 16 ];
for( unsigned int i = 0; i < 6; i++ ) {
glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE,
CreateLetter16x16( rgb, {0,250,0}, bk_cols[i], {0,0,0}, letters[ i >> 1 ], (i & 1 ? false : true) ) );
}
delete [ ] rgb;
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_REPEAT/*GL_CLAMP_TO_EDGE*/ );
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_REPEAT/*GL_CLAMP_TO_EDGE*/ );
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
}
void DrawTexturedCube( void ) {
float v = 2.0;
float p = 6.0;
// All the faces that are not front-faces are discarded.
// This is a good test of vertex sequence.
glEnable( GL_CULL_FACE );
// Of course a depth test is needed here.
glEnable( GL_DEPTH_TEST );
// Must be enabled, else textures doesn't work
glEnable( GL_TEXTURE_CUBE_MAP );
// If you want your image to be unaffected by the current color,
// you must change the texture environment parameter to decal
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
// Select texture
glBindTexture( GL_TEXTURE_CUBE_MAP, sq_txt.id );
glBegin( GL_QUADS );
// Right
glTexCoord3f( 1,-1,-1); glVertex3f( p,-v,-v);
glTexCoord3f( 1, 1,-1); glVertex3f( p, v,-v);
glTexCoord3f( 1, 1, 1); glVertex3f( p, v, v);
glTexCoord3f( 1,-1, 1); glVertex3f( p,-v, v);
// Left
glTexCoord3f(-1,-1,-1); glVertex3f(-p,-v,-v);
glTexCoord3f(-1,-1, 1); glVertex3f(-p,-v, v);
glTexCoord3f(-1, 1, 1); glVertex3f(-p, v, v);
glTexCoord3f(-1, 1,-1); glVertex3f(-p, v,-v);
// Top
glTexCoord3f(-1, 1, 1); glVertex3f(-p, v, v);
glTexCoord3f( 1, 1, 1); glVertex3f( p, v, v);
glTexCoord3f( 1, 1,-1); glVertex3f( p, v,-v);
glTexCoord3f(-1, 1,-1); glVertex3f(-p, v,-v);
// Bottom
glTexCoord3f(-1,-1,-1); glVertex3f(-p,-v,-v);
glTexCoord3f( 1,-1,-1); glVertex3f( p,-v,-v);
glTexCoord3f( 1,-1, 1); glVertex3f( p,-v, v);
glTexCoord3f(-1,-1, 1); glVertex3f(-p,-v, v);
// Front
float xn = -3.0;
float xp = 3.0;
float yn = -1.0;
float yp = 1.0;
float zz = 1.0;
glTexCoord3f(xn,yn,zz); glVertex3f(-p,-v, v);
glTexCoord3f(xp,yn,zz); glVertex3f( p,-v, v);
glTexCoord3f(xp,yp,zz); glVertex3f( p, v, v);
glTexCoord3f(xn,yp,zz); glVertex3f(-p, v, v);
// Back
glTexCoord3f( 1,-1,-1); glVertex3f( p,-v,-v);
glTexCoord3f(-1,-1,-1); glVertex3f(-p,-v,-v);
glTexCoord3f(-1, 1,-1); glVertex3f(-p, v,-v);
glTexCoord3f( 1, 1,-1); glVertex3f( p, v,-v);
glEnd();
// Restore default parameters
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// Must be disabled, else colors doesn't work ( Everything will be textured ).
glDisable( GL_TEXTURE_CUBE_MAP );
// --------------------------------------------------------------------
float k = v+.01f;
// Disable fill
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
// Set line width
glLineWidth( 3 );
glBegin( GL_QUADS );
glColor3f( .9f, 0, 0 );
glVertex3f( k,-k,-k); glVertex3f( k, k,-k); glVertex3f( k, k, k); glVertex3f( k,-k, k); // Right
glVertex3f(-k,-k,-k); glVertex3f(-k,-k, k); glVertex3f(-k, k, k); glVertex3f(-k, k,-k); // Left
glVertex3f(-k, k, k); glVertex3f( k, k, k); glVertex3f( k, k,-k); glVertex3f(-k, k,-k); // Top
glVertex3f(-k,-k,-k); glVertex3f( k,-k,-k); glVertex3f( k,-k, k); glVertex3f(-k,-k, k); // Bottom
glVertex3f(-k,-k, k); glVertex3f( k,-k, k); glVertex3f( k, k, k); glVertex3f(-k, k, k); // Front
glVertex3f( k,-k,-k); glVertex3f(-k,-k,-k); glVertex3f(-k, k,-k); glVertex3f( k, k,-k); // Back
glEnd();
// Restore fill
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
// Restore default line width
glLineWidth( 1 );
// Restore default state
glDisable( GL_DEPTH_TEST );
// Restore default state
glDisable( GL_CULL_FACE );
}

Repeat filtering is a texture sampling wrap mode. And wrap modes explain how texture coordinates outside of the space of the texture work.
But the way cubemap texture coordinates are defined (they are vectors from the center of a cube pointing to a location inside that cube), they basically never fall outside of the size of a face of the cubemap. So repeat filtering is a no-op, functionally identical to clamp-to-edge.

Related

Loaded 2D texture is not binding itself to a QUAD

I've loaded a texture's ID into the tex variable, but when I bind the texture with this ID just before drawing a QUAD (seen in code below inside the renderScene function surrounded by the xxxxxxxxx... comments), no texture is getting applied to the QUAD; it remains colorless. No error messages either.
I've included all the texture-related things I've written in my program.
What else do I need to add/change?
#include<windows.h>
#include <GL/glut.h>
#include<iostream>
#include <stdlib.h>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
// (...)
GLuint loadBMP_custom(const char * imagepath);
GLuint tex = loadBMP_custom("texture.bmp");
GLuint loadBMP_custom( const char * imagepath )
{
GLuint texture;
int width, height;
unsigned char * data;
FILE * file;
file = fopen( imagepath, "rb" );
if ( file == NULL ) return 0;
width = 256;
height = 256;
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;
}
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 );
return texture;
}
// (...)
void renderScene(void)
{
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Set the camera
gluLookAt( posX, 1.0f, posZ,
posX+vlx, posY+vly, posZ+vlz,
0.0f, 1.0f, 0.0f);
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f(-100.0f, -0.02f, -100.0f);
glTexCoord2f (0.0, 1.0);
glVertex3f(-100.0f, -0.02f, 100.0f);
glTexCoord2f (1.0, 1.0);
glVertex3f( 100.0f, -0.02f, 100.0f);
glTexCoord2f (1.0, 0.0);
glVertex3f( 100.0f, -0.02f, -100.0f);
glEnd();
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// [Also display 3D blocks in space besides the above QUAD, which serves as ground]
glFlush();
glutSwapBuffers();
}
//(...)
int main(int argc, char **argv)
{
// (...)
glEnable (GL_TEXTURE_2D) ;
glutMainLoop();
return 1;
}
As mentioned in the comments, your method to load a BMP file is incorrect: even if you know how big the image is (256x256), you would still need to skip ahead to the pixel data part (usually 54 bytes, which is the usual size of the header).
So now you could write your own importer by reading the official spec over here: https://en.wikipedia.org/wiki/BMP_file_format
...Or also find many implementations on the web such as the one mentioned in this question: C++: Read bitmap wrong
Unless you find some easy-to-plug header(s)-only library, I would personally go against using a library to specifically deal with BMP files since it introduces extra dependencies for something quite easy to roll on your own (and at the same time, learn how to implement a simple file loader).

openGL - testure mapping cube fails

I am trying something quite easy, normally: applying a texture on the different surfaces of a cube.
I am able to apply it but it seems as if he just takes an average of the colors of my image.
why please?
my code:
void MyGLWidget::drawCube()
{
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glLoadIdentity();
// glPushMatrix();
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0.5, 0, 0.0);
glRotatef(getCubeAngle(), 0.0f, 1.0f, 0.0f);
glTranslatef(0, 0, 0);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glBegin(GL_QUADS);
//back
glVertex3f(-0.1, 0.1,-0.1 );//upper left corner
glVertex3f(0.1, 0.1,-0.1); //uper right
glVertex3f(0.1,-0.1,-0.1 ); // down left
glVertex3f(-0.1,-0.1,-0.1); // down right
/* other code to create rest of the cube*/
glEnd();
glFlush();
// glPopMatrix();
}
void MyGLWidget::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glScalef(height *1./width, 1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
void MyGLWidget::myTextureMapping()
{
QImage t;
QImage b;
if(!b.load("..../myImage.bmp"))
{qDebug("error with image\n");}
t = QGLWidget::convertToGLFormat(b);
glGenTextures( 1, &texture[0] );
glBindTexture( GL_TEXTURE_2D, texture[0] );
glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits() );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
void MyGLWidget::initializeGL()
{
myTextureMapping();
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
EDIT:
added those tex coordinates:
glTexCoord2f(-0.1, 0.1);
glVertex3f(-0.1, 0.1,0 );//upper left corner
glTexCoord2f(0.1, 0.1);
glVertex3f(0.1, 0.1,0); //uper right
glTexCoord2f(0.1, -0.1);
glVertex3f(0.1,-0.1,0 ); // down left
glTexCoord2f(-0.1, -0.1);
glVertex3f(-0.1,-0.1,0); // down right
But my image is bigger than the face of my cube:
source image : http://imgur.com/h48QARM
result in software: http://imgur.com/rxvK0Ot
You should be providing the texture co-ordinates for each vertex. What you have right now is just a position data for the Quad, texture co-ordinates are missing.
Have a look at this :
OpenGL Textured Cube Not Being Mapped Correctly
Try this :
glTexCoord2f(0, 0);
glVertex3f(-0.1, 0.1,0 );//upper left corner
glTexCoord2f(1, 0);
glVertex3f(0.1, 0.1,0); //uper right
glTexCoord2f(0, 1);
glVertex3f(-0.1,-0.1,0 ); // down left
glTexCoord2f(1, 1);
glVertex3f(0.1,-0.1,0); // down right
Isn't the texture coordinates wrong? To me it seems like you're going -0.1 to 0.1, while texture coordinates normally are defined in the interval [0,1].

OpenGL: Nothing drawn

Graphics: AMD Radeon HD 7900 Series
Running: Windows 7(64 bit)
Program: CodeBlocks(32 bit)
OpenGL Library: GLee
This is where I setup the window. Its an SDL window using OpenGL rendering.
void Init(int w, int h, bool fullScr)
{
if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
printf("Unable to initialize SDL: %s\n", SDL_GetError());
}
winW = w*scale;
winH = h*scale;
original_winW = w;
origianl_winH = h;
putenv("SDL_VIDEO_WINDOW_POS");
putenv("SDL_VIDEO_CENTERED=1");
getenv("SDL_VIDEO_WINDOW_POS");
getenv("SDL_VIDEO_CENTERED");
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new*
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0 ); // *new*
//Sets up the screen and displays the window
screen = SDL_SetVideoMode( winW, winH, 32, SDL_OPENGL | (fullScr*SDL_FULLSCREEN) ); // *changed*
screenRect.x = 0;
screenRect.y = 0;
screenRect.w = winW;
screenRect.h = winH;
SDL_ShowCursor(false);
SetGLState();
}
This is the SetGLState() mentioned above.
void SetGLState(){
glEnable( GL_TEXTURE_2D ); //Enable 2d texturing
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); //Set clear color (rgba)
glViewport( 0, 0, winW, winH ); //Set the viewport
glClear( GL_COLOR_BUFFER_BIT ); //Clear back buffer?
glMatrixMode( GL_PROJECTION ); //Set to projection
glLoadIdentity();
glOrtho(0.0f, winW, winH, 0.0f, -1.0f, 1.0f); //Create orthogonal projection matrix
glMatrixMode( GL_MODELVIEW ); //Set back to model view
glLoadIdentity();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
This is where the images are drawn to the screen
void DrawImage(GLSurface image, float x, float y)
{
// Bind the texture to which subsequent calls refer to
if(boundTexture != image.Surface){glBindTexture( GL_TEXTURE_2D, image.Surface ); boundTexture = image.Surface; }
glReadPixels(x,y,image.w*2,image.h*2,GL_UNSIGNED_BYTE,NULL,NULL);
glLoadIdentity();
glScalef(scale,scale,1);
glRotatef(image.rotation[0], 1.0f, 0.0f, 0.0f);
glRotatef(image.rotation[1], 0.0f, 1.0f, 0.0f);
glRotatef(image.rotation[2], 0.0f, 0.0f, 1.0f);
if(scale == 7.5)x += 48;
glBegin( GL_QUADS );
//Bottom-left vertex (corner)
glColor3b(127,127,127);
glTexCoord2i( 0, 0 ); //Position on texture to begin interpolation
glVertex3f( x, y, 0.f ); //Vertex Coords
//Bottom-right vertex (corner)
glTexCoord2i( 1, 0 );
glVertex3f( x+image.w, y, 0.f );
//Top-right vertex (corner)
glTexCoord2i( 1, 1 );
glVertex3f( x+image.w, y+image.h, 0.f );
//Top-left vertex (corner)
glTexCoord2i( 0, 1 );
glVertex3f( x, y+image.h, 0.f );
glEnd();
}
This window doesn't draw anything, and I can't figure out why. I haven't looked at this code in awhile, but I know that on a previous install of windows, I had it working. All of my other projects run, but this one doesn't. It just renders a blank screen. The weird thing is--I have a resize function for this window. When that function gets called, the screen displays a white screen instead of a black one.
Edit**
This code is called at the end once everything has been drawn to the screen. It was already included in my code.
void Flip(){
SDL_GL_SwapBuffers();
glClear( GL_COLOR_BUFFER_BIT );
}
All the state set in SetGLState is drawing state. Call it from the DrawImage function. Most importantly, glClear must be put in the draw function, it doesn't make sense anywhere else.
That call to glReadPixels makes no sense.
And you must swap the buffers when done SDL_SwapBuffers (IIRC, haven't used SDL in some time).

simple 2d animation in glut

I have an assignment to do, but i can't seem to trully comprehend it.
The assignment is as follows : Adding a texture to background (solar system), adding texture to 2 objects (drawn shapes) and adding an animation where the two objects have to bounce from eachother & from far walls (as in end of screen).
I have managed to do everything except the animation.
How can I do this kind of animation?
p.s. animation in there is the best i could come up with.
#include <gl/glut.h>
#include <gl/gl.h >
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
float x;
float y;
unsigned char *imageData;
int imageRows, imageCols;
extern void loadBMP(char *);
char cotton1[] = "cotton1.bmp";
char cotton2[] = "cotton2.bmp";
char fons[] = "solar.bmp";
GLuint texture[3];
float cube[1], Vcube[1];
/* GLUT callback Handlers */
void init()
{
cube[0]=0;
Vcube[0]=0.01;
cube[1]=0;
Vcube[1]=0.01;
glShadeModel(GL_SMOOTH);
glGenTextures( 3, &texture[0] );
loadBMP(cotton1);
glBindTexture( GL_TEXTURE_2D, texture[0] );
glTexImage2D(GL_TEXTURE_2D, 0, 3, imageCols, imageRows,
0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
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);
loadBMP(cotton2);
glBindTexture( GL_TEXTURE_2D, texture[1] );
glTexImage2D(GL_TEXTURE_2D, 0, 3, imageCols, imageRows,
0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
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);
loadBMP(fons);
glBindTexture( GL_TEXTURE_2D, texture[2] );
glTexImage2D(GL_TEXTURE_2D, 0, 3, imageCols, imageRows,
0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
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);
}
static void
resize(int width, int height)
{
const float ar = (float) width / (float) height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity() ;
}
static void
idle(void)
{
glutPostRedisplay();
}
void animation()
{
cube[1]+=Vcube[1];
if (cube[1]<0.1)
{ Vcube[1]+=Vcube[1]; }
if (cube[1]>0.095)
{ Vcube[1]=-0.01; }
if (cube[1]<0)
{ Vcube[1]=+0.01; }
glTranslatef(cube[1],0,0);
Sleep(100);
glutPostRedisplay();
}
void animation2()
{
cube[0]+=Vcube[0];
if (cube[0]<(-0.1))
{ Vcube[0]-=0.01; }
if (cube[0]>0)
{ Vcube[0]-=0.01; }
if (cube[0]<0.1)
{ Vcube[0]+=0.01; }
glTranslatef(cube[0],0,0);
Sleep(100);
glutPostRedisplay();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
//Background
glLoadIdentity();
glBindTexture( GL_TEXTURE_2D, texture[2]);
glEnable( GL_TEXTURE_2D );
glPushMatrix();
glBegin( GL_QUADS );
glTexCoord2f(1.0,1.0); glVertex2f(-1.0,1.0);
glTexCoord2f(0.0,1.0); glVertex2f(1.0,1.0);
glTexCoord2f(0.0,0.0); glVertex2f(1.0,-1.0);
glTexCoord2f(1.0,0.0); glVertex2f(-1.0,-1.0);
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
animation();
//TEXTURE 1
glBindTexture( GL_TEXTURE_2D, texture[0]);
glEnable( GL_TEXTURE_2D );
glPushMatrix();
glBegin( GL_TRIANGLE_FAN );
glTexCoord2f(0.5f, 0.5f); glVertex2f( 0.5f, 0.0f); //center
glTexCoord2f(1.0f, 0.5f); glVertex2f( 0.8f+x, 0.0f); //right
glTexCoord2f(0.75f, 1.0f); glVertex2f( 0.55f+x, 0.3f+x); //top right
glTexCoord2f(0.25f, 1.0f); glVertex2f( 0.35f-x, 0.3f+x); //Top left
glTexCoord2f(0.0f, 0.5f); glVertex2f( 0.25f-x, 0.0f); //left
glTexCoord2f(0.25f, 0.0f); glVertex2f( 0.45f-x,-0.3f-x); //bottom left
glTexCoord2f(0.75f, 0.0f); glVertex2f( 0.7f+x, -0.2f-x); //bottom right
glTexCoord2f(1.0f, 0.5f); glVertex2f( 0.8f+x, 0.0f); //right
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
//TEXTURE 2
animation2();
glBindTexture( GL_TEXTURE_2D, texture[1]);
glEnable( GL_TEXTURE_2D );
glPushMatrix();
glBegin( GL_TRIANGLE_FAN );
glTexCoord2f(0.5f, 0.5f); glVertex2f( -0.5f, 0.0f); //center
glTexCoord2f(1.0f, 0.5f); glVertex2f( -0.2f+y, 0.0f); //right
glTexCoord2f(0.75f, 1.0f); glVertex2f( -0.4f+y, 0.2f+y); //top right
glTexCoord2f(0.25f, 1.0f); glVertex2f( -0.7f-y, 0.1f+y); //Top left
glTexCoord2f(0.0f, 0.5f); glVertex2f( -0.8f-y, 0.0f); //left
glTexCoord2f(0.25f, 0.0f); glVertex2f( -0.7f-y, -0.1f-y); //bottom left
glTexCoord2f(0.75f, 0.0f); glVertex2f( -0.3f+y, -0.2f-y); //bottom right
glTexCoord2f(1.0f, 0.5f); glVertex2f( -0.2f+y, 0.0f); //right
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glutSwapBuffers();
glFlush();
}
static void
key(unsigned char key, int a, int b)
{
switch (key)
{
case 27 :
case 'q':
exit(0);
break;
case '+':
if ((x+0.01)<0.98)
x=x+0.01;
if ((y+0.01)<0.98)
y=y+0.01;
break;
case '-':
if ((x-0.1)>(-0.15))
x=x-0.01;
if ((y-0.1)>(-0.10))
y=y-0.01;
break;
case 'o':
if ((x+0.01)<0.98)
x=x+0.01;
break;
case 'p':
if ((x-0.1)>(-0.15))
x=x-0.01;
break;
case '[':
if ((y+0.01)<0.98)
y=y+0.01;
break;
case ']':
if ((y-0.1)>(-0.10))
y=y-0.01;
break;
}
glutPostRedisplay();
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(640, 640);
glutInitWindowPosition(50, 50);
glutCreateWindow("Assignment number 3");
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);
glClearColor(1.0, 1.0, 1.0, 1.0);
init();
glutMainLoop();
return EXIT_SUCCESS;
}
Problem 1: You mistake OpenGL for a scene graph. Take your animation1 function for example:
void animation2(
)
{
cube[0] += Vcube[0];
if( cube[0] < ( -0.1 ) ) {
Vcube[0] -= 0.01;
}
if( cube[0] > 0 ) {
Vcube[0] -= 0.01;
}
if( cube[0] < 0.1 ) {
Vcube[0] += 0.01;
}
glTranslatef( cube[0], 0, 0 );
Sleep( 100 );
glutPostRedisplay( );
}
That glTranslatef there at the end will just trash around on whatever matrix is currently active in the OpenGL context. That's not how to do it.
Next problem: You're calling the animation functions from the drawing code. At the point of drawing all the scene state should be determined. Also, calling that animation function will sleep in your display function. That's not how to do it.
Okay, what to do: First put all the animation progressor functions into the idle loop. Don't sleep, instead measure the time between animation iterations and advance the animation accordingly. Don't call glutPostRedisplay in the animation functions. At the end of the idle handler yes, but not in the animators. In the drawing code use the evaluated animation state to place objects accordingly. Use the matrix stack (glPushMatrix, glPopMatrix) to keep things nicely separated.
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* for gettimeofday */
#include <sys/time.h>
/* In general, littering your program with global variables should be avoided.
* I admit, that sometimes even I don't adhere to this rule, and especially
* using GLUT it takes to jump several very arcane hoops to avoid it.
* So in this case, yes, having global variables is in order.
*
* The principle idea of global variables is to put data into them, that is
* valid and the same for the whole of the program. More importantly they
* must not be used to pass around data.
*
* It's also a good idea to make those variables static, so that they are
* contained withing this compilation unit.
*/
static float x;
static float y;
/* This is not how globals should be used. They're used to pass data around between
* functions. DON'T DO THAT!
*
* Also this misses the extern keyword. Unless the compilation unit loading the
* bmp files declares those being extern, hence relying on another compilation unit
* to expose them like this, this code is likely to break.
unsigned char *imageData;
int imageRows, imageCols;
extern void loadBMP(char *);
* BTW: You don't need the extern keyword here.
* Instead have a nice little function that loads a BMP file and puts it into a
* newly allocated texture object.
*/
GLuint loadBmpToTexture(char const * const filename)
{
/* Implementation of this left as an exercise to the reader */
return 0;
}
static double ftime(void)
{
/* Now this is a bit complicated: There's no portable high resolution
* timer function. On Linux and Unices (hence also MacOS X) you have
* gettimeofday, on Windows there are the High Performance Counters.
* ... Totally annoying.
* Look here for a comparison:
* http://www.songho.ca/misc/timer/timer.html
*
* Since I'm on a Linux box this is using gettimeofday
*/
struct timeval t;
gettimeofday(&t, NULL);
return 1.0*t.tv_sec + 1e-6*t.tv_usec;
}
/* In this variable we store the time of the last iteration of the animation
* loop to determine the time to time difference for the next one. */
static double last_T;
/* Actually those should be of type char const * const
* This is one of the finer details of C. The arrays like you've declared them
* here are mutable, but of constant size.
* However you normally don't want string constant be like this. The preferred
* modus operandi is to have the string constants in read only memory and pointers
* to them. Like this:
*/
char const * const cotton1 = "cotton1.bmp";
char const * const cotton2 = "cotton2.bmp";
char const * const fons = "solar.bmp";
/* Okay, now consider what would happen if you had several objects, not just two or
* three? How would you keep track of all those indices? Really, that's bad style.
* If you've data belonging together, like state of an object, put it into a struct
* and then also use useful variable names.
*/
GLuint texture_background;
typedef struct s_Cube {
float x, V_x;
GLuint texture;
} Cube;
/* also we can statically initialize here */
Cube cube[2] = {
{-0.05, 0.01, 0},
{0.05, -0.02, 0}
};
/* GLUT callback Handlers */
static void init(void)
{
/* loadBmpToTexture is defined to return 0 in case of failure
* which is also the OpenGL default texture object, so this
* fails safely. */
texture_background = loadBmpToTexture(fons);
cube[0].texture = loadBmpToTexture(cotton1);
cube[1].texture = loadBmpToTexture(cotton2);
glClearColor( 0.0, 0.5, 0.7, 1.0 );
last_T = ftime();
}
static void animation(
float const speed
)
{
/* The objective is to let the cubes bounce into each other
* (collision) and with the walls. First the collision: */
if( cube[0].x > cube[1].x && cube[0].V_x > 0 && cube[1].V_x < 0 ) {
/* cubes bounced off each other. Exchange their velocities */
double const V_x = cube[0].V_x;
cube[0].V_x = cube[1].V_x;
cube[1].V_x = V_x;
double const x = cube[0].x;
cube[0].x = cube[1].x;
cube[1].x = x;
}
/* and the wall bounce */
if( cube[0].x < -0.1 && cube[0].V_x < 0 ) {
/* left cube bounced into left wall */
cube[0].V_x *= -1;
}
if( cube[1].x > 0.1 && cube[1].V_x > 0 ) {
/* right cube bounced into left wall */
cube[1].V_x *= -1;
}
cube[0].x += speed * cube[0].V_x;
cube[1].x += speed * cube[1].V_x;
}
/* Ideally we'd use a precise animation loop interleaved with event processing here.
* Unfortunately GLUT doesn't offer those, so we use this arcane kludge.
*
* It would get a bit more robust by putting the whole timing into the display function
* but better abandon GLUT and get a true event loop.
*/
static void idle(
void )
{
const double now_T = ftime();
const double delta_T = now_T - last_T;
last_T = now_T;
const double speed = delta_T * 60;
animation( speed );
glutPostRedisplay( );
}
static void display(void)
{
/* We try to be as stateless as possible. Yes, in the face of a statefull
* API, like OpenGL, this may sound a bit pedantic. */
const int width = glutGet(GLUT_WINDOW_WIDTH);
const int height = glutGet(GLUT_WINDOW_HEIGHT);
const float ar = ( float ) width / ( float ) height;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
/* It's really best practice to set everything related to drawing
* – and that includes the projection – in the drawing function */
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho(-ar, ar, -1, 1, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
//Background
if(texture_background) {
glBindTexture( GL_TEXTURE_2D, texture_background );
glEnable( GL_TEXTURE_2D );
glBegin( GL_QUADS );
glTexCoord2f( 1.0, 1.0 );
glVertex2f( -1.0, 1.0 );
glTexCoord2f( 0.0, 1.0 );
glVertex2f( 1.0, 1.0 );
glTexCoord2f( 0.0, 0.0 );
glVertex2f( 1.0, -1.0 );
glTexCoord2f( 1.0, 0.0 );
glVertex2f( -1.0, -1.0 );
glEnd();
glDisable( GL_TEXTURE_2D );
}
//TEXTURE 1
glBindTexture( GL_TEXTURE_2D, cube[1].texture );
glEnable( GL_TEXTURE_2D );
/* Remember we're still in modelview matrix mode.
* This push creates a copy of the currently modelview matrix,
* for our disposal. With a following pop we restore to the
* state saved now. Pushes and Pops nest. */
glPushMatrix();
/* This applies our animation position to the modelview matrix.
* All geometry drawing to follow is subject to this additional
* transformation, until the matrix changes again. */
glTranslatef(cube[1].x, 0, 0);
glBegin( GL_TRIANGLE_FAN );
glTexCoord2f( 0.5f, 0.5f );
glVertex2f( 0.5f, 0.0f ); //center
glTexCoord2f( 1.0f, 0.5f );
glVertex2f( 0.8f + x, 0.0f ); //right
glTexCoord2f( 0.75f, 1.0f );
glVertex2f( 0.55f + x, 0.3f + x ); //top right
glTexCoord2f( 0.25f, 1.0f );
glVertex2f( 0.35f - x, 0.3f + x ); //Top left
glTexCoord2f( 0.0f, 0.5f );
glVertex2f( 0.25f - x, 0.0f ); //left
glTexCoord2f( 0.25f, 0.0f );
glVertex2f( 0.45f - x, -0.3f - x ); //bottom left
glTexCoord2f( 0.75f, 0.0f );
glVertex2f( 0.7f + x, -0.2f - x ); //bottom right
glTexCoord2f( 1.0f, 0.5f );
glVertex2f( 0.8f + x, 0.0f ); //right
glEnd( );
glPopMatrix( );
glDisable( GL_TEXTURE_2D );
//TEXTURE 2
/* in the original code you didn't use the other texture,
* Probably because you lost track of variables and indices. */
glBindTexture( GL_TEXTURE_2D, cube[0].texture );
glEnable( GL_TEXTURE_2D );
glPushMatrix();
glTranslatef(cube[0].x, 0, 0);
glBegin( GL_TRIANGLE_FAN );
glTexCoord2f( 0.5f, 0.5f );
glVertex2f( -0.5f, 0.0f ); //center
glTexCoord2f( 1.0f, 0.5f );
glVertex2f( -0.2f + y, 0.0f ); //right
glTexCoord2f( 0.75f, 1.0f );
glVertex2f( -0.4f + y, 0.2f + y ); //top right
glTexCoord2f( 0.25f, 1.0f );
glVertex2f( -0.7f - y, 0.1f + y ); //Top left
glTexCoord2f( 0.0f, 0.5f );
glVertex2f( -0.8f - y, 0.0f ); //left
glTexCoord2f( 0.25f, 0.0f );
glVertex2f( -0.7f - y, -0.1f - y ); //bottom left
glTexCoord2f( 0.75f, 0.0f );
glVertex2f( -0.3f + y, -0.2f - y ); //bottom right
glTexCoord2f( 1.0f, 0.5f );
glVertex2f( -0.2f + y, 0.0f ); //right
glEnd();
glPopMatrix();
glDisable( GL_TEXTURE_2D );
glutSwapBuffers();
/* Your glFinish here was totally pointless.
* First it would belong _before_ glutSwapBuffers.
* Second glutSwapBuffers implies a glFinish, so it's totally redundant. */
}
static void key(
unsigned char key,
int a,
int b )
{
switch ( key ) {
case 27:
case 'q':
exit( 0 );
break;
case '+':
if( ( x + 0.01 ) < 0.98 )
x = x + 0.01;
if( ( y + 0.01 ) < 0.98 )
y = y + 0.01;
break;
case '-':
if( ( x - 0.1 ) > ( -0.15 ) )
x = x - 0.01;
if( ( y - 0.1 ) > ( -0.10 ) )
y = y - 0.01;
break;
case 'o':
if( ( x + 0.01 ) < 0.98 )
x = x + 0.01;
break;
case 'p':
if( ( x - 0.1 ) > ( -0.15 ) )
x = x - 0.01;
break;
case '[':
if( ( y + 0.01 ) < 0.98 )
y = y + 0.01;
break;
case ']':
if( ( y - 0.1 ) > ( -0.10 ) )
y = y - 0.01;
break;
}
glutPostRedisplay();
}
int main(
int argc,
char *argv[] )
{
glutInit( &argc, argv );
glutInitWindowSize( 640, 640 );
glutInitWindowPosition( 50, 50 );
/* glutInitDisplayMode must be called before calling glutCreateWindow
* GLUT, like OpenGL is stateful */
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
glutCreateWindow( "Assignment number 3" );
glutDisplayFunc( display );
glutKeyboardFunc( key );
glutIdleFunc( idle );
init();
glutMainLoop( );
return EXIT_SUCCESS;
}

Memory leak when using freetype library

In the following code snippet, I am leaking 52 bytes of memory for every iteration of the for loop, but after several hours I am unable to determine why =/
Any help will be appreciated.
for(unsigned char i=0; i<128; ++i)
{
ttf.loadGlyph(i);
FT_Glyph glyph;
FT_Get_Glyph(ttf.ftFace_->glyph, &glyph);
FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
FT_Bitmap& bitmap = bitmap_glyph->bitmap;
int width = nextPowerOf2(bitmap.width);
int height = nextPowerOf2(bitmap.rows);
GLubyte* expanded_data = new GLubyte[ 2 * width * height]; // Allocate Memory For The Texture Data.
for(int j=0; j <height;j++) {
for(int i=0; i < width; i++){
expanded_data[2*(i+j*width)]= expanded_data[2*(i+j*width)+1] =
(i>=bitmap.width || j>=bitmap.rows) ?
0 : bitmap.buffer[i + bitmap.width*j];
}
}
glBindTexture( GL_TEXTURE_2D, fontData_.pTextures_[i]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );
delete [] expanded_data;
glNewList(fontData_.fontBase_+i, GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, fontData_.pTextures_[i]);
glPushMatrix();
glTranslatef( (GLfloat)bitmap_glyph->left, 0.0f, 0.0f );
glTranslatef(0.0f, (GLfloat)bitmap_glyph->top-bitmap.rows, 0.0f);
float x=(float)bitmap.width / (float)width,
y=(float)bitmap.rows / (float)height;
glBegin(GL_QUADS);
glTexCoord2d(0,0); glVertex3f( 0, 0, 1 ); //Bottom-left vertex (corner)
glTexCoord2d(0,y); glVertex3f( 0, (GLfloat)bitmap.rows, 1 ); // top left vertex
glTexCoord2d(x,y); glVertex3f( (GLfloat)bitmap.width, (GLfloat)bitmap.rows, 1 ); // top right vertex
glTexCoord2d(x,0); glVertex3f( (GLfloat)bitmap.width, 0, 1 ); // bottom right
glEnd();
glPopMatrix();
glTranslatef( (GLfloat)( ttf.ftFace_->glyph->advance.x >> 6 ), 0, 0);
glEndList();
}
From the docs:
FT_Get_Glyph
A function used to extract a glyph image from a slot. Note that the
created FT_Glyph object must be released with FT_Done_Glyph.