Atlas Sprite / Texture: GDI + Bitmap.MakeTransparent for a color key with OpenTK

I am writing a support class for the functionality of the sprite / texture atlas using C # with OpenTK. Most of the features still work fine (simple 2D tiles in the spelling image).

My problem is due to unexpected display results when calling the GDI + Bitmap.MakeTransparent () method to set the color (Magenta / 0xFFFF00FF) to use as a color key.

It would seem that I am using the wrong pixel format options for calls to bitmap.LockBits () and GL.TexImage2D (). My code was based on examples that really worked, but which had in common that the rectangle passed by LockBits () was for the whole image.

Challenges related to this process:

<!-- language: C# --> Bitmap bitmap = new Bitmap(filename); bitmap.MakeTransparent(Color.Magenta); GL.GenTextures(1, out texture_id); GL.BindTexture(TextureTarget.Texture2D, texture_id); // "rect" is initialized for one of: // - the dimensions of the entire image // (0, 0, bitmap.width, bitmap.height) // - the dimensions for a sub-rectangle within the image (for one tile) // (tile_x * tile_width, tile_y * tile_height, tile_width, tile_height) // I observe different behaviors for a sub-rectangle, // as compared to the entire image, when in combination with // the .MakeTransparent() call. // // This code is in a load_tile() method, and the plan was to make // multiple calls per image file, one per tile to extract as a GL texture. // Without transparency, that worked fine. Rectangle rect = new Rectangle(xx, yy, width, height); BitmapData data = bitmap.LockBits(rect, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb); // In the absence of calling bitmap.MakeTransparent(), // images loaded and displayed as expected with Format24bppRgb. // With MakeTransparent() and Format32bppRgb, the results seem to be OS-dependent. // (At first I thought the "correct" combination to be found, // but then found that the results were "right" only under Windows 7.) GL.TexImage2D( OpenTK.Graphics.OpenGL.TextureTarget.Texture2D, // texture_target, 0, // level, OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgba, // internal_format data.Width, data.Height, // width, height, 0, // border, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, // pixel_format OpenTK.Graphics.OpenGL.PixelType.UnsignedByte, // pixel_type data.Scan0 // pixels ); // Certainly the internal_format and pixel_format arguments are pertinent, // but other combinations I have tried produced various undesired display results. // After reading various (OpenGL, OpenTK, and GDI+) docs, still I am not enlightened.. bitmap.UnlockBits(data); 

I tested a small demo using the above code on different boxes, and am observing these results:

  • Window 7: magenta pixels act as transparent (desired result)
  • Windows XP window: magenta pixels displayed as black
  • Ubuntu Linux box: magenta pixels displayed as magenta.

This surprises me as I expected that (GDI + and OpenGL and OpenTK bindings) would act the same in different blocks.

To the extent that I have delved into the documentation of the GDI + API and OpenGL / OpenTK, I think that my perplexity is connected with these two points:

  • What is the correct way to call MakeTransparent () + LockBits () + GL.TexImage2D () to ensure the transparency of the specified color?

  • Why do I see strange display results (as if the "step" was not calculated correctly) for some combinations of pixel format parameters when LockBits () is called for a sub-rectangle, and not the whole image?

Update: I shortened my code in a small Github project: https://github.com/sglasby/OpenGL_Transparent_Sprite

Also, I came across a combination of parameters that works (arg 3 from LockBits () - Format32bppPArgb), although it is not clear why this works, given that the documentation implies a different pixel format: http://msdn.microsoft.com/en -us / library / 8517ckds.aspx (which says that the bitmap will be in Format32bppArgb after calling MakeTransparent).

+4
source share
1 answer

Although this is a separate question for your question, in most cases you should use premultiplied-alpha ( Format32bppPArgb ). If this format works correctly, then understanding why Format32bppArgb does not work is basically an academic exercise.

I launched your sample project on Win7 with Intel 2000HD and got the following results:

  • Format32bppPArgb working properly
  • Format32bppRgb working correctly
  • Format32bppArgb scrambled

Upon further investigation, this does not seem to be related to OpenGL, but rather to how Bitmap.LockBits works.

Check the data.Stride values ​​in the debugger for each approach:

  • Format32bppPArgb has a step of 128 (4x width of the raster map, correct)
  • Format32bppRgb has a step of 128 (4x bitmap width, correct)
  • Format32bppArgb has a step of 512 (16x width of the raster map ,?)

There is nothing useful in MSDN here. At the moment, I can’t understand why this is happening. I will update this answer if I manage to reveal something.

Edit: lo and behold, if you force the right step when unpacking the data, the result looks right:

 GL.PixelStore(PixelStoreParameter.UnpackRowLength, data.Width * 4); // 4x for 32bpp 
0
source

Source: https://habr.com/ru/post/1434118/


All Articles