OpenGL Alternative for Drawing Textures with Immediate Mode? - c++

I'm writing a simple graphics engine that draws textures on the screen using OpenGL and C++. The way that I draw the textures is using the source code below--the drawing is done in a method contained in a "Sprite" class that I wrote, which is called by the main scene's game loop.
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureID);
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_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(m_pos.x, m_pos.y);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(m_pos.x + m_size.x, m_pos.y);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(m_pos.x + m_size.x, m_pos.y + m_size.y);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(m_pos.x, m_pos.y + m_size.y);
glEnd();
glDisable(GL_TEXTURE_2D);
m_textureID is the id of the texture that was already loaded with OpenGL, and m_pos is a vector that stores the x and y position of the sprite, and m_size stores the size of the sprite.
The reason why I'm posting this is because I heard from somebody who is familiar with OpenGL that this is the wrong way to draw many different textures on the screen. Apparently, using glBegin(GL_QUADS) and glEnd() around calls to glVertex can be slow if there are many graphics on the screen at once, and that the correct way to do it is using vertex pointers.
Can anyone give me any pointers (no pun intended) on how to speed up the performance of this technique, using my implementation that I described above? Is there anything else I may be doing wrong? (I'm relatively new to OpenGL and graphics programming.)
Thanks in advance!

You are using immediate mode, which isn't used much (if at all) in serious 3D graphics programming these days. In fact, on mobile devices with OpenGL ES (1.1 and 2.0) it isn't even available.
At the very least, you should use vertex arrays, which are set up using glVertexPointer, glNormalPointer, glColorPointer and glTexCoordPointer, and then drawn using glDrawArrays or glDrawElements.
The next step is to push your vertex data into GPU memory by using vertex buffer objects (VBOs) via glGenBuffer, glBindBuffer and glBufferData. You can find example code here and here.

Related

Scale Bitmapfont clearly with openGL (interpolation)?

I load an bitmapfont (as png image) in my openGL Application to render characters from there at a fixed size. That's working. But: If I want to scale some glyphs at a smaller size it doesnt look great. Is there a way - without using pregenerated mipmaps (I have a big bunch of several characters and need stepless sizes) to scale this more beautiful? Some way of interpolation or something?
At the moment I use something like this (C/C++ on Mac OS X):
glPopMatrix();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, texture->getID());
glScalef(0.7f, 0.7f, 0); //scale here a size
{draw vertexes & set texcoords}
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glPushMatrix();
Any suggestion?
Did you try using Linear filtering on your textures?:
glTexParameteri(GL_TEXTURE_2D, GL_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_MAG_FILTER, GL_LINEAR);
This after binding textures.

png image blurry when loaded onto texture

