From 4d8ba1986e3d46e9a6bcf7b182d8b77a5bc51bf2 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 2 Jul 2025 17:07:16 -0700 Subject: [PATCH 01/12] Fix writing default texture (#1602) --- LEGO1/lego/legoomni/src/common/legoutils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index a9ea98a7..1e0dbba5 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -705,14 +705,14 @@ void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name) if (image != NULL) { if (desc.dwWidth == desc.lPitch) { - memcpy(desc.lpSurface, image->GetBits(), desc.dwWidth * desc.dwHeight); + memcpy(image->GetBits(), desc.lpSurface, desc.dwWidth * desc.dwHeight); } else { MxU8* surface = (MxU8*) desc.lpSurface; - const LegoU8* bits = image->GetBits(); + LegoU8* bits = image->GetBits(); for (MxS32 i = 0; i < desc.dwHeight; i++) { - memcpy(surface, bits, desc.dwWidth); + memcpy(bits, surface, desc.dwWidth); surface += desc.lPitch; bits += desc.dwWidth; } From 44d1ad13fed7416451348f0401477bf202eb680a Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 21:57:47 +0200 Subject: [PATCH 02/12] Set dwDDFX using flag (#1603) --- LEGO1/omni/src/video/mxdisplaysurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 86f1b4dc..bd751a57 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -861,7 +861,7 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p DDBLTFX data; memset(&data, 0, sizeof(data)); data.dwSize = sizeof(data); - data.dwDDFX = 8; + data.dwDDFX = DDBLTFX_NOTEARING; if (m_ddSurface1->Blt((LPRECT) &b, m_ddSurface2, (LPRECT) &a, 0, &data) == DDERR_SURFACELOST) { m_ddSurface1->Restore(); From 16c76c96f23aa26967ba2fdc3291d8f33536ee80 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Thu, 3 Jul 2025 23:56:48 +0200 Subject: [PATCH 03/12] Clear time started unknown in `MxDSAction` (#1604) This should not be confused with `GetStartTime()`, as that represents the time offset from the SI file. --- .../legoomni/src/common/legoanimmmpresenter.cpp | 2 +- .../src/common/mxcompositemediapresenter.cpp | 4 ++-- .../legoomni/src/common/mxcontrolpresenter.cpp | 2 +- .../lego/legoomni/src/video/legoanimpresenter.cpp | 2 +- LEGO1/omni/include/mxdsaction.h | 6 +++--- LEGO1/omni/include/mxdsmultiaction.h | 2 +- LEGO1/omni/src/action/mxdsaction.cpp | 14 +++++++------- LEGO1/omni/src/action/mxdsmultiaction.cpp | 6 +++--- LEGO1/omni/src/common/mxmediapresenter.cpp | 2 +- LEGO1/omni/src/stream/mxdsbuffer.cpp | 2 +- LEGO1/omni/src/stream/mxstreamcontroller.cpp | 2 +- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp index dfa55d51..ca6c2412 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp @@ -400,7 +400,7 @@ MxBool LegoAnimMMPresenter::FUN_1004b610(MxLong p_time) } } - m_action->SetUnknown90(Timer()->GetTime()); + m_action->SetTimeStarted(Timer()->GetTime()); if (m_compositePresenter != NULL) { m_compositePresenter->VTable0x60(this); diff --git a/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp index dadd8de7..04437877 100644 --- a/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp @@ -84,7 +84,7 @@ MxResult MxCompositeMediaPresenter::StartAction(MxStreamController* p_controller if (!m_compositePresenter) { SetTickleState(e_ready); MxLong time = Timer()->GetTime(); - m_action->SetUnknown90(time); + m_action->SetTimeStarted(time); } result = SUCCESS; @@ -134,7 +134,7 @@ void MxCompositeMediaPresenter::StartingTickle() if (!m_unk0x4c) { ProgressTickleState(e_streaming); MxLong time = Timer()->GetTime(); - m_action->SetUnknown90(time); + m_action->SetTimeStarted(time); } } } diff --git a/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp index 13ce2cee..76780d6e 100644 --- a/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp @@ -189,7 +189,7 @@ void MxControlPresenter::VTable0x6c(MxS16 p_unk0x4e) m_unk0x4e = p_unk0x4e; } - m_action->SetUnknown90(Timer()->GetTime()); + m_action->SetTimeStarted(Timer()->GetTime()); MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 73918606..82c76aa6 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -815,7 +815,7 @@ void LegoAnimPresenter::StartingTickle() m_compositePresenter->VTable0x60(this); } else { - m_action->SetUnknown90(Timer()->GetTime()); + m_action->SetTimeStarted(Timer()->GetTime()); } ProgressTickleState(e_streaming); diff --git a/LEGO1/omni/include/mxdsaction.h b/LEGO1/omni/include/mxdsaction.h index 7e2c4d89..2899d3fb 100644 --- a/LEGO1/omni/include/mxdsaction.h +++ b/LEGO1/omni/include/mxdsaction.h @@ -55,8 +55,8 @@ class MxDSAction : public MxDSObject { virtual MxDSAction* Clone(); // vtable+0x2c virtual void MergeFrom(MxDSAction& p_dsAction); // vtable+0x30 virtual MxBool HasId(MxU32 p_objectId); // vtable+0x34 - virtual void SetUnknown90(MxLong p_unk0x90); // vtable+0x38 - virtual MxLong GetUnknown90(); // vtable+0x3c + virtual void SetTimeStarted(MxLong p_timeStarted); // vtable+0x38 + virtual MxLong GetTimeStarted(); // vtable+0x3c virtual MxLong GetElapsedTime(); // vtable+0x40 void AppendExtra(MxU16 p_extraLength, const char* p_extraData); @@ -130,7 +130,7 @@ class MxDSAction : public MxDSObject { MxCore* m_notificationObject; // 0x84 undefined4 m_unk0x88; // 0x88 MxCore* m_origin; // 0x8c - MxLong m_unk0x90; // 0x90 + MxLong m_timeStarted; // 0x90 }; #endif // MXDSACTION_H diff --git a/LEGO1/omni/include/mxdsmultiaction.h b/LEGO1/omni/include/mxdsmultiaction.h index 90cc5192..77ae8d67 100644 --- a/LEGO1/omni/include/mxdsmultiaction.h +++ b/LEGO1/omni/include/mxdsmultiaction.h @@ -38,7 +38,7 @@ class MxDSMultiAction : public MxDSAction { MxDSAction* Clone() override; // vtable+0x2c void MergeFrom(MxDSAction& p_dsAction) override; // vtable+0x30 MxBool HasId(MxU32 p_objectId) override; // vtable+0x34 - void SetUnknown90(MxLong p_unk0x90) override; // vtable+0x38 + void SetTimeStarted(MxLong p_timeStarted) override; // vtable+0x38 // FUNCTION: BETA10 0x1004e180 MxDSActionList* GetActionList() const { return m_actionList; } diff --git a/LEGO1/omni/src/action/mxdsaction.cpp b/LEGO1/omni/src/action/mxdsaction.cpp index 035b1046..4b77c6ed 100644 --- a/LEGO1/omni/src/action/mxdsaction.cpp +++ b/LEGO1/omni/src/action/mxdsaction.cpp @@ -31,7 +31,7 @@ MxDSAction::MxDSAction() m_notificationObject = NULL; m_unk0x88 = 0; m_origin = NULL; - m_unk0x90 = INT_MIN; + m_timeStarted = INT_MIN; } // FUNCTION: LEGO1 0x100ad940 @@ -57,16 +57,16 @@ MxBool MxDSAction::HasId(MxU32 p_objectId) // FUNCTION: LEGO1 0x100ada40 // FUNCTION: BETA10 0x1012bdf0 -void MxDSAction::SetUnknown90(MxLong p_unk0x90) +void MxDSAction::SetTimeStarted(MxLong p_timeStarted) { - m_unk0x90 = p_unk0x90; + m_timeStarted = p_timeStarted; } // FUNCTION: LEGO1 0x100ada50 // FUNCTION: BETA10 0x1012be20 -MxLong MxDSAction::GetUnknown90() +MxLong MxDSAction::GetTimeStarted() { - return m_unk0x90; + return m_timeStarted; } // FUNCTION: LEGO1 0x100ada80 @@ -92,7 +92,7 @@ void MxDSAction::CopyFrom(MxDSAction& p_dsAction) m_notificationObject = p_dsAction.m_notificationObject; m_unk0x88 = p_dsAction.m_unk0x88; m_origin = p_dsAction.m_origin; - m_unk0x90 = p_dsAction.m_unk0x90; + m_timeStarted = p_dsAction.m_timeStarted; } // FUNCTION: BETA10 0x1012b2b3 @@ -158,7 +158,7 @@ MxDSAction* MxDSAction::Clone() // FUNCTION: BETA10 0x1012b4ca MxLong MxDSAction::GetElapsedTime() { - return Timer()->GetTime() - m_unk0x90; + return Timer()->GetTime() - m_timeStarted; } // FUNCTION: LEGO1 0x100add00 diff --git a/LEGO1/omni/src/action/mxdsmultiaction.cpp b/LEGO1/omni/src/action/mxdsmultiaction.cpp index 39adfe9b..648de181 100644 --- a/LEGO1/omni/src/action/mxdsmultiaction.cpp +++ b/LEGO1/omni/src/action/mxdsmultiaction.cpp @@ -57,14 +57,14 @@ MxDSMultiAction& MxDSMultiAction::operator=(MxDSMultiAction& p_dsMultiAction) // FUNCTION: LEGO1 0x100ca290 // FUNCTION: BETA10 0x10159728 -void MxDSMultiAction::SetUnknown90(MxLong p_unk0x90) +void MxDSMultiAction::SetTimeStarted(MxLong p_timeStarted) { - m_unk0x90 = p_unk0x90; + m_timeStarted = p_timeStarted; MxDSActionListCursor cursor(m_actionList); MxDSAction* action; while (cursor.Next(action)) { - action->SetUnknown90(p_unk0x90); + action->SetTimeStarted(p_timeStarted); } } diff --git a/LEGO1/omni/src/common/mxmediapresenter.cpp b/LEGO1/omni/src/common/mxmediapresenter.cpp index 0a1b96d9..c8b9abcd 100644 --- a/LEGO1/omni/src/common/mxmediapresenter.cpp +++ b/LEGO1/omni/src/common/mxmediapresenter.cpp @@ -252,7 +252,7 @@ void MxMediaPresenter::Enable(MxBool p_enable) if (p_enable) { MxLong time = Timer()->GetTime(); - m_action->SetUnknown90(time); + m_action->SetTimeStarted(time); SetTickleState(e_repeating); } else { diff --git a/LEGO1/omni/src/stream/mxdsbuffer.cpp b/LEGO1/omni/src/stream/mxdsbuffer.cpp index d9216b3f..a73be62f 100644 --- a/LEGO1/omni/src/stream/mxdsbuffer.cpp +++ b/LEGO1/omni/src/stream/mxdsbuffer.cpp @@ -209,7 +209,7 @@ MxResult MxDSBuffer::StartPresenterFromAction( p_objectheader->SetUnknown28(p_action1->GetUnknown28()); p_objectheader->SetNotificationObject(p_action1->GetNotificationObject()); p_objectheader->SetOrigin(p_action1->GetOrigin()); - p_objectheader->SetUnknown90(p_action1->GetUnknown90()); + p_objectheader->SetTimeStarted(p_action1->GetTimeStarted()); p_objectheader->MergeFrom(*p_action1); m_unk0x30->SetInternalAction(p_objectheader->Clone()); diff --git a/LEGO1/omni/src/stream/mxstreamcontroller.cpp b/LEGO1/omni/src/stream/mxstreamcontroller.cpp index dadd03ca..8c3cf079 100644 --- a/LEGO1/omni/src/stream/mxstreamcontroller.cpp +++ b/LEGO1/omni/src/stream/mxstreamcontroller.cpp @@ -202,7 +202,7 @@ MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_offset) streamingAction->SetObjectId(p_action->GetObjectId()); MxLong time = Timer()->GetTime(); - streamingAction->SetUnknown90(time); + streamingAction->SetTimeStarted(time); m_unk0x3c.PushBack(streamingAction); return SUCCESS; From df3d144ed9b71006e142074ff8fbb9b62d8561b5 Mon Sep 17 00:00:00 2001 From: MasterTimeThief Date: Thu, 3 Jul 2025 20:23:07 -0400 Subject: [PATCH 04/12] Renamed more functions and variables in Car Build sections (#1605) * Renamed variables and functions related to the Car Build sections * Car Build variable renaming - fixed issues and added enum `ShelfState` * Fixed some spacing in `legocarbuildpresenter.h` * Fixed tab spacing * Changed `m_shelfState` back to `MxU16` * Cleared up `InitBuildPlatform` * Fixed comments * Renamed more functions and variables in Car Build sections * Named `SelectPartFromMousePosition` * Updated spacing formatting in `LegoCarBuild` --- LEGO1/lego/legoomni/include/legocarbuild.h | 14 +-- .../legoomni/include/legocarbuildpresenter.h | 6 +- .../lego/legoomni/src/build/legocarbuild.cpp | 112 +++++++++--------- .../src/build/legocarbuildpresenter.cpp | 16 +-- 4 files changed, 74 insertions(+), 74 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocarbuild.h b/LEGO1/lego/legoomni/include/legocarbuild.h index f13f0450..a96b7b67 100644 --- a/LEGO1/lego/legoomni/include/legocarbuild.h +++ b/LEGO1/lego/legoomni/include/legocarbuild.h @@ -135,11 +135,11 @@ class LegoCarBuild : public LegoWorld { void FUN_10022f00(); void FUN_10022f30(); void FUN_10023130(MxLong p_x, MxLong p_y); - void FUN_100236d0(); + void AddSelectedPartToBuild(); undefined4 FUN_10024250(LegoEventNotificationParam* p_param); void FUN_100243a0(); undefined4 FUN_10024480(MxActionNotificationParam* p_param); - undefined4 FUN_100244e0(MxLong p_x, MxLong p_y); + undefined4 SelectPartFromMousePosition(MxLong p_x, MxLong p_y); undefined4 FUN_100246e0(MxLong p_x, MxLong p_y); MxS32 FUN_10024850(MxLong p_x, MxLong p_y); undefined4 FUN_10024890(MxParam* p_param); @@ -182,7 +182,7 @@ class LegoCarBuild : public LegoWorld { MxU8 m_unk0x109; // 0x109 MxU16 m_unk0x10a; // 0x10a DWORD m_unk0x10c; // 0x10c - LegoROI* m_unk0x110; // 0x110 + LegoROI* m_selectedPart; // 0x110 BoundingSphere m_unk0x114; // 0x114 MxMatrix m_unk0x12c; // 0x12c undefined m_unk0x174; // 0x174 @@ -200,10 +200,10 @@ class LegoCarBuild : public LegoWorld { MxS32 m_unk0x290[2]; // 0x290 MxS32 m_unk0x298[2]; // 0x298 - MxFloat m_unk0x2a0; // 0x2a0 - Mx4DPointFloat m_unk0x2a4; // 0x2a4 - Mx4DPointFloat m_unk0x2bc; // 0x2bc - MxBool m_unk0x2d4; // 0x2d4 + MxFloat m_unk0x2a0; // 0x2a0 + Mx4DPointFloat m_unk0x2a4; // 0x2a4 + Mx4DPointFloat m_unk0x2bc; // 0x2bc + MxBool m_selectedPartIsPlaced; // 0x2d4 // variable names verified by BETA10 0x1006b27a MxStillPresenter* m_ColorBook_Bitmap; // 0x2dc diff --git a/LEGO1/lego/legoomni/include/legocarbuildpresenter.h b/LEGO1/lego/legoomni/include/legocarbuildpresenter.h index a13c1adf..31423e32 100644 --- a/LEGO1/lego/legoomni/include/legocarbuildpresenter.h +++ b/LEGO1/lego/legoomni/include/legocarbuildpresenter.h @@ -77,11 +77,11 @@ class LegoCarBuildAnimPresenter : public LegoAnimPresenter { void FUN_10079050(MxS16 p_index); void SwapNodesByName(LegoChar* p_param1, LegoChar* p_param2); void InitBuildPlatform(); - void FUN_100795d0(LegoChar* p_param); - void FUN_10079680(LegoChar* p_param); + void HideBuildPartByName(LegoChar* p_param); + void ShowBuildPartByName(LegoChar* p_param); LegoAnimNodeData* FindNodeDataByName(LegoTreeNode* p_treeNode, const LegoChar* p_name); LegoTreeNode* FindNodeByName(LegoTreeNode* p_treeNode, const LegoChar* p_name); - void FUN_10079790(const LegoChar* p_name); + void AddPartToBuildByName(const LegoChar* p_name); void RotateAroundYAxis(MxFloat p_angle); MxBool FUN_10079c30(const LegoChar* p_name); MxBool PartIsPlaced(const LegoChar* p_name); diff --git a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp index 6876d199..a7b1e863 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp @@ -93,9 +93,9 @@ MxS16 LegoCarBuild::g_unk0x100f11cc = -1; LegoCarBuild::LegoCarBuild() { m_unk0x100 = 0; - m_unk0x110 = 0; + m_selectedPart = 0; m_unk0xf8 = c_unknownminusone; - m_unk0x2d4 = FALSE; + m_selectedPartIsPlaced = FALSE; m_animPresenter = NULL; m_ColorBook_Bitmap = NULL; m_Yellow_Ctl = NULL; @@ -135,7 +135,7 @@ LegoCarBuild::LegoCarBuild() LegoCarBuild::~LegoCarBuild() { m_unk0x100 = 0; - m_unk0x110 = NULL; + m_selectedPart = NULL; if (m_animPresenter) { m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_selected); @@ -288,7 +288,7 @@ void LegoCarBuild::InitPresenters() // FUNCTION: LEGO1 0x10022f00 void LegoCarBuild::FUN_10022f00() { - if (m_unk0x110) { + if (m_selectedPart) { VTable0x6c(); m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_selected); m_unk0x100 = 5; @@ -299,18 +299,18 @@ void LegoCarBuild::FUN_10022f00() // FUNCTION: BETA10 0x1006b835 void LegoCarBuild::FUN_10022f30() { - if (m_unk0x110) { + if (m_selectedPart) { FUN_10024f70(FALSE); FUN_100250e0(FALSE); - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { m_PlaceBrick_Sound->Enable(FALSE); m_PlaceBrick_Sound->Enable(TRUE); } m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_stopped); m_animPresenter->PutFrame(); - m_unk0x110 = NULL; + m_selectedPart = NULL; m_unk0x100 = 0; } } @@ -320,8 +320,8 @@ void LegoCarBuild::FUN_10022f30() void LegoCarBuild::VTable0x6c() { m_unk0x178 = m_unk0x1c0; - m_unk0x110->WrappedSetLocal2WorldWithWorldDataUpdate(m_unk0x178); - m_unk0x2a4 = Vector4(m_unk0x110->GetWorldPosition()); + m_selectedPart->WrappedSetLocal2WorldWithWorldDataUpdate(m_unk0x178); + m_unk0x2a4 = Vector4(m_selectedPart->GetWorldPosition()); VTable0x70(); } @@ -360,7 +360,7 @@ void LegoCarBuild::VTable0x70() // FUNCTION: BETA10 0x1006bb22 void LegoCarBuild::FUN_10023130(MxLong p_x, MxLong p_y) { - if (m_unk0x110) { + if (m_selectedPart) { MxFloat pfVar3[2]; MxFloat local30[3]; MxFloat local84[3]; @@ -408,7 +408,7 @@ void LegoCarBuild::FUN_10023130(MxLong p_x, MxLong p_y) local78[3][2] = m_unk0x178[3][2] + local18[2]; local78[3][3] = 1.0; - m_unk0x110->WrappedSetLocal2WorldWithWorldDataUpdate(local78); + m_selectedPart->WrappedSetLocal2WorldWithWorldDataUpdate(local78); } } } @@ -474,15 +474,15 @@ void LegoCarBuild::VTable0x80(MxFloat p_param1[2], MxFloat p_param2[2], MxFloat // FUNCTION: LEGO1 0x100236d0 // FUNCTION: BETA10 0x1006c076 -void LegoCarBuild::FUN_100236d0() +void LegoCarBuild::AddSelectedPartToBuild() { MxS32 pLVar2; FUN_10024f70(FALSE); FUN_100250e0(FALSE); - m_animPresenter->FUN_10079790(m_unk0x110->GetName()); + m_animPresenter->AddPartToBuildByName(m_selectedPart->GetName()); m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_stopped); - m_unk0x110 = NULL; + m_selectedPart = NULL; m_unk0x100 = 0; if (m_animPresenter->AllPartsPlaced()) { @@ -541,15 +541,15 @@ MxResult LegoCarBuild::Tickle() FUN_10024f50(); } - if (m_unk0x110) { - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { + if (m_selectedPart) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { FUN_10022f30(); } } } - if (m_unk0x100 == 5 && m_unk0x110) { - RotateY(m_unk0x110, g_unk0x100d65a4); + if (m_unk0x100 == 5 && m_selectedPart) { + RotateY(m_selectedPart, g_unk0x100d65a4); } if (m_unk0x10a) { @@ -687,7 +687,7 @@ MxLong LegoCarBuild::Notify(MxParam& p_param) if (((m_buildState->m_animationState != 4) && (m_buildState->m_animationState != 6)) && (m_buildState->m_animationState != 2)) { m_buildState->m_animationState = LegoVehicleBuildState::e_unknown0; - result = FUN_100244e0( + result = SelectPartFromMousePosition( ((LegoEventNotificationParam&) p_param).GetX(), ((LegoEventNotificationParam&) p_param).GetY() ); @@ -817,7 +817,7 @@ undefined4 LegoCarBuild::FUN_10024480(MxActionNotificationParam* p_param) // FUNCTION: LEGO1 0x100244e0 // FUNCTION: BETA10 0x1006cfb6 -undefined4 LegoCarBuild::FUN_100244e0(MxLong p_x, MxLong p_y) +undefined4 LegoCarBuild::SelectPartFromMousePosition(MxLong p_x, MxLong p_y) { m_unk0x250[0] = p_x; m_unk0x250[1] = p_y; @@ -828,34 +828,34 @@ undefined4 LegoCarBuild::FUN_100244e0(MxLong p_x, MxLong p_y) return 0; } - if (m_unk0x110 != roi) { + if (m_selectedPart != roi) { FUN_10022f30(); - m_unk0x110 = roi; + m_selectedPart = roi; FUN_10024f70(TRUE); FUN_100250e0(TRUE); } - if (m_unk0x100 == 5 && m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { - m_unk0x2d4 = TRUE; + if (m_unk0x100 == 5 && m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { + m_selectedPartIsPlaced = TRUE; } else { - m_unk0x2d4 = FALSE; + m_selectedPartIsPlaced = FALSE; } FUN_10025450(); VTable0x70(); - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { if (m_unk0x100 != 5) { m_unk0x250[0] += m_unk0x290[0] - m_unk0x298[0]; m_unk0x250[1] += m_unk0x290[1] - m_unk0x298[1]; } if (m_unk0x100 == 0) { - m_unk0x114 = m_unk0x110->GetWorldBoundingSphere(); + m_unk0x114 = m_selectedPart->GetWorldBoundingSphere(); } } else { - if (m_animPresenter->FUN_10079c30(m_unk0x110->GetName())) { + if (m_animPresenter->FUN_10079c30(m_selectedPart->GetName())) { m_unk0x114 = m_animPresenter->FUN_10079e20(); } } @@ -892,21 +892,21 @@ undefined4 LegoCarBuild::FUN_100246e0(MxLong p_x, MxLong p_y) result = 1; break; case 6: - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName()) && - SpheresIntersect(m_unk0x114, m_unk0x110->GetWorldBoundingSphere())) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName()) && + SpheresIntersect(m_unk0x114, m_selectedPart->GetWorldBoundingSphere())) { FUN_10024f70(FALSE); FUN_100250e0(FALSE); m_unk0x100 = 0; - m_unk0x110 = NULL; + m_selectedPart = NULL; m_PlaceBrick_Sound->Enable(FALSE); m_PlaceBrick_Sound->Enable(TRUE); m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_stopped); } - else if (m_animPresenter->FUN_10079c30(m_unk0x110->GetName())) { - if (SpheresIntersect(m_unk0x114, m_unk0x110->GetWorldBoundingSphere())) { + else if (m_animPresenter->FUN_10079c30(m_selectedPart->GetName())) { + if (SpheresIntersect(m_unk0x114, m_selectedPart->GetWorldBoundingSphere())) { m_PlaceBrick_Sound->Enable(FALSE); m_PlaceBrick_Sound->Enable(TRUE); - FUN_100236d0(); + AddSelectedPartToBuild(); } else { VTable0x6c(); @@ -1021,7 +1021,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) (m_Decals_Ctl5 && m_Decals_Ctl5->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl6 && m_Decals_Ctl6->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl7 && m_Decals_Ctl7->GetAction()->GetObjectId() == param->m_clickedObjectId)) { - m_animPresenter->SetPartObjectIdByName(m_unk0x110->GetName(), param->m_clickedObjectId); + m_animPresenter->SetPartObjectIdByName(m_selectedPart->GetName(), param->m_clickedObjectId); m_Decal_Sound->Enable(FALSE); m_Decal_Sound->Enable(TRUE); } @@ -1125,7 +1125,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) (m_Decals_Ctl5 && m_Decals_Ctl5->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl6 && m_Decals_Ctl6->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl7 && m_Decals_Ctl7->GetAction()->GetObjectId() == param->m_clickedObjectId)) { - m_animPresenter->SetPartObjectIdByName(m_unk0x110->GetName(), param->m_clickedObjectId); + m_animPresenter->SetPartObjectIdByName(m_selectedPart->GetName(), param->m_clickedObjectId); m_Decal_Sound->Enable(FALSE); m_Decal_Sound->Enable(TRUE); } @@ -1268,7 +1268,7 @@ void LegoCarBuild::FUN_10024f30() // FUNCTION: BETA10 0x1006dfce void LegoCarBuild::FUN_10024f50() { - m_unk0x2d4 = FALSE; + m_selectedPartIsPlaced = FALSE; m_animPresenter->RotateAroundYAxis(g_rotationAngleStepYAxis); } @@ -1276,7 +1276,7 @@ void LegoCarBuild::FUN_10024f50() // FUNCTION: BETA10 0x1006e002 void LegoCarBuild::FUN_10024f70(MxBool p_enabled) { - if (m_animPresenter->StringEndsOnY(m_unk0x110->GetName())) { + if (m_animPresenter->StringEndsOnY(m_selectedPart->GetName())) { SetPresentersEnabled(p_enabled); } } @@ -1311,31 +1311,31 @@ void LegoCarBuild::TogglePresentersEnabled() // FUNCTION: BETA10 0x1006e124 void LegoCarBuild::FUN_100250e0(MxBool p_enabled) { - if (m_animPresenter->StringDoesNotEndOnZero(m_unk0x110->GetName()) && m_Decals_Ctl) { - if (strnicmp(m_unk0x110->GetName(), "JSFRNT", strlen("JSFRNT")) == 0) { + if (m_animPresenter->StringDoesNotEndOnZero(m_selectedPart->GetName()) && m_Decals_Ctl) { + if (strnicmp(m_selectedPart->GetName(), "JSFRNT", strlen("JSFRNT")) == 0) { m_Decal_Bitmap->Enable(p_enabled); m_Decals_Ctl->Enable(p_enabled); m_Decals_Ctl1->Enable(p_enabled); m_Decals_Ctl2->Enable(p_enabled); m_Decals_Ctl3->Enable(p_enabled); } - else if (strnicmp(m_unk0x110->GetName(), "JSWNSH", strlen("JSWNSH")) == 0) { + else if (strnicmp(m_selectedPart->GetName(), "JSWNSH", strlen("JSWNSH")) == 0) { m_Decal_Bitmap->Enable(p_enabled); m_Decals_Ctl4->Enable(p_enabled); m_Decals_Ctl5->Enable(p_enabled); m_Decals_Ctl6->Enable(p_enabled); m_Decals_Ctl7->Enable(p_enabled); } - else if (strnicmp(m_unk0x110->GetName(), "RCBACK", strlen("RCBACK")) == 0) { + else if (strnicmp(m_selectedPart->GetName(), "RCBACK", strlen("RCBACK")) == 0) { m_Decals_Ctl1->Enable(p_enabled); } - else if (strnicmp(m_unk0x110->GetName(), "RCTAIL", strlen("RCTAIL")) == 0) { + else if (strnicmp(m_selectedPart->GetName(), "RCTAIL", strlen("RCTAIL")) == 0) { m_Decals_Ctl2->Enable(p_enabled); } - else if (m_Decals_Ctl1 && strnicmp(m_unk0x110->GetName(), "chljety", strlen("chljety")) == 0) { + else if (m_Decals_Ctl1 && strnicmp(m_selectedPart->GetName(), "chljety", strlen("chljety")) == 0) { m_Decals_Ctl1->Enable(p_enabled); } - else if (m_Decals_Ctl2 && strnicmp(m_unk0x110->GetName(), "chrjety", strlen("chrjety")) == 0) { + else if (m_Decals_Ctl2 && strnicmp(m_selectedPart->GetName(), "chrjety", strlen("chrjety")) == 0) { m_Decals_Ctl2->Enable(p_enabled); } else if (m_Decals_Ctl) { @@ -1351,7 +1351,7 @@ void LegoCarBuild::FUN_10025350(MxS32 p_objectId) const LegoChar* color; LegoChar buffer[256]; - if (!m_unk0x110) { + if (!m_selectedPart) { return; } @@ -1379,8 +1379,8 @@ void LegoCarBuild::FUN_10025350(MxS32 p_objectId) m_Paint_Sound->Enable(FALSE); m_Paint_Sound->Enable(TRUE); - m_unk0x110->FUN_100a93b0(color); - sprintf(buffer, "c_%s", m_unk0x110->GetName()); + m_selectedPart->FUN_100a93b0(color); + sprintf(buffer, "c_%s", m_selectedPart->GetName()); VariableTable()->SetVariable(buffer, color); } @@ -1388,7 +1388,7 @@ void LegoCarBuild::FUN_10025350(MxS32 p_objectId) // FUNCTION: BETA10 0x1006e599 void LegoCarBuild::FUN_10025450() { - m_unk0x12c = m_unk0x110->GetLocal2World(); + m_unk0x12c = m_selectedPart->GetLocal2World(); m_unk0x1c0 = m_unk0x12c; Vector3 lastColumnOfUnk0x1c0(m_unk0x1c0[3]); @@ -1401,10 +1401,10 @@ void LegoCarBuild::FUN_10025450() MxMatrix* unk0x178 = &m_unk0x178; *unk0x178 = m_unk0x12c; - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { - m_unk0x2a4 = Vector4(m_unk0x110->GetWorldPosition()); + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { + m_unk0x2a4 = Vector4(m_selectedPart->GetWorldPosition()); - if (!m_unk0x2d4) { + if (!m_selectedPartIsPlaced) { m_unk0x2bc = m_unk0x2a4; m_unk0x208 = m_unk0x12c; @@ -1418,17 +1418,17 @@ void LegoCarBuild::FUN_10025450() else { const LegoChar* wiredName; - if (!m_animPresenter->FUN_10079c30(m_unk0x110->GetName())) { - wiredName = m_animPresenter->GetWiredNameByPartName(m_unk0x110->GetName()); + if (!m_animPresenter->FUN_10079c30(m_selectedPart->GetName())) { + wiredName = m_animPresenter->GetWiredNameByPartName(m_selectedPart->GetName()); } else { wiredName = m_animPresenter->GetWiredNameOfLastPlacedPart(); } - LegoROI* parentROI = (LegoROI*) m_unk0x110->GetParentROI(); + LegoROI* parentROI = (LegoROI*) m_selectedPart->GetParentROI(); m_unk0x208 = parentROI->FindChildROI(wiredName, parentROI)->GetLocal2World(); m_unk0x2bc = Vector4(parentROI->FindChildROI(wiredName, parentROI)->GetWorldPosition()); - m_unk0x2a4 = Vector4(m_unk0x110->GetWorldPosition()); + m_unk0x2a4 = Vector4(m_selectedPart->GetWorldPosition()); m_unk0x2a4[2] += (m_unk0x1c0[3][2] - m_unk0x12c[3][2]); m_unk0x178[3][2] = m_unk0x1c0[3][2]; diff --git a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp index d6512c8b..c2dbbd8a 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp @@ -202,15 +202,15 @@ void LegoCarBuildAnimPresenter::StreamingTickle() for (i = 0; i < m_numberOfParts; i++) { if (m_placedPartCount == i) { - FUN_10079680(m_parts[i].m_wiredName); + ShowBuildPartByName(m_parts[i].m_wiredName); } else { - FUN_100795d0(m_parts[i].m_wiredName); + HideBuildPartByName(m_parts[i].m_wiredName); } if (i < m_placedPartCount) { FUN_10079050(i); - FUN_10079680(m_parts[i].m_name); + ShowBuildPartByName(m_parts[i].m_name); } LegoChar* name = m_parts[i].m_wiredName; @@ -319,7 +319,7 @@ MxResult LegoCarBuildAnimPresenter::Serialize(LegoStorage* p_storage) void LegoCarBuildAnimPresenter::FUN_10079050(MxS16 p_index) { SwapNodesByName(m_parts[p_index].m_wiredName, m_parts[p_index].m_name); - FUN_100795d0(m_parts[p_index].m_wiredName); + HideBuildPartByName(m_parts[p_index].m_wiredName); } // FUNCTION: LEGO1 0x10079090 @@ -445,7 +445,7 @@ void LegoCarBuildAnimPresenter::InitBuildPlatform() // FUNCTION: LEGO1 0x100795d0 // FUNCTION: BETA10 0x10071d96 -void LegoCarBuildAnimPresenter::FUN_100795d0(LegoChar* p_param) +void LegoCarBuildAnimPresenter::HideBuildPartByName(LegoChar* p_param) { LegoAnimNodeData* data = FindNodeDataByName(m_anim->GetRoot(), p_param); @@ -467,7 +467,7 @@ void LegoCarBuildAnimPresenter::FUN_100795d0(LegoChar* p_param) // FUNCTION: LEGO1 0x10079680 // FUNCTION: BETA10 0x10071ec5 -void LegoCarBuildAnimPresenter::FUN_10079680(LegoChar* p_param) +void LegoCarBuildAnimPresenter::ShowBuildPartByName(LegoChar* p_param) { LegoAnimNodeData* data = FindNodeDataByName(m_anim->GetRoot(), p_param); @@ -534,7 +534,7 @@ LegoTreeNode* LegoCarBuildAnimPresenter::FindNodeByName(LegoTreeNode* p_treeNode // FUNCTION: LEGO1 0x10079790 // FUNCTION: BETA10 0x100720a3 -void LegoCarBuildAnimPresenter::FUN_10079790(const LegoChar* p_name) +void LegoCarBuildAnimPresenter::AddPartToBuildByName(const LegoChar* p_name) { MxS16 i; LegoChar buffer[40]; @@ -557,7 +557,7 @@ void LegoCarBuildAnimPresenter::FUN_10079790(const LegoChar* p_name) ((LegoCarBuild*) m_currentWorld)->SetPlacedPartCount(m_placedPartCount); if (m_placedPartCount < m_numberOfParts) { - FUN_10079680(m_parts[m_placedPartCount].m_wiredName); + ShowBuildPartByName(m_parts[m_placedPartCount].m_wiredName); } } From 4983da422c56e71f193658273ee337d7286928fa Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 14:47:24 +0200 Subject: [PATCH 05/12] OpenGL: Respect max supported texture size (#518) --- miniwin/src/d3drm/backends/opengl1/actual.cpp | 7 +++++++ miniwin/src/d3drm/backends/opengl1/actual.h | 1 + miniwin/src/d3drm/backends/opengl1/renderer.cpp | 17 ++++++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/miniwin/src/d3drm/backends/opengl1/actual.cpp b/miniwin/src/d3drm/backends/opengl1/actual.cpp index b1a464d5..a86ebec1 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.cpp +++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp @@ -42,6 +42,13 @@ void GL11_DestroyTexture(GLuint texId) glDeleteTextures(1, &texId); } +int GL11_GetMaxTextureSize() +{ + GLint maxTextureSize = 0; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + return maxTextureSize; +} + GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUi) { GLuint texId; diff --git a/miniwin/src/d3drm/backends/opengl1/actual.h b/miniwin/src/d3drm/backends/opengl1/actual.h index 9460119c..87f33687 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.h +++ b/miniwin/src/d3drm/backends/opengl1/actual.h @@ -64,6 +64,7 @@ struct GLMeshCacheEntry { void GL11_InitState(); void GL11_LoadExtensions(); void GL11_DestroyTexture(GLuint texId); +int GL11_GetMaxTextureSize(); GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI); void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture); void GL11_DestroyMesh(GLMeshCacheEntry& cache); diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index 8c43d14a..00088da9 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -132,10 +132,21 @@ static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUi) SDL_Surface* finalSurface = working; - int newW = NextPowerOfTwo(working->w); - int newH = NextPowerOfTwo(working->h); + int newW = working->w; + int newH = working->h; + if (!useNPOT) { + newW = NextPowerOfTwo(newW); + newH = NextPowerOfTwo(newH); + } + int max = GL11_GetMaxTextureSize(); + if (newW > max) { + newW = max; + } + if (newH > max) { + newH = max; + } - if (!useNPOT && (newW != working->w || newH != working->h)) { + if (newW != working->w || newH != working->h) { SDL_Surface* resized = SDL_CreateSurface(newW, newH, working->format); if (!resized) { SDL_Log("SDL_CreateSurface (resize) failed: %s", SDL_GetError()); From 0d2cbd50d58eb217311c8ceb2160bd1ce76acb8e Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 14:48:01 +0200 Subject: [PATCH 06/12] Fake mosaic transition (#516) --- .../legoomni/include/mxtransitionmanager.h | 4 +- .../src/common/mxtransitionmanager.cpp | 128 ++++++++++++++++++ LEGO1/omni/include/mxdisplaysurface.h | 3 + LEGO1/omni/src/video/mxdisplaysurface.cpp | 3 - 4 files changed, 134 insertions(+), 4 deletions(-) diff --git a/LEGO1/lego/legoomni/include/mxtransitionmanager.h b/LEGO1/lego/legoomni/include/mxtransitionmanager.h index dd9dc9ed..7c31daf7 100644 --- a/LEGO1/lego/legoomni/include/mxtransitionmanager.h +++ b/LEGO1/lego/legoomni/include/mxtransitionmanager.h @@ -48,7 +48,8 @@ class MxTransitionManager : public MxCore { e_mosaic, e_wipeDown, e_windows, - e_broken // Unknown what this is supposed to be, it locks the game up + e_broken, // Unknown what this is supposed to be, it locks the game up + e_fakeMosaic }; MxResult StartTransition(TransitionType p_animationType, MxS32 p_speed, MxBool p_doCopy, MxBool p_playMusicInAnim); @@ -68,6 +69,7 @@ class MxTransitionManager : public MxCore { void WipeDownTransition(); void WindowsTransition(); void BrokenTransition(); + void FakeMosaicTransition(); void SubmitCopyRect(LPDDSURFACEDESC p_ddsc); void SetupCopyRect(LPDDSURFACEDESC p_ddsc); diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 6fd211c6..1987b6cd 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -84,6 +84,9 @@ MxResult MxTransitionManager::Tickle() case e_broken: BrokenTransition(); break; + case e_fakeMosaic: + FakeMosaicTransition(); + break; } return SUCCESS; } @@ -613,3 +616,128 @@ void MxTransitionManager::configureMxTransitionManager(TransitionType p_transiti { g_transitionManagerConfig = p_transitionManagerConfig; } + +int g_colorOffset; +int GetColorIndexWithLocality(int p_col, int p_row) +{ + int islandX = p_col / 8; + int islandY = p_row / 8; // Dvide screen in 8x6 tiles + + int island = islandY * 8 + islandX; // tile id + + if (SDL_rand(3) > island / 8) { + return 6 + SDL_rand(2); // emulate sky + } + + if (SDL_rand(16) > 2) { + island += SDL_rand(3) - 1 + (SDL_rand(3) - 1) * 8; // blure tiles + } + + int hash = (island + g_colorOffset) * 2654435761u; + int scrambled = (hash >> 16) % 32; + + int finalIndex = scrambled + SDL_rand(3) - 1; + return finalIndex % 32; +} + +void MxTransitionManager::FakeMosaicTransition() +{ + if (m_animationTimer == 16) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + + if (m_animationTimer == 0) { + g_colorOffset = SDL_rand(32); + for (MxS32 i = 0; i < 64; i++) { + m_columnOrder[i] = i; + } + for (MxS32 i = 0; i < 64; i++) { + MxS32 swap = SDL_rand(64); + std::swap(m_columnOrder[i], m_columnOrder[swap]); + } + for (MxS32 i = 0; i < 48; i++) { + m_randomShift[i] = SDL_rand(64); + } + } + + DDSURFACEDESC ddsd = {}; + ddsd.dwSize = sizeof(ddsd); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + static const MxU8 g_palette[32][3] = { + {0x00, 0x00, 0x00}, {0x12, 0x1e, 0x50}, {0x00, 0x22, 0x6c}, {0x14, 0x2d, 0x9f}, {0x0e, 0x36, 0xb0}, + {0x0e, 0x39, 0xd0}, {0x47, 0x96, 0xe2}, {0x79, 0xaa, 0xca}, {0xff, 0xff, 0xff}, {0xc9, 0xcd, 0xcb}, + {0xad, 0xad, 0xab}, {0xa6, 0x91, 0x8e}, {0xaf, 0x59, 0x49}, {0xc0, 0x00, 0x00}, {0xab, 0x18, 0x18}, + {0x61, 0x0c, 0x0c}, {0x04, 0x38, 0x12}, {0x2c, 0x67, 0x28}, {0x4a, 0xb4, 0x6b}, {0x94, 0xb7, 0x7c}, + {0xb6, 0xb9, 0x87}, {0x52, 0x4a, 0x67}, {0x87, 0x8d, 0x8a}, {0xa6, 0x91, 0x8e}, {0xf8, 0xee, 0xdc}, + {0xf4, 0xe2, 0xc3}, {0x87, 0x8d, 0x8a}, {0xba, 0x9f, 0x12}, {0xb5, 0x83, 0x00}, {0x6a, 0x44, 0x27}, + {0x36, 0x37, 0x34}, {0x2b, 0x23, 0x0f} + }; + + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + for (MxS32 col = 0; col < 64; col++) { + if (m_animationTimer * 4 > m_columnOrder[col]) { + continue; + } + if (m_animationTimer * 4 + 3 < m_columnOrder[col]) { + continue; + } + + for (MxS32 row = 0; row < 48; row++) { + MxS32 xShift = 10 * ((m_randomShift[row] + col) % 64); + MxS32 yStart = 10 * row; + + int paletteIndex = GetColorIndexWithLocality(xShift / 10, row); + + const MxU8* color = g_palette[paletteIndex]; + + for (MxS32 y = 0; y < 10; y++) { + MxU8* dest = (MxU8*) ddsd.lpSurface + (yStart + y) * ddsd.lPitch + xShift * bytesPerPixel; + switch (bytesPerPixel) { + case 1: + memset(dest, paletteIndex, 10); + break; + case 2: { + MxU32 pixel = RGB555_CREATE(color[2], color[1], color[0]); + MxU16* p = (MxU16*) dest; + for (MxS32 i = 0; i < 10; i++) { + p[i] = pixel; + } + break; + } + default: { + MxU32 pixel = RGB8888_CREATE(color[2], color[1], color[0], 255); + MxU32* p = (MxU32*) dest; + for (MxS32 i = 0; i < 10; i++) { + p[i] = pixel; + } + break; + } + } + } + } + } + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) { + VideoManager() + ->GetDisplaySurface() + ->GetDirectDrawSurface1() + ->BltFast(0, 0, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); + } + + m_animationTimer++; + } +} diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index 3a3dcd08..aa30b543 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -12,6 +12,9 @@ #include #endif +#define RGB555_CREATE(R, G, B) (((R) << 10) | (G) << 5 | (B) << 0) +#define RGB8888_CREATE(R, G, B, A) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B)) + class MxBitmap; class MxPalette; diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index b10330f2..c07f475e 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -18,9 +18,6 @@ DECOMP_SIZE_ASSERT(MxDisplaySurface, 0xac); -#define RGB555_CREATE(R, G, B) (((R) << 10) | (G) << 5 | (B) << 0) -#define RGB8888_CREATE(R, G, B, A) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B)) - // GLOBAL: LEGO1 0x1010215c MxU32 g_unk0x1010215c = 0; From af045eefed747ca26e4f90f50131cff9141aaa3c Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 17:41:18 +0200 Subject: [PATCH 07/12] Add fake mosaic to config tool (#522) --- CONFIG/res/maindialog.ui | 5 +++++ ISLE/3ds/config.cpp | 2 +- LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CONFIG/res/maindialog.ui b/CONFIG/res/maindialog.ui index 66e2b52e..12739f27 100644 --- a/CONFIG/res/maindialog.ui +++ b/CONFIG/res/maindialog.ui @@ -455,6 +455,11 @@ Unknown - Broken + + + Fake Mosaic + + diff --git a/ISLE/3ds/config.cpp b/ISLE/3ds/config.cpp index dc5dd8dc..e70ec4dd 100644 --- a/ISLE/3ds/config.cpp +++ b/ISLE/3ds/config.cpp @@ -18,5 +18,5 @@ void N3DS_SetupDefaultConfigOverrides(dictionary* p_dictionary) iniparser_set(p_dictionary, "isle:savepath", "sdmc:/3ds/isle"); // Use e_noAnimation/cut transition - iniparser_set(p_dictionary, "isle:Transition Type", "1"); + iniparser_set(p_dictionary, "isle:Transition Type", "7"); } diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 1987b6cd..6c4f94ea 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -637,7 +637,7 @@ int GetColorIndexWithLocality(int p_col, int p_row) int scrambled = (hash >> 16) % 32; int finalIndex = scrambled + SDL_rand(3) - 1; - return finalIndex % 32; + return abs(finalIndex) % 32; } void MxTransitionManager::FakeMosaicTransition() From 77c832c237fe90c5bc2793c6349d2f52c7502bc6 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 21:27:01 +0200 Subject: [PATCH 08/12] Use sprites to render things on screen (#478) --- LEGO1/omni/src/video/mxdisplaysurface.cpp | 119 +++++++++++----------- 1 file changed, 57 insertions(+), 62 deletions(-) diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index c07f475e..5d08a64b 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -396,86 +396,81 @@ void MxDisplaySurface::VTable0x28( DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + ddsd.dwWidth = p_width; + ddsd.dwHeight = p_height; + ddsd.ddpfPixelFormat = m_surfaceDesc.ddpfPixelFormat; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + LPDIRECTDRAWSURFACE tempSurface = nullptr; + LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw(); + HRESULT hr = draw->CreateSurface(&ddsd, &tempSurface, nullptr); + if (hr != DD_OK || !tempSurface) { + return; + } + + DDCOLORKEY colorKey; + colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); + tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey); + + DDSURFACEDESC tempDesc; + memset(&tempDesc, 0, sizeof(tempDesc)); + tempDesc.dwSize = sizeof(tempDesc); + + hr = tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (hr == DDERR_SURFACELOST) { - m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + tempSurface->Restore(); + hr = tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (hr != DD_OK) { + tempSurface->Release(); return; } MxU8* data = p_bitmap->GetStart(p_left, p_top); MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8; - if (m_videoParam.Flags().GetF1bit3()) { - p_bottom *= 2; - p_right *= 2; + MxU8* surface = (MxU8*) tempDesc.lpSurface; - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); - MxLong stride = -p_width + GetAdjustedStride(p_bitmap); - MxS32 copyWidth = p_width * bytesPerPixel * 2; - MxLong length = -(copyWidth) + ddsd.lPitch; + MxLong stride = (bytesPerPixel == 1) ? GetAdjustedStride(p_bitmap) : -p_width + GetAdjustedStride(p_bitmap); + MxLong length = tempDesc.lPitch - (p_width * bytesPerPixel); - while (p_height--) { - MxU8* surfaceBefore = surface; - - for (MxS32 i = 0; i < p_width; i++) { - if (bytesPerPixel == 1) { - surface[0] = surface[1] = *data; - } - else if (bytesPerPixel == 2) { - ((MxU16*) surface)[0] = ((MxU16*) surface)[1] = m_16bitPal[*data]; - } - else { - ((MxU32*) surface)[0] = ((MxU32*) surface)[1] = m_32bitPal[*data]; - } - surface += bytesPerPixel * 2; - data++; - } - - if (stride || length != ddsd.lPitch - copyWidth) { - data += stride; - surface += length; - } - - memcpy(surface, surfaceBefore, copyWidth); - surface += ddsd.lPitch; + for (MxS32 i = 0; i < p_height; i++) { + if (bytesPerPixel == 1) { + memcpy(surface, data, p_width); + surface += length + p_width; } + else if (bytesPerPixel == 2) { + for (MxS32 j = 0; j < p_width; j++) { + *(MxU16*) surface = m_16bitPal[*data++]; + surface += bytesPerPixel; + } + + surface += length; + } + else { + for (MxS32 j = 0; j < p_width; j++) { + *(MxU32*) surface = m_32bitPal[*data++]; + surface += bytesPerPixel; + } + surface += length; + } + + data += stride; + } + + tempSurface->Unlock(NULL); + + if (m_videoParam.Flags().GetF1bit3()) { + RECT destRect = {p_right, p_bottom, p_right + p_width * 2, p_bottom + p_height * 2}; + m_ddSurface2->Blt(&destRect, tempSurface, NULL, DDBLT_WAIT | DDBLT_KEYSRC, NULL); } else { - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); - MxLong stride = (bytesPerPixel == 1) ? GetAdjustedStride(p_bitmap) : -p_width + GetAdjustedStride(p_bitmap); - MxLong length = ddsd.lPitch - (p_width * bytesPerPixel); - - for (MxS32 i = 0; i < p_height; i++) { - if (bytesPerPixel == 1) { - memcpy(surface, data, p_width); - surface += length + p_width; - } - else if (bytesPerPixel == 2) { - for (MxS32 j = 0; j < p_width; j++) { - *(MxU16*) surface = m_16bitPal[*data++]; - surface += bytesPerPixel; - } - - surface += length; - } - else { - for (MxS32 j = 0; j < p_width; j++) { - *(MxU32*) surface = m_32bitPal[*data++]; - surface += bytesPerPixel; - } - surface += length; - } - - data += stride; - } + m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); } - m_ddSurface2->Unlock(ddsd.lpSurface); + tempSurface->Release(); } // FUNCTION: LEGO1 0x100bb1d0 From 5544640b228ccf3ac2e735363c72b57e9e961c42 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Fri, 4 Jul 2025 21:53:50 +0200 Subject: [PATCH 09/12] Clear unknowns in `MxControlPresenter` (#1606) --- .../legoomni/include/mxcontrolpresenter.h | 29 ++++--- LEGO1/lego/legoomni/src/actors/radio.cpp | 2 +- .../lego/legoomni/src/build/legocarbuild.cpp | 6 +- .../src/common/mxcontrolpresenter.cpp | 86 +++++++++---------- .../src/control/legocontrolmanager.cpp | 10 +-- 5 files changed, 70 insertions(+), 63 deletions(-) diff --git a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h index 8ecfeacf..d3d2a96a 100644 --- a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h +++ b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h @@ -44,21 +44,28 @@ class MxControlPresenter : public MxCompositePresenter { void EndAction() override; // vtable+0x40 MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48 void Enable(MxBool p_enable) override; // vtable+0x54 - virtual void VTable0x6c(MxS16 p_unk0x4e); // vtable+0x6c + virtual void UpdateEnabledChild(MxS16 p_enabledChild); // vtable+0x6c - MxBool FUN_10044480(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter); - MxBool FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter); + MxBool Notify(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter); + MxBool CheckButtonDown(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter); - MxS16 GetUnknown0x4e() { return m_unk0x4e; } + MxS16 GetEnabledChild() { return m_enabledChild; } private: - MxS16 m_unk0x4c; // 0x4c - MxS16 m_unk0x4e; // 0x4e - MxBool m_unk0x50; // 0x50 - MxS16 m_unk0x52; // 0x52 - MxS16 m_unk0x54; // 0x54 - MxS16 m_unk0x56; // 0x56 - MxS16* m_states; // 0x58 + enum { + e_none, + e_toggle, + e_grid, + e_map, + }; + + MxS16 m_style; // 0x4c + MxS16 m_enabledChild; // 0x4e + MxBool m_unk0x50; // 0x50 + MxS16 m_columnsOrRows; // 0x52 + MxS16 m_rowsOrColumns; // 0x54 + MxS16 m_stateOrCellIndex; // 0x56 + MxS16* m_states; // 0x58 }; // SYNTHETIC: LEGO1 0x100440f0 diff --git a/LEGO1/lego/legoomni/src/actors/radio.cpp b/LEGO1/lego/legoomni/src/actors/radio.cpp index d32955fe..fa600b7d 100644 --- a/LEGO1/lego/legoomni/src/actors/radio.cpp +++ b/LEGO1/lego/legoomni/src/actors/radio.cpp @@ -131,7 +131,7 @@ void Radio::Stop() MxControlPresenter* presenter = (MxControlPresenter*) world->Find(world->GetAtomId(), IsleScript::c_Radio_Ctl); if (presenter) { - presenter->VTable0x6c(0); + presenter->UpdateEnabledChild(0); } BackgroundAudioManager()->Stop(); diff --git a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp index a7b1e863..0cea0c0d 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp @@ -1650,8 +1650,8 @@ void LegoCarBuild::FUN_10025db0(const char* p_param1, undefined4 p_param2) } } else { - if (m_unk0x33c->GetUnknown0x4e() != sVar3) { - m_unk0x33c->VTable0x6c(sVar3); + if (m_unk0x33c->GetEnabledChild() != sVar3) { + m_unk0x33c->UpdateEnabledChild(sVar3); } g_unk0x100f11cc = -1; @@ -1664,7 +1664,7 @@ void LegoCarBuild::FUN_10025e40() { SetPresentersEnabled(m_presentersEnabled); if (m_unk0x33c && m_Yellow_Ctl != m_unk0x33c) { - m_unk0x33c->VTable0x6c(0); + m_unk0x33c->UpdateEnabledChild(0); } } diff --git a/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp index 76780d6e..9374cb9f 100644 --- a/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp @@ -16,12 +16,12 @@ DECOMP_SIZE_ASSERT(MxControlPresenter, 0x5c) // FUNCTION: LEGO1 0x10043f50 MxControlPresenter::MxControlPresenter() { - m_unk0x4c = 0; - m_unk0x4e = -1; + m_style = e_none; + m_enabledChild = -1; m_unk0x50 = FALSE; - m_unk0x52 = 0; + m_columnsOrRows = 0; m_states = NULL; - m_unk0x54 = 0; + m_rowsOrColumns = 0; } // FUNCTION: LEGO1 0x10044110 @@ -35,7 +35,7 @@ MxControlPresenter::~MxControlPresenter() // FUNCTION: LEGO1 0x10044180 MxResult MxControlPresenter::AddToManager() { - m_unk0x4e = 0; + m_enabledChild = 0; return SUCCESS; } @@ -49,11 +49,11 @@ MxResult MxControlPresenter::StartAction(MxStreamController* p_controller, MxDSA MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { - (*it)->Enable((m_unk0x4c != 3 || m_unk0x4e) && IsEnabled() ? m_unk0x4e == i : FALSE); + (*it)->Enable((m_style != e_map || m_enabledChild) && IsEnabled() ? m_enabledChild == i : FALSE); i++; } - if (m_unk0x4c == 3) { + if (m_style == e_map) { MxDSAction* action = (*m_list.begin())->GetAction(); action->SetFlags(action->GetFlags() | MxDSAction::c_bit11); } @@ -74,12 +74,12 @@ void MxControlPresenter::EndAction() // FUNCTION: LEGO1 0x10044270 // FUNCTION: BETA10 0x100eae68 -MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter) +MxBool MxControlPresenter::CheckButtonDown(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter) { assert(p_presenter); MxVideoPresenter* presenter = (MxVideoPresenter*) p_presenter; - if (m_unk0x4c == 3) { + if (m_style == e_map) { MxStillPresenter* map = (MxStillPresenter*) m_list.front(); assert(map && map->IsA("MxStillPresenter")); @@ -94,23 +94,23 @@ MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_pre ? NULL : map->GetBitmap()->GetStart(p_x - rect.GetLeft(), p_y - rect.GetTop()); - m_unk0x56 = 0; + m_stateOrCellIndex = 0; if (m_states) { for (MxS16 i = 1; i <= *m_states; i++) { // TODO: Can we match without the cast here? if (m_states[i] == (MxS16) *start) { - m_unk0x56 = i; + m_stateOrCellIndex = i; break; } } } else { if (*start != 0) { - m_unk0x56 = 1; + m_stateOrCellIndex = 1; } } - if (m_unk0x56) { + if (m_stateOrCellIndex) { return TRUE; } } @@ -119,21 +119,21 @@ MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_pre } else { if (ContainsPresenter(m_list, presenter)) { - if (m_unk0x4c == 2) { + if (m_style == e_grid) { MxS32 width = presenter->GetWidth(); MxS32 height = presenter->GetHeight(); - if (m_unk0x52 == 2 && m_unk0x54 == 2) { + if (m_columnsOrRows == 2 && m_rowsOrColumns == 2) { if (p_x < presenter->GetX() + width / 2) { - m_unk0x56 = (p_y >= presenter->GetY() + height / 2) ? 3 : 1; + m_stateOrCellIndex = (p_y >= presenter->GetY() + height / 2) ? 3 : 1; } else { - m_unk0x56 = (p_y >= presenter->GetY() + height / 2) ? 4 : 2; + m_stateOrCellIndex = (p_y >= presenter->GetY() + height / 2) ? 4 : 2; } } } else { - m_unk0x56 = -1; + m_stateOrCellIndex = -1; } return TRUE; @@ -144,27 +144,27 @@ MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_pre } // FUNCTION: LEGO1 0x10044480 -MxBool MxControlPresenter::FUN_10044480(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter) +MxBool MxControlPresenter::Notify(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter) { if (IsEnabled()) { switch (p_param->GetNotification()) { case c_notificationButtonUp: - if (m_unk0x4c == 0 || m_unk0x4c == 2 || m_unk0x4c == 3) { + if (m_style == e_none || m_style == e_grid || m_style == e_map) { p_param->SetClickedObjectId(m_action->GetObjectId()); p_param->SetClickedAtom(m_action->GetAtomId().GetInternal()); - VTable0x6c(0); + UpdateEnabledChild(0); p_param->SetNotification(c_notificationControl); - p_param->SetUnknown0x28(m_unk0x4e); + p_param->SetUnknown0x28(m_enabledChild); return TRUE; } break; case c_notificationButtonDown: - if (FUN_10044270(p_param->GetX(), p_param->GetY(), p_presenter)) { + if (CheckButtonDown(p_param->GetX(), p_param->GetY(), p_presenter)) { p_param->SetClickedObjectId(m_action->GetObjectId()); p_param->SetClickedAtom(m_action->GetAtomId().GetInternal()); - VTable0x6c(m_unk0x56); + UpdateEnabledChild(m_stateOrCellIndex); p_param->SetNotification(c_notificationControl); - p_param->SetUnknown0x28(m_unk0x4e); + p_param->SetUnknown0x28(m_enabledChild); return TRUE; } break; @@ -175,25 +175,25 @@ MxBool MxControlPresenter::FUN_10044480(LegoControlManagerNotificationParam* p_p } // FUNCTION: LEGO1 0x10044540 -void MxControlPresenter::VTable0x6c(MxS16 p_unk0x4e) +void MxControlPresenter::UpdateEnabledChild(MxS16 p_enabledChild) { - if (p_unk0x4e == -1) { - if ((MxS16) ((MxDSMultiAction*) m_action)->GetActionList()->GetNumElements() - m_unk0x4e == 1) { - m_unk0x4e = 0; + if (p_enabledChild == -1) { + if ((MxS16) ((MxDSMultiAction*) m_action)->GetActionList()->GetNumElements() - m_enabledChild == 1) { + m_enabledChild = 0; } else { - m_unk0x4e++; + m_enabledChild++; } } else { - m_unk0x4e = p_unk0x4e; + m_enabledChild = p_enabledChild; } m_action->SetTimeStarted(Timer()->GetTime()); MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { - (*it)->Enable(((m_unk0x4c == 3 && m_unk0x4e == 0) || !IsEnabled()) ? FALSE : m_unk0x4e == i); + (*it)->Enable(((m_style == e_map && m_enabledChild == 0) || !IsEnabled()) ? FALSE : m_enabledChild == i); i++; } } @@ -224,20 +224,20 @@ void MxControlPresenter::ParseExtra() char* token = strtok(output, g_parseExtraTokens); if (!strcmpi(token, g_strTOGGLE)) { - m_unk0x4c = 1; + m_style = e_toggle; } else if (!strcmpi(token, g_strGRID)) { - m_unk0x4c = 2; + m_style = e_grid; token = strtok(NULL, g_parseExtraTokens); assert(token); - m_unk0x52 = atoi(token); + m_columnsOrRows = atoi(token); token = strtok(NULL, g_parseExtraTokens); assert(token); - m_unk0x54 = atoi(token); + m_rowsOrColumns = atoi(token); } else if (!strcmpi(token, g_strMAP)) { - m_unk0x4c = 3; + m_style = e_map; token = strtok(NULL, g_parseExtraTokens); if (token) { @@ -254,7 +254,7 @@ void MxControlPresenter::ParseExtra() } } else { - m_unk0x4c = 0; + m_style = e_none; } } @@ -274,8 +274,8 @@ void MxControlPresenter::Enable(MxBool p_enable) MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { - if (i == m_unk0x4e) { - (*it)->Enable((m_unk0x4c != 3 || i != 0) ? p_enable : 0); + if (i == m_enabledChild) { + (*it)->Enable((m_style != e_map || i != 0) ? p_enable : 0); break; } @@ -283,7 +283,7 @@ void MxControlPresenter::Enable(MxBool p_enable) } if (!p_enable) { - m_unk0x4e = 0; + m_enabledChild = 0; } } } @@ -294,10 +294,10 @@ MxBool MxControlPresenter::HasTickleStatePassed(TickleState p_tickleState) MxCompositePresenterList::const_iterator it = m_list.begin(); #ifdef COMPAT_MODE - advance(it, m_unk0x4e); + advance(it, m_enabledChild); #else // Uses forward iterator logic instead of bidrectional for some reason. - _Advance(it, m_unk0x4e, forward_iterator_tag()); + _Advance(it, m_enabledChild, forward_iterator_tag()); #endif return (*it)->HasTickleStatePassed(p_tickleState); diff --git a/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp index 8dd094f9..dc355be7 100644 --- a/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp +++ b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp @@ -131,9 +131,9 @@ void LegoControlManager::FUN_100293c0(MxU32 p_objectId, const char* p_atom, MxS1 MxDSAction* action = control->GetAction(); if (action->GetObjectId() == p_objectId && action->GetAtomId().GetInternal() == p_atom) { - ((MxControlPresenter*) control)->VTable0x6c(p_unk0x4e); + ((MxControlPresenter*) control)->UpdateEnabledChild(p_unk0x4e); - if (((MxControlPresenter*) control)->GetUnknown0x4e() == 0) { + if (((MxControlPresenter*) control)->GetEnabledChild() == 0) { g_unk0x100f31b0 = -1; g_unk0x100f31b4 = NULL; break; @@ -154,7 +154,7 @@ MxControlPresenter* LegoControlManager::FUN_100294e0(MxS32 p_x, MxS32 p_y) if (presenter) { while (cursor.Next(control)) { - if (((MxControlPresenter*) control)->FUN_10044270(p_x, p_y, presenter)) { + if (((MxControlPresenter*) control)->CheckButtonDown(p_x, p_y, presenter)) { return (MxControlPresenter*) control; } } @@ -185,7 +185,7 @@ MxBool LegoControlManager::FUN_10029630() MxPresenter* presenter; while (cursor.Next(presenter)) { - if (((MxControlPresenter*) presenter)->FUN_10044480(&m_event, m_unk0x14)) { + if (((MxControlPresenter*) presenter)->Notify(&m_event, m_unk0x14)) { g_unk0x100f31b0 = m_event.m_clickedObjectId; g_unk0x100f31b4 = m_event.GetClickedAtom(); FUN_100292e0(); @@ -206,7 +206,7 @@ MxBool LegoControlManager::FUN_10029750() while (cursor.Next(presenter)) { if (presenter->GetAction() && presenter->GetAction()->GetObjectId() == g_unk0x100f31b0 && presenter->GetAction()->GetAtomId().GetInternal() == g_unk0x100f31b4) { - if (((MxControlPresenter*) presenter)->FUN_10044480(&m_event, m_unk0x14)) { + if (((MxControlPresenter*) presenter)->Notify(&m_event, m_unk0x14)) { FUN_100292e0(); } From af9f7cd7915bd2ef7b87a34e051f2bebcb8b61d6 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sat, 5 Jul 2025 01:48:13 +0200 Subject: [PATCH 10/12] 3DS: Account for sprite scaling when resizing UI (#503) --- .../src/common/mxtransitionmanager.cpp | 88 +++++++++++-------- .../src/d3drm/backends/citro3d/renderer.cpp | 61 ++++++++----- .../src/d3drm/backends/directx9/renderer.cpp | 2 +- miniwin/src/d3drm/backends/opengl1/actual.cpp | 4 +- miniwin/src/d3drm/backends/opengl1/actual.h | 2 +- .../src/d3drm/backends/opengl1/renderer.cpp | 10 +-- .../src/d3drm/backends/opengles2/renderer.cpp | 10 +-- .../src/d3drm/backends/sdl3gpu/renderer.cpp | 2 +- .../src/d3drm/backends/software/renderer.cpp | 2 +- miniwin/src/ddraw/framebuffer.cpp | 4 +- miniwin/src/internal/d3drmrenderer.h | 2 +- miniwin/src/internal/d3drmrenderer_citro3d.h | 2 +- miniwin/src/internal/d3drmrenderer_directx9.h | 2 +- miniwin/src/internal/d3drmrenderer_opengl1.h | 2 +- .../src/internal/d3drmrenderer_opengles2.h | 2 +- miniwin/src/internal/d3drmrenderer_sdl3gpu.h | 2 +- miniwin/src/internal/d3drmrenderer_software.h | 2 +- 17 files changed, 116 insertions(+), 83 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 6c4f94ea..27086eb3 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -642,8 +642,14 @@ int GetColorIndexWithLocality(int p_col, int p_row) void MxTransitionManager::FakeMosaicTransition() { + static LPDIRECTDRAWSURFACE g_fakeTranstionSurface = nullptr; + if (m_animationTimer == 16) { m_animationTimer = 0; + if (g_fakeTranstionSurface) { + g_fakeTranstionSurface->Release(); + g_fakeTranstionSurface = nullptr; + } EndTransition(TRUE); return; } @@ -662,12 +668,33 @@ void MxTransitionManager::FakeMosaicTransition() } } + if (!g_fakeTranstionSurface) { + DDSURFACEDESC mainDesc = {}; + mainDesc.dwSize = sizeof(mainDesc); + if (m_ddSurface->GetSurfaceDesc(&mainDesc) != DD_OK) { + return; + } + + DDSURFACEDESC tempDesc = {}; + tempDesc.dwSize = sizeof(tempDesc); + tempDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + tempDesc.dwWidth = 64; + tempDesc.dwHeight = 48; + tempDesc.ddpfPixelFormat = mainDesc.ddpfPixelFormat; + tempDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + + HRESULT hr = MVideoManager()->GetDirectDraw()->CreateSurface(&tempDesc, &g_fakeTranstionSurface, nullptr); + if (hr != DD_OK || !g_fakeTranstionSurface) { + return; + } + } + DDSURFACEDESC ddsd = {}; ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + HRESULT res = g_fakeTranstionSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { - m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + g_fakeTranstionSurface->Restore(); + res = g_fakeTranstionSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -694,50 +721,33 @@ void MxTransitionManager::FakeMosaicTransition() } for (MxS32 row = 0; row < 48; row++) { - MxS32 xShift = 10 * ((m_randomShift[row] + col) % 64); - MxS32 yStart = 10 * row; - - int paletteIndex = GetColorIndexWithLocality(xShift / 10, row); + int paletteIndex = GetColorIndexWithLocality(col, row); const MxU8* color = g_palette[paletteIndex]; - for (MxS32 y = 0; y < 10; y++) { - MxU8* dest = (MxU8*) ddsd.lpSurface + (yStart + y) * ddsd.lPitch + xShift * bytesPerPixel; - switch (bytesPerPixel) { - case 1: - memset(dest, paletteIndex, 10); - break; - case 2: { - MxU32 pixel = RGB555_CREATE(color[2], color[1], color[0]); - MxU16* p = (MxU16*) dest; - for (MxS32 i = 0; i < 10; i++) { - p[i] = pixel; - } - break; - } - default: { - MxU32 pixel = RGB8888_CREATE(color[2], color[1], color[0], 255); - MxU32* p = (MxU32*) dest; - for (MxS32 i = 0; i < 10; i++) { - p[i] = pixel; - } - break; - } - } + MxS32 xShift = (m_randomShift[row] + col) % 64; + MxU8* dest = (MxU8*) ddsd.lpSurface + row * ddsd.lPitch + xShift * bytesPerPixel; + + switch (bytesPerPixel) { + case 1: + *dest = paletteIndex; + break; + case 2: + *((MxU16*) dest) = RGB555_CREATE(color[2], color[1], color[0]); + break; + default: + *((MxU32*) dest) = RGB8888_CREATE(color[2], color[1], color[0], 255); + break; } } } SetupCopyRect(&ddsd); - m_ddSurface->Unlock(ddsd.lpSurface); + g_fakeTranstionSurface->Unlock(ddsd.lpSurface); - if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) { - VideoManager() - ->GetDisplaySurface() - ->GetDirectDrawSurface1() - ->BltFast(0, 0, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); - } - - m_animationTimer++; + RECT srcRect = {0, 0, 64, 48}; + m_ddSurface->Blt(&g_fullScreenRect, g_fakeTranstionSurface, &srcRect, DDBLT_WAIT, NULL); } + + m_animationTimer++; } diff --git a/miniwin/src/d3drm/backends/citro3d/renderer.cpp b/miniwin/src/d3drm/backends/citro3d/renderer.cpp index f71f9255..ab9088bc 100644 --- a/miniwin/src/d3drm/backends/citro3d/renderer.cpp +++ b/miniwin/src/d3drm/backends/citro3d/renderer.cpp @@ -115,31 +115,34 @@ static int NearestPowerOfTwoClamp(int val) return 512; } -static SDL_Surface* ConvertAndResizeSurface(SDL_Surface* original, bool isUI, float scale) +static SDL_Surface* ConvertAndResizeSurface(SDL_Surface* original, bool isUI, float scaleX, float scaleY) { - SDL_Surface* converted = SDL_ConvertSurface(original, SDL_PIXELFORMAT_RGBA8888); - if (!converted) { - return nullptr; - } if (!isUI) { - return converted; + return SDL_ConvertSurface(original, SDL_PIXELFORMAT_RGBA8888); } - int scaledW = static_cast(converted->w * scale); - int scaledH = static_cast(converted->h * scale); + scaleX = std::min(scaleX, 1.0f); + scaleY = std::min(scaleY, 1.0f); + + int scaledW = static_cast(original->w * scaleX); + int scaledH = static_cast(original->h * scaleY); int paddedW = NearestPowerOfTwoClamp(scaledW); int paddedH = NearestPowerOfTwoClamp(scaledH); SDL_Surface* padded = SDL_CreateSurface(paddedW, paddedH, SDL_PIXELFORMAT_RGBA8888); if (!padded) { - SDL_DestroySurface(converted); return nullptr; } - SDL_Rect dstRect = {0, 0, scaledW, scaledH}; - SDL_BlitSurfaceScaled(converted, nullptr, padded, &dstRect, SDL_SCALEMODE_LINEAR); - SDL_DestroySurface(converted); + if (scaleX == 1.0f && scaleY == 1.0f) { + SDL_BlitSurface(original, nullptr, padded, nullptr); + } + else { + SDL_ScaleMode scaleMode = (scaleX >= 1.0f && scaleY >= 1.0f) ? SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR; + SDL_Rect dstRect = {0, 0, scaledW, scaledH}; + SDL_BlitSurfaceScaled(original, nullptr, padded, &dstRect, scaleMode); + } return padded; } @@ -181,9 +184,9 @@ static void EncodeTextureLayout(const u8* src, u8* dst, int width, int height) } } -static bool ConvertAndUploadTexture(C3D_Tex* tex, SDL_Surface* originalSurface, bool isUI, float scale) +static bool ConvertAndUploadTexture(C3D_Tex* tex, SDL_Surface* originalSurface, bool isUI, float scaleX, float scaleY) { - SDL_Surface* resized = ConvertAndResizeSurface(originalSurface, isUI, scale); + SDL_Surface* resized = ConvertAndResizeSurface(originalSurface, isUI, scaleX, scaleY); if (!resized) { return false; } @@ -198,18 +201,24 @@ static bool ConvertAndUploadTexture(C3D_Tex* tex, SDL_Surface* originalSurface, params.maxLevel = isUI ? 0 : 4; params.type = GPU_TEX_2D; if (!C3D_TexInitWithParams(tex, nullptr, params)) { - SDL_DestroySurface(resized); + if (resized != originalSurface) { + SDL_DestroySurface(resized); + } return false; } uint8_t* tiledData = (uint8_t*) malloc(width * height * 4); if (!tiledData) { - SDL_DestroySurface(resized); + if (resized != originalSurface) { + SDL_DestroySurface(resized); + } return false; } EncodeTextureLayout((const u8*) resized->pixels, tiledData, width, height); - SDL_DestroySurface(resized); + if (resized != originalSurface) { + SDL_DestroySurface(resized); + } C3D_TexUpload(tex, tiledData); free(tiledData); @@ -228,7 +237,7 @@ static bool ConvertAndUploadTexture(C3D_Tex* tex, SDL_Surface* originalSurface, return true; } -Uint32 Citro3DRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) +Uint32 Citro3DRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -242,7 +251,13 @@ Uint32 Citro3DRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) if (tex.texture == texture) { if (tex.version != texture->m_version) { C3D_TexDelete(&tex.c3dTex); - if (!ConvertAndUploadTexture(&tex.c3dTex, originalSurface, isUi, m_viewportTransform.scale)) { + if (!ConvertAndUploadTexture( + &tex.c3dTex, + originalSurface, + isUI, + scaleX * m_viewportTransform.scale, + scaleY * m_viewportTransform.scale + )) { return NO_TEXTURE_ID; } @@ -260,7 +275,13 @@ Uint32 Citro3DRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) entry.width = NearestPowerOfTwoClamp(originalW * m_viewportTransform.scale); entry.height = NearestPowerOfTwoClamp(originalH * m_viewportTransform.scale); - if (!ConvertAndUploadTexture(&entry.c3dTex, originalSurface, isUi, m_viewportTransform.scale)) { + if (!ConvertAndUploadTexture( + &entry.c3dTex, + originalSurface, + isUI, + scaleX * m_viewportTransform.scale, + scaleY * m_viewportTransform.scale + )) { return NO_TEXTURE_ID; } diff --git a/miniwin/src/d3drm/backends/directx9/renderer.cpp b/miniwin/src/d3drm/backends/directx9/renderer.cpp index 5c8a2354..e97dfa17 100644 --- a/miniwin/src/d3drm/backends/directx9/renderer.cpp +++ b/miniwin/src/d3drm/backends/directx9/renderer.cpp @@ -76,7 +76,7 @@ void DirectX9Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* ); } -Uint32 DirectX9Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) +Uint32 DirectX9Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); diff --git a/miniwin/src/d3drm/backends/opengl1/actual.cpp b/miniwin/src/d3drm/backends/opengl1/actual.cpp index a86ebec1..4b83daff 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.cpp +++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp @@ -49,12 +49,12 @@ int GL11_GetMaxTextureSize() return maxTextureSize; } -GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUi) +GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI, float scaleX, float scaleY) { GLuint texId; glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); - if (isUi) { + if (isUI) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); diff --git a/miniwin/src/d3drm/backends/opengl1/actual.h b/miniwin/src/d3drm/backends/opengl1/actual.h index 87f33687..232fc88d 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.h +++ b/miniwin/src/d3drm/backends/opengl1/actual.h @@ -65,7 +65,7 @@ void GL11_InitState(); void GL11_LoadExtensions(); void GL11_DestroyTexture(GLuint texId); int GL11_GetMaxTextureSize(); -GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI); +GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI, float scaleX, float scaleY); void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture); void GL11_DestroyMesh(GLMeshCacheEntry& cache); void GL11_BeginFrame(const Matrix4x4* projection); diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index 00088da9..e537a396 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -119,7 +119,7 @@ static int NextPowerOfTwo(int v) return power; } -static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUi) +static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUI, float scaleX, float scaleY) { SDL_Surface* working = src; if (src->format != SDL_PIXELFORMAT_RGBA32) { @@ -166,14 +166,14 @@ static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUi) finalSurface = resized; } - Uint32 texId = GL11_UploadTextureData(finalSurface->pixels, finalSurface->w, finalSurface->h, isUi); + Uint32 texId = GL11_UploadTextureData(finalSurface->pixels, finalSurface->w, finalSurface->h, isUI, scaleX, scaleY); if (finalSurface != src) { SDL_DestroySurface(finalSurface); } return texId; } -Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) +Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -183,7 +183,7 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) if (tex.texture == texture) { if (tex.version != texture->m_version) { GL11_DestroyTexture(tex.glTextureId); - tex.glTextureId = UploadTextureData(surface->m_surface, m_useNPOT, isUi); + tex.glTextureId = UploadTextureData(surface->m_surface, m_useNPOT, isUI, scaleX, scaleY); tex.version = texture->m_version; tex.width = surface->m_surface->w; tex.height = surface->m_surface->h; @@ -192,7 +192,7 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) } } - GLuint texId = UploadTextureData(surface->m_surface, m_useNPOT, isUi); + GLuint texId = UploadTextureData(surface->m_surface, m_useNPOT, isUI, scaleX, scaleY); for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 850e8b6e..ebcb38e6 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -321,7 +321,7 @@ void OpenGLES2Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* ); } -bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUi) +bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI) { SDL_Surface* surf = source; if (source->format != SDL_PIXELFORMAT_RGBA32) { @@ -335,7 +335,7 @@ bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUi) glBindTexture(GL_TEXTURE_2D, outTexId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - if (isUi) { + if (isUI) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -362,7 +362,7 @@ bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUi) return true; } -Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) +Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -372,7 +372,7 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) if (tex.texture == texture) { if (tex.version != texture->m_version) { glDeleteTextures(1, &tex.glTextureId); - if (UploadTexture(surface->m_surface, tex.glTextureId, isUi)) { + if (UploadTexture(surface->m_surface, tex.glTextureId, isUI)) { tex.version = texture->m_version; } } @@ -381,7 +381,7 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) } GLuint texId; - if (!UploadTexture(surface->m_surface, texId, isUi)) { + if (!UploadTexture(surface->m_surface, texId, isUI)) { return NO_TEXTURE_ID; } diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index c6324f03..0609bbdc 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -499,7 +499,7 @@ SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* return texptr; } -Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) +Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index 2ae8697e..bd99d2aa 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -554,7 +554,7 @@ void Direct3DRMSoftwareRenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DR ); } -Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) +Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); diff --git a/miniwin/src/ddraw/framebuffer.cpp b/miniwin/src/ddraw/framebuffer.cpp index 20490b42..843c36ec 100644 --- a/miniwin/src/ddraw/framebuffer.cpp +++ b/miniwin/src/ddraw/framebuffer.cpp @@ -78,11 +78,13 @@ HRESULT FrameBufferImpl::Blt( if (!surface) { return DDERR_GENERIC; } - Uint32 textureId = DDRenderer->GetTextureId(surface->ToTexture(), true); SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, surface->m_surface->w, surface->m_surface->h}; SDL_Rect dstRect = lpDestRect ? ConvertRect(lpDestRect) : SDL_Rect{0, 0, (int) m_virtualWidth, (int) m_virtualHeight}; + float scaleX = (float) dstRect.w / (float) srcRect.w; + float scaleY = (float) dstRect.h / (float) srcRect.h; + Uint32 textureId = DDRenderer->GetTextureId(surface->ToTexture(), true, scaleX, scaleY); DDRenderer->Draw2DImage(textureId, srcRect, dstRect, {1.0f, 1.0f, 1.0f, 1.0f}); return DD_OK; diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index d6464eb7..7cfe14b2 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -31,7 +31,7 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { virtual void PushLights(const SceneLight* vertices, size_t count) = 0; virtual void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) = 0; virtual void SetFrustumPlanes(const Plane* frustumPlanes) = 0; - virtual Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi = false) = 0; + virtual Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI = false, float scaleX = 0, float scaleY = 0) = 0; virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0; int GetWidth() { return m_width; } int GetHeight() { return m_height; } diff --git a/miniwin/src/internal/d3drmrenderer_citro3d.h b/miniwin/src/internal/d3drmrenderer_citro3d.h index 34863497..2359a88e 100644 --- a/miniwin/src/internal/d3drmrenderer_citro3d.h +++ b/miniwin/src/internal/d3drmrenderer_citro3d.h @@ -32,7 +32,7 @@ class Citro3DRenderer : public Direct3DRMRenderer { void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; HRESULT BeginFrame() override; void EnableTransparency() override; diff --git a/miniwin/src/internal/d3drmrenderer_directx9.h b/miniwin/src/internal/d3drmrenderer_directx9.h index d1b0a581..5e87aed3 100644 --- a/miniwin/src/internal/d3drmrenderer_directx9.h +++ b/miniwin/src/internal/d3drmrenderer_directx9.h @@ -18,7 +18,7 @@ class DirectX9Renderer : public Direct3DRMRenderer { void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; HRESULT BeginFrame() override; void EnableTransparency() override; diff --git a/miniwin/src/internal/d3drmrenderer_opengl1.h b/miniwin/src/internal/d3drmrenderer_opengl1.h index bd0fa003..2f1c8173 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl1.h +++ b/miniwin/src/internal/d3drmrenderer_opengl1.h @@ -18,7 +18,7 @@ class OpenGL1Renderer : public Direct3DRMRenderer { void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; HRESULT BeginFrame() override; void EnableTransparency() override; diff --git a/miniwin/src/internal/d3drmrenderer_opengles2.h b/miniwin/src/internal/d3drmrenderer_opengles2.h index 7dbb1f4b..0472ff80 100644 --- a/miniwin/src/internal/d3drmrenderer_opengles2.h +++ b/miniwin/src/internal/d3drmrenderer_opengles2.h @@ -39,7 +39,7 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; HRESULT BeginFrame() override; void EnableTransparency() override; diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index b3afd674..7f948a37 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -47,7 +47,7 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { static Direct3DRMRenderer* Create(DWORD width, DWORD height); ~Direct3DRMSDL3GPURenderer() override; void PushLights(const SceneLight* vertices, size_t count) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 8b8c0dde..0c422597 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -29,7 +29,7 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { Direct3DRMSoftwareRenderer(DWORD width, DWORD height); ~Direct3DRMSoftwareRenderer() override; void PushLights(const SceneLight* vertices, size_t count) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; From b2156c94bf6170cacd22f167199912720777d470 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sat, 5 Jul 2025 05:21:32 +0200 Subject: [PATCH 11/12] Fix uninitialized presenter (#525) --- LEGO1/lego/legoomni/src/worlds/registrationbook.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp b/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp index adaf45d4..709b338d 100644 --- a/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp +++ b/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp @@ -671,14 +671,14 @@ MxLong RegistrationBook::HandlePathStruct(LegoPathStructNotificationParam& p_par MxBool RegistrationBook::CreateSurface() { MxCompositePresenterList* presenters = m_checkmark[0]->GetList(); - MxStillPresenter *presenter, *uninitialized; + MxStillPresenter* presenter; if (presenters) { if (presenters->begin() != presenters->end()) { presenter = (MxStillPresenter*) presenters->front(); } else { - presenter = uninitialized; // intentionally uninitialized variable + presenter = NULL; } if (presenter) { From 761dc31ac04433a4019c57908c32aa50e7fa5f1e Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sat, 5 Jul 2025 07:39:51 +0200 Subject: [PATCH 12/12] Render buttons as sprites (#488) --- LEGO1/omni/src/video/mxdisplaysurface.cpp | 49 +++++++++++++++++------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 5d08a64b..612caba4 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -409,9 +409,16 @@ void MxDisplaySurface::VTable0x28( return; } - DDCOLORKEY colorKey; - colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); - tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey); + if (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount != 32) { + DDCOLORKEY colorKey; + if (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount == 8) { + colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = 0x10; + } + else { + colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); + } + tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey); + } DDSURFACEDESC tempDesc; memset(&tempDesc, 0, sizeof(tempDesc)); @@ -503,29 +510,43 @@ void MxDisplaySurface::VTable0x30( DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + ddsd.dwWidth = p_width; + ddsd.dwHeight = p_height; + ddsd.ddpfPixelFormat = m_surfaceDesc.ddpfPixelFormat; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - if (hr == DDERR_SURFACELOST) { - m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw(); + LPDIRECTDRAWSURFACE tempSurface = nullptr; + if (draw->CreateSurface(&ddsd, &tempSurface, nullptr) != DD_OK || !tempSurface) { + return; } - if (hr != DD_OK) { + DDCOLORKEY colorKey; + colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = 0; + tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey); + + DDSURFACEDESC tempDesc; + memset(&tempDesc, 0, sizeof(tempDesc)); + tempDesc.dwSize = sizeof(tempDesc); + + if (tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { + tempSurface->Release(); return; } MxU8* data = p_bitmap->GetStart(p_left, p_top); MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8; - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); + MxU8* surface = (MxU8*) tempDesc.lpSurface; if (p_RLE) { MxS32 size = p_bitmap->GetBmiHeader()->biSizeImage; - DrawTransparentRLE(data, surface, size, p_width, p_height, ddsd.lPitch, bytesPerPixel * 8); + DrawTransparentRLE(data, surface, size, p_width, p_height, tempDesc.lPitch, bytesPerPixel * 8); } else { MxLong stride = -p_width + GetAdjustedStride(p_bitmap); - MxLong length = -bytesPerPixel * p_width + ddsd.lPitch; + MxLong length = -bytesPerPixel * p_width + tempDesc.lPitch; for (MxS32 i = 0; i < p_height; i++) { for (MxS32 j = 0; j < p_width; j++) { @@ -550,7 +571,11 @@ void MxDisplaySurface::VTable0x30( } } - m_ddSurface2->Unlock(ddsd.lpSurface); + tempSurface->Unlock(NULL); + + m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); + + tempSurface->Release(); } // FUNCTION: LEGO1 0x100bb500