2011-10-03 96 views
2

我正在嘗試爲iOS編寫一個小型的,便攜式的2D引擎來學習C++和OpenGL。現在我正在嘗試顯示已加載的紋理。使用CoreGraphic庫加載時,我已成功顯示紋理,但現在我試圖使用fread和libpng在C++中加載文件,並且我看到的只是一個白色的盒子。使用C++在OpenGL ES中顯示紋理故障

我的紋理是64x64,所以它不是2問題的力量。我也啓用了GL_TEXTURE_2D。

第一塊代碼用於加載png,將png轉換爲圖像數據,並將數據加載到OpenGL中。

void AssetManager::loadImage(const std::string &filename) 
{ 
Texture texture(filename); 
png_structp png_ptr = NULL; 
png_infop info_ptr = NULL; 
png_bytep *row_pointers = NULL; 
int bitDepth, colourType; 

FILE *pngFile = fopen(std::string(Game::environmentData.basePath + "/" + filename).c_str(), "rb"); 

if(!pngFile) 
    return; 

png_byte sig[8]; 

fread(&sig, 8, sizeof(png_byte), pngFile); 
rewind(pngFile);//so when we init io it won't bitch 
if(!png_check_sig(sig, 8)) 
    return; 

png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); 

if(!png_ptr) 
    return; 

if(setjmp(png_jmpbuf(png_ptr))) 
    return; 

info_ptr = png_create_info_struct(png_ptr); 

if(!info_ptr) 
    return; 

png_init_io(png_ptr, pngFile); 

png_read_info(png_ptr, info_ptr); 

bitDepth = png_get_bit_depth(png_ptr, info_ptr); 

colourType = png_get_color_type(png_ptr, info_ptr); 

if(colourType == PNG_COLOR_TYPE_PALETTE) 
    png_set_palette_to_rgb(png_ptr); 

/*if(colourType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) 
    png_set_gray_1_2_4_to_8(png_ptr);*/ 

if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) 
    png_set_tRNS_to_alpha(png_ptr); 

if(bitDepth == 16) 
    png_set_strip_16(png_ptr); 
else if(bitDepth < 8) 
    png_set_packing(png_ptr); 

png_read_update_info(png_ptr, info_ptr); 


png_get_IHDR(png_ptr, info_ptr, &texture.width, &texture.height, 
      &bitDepth, &colourType, NULL, NULL, NULL); 

int components = GetTextureInfo(colourType); 

if(components == -1) 
{ 
    if(png_ptr) 
     png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 
    return; 
} 

GLubyte *pixels = (GLubyte *)malloc(sizeof(GLubyte) * (texture.width * texture.height * components)); 

row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * texture.height); 

for(int i = 0; i < texture.height; ++i) 
    row_pointers[i] = (png_bytep)(pixels + (i * texture.width * components)); 

png_read_image(png_ptr, row_pointers); 
png_read_end(png_ptr, NULL); 


// make it 
glGenTextures(1, &texture.name); 
// bind it 
glBindTexture(GL_TEXTURE_2D, texture.name); 

GLuint glcolours; 

switch (components) { 
    case 1: 
     glcolours = GL_LUMINANCE; 
     break; 
    case 2: 
     glcolours = GL_LUMINANCE_ALPHA; 
     break; 
    case 3: 
     glcolours = GL_RGB; 
     break; 
    case 4: 
     glcolours = GL_RGBA; 
     break; 
} 

glTexImage2D(GL_TEXTURE_2D, 0, components, texture.width, texture.height, 0, glcolours, GL_UNSIGNED_BYTE, pixels); 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 

fclose(pngFile); 
free(row_pointers); 
free(pixels); 

textures.push_back(texture); 
} 

這裏是我的紋理類的代碼:

class Texture 
{ 
public: 

Texture(const std::string &filename) { this->filename = filename; } 

unsigned int name; 
unsigned int size; 

unsigned int width; 
unsigned int height; 

std::string filename; 
}; 

這裏是我安裝我的看法如何:

void Renderer::Setup(Rectangle rect, CameraType cameraType) 
{ 
_viewRect = rect; 

glViewport(0,0,_viewRect.width,_viewRect.height); 

if(cameraType == Renderer::Orthographic) 
{ 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glOrthof(_viewRect.x,_viewRect.width,_viewRect.y,_viewRect.height,kZNear,kZFar); 
    glMatrixMode(GL_MODELVIEW); 
} 
else 
{ 
    GLfloat size = kZNear * tanf(DegreesToRadians(kFieldOfView)/2.0); 

    glEnable(GL_DEPTH_TEST); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glFrustumf(-size, size, -size/(_viewRect.width/_viewRect.height), size/(_viewRect.width/_viewRect.height), kZNear, kZFar); 
    glMatrixMode(GL_MODELVIEW); 
} 

glEnable(GL_TEXTURE_2D); 
glBlendFunc(GL_ONE, GL_SRC_COLOR); 
glEnable(GL_BLEND); 
} 

