Reputation: 1903
I'm working on a simple little game for the iPhone, and I'd like to use textures, however I can't quite seem to get it working...
After some research I found this page and this site. Both are great references, and taught me a little bit about textures, however, after loading a texture using either function I can't get the texture displayed, here's what my code looks like:
Very Simple Texture Display Function (not working)
void drawTexture(GLuint texture, float x, float y, float w, float h)
{
glBindTexture(GL_TEXTURE_2D,texture);
GLfloat box[] = {x,y+h, x+w,y+h, x,y, x+w,y};
GLfloat tex[] = {0,0, 1,0, 1,1, 0,1};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0,box);
glTexCoordPointer(2, GL_FLOAT, 0, tex);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
Normally, I'd not create an array every single frame only to display an image, but this is just an example. When I run this function, I get nothing. Blank- no image, nothing (unless of course I'd previously enabled a color array and hadn't disabled it afterwards)
Second Simple Display Function (this one uses a quick little class)
void draw_rect(RectObject* robj){
glVertexPointer(2, GL_FLOAT, 0, [robj vertices]);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, [robj colors]);
glEnableClientState(GL_COLOR_ARRAY);
if ([robj texture] != -1){
glEnable(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glClientActiveTexture([robj texture]);
glTexCoordPointer(2, GL_FLOAT, 0, defaultTexCoord);
glBindTexture(GL_TEXTURE_2D, [robj texture]);
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_COORD_ARRAY);
}
This function on the other hand, does change the display, instead of outputting the texture however it outputs a black square...
Setup Background
In my init function I'm calling
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_SRC_COLOR);
Two LONG Texture Loading Functions
struct Texture2D LoadImage(NSString* path)
{
struct Texture2D tex;
tex.texture = -1;
// Id for texture
GLuint texture;
// Generate textures
glGenTextures(1, &texture);
// Bind it
glBindTexture(GL_TEXTURE_2D, texture);
// Set a few parameters to handle drawing the image
// at lower and higher sizes than original
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
//NSString *path = [[NSString alloc] initWithUTF8String:imagefile.c_str()];
path = [[NSBundle mainBundle] pathForResource:path ofType:@""];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
return tex;
// Get Image size
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// Allocate memory for image
void *imageData = malloc( height * width * 4 );
CGContextRef imgcontext = CGBitmapContextCreate(
imageData, width, height, 8, 4 * width, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGColorSpaceRelease( colorSpace );
CGContextClearRect( imgcontext,
CGRectMake( 0, 0, width, height ) );
CGContextTranslateCTM( imgcontext, 0, height - height );
CGContextDrawImage( imgcontext,
CGRectMake( 0, 0, width, height ), image.CGImage );
// Generate texture in opengl
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
// Release context
CGContextRelease(imgcontext);
// Free Stuff
free(imageData);
[image release];
[texData release];
// Create and return texture
tex.texture=texture;
tex.width=width;
tex.height=height;
return tex;
}
GLuint makeTexture(NSString* path){
GLuint texture[1]={-1};
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
path = [[NSBundle mainBundle] pathForResource:path ofType:@"png"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(@"Do real error checking here");
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextTranslateCTM( context, 0, height - height );
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context);
free(imageData);
[image release];
[texData release];
return texture[0];
}
If you could point me in the right direction it would be much appreciated.
Upvotes: 1
Views: 2876
Reputation: 71
The fun does work.
void drawTexture(GLuint texture, float x, float y, float w, float h)
{
glBindTexture(GL_TEXTURE_2D,texture);
glEnable(GL_TEXTURE_2D);
GLfloat box[] = {x,y+h, x+w,y+h, x,y, x+w,y};
GLfloat tex[] = {0,0, 1,0, 1,1, 0,1};
glTexCoordPointer(2, GL_FLOAT, 0, tex);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, box);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
but we should relate to the right coordinate for texture. wo should change the code
form
GLfloat box[] = {x,y+h, x+w,y+h, x,y, x+w,y};
GLfloat tex[] = {0,0, 1,0, 1,1, 0,1};
to
GLfloat box[] = {x,y+h, x+w,y+h, x,y, x+w,y};
GLfloat tex[] = { 0.0f,1.0f, 1.0f,1.0f, 0.0f,0.0f, 1.0f, 0.0f };
Thanks stackoverflow. Thanks your help. Good luck!
Upvotes: 0
Reputation: 781
If one of the textures work and the other not, could it be a problem with the texture file ? Dimensions sometimes can trick you, try to use the same file (the one working) on both textures and see if that solved. If it does it's a problem with the texture file.
Upvotes: 1
Reputation: 45968
First of all, your draw_rect
function has an error. Don't call glClientActiveTexture
, it is used for multi-texturing and you don't need it. Calling it with a texture object will either bind some really strange texture unit or, most likely, result in an error.
And in the drawTexture
function you are actually drawing the triangles in clockwise order. Assuming you didn't flip the y-direction in the projection matrix or something similar, if you have back-face culling enabled your whole geometry will get culled away. Try calling glDisable(GL_CULL_FACE)
, although back-face culling should be disabled by default. Or even better, change your vertices to counter-clockwise ordering:
box[] = { x,y+h, x,y, x+w,y+h, x+w,y };
You also have a mismatch of texture coordinates to vertices in your drawTexture
function, but this shouldn't cause the texture not to be drawn, but rather just look a bit strange. Considering the changes to counter-clockwise ordering from the last paragraph, the texture coordinates should be:
tex[] = { 0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f, 1.0f, 0.0f };
EDIT: Your draw_rect
function is also messing up the state, because you enable the vertex and color arrays, but then don't disable them again when you are finished with rendering. When you now want to draw something different without a color array (like in drawTexture
), the color array is still enabled and uses some arbitrary data. So you should add
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
right after
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
in draw_rect
.
EDIT: And you should also wrap the drawTexture function in a pair of glEnable(GL_TEXTURE_2D)
and glDisable(GL_TEXTURE_2D)
. You enable texturing in the initialization code, which is wrong. You should set all neccessary state right before rendering, especially such highly object-dependent state like texturing. For example once you call draw_rect
before drawTexture
, you end up with disabled texturing, although you enabled it in the initialization code and thought it to be always enabled. Do you see that this is not a good idea?
EDIT: I just spotted another error. In draw_rect
you call glEnable
and glDisable
with GL_TEXTURE_COORD_ARRAY
, which is wrong. You have to use glEnableClientState
and glDisableClientState
for enabling/disabling vertex arrays, like you did int drawTexture
.
So as a little mid-way conclusion your functions should actually look like:
void drawTexture(GLuint texture, float x, float y, float w, float h)
{
glBindTexture(GL_TEXTURE_2D,texture);
glEnable(GL_TEXTURE_2D);
GLfloat box[] = {x,y+h, x+w,y+h, x,y, x+w,y};
GLfloat tex[] = {0,0, 1,0, 1,1, 0,1};
glTexCoordPointer(2, GL_FLOAT, 0, tex);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, box);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
void draw_rect(RectObject* robj)
{
if ([robj texture] != -1)
{
glBindTexture(GL_TEXTURE_2D, [robj texture]);
glEnable(GL_TEXTURE_2D);
glTexCoordPointer(2, GL_FLOAT, 0, defaultTexCoord);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
glColorPointer(4, GL_UNSIGNED_BYTE, 0, [robj colors]);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, [robj vertices]);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
if ([robj texture] != -1)
{
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
}
Upvotes: 4