Textures openGl. C++, qt - c++

I'm trying to cover my terrain(which is made from heightmap) with a grass texture, but it's not working as it should. I can't even get the texture on a simple GL_QUAD, the result is multicolor net.
void GLWidget::initializeGL()
{
//
glEnable(GL_TEXTURE_2D);
//
}
in QGLwidget I call
openTextureImg();
code of openTextureImg():
bool GLWidget::openTextureImg()
{
QString fileName = QFileDialog::getOpenFileName(this,tr("Open Image"),QDir::homePath(), tr("Image Files (*.png *.tga *.bmp)"));
QImage textureImg;
if (!fileName.isEmpty())
{
textureImg = QImage(fileName, "PNG");
qDebug()<<"image loaded";
textureImg = QGLWidget::convertToGLFormat( textureImg );
glGenTextures( 1, &texHandle );
glBindTexture( GL_TEXTURE_2D, texHandle );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureImg.width(), textureImg.height(), 0, GL_RGB,
GL_UNSIGNED_BYTE, textureImg.bits());
//glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glBindTexture( GL_TEXTURE_2D, 0 );
return true;
}
return false;
}
Here I'm trying to draw a quad:
void GLWidget::drawRect()
{
glColor3f(0.5,0.5,1.0);
glBindTexture(GL_TEXTURE_2D,texHandle);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0); glVertex2d(0.0,0.0);
glTexCoord2d(1.0,0.0); glVertex2d(1000.0,0.0);
glTexCoord2d(1.0,1.0); glVertex2d(1000.0,1000.0);
glTexCoord2d(0.0,1.0); glVertex2d(0.0,1000.0);
glEnd();
}
What am I doing wrong.

From the docs:
QImage QGLWidget::convertToGLFormat ( const QImage & img ) [static]
Converts the image img into the unnamed format expected by OpenGL functions such as glTexImage2D(). The returned image is not usable as a QImage, but QImage::width(), QImage::height() and QImage::bits() may be used with OpenGL. The GL format used is GL_RGBA [emphasis mine].
In your call to glTexImage2D use GL_RGBA instead of GL_RGB.

Related

OpenGL Texture Rendering issue

I have copied the QImage into OpenGL Texture below. If I want to render the Texture, should I
just bind the Texture in Flush() ? Or should I have to do anything else? Please find my below
code
void SaveBackBuffer() {
QPixmap pixmap = QPixmap::grabWindow(this->winId());
QImage buf = pixmap.toImage();
_savedBackBuffer = buf.convertToFormat(QImage::Format_RGBA8888);
}
void RestoreBackBuffer() {
glBindTexture(GL_TEXTURE_2D, _scrTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _savedBackBuffer.width(),
_savedBackBuffer.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
_savedBackBuffer.bits());
glBindTexture(GL_TEXTURE_2D, 0);
_bSavingBackBuffer = false;
}
Flush() {
glBindTexture(GL_TEXTURE_2D, _scrTex);
...
glDrawArrays...
}

OpenGL Won't Change Texture

