Checkorder tool to keep functions in original binary order (#228)

* First commit of order tool

* More flexible match on module name. Bugfix on blank_or_comment

* Report inexact offset comments in verbose mode. Bugfix for exact regex

* Refactor checkorder into reusable isledecomp module

* Find bad comments in one pass, add awareness of TEMPLATE

* Refactor of state machine to prepare for reccmp integration

* Use isledecomp lib in reccmp

* Build isledecomp in GH actions, fix mypy complaint

* Ensure unit test cpp files will be ignored by reccmp

* Allow multiple offset markers, pep8 cleanup

* Remove unused variable

* Code style, remove unneeded module and TODO

* Final renaming and type hints

* Fix checkorder issues, add GH action and enforce (#2)

* Fix checkorder issues

* Add GH action

* Test error case

* Works

* Fixes

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
MS 2023-11-21 03:44:45 -05:00 committed by GitHub
parent 714d36b57d
commit 1ae3b07dc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
84 changed files with 4021 additions and 3209 deletions

View file

@ -70,6 +70,11 @@ jobs:
path: legobin
key: legobin
- name: Build isledecomp library
shell: bash
run: |
pip install tools/isledecomp
- name: Summarize Accuracy
shell: bash
run: |

20
.github/workflows/order.yml vendored Normal file
View file

@ -0,0 +1,20 @@
name: Check order
on: [push, pull_request]
jobs:
checkorder:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build isledecomp library
run: |
pip install tools/isledecomp
- name: Run checkorder.py
run: |
pip install -r tools/checkorder/requirements.txt
python3 tools/checkorder/checkorder.py --verbose --enforce ISLE
python3 tools/checkorder/checkorder.py --verbose --enforce LEGO1

1
.gitignore vendored
View file

@ -18,3 +18,4 @@ build/
*.swp
LEGO1PROGRESS.HTML
LEGO1PROGRESS.SVG
*.pyc

View file

@ -281,6 +281,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
return msg.wParam;
}
// OFFSET: ISLE 0x401c40 TEMPLATE
// MxDSObject::SetAtomId
// OFFSET: ISLE 0x401ca0
BOOL FindExistingInstance(void)
{

View file

@ -3,6 +3,12 @@
// 0x100f37cc
int g_buildingManagerConfig = 1;
// OFFSET: LEGO1 0x1002f8b0
void LegoBuildingManager::configureLegoBuildingManager(int param_1)
{
g_buildingManagerConfig = param_1;
}
// OFFSET: LEGO1 0x1002f8c0
LegoBuildingManager::LegoBuildingManager()
{
@ -20,9 +26,3 @@ void LegoBuildingManager::Init()
{
// TODO
}
// OFFSET: LEGO1 0x1002f8b0
void LegoBuildingManager::configureLegoBuildingManager(int param_1)
{
g_buildingManagerConfig = param_1;
}

View file

@ -12,14 +12,6 @@ LegoCarBuild::~LegoCarBuild()
// TODO
}
// OFFSET: LEGO1 0x10024050 STUB
MxLong LegoCarBuild::Notify(MxParam& p)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x100238b0 STUB
MxResult LegoCarBuild::Tickle()
{
@ -27,3 +19,11 @@ MxResult LegoCarBuild::Tickle()
return 0;
}
// OFFSET: LEGO1 0x10024050 STUB
MxLong LegoCarBuild::Notify(MxParam& p)
{
// TODO
return 0;
}

View file

@ -12,14 +12,6 @@ LegoControlManager::~LegoControlManager()
// TODO
}
// OFFSET: LEGO1 0x10029600 STUB
MxResult LegoControlManager::Tickle()
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x10028e10 STUB
void LegoControlManager::Register(MxCore* p_listener)
{
@ -31,3 +23,11 @@ void LegoControlManager::Unregister(MxCore* p_listener)
{
// TODO
}
// OFFSET: LEGO1 0x10029600 STUB
MxResult LegoControlManager::Tickle()
{
// TODO
return 0;
}

View file

@ -7,6 +7,9 @@
DECOMP_SIZE_ASSERT(LegoEntity, 0x68)
// OFFSET: LEGO1 0x10001090 TEMPLATE
// LegoEntity::SetWorldSpeed
// OFFSET: LEGO1 0x1000c290
LegoEntity::~LegoEntity()
{

View file

@ -38,15 +38,14 @@ class LegoEntity : public MxEntity {
virtual void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2); // vtable+0x24
virtual void SetWorldTransform(Vector3Impl& p_loc, Vector3Impl& p_dir, Vector3Impl& p_up); // vtable+0x28
virtual void ResetWorldTransform(MxBool p_inVehicle); // vtable+0x2c
// OFFSET: LEGO1 0x10001090
virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30
virtual void VTable0x34(); // vtable+0x34
virtual void VTable0x38(); // vtable+0x38
virtual void VTable0x3c(); // vtable+0x3c
virtual void VTable0x40(); // vtable+0x40
virtual void VTable0x44(); // vtable+0x44
virtual void VTable0x48(); // vtable+0x48
virtual void VTable0x4c(); // vtable+0x4c
virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30
virtual void VTable0x34(); // vtable+0x34
virtual void VTable0x38(); // vtable+0x38
virtual void VTable0x3c(); // vtable+0x3c
virtual void VTable0x40(); // vtable+0x40
virtual void VTable0x44(); // vtable+0x44
virtual void VTable0x48(); // vtable+0x48
virtual void VTable0x4c(); // vtable+0x4c
protected:
void Init();

View file

@ -78,42 +78,6 @@ LegoGameState::~LegoGameState()
delete[] m_savePath;
}
// OFFSET: LEGO1 0x10039c60 STUB
MxResult LegoGameState::Load(MxULong)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1003a170
void LegoGameState::GetFileSavePath(MxString* p_outPath, MxULong p_slotn)
{
char baseForSlot[2] = "0";
char path[1024] = "";
// Save path base
if (m_savePath != NULL)
strcpy(path, m_savePath);
// Slot: "G0", "G1", ...
strcat(path, "G");
baseForSlot[0] += p_slotn;
strcat(path, baseForSlot);
// Extension: ".GS"
strcat(path, g_fileExtensionGS);
*p_outPath = MxString(path);
}
// OFFSET: LEGO1 0x1003a020
MxResult LegoGameState::WriteEndOfVariables(LegoStream* p_stream)
{
MxU8 len = strlen(s_endOfVariables);
if (p_stream->Write(&len, 1) == SUCCESS)
return p_stream->Write(s_endOfVariables, len);
return FAILURE;
}
// OFFSET: LEGO1 0x10039980
MxResult LegoGameState::Save(MxULong p_slot)
{
@ -152,22 +116,11 @@ MxResult LegoGameState::Save(MxULong p_slot)
return result;
}
// OFFSET: LEGO1 0x1003a2e0 STUB
void LegoGameState::SerializePlayersInfo(MxS16 p)
// OFFSET: LEGO1 0x10039c60 STUB
MxResult LegoGameState::Load(MxULong)
{
// TODO
}
// OFFSET: LEGO1 0x1003cdd0 STUB
void LegoGameState::SerializeScoreHistory(MxS16 p)
{
// TODO
}
// OFFSET: LEGO1 0x1003cea0
void LegoGameState::SetSomeEnumState(undefined4 p_state)
{
m_unk10 = p_state;
return 0;
}
// OFFSET: LEGO1 0x10039f00
@ -184,6 +137,53 @@ void LegoGameState::SetSavePath(char* p_savePath)
m_savePath = NULL;
}
// OFFSET: LEGO1 0x1003a020
MxResult LegoGameState::WriteEndOfVariables(LegoStream* p_stream)
{
MxU8 len = strlen(s_endOfVariables);
if (p_stream->Write(&len, 1) == SUCCESS)
return p_stream->Write(s_endOfVariables, len);
return FAILURE;
}
// OFFSET: LEGO1 0x1003a170
void LegoGameState::GetFileSavePath(MxString* p_outPath, MxULong p_slotn)
{
char baseForSlot[2] = "0";
char path[1024] = "";
// Save path base
if (m_savePath != NULL)
strcpy(path, m_savePath);
// Slot: "G0", "G1", ...
strcat(path, "G");
baseForSlot[0] += p_slotn;
strcat(path, baseForSlot);
// Extension: ".GS"
strcat(path, g_fileExtensionGS);
*p_outPath = MxString(path);
}
// OFFSET: LEGO1 0x1003a2e0 STUB
void LegoGameState::SerializePlayersInfo(MxS16 p)
{
// TODO
}
// OFFSET: LEGO1 0x1003a720 STUB
void LegoGameState::FUN_1003a720(MxU32 p_unk)
{
// TODO
}
// OFFSET: LEGO1 0x1003b060 STUB
void LegoGameState::HandleAction(MxU32 p_unk)
{
// TODO
}
// OFFSET: LEGO1 0x1003bac0
void LegoGameState::SetROIHandlerFunction()
{
@ -255,14 +255,14 @@ void LegoGameState::RegisterState(LegoState* p_state)
m_stateArray[targetIndex] = p_state;
}
// OFFSET: LEGO1 0x1003a720 STUB
void LegoGameState::FUN_1003a720(MxU32 p_unk)
// OFFSET: LEGO1 0x1003cdd0 STUB
void LegoGameState::SerializeScoreHistory(MxS16 p)
{
// TODO
}
// OFFSET: LEGO1 0x1003b060 STUB
void LegoGameState::HandleAction(MxU32 p_unk)
// OFFSET: LEGO1 0x1003cea0
void LegoGameState::SetSomeEnumState(undefined4 p_state)
{
// TODO
m_unk10 = p_state;
}

View file

@ -30,62 +30,6 @@ float g_turnSensitivity = 0.4f;
// 0x100f4c54
MxBool g_turnUseVelocity = FALSE;
// OFFSET: LEGO1 0x10054d40
void LegoNavController::GetDefaults(
int* p_mouseDeadzone,
float* p_movementMaxSpeed,
float* p_turnMaxSpeed,
float* p_movementMaxAccel,
float* p_turnMaxAccel,
float* p_movementDecel,
float* p_turnDecel,
float* p_movementMinAccel,
float* p_turnMinAccel,
float* p_turnSensitivity,
MxBool* p_turnUseVelocity
)
{
*p_mouseDeadzone = g_mouseDeadzone;
*p_movementMaxSpeed = g_movementMaxSpeed;
*p_turnMaxSpeed = g_turnMaxSpeed;
*p_movementMaxAccel = g_movementMaxAccel;
*p_turnMaxAccel = g_turnMaxAccel;
*p_movementDecel = g_movementDecel;
*p_turnDecel = g_turnDecel;
*p_movementMinAccel = g_movementMinAccel;
*p_turnMinAccel = g_turnMinAccel;
*p_turnSensitivity = g_turnSensitivity;
*p_turnUseVelocity = g_turnUseVelocity;
}
// OFFSET: LEGO1 0x10054dd0
void LegoNavController::SetDefaults(
int p_mouseDeadzone,
float p_movementMaxSpeed,
float p_turnMaxSpeed,
float p_movementMaxAccel,
float p_turnMaxAccel,
float p_movementDecel,
float p_turnDecel,
float p_movementMinAccel,
float p_turnMinAccel,
float p_turnSensitivity,
MxBool p_turnUseVelocity
)
{
g_mouseDeadzone = p_mouseDeadzone;
g_movementMaxSpeed = p_movementMaxSpeed;
g_turnMaxSpeed = p_turnMaxSpeed;
g_movementMaxAccel = p_movementMaxAccel;
g_turnMaxAccel = p_turnMaxAccel;
g_movementDecel = p_movementDecel;
g_turnDecel = p_turnDecel;
g_movementMinAccel = p_movementMinAccel;
g_turnMinAccel = p_turnMinAccel;
g_turnSensitivity = p_turnSensitivity;
g_turnUseVelocity = p_turnUseVelocity;
}
// OFFSET: LEGO1 0x10054ac0
LegoNavController::LegoNavController()
{
@ -145,6 +89,62 @@ void LegoNavController::ResetToDefault()
this->m_turnSensitivity = g_turnSensitivity;
}
// OFFSET: LEGO1 0x10054d40
void LegoNavController::GetDefaults(
int* p_mouseDeadzone,
float* p_movementMaxSpeed,
float* p_turnMaxSpeed,
float* p_movementMaxAccel,
float* p_turnMaxAccel,
float* p_movementDecel,
float* p_turnDecel,
float* p_movementMinAccel,
float* p_turnMinAccel,
float* p_turnSensitivity,
MxBool* p_turnUseVelocity
)
{
*p_mouseDeadzone = g_mouseDeadzone;
*p_movementMaxSpeed = g_movementMaxSpeed;
*p_turnMaxSpeed = g_turnMaxSpeed;
*p_movementMaxAccel = g_movementMaxAccel;
*p_turnMaxAccel = g_turnMaxAccel;
*p_movementDecel = g_movementDecel;
*p_turnDecel = g_turnDecel;
*p_movementMinAccel = g_movementMinAccel;
*p_turnMinAccel = g_turnMinAccel;
*p_turnSensitivity = g_turnSensitivity;
*p_turnUseVelocity = g_turnUseVelocity;
}
// OFFSET: LEGO1 0x10054dd0
void LegoNavController::SetDefaults(
int p_mouseDeadzone,
float p_movementMaxSpeed,
float p_turnMaxSpeed,
float p_movementMaxAccel,
float p_turnMaxAccel,
float p_movementDecel,
float p_turnDecel,
float p_movementMinAccel,
float p_turnMinAccel,
float p_turnSensitivity,
MxBool p_turnUseVelocity
)
{
g_mouseDeadzone = p_mouseDeadzone;
g_movementMaxSpeed = p_movementMaxSpeed;
g_turnMaxSpeed = p_turnMaxSpeed;
g_movementMaxAccel = p_movementMaxAccel;
g_turnMaxAccel = p_turnMaxAccel;
g_movementDecel = p_movementDecel;
g_turnDecel = p_turnDecel;
g_movementMinAccel = p_movementMinAccel;
g_turnMinAccel = p_turnMinAccel;
g_turnSensitivity = p_turnSensitivity;
g_turnUseVelocity = p_turnUseVelocity;
}
// OFFSET: LEGO1 0x10054e40
void LegoNavController::SetTargets(int p_hPos, int p_vPos, MxBool p_accel)
{

View file

@ -109,124 +109,6 @@ const char* g_current = "current";
// 0x101020e8
void (*g_omniUserMessage)(const char*, int);
// OFFSET: LEGO1 0x10058a00
LegoOmni::LegoOmni()
{
Init();
}
// OFFSET: LEGO1 0x10058b50
LegoOmni::~LegoOmni()
{
Destroy();
}
// OFFSET: LEGO1 0x1005b560
void LegoOmni::CreateBackgroundAudio()
{
if (m_bkgAudioManager)
m_bkgAudioManager->Create(*g_jukeboxScript, 100);
}
// OFFSET: LEGO1 0x1005af10 STUB
void LegoOmni::RemoveWorld(const MxAtomId& p1, MxLong p2)
{
// TODO
}
// OFFSET: LEGO1 0x1005b0c0 STUB
LegoEntity* LegoOmni::FindByEntityIdOrAtomId(const MxAtomId& p_atom, MxS32 p_entityid)
{
// TODO
return NULL;
}
// OFFSET: LEGO1 0x1005b400 STUB
int LegoOmni::GetCurrPathInfo(LegoPathBoundary**, int&)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x100b6ff0
void MakeSourceName(char* p_output, const char* p_input)
{
const char* cln = strchr(p_input, ':');
if (cln) {
p_input = cln + 1;
}
strcpy(p_output, p_input);
strlwr(p_output);
char* extLoc = strstr(p_output, ".si");
if (extLoc) {
*extLoc = 0;
}
}
// OFFSET: LEGO1 0x100b7050
MxBool KeyValueStringParse(char* p_outputValue, const char* p_key, const char* p_source)
{
MxBool didMatch = FALSE;
MxS16 len = strlen(p_source);
char* temp = new char[len + 1];
strcpy(temp, p_source);
char* token = strtok(temp, ", \t\r\n:");
while (token) {
len -= (strlen(token) + 1);
if (strcmpi(token, p_key) == 0) {
if (p_outputValue && len > 0) {
char* cur = &token[strlen(p_key)];
cur++;
while (*cur != ',') {
if (*cur == ' ' || *cur == '\0' || *cur == '\t' || *cur == '\n' || *cur == '\r')
break;
*p_outputValue++ = *cur++;
}
*p_outputValue = '\0';
}
didMatch = TRUE;
break;
}
token = strtok(NULL, ", \t\r\n:");
}
delete[] temp;
return didMatch;
}
// OFFSET: LEGO1 0x100b7210
void SetOmniUserMessage(void (*p_userMsg)(const char*, int))
{
g_omniUserMessage = p_userMsg;
}
// OFFSET: LEGO1 0x100acf50
MxResult Start(MxDSAction* p_dsAction)
{
return MxOmni::GetInstance()->Start(p_dsAction);
}
// OFFSET: LEGO1 0x1005ad10
LegoOmni* LegoOmni::GetInstance()
{
return (LegoOmni*) MxOmni::GetInstance();
}
// OFFSET: LEGO1 0x1005ac90
void LegoOmni::CreateInstance()
{
MxOmni::DestroyInstance();
MxOmni::SetInstance(new LegoOmni());
}
// OFFSET: LEGO1 0x10015700
LegoOmni* Lego()
{
@ -334,52 +216,10 @@ void PlayMusic(MxU32 p_index)
LegoOmni::GetInstance()->GetBackgroundAudioManager()->PlayMusic(action, 5, 4);
}
// OFFSET: LEGO1 0x100c0280
MxDSObject* CreateStreamObject(MxDSFile* p_file, MxS16 p_ofs)
{
char* buf;
_MMCKINFO tmp_chunk;
if (p_file->Seek(((MxLong*) p_file->GetBuffer())[p_ofs], 0)) {
return NULL;
}
if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'S', 't')) {
if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'O', 'b')) {
buf = new char[tmp_chunk.cksize];
if (!buf) {
return NULL;
}
if (p_file->Read((MxU8*) buf, tmp_chunk.cksize) != 0) {
return NULL;
}
// Save a copy so we can clean up properly, because
// this function will alter the pointer value.
char* copy = buf;
MxDSObject* obj = DeserializeDSObjectDispatch(&buf, -1);
delete[] copy;
return obj;
}
return NULL;
}
return NULL;
}
// OFFSET: LEGO1 0x10053430
const char* GetNoCD_SourceName()
{
return g_nocdSourceName->GetInternal();
}
// OFFSET: LEGO1 0x1005b5f0 STUB
MxLong LegoOmni::Notify(MxParam& p)
// OFFSET: LEGO1 0x1001a700 STUB
void FUN_1001a700()
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1003dd70 STUB
@ -396,180 +236,6 @@ LegoEntity* PickEntity(MxLong, MxLong)
return NULL;
}
// OFFSET: LEGO1 0x10058bd0
void LegoOmni::Init()
{
MxOmni::Init();
m_unk68 = 0;
m_inputMgr = NULL;
m_unk6c = 0;
m_gifManager = NULL;
m_unk78 = 0;
m_currentWorld = NULL;
m_unk80 = FALSE;
m_currentVehicle = NULL;
m_unkLegoSaveDataWriter = NULL;
m_plantManager = NULL;
m_gameState = NULL;
m_animationManager = NULL;
m_buildingManager = NULL;
m_bkgAudioManager = NULL;
m_unk13c = TRUE;
m_transitionManager = NULL;
}
// OFFSET: LEGO1 0x1001a700 STUB
void FUN_1001a700()
{
// TODO
}
// OFFSET: LEGO1 0x10058e70
MxResult LegoOmni::Create(MxOmniCreateParam& p)
{
MxResult result = FAILURE;
MxAutoLocker lock(&this->m_criticalsection);
p.CreateFlags().CreateObjectFactory(FALSE);
p.CreateFlags().CreateVideoManager(FALSE);
p.CreateFlags().CreateSoundManager(FALSE);
p.CreateFlags().CreateTickleManager(FALSE);
if (!(m_tickleManager = new MxTickleManager()))
return FAILURE;
if (MxOmni::Create(p) != SUCCESS)
return FAILURE;
m_objectFactory = new LegoObjectFactory();
if (m_objectFactory == NULL)
return FAILURE;
if (m_soundManager = new LegoSoundManager()) {
if (m_soundManager->Create(10, 0) != SUCCESS) {
delete m_soundManager;
m_soundManager = NULL;
return FAILURE;
}
}
if (m_videoManager = new LegoVideoManager()) {
if (m_videoManager->Create(p.GetVideoParam(), 100, 0) != SUCCESS) {
delete m_videoManager;
m_videoManager = NULL;
}
}
if (m_inputMgr = new LegoInputManager()) {
if (m_inputMgr->Create(p.GetWindowHandle()) != SUCCESS) {
delete m_inputMgr;
m_inputMgr = NULL;
}
}
// TODO: there are a few more classes here
m_gifManager = new GifManager();
m_plantManager = new LegoPlantManager();
m_animationManager = new LegoAnimationManager();
m_buildingManager = new LegoBuildingManager();
m_gameState = new LegoGameState();
// TODO: initialize list at m_unk78
if (m_unk6c && m_gifManager && m_unk78 && m_plantManager && m_animationManager && m_buildingManager) {
// TODO: initialize a bunch of MxVariables
RegisterScripts();
FUN_1001a700();
// todo: another function call. in legoomni maybe?
m_bkgAudioManager = new MxBackgroundAudioManager();
if (m_bkgAudioManager != NULL) {
m_transitionManager = new MxTransitionManager();
if (m_transitionManager != NULL) {
if (m_transitionManager->GetDDrawSurfaceFromVideoManager() == SUCCESS) {
m_notificationManager->Register(this);
SetAppCursor(1);
m_gameState->SetSomeEnumState(0);
return SUCCESS;
}
}
}
}
return FAILURE;
}
// OFFSET: LEGO1 0x10058c30 STUB
void LegoOmni::Destroy()
{
// TODO
}
// OFFSET: LEGO1 0x1005b580
MxResult LegoOmni::Start(MxDSAction* action)
{
MxResult result = MxOmni::Start(action);
this->m_action.SetAtomId(action->GetAtomId());
this->m_action.SetObjectId(action->GetObjectId());
this->m_action.SetUnknown24(action->GetUnknown24());
return result;
}
// OFFSET: LEGO1 0x1005b1d0 STUB
MxResult LegoOmni::DeleteObject(MxDSAction& ds)
{
// TODO
return FAILURE;
}
// OFFSET: LEGO1 0x1005b3c0
MxBool LegoOmni::DoesEntityExist(MxDSAction& ds)
{
if (MxOmni::DoesEntityExist(ds)) {
if (FindByEntityIdOrAtomId(ds.GetAtomId(), ds.GetObjectId()) == NULL) {
return TRUE;
}
}
return FALSE;
}
// OFFSET: LEGO1 0x1005b2f0
MxEntity* LegoOmni::FindWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter)
{
LegoWorld* foundEntity = NULL;
if (strcmpi(p_id, g_current)) {
foundEntity = (LegoWorld*) FindByEntityIdOrAtomId(MxAtomId(p_id, LookupMode_LowerCase2), p_entityId);
}
else {
foundEntity = this->m_currentWorld;
}
if (foundEntity != NULL) {
foundEntity->VTable0x58(p_presenter);
}
return foundEntity;
}
// OFFSET: LEGO1 0x1005b3a0
void LegoOmni::NotifyCurrentEntity(MxNotificationParam* p_param)
{
if (m_currentWorld)
NotificationManager()->Send(m_currentWorld, p_param);
}
// OFFSET: LEGO1 0x1005b640
void LegoOmni::StartTimer()
{
MxOmni::StartTimer();
SetAppCursor(2);
}
// OFFSET: LEGO1 0x1005b650
void LegoOmni::StopTimer()
{
MxOmni::StopTimer();
SetAppCursor(0);
}
// OFFSET: LEGO1 0x100528e0
void RegisterScripts()
{
@ -665,3 +331,337 @@ void UnregisterScripts()
g_creditsScript = NULL;
g_nocdSourceName = NULL;
}
// OFFSET: LEGO1 0x10053430
const char* GetNoCD_SourceName()
{
return g_nocdSourceName->GetInternal();
}
// OFFSET: LEGO1 0x10058a00
LegoOmni::LegoOmni()
{
Init();
}
// OFFSET: LEGO1 0x10058b50
LegoOmni::~LegoOmni()
{
Destroy();
}
// OFFSET: LEGO1 0x10058bd0
void LegoOmni::Init()
{
MxOmni::Init();
m_unk68 = 0;
m_inputMgr = NULL;
m_unk6c = 0;
m_gifManager = NULL;
m_unk78 = 0;
m_currentWorld = NULL;
m_unk80 = FALSE;
m_currentVehicle = NULL;
m_unkLegoSaveDataWriter = NULL;
m_plantManager = NULL;
m_gameState = NULL;
m_animationManager = NULL;
m_buildingManager = NULL;
m_bkgAudioManager = NULL;
m_unk13c = TRUE;
m_transitionManager = NULL;
}
// OFFSET: LEGO1 0x10058c30 STUB
void LegoOmni::Destroy()
{
// TODO
}
// OFFSET: LEGO1 0x10058e70
MxResult LegoOmni::Create(MxOmniCreateParam& p)
{
MxResult result = FAILURE;
MxAutoLocker lock(&this->m_criticalsection);
p.CreateFlags().CreateObjectFactory(FALSE);
p.CreateFlags().CreateVideoManager(FALSE);
p.CreateFlags().CreateSoundManager(FALSE);
p.CreateFlags().CreateTickleManager(FALSE);
if (!(m_tickleManager = new MxTickleManager()))
return FAILURE;
if (MxOmni::Create(p) != SUCCESS)
return FAILURE;
m_objectFactory = new LegoObjectFactory();
if (m_objectFactory == NULL)
return FAILURE;
if (m_soundManager = new LegoSoundManager()) {
if (m_soundManager->Create(10, 0) != SUCCESS) {
delete m_soundManager;
m_soundManager = NULL;
return FAILURE;
}
}
if (m_videoManager = new LegoVideoManager()) {
if (m_videoManager->Create(p.GetVideoParam(), 100, 0) != SUCCESS) {
delete m_videoManager;
m_videoManager = NULL;
}
}
if (m_inputMgr = new LegoInputManager()) {
if (m_inputMgr->Create(p.GetWindowHandle()) != SUCCESS) {
delete m_inputMgr;
m_inputMgr = NULL;
}
}
// TODO: there are a few more classes here
m_gifManager = new GifManager();
m_plantManager = new LegoPlantManager();
m_animationManager = new LegoAnimationManager();
m_buildingManager = new LegoBuildingManager();
m_gameState = new LegoGameState();
// TODO: initialize list at m_unk78
if (m_unk6c && m_gifManager && m_unk78 && m_plantManager && m_animationManager && m_buildingManager) {
// TODO: initialize a bunch of MxVariables
RegisterScripts();
FUN_1001a700();
// todo: another function call. in legoomni maybe?
m_bkgAudioManager = new MxBackgroundAudioManager();
if (m_bkgAudioManager != NULL) {
m_transitionManager = new MxTransitionManager();
if (m_transitionManager != NULL) {
if (m_transitionManager->GetDDrawSurfaceFromVideoManager() == SUCCESS) {
m_notificationManager->Register(this);
SetAppCursor(1);
m_gameState->SetSomeEnumState(0);
return SUCCESS;
}
}
}
}
return FAILURE;
}
// OFFSET: LEGO1 0x1005ac90
void LegoOmni::CreateInstance()
{
MxOmni::DestroyInstance();
MxOmni::SetInstance(new LegoOmni());
}
// OFFSET: LEGO1 0x1005ad10
LegoOmni* LegoOmni::GetInstance()
{
return (LegoOmni*) MxOmni::GetInstance();
}
// OFFSET: LEGO1 0x1005af10 STUB
void LegoOmni::RemoveWorld(const MxAtomId& p1, MxLong p2)
{
// TODO
}
// OFFSET: LEGO1 0x1005b0c0 STUB
LegoEntity* LegoOmni::FindByEntityIdOrAtomId(const MxAtomId& p_atom, MxS32 p_entityid)
{
// TODO
return NULL;
}
// OFFSET: LEGO1 0x1005b1d0 STUB
MxResult LegoOmni::DeleteObject(MxDSAction& ds)
{
// TODO
return FAILURE;
}
// OFFSET: LEGO1 0x1005b2f0
MxEntity* LegoOmni::FindWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter)
{
LegoWorld* foundEntity = NULL;
if (strcmpi(p_id, g_current)) {
foundEntity = (LegoWorld*) FindByEntityIdOrAtomId(MxAtomId(p_id, LookupMode_LowerCase2), p_entityId);
}
else {
foundEntity = this->m_currentWorld;
}
if (foundEntity != NULL) {
foundEntity->VTable0x58(p_presenter);
}
return foundEntity;
}
// OFFSET: LEGO1 0x1005b3a0
void LegoOmni::NotifyCurrentEntity(MxNotificationParam* p_param)
{
if (m_currentWorld)
NotificationManager()->Send(m_currentWorld, p_param);
}
// OFFSET: LEGO1 0x1005b3c0
MxBool LegoOmni::DoesEntityExist(MxDSAction& ds)
{
if (MxOmni::DoesEntityExist(ds)) {
if (FindByEntityIdOrAtomId(ds.GetAtomId(), ds.GetObjectId()) == NULL) {
return TRUE;
}
}
return FALSE;
}
// OFFSET: LEGO1 0x1005b400 STUB
int LegoOmni::GetCurrPathInfo(LegoPathBoundary**, int&)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1005b560
void LegoOmni::CreateBackgroundAudio()
{
if (m_bkgAudioManager)
m_bkgAudioManager->Create(*g_jukeboxScript, 100);
}
// OFFSET: LEGO1 0x1005b580
MxResult LegoOmni::Start(MxDSAction* action)
{
MxResult result = MxOmni::Start(action);
this->m_action.SetAtomId(action->GetAtomId());
this->m_action.SetObjectId(action->GetObjectId());
this->m_action.SetUnknown24(action->GetUnknown24());
return result;
}
// OFFSET: LEGO1 0x1005b5f0 STUB
MxLong LegoOmni::Notify(MxParam& p)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1005b640
void LegoOmni::StartTimer()
{
MxOmni::StartTimer();
SetAppCursor(2);
}
// OFFSET: LEGO1 0x1005b650
void LegoOmni::StopTimer()
{
MxOmni::StopTimer();
SetAppCursor(0);
}
// OFFSET: LEGO1 0x100acf50
MxResult Start(MxDSAction* p_dsAction)
{
return MxOmni::GetInstance()->Start(p_dsAction);
}
// OFFSET: LEGO1 0x100b6ff0
void MakeSourceName(char* p_output, const char* p_input)
{
const char* cln = strchr(p_input, ':');
if (cln) {
p_input = cln + 1;
}
strcpy(p_output, p_input);
strlwr(p_output);
char* extLoc = strstr(p_output, ".si");
if (extLoc) {
*extLoc = 0;
}
}
// OFFSET: LEGO1 0x100b7050
MxBool KeyValueStringParse(char* p_outputValue, const char* p_key, const char* p_source)
{
MxBool didMatch = FALSE;
MxS16 len = strlen(p_source);
char* temp = new char[len + 1];
strcpy(temp, p_source);
char* token = strtok(temp, ", \t\r\n:");
while (token) {
len -= (strlen(token) + 1);
if (strcmpi(token, p_key) == 0) {
if (p_outputValue && len > 0) {
char* cur = &token[strlen(p_key)];
cur++;
while (*cur != ',') {
if (*cur == ' ' || *cur == '\0' || *cur == '\t' || *cur == '\n' || *cur == '\r')
break;
*p_outputValue++ = *cur++;
}
*p_outputValue = '\0';
}
didMatch = TRUE;
break;
}
token = strtok(NULL, ", \t\r\n:");
}
delete[] temp;
return didMatch;
}
// OFFSET: LEGO1 0x100b7210
void SetOmniUserMessage(void (*p_userMsg)(const char*, int))
{
g_omniUserMessage = p_userMsg;
}
// OFFSET: LEGO1 0x100c0280
MxDSObject* CreateStreamObject(MxDSFile* p_file, MxS16 p_ofs)
{
char* buf;
_MMCKINFO tmp_chunk;
if (p_file->Seek(((MxLong*) p_file->GetBuffer())[p_ofs], 0)) {
return NULL;
}
if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'S', 't')) {
if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'O', 'b')) {
buf = new char[tmp_chunk.cksize];
if (!buf) {
return NULL;
}
if (p_file->Read((MxU8*) buf, tmp_chunk.cksize) != 0) {
return NULL;
}
// Save a copy so we can clean up properly, because
// this function will alter the pointer value.
char* copy = buf;
MxDSObject* obj = DeserializeDSObjectDispatch(&buf, -1);
delete[] copy;
return obj;
}
return NULL;
}
return NULL;
}