I have created a png image in photoshop with transparencies that I have loaded into and OpenGL program. I have binded it to a texture and in the program the picture looks blurry and I'm not sure why.
alt text http://img685.imageshack.us/img685/9130/upload2.png
alt text http://img695.imageshack.us/img695/2424/upload1e.png
Loading Code
// Texture loading object
nv::Image title;
// Return true on success
if(title.loadImageFromFile("test.png"))
{
glGenTextures(1, &titleTex);
glBindTexture(GL_TEXTURE_2D, titleTex);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, title.getInternalFormat(), title.getWidth(), title.getHeight(), 0, title.getFormat(), title.getType(), title.getLevel(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
}
else
MessageBox(NULL, "Failed to load texture", "End of the world", MB_OK | MB_ICONINFORMATION);
Display Code
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, titleTex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTranslatef(-800, 0, 0.0);
glColor3f(1,1,1);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(0,0);
glTexCoord2f(0.0, 1.0); glVertex2f(0,600);
glTexCoord2f(1.0, 1.0); glVertex2f(1600,600);
glTexCoord2f(1.0, 0.0); glVertex2f(1600,0);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
EDIT: I don't think i'm stretching each pixel should be two in the co-ordinate system
int width=800, height=600;
int left = -400-(width-400);
int right = 400+(width-400);
int top = 400+(height-400);
int bottom = -400-(height-400);
gluOrtho2D(left,right,bottom,top);
OpenGL will (normally) require that the texture itself have a size that's a power of 2, so what's (probably) happening is that your texture is being scaled to a size where the dimensions are a power of 2, then it's being scaled back to the original size -- in the process of being scaled twice, you're losing some quality.
You apparently just want to display your bitmap without any scaling, without wrapping it to the surface of another object, or anything like that (i.e., any of the things textures are intended for). That being the case, I'd just display it as a bitmap, not a texture (e.g. see glRasterPos2i and glBitmap).
Why would you want to use mipmapping and anisotropic filtering for a static image on your start screen in the first place? It looks unlikely the image will be rotated (what anisotropic filtering is for) or has to be resized many times really fast (what mipmapping is for).
If the texture is being stretched: try using GL_NEAREST for your GL_MAG_FILTER, in this case it could give better results (GL_LINEAR is more accurate, but has a nature of blurring).
If the texture is minimized: same thing, try using GL_NEAREST_MIPMAP_NEAREST, or even better, try using no mipmaps and GL_NEAREST (or GL_LINEAR, whichever gives you the best result).
I'd suggest that you make the png have a resolution in a power of 2's. Ie 1024x512 and place the part you want to drawn in the upper left corner of it still in the resolution for the screen. Then rescale the texcoords to be 800.0/1024.0 and 600.0/512.0 to get the right part from the texture. I belive that what is going on is glTexImage2D can sometime handle width and height that are not a power of 2 but can then scale the input image thus filter it.
An example of handling this can be viewed here (a iPhone - OpenGLES - project that grabs a screen part non-power of 2 and draws that into a 512x512 texture and rescales the GL_TEXTURE matrix, line 123, instead of doing a manual rescale of the texcoords)
Here is another post mentioning this method.
Here is an hypothesis:
Your window is 800x600 (and maybe your framebuffer too), but your client area is not, because of the window decoration on the sides.
So your frame-buffer gets resized when being blitted to the client area of your window. Can you check your window creation code ?
Beware of exact size of the client area of your window. Double check it is what you expect it to be
Beware of pixel alignment rules. You might need to add 0.5 to your x/y coordinates to hit the pixel centers. Description for DirectX can be found here - OpenGL rules may be different, though.

texture on cube-side with opengl

hello i want to use a texture on a cube (created by glutsolidcube()), how can i define where the texture is pictured at?
(for example on the "frontside" of a cube)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterMode);
glColor4f(0.8,0.7,0.11,1.0);
glPushMatrix();
glScalef(4, 1.2, 1.5);
glTranslatef( 0, 0.025, 0);
glutSolidCube(0.1);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
thanks
Not possible, since glutSolidCube() only generates vertexes and normals, not texture coordinates.
However, there are workarounds.
Unfortunately, using glutSolidCube is impossible, as it doesn't support texturing. What I'd suggest is a tutorial that explains the process that may help you. It's a bit outdated, but NeHe's texturing tutorial has some code that explains how to draw a cube, and the code is commented to explain which side is which for you.

How to Draw pixel data taken from the backbuffer back to itself?

