a-game

2D platformer written from scratch.
git clone git://git.amin.space/a-game.git
Log | Files | Refs | README | LICENSE

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 }