PDA

View Full Version : Texture from bitmaps in memory



RickCHodgin
11-05-2014, 06:33 PM
Greetings. :-) I have programmed off-and-on in OpenGL since 2009. I consider myself a newbie, but I do have a functional simple graphics engine for 3D geometry. It works well with stand-alone textures and colors. I'm moving on to non-stand-alone textures and am running into a problem.

I have a bitmap that's created and rendered in memory using existing non-OpenGL algorithms. It changes per user interaction 5 to 30 fps. Some of the changes are minor (an area near the top or corner is updated), and other itmes it re-renders the entire image. The texture is about 1700 x 900 with 24-bit color depth.

How should I be updating the texture in OpenGL so that it updates with my live bitmap changes each time the raw bits change? I have been trying this:

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
gluBuild2DMipmaps(GL_TEXTURE_2D, ...);
at each iteration, where I also delete the old texture. This process works, of course, but it is very slow. The updates lag behind and I only get about 1 fps.

Is there some way to dynamically update the texture already loaded (by obtaining a pointer to its bits and BitBlt()-ing the new image data over the top)? Can I tell OpenGL to use the bits from my existing buffer without it building 2D mipmaps? Is there something else I should be doing entirely?

I've also observed that no matter how much I scale in or out, the image is always somewhat blurry compared to the original bitmap data. Is there some way to obtain a sharper bitmap image with gluBuild2DMipmaps? I look at tools like Blender, for example, and I see how clear their text is when zooming in and out. I'd like to achieve something like that if possible (he said laughingly). :-)

Thank you in advance for any assistance. :-)

Best regards,
Rick C. Hodgin

GClements
11-05-2014, 09:43 PM
I have been trying this:

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
gluBuild2DMipmaps(GL_TEXTURE_2D, ...);
at each iteration, where I also delete the old texture. This process works, of course, but it is very slow. The updates lag behind and I only get about 1 fps.

Is there some way to dynamically update the texture already loaded (by obtaining a pointer to its bits and BitBlt()-ing the new image data over the top)? Can I tell OpenGL to use the bits from my existing buffer without it building 2D mipmaps?
You can replace a portion of an existing texture using glTexSubImage2D(). However, this will replace a specific rectangle of a specific mipmap level. If you want mipmaps, you either need to generate the lower levels yourself and upload them as well, or (if you can rely upon support for OpenGL 3.x) use glGenerateMipmap() to re-construct the lower levels from the base level.

Unlike gluBuild2DMipmaps(), glGenerateMipmap() can reasonably be expected to use the GPU for decimation.

Another factor: it might be faster to use two copies of the texture and alternate between them, so that uploading new data doesn't have to wait until the texture has finished being used by the GPU, and rendering doesn't have to wait while new data is being uploaded. Or the implementation might be smart enough to do this for itself.


I've also observed that no matter how much I scale in or out, the image is always somewhat blurry compared to the original bitmap data. Is there some way to obtain a sharper bitmap image with gluBuild2DMipmaps?
No. The first thing gluBuild2DMipmaps() does is, if the width or height aren't powers of two, it resamples the image so that they are. Next, it checks whether the implementation can accept the full-size image. If it can't (either because it exceeds the maximum allowed size or because there is insufficient memory available), it repeatedly halves both dimensions until it will fit. Either of these steps will reduce the sharpness of the texture.

If the texture is 1700 x 900, it will definitely be resampled to satisfy the power-of-two requirement. Depending upon the hardware, it may also need to be resampled to satisfy the maximum texture size constraint.

So if you want sharper textures, you have to forego using gluBuild2DMipmaps. Either use glGenerateMipmap() or build the mipmap levels yourself (the latter can be done on the GPU if you can assume a version which supports render-to-texture).

RickCHodgin
11-06-2014, 05:07 AM
Thank you, GClements. I appreciate your response.


So if you want sharper textures, you have to forego using gluBuild2DMipmaps. Either use glGenerateMipmap() or build the mipmap levels yourself (the latter can be done on the GPU if you can assume a version which supports render-to-texture).
Okay. That sounds great. Next question: What are mipmaps? :-) LOL!