View file

@ -8,6 +8,11 @@ LegoPhonemePresenter::LegoPhonemePresenter()
Init();
}
// OFFSET: LEGO1 0x1004e340
LegoPhonemePresenter::~LegoPhonemePresenter()
{
}
// OFFSET: LEGO1 0x1004e3b0
void LegoPhonemePresenter::Init()
{
@ -16,8 +21,3 @@ void LegoPhonemePresenter::Init()
m_unk70 = 0;
m_unk84 = 0;
}
// OFFSET: LEGO1 0x1004e340
LegoPhonemePresenter::~LegoPhonemePresenter()
{
}

View file

@ -12,6 +12,12 @@ LegoPlantManager::~LegoPlantManager()
// TODO
}
// OFFSET: LEGO1 0x10026330 STUB
void LegoPlantManager::Init()
{
// TODO
}
// OFFSET: LEGO1 0x10026e00 STUB
MxResult LegoPlantManager::Tickle()
{
@ -19,9 +25,3 @@ MxResult LegoPlantManager::Tickle()
return 0;
}
// OFFSET: LEGO1 0x10026330 STUB
void LegoPlantManager::Init()
{
// TODO
}

View file

@ -14,10 +14,11 @@ LegoSoundManager::~LegoSoundManager()
Destroy(TRUE);
}
// OFFSET: LEGO1 0x1002a390
void LegoSoundManager::Destroy()
// OFFSET: LEGO1 0x100299a0
void LegoSoundManager::Init()
{
Destroy(FALSE);
unk0x40 = 0;
unk0x3c = 0;
}
// OFFSET: LEGO1 0x100299b0 STUB
@ -31,11 +32,10 @@ MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
return FAILURE;
}
// OFFSET: LEGO1 0x100299a0
void LegoSoundManager::Init()
// OFFSET: LEGO1 0x1002a390
void LegoSoundManager::Destroy()
{
unk0x40 = 0;
unk0x3c = 0;
Destroy(FALSE);
}
// OFFSET: LEGO1 0x1002a3a0 STUB

View file

@ -19,6 +19,55 @@ DECOMP_SIZE_ASSERT(LegoStream, 0x8);
DECOMP_SIZE_ASSERT(LegoFileStream, 0xC);
DECOMP_SIZE_ASSERT(LegoMemoryStream, 0x10);
// OFFSET: LEGO1 0x10039f70
MxResult LegoStream::WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName)
{
MxResult result = FAILURE;
const char* variableValue = p_from->GetVariable(p_variableName);
if (variableValue) {
MxU8 length = strlen(p_variableName);
if (p_stream->Write((char*) &length, 1) == SUCCESS) {
if (p_stream->Write(p_variableName, length) == SUCCESS) {
length = strlen(variableValue);
if (p_stream->Write((char*) &length, 1) == SUCCESS)
result = p_stream->Write((char*) variableValue, length);
}
}
}
return result;
}
// 95% match, just some instruction ordering differences on the call to
// MxVariableTable::SetVariable at the end.
// OFFSET: LEGO1 0x1003a080
MxS32 LegoStream::ReadVariable(LegoStream* p_stream, MxVariableTable* p_to)
{
MxS32 result = 1;
MxU8 length;
if (p_stream->Read((char*) &length, 1) == SUCCESS) {
char nameBuffer[256];
if (p_stream->Read(nameBuffer, length) == SUCCESS) {
nameBuffer[length] = '\0';
if (strcmp(nameBuffer, s_endOfVariables) == 0)
// 2 -> "This was the last entry, done reading."
result = 2;
else {
if (p_stream->Read((char*) &length, 1) == SUCCESS) {
char valueBuffer[256];
if (p_stream->Read(valueBuffer, length) == SUCCESS) {
result = 0;
valueBuffer[length] = '\0';
p_to->SetVariable(nameBuffer, valueBuffer);
}
}
}
}
}
return result;
}
// OFFSET: LEGO1 0x10045ae0
MxBool LegoStream::IsWriteMode()
{
@ -31,6 +80,29 @@ MxBool LegoStream::IsReadMode()
return m_mode == LEGOSTREAM_MODE_READ;
}
// OFFSET: LEGO1 0x10099080
LegoMemoryStream::LegoMemoryStream(char* p_buffer) : LegoStream()
{
m_buffer = p_buffer;
m_offset = 0;
}
// OFFSET: LEGO1 0x10099160
MxResult LegoMemoryStream::Read(void* p_buffer, MxU32 p_size)
{
memcpy(p_buffer, m_buffer + m_offset, p_size);
m_offset += p_size;
return SUCCESS;
}
// OFFSET: LEGO1 0x10099190
MxResult LegoMemoryStream::Write(const void* p_buffer, MxU32 p_size)
{
memcpy(m_buffer + m_offset, p_buffer, p_size);
m_offset += p_size;
return SUCCESS;
}
// OFFSET: LEGO1 0x100991c0
LegoFileStream::LegoFileStream() : LegoStream()
{
@ -113,29 +185,6 @@ MxResult LegoFileStream::Open(const char* p_filename, OpenFlags p_mode)
return (m_hFile = fopen(p_filename, modeString)) ? SUCCESS : FAILURE;
}
// OFFSET: LEGO1 0x10099080
LegoMemoryStream::LegoMemoryStream(char* p_buffer) : LegoStream()
{
m_buffer = p_buffer;
m_offset = 0;
}
// OFFSET: LEGO1 0x10099160
MxResult LegoMemoryStream::Read(void* p_buffer, MxU32 p_size)
{
memcpy(p_buffer, m_buffer + m_offset, p_size);
m_offset += p_size;
return SUCCESS;
}
// OFFSET: LEGO1 0x10099190
MxResult LegoMemoryStream::Write(const void* p_buffer, MxU32 p_size)
{
memcpy(m_buffer + m_offset, p_buffer, p_size);
m_offset += p_size;
return SUCCESS;
}
// OFFSET: LEGO1 0x100994a0
MxResult LegoMemoryStream::Tell(MxU32* p_offset)
{
@ -149,52 +198,3 @@ MxResult LegoMemoryStream::Seek(MxU32 p_offset)
m_offset = p_offset;
return SUCCESS;
}
// OFFSET: LEGO1 0x10039f70
MxResult LegoStream::WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName)
{
MxResult result = FAILURE;
const char* variableValue = p_from->GetVariable(p_variableName);
if (variableValue) {
MxU8 length = strlen(p_variableName);
if (p_stream->Write((char*) &length, 1) == SUCCESS) {
if (p_stream->Write(p_variableName, length) == SUCCESS) {
length = strlen(variableValue);
if (p_stream->Write((char*) &length, 1) == SUCCESS)
result = p_stream->Write((char*) variableValue, length);
}
}
}
return result;
}
// 95% match, just some instruction ordering differences on the call to
// MxVariableTable::SetVariable at the end.
// OFFSET: LEGO1 0x1003a080
MxS32 LegoStream::ReadVariable(LegoStream* p_stream, MxVariableTable* p_to)
{
MxS32 result = 1;
MxU8 length;
if (p_stream->Read((char*) &length, 1) == SUCCESS) {
char nameBuffer[256];
if (p_stream->Read(nameBuffer, length) == SUCCESS) {
nameBuffer[length] = '\0';
if (strcmp(nameBuffer, s_endOfVariables) == 0)
// 2 -> "This was the last entry, done reading."
result = 2;
else {
if (p_stream->Read((char*) &length, 1) == SUCCESS) {
char valueBuffer[256];
if (p_stream->Read(valueBuffer, length) == SUCCESS) {
result = 0;
valueBuffer[length] = '\0';
p_to->SetVariable(nameBuffer, valueBuffer);
}
}
}
}
}
return result;
}

View file

@ -5,6 +5,15 @@
DECOMP_SIZE_ASSERT(LegoVehicleBuildState, 0x50); // 1000acd7
DECOMP_SIZE_ASSERT(LegoVehicleBuildState::UnkStruct, 0xc);
// OFFSET: LEGO1 0x10017c00
LegoVehicleBuildState::UnkStruct::UnkStruct()
{
m_unk04 = 0;
m_unk00 = 0;
m_unk06 = 0;
m_unk08 = 0;
}
// OFFSET: LEGO1 0x10025f30
LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType)
{
@ -14,12 +23,3 @@ LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType)
this->m_unk4e = 0;
this->m_placedPartCount = 0;
}
// OFFSET: LEGO1 10017c00
LegoVehicleBuildState::UnkStruct::UnkStruct()
{
m_unk04 = 0;
m_unk00 = 0;
m_unk06 = 0;
m_unk08 = 0;
}

View file

@ -55,32 +55,6 @@ void LegoVideoManager::Destroy()
delete[] m_prefCounter;
}
// OFFSET: LEGO1 0x1007c560 STUB
int LegoVideoManager::EnableRMDevice()
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1007c740 STUB
int LegoVideoManager::DisableRMDevice()
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1007c300
void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable)
{
EnableFullScreenMovie(p_enable, TRUE);
}
// OFFSET: LEGO1 0x1007c310 STUB
void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale)
{
// TODO
}
// OFFSET: LEGO1 0x1007b6a0
void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY)
{
@ -95,6 +69,18 @@ void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY)
m_cursorY = 463;
}
// OFFSET: LEGO1 0x1007c300
void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable)
{
EnableFullScreenMovie(p_enable, TRUE);
}
// OFFSET: LEGO1 0x1007c310 STUB
void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale)
{
// TODO
}
// OFFSET: LEGO1 0x1007c440
void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue)
{
@ -110,3 +96,17 @@ void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue)
// TODO 3d manager
// m_3dManager->m_pViewport->vtable1c(red, green, blue)
}
// OFFSET: LEGO1 0x1007c560 STUB
int LegoVideoManager::EnableRMDevice()
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1007c740 STUB
int LegoVideoManager::DisableRMDevice()
{
// TODO
return 0;
}

View file

@ -16,22 +16,55 @@ void LegoWorld::VTable0x60()
{
}
// OFFSET: LEGO1 0x10015820 STUB
void FUN_10015820(MxU32 p_unk1, MxU32 p_unk2)
{
// TODO
}
// OFFSET: LEGO1 0x10015910 STUB
void FUN_10015910(MxU32 p_unk1)
{
// TODO
}
// OFFSET: LEGO1 0x100159c0
void SetIsWorldActive(MxBool p_isWorldActive)
{
if (!p_isWorldActive)
LegoOmni::GetInstance()->GetInputManager()->SetCamera(NULL);
g_isWorldActive = p_isWorldActive;
}
// OFFSET: LEGO1 0x1001ca40 STUB
LegoWorld::LegoWorld()
{
// TODO
}
// OFFSET: LEGO1 0x1001d670
MxBool LegoWorld::VTable0x5c()
{
return FALSE;
}
// OFFSET: LEGO1 0x1001d680
MxBool LegoWorld::VTable0x64()
{
return FALSE;
}
// OFFSET: LEGO1 0x1001dfa0 STUB
LegoWorld::~LegoWorld()
{
// TODO
}
// OFFSET: LEGO1 0x10022340
void LegoWorld::Stop()
// OFFSET: LEGO1 0x1001e0b0 STUB
MxResult LegoWorld::SetAsCurrentWorld(MxDSObject& p_dsObject)
{
TickleManager()->UnregisterClient(this);
// TODO
return SUCCESS;
}
// OFFSET: LEGO1 0x1001f5e0
@ -58,27 +91,15 @@ void LegoWorld::VTable0x54()
// TODO
}
// OFFSET: LEGO1 0x10020f10 STUB
void LegoWorld::EndAction(MxPresenter* p_presenter)
{
}
// OFFSET: LEGO1 0x10020220 STUB
void LegoWorld::VTable0x58(MxCore* p_object)
{
// TODO
}
// OFFSET: LEGO1 0x1001d670
MxBool LegoWorld::VTable0x5c()
// OFFSET: LEGO1 0x10020f10 STUB
void LegoWorld::EndAction(MxPresenter* p_presenter)
{
return FALSE;
}
// OFFSET: LEGO1 0x1001d680
MxBool LegoWorld::VTable0x64()
{
return FALSE;
}
// OFFSET: LEGO1 0x10021a70 STUB
@ -87,29 +108,8 @@ void LegoWorld::VTable0x68(MxBool p_add)
// TODO
}
// OFFSET: LEGO1 0x1001e0b0 STUB
MxResult LegoWorld::SetAsCurrentWorld(MxDSObject& p_dsObject)
// OFFSET: LEGO1 0x10022340
void LegoWorld::Stop()
{
// TODO
return SUCCESS;
}
// OFFSET: LEGO1 0x10015820 STUB
void FUN_10015820(MxU32 p_unk1, MxU32 p_unk2)
{
// TODO
}
// OFFSET: LEGO1 0x10015910 STUB
void FUN_10015910(MxU32 p_unk1)
{
// TODO
}
// OFFSET: LEGO1 0x100159c0
void SetIsWorldActive(MxBool p_isWorldActive)
{
if (!p_isWorldActive)
LegoOmni::GetInstance()->GetInputManager()->SetCamera(NULL);
g_isWorldActive = p_isWorldActive;
TickleManager()->UnregisterClient(this);
}

View file

