image.c (4318B)
1 internal void img_tga_header_print(struct ImgTgaHeader h) 2 { 3 printf("id_length: %u\n", h.id_length); 4 printf("color_map_type: %u\n", h.color_map_type); 5 printf("data_type_code: %u\n", h.data_type_code); 6 printf("color_map_origin: %u\n", h.color_map_origin); 7 printf("color_map_length: %u\n", h.color_map_length); 8 printf("color_map_depth: %u\n", h.color_map_depth); 9 printf("x_origin: %u\n", h.x_origin); 10 printf("y_origin: %u\n", h.y_origin); 11 printf("width: %u\n", h.width); 12 printf("height: %u\n", h.height); 13 printf("bits_per_pixel: %u\n", h.bits_per_pixel); 14 printf("image_descriptor: %u\n", h.image_descriptor); 15 } 16 17 internal u8 img_consume_byte(u8 **buffer, uintptr_t end_address) 18 { 19 u8 byte = 0; 20 if ((uintptr_t)*buffer < end_address) 21 { 22 byte = **buffer; 23 (*buffer)++; 24 } 25 return byte; 26 } 27 28 internal u8 *img_load_from_memory(u8 *buffer, size_t len, i32 *out_width, i32 *out_height, struct StackAllocator *allocator) 29 { 30 assert(buffer); 31 uintptr_t buf_end = (uintptr_t)buffer + (len * sizeof(u8)); 32 33 assert(len >= sizeof(struct ImgTgaHeader)); 34 struct ImgTgaHeader h = *(struct ImgTgaHeader *)buffer; 35 buffer += sizeof(struct ImgTgaHeader); 36 //img_tga_header_print(h); 37 38 // Image descriptor not currently accounted for 39 assert(h.id_length == 0); 40 // Color maps not currently supported 41 assert(h.color_map_type == 0); 42 // Only RGB is supported 43 assert(h.data_type_code == 2 || h.data_type_code == 10); 44 assert(h.bits_per_pixel <= 32); 45 46 if (out_width) 47 { 48 *out_width = h.width; 49 } 50 if (out_height) 51 { 52 *out_height = h.height; 53 } 54 55 u8 bytes_per_pixel = h.bits_per_pixel / 8; 56 size_t bytes_per_row = h.width * bytes_per_pixel; 57 size_t img_data_buf_len = h.height * bytes_per_row; 58 u8 *img_data = mem_st_alloc_buffer(allocator, u8, img_data_buf_len); 59 assert(img_data); 60 61 if (h.data_type_code == 2) 62 { 63 // uncompressed RGB 64 for (size_t b = 0; b < img_data_buf_len; b++) 65 { 66 img_data[b] = img_consume_byte(&buffer, buf_end); 67 } 68 } 69 else if (h.data_type_code == 10) 70 { 71 // Run Length Encoded RGB 72 size_t img_bytes_read = 0; 73 while (img_bytes_read < img_data_buf_len) 74 { 75 u8 packet_header = img_consume_byte(&buffer, buf_end); 76 u8 run_length_header_bit = packet_header >> 7; 77 u32 run_count = (packet_header & (~(1 << 7))) + 1; 78 assert(run_count <= 128); 79 u32 run_length_in_bytes = run_count * bytes_per_pixel; 80 81 if (run_length_header_bit) 82 { 83 u8 pixel[4] = {0}; 84 for (u32 b = 0; b < bytes_per_pixel; b++) 85 { 86 pixel[b] = img_consume_byte(&buffer, buf_end); 87 } 88 for (u32 b = 0; b < run_length_in_bytes; b++) 89 { 90 img_data[img_bytes_read + b] = pixel[b % bytes_per_pixel]; 91 } 92 img_bytes_read += run_length_in_bytes; 93 } 94 else 95 { 96 for (u32 b = 0; b < run_length_in_bytes; b++) 97 { 98 img_data[img_bytes_read + b] = img_consume_byte(&buffer, buf_end); 99 } 100 img_bytes_read += run_length_in_bytes; 101 } 102 } 103 assert(img_bytes_read == img_data_buf_len); 104 } 105 106 // NOTE(amin): we convert BGRA to RGBA because OpenGL ES and WebGL don't 107 // support the GL_BGRA texture format. 108 for (size_t b = 0; b < img_data_buf_len; b += 4) 109 { 110 u8 temp = img_data[b]; 111 img_data[b + 0] = img_data[b + 2]; 112 img_data[b + 2] = temp; 113 } 114 115 // NOTE(amin): Intentional truncating division. If height is odd, we want 116 // our last row offset to be 1 less than the middle row. 117 u32 half_height = h.height / 2; 118 for (size_t row_offset = 0; row_offset < half_height; row_offset++) 119 { 120 u8 *top_row = &img_data[row_offset * bytes_per_row]; 121 u8 *bot_row = &img_data[(h.height - row_offset - 1) * bytes_per_row]; 122 for (size_t b = 0; b < bytes_per_row; b++) 123 { 124 u8 temp = top_row[b]; 125 top_row[b] = bot_row[b]; 126 bot_row[b] = temp; 127 } 128 } 129 return img_data; 130 }