在RGBA4444 RGBA5551中为openGL创建和加载.pngs

时间:2010-01-05 20:27:31

标签: iphone opengl-es textures

我正在创建一个openGL游戏,到目前为止,我一直在使用RGBA8888格式的.pngs作为纹理表,但那些内存太多,我的应用程序经常崩溃。我在Apple的网站上看到,只要需要太多质量就可以使用这种格式,并建议使用RGBA4444和RGBA5551(我已经将纹理转换为PVR,但在大多数精灵表中质量损失太大)。

我只需要在我的纹理加载器类中的glTexImage2D调用中使用GL_UNSIGNED_SHORT_5_5_5_1或GL_UNSIGNED_SHORT_4_4_4_4来加载我的纹理,但我需要将纹理表转换为RGBA4444和RGBA5551,我对如何实现无能为力此

6 个答案:

答案 0 :(得分:5)

使用ImageMagick,您可以运行以下命令创建RGBA4444 PNG文件:

convert source.png -depth 4 destination.png

您可以从MacPorts获取ImageMagick。

答案 1 :(得分:5)

您可以考虑在Windows上使用Imagination的PVRTexTool。它专门用于以每种支持的颜色格式创建PVR纹理。它可以在8888,5551,4444等中创建PVRTC压缩纹理(你称之为“PVR”)以及未压缩纹理。

但是,它不输出PNG(仅PVR),因此您的加载代码会发生变化。此外,有时PVR比PNG大得多,因为PNG中的像素是通过压缩压缩来压缩的。

由于您最有可能运行OS X,因此可以使用Darwine (now WineBottler)在OS X上运行它(以及其他Windows程序)。

在下载PVRTexTool之前,您需要register as an Imagination developer。注册和工具都是免费的。

一旦你进行了设置,它就会非常轻松,它为你提供了一个适合使用PVR的图形用户界面。

答案 2 :(得分:4)

您可能还想了解如何使用GIMP中的floyd-steinberg抖动优化RGBA8888以转换为RGBA4444:http://www.youtube.com/watch?v=v1xGYecsnX0

答案 3 :(得分:3)

真的?有些库可以进行这种转换。但坦率地说,这有点令人费解。有些库使用asm或专门的SSE命令来加速这个,这将是很快的,但它很容易在C / C ++中滚动你自己的格式转换器。 你的基本流程是:

  • 给出RGBA8888编码值的缓冲区
  • 创建一个足以容纳RGBA4444或RGBA5551值的缓冲区。在这种情况下,它的简单 - 一半大小。
  • 遍历源缓冲区,解压缩每个组件,然后重新打包到目标格式,并将其写入目标缓冲区。

    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;
    } 
    

实际的转换循环我非常浪费,组件可以一次性提取,转换和重新打包,从而实现更快的代码。我这样做是为了使转换明确,并且易于更改。另外,我不确定我是否正确地获得了组件顺序。所以它可能是b,r,g,a,但它不应该影响函数的结果,因为它以相同的顺序重新包装到dest缓冲区。

答案 4 :(得分:2)

您也可以使用http://www.texturepacker.com进行转化。

答案 5 :(得分:0)

这是Chris'代码的优化就地转换,它应该以2倍的速度运行,但不是前进的。就地转换有助于通过降低内存峰值来避免崩溃。只是想我会分享以防任何人计划使用此代码。我已经测试过了,效果很好:

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;
}