Unable to load textures

Apprentice
Posts: 14
Joined: 2010.01
Post: #1
Hello. I am new to iPhone game development. I am trying to load .png textures from files, but the code I am using is not working.

Code:
GLuint loadPNG(NSString* path)
    {    
    GLuint texture[1];
    glGenTextures(1, &texture[0]);
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    CGImageRef textureImage = [UIImage imageNamed:path].CGImage;
    if (textureImage == nil)
        {
        NSLog(@"Failed to load texture image");
        return 0;
        }
    NSInteger texWidth = CGImageGetWidth(textureImage);
    NSInteger texHeight = CGImageGetHeight(textureImage);
    GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);
    CGContextRef textureContext = CGBitmapContextCreate(textureData, texWidth, texHeight, 8, texWidth * 4, CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast);
    // Rotate the image
    //CGContextTranslateCTM(textureContext, 0, texHeight);
    //CGContextScaleCTM(textureContext, 1.0, -1.0);
    CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight), textureImage);
    CGContextRelease(textureContext);
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
    free(textureData);
    //[textureImage release];
    //[textureData release];
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    return texture[0];
    }

I am trying to load a 64x64 png image with an alpha channel.

Can somebody help please? Mad
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #2
Are you getting garbage in your alpha channel? Try changing the malloc to calloc.
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2010.01
Post: #3
AnotherJake Wrote:Are you getting garbage in your alpha channel? Try changing the malloc to calloc.
I tried that. Now I have a code that doesn't freeze the app, but the image loads white.

Code:
GLuint loadPNG(NSString* imageFileName)
    {
        GLuint texture[1];
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        //glBlendFunc(GL_ONE, GL_SRC_COLOR);
        glGenTextures(1, &texture[0]);
        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);
        NSString *path = [[NSBundle mainBundle] pathForResource:imageFileName ofType:@"png"];
        NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
        UIImage *image = [[UIImage alloc] initWithData:texData];
        
        if (image == nil)
            {
            NSLog(@"Do real error checking here");
                return 42;
            }
        
        GLuint width = CGImageGetWidth(image.CGImage);
        GLuint height = CGImageGetHeight(image.CGImage);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        void *imageData = calloc( height * width * 4 ,1);
        CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
        
        // Flip the Y-axis
        CGContextTranslateCTM (context, 0, height);
        CGContextScaleCTM (context, 1.0, -1.0);
        
        CGColorSpaceRelease( colorSpace );
        CGContextClearRect( context, CGRectMake( 0, 0, width, 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);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);        
        CGContextRelease(context);
        
        free(imageData);
        [image release];
        [texData release];
        NSLog(@"Value of width = %i", width); // This outputs "Value of width = 64"
        NSLog(@"Value of height = %i", height); // This outputs "Value of height = 64"
                NSLog(@"Value of texture[0] = %i", texture[0]);  // This outputs "Value of texture[0] = 1"
    return texture[0];
    }

The NSLogs confirm that the image is being loaded... but it appears white.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #4
Try this instead:
Code:
GLuint loadPNG(NSString* imageFileName)
{
    CGImageRef image = [[UIImage imageNamed:imageFileName] CGImage];
    if (image == nil)
    {
        NSLog(@"could not find %@", imageFileName);
        return 0;
    }
    GLuint width = CGImageGetWidth(image);
    GLuint height = CGImageGetHeight(image);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    void *imageData = calloc( height * width * 4 ,1);
    CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );

    // Flip the Y-axis
    CGContextTranslateCTM (context, 0, height);
    CGContextScaleCTM (context, 1.0, -1.0);
    CGColorSpaceRelease( colorSpace );
    CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image );

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);        
    CGContextRelease(context);

    free(imageData);
    CGImageRelease(image);
    return texture;
}
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2010.01
Post: #5
AnotherJake Wrote:Try this instead:
Code:
snip

Well... My code has the same result. A white square.

The console does not output that face.png wasn't found.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #6
Can you paste your drawing code here?