@ -3,6 +3,12 @@
// 0x100f75d4
undefined4 g_LegoWorldPresenterQuality = 1;
// OFFSET: LEGO1 0x100665b0
void LegoWorldPresenter::configureLegoWorldPresenter(int p_quality)
{
g_LegoWorldPresenterQuality = p_quality;
}
// OFFSET: LEGO1 0x100665c0
LegoWorldPresenter::LegoWorldPresenter()
{
@ -14,9 +20,3 @@ LegoWorldPresenter::~LegoWorldPresenter()
{
// TODO
}
// OFFSET: LEGO1 0x100665b0
void LegoWorldPresenter::configureLegoWorldPresenter(int p_quality)
{
g_LegoWorldPresenterQuality = p_quality;
}

View file

@ -5,6 +5,12 @@ DECOMP_SIZE_ASSERT(MxAudioManager, 0x30);
// GLOBAL: LEGO1 0x10102108
MxS32 MxAudioManager::g_unkCount = 0;
// OFFSET: LEGO1 0x10029910
MxS32 MxAudioManager::GetVolume()
{
return this->m_volume;
}
// OFFSET: LEGO1 0x100b8d00
MxAudioManager::MxAudioManager()
{
@ -23,20 +29,6 @@ void MxAudioManager::Init()
this->m_volume = 100;
}
// OFFSET: LEGO1 0x10029910
MxS32 MxAudioManager::GetVolume()
{
return this->m_volume;
}
// OFFSET: LEGO1 0x100b8ea0
void MxAudioManager::SetVolume(MxS32 p_volume)
{
this->m_criticalSection.Enter();
this->m_volume = p_volume;
this->m_criticalSection.Leave();
}
// OFFSET: LEGO1 0x100b8e00
void MxAudioManager::Destroy(MxBool p_fromDestructor)
{
@ -76,3 +68,11 @@ void MxAudioManager::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100b8ea0
void MxAudioManager::SetVolume(MxS32 p_volume)
{
this->m_criticalSection.Enter();
this->m_volume = p_volume;
this->m_criticalSection.Leave();
}

View file

@ -31,70 +31,6 @@ MxBackgroundAudioManager::~MxBackgroundAudioManager()
DestroyMusic();
}
// OFFSET: LEGO1 0x1007f470
void MxBackgroundAudioManager::Stop()
{
if (m_action2.GetObjectId() != -1)
DeleteObject(m_action2);
m_unk138 = 0;
m_action2.SetAtomId(MxAtomId());
m_action2.SetObjectId(-1);
if (m_action1.GetObjectId() != -1)
DeleteObject(m_action1);
m_unka0 = 0;
m_action1.SetAtomId(MxAtomId());
m_unk148 = 0;
m_action1.SetObjectId(-1);
m_unk13c = 0;
}
// OFFSET: LEGO1 0x1007f570
void MxBackgroundAudioManager::LowerVolume()
{
if (m_unk148 == 0) {
if (m_unk13c == 0) {
m_unk13c = 2;
}
m_unk140 = 20;
}
m_unk148++;
}
// OFFSET: LEGO1 0x1007f5b0
void MxBackgroundAudioManager::RaiseVolume()
{
if (m_unk148 != 0) {
m_unk148--;
if (m_unk148 == 0) {
if (m_unk13c == 0) {
m_unk13c = 2;
}
m_unk140 = 10;
}
}
}
// OFFSET: LEGO1 0x1007f5f0
void MxBackgroundAudioManager::Enable(MxBool p)
{
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;
}
// OFFSET: LEGO1 0x1007ece0
MxResult MxBackgroundAudioManager::Create(MxAtomId& p_script, MxU32 p_frequencyMS)
{
@ -137,80 +73,6 @@ void MxBackgroundAudioManager::DestroyMusic()
}
}
// OFFSET: LEGO1 0x1007f170
MxLong MxBackgroundAudioManager::Notify(MxParam& p)
{
switch (((MxNotificationParam&) p).GetNotification()) {
case c_notificationStartAction:
StartAction(p);
return 1;
case c_notificationEndAction:
StopAction(p);
return 1;
}
return 0;
}
// OFFSET: LEGO1 0x1007f1b0
void MxBackgroundAudioManager::StartAction(MxParam& p)
{
// TODO: the sender is most likely a MxAudioPresenter?
m_unk138 = (MxAudioPresenter*) ((MxNotificationParam&) p).GetSender();
m_action2.SetAtomId(m_unk138->GetAction()->GetAtomId());
m_action2.SetObjectId(m_unk138->GetAction()->GetObjectId());
m_targetVolume = ((MxDSSound*) (m_unk138->GetAction()))->GetVolume();
m_unk138->SetVolume(0);
}
// OFFSET: LEGO1 0x1007f200
void MxBackgroundAudioManager::StopAction(MxParam& p)
{
if (((MxNotificationParam&) p).GetSender() == m_unka0) {
m_unka0 = NULL;
m_action1.SetAtomId(MxAtomId());
m_action1.SetObjectId(-1);
}
else if (((MxNotificationParam&) p).GetSender() == m_unk138) {
m_unk138 = NULL;
m_action2.SetAtomId(MxAtomId());
m_action2.SetObjectId(-1);
}
Lego()->HandleNotificationType2(p);
}
// OFFSET: LEGO1 0x1007f2f0
MxResult MxBackgroundAudioManager::PlayMusic(MxDSAction& p_action, undefined4 p_unknown, undefined4 p_unknown2)
{
if (!m_musicEnabled) {
return SUCCESS;
}
if (m_action2.GetObjectId() == -1 && m_action1.GetObjectId() != p_action.GetObjectId()) {
MxDSAction action;
action.SetAtomId(GetCurrentAction().GetAtomId());
action.SetObjectId(GetCurrentAction().GetObjectId());
action.SetUnknown24(GetCurrentAction().GetUnknown24());
m_action2.SetAtomId(p_action.GetAtomId());
m_action2.SetObjectId(p_action.GetObjectId());
m_action2.SetUnknown84(this);
m_action2.SetUnknown8c(this);
MxResult result = Start(&m_action2);
GetCurrentAction().SetAtomId(action.GetAtomId());
GetCurrentAction().SetObjectId(action.GetObjectId());
GetCurrentAction().SetUnknown24(action.GetUnknown24());
if (result == SUCCESS) {
m_unk13c = p_unknown2;
m_unk140 = p_unknown;
}
return result;
}
return FAILURE;
}
// OFFSET: LEGO1 0x1007ee40
MxResult MxBackgroundAudioManager::Tickle()
{
@ -324,3 +186,141 @@ void MxBackgroundAudioManager::FadeInOrFadeOut()
m_unk13c = 0;
}
}
// OFFSET: LEGO1 0x1007f170
MxLong MxBackgroundAudioManager::Notify(MxParam& p)
{
switch (((MxNotificationParam&) p).GetNotification()) {
case c_notificationStartAction:
StartAction(p);
return 1;
case c_notificationEndAction:
StopAction(p);
return 1;
}
return 0;
}
// OFFSET: LEGO1 0x1007f1b0
void MxBackgroundAudioManager::StartAction(MxParam& p)
{
// TODO: the sender is most likely a MxAudioPresenter?
m_unk138 = (MxAudioPresenter*) ((MxNotificationParam&) p).GetSender();
m_action2.SetAtomId(m_unk138->GetAction()->GetAtomId());
m_action2.SetObjectId(m_unk138->GetAction()->GetObjectId());
m_targetVolume = ((MxDSSound*) (m_unk138->GetAction()))->GetVolume();
m_unk138->SetVolume(0);
}
// OFFSET: LEGO1 0x1007f200
void MxBackgroundAudioManager::StopAction(MxParam& p)
{
if (((MxNotificationParam&) p).GetSender() == m_unka0) {
m_unka0 = NULL;
m_action1.SetAtomId(MxAtomId());
m_action1.SetObjectId(-1);
}
else if (((MxNotificationParam&) p).GetSender() == m_unk138) {
m_unk138 = NULL;
m_action2.SetAtomId(MxAtomId());
m_action2.SetObjectId(-1);
}
Lego()->HandleNotificationType2(p);
}
// OFFSET: LEGO1 0x1007f2f0
MxResult MxBackgroundAudioManager::PlayMusic(MxDSAction& p_action, undefined4 p_unknown, undefined4 p_unknown2)
{
if (!m_musicEnabled) {
return SUCCESS;
}
if (m_action2.GetObjectId() == -1 && m_action1.GetObjectId() != p_action.GetObjectId()) {
MxDSAction action;
action.SetAtomId(GetCurrentAction().GetAtomId());
action.SetObjectId(GetCurrentAction().GetObjectId());
action.SetUnknown24(GetCurrentAction().GetUnknown24());
m_action2.SetAtomId(p_action.GetAtomId());
m_action2.SetObjectId(p_action.GetObjectId());
m_action2.SetUnknown84(this);
m_action2.SetUnknown8c(this);
MxResult result = Start(&m_action2);
GetCurrentAction().SetAtomId(action.GetAtomId());
GetCurrentAction().SetObjectId(action.GetObjectId());
GetCurrentAction().SetUnknown24(action.GetUnknown24());
if (result == SUCCESS) {
m_unk13c = p_unknown2;
m_unk140 = p_unknown;
}
return result;
}
return FAILURE;
}
// OFFSET: LEGO1 0x1007f470
void MxBackgroundAudioManager::Stop()
{
if (m_action2.GetObjectId() != -1)
DeleteObject(m_action2);
m_unk138 = 0;
m_action2.SetAtomId(MxAtomId());
m_action2.SetObjectId(-1);
if (m_action1.GetObjectId() != -1)
DeleteObject(m_action1);
m_unka0 = 0;
m_action1.SetAtomId(MxAtomId());
m_unk148 = 0;
m_action1.SetObjectId(-1);
m_unk13c = 0;
}
// OFFSET: LEGO1 0x1007f570
void MxBackgroundAudioManager::LowerVolume()
{
if (m_unk148 == 0) {
if (m_unk13c == 0) {
m_unk13c = 2;
}
m_unk140 = 20;
}
m_unk148++;
}
// OFFSET: LEGO1 0x1007f5b0
void MxBackgroundAudioManager::RaiseVolume()
{
if (m_unk148 != 0) {
m_unk148--;
if (m_unk148 == 0) {
if (m_unk13c == 0) {
m_unk13c = 2;
}
m_unk140 = 10;
}
}
}
// OFFSET: LEGO1 0x1007f5f0
void MxBackgroundAudioManager::Enable(MxBool p)
{
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;
}

View file

@ -10,6 +10,28 @@ DECOMP_SIZE_ASSERT(MxBITMAPINFO, 0x428);
// (1998) GLOBAL: LEGO1 0x10102184
MxU16 g_bitmapSignature = TWOCC('B', 'M');
// Bit mask trick to round up to the nearest multiple of four.
// Pixel data may be stored with padding.
// https://learn.microsoft.com/en-us/windows/win32/medfound/image-stride
inline MxLong AlignToFourByte(MxLong p_value)
{
return (p_value + 3) & -4;
}
// Same as the one from legoutil.h, but flipped the other way
// TODO: While it's not outside the realm of possibility that they
// reimplemented Abs for only this file, that seems odd, right?
inline MxLong _Abs(MxLong p_value)
{
return p_value > 0 ? p_value : -p_value;
}
// OFFSET: LEGO1 0x1004e0d0
int MxBitmap::vtable28(int)
{
return -1;
}
// OFFSET: LEGO1 0x100bc980
MxBitmap::MxBitmap()
{
@ -32,118 +54,6 @@ MxBitmap::~MxBitmap()
delete m_palette;
}
// Bit mask trick to round up to the nearest multiple of four.
// Pixel data may be stored with padding.
// https://learn.microsoft.com/en-us/windows/win32/medfound/image-stride
inline MxLong AlignToFourByte(MxLong p_value)
{
return (p_value + 3) & -4;
}
// Same as the one from legoutil.h, but flipped the other way
// TODO: While it's not outside the realm of possibility that they
// reimplemented Abs for only this file, that seems odd, right?
inline MxLong _Abs(MxLong p_value)
{
return p_value > 0 ? p_value : -p_value;
}
// OFFSET: LEGO1 0x100bcc40
MxResult MxBitmap::ImportBitmap(MxBitmap* p_bitmap)
{
MxResult result = FAILURE;
this->m_info = new MxBITMAPINFO;
if (this->m_info) {
MxLong height = _Abs(p_bitmap->m_bmiHeader->biHeight);
this->m_data = new MxU8[AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height];
if (this->m_data) {
memcpy(this->m_info, p_bitmap->m_info, sizeof(*this->m_info));
height = _Abs(p_bitmap->m_bmiHeader->biHeight);
memcpy(this->m_data, p_bitmap->m_data, AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height);
result = SUCCESS;
this->m_bmiHeader = &this->m_info->bmiHeader;
this->m_paletteData = this->m_info->bmiColors;
}
}
if (result != SUCCESS) {
if (this->m_info) {
delete this->m_info;
this->m_info = NULL;
}
if (this->m_data) {
delete this->m_data;
this->m_data = NULL;
}
}
return result;
}
// OFFSET: LEGO1 0x100bcba0
MxResult MxBitmap::ImportBitmapInfo(MxBITMAPINFO* p_info)
{
MxResult result = FAILURE;
MxLong width = p_info->bmiHeader.biWidth;
MxLong height = p_info->bmiHeader.biHeight;
MxLong size = AlignToFourByte(width) * height;
this->m_info = new MxBITMAPINFO;
if (this->m_info) {
this->m_data = new MxU8[size];
if (this->m_data) {
memcpy(this->m_info, p_info, sizeof(*this->m_info));
this->m_bmiHeader = &this->m_info->bmiHeader;
this->m_paletteData = this->m_info->bmiColors;
result = SUCCESS;
}
}
if (result != SUCCESS) {
if (this->m_info) {
delete this->m_info;
this->m_info = NULL;
}
if (this->m_data) {
delete this->m_data;
this->m_data = NULL;
}
}
return result;
}
// OFFSET: LEGO1 0x100bd450
MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette)
{
MxResult ret = FAILURE;
PALETTEENTRY entries[256];
if (p_palette) {
if (p_palette->GetEntries(entries))
return ret;
}
else {
MxPalette local_pal;
if (local_pal.GetEntries(entries))
return ret;
}
for (MxS32 i = 0; i < 256; i++) {
p_rgbquad[i].rgbRed = entries[i].peRed;
p_rgbquad[i].rgbGreen = entries[i].peGreen;
p_rgbquad[i].rgbBlue = entries[i].peBlue;
p_rgbquad[i].rgbReserved = 0;
}
ret = SUCCESS;
return ret;
}
// OFFSET: LEGO1 0x100bcaa0
MxResult MxBitmap::SetSize(MxS32 p_width, MxS32 p_height, MxPalette* p_palette, MxBool p_isHighColor)
{
@ -189,6 +99,91 @@ MxResult MxBitmap::SetSize(MxS32 p_width, MxS32 p_height, MxPalette* p_palette,
return ret;
}
// OFFSET: LEGO1 0x100bcba0
MxResult MxBitmap::ImportBitmapInfo(MxBITMAPINFO* p_info)
{
MxResult result = FAILURE;
MxLong width = p_info->bmiHeader.biWidth;
MxLong height = p_info->bmiHeader.biHeight;
MxLong size = AlignToFourByte(width) * height;
this->m_info = new MxBITMAPINFO;
if (this->m_info) {
this->m_data = new MxU8[size];
if (this->m_data) {
memcpy(this->m_info, p_info, sizeof(*this->m_info));
this->m_bmiHeader = &this->m_info->bmiHeader;
this->m_paletteData = this->m_info->bmiColors;
result = SUCCESS;
}
}
if (result != SUCCESS) {
if (this->m_info) {
delete this->m_info;
this->m_info = NULL;
}
if (this->m_data) {
delete this->m_data;
this->m_data = NULL;
}
}
return result;
}
// OFFSET: LEGO1 0x100bcc40
MxResult MxBitmap::ImportBitmap(MxBitmap* p_bitmap)
{
MxResult result = FAILURE;
this->m_info = new MxBITMAPINFO;
if (this->m_info) {
MxLong height = _Abs(p_bitmap->m_bmiHeader->biHeight);
this->m_data = new MxU8[AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height];
if (this->m_data) {
memcpy(this->m_info, p_bitmap->m_info, sizeof(*this->m_info));
height = _Abs(p_bitmap->m_bmiHeader->biHeight);
memcpy(this->m_data, p_bitmap->m_data, AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height);
result = SUCCESS;
this->m_bmiHeader = &this->m_info->bmiHeader;
this->m_paletteData = this->m_info->bmiColors;
}
}
if (result != SUCCESS) {
if (this->m_info) {
delete this->m_info;
this->m_info = NULL;
}
if (this->m_data) {
delete this->m_data;
this->m_data = NULL;
}
}
return result;
}
// OFFSET: LEGO1 0x100bcd10
MxLong MxBitmap::Read(const char* p_filename)
{
MxResult result = FAILURE;
HANDLE handle =
CreateFileA(p_filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE && !LoadFile(handle))
result = SUCCESS;
if (handle)
CloseHandle(handle);
return result;
}
// OFFSET: LEGO1 0x100bcd60
MxResult MxBitmap::LoadFile(HANDLE p_handle)
{
@ -236,28 +231,6 @@ MxResult MxBitmap::LoadFile(HANDLE p_handle)
return result;
}
// OFFSET: LEGO1 0x100bcd10
MxLong MxBitmap::Read(const char* p_filename)
{
MxResult result = FAILURE;
HANDLE handle =
CreateFileA(p_filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE && !LoadFile(handle))
result = SUCCESS;
if (handle)
CloseHandle(handle);
return result;
}
// OFFSET: LEGO1 0x1004e0d0
int MxBitmap::vtable28(int)
{
return -1;
}
// OFFSET: LEGO1 0x100bce70 STUB
void MxBitmap::vtable2c(int, int, int, int, int, int, int)
{
@ -393,3 +366,30 @@ MxResult MxBitmap::StretchBits(
SRCCOPY
);
}
// OFFSET: LEGO1 0x100bd450
MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette)
{
MxResult ret = FAILURE;
PALETTEENTRY entries[256];
if (p_palette) {
if (p_palette->GetEntries(entries))
return ret;
}
else {
MxPalette local_pal;
if (local_pal.GetEntries(entries))
return ret;
}
for (MxS32 i = 0; i < 256; i++) {
p_rgbquad[i].rgbRed = entries[i].peRed;
p_rgbquad[i].rgbGreen = entries[i].peGreen;
p_rgbquad[i].rgbBlue = entries[i].peBlue;
p_rgbquad[i].rgbReserved = 0;
}
ret = SUCCESS;
return ret;
}

View file

@ -5,6 +5,14 @@
DECOMP_SIZE_ASSERT(MxCompositePresenter, 0x4c);
// OFFSET: LEGO1 0x1000caf0
MxBool MxCompositePresenter::VTable0x64(undefined4 p_unknown)
{
if (m_compositePresenter)
return m_compositePresenter->VTable0x64(p_unknown);
return TRUE;
}
// OFFSET: LEGO1 0x100b60b0
MxCompositePresenter::MxCompositePresenter()
{
@ -34,11 +42,3 @@ void MxCompositePresenter::VTable0x60(undefined4 p_unknown)
{
// TODO
}
// OFFSET: LEGO1 0x1000caf0
MxBool MxCompositePresenter::VTable0x64(undefined4 p_unknown)
{
if (m_compositePresenter)
return m_compositePresenter->VTable0x64(p_unknown);
return TRUE;
}

View file

@ -2,6 +2,12 @@
#include "define.h"
// OFFSET: LEGO1 0x10001f70
MxResult MxCore::Tickle()
{
return SUCCESS;
}
// OFFSET: LEGO1 0x100ae1a0
MxCore::MxCore()
{
@ -19,9 +25,3 @@ MxLong MxCore::Notify(MxParam& p)
{
return 0;
}
// OFFSET: LEGO1 0x10001f70
MxResult MxCore::Tickle()
{
return SUCCESS;
}

View file

@ -8,6 +8,13 @@
class MxParam;
// TODO: Find proper compilation unit to put these
// OFFSET: LEGO1 0x100140d0 TEMPLATE
// MxCore::IsA
// OFFSET: LEGO1 0x100144c0 TEMPLATE
// MxCore::ClassName
// VTABLE 0x100dc0f8
// SIZE 0x8
class MxCore {
@ -17,14 +24,12 @@ class MxCore {
__declspec(dllexport) virtual MxLong Notify(MxParam& p); // vtable+04
virtual MxResult Tickle(); // vtable+08
// OFFSET: LEGO1 0x100144c0
inline virtual const char* ClassName() const // vtable+0c
{
// 0x100f007c
return "MxCore";
}
// OFFSET: LEGO1 0x100140d0
inline virtual MxBool IsA(const char* name) const // vtable+10
{
return !strcmp(name, MxCore::ClassName());

View file

@ -31,12 +31,6 @@ MxCriticalSection::~MxCriticalSection()
DeleteCriticalSection(&this->m_criticalSection);
}
// OFFSET: LEGO1 0x100b6e00
void MxCriticalSection::SetDoMutex()
{
g_useMutex = 1;
}
// OFFSET: LEGO1 0x100b6d80
void MxCriticalSection::Enter()
{
@ -70,3 +64,9 @@ void MxCriticalSection::Leave()
LeaveCriticalSection(&this->m_criticalSection);
}
// OFFSET: LEGO1 0x100b6e00
void MxCriticalSection::SetDoMutex()
{
g_useMutex = 1;
}

File diff suppressed because it is too large Load diff

View file

@ -17,13 +17,6 @@ MxDiskStreamController::~MxDiskStreamController()
// TODO
}
// OFFSET: LEGO1 0x100c8640 STUB
MxResult MxDiskStreamController::Tickle()
{
// TODO
return SUCCESS;
}
// OFFSET: LEGO1 0x100c7790
MxResult MxDiskStreamController::Open(const char* p_filename)
{
@ -56,17 +49,9 @@ MxResult MxDiskStreamController::vtable0x18(undefined4 p_unknown, undefined4 p_u
return SUCCESS;
}
// OFFSET: LEGO1 0x100c7ff0 STUB
MxResult MxDiskStreamController::vtable0x20(MxDSAction* p_action)
// OFFSET: LEGO1 0x100c7960
MxResult MxDiskStreamController::vtable0x34(undefined4 p_unknown)
{
// TODO
return FAILURE;
}
// OFFSET: LEGO1 0x100c8160 STUB
MxResult MxDiskStreamController::vtable0x24(undefined4 p_unknown)
{
// TODO
return FAILURE;
}
@ -84,8 +69,23 @@ MxResult MxDiskStreamController::vtable0x30(undefined4 p_unknown)
return FAILURE;
}
// OFFSET: LEGO1 0x100c7960
MxResult MxDiskStreamController::vtable0x34(undefined4 p_unknown)
// OFFSET: LEGO1 0x100c7ff0 STUB
MxResult MxDiskStreamController::vtable0x20(MxDSAction* p_action)
{
// TODO
return FAILURE;
}
// OFFSET: LEGO1 0x100c8160 STUB
MxResult MxDiskStreamController::vtable0x24(undefined4 p_unknown)
{
// TODO
return FAILURE;
}
// OFFSET: LEGO1 0x100c8640 STUB
MxResult MxDiskStreamController::Tickle()
{
// TODO
return SUCCESS;
}

View file

@ -70,6 +70,12 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource)
return result;
}
// OFFSET: LEGO1 0x100d15e0 STUB
void MxDiskStreamProvider::vtable0x20(undefined4 p_unknown1)
{
// TODO
}
// OFFSET: LEGO1 0x100d1750
MxResult MxDiskStreamProvider::WaitForWorkToComplete()
{
@ -99,12 +105,6 @@ MxU32 MxDiskStreamProvider::GetStreamBuffersNum()
return m_pFile->GetStreamBuffersNum();
}
// OFFSET: LEGO1 0x100d15e0 STUB
void MxDiskStreamProvider::vtable0x20(undefined4 p_unknown1)
{
// TODO
}
// OFFSET: LEGO1 0x100d1eb0
MxU32 MxDiskStreamProvider::GetLengthInDWords()
{

View file

@ -28,6 +28,12 @@ void MxDisplaySurface::Reset()
memset(&this->m_surfaceDesc, 0, sizeof(this->m_surfaceDesc));
}
// OFFSET: LEGO1 0x100ba640 STUB
void MxDisplaySurface::FUN_100ba640()
{
// TODO
}
// OFFSET: LEGO1 0x100ba790
MxResult MxDisplaySurface::Init(
MxVideoParam& p_videoParam,
@ -178,33 +184,12 @@ void MxDisplaySurface::SetPalette(MxPalette* p_palette)
{
}
// OFFSET: LEGO1 0x100bc200 STUB
void MxDisplaySurface::vtable24(
LPDDSURFACEDESC,
MxBitmap*,
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(LPDDSURFACEDESC, MxBitmap*, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, MxBool)
{
return 0;
}
// OFFSET: LEGO1 0x100bb1d0 STUB
MxBool MxDisplaySurface::vtable30(
undefined4,
@ -253,8 +238,23 @@ undefined4 MxDisplaySurface::vtable44(undefined4, undefined4*, undefined4, undef
return 0;
}
// OFFSET: LEGO1 0x100ba640 STUB
void MxDisplaySurface::FUN_100ba640()
// OFFSET: LEGO1 0x100bc200 STUB
void MxDisplaySurface::vtable24(
LPDDSURFACEDESC,
MxBitmap*,
undefined4,
undefined4,
undefined4,
undefined4,
undefined4,
undefined4
)
{
// TODO
}
// OFFSET: LEGO1 0x100bc630 STUB
MxBool MxDisplaySurface::
vtable2c(LPDDSURFACEDESC, MxBitmap*, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, MxBool)
{
return 0;
}

View file

@ -32,6 +32,36 @@ MxDSAction::MxDSAction()
this->m_unkTimingField = INT_MIN;
}
// OFFSET: LEGO1 0x100ad940
MxLong MxDSAction::GetDuration()
{
return this->m_duration;
}
// OFFSET: LEGO1 0x100ad950
void MxDSAction::SetDuration(MxLong p_duration)
{
this->m_duration = p_duration;
}
// OFFSET: LEGO1 0x100ad960
MxBool MxDSAction::HasId(MxU32 p_objectId)
{
return this->GetObjectId() == p_objectId;
}
// OFFSET: LEGO1 0x100ada40
void MxDSAction::SetUnkTimingField(MxLong p_unkTimingField)
{
this->m_unkTimingField = p_unkTimingField;
}
// OFFSET: LEGO1 0x100ada50
MxLong MxDSAction::GetUnkTimingField()
{
return this->m_unkTimingField;
}
// OFFSET: LEGO1 0x100ada80
MxDSAction::~MxDSAction()
{
@ -58,17 +88,6 @@ void MxDSAction::CopyFrom(MxDSAction& p_dsAction)
this->m_unkTimingField = p_dsAction.m_unkTimingField;
}
// OFFSET: LEGO1 0x100adc10
MxDSAction& MxDSAction::operator=(MxDSAction& p_dsAction)
{
if (this == &p_dsAction)
return *this;
MxDSObject::operator=(p_dsAction);
this->CopyFrom(p_dsAction);
return *this;
}
// OFFSET: LEGO1 0x100adbe0
MxU32 MxDSAction::GetSizeOnDisk()
{
@ -80,42 +99,15 @@ MxU32 MxDSAction::GetSizeOnDisk()
return totalSizeOnDisk;
}
// OFFSET: LEGO1 0x100adf70
void MxDSAction::Deserialize(char** p_source, MxS16 p_unk24)
// OFFSET: LEGO1 0x100adc10
MxDSAction& MxDSAction::operator=(MxDSAction& p_dsAction)
{
MxDSObject::Deserialize(p_source, p_unk24);
if (this == &p_dsAction)
return *this;
GetScalar(p_source, this->m_flags);
GetScalar(p_source, this->m_startTime);
GetScalar(p_source, this->m_duration);
GetScalar(p_source, this->m_loopCount);
GetDouble(p_source, this->m_location[0]);
GetDouble(p_source, this->m_location[1]);
GetDouble(p_source, this->m_location[2]);
GetDouble(p_source, this->m_direction[0]);
GetDouble(p_source, this->m_direction[1]);
GetDouble(p_source, this->m_direction[2]);
GetDouble(p_source, this->m_up[0]);
GetDouble(p_source, this->m_up[1]);
GetDouble(p_source, this->m_up[2]);
MxU16 extraLength = GetScalar((MxU16**) p_source);
if (extraLength) {
AppendData(extraLength, *p_source);
*p_source += extraLength;
}
}
// OFFSET: LEGO1 0x100ad940
MxLong MxDSAction::GetDuration()
{
return this->m_duration;
}
// OFFSET: LEGO1 0x100ad950
void MxDSAction::SetDuration(MxLong p_duration)
{
this->m_duration = p_duration;
MxDSObject::operator=(p_dsAction);
this->CopyFrom(p_dsAction);
return *this;
}
// OFFSET: LEGO1 0x100adc40
@ -129,6 +121,12 @@ MxDSAction* MxDSAction::Clone()
return clone;
}
// OFFSET: LEGO1 0x100adcd0
MxLong MxDSAction::GetElapsedTime()
{
return Timer()->GetTime() - this->m_unkTimingField;
}
// OFFSET: LEGO1 0x100add00
void MxDSAction::MergeFrom(MxDSAction& p_dsAction)
{
@ -178,30 +176,6 @@ void MxDSAction::MergeFrom(MxDSAction& p_dsAction)
}
}
// OFFSET: LEGO1 0x100ad960
MxBool MxDSAction::HasId(MxU32 p_objectId)
{
return this->GetObjectId() == p_objectId;
}
// OFFSET: LEGO1 0x100ada40
void MxDSAction::SetUnkTimingField(MxLong p_unkTimingField)
{
this->m_unkTimingField = p_unkTimingField;
}
// OFFSET: LEGO1 0x100ada50
MxLong MxDSAction::GetUnkTimingField()
{
return this->m_unkTimingField;
}
// OFFSET: LEGO1 0x100adcd0
MxLong MxDSAction::GetElapsedTime()
{
return Timer()->GetTime() - this->m_unkTimingField;
}
// OFFSET: LEGO1 0x100ade60
void MxDSAction::AppendData(MxU16 p_extraLength, const char* p_extraData)
{
@ -229,3 +203,29 @@ void MxDSAction::AppendData(MxU16 p_extraLength, const char* p_extraData)
}
}
}
// OFFSET: LEGO1 0x100adf70
void MxDSAction::Deserialize(char** p_source, MxS16 p_unk24)
{
MxDSObject::Deserialize(p_source, p_unk24);
GetScalar(p_source, this->m_flags);
GetScalar(p_source, this->m_startTime);
GetScalar(p_source, this->m_duration);
GetScalar(p_source, this->m_loopCount);
GetDouble(p_source, this->m_location[0]);
GetDouble(p_source, this->m_location[1]);
GetDouble(p_source, this->m_location[2]);
GetDouble(p_source, this->m_direction[0]);
GetDouble(p_source, this->m_direction[1]);
GetDouble(p_source, this->m_direction[2]);
GetDouble(p_source, this->m_up[0]);
GetDouble(p_source, this->m_up[1]);
GetDouble(p_source, this->m_up[2]);
MxU16 extraLength = GetScalar((MxU16**) p_source);
if (extraLength) {
AppendData(extraLength, *p_source);
*p_source += extraLength;
}
}

