mirror of
https://github.com/isledecomp/isle-portable.git
synced 2024-11-22 15:37:55 -05:00
Some MxBitmap vtable functions (#89)
* Match MxBitmap::vtable+40 (CopyColorData) It's basically a call to StretchDIBits, which copies color data for a rectangle * Name a ternary raster op * Name variable m_unk18 (m_bmiColorsProvided) Since this variable is passed to StretchDIBits, we can see what its supposed to mean. We dont have DX5 docs, but we have docs of the current day, and this as its 'iUsage': "Specifies whether the bmiColors member of the BITMAPINFO structure was provided and, if so, whether bmiColors contains explicit red, green, blue (RGB) values or indexes." The second part (about what the bmiColors contains) seems redundant, since we know this is a boolean. Source: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchdibits * MxBitmap::CreatePalette is now up to 60% * Add progress on MxBitmap::LoadFile, add the global bitmap signature, add Clone call in CreatePalette * getting closer * Implement MxBitmap::vtable18 * Got vtable18 into a better state It's progress doesn't affect the status of CopyColorData, which is back at 100%, as it makes sense the loop is a memcpy * if you want to do more of vtable18 have fun * Cleanup MxBitmap::LoadFile * Begin work on FUN_100bd450 (ImportColorsToPalette) This took a lot of time, finally I got a good understanding of it. Primarily what's left now is the loop https://hackmd.io/@KsNMFSBHTO2gxDyRIPRQ1g/H1LCVQXon * Don’t include class name in method declaration * yolo vtable38 (I can't test the build atm) I moved up ImportColorsToPalette so other functions, including this one can use it * Cleanup while i keep getting bored of matching these functions that wont match * likely malloc is an operator new * A few things for MxBitmap * new struct MxBITMAPINFO * vtable18 and ImportPalette 100% * ImportColorsToPalette improvement * Match vtable1c and vtable3c * use MxResult return types * CreatePalette - Use MxResult to track success * Define types for the bit depth That boolean is not really a boolean, its just a variable to store the bit depth as some DWORD. 0 = 256 color, 1 = High Color (16-bit). * Match MxBitmap::CreatePalette * Match LoadFile YEGYEEHEEHEHEHEHEHE3 YES THIS IS FINALLY DONE OMFG * Reorder variable placement in CreatePalette * Start vtable14 * Match MxBitmap vtable14, down to reg swap. Maybe some import function? * Name MxBitmap vtable functions --------- Co-authored-by: disinvite <disinvite@users.noreply.github.com> Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
parent
5a2cc72dbb
commit
c7458211f3
2 changed files with 319 additions and 58 deletions
|
@ -1,4 +1,12 @@
|
|||
#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)
|
||||
// GLOBAL: LEGO1 0x10102184
|
||||
undefined2 g_bitmapSignature = 0x424d;
|
||||
|
||||
// OFFSET: LEGO1 0x100bc980
|
||||
MxBitmap::MxBitmap()
|
||||
|
@ -7,43 +15,214 @@ MxBitmap::MxBitmap()
|
|||
this->m_bmiHeader = NULL;
|
||||
this->m_paletteData = NULL;
|
||||
this->m_data = NULL;
|
||||
this->m_unk18 = FALSE;
|
||||
this->m_bitDepth = LOWCOLOR;
|
||||
this->m_palette = NULL;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bca10
|
||||
MxBitmap::~MxBitmap()
|
||||
{
|
||||
if (this->m_info != NULL)
|
||||
if (this->m_info)
|
||||
delete m_info;
|
||||
if (this->m_data != NULL)
|
||||
if (this->m_data)
|
||||
delete m_data;
|
||||
if (this->m_palette != NULL)
|
||||
if (this->m_palette)
|
||||
delete m_palette;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bcc40 STUB
|
||||
int MxBitmap::vtable14(int)
|
||||
// OFFSET: LEGO1 0x100bcc40
|
||||
MxResult MxBitmap::ImportBitmap(MxBitmap *p_bitmap)
|
||||
{
|
||||
return 0;
|
||||
MxLong height;
|
||||
MxResult result = FAILURE;
|
||||
|
||||
this->m_info = new MxBITMAPINFO;
|
||||
if(this->m_info) {
|
||||
height = p_bitmap->m_bmiHeader->biHeight;
|
||||
if (height <= 0L) {
|
||||
height = -height;
|
||||
}
|
||||
this->m_data = (LPVOID*) new MxU8[(p_bitmap->m_bmiHeader->biWidth + 3U & -4) * height];
|
||||
if(this->m_data) {
|
||||
memcpy(this->m_info, p_bitmap->m_info, sizeof(MxBITMAPINFO));
|
||||
|
||||
height = p_bitmap->m_bmiHeader->biHeight;
|
||||
if (height <= 0L) {
|
||||
height = -height;
|
||||
}
|
||||
memcpy(this->m_data, p_bitmap->m_data, (p_bitmap->m_bmiHeader->biWidth + 3U & -4) * height);
|
||||
|
||||
result = SUCCESS;
|
||||
this->m_bmiHeader = &this->m_info->bmiHeader;
|
||||
this->m_paletteData = this->m_info->bmiColors;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bcba0 STUB
|
||||
int MxBitmap::vtable18(BITMAPINFOHEADER *p_bmiHeader)
|
||||
// OFFSET: LEGO1 0x100bcba0
|
||||
MxResult MxBitmap::ImportBitmapInfo(MxBITMAPINFO *p_info)
|
||||
{
|
||||
return 0;
|
||||
MxResult result = FAILURE;
|
||||
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 MxBITMAPINFO;
|
||||
if (this->m_info) {
|
||||
this->m_data = (LPVOID*) new MxU8[size];
|
||||
if(this->m_data) {
|
||||
memcpy(this->m_info, p_info, sizeof(MxBITMAPINFO));
|
||||
this->m_bmiHeader = &this->m_info->bmiHeader;
|
||||
this->m_paletteData = this->m_info->bmiColors;
|
||||
result = SUCCESS;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bcaa0 STUB
|
||||
int MxBitmap::vtable1c(int p_width, int p_height, MxPalette *p_palette, int)
|
||||
|
||||
// OFFSET: LEGO1 0x100bd450
|
||||
MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette)
|
||||
{
|
||||
return 0;
|
||||
MxResult ret = FAILURE;
|
||||
PALETTEENTRY entries[256];
|
||||
|
||||
if (p_palette) {
|
||||
if (p_palette->GetEntries(entries))
|
||||
return ret;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
ret = SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bcd60 STUB
|
||||
// OFFSET: LEGO1 0x100bcaa0
|
||||
MxResult MxBitmap::SetSize(int p_width, int p_height, MxPalette *p_palette, int p_bitDepth)
|
||||
{
|
||||
MxResult ret = FAILURE;
|
||||
MxLong size = ((p_width + 3) & -4) * p_height;
|
||||
|
||||
m_info = new MxBITMAPINFO;
|
||||
if (m_info) {
|
||||
m_data = (LPVOID*) new MxU8[size];
|
||||
if (m_data) {
|
||||
m_bmiHeader = &m_info->bmiHeader;
|
||||
m_paletteData = m_info->bmiColors;
|
||||
memset(&m_info->bmiHeader, 0, sizeof(m_info->bmiHeader));
|
||||
|
||||
m_bmiHeader->biSize = sizeof(*m_bmiHeader); // should be 40 bytes
|
||||
m_bmiHeader->biWidth = p_width;
|
||||
m_bmiHeader->biHeight = p_height;
|
||||
m_bmiHeader->biPlanes = 1;
|
||||
m_bmiHeader->biBitCount = 8;
|
||||
m_bmiHeader->biCompression = 0;
|
||||
m_bmiHeader->biSizeImage = size;
|
||||
|
||||
if (!ImportColorsToPalette(m_paletteData, p_palette)) {
|
||||
if (!SetBitDepth(p_bitDepth)) {
|
||||
ret = SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (m_info) {
|
||||
delete m_info;
|
||||
m_info = NULL;
|
||||
}
|
||||
|
||||
if (m_data) {
|
||||
delete[] m_data;
|
||||
m_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bcd60
|
||||
MxResult MxBitmap::LoadFile(HANDLE p_handle)
|
||||
{
|
||||
return SUCCESS;
|
||||
BOOL ret;
|
||||
LPVOID* lpBuffer;
|
||||
MxLong height;
|
||||
MxResult result = FAILURE;
|
||||
DWORD bytesRead;
|
||||
BITMAPFILEHEADER hdr;
|
||||
MxLong size;
|
||||
|
||||
ret = ReadFile(p_handle, &hdr, sizeof(hdr), &bytesRead, NULL);
|
||||
if (ret && (hdr.bfType == g_bitmapSignature)) {
|
||||
this->m_info = new MxBITMAPINFO;
|
||||
if(this->m_info) {
|
||||
ret = ReadFile(p_handle, this->m_info, sizeof(MxBITMAPINFO), &bytesRead, NULL);
|
||||
if (ret && ((this->m_info->bmiHeader).biBitCount == 8)) {
|
||||
size = hdr.bfSize - (sizeof(MxBITMAPINFO) + sizeof(BITMAPFILEHEADER));
|
||||
lpBuffer = (LPVOID*) new MxU8[size];
|
||||
this->m_data = lpBuffer;
|
||||
if (lpBuffer) {
|
||||
ret = ReadFile(p_handle, lpBuffer, size, &bytesRead, NULL);
|
||||
if(ret) {
|
||||
this->m_bmiHeader = &this->m_info->bmiHeader;
|
||||
this->m_paletteData = this->m_info->bmiColors;
|
||||
if((this->m_info->bmiHeader).biSizeImage == 0) {
|
||||
height = (this->m_info->bmiHeader).biHeight;
|
||||
if (height <= 0L) {
|
||||
height = -height;
|
||||
}
|
||||
(this->m_info->bmiHeader).biSizeImage = ((this->m_info->bmiHeader).biWidth + 3U & -4) * height;
|
||||
}
|
||||
result = SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bcd10
|
||||
|
@ -75,12 +254,12 @@ int MxBitmap::vtable28(int)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100ce70 STUB
|
||||
// OFFSET: LEGO1 0x100bce70 STUB
|
||||
void MxBitmap::vtable2c(int, int, int, int, int, int, int)
|
||||
{
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100d020 STUB
|
||||
// OFFSET: LEGO1 0x100bd020 STUB
|
||||
void MxBitmap::vtable30(int, int, int, int, int, int, int)
|
||||
{
|
||||
}
|
||||
|
@ -88,42 +267,104 @@ void MxBitmap::vtable30(int, int, int, int, int, int, int)
|
|||
// OFFSET: LEGO1 0x100bd1c0
|
||||
MxPalette *MxBitmap::CreatePalette()
|
||||
{
|
||||
// FIXME: This function needs MxPalette to be completed. Also INFERRING usage of MxBool
|
||||
MxPalette *pal = NULL;
|
||||
MxPalette *ppal;
|
||||
MxBool success = FALSE;
|
||||
MxPalette *palette = NULL;
|
||||
|
||||
if(this->m_unk18 == FALSE) {
|
||||
// ppal = MxPalette::FromBitmapPalette(this->m_paletteData);
|
||||
} else {
|
||||
if(this->m_unk18 != TRUE) {
|
||||
if(!success && pal != NULL) {
|
||||
delete pal;
|
||||
pal = NULL;
|
||||
switch (this->m_bitDepth) {
|
||||
case LOWCOLOR:
|
||||
palette = new MxPalette(this->m_paletteData);
|
||||
if (palette)
|
||||
success = TRUE;
|
||||
break;
|
||||
|
||||
case HIGHCOLOR:
|
||||
palette = this->m_palette->Clone();
|
||||
if (palette)
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success && palette) {
|
||||
delete palette;
|
||||
palette = NULL;
|
||||
}
|
||||
|
||||
return palette;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bd280
|
||||
void MxBitmap::ImportPalette(MxPalette* 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_bitDepth) {
|
||||
case LOWCOLOR:
|
||||
ImportColorsToPalette(this->m_paletteData, p_palette);
|
||||
break;
|
||||
|
||||
case HIGHCOLOR:
|
||||
if (this->m_palette) {
|
||||
delete this->m_palette;
|
||||
}
|
||||
this->m_palette = p_palette->Clone();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bd2d0
|
||||
MxResult MxBitmap::SetBitDepth(MxBool p_bitDepth)
|
||||
{
|
||||
MxResult ret = FAILURE;
|
||||
MxPalette *pal = NULL;
|
||||
|
||||
if (m_bitDepth == p_bitDepth) {
|
||||
// no change: do nothing.
|
||||
ret = SUCCESS;
|
||||
} else {
|
||||
// TODO: Another switch used for this boolean value? Is it not a bool?
|
||||
switch (p_bitDepth) {
|
||||
case 0:
|
||||
ImportColorsToPalette(m_paletteData, m_palette);
|
||||
if (m_palette)
|
||||
delete m_palette;
|
||||
|
||||
m_palette = NULL;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pal = NULL;
|
||||
pal = new MxPalette(m_paletteData);
|
||||
if (pal) {
|
||||
m_palette = pal;
|
||||
|
||||
// TODO: what is this? zeroing out top half of palette?
|
||||
MxU16 *buf = (MxU16*)m_paletteData;
|
||||
for (MxU16 i = 0; i < 256; i++) {
|
||||
buf[i] = i;
|
||||
}
|
||||
|
||||
m_bitDepth = p_bitDepth;
|
||||
ret = SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//.pal = MxPalette::Clone(this->m_palette);
|
||||
}
|
||||
if(pal != NULL) {
|
||||
success = TRUE;
|
||||
}
|
||||
|
||||
return pal;
|
||||
// If we were unsuccessful overall but did manage to alloc
|
||||
// the MxPalette, free it.
|
||||
if (ret && pal)
|
||||
delete pal;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bd280 STUB
|
||||
void MxBitmap::vtable38(void*)
|
||||
// OFFSET: LEGO1 0x100bd3e0
|
||||
MxResult MxBitmap::StretchBits(HDC p_hdc, int p_xSrc, int p_ySrc, int p_xDest, int p_yDest, int p_destWidth, int p_destHeight)
|
||||
{
|
||||
}
|
||||
// Compression fix?
|
||||
if ((this->m_bmiHeader->biCompression != 16) && (0 < this->m_bmiHeader->biHeight)) {
|
||||
p_ySrc = (this->m_bmiHeader->biHeight - p_destHeight) - p_ySrc;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bd2d0 STUB
|
||||
int MxBitmap::vtable3c(MxBool)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OFFSET: LEGO1 0x100bd3e0 STUB
|
||||
int MxBitmap::vtable40(HDC p_hdc, int p_xSrc, int p_ySrc, int p_xDest, int p_yDest, int p_destWidth, int p_destHeight)
|
||||
{
|
||||
return 0;
|
||||
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_bitDepth, SRCCOPY);
|
||||
}
|
|
@ -7,32 +7,52 @@
|
|||
#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];
|
||||
};
|
||||
|
||||
// These values are the bit depth, set in the registry
|
||||
#define LOWCOLOR 0 // 256 color
|
||||
#define HIGHCOLOR 1 // High Color (16-bit)
|
||||
|
||||
class MxBitmap : public MxCore
|
||||
{
|
||||
public:
|
||||
__declspec(dllexport) MxBitmap();
|
||||
__declspec(dllexport) virtual ~MxBitmap(); // vtable+00
|
||||
|
||||
virtual int vtable14(int);
|
||||
virtual int vtable18(BITMAPINFOHEADER *p_bmiHeader);
|
||||
virtual int vtable1c(int p_width, int p_height, MxPalette *p_palette, int);
|
||||
virtual MxResult LoadFile(HANDLE p_handle);
|
||||
virtual MxResult ImportBitmap(MxBitmap *p_bitmap); // vtable+14
|
||||
virtual MxResult ImportBitmapInfo(MxBITMAPINFO *p_info); // vtable+18
|
||||
virtual MxResult SetSize(int p_width, int p_height, MxPalette *p_palette, int); // vtable+1c
|
||||
virtual MxResult LoadFile(HANDLE p_handle); // vtable+20
|
||||
__declspec(dllexport) virtual MxLong Read(const char *p_filename); // vtable+24
|
||||
virtual int vtable28(int);
|
||||
virtual void vtable2c(int, int, int, int, int, int, int);
|
||||
virtual void vtable30(int, int, int, int, int, int, int);
|
||||
__declspec(dllexport) virtual MxPalette *CreatePalette(); // vtable+34
|
||||
virtual void vtable38(void*);
|
||||
virtual int vtable3c(MxBool);
|
||||
virtual int vtable40(HDC p_hdc, int p_xSrc, int p_ySrc, int p_xDest, int p_yDest, int p_destWidth, int p_destHeight);
|
||||
virtual void ImportPalette(MxPalette* p_palette); // vtable+38
|
||||
virtual MxResult SetBitDepth(MxBool); // vtable+3c
|
||||
virtual MxResult StretchBits(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;
|
||||
BITMAPINFOHEADER *m_bmiHeader;
|
||||
RGBQUAD *m_paletteData;
|
||||
LPVOID *m_data;
|
||||
MxBool m_unk18;
|
||||
MxPalette *m_palette;
|
||||
MxResult ImportColorsToPalette(RGBQUAD*, MxPalette*);
|
||||
|
||||
MxBITMAPINFO *m_info; // 0x8
|
||||
BITMAPINFOHEADER *m_bmiHeader; // 0xc
|
||||
RGBQUAD *m_paletteData; // 0x10
|
||||
LPVOID *m_data; // 0x14
|
||||
MxBool m_bitDepth; // 0x18
|
||||
MxPalette *m_palette; // 0x1c
|
||||
};
|
||||
|
||||
#endif // MXBITMAP_H
|
||||
|
|
Loading…
Reference in a new issue