Sign in to follow this  
SelethD

OpenGL Trouble loading and displaying with transparency, 8bit indexed bitmaps

Recommended Posts

SelethD    456

I am working on a project, that uses some legacy graphics, that are in an 8bit indexed bitmaps.  These are the ones with a 1 byte pixel, pointing to an array of 256 colors.

 

So far, this is how I have been doing things.... (note, I'm using C#, with OpenTK, although a solution in C++ can be easily converted)

Bitmap bitmap = new Bitmap(path);
                       System.Drawing.Imaging.BitmapData textureData = bitmap.LockBits(
                           new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                           System.Drawing.Imaging.ImageLockMode.ReadOnly,
                           System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

                        int srcmax = textureData.Height * textureData.Stride;
                        byte[] origBytes = new Byte[srcmax];
                        Marshal.Copy(textureData.Scan0, origBytes, 0, srcmax);

                        bitmap.UnlockBits(textureData);

this gives me the bitmap pixel data (the 1 byte index numbers) in textureData.

So now, I very slowly and very painfully, go through the data, as such....

                        //loop through all the pixels
                        byte[] data = new byte[(bitmap.Width * bitmap.Height) * 4];



                        int srcloc = 0;
                        int dstloc = 0;
                        byte index;
                        Color color;
                        for (int y = 0; y < textureData.Height; y++)
                        {
                            srcloc = y * textureData.Stride;
                            for (int x = 0; x < textureData.Width; x++)
                            {
                                index = origBytes[srcloc];
                                if (index == 0)
                                {
                                    data[dstloc] = 0;
                                    data[dstloc + 1] = 0;
                                    data[dstloc + 2] = 0;
                                    data[dstloc + 3] = 0;
                                }
                                else
                                {
                                    color = bitmap.Palette.Entries[index];
                                    data[dstloc] = color.R;
                                    data[dstloc + 1] = color.G;
                                    data[dstloc + 2] = color.B;
                                    data[dstloc + 3] = color.A;
                                }
                                dstloc += 4;
                                srcloc++;
                            }
                        }

as you can see, I am looking at the color, pointed to, by each pixel index... and manually reversing the red, and blue values, and also, setting alpha to 0, when the index number is 0.  This converted data is then used to create an opengl texture, as follows...

                GL.Enable(EnableCap.Texture2D);
                uint textureID = 0;
                GL.GenTextures(1, out textureID);
  
                GL.BindTexture(TextureTarget.Texture2D, ret.ID);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.Clamp);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.Clamp);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest);
                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0,
                    PixelFormat.Rgba, PixelType.UnsignedByte, pixelData);

                GL.Disable(EnableCap.Texture2D);
                

Now... this totally works, I end up with a rgba opengl texture2d, with transparency that can be used to texture a quad  and it looks perfect.... only problem is the super slow speed of going through each pixel, as some of these images are > 800x800

 

So... If anyone knows of a better solution, something faster, or if you know of anything I seem to be doing wrong (opengl wise, as I am an opengl noob) please let me know.

 

Thanks

Share this post


Link to post
Share on other sites
haegarr    7372

Are you sure it is "super slow"? However, some thoughts:

 

1.) One thing is to avoid the in-loop case distinction. If Palette.Entries[0] would store {0,0,0,0} then index ==0 would be handled as any other index, and the if-clause could be eliminated.

 

2.) Another thing is perhaps the possibility to reduce the 4x1-byte writes to 1x4-bytes write, but I'm not sure; perhaps modern hardware / compilers can hide that anyway. Maybe somebody else can comment on this attempt ...

 

3.) If this step is in time critical code, then move it out into a pre-processing step if possible.

Share this post


Link to post
Share on other sites
SelethD    456

Thanks so much for your input.

 

Well, the case with Palette.Entries[0], is that it's alpha value is non 0, and I really don't care what color the pixels are for index 0, as long as it is transparent.  I cant edit the original images, unless there is some magical opengl, trick to mass convert data or something, I'm afraid I'll have to check and set to alpha 0 each time I hit an index 0 byte.

 