View file

@ -5,6 +5,12 @@
#define SI_MAJOR_VERSION 2
#define SI_MINOR_VERSION 2
// OFFSET: LEGO1 0x100bfed0
MxDSFile::~MxDSFile()
{
Close();
}
// OFFSET: LEGO1 0x100cc4b0
MxDSFile::MxDSFile(const char* filename, MxULong skipReadingChunks)
{
@ -12,12 +18,6 @@ MxDSFile::MxDSFile(const char* filename, MxULong skipReadingChunks)
m_skipReadingChunks = skipReadingChunks;
}
// OFFSET: LEGO1 0x100bfed0
MxDSFile::~MxDSFile()
{
Close();
}
// OFFSET: LEGO1 0x100cc590
MxLong MxDSFile::Open(MxULong uStyle)
{
@ -46,16 +46,6 @@ MxLong MxDSFile::Open(MxULong uStyle)
return longResult;
}
// OFFSET: LEGO1 0x100cc780
MxResult MxDSFile::Read(unsigned char* p_buf, MxULong p_nbytes)
{
if (m_io.Read(p_buf, p_nbytes) != p_nbytes)
return FAILURE;
m_position += p_nbytes;
return SUCCESS;
}
// OFFSET: LEGO1 0x100cc620
MxLong MxDSFile::ReadChunks()
{
@ -91,6 +81,30 @@ MxLong MxDSFile::ReadChunks()
}
}
// OFFSET: LEGO1 0x100cc740
MxLong MxDSFile::Close()
{
m_io.Close(0);
m_position = -1;
memset(&m_header, 0, sizeof(m_header));
if (m_lengthInDWords != 0) {
m_lengthInDWords = 0;
delete[] m_pBuffer;
m_pBuffer = NULL;
}
return 0;
}
// OFFSET: LEGO1 0x100cc780
MxResult MxDSFile::Read(unsigned char* p_buf, MxULong p_nbytes)
{
if (m_io.Read(p_buf, p_nbytes) != p_nbytes)
return FAILURE;
m_position += p_nbytes;
return SUCCESS;
}
// OFFSET: LEGO1 0x100cc7b0
MxLong MxDSFile::Seek(MxLong lOffset, int iOrigin)
{
@ -108,17 +122,3 @@ MxULong MxDSFile::GetStreamBuffersNum()
{
return m_header.streamBuffersNum;
}
// OFFSET: LEGO1 0x100cc740
MxLong MxDSFile::Close()
{
m_io.Close(0);
m_position = -1;
memset(&m_header, 0, sizeof(m_header));
if (m_lengthInDWords != 0) {
m_lengthInDWords = 0;
delete[] m_pBuffer;
m_pBuffer = NULL;
}
return 0;
}

View file

@ -47,6 +47,23 @@ MxDSMediaAction& MxDSMediaAction::operator=(MxDSMediaAction& p_dsMediaAction)
return *this;
}
// OFFSET: LEGO1 0x100c8e80
void MxDSMediaAction::CopyMediaSrcPath(const char* p_mediaSrcPath)
{
if (this->m_mediaSrcPath == p_mediaSrcPath)
return;
delete[] this->m_mediaSrcPath;
if (p_mediaSrcPath) {
this->m_mediaSrcPath = new char[strlen(p_mediaSrcPath) + 1];
if (this->m_mediaSrcPath)
strcpy(this->m_mediaSrcPath, p_mediaSrcPath);
}
else
this->m_mediaSrcPath = NULL;
}
// OFFSET: LEGO1 0x100c8f10
MxU32 MxDSMediaAction::GetSizeOnDisk()
{
@ -75,20 +92,3 @@ void MxDSMediaAction::Deserialize(char** p_source, MxS16 p_unk24)
GetScalar(p_source, this->m_paletteManagement);
GetScalar(p_source, this->m_sustainTime);
}
// OFFSET: LEGO1 0x100c8e80
void MxDSMediaAction::CopyMediaSrcPath(const char* p_mediaSrcPath)
{
if (this->m_mediaSrcPath == p_mediaSrcPath)
return;
delete[] this->m_mediaSrcPath;
if (p_mediaSrcPath) {
this->m_mediaSrcPath = new char[strlen(p_mediaSrcPath) + 1];
if (this->m_mediaSrcPath)
strcpy(this->m_mediaSrcPath, p_mediaSrcPath);
}
else
this->m_mediaSrcPath = NULL;
}

View file

@ -6,6 +6,10 @@
#include "mxcore.h"
#include "mxdstypes.h"
// TODO: Find proper compilation unit to put this
// OFFSET: LEGO1 0x10005530 TEMPLATE
// MxDSObject::SetAtomId
// VTABLE 0x100dc868
// SIZE 0x2c
class MxDSObject : public MxCore {
@ -28,11 +32,9 @@ class MxDSObject : public MxCore {
return !strcmp(name, MxDSObject::ClassName()) || MxCore::IsA(name);
}; // vtable+10;
virtual undefined4 unk14(); // vtable+14;
virtual MxU32 GetSizeOnDisk(); // vtable+18;
virtual void Deserialize(char** p_source, MxS16 p_unk24); // vtable+1c;
// OFFSET: ISLE 0x401c40
// OFFSET: LEGO1 0x10005530
virtual undefined4 unk14(); // vtable+14;
virtual MxU32 GetSizeOnDisk(); // vtable+18;
virtual void Deserialize(char** p_source, MxS16 p_unk24); // vtable+1c;
inline virtual void SetAtomId(MxAtomId p_atomId) { this->m_atomId = p_atomId; } // vtable+20;
inline const MxAtomId& GetAtomId() { return this->m_atomId; }

View file

@ -34,23 +34,6 @@ MxDSSound& MxDSSound::operator=(MxDSSound& p_dsSound)
return *this;
}
// OFFSET: LEGO1 0x100c95d0
MxU32 MxDSSound::GetSizeOnDisk()
{
MxU32 totalSizeOnDisk = MxDSMediaAction::GetSizeOnDisk();
this->m_sizeOnDisk = sizeof(this->m_volume);
return totalSizeOnDisk + 4;
}
// OFFSET: LEGO1 0x100c95a0
void MxDSSound::Deserialize(char** p_source, MxS16 p_unk24)
{
MxDSMediaAction::Deserialize(p_source, p_unk24);
GetScalar(p_source, this->m_volume);
}
// OFFSET: LEGO1 0x100c9510
MxDSAction* MxDSSound::Clone()
{
@ -61,3 +44,20 @@ MxDSAction* MxDSSound::Clone()
return clone;
}
// OFFSET: LEGO1 0x100c95a0
void MxDSSound::Deserialize(char** p_source, MxS16 p_unk24)
{
MxDSMediaAction::Deserialize(p_source, p_unk24);
GetScalar(p_source, this->m_volume);
}
// OFFSET: LEGO1 0x100c95d0
MxU32 MxDSSound::GetSizeOnDisk()
{
MxU32 totalSizeOnDisk = MxDSMediaAction::GetSizeOnDisk();
this->m_sizeOnDisk = sizeof(this->m_volume);
return totalSizeOnDisk + 4;
}

View file

@ -14,6 +14,14 @@ MxDSStreamingAction::MxDSStreamingAction(MxDSAction& p_dsAction, MxU32 p_offset)
this->m_bufferOffset = p_offset;
}
// OFFSET: LEGO1 0x100cd090
MxBool MxDSStreamingAction::HasId(MxU32 p_objectId)
{
if (this->m_internalAction)
return this->m_internalAction->HasId(p_objectId);
return FALSE;
}
// OFFSET: LEGO1 0x100cd0d0
MxDSStreamingAction::MxDSStreamingAction(MxDSStreamingAction& p_dsStreamingAction)
{
@ -32,6 +40,20 @@ MxDSStreamingAction::~MxDSStreamingAction()
delete this->m_internalAction;
}
// OFFSET: LEGO1 0x100cd1e0
MxResult MxDSStreamingAction::Init()
{
this->m_unk94 = 0;
this->m_bufferOffset = 0;
this->m_unk9c = 0;
this->m_unka0 = NULL;
this->m_unka4 = NULL;
this->m_unka8 = 0;
this->m_unkac = 2;
this->m_internalAction = NULL;
return SUCCESS;
}
// OFFSET: LEGO1 0x100cd220
MxDSStreamingAction* MxDSStreamingAction::CopyFrom(MxDSStreamingAction& p_dsStreamingAction)
{
@ -48,28 +70,6 @@ MxDSStreamingAction* MxDSStreamingAction::CopyFrom(MxDSStreamingAction& p_dsStre
return this;
}
// OFFSET: LEGO1 0x100cd090
MxBool MxDSStreamingAction::HasId(MxU32 p_objectId)
{
if (this->m_internalAction)
return this->m_internalAction->HasId(p_objectId);
return FALSE;
}
// OFFSET: LEGO1 0x100cd1e0
MxResult MxDSStreamingAction::Init()
{
this->m_unk94 = 0;
this->m_bufferOffset = 0;
this->m_unk9c = 0;
this->m_unka0 = NULL;
this->m_unka4 = NULL;
this->m_unka8 = 0;
this->m_unkac = 2;
this->m_internalAction = NULL;
return SUCCESS;
}
// OFFSET: LEGO1 0x100cd2a0
void MxDSStreamingAction::SetInternalAction(MxDSAction* p_dsAction)
{

View file

@ -2,17 +2,6 @@
DECOMP_SIZE_ASSERT(MxEntity, 0x10)
// OFFSET: LEGO1 0x1001d190
MxEntity::MxEntity()
{
this->m_mxEntityId = -1;
}
// OFFSET: LEGO1 0x1000c110
MxEntity::~MxEntity()
{
}
// OFFSET: LEGO1 0x10001070
MxResult MxEntity::Create(MxS32 p_id, const MxAtomId& p_atom)
{
@ -20,3 +9,14 @@ MxResult MxEntity::Create(MxS32 p_id, const MxAtomId& p_atom)
this->m_atom = p_atom;
return SUCCESS;
}
// OFFSET: LEGO1 0x1000c110
MxEntity::~MxEntity()
{
}
// OFFSET: LEGO1 0x1001d190
MxEntity::MxEntity()
{
this->m_mxEntityId = -1;
}

View file

@ -11,6 +11,12 @@ class MxFlcPresenter : public MxVideoPresenter {
MxFlcPresenter();
virtual ~MxFlcPresenter() override;
// OFFSET: LEGO1 0x1004e200
inline virtual MxBool IsA(const char* name) const override // vtable+0x10
{
return !strcmp(name, MxFlcPresenter::ClassName()) || MxVideoPresenter::IsA(name);
}
// OFFSET: LEGO1 0x100b33f0
inline virtual const char* ClassName() const override // vtable+0xc
{
@ -18,12 +24,6 @@ class MxFlcPresenter : public MxVideoPresenter {
return "MxFlcPresenter";
}
// OFFSET: LEGO1 0x1004e200
inline virtual MxBool IsA(const char* name) const override // vtable+0x10
{
return !strcmp(name, MxFlcPresenter::ClassName()) || MxVideoPresenter::IsA(name);
}
virtual void VTable0x70() override; // vtable+0x70
undefined4* m_unk64;

View file

@ -28,24 +28,6 @@ MxResult MxMediaManager::Init()
return SUCCESS;
}
// OFFSET: LEGO1 0x100b8790
MxResult MxMediaManager::Tickle()
{
MxAutoLocker lock(&this->m_criticalSection);
MxPresenter* presenter;
MxPresenterListCursor cursor(this->m_presenters);
while (cursor.Next(presenter))
presenter->Tickle();
cursor.Reset();
while (cursor.Next(presenter))
presenter->PutData();
return SUCCESS;
}
// OFFSET: LEGO1 0x100b85e0
MxResult MxMediaManager::InitPresenters()
{
@ -72,6 +54,24 @@ void MxMediaManager::Destroy()
Init();
}
// OFFSET: LEGO1 0x100b8790
MxResult MxMediaManager::Tickle()
{
MxAutoLocker lock(&this->m_criticalSection);
MxPresenter* presenter;
MxPresenterListCursor cursor(this->m_presenters);
while (cursor.Next(presenter))
presenter->Tickle();
cursor.Reset();
while (cursor.Next(presenter))
presenter->PutData();
return SUCCESS;
}
// OFFSET: LEGO1 0x100b88c0
void MxMediaManager::AddPresenter(MxPresenter& p_presenter)
{

View file

@ -103,6 +103,69 @@ MxStreamChunk* MxMediaPresenter::NextChunk()
return result;
}
// OFFSET: LEGO1 0x100b5700
MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action)
{
MxResult result = FAILURE;
MxAutoLocker lock(&m_criticalSection);
if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) {
if (m_action->GetFlags() & MxDSAction::Flag_Looping) {
m_chunks = new MxStreamChunkList;
m_cursor = new MxStreamChunkListCursor(m_chunks);
if (!m_chunks && !m_cursor)
goto done;
}
if (p_controller) {
m_subscriber = new MxDSSubscriber;
if (!m_subscriber ||
m_subscriber->FUN_100b7ed0(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS)
goto done;
}
result = SUCCESS;
}
done:
return result;
}
// OFFSET: LEGO1 0x100b5bc0
void MxMediaPresenter::EndAction()
{
MxAutoLocker lock(&m_criticalSection);
if (!m_action)
return;
m_currentChunk = NULL;
if (m_action->GetFlags() & MxDSAction::Flag_World &&
(!m_compositePresenter || !m_compositePresenter->VTable0x64(2))) {
MxPresenter::Enable(FALSE);
SetTickleState(TickleState_Idle);
}
else {
MxDSAction* action = m_action;
MxPresenter::EndAction();
if (m_subscriber) {
delete m_subscriber;
m_subscriber = NULL;
}
if (action && action->GetUnknown8c()) {
NotificationManager()->Send(
action->GetUnknown8c(),
&MxEndActionNotificationParam(c_notificationEndAction, this, action, FALSE)
);
}
}
}
// OFFSET: LEGO1 0x100b5d10
MxResult MxMediaPresenter::Tickle()
{
@ -170,6 +233,20 @@ void MxMediaPresenter::DoneTickle()
EndAction();
}
// OFFSET: LEGO1 0x100b5f10
void MxMediaPresenter::AppendChunk(MxStreamChunk* p_chunk)
{
MxStreamChunk* chunk = new MxStreamChunk;
MxU32 length = p_chunk->GetLength();
chunk->SetLength(length);
chunk->SetData(new MxU8[length]);
chunk->SetTime(p_chunk->GetTime());
memcpy(chunk->GetData(), p_chunk->GetData(), chunk->GetLength());
m_chunks->Append(chunk);
}
// OFFSET: LEGO1 0x100b6030
void MxMediaPresenter::Enable(MxBool p_enable)
{
@ -189,80 +266,3 @@ void MxMediaPresenter::Enable(MxBool p_enable)
}
}
}
// OFFSET: LEGO1 0x100b5700
MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action)
{
MxResult result = FAILURE;
MxAutoLocker lock(&m_criticalSection);
if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) {
if (m_action->GetFlags() & MxDSAction::Flag_Looping) {
m_chunks = new MxStreamChunkList;
m_cursor = new MxStreamChunkListCursor(m_chunks);
if (!m_chunks && !m_cursor)
goto done;
}
if (p_controller) {
m_subscriber = new MxDSSubscriber;
if (!m_subscriber ||
m_subscriber->FUN_100b7ed0(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS)
goto done;
}
result = SUCCESS;
}
done:
return result;
}
// OFFSET: LEGO1 0x100b5bc0
void MxMediaPresenter::EndAction()
{
MxAutoLocker lock(&m_criticalSection);
if (!m_action)
return;
m_currentChunk = NULL;
if (m_action->GetFlags() & MxDSAction::Flag_World &&
(!m_compositePresenter || !m_compositePresenter->VTable0x64(2))) {
MxPresenter::Enable(FALSE);
SetTickleState(TickleState_Idle);
}
else {
MxDSAction* action = m_action;
MxPresenter::EndAction();
if (m_subscriber) {
delete m_subscriber;
m_subscriber = NULL;
}
if (action && action->GetUnknown8c()) {
NotificationManager()->Send(
action->GetUnknown8c(),
&MxEndActionNotificationParam(c_notificationEndAction, this, action, FALSE)
);
}
}
}
// OFFSET: LEGO1 0x100b5f10
void MxMediaPresenter::AppendChunk(MxStreamChunk* p_chunk)
{
MxStreamChunk* chunk = new MxStreamChunk;
MxU32 length = p_chunk->GetLength();
chunk->SetLength(length);
chunk->SetData(new MxU8[length]);
chunk->SetTime(p_chunk->GetTime());
memcpy(chunk->GetData(), p_chunk->GetData(), chunk->GetLength());
m_chunks->Append(chunk);
}

View file

@ -19,24 +19,6 @@ MxMusicManager::~MxMusicManager()
Destroy(TRUE);
}
// OFFSET: LEGO1 0x100c0b20
void MxMusicManager::DeinitializeMIDI()
{
m_criticalSection.Enter();
if (m_MIDIInitialized) {
m_MIDIInitialized = FALSE;
midiStreamStop(m_MIDIStreamH);
midiOutUnprepareHeader((HMIDIOUT) m_MIDIStreamH, m_MIDIHdrP, sizeof(MIDIHDR));
midiOutSetVolume((HMIDIOUT) m_MIDIStreamH, m_MIDIVolume);
midiStreamClose(m_MIDIStreamH);
delete m_MIDIHdrP;
InitData();
}
m_criticalSection.Leave();
}
// OFFSET: LEGO1 0x100c0690
void MxMusicManager::Init()
{
@ -80,19 +62,6 @@ void MxMusicManager::Destroy(MxBool p_fromDestructor)
}
}
// OFFSET: LEGO1 0x100c0930
void MxMusicManager::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100c09a0
MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume)
{
MxS32 result = (p_volume * 0xffff) / 100;
return (result << 0x10) | result;
}
// OFFSET: LEGO1 0x100c07f0
void MxMusicManager::SetMIDIVolume()
{
@ -105,15 +74,6 @@ void MxMusicManager::SetMIDIVolume()
}
}
// OFFSET: LEGO1 0x100c0940
void MxMusicManager::SetVolume(MxS32 p_volume)
{
MxAudioManager::SetVolume(p_volume);
m_criticalSection.Enter();
SetMIDIVolume();
m_criticalSection.Leave();
}
// OFFSET: LEGO1 0x100c0840
MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
{
@ -144,3 +104,43 @@ MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
return status;
}
// OFFSET: LEGO1 0x100c0930
void MxMusicManager::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100c0940
void MxMusicManager::SetVolume(MxS32 p_volume)
{
MxAudioManager::SetVolume(p_volume);
m_criticalSection.Enter();
SetMIDIVolume();
m_criticalSection.Leave();
}
// OFFSET: LEGO1 0x100c09a0
MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume)
{
MxS32 result = (p_volume * 0xffff) / 100;
return (result << 0x10) | result;
}
// OFFSET: LEGO1 0x100c0b20
void MxMusicManager::DeinitializeMIDI()
{
m_criticalSection.Enter();
if (m_MIDIInitialized) {
m_MIDIInitialized = FALSE;
midiStreamStop(m_MIDIStreamH);
midiOutUnprepareHeader((HMIDIOUT) m_MIDIStreamH, m_MIDIHdrP, sizeof(MIDIHDR));
midiOutSetVolume((HMIDIOUT) m_MIDIStreamH, m_MIDIVolume);
midiStreamClose(m_MIDIStreamH);
delete m_MIDIHdrP;
InitData();
}
m_criticalSection.Leave();
}

View file

@ -44,6 +44,47 @@ MxNotificationManager::~MxNotificationManager()
TickleManager()->UnregisterClient(this);
}
// OFFSET: LEGO1 0x100ac600
MxResult MxNotificationManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
{
MxResult result = SUCCESS;
m_queue = new MxNotificationPtrList();
if (m_queue == NULL) {
result = FAILURE;
}
else {
TickleManager()->RegisterClient(this, 10);
}
return result;
}
// OFFSET: LEGO1 0x100ac6c0
MxResult MxNotificationManager::Send(MxCore* p_listener, MxNotificationParam* p_param)
{
MxAutoLocker lock(&m_lock);
if (m_active == FALSE) {
return FAILURE;
}
else {
MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId());
if (it == m_listenerIds.end()) {
return FAILURE;
}
else {
MxNotification* notif = new MxNotification(p_listener, p_param);
if (notif != NULL) {
m_queue->push_back(notif);
return SUCCESS;
}
}
}
return FAILURE;
}
// OFFSET: LEGO1 0x100ac800
MxResult MxNotificationManager::Tickle()
{
@ -73,47 +114,6 @@ MxResult MxNotificationManager::Tickle()
}
}
// OFFSET: LEGO1 0x100ac600
MxResult MxNotificationManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
{
MxResult result = SUCCESS;
m_queue = new MxNotificationPtrList();
if (m_queue == NULL) {
result = FAILURE;
}
else {
TickleManager()->RegisterClient(this, 10);
}
return result;
}
// OFFSET: LEGO1 0x100acd20
void MxNotificationManager::Register(MxCore* p_listener)
{
MxAutoLocker lock(&m_lock);
MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId());
if (it != m_listenerIds.end())
return;
m_listenerIds.push_back(p_listener->GetId());
}
// OFFSET: LEGO1 0x100acdf0
void MxNotificationManager::Unregister(MxCore* p_listener)
{
MxAutoLocker lock(&m_lock);
MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId());
if (it != m_listenerIds.end()) {
m_listenerIds.erase(it);
FlushPending(p_listener);
}
}
// OFFSET: LEGO1 0x100ac990
void MxNotificationManager::FlushPending(MxCore* p_listener)
{
@ -163,27 +163,27 @@ void MxNotificationManager::FlushPending(MxCore* p_listener)
}
}
// OFFSET: LEGO1 0x100ac6c0
MxResult MxNotificationManager::Send(MxCore* p_listener, MxNotificationParam* p_param)
// OFFSET: LEGO1 0x100acd20
void MxNotificationManager::Register(MxCore* p_listener)
{
MxAutoLocker lock(&m_lock);
if (m_active == FALSE) {
return FAILURE;
}
else {
MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId());
if (it == m_listenerIds.end()) {
return FAILURE;
}
else {
MxNotification* notif = new MxNotification(p_listener, p_param);
if (notif != NULL) {
m_queue->push_back(notif);
return SUCCESS;
}
}
}
MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId());
if (it != m_listenerIds.end())
return;
return FAILURE;
m_listenerIds.push_back(p_listener->GetId());
}
// OFFSET: LEGO1 0x100acdf0
void MxNotificationManager::Unregister(MxCore* p_listener)
{
MxAutoLocker lock(&m_lock);
MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId());
if (it != m_listenerIds.end()) {
m_listenerIds.erase(it);
FlushPending(p_listener);
}
}

