Creating and loading .pngs in RGBA4444 RGBA5551 for openGL

给你一囗甜甜゛ 提交于 2019-12-06 05:53:31

Seriously? There are libraries to do this kind of conversion. But frankly, this is a bit of bit twiddling. There are libraries that use asm, or specialized SSE commands to accellerate this which will be fast, but its pretty easy to roll your own format converter in C/C++. Your basic process would be:

  • Given a buffer of RGBA8888 encoded values
  • Create a buffer big enough to hold the RGBA4444 or RGBA5551 values. In this case, its simple - half the size.
  • Loop over the source buffer, unpacking each component, and repacking into the destination format, and write it into the destination buffer.

    void* rgba8888_to_rgba4444(
      void* src, // IN, pointer to source buffer
      int cb)    // IN size of source buffer, in bytes
    {
      // this code assumes that a long is 4 bytes and short is 2.
      //on some compilers this isnt true
      int i;
      // compute the actual number of pixel elements in the buffer.
      int cpel = cb/4;
      unsigned long* psrc = (unsigned long*)src;
      // create the RGBA4444 buffer
      unsigned short* pdst = (unsigned short*)malloc(cpel*2);
      // convert every pixel
      for(i=0;i<cpel; i++)
      {
        // read a source pixel
        unsigned pel = psrc[i];
        // unpack the source data as 8 bit values
        unsigned r = p & 0xff;
        unsigned g = (pel >> 8) & 0xff;
        unsigned b = (pel >> 16) & 0xff; 
        unsigned a = (pel >> 24) & 0xff;
        //convert to 4 bit vales
        r >>= 4;
        g >>= 4;
        b >>= 4;
        a >>= 4;
        // and store
        pdst[i] = r | g << 4  | b << 8 | a << 12;
      }
      return pdst;
    } 
    

The actual conversion loop I did very wastefully, the components can be extracted, converted and repacked in a single pass, making for far faster code. I did it this way to make the conversion explicit, and easy to change. Also, im not sure that I got the component order the right way around. So it might be b, r, g, a, but it shouldn't effect the result of the function as it repackes in the same order into the dest buffer.

Using ImageMagick you can create RGBA4444 PNG files by running:

convert source.png -depth 4 destination.png

You can get ImageMagick from MacPorts.

You may consider using Imagination's PVRTexTool for Windows. It's specifically for creating PVR textures in every supported color format. It can create both PVRTC compressed textures (what you call "PVR") as well as uncompressed textures in 8888, 5551, 4444, etc.

However, it doesn't output PNGs (only PVRs) so your loading code would have change. Also, sometimes PVRs are much larger than PNGs because the pixels in PNGs are compressed with deflate compression.

Since you're most likely running OS X, you can use Darwine (now WineBottler) to run it (and other windows programs) on OS X.

You'll need to register as an Imagination developer before you can download PVRTexTool. Registration and the tool are both free.

Once you set it up, it's pretty painless and it gives you a decent GUI for working with PVRs.

You might also want to look how to optimize RGBA8888 for conversion to RGBA4444 using floyd-steinberg dithering in GIMP: http://www.youtube.com/watch?v=v1xGYecsnX0

You could also use http://www.texturepacker.com for conversion.

Here is an optimized in-place conversion of Chris' code which should run 2x as fast but is not as strait forward. The in-place conversion helps to avoid crashes by lowering the memory spike. Just thought I'd share in case anyone was planning on using this code. I've tested it and it works great:

void* rgba8888_to_rgba4444( void* src, // IN, pointer to source buffer
                           int cb)    // IN size of source buffer, in bytes
{
    int i;
    // compute the actual number of pixel elements in the buffer.
    int cpel = cb/4;
    unsigned long* psrc = (unsigned long*)src;
    unsigned short* pdst = (unsigned short*)src;

    // convert every pixel

    for(i=0;i<cpel; i++)
    {
        // read a source pixel
        unsigned pel = psrc[i];
        // unpack the source data as 8 bit values
        unsigned r = (pel << 8)  & 0xf000;
        unsigned g = (pel >> 4) & 0x0f00;
        unsigned b = (pel >> 16) & 0x00f0;
        unsigned a = (pel >> 28) & 0x000f;

        // and store
        pdst[i] = r | g | b | a;
    }
    return pdst;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!