From 9184b284d1788a4aef5db6b528766e9d6db7365f Mon Sep 17 00:00:00 2001 From: disinvite Date: Tue, 15 Aug 2023 12:38:51 -0400 Subject: [PATCH] A few things for MxBitmap * new struct MxBITMAPINFO * vtable18 and ImportPalette 100% * ImportColorsToPalette improvement --- LEGO1/mxbitmap.cpp | 73 ++++++++++++++++++++++++++++------------------ LEGO1/mxbitmap.h | 20 +++++++++++-- 2 files changed, 62 insertions(+), 31 deletions(-) diff --git a/LEGO1/mxbitmap.cpp b/LEGO1/mxbitmap.cpp index 17a54996..30f5eb8e 100644 --- a/LEGO1/mxbitmap.cpp +++ b/LEGO1/mxbitmap.cpp @@ -1,4 +1,7 @@ #include "mxbitmap.h" +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxBITMAPINFO, 1064); // The way that the BITMAPFILEHEADER structure ensures the file type is by ensuring it is "BM", which is literally just 0x424d. // Sources: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapfileheader, DirectX Complete (1998) @@ -34,17 +37,19 @@ int MxBitmap::vtable14(int) } // OFFSET: LEGO1 0x100bcba0 -MxResult MxBitmap::vtable18(BITMAPINFOHEADER *p_bmiHeader) +MxResult MxBitmap::vtable18(MxBITMAPINFO *p_info) { MxResult result = FAILURE; - MxU32 width = p_bmiHeader->biWidth; - MxU32 height = p_bmiHeader->biHeight; + MxLong width = p_info->bmiHeader.biWidth; + MxLong height = p_info->bmiHeader.biHeight; + // ((width + 3) & -4) clamps width to nearest 4-byte boundary + MxLong size = ((width + 3) & -4) * height; - this->m_info = new BITMAPINFO; + this->m_info = new MxBITMAPINFO; if (this->m_info) { - this->m_data = (LPVOID*) malloc((sizeof(width + 3U & -4) * height)); + this->m_data = (LPVOID*) new MxU8[size]; if(this->m_data) { - memcpy(&this->m_info->bmiHeader, p_bmiHeader, sizeof(BITMAPINFO)); + memcpy(this->m_info, p_info, sizeof(MxBITMAPINFO)); this->m_bmiHeader = &this->m_info->bmiHeader; this->m_paletteData = this->m_info->bmiColors; result = SUCCESS; @@ -53,9 +58,11 @@ MxResult MxBitmap::vtable18(BITMAPINFOHEADER *p_bmiHeader) if (result != SUCCESS) { if (this->m_info) { delete this->m_info; + this->m_info = NULL; } if (this->m_data) { delete this->m_data; + this->m_data = NULL; } } return result; @@ -63,26 +70,27 @@ MxResult MxBitmap::vtable18(BITMAPINFOHEADER *p_bmiHeader) // OFFSET: LEGO1 0x100bd450 -MxResult ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette) +MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette) { - MxPalette* local_pal; MxResult ret = FAILURE; PALETTEENTRY entries[256]; - MxResult opret; - if(p_palette == NULL) { - local_pal = new MxPalette; - opret = local_pal->GetEntries(entries); - if(opret != 0) { - delete local_pal; + if (p_palette) { + if (p_palette->GetEntries(entries)) return ret; - } } else { - opret = p_palette->GetEntries(entries); - if(opret != 0) return ret; + MxPalette local_pal; + if (local_pal.GetEntries(entries)) + return ret; + } + + for (int i = 0; i < 256; i++) { + p_rgbquad[i].rgbRed = entries[i].peRed; + p_rgbquad[i].rgbGreen = entries[i].peGreen; + p_rgbquad[i].rgbBlue = entries[i].peBlue; + p_rgbquad[i].rgbReserved = 0; } - // FIXME/TODO: the loop here, possibly memcpy ret = SUCCESS; return ret; } @@ -105,14 +113,14 @@ MxResult MxBitmap::LoadFile(HANDLE p_handle) ret = ReadFile(p_handle, &hdr, sizeof(hdr), &bytesRead, NULL); if (ret && (hdr.bfType == g_bitmapSignature)) { - this->m_info = new BITMAPINFO; + this->m_info = new MxBITMAPINFO; if(this->m_info) { - ret = ReadFile(p_handle, this->m_info, 1064, &bytesRead, NULL); + ret = ReadFile(p_handle, this->m_info, sizeof(MxBITMAPINFO), &bytesRead, NULL); if (ret && ((this->m_info->bmiHeader).biBitCount == 8)) { - lpBuffer = (LPVOID*) malloc(hdr.bfSize - 1078); + lpBuffer = (LPVOID*) malloc(hdr.bfSize - (sizeof(MxBITMAPINFO) + sizeof(BITMAPFILEHEADER))); this->m_data = lpBuffer; if (this->m_data) { - ret = ReadFile(p_handle, lpBuffer, hdr.bfSize - 1078, &bytesRead, NULL); + ret = ReadFile(p_handle, lpBuffer, hdr.bfSize - (sizeof(MxBITMAPINFO) + sizeof(BITMAPFILEHEADER)), &bytesRead, NULL); if(ret != 0) { this->m_bmiHeader = &this->m_info->bmiHeader; this->m_paletteData = this->m_info->bmiColors; @@ -211,13 +219,20 @@ MxPalette *MxBitmap::CreatePalette() // OFFSET: LEGO1 0x100bd280 void MxBitmap::ImportPalette(MxPalette* p_palette) { - if (this->m_bmiColorsProvided) { - ImportColorsToPalette(this->m_paletteData, p_palette); + // This is weird but it matches. Maybe m_bmiColorsProvided had more + // potential values than just true/false at some point? + switch (this->m_bmiColorsProvided) { + case FALSE: + ImportColorsToPalette(this->m_paletteData, p_palette); + break; + + case TRUE: + if (this->m_palette) { + delete this->m_palette; + } + this->m_palette = p_palette->Clone(); + break; } - if (this->m_palette) { - delete this->m_palette; - } - this->m_palette = p_palette->Clone(); } // OFFSET: LEGO1 0x100bd2d0 STUB @@ -234,5 +249,5 @@ MxResult MxBitmap::CopyColorData(HDC p_hdc, int p_xSrc, int p_ySrc, int p_xDest, p_ySrc = (this->m_bmiHeader->biHeight - p_destHeight) - p_ySrc; } - return StretchDIBits(p_hdc, p_xDest, p_yDest, p_destWidth, p_destHeight, p_xSrc, p_ySrc, p_destWidth, p_destHeight, this->m_data, this->m_info, this->m_bmiColorsProvided, SRCCOPY); + return StretchDIBits(p_hdc, p_xDest, p_yDest, p_destWidth, p_destHeight, p_xSrc, p_ySrc, p_destWidth, p_destHeight, this->m_data, (BITMAPINFO*)this->m_info, this->m_bmiColorsProvided, SRCCOPY); } \ No newline at end of file diff --git a/LEGO1/mxbitmap.h b/LEGO1/mxbitmap.h index 92e66507..256b497e 100644 --- a/LEGO1/mxbitmap.h +++ b/LEGO1/mxbitmap.h @@ -7,6 +7,20 @@ #include "mxpalette.h" #include "mxtypes.h" +// The stock BITMAPINFO struct from wingdi.h only makes room for one color +// in the palette. It seems like the expectation (if you use the struct) +// is to malloc as much as you actually need, and then index into the array +// anyway even though its stated size is [1]. +// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfo +// In our case, the size 0x428 is used frequently, which matches +// a 40-byte header plus 256 colors, so just use that as our template. + +// SIZE 0x428 +struct MxBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +}; + class MxBitmap : public MxCore { public: @@ -14,7 +28,7 @@ class MxBitmap : public MxCore __declspec(dllexport) virtual ~MxBitmap(); // vtable+00 virtual int vtable14(int); - virtual MxResult vtable18(BITMAPINFOHEADER *p_bmiHeader); + virtual MxResult vtable18(MxBITMAPINFO *p_info); virtual int vtable1c(int p_width, int p_height, MxPalette *p_palette, int); virtual MxResult LoadFile(HANDLE p_handle); __declspec(dllexport) virtual MxLong Read(const char *p_filename); // vtable+24 @@ -27,7 +41,9 @@ class MxBitmap : public MxCore virtual MxResult CopyColorData(HDC p_hdc, int p_xSrc, int p_ySrc, int p_xDest, int p_yDest, int p_destWidth, int p_destHeight); // vtable+40 private: - BITMAPINFO *m_info; // 0x8 + MxResult ImportColorsToPalette(RGBQUAD*, MxPalette*); + + MxBITMAPINFO *m_info; // 0x8 BITMAPINFOHEADER *m_bmiHeader; // 0xc RGBQUAD *m_paletteData; // 0x10 LPVOID *m_data; // 0x14