| /* |
| resource definitions are stored in MEMLIST.BIN |
| |
| each record is twenty bytes long and numbers are stored as |
| big endian |
| */ |
| |
| #include <cassert> |
| #include <cstring> |
| #include <algorithm> |
| #include <ctime> |
| |
| #include "virtual-machine.hpp" |
| |
| namespace another_world { |
| |
| uint8_t resource_heap[HEAP_SIZE]; |
| uint32_t resource_heap_offset = 0; |
| std::vector<Resource *> resources; |
| |
| ChapterResources chapter_resources[10] = { |
| {0x14, 0x15, 0x16, 0x00}, |
| {0x17, 0x18, 0x19, 0x00}, |
| {0x1a, 0x1b, 0x1c, 0x11}, |
| {0x1d, 0x1e, 0x1f, 0x11}, |
| {0x20, 0x21, 0x22, 0x11}, |
| {0x23, 0x24, 0x25, 0x00}, |
| {0x26, 0x27, 0x28, 0x11}, |
| {0x29, 0x2a, 0x2b, 0x11}, |
| {0x7d, 0x7e, 0x7f, 0x00}, |
| {0x7d, 0x7e, 0x7f, 0x00} |
| }; |
| |
| |
| // load the resource definitions from MEMLIST.BIN |
| // you must provide a pointer to a buffer than contains the |
| // file contents |
| void init_resources() { |
| |
| // TODO: move file access out of here by requiring a basic set |
| // of system calls to be provided |
| uint8_t memlist[2940]; |
| uint8_t* p = memlist; |
| |
| read_file("memlist.bin", 0, 2940, (char*)memlist); |
| |
| while (static_cast<Resource::State>(p[0]) != Resource::State::END_OF_MEMLIST) { |
| Resource* resource = new Resource(); |
| |
| // each memlist entry (resource) contains 20 bytes: |
| // |
| // 0 : state |
| // 1 : type |
| // 2 - 6: unknown (always zero) |
| // 7 : bank id |
| // 8 - 11: bank data start offset |
| // 12 - 15: packed size |
| // 16 - 19: unpacked size |
| |
| resource->state = (Resource::State)p[0]; |
| resource->type = (Resource::Type)p[1]; |
| resource->bank_id = p[7]; |
| resource->bank_offset = read_uint32_bigendian(p + 8); |
| resource->packed_size = read_uint32_bigendian(p + 12); |
| resource->size = read_uint32_bigendian(p + 16); |
| |
| resources.push_back(resource); |
| |
| p += 20; |
| } |
| } |
| |
| void load_chapter_resources(uint16_t id) { |
| |
| } |
| |
| // loads all resources that are currently in the NEEDS_LOADING state |
| void load_needed_resources() { |
| for (auto resource : resources) { |
| if (resource->state == Resource::State::NEEDS_LOADING) { |
| |
| if (resource->type == Resource::Type::SOUND || resource->type == Resource::Type::MUSIC) { |
| // TODO: we're not currently supporting audio so no point in loading the |
| // resources just yet... |
| continue; |
| } |
| |
| uint8_t* destination; |
| if (resource->type == Resource::Type::IMAGE) { |
| destination = vram[0]; |
| } |
| else { |
| destination = resource_heap + resource_heap_offset; |
| resource_heap_offset += resource->size; |
| } |
| |
| //debug("Loading resource of type " + std::to_string(resource->type) + " at offset " + std::to_string(heap_offset)); |
| resource->load(destination); |
| |
| // TODO: if the resource was an image then it's encoded as 4 bitplanes a la mode 9 |
| // we need to shuffle the pixels around to get it into our buffer format |
| if (resource->type == Resource::Type::IMAGE) { |
| uint8_t temp[320 * 200 / 2]; |
| memcpy(temp, destination, 320 * 200 / 2); |
| uint8_t* p = destination; |
| for (uint16_t y = 0; y < 200; y++) { |
| for (uint16_t x = 0; x < 320; x += 8) { |
| uint8_t b1 = temp[y * 40 + x / 8 + 0]; |
| uint8_t b2 = temp[y * 40 + x / 8 + 8000]; |
| uint8_t b3 = temp[y * 40 + x / 8 + 16000]; |
| uint8_t b4 = temp[y * 40 + x / 8 + 24000]; |
| |
| for (uint8_t i = 0; i < 4; i++) { |
| uint8_t v1 = (b1 & 0b10000000) >> 0; |
| uint8_t v2 = (b2 & 0b10000000) >> 1; |
| uint8_t v3 = (b3 & 0b10000000) >> 2; |
| uint8_t v4 = (b4 & 0b10000000) >> 3; |
| |
| b1 <<= 1; |
| b2 <<= 1; |
| b3 <<= 1; |
| b4 <<= 1; |
| |
| uint8_t v5 = (b1 & 0b10000000) >> 4; |
| uint8_t v6 = (b2 & 0b10000000) >> 5; |
| uint8_t v7 = (b3 & 0b10000000) >> 6; |
| uint8_t v8 = (b4 & 0b10000000) >> 7; |
| |
| b1 <<= 1; |
| b2 <<= 1; |
| b3 <<= 1; |
| b4 <<= 1; |
| |
| *p++ = v1 | v2 | v3 | v4 | v5 | v6 | v7 | v8; |
| } |
| } |
| } |
| } |
| |
| if (resource->type == Resource::Type::IMAGE) { |
| resource->state = Resource::State::NOT_NEEDED; |
| } |
| else { |
| resource->state = Resource::State::LOADED; |
| } |
| } |
| } |
| } |
| |
| bool Resource::load(uint8_t* destination) { |
| static std::string hex[16] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; |
| |
| // TODO: move file access out of here by requiring a basic set |
| // of system calls to be provided |
| std::string bank_filename = "bank0" + hex[this->bank_id]; |
| read_file(bank_filename, this->bank_offset, this->packed_size, (char*)destination); |
| |
| bool success = false; |
| |
| if (this->packed_size != this->size) { |
| ByteKiller bk; |
| success = bk.unpack(destination, this->packed_size); |
| } |
| |
| this->data = destination; |
| |
| return success; |
| } |
| |
| } |