My textures wont change and i'm not sure why. This my Texture Loader.h
class TextureLoader
{
private:
GLuint* Texture;
std::map<std::string, GLuint*> TextureMap;
public:
TextureLoader(){};
~TextureLoader()
{
delete Texture;
}
bool LoadTexture(std::string Source);
GLuint* GetImage(std::string TextureID);
bool CheckTextureExsist(std::string TextureID);
};
This is the CPP.
bool TextureLoader::LoadTexture(std::string Source)
{
//Bind the texture to load in.
Texture = new GLuint;
glGenTextures (1, Texture);
glBindTexture (GL_TEXTURE_CUBE_MAP, *Texture);
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
//Width, Height and Components of the image.
int x, y, n;
//Set pixel format
int force_channels = 4;
//Load data into the char.
unsigned char* image_data = stbi_load (
Source.c_str(), &x, &y, &n, force_channels);
//Check too see if the image loaded.
if (!image_data) {
fprintf (stderr, "ERROR: could not load %s\n", Source);
return false;
}
//Copy the image data to the selected target.
glTexImage2D (
GL_TEXTURE_2D,
0,
GL_RGBA,
x,
y,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
image_data
);
free (image_data);
TextureMap.insert(std::pair<std::string, GLuint*>(Source,Texture));
return true;
}
GLuint* TextureLoader::GetImage(std::string TextureID)
{
return TextureMap.find(TextureID)->second;
}
bool TextureLoader::CheckTextureExsist(std::string TextureID)
{
if(TextureMap.find(TextureID) == TextureMap.end())
{
return false;
}
else
return true;
}
This is how i am drawing.
glBindTexture(GL_TEXTURE_2D, *TextureID);
glMaterialfv(GL_FRONT , GL_AMBIENT, Ambient);
glMaterialfv(GL_FRONT , GL_DIFFUSE, Diffuse);
glMaterialfv(GL_FRONT , GL_SPECULAR, Specular);
glMaterialf(GL_FRONT , GL_SHININESS, Shininess);
glVertexPointer(3,GL_FLOAT,0,&Vertices[0]);
glNormalPointer(GL_FLOAT,0,&Normals[0]);
glTexCoordPointer(2,GL_FLOAT,0,&TextureCoords[0]);
glPushMatrix();
glScalef(Scale[0],Scale[1],Scale[2]);
glTranslatef(Translate[0],Translate[1],Translate[2]);
glRotatef(Rotate[0],Rotate[1],Rotate[2],Rotate[3]);
glDrawArrays(GL_TRIANGLES, 0,(GLsizei)(Vertices.size()/3));
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, NULL);
The TextureID gets passed the pointer, of the texture handle . The handle does change during run time to the different handles but it does draws the last texture that i loaded in, regardless of texture handle.
The problem is binding to GL_TEXTURE_CUBE_MAP in your LoadTexture function:
glBindTexture (GL_TEXTURE_CUBE_MAP, *Texture);
Change that to
glBindTexture(GL_TEXTURE_2D, *Texture);
I would also suggest to use GLuint instead of a GLuint* and store that into the map. The only reason glGenTextures takes a pointer is because it can also output to an array of GLuint.

OpenGL Applying Texture to Tessellation

