2023-04-27 22:19:39 -04:00
|
|
|
#ifndef MXBITMAP_H
|
|
|
|
#define MXBITMAP_H
|
|
|
|
|
2023-06-30 19:24:00 -04:00
|
|
|
#include "mxcore.h"
|
|
|
|
#include "mxtypes.h"
|
2023-06-30 14:34:39 -04:00
|
|
|
|
2024-05-03 12:19:12 -04:00
|
|
|
#include <ddraw.h>
|
2023-10-24 19:38:27 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2024-05-03 12:19:12 -04:00
|
|
|
class MxPalette;
|
|
|
|
|
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>
2023-08-28 06:04:39 -04:00
|
|
|
// 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 {
|
2023-12-13 05:48:14 -05:00
|
|
|
BITMAPINFOHEADER m_bmiHeader;
|
|
|
|
RGBQUAD m_bmiColors[256];
|
2023-12-25 21:58:39 -05:00
|
|
|
|
|
|
|
static MxU32 Size() { return sizeof(MxBITMAPINFO); }
|
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>
2023-08-28 06:04:39 -04:00
|
|
|
};
|
|
|
|
|
2023-10-21 18:40:31 -04:00
|
|
|
// Non-standard value for biCompression in the BITMAPINFOHEADER struct.
|
|
|
|
// By default, uncompressed bitmaps (BI_RGB) are stored in bottom-up order.
|
|
|
|
// You can specify that the bitmap has top-down order instead by providing
|
|
|
|
// a negative number for biHeight. It could be that Mindscape decided on a
|
|
|
|
// belt & suspenders approach here.
|
2023-10-24 19:38:27 -04:00
|
|
|
#define BI_RGB_TOPDOWN 0x10
|
2023-10-21 18:40:31 -04:00
|
|
|
|
2023-10-07 12:48:36 -04:00
|
|
|
// SIZE 0x20
|
2023-12-06 07:10:45 -05:00
|
|
|
// VTABLE: LEGO1 0x100dc7b0
|
2024-05-28 03:32:51 -04:00
|
|
|
// VTABLE: BETA10 0x101c21f8
|
2023-10-24 19:38:27 -04:00
|
|
|
class MxBitmap : public MxCore {
|
2023-04-27 22:19:39 -04:00
|
|
|
public:
|
2024-01-24 21:16:29 -05:00
|
|
|
MxBitmap();
|
2024-02-01 15:42:10 -05:00
|
|
|
~MxBitmap() override; // vtable+00
|
2023-07-02 00:49:42 -04:00
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
virtual MxResult ImportBitmap(MxBitmap* p_bitmap); // vtable+14
|
|
|
|
virtual MxResult ImportBitmapInfo(MxBITMAPINFO* p_info); // vtable+18
|
|
|
|
virtual MxResult SetSize(MxS32 p_width, MxS32 p_height, MxPalette* p_palette, MxBool); // vtable+1c
|
|
|
|
virtual MxResult LoadFile(HANDLE p_handle); // vtable+20
|
2024-01-24 21:16:29 -05:00
|
|
|
virtual MxLong Read(const char* p_filename); // vtable+24
|
2024-01-11 10:02:55 -05:00
|
|
|
|
|
|
|
// FUNCTION: LEGO1 0x1004e0d0
|
2024-05-28 03:32:51 -04:00
|
|
|
// FUNCTION: BETA10 0x10060fc0
|
2024-01-29 17:30:20 -05:00
|
|
|
virtual int VTable0x28(int) { return -1; } // vtable+28
|
2024-01-19 09:38:06 -05:00
|
|
|
|
|
|
|
virtual void BitBlt(
|
|
|
|
MxBitmap* p_src,
|
|
|
|
MxS32 p_left,
|
|
|
|
MxS32 p_top,
|
|
|
|
MxS32 p_right,
|
|
|
|
MxS32 p_bottom,
|
|
|
|
MxS32 p_width,
|
|
|
|
MxS32 p_height
|
|
|
|
); // vtable+2c
|
|
|
|
virtual void BitBltTransparent(
|
|
|
|
MxBitmap* p_src,
|
|
|
|
MxS32 p_left,
|
|
|
|
MxS32 p_top,
|
|
|
|
MxS32 p_right,
|
|
|
|
MxS32 p_bottom,
|
|
|
|
MxS32 p_width,
|
|
|
|
MxS32 p_height
|
2024-01-24 21:16:29 -05:00
|
|
|
); // vtable+30
|
|
|
|
virtual MxPalette* CreatePalette(); // vtable+34
|
|
|
|
virtual void ImportPalette(MxPalette* p_palette); // vtable+38
|
|
|
|
virtual MxResult SetBitDepth(MxBool); // vtable+3c
|
2023-10-24 19:38:27 -04:00
|
|
|
virtual MxResult StretchBits(
|
|
|
|
HDC p_hdc,
|
|
|
|
MxS32 p_xSrc,
|
|
|
|
MxS32 p_ySrc,
|
|
|
|
MxS32 p_xDest,
|
|
|
|
MxS32 p_yDest,
|
|
|
|
MxS32 p_destWidth,
|
|
|
|
MxS32 p_destHeight
|
|
|
|
); // vtable+40
|
2023-07-02 00:49:42 -04:00
|
|
|
|
2023-12-25 21:58:39 -05:00
|
|
|
// Bit mask trick to round up to the nearest multiple of four.
|
|
|
|
// Pixel data may be stored with padding.
|
|
|
|
// https://learn.microsoft.com/en-us/windows/win32/medfound/image-stride
|
2024-05-28 03:32:51 -04:00
|
|
|
// FUNCTION: BETA10 0x1002c510
|
2024-07-04 19:06:32 -04:00
|
|
|
MxLong AlignToFourByte(MxLong p_value) const { return (p_value + 3) & -4; }
|
2023-12-25 21:58:39 -05:00
|
|
|
|
2024-05-28 03:32:51 -04:00
|
|
|
// DECOMP: This could be a free function. It is static here because it has no
|
|
|
|
// reference to "this". In the beta it is called in two places:
|
|
|
|
// 1. GetBmiHeightAbs
|
|
|
|
// 2. at 0x101523b9, in reference to BITMAPINFOHEADER.biHeight
|
|
|
|
// FUNCTION: BETA10 0x1002c690
|
|
|
|
static MxLong HeightAbs(MxLong p_value) { return p_value > 0 ? p_value : -p_value; }
|
2023-12-25 21:58:39 -05:00
|
|
|
|
2024-07-04 12:50:04 -04:00
|
|
|
// FUNCTION: BETA10 0x10142030
|
2024-07-04 19:06:32 -04:00
|
|
|
BITMAPINFOHEADER* GetBmiHeader() const { return m_bmiHeader; }
|
2024-05-28 03:32:51 -04:00
|
|
|
|
|
|
|
// FUNCTION: BETA10 0x1002c440
|
2024-07-04 19:06:32 -04:00
|
|
|
MxLong GetBmiWidth() const { return m_bmiHeader->biWidth; }
|
|
|
|
MxLong GetBmiStride() const { return ((m_bmiHeader->biWidth + 3) & -4); }
|
|
|
|
MxLong GetBmiHeight() const { return m_bmiHeader->biHeight; }
|
2024-05-28 03:32:51 -04:00
|
|
|
|
|
|
|
// FUNCTION: BETA10 0x1002c470
|
2024-07-04 19:06:32 -04:00
|
|
|
MxLong GetBmiHeightAbs() const { return HeightAbs(m_bmiHeader->biHeight); }
|
2024-05-28 03:32:51 -04:00
|
|
|
|
|
|
|
// FUNCTION: BETA10 0x10083900
|
2024-07-04 19:06:32 -04:00
|
|
|
MxU8* GetImage() const { return m_data; }
|
2024-05-28 03:32:51 -04:00
|
|
|
|
|
|
|
// FUNCTION: BETA10 0x100838d0
|
2024-07-04 19:06:32 -04:00
|
|
|
MxBITMAPINFO* GetBitmapInfo() const { return m_info; }
|
2024-05-28 03:32:51 -04:00
|
|
|
|
|
|
|
// FUNCTION: BETA10 0x100982b0
|
2024-07-04 19:06:32 -04:00
|
|
|
MxLong GetDataSize() const { return AlignToFourByte(m_bmiHeader->biWidth) * GetBmiHeightAbs(); }
|
2024-05-28 03:32:51 -04:00
|
|
|
|
2024-05-29 10:47:25 -04:00
|
|
|
// FUNCTION: BETA10 0x1002c4b0
|
2024-07-04 19:06:32 -04:00
|
|
|
MxBool IsTopDown()
|
2023-12-31 15:29:05 -05:00
|
|
|
{
|
2024-05-29 10:47:25 -04:00
|
|
|
if (m_bmiHeader->biCompression == BI_RGB_TOPDOWN) {
|
|
|
|
return TRUE;
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
|
|
|
else {
|
2024-05-29 10:47:25 -04:00
|
|
|
return m_bmiHeader->biHeight < 0;
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
2023-12-31 15:29:05 -05:00
|
|
|
}
|
2023-10-07 12:48:36 -04:00
|
|
|
|
2024-07-04 12:50:04 -04:00
|
|
|
#define GetAdjustedStride(p_bitmap) \
|
|
|
|
(p_bitmap->IsTopDown() ? p_bitmap->AlignToFourByte(p_bitmap->GetBmiWidth()) \
|
|
|
|
: -p_bitmap->AlignToFourByte(p_bitmap->GetBmiWidth()))
|
2024-01-19 09:38:06 -05:00
|
|
|
|
2024-05-29 10:47:25 -04:00
|
|
|
// FUNCTION: BETA10 0x1002c320
|
2024-07-04 19:06:32 -04:00
|
|
|
MxU8* GetStart(MxS32 p_left, MxS32 p_top)
|
2024-01-19 09:38:06 -05:00
|
|
|
{
|
2024-02-01 15:42:10 -05:00
|
|
|
if (m_bmiHeader->biCompression == BI_RGB) {
|
2024-05-29 10:47:25 -04:00
|
|
|
return m_data + p_left +
|
|
|
|
AlignToFourByte(GetBmiWidth()) * (IsTopDown() ? p_top : (GetBmiHeightAbs() - 1) - p_top);
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
|
|
|
else if (m_bmiHeader->biCompression == BI_RGB_TOPDOWN) {
|
2024-01-19 09:38:06 -05:00
|
|
|
return m_data;
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
|
|
|
else {
|
2024-05-29 10:47:25 -04:00
|
|
|
return m_data + AlignToFourByte(GetBmiWidth()) * (IsTopDown() ? 0 : (GetBmiHeightAbs() - 1));
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
2024-01-19 09:38:06 -05:00
|
|
|
}
|
|
|
|
|
2024-01-18 08:34:14 -05:00
|
|
|
// SYNTHETIC: LEGO1 0x100bc9f0
|
2024-05-28 03:32:51 -04:00
|
|
|
// SYNTHETIC: BETA10 0x1013dcd0
|
2024-01-18 08:34:14 -05:00
|
|
|
// MxBitmap::`scalar deleting destructor'
|
|
|
|
|
2023-06-30 19:24:00 -04:00
|
|
|
private:
|
2024-05-28 03:32:51 -04:00
|
|
|
// FUNCTION: BETA10 0x1013dd10
|
2024-07-04 19:06:32 -04:00
|
|
|
MxLong MxBitmapInfoSize() const { return sizeof(MxBITMAPINFO); }
|
2024-05-28 03:32:51 -04:00
|
|
|
|
|
|
|
// FUNCTION: BETA10 0x1013dd30
|
2024-07-04 19:06:32 -04:00
|
|
|
MxBool IsBottomUp()
|
2024-05-28 03:32:51 -04:00
|
|
|
{
|
|
|
|
if (m_bmiHeader->biCompression == BI_RGB_TOPDOWN) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return m_bmiHeader->biHeight > 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
MxResult ImportColorsToPalette(RGBQUAD*, MxPalette*);
|
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>
2023-08-28 06:04:39 -04:00
|
|
|
|
2024-01-29 16:17:17 -05:00
|
|
|
MxBITMAPINFO* m_info; // 0x08
|
|
|
|
BITMAPINFOHEADER* m_bmiHeader; // 0x0c
|
2023-10-24 19:38:27 -04:00
|
|
|
RGBQUAD* m_paletteData; // 0x10
|
|
|
|
MxU8* m_data; // 0x14
|
|
|
|
MxBool m_isHighColor; // 0x18
|
|
|
|
MxPalette* m_palette; // 0x1c
|
2023-04-27 22:19:39 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // MXBITMAP_H
|