diff --git a/.gitignore b/.gitignore index 402fb660..8768f944 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ Debug/ Release/ *.ncb +/.vs ISLE.EXE LEGO1.DLL build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index fa4de1e5..df71ccf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,9 @@ add_library(lego1 SHARED LEGO1/jukeboxentity.cpp LEGO1/jukeboxstate.cpp LEGO1/legoact2state.cpp + LEGO1/legoactor.cpp LEGO1/legoactioncontrolpresenter.cpp + LEGO1/legoactor.cpp LEGO1/legoanimactor.cpp LEGO1/legoanimationmanager.cpp LEGO1/legoanimmmpresenter.cpp @@ -101,6 +103,7 @@ add_library(lego1 SHARED LEGO1/mxdirectdraw.cpp LEGO1/mxdiskstreamcontroller.cpp LEGO1/mxdiskstreamprovider.cpp + LEGO1/mxdisplaysurface.cpp LEGO1/mxdsaction.cpp LEGO1/mxdsanim.cpp LEGO1/mxdschunk.cpp @@ -125,6 +128,7 @@ add_library(lego1 SHARED LEGO1/mxloopingflcpresenter.cpp LEGO1/mxloopingmidipresenter.cpp LEGO1/mxloopingsmkpresenter.cpp + LEGO1/mxmatrix.cpp LEGO1/mxmediapresenter.cpp LEGO1/mxmidipresenter.cpp LEGO1/mxmusicpresenter.cpp @@ -147,11 +151,13 @@ add_library(lego1 SHARED LEGO1/mxstring.cpp LEGO1/mxstringvariable.cpp LEGO1/mxthread.cpp + LEGO1/mxticklemanager.cpp LEGO1/mxtimer.cpp LEGO1/mxtransitionmanager.cpp LEGO1/mxunknown100dc6b0.cpp LEGO1/mxunknown100dc6e0.cpp LEGO1/mxvariabletable.cpp + LEGO1/mxvector.cpp LEGO1/mxvideomanager.cpp LEGO1/mxvideoparam.cpp LEGO1/mxvideoparamflags.cpp diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index a1836e8c..8d175dfa 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -121,7 +121,7 @@ BOOL IsleApp::SetupLegoOmni() BOOL failure = Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__ *) m_windowHandle, m_videoParam, MxOmniCreateFlags())) == FAILURE; if (!failure) { VariableTable()->SetVariable("ACTOR_01", ""); - TickleManager()->vtable1c(VideoManager(), 10); + TickleManager()->SetClientTickleInterval(VideoManager(), 10); result = TRUE; } diff --git a/LEGO1/decomp.h b/LEGO1/decomp.h index 5466e6d8..cd179ae6 100644 --- a/LEGO1/decomp.h +++ b/LEGO1/decomp.h @@ -4,6 +4,10 @@ #define DECOMP_STATIC_ASSERT(V) namespace { typedef int foo[(V)?1:-1]; } #define DECOMP_SIZE_ASSERT(T, S) DECOMP_STATIC_ASSERT(sizeof(T) == S) +#ifndef _countof +#define _countof(arr) sizeof(arr) / sizeof(arr[0]) +#endif + typedef unsigned char undefined; typedef unsigned short undefined2; typedef unsigned int undefined4; diff --git a/LEGO1/isleactor.cpp b/LEGO1/isleactor.cpp index ca286e37..a28afc6b 100644 --- a/LEGO1/isleactor.cpp +++ b/LEGO1/isleactor.cpp @@ -1 +1,4 @@ #include "isleactor.h" + +// NOTE: This is copied from base class LegoActor. IsleActor may in fact be larger but we don't know yet. +DECOMP_SIZE_ASSERT(IsleActor, 0x78) diff --git a/LEGO1/islepathactor.cpp b/LEGO1/islepathactor.cpp index 72ed76d8..0024b4bc 100644 --- a/LEGO1/islepathactor.cpp +++ b/LEGO1/islepathactor.cpp @@ -1 +1,17 @@ #include "islepathactor.h" + +DECOMP_SIZE_ASSERT(IslePathActor, 0x160) + +// OFFSET: LEGO1 0x1001a200 +IslePathActor::IslePathActor() +{ + this->m_pLegoWorld = NULL; + this->m_unk13c = 6.0; + this->m_unk15c = 1.0; + this->m_unk158 = 0; +} + +// OFFSET: LEGO1 0x10002e10 +IslePathActor::~IslePathActor() +{ +} diff --git a/LEGO1/islepathactor.h b/LEGO1/islepathactor.h index fce450ac..f4574355 100644 --- a/LEGO1/islepathactor.h +++ b/LEGO1/islepathactor.h @@ -2,12 +2,17 @@ #define ISLEPATHACTOR_H #include "legopathactor.h" +#include "legoworld.h" +#include "mxtypes.h" // VTABLE 0x100d4398 -// SIZE >= 0x230 +// SIZE 0x160 class IslePathActor : public LegoPathActor { -public: +public: + IslePathActor(); + ~IslePathActor(); + // OFFSET: LEGO1 0x10002ea0 inline virtual const char *ClassName() const override // vtable+0x0c { @@ -20,6 +25,11 @@ class IslePathActor : public LegoPathActor { return !strcmp(name, IslePathActor::ClassName()) || LegoPathActor::IsA(name); } + +private: + LegoWorld* m_pLegoWorld; // 0x154 + MxFloat m_unk158; + MxFloat m_unk15c; }; #endif // ISLEPATHACTOR_H diff --git a/LEGO1/legoactor.cpp b/LEGO1/legoactor.cpp new file mode 100644 index 00000000..c26cc1fc --- /dev/null +++ b/LEGO1/legoactor.cpp @@ -0,0 +1,3 @@ +#include "legoactor.h" + +DECOMP_SIZE_ASSERT(LegoActor, 0x78) diff --git a/LEGO1/legoactor.h b/LEGO1/legoactor.h index 9b23e943..cc8778db 100644 --- a/LEGO1/legoactor.h +++ b/LEGO1/legoactor.h @@ -1,6 +1,7 @@ #ifndef LEGOACTOR_H #define LEGOACTOR_H +#include "decomp.h" #include "legoentity.h" // VTABLE 0x100d6d68 @@ -20,6 +21,10 @@ class LegoActor : public LegoEntity { return !strcmp(name, LegoActor::ClassName()) || LegoEntity::IsA(name); } + +private: + undefined unk68[0x10]; + }; #endif // LEGOACTOR_H diff --git a/LEGO1/legoentity.cpp b/LEGO1/legoentity.cpp index b79bc587..b8ed69f9 100644 --- a/LEGO1/legoentity.cpp +++ b/LEGO1/legoentity.cpp @@ -1,5 +1,7 @@ #include "legoentity.h" +DECOMP_SIZE_ASSERT(LegoEntity, 0x68) + // OFFSET: LEGO1 0x1000c290 LegoEntity::~LegoEntity() { diff --git a/LEGO1/legoentity.h b/LEGO1/legoentity.h index 46aea940..fdfe997f 100644 --- a/LEGO1/legoentity.h +++ b/LEGO1/legoentity.h @@ -4,6 +4,7 @@ #include "mxentity.h" // VTABLE 0x100d4858 +// SIZE 0x68 (probably) class LegoEntity : public MxEntity { public: diff --git a/LEGO1/legopathactor.cpp b/LEGO1/legopathactor.cpp index 336cdc13..f1c39b82 100644 --- a/LEGO1/legopathactor.cpp +++ b/LEGO1/legopathactor.cpp @@ -1,5 +1,7 @@ #include "legopathactor.h" +DECOMP_SIZE_ASSERT(LegoPathActor, 0x154) + // OFFSET: LEGO1 0x1002d700 STUB LegoPathActor::LegoPathActor() { diff --git a/LEGO1/legopathactor.h b/LEGO1/legopathactor.h index e6f643c2..7e524b08 100644 --- a/LEGO1/legopathactor.h +++ b/LEGO1/legopathactor.h @@ -2,6 +2,7 @@ #define LEGOPATHACTOR_H #include "legoactor.h" +#include "mxtypes.h" // VTABLE 0x100d6e28 // SIZE 0x154 (from inlined construction at 0x1000a346) @@ -25,6 +26,10 @@ class LegoPathActor : public LegoActor return !strcmp(name, LegoPathActor::ClassName()) || LegoActor::IsA(name); } + // TODO: the types. Pizza needs this as public: + undefined unk78[0xc4]; + MxS32 m_unk13c; + undefined unk140[0x14]; }; #endif // LEGOPATHACTOR_H diff --git a/LEGO1/mxbackgroundaudiomanager.cpp b/LEGO1/mxbackgroundaudiomanager.cpp index 6f001303..a24286ad 100644 --- a/LEGO1/mxbackgroundaudiomanager.cpp +++ b/LEGO1/mxbackgroundaudiomanager.cpp @@ -1,13 +1,29 @@ #include "mxbackgroundaudiomanager.h" +DECOMP_SIZE_ASSERT(MxBackgroundAudioManager, 0x150) + // OFFSET: LEGO1 0x1007ea90 MxBackgroundAudioManager::MxBackgroundAudioManager() { - // TODO + NotificationManager()->Register(this); + m_unka0 = 0; + m_unk138 = 0; + m_unk13c = 0; + m_unk140 = 0; + m_unk144 = 0; + m_unk148 = 0; + m_musicEnabled = FALSE; } // OFFSET: LEGO1 0x1007ec20 MxBackgroundAudioManager::~MxBackgroundAudioManager() +{ + // TODO + NotificationManager()->Unregister(this); +} + +// OFFSET: LEGO1 0x1007f470 +void MxBackgroundAudioManager::Stop() { // TODO } @@ -15,5 +31,17 @@ MxBackgroundAudioManager::~MxBackgroundAudioManager() // OFFSET: LEGO1 0x1007f5f0 void MxBackgroundAudioManager::Enable(MxBool p) { - // TODO + if (this->m_musicEnabled != p) { + this->m_musicEnabled = p; + if (!p) { + Stop(); + } + } +} + +// OFFSET: LEGO1 0x1007f650 +void MxBackgroundAudioManager::Init() +{ + this->m_unka0 = 0; + this->m_unk13c = 0; } diff --git a/LEGO1/mxbackgroundaudiomanager.h b/LEGO1/mxbackgroundaudiomanager.h index 9a23a671..c6f2f1e7 100644 --- a/LEGO1/mxbackgroundaudiomanager.h +++ b/LEGO1/mxbackgroundaudiomanager.h @@ -2,6 +2,9 @@ #define MXBACKGROUNDAUDIOMANAGER_H #include "mxcore.h" +#include "mxdsaction.h" +#include "mxtypes.h" +#include "mxnotificationmanager.h" // VTABLE 0x100d9fe8 // SIZE 0x150 @@ -25,6 +28,20 @@ class MxBackgroundAudioManager : public MxCore } __declspec(dllexport) void Enable(unsigned char p); +private: + void Stop(); + void Init(); + + MxBool m_musicEnabled; // 0x8 + MxDSAction m_action1; // 0xc + MxS32 m_unka0; + MxDSAction m_action2; // 0xa4 + MxS32 m_unk138; + MxS32 m_unk13c; + MxS32 m_unk140; + MxS32 m_unk144; + MxS16 m_unk148; + MxAtomId m_unk14c; }; #endif // MXBACKGROUNDAUDIOMANAGER_H diff --git a/LEGO1/mxdirect3d.cpp b/LEGO1/mxdirect3d.cpp new file mode 100644 index 00000000..e69de29b diff --git a/LEGO1/mxdirect3d.h b/LEGO1/mxdirect3d.h new file mode 100644 index 00000000..e69de29b diff --git a/LEGO1/mxdirectdraw.cpp b/LEGO1/mxdirectdraw.cpp index dde59ba0..dbe07d12 100644 --- a/LEGO1/mxdirectdraw.cpp +++ b/LEGO1/mxdirectdraw.cpp @@ -1,22 +1,1223 @@ -#include "mxdirectdraw.h" -// OFFSET: LEGO1 0x1009e7f0 -int MxDirectDraw::FlipToGDISurface() +#include "mxdirectdraw.h" +#include "decomp.h" + + +#ifndef DDSCAPS_3DDEVICE +#define DDSCAPS_3DDEVICE 0x00002000l +#endif + +// GLOBAL OFFSET: LEGO1 0x10100C68 +extern BOOL g_is_PALETTEINDEXED8 = 0; + +// OFFSET: LEGO1 0x1009DA20 +void EnableResizing(HWND hwnd, BOOL flag) { - // TODO - return 0; + static DWORD dwStyle; + + if (!flag) + { + dwStyle = GetWindowLong(hwnd, GWL_STYLE); + if (dwStyle & WS_THICKFRAME) + { + SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) ^ WS_THICKFRAME); + } + } + else + { + SetWindowLong(hwnd, GWL_STYLE, dwStyle); + } +} + +// OFFSET: LEGO1 0x1009EFD0 +MxDirectDraw::DeviceModesInfo::~DeviceModesInfo() +{ + if (p_guid != NULL) + { + delete p_guid; + } + + if (m_mode_ARRAY != NULL) + { + delete m_mode_ARRAY; + } +} + +// OFFSET: LEGO1 0x1009D490 +MxDirectDraw::MxDirectDraw() +{ + m_pFrontBuffer = NULL; + m_pBackBuffer = NULL; + m_pZBuffer = NULL; + m_pClipper = NULL; + m_pPalette = NULL; + m_pDirectDraw = NULL; + m_pText1Surface = NULL; + m_pText2Surface = NULL; + m_hWndMain = NULL; + m_bIgnoreWM_SIZE = FALSE; + m_bPrimaryPalettized = FALSE; + m_bOnlySystemMemory = FALSE; + m_bFullScreen = FALSE; + m_bOnlySoftRender = FALSE; + m_pauseCount = 0; + m_pErrorHandler = NULL; + m_pFatalErrorHandler = NULL; + m_pErrorHandlerArg = NULL; + m_pFatalErrorHandlerArg = NULL; + m_pCurrentDeviceModesList = NULL; + m_bIsOnPrimaryDevice = TRUE; + m_hFont = NULL; +} + +// OFFSET: LEGO1 0x1009D530 +MxDirectDraw::~MxDirectDraw() +{ + Destroy(); + + if (m_pCurrentDeviceModesList != NULL) + { + delete m_pCurrentDeviceModesList; + m_pCurrentDeviceModesList = NULL; + } } // OFFSET: LEGO1 0x1009d570 int MxDirectDraw::GetPrimaryBitDepth() { - // TODO - return 0; + DWORD dwRGBBitCount; + LPDIRECTDRAW pDDraw; + DDSURFACEDESC ddsd; + + HRESULT result = DirectDrawCreate(NULL, &pDDraw, NULL); + dwRGBBitCount = 8; + if (!result) + { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + pDDraw->GetDisplayMode(&ddsd); + dwRGBBitCount = ddsd.ddpfPixelFormat.dwRGBBitCount; + g_is_PALETTEINDEXED8 = (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) != 0; + pDDraw->Release(); +} + + return dwRGBBitCount; +} + +// OFFSET: LEGO1 0x1009D5E0 +BOOL MxDirectDraw::Create( + HWND hWnd, + BOOL fullscreen_1, + BOOL surface_fullscreen, + BOOL onlySystemMemory, + int width, + int height, + int bpp, + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount) +{ + m_hWndMain = hWnd; + + CacheOriginalPaletteEntries(); + + if (!RecreateDirectDraw(&m_pCurrentDeviceModesList->p_guid)) + { + return FALSE; + } + + m_bFlipSurfaces = surface_fullscreen; + m_bOnlySystemMemory = onlySystemMemory; + m_bIsOnPrimaryDevice = !m_pCurrentDeviceModesList->p_guid; + BOOL fullscreen = 1; + + if (m_bIsOnPrimaryDevice) + { + fullscreen = fullscreen_1; + } + + if (!SetPaletteEntries(pPaletteEntries, paletteEntryCount, fullscreen)) + { + return FALSE; + } + + if (!DDInit(fullscreen)) + { + return FALSE; + } + + if (!DDSetMode(width, height, bpp)) + { + return FALSE; + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009D800 +void MxDirectDraw::Destroy() +{ + DestroyButNotDirectDraw(); + + FUN_1009D920(); + + if (m_pDirectDraw != NULL) + { + m_pDirectDraw->Release(); + m_pDirectDraw = NULL; + } + + m_bIsOnPrimaryDevice = TRUE; + + if (m_pCurrentDeviceModesList != NULL) + { + delete m_pCurrentDeviceModesList; + m_pCurrentDeviceModesList = NULL; + } +} + +// OFFSET: LEGO1 0x1009D860 +void MxDirectDraw::DestroyButNotDirectDraw() +{ + RestoreOriginalPaletteEntries(); + if (m_bFullScreen) + { + if (m_pDirectDraw != NULL) + { + m_bIgnoreWM_SIZE = TRUE; + m_pDirectDraw->RestoreDisplayMode(); + m_bIgnoreWM_SIZE = FALSE; + } + } + + if (m_pPalette) + { + m_pPalette->Release(); + m_pPalette = NULL; + } + + if (m_pClipper) + { + m_pClipper->Release(); + m_pClipper = NULL; + } + + if (m_pText1Surface) + { + m_pText1Surface->Release(); + m_pText1Surface = NULL; + } + + if (m_pText2Surface) + { + m_pText2Surface->Release(); + m_pText2Surface = NULL; + } + + if (m_pZBuffer) + { + m_pZBuffer->Release(); + m_pZBuffer = NULL; + } + + if (m_pBackBuffer) + { + m_pBackBuffer->Release(); + m_pBackBuffer = NULL; + } + + if (m_pFrontBuffer) + { + m_pFrontBuffer->Release(); + m_pFrontBuffer = NULL; + } } // OFFSET: LEGO1 0x1009e6a0 -int MxDirectDraw::Pause(int) +int MxDirectDraw::Pause(int p_increment) { - // TODO - return 0; + if (p_increment) + { + m_pauseCount++; + + if (m_pauseCount > 1) + { + return TRUE; + } + + if (!RestoreOriginalPaletteEntries()) + { + return FALSE; + } + + if (m_bFullScreen) + { + if (!FlipToGDISurface()) + { + return FALSE; + } + + DrawMenuBar(m_hWndMain); + RedrawWindow(m_hWndMain, NULL, NULL, RDW_FRAME); + } + } + else + { + m_pauseCount--; + if (m_pauseCount > 0) + { + return TRUE; + } + else if (m_pauseCount < 0) + { + m_pauseCount = 0; + } + + if (!RestorePaletteEntries()) + { + return FALSE; + } + } + + return TRUE; } + +// OFFSET: LEGO1 0x1009E880 +const char* MxDirectDraw::ErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + default: + return "Unrecognized error value.\0"; + } +} + + +// OFFSET: LEGO1 0x1009D6C0 +BOOL MxDirectDraw::CacheOriginalPaletteEntries() +{ + HDC DC; + + if (g_is_PALETTEINDEXED8) + { + DC = GetDC(0); + GetSystemPaletteEntries(DC, 0, _countof(m_originalPaletteEntries), m_originalPaletteEntries); + ReleaseDC(0, DC); + } + return TRUE; +} + + +// OFFSET: LEGO1 0x1009DD80 +HRESULT MxDirectDraw::CreateDDSurface( + LPDDSURFACEDESC a2, + LPDIRECTDRAWSURFACE* a3, + IUnknown* a4) +{ + return m_pDirectDraw->CreateSurface(a2, a3, a4); +} + +// OFFSET: LEGO1 0x1009E250 +BOOL MxDirectDraw::CreateTextSurfaces() +{ + HRESULT result; + DDCOLORKEY ddck; + DDSURFACEDESC ddsd; + HDC DC; + char dummyinfo[] = "000x000x00 (RAMP) 0000"; + char dummyfps[] = "000.00 fps (000.00 fps (000.00 fps) 00000 tps)"; + + if (m_hFont != NULL) + { + DeleteObject(m_hFont); + } + + m_hFont = CreateFontA(m_currentMode.width <= 600 ? 12 : 24, + 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + VARIABLE_PITCH, + "Arial"); + + DC = GetDC(NULL); + SelectObject(DC, m_hFont); + GetTextExtentPointA(DC, dummyfps, strlen(dummyfps), &m_text1SizeOnSurface); + GetTextExtentPointA(DC, dummyinfo, strlen(dummyinfo), &m_text2SizeOnSurface); + ReleaseDC(NULL, DC); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + if (m_bOnlySystemMemory) + ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + ddsd.dwHeight = m_text1SizeOnSurface.cy; + ddsd.dwWidth = m_text1SizeOnSurface.cx; + + result = CreateDDSurface(&ddsd, &m_pText1Surface, 0); + if (result != DD_OK) + { + Error("CreateSurface for text surface 1 failed", result); + return FALSE; + } + + memset(&ddck, 0, sizeof(ddck)); + m_pText1Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); + if (!TextToTextSurface1(dummyfps)) + { + return FALSE; + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + if (m_bOnlySystemMemory) + ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + ddsd.dwHeight = m_text2SizeOnSurface.cy; + ddsd.dwWidth = m_text2SizeOnSurface.cx; + + result = CreateDDSurface(&ddsd, &m_pText2Surface, 0); + if (result != DD_OK) + { + Error("CreateSurface for text surface 2 failed", result); + return FALSE; + } + + memset(&ddck, 0, sizeof(ddck)); + m_pText2Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); + if (!TextToTextSurface2(dummyinfo)) + { + return FALSE; + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009E5E0 +BOOL MxDirectDraw::CreateZBuffer(DWORD memorytype, DWORD depth) +{ + HRESULT result; // eax + LPDIRECTDRAWSURFACE lpZBuffer; // [esp+8h] [ebp-70h] BYREF + DDSURFACEDESC ddsd; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwHeight = m_currentMode.height; + ddsd.dwWidth = m_currentMode.width; + ddsd.dwZBufferBitDepth = depth; + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_ZBUFFERBITDEPTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | memorytype; + + result = CreateDDSurface(&ddsd, &lpZBuffer, 0); + if (result != DD_OK) + { + Error("CreateSurface for fullScreen Z-buffer failed", result); + return FALSE; + } + + result = m_pBackBuffer->AddAttachedSurface(lpZBuffer); + if (result != DD_OK) + { + Error("AddAttachedBuffer failed for Z-Buffer", result); + return FALSE; + } + + m_pZBuffer = lpZBuffer; + return TRUE; +} + +// OFFSET: LEGO1 0x1009DDF0 +BOOL MxDirectDraw::DDCreateSurfaces() +{ + HRESULT result; + DDSCAPS ddscaps; + DDSURFACEDESC ddsd; + + if (m_bFlipSurfaces) + { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; + if (m_bOnlySystemMemory) + { + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_SYSTEMMEMORY; + } + ddsd.dwBackBufferCount = 1; + result = CreateDDSurface(&ddsd, &m_pFrontBuffer, 0); + if (result != DD_OK) + { + Error("CreateSurface for front/back fullScreen buffer failed", result); + return FALSE; + } + + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + result = m_pFrontBuffer->GetAttachedSurface(&ddscaps, &m_pBackBuffer); + if (result != DD_OK) + { + Error("GetAttachedSurface failed to get back buffer", result); + return FALSE; + } + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) + { + return FALSE; + } + } + else + { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + result = CreateDDSurface(&ddsd, &m_pFrontBuffer, NULL); + if (result != DD_OK) + { + Error("CreateSurface for window front buffer failed", result); + return FALSE; + } + ddsd.dwHeight = m_currentMode.height; + ddsd.dwWidth = m_currentMode.width; + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + if (m_bOnlySystemMemory) + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_SYSTEMMEMORY; + result = CreateDDSurface(&ddsd, &m_pBackBuffer, NULL); + if (result != DD_OK) + { + Error("CreateSurface for window back buffer failed", result); + return FALSE; + } + + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) + { + return FALSE; + } + + result = m_pDirectDraw->CreateClipper(0, &m_pClipper, NULL); + if (result != DD_OK) + { + Error("CreateClipper failed", result); + return FALSE; + } + result = m_pClipper->SetHWnd(0, m_hWndMain); + if (result != DD_OK) + { + Error("Clipper SetHWnd failed", result); + return FALSE; + } + result = m_pFrontBuffer->SetClipper(m_pClipper); + if (result != DD_OK) + { + Error("SetClipper failed", result); + return FALSE; + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009D960 +BOOL MxDirectDraw::DDInit(BOOL fullscreen) +{ + HRESULT result; + + if (fullscreen) + { + m_bIgnoreWM_SIZE = 1; + result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + m_bIgnoreWM_SIZE = 0; + } + else + { + result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_NORMAL); + } + + if (result != DD_OK) + { + Error("SetCooperativeLevel failed", result); + return FALSE; + } + + m_bFullScreen = fullscreen; + + return TRUE; +} + +// OFFSET: LEGO1 0x1009DA80 +BOOL MxDirectDraw::DDSetMode(int width, int height, int bpp) +{ + HRESULT result; + + if (m_bFullScreen) + { + LPDIRECTDRAW lpDD; + + EnableResizing(m_hWndMain, FALSE); + + if (!m_bIsOnPrimaryDevice) + { + lpDD = NULL; + result = DirectDrawCreate(0, &lpDD, 0); + if (result == DD_OK) + { + result = lpDD->SetCooperativeLevel(m_hWndMain, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT); + if (result == DD_OK) + { + lpDD->SetDisplayMode(width, height, 8); + } + } + } + + if (!IsSupportedMode(width, height, bpp)) + { + width = m_pCurrentDeviceModesList->m_mode_ARRAY[0].width; + height = m_pCurrentDeviceModesList->m_mode_ARRAY[0].height; + bpp = m_pCurrentDeviceModesList->m_mode_ARRAY[0].bitsPerPixel; + } + + m_bIgnoreWM_SIZE = TRUE; + result = m_pDirectDraw->SetDisplayMode(width, height, bpp); + m_bIgnoreWM_SIZE = FALSE; + if (result != DD_OK) + { + Error("SetDisplayMode failed", result); + return FALSE; + } + } + else + { + RECT rc; + DWORD dwStyle; + + if (!m_bIsOnPrimaryDevice) + { + Error("Attempt made enter a windowed mode on a DirectDraw device that is not the primary display", E_FAIL); + return FALSE; + } + + m_bIgnoreWM_SIZE = TRUE; + dwStyle = GetWindowLong(m_hWndMain, GWL_STYLE); + dwStyle &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_OVERLAPPED); + dwStyle |= WS_CAPTION | WS_THICKFRAME | WS_OVERLAPPED; + SetWindowLong(m_hWndMain, GWL_STYLE, dwStyle); + + SetRect(&rc, 0, 0, width - 1, height - 1); + AdjustWindowRectEx( + &rc, + GetWindowLong(m_hWndMain, GWL_STYLE), + GetMenu(m_hWndMain) != NULL, + GetWindowLong(m_hWndMain, GWL_EXSTYLE) + ); + SetWindowPos(m_hWndMain, NULL, 0, 0, rc.right - rc.left + 1, rc.bottom - rc.top + 1, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + SetWindowPos(m_hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + m_bIgnoreWM_SIZE = FALSE; + } + + m_currentMode.width = width; + m_currentMode.height = height; + m_currentMode.bitsPerPixel = bpp; + + if (!DDCreateSurfaces()) + { + return FALSE; + } + + DDSURFACEDESC ddsd; + + FUN_1009E020(); + + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) + { + return FALSE; + } + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + m_bPrimaryPalettized = TRUE; + } + else + { + m_bPrimaryPalettized = FALSE; + } + + if (m_bPrimaryPalettized) + { + result = m_pDirectDraw->CreatePalette( + DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, //0x4c + m_paletteEntries, + &m_pPalette, + NULL); + if (result != DD_OK) + { + Error("CreatePalette failed", result); + return 0; + } + result = m_pBackBuffer->SetPalette(m_pPalette); // TODO: add FIX_BUGS define and fix this + result = m_pFrontBuffer->SetPalette(m_pPalette); + if (result != DD_OK) + { + Error("SetPalette failed", result); + return FALSE; + } + } + + // create debug text only in windowed mode? + return m_bFullScreen || CreateTextSurfaces(); +} + +// OFFSET: LEGO1 0x1009E830 +void MxDirectDraw::Error(const char* message, int error) +{ + // OFFSET: LEGO1 0x10100C70 + static BOOL isInsideError = FALSE; + if (!isInsideError) + { + isInsideError = TRUE; + Destroy(); + if (m_pErrorHandler) + { + m_pErrorHandler(message, error, m_pErrorHandlerArg); + } + isInsideError = FALSE; + } +} + +// OFFSET: LEGO1 0x1009DDA0 +BOOL MxDirectDraw::GetDDSurfaceDesc(LPDDSURFACEDESC lpDDSurfDesc, LPDIRECTDRAWSURFACE lpDDSurf) +{ + HRESULT result; + + memset(lpDDSurfDesc, 0, sizeof(*lpDDSurfDesc)); + lpDDSurfDesc->dwSize = sizeof(*lpDDSurfDesc); + result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); + if (result != DD_OK) + { + Error("Error getting a surface description", result); + } + + return (result == DD_OK); +} + +// OFFSET: LEGO1 0x1009D9D0 +BOOL MxDirectDraw::IsSupportedMode(int width, int height, int bpp) +{ + Mode mode = { width, height, bpp }; + + for (int i = 0; i < m_pCurrentDeviceModesList->count; i++) + { + if (m_pCurrentDeviceModesList->m_mode_ARRAY[i] == mode) + { + return TRUE; + } + } + + return FALSE; +} + +// OFFSET: LEGO1 0x1009D690 +BOOL MxDirectDraw::RecreateDirectDraw(GUID** ppGUID) +{ + if (m_pDirectDraw) + { + m_pDirectDraw->Release(); + m_pDirectDraw = NULL; + } + + return (DirectDrawCreate(*ppGUID, &m_pDirectDraw, 0) == DD_OK); +} + +// OFFSET: LEGO1 0x1009E7A0 +BOOL MxDirectDraw::RestoreOriginalPaletteEntries() +{ + HRESULT result; + + if (m_bPrimaryPalettized) + { + if (m_pPalette) + { + result = m_pPalette->SetEntries(0, 0, 256, m_originalPaletteEntries); + if (result != DD_OK) + { + Error("SetEntries failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009E750 +BOOL MxDirectDraw::RestorePaletteEntries() +{ + HRESULT result; + + if (m_bFullScreen && m_bPrimaryPalettized) + { + if (m_pPalette) + { + result = m_pPalette->SetEntries(0, 0, _countof(m_paletteEntries), m_paletteEntries); + if (result != DD_OK) + { + Error("SetEntries failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009e7f0 +int MxDirectDraw::FlipToGDISurface() +{ + HRESULT ret; + + if (m_pDirectDraw) + { + ret = m_pDirectDraw->FlipToGDISurface(); + if (ret != DD_OK) + { + Error("FlipToGDISurface failed", ret); + } + return !ret; + } + + return 1; +} + +// OFFSET: LEGO1 0x1009E4D0 +BOOL MxDirectDraw::RestoreSurfaces() +{ + HRESULT result; + + if (m_pFrontBuffer != NULL) + { + if (m_pFrontBuffer->IsLost() == DDERR_SURFACELOST) + { + result = m_pFrontBuffer->Restore(); + if (result != DD_OK) + { + Error("Restore of front buffer failed", result); + return FALSE; + } + } + } + + if (m_pBackBuffer != NULL) + { + if (m_pBackBuffer->IsLost() == DDERR_SURFACELOST) + { + result = m_pBackBuffer->Restore(); + if (result != DD_OK) + { + Error("Restore of back buffer failed", result); + return FALSE; + } + } + } + + if (m_pZBuffer != NULL) + { + if (m_pZBuffer->IsLost() == DDERR_SURFACELOST) + { + result = m_pZBuffer->Restore(); + if (result != DD_OK) + { + Error("Restore of Z-buffer failed", result); + return FALSE; + } + } + } + + if (m_pText1Surface != NULL) + { + if (m_pText1Surface->IsLost() == DDERR_SURFACELOST) + { + result = m_pText1Surface->Restore(); + if (result != DD_OK) + { + Error("Restore of text surface 1 failed", result); + return FALSE; + } + } + } + + if (m_pText2Surface != NULL) + { + if (m_pText2Surface->IsLost() == DDERR_SURFACELOST) + { + result = m_pText2Surface->Restore(); + if (result != DD_OK) + { + Error("Restore of text surface 2 failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009D700 +BOOL MxDirectDraw::SetPaletteEntries( + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount, + BOOL fullscreen) +{ + int reservedLowEntryCount = 10; + int reservedHighEntryCount = 10; + int arraySize = _countof(m_paletteEntries); + HDC hdc; + int i; + + if (g_is_PALETTEINDEXED8) + { + hdc = GetDC(NULL); + GetSystemPaletteEntries(hdc, 0, arraySize, m_paletteEntries); + ReleaseDC(NULL, hdc); + } + + for (i = 0; i < reservedLowEntryCount; i++) + { + m_paletteEntries[i].peFlags = 0x80; + } + + for (i = reservedLowEntryCount; i < 142; i++) + { + m_paletteEntries[i].peFlags = 0x44; + } + + for (i = 142; i < arraySize - reservedHighEntryCount; i++) + { + m_paletteEntries[i].peFlags = 0x84; + } + + for (i = arraySize - reservedHighEntryCount; i < arraySize; i++) + { + m_paletteEntries[i].peFlags = 0x80; + } + + if (paletteEntryCount != 0) + { + for (i = reservedLowEntryCount; + (i < paletteEntryCount) && (i < arraySize - reservedHighEntryCount); + i++) + { + m_paletteEntries[i].peRed = pPaletteEntries[i].peRed; + m_paletteEntries[i].peGreen = pPaletteEntries[i].peGreen; + m_paletteEntries[i].peBlue = pPaletteEntries[i].peBlue; + } + } + + if (m_pPalette != NULL) + { + HRESULT result; + result = m_pPalette->SetEntries(0, 0, _countof(m_paletteEntries), m_paletteEntries); + if (result != DD_OK) + { + Error("SetEntries failed", result); + return FALSE; + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009E110 +BOOL MxDirectDraw::TextToTextSurface( + const char* text, + IDirectDrawSurface* pSurface, + SIZE& textSizeOnSurface) +{ + HRESULT result; + HDC hdc; + RECT rc; + size_t textLength; + + if (pSurface == NULL) + { + return FALSE; + } + + result = pSurface->GetDC(&hdc); + if (result != DD_OK) + { + Error("GetDC for text surface failed", result); + return FALSE; + } + + textLength = strlen(text); + + SelectObject(hdc, m_hFont); + SetTextColor(hdc, RGB(255, 255, 0)); + SetBkColor(hdc, RGB(0, 0, 0)); + SetBkMode(hdc, OPAQUE); + GetTextExtentPoint32(hdc, text, textLength, &textSizeOnSurface); + SetRect(&rc, 0, 0, textSizeOnSurface.cx, textSizeOnSurface.cy); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, text, textLength, NULL); + pSurface->ReleaseDC(hdc); + + return TRUE; +} + +// OFFSET: LEGO1 0x1009E210 +BOOL MxDirectDraw::TextToTextSurface1(const char* text) +{ + return TextToTextSurface( + text, + m_pText1Surface, + m_text1SizeOnSurface); +} + +// OFFSET: LEGO1 0x1009E230 +BOOL MxDirectDraw::TextToTextSurface2(const char* text) +{ + return TextToTextSurface( + text, + m_pText2Surface, + m_text2SizeOnSurface); +} + +// OFFSET: LEGO1 0x1009E020 +void MxDirectDraw::FUN_1009E020() +{ + HRESULT result; + byte* line; + DDSURFACEDESC ddsd; + int j; + int count = m_bFlipSurfaces ? 2 : 1; + + for (int i = 0; i < count; i++) + { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); + if (result == DDERR_SURFACELOST) + { + m_pBackBuffer->Restore(); + result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); + } + + if (result != DD_OK) + { + // lock failed + return; + } + + // clear backBuffer + line = (byte*)ddsd.lpSurface; + for (j = ddsd.dwHeight; j-- ;) + { + memset(line, 0, ddsd.dwWidth); + line += ddsd.lPitch; + } + + m_pBackBuffer->Unlock(ddsd.lpSurface); + + + if (m_bFlipSurfaces) + { + m_pFrontBuffer->Flip(NULL, DDFLIP_WAIT); + } + } +} + +// OFFSET: LEGO1 0x1009D920 +void MxDirectDraw::FUN_1009D920() +{ + RestoreOriginalPaletteEntries(); + if (m_pDirectDraw != NULL) + { + m_bIgnoreWM_SIZE = TRUE; + m_pDirectDraw->RestoreDisplayMode(); + m_pDirectDraw->SetCooperativeLevel(NULL, DDSCL_NORMAL); + m_bIgnoreWM_SIZE = FALSE; + } +} + diff --git a/LEGO1/mxdirectdraw.h b/LEGO1/mxdirectdraw.h index 04f73dde..2024a3ac 100644 --- a/LEGO1/mxdirectdraw.h +++ b/LEGO1/mxdirectdraw.h @@ -1,12 +1,130 @@ + #ifndef MXDIRECTDRAW_H #define MXDIRECTDRAW_H +#include +#include + +extern BOOL g_is_PALETTEINDEXED8; + +//size 0x880 class MxDirectDraw { +public: + typedef void (*ErrorHandler)(const char*, HRESULT, void*); + + //size 0x0c + struct Mode + { + int width; + int height; + int bitsPerPixel; + + int operator==(const Mode& rMode) const + { + return ((width == rMode.width) && + (height == rMode.height) && + (bitsPerPixel == rMode.bitsPerPixel)); + } + }; + + //size 0x17c + struct DeviceModesInfo + { + GUID* p_guid; + Mode* m_mode_ARRAY; + int count; + DDCAPS m_ddcaps; + void* a_178; + + ~DeviceModesInfo(); + }; + + +private: + BOOL m_bOnlySoftRender; + BOOL m_bFlipSurfaces; + IDirectDraw* m_pDirectDraw; + IDirectDrawSurface* m_pFrontBuffer; + IDirectDrawSurface* m_pBackBuffer; + IDirectDrawSurface* m_pZBuffer; + IDirectDrawSurface* m_pText1Surface; + IDirectDrawSurface* m_pText2Surface; + IDirectDrawClipper* m_pClipper; + IDirectDrawPalette* m_pPalette; + PALETTEENTRY m_paletteEntries[256]; + PALETTEENTRY m_originalPaletteEntries[256]; + SIZE m_text1SizeOnSurface; + SIZE m_text2SizeOnSurface; + HWND m_hWndMain; + HFONT m_hFont; + BOOL m_bIgnoreWM_SIZE; + BOOL m_bPrimaryPalettized; + BOOL m_bFullScreen; + void* a_850; + BOOL m_bOnlySystemMemory; + BOOL m_bIsOnPrimaryDevice; + ErrorHandler m_pErrorHandler; + ErrorHandler m_pFatalErrorHandler; + void* m_pErrorHandlerArg; + void* m_pFatalErrorHandlerArg; + int m_pauseCount; + DeviceModesInfo* m_pCurrentDeviceModesList; + Mode m_currentMode; + public: __declspec(dllexport) int FlipToGDISurface(); __declspec(dllexport) static int GetPrimaryBitDepth(); __declspec(dllexport) int Pause(int); + + MxDirectDraw(); + + virtual ~MxDirectDraw(); + virtual BOOL Create( + HWND hWnd, + BOOL fullscreen_1, + BOOL surface_fullscreen, + BOOL onlySystemMemory, + int width, + int height, + int bpp, + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount); + virtual void Destroy(); + virtual void DestroyButNotDirectDraw(); + virtual const char* ErrorToString(HRESULT error); + +private: + BOOL CacheOriginalPaletteEntries(); + HRESULT CreateDDSurface( + LPDDSURFACEDESC a2, + LPDIRECTDRAWSURFACE* a3, + IUnknown* a4); + BOOL CreateTextSurfaces(); + BOOL CreateZBuffer(DWORD memorytype, DWORD depth); + BOOL DDCreateSurfaces(); + BOOL DDInit(BOOL fullscreen); + BOOL DDSetMode(int width, int height, int bpp); + void Error(const char* message, int error); + + BOOL GetDDSurfaceDesc(LPDDSURFACEDESC lpDDSurfDesc, LPDIRECTDRAWSURFACE lpDDSurf); + BOOL IsSupportedMode(int width, int height, int bpp); + BOOL RecreateDirectDraw(GUID** a2); + BOOL RestoreOriginalPaletteEntries(); + BOOL RestorePaletteEntries(); + BOOL RestoreSurfaces(); + BOOL SetPaletteEntries( + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount, + BOOL fullscreen); + BOOL TextToTextSurface( + const char* text, + IDirectDrawSurface* pSurface, + SIZE& textSizeOnSurface); + BOOL TextToTextSurface1(const char* text); + BOOL TextToTextSurface2(const char* lpString); + void FUN_1009E020(); + void FUN_1009D920(); }; #endif // MXDIRECTDRAW_H diff --git a/LEGO1/mxdisplaysurface.cpp b/LEGO1/mxdisplaysurface.cpp new file mode 100644 index 00000000..edf1cb1a --- /dev/null +++ b/LEGO1/mxdisplaysurface.cpp @@ -0,0 +1,136 @@ +#include "mxdisplaysurface.h" + +DECOMP_SIZE_ASSERT(MxDisplaySurface, 0xac); + +// OFFSET: LEGO1 0x100ba500 +MxDisplaySurface::MxDisplaySurface() +{ + this->Reset(); +} + +// OFFSET: LEGO1 0x100ba5a0 +MxDisplaySurface::~MxDisplaySurface() +{ + this->Clear(); +} + +// OFFSET: LEGO1 0x100ba610 +void MxDisplaySurface::Reset() +{ + this->m_ddSurface1 = NULL; + this->m_ddSurface2 = NULL; + this->m_ddClipper = NULL; + this->m_16bitPal = NULL; + this->m_initialized = FALSE; + memset(&this->m_surfaceDesc, 0, sizeof(this->m_surfaceDesc)); +} + +// OFFSET: LEGO1 0x100ba790 +MxResult MxDisplaySurface::Init(MxVideoParam &p_videoParam, LPDIRECTDRAWSURFACE p_ddSurface1, LPDIRECTDRAWSURFACE p_ddSurface2, LPDIRECTDRAWCLIPPER p_ddClipper) +{ + MxResult result = SUCCESS; + + this->m_videoParam = p_videoParam; + this->m_ddSurface1 = p_ddSurface1; + this->m_ddSurface2 = p_ddSurface2; + this->m_ddClipper = p_ddClipper; + this->m_initialized = FALSE; + + memset(&this->m_surfaceDesc, 0, sizeof(this->m_surfaceDesc)); + this->m_surfaceDesc.dwSize = sizeof(this->m_surfaceDesc); + + if (this->m_ddSurface2->GetSurfaceDesc(&this->m_surfaceDesc)) + result = FAILURE; + + return result; +} + +// OFFSET: LEGO1 0x100ba7f0 STUB +MxResult MxDisplaySurface::Create(MxVideoParam *p_videoParam) +{ + return 0; +} + +// OFFSET: LEGO1 0x100baa90 +void MxDisplaySurface::Clear() +{ + if (this->m_initialized) { + if (this->m_ddSurface2) + this->m_ddSurface2->Release(); + + if (this->m_ddSurface1) + this->m_ddSurface1->Release(); + + if (this->m_ddClipper) + this->m_ddClipper->Release(); + } + + if (this->m_16bitPal) + delete this->m_16bitPal; + + this->Reset(); +} + +// OFFSET: LEGO1 0x100baae0 STUB +void MxDisplaySurface::SetPalette(MxPalette *p_palette) +{ + +} + +// OFFSET: LEGO1 0x100bc200 STUB +void MxDisplaySurface::vtable24(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4) +{ + +} + +// OFFSET: LEGO1 0x100bacc0 STUB +MxBool MxDisplaySurface::vtable28(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4) +{ + return 0; +} + +// OFFSET: LEGO1 0x100bc630 STUB +MxBool MxDisplaySurface::vtable2c(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, MxBool) +{ + return 0; +} + +// OFFSET: LEGO1 0x100bb1d0 STUB +MxBool MxDisplaySurface::vtable30(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, MxBool) +{ + return 0; +} + +// OFFSET: LEGO1 0x100bb850 STUB +undefined4 MxDisplaySurface::vtable34(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4) +{ + return 0; +} + +// OFFSET: LEGO1 0x100bba50 STUB +void MxDisplaySurface::Display(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4) +{ + +} + +// OFFSET: LEGO1 0x100bbc10 +void MxDisplaySurface::GetDC(HDC *p_hdc) +{ + if (this->m_ddSurface2 && !this->m_ddSurface2->GetDC(p_hdc)) + return; + + *p_hdc = NULL; +} + +// OFFSET: LEGO1 0x100bbc40 +void MxDisplaySurface::ReleaseDC(HDC p_hdc) +{ + if (this->m_ddSurface2 && p_hdc) + this->m_ddSurface2->ReleaseDC(p_hdc); +} + +// OFFSET: LEGO1 0x100bbc60 STUB +undefined4 MxDisplaySurface::vtable44(undefined4, undefined4*, undefined4, undefined4) +{ + return 0; +} diff --git a/LEGO1/mxdisplaysurface.h b/LEGO1/mxdisplaysurface.h index 9da02fda..aef3d5d5 100644 --- a/LEGO1/mxdisplaysurface.h +++ b/LEGO1/mxdisplaysurface.h @@ -10,13 +10,16 @@ #include "decomp.h" // VTABLE 0x100dc768 +// SIZE 0xac class MxDisplaySurface : public MxCore { public: MxDisplaySurface(); virtual ~MxDisplaySurface() override; - virtual MxResult Init(MxVideoParam *p_videoParam, LPDIRECTDRAWSURFACE p_surface1, LPDIRECTDRAWSURFACE p_surface2, LPDIRECTDRAWCLIPPER p_clipper); + void Reset(); + + virtual MxResult Init(MxVideoParam &p_videoParam, LPDIRECTDRAWSURFACE p_ddSurface1, LPDIRECTDRAWSURFACE p_ddSurface2, LPDIRECTDRAWCLIPPER p_ddClipper); virtual MxResult Create(MxVideoParam *p_videoParam); virtual void Clear(); virtual void SetPalette(MxPalette *p_palette); @@ -26,9 +29,18 @@ class MxDisplaySurface : public MxCore virtual MxBool vtable30(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, MxBool); virtual undefined4 vtable34(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4); virtual void Display(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4); - virtual undefined4 vtable3c(undefined4*); - virtual undefined4 vtable40(undefined4); + virtual void GetDC(HDC *p_hdc); + virtual void ReleaseDC(HDC p_hdc); virtual undefined4 vtable44(undefined4, undefined4*, undefined4, undefined4); + +private: + MxVideoParam m_videoParam; + LPDIRECTDRAWSURFACE m_ddSurface1; + LPDIRECTDRAWSURFACE m_ddSurface2; + LPDIRECTDRAWCLIPPER m_ddClipper; + MxBool m_initialized; + DDSURFACEDESC m_surfaceDesc; + MxU16 *m_16bitPal; }; #endif // MXDISPLAYSURFACE_H diff --git a/LEGO1/mxentity.cpp b/LEGO1/mxentity.cpp index cb49f256..65adad67 100644 --- a/LEGO1/mxentity.cpp +++ b/LEGO1/mxentity.cpp @@ -1,5 +1,7 @@ #include "mxentity.h" +DECOMP_SIZE_ASSERT(MxEntity, 0x68) + // OFFSET: LEGO1 0x1001d190 MxEntity::MxEntity() { @@ -17,4 +19,4 @@ MxResult MxEntity::SetEntityId(MxS32 p_id, const MxAtomId &p_atom) this->m_mxEntityId = p_id; this->m_atom = p_atom; return SUCCESS; -} \ No newline at end of file +} diff --git a/LEGO1/mxentity.h b/LEGO1/mxentity.h index 6c98782d..25e74d1b 100644 --- a/LEGO1/mxentity.h +++ b/LEGO1/mxentity.h @@ -1,11 +1,13 @@ #ifndef MXENTITY_H #define MXENTITY_H +#include "decomp.h" #include "mxatomid.h" #include "mxcore.h" #include "mxtypes.h" // VTABLE 0x100d5390 +// SIZE 0x68 or less class MxEntity : public MxCore { public: @@ -29,6 +31,7 @@ class MxEntity : public MxCore private: MxS32 m_mxEntityId; // 0x8 MxAtomId m_atom; // 0xc + undefined m_unk10[0x58]; }; #endif // MXENTITY_H diff --git a/LEGO1/mxmatrix.cpp b/LEGO1/mxmatrix.cpp new file mode 100644 index 00000000..534db6a9 --- /dev/null +++ b/LEGO1/mxmatrix.cpp @@ -0,0 +1,188 @@ + +#include "mxmatrix.h" + +#include +#include "math.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxMatrix, 0x8); +DECOMP_SIZE_ASSERT(MxMatrixData, 0x48); + +// OFFSET: LEGO1 0x10002340 +void MxMatrix::EqualsMxMatrix(const MxMatrix *p_other) +{ + memcpy(m_data, p_other->m_data, 16 * sizeof(float)); +} + +// OFFSET: LEGO1 0x10002320 +void MxMatrix::EqualsMatrixData(const float *p_matrix) +{ + memcpy(m_data, p_matrix, 16 * sizeof(float)); +} + +// OFFSET: LEGO1 0x10002370 +void MxMatrix::SetData(float *p_data) +{ + m_data = p_data; +} + +// OFFSET: LEGO1 0x10002360 +void MxMatrix::AnotherSetData(float *p_data) +{ + m_data = p_data; +} + +// OFFSET: LEGO1 0x10002390 +float *MxMatrix::GetData() +{ + return m_data; +} + +// OFFSET: LEGO1 0x10002380 +const float *MxMatrix::GetData() const +{ + return m_data; +} + +// OFFSET: LEGO1 0x100023c0 +float *MxMatrix::Element(int p_row, int p_col) +{ + return &m_data[p_row * 4 + p_col]; +} + +// OFFSET: LEGO1 0x100023a0 +const float *MxMatrix::Element(int p_row, int p_col) const +{ + return &m_data[p_row * 4 + p_col]; +} + +// OFFSET: LEGO1 0x100023e0 +void MxMatrix::Clear() +{ + memset(m_data, 0, 16 * sizeof(float)); +} + +// OFFSET: LEGO1 0x100023f0 +void MxMatrix::SetIdentity() +{ + Clear(); + m_data[0] = 1.0f; + m_data[5] = 1.0f; + m_data[10] = 1.0f; + m_data[15] = 1.0f; +} + +// OFFSET: LEGO1 0x10002850 +void MxMatrix::operator=(const MxMatrix& p_other) +{ + EqualsMxMatrix(&p_other); +} + +// OFFSET: LEGO1 0x10002430 +MxMatrix* MxMatrix::operator+=(const float *p_matrix) +{ + for (int i = 0; i < 16; ++i) + m_data[i] += p_matrix[i]; + return this; +} + +// Matches but instructions are significantly out of order. Probably not wrong +// code given that the very similar SetTranslation does match. +// OFFSET: LEGO1 0x10002460 +void MxMatrix::TranslateBy(const float *p_x, const float *p_y, const float *p_z) +{ + m_data[12] += *p_x; + m_data[13] += *p_y; + m_data[14] += *p_z; +} + +// OFFSET: LEGO1 0x100024a0 +void MxMatrix::SetTranslation(const float *p_x, const float *p_y, const float *p_z) +{ + m_data[12] = *p_x; + m_data[13] = *p_y; + m_data[14] = *p_z; +} + +// OFFSET: LEGO1 0x10002530 +void MxMatrix::EqualsMxProduct(const MxMatrix *p_a, const MxMatrix *p_b) +{ + EqualsDataProduct(p_a->m_data, p_b->m_data); +} + +// Just a placeholder matrix multiply implementation. I think the decomp will +// look roughly like this but it's not close to matching and won't be until +// an exact match is found given it's all loop and float crunching. +// OFFSET: LEGO1 0x100024d0 STUB +void MxMatrix::EqualsDataProduct(const float *p_a, const float *p_b) +{ + for (int row = 0; row < 4; ++row) + { + for (int col = 0; col < 4; ++col) + { + m_data[row * 4 + col] = 0.0f; + for (int k = 0; k < 4; ++k) + { + m_data[row * 4 + col] += p_a[row * 4 + k] * p_b[k * 4 + col]; + } + } + } +} + +// Not close, Ghidra struggles understinging this method so it will have to +// be manually worked out. Included since I at least figured out what it was +// doing with rotateIndex and what overall operation it's trying to do. +// OFFSET: LEGO1 0x10002550 STUB +void MxMatrix::ToQuaternion(MxVector4 *p_outQuat) +{ + float trace = m_data[0] + m_data[5] + m_data[10]; + if (trace > 0) + { + trace = sqrt(trace + 1.0); + p_outQuat->GetData()[3] = trace * 0.5f; + p_outQuat->GetData()[0] = (m_data[9] - m_data[6]) * trace; + p_outQuat->GetData()[1] = (m_data[2] - m_data[8]) * trace; + p_outQuat->GetData()[2] = (m_data[4] - m_data[1]) * trace; + return; + } + + // OFFSET: LEGO1 0x100d4090 + static int rotateIndex[] = {1, 2, 0}; + + // Largest element along the trace + int largest = m_data[0] < m_data[5]; + if (*Element(largest, largest) < m_data[10]) + largest = 2; + + int next = rotateIndex[largest]; + int nextNext = rotateIndex[next]; + float valueA = *Element(nextNext, nextNext); + float valueB = *Element(next, next); + float valueC = *Element(largest, largest); + + // Above is somewhat decomped, below is pure speculation since the automatic + // decomp becomes very garbled. + float traceValue = sqrt(valueA - valueB - valueC + 1.0); + + p_outQuat->GetData()[largest] = traceValue * 0.5f; + traceValue = 0.5f / traceValue; + + p_outQuat->GetData()[3] = (m_data[next + 4 * nextNext] - m_data[nextNext + 4 * next]) * traceValue; + p_outQuat->GetData()[next] = (m_data[next + 4 * largest] + m_data[largest + 4 * next]) * traceValue; + p_outQuat->GetData()[nextNext] = (m_data[nextNext + 4 * largest] + m_data[largest + 4 * nextNext]) * traceValue; +} + +// No idea what this function is doing and it will be hard to tell until +// we have a confirmed usage site. +// OFFSET: LEGO1 0x10002710 STUB +MxResult MxMatrix::DoSomethingWithLength(const MxVector3 *p_vec) +{ + return FAILURE; +} + +// OFFSET: LEGO1 0x10002860 +void MxMatrixData::operator=(const MxMatrixData& p_other) +{ + EqualsMxMatrix(&p_other); +} diff --git a/LEGO1/mxmatrix.h b/LEGO1/mxmatrix.h new file mode 100644 index 00000000..0dcb20cb --- /dev/null +++ b/LEGO1/mxmatrix.h @@ -0,0 +1,70 @@ +#ifndef MXMATRIX_H +#define MXMATRIX_H + +#include "mxvector.h" + +// VTABLE 0x100d4350 +// SIZE 0x8 +class MxMatrix +{ +public: + inline MxMatrix(float *p_data) : m_data(p_data) {} + + // vtable + 0x00 + virtual void EqualsMxMatrix(const MxMatrix *p_other); + virtual void EqualsMatrixData(const float *p_matrix); + virtual void SetData(float *p_data); + virtual void AnotherSetData(float *p_data); + + // vtable + 0x10 + virtual float *GetData(); + virtual const float *GetData() const; + virtual float *Element(int p_row, int p_col); + virtual const float *Element(int p_row, int p_col) const; + + // vtable + 0x20 + virtual void Clear(); + virtual void SetIdentity(); + virtual void operator=(const MxMatrix& p_other); + virtual MxMatrix *operator+=(const float *p_matrix); + + // vtable + 0x30 + virtual void TranslateBy(const float *p_x, const float *p_y, const float *p_z); + virtual void SetTranslation(const float *p_x, const float *p_y, const float *p_z); + virtual void EqualsMxProduct(const MxMatrix *p_a, const MxMatrix *p_b); + virtual void EqualsDataProduct(const float *p_a, const float *p_b); + + // vtable + 0x40 + virtual void ToQuaternion(MxVector4 *p_resultQuat); + virtual MxResult DoSomethingWithLength(const MxVector3 *p_vec); + +private: + float *m_data; +}; + +// VTABLE 0x100d4300 +// SIZE 0x48 +class MxMatrixData : public MxMatrix +{ +public: + inline MxMatrixData() : MxMatrix(e) {} + + // No idea why there's another equals. Maybe to some other type like the + // DirectX Retained Mode Matrix type which is also a float* alias? + // vtable + 0x44 + virtual void operator=(const MxMatrixData& p_other); + + // Alias an easy way to access the translation part of the matrix, because + // various members / other functions benefit from the clarity. + union + { + float e[16]; + struct + { + float _[12]; + float x, y, z, w; + }; + }; +}; + +#endif // MXMATRIX_H \ No newline at end of file diff --git a/LEGO1/mxnotificationmanager.cpp b/LEGO1/mxnotificationmanager.cpp index b7d001aa..fe48c7c2 100644 --- a/LEGO1/mxnotificationmanager.cpp +++ b/LEGO1/mxnotificationmanager.cpp @@ -41,7 +41,7 @@ MxNotificationManager::~MxNotificationManager() delete m_queue; m_queue = NULL; - TickleManager()->Unregister(this); + TickleManager()->UnregisterClient(this); } // OFFSET: LEGO1 0x100ac800 @@ -80,7 +80,7 @@ MxResult MxNotificationManager::Create(MxS32 p_unk1, MxS32 p_unk2) result = FAILURE; } else { - TickleManager()->Register(this, 10); + TickleManager()->RegisterClient(this, 10); } return result; diff --git a/LEGO1/mxticklemanager.cpp b/LEGO1/mxticklemanager.cpp new file mode 100644 index 00000000..38cdd37f --- /dev/null +++ b/LEGO1/mxticklemanager.cpp @@ -0,0 +1,113 @@ +#include "mxomni.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxtypes.h" + +#include "decomp.h" + +#define TICKLE_MANAGER_FLAG_DESTROY 0x1 + +DECOMP_SIZE_ASSERT(MxTickleClient, 0x10); +DECOMP_SIZE_ASSERT(MxTickleManager, 0x14); + +// OFFSET: LEGO1 0x100bdd10 +MxTickleClient::MxTickleClient(MxCore *p_client, MxTime p_interval) +{ + m_flags = 0; + m_client = p_client; + m_interval = p_interval; + m_lastUpdateTime = -m_interval; +} + +// OFFSET: LEGO1 0x100bdd30 +MxTickleManager::~MxTickleManager() +{ + while (m_clients.size() != 0) { + MxTickleClient *client = m_clients.front(); + m_clients.pop_front(); + delete client; + } +} + +// TODO: Match. +// OFFSET: LEGO1 0x100bdde0 +MxResult MxTickleManager::Tickle() +{ + MxTime time = Timer()->GetTime(); + + MxTickleClientPtrList::iterator it = m_clients.begin(); + + while (it != m_clients.end()) { + MxTickleClient *client = *it; + if ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0) { + if (client->GetLastUpdateTime() >= time) + client->SetLastUpdateTime(-client->GetTickleInterval()); + + if ((client->GetTickleInterval() + client->GetLastUpdateTime()) < time) { + client->GetClient()->Tickle(); + client->SetLastUpdateTime(time); + } + + it++; + } + else { + m_clients.erase(it++); + delete client; + } + } + + return SUCCESS; +} + +// OFFSET: LEGO1 0x100bde80 +void MxTickleManager::RegisterClient(MxCore *p_client, MxTime p_interval) +{ + MxTime interval = GetClientTickleInterval(p_client); + if (interval == TICKLE_MANAGER_NOT_FOUND) { + MxTickleClient *client = new MxTickleClient(p_client, p_interval); + if (client != NULL) + m_clients.push_back(client); + } +} + +// OFFSET: LEGO1 0x100bdf60 +void MxTickleManager::UnregisterClient(MxCore *p_client) +{ + MxTickleClientPtrList::iterator it = m_clients.begin(); + while (it != m_clients.end()) { + MxTickleClient *client = *it; + if (client->GetClient() == p_client) { + client->SetFlags(client->GetFlags() | TICKLE_MANAGER_FLAG_DESTROY); + return; + } + + it++; + } +} + +// OFFSET: LEGO1 0x100bdfa0 +void MxTickleManager::SetClientTickleInterval(MxCore *p_client, MxTime p_interval) +{ + for (MxTickleClientPtrList::iterator it = m_clients.begin(); it != m_clients.end(); it++) { + MxTickleClient *client = *it; + if ((client->GetClient() == p_client) && ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0)) { + client->SetTickleInterval(p_interval); + return; + } + } +} + +// OFFSET: LEGO1 0x100be000 +MxTime MxTickleManager::GetClientTickleInterval(MxCore *p_client) +{ + MxTickleClientPtrList::iterator it = m_clients.begin(); + while (it != m_clients.end()) { + MxTickleClient *client = *it; + if ((client->GetClient() == p_client) && ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0)) + return client->GetTickleInterval(); + + it++; + } + + return TICKLE_MANAGER_NOT_FOUND; +} diff --git a/LEGO1/mxticklemanager.h b/LEGO1/mxticklemanager.h index 3d976d5a..103d3721 100644 --- a/LEGO1/mxticklemanager.h +++ b/LEGO1/mxticklemanager.h @@ -2,20 +2,77 @@ #define MXTICKLEMANAGER_H #include "mxcore.h" +#include "mxtypes.h" + +#include "compat.h" + +class MxTickleClient +{ +public: + MxTickleClient(MxCore *p_client, MxTime p_interval); + + inline MxCore *GetClient() const + { + return m_client; + } + + inline MxTime GetTickleInterval() const + { + return m_interval; + } + + inline MxTime GetLastUpdateTime() const + { + return m_lastUpdateTime; + } + + inline MxU16 GetFlags() const + { + return m_flags; + } + + inline void SetTickleInterval(MxTime p_interval) + { + m_interval = p_interval; + } + + inline void SetLastUpdateTime(MxTime p_lastUpdateTime) + { + m_lastUpdateTime = p_lastUpdateTime; + } + + inline void SetFlags(MxU16 flags) + { + m_flags = flags; + } + +private: + MxCore *m_client; // 0x0 + MxTime m_interval; // 0x4 + MxTime m_lastUpdateTime; // 0x8 + MxU16 m_flags; // 0xc +}; + +class MxTickleClientPtrList : public List +{}; // VTABLE 0x100d86d8 class MxTickleManager : public MxCore { public: - virtual ~MxTickleManager(); + inline MxTickleManager() : MxCore(), m_clients() {} + virtual ~MxTickleManager(); // vtable+0x0 (scalar deleting destructor) - virtual MxLong Tickle(); - virtual const char *ClassName() const; - virtual MxBool IsA(const char *name) const; - virtual void Register(MxCore *p_listener, int p_milliseconds); - virtual void Unregister(MxCore *p_listener); - virtual void vtable1c(void *v, int p); - virtual void vtable20(); + virtual MxResult Tickle(); // vtable+0x8 + virtual void RegisterClient(MxCore *p_client, MxTime p_interval); // vtable+0x14 + virtual void UnregisterClient(MxCore *p_client); // vtable+0x18 + virtual void SetClientTickleInterval(MxCore *p_client, MxTime p_interval); // vtable+0x1c + virtual MxTime GetClientTickleInterval(MxCore *p_client); // vtable+0x20 + +private: + MxTickleClientPtrList m_clients; // 0x8 }; +#define TICKLE_MANAGER_NOT_FOUND 0x80000000 + #endif // MXTICKLEMANAGER_H diff --git a/LEGO1/mxtypes.h b/LEGO1/mxtypes.h index d17ac09a..1f0aaac7 100644 --- a/LEGO1/mxtypes.h +++ b/LEGO1/mxtypes.h @@ -25,6 +25,8 @@ typedef int MxLong; typedef unsigned int MxULong; #endif +typedef MxS32 MxTime; + typedef MxLong MxResult; const MxResult SUCCESS = 0; const MxResult FAILURE = -1; diff --git a/LEGO1/mxvector.cpp b/LEGO1/mxvector.cpp new file mode 100644 index 00000000..80ca1a17 --- /dev/null +++ b/LEGO1/mxvector.cpp @@ -0,0 +1,466 @@ + +#include "mxvector.h" + +#include +#include + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxVector2, 0x8); +DECOMP_SIZE_ASSERT(MxVector3, 0x8); +DECOMP_SIZE_ASSERT(MxVector4, 0x8); +DECOMP_SIZE_ASSERT(MxVector3Data, 0x14); +DECOMP_SIZE_ASSERT(MxVector4Data, 0x18); + +// OFFSET: LEGO1 0x10002060 +void MxVector2::SetData(float *p_data) +{ + m_data = p_data; +} + +// OFFSET: LEGO1 0x100020a0 +const float *MxVector2::GetData() const +{ + return m_data; +} + +// OFFSET: LEGO1 0x10002090 +float *MxVector2::GetData() +{ + return m_data; +} + +// OFFSET: LEGO1 0x10002130 +float MxVector2::Dot(MxVector2 *p_a, float *p_b) const +{ + return DotImpl(p_a->m_data, p_b); +} + +// OFFSET: LEGO1 0x10002110 +float MxVector2::Dot(float *p_a, MxVector2 *p_b) const +{ + return DotImpl(p_a, p_b->m_data); +} + +// OFFSET: LEGO1 0x100020f0 +float MxVector2::Dot(MxVector2 *p_a, MxVector2 *p_b) const +{ + return DotImpl(p_a->m_data, p_b->m_data); +} + +// OFFSET: LEGO1 0x100020d0 +float MxVector2::Dot(float *p_a, float *p_b) const +{ + return DotImpl(p_a, p_b); +} + +// OFFSET: LEGO1 0x10002160 +MxResult MxVector2::Unitize() +{ + float sq = LenSquared(); + if (sq > 0.0f) + { + float root = sqrt(sq); + if (root > 0) + { + DivScalarImpl(&root); + return SUCCESS; + } + } + return FAILURE; +} + +// OFFSET: LEGO1 0x100021e0 +void MxVector2::AddVector(MxVector2 *p_other) +{ + AddVectorImpl(p_other->m_data); +} + +// OFFSET: LEGO1 0x100021d0 +void MxVector2::AddVector(float *p_other) +{ + AddVectorImpl(p_other); +} + +// OFFSET: LEGO1 0x100021c0 +void MxVector2::AddScalar(float p_value) +{ + AddScalarImpl(p_value); +} + +// OFFSET: LEGO1 0x10002200 +void MxVector2::SubVector(MxVector2 *p_other) +{ + SubVectorImpl(p_other->m_data); +} + +// OFFSET: LEGO1 0x100021f0 +void MxVector2::SubVector(float *p_other) +{ + SubVectorImpl(p_other); +} + +// OFFSET: LEGO1 0x10002230 +void MxVector2::MullScalar(float *p_value) +{ + MullScalarImpl(p_value); +} + +// OFFSET: LEGO1 0x10002220 +void MxVector2::MullVector(MxVector2 *p_other) +{ + MullVectorImpl(p_other->m_data); +} + +// OFFSET: LEGO1 0x10002210 +void MxVector2::MullVector(float *p_other) +{ + MullVectorImpl(p_other); +} + +// OFFSET: LEGO1 0x10002240 +void MxVector2::DivScalar(float *p_value) +{ + DivScalarImpl(p_value); +} + +// OFFSET: LEGO1 0x10002260 +void MxVector2::SetVector(MxVector2 *p_other) +{ + EqualsImpl(p_other->m_data); +} + +// OFFSET: LEGO1 0x10002250 +void MxVector2::SetVector(float *p_other) +{ + EqualsImpl(p_other); +} + +// OFFSET: LEGO1 0x10001fa0 +void MxVector2::AddScalarImpl(float p_value) +{ + m_data[0] += p_value; + m_data[1] += p_value; +} + +// OFFSET: LEGO1 0x10001f80 +void MxVector2::AddVectorImpl(float *p_value) +{ + m_data[0] += p_value[0]; + m_data[1] += p_value[1]; +} + +// OFFSET: LEGO1 0x10001fc0 +void MxVector2::SubVectorImpl(float *p_value) +{ + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; +} + +// OFFSET: LEGO1 0x10002000 +void MxVector2::MullScalarImpl(float *p_value) +{ + m_data[0] *= *p_value; + m_data[1] *= *p_value; +} + +// OFFSET: LEGO1 0x10001fe0 +void MxVector2::MullVectorImpl(float *p_value) +{ + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; +} + +// OFFSET: LEGO1 0x10002020 +void MxVector2::DivScalarImpl(float *p_value) +{ + m_data[0] /= *p_value; + m_data[1] /= *p_value; +} + +// OFFSET: LEGO1 0x10002040 +float MxVector2::DotImpl(float *p_a, float *p_b) const +{ + return p_b[0] * p_a[0] + p_b[1] * p_a[1]; +} + +// OFFSET: LEGO1 0x10002070 +void MxVector2::EqualsImpl(float *p_data) +{ + float *vec = m_data; + vec[0] = p_data[0]; + vec[1] = p_data[1]; +} + +// OFFSET: LEGO1 0x100020b0 +void MxVector2::Clear() +{ + float *vec = m_data; + vec[0] = 0.0f; + vec[1] = 0.0f; +} + +// OFFSET: LEGO1 0x10002150 +float MxVector2::LenSquared() const +{ + return m_data[0] * m_data[0] + m_data[1] * m_data[1]; +} + +// OFFSET: LEGO1 0x10003a90 +void MxVector3::AddScalarImpl(float p_value) +{ + m_data[0] += p_value; + m_data[1] += p_value; + m_data[2] += p_value; +} + +// OFFSET: LEGO1 0x10003a60 +void MxVector3::AddVectorImpl(float *p_value) +{ + m_data[0] += p_value[0]; + m_data[1] += p_value[1]; + m_data[2] += p_value[2]; +} + +// OFFSET: LEGO1 0x10003ac0 +void MxVector3::SubVectorImpl(float *p_value) +{ + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; + m_data[2] -= p_value[2]; +} + +// OFFSET: LEGO1 0x10003b20 +void MxVector3::MullScalarImpl(float *p_value) +{ + m_data[0] *= *p_value; + m_data[1] *= *p_value; + m_data[2] *= *p_value; +} + +// OFFSET: LEGO1 0x10003af0 +void MxVector3::MullVectorImpl(float *p_value) +{ + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; + m_data[2] *= p_value[2]; +} + +// OFFSET: LEGO1 0x10003b50 +void MxVector3::DivScalarImpl(float *p_value) +{ + m_data[0] /= *p_value; + m_data[1] /= *p_value; + m_data[2] /= *p_value; +} + +// OFFSET: LEGO1 0x10003b80 +float MxVector3::DotImpl(float *p_a, float *p_b) const +{ + return p_a[0] * p_b[0] + p_a[2] * p_b[2] + p_a[1] * p_b[1]; +} + +// OFFSET: LEGO1 0x10003ba0 +void MxVector3::EqualsImpl(float *p_data) +{ + float *vec = m_data; + vec[0] = p_data[0]; + vec[1] = p_data[1]; + vec[2] = p_data[2]; +} + +// OFFSET: LEGO1 0x10003bc0 +void MxVector3::Clear() +{ + float *vec = m_data; + vec[0] = 0.0f; + vec[1] = 0.0f; + vec[2] = 0.0f; +} + +// OFFSET: LEGO1 0x10003bd0 +float MxVector3::LenSquared() const +{ + return m_data[1] * m_data[1] + m_data[0] * m_data[0] + m_data[2] * m_data[2]; +} + +// OFFSET: LEGO1 0x10002270 +void MxVector3::EqualsCrossImpl(float* p_a, float* p_b) +{ + m_data[0] = p_a[1] * p_b[2] - p_a[2] * p_b[1]; + m_data[1] = p_a[2] * p_b[0] - p_a[0] * p_b[2]; + m_data[2] = p_a[0] * p_b[1] - p_a[1] * p_b[0]; +} + +// OFFSET: LEGO1 0x10002300 +void MxVector3::EqualsCross(float *p_a, MxVector3 *p_b) +{ + EqualsCrossImpl(p_a, p_b->m_data); +} + +// OFFSET: LEGO1 0x100022e0 +void MxVector3::EqualsCross(MxVector3 *p_a, float *p_b) +{ + EqualsCrossImpl(p_a->m_data, p_b); +} + +// OFFSET: LEGO1 0x100022c0 +void MxVector3::EqualsCross(MxVector3 *p_a, MxVector3 *p_b) +{ + EqualsCrossImpl(p_a->m_data, p_b->m_data); +} + +// OFFSET: LEGO1 0x10003bf0 +void MxVector3::EqualsScalar(float *p_value) +{ + m_data[0] = *p_value; + m_data[1] = *p_value; + m_data[2] = *p_value; +} + +// OFFSET: LEGO1 0x100028b0 +void MxVector4::AddScalarImpl(float p_value) +{ + m_data[0] += p_value; + m_data[1] += p_value; + m_data[2] += p_value; + m_data[3] += p_value; +} + +// OFFSET: LEGO1 0x10002870 +void MxVector4::AddVectorImpl(float *p_value) +{ + m_data[0] += p_value[0]; + m_data[1] += p_value[1]; + m_data[2] += p_value[2]; + m_data[3] += p_value[3]; +} + +// OFFSET: LEGO1 0x100028f0 +void MxVector4::SubVectorImpl(float *p_value) +{ + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; + m_data[2] -= p_value[2]; + m_data[3] -= p_value[3]; +} + +// OFFSET: LEGO1 0x10002970 +void MxVector4::MullScalarImpl(float *p_value) +{ + m_data[0] *= *p_value; + m_data[1] *= *p_value; + m_data[2] *= *p_value; + m_data[3] *= *p_value; +} + +// OFFSET: LEGO1 0x10002930 +void MxVector4::MullVectorImpl(float *p_value) +{ + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; + m_data[2] *= p_value[2]; + m_data[3] *= p_value[3]; +} + +// OFFSET: LEGO1 0x100029b0 +void MxVector4::DivScalarImpl(float *p_value) +{ + m_data[0] /= *p_value; + m_data[1] /= *p_value; + m_data[2] /= *p_value; + m_data[3] /= *p_value; +} + +// OFFSET: LEGO1 0x100029f0 +float MxVector4::DotImpl(float *p_a, float *p_b) const +{ + return + p_a[0] * p_b[0] + p_a[2] * p_b[2] + + p_a[1] * p_b[1] + p_a[3] * p_b[3]; +} + +// OFFSET: LEGO1 0x10002a20 +void MxVector4::EqualsImpl(float *p_data) +{ + float *vec = m_data; + vec[0] = p_data[0]; + vec[1] = p_data[1]; + vec[2] = p_data[2]; + vec[3] = p_data[3]; +} + +// OFFSET: LEGO1 0x10002b00 +void MxVector4::Clear() +{ + float *vec = m_data; + vec[0] = 0.0f; + vec[1] = 0.0f; + vec[2] = 0.0f; + vec[3] = 0.0f; +} + +// OFFSET: LEGO1 0x10002b20 +float MxVector4::LenSquared() const +{ + return m_data[1] * m_data[1] + m_data[0] * m_data[0] + + m_data[2] * m_data[2] + m_data[3] * m_data[3]; +} + +// OFFSET: LEGO1 0x10002b40 +void MxVector4::EqualsScalar(float *p_value) +{ + m_data[0] = *p_value; + m_data[1] = *p_value; + m_data[2] = *p_value; + m_data[3] = *p_value; +} + +// OFFSET: LEGO1 0x10002ae0 STUB +void MxVector4::unk1(MxVector4 *p_a, float *p_b) +{ +} + +// OFFSET: LEGO1 0x10002a40 +void MxVector4::SetMatrixProduct(float *p_vec, float *p_mat) +{ + m_data[0] = + p_vec[0] * p_mat[0] + p_vec[1] * p_mat[4] + + p_vec[2] * p_mat[8] + p_vec[3] * p_mat[12]; + m_data[1] = + p_vec[0] * p_mat[1] + p_vec[1] * p_mat[5] + + p_vec[2] * p_mat[9] + p_vec[4] * p_mat[13]; + m_data[2] = + p_vec[0] * p_mat[2] + p_vec[1] * p_mat[6] + + p_vec[2] * p_mat[10] + p_vec[4] * p_mat[14]; + m_data[3] = + p_vec[0] * p_mat[3] + p_vec[1] * p_mat[7] + + p_vec[2] * p_mat[11] + p_vec[4] * p_mat[15]; +} + +// Note close yet, included because I'm at least confident I know what operation +// it's trying to do. +// OFFSET: LEGO1 0x10002b70 STUB +MxResult MxVector4::NormalizeQuaternion() +{ + float *v = m_data; + float magnitude = v[1] * v[1] + v[2] * v[2] + v[0] * v[0]; + if (magnitude > 0.0f) + { + float theta = v[3] * 0.5f; + v[3] = cos(theta); + float frac = sin(theta); + magnitude = frac / sqrt(magnitude); + v[0] *= magnitude; + v[1] *= magnitude; + v[2] *= magnitude; + return SUCCESS; + } + return FAILURE; +} + +// OFFSET: LEGO1 0x10002bf0 STUB +void MxVector4::UnknownQuaternionOp(MxVector4 *p_a, MxVector4 *p_b) +{ + +} \ No newline at end of file diff --git a/LEGO1/mxvector.h b/LEGO1/mxvector.h new file mode 100644 index 00000000..0b766348 --- /dev/null +++ b/LEGO1/mxvector.h @@ -0,0 +1,150 @@ +#ifndef MXVECTOR_H +#define MXVECTOR_H + +#include "mxtypes.h" + +// VTABLE 0x100d4288 +// SIZE 0x8 +class MxVector2 +{ +public: + // OFFSET: LEGO1 0x1000c0f0 + inline MxVector2(float* p_data) : m_data(p_data) {} + + // vtable + 0x00 (no virtual destructor) + virtual void AddScalarImpl(float p_value) = 0; + virtual void AddVectorImpl(float *p_value) = 0; + virtual void SubVectorImpl(float *p_value) = 0; + virtual void MullScalarImpl(float *p_value) = 0; + + // vtable + 0x10 + virtual void MullVectorImpl(float *p_value) = 0; + virtual void DivScalarImpl(float *p_value) = 0; + virtual float DotImpl(float *p_a, float *p_b) const = 0; + virtual void SetData(float *p_data); + + // vtable + 0x20 + virtual void EqualsImpl(float *p_data) = 0; + virtual const float *GetData() const; + virtual float *GetData(); + virtual void Clear() = 0; + + // vtable + 0x30 + virtual float Dot(MxVector2 *p_a, float *p_b) const; + virtual float Dot(float *p_a, MxVector2 *p_b) const; + virtual float Dot(MxVector2 *p_a, MxVector2 *p_b) const; + virtual float Dot(float *p_a, float *p_b) const; + + // vtable + 0x40 + virtual float LenSquared() const = 0; + virtual MxResult Unitize(); + + // vtable + 0x48 + virtual void AddVector(MxVector2 *p_other); + virtual void AddVector(float *p_other); + virtual void AddScalar(float p_value); + + // vtable + 0x54 + virtual void SubVector(MxVector2 *p_other); + virtual void SubVector(float *p_other); + + // vtable + 0x5C + virtual void MullScalar(float *p_value); + virtual void MullVector(MxVector2 *p_other); + virtual void MullVector(float *p_other); + virtual void DivScalar(float *p_value); + + // vtable + 0x6C + virtual void SetVector(MxVector2 *other); + virtual void SetVector(float *other); + +protected: + float *m_data; +}; + +// VTABLE 0x100d4518 +// SIZE 0x8 +class MxVector3 : public MxVector2 +{ +public: + inline MxVector3(float* p_data) : MxVector2(p_data) {} + + void AddScalarImpl(float p_value); + + void AddVectorImpl(float *p_value); + + void SubVectorImpl(float *p_value); + void MullScalarImpl(float *p_value); + void MullVectorImpl(float *p_value); + void DivScalarImpl(float *p_value); + float DotImpl(float *p_a, float *p_b) const; + + void EqualsImpl(float *p_data); + + void Clear(); + + float LenSquared() const; + + // vtable + 0x74 + virtual void EqualsCrossImpl(float* p_a, float* p_b); + virtual void EqualsCross(float *p_a, MxVector3 *p_b); + virtual void EqualsCross(MxVector3 *p_a, float *p_b); + virtual void EqualsCross(MxVector3 *p_a, MxVector3 *p_b); + virtual void EqualsScalar(float *p_value); +}; + +// VTABLE 0x100d45a0 +// SIZE 0x8 +class MxVector4 : public MxVector3 +{ +public: + inline MxVector4(float* p_data) : MxVector3(p_data) {} + + void AddScalarImpl(float p_value); + + void AddVectorImpl(float *p_value); + + void SubVectorImpl(float *p_value); + void MullScalarImpl(float *p_value); + void MullVectorImpl(float *p_value); + void DivScalarImpl(float *p_value); + float DotImpl(float *p_a, float *p_b) const; + + void EqualsImpl(float *p_data); + + void Clear(); + + float LenSquared() const; + + void EqualsScalar(float *p_value); + + // vtable + 0x84 + virtual void unk1(MxVector4 *p_a, float *p_b); + virtual void SetMatrixProduct(float *p_vec, float *p_mat); + virtual MxResult NormalizeQuaternion(); + virtual void UnknownQuaternionOp(MxVector4 *p_a, MxVector4 *p_b); +}; + +// VTABLE 0x100d4488 +// SIZE 0x14 +class MxVector3Data : public MxVector3 +{ +public: + inline MxVector3Data() : MxVector3(&x) {} + inline MxVector3Data(float p_x, float p_y, float p_z) + : MxVector3(&x) + , x(p_x), y(p_y), z(p_z) + {} + float x, y, z; +}; + +// VTABLE 0x100d41e8 +// SIZE 0x18 +class MxVector4Data : public MxVector4 +{ +public: + inline MxVector4Data() : MxVector4(&x) {} + float x, y, z, w; +}; + +#endif // MXVECTOR_H \ No newline at end of file diff --git a/LEGO1/pizza.cpp b/LEGO1/pizza.cpp index e7e9c552..7e153b26 100644 --- a/LEGO1/pizza.cpp +++ b/LEGO1/pizza.cpp @@ -1,13 +1,30 @@ #include "pizza.h" -// OFFSET: LEGO1 0x10037ef0 STUB +#include "decomp.h" + +DECOMP_SIZE_ASSERT(Pizza, 0x9c); + +// OFFSET: LEGO1 0x10037ef0 Pizza::Pizza() { - // TODO + // FIXME: This inherits from LegoActor, probably why this isn't matching + this->m_unk80 = 0; + this->m_unk84 = 0; + this->m_unk88 = 0; + this->m_unk8c = -1; + this->m_unk98 = 0; + this->m_unk90 = 0x80000000; } -// OFFSET: LEGO1 0x10038100 STUB +// OFFSET: LEGO1 0x10038100 Pizza::~Pizza() { - // TODO + TickleManager()->UnregisterClient(this); +} + +// OFFSET: LEGO1 0x100388a0 +MxResult Pizza::Tickle() +{ + // TODO + return SUCCESS; } diff --git a/LEGO1/pizza.h b/LEGO1/pizza.h index c47ef40e..34d781c9 100644 --- a/LEGO1/pizza.h +++ b/LEGO1/pizza.h @@ -2,6 +2,10 @@ #define PIZZA_H #include "isleactor.h" +#include "mxcore.h" +#include "mxomni.h" +#include "mxticklemanager.h" +#include "mxtypes.h" // VTABLE 0x100d7380 // SIZE 0x9c @@ -11,6 +15,30 @@ class Pizza : public IsleActor Pizza(); virtual ~Pizza() override; + virtual MxResult Tickle() override; // vtable+08 + + // OFFSET: LEGO1 0x10037f90 + inline const char *ClassName() const //vtable+0c + { + // 0x100f038c + return "Pizza"; + } + + // OFFSET: LEGO1 0x10037fa0 + inline MxBool Pizza::IsA(const char *name) const override //vtable+10 + { + return !strcmp(name, Pizza::ClassName()) || IsleActor::IsA(name); + } +private: + MxS32 m_unk78; + MxS32 m_unk7c; + MxS32 m_unk80; + MxS32 m_unk84; + MxS32 m_unk88; + MxS32 m_unk8c; + MxU32 m_unk90; + MxS32 m_unk94; + MxS32 m_unk98; }; #endif // PIZZA_H diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index 69779872..1beec5dd 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -343,14 +343,15 @@ def replace_register(lines: list[str], start_line: int, reg: str, replacement: s # Is it possible to make new_asm the same as original_asm by swapping registers? def can_resolve_register_differences(original_asm, new_asm): + # Split the ASM on spaces to get more granularity, and so + # that we don't modify the original arrays passed in. + original_asm = [part for line in original_asm for part in line.split()] + new_asm = [part for line in new_asm for part in line.split()] + # Swapping ain't gonna help if the lengths are different if len(original_asm) != len(new_asm): return False - # Make copies so we don't modify the original - original_asm = original_asm.copy() - new_asm = new_asm.copy() - # Look for the mismatching lines for i in range(len(original_asm)): new_line = new_asm[i]