| 8 | { |
| 9 | |
| 10 | LOFTemps::LOFTemps(IFile &datFile, IFile &tabFile) |
| 11 | { |
| 12 | if (!tabFile) |
| 13 | { |
| 14 | LogError("Invalid TAB file"); |
| 15 | return; |
| 16 | } |
| 17 | |
| 18 | if (!datFile) |
| 19 | { |
| 20 | LogError("Invalid DAT file"); |
| 21 | return; |
| 22 | } |
| 23 | |
| 24 | uint32_t offset; |
| 25 | while (tabFile.readule32(offset)) |
| 26 | { |
| 27 | datFile.seekg(offset * 4, std::ios::beg); |
| 28 | if (!datFile) |
| 29 | { |
| 30 | LogError("Seeking beyond end of file reading offset %u", offset * 4); |
| 31 | return; |
| 32 | } |
| 33 | |
| 34 | uint32_t width; |
| 35 | if (!datFile.readule32(width)) |
| 36 | { |
| 37 | LogError("Failed to read width"); |
| 38 | return; |
| 39 | } |
| 40 | uint32_t height; |
| 41 | if (!datFile.readule32(height)) |
| 42 | { |
| 43 | LogError("Failed to read height"); |
| 44 | return; |
| 45 | } |
| 46 | |
| 47 | if (width % 8) |
| 48 | { |
| 49 | LogError("Non-8-bit-aligned width: %u", width); |
| 50 | return; |
| 51 | } |
| 52 | |
| 53 | auto slice = mksp<VoxelSlice>(Vec2<int>{width, height}); |
| 54 | |
| 55 | for (unsigned int y = 0; y < height; y++) |
| 56 | { |
| 57 | // Bitmasks are packed into a 32-bit word, so all strides will |
| 58 | // be 4-byte aligned |
| 59 | for (unsigned int x = 0; x < width; x += 32) |
| 60 | { |
| 61 | uint32_t bitmask; |
| 62 | if (!datFile.readule32(bitmask)) |
| 63 | { |
| 64 | LogError("Failed to read bitmask at {%u,%u}", x, y); |
| 65 | return; |
| 66 | } |
| 67 | for (unsigned int bit = 0; bit < 32; bit++) |