isle/LEGO1/mxvideopresenter.cpp
Ramen2X 74329d681b
implement/match CalcLocalTransform (#241)
* implement/match CalcLocalTransform

* fix odd build error

* address feedback

move vec.h to thirdparty folder
update vec.h
move all realtime code to realtime folder
move calclocaltransform out of legoutil and into realtime
cast shift to MxS32
add additional unroll hack to CalcLocalTransform to prevent msvc entropy
2023-10-24 14:27:24 +02:00

239 lines
5.5 KiB
C++

#include "mxvideopresenter.h"
#include "mxvideomanager.h"
DECOMP_SIZE_ASSERT(MxVideoPresenter, 0x64);
DECOMP_SIZE_ASSERT(MxVideoPresenter::AlphaMask, 0xc);
// OFFSET: LEGO1 0x1000c700
void MxVideoPresenter::VTable0x5c(undefined4 p_unknown1)
{
// Empty
}
// OFFSET: LEGO1 0x1000c710
void MxVideoPresenter::VTable0x60()
{
// Empty
}
// OFFSET: LEGO1 0x1000c720
void MxVideoPresenter::VTable0x68(undefined4 p_unknown1)
{
// Empty
}
// OFFSET: LEGO1 0x1000c730
void MxVideoPresenter::VTable0x70()
{
// Empty
}
// OFFSET: LEGO1 0x1000c740
MxVideoPresenter::~MxVideoPresenter()
{
Destroy(TRUE);
}
// OFFSET: LEGO1 0x1000c7a0
void MxVideoPresenter::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x1000c7b0
LPDIRECTDRAWSURFACE MxVideoPresenter::VTable0x78()
{
return m_unk58;
}
// OFFSET: LEGO1 0x1000c7c0
MxBool MxVideoPresenter::VTable0x7c()
{
return (m_bitmap != NULL) || (m_alpha != NULL);
}
// OFFSET: LEGO1 0x1000c7e0
MxS32 MxVideoPresenter::GetWidth()
{
return m_alpha ? m_alpha->m_width
: m_bitmap->GetBmiHeader()->biWidth;
}
// OFFSET: LEGO1 0x1000c800
MxS32 MxVideoPresenter::GetHeight()
{
return m_alpha ? m_alpha->m_height
: m_bitmap->GetBmiHeader()->biHeight;
}
// OFFSET: LEGO1 0x100b24f0
MxVideoPresenter::AlphaMask::AlphaMask(const MxBitmap &p_bitmap)
{
m_width = p_bitmap.GetBmiWidth();
// DECOMP: ECX becomes word-sized if these are not two separate actions.
MxLong _height = p_bitmap.GetBmiHeightAbs();
m_height = _height;
MxS32 size = ((m_width * m_height) / 8) + 1;
m_bitmask = new MxU8[size];
memset(m_bitmask, 0, size);
MxU32 biCompression = p_bitmap.GetBmiHeader()->biCompression;
MxU32 rows_before_top;
MxU8 *bitmap_src_ptr;
// The goal here is to enable us to walk through the bitmap's rows
// in order, regardless of the orientation. We want to end up at the
// start of the first row, which is either at position 0, or at
// (image_stride * biHeight) - 1.
// Reminder: Negative biHeight means this is a top-down DIB.
// Otherwise it is bottom-up.
if (biCompression == BI_RGB) {
// DECOMP: I think this must be an OR. If not, the check for
// biCompression == 16 gets optimized away.
if (biCompression == BI_RGB_TOPDOWN || p_bitmap.GetBmiHeight() < 0) {
rows_before_top = 0;
} else {
rows_before_top = p_bitmap.GetBmiHeightAbs();
rows_before_top--;
}
goto seek_to_last_row;
} else if (biCompression == BI_RGB_TOPDOWN) {
// DECOMP: This is the only condition where we skip the
// calculation below.
bitmap_src_ptr = p_bitmap.GetBitmapData();
} else {
if (p_bitmap.GetBmiHeight() < 0) {
rows_before_top = 0;
} else {
rows_before_top = p_bitmap.GetBmiHeightAbs();
rows_before_top--;
}
// TODO: would prefer not to use goto if we can figure this structure out
seek_to_last_row:
bitmap_src_ptr = ((p_bitmap.GetBmiWidth()+3)&-4) * rows_before_top + p_bitmap.GetBitmapData();
}
// How many bytes are there for each row of the bitmap?
// (i.e. the image stride)
// If this is a bottom-up DIB, we will walk it in reverse.
// TODO: Same rounding trick as in MxBitmap
MxS32 row_seek = ((m_height+3)&-4);
if (p_bitmap.GetBmiHeight() < 0)
row_seek = -row_seek;
// The actual offset into the m_bitmask array. The two for-loops
// are just for counting the pixels.
MxS32 offset = 0;
MxU8 *t_ptr = bitmap_src_ptr;
for (MxS32 j = 0; j < m_height; j++) {
for (MxS32 i = 0; i < m_width; i++) {
if (*t_ptr) {
// TODO: Second CDQ instruction for abs() should not be there.
MxU32 shift = abs(offset) & 7;
m_bitmask[offset / 8] |= (1 << abs((MxS32)shift));
}
t_ptr++;
offset++;
}
// Seek to the start of the next row
bitmap_src_ptr += row_seek;
t_ptr = bitmap_src_ptr;
}
}
// OFFSET: LEGO1 0x100b2670
MxVideoPresenter::AlphaMask::AlphaMask(const MxVideoPresenter::AlphaMask &p_alpha)
{
m_width = p_alpha.m_width;
m_height = p_alpha.m_height;
MxS32 size = ((m_width * m_height) / 8) + 1;
m_bitmask = new MxU8[size];
memcpy(m_bitmask, p_alpha.m_bitmask, size);
}
// OFFSET: LEGO1 0x100b26d0
MxVideoPresenter::AlphaMask::~AlphaMask()
{
if (m_bitmask)
delete[] m_bitmask;
}
// OFFSET: LEGO1 0x100b2760
void MxVideoPresenter::Init()
{
m_bitmap = NULL;
m_alpha = NULL;
m_unk5c = 1;
m_unk58 = NULL;
m_unk60 = -1;
m_flags = m_flags & 0xfe;
if (MVideoManager() != NULL) {
MVideoManager();
m_flags = m_flags | 2;
m_flags = m_flags & 0xfb;
}
m_flags = m_flags & 0xf7;
m_flags = m_flags & 0xef;
}
// OFFSET: LEGO1 0x100b27b0
void MxVideoPresenter::Destroy(MxBool p_fromDestructor)
{
if (MVideoManager() != NULL)
MVideoManager()->RemovePresenter(*this);
if (m_unk58) {
m_unk58->Release();
m_unk58 = NULL;
m_flags = m_flags & 0xfd;
m_flags = m_flags & 0xfb;
}
if (MVideoManager() && (m_alpha || m_bitmap)) {
MxS32 height = GetHeight();
MxS32 width = GetWidth();
MxS32 x = GetLocationX();
MxS32 y = GetLocationY();
MxRect32 rect(x, y, x + width, y + height);
MVideoManager()->InvalidateRect(rect);
MVideoManager()->vtable0x34(rect.m_left, rect.m_top, rect.GetWidth(), rect.GetHeight());
}
delete m_bitmap;
delete m_alpha;
Init();
if (!p_fromDestructor)
MxMediaPresenter::Destroy(FALSE);
}
// OFFSET: LEGO1 0x100b28b0 STUB
void MxVideoPresenter::VTable0x64()
{
// TODO
}
// OFFSET: LEGO1 0x100b2a70 STUB
void MxVideoPresenter::VTable0x6c()
{
// TODO
}
// OFFSET: LEGO1 0x100b3300
undefined MxVideoPresenter::VTable0x74()
{
return 0;
}