View file

@ -25,12 +25,115 @@ MxBool g_use3dSound;
// 0x101015b0
MxOmni* MxOmni::g_instance = NULL;
// OFFSET: LEGO1 0x100159e0
void DeleteObjects(MxAtomId* p_id, MxS32 p_first, MxS32 p_last)
{
MxDSAction action;
action.SetAtomId(*p_id);
action.SetUnknown24(-2);
for (MxS32 l_first = p_first, l_last = p_last; l_first <= l_last; l_first++) {
action.SetObjectId(l_first);
DeleteObject(action);
}
}
// OFFSET: LEGO1 0x10058a90
MxBool MxOmni::IsTimerRunning()
{
return m_timerRunning;
}
// OFFSET: LEGO1 0x100acea0
MxObjectFactory* ObjectFactory()
{
return MxOmni::GetInstance()->GetObjectFactory();
}
// OFFSET: LEGO1 0x100aceb0
MxNotificationManager* NotificationManager()
{
return MxOmni::GetInstance()->GetNotificationManager();
}
// OFFSET: LEGO1 0x100acec0
MxTickleManager* TickleManager()
{
return MxOmni::GetInstance()->GetTickleManager();
}
// OFFSET: LEGO1 0x100aced0
MxTimer* Timer()
{
return MxOmni::GetInstance()->GetTimer();
}
// OFFSET: LEGO1 0x100acee0
MxAtomIdCounterSet* AtomIdCounterSet()
{
return MxOmni::GetInstance()->GetAtomIdCounterSet();
}
// OFFSET: LEGO1 0x100acef0
MxStreamer* Streamer()
{
return MxOmni::GetInstance()->GetStreamer();
}
// OFFSET: LEGO1 0x100acf00
MxSoundManager* MSoundManager()
{
return MxOmni::GetInstance()->GetSoundManager();
}
// OFFSET: LEGO1 0x100acf10
MxVideoManager* MVideoManager()
{
return MxOmni::GetInstance()->GetVideoManager();
}
// OFFSET: LEGO1 0x100acf20
MxVariableTable* VariableTable()
{
return MxOmni::GetInstance()->GetVariableTable();
}
// OFFSET: LEGO1 0x100acf30
MxMusicManager* MusicManager()
{
return MxOmni::GetInstance()->GetMusicManager();
}
// OFFSET: LEGO1 0x100acf40
MxEventManager* EventManager()
{
return MxOmni::GetInstance()->GetEventManager();
}
// OFFSET: LEGO1 0x100acf70
MxResult DeleteObject(MxDSAction& p_dsAction)
{
return MxOmni::GetInstance()->DeleteObject(p_dsAction);
}
// OFFSET: LEGO1 0x100aef10
MxOmni::MxOmni()
{
Init();
}
// OFFSET: LEGO1 0x100aefb0
MxEntity* MxOmni::FindWorld(const char*, MxS32, MxPresenter*)
{
return NULL;
}
// OFFSET: LEGO1 0x100aefc0
void MxOmni::NotifyCurrentEntity(MxNotificationParam* p_param)
{
}
// OFFSET: LEGO1 0x100aeff0
MxOmni::~MxOmni()
{
@ -55,130 +158,6 @@ void MxOmni::Init()
m_timerRunning = NULL;
}
// OFFSET: LEGO1 0x100b0090
MxResult MxOmni::Start(MxDSAction* p_dsAction)
{
MxResult result = FAILURE;
if (p_dsAction->GetAtomId().GetInternal() != NULL && p_dsAction->GetObjectId() != -1 && m_streamer != NULL) {
result = m_streamer->FUN_100b99b0(p_dsAction);
}
return result;
}
// OFFSET: LEGO1 0x100b00c0 STUB
MxResult MxOmni::DeleteObject(MxDSAction& p_dsAction)
{
// TODO
return FAILURE;
}
// OFFSET: LEGO1 0x100b09a0
MxBool MxOmni::DoesEntityExist(MxDSAction& p_dsAction)
{
if (m_streamer->FUN_100b9b30(p_dsAction)) {
MxNotificationPtrList* queue = m_notificationManager->GetQueue();
if (!queue || queue->size() == 0)
return TRUE;
}
return FALSE;
}
// OFFSET: LEGO1 0x100b00e0 STUB
void MxOmni::Vtable0x2c()
{
// TODO
}
// OFFSET: LEGO1 0x100aefb0
MxEntity* MxOmni::FindWorld(const char*, MxS32, MxPresenter*)
{
return NULL;
}
// OFFSET: LEGO1 0x100aefc0
void MxOmni::NotifyCurrentEntity(MxNotificationParam* p_param)
{
}
// OFFSET: LEGO1 0x100b09d0
void MxOmni::StartTimer()
{
if (m_timerRunning == FALSE && m_timer != NULL && m_soundManager != NULL) {
m_timer->Start();
m_soundManager->vtable0x34();
m_timerRunning = TRUE;
}
}
// OFFSET: LEGO1 0x100b0a00
void MxOmni::StopTimer()
{
if (m_timerRunning != FALSE && m_timer != NULL && m_soundManager != NULL) {
m_timer->Stop();
m_soundManager->vtable0x38();
m_timerRunning = FALSE;
}
}
// OFFSET: LEGO1 0x10058a90
MxBool MxOmni::IsTimerRunning()
{
return m_timerRunning;
}
// OFFSET: LEGO1 0x100b0690
void MxOmni::DestroyInstance()
{
if (g_instance != NULL) {
delete g_instance;
g_instance = NULL;
}
}
// OFFSET: LEGO1 0x100b0900
const char* MxOmni::GetHD()
{
return g_hdPath;
}
// OFFSET: LEGO1 0x100b0940
const char* MxOmni::GetCD()
{
return g_cdPath;
}
// OFFSET: LEGO1 0x100b0980
MxBool MxOmni::IsSound3D()
{
return g_use3dSound;
}
// OFFSET: LEGO1 0x100b0910
void MxOmni::SetHD(const char* p_hd)
{
strcpy(g_hdPath, p_hd);
}
// OFFSET: LEGO1 0x100b0950
void MxOmni::SetCD(const char* p_cd)
{
strcpy(g_cdPath, p_cd);
}
// OFFSET: LEGO1 0x100b0990
void MxOmni::SetSound3D(MxBool p_3dsound)
{
g_use3dSound = p_3dsound;
}
// OFFSET: LEGO1 0x100b0680
MxOmni* MxOmni::GetInstance()
{
return g_instance;
}
// OFFSET: LEGO1 0x100af0b0
void MxOmni::SetInstance(MxOmni* instance)
{
@ -320,6 +299,45 @@ void MxOmni::Destroy()
Init();
}
// OFFSET: LEGO1 0x100b0090
MxResult MxOmni::Start(MxDSAction* p_dsAction)
{
MxResult result = FAILURE;
if (p_dsAction->GetAtomId().GetInternal() != NULL && p_dsAction->GetObjectId() != -1 && m_streamer != NULL) {
result = m_streamer->FUN_100b99b0(p_dsAction);
}
return result;
}
// OFFSET: LEGO1 0x100b00c0 STUB
MxResult MxOmni::DeleteObject(MxDSAction& p_dsAction)
{
// TODO
return FAILURE;
}
// OFFSET: LEGO1 0x100b00e0 STUB
void MxOmni::Vtable0x2c()
{
// TODO
}
// OFFSET: LEGO1 0x100b0680
MxOmni* MxOmni::GetInstance()
{
return g_instance;
}
// OFFSET: LEGO1 0x100b0690
void MxOmni::DestroyInstance()
{
if (g_instance != NULL) {
delete g_instance;
g_instance = NULL;
}
}
// OFFSET: LEGO1 0x100b07f0
MxLong MxOmni::Notify(MxParam& p)
{
@ -338,88 +356,70 @@ MxResult MxOmni::HandleNotificationType2(MxParam& p_param)
return FAILURE;
}
// OFFSET: LEGO1 0x100acea0
MxObjectFactory* ObjectFactory()
// OFFSET: LEGO1 0x100b0900
const char* MxOmni::GetHD()
{
return MxOmni::GetInstance()->GetObjectFactory();
return g_hdPath;
}
// OFFSET: LEGO1 0x100aceb0
MxNotificationManager* NotificationManager()
// OFFSET: LEGO1 0x100b0910
void MxOmni::SetHD(const char* p_hd)
{
return MxOmni::GetInstance()->GetNotificationManager();
strcpy(g_hdPath, p_hd);
}
// OFFSET: LEGO1 0x100acec0
MxTickleManager* TickleManager()
// OFFSET: LEGO1 0x100b0940
const char* MxOmni::GetCD()
{
return MxOmni::GetInstance()->GetTickleManager();
return g_cdPath;
}
// OFFSET: LEGO1 0x100aced0
MxTimer* Timer()
// OFFSET: LEGO1 0x100b0950
void MxOmni::SetCD(const char* p_cd)
{
return MxOmni::GetInstance()->GetTimer();
strcpy(g_cdPath, p_cd);
}
// OFFSET: LEGO1 0x100acee0
MxAtomIdCounterSet* AtomIdCounterSet()
// OFFSET: LEGO1 0x100b0980
MxBool MxOmni::IsSound3D()
{
return MxOmni::GetInstance()->GetAtomIdCounterSet();
return g_use3dSound;
}
// OFFSET: LEGO1 0x100acef0
MxStreamer* Streamer()
// OFFSET: LEGO1 0x100b0990
void MxOmni::SetSound3D(MxBool p_3dsound)
{
return MxOmni::GetInstance()->GetStreamer();
g_use3dSound = p_3dsound;
}
// OFFSET: LEGO1 0x100acf00
MxSoundManager* MSoundManager()
// OFFSET: LEGO1 0x100b09a0
MxBool MxOmni::DoesEntityExist(MxDSAction& p_dsAction)
{
return MxOmni::GetInstance()->GetSoundManager();
if (m_streamer->FUN_100b9b30(p_dsAction)) {
MxNotificationPtrList* queue = m_notificationManager->GetQueue();
if (!queue || queue->size() == 0)
return TRUE;
}
return FALSE;
}
// OFFSET: LEGO1 0x100acf10
MxVideoManager* MVideoManager()
// OFFSET: LEGO1 0x100b09d0
void MxOmni::StartTimer()
{
return MxOmni::GetInstance()->GetVideoManager();
}
// OFFSET: LEGO1 0x100acf20
MxVariableTable* VariableTable()
{
return MxOmni::GetInstance()->GetVariableTable();
}
// OFFSET: LEGO1 0x100acf30
MxMusicManager* MusicManager()
{
return MxOmni::GetInstance()->GetMusicManager();
}
// OFFSET: LEGO1 0x100acf40
MxEventManager* EventManager()
{
return MxOmni::GetInstance()->GetEventManager();
}
// OFFSET: LEGO1 0x100acf70
MxResult DeleteObject(MxDSAction& p_dsAction)
{
return MxOmni::GetInstance()->DeleteObject(p_dsAction);
}
// OFFSET: LEGO1 0x100159e0
void DeleteObjects(MxAtomId* p_id, MxS32 p_first, MxS32 p_last)
{
MxDSAction action;
action.SetAtomId(*p_id);
action.SetUnknown24(-2);
for (MxS32 l_first = p_first, l_last = p_last; l_first <= l_last; l_first++) {
action.SetObjectId(l_first);
DeleteObject(action);
if (m_timerRunning == FALSE && m_timer != NULL && m_soundManager != NULL) {
m_timer->Start();
m_soundManager->vtable0x34();
m_timerRunning = TRUE;
}
}
// OFFSET: LEGO1 0x100b0a00
void MxOmni::StopTimer()
{
if (m_timerRunning != FALSE && m_timer != NULL && m_soundManager != NULL) {
m_timer->Stop();
m_soundManager->vtable0x38();
m_timerRunning = FALSE;
}
}

View file

@ -80,7 +80,7 @@ MxPalette::MxPalette()
this->m_skyColor = this->m_entries[141];
}
// OFFSET: LEGO1 0x100BEED0
// OFFSET: LEGO1 0x100beed0
MxPalette::MxPalette(const RGBQUAD* p_colors)
{
this->m_overrideSkyColor = FALSE;
@ -97,7 +97,7 @@ MxPalette::MxPalette(const RGBQUAD* p_colors)
this->m_skyColor = this->m_entries[141];
}
// OFFSET: LEGO1 100bef90
// OFFSET: LEGO1 0x100bef90
MxPalette::~MxPalette()
{
if (m_palette) {
@ -105,21 +105,30 @@ MxPalette::~MxPalette()
}
}
// OFFSET: LEGO1 0x100bf390
void MxPalette::ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries)
// OFFSET: LEGO1 0x100bf000
LPDIRECTDRAWPALETTE MxPalette::CreateNativePalette()
{
HDC hdc;
MxS32 i;
if (this->m_palette == NULL) {
for (i = 0; i < 10; i++)
this->m_entries[i].peFlags = 0x80;
for (i = 10; i < 136; i++)
this->m_entries[i].peFlags = 0x44;
for (i = 136; i < 140; i++)
this->m_entries[i].peFlags = 0x84;
this->m_entries[140].peFlags = 0x84;
this->m_entries[141].peFlags = 0x44;
for (i = 142; i < 246; i++)
this->m_entries[i].peFlags = 0x84;
for (i = 246; i < 256; i++)
this->m_entries[i].peFlags = 0x80;
hdc = GetDC(0);
if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) {
GetSystemPaletteEntries(hdc, 0, 10, p_entries);
GetSystemPaletteEntries(hdc, 246, 10, &p_entries[246]);
if (MVideoManager() && MVideoManager()->GetDirectDraw()) {
MVideoManager()->GetDirectDraw()->CreatePalette(4, this->m_entries, &this->m_palette, NULL);
}
}
else {
memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 10);
memcpy(&p_entries[246], &g_defaultPaletteEntries[246], sizeof(PALETTEENTRY) * 10);
}
ReleaseDC(0, hdc);
return this->m_palette;
}
// OFFSET: LEGO1 0x100bf0b0
@ -131,23 +140,6 @@ MxPalette* MxPalette::Clone()
return result;
}
// OFFSET: LEGO1 0x100bf420
void MxPalette::GetDefaultPalette(LPPALETTEENTRY p_entries)
{
HDC hdc;
hdc = GetDC(0);
if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) {
GetSystemPaletteEntries(hdc, 0, 256, p_entries);
memcpy(&p_entries[10], &g_defaultPaletteEntries[10], sizeof(PALETTEENTRY) * 236);
}
else {
memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 256);
}
ReleaseDC(0, hdc);
}
// OFFSET: LEGO1 0x100bf150
MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries)
{
@ -155,26 +147,6 @@ MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries)
return SUCCESS;
}
// OFFSET: LEGO1 0x100bf340
MxBool MxPalette::operator==(MxPalette& other)
{
for (MxS32 i = 0; i < 256; i++) {
if (this->m_entries[i].peRed != other.m_entries[i].peRed)
return FALSE;
if (this->m_entries[i].peGreen != other.m_entries[i].peGreen)
return FALSE;
if (this->m_entries[i].peBlue != other.m_entries[i].peBlue)
return FALSE;
}
return TRUE;
}
// OFFSET: LEGO1 0x100bf330
void MxPalette::Detach()
{
this->m_palette = NULL;
}
// OFFSET: LEGO1 0x100bf170
MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries)
{
@ -240,7 +212,61 @@ MxResult MxPalette::SetSkyColor(LPPALETTEENTRY p_sky_color)
return status;
}
// OFFSET: LEGO1 0x100BF490
// OFFSET: LEGO1 0x100bf330
void MxPalette::Detach()
{
this->m_palette = NULL;
}
// OFFSET: LEGO1 0x100bf340
MxBool MxPalette::operator==(MxPalette& other)
{
for (MxS32 i = 0; i < 256; i++) {
if (this->m_entries[i].peRed != other.m_entries[i].peRed)
return FALSE;
if (this->m_entries[i].peGreen != other.m_entries[i].peGreen)
return FALSE;
if (this->m_entries[i].peBlue != other.m_entries[i].peBlue)
return FALSE;
}
return TRUE;
}
// OFFSET: LEGO1 0x100bf390
void MxPalette::ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries)
{
HDC hdc;
hdc = GetDC(0);
if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) {
GetSystemPaletteEntries(hdc, 0, 10, p_entries);
GetSystemPaletteEntries(hdc, 246, 10, &p_entries[246]);
}
else {
memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 10);
memcpy(&p_entries[246], &g_defaultPaletteEntries[246], sizeof(PALETTEENTRY) * 10);
}
ReleaseDC(0, hdc);
}
// OFFSET: LEGO1 0x100bf420
void MxPalette::GetDefaultPalette(LPPALETTEENTRY p_entries)
{
HDC hdc;
hdc = GetDC(0);
if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) {
GetSystemPaletteEntries(hdc, 0, 256, p_entries);
memcpy(&p_entries[10], &g_defaultPaletteEntries[10], sizeof(PALETTEENTRY) * 236);
}
else {
memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 256);
}
ReleaseDC(0, hdc);
}
// OFFSET: LEGO1 0x100bf490
void MxPalette::Reset(MxBool p_ignoreSkyColor)
{
if (this->m_palette != NULL) {
@ -252,29 +278,3 @@ void MxPalette::Reset(MxBool p_ignoreSkyColor)
this->m_palette->SetEntries(0, 0, 256, this->m_entries);
}
}
// OFFSET: LEGO1 0x100BF000
LPDIRECTDRAWPALETTE MxPalette::CreateNativePalette()
{
MxS32 i;
if (this->m_palette == NULL) {
for (i = 0; i < 10; i++)
this->m_entries[i].peFlags = 0x80;
for (i = 10; i < 136; i++)
this->m_entries[i].peFlags = 0x44;
for (i = 136; i < 140; i++)
this->m_entries[i].peFlags = 0x84;
this->m_entries[140].peFlags = 0x84;
this->m_entries[141].peFlags = 0x44;
for (i = 142; i < 246; i++)
this->m_entries[i].peFlags = 0x84;
for (i = 246; i < 256; i++)
this->m_entries[i].peFlags = 0x80;
if (MVideoManager() && MVideoManager()->GetDirectDraw()) {
MVideoManager()->GetDirectDraw()->CreatePalette(4, this->m_entries, &this->m_palette, NULL);
}
}
return this->m_palette;
}

View file

@ -16,6 +16,97 @@
DECOMP_SIZE_ASSERT(MxPresenter, 0x40);
// OFFSET: LEGO1 0x1000be30
void MxPresenter::VTable0x14()
{
}
// OFFSET: LEGO1 0x1000be40
void MxPresenter::ReadyTickle()
{
ParseExtra();
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Starting;
}
// OFFSET: LEGO1 0x1000be60
void MxPresenter::StartingTickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Streaming;
}
// OFFSET: LEGO1 0x1000be80
void MxPresenter::StreamingTickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Repeating;
}
// OFFSET: LEGO1 0x1000bea0
void MxPresenter::RepeatingTickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_unk5;
}
// OFFSET: LEGO1 0x1000bec0
void MxPresenter::Unk5Tickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Done;
}
// OFFSET: LEGO1 0x1000bee0
void MxPresenter::DoneTickle()
{
m_previousTickleStates |= 1 << m_currentTickleState;
m_currentTickleState = TickleState_Idle;
}
// OFFSET: LEGO1 0x1000bf00
MxPresenter::~MxPresenter()
{
}
// OFFSET: LEGO1 0x1000bf70
MxResult MxPresenter::AddToManager()
{
return SUCCESS;
}
// OFFSET: LEGO1 0x1000bf80
void MxPresenter::Destroy()
{
Init();
}
// OFFSET: LEGO1 0x1000bf90
void MxPresenter::SetTickleState(TickleState p_tickleState)
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = p_tickleState;
}
// OFFSET: LEGO1 0x1000bfb0
MxBool MxPresenter::HasTickleStatePassed(TickleState p_tickleState)
{
return m_previousTickleStates & (1 << (unsigned char) p_tickleState);
}
// OFFSET: LEGO1 0x1000bfc0
undefined4 MxPresenter::PutData()
{
return 0;
}
// OFFSET: LEGO1 0x1000bfd0
MxBool MxPresenter::IsHit(MxS32 p_x, MxS32 p_y)
{
return FALSE;
}
// OFFSET: LEGO1 0x100b4d50
void MxPresenter::Init()
{
@ -27,6 +118,44 @@ void MxPresenter::Init()
m_previousTickleStates = 0;
}
// OFFSET: LEGO1 0x100b4d80
MxResult MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action)
{
MxAutoLocker lock(&this->m_criticalSection);
this->m_action = p_action;
const Vector3Data& location = this->m_action->GetLocation();
MxS32 previousTickleState = this->m_currentTickleState;
this->m_location = MxPoint32(this->m_action->GetLocation()[0], this->m_action->GetLocation()[1]);
this->m_displayZ = this->m_action->GetLocation()[2];
this->m_previousTickleStates |= 1 << (unsigned char) previousTickleState;
this->m_currentTickleState = TickleState_Ready;
return SUCCESS;
}
// OFFSET: LEGO1 0x100b4e40
void MxPresenter::EndAction()
{
if (this->m_action == FALSE)
return;
MxAutoLocker lock(&this->m_criticalSection);
if (!this->m_compositePresenter) {
MxOmni::GetInstance()->NotifyCurrentEntity(
&MxEndActionNotificationParam(c_notificationEndAction, NULL, this->m_action, TRUE)
);
}
this->m_action = FALSE;
MxS32 previousTickleState = 1 << m_currentTickleState;
this->m_previousTickleStates |= previousTickleState;
this->m_currentTickleState = TickleState_Idle;
}
// OFFSET: LEGO1 0x100b4fc0
void MxPresenter::ParseExtra()
{
@ -71,11 +200,6 @@ void MxPresenter::SendToCompositePresenter(MxOmni* p_omni)
}
}
// OFFSET: LEGO1 0x1000bf00
MxPresenter::~MxPresenter()
{
}
// OFFSET: LEGO1 0x100b5200
MxResult MxPresenter::Tickle()
{
@ -116,44 +240,6 @@ MxResult MxPresenter::Tickle()
return SUCCESS;
}
// OFFSET: LEGO1 0x100b4d80
MxResult MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action)
{
MxAutoLocker lock(&this->m_criticalSection);
this->m_action = p_action;
const Vector3Data& location = this->m_action->GetLocation();
MxS32 previousTickleState = this->m_currentTickleState;
this->m_location = MxPoint32(this->m_action->GetLocation()[0], this->m_action->GetLocation()[1]);
this->m_displayZ = this->m_action->GetLocation()[2];
this->m_previousTickleStates |= 1 << (unsigned char) previousTickleState;
this->m_currentTickleState = TickleState_Ready;
return SUCCESS;
}
// OFFSET: LEGO1 0x100b4e40
void MxPresenter::EndAction()
{
if (this->m_action == FALSE)
return;
MxAutoLocker lock(&this->m_criticalSection);
if (!this->m_compositePresenter) {
MxOmni::GetInstance()->NotifyCurrentEntity(
&MxEndActionNotificationParam(c_notificationEndAction, NULL, this->m_action, TRUE)
);
}
this->m_action = FALSE;
MxS32 previousTickleState = 1 << m_currentTickleState;
this->m_previousTickleStates |= previousTickleState;
this->m_currentTickleState = TickleState_Idle;
}
// OFFSET: LEGO1 0x100b52d0
void MxPresenter::Enable(MxBool p_enable)
{
@ -223,89 +309,3 @@ MxBool MxPresenter::IsEnabled()
{
return this->m_action && this->m_action->GetFlags() & MxDSAction::Flag_Enabled;
}
// OFFSET: LEGO1 0x1000be30
void MxPresenter::VTable0x14()
{
}
// OFFSET: LEGO1 0x1000be40
void MxPresenter::ReadyTickle()
{
ParseExtra();
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Starting;
}
// OFFSET: LEGO1 0x1000be60
void MxPresenter::StartingTickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Streaming;
}
// OFFSET: LEGO1 0x1000be80
void MxPresenter::StreamingTickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Repeating;
}
// OFFSET: LEGO1 0x1000bea0
void MxPresenter::RepeatingTickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_unk5;
}
// OFFSET: LEGO1 0x1000bec0
void MxPresenter::Unk5Tickle()
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Done;
}
// OFFSET: LEGO1 0x1000bee0
void MxPresenter::DoneTickle()
{
m_previousTickleStates |= 1 << m_currentTickleState;
m_currentTickleState = TickleState_Idle;
}
// OFFSET: LEGO1 0x1000bf70
MxResult MxPresenter::AddToManager()
{
return SUCCESS;
}
// OFFSET: LEGO1 0x1000bf80
void MxPresenter::Destroy()
{
Init();
}
// OFFSET: LEGO1 0x1000bf90
void MxPresenter::SetTickleState(TickleState p_tickleState)
{
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = p_tickleState;
}
// OFFSET: LEGO1 0x1000bfb0
MxBool MxPresenter::HasTickleStatePassed(TickleState p_tickleState)
{
return m_previousTickleStates & (1 << (unsigned char) p_tickleState);
}
// OFFSET: LEGO1 0x1000bfc0
undefined4 MxPresenter::PutData()
{
return 0;
}
// OFFSET: LEGO1 0x1000bfd0
MxBool MxPresenter::IsHit(MxS32 p_x, MxS32 p_y)
{
return FALSE;
}