I'm working on a mobile application for Symbian 5th edition using OpenGLES.
This application is a pretty standard 2D app, and I make no use of the DepthBuffer.
I need to grab a snapshot of the display and then draw the very same snapshot back to the backbuffer.
I'm using glReadPixels((GLint)0, (GLint)0,
(GLint)nWidth-1, (GLint)nHeight-1,
GL_RGB, GL_UNSIGNED_BYTE, m_pPixelData)
in order to get the pixel data I need, but I'm rather new to OpenGLES and I don't know how to draw the data back to the backbuffer. (in OpenGL its easy using DrawPixels..)
I've read that I should generate a texture from the data, so I did.
But now I'm not sure how to draw this texture.
Do I need to draw it as a texture of a Rectangular element ? if so than how am I suppose to define this rect ? ( the coordinates just doesn't make sense to me..)
The display size is 480x640 and here is the code I want to use in order to draw the rect:
glEnable(GL_TEXTURE_2D);
//displayTex is my texture built out of the pixel data
glBindTexture(GL_TEXTURE_2D, m_pESSharedData->displayTex);
//Bottom
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(2.5f, -2.5f, -2.5f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
glEnd();
Note that above code is something I've picked up along the way, and I think this is the outline of what I'm suppose to do. feel free to take me off this track. :)
I thank you for your time.
You first need to make sure that the version of OpenGL-ES on Series60 5th edition can handle textures whose height and width aren't powers of 2.
I would advise forum nokia for that kind of query.
Shameless plug:
Quick Recipes On Symbian OS contains a whole chapter explaining the basics of OpenGL-ES on Symbian OS. The 3D code samples are here.

Simple OpenGL texture map not working?

I'm trying to figure out texture mapping in OpenGL and I can't get a simple example to work.
The polygon is being drawn, though it's not textured but just a solid color. Also the bitmap is being loaded correctly into sprite1[] as I was successfully using glDrawPixels up til now.
I use glGenTextures to get my tex name, but I notice it doesn't change texName1; this GLuint is whatever I initialize it to, even after the call to glGenTextures...
I have enabled GL_TEXTURE_2D.
Heres the code:
GLuint texName1 = 0;
glGenTextures(1, &texName1);
glBindTexture(GL_TEXTURE_2D, texName1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, sprite1[18], sprite1[22], 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &sprite1[54]);
glColor3f(1, 1, 0);
glBindTexture(GL_TEXTURE_2D, texName1);
glBegin(GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0, 0.0, -5.0f);
glTexCoord2f (1.0, 0.0);
glVertex3f (.5, 0.0, -5.0f);
glTexCoord2f (1.0, 1.0);
glVertex3f (.5, .5, -5.0f);
glTexCoord2f (0.0, 1.0);
glVertex3f (0.0, .5, -5.0f);
glEnd();
UPDATE:
I'm at a loss. Here's everything I've tried:
Turns out I was initializing my texture before OGL was initialized. The texture is initialized (glGenTextures->glTexImage2D) in a class constructor and drawn (glBegin->glEnd) in a member function that is called every frame. genTextures appears to be working correctly now and I'm getting a name of 1.
Every possible combination of GL_RGBA8, GL_BGRA_EXT (GL_BGRA doesn't work on my system; I need the _EXT), and I even removed the alpha channel from the bitmap and tried all combinations of GL_RGB, GL_BGR_EXT, etc etc. No luck.
Tried procedurally creating a bitmap and using that
Made sure GL_COLOR_MATERIAL isn't enabled.
Changed bitmap size to 32x32.
Tried glTexEnvi instead of glTexEnvf.
In addition to mentat's note that you might have a problem with non-power-of-two texture dimensions, you mention the texture name generation not changing the name.
That sounds as if you're calling glGenTextures() too early, i.e. before initializing OpenGL. If you're not, then I suggest adding code just after the call to glGenTextures() that check the OpenGL error state, by calling glGetError().
In your comments, you say your bitmap is 29x20 pixels. Afaik to generate a valid texture, OpenGL requires that the image size (on each dimension) be a power of 2. It doesn't need to be a square, it can be a rectangle though. You can overcome this by using some OpenGL extensions like GL_ARB_texture_rectangle.
I'll put this here as I had the same issue and found another post explaining the issue.
The iPhone does support GL_BGRA(GL_EXT_BGRA) but seemingly only as an input format and not as an internal format. So, if you change the glTexImage2D call to have an internal format of GL_RGBA then it works.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, &sprite1[54]);
I hope this helps someone else that stumbles upon this post.
Some random ideas:
GL_COLOR_MATERIAL might be enabled
change "glTexEnvf" to "glTexEnvi" and see if that helps
if texName1 is 0 after glGenTextures you might not have an active OpenGL context
For error checking I recommend writing a small function that prints readable output for the most common results from glGetErrors and use that to find the line that creates the error. Another possibility would be to use something like GLIntercept, BuGLe or gDEBugger.
My OpenGL is rusty, but I remember having same problems with with glTexImage2D
. Finally I managed to make it work, but I always had more luck with gluBuild2DMipmaps
so i ended up with
gluBuild2DMipmaps (
GL_TEXTURE_2D, type, i.width, i.height, type, GL_UNSIGNED_BYTE, i.data
);
which replaced
glTexImage2D (
GL_TEXTURE_2D, 0, type, i.width, i.height, 0, type, GL_UNSIGNED_BYTE, i.data
);
I found the problem. My call to glEnable was glEnable(GL_BLEND | GL_TEXTURE_2D). Using glGetError I saw I was getting a GL_INVALID_ENUM for this call, so I moved GL_TEXTURE_2D to its own enable function and bingo. I guess logical OR isn't allowed for glEnable?
First thing I'd check is the colour material setting, as mentioned by ShadowIce, then check your texture file to ensure it's a reasonable size (i.e. something like 256x256) and an RGB bitmap. If the file has even a slight problem it WILL NOT render correctly, no matter how you try.
Then, I'd stop trying to just debug that code and instead see what you have different to the tutorial on the NeHe website.
NeHe is always a good place to check if you're trying to do stuff in OpenGL. Textures are probably the hardest thing to get right, and they only get more difficult as the rest of your GL skills increase.