OpenGL纹理+ libpng导致图像失真

时间:2011-09-05 20:02:39

标签: android opengl-es android-ndk libpng

我无法弄清楚为什么我的PNG图像在尝试使用NDK& OpenGL的。 PNG位于我的资源文件夹中,它们具有alpha图层。以下是我从资源文件夹中获取它们的方法:

void loadNativePNG(texture_t* tmpTex)
{
    png_structp     png_ptr; 
    png_infop       info_ptr; 
    unsigned int    width;
    unsigned int    height;
    int             i;

    int             bit_depth;
    int             color_type ;
    png_size_t      rowbytes;
    png_bytep       *row_pointers;
    png_byte header[8];

  char realPath[1024];

  memset(realPath, 0, 1024);  
  strcat(realPath, FS_Gamedir());
  if (tmpTex->path[0] != '/')
    strcat(realPath, "/");
  strcat(realPath, tmpTex->path);

  tmpTex->format = TEXTURE_TYPE_UNKNOWN ;

  file = zip_fopen(APKArchive, realPath, 0);

  //LOGI("[Android Main] Opening %s", realPath);

    if ( !file  )
    abort_textureLoading_("Could not open file '%s'\n",tmpTex->path);

    zip_fread(file, header, 8);
    if (png_sig_cmp(header, 0, 8) != 0 )
        abort_textureLoading_("[read_png_file] File is not recognized as a PNG file.\n", tmpTex->path);

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

    if (png_ptr == NULL)
        abort_textureLoading_("[read_png_file] png_create_read_struct failed");

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
        abort_textureLoading_("[read_png_file] png_create_info_struct failed");

    if (setjmp(png_jmpbuf(png_ptr)))
        abort_textureLoading_("[read_png_file] Error during init_io");

    png_set_read_fn(png_ptr, NULL, png_zip_read);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

  //Retrieve metadata and transfer to structure bean tmpTex
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

    tmpTex->width = width; 
    tmpTex->height =  height;


    // Set up some transforms. 
    if (color_type & PNG_COLOR_MASK_ALPHA) {
        png_set_strip_alpha(png_ptr);
    }
    if (bit_depth > 8) {
        png_set_strip_16(png_ptr);
    }
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
    }

    // Update the png info struct.
    png_read_update_info(png_ptr, info_ptr);

    // Rowsize in bytes. 
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    tmpTex->bpp = rowbytes / width;
    if (tmpTex->bpp == 4)
        tmpTex->format = TEXTURE_GL_RGBA;
    else
        tmpTex->format = TEXTURE_GL_RGB;

  //Since PNG can only store one image there is only one mipmap, allocated an array of one
  tmpTex->numMipmaps = 1;
  tmpTex->data = malloc(sizeof(uchar*));
    if ((tmpTex->data[0] = (uchar*)malloc(rowbytes * height))==NULL) 
  {
    //Oops texture won't be able to hold the result :(, cleanup LIBPNG internal state and return;
    free(tmpTex->data);
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return;
    }

  //Next we need to send to libpng an array of pointer, let's point to tmpTex->data[0]
    if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) 
  {
    // Oops looks like we won't have enough RAM to allocate an array of pointer....
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        free(tmpTex->data );
        tmpTex->data  = NULL;
    return;
    }

  //FCS: Hm, it looks like we are flipping the image vertically.
  //     Since iOS did not do it, we may have to not to that. If result is 
  //     messed up, just swap to:   row_pointers[             i] = ....
    for (i = 0;  i < height;  ++i) 
        row_pointers[height - 1 - i] = tmpTex->data[0]  + i * rowbytes;
    //row_pointers[             i] = tmpTex->data[0]  + i*rowbytes;


  //Decompressing PNG to RAW where row_pointers are pointing (tmpTex->data[0])
    png_read_image(png_ptr, row_pointers);

  //Last but not least:


    // Free LIBPNG internal state.
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

  //Free the decompression buffer
  free(row_pointers);

    zip_fclose(file);
}

以下是它们在OpenGL中的呈现方式:

void UpLoadTextureToGPUF(texture_t* texture)
{
    int i,mipMapDiv;

    if (!texture || !texture->data || texture->textureId != 0)
        return;

    glGenTextures(1, &texture->textureId);
    glBindTexture(GL_TEXTURE_2D, texture->textureId);

    if (texture->format == TEXTURE_GL_RGB ||texture->format == TEXTURE_GL_RGBA)
    {
        glTexParameterf(GL_TEXTURE_2D,GL_GENERATE_MIPMAP, GL_TRUE);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture->data[0]);
        free(texture->data[0]);
        texture->data[0] = 0;
    }
    else
    {
        glTexParameterf(GL_TEXTURE_2D,GL_GENERATE_MIPMAP, GL_FALSE);

        glCompressedTexImage2D(GL_TEXTURE_2D, 0, texture->format, texture->width,texture-> height, 0, texture->dataLength[0], texture->data[0]);
        //printf("Uploading mipmapp %d w=%d, h=%d, size=%d\n",0,texture->width,texture-> height,texture->dataLength[0]);

        mipMapDiv = 2;
        for (i=1; i < texture->numMipmaps; i++,mipMapDiv*=2) 
        {
            glCompressedTexImage2D(GL_TEXTURE_2D, i, texture->format, texture->width/mipMapDiv,texture-> height/mipMapDiv, 0, texture->dataLength[i], texture->data[i]);
        //  printf("Uploading mipmapp %d w=%d, h=%d, size=%d\n",i,texture->width/mipMapDiv,texture-> height/mipMapDiv,texture->dataLength[i]);
            free(texture->data[i]);
            texture->data[i] = 0;
        }
    }


    //Using mipMapping to reduce bandwidth consumption
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


    SCR_CheckErrors("Loading texture",texture->path);

    free(texture->dataLength); 
    texture->dataLength = 0;
    free(texture->data);    
    texture->data = 0;

    texture->memLocation = TEXT_MEM_LOC_VRAM;

    if (texture->file != NULL)
        FS_CloseFile(texture->file);
}

SCR_CheckErrors()会进行一些错误检查(但不会打印错误):

void SCR_CheckErrors(char* step, char* details)
{
    GLenum err = glGetError();
    switch (err) {
        case GL_INVALID_ENUM:printf("Error GL_INVALID_ENUM %s, %s\n", step,details); break;
        case GL_INVALID_VALUE:printf("Error GL_INVALID_VALUE  %s, %s\n", step,details); break;
        case GL_INVALID_OPERATION:printf("Error GL_INVALID_OPERATION  %s, %s\n", step,details); break;              
        case GL_OUT_OF_MEMORY:printf("Error GL_OUT_OF_MEMORY  %s, %s\n", step,details); break;          
        case GL_NO_ERROR: break;
        default : printf("Error UNKNOWN  %s, %s\n", step,details);break;
    }
}

And here's what the image looks like...

0 个答案:

没有答案