View file

@ -5,11 +5,7 @@
DECOMP_SIZE_ASSERT(MxRAMStreamController, 0x98);
// OFFSET: LEGO1 0x100d0d80 STUB
undefined* __cdecl FUN_100d0d80(MxU32* p_fileSizeBuffer, MxU32 p_fileSize)
{
return NULL;
}
undefined* __cdecl FUN_100d0d80(MxU32* p_fileSizeBuffer, MxU32 p_fileSize);
// OFFSET: LEGO1 0x100c6110
MxResult MxRAMStreamController::Open(const char* p_filename)
@ -52,3 +48,9 @@ MxResult MxRAMStreamController::vtable0x24(undefined4 p_unknown)
// TODO STUB
return FAILURE;
}
// OFFSET: LEGO1 0x100d0d80 STUB
undefined* __cdecl FUN_100d0d80(MxU32* p_fileSizeBuffer, MxU32 p_fileSize)
{
return NULL;
}

View file

@ -14,27 +14,6 @@ MxRAMStreamProvider::MxRAMStreamProvider()
m_bufferForDWords = NULL;
}
// OFFSET: LEGO1 0x100d0a50
MxRAMStreamProvider::~MxRAMStreamProvider()
{
m_bufferSize = 0;
m_fileSize = 0;
free(m_pBufferOfFileSize);
m_pBufferOfFileSize = NULL;
m_lengthInDWords = 0;
free(m_bufferForDWords);
m_bufferForDWords = NULL;
}
// OFFSET: LEGO1 0x100d0ae0 STUB
MxResult MxRAMStreamProvider::SetResourceToGet(MxStreamController* p_resource)
{
return FAILURE;
}
// OFFSET: LEGO1 0x100d0930
MxU32 MxRAMStreamProvider::GetFileSize()
{
@ -58,3 +37,24 @@ MxU32* MxRAMStreamProvider::GetBufferForDWords()
{
return m_bufferForDWords;
}
// OFFSET: LEGO1 0x100d0a50
MxRAMStreamProvider::~MxRAMStreamProvider()
{
m_bufferSize = 0;
m_fileSize = 0;
free(m_pBufferOfFileSize);
m_pBufferOfFileSize = NULL;
m_lengthInDWords = 0;
free(m_bufferForDWords);
m_bufferForDWords = NULL;
}
// OFFSET: LEGO1 0x100d0ae0 STUB
MxResult MxRAMStreamProvider::SetResourceToGet(MxStreamController* p_resource)
{
return FAILURE;
}

View file

@ -2,6 +2,12 @@
#include "mxregion.h"
// OFFSET: LEGO1 0x100c32e0 TEMPLATE
// MxCollection<MxRegionTopBottom *>::Compare
// OFFSET: LEGO1 0x100c3340 TEMPLATE
// MxCollection<MxRegionTopBottom *>::Destroy
// OFFSET: LEGO1 0x100c33e0
void MxRegionList::Destroy(MxRegionTopBottom* p_topBottom)
{
@ -12,18 +18,6 @@ void MxRegionList::Destroy(MxRegionTopBottom* p_topBottom)
}
}
// OFFSET: LEGO1 0x100c4e80
void MxRegionLeftRightList::Destroy(MxRegionLeftRight* p_leftRight)
{
delete p_leftRight;
}
// OFFSET: LEGO1 0x100c32e0 TEMPLATE
// MxCollection<MxRegionTopBottom *>::Compare
// OFFSET: LEGO1 0x100c3340 TEMPLATE
// MxCollection<MxRegionTopBottom *>::Destroy
// OFFSET: LEGO1 0x100c34d0 TEMPLATE
// MxCollection<MxRegionTopBottom *>::`scalar deleting destructor'
@ -39,6 +33,12 @@ void MxRegionLeftRightList::Destroy(MxRegionLeftRight* p_leftRight)
// OFFSET: LEGO1 0x100c4de0 TEMPLATE
// MxCollection<MxRegionLeftRight *>::Destroy
// OFFSET: LEGO1 0x100c4e80
void MxRegionLeftRightList::Destroy(MxRegionLeftRight* p_leftRight)
{
delete p_leftRight;
}
// OFFSET: LEGO1 0x100c4f50 TEMPLATE
// MxCollection<MxRegionLeftRight *>::`scalar deleting destructor'

View file

@ -41,6 +41,11 @@ void MxSmkPresenter::Destroy(MxBool p_fromDestructor)
}
}
// OFFSET: LEGO1 0x100b3940 STUB
void MxSmkPresenter::VTable0x5c(undefined4 p_unknown1)
{
}
// OFFSET: LEGO1 0x100b3960
void MxSmkPresenter::VTable0x60()
{
@ -52,45 +57,11 @@ void MxSmkPresenter::VTable0x60()
m_bitmap->SetSize(m_mxSmack.m_smack.m_width, m_mxSmack.m_smack.m_height, NULL, FALSE);
}
// OFFSET: LEGO1 0x100c5d40
void MxSmkPresenter::FUN_100c5d40(MxSmack* p_mxSmack)
{
if (p_mxSmack->m_unk0x6a0)
delete p_mxSmack->m_unk0x6a0;
if (p_mxSmack->m_unk0x6a4)
delete p_mxSmack->m_unk0x6a4;
if (p_mxSmack->m_unk0x6a8)
delete p_mxSmack->m_unk0x6a8;
if (p_mxSmack->m_unk0x6ac)
delete p_mxSmack->m_unk0x6ac;
if (p_mxSmack->m_unk0x6b4)
delete p_mxSmack->m_unk0x6b4;
}
// OFFSET: LEGO1 0x100b4300
void MxSmkPresenter::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100b3940 STUB
void MxSmkPresenter::VTable0x5c(undefined4 p_unknown1)
{
}
// OFFSET: LEGO1 0x100b3a00 STUB
void MxSmkPresenter::VTable0x68(undefined4 p_unknown1)
{
}
// OFFSET: LEGO1 0x100b42c0
void MxSmkPresenter::VTable0x70()
{
MxPalette* palette = m_bitmap->CreatePalette();
MVideoManager()->RealizePalette(palette);
delete palette;
}
// OFFSET: LEGO1 0x100b4260
MxU32 MxSmkPresenter::VTable0x88()
{
@ -111,3 +82,32 @@ MxU32 MxSmkPresenter::VTable0x88()
return result;
}
}
// OFFSET: LEGO1 0x100b42c0
void MxSmkPresenter::VTable0x70()
{
MxPalette* palette = m_bitmap->CreatePalette();
MVideoManager()->RealizePalette(palette);
delete palette;
}
// OFFSET: LEGO1 0x100b4300
void MxSmkPresenter::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100c5d40
void MxSmkPresenter::FUN_100c5d40(MxSmack* p_mxSmack)
{
if (p_mxSmack->m_unk0x6a0)
delete p_mxSmack->m_unk0x6a0;
if (p_mxSmack->m_unk0x6a4)
delete p_mxSmack->m_unk0x6a4;
if (p_mxSmack->m_unk0x6a8)
delete p_mxSmack->m_unk0x6a8;
if (p_mxSmack->m_unk0x6ac)
delete p_mxSmack->m_unk0x6ac;
if (p_mxSmack->m_unk0x6b4)
delete p_mxSmack->m_unk0x6b4;
}

View file

@ -6,6 +6,24 @@
DECOMP_SIZE_ASSERT(MxNextActionDataStart, 0x14)
// OFFSET: LEGO1 0x100b9400
MxResult MxStreamController::vtable0x18(undefined4 p_unknown, undefined4 p_unknown2)
{
return FAILURE;
}
// OFFSET: LEGO1 0x100b9410
MxResult MxStreamController::vtable0x1C(undefined4 p_unknown, undefined4 p_unknown2)
{
return FAILURE;
}
// OFFSET: LEGO1 0x100b9420
MxResult MxStreamController::vtable0x28()
{
return SUCCESS;
}
// OFFSET: LEGO1 0x100c0b90 STUB
MxStreamController::MxStreamController()
{
@ -18,13 +36,6 @@ MxStreamController::~MxStreamController()
// TODO
}
// OFFSET: LEGO1 0x100c20d0 STUB
MxBool MxStreamController::FUN_100c20d0(MxDSObject& p_obj)
{
// TODO
return TRUE;
}
// OFFSET: LEGO1 0x100c1520
MxResult MxStreamController::Open(const char* p_filename)
{
@ -36,18 +47,6 @@ MxResult MxStreamController::Open(const char* p_filename)
return SUCCESS;
}
// OFFSET: LEGO1 0x100b9400
MxResult MxStreamController::vtable0x18(undefined4 p_unknown, undefined4 p_unknown2)
{
return FAILURE;
}
// OFFSET: LEGO1 0x100b9410
MxResult MxStreamController::vtable0x1C(undefined4 p_unknown, undefined4 p_unknown2)
{
return FAILURE;
}
// OFFSET: LEGO1 0x100c1690
MxResult MxStreamController::vtable0x20(MxDSAction* p_action)
{
@ -89,10 +88,10 @@ MxResult MxStreamController::FUN_100c1800(MxDSAction* p_action, MxU32 p_val)
return FAILURE;
}
// OFFSET: LEGO1 0x100b9420
MxResult MxStreamController::vtable0x28()
// OFFSET: LEGO1 0x100c1a00 STUB
MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval)
{
return SUCCESS;
return FAILURE;
}
// OFFSET: LEGO1 0x100c1c10
@ -111,8 +110,9 @@ MxResult MxStreamController::vtable0x30(undefined4 p_unknown)
return FAILURE;
}
// OFFSET: LEGO1 0x100c1a00 STUB
MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval)
// OFFSET: LEGO1 0x100c20d0 STUB
MxBool MxStreamController::FUN_100c20d0(MxDSObject& p_obj)
{
return FAILURE;
// TODO
return TRUE;
}

View file

@ -6,11 +6,34 @@
#include <process.h>
// OFFSET: LEGO1 0x100bf690
MxResult MxThread::Run()
// OFFSET: LEGO1 0x100b8bb0
MxTickleThread::MxTickleThread(MxCore* p_target, int p_frequencyMS)
{
m_semaphore.Release(1);
return SUCCESS;
m_target = p_target;
m_frequencyMS = p_frequencyMS;
}
// Match except for register allocation
// OFFSET: LEGO1 0x100b8c90
MxResult MxTickleThread::Run()
{
MxTimer* timer = Timer();
int lastTickled = -m_frequencyMS;
while (IsRunning()) {
int currentTime = timer->GetTime();
if (currentTime < lastTickled) {
lastTickled = -m_frequencyMS;
}
int timeRemainingMS = (m_frequencyMS - currentTime) + lastTickled;
if (timeRemainingMS <= 0) {
m_target->Tickle();
timeRemainingMS = 0;
lastTickled = currentTime;
}
Sleep(timeRemainingMS);
}
return MxThread::Run();
}
// OFFSET: LEGO1 0x100bf510
@ -42,6 +65,12 @@ MxResult MxThread::Start(int p_stack, int p_flag)
return result;
}
// OFFSET: LEGO1 0x100bf660
void MxThread::Sleep(MxS32 p_milliseconds)
{
::Sleep(p_milliseconds);
}
// OFFSET: LEGO1 0x100bf670
void MxThread::Terminate()
{
@ -55,38 +84,9 @@ unsigned MxThread::ThreadProc(void* p_thread)
return static_cast<MxThread*>(p_thread)->Run();
}
// OFFSET: LEGO1 0x100bf660
void MxThread::Sleep(MxS32 p_milliseconds)
// OFFSET: LEGO1 0x100bf690
MxResult MxThread::Run()
{
::Sleep(p_milliseconds);
}
// OFFSET: LEGO1 0x100b8bb0
MxTickleThread::MxTickleThread(MxCore* p_target, int p_frequencyMS)
{
m_target = p_target;
m_frequencyMS = p_frequencyMS;
}
// Match except for register allocation
// OFFSET: LEGO1 0x100b8c90
MxResult MxTickleThread::Run()
{
MxTimer* timer = Timer();
int lastTickled = -m_frequencyMS;
while (IsRunning()) {
int currentTime = timer->GetTime();
if (currentTime < lastTickled) {
lastTickled = -m_frequencyMS;
}
int timeRemainingMS = (m_frequencyMS - currentTime) + lastTickled;
if (timeRemainingMS <= 0) {
m_target->Tickle();
timeRemainingMS = 0;
lastTickled = currentTime;
}
Sleep(timeRemainingMS);
}
return MxThread::Run();
m_semaphore.Release(1);
return SUCCESS;
}

View file

@ -17,6 +17,13 @@ MxTimer::MxTimer()
s_LastTimeCalculated = m_startTime;
}
// OFFSET: LEGO1 0x100ae140
MxLong MxTimer::GetRealTime()
{
MxTimer::s_LastTimeCalculated = timeGetTime();
return MxTimer::s_LastTimeCalculated - this->m_startTime;
}
// OFFSET: LEGO1 0x100ae160
void MxTimer::Start()
{
@ -33,10 +40,3 @@ void MxTimer::Stop()
// this feels very stupid but it's what the assembly does
this->m_startTime = this->m_startTime + startTime - 5;
}
// OFFSET: LEGO1 0x100ae140
MxLong MxTimer::GetRealTime()
{
MxTimer::s_LastTimeCalculated = timeGetTime();
return MxTimer::s_LastTimeCalculated - this->m_startTime;
}

View file

@ -39,6 +39,14 @@ MxTransitionManager::~MxTransitionManager()
TickleManager()->UnregisterClient(this);
}
// OFFSET: LEGO1 0x1004baa0
MxResult MxTransitionManager::GetDDrawSurfaceFromVideoManager() // vtable+0x14
{
LegoVideoManager* videoManager = VideoManager();
this->m_ddSurface = videoManager->GetDisplaySurface()->GetDirectDrawSurface2();
return SUCCESS;
}
// OFFSET: LEGO1 0x1004bac0
MxResult MxTransitionManager::Tickle()
{
@ -71,6 +79,53 @@ MxResult MxTransitionManager::Tickle()
return SUCCESS;
}
// OFFSET: LEGO1 0x1004bb70
MxResult MxTransitionManager::StartTransition(
TransitionType p_animationType,
MxS32 p_speed,
MxBool p_doCopy,
MxBool p_playMusicInAnim
)
{
if (this->m_transitionType == NOT_TRANSITIONING) {
if (!p_playMusicInAnim) {
MxBackgroundAudioManager* backgroundAudioManager = BackgroundAudioManager();
backgroundAudioManager->Stop();
}
this->m_transitionType = p_animationType;
m_copyFlags.bit0 = p_doCopy;
if (m_copyFlags.bit0 && m_waitIndicator != NULL) {
m_waitIndicator->Enable(TRUE);
MxDSAction* action = m_waitIndicator->GetAction();
action->SetLoopCount(10000);
action->SetFlags(action->GetFlags() | MxDSAction::Flag_Bit9);
}
MxU32 time = timeGetTime();
this->m_systemTime = time;
this->m_animationSpeed = p_speed;
MxTickleManager* tickleManager = TickleManager();
tickleManager->RegisterClient(this, p_speed);
LegoInputManager* inputManager = InputManager();
inputManager->m_unk0x88 = TRUE;
inputManager->m_unk0x336 = FALSE;
LegoVideoManager* videoManager = VideoManager();
videoManager->SetUnkE4(FALSE);
SetAppCursor(1);
return SUCCESS;
}
return FAILURE;
}
// OFFSET: LEGO1 0x1004bc30
void MxTransitionManager::EndTransition(MxBool p_notifyWorld)
{
@ -91,6 +146,14 @@ void MxTransitionManager::EndTransition(MxBool p_notifyWorld)
}
}
// OFFSET: LEGO1 0x1004bcf0
void MxTransitionManager::Transition_None()
{
LegoVideoManager* videoManager = VideoManager();
videoManager->GetDisplaySurface()->FUN_100ba640();
EndTransition(TRUE);
}
// OFFSET: LEGO1 0x1004bd10
void MxTransitionManager::Transition_Dissolve()
{
@ -173,69 +236,6 @@ void MxTransitionManager::Transition_Dissolve()
}
}
// OFFSET: LEGO1 0x1004baa0
MxResult MxTransitionManager::GetDDrawSurfaceFromVideoManager() // vtable+0x14
{
LegoVideoManager* videoManager = VideoManager();
this->m_ddSurface = videoManager->GetDisplaySurface()->GetDirectDrawSurface2();
return SUCCESS;
}
// OFFSET: LEGO1 0x1004bb70
MxResult MxTransitionManager::StartTransition(
TransitionType p_animationType,
MxS32 p_speed,
MxBool p_doCopy,
MxBool p_playMusicInAnim
)
{
if (this->m_transitionType == NOT_TRANSITIONING) {
if (!p_playMusicInAnim) {
MxBackgroundAudioManager* backgroundAudioManager = BackgroundAudioManager();
backgroundAudioManager->Stop();
}
this->m_transitionType = p_animationType;
m_copyFlags.bit0 = p_doCopy;
if (m_copyFlags.bit0 && m_waitIndicator != NULL) {
m_waitIndicator->Enable(TRUE);
MxDSAction* action = m_waitIndicator->GetAction();
action->SetLoopCount(10000);
action->SetFlags(action->GetFlags() | MxDSAction::Flag_Bit9);
}
MxU32 time = timeGetTime();
this->m_systemTime = time;
this->m_animationSpeed = p_speed;
MxTickleManager* tickleManager = TickleManager();
tickleManager->RegisterClient(this, p_speed);
LegoInputManager* inputManager = InputManager();
inputManager->m_unk0x88 = TRUE;
inputManager->m_unk0x336 = FALSE;
LegoVideoManager* videoManager = VideoManager();
videoManager->SetUnkE4(FALSE);
SetAppCursor(1);
return SUCCESS;
}
return FAILURE;
}
// OFFSET: LEGO1 0x1004bcf0
void MxTransitionManager::Transition_None()
{
LegoVideoManager* videoManager = VideoManager();
videoManager->GetDisplaySurface()->FUN_100ba640();
EndTransition(TRUE);
}
// OFFSET: LEGO1 0x1004bed0
void MxTransitionManager::Transition_Pixelation()
{
@ -353,6 +353,45 @@ void MxTransitionManager::Transition_Pixelation()
}
}
// OFFSET: LEGO1 0x1004c170
void MxTransitionManager::Transition_Wipe()
{
// If the animation is finished
if (m_animationTimer == 240) {
m_animationTimer = 0;
EndTransition(TRUE);
return;
}
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
}
if (res == DD_OK) {
SubmitCopyRect(&ddsd);
// For each of the 240 animation ticks, blank out two scanlines
// starting at the top of the screen.
// (dwRGBBitCount / 8) will tell how many bytes are used per pixel.
MxU8* line = (MxU8*) ddsd.lpSurface + 2 * ddsd.lPitch * m_animationTimer;
memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8);
line += ddsd.lPitch;
memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8);
SetupCopyRect(&ddsd);
m_ddSurface->Unlock(ddsd.lpSurface);
m_animationTimer++;
}
}
// OFFSET: LEGO1 0x1004c270
void MxTransitionManager::Transition_Windows()
{
@ -424,45 +463,6 @@ void MxTransitionManager::Transition_Broken()
}
}
// OFFSET: LEGO1 0x1004c170
void MxTransitionManager::Transition_Wipe()
{
// If the animation is finished
if (m_animationTimer == 240) {
m_animationTimer = 0;
EndTransition(TRUE);
return;
}
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
}
if (res == DD_OK) {
SubmitCopyRect(&ddsd);
// For each of the 240 animation ticks, blank out two scanlines
// starting at the top of the screen.
// (dwRGBBitCount / 8) will tell how many bytes are used per pixel.
MxU8* line = (MxU8*) ddsd.lpSurface + 2 * ddsd.lPitch * m_animationTimer;
memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8);
line += ddsd.lPitch;
memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8);
SetupCopyRect(&ddsd);
m_ddSurface->Unlock(ddsd.lpSurface);
m_animationTimer++;
}
}
// OFFSET: LEGO1 0x1004c470
void MxTransitionManager::SetWaitIndicator(MxVideoPresenter* p_waitIndicator)
{

View file

@ -1,5 +1,29 @@
#include "mxvariabletable.h"
// OFFSET: LEGO1 0x100afcd0 TEMPLATE
// MxCollection<MxVariable *>::Compare
// OFFSET: LEGO1 0x100afce0 TEMPLATE
// MxCollection<MxVariable *>::~MxCollection<MxVariable *>
// OFFSET: LEGO1 0x100afd30 TEMPLATE
// MxCollection<MxVariable *>::Destroy
// OFFSET: LEGO1 0x100afd40 TEMPLATE
// MxCollection<MxVariable *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100afdb0 TEMPLATE
// MxVariableTable::Destroy
// OFFSET: LEGO1 0x100afdc0 TEMPLATE
// MxHashTable<MxVariable *>::Hash
// OFFSET: LEGO1 0x100b0bd0 TEMPLATE
// MxHashTable<MxVariable *>::~MxHashTable<MxVariable *>
// OFFSET: LEGO1 0x100b0ca0 TEMPLATE
// MxHashTable<MxVariable *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100b7330
MxS8 MxVariableTable::Compare(MxVariable* p_var0, MxVariable* p_var1)
{
@ -64,3 +88,9 @@ const char* MxVariableTable::GetVariable(const char* p_key)
return value;
}
// OFFSET: LEGO1 0x100b7ab0 TEMPLATE
// MxHashTable<MxVariable *>::Resize
// OFFSET: LEGO1 0x100b7b80 TEMPLATE
// MxHashTable<MxVariable *>::_NodeInsert

View file

@ -14,40 +14,12 @@ class MxVariableTable : public MxHashTable<MxVariable*> {
__declspec(dllexport) void SetVariable(MxVariable* p_var);
__declspec(dllexport) const char* GetVariable(const char* p_key);
// OFFSET: LEGO1 0x100afdb0
static void Destroy(MxVariable* p_obj) { p_obj->Destroy(); }
virtual MxS8 Compare(MxVariable*, MxVariable*) override; // vtable+0x14
virtual MxU32 Hash(MxVariable*) override; // vtable+0x18
};
// OFFSET: LEGO1 0x100afcd0 TEMPLATE
// MxCollection<MxVariable *>::Compare
// OFFSET: LEGO1 0x100afce0 TEMPLATE
// MxCollection<MxVariable *>::~MxCollection<MxVariable *>
// OFFSET: LEGO1 0x100afd30 TEMPLATE
// MxCollection<MxVariable *>::Destroy
// OFFSET: LEGO1 0x100afd40 TEMPLATE
// MxCollection<MxVariable *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100afdc0 TEMPLATE
// MxHashTable<MxVariable *>::Hash
// OFFSET: LEGO1 0x100b0bd0 TEMPLATE
// MxHashTable<MxVariable *>::~MxHashTable<MxVariable *>
// OFFSET: LEGO1 0x100b0ca0 TEMPLATE
// MxHashTable<MxVariable *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100b7ab0 TEMPLATE
// MxHashTable<MxVariable *>::Resize
// OFFSET: LEGO1 0x100b7b80 TEMPLATE
// MxHashTable<MxVariable *>::_NodeInsert
// VTABLE 0x100dc1b0 TEMPLATE
// class MxCollection<MxVariable *>

View file

@ -44,17 +44,11 @@ MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam)
SetDeviceName(p_videoParam.m_deviceId);
}
// OFFSET: LEGO1 0x100bede0
MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam)
// OFFSET: LEGO1 0x100bed50
MxVideoParam::~MxVideoParam()
{
this->m_rect = p_videoParam.m_rect;
this->m_palette = p_videoParam.m_palette;
this->m_backBuffers = p_videoParam.m_backBuffers;
this->m_flags = p_videoParam.m_flags;
this->m_unk1c = p_videoParam.m_unk1c;
SetDeviceName(p_videoParam.m_deviceId);
return *this;
if (this->m_deviceId != NULL)
delete[] this->m_deviceId;
}
// OFFSET: LEGO1 0x100bed70
@ -75,9 +69,15 @@ void MxVideoParam::SetDeviceName(char* id)
}
}
// OFFSET: LEGO1 0x100bed50
MxVideoParam::~MxVideoParam()
// OFFSET: LEGO1 0x100bede0
MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam)
{
if (this->m_deviceId != NULL)
delete[] this->m_deviceId;
this->m_rect = p_videoParam.m_rect;
this->m_palette = p_videoParam.m_palette;
this->m_backBuffers = p_videoParam.m_backBuffers;
this->m_flags = p_videoParam.m_flags;
this->m_unk1c = p_videoParam.m_unk1c;
SetDeviceName(p_videoParam.m_deviceId);
return *this;
}