Here's the code I'm using for drawing this test, which is just slightly modified from the OpenGL ES Xcode template:
Code:
- (void) render
{
    // This application only creates a single context which is already set current at this point.
    // This call is redundant, but needed if dealing with multiple contexts.
    [EAGLContext setCurrentContext:context];

    // This application only creates a single default framebuffer which is already bound at this point.
    // This call is redundant, but needed if dealing with multiple framebuffers.
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
    glViewport(0, 0, backingWidth, backingHeight);

    // Replace the implementation of this method to do your own custom drawing

    const GLfloat squareVertices[] = {
        -0.5f, -0.5f,
        0.5f,  -0.5f,
        -0.5f,  0.5f,
        0.5f,   0.5f,
    };

    GLshort    genericTexCoords[] = { 0, 1, 1, 1, 0, 0, 1, 0 };

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glRotatef(3.0f, 0.0f, 0.0f, 1.0f);

    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glTexCoordPointer(2, GL_SHORT, 0, genericTexCoords);

    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, sprite);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    // This application only creates a single color renderbuffer which is already bound at this point.
    // This call is redundant, but needed if dealing with multiple renderbuffers.
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2010.01
Post: #7
Is there a reason why my posts have to be approved? Or does that go away after a certain number of posts?

Code:
texFace = loadPNG(@"face.png");
texFace is a GLuint

Code:
- (void) render
{
    // Replace the implementation of this method to do your own custom drawing
    static GLfloat x1 = 32;
    static GLfloat y1 = 48;
    static GLfloat width = 64;
    static GLfloat height = 64;
    static GLfloat hspeed = 4;
    static GLfloat vspeed = 4;
    /* static const GLfloat xpx = (GLfloat) 1/(GLfloat) 160;
     static const GLfloat ypx = (GLfloat) 1/(GLfloat) 240;
     GLfloat squareVertices[] = {
     -1+x1*xpx, 1-y1*ypx,
     -1+x1*xpx+width*xpx, 1-y1*ypx,
     -1+x1*xpx, 1-y1*ypx-height*ypx,
     -1+x1*xpx+width*xpx, 1-y1*ypx-height*ypx
     };*/
    if (!isTouch)
    {
    x1 += hspeed;
    y1 += vspeed;
    if (x1 >= 320-width || x1 <= 0)
        hspeed *= -1;
    if (y1 >= 480-height || y1 <= 0)
        vspeed *= -1;
    }
    /*static const GLubyte squareColors[] = {
        255, 255,   0, 255,
        0,   255, 255, 255,
        0,     0,   0,   0,
        255,   0, 255, 255,
    };
    
    static float transY = 0.0f;*/
    
    // This application only creates a single context which is already set current at this point.
    // This call is redundant, but needed if dealing with multiple contexts.
    [EAGLContext setCurrentContext:context];
    
    // This application only creates a single default framebuffer which is already bound at this point.
    // This call is redundant, but needed if dealing with multiple framebuffers.
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
    glViewport(0, 0, backingWidth, backingHeight);
    
    test(); //WHY THE EXPLETIVE IS THIS NOT WORKING?!?!
    
    // Use shader program
    glUseProgram(program);
    
    // Update uniform value
    //glUniform1f(uniforms[UNIFORM_TRANSLATE], (GLfloat)transY);
    //transY += 0.075f;    
    
    // Update attribute values
    //glTranslatef(0,0,0);
    if (isTouch)
    {
        x1 = xTouch-32;
        y1 = yTouch-32;
    }
    drawRect(x1,y1,64,64,128,255,64);
    drawTexture(texFace,x1,y1+64,64,64);
    /*glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
    glEnableVertexAttribArray(ATTRIB_COLOR);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);*/
    
    /*glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
    glEnableVertexAttribArray(ATTRIB_COLOR);*/
    
    // Validate program before drawing. This is a good check, but only really necessary in a debug build.
    // DEBUG macro must be defined in your debug configurations if that's not already the case.
#if defined(DEBUG)
    if (![self validateProgram:program])
    {
        NSLog(@"Failed to validate program: %d", program);
        return;
    }
#endif
    
    // This application only creates a single color renderbuffer which is already bound at this point.
    // This call is redundant, but needed if dealing with multiple renderbuffers.
    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER];
}

Code:
void test()
{
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
}

