2011-10-03 59 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。学过的知识。