View file

@ -138,7 +138,7 @@ void Matrix4Impl::ToQuaternion(Vector4Impl* p_outQuat)
return;
}
// OFFSET: LEGO1 0x100d4090
// 0x100d4090
static int rotateIndex[] = {1, 2, 0};
// Largest element along the trace

View file

@ -14,6 +14,19 @@ float g_userMaxLod = 3.6f;
// 0x1010104c
float g_partsThreshold = 1000.0f;
// OFFSET: LEGO1 0x100a5de0
void RealtimeView::SetUserMaxLOD(float p_lod)
{
g_userMaxLod = p_lod;
UpdateMaxLOD();
}
// OFFSET: LEGO1 0x100a5df0
void RealtimeView::SetPartsThreshold(float p_threshold)
{
g_partsThreshold = p_threshold;
}
// OFFSET: LEGO1 0x100a5e00
float RealtimeView::GetUserMaxLOD()
{
@ -27,21 +40,8 @@ float RealtimeView::GetPartsThreshold()
return g_partsThreshold;
}
// OFFSET: LEGO1 100a5e20
// OFFSET: LEGO1 0x100a5e20
void RealtimeView::UpdateMaxLOD()
{
g_userMaxLodPower = pow(g_userMaxBase, -g_userMaxLod);
}
// OFFSET: LEGO1 0x100a5de0
void RealtimeView::SetUserMaxLOD(float p_lod)
{
g_userMaxLod = p_lod;
UpdateMaxLOD();
}
// OFFSET: LEGO1 0x100a5df0
void RealtimeView::SetPartsThreshold(float p_threshold)
{
g_partsThreshold = p_threshold;
}

View file

