diff options
Diffstat (limited to 'texture.c')
-rw-r--r-- | texture.c | 194 |
1 files changed, 135 insertions, 59 deletions
@@ -3,69 +3,145 @@ #include <string.h> #include <GL/gl.h> #include <zoom/texture.h> - - -#pragma pack(push,2) -typedef struct _TEXHEADER { - unsigned char t; - unsigned char x; - unsigned long w; - unsigned long h; -} TEXHEADER; -#pragma pack(pop) +#include <png.h> int nTex; TEXLIST *texlist; + GLuint LoadTexture(char *filename) { - GLuint tex; - FILE *file; - TEXHEADER txh; - unsigned char *data; - int i; - char name[100]; - - for(i = 0; i < nTex; i++) { - if(strcasecmp(filename, texlist[i].name) == 0) return texlist[i].id; - } - - strcpy(name, "tex/"); - strcat(name, filename); - file = fopen(name, "rb"); - if(!file) return 0; - - fread(&txh, sizeof(txh), 1, file); - if(txh.t != 'T' || txh.x != 'X') { - fclose(file); - return 0; - } - - data = malloc(txh.w*txh.h*4); - if(!data) { - fclose(file); - return 0; - } - fread(data, txh.w*txh.h*4, 1, file); - - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - 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_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, 4, txh.w, txh.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - free(data); - fclose(file); - - nTex++; - - if(nTex == 1) texlist = malloc(sizeof(TEXLIST)); - else texlist = realloc(texlist, sizeof(TEXLIST)*nTex); - - strcpy(texlist[nTex-1].name, filename); - texlist[nTex-1].id = tex; - - return tex; + FILE *file; + GLuint tex; + char *name; + png_byte header[8]; + png_structp png_ptr; + png_infop info_ptr; + png_bytep *row_pointers; + png_bytep data; + png_uint_32 width, height; + int bit_depth, color_type, i; + GLenum format; + + + for(i = 0; i < nTex; i++) { + if(strcasecmp(filename, texlist[i].name) == 0) return texlist[i].id; + } + + name = malloc(strlen(filename)+5); + strcpy(name, "tex/"); + strcat(name, filename); + + file = fopen(name, "rb"); + + free(name); + + if(!file) return 0; + + fread(&header, 1, sizeof(header), file); + if(png_sig_cmp(header, 0, sizeof(header))) { + fclose(file); + return 0; + } + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(!png_ptr) { + fclose(file); + return 0; + } + + info_ptr = png_create_info_struct(png_ptr); + if(!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + fclose(file); + return 0; + } + + if(setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(file); + return 0; + } + + png_init_io(png_ptr, file); + png_set_sig_bytes(png_ptr, sizeof(header)); + + png_read_info(png_ptr, info_ptr); + + width = png_get_image_width(png_ptr, info_ptr); + height = png_get_image_height(png_ptr, info_ptr); + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + color_type = png_get_color_type(png_ptr, info_ptr); + + if(color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_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(bit_depth < 8) + png_set_packing(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + color_type = png_get_color_type(png_ptr, info_ptr); + + if((bit_depth != 8 && bit_depth != 16) || color_type & PNG_COLOR_MASK_PALETTE) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(file); + return 0; + } + + data = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)*height); + row_pointers = png_malloc(png_ptr, height*png_sizeof(png_bytep)); + for(i = 0; i < height; i++) + row_pointers[i] = data + png_get_rowbytes(png_ptr, info_ptr)*i; + + png_read_image(png_ptr, row_pointers); + + switch(color_type) { + case PNG_COLOR_TYPE_GRAY: + format = GL_LUMINANCE; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + format = GL_LUMINANCE_ALPHA; + break; + case PNG_COLOR_TYPE_RGB: + format = GL_RGB; + break; + case PNG_COLOR_TYPE_RGBA: + format = GL_RGBA; + break; + default: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(file); + return 0; + } + + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + 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_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, png_get_channels(png_ptr, info_ptr), width, height, 0, + format, (bit_depth == 8) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT, data); + + png_free(png_ptr, row_pointers); + png_free(png_ptr, data); + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + fclose(file); + + nTex++; + + if(nTex == 1) texlist = malloc(sizeof(TEXLIST)); + else texlist = realloc(texlist, sizeof(TEXLIST)*nTex); + + strcpy(texlist[nTex-1].name, filename); + texlist[nTex-1].id = tex; + + return tex; } |