I'm trying to take a concave polygon and apply an image to it as a texture. The polygon can have multiple contours, both internal holes and external "islands". It can be any shape, but will be smaller than the image and will fit inside it. It does not necessarily touch the edges of the image.
I've successfully displayed the tessellated polygon, and textured a simple square, but can't get the two to work together.
Here's how I'm loading the texture:
GLuint texture;
int width, height;
BYTE * data;
FILE * file;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL ) return 0;
// allocate buffer
width = 256;
height = 256;
data = (BYTE *)malloc( width * height * 3 );
// read texture data
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 );
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, wrap ? GL_REPEAT : GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap ? GL_REPEAT : GL_CLAMP );
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width,height, GL_RGB, GL_UNSIGNED_BYTE, data );
free( data );
return texture;
Here's the tessellation function:
GLuint tessellate1()
{
GLuint id = glGenLists(1); // create a display list
if(!id) return id; // failed to create a list, return 0
GLUtesselator *tess = gluNewTess(); // create a tessellator
if(!tess) return 0; // failed to create tessellation object, return 0
GLdouble quad1[4][3] = { {-1,3,0}, {0,0,0}, {1,3,0}, {0,2,0} };
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GLTexture::LoadTextureRAW("texture.raw", true));
// register callback functions
gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK *)())tessBeginCB);
gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK *)())tessEndCB);
gluTessCallback(tess, GLU_TESS_ERROR, (void (CALLBACK *)())tessErrorCB);
gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK *)())tessVertexCB);
glNewList(id, GL_COMPILE);
glColor3f(1,1,1);
gluTessBeginPolygon(tess, 0); // with NULL data
gluTessBeginContour(tess);
gluTessVertex(tess, quad1[0], quad1[0]);
gluTessVertex(tess, quad1[1], quad1[1]);
gluTessVertex(tess, quad1[2], quad1[2]);
gluTessVertex(tess, quad1[3], quad1[3]);
gluTessEndContour(tess);
gluTessEndPolygon(tess);
glEndList();
gluDeleteTess(tess); // delete after tessellation
glDisable(GL_TEXTURE_2D);
setCamera(0, 0, 5, 0, 0, 0);
return id; // return handle ID of a display list
}
Here's the tessellation vertex callback function:
// cast back to double type
const GLdouble *ptr = (const GLdouble*)data;
double dImageX = -1, dImageY = -1;
//hardcoded extents of the polygon for the purposes of testing
int minX = 607011, maxX = 616590;
int minY = 4918219, maxY = 4923933;
//get the % coord of the texture for a poly vertex. Assumes image and poly bounds are the same for the purposes of testing
dImageX = (ptr[0] - minX) / (maxX - minX);
dImageY = (ptr[1] - minY) / (maxY - minY);
glTexCoord2d(dImageX, dImageY);
glVertex2d(ptr[0], ptr[1]);
And here's the display callback:
void displayCB()
{
// clear buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// save the initial ModelView matrix before modifying ModelView matrix
glPushMatrix();
// tramsform camera
glTranslatef(0, 0, cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0); // pitch
glRotatef(cameraAngleY, 0, 1, 0); // heading
// draw meshes
glCallList(listId1); //id of the tessellated poly
// draw info messages
showInfo();
glPopMatrix();
glutSwapBuffers();
}
The results of this are a correctly drawn polygon with no texture applied.
// init
glGenTextures( 1, &texture );
// vertex callback
glBindTexture(GL_TEXTURE_2D, 1);
I don't think the first ID returned by glGenTextures() is required to be 1.
Try using texture instead of 1 in your glBindTexture() call.
Also, there's really no reason to enable texturing and re-bind the texture for every vertex. Just do it once before you call into the tesselator.
You're not capturing the texture binding and Enable inside the display list, so it's not going to be taken into account when you replay it. So, either:
Capture the BindTexture and Enable inside the display list, or
BindTexture and Enable(TEXTURE_2D) before calling CallList
The problem was the glDisable(GL_TEXTURE_2D) call in the tessellation function. After removing it, the texture was applied correctly.

Can't load .png image using opengl texture

#include <stdio.h>
#include <GL/gl.h>
#include <GL/glut.h>
#define KEY_ESCAPE 27
void display();
void keyboard(unsigned char,int,int);
GLuint LoadTextureRAW( const char * filename, int wrap );
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH );
glutInitWindowSize(600,400);
glutCreateWindow("Opengl Test");
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
void display() {
GLuint texture=LoadTextureRAW("ball.png",1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,texture);
glBegin( GL_QUADS );
glTexCoord2d(0.0,0.0); glVertex2d(0.0,0.0);
glTexCoord2d(1.0,0.0); glVertex2d(1.0,0.0);
glTexCoord2d(1.0,1.0); glVertex2d(1.0,1.0);
glTexCoord2d(0.0,1.0); glVertex2d(0.0,1.0);
glEnd();
glutSwapBuffers();
}
// load a 256x256 RGB .RAW file as a texture
GLuint LoadTextureRAW( const char * filename, int wrap )
{
GLuint texture;
int width, height;
// BYTE * data;
int *data;
FILE * file;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL ) return 0;
// allocate buffer
width = 256;
height = 256;
data = (int*)malloc( width * height * 3 );
// read texture data
fread( data, width * height * 3, 1, file );
fclose( file );
// allocate a texture name
glGenTextures( 1, &texture );
// select our current texture
glBindTexture( GL_TEXTURE_2D, texture );
// select modulate to mix texture with color for shading
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// when texture area is small, bilinear filter the closest mipmap
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST );
// when texture area is large, bilinear filter the first mipmap
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// if wrap is true, the texture wraps over at the edges (repeat)
// ... false, the texture ends at the edges (clamp)
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
wrap ? GL_REPEAT : GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
wrap ? GL_REPEAT : GL_CLAMP );
// build our texture mipmaps
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
GL_RGB, GL_UNSIGNED_BYTE, data );
// free buffer
free( data );
return texture;
}
void keyboard(unsigned char key, int mousePositionX, int mousePositionY) {
switch ( key ) {
case KEY_ESCAPE:
exit ( 0 );
break;
default:
break;
}
}
I followed this, http://www.nullterminator.net/gltexture.html
What should i do?
"LoadTextureRAW()" is not for PNG files. You will need a third party library like libpng to decode a png file, because they are compressed.
If you don't want to implement libpng yourself, which is kind of advanced, then you can probably find a wrapper library on google somewhere.
You can find a minimal implementation of libpng here:
http://zarb.org/~gc/html/libpng.html

