From 51adb31541ee49f8eccabd3ed0f22d667d11dbaa Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 29 Dec 2023 16:30:17 -0500 Subject: [PATCH] Implement MxVideoPresenter::PutFrame (#389) * Implementation of MxVideoPresenter::PutFrame * Add TODOs --- LEGO1/mxdisplaysurface.cpp | 24 ++++--- LEGO1/mxdisplaysurface.h | 24 ++++--- LEGO1/mxrect32.h | 18 ++--- LEGO1/mxsize32.h | 12 ++-- LEGO1/mxstillpresenter.cpp | 15 +--- LEGO1/mxvideomanager.h | 1 + LEGO1/mxvideopresenter.cpp | 140 ++++++++++++++++++++++++++++++++++--- LEGO1/mxvideopresenter.h | 2 + 8 files changed, 186 insertions(+), 50 deletions(-) diff --git a/LEGO1/mxdisplaysurface.cpp b/LEGO1/mxdisplaysurface.cpp index de4d7006..59aadaff 100644 --- a/LEGO1/mxdisplaysurface.cpp +++ b/LEGO1/mxdisplaysurface.cpp @@ -224,20 +224,28 @@ void MxDisplaySurface::SetPalette(MxPalette* p_palette) } // STUB: LEGO1 0x100bacc0 -MxBool MxDisplaySurface::VTable0x28(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4) +MxBool MxDisplaySurface::VTable0x28( + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height +) { return 0; } // STUB: LEGO1 0x100bb1d0 MxBool MxDisplaySurface::VTable0x30( - undefined4, - undefined4, - undefined4, - undefined4, - undefined4, - undefined4, - undefined4, + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height, MxBool ) { diff --git a/LEGO1/mxdisplaysurface.h b/LEGO1/mxdisplaysurface.h index 45714ce1..46732afe 100644 --- a/LEGO1/mxdisplaysurface.h +++ b/LEGO1/mxdisplaysurface.h @@ -39,7 +39,15 @@ class MxDisplaySurface : public MxCore { undefined4, undefined4 ); - virtual MxBool VTable0x28(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4); + virtual MxBool VTable0x28( + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height + ); virtual MxBool VTable0x2c( LPDDSURFACEDESC, MxBitmap*, @@ -52,13 +60,13 @@ class MxDisplaySurface : public MxCore { MxBool ); virtual MxBool VTable0x30( - undefined4, - undefined4, - undefined4, - undefined4, - undefined4, - undefined4, - undefined4, + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height, MxBool ); virtual undefined4 VTable0x34(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4); diff --git a/LEGO1/mxrect32.h b/LEGO1/mxrect32.h index 7566a9ea..c05d5c67 100644 --- a/LEGO1/mxrect32.h +++ b/LEGO1/mxrect32.h @@ -16,13 +16,7 @@ class MxRect32 { this->m_bottom = p_bottom; } - MxRect32(const MxPoint32& p_point, const MxSize32& p_size) - { - this->m_left = p_point.GetX(); - this->m_top = p_point.GetY(); - this->m_right = p_size.GetWidth(); - this->m_bottom = p_size.GetHeight(); - } + MxRect32(const MxPoint32& p_point, const MxSize32& p_size) { CopyFrom(p_point, p_size); } MxRect32(const MxRect32& p_a, const MxRect32& p_b) { @@ -98,7 +92,6 @@ class MxRect32 { inline void SetRight(MxS32 p_right) { m_right = p_right; } inline void SetBottom(MxS32 p_bottom) { m_bottom = p_bottom; } -private: inline void CopyFrom(const MxRect32& p_rect) { this->m_left = p_rect.m_left; @@ -107,6 +100,15 @@ class MxRect32 { this->m_bottom = p_rect.m_bottom; } + inline void CopyFrom(const MxPoint32& p_point, const MxSize32& p_size) + { + this->m_left = p_point.GetX(); + this->m_top = p_point.GetY(); + this->m_right = p_size.GetWidth() + p_point.GetX(); + this->m_bottom = p_size.GetHeight() + p_point.GetY(); + } + +private: inline static MxS32 Min(MxS32 p_a, MxS32 p_b) { return p_a <= p_b ? p_a : p_b; }; inline static MxS32 Max(MxS32 p_a, MxS32 p_b) { return p_a <= p_b ? p_b : p_a; }; diff --git a/LEGO1/mxsize32.h b/LEGO1/mxsize32.h index a8b30368..2c0141bc 100644 --- a/LEGO1/mxsize32.h +++ b/LEGO1/mxsize32.h @@ -6,16 +6,18 @@ class MxSize32 { public: MxSize32() {} - MxSize32(MxS32 p_width, MxS32 p_height) - { - this->m_width = p_width; - this->m_height = p_height; - } + MxSize32(MxS32 p_width, MxS32 p_height) { Assign(p_width, p_height); } inline MxS32 GetWidth() const { return m_width; } inline MxS32 GetHeight() const { return m_height; } private: + inline void Assign(MxS32 p_width, MxS32 p_height) + { + this->m_width = p_width; + this->m_height = p_height; + } + MxS32 m_width; MxS32 m_height; }; diff --git a/LEGO1/mxstillpresenter.cpp b/LEGO1/mxstillpresenter.cpp index 5474f8e3..8b17207f 100644 --- a/LEGO1/mxstillpresenter.cpp +++ b/LEGO1/mxstillpresenter.cpp @@ -71,12 +71,7 @@ void MxStillPresenter::LoadFrame(MxStreamChunk* p_chunk) { memcpy(m_bitmap->GetBitmapData(), p_chunk->GetData(), p_chunk->GetLength()); - MxS32 height = GetHeight() - 1; - MxS32 width = GetWidth() - 1; - MxS32 x = m_location.GetX(); - MxS32 y = m_location.GetY(); - - MxRect32 rect(x, y, width + x, height + y); + MxRect32 rect(m_location, MxSize32(GetWidth() - 1, GetHeight() - 1)); MVideoManager()->InvalidateRect(rect); if (m_flags & Flag_Bit2) { @@ -154,6 +149,7 @@ void MxStillPresenter::VTable0x88(MxS32 p_x, MxS32 p_y) m_location.SetY(p_y); if (IsEnabled()) { + // Most likely needs to work with MxSize32 and MxPoint32 MxS32 height = GetHeight() - 1; MxS32 width = GetWidth() - 1; @@ -174,12 +170,7 @@ void MxStillPresenter::Enable(MxBool p_enable) MxVideoPresenter::Enable(p_enable); if (MVideoManager() && (m_alpha || m_bitmap)) { - MxS32 height = GetHeight(); - MxS32 width = GetWidth(); - MxS32 x = m_location.GetX(); - MxS32 y = m_location.GetY(); - - MxRect32 rect(x, y, width + x, height + y); + MxRect32 rect(m_location, MxSize32(GetWidth(), GetHeight())); MVideoManager()->InvalidateRect(rect); MVideoManager()->VTable0x34(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight()); } diff --git a/LEGO1/mxvideomanager.h b/LEGO1/mxvideomanager.h index 6d03d84e..8d4d088c 100644 --- a/LEGO1/mxvideomanager.h +++ b/LEGO1/mxvideomanager.h @@ -40,6 +40,7 @@ class MxVideoManager : public MxMediaManager { inline MxVideoParam& GetVideoParam() { return this->m_videoParam; } inline LPDIRECTDRAW GetDirectDraw() { return this->m_pDirectDraw; } inline MxDisplaySurface* GetDisplaySurface() { return this->m_displaySurface; } + inline MxRegion* GetRegion() { return this->m_region; } protected: MxVideoParam m_videoParam; // 0x2c diff --git a/LEGO1/mxvideopresenter.cpp b/LEGO1/mxvideopresenter.cpp index 4162be43..957c5a01 100644 --- a/LEGO1/mxvideopresenter.cpp +++ b/LEGO1/mxvideopresenter.cpp @@ -2,6 +2,7 @@ #include "mxautolocker.h" #include "mxdsmediaaction.h" +#include "mxregioncursor.h" #include "mxvideomanager.h" DECOMP_SIZE_ASSERT(MxVideoPresenter, 0x64); @@ -214,13 +215,7 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor) } if (MVideoManager() && (m_alpha || m_bitmap)) { - MxS32 height = GetHeight(); - MxS32 width = GetWidth(); - - MxS32 x = m_location.GetX(); - MxS32 y = m_location.GetY(); - MxRect32 rect(x, y, x + width, y + height); - + MxRect32 rect(m_location, MxSize32(GetWidth(), GetHeight())); MVideoManager()->InvalidateRect(rect); MVideoManager()->VTable0x34(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight()); } @@ -312,10 +307,137 @@ MxBool MxVideoPresenter::IsHit(MxS32 p_x, MxS32 p_y) return TRUE; } -// STUB: LEGO1 0x100b2a70 +inline MxS32 MxVideoPresenter::PrepareRects(MxRect32& p_rectDest, MxRect32& p_rectSrc) +{ + if (p_rectDest.GetTop() > 480 || p_rectDest.GetLeft() > 640 || p_rectSrc.GetTop() > 480 || + p_rectSrc.GetLeft() > 640) + return -1; + + if (p_rectDest.GetBottom() > 480) + p_rectDest.SetBottom(480); + + if (p_rectDest.GetRight() > 640) + p_rectDest.SetRight(640); + + if (p_rectSrc.GetBottom() > 480) + p_rectSrc.SetBottom(480); + + if (p_rectSrc.GetRight() > 640) + p_rectSrc.SetRight(640); + + MxS32 height = p_rectDest.GetHeight(); + if (height <= 1) + return -1; + + MxS32 width = p_rectDest.GetWidth(); + if (width <= 1) + return -1; + + if (p_rectSrc.GetRight() - width - p_rectSrc.GetLeft() == -1 && + p_rectSrc.GetBottom() - height - p_rectSrc.GetTop() == -1) + return 1; + + p_rectSrc.SetRight(p_rectSrc.GetLeft() + width - 1); + p_rectSrc.SetBottom(p_rectSrc.GetTop() + height - 1); + return 0; +} + +// FUNCTION: LEGO1 0x100b2a70 void MxVideoPresenter::PutFrame() { - // TODO + MxDisplaySurface* displaySurface = MVideoManager()->GetDisplaySurface(); + MxRegion* region = MVideoManager()->GetRegion(); + MxRect32 rect(m_location, MxSize32(GetWidth() - 1, GetHeight() - 1)); + LPDIRECTDRAWSURFACE ddSurface = displaySurface->GetDirectDrawSurface2(); + + MxRect32 rectSrc, rectDest; + if (m_action->GetFlags() & MxDSAction::Flag_Bit5) { + if (m_unk0x58) { + // TODO: Match + rectSrc.CopyFrom(MxPoint32(0, 0), MxSize32(GetWidth(), GetHeight())); + rectDest.CopyFrom(m_location, MxSize32(GetWidth(), GetHeight())); + + switch (PrepareRects(rectDest, rectSrc)) { + case 0: + ddSurface->Blt((LPRECT) &rectDest, m_unk0x58, (LPRECT) &rectSrc, DDBLT_KEYSRC, NULL); + break; + case 1: + ddSurface->BltFast( + rectDest.GetLeft(), + rectDest.GetTop(), + m_unk0x58, + (LPRECT) &rectSrc, + DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT + ); + } + } + else { + displaySurface->VTable0x30( + m_bitmap, + 0, + 0, + rect.GetLeft(), + rect.GetTop(), + m_bitmap->GetBmiWidth(), + m_bitmap->GetBmiHeightAbs(), + TRUE + ); + } + } + else { + MxRegionCursor cursor(region); + MxRect32* regionRect; + + while (regionRect = cursor.VTable0x24(rect)) { + if (regionRect->GetWidth() >= 1 && regionRect->GetHeight() >= 1) { + if (m_unk0x58) { + // TODO: Match + rectSrc.CopyFrom( + MxPoint32(regionRect->GetLeft() - m_location.GetX(), regionRect->GetTop() - m_location.GetY()), + MxSize32(regionRect->GetWidth(), regionRect->GetHeight()) + ); + rectDest.CopyFrom( + MxPoint32(regionRect->GetLeft(), regionRect->GetTop()), + MxSize32(regionRect->GetWidth(), regionRect->GetHeight()) + ); + } + + if (m_action->GetFlags() & MxDSAction::Flag_Bit4) { + if (m_unk0x58) { + if (PrepareRects(rectDest, rectSrc) >= 0) + ddSurface->Blt((LPRECT) &rectDest, m_unk0x58, (LPRECT) &rectSrc, DDBLT_KEYSRC, NULL); + } + else { + displaySurface->VTable0x30( + m_bitmap, + regionRect->GetLeft() - m_location.GetX(), + regionRect->GetTop() - m_location.GetY(), + regionRect->GetLeft(), + regionRect->GetTop(), + regionRect->GetWidth(), + regionRect->GetHeight(), + FALSE + ); + } + } + else if (m_unk0x58) { + if (PrepareRects(rectDest, rectSrc) >= 0) + ddSurface->Blt((LPRECT) &rectDest, m_unk0x58, (LPRECT) &rectSrc, 0, NULL); + } + else { + displaySurface->VTable0x28( + m_bitmap, + regionRect->GetLeft() - m_location.GetX(), + regionRect->GetTop() - m_location.GetY(), + regionRect->GetLeft(), + regionRect->GetTop(), + regionRect->GetWidth(), + regionRect->GetHeight() + ); + } + } + } + } } // FUNCTION: LEGO1 0x100b2f60 diff --git a/LEGO1/mxvideopresenter.h b/LEGO1/mxvideopresenter.h index 72ea33d8..f02f3f08 100644 --- a/LEGO1/mxvideopresenter.h +++ b/LEGO1/mxvideopresenter.h @@ -4,6 +4,7 @@ #include "decomp.h" #include "mxbitmap.h" #include "mxmediapresenter.h" +#include "mxrect32.h" // VTABLE: LEGO1 0x100d4be8 // SIZE 0x64 @@ -68,6 +69,7 @@ class MxVideoPresenter : public MxMediaPresenter { MxS32 IsHit(MxU32 p_x, MxU32 p_y); }; + inline MxS32 PrepareRects(MxRect32& p_rectDest, MxRect32& p_rectSrc); inline MxBitmap* GetBitmap() { return m_bitmap; } private: