2011-10-28 7 views
4

私は2048x2048スプライトシートの束で作業していますので、すばやくメモリをいっぱいにしています。 、私はテクスチャをロードするために(レイWenderlich経由)は、以下の方法を使用していているとおり:OpenGL ESのiOSテクスチャ読み込み - RGBA8888の.pngファイルからRGB565のテクスチャを取得するにはどうすればよいですか?

- (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に伝えますか?

答えて

7

このコードを使用して、CGContextDrawImageで書き込まれたデータをRGB565に変換します。 NEONをサポートしているデバイス(armv7コードを実行するすべてのiOSデバイスにはこのようなチップが搭載されています)で、最適化されたNEONコードを使用して一度に8ピクセルを処理します。あなたが見ている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; 
+1

'uint8x8_t'型は' arm_neon.h'で定義されています – brigadir

+0

splendid!glTexImage2D行を次のパラメータに変更しなければならなかった: 'glTexImage2D(GL_TEXTURE_2D、0、GL_RGB、幅、高さ、0、GL_RGB、GL_UNSIGNED_SHORT_5_6_5、スプライトデータ); ' – Jakob

+0

素晴らしい答え、そこには多くのNEONコードが見当たらない。ハードウェアに依存しないようにするには、Accelerateフレームワークを使用してこれを実装してみましたか? –

0

internalFormatパラメータを確認してください。おそらくGL_R3_G3_B2を指定してピクセルあたり8ビットしか使用できないか、またはGL_RGB5が便利かもしれません。便利なオプションがいくつかあります。

詳細については、Texture Internal Formatsを参照してください。

3

単に色空間を変更するのではなく、ここでPVRTC圧縮テクスチャを使用することをおすすめします。これらのテクスチャは圧縮されていないビットマップに展開されるのではなく、圧縮されたままであるため、GPUのメモリをRGB565バージョンよりもはるかに少なくする必要があります。 iOS用のOpenGL ESプログラミングガイドの「Best Practices for Working with Texture Data」セクションで

は、Appleが

テクスチャ圧縮は、通常、メモリ 削減と品質の最適なバランスを提供して言います。 iOS用OpenGL ESは、 GL_IMG_texture_compression_pvrtc拡張機能を実装することにより、PowerVRテクスチャ 圧縮(PVRTC)フォーマットをサポートしています。 PVRTC圧縮の2つのレベル、チャネル当たり4ビットおよびチャネル当たり2ビットがあり、 は非圧縮32ビットの のテクスチャフォーマットに対してそれぞれ8:1と16:1の圧縮率を提供します。圧縮されたPVRTCテクスチャは、特に4ビットレベルで、かなりのレベルの品質を依然として提供しています( )。

アプリケーションは圧縮されたテクスチャを使用できない場合は、 精度の低いピクセルフォーマットを使用することを検討してください。

これは、より小さい色空間を使用するものよりも、圧縮テクスチャのメモリ内サイズが小さくなることを示します。

AppleはPVRTextureLoaderのサンプルアプリケーションでこの良い例を持っており、私は一緒に打ったtextured cube sample applicationでPVRTCテクスチャを読み込むコードをいくつか再利用しました。コンパイル時にPNGテクスチャのPVRTCへの変換をスクリプト化する方法については、PVRTextureLoaderの「エンコードイメージ」構築フェーズを参照してください。

+0

あなたの答えはPVRTexturLoaderの例をもう一度見てください。前回の夜にテクスチャを使って作業しようとしましたが、今は動作しています。巨大なメモリフットプリントの改善!ラーソン氏に感謝 – Jakob

関連する問題