#include "frontends/retro/environment.h" #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; log_cb(RETRO_LOG_INFO, "RA2: %s. Path = %s\n", __FUNCTION__, path.c_str()); 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); if (res) { CBITMAP * bitmap = new CBITMAP; bitmap->image.assign(data, data + size); 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); for (size_t i = 0; i < copied; ++i) { dest[i] = ~bits[i]; } return copied; }