Создание и загрузка файлов .png в RGBA4444 RGBA5551 для openGL

Я создаю игру openGL, и до сих пор я использовал .png в формате RGBA8888 в качестве листов текстур, но они слишком требовательны к памяти, и мое приложение часто дает сбой. Я читал на сайте Apple, что такой формат можно использовать только тогда, когда требуется слишком высокое качество, и рекомендую вместо этого использовать RGBA4444 и RGBA5551 (я уже преобразовал свои текстуры в PVR, но потеря качества слишком велика в большинстве листов спрайтов).

Мне нужно только использовать GL_UNSIGNED_SHORT_5_5_5_1 или GL_UNSIGNED_SHORT_4_4_4_4 в моем вызове glTexImage2D внутри моего класса загрузчика текстур, чтобы загрузить мои текстуры, но мне нужно преобразовать мои текстурные листы в RGBA4444 и RGBA5551, и я не знаю, как я могу этого добиться.


person José Joel.    schedule 05.01.2010    source источник
comment
Для этого есть инструменты. Я не занимаюсь разработкой iphone, но домашнее сообщество Nintendo DS имеет некоторые инструменты для преобразования изображений в эти форматы.   -  person LiraNuna    schedule 05.01.2010
comment
Не могли бы вы назвать мне эти инструменты?!, Спасибо.   -  person José Joel.    schedule 05.01.2010
comment
Существует буквально почти бесконечное количество инструментов, которые могут конвертировать изображения в разные форматы. Некоторые из них могут быть специфичны для Windows, но некоторые будут специфичны для iOS. Простой Google приведет к появлению множества программ, которые могут конвертировать png в RGBA4444.   -  person    schedule 10.06.2013


Ответы (6)


Шутки в сторону? Существуют библиотеки для такого преобразования. Но, честно говоря, это немного пустяк. Существуют библиотеки, которые используют 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, но это не должно влиять на результат функции, поскольку она переупаковывается в том же порядке в целевой буфер.

person Chris Becke    schedule 06.01.2010
comment
Отличный образец кода. Кстати, я думаю, что ваше значение pdst должно быть .... pdst [i] = r ‹---------------- 12 | g ‹---------------- 8 | b ‹---------------- 4 | а; - person tyshock; 16.02.2012
comment
Ой. Я неправильно понял направление переключения !. Это ужасно. Я не могу найти нигде на Opengl.org документ, который фактически определяет макет всех различных форматов: / - person Chris Becke; 01.04.2012

Используя ImageMagick, вы можете создавать файлы PNG RGBA4444, запустив:

convert source.png -depth 4 destination.png

Вы можете получить ImageMagick с MacPorts.

person pgb    schedule 05.01.2010
comment
Это приведет к усечению нижних битов значений пикселей, но вывод из libpng (или другого используемого загрузчика) по-прежнему будет 8-битными компонентами. Вопрос в том, как растянуть значения пиксельных компонентов в форматы OpenGL. Для этого в Интернете есть множество примеров кода, это просто набор бит-тидлинга. - person Andy Ross; 06.01.2010

Вы можете рассмотреть возможность использования PVRTexTool от Imagination для Windows. Это специально для создания текстур PVR во всех поддерживаемых цветовых форматах. Он может создавать как сжатые текстуры PVRTC (то, что вы называете «PVR»), так и несжатые текстуры в 8888, 5551, 4444 и т. Д.

Однако он не выводит PNG (только PVR), поэтому ваш код загрузки может измениться. Кроме того, иногда PVR намного больше, чем PNG, потому что пиксели в PNG сжимаются со сжатием deflate.

Поскольку вы, скорее всего, используете OS X, вы можете использовать Darwine (теперь WineBottler) для его запуска (и другие программы Windows) в OS X.

Вам нужно будет зарегистрироваться в качестве разработчика Imagination, прежде чем вы сможете скачать PVRTexTool . Регистрация и инструмент бесплатны.

После того, как вы его настроите, это довольно безболезненно и дает вам достойный графический интерфейс для работы с PVR.

person Jon-Eric    schedule 05.01.2010

Вы также можете узнать, как оптимизировать RGBA8888 для преобразования в RGBA4444 с помощью дизеринга Floyd-Steinberg в GIMP: http://www.youtube.com/watch?v=v1xGYecsnX0

person noname    schedule 21.08.2011

Вы также можете использовать http://www.texturepacker.com для преобразования.

person bjoern    schedule 20.11.2010

Вот оптимизированное преобразование кода Криса на месте, которое должно выполняться в 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;
}
person David    schedule 07.11.2012