現在,這裏是我畫的質地:

void Renderer::DrawTexture(int x, int y, Texture &texture) 
{ 
GLfloat vertices[] = { 
    x, _viewRect.height - y, 0.0, 
    x, _viewRect.height - (y + texture.height), 0.0, 
    x + texture.width, _viewRect.height - y, 0.0, 
    x + texture.width, _viewRect.height - (y + texture.height), 0.0 
}; 


static const GLfloat normals[] = { 
    0.0, 0.0, 1.0, 
    0.0, 0.0, 1.0, 
    0.0, 0.0, 1.0, 
    0.0, 0.0, 1.0 
}; 

GLfloat texCoords[] = { 
0.0, 1.0, 
0.0, 0.0, 
1.0, 1.0,  
1.0, 0.0 
}; 


glEnableClientState(GL_VERTEX_ARRAY); 
glEnableClientState(GL_NORMAL_ARRAY); 
glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

glLoadIdentity(); 
glTranslatef(0.0, 0.0, -3.0); 

glBindTexture(GL_TEXTURE_2D, texture.name); 

glVertexPointer(3, GL_FLOAT, 0, vertices); 
glNormalPointer(GL_FLOAT, 0, normals); 
glTexCoordPointer(2, GL_FLOAT, 0, texCoords); 
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 

glDisableClientState(GL_VERTEX_ARRAY); 
glDisableClientState(GL_NORMAL_ARRAY); 
glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
} 

U PDATE:

我改變了我用來生成紋理的功能。它現在創建一個隨機測試紋理。無論如何,我仍然看到一個白色的質地。要繼續挖掘我如何renderering。

這裏的新功能:

void AssetManager::CreateNoisyTexture(const char * key) 
{  
Texture texture(key, 64, 64); 
const unsigned int components = 4; 


GLubyte *pixels = (GLubyte *)malloc(sizeof(GLubyte) * (texture.width * texture.height * components)); 
GLubyte *pitr1 = pixels;  
GLubyte *pitr2 = pixels + (texture.width * texture.height * components); 

while (pitr1 != pitr2) { 

    *pitr1 = rand() * 0xFF; 
    *(pitr1 + 1) = rand() * 0xFF; 
    *(pitr1 + 2) = rand() * 0xFF; 
    *(pitr1 + 3) = 0xFF; 

    pitr1 += 4; 
} 

glGenTextures(1, &texture.name);  
glBindTexture(GL_TEXTURE_2D, texture.name); 
glTexImage2D(GL_TEXTURE_2D, 0, components, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

free(pixels); 

printf("Created texture with key: %s name: %d", texture.key, texture.name); 

textures.push_back(texture); 
} 
+0

您確定PNG解壓縮工作正常嗎?我會先在內存中生成一個RGBA紋理,然後嘗試先使用它。一些簡單的像半紅和半綠色的工作。它應該有助於縮小問題所在。 – IronMensan

+0

幾個nits:'Texture'的'name'成員應該是'GLuint',而不是'unsigned int'。你可以將'GL_TEXTURE_MIN_FILTER'設置爲'GL_LINEAR',因爲之後立即將它改爲'GL_NEAREST'。 – IronMensan

+0

感謝您的反饋!今晚我會給你一個鏡頭,讓你知道。 – Meroon

回答

2

好吧,我想通了。問題是我使用了錯誤的內部像素格式。

glTexImage2D(GL_TEXTURE_2D, 0, 4, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 

應該是:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 

我需要GL_RGBA傳遞,而不是4。在我讀到這篇文檔:

internalFormat - 指定的顏色組件的數量質地。必須是1,2,3或4或以下符號常量之一:

我覺得這並不重要,但我想它確實如此。還有一點需要注意,我通過使用glGetError()來計算出錯誤發生的位置。當我調用glTexImage2D()時,錯誤是GL_INVALID_OPERATION。

感謝您的幫助IronMensan!

UPDATE:

那麼,爲什麼我不能送4,是因爲它是不允許的,internalFormat和格式需要在OpenGL ES的1.1規格相同的原因。您只能發送GL_ALPHA,GL_RGB,GL_RGBA,GL_LUMINANCE或GL_LUMINANCE_ALPHA。學過的知識。