I see what you mean, as far as writing 1x4 bytes, not sure if this would be a speed increase, but its something I will try, just to see if I get different results.

 

It is a time critical piece of code, and I do have it in a 'title/loading' screen, its just.... slow loading.

 

Now you mention, am I sure its 'super slow'... yeah, it kinda is... and actually that is a bit surprising, even for an 800x800 image... I would think it would be faster on a modern computer.  So, I'm wondering if the part that is taking up so much time, might be the part of the code where I am reading in the Bitmap, with LockBits, and copying its data.

 

I plan to keep trying and experimenting

 

If anyone has any other input or have used 8bit indexed bitmaps.... please share some secrets, thanks.

Share this post


Link to post
Share on other sites
SelethD    456

It is definately the 'looping' through the indexes that is causing the slow operation.

 

I have been searching and searching online for a solution, and came across something interesting...

 

I've seen 

GL.TexImage2D(TextureTarget.Texture2D, 0, 
                    PixelInternalFormat.Rgba, 
                    bitmap.Width, bitmap.Height, 0,
                    PixelFormat.ColorIndex, PixelType.UnsignedByte, data);

now, the PixelFormat is ColorIndex.... this is what I need... however, when I use this, I get pure black images, no transparency...

So, I think I must be missing the 'color palette' somewhere... I'm trying to discover, how to let opengl know the data of the colorpalette tha the ColorIndex will look at.

 

I also read this...

"Similarly, to offset the color indices of a bitmap to the palette entries you have defined for it, use

glPixelTransferi(GL_INDEX_OFFSET, bitmap_entry);"

 

it says 'the palette entries you have defined', and im assuming this is 'bitmap_entry', but nothing shows 'HOW' to define the palette entries

 

 

So... I'm feeling more lost than ever, surely surely someone has used indexed graphics, and knows how to do this, but the lack of information on the web is troubling, i'm thinking, is it even possible anymore?  

 

Thanks for any help

Share this post


Link to post
Share on other sites
Sponji    2503

I think this line makes your code slow:

color = bitmap.Palette.Entries[index];

Because this says: "This property returns a copy of the ColorPalette object used by this Image."

 

Maybe just grab the palette/entries first so you can access them directly?

Share this post


Link to post
Share on other sites
haegarr    7372


Well, the case with Palette.Entries[0], is that it's alpha value is non 0, and I really don't care what color the pixels are for index 0, as long as it is transparent.  I cant edit the original images, unless there is some magical opengl, trick to mass convert data or something, I'm afraid I'll have to check and set to alpha 0 each time I hit an index 0 byte.

Make a copy of the palette in an own byte array and set the entry at index 0 accordingly. That has nothing to do with OpenGL. 

 


now, the PixelFormat is ColorIndex.... this is what I need... however, when I use this, I get pure black images, no transparency...
So, I think I must be missing the 'color palette' somewhere... I'm trying to discover, how to let opengl know the data of the colorpalette tha the ColorIndex will look at.

Color index mode has been deprecated in 2009 with OpenGL 3.0. You should not use it any more.

 


Because this says: "This property returns a copy of the ColorPalette object used by this Image."

Oh yes, a single access would be better then.

Share this post


Link to post
Share on other sites
SelethD    456

Its too bad there is no apparent 'native support' for 8bit images in opengl anymore.  However, I did not know it was getting a copy of the entire palette on each call, I tried to suggestion of making one copy to an array, and using the array, and the results were 100% faster.

 

I cant even tell how long its taking to load, as it zips through the files.

 