void drawRect(GLfloat x1, GLfloat y1, GLfloat width, GLfloat height, GLubyte r, GLubyte g, GLubyte b)
{
    static const GLfloat xpx = (GLfloat) 1/(GLfloat) 160;
    static const GLfloat ypx = (GLfloat) 1/(GLfloat) 240;
    GLfloat squareVertices[] = {
        -1+x1*xpx, 1-y1*ypx,
        -1+x1*xpx+width*xpx, 1-y1*ypx,
        -1+x1*xpx, 1-y1*ypx-height*ypx,
        -1+x1*xpx+width*xpx, 1-y1*ypx-height*ypx
    };
    
    const GLubyte squareColors[] = {
        r,g,b,255,
        r,g,b,255,
        r,g,b,255,
        r,g,b,255
    };
    
    const GLfloat texCoords[] = {
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0
    };
    glBindTexture(GL_TEXTURE_2D, 0);
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_NORMAL, 2, GL_FLOAT, 0, 0, texCoords);
    glEnableVertexAttribArray(ATTRIB_NORMAL);
    glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
    glEnableVertexAttribArray(ATTRIB_COLOR);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindTexture(GL_TEXTURE_2D, 0);
    /*glBindTexture(GL_TEXTURE_2D, 0);
    glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
    glColorPointer(4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindTexture(GL_TEXTURE_2D, 0);*/
}

void drawTexture(GLuint tex, GLfloat x1, GLfloat y1, GLfloat width, GLfloat height)
{
    static const GLfloat xpx = (GLfloat) 1/(GLfloat) 160;
    static const GLfloat ypx = (GLfloat) 1/(GLfloat) 240;
    GLfloat squareVertices[] = {
        -1+x1*xpx, 1-y1*ypx,
        -1+x1*xpx+width*xpx, 1-y1*ypx,
        -1+x1*xpx, 1-y1*ypx-height*ypx,
        -1+x1*xpx+width*xpx, 1-y1*ypx-height*ypx
    };
    
    const GLubyte squareColors[] = {
        128,128,128,255,
        128,128,128,255,
        128,128,128,255,
        128,128,128,255
    };
    
    const GLfloat texCoords[] = {
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0
    };
    glBindTexture(GL_TEXTURE_2D, tex);
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_NORMAL, 2, GL_FLOAT, 0, 0, texCoords);
    glEnableVertexAttribArray(ATTRIB_NORMAL);
    glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
    glEnableVertexAttribArray(ATTRIB_COLOR);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindTexture(GL_TEXTURE_2D, 0);
}


GLuint loadPNG(NSString* imageFileName)
{
    CGImageRef image = [[UIImage imageNamed:imageFileName] CGImage];
    if (image == nil)
    {
        NSLog(@"could not find %@", imageFileName);
        return 0;
    }
    GLuint width = CGImageGetWidth(image);
    GLuint height = CGImageGetHeight(image);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    void *imageData = calloc( height * width * 4 ,1);
    CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
    
    // Flip the Y-axis
    CGContextTranslateCTM (context, 0, height);
    CGContextScaleCTM (context, 1.0, -1.0);
    CGColorSpaceRelease( colorSpace );
    CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image );
    
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);        
    CGContextRelease(context);
    
    free(imageData);
    CGImageRelease(image);
    return texture;
}



I included everything that you might ask about. Also, those are basically all of the modifications I have made to the Open GL ES default template project.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #8
wademcgillis Wrote:Is there a reason why my posts have to be approved? Or does that go away after a certain number of posts?
Sorry about that. The owner of the forum made it so that the first few posts have to be approved so that we manually filter out spammers and spam bots. It's a real bother, I know, but it is effective. I didn't have to approve this last post of yours so I assume you're good to go now.

wademcgillis Wrote:...

I included everything that you might ask about. Also, those are basically all of the modifications I have made to the Open GL ES default template project.

Aww rats.. I haven't even so much as *glanced* at OpenGL ES 2.0 so I can't really help, sorry. Sad

I don't really have any need for 2.0 yet so I just stick to 1.1 and call it good. That loader should work just fine though, so it is more than likely that your problem is not related to that. Using that loader and the code I posted above for drawing, does work for me in the ES1Renderer in the template.

Until someone more knowledgeable in ES 2 comes along, or you switch to ES 1, all I can offer is a link to the OpenGL FAQ. In particular, you might find some useful tips in the "How to Debug" section.
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2010.01
Post: #9
AnotherJake Wrote:Sorry about that. The owner of the forum made it so that the first few posts have to be approved so that we manually filter out spammers and spam bots. It's a real bother, I know, but it is effective. I didn't have to approve this last post of yours so I assume you're good to go now.



Aww rats.. I haven't even so much as *glanced* at OpenGL ES 2.0 so I can't really help, sorry. Sad

I don't really have any need for 2.0 yet so I just stick to 1.1 and call it good. That loader should work just fine though, so it is more than likely that your problem is not related to that. Using that loader and the code I posted above for drawing, does work for me in the ES1Renderer in the template.

Until someone more knowledgeable in ES 2 comes along, or you switch to ES 1, all I can offer is a link to the OpenGL FAQ. In particular, you might find some useful tips in the "How to Debug" section.

Well, I only chose 2.0 because I heard it was faster... I don't plan on doing 3D or anything graphically intensive, I just wanted my apps to run without lag. But thanks for the help.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #10
wademcgillis Wrote:Well, I only chose 2.0 because I heard it was faster... I don't plan on doing 3D or anything graphically intensive, I just wanted my apps to run without lag. But thanks for the help.

I hadn't heard that there was any performance difference between the two; only that 2.0 breaks away from the fixed pipeline so it's more flexible. I know 2.0 only runs on the newer hardware though, so the performance connection may be being confused with that. In fact, the only device I *know* can use 2.0 is the 3GS. So if you're only developing for ES 2 you're developing for a very small portion of the overall market. I would wager that very few, if any, developers around here develop for ES 2 yet, specifically because of the limited market.

If you're not planning on doing anything graphically intensive then ES 1.1 should be plenty sufficient. Wink
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2010.01
Post: #11
I switched to ES 1.1 because of what you said, and your code works perfectly. Now I can continue making iPhone OS apps. Thanks.
Quote this message in a reply
Sage
Posts: 1,234
Joined: 2002.10
Post: #12
AnotherJake Wrote:I hadn't heard that there was any performance difference between the two; only that 2.0 breaks away from the fixed pipeline so it's more flexible.

ES2 can be significantly faster than ES1.1 on the same hardware. The increased flexibility in GLSL usually allows you to express your rendering algorithm more precisely than ES1.1's fixed function transform and TexEnv can. Which means you can skip steps, which means higher performance.

As a practical example: take the hue rotation filter in the GLImageProcessing sample code. In ES1.1 it is expressed using the DOT3 TexEnv combiner, which requires two units per dot product, because the input to DOT3 must be pre-scaled into the correct range. Rotating all R,G,B channels independently requires 6 units total. MBX-based devices only have two textures units, so that breaks down into three separate passes, each with a masked framebuffer write.

By comparison, the equivalent fragment shader in ES2 simply contains 3 dot products, precisely expressing a color matrix multiply. Everything executes in a single pass. If you benchmark this, you'll see it runs about five times faster on the same hardware.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #13
Interesting. Thanks for the clarification arekkusu Smile

So then the only thing remaining against using ES2 is that it's only available on a small segment of the iPhone/iPod Touch market at this point.

Question is: when will the market of ES2 hardware grow large enough that the majority of developers will start transitioning to ES2? Just for the fun of it, I'll put my money on 18 months from now (at the earliest).
Quote this message in a reply
Apprentice
Posts: 9
Joined: 2010.04
Post: #14
Is the iPADDY in fact "ES2", Jake.2 ?

(As you know I know absolutely nothing about it, I just copy and paste code to move sprites around. I didn't even know there was a "1.1" or "2" until I saw your discussion above :-) )
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #15
It is exactly the same API as you get on iPhone, so yes, you can do ES 2 or ES 1.1. iPad is starting to look like a good excuse for me to start learning ES 2, now that you mention it.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Unable to implement OES_matrix_palette mariocaprino 0 2,123 Sep 14, 2010 09:43 AM
Last Post: mariocaprino
  How do you load PNGs on a C++ program? riruilo 8 6,456 Oct 20, 2009 05:20 PM
Last Post: miketucker
  unable to locate a suitable developer disk image Parystec 16 14,418 Oct 7, 2008 10:25 AM
Last Post: mamweb