And... how would I build them? Is there a tutorial or source code example of taking a 24-bit bitmap and creating mipmaps sufficient for sharper presentations? I have a lot of C/C++ coding experience and can do these things. I just don't know enough about OpenGL.

Best regards,
Rick C. Hodgin

GClements
11-06-2014, 07:24 AM
Next question: What are mipmaps?
A mipmap is a texture which consists of multiple levels at different resolutions ("mip" comes from "multum in parvo", roughly: many things in one place). If you create e.g. a 256x256 texture, level 0 will be 256x256, level 1 is 128x128, level 2 is 64x64 and so on, down to level 8 being a single pixel. gluBuild2DMipmaps() creates all of the levels from a single image (compared to glTexImage2D, where each level has to be provided separately).

They are used to avoid aliasing artifacts when a texture appears down-scaled on screen.

You don't have to create any levels other than the base level, provided that you only use the GL_LINEAR or GL_NEAREST minification filters (glTexParameter(GL_TEXTURE_MIN_FILTER)). The initial setting is GL_NEAREST_MIPMAP_LINEAR, so you have to either change it or define all of the levels for each texture (if you use any of the GL_*_MIPMAP_* filters and the texture doesn't have all of the levels defined, it behaves as if texturing is disabled).

[QUOTE=RickCHodgin;1262419]And... how would I build them?
Any image rescaling algorithm can be used. But if you're always rescaling by exactly 2:1 at each step (i.e. if the base image has power-of-two dimensions), the problem is simplified, as you can just use the average of each 2x2 block of pixels.

If you're not starting with a power-of-two image, then you will occasionally have to have to deal with the case where you're down-scaling an image where one or both of the dimensions is odd. E.g. if the width of one level is 123 pixels, the width of the next level down will be 61 pixels (you can't have an image that 61.5 pixels wide). And doing a reasonable job of scaling by 0.49593... (61/123) is harder than by exactly 0.5.

RickCHodgin
11-06-2014, 12:09 PM
[QUOTE=RickCHodgin;1262419]Next question: What are mipmaps?
A mipmap is a texture which consists of multiple levels at different resolutions ("mip" comes from "multum in parvo", roughly: many things in one place). If you create e.g. a 256x256 texture, level 0 will be 256x256, level 1 is 128x128, level 2 is 64x64 and so on, down to level 8 being a single pixel. gluBuild2DMipmaps() creates all of the levels from a single image (compared to glTexImage2D, where each level has to be provided separately).
Interesting. Now that you mention this I actually remember doing this at one point, resizing by half each iteration.


They are used to avoid aliasing artifacts when a texture appears down-scaled on screen.

You don't have to create any levels other than the base level, provided that you only use the GL_LINEAR or GL_NEAREST minification filters (glTexParameter(GL_TEXTURE_MIN_FILTER)). The initial setting is GL_NEAREST_MIPMAP_LINEAR, so you have to either change it or define all of the levels for each texture (if you use any of the GL_*_MIPMAP_* filters and the texture doesn't have all of the levels defined, it behaves as if texturing is disabled).

Any image rescaling algorithm can be used. But if you're always rescaling by exactly 2:1 at each step (i.e. if the base image has power-of-two dimensions), the problem is simplified, as you can just use the average of each 2x2 block of pixels.

If you're not starting with a power-of-two image, then you will occasionally have to have to deal with the case where you're down-scaling an image where one or both of the dimensions is odd. E.g. if the width of one level is 123 pixels, the width of the next level down will be 61 pixels (you can't have an image that 61.5 pixels wide). And doing a reasonable job of scaling by 0.49593... (61/123) is harder than by exactly 0.5.

The size of the window is largely arbitrary. Now that I know about this I will make sure I render them to pixel buffers that are even powers of two, and then if I need less I can just adjust my texture coordinates to use something less than 0..1, to match the actual size of the image.

I really appreciate your help, GClements. Thank you very much.

Best regards,
Rick C. Hodgin