@ -12,10 +12,63 @@ DECOMP_SIZE_ASSERT(Vector4Impl, 0x8);
DECOMP_SIZE_ASSERT(Vector3Data, 0x14);
DECOMP_SIZE_ASSERT(Vector4Data, 0x18);
// OFFSET: LEGO1 0x100020a0
const float* Vector2Impl::GetData() const
// OFFSET: LEGO1 0x10001f80
void Vector2Impl::AddVectorImpl(float* p_value)
{
return m_data;
m_data[0] += p_value[0];
m_data[1] += p_value[1];
}
// OFFSET: LEGO1 0x10001fa0
void Vector2Impl::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
}
// OFFSET: LEGO1 0x10001fc0
void Vector2Impl::SubVectorImpl(float* p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
}
// OFFSET: LEGO1 0x10001fe0
void Vector2Impl::MullVectorImpl(float* p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
}
// OFFSET: LEGO1 0x10002000
void Vector2Impl::MullScalarImpl(float* p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
}
// OFFSET: LEGO1 0x10002020
void Vector2Impl::DivScalarImpl(float* p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
}
// OFFSET: LEGO1 0x10002040
float Vector2Impl::DotImpl(float* p_a, float* p_b) const
{
return p_b[0] * p_a[0] + p_b[1] * p_a[1];
}
// OFFSET: LEGO1 0x10002060 TEMPLATE
// Vector2Impl::SetData
// OFFSET: LEGO1 0x10002070
void Vector2Impl::EqualsImpl(float* p_data)
{
float* vec = m_data;
vec[0] = p_data[0];
vec[1] = p_data[1];
}
// OFFSET: LEGO1 0x10002090
@ -24,16 +77,24 @@ float* Vector2Impl::GetData()
return m_data;
}
// OFFSET: LEGO1 0x10002130
float Vector2Impl::Dot(Vector2Impl* p_a, float* p_b) const
// OFFSET: LEGO1 0x100020a0
const float* Vector2Impl::GetData() const
{
return DotImpl(p_a->m_data, p_b);
return m_data;
}
// OFFSET: LEGO1 0x10002110
float Vector2Impl::Dot(float* p_a, Vector2Impl* p_b) const
// OFFSET: LEGO1 0x100020b0
void Vector2Impl::Clear()
{
return DotImpl(p_a, p_b->m_data);
float* vec = m_data;
vec[0] = 0.0f;
vec[1] = 0.0f;
}
// OFFSET: LEGO1 0x100020d0
float Vector2Impl::Dot(float* p_a, float* p_b) const
{
return DotImpl(p_a, p_b);
}
// OFFSET: LEGO1 0x100020f0
@ -42,10 +103,22 @@ float Vector2Impl::Dot(Vector2Impl* p_a, Vector2Impl* p_b) const
return DotImpl(p_a->m_data, p_b->m_data);
}
// OFFSET: LEGO1 0x100020d0
float Vector2Impl::Dot(float* p_a, float* p_b) const
// OFFSET: LEGO1 0x10002110
float Vector2Impl::Dot(float* p_a, Vector2Impl* p_b) const
{
return DotImpl(p_a, p_b);
return DotImpl(p_a, p_b->m_data);
}
// OFFSET: LEGO1 0x10002130
float Vector2Impl::Dot(Vector2Impl* p_a, float* p_b) const
{
return DotImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x10002150
float Vector2Impl::LenSquared() const
{
return m_data[0] * m_data[0] + m_data[1] * m_data[1];
}
// OFFSET: LEGO1 0x10002160
@ -62,10 +135,10 @@ int Vector2Impl::Unitize()
return -1;
}
// OFFSET: LEGO1 0x100021e0
void Vector2Impl::AddVector(Vector2Impl* p_other)
// OFFSET: LEGO1 0x100021c0
void Vector2Impl::AddScalar(float p_value)
{
AddVectorImpl(p_other->m_data);
AddScalarImpl(p_value);
}
// OFFSET: LEGO1 0x100021d0
@ -74,16 +147,10 @@ void Vector2Impl::AddVector(float* p_other)
AddVectorImpl(p_other);
}
// OFFSET: LEGO1 0x100021c0
void Vector2Impl::AddScalar(float p_value)
// OFFSET: LEGO1 0x100021e0
void Vector2Impl::AddVector(Vector2Impl* p_other)
{
AddScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002200
void Vector2Impl::SubVector(Vector2Impl* p_other)
{
SubVectorImpl(p_other->m_data);
AddVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x100021f0
@ -92,16 +159,10 @@ void Vector2Impl::SubVector(float* p_other)
SubVectorImpl(p_other);
}
// OFFSET: LEGO1 0x10002230
void Vector2Impl::MullScalar(float* p_value)
// OFFSET: LEGO1 0x10002200
void Vector2Impl::SubVector(Vector2Impl* p_other)
{
MullScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002220
void Vector2Impl::MullVector(Vector2Impl* p_other)
{
MullVectorImpl(p_other->m_data);
SubVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10002210
@ -110,100 +171,206 @@ void Vector2Impl::MullVector(float* p_other)
MullVectorImpl(p_other);
}
// OFFSET: LEGO1 0x10002220
void Vector2Impl::MullVector(Vector2Impl* p_other)
{
MullVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10002230
void Vector2Impl::MullScalar(float* p_value)
{
MullScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002240
void Vector2Impl::DivScalar(float* p_value)
{
DivScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002260
void Vector2Impl::SetVector(Vector2Impl* p_other)
{
EqualsImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10002250
void Vector2Impl::SetVector(float* p_other)
{
EqualsImpl(p_other);
}
// OFFSET: LEGO1 0x10001fa0
void Vector2Impl::AddScalarImpl(float p_value)
// OFFSET: LEGO1 0x10002260
void Vector2Impl::SetVector(Vector2Impl* p_other)
{
m_data[0] += p_value;
m_data[1] += p_value;
EqualsImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10001f80
void Vector2Impl::AddVectorImpl(float* p_value)
// OFFSET: LEGO1 0x10002270
void Vector3Impl::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 0x100022c0
void Vector3Impl::EqualsCross(Vector3Impl* p_a, Vector3Impl* p_b)
{
EqualsCrossImpl(p_a->m_data, p_b->m_data);
}
// OFFSET: LEGO1 0x100022e0
void Vector3Impl::EqualsCross(Vector3Impl* p_a, float* p_b)
{
EqualsCrossImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x10002300
void Vector3Impl::EqualsCross(float* p_a, Vector3Impl* p_b)
{
EqualsCrossImpl(p_a, p_b->m_data);
}
// OFFSET: LEGO1 0x10002870
void Vector4Impl::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 0x10001fc0
void Vector2Impl::SubVectorImpl(float* p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
}
// OFFSET: LEGO1 0x10002000
void Vector2Impl::MullScalarImpl(float* p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
}
// OFFSET: LEGO1 0x10001fe0
void Vector2Impl::MullVectorImpl(float* p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
}
// OFFSET: LEGO1 0x10002020
void Vector2Impl::DivScalarImpl(float* p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
}
// OFFSET: LEGO1 0x10002040
float Vector2Impl::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 Vector2Impl::EqualsImpl(float* p_data)
{
float* vec = m_data;
vec[0] = p_data[0];
vec[1] = p_data[1];
}
// OFFSET: LEGO1 0x100020b0
void Vector2Impl::Clear()
{
float* vec = m_data;
vec[0] = 0.0f;
vec[1] = 0.0f;
}
// OFFSET: LEGO1 0x10002150
float Vector2Impl::LenSquared() const
{
return m_data[0] * m_data[0] + m_data[1] * m_data[1];
}
// OFFSET: LEGO1 0x10003a90
void Vector3Impl::AddScalarImpl(float p_value)
// OFFSET: LEGO1 0x100028b0
void Vector4Impl::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 0x100028f0
void Vector4Impl::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 0x10002930
void Vector4Impl::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 0x10002970
void Vector4Impl::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 0x100029b0
void Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 0x10002a40
void Vector4Impl::SetMatrixProductImpl(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];
}
// OFFSET: LEGO1 0x10002ae0
void Vector4Impl::SetMatrixProduct(Vector4Impl* p_a, float* p_b)
{
SetMatrixProductImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x10002b00
void Vector4Impl::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 Vector4Impl::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 Vector4Impl::EqualsScalar(float* p_value)
{
m_data[0] = *p_value;
m_data[1] = *p_value;
m_data[2] = *p_value;
m_data[3] = *p_value;
}
// Note close yet, included because I'm at least confident I know what operation
// it's trying to do.
// OFFSET: LEGO1 0x10002b70 STUB
int Vector4Impl::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 0;
}
return -1;
}
// OFFSET: LEGO1 0x10002bf0
void Vector4Impl::UnknownQuaternionOp(Vector4Impl* p_a, Vector4Impl* p_b)
{
float* bDat = p_b->m_data;
float* aDat = p_a->m_data;
this->m_data[3] = aDat[3] * bDat[3] - (bDat[0] * aDat[0] + aDat[2] * bDat[2] + aDat[1] * aDat[1]);
this->m_data[0] = bDat[2] * aDat[1] - bDat[1] * aDat[2];
this->m_data[1] = aDat[2] * bDat[0] - bDat[2] * aDat[0];
this->m_data[2] = bDat[1] * aDat[0] - aDat[1] * bDat[0];
m_data[0] = p_b->m_data[3] * p_a->m_data[0] + p_a->m_data[3] * p_b->m_data[0] + m_data[0];
m_data[1] = p_b->m_data[1] * p_a->m_data[3] + p_a->m_data[1] * p_b->m_data[3] + m_data[1];
m_data[2] = p_b->m_data[2] * p_a->m_data[3] + p_a->m_data[2] * p_b->m_data[3] + m_data[2];
}
// OFFSET: LEGO1 0x10003a60
@ -214,6 +381,14 @@ void Vector3Impl::AddVectorImpl(float* p_value)
m_data[2] += p_value[2];
}
// OFFSET: LEGO1 0x10003a90
void Vector3Impl::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
m_data[2] += p_value;
}
// OFFSET: LEGO1 0x10003ac0
void Vector3Impl::SubVectorImpl(float* p_value)
{
@ -222,14 +397,6 @@ void Vector3Impl::SubVectorImpl(float* p_value)
m_data[2] -= p_value[2];
}
// OFFSET: LEGO1 0x10003b20
void Vector3Impl::MullScalarImpl(float* p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
m_data[2] *= *p_value;
}
// OFFSET: LEGO1 0x10003af0
void Vector3Impl::MullVectorImpl(float* p_value)
{
@ -238,6 +405,14 @@ void Vector3Impl::MullVectorImpl(float* p_value)
m_data[2] *= p_value[2];
}
// OFFSET: LEGO1 0x10003b20
void Vector3Impl::MullScalarImpl(float* p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
m_data[2] *= *p_value;
}
// OFFSET: LEGO1 0x10003b50
void Vector3Impl::DivScalarImpl(float* p_value)
{
@ -276,32 +451,6 @@ float Vector3Impl::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 Vector3Impl::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 Vector3Impl::EqualsCross(float* p_a, Vector3Impl* p_b)
{
EqualsCrossImpl(p_a, p_b->m_data);
}
// OFFSET: LEGO1 0x100022e0
void Vector3Impl::EqualsCross(Vector3Impl* p_a, float* p_b)
{
EqualsCrossImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x100022c0
void Vector3Impl::EqualsCross(Vector3Impl* p_a, Vector3Impl* p_b)
{
EqualsCrossImpl(p_a->m_data, p_b->m_data);
}
// OFFSET: LEGO1 0x10003bf0
void Vector3Impl::EqualsScalar(float* p_value)
{
@ -309,149 +458,3 @@ void Vector3Impl::EqualsScalar(float* p_value)
m_data[1] = *p_value;
m_data[2] = *p_value;
}
// OFFSET: LEGO1 0x100028b0
void Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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 Vector4Impl::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
void Vector4Impl::SetMatrixProduct(Vector4Impl* p_a, float* p_b)
{
SetMatrixProductImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x10002a40
void Vector4Impl::SetMatrixProductImpl(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
int Vector4Impl::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 0;
}
return -1;
}
// OFFSET: LEGO1 0x10002bf0
void Vector4Impl::UnknownQuaternionOp(Vector4Impl* p_a, Vector4Impl* p_b)
{
float* bDat = p_b->m_data;
float* aDat = p_a->m_data;
this->m_data[3] = aDat[3] * bDat[3] - (bDat[0] * aDat[0] + aDat[2] * bDat[2] + aDat[1] * aDat[1]);
this->m_data[0] = bDat[2] * aDat[1] - bDat[1] * aDat[2];
this->m_data[1] = aDat[2] * bDat[0] - bDat[2] * aDat[0];
this->m_data[2] = bDat[1] * aDat[0] - aDat[1] * bDat[0];
m_data[0] = p_b->m_data[3] * p_a->m_data[0] + p_a->m_data[3] * p_b->m_data[0] + m_data[0];
m_data[1] = p_b->m_data[1] * p_a->m_data[3] + p_a->m_data[1] * p_b->m_data[3] + m_data[1];
m_data[2] = p_b->m_data[2] * p_a->m_data[3] + p_a->m_data[2] * p_b->m_data[3] + m_data[2];
}

View file

@ -3,6 +3,10 @@
#include <vec.h>
// TODO: Find proper compilation unit to put this
// OFFSET: LEGO1 0x1000c0f0 TEMPLATE
// Vector2Impl::Vector2Impl
/*
* A simple array of three floats that can be indexed into.
*/
@ -60,7 +64,6 @@ struct Vector4 {
// SIZE 0x8
class Vector2Impl {
public:
// OFFSET: LEGO1 0x1000c0f0
inline Vector2Impl(float* p_data) { this->SetData(p_data); }
// vtable + 0x00 (no virtual destructor)
@ -73,8 +76,6 @@ class Vector2Impl {
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;
// OFFSET: LEGO1 0x10002060
virtual void SetData(float* p_data) { this->m_data = p_data; }
// vtable + 0x20

View file

@ -22,6 +22,12 @@ Score::Score()
NotificationManager()->Register(this);
}
// OFFSET: LEGO1 0x100010b0
MxBool Score::VTable0x5c()
{
return TRUE;
}
// OFFSET: LEGO1 0x10001200
Score::~Score()
{
@ -32,6 +38,39 @@ Score::~Score()
NotificationManager()->Unregister(this);
}
// OFFSET: LEGO1 0x100012a0
MxResult Score::Create(MxDSObject& p_dsObject)
{
MxResult result = SetAsCurrentWorld(p_dsObject);
if (result == SUCCESS) {
InputManager()->SetWorld(this);
ControlManager()->Register(this);
InputManager()->Register(this);
SetIsWorldActive(FALSE);
LegoGameState* gs = GameState();
ScoreState* state = (ScoreState*) gs->GetState("ScoreState");
m_state = state ? state : (ScoreState*) gs->CreateState("ScoreState");
GameState()->SetUnknown424(0xd);
GameState()->FUN_1003a720(0);
}
return result;
}
// OFFSET: LEGO1 0x10001340
void Score::DeleteScript()
{
if (m_state->GetTutorialFlag()) {
MxDSAction action;
action.SetObjectId(0x1f5);
action.SetAtomId(*g_infoscorScript);
action.SetUnknown24(-2);
DeleteObject(action);
m_state->SetTutorialFlag(FALSE);
}
}
// OFFSET: LEGO1 0x10001410
MxLong Score::Notify(MxParam& p)
{
@ -67,45 +106,6 @@ MxLong Score::Notify(MxParam& p)
return ret;
}
// OFFSET: LEGO1 0x100010b0
MxBool Score::VTable0x5c()
{
return TRUE;
}
// OFFSET: LEGO1 0x100012a0
MxResult Score::Create(MxDSObject& p_dsObject)
{
MxResult result = SetAsCurrentWorld(p_dsObject);
if (result == SUCCESS) {
InputManager()->SetWorld(this);
ControlManager()->Register(this);
InputManager()->Register(this);
SetIsWorldActive(FALSE);
LegoGameState* gs = GameState();
ScoreState* state = (ScoreState*) gs->GetState("ScoreState");
m_state = state ? state : (ScoreState*) gs->CreateState("ScoreState");
GameState()->SetUnknown424(0xd);
GameState()->FUN_1003a720(0);
}
return result;
}
// OFFSET: LEGO1 0x10001340
void Score::DeleteScript()
{
if (m_state->GetTutorialFlag()) {
MxDSAction action;
action.SetObjectId(0x1f5);
action.SetAtomId(*g_infoscorScript);
action.SetUnknown24(-2);
DeleteObject(action);
m_state->SetTutorialFlag(FALSE);
}
}
// OFFSET: LEGO1 0x10001510
MxLong Score::FUN_10001510(MxEndActionNotificationParam& p)
{

View file

@ -0,0 +1,120 @@
import os
import sys
import argparse
from isledecomp.dir import (
walk_source_dir,
is_file_cpp
)
from isledecomp.parser import find_code_blocks
from isledecomp.parser.util import (
is_exact_offset_comment
)
def sig_truncate(sig: str) -> str:
"""Helper to truncate function names to 50 chars and append ellipsis
if needed. Goal is to stay under 80 columns for tool output."""
return f"{sig[:47]}{'...' if len(sig) >= 50 else ''}"
def check_file(filename: str, verbose: bool = False) -> bool:
"""Open and read the given file, then check whether the code blocks
are in order. If verbose, print each block."""
with open(filename, 'r') as f:
code_blocks = find_code_blocks(f)
bad_comments = [(block.start_line, block.offset_comment)
for block in code_blocks
if not is_exact_offset_comment(block.offset_comment)]
just_offsets = [block.offset for block in code_blocks]
sorted_offsets = sorted(just_offsets)
file_out_of_order = just_offsets != sorted_offsets
# If we detect inexact comments, don't print anything unless we are
# in verbose mode. If the file is out of order, we always print the
# file name.
should_report = ((len(bad_comments) > 0 and verbose)
or file_out_of_order)
if not should_report and not file_out_of_order:
return False
# Else: we are alerting to some problem in this file
print(filename)
if verbose:
if file_out_of_order:
order_lookup = {k: i for i, k in enumerate(sorted_offsets)}
prev_offset = 0
for block in code_blocks:
msg = ' '.join([
' ' if block.offset > prev_offset else '!',
f'{block.offset:08x}',
f'{block.end_line - block.start_line:4} lines',
f'{order_lookup[block.offset]:3}',
' ',
sig_truncate(block.signature),
])
print(msg)
prev_offset = block.offset
for (line_no, line) in bad_comments:
print(f'* line {line_no:3} bad offset comment ({line})')
print()
return file_out_of_order
def parse_args(test_args: list | None = None) -> dict:
p = argparse.ArgumentParser()
p.add_argument('target', help='The file or directory to check.')
p.add_argument('--enforce', action=argparse.BooleanOptionalAction,
default=False,
help='Fail with error code if target is out of order.')
p.add_argument('--verbose', action=argparse.BooleanOptionalAction,
default=False,
help=('Display each code block in the file and show '
'where each consecutive run of blocks is broken.'))
if test_args is None:
args = p.parse_args()
else:
args = p.parse_args(test_args)
return vars(args)
def main():
args = parse_args()
if os.path.isdir(args['target']):
files_to_check = list(walk_source_dir(args['target']))
elif os.path.isfile(args['target']) and is_file_cpp(args['target']):
files_to_check = [args['target']]
else:
sys.exit('Invalid target')
files_out_of_order = 0
for file in files_to_check:
is_jumbled = check_file(file, args['verbose'])
if is_jumbled:
files_out_of_order += 1
if files_out_of_order > 0:
error_message = ' '.join([
str(files_out_of_order),
'files are' if files_out_of_order > 1 else 'file is',
'out of order'
])
print(error_message)
if files_out_of_order > 0 and args['enforce']:
sys.exit(1)
if __name__ == '__main__':
main()

View file

@ -0,0 +1 @@
isledecomp

1
tools/isledecomp/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
isledecomp.egg-info/

View file

View file

@ -0,0 +1,21 @@
import os
from typing import Iterator
def is_file_cpp(filename: str) -> bool:
(basefile, ext) = os.path.splitext(filename)
return ext.lower() in ('.h', '.cpp')
def walk_source_dir(source: str, recursive: bool = True) -> Iterator[str]:
"""Generator to walk the given directory recursively and return
any C++ files found."""
source = os.path.abspath(source)
for subdir, dirs, files in os.walk(source):
for file in files:
if is_file_cpp(file):
yield os.path.join(subdir, file)
if not recursive:
break

View file

@ -0,0 +1 @@
from .parser import find_code_blocks

View file

@ -0,0 +1,142 @@
# C++ file parser
from typing import List, TextIO
from enum import Enum
from .util import (
CodeBlock,
OffsetMatch,
is_blank_or_comment,
match_offset_comment,
is_exact_offset_comment,
get_template_function_name,
remove_trailing_comment,
distinct_by_module,
)
class ReaderState(Enum):
WANT_OFFSET = 0
WANT_SIG = 1
IN_FUNC = 2
IN_TEMPLATE = 3
WANT_CURLY = 4
FUNCTION_DONE = 5
def find_code_blocks(stream: TextIO) -> List[CodeBlock]:
"""Read the IO stream (file) line-by-line and give the following report:
Foreach code block (function) in the file, what are its starting and
ending line numbers, and what is the given offset in the original
binary. We expect the result to be ordered by line number because we
are reading the file from start to finish."""
blocks: List[CodeBlock] = []
offset_matches: List[OffsetMatch] = []
function_sig = None
start_line = None
end_line = None
state = ReaderState.WANT_OFFSET
# 1-based to match cvdump and your text editor
# I know it says 0, but we will increment before each readline()
line_no = 0
can_seek = True
while True:
# Do this before reading again so that an EOF will not
# cause us to miss the last function of the file.
if state == ReaderState.FUNCTION_DONE:
# Our list of offset marks could have duplicates on
# module name, so we'll eliminate those now.
for offset_match in distinct_by_module(offset_matches):
block = CodeBlock(offset=offset_match.address,
signature=function_sig,
start_line=start_line,
end_line=end_line,
offset_comment=offset_match.comment,
module=offset_match.module,
is_template=offset_match.is_template,
is_stub=offset_match.is_stub)
blocks.append(block)
offset_matches = []
state = ReaderState.WANT_OFFSET
if can_seek:
line_no += 1
line = stream.readline()
if line == '':
break
new_match = match_offset_comment(line)
if new_match is not None:
# We will allow multiple offsets if we have just begun
# the code block, but not after we hit the curly brace.
if state in (ReaderState.WANT_OFFSET, ReaderState.IN_TEMPLATE,
ReaderState.WANT_SIG):
# If we detected an offset marker unexpectedly,
# we are handling it here so we can continue seeking.
can_seek = True
offset_matches.append(new_match)
if new_match.is_template:
state = ReaderState.IN_TEMPLATE
else:
state = ReaderState.WANT_SIG
else:
# We hit another offset unexpectedly.
# We can recover easily by just ending the function here.
end_line = line_no - 1
state = ReaderState.FUNCTION_DONE
# Pause reading here so we handle the offset marker
# on the next loop iteration
can_seek = False
elif state == ReaderState.IN_TEMPLATE:
# TEMPLATE functions are a special case. The signature is
# given on the next line (in a // comment)
function_sig = get_template_function_name(line)
start_line = line_no
end_line = line_no
state = ReaderState.FUNCTION_DONE
elif state == ReaderState.WANT_SIG:
# Skip blank lines or comments that come after the offset
# marker. There is not a formal procedure for this, so just
# assume the next "code line" is the function signature
if not is_blank_or_comment(line):
# Inline functions may end with a comment. Strip that out
# to help parsing.
function_sig = remove_trailing_comment(line.strip())
# Now check to see if the opening curly bracket is on the
# same line. clang-format should prevent this (BraceWrapping)
# but it is easy to detect.
# If the entire function is on one line, handle that too.
if function_sig.endswith('{'):
start_line = line_no
state = ReaderState.IN_FUNC
elif (function_sig.endswith('}') or
function_sig.endswith('};')):
start_line = line_no
end_line = line_no
state = ReaderState.FUNCTION_DONE
else:
state = ReaderState.WANT_CURLY
elif state == ReaderState.WANT_CURLY:
if line.strip() == '{':
start_line = line_no
state = ReaderState.IN_FUNC
elif state == ReaderState.IN_FUNC:
# Naive but reasonable assumption that functions will end with
# a curly brace on its own line with no prepended spaces.
if line.startswith('}'):
end_line = line_no
state = ReaderState.FUNCTION_DONE
return blocks

View file

@ -0,0 +1,97 @@
# C++ Parser utility functions and data structures
from __future__ import annotations # python <3.10 compatibility
import re
from typing import List
from collections import namedtuple
CodeBlock = namedtuple('CodeBlock',
['offset', 'signature', 'start_line', 'end_line',
'offset_comment', 'module', 'is_template', 'is_stub'])
OffsetMatch = namedtuple('OffsetMatch', ['module', 'address', 'is_template',
'is_stub', 'comment'])
# This has not been formally established, but considering that "STUB"
# is a temporary state for a function, we assume it will appear last,
# after any other modifiers (i.e. TEMPLATE)
# To match a reasonable variance of formatting for the offset comment
offsetCommentRegex = re.compile(r'\s*//\s*OFFSET:\s*(\w+)\s+(?:0x)?([a-f0-9]+)(\s+TEMPLATE)?(\s+STUB)?', # nopep8
flags=re.I)
# To match the exact syntax (text upper case, hex lower case, with spaces)
# that is used in most places
offsetCommentExactRegex = re.compile(r'^// OFFSET: [A-Z0-9]+ (0x[a-f0-9]+)( TEMPLATE)?( STUB)?$') # nopep8
# The goal here is to just read whatever is on the next line, so some
# flexibility in the formatting seems OK
templateCommentRegex = re.compile(r'\s*//\s+(.*)')
# To remove any comment (//) or block comment (/*) and its leading spaces
# from the end of a code line
trailingCommentRegex = re.compile(r'(\s*(?://|/\*).*)$')
def get_template_function_name(line: str) -> str:
"""Parse function signature for special TEMPLATE functions"""
template_match = templateCommentRegex.match(line)
# If we don't match, you get whatever is on the line as the signature
if template_match is not None:
return template_match.group(1)
return line
def remove_trailing_comment(line: str) -> str:
return trailingCommentRegex.sub('', line)
def is_blank_or_comment(line: str) -> bool:
"""Helper to read ahead after the offset comment is matched.
There could be blank lines or other comments before the
function signature, and we want to skip those."""
line_strip = line.strip()
return (len(line_strip) == 0
or line_strip.startswith('//')
or line_strip.startswith('/*')
or line_strip.endswith('*/'))
def is_exact_offset_comment(line: str) -> bool:
"""If the offset comment does not match our (unofficial) syntax
we may want to alert the user to fix it for style points."""
return offsetCommentExactRegex.match(line) is not None
def match_offset_comment(line: str) -> OffsetMatch | None:
match = offsetCommentRegex.match(line)
if match is None:
return None
return OffsetMatch(module=match.group(1),
address=int(match.group(2), 16),
is_template=match.group(3) is not None,
is_stub=match.group(4) is not None,
comment=line.strip())
def distinct_by_module(offsets: List) -> List:
"""Given a list of offset markers, return a list with distinct
module names. If module names (case-insensitive) are repeated,
choose the offset that appears first."""
if len(offsets) < 2:
return offsets
# Dict maintains insertion order in python >=3.7
offsets_dict = {}
for offset in offsets:
module_upper = offset.module.upper()
if module_upper not in offsets_dict:
offsets_dict[module_upper] = offset
return list(offsets_dict.values())

View file

@ -0,0 +1,9 @@
from setuptools import setup, find_packages
setup(
name='isledecomp',
version='0.1.0',
description='Python tools for the isledecomp project',
packages=find_packages(),
tests_require=['pytest'],
)

View file

View file

@ -0,0 +1,29 @@
// Sample for python unit tests
// Not part of the decomp
// A very simple class
class TestClass {
public:
TestClass();
virtual ~TestClass() override;
virtual MxResult Tickle() override; // vtable+08
// OFFSET: TEST 0x12345678
inline const char* ClassName() const // vtable+0c
{
// 0xabcd1234
return "TestClass";
}
// OFFSET: TEST 0xdeadbeef
inline MxBool IsA(const char* name) const override // vtable+10
{
return !strcmp(name, TestClass::ClassName());
}
private:
int m_hello;
int m_hiThere;
};

View file

@ -0,0 +1,22 @@
// Sample for python unit tests
// Not part of the decomp
// A very simple well-formed code file
// OFFSET: TEST 0x1234
void function01()
{
// TODO
}
// OFFSET: TEST 0x2345
void function02()
{
// TODO
}
// OFFSET: TEST 0x3456
void function03()
{
// TODO
}

View file

@ -0,0 +1,8 @@
// Sample for python unit tests
// Not part of the decomp
// OFFSET: TEST 0x10000001
inline const char* OneLineWithComment() const { return "MxDSObject"; }; // hi there
// OFFSET: TEST 0x10000002
inline const char* OneLine() const { return "MxDSObject"; };

View file

@ -0,0 +1,16 @@
// Sample for python unit tests
// Not part of the decomp
#include <stdio.h>
int no_offset_comment()
{
static int dummy = 123;
return -1;
}
// OFFSET: TEST 0xdeadbeef
void regular_ole_function()
{
printf("hi there");
}

View file

@ -0,0 +1,25 @@
// Sample for python unit tests
// Not part of the decomp
// Handling multiple offset markers
// OFFSET: TEST 0x1234
// OFFSET: HELLO 0x5555
void different_modules()
{
// TODO
}
// OFFSET: TEST 0x2345
// OFFSET: TEST 0x1234
void same_module()
{
// TODO
}
// OFFSET: TEST 0x2002
// OFFSET: test 0x1001
void same_case_insensitive()
{
// TODO
}

View file

@ -0,0 +1,12 @@
// Sample for python unit tests
// Not part of the decomp
// OFFSET: TEST 0x1234
void short_function() { static char* msg = "oneliner"; }
// OFFSET: TEST 0x5555
void function_after_one_liner()
{
// This function comes after the previous that is on a single line.
// Do we report the offset for this one correctly?
}

View file

@ -0,0 +1,20 @@
// Sample for python unit tests
// Not part of the decomp
// OFFSET: TEST 0x1001
void function_order01()
{
// TODO
}
// OFFSET: TEST 0x1003
void function_order03()
{
// TODO
}
// OFFSET: TEST 0x1002
void function_order02()
{
// TODO
}

View file

@ -0,0 +1,23 @@
// Sample for python unit tests
// Not part of the decomp
// While it's reasonable to expect a well-formed file (and clang-format
// will make sure we get one), this will put the parser through its paces.
// OFFSET: TEST 0x1234
void curly_with_spaces()
{
static char* msg = "hello";
}
// OFFSET: TEST 0x5555
void weird_closing_curly()
{
int x = 123; }
// OFFSET: HELLO 0x5656
void bad_indenting() {
if (0)
{
int y = 5;
}}

View file

@ -0,0 +1,128 @@
import os
import pytest
from typing import List, TextIO
from isledecomp.parser import find_code_blocks
from isledecomp.parser.util import CodeBlock
SAMPLE_DIR = os.path.join(os.path.dirname(__file__), 'samples')
def sample_file(filename: str) -> TextIO:
"""Wrapper for opening the samples from the directory that does not
depend on the cwd where we run the test"""
full_path = os.path.join(SAMPLE_DIR, filename)
return open(full_path, 'r')
def code_blocks_are_sorted(blocks: List[CodeBlock]) -> bool:
"""Helper to make this more idiomatic"""
just_offsets = [block.offset for block in blocks]
return just_offsets == sorted(just_offsets)
# Tests are below #
def test_sanity():
"""Read a very basic file"""
with sample_file('basic_file.cpp') as f:
blocks = find_code_blocks(f)
assert len(blocks) == 3
assert code_blocks_are_sorted(blocks) is True
# n.b. The parser returns line numbers as 1-based
# Function starts when we see the opening curly brace
assert blocks[0].start_line == 8
assert blocks[0].end_line == 10
def test_oneline():
"""(Assuming clang-format permits this) This sample has a function
on a single line. This will test the end-of-function detection"""
with sample_file('oneline_function.cpp') as f:
blocks = find_code_blocks(f)
assert len(blocks) == 2
assert blocks[0].start_line == 5
assert blocks[0].end_line == 5
def test_missing_offset():
"""What if the function doesn't have an offset comment?"""
with sample_file('missing_offset.cpp') as f:
blocks = find_code_blocks(f)
# TODO: For now, the function without the offset will just be ignored.
# Would be the same outcome if the comment was present but mangled and
# we failed to match it. We should detect these cases in the future.
assert len(blocks) == 1
def test_jumbled_case():
"""The parser just reports what it sees. It is the responsibility of
the downstream tools to do something about a jumbled file.
Just verify that we are reading it correctly."""
with sample_file('out_of_order.cpp') as f:
blocks = find_code_blocks(f)
assert len(blocks) == 3
assert code_blocks_are_sorted(blocks) is False
def test_bad_file():
with sample_file('poorly_formatted.cpp') as f:
blocks = find_code_blocks(f)
assert len(blocks) == 3
def test_indented():
"""Offsets for functions inside of a class will probably be indented."""
with sample_file('basic_class.cpp') as f:
blocks = find_code_blocks(f)
# TODO: We don't properly detect the end of these functions
# because the closing brace is indented. However... knowing where each
# function ends is less important (for now) than capturing
# all the functions that are there.
assert len(blocks) == 2
assert blocks[0].offset == int('0x12345678', 16)
assert blocks[0].start_line == 15
# assert blocks[0].end_line == 18
assert blocks[1].offset == int('0xdeadbeef', 16)
assert blocks[1].start_line == 22
# assert blocks[1].end_line == 24
def test_inline():
with sample_file('inline.cpp') as f:
blocks = find_code_blocks(f)
assert len(blocks) == 2
for block in blocks:
assert block.start_line is not None
assert block.start_line == block.end_line
def test_multiple_offsets():
"""If multiple offset marks appear before for a code block, take them
all but ensure module name (case-insensitive) is distinct.
Use first module occurrence in case of duplicates."""
with sample_file('multiple_offsets.cpp') as f:
blocks = find_code_blocks(f)
assert len(blocks) == 4
assert blocks[0].module == 'TEST'
assert blocks[0].start_line == 9
assert blocks[1].module == 'HELLO'
assert blocks[1].start_line == 9
# Duplicate modules are ignored
assert blocks[2].start_line == 16
assert blocks[2].offset == 0x2345
assert blocks[3].module == 'TEST'
assert blocks[3].offset == 0x2002

View file

@ -0,0 +1,113 @@
import pytest
from collections import namedtuple
from typing import List
from isledecomp.parser.util import (
is_blank_or_comment,
match_offset_comment,
is_exact_offset_comment,
distinct_by_module,
)
blank_or_comment_param = [
(True, ''),
(True, '\t'),
(True, ' '),
(False, '\tint abc=123;'),
(True, '// OFFSET: LEGO1 0xdeadbeef'),
(True, ' /* Block comment beginning'),
(True, 'Block comment ending */ '),
# TODO: does clang-format have anything to say about these cases?
(False, 'x++; // Comment folows'),
(False, 'x++; /* Block comment begins'),
]
@pytest.mark.parametrize('expected, line', blank_or_comment_param)
def test_is_blank_or_comment(line: str, expected: bool):
assert is_blank_or_comment(line) is expected
offset_comment_samples = [
# (can_parse: bool, exact_match: bool, line: str)
# Should match both expected modules with optional STUB marker
(True, True, '// OFFSET: LEGO1 0xdeadbeef'),
(True, True, '// OFFSET: LEGO1 0xdeadbeef STUB'),
(True, True, '// OFFSET: ISLE 0x12345678'),
(True, True, '// OFFSET: ISLE 0x12345678 STUB'),
# No trailing spaces allowed
(True, False, '// OFFSET: LEGO1 0xdeadbeef '),
(True, False, '// OFFSET: LEGO1 0xdeadbeef STUB '),
# Must have exactly one space between elements
(True, False, '//OFFSET: ISLE 0xdeadbeef'),
(True, False, '// OFFSET:ISLE 0xdeadbeef'),
(True, False, '// OFFSET: ISLE 0xdeadbeef'),
(True, False, '// OFFSET: ISLE 0xdeadbeef'),
(True, False, '// OFFSET: ISLE 0xdeadbeef'),
(True, False, '// OFFSET: ISLE 0xdeadbeef STUB'),
# Must have 0x prefix for hex number
(True, False, '// OFFSET: ISLE deadbeef'),
# Offset, module name, and STUB must be uppercase
(True, False, '// offset: ISLE 0xdeadbeef'),
(True, False, '// offset: isle 0xdeadbeef'),
(True, False, '// OFFSET: LEGO1 0xdeadbeef stub'),
# Hex string must be lowercase
(True, False, '// OFFSET: ISLE 0xDEADBEEF'),
# TODO: How flexible should we be with matching the module name?
(True, True, '// OFFSET: OMNI 0x12345678'),
(True, True, '// OFFSET: LEG01 0x12345678'),
(True, False, '// OFFSET: hello 0x12345678'),
# Not close enough to match
(False, False, '// OFFSET: ISLE0x12345678'),
(False, False, '// OFFSET: 0x12345678'),
(False, False, '// LEGO1: 0x12345678'),
# Hex string shorter than 8 characters
(True, True, '// OFFSET: LEGO1 0x1234'),
# TODO: These match but shouldn't.
# (False, False, '// OFFSET: LEGO1 0'),
# (False, False, '// OFFSET: LEGO1 0x'),
]
@pytest.mark.parametrize('match, exact, line', offset_comment_samples)
def test_offset_match(line: str, match: bool, exact):
did_match = match_offset_comment(line) is not None
assert did_match is match
@pytest.mark.parametrize('match, exact, line', offset_comment_samples)
def test_exact_offset_comment(line: str, exact: bool, match):
assert is_exact_offset_comment(line) is exact
# Helper for the next test: cut down version of OffsetMatch
MiniOfs = namedtuple('MiniOfs', ['module', 'value'])
distinct_by_module_samples = [
# empty set
([], []),
# same module name
([MiniOfs('TEST', 123), MiniOfs('TEST', 555)],
[MiniOfs('TEST', 123)]),
# same module name, case-insensitive
([MiniOfs('test', 123), MiniOfs('TEST', 555)],
[MiniOfs('test', 123)]),
# duplicates, non-consecutive
([MiniOfs('test', 123), MiniOfs('abc', 111), MiniOfs('TEST', 555)],
[MiniOfs('test', 123), MiniOfs('abc', 111)]),
]
@pytest.mark.parametrize('sample, expected', distinct_by_module_samples)
def test_distinct_by_module(sample: List[MiniOfs], expected: List[MiniOfs]):
assert distinct_by_module(sample) == expected

View file

@ -12,6 +12,8 @@
import colorama
import html
import re
from isledecomp.dir import walk_source_dir
from isledecomp.parser import find_code_blocks
from pystache import Renderer
parser = argparse.ArgumentParser(allow_abbrev=False,
@ -413,145 +415,120 @@ def can_resolve_register_differences(original_asm, new_asm):
# Generate basename of original file, used in locating OFFSET lines
basename = os.path.basename(os.path.splitext(original)[0])
pattern = '// OFFSET:'
for subdir, dirs, files in os.walk(source):
for file in files:
srcfilename = os.path.join(os.path.abspath(subdir), file)
with open(srcfilename, 'r') as srcfile:
line_no = 0
for srcfilename in walk_source_dir(source):
with open(srcfilename, 'r') as srcfile:
blocks = find_code_blocks(srcfile)
while True:
try:
line = srcfile.readline()
line_no += 1
for block in blocks:
if block.is_stub:
continue
if not line:
break
if block.module != basename:
continue
line = line.strip()
addr = block.offset
# Verbose flag handling
if verbose:
if addr == verbose:
found_verbose_target = True
else:
continue
if line.startswith(pattern) and not line.endswith('STUB'):
par = line[len(pattern):].strip().split()
module = par[0]
if module != basename:
continue
if block.is_template:
recinfo = syminfo.get_recompiled_address_from_name(block.signature)
if not recinfo:
continue
else:
recinfo = syminfo.get_recompiled_address(srcfilename, block.start_line)
if not recinfo:
continue
addr = int(par[1], 16)
# The effective_ratio is the ratio when ignoring differing register
# allocation vs the ratio is the true ratio.
ratio = 0.0
effective_ratio = 0.0
if recinfo.size:
origasm = parse_asm(origfile, addr + recinfo.start, recinfo.size)
recompasm = parse_asm(recompfile, recinfo.addr + recinfo.start, recinfo.size)
# Verbose flag handling
if verbose:
if addr == verbose:
found_verbose_target = True
else:
continue
diff = difflib.SequenceMatcher(None, origasm, recompasm)
ratio = diff.ratio()
effective_ratio = ratio
if line.endswith('TEMPLATE'):
line = srcfile.readline()
line_no += 1
# Name comes after // comment
name = line.strip()[2:].strip()
if ratio != 1.0:
# Check whether we can resolve register swaps which are actually
# perfect matches modulo compiler entropy.
if can_resolve_register_differences(origasm, recompasm):
effective_ratio = 1.0
else:
ratio = 0
recinfo = syminfo.get_recompiled_address_from_name(name)
if not recinfo:
continue
else:
find_open_bracket = line
while '{' not in find_open_bracket:
find_open_bracket = srcfile.readline()
line_no += 1
percenttext = f'{(effective_ratio * 100):.2f}%'
if not plain:
if effective_ratio == 1.0:
percenttext = colorama.Fore.GREEN + percenttext + colorama.Style.RESET_ALL
elif effective_ratio > 0.8:
percenttext = colorama.Fore.YELLOW + percenttext + colorama.Style.RESET_ALL
else:
percenttext = colorama.Fore.RED + percenttext + colorama.Style.RESET_ALL
recinfo = syminfo.get_recompiled_address(srcfilename, line_no)
if not recinfo:
continue
if effective_ratio == 1.0 and ratio != 1.0:
if plain:
percenttext += '*'
else:
percenttext += colorama.Fore.RED + '*' + colorama.Style.RESET_ALL
# The effective_ratio is the ratio when ignoring differing register
# allocation vs the ratio is the true ratio.
ratio = 0.0
effective_ratio = 0.0
if recinfo.size:
origasm = parse_asm(origfile, addr + recinfo.start, recinfo.size)
recompasm = parse_asm(recompfile, recinfo.addr + recinfo.start, recinfo.size)
if args.print_rec_addr:
addrs = f'0x{addr:x} / 0x{recinfo.addr:x}'
else:
addrs = hex(addr)
diff = difflib.SequenceMatcher(None, origasm, recompasm)
ratio = diff.ratio()
effective_ratio = ratio
if not verbose:
print(f' {recinfo.name} ({addrs}) is {percenttext} similar to the original')
if ratio != 1.0:
# Check whether we can resolve register swaps which are actually
# perfect matches modulo compiler entropy.
if can_resolve_register_differences(origasm, recompasm):
effective_ratio = 1.0
else:
ratio = 0
function_count += 1
total_accuracy += ratio
total_effective_accuracy += effective_ratio
percenttext = f'{(effective_ratio * 100):.2f}%'
if not plain:
if effective_ratio == 1.0:
percenttext = colorama.Fore.GREEN + percenttext + colorama.Style.RESET_ALL
elif effective_ratio > 0.8:
percenttext = colorama.Fore.YELLOW + percenttext + colorama.Style.RESET_ALL
else:
percenttext = colorama.Fore.RED + percenttext + colorama.Style.RESET_ALL
if recinfo.size:
udiff = difflib.unified_diff(origasm, recompasm, n=10)
if effective_ratio == 1.0 and ratio != 1.0:
# If verbose, print the diff for that function to the output
if verbose:
if effective_ratio == 1.0:
ok_text = 'OK!' if plain else (colorama.Fore.GREEN + '✨ OK! ✨' + colorama.Style.RESET_ALL)
if ratio == 1.0:
print(f'{addrs}: {recinfo.name} 100% match.\n\n{ok_text}\n\n')
else:
print(f'{addrs}: {recinfo.name} Effective 100%% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n')
else:
for line in udiff:
if line.startswith('++') or line.startswith('@@') or line.startswith('--'):
# Skip unneeded parts of the diff for the brief view
pass
elif line.startswith('+'):
if plain:
percenttext += '*'
print(line)
else:
percenttext += colorama.Fore.RED + '*' + colorama.Style.RESET_ALL
if args.print_rec_addr:
addrs = f'0x{addr:x} / 0x{recinfo.addr:x}'
print(colorama.Fore.GREEN + line)
elif line.startswith('-'):
if plain:
print(line)
else:
print(colorama.Fore.RED + line)
else:
addrs = hex(addr)
print(line)
if not plain:
print(colorama.Style.RESET_ALL, end='')
if not verbose:
print(f' {recinfo.name} ({addrs}) is {percenttext} similar to the original')
print(f'\n{recinfo.name} is only {percenttext} similar to the original, diff above')
function_count += 1
total_accuracy += ratio
total_effective_accuracy += effective_ratio
# If html, record the diffs to an HTML file
if html_path:
escaped = html.escape('\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n'))
htmlinsert.append(f'{{address: "0x{addr:x}", name: "{html.escape(recinfo.name)}", matching: {effective_ratio}, diff: "{escaped}"}}')
if recinfo.size:
udiff = difflib.unified_diff(origasm, recompasm, n=10)
# If verbose, print the diff for that function to the output
if verbose:
if effective_ratio == 1.0:
ok_text = 'OK!' if plain else (colorama.Fore.GREEN + '✨ OK! ✨' + colorama.Style.RESET_ALL)
if ratio == 1.0:
print(f'{addrs}: {recinfo.name} 100% match.\n\n{ok_text}\n\n')
else:
print(f'{addrs}: {recinfo.name} Effective 100%% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n')
else:
for line in udiff:
if line.startswith('++') or line.startswith('@@') or line.startswith('--'):
# Skip unneeded parts of the diff for the brief view
pass
elif line.startswith('+'):
if plain:
print(line)
else:
print(colorama.Fore.GREEN + line)
elif line.startswith('-'):
if plain:
print(line)
else:
print(colorama.Fore.RED + line)
else:
print(line)
if not plain:
print(colorama.Style.RESET_ALL, end='')
print(f'\n{recinfo.name} is only {percenttext} similar to the original, diff above')
# If html, record the diffs to an HTML file
if html_path:
escaped = html.escape('\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n'))
htmlinsert.append(f'{{address: "0x{addr:x}", name: "{html.escape(recinfo.name)}", matching: {effective_ratio}, diff: "{escaped}"}}')
except UnicodeDecodeError:
break
def gen_html(html_file, data):
output_data = Renderer().render_path(get_file_in_script_dir('template.html'),

View file

@ -1,3 +1,4 @@
capstone
colorama
pystache
isledecomp
pystache