OpenGL ES при загрузке текстуры iOS - как мне получить из файла RGBA8888 .png в текстуру RGB565? - PullRequest
4 голосов
/ 28 октября 2011

, поэтому я работаю с кучей листов спрайтов 2048x2048, которые заполняют память довольно быстро.Таким образом, я использую следующий метод (через Рэя Вендерлиха) для загрузки текстуры:

- (GLuint)setupTexture:(NSString *)fileName 
{    
    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
    if (!spriteImage) 
    {
        NSLog(@"Failed to load image %@", fileName);
        exit(1);
    }
    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);
    GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8,     width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);    
    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
    CGContextRelease(spriteContext);
    GLuint texName;
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    GLenum err = glGetError();
    if (err != GL_NO_ERROR)
        NSLog(@"Error uploading texture. glError: 0x%04X", err);    
    free(spriteData);        
    return texName;    
}

, поэтому мой вопрос, как мне отбросить альфа-информацию из CGImage, а затем "уменьшить выборку" изображенияменьше бит на пиксель, и, наконец, расскажите об этом OpenGL?

Ответы [ 3 ]

7 голосов
/ 28 октября 2011

Я использую этот код для преобразования данных, записанных CGContextDrawImage в RGB565. Он использует оптимизированный код NEON для одновременной обработки 8 пикселей на устройствах с поддержкой NEON (такое устройство есть на каждом устройстве iOS, на котором выполняется код armv7). Указатель data, который вы видите там, совпадает с указателем spriteData, мне просто было лень его переименовывать.

void *temp = malloc(width * height * 2);
uint32_t *inPixel32  = (uint32_t *)data;
uint16_t *outPixel16 = (uint16_t *)temp;
uint32_t pixelCount = width * height;

#ifdef __ARM_NEON__
for(uint32_t i=0; i<pixelCount; i+=8, inPixel32+=8, outPixel16+=8)
{
    uint8x8x4_t rgba  = vld4_u8((const uint8_t *)inPixel32);

    uint8x8_t r = vshr_n_u8(rgba.val[0], 3);
    uint8x8_t g = vshr_n_u8(rgba.val[1], 2);
    uint8x8_t b = vshr_n_u8(rgba.val[2], 3);

    uint16x8_t r16 = vmovl_u8(r);
    uint16x8_t g16 = vmovl_u8(g);
    uint16x8_t b16 = vmovl_u8(b);

    r16 = vshlq_n_u16(r16, 11);
    g16 = vshlq_n_u16(g16, 5);

    uint16x8_t rg16 = vorrq_u16(r16, g16);
    uint16x8_t result = vorrq_u16(rg16, b16);

    vst1q_u16(outPixel16, result);
}
#else                
for(uint32_t i=0; i<pixelCount; i++, inPixel32++)
{
    uint32_t r = (((*inPixel32 >> 0)  & 0xFF) >> 3);
    uint32_t g = (((*inPixel32 >> 8)  & 0xFF) >> 2);
    uint32_t b = (((*inPixel32 >> 16) & 0xFF) >> 3);

    *outPixel16++ = (r << 11) | (g << 5) | (b << 0);               
}
#endif

free(data);
data = temp;
3 голосов
/ 28 октября 2011

Вместо простого изменения цветового пространства, я мог бы предложить использовать здесь сжатую PVRTC текстуру. Это должно использовать гораздо меньше памяти на GPU, чем даже версия RGB565, потому что эти текстуры остаются сжатыми, а не расширяются в несжатые растровые изображения.

В разделе " Рекомендации по работе с данными текстуры " в Руководстве по программированию OpenGL ES для iOS Apple сообщает

Сжатие текстур обычно обеспечивает лучший баланс памяти экономия и качество. OpenGL ES для iOS поддерживает текстуру PowerVR Формат сжатия (PVRTC) путем реализации Расширение GL_IMG_texture_compression_pvrtc. Есть два уровня Сжатие PVRTC, 4 бита на канал и 2 бита на канал, что предлагает степень сжатия 8: 1 и 16: 1 по сравнению с несжатыми 32-разрядными формат текстур соответственно. Сжатая текстура PVRTC по-прежнему обеспечивает достойный уровень качества, особенно на 4-битном уровне.

и

Если ваше приложение не может использовать сжатые текстуры, рассмотрите возможность использования пиксельный формат с низкой точностью.

, что означает, что вы получите меньшие размеры в памяти для сжатых текстур, чем даже те, которые используют меньшее цветовое пространство.

У Apple есть хороший пример этого в их PVRTextureLoader примере приложения, и я повторно использовал этот код для загрузки текстур PVRTC в примере текстурированного куба приложения , который я сложил вместе. Вы можете посмотреть на этапе сборки «Кодировать изображения» в PVRTextureLoader, чтобы узнать, как написать сценарий преобразования текстур PNG в PVRTC во время компиляции.

0 голосов
/ 28 октября 2011

Посмотрите на параметр internalFormat. Возможно, вы могли бы указать GL_R3_G3_B2, чтобы использовать только 8 бит на пиксель, или GL_RGB5 может быть полезным. Есть несколько вариантов, которые могут быть полезны.

Подробнее см. Внутренние форматы текстуры .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...