| 1005 | } |
| 1006 | |
| 1007 | bool LoadCompressedBMP(u32* pixels, const u8* src, u32 src_size, u32 width, u32 height, const BMPInfoHeader& info_header, const std::vector<u32>& palette, bool flip_vertical) |
| 1008 | { |
| 1009 | u32 src_pos = 0; |
| 1010 | const u32 pixel_size = (info_header.bit_count == 8) ? 1 : 2; |
| 1011 | |
| 1012 | for (u32 y = 0; y < height; y++) |
| 1013 | { |
| 1014 | u32 dst_y = flip_vertical ? (height - 1 - y) : y; |
| 1015 | u32* row_dst = pixels + (dst_y * width); |
| 1016 | u32 x = 0; |
| 1017 | |
| 1018 | while (x < width) |
| 1019 | { |
| 1020 | // Check bounds before reading |
| 1021 | if (src_pos + 2 > src_size) |
| 1022 | return false; |
| 1023 | |
| 1024 | const u8 count = src[src_pos++]; |
| 1025 | const u8 value = src[src_pos++]; |
| 1026 | |
| 1027 | if (count == 0) |
| 1028 | { |
| 1029 | if (value == 0) |
| 1030 | { |
| 1031 | break; |
| 1032 | } |
| 1033 | else if (value == 1) |
| 1034 | { |
| 1035 | return true; |
| 1036 | } |
| 1037 | else if (value == 2) |
| 1038 | { |
| 1039 | // Delta (jump) need 2 more bytes |
| 1040 | if (src_pos + 2 > src_size) |
| 1041 | return false; |
| 1042 | const u8 dx = src[src_pos++]; |
| 1043 | const u8 dy = src[src_pos++]; |
| 1044 | x += dx; |
| 1045 | y += dy; |
| 1046 | if (y >= height || x >= width) |
| 1047 | return false; |
| 1048 | const u32 new_dst_y = flip_vertical ? (height - 1 - y) : y; |
| 1049 | row_dst = pixels + (new_dst_y * width); |
| 1050 | } |
| 1051 | else |
| 1052 | { |
| 1053 | // Absolute mode need "value" bytes of pixel data |
| 1054 | const u32 run_length = value; |
| 1055 | const u32 bytes_needed = run_length * pixel_size; |
| 1056 | if (src_pos + bytes_needed > src_size) |
| 1057 | return false; |
| 1058 | |
| 1059 | for (u32 i = 0; i < run_length; i++) |
| 1060 | { |
| 1061 | if (x >= width) |
| 1062 | break; |
| 1063 | |
| 1064 | u8 pixel_value = 0; |