Thanks so much.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By cebugdev
      hi all,

      i am trying to build an OpenGL 2D GUI system, (yeah yeah, i know i should not be re inventing the wheel, but this is for educational and some other purpose only),
      i have built GUI system before using 2D systems such as that of HTML/JS canvas, but in 2D system, i can directly match a mouse coordinates to the actual graphic coordinates with additional computation for screen size/ratio/scale ofcourse.
      now i want to port it to OpenGL, i know that to render a 2D object in OpenGL we specify coordiantes in Clip space or use the orthographic projection, now heres what i need help about.
      1. what is the right way of rendering the GUI? is it thru drawing in clip space or switching to ortho projection?
      2. from screen coordinates (top left is 0,0 nd bottom right is width height), how can i map the mouse coordinates to OpenGL 2D so that mouse events such as button click works? In consideration ofcourse to the current screen/size dimension.
      3. when let say if the screen size/dimension is different, how to handle this? in my previous javascript 2D engine using canvas, i just have my working coordinates and then just perform the bitblk or copying my working canvas to screen canvas and scale the mouse coordinates from there, in OpenGL how to work on a multiple screen sizes (more like an OpenGL ES question).
      lastly, if you guys know any books, resources, links or tutorials that handle or discuss this, i found one with marekknows opengl game engine website but its not free,
      Just let me know. Did not have any luck finding resource in google for writing our own OpenGL GUI framework.
      IF there are no any available online, just let me know, what things do i need to look into for OpenGL and i will study them one by one to make it work.
      thank you, and looking forward to positive replies.
    • By fllwr0491
      I have a few beginner questions about tesselation that I really have no clue.
      The opengl wiki doesn't seem to talk anything about the details.
       
      What is the relationship between TCS layout out and TES layout in?
      How does the tesselator know how control points are organized?
          e.g. If TES input requests triangles, but TCS can output N vertices.
             What happens in this case?
      In this article,
      http://www.informit.com/articles/article.aspx?p=2120983
      the isoline example TCS out=4, but TES in=isoline.
      And gl_TessCoord is only a single one.
      So which ones are the control points?
      How are tesselator building primitives?
    • By Orella
      I've been developing a 2D Engine using SFML + ImGui.
      Here you can see an image
      The editor is rendered using ImGui and the scene window is a sf::RenderTexture where I draw the GameObjects and then is converted to ImGui::Image to render it in the editor.
      Now I need to create a 3D Engine during this year in my Bachelor Degree but using SDL2 + ImGui and I want to recreate what I did with the 2D Engine. 
      I've managed to render the editor like I did in the 2D Engine using this example that comes with ImGui. 
      3D Editor preview
      But I don't know how to create an equivalent of sf::RenderTexture in SDL2, so I can draw the 3D scene there and convert it to ImGui::Image to show it in the editor.
      If you can provide code will be better. And if you want me to provide any specific code tell me.
      Thanks!
    • By Picpenguin
      Hi
      I'm new to learning OpenGL and still learning C. I'm using SDL2, glew, OpenGL 3.3, linmath and stb_image.
      I started following through learnopengl.com and got through it until I had to load models. The problem is, it uses Assimp for loading models. Assimp is C++ and uses things I don't want in my program (boost for example) and C support doesn't seem that good.
      Things like glVertexAttribPointer and shaders are still confusing to me, but I have to start somewhere right?
      I can't seem to find any good loading/rendering tutorials or source code that is simple to use and easy to understand.
      I have tried this for over a week by myself, searching for solutions but so far no luck. With tinyobjloader-c and project that uses it, FantasyGolfSimulator, I was able to actually load the model with plain color (always the same color no matter what I do) on screen and move it around, but cannot figure out how to use textures or use its multiple textures with it.
      I don't ask much: I just want to load models with textures in them, maybe have lights affect them (directional spotlight etc). Also, some models have multiple parts and multiple textures in them, how can I handle those?
      Are there solutions anywhere?
      Thank you for your time. Sorry if this is a bit confusing, English isn't my native language
    • By dpadam450
      FINALLY, upgrading my engine to openGL 4. I was having some trouble so I started with a stripped down application and was wondering if VAO's are required, because I have a sample working, but if I remove the VAO then it doesn't seem to like drawing my triangle.
  • Popular Now