iPhone HUD / GUI Newbie
Hey Everyone,
I'm a big newb when it comes to the iphone, so please help me out
I'm trying to create a HUD for my game, but am having problems drawing it. I've been looking at this for a couple hours read a bunch of posts and still can't figure out what I'm doing wrong...
Here is the important parts of my code, I've condensed everything into one function so it's easy to follow.
Now I would expect this code to draw my window at the top left corner of the screen with a 100X100 dimension, utilizing the full texture. Instead the entire screen is filled with a piece of my texture.
Thanks in advance
I'm a big newb when it comes to the iphone, so please help me out

I'm trying to create a HUD for my game, but am having problems drawing it. I've been looking at this for a couple hours read a bunch of posts and still can't figure out what I'm doing wrong...
Here is the important parts of my code, I've condensed everything into one function so it's easy to follow.
Code:
void CC_UIWindow::Draw()
{
SetupOrtho();
glDisable(GL_DEPTH_TEST);
//enable vertex arrays
glEnableClientState(GL_VERTEX_ARRAY);
//enable color blending
glEnableClientState (GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, mQuad.mVertColors);
//enable texture mapping
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//bind the appropriate texture
glBindTexture(GL_TEXTURE_2D, mQuad.mTexture[0]);
mQuad.mVertices[0] = 0; mQuad.mVertices[1] = 0; mQuad.mVertices[2] = 0;
mQuad.mVertices[3] = 100; mQuad.mVertices[4] = 0; mQuad.mVertices[5] = 0;
mQuad.mVertices[6] = 100; mQuad.mVertices[7] = 100; mQuad.mVertices[8] = 0;
mQuad.mVertices[9] = 0; mQuad.mVertices[10] = 100; mQuad.mVertices[11] = 0;
mQuad.mVertIndicies[0] = 3; mQuad.mVertIndicies[1] = 2; mQuad.mVertIndicies[2] = 1;
mQuad.mVertIndicies[3] = 0; mQuad.mVertIndicies[4] = 3; mQuad.mVertIndicies[5] = 1;
mQuad.mTextureCoords[0] = 0.0f; mQuad.mTextureCoords[1] = 0.0f;
mQuad.mTextureCoords[2] = 1.0f; mQuad.mTextureCoords[3] = 0.0f;
mQuad.mTextureCoords[4] = 1.0f; mQuad.mTextureCoords[5] = 1.0f;
mQuad.mTextureCoords[6] = 0.0f; mQuad.mTextureCoords[7] = 1.0f;
//grab pointers so we can draw
glVertexPointer(3, GL_FLOAT, 0, mQuad.mVertices);
glTexCoordPointer(2, GL_FLOAT, 0, mQuad.mTextureCoords);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, mQuad.mVertIndicies);
//restore our texture states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
SetupPerspective();
}
void CC_UIWindow::SetupOrtho(void) // Set Up An Ortho View
{
glMatrixMode(GL_PROJECTION); // Select Projection
glPushMatrix(); // Push The Matrix
glLoadIdentity(); // Reset The Matrix
glOrthox( 0, 320, 480, 0, -1, 1 ); // Select Ortho Mode
glMatrixMode(GL_MODELVIEW); // Select Modelview Matrix
glPushMatrix(); // Push The Matrix
glLoadIdentity(); // Reset The Matrix
}
void CC_UIWindow::SetupPerspective(void) // Set Up A Perspective View
{
glMatrixMode( GL_PROJECTION ); // Select Projection
glPopMatrix(); // Pop The Matrix
glMatrixMode( GL_MODELVIEW ); // Select Modelview
glPopMatrix(); // Pop The Matrix
}Now I would expect this code to draw my window at the top left corner of the screen with a 100X100 dimension, utilizing the full texture. Instead the entire screen is filled with a piece of my texture.
Thanks in advance
It's because of:
"320" is a very small number when it is interpreted as 16.16 fixed point.
There are various other inefficiencies with your code, would you like them all pointed out?
Code:
glOrthox( 0, 320, 480, 0, -1, 1 ); // Select Ortho Mode"320" is a very small number when it is interpreted as 16.16 fixed point.
There are various other inefficiencies with your code, would you like them all pointed out?
Thanks for replying arekkusu,
I don't understand what you mean by 16.16 fixed point...
Please point out the inefficiencies in my code, that's the only way I'll learn.
Thanks so much.
I don't understand what you mean by 16.16 fixed point...
Please point out the inefficiencies in my code, that's the only way I'll learn.
Thanks so much.
I should also note:
besides
I'm not sure what the pieces are that are inefficent.
besides
Code:
mQuad.mVertIndicies[0] = 3; mQuad.mVertIndicies[1] = 2; mQuad.mVertIndicies[2] = 1;
mQuad.mVertIndicies[3] = 0; mQuad.mVertIndicies[4] = 3; mQuad.mVertIndicies[5] = 1;
mQuad.mTextureCoords[0] = 0.0f; mQuad.mTextureCoords[1] = 0.0f;
mQuad.mTextureCoords[2] = 1.0f; mQuad.mTextureCoords[3] = 0.0f;
mQuad.mTextureCoords[4] = 1.0f; mQuad.mTextureCoords[5] = 1.0f;
mQuad.mTextureCoords[6] = 0.0f; mQuad.mTextureCoords[7] = 1.0f;I'm not sure what the pieces are that are inefficent.
arekkusu Wrote:It's because of:
Code:
glOrthox( 0, 320, 480, 0, -1, 1 ); // Select Ortho Mode
"320" is a very small number when it is interpreted as 16.16 fixed point.
There are various other inefficiencies with your code, would you like them all pointed out?
Do it as I'm doing something similar.
Why do you say 320 is a small number? What do you suggest? Can you explain that?
Thanks a lot for your help.
glOrthox uses fixed point numbers. You probably want glOrthof instead.
http://www.khronos.org/opengles/document...Ortho.html
http://www.khronos.org/opengles/document...Ortho.html
All of the "x" entry points in ES (like glOrthox) expect 16.16 fixed point numbers. "320" in 16.16 fixed point = 320/65536, or about 0.005, which is going to clip your scene to a small corner of the content you're drawing. That content will then be stretched by your glViewport scale to fill the entire window.
If this doesn't make sense yet, you should read section 2.10 "Coordinate transformations" in the spec to understand how the vertex positions and matrices you set up are used.
The short answer to this problem is-- you really didn't mean to use glOrthox. You should use glOrthof instead. Or, you could pass in fixed point data, but there's really no reason to ever do that on the iPhone where the CPU natively supports floats.
As for the other inefficiencies, let me comment a couple areas in your code:
In OpenGL ES1.1, there's no reason to ever disable the vertex array. So you might as well enable it once in your initialization and leave it that way forever. Just call glVertexPointer, and enable/disable the other arrays when needed.
Actually, this is just enabling an array of vertex colors. It doesn't have anything to do with blending. Whether the colors are used or not depends on your current TexEnv state-- the default state is MODULATE, so the interpolated colors will be multiplied by the texture color. This is fine if you want to tint your HUD different colors, but is inefficient otherwise.
Your HUD is 2D, and all of the geometry has a Z coordinate of zero. So don't bother passing that in; use glVertexPointer(2, ...) instead, and Z will automatically default to zero.
For drawing one quad, it's overkill to set up indices. Just set up four vertices and use glDrawArrays(GL_TRIANGLE_STRIP, ...) instead, submitting 4 vertices instead of 6. If you're going to draw many quads (like a string of text) then indexed triangles is fine.
If this doesn't make sense yet, you should read section 2.10 "Coordinate transformations" in the spec to understand how the vertex positions and matrices you set up are used.
The short answer to this problem is-- you really didn't mean to use glOrthox. You should use glOrthof instead. Or, you could pass in fixed point data, but there's really no reason to ever do that on the iPhone where the CPU natively supports floats.
As for the other inefficiencies, let me comment a couple areas in your code:
Code:
//enable vertex arrays
glEnableClientState(GL_VERTEX_ARRAY);
...
glDisableClientState(GL_VERTEX_ARRAY);In OpenGL ES1.1, there's no reason to ever disable the vertex array. So you might as well enable it once in your initialization and leave it that way forever. Just call glVertexPointer, and enable/disable the other arrays when needed.
Code:
//enable color blending
glEnableClientState (GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, mQuad.mVertColors);Actually, this is just enabling an array of vertex colors. It doesn't have anything to do with blending. Whether the colors are used or not depends on your current TexEnv state-- the default state is MODULATE, so the interpolated colors will be multiplied by the texture color. This is fine if you want to tint your HUD different colors, but is inefficient otherwise.
Code:
mQuad.mVertices[0] = 0; mQuad.mVertices[1] = 0; mQuad.mVertices[2] = 0;
...
glVertexPointer(3, GL_FLOAT, 0, mQuad.mVertices);Your HUD is 2D, and all of the geometry has a Z coordinate of zero. So don't bother passing that in; use glVertexPointer(2, ...) instead, and Z will automatically default to zero.
Code:
mQuad.mVertIndicies[0] = 3; mQuad.mVertIndicies[1] = 2; mQuad.mVertIndicies[2] = 1;
...
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, mQuad.mVertIndicies);For drawing one quad, it's overkill to set up indices. Just set up four vertices and use glDrawArrays(GL_TRIANGLE_STRIP, ...) instead, submitting 4 vertices instead of 6. If you're going to draw many quads (like a string of text) then indexed triangles is fine.
Oh wow thanks Arekkusu! I made that one change and it worked "perfectly" I really appreciate all the other information you provided me. You've exposed how little I truly know about Open GL.
Question. Is triangle strips "always" better? Under what scenarios would you want to use one versus the other?
Question. Is triangle strips "always" better? Under what scenarios would you want to use one versus the other?
Triangle strips are better if you're drawing connected chunks of geometry, like a typical 3D model. There are various algorithms to convert arbitrary 3D geometry into triangles trips, and this is generally a win.
If you need to draw disconnected pieces of geometry (for example, one quad per glyph in a font, where the texture coordinates can't be shared between two adjacent glyphs) then you can't use triangle strips. This also applies to 3D models where the geometry may be connected, but some attribute is not continuous across the connected faces (for example, take a 3D cube where you want to light each face with the vertex normal. You need different normals per face, so you have to break the geometry apart and can't share vertices between faces.)
If you need to draw disconnected pieces of geometry (for example, one quad per glyph in a font, where the texture coordinates can't be shared between two adjacent glyphs) then you can't use triangle strips. This also applies to 3D models where the geometry may be connected, but some attribute is not continuous across the connected faces (for example, take a 3D cube where you want to light each face with the vertex normal. You need different normals per face, so you have to break the geometry apart and can't share vertices between faces.)
haudio Wrote:Oh wow thanks Arekkusu! I made that one change and it worked "perfectly" I really appreciate all the other information you provided me. You've exposed how little I truly know about Open GL.
Question. Is triangle strips "always" better? Under what scenarios would you want to use one versus the other?
Hate to pry, but what file format are you using for your textures and how do you load them as GLuint textures? I've been struggling with this for a while now. I have .bmp files working great, but I would really like to get .png files working. Thanks.
Quote:I've been struggling with this for a while now.Sheesh, man, no kidding! I can't believe you haven't got it working for you yet, after all this time. What is the problem? We gotta get to the bottom of this, because it really isn't hard.
I'm using pvrtc which is a compressed version of png. Although I think the loading code is the same for both... I think the only difference is you should use
glTexImage2D rather than glCompressedTexImage2D
Basically here is the loading code
Let me know if you need more guidance.
glTexImage2D rather than glCompressedTexImage2D
Basically here is the loading code
Code:
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
// Most likely for PNG you should use: of glTexImage2D,
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, mPower2Width, mPower2Height, 0, (mPower2Width * mPower2Height) / 2, [texData bytes]);Let me know if you need more guidance.
The "loading code" will be quite different.
When you use one of the TexImage APIs, OpenGL just reads bytes from the pointer you hand it, and interprets the data according to the parameters (like format) you specified.
Loading the image off disk (perhaps decompressing it in the process) has nothing to do with OpenGL, so it belongs in another thread. But briefly-- loading a .png needs to decompress the image into an array of pixels before you pass the address of those pixels to GL. That requires an image decompressor like ImageIO or libpng, and with the API that Apple provided, perhaps rendering the image to a CoreGraphics context to get the pixels. On the other hand, loading a compressed texture like DXT or PVRTC is just a matter of reading bytes off disk, like with NSData.
When you use one of the TexImage APIs, OpenGL just reads bytes from the pointer you hand it, and interprets the data according to the parameters (like format) you specified.
Loading the image off disk (perhaps decompressing it in the process) has nothing to do with OpenGL, so it belongs in another thread. But briefly-- loading a .png needs to decompress the image into an array of pixels before you pass the address of those pixels to GL. That requires an image decompressor like ImageIO or libpng, and with the API that Apple provided, perhaps rendering the image to a CoreGraphics context to get the pixels. On the other hand, loading a compressed texture like DXT or PVRTC is just a matter of reading bytes off disk, like with NSData.

