From 77b93bc4801a1eb57ab1b20c621bdf4ae24c5e7a Mon Sep 17 00:00:00 2001 From: Shariq Shah Date: Fri, 9 Oct 2015 16:49:00 +0500 Subject: [PATCH] Added support for RLE encoded tga images --- src/game.c | 2 +- src/model.c | 4 +- src/texture.c | 112 ++++++++++++++++++++++++++++++++++---------------- 3 files changed, 79 insertions(+), 39 deletions(-) diff --git a/src/game.c b/src/game.c index 6cc408c..326233a 100644 --- a/src/game.c +++ b/src/game.c @@ -106,7 +106,7 @@ void scene_setup(void) transform_set_position(ground_tran, &pos); transform_scale(ground_tran, &scale_ground); - texture_create_from_file("test.tga"); + texture_create_from_file("test_comp.tga"); } void debug(float dt) diff --git a/src/model.c b/src/model.c index 4f0762c..e3703fc 100644 --- a/src/model.c +++ b/src/model.c @@ -93,7 +93,7 @@ void model_cleanup(void) void model_render_all(struct Camera* camera) { - int texture = texture_find("test.tga"); + int texture = texture_find("test_comp.tga"); mat4 mvp; for(int i = 0; i < array_len(model_list); i++) { @@ -103,7 +103,7 @@ void model_render_all(struct Camera* camera) mat4_identity(&mvp); shader_bind(model->shader); - /* shader_set_uniform_int(model->shader, "sampler", (GL_TEXTURE0 + 4) - GL_TEXTURE0); */ + shader_set_uniform_int(model->shader, "sampler", (GL_TEXTURE0 + 4) - GL_TEXTURE0); texture_bind(texture, 4); renderer_check_glerror("model:render_all"); mat4_mul(&mvp, &camera->view_proj_mat, &transform->trans_mat); diff --git a/src/texture.c b/src/texture.c index d4e4cbe..c4e73da 100644 --- a/src/texture.c +++ b/src/texture.c @@ -41,8 +41,9 @@ static struct Texture* texture_list; static int* empty_indices; int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt, int* internal_fmt); -void texture_debug_write_tga(struct Tga_Header* header, GLubyte* image_data); - +void debug_write_tga(struct Tga_Header* header, GLubyte* image_data); +void copy_tga_pixel(GLubyte* source, GLubyte* dest, size_t bytes_per_pixel); + void texture_init(void) { texture_list = array_new(struct Texture); @@ -157,13 +158,13 @@ void texture_cleanup(void) void texture_bind(int index, int texture_unit) { assert(index > -1 && index < array_len(texture_list)); - //glActiveTexture(GL_TEXTURE0 + texture_unit); + glActiveTexture(GL_TEXTURE0 + texture_unit); glBindTexture(GL_TEXTURE_2D, texture_list[index].handle); } void texture_unbind(int texture_unit) { - //glActiveTexture(GL_TEXTURE0 + texture_unit); + glActiveTexture(GL_TEXTURE0 + texture_unit); glBindTexture(GL_TEXTURE_2D, 0); } @@ -192,7 +193,6 @@ int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt if(header.datatypecode == 0) { log_error("texture:load_img", "No image data in file"); - success = 0; } else { @@ -200,7 +200,6 @@ int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt if(header.datatypecode != 2 && header.datatypecode != 10) { log_error("texture:load_img", "Unsupported image data type"); - success = 0; return success; } @@ -208,14 +207,12 @@ int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt { log_error("texture:load_img", "Unsupported bitsperpixel size(%d), only 24 and 32 supported", header.bitsperpixel); - success = 0; return success; } if(header.width <= 0 || header.height <= 0) { log_error("texture:load_img", "Invalid width and height (%d:%d)", header.width, header.height); - success = 0; return success; } @@ -225,7 +222,6 @@ int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt if(!*image_data) { log_error("texture:load_img", "Out of memory"); - success = 0; return success; } @@ -236,35 +232,70 @@ int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt fseek(file, skipover, SEEK_CUR); /* Start reading pixel by pixel */ - GLubyte pixel[bytes_per_pixel]; - GLubyte* curr_pixel = *image_data; - for(int i = 0; i < header.width * header.height; i++) + if(header.datatypecode == 2) /* uncompressed image data */ { - if(header.datatypecode == 2) /* uncompressed image data */ - { - if(fread(&pixel, 1, bytes_per_pixel, file) != bytes_per_pixel) - { - success = 0; - log_error("texture:load_img", "Unexpected end of file at pixel %d", i); - free(image_data); - return success; - } - - /* Swap BGR to RGB */ - curr_pixel[0] = pixel[2]; - curr_pixel[1] = pixel[1]; - curr_pixel[2] = pixel[0]; - if(bytes_per_pixel == 4) curr_pixel[3] = pixel[3]; + GLubyte pixel[bytes_per_pixel]; + GLubyte* curr_pixel = *image_data; + for(int i = 0; i < header.width * header.height; i++) + { + if(fread(&pixel, 1, bytes_per_pixel, file) != bytes_per_pixel) + { + log_error("texture:load_img", "Unexpected end of file at pixel %d", i); + free(image_data); + return success; + } - curr_pixel += bytes_per_pixel; - } - else if(header.datatypecode == 10) /* compressed image data */ - { - log_message("Not implemented yet!"); - } + /* Copy pixel and change BGR to RGB */ + copy_tga_pixel(&pixel[0], curr_pixel, bytes_per_pixel); + curr_pixel += bytes_per_pixel; + } } - - texture_debug_write_tga(&header, *image_data); + else if(header.datatypecode == 10) /* RLE encoded image data */ + { + GLubyte chunk[bytes_per_pixel + 1]; + GLubyte* curr_chunk = *image_data; + for(int i = 0; i < header.width * header.height;) + { + /* read chunk (header+pixel) */ + if(fread(chunk, 1, sizeof(chunk), file) != sizeof(chunk)) + { + log_error("texture:img_load", "Unexpected end of file at chunk %d", i); + free(*image_data); + return success; + } + i++; + copy_tga_pixel(&chunk[1], curr_chunk, bytes_per_pixel); + curr_chunk += bytes_per_pixel; + GLubyte chunk_identifier = chunk[0]; + int count = chunk[0] & 0x7f; + if(chunk_identifier & 0x80) /* RLE chunk */ + { + for(int j = 0; j < count; j++) + { + copy_tga_pixel(&chunk[1], curr_chunk, bytes_per_pixel); + curr_chunk += bytes_per_pixel; + i++; + } + } + else /* Normal chunk */ + { + for(int j = 0; j < count; j++) + { + if(fread(&chunk[1], 1, bytes_per_pixel, file) != bytes_per_pixel) + { + log_error("texture:img_load", "Unexpected end of file at pixel %d", i); + free(*image_data); + return success; + } + copy_tga_pixel(&chunk[1], curr_chunk, bytes_per_pixel); + curr_chunk += bytes_per_pixel; + i++; + } + } + } + } + + debug_write_tga(&header, *image_data); *height = header.height; *width = header.width; *fmt = bytes_per_pixel == 3 ? GL_RGB : GL_RGBA; @@ -298,7 +329,7 @@ void texture_param_set(int index, int parameter, int value) glBindTexture(GL_TEXTURE_2D, curr_texture); } -void texture_debug_write_tga(struct Tga_Header* header, GLubyte* image_data) +void debug_write_tga(struct Tga_Header* header, GLubyte* image_data) { /* Debug only, write the loaded image to file */ FILE* fptr = NULL; @@ -306,6 +337,7 @@ void texture_debug_write_tga(struct Tga_Header* header, GLubyte* image_data) fprintf(stderr,"Failed to open outputfile\n"); exit(-1); } + if(header->datatypecode == 10) header->datatypecode = 2; /* Only uncompressed supported currently */ fwrite(header, sizeof(struct Tga_Header), 1, fptr); for (int i = 0; i < header->height * header->width; i++) { @@ -316,3 +348,11 @@ void texture_debug_write_tga(struct Tga_Header* header, GLubyte* image_data) } fclose(fptr); } + +void copy_tga_pixel(GLubyte* source, GLubyte* dest, size_t bytes_per_pixel) +{ + dest[0] = source[2]; + dest[1] = source[1]; + dest[2] = source[0]; + if(bytes_per_pixel == 4) dest[3] = source[3]; +}