rendering SDL_TTF text onto openGL Red Square instead of text

I've been attempting to render text onto an openGL window using SDL and the SDL_TTF library on windows XP, VS2010.
Versions:
SDL version 1.2.14
SDL TTF devel 1.2.10
openGL (version is at least 2-3 years old).
I have successfully created an openGL window using SDL / SDL_image and can render lines / polygons onto it with no problems.
However, moving onto text it appears that there is some flaw in my current program, I am getting the following result when trying this code here
for those not willing to pastebin here are only the crutial code segments:
void drawText(char * text) {
glLoadIdentity();
SDL_Color clrFg = {0,0,255,0}; // set colour to blue (or 'red' for BGRA)
SDL_Surface *sText = TTF_RenderUTF8_Blended( fntCourier, text, clrFg );
GLuint * texture = create_texture(sText);
glBindTexture(GL_TEXTURE_2D, *texture);
// draw a polygon and map the texture to it, may be the source of error
glBegin(GL_QUADS); {
glTexCoord2i(0, 0); glVertex3f(0, 0, 0);
glTexCoord2i(1, 0); glVertex3f(0 + sText->w, 0, 0);
glTexCoord2i(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
glTexCoord2i(0, 1); glVertex3f(0, 0 + sText->h, 0);
} glEnd();
// free the surface and texture, removing this code has no effect
SDL_FreeSurface( sText );
glDeleteTextures( 1, texture );
}
segment 2:
// create GLTexture out of SDL_Surface
GLuint * create_texture(SDL_Surface *surface) {
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// The SDL_Surface appears to have BGR_A formatting, however this ends up with a
// white rectangle no matter which colour i set in the previous code.
int Mode = GL_RGB;
if(surface->format->BytesPerPixel == 4) {
Mode = GL_RGBA;
}
glTexImage2D(GL_TEXTURE_2D, 0, Mode, surface->w, surface->h, 0, Mode,
GL_UNSIGNED_BYTE, surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return &texture;
}
Is there an obvious bit of code I am missing?
Thank you for any help on this subject.
I've been trying to learn openGL and SDL for 3 days now, so please forgive any misinformation on my part.
EDIT:
I notice that using
TTF_RenderUTF8_Shaded
TTF_RenderUTF8_Solid
Throw a null pointer exception, meaning that there is an error within the actual text rendering function (I suspect), I do not know how this means TTF_RenderUTF8_Blended returns a red square but I suspect all troubles hinge on this.
I think the problem is in the glEnable(GL_TEXTURE_2D) and glDisable(GL_TEXTURE_2D) functions which must be called every time the text is painted on the screen.And maybe also the color conversion between the SDL and GL surface is not right.
I have combined create_texture and drawText into a single function that displays the text properly. That's the code:
void drawText(char * text, TTF_Font* tmpfont) {
SDL_Rect area;
SDL_Color clrFg = {0,0,255,0};
SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended( tmpfont, text, clrFg ));
area.x = 0;area.y = 0;area.w = sText->w;area.h = sText->h;
SDL_Surface* temp = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA,sText->w,sText->h,32,0x000000ff,0x0000ff00,0x00ff0000,0x000000ff);
SDL_BlitSurface(sText, &area, temp, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sText->w, sText->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS); {
glTexCoord2d(0, 0); glVertex3f(0, 0, 0);
glTexCoord2d(1, 0); glVertex3f(0 + sText->w, 0, 0);
glTexCoord2d(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
glTexCoord2d(0, 1); glVertex3f(0, 0 + sText->h, 0);
} glEnd();
glDisable(GL_TEXTURE_2D);
SDL_FreeSurface( sText );
SDL_FreeSurface( temp );
}
screenshot
I'm initializing OpenGL as follows:
int Init(){
glClearColor( 0.1, 0.2, 0.2, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( 0, 600, 300, 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if( glGetError() != GL_NO_ERROR ){
return false;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
}
I think you should just add glEnable(GL_BLEND), because the code for the text surface says TTF_RenderUTF8_Blended( fntCourier, text, clrFg ) and you have to enable the blending abilities of opengl.
EDIT
Okay, I finally took the time to put your code through a compiler. Most importantly, compiler with -Werror so that warning turn into errors
GLuint * create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return &texture;
}
I didn't see it first, because that's something like C coder's 101 and is quite unexpected: You must not return pointers to local variables!. Once the functions goes out of scope the pointer returned will point to nonsense only. Why do you return a pointer at all? Just return a integer:
GLuint create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return texture;
}
Because of this you're also not going to delete the texture afterward. You upload it to OpenGL, but then loose the reference to it.
Your code misses a glEnable(GL_TEXTURE_2D) that's why you can't see any effects of texture. However your use of textures is suboptimal. They way you did it, you recreate a whole new texture each time you're about to draw that text. If that happens in a animation loop, you'll
run out of texture memory rather soon
slow it down significantly
(1) can be addressed by not generating a new texture name each redraw
(2) can be addresses by uploading new texture data only when the text changes and by not using glTexImage2D, but glTexSubImage2D (of course, if the dimensions of the texture change, it must be glTexImage2D).
EDIT, found another possible issue, but first fix your pointer issue.
You should make sure, that you're using GL_REPLACE or GL_MODULATE texture environment mode. If using GL_DECAL or GL_BLEND you end up with red text on a red quad.
There was leaking memory of of the function in my previous post and the program was crashing after some time...
I improved this by separating the texture loading and displaying:
The first function must be called before the SDL loop.It loads text string into memory:
Every string loaded must have different txtNum parameter
GLuint texture[100];
SDL_Rect area[100];
void Load_string(char * text, SDL_Color clr, int txtNum, const char* file, int ptsize){
TTF_Font* tmpfont;
tmpfont = TTF_OpenFont(file, ptsize);
SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Solid( tmpfont, text, clr ));
area[txtNum].x = 0;area[txtNum].y = 0;area[txtNum].w = sText->w;area[txtNum].h = sText->h;
glGenTextures(1, &texture[txtNum]);
glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sText->w, sText->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, sText->pixels);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
SDL_FreeSurface( sText );
TTF_CloseFont(tmpfont);
}
The second one displays the string, must be called in the SDL loop:
void drawText(float coords[3], int txtNum) {
glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS); {
glTexCoord2f(0, 0); glVertex3f(coords[0], coords[1], coords[2]);
glTexCoord2f(1, 0); glVertex3f(coords[0] + area[txtNum].w, coords[1], coords[2]);
glTexCoord2f(1, 1); glVertex3f(coords[0] + area[txtNum].w, coords[1] + area[txtNum].h, coords[2]);
glTexCoord2f(0, 1); glVertex3f(coords[0], coords[1] + area[txtNum].h, coords[2]);
} glEnd();
glDisable(GL_TEXTURE_2D);
}