Can anyone tell me what's going on, a better way to do this, point me to an Obj-C class to do this, or tell me to quit while I'm way behind?! This has been 3 weeks of nothing but torture trying to get PNG loading working. Thanks ahead of time.

There's an obvious problem with your code, but... if you've spent three weeks on this, then your biggest problem is that you need to learn how to use the debugger.

Step through your function one line at a time in the debugger and watch it execute. At each line, check all the variables and make sure they're what you expect. When you hit glTexImage, look at the pointer you're passing in (learn how to use gdb) and make sure the pixels you're passing to GL are correct.

Now, for your obvious bug. Take a look at the texture target you're binding when you load the texture. Now compare with the texture target you're binding when you draw the texture. OpenGL Profiler can help you find this sort of bug-- just break on your draw call and look at the current state and the current textures.

arekkusu Wrote:There's an obvious problem with your code, but... if you've spent three weeks on this, then your biggest problem is that you need to learn how to use the debugger.

Step through your function one line at a time in the debugger and watch it execute. At each line, check all the variables and make sure they're what you expect. When you hit glTexImage, look at the pointer you're passing in (learn how to use gdb) and make sure the pixels you're passing to GL are correct.

Now, for your obvious bug. Take a look at the texture target you're binding when you load the texture. Now compare with the texture target you're binding when you draw the texture. OpenGL Profiler can help you find this sort of bug-- just break on your draw call and look at the current state and the current textures.

I have already stepped through using the GDB debugger, and my biggest issue is that I'm not sure what I should be looking for. Also, when I run OpenGL Profiler, it refuses to attach to my project. Any idea why? To clear up the naming issue I believe you are trying to highlight: shortly after the call textureFromImage: is called, [o setTexture:tex]; is sent.

EDIT: Using the debugger, GLuint tex is initialized to 107808. After the load it is still 107808. When my object is drawn it is STILL 107808. What's going on?

In gdb, you're looking for anything unexpected, like the NSBitmapImageRep being NULL, or pixelsWide not being the size of your image. You should get in the habit of using assertions-- in your debug build, assert that the image was loaded, and that no GL errors occurred.

If Profiler won't attach to your app, launch it from Profiler instead-- add your app with the + button in Profiler's main window. Set a breakpoint on something you know you'll hit, like CGLFlushDrawable. Then launch your application, you should break the first time you're about to swap. At that point, you can inspect all of the GL state (the changed "from default state" checkbox is your friend here) as well as the current content of the back/depth/stencil buffers and all resources such as textures.

To be very specific-- in your image loader, you're binding and creating a RECTANGLE texture. But then when you draw, you're binding a 2D texture. Of course that's not going to work. Profiler will show you this-- in the resource viewer you should see a RECTANGLE texture with the name that you Gen'd. And in the state inspector you'll see that TEXTURE_2D is enabled, not TEXTURE_RECTANGLE. Profiler's "break on errors" checkbox should also catch this, because it's illegal to bind a texture name to a target different than the one it was initially used as.

arekkusu Wrote:In gdb, you're looking for anything unexpected, like the NSBitmapImageRep being NULL, or pixelsWide not being the size of your image. You should get in the habit of using assertions-- in your debug build, assert that the image was loaded, and that no GL errors occurred.

If Profiler won't attach to your app, launch it from Profiler instead-- add your app with the + button in Profiler's main window. Set a breakpoint on something you know you'll hit, like CGLFlushDrawable. Then launch your application, you should break the first time you're about to swap. At that point, you can inspect all of the GL state (the changed "from default state" checkbox is your friend here) as well as the current content of the back/depth/stencil buffers and all resources such as textures.

To be very specific-- in your image loader, you're binding and creating a RECTANGLE texture. But then when you draw, you're binding a 2D texture. Of course that's not going to work. Profiler will show you this-- in the resource viewer you should see a RECTANGLE texture with the name that you Gen'd. And in the state inspector you'll see that TEXTURE_2D is enabled, not TEXTURE_RECTANGLE. Profiler's "break on errors" checkbox should also catch this, because it's illegal to bind a texture name to a target different than the one it was initially used as.

OH! I had no idea that OGL would be unable to convert between a PoT image size and a variable image size. Alright, we're getting somewhere. So, with those changes in place, specifically:

I end up with a quad colored with a solid single color (dark red in this case). Any idea what may be causing it to draw only this color? I have not yet tried to run my project from the Profiler, I'll let you know how that goes. Thanks!

USED OGLProfiler: How do I set breakpoints? And I've been tracking my texture, it's value is STILL 107808. I have no idea how that's happening.

Not to detract from what you're learning right now, but here's some more code donation that might help for comparison. To use it:

- create a new iPhone project using the "OpenGL ES Application" template
- add CoreGraphics.framework
- drag a POT image into the Resources group, named "Sprite.png"
- copy and paste this code to replace all the code in EAGLView.m [the only major addition to the template code is LoadTextureWithAlpha]:

So, now there are two problems, both of which stem from you not having read the documentation.

First, this isn't an issue of converting NPOT images or anything like that. When you bind an object, like with glBindTexture, you're binding a specific name in a specific target. Another word for target is "namespace" if that helps you understand it.

If you create a 2D texture object, and try to use it as a vertex buffer object, do you expect OpenGL to magically convert it for you? Of course not. What if you try to use it as a 3D texture object? A 2D texture object is sort of like a 3D texture object with only one slice of data, but they're technically completely different. They're in different namespaces. So this is an error. You should call glGetError at least once (at the end of your main rendering loop, protected by #if DEBUG) to catch this kind of bug. It's your bug-- you're misusing the API.

Second, RECTANGLE texture objects have some specific differences from 2D texture objects. That's why they exist-- they're different. One of the differences is how the texture coordinates are used. You need to pass in unnormalized coordinates. If you pass in [0,1] you're going to sample exactly one pixel, so you see the same color everywhere.

arekkusu Wrote:So, now there are two problems, both of which stem from you not having read the documentation.

First, this isn't an issue of converting NPOT images or anything like that. When you bind an object, like with glBindTexture, you're binding a specific name in a specific target. Another word for target is "namespace" if that helps you understand it.

If you create a 2D texture object, and try to use it as a vertex buffer object, do you expect OpenGL to magically convert it for you? Of course not. What if you try to use it as a 3D texture object? A 2D texture object is sort of like a 3D texture object with only one slice of data, but they're technically completely different. They're in different namespaces. So this is an error. You should call glGetError at least once (at the end of your main rendering loop, protected by #if DEBUG) to catch this kind of bug. It's your bug-- you're misusing the API.

Second, RECTANGLE texture objects have some specific differences from 2D texture objects. That's why they exist-- they're different. One of the differences is how the texture coordinates are used. You need to pass in unnormalized coordinates. If you pass in [0,1] you're going to sample exactly one pixel, so you see the same color everywhere.

Read the documentation, it explains all of this.

Awesome! That explains a lot. Changing the draw code to glTexCoord2f(256.0f, 256.0f) fixed it...except it's upside down. Is there a way to invert the image before storage as the texture, or is that explained in the documentation? I'm sensing some annoyance on your part, arekksu, and I would just like to say thank you. Myself and others thank you for your help here. Thanks again, and you're right: I really should just RTFM, but I'm in a bit of rush... However, once this is ready to go, I will be sure to read the appropriate documentation before bugging you guys.

I'm happy to explain these things, but I've started a FAQ thread to attempt to document some of these recurring issues in one place. Texturing is very easy... after you've figured it out once. But these questions keep coming up.

As for flipping the image, the documentation explains how both GL's coordinate system and a texture's image is treated with the origin in the lower left. Yes, this is upside down compared to every file format out there. Yes, everybody runs into this. There are several ways to deal with it, the simplest way is to flip your geometry upside down.

arekkusu Wrote:I'm happy to explain these things, but I've started a FAQ thread to attempt to document some of these recurring issues in one place. Texturing is very easy... after you've figured it out once. But these questions keep coming up.

As for flipping the image, the documentation explains how both GL's coordinate system and a texture's image is treated with the origin in the lower left. Yes, this is upside down compared to every file format out there. Yes, everybody runs into this. There are several ways to deal with it, the simplest way is to flip your geometry upside down.

So you recommend doing a glRotatef(180.0f, 0.0f, 0.0f, 1.0f) before drawing to solve this issue? I'm somewhat surprised that NSImage does not have a method to invert the image. Again, thanks for the help!

I wouldn't use glRotate per draw. You can generally assume that all of your images are going to be loaded in the same way, so you can flip your entire coordinate system once so that the origin is at top left. The place to do that is the projection matrix.

If you do this, you still need to keep in mind that the GL API expects the origin at lower left, and you can't control non-drawing API with a matrix. For example, if you use glReadPixels, those coordinates will be upside down compared to your drawing.

If it's conceptually easier for you to leave the origin alone, then of course you can flip images when you load them. That's just some extra cost to shuffle the data around.

arekkusu Wrote:I wouldn't use glRotate per draw. You can generally assume that all of your images are going to be loaded in the same way, so you can flip your entire coordinate system once so that the origin is at top left. The place to do that is the projection matrix.

If you do this, you still need to keep in mind that the GL API expects the origin at lower left, and you can't control non-drawing API with a matrix. For example, if you use glReadPixels, those coordinates will be upside down compared to your drawing.

If it's conceptually easier for you to leave the origin alone, then of course you can flip images when you load them. That's just some extra cost to shuffle the data around.

Well, after some thought, my system works really well with the coordinate system that I have now. It certainly seems like the minor overhead of flipping the image data would be preferred over having to completely re-think my coordinate system. Of course, I say all this before seeing HOW to flip the data... How would you recommend flipping the data and what are some of the caveats of the technique you recommend?