#include "frontends/libretro/environment.h" #include #include #include #include #include namespace { void readFileToBuffer(const std::string & filename, std::vector & buffer) { std::ifstream file(filename.c_str(), std::ios::binary | std::ios::ate); const std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); buffer.resize(size); file.read(buffer.data(), size); } template T getAs(const std::vector & buffer, const size_t offset) { if (offset + sizeof(T) > buffer.size()) { throw std::runtime_error("Invalid bitmap"); } const T * ptr = reinterpret_cast(buffer.data() + offset); return * ptr; } // libretro cannot parse BMP with 1 bpp // simple version implemented here bool getBitmapData(const std::vector & buffer, int32_t & width, int32_t & height, uint16_t & bpp, const char * & data, uint32_t & size) { if (buffer.size() < 2) { return false; } if (buffer[0] != 0x42 || buffer[1] != 0x4D) { return false; } const uint32_t fileSize = getAs(buffer, 2); if (fileSize != buffer.size()) { return false; } const uint32_t offset = getAs(buffer, 10); const uint32_t header = getAs(buffer, 14); if (header != 40) { return false; } width = getAs(buffer, 18); height = getAs(buffer, 22); bpp = getAs(buffer, 28); const uint32_t imageSize = getAs(buffer, 34); if (offset + imageSize > fileSize) { return false; } data = buffer.data() + offset; size = imageSize; return true; } } struct CBITMAP : public CHANDLE { std::vector image; }; std::string getFilename(const std::string & resource) { if (resource == "CHARSET40") return "CHARSET4.BMP"; if (resource == "CHARSET82") return "CHARSET82.bmp"; if (resource == "CHARSET8M") return "CHARSET8M.bmp"; if (resource == "CHARSET8C") return "CHARSET8C.bmp"; return resource; } HBITMAP LoadBitmap(HINSTANCE hInstance, const char * resource) { if (resource) { const std::string filename = getFilename(resource); const std::string path = getResourcePath() + filename; std::vector buffer; readFileToBuffer(path, buffer); if (!buffer.empty()) { int32_t width, height; uint16_t bpp; const char * data; uint32_t size; const bool res = getBitmapData(buffer, width, height, bpp, data, size); log_cb(RETRO_LOG_INFO, "RA2: %s. %s = %dx%d, %dbpp\n", __FUNCTION__, path.c_str(), width, height, bpp); if (res && height > 0) { CBITMAP * bitmap = new CBITMAP; bitmap->image.resize(size); const size_t length = size / height; // rows are stored upside down for (size_t row = 0; row < height; ++row) { const char * src = data + row * length; char * dst = bitmap->image.data() + (height - row - 1) * length; memcpy(dst, src, length); } return bitmap; } } else { log_cb(RETRO_LOG_INFO, "RA2: %s. Cannot load: %s with path: %s\n", __FUNCTION__, resource, path.c_str()); return nullptr; } } log_cb(RETRO_LOG_INFO, "RA2: %s. Cannot load invaid resource\n", __FUNCTION__); return nullptr; } LONG GetBitmapBits(HBITMAP hbit, LONG cb, LPVOID lpvBits) { const CBITMAP & bitmap = dynamic_cast(*hbit); const char * bits = bitmap.image.data(); const size_t size = bitmap.image.size(); const size_t requested = cb; const size_t copied = std::min(requested, size); char * dest = static_cast(lpvBits); memcpy(dest, bits, copied); return copied; }