Merge branch 'master' into impl/video-presenter

This commit is contained in:
Misha 2023-10-16 11:04:36 -04:00 committed by GitHub
commit d1fd224692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 1303 additions and 356 deletions

View File

@ -72,8 +72,10 @@ add_library(lego1 SHARED
LEGO1/legojetski.cpp
LEGO1/legoloadcachesoundpresenter.cpp
LEGO1/legolocomotionanimpresenter.cpp
LEGO1/legometerpresenter.cpp
LEGO1/legomodelpresenter.cpp
LEGO1/legonavcontroller.cpp
LEGO1/legoobjectfactory.cpp
LEGO1/legoomni.cpp
LEGO1/legopalettepresenter.cpp
LEGO1/legopartpresenter.cpp
@ -89,6 +91,8 @@ add_library(lego1 SHARED
LEGO1/legostream.cpp
LEGO1/legotexturepresenter.cpp
LEGO1/legoutil.cpp
LEGO1/legounksavedatawriter.cpp
LEGO1/legovehiclebuildstate.cpp
LEGO1/legovideomanager.cpp
LEGO1/legoworld.cpp
LEGO1/legoworldpresenter.cpp
@ -156,6 +160,7 @@ add_library(lego1 SHARED
LEGO1/mxpresenterlist.cpp
LEGO1/mxramstreamcontroller.cpp
LEGO1/mxramstreamprovider.cpp
LEGO1/mxregion.cpp
LEGO1/mxscheduler.cpp
LEGO1/mxsemaphore.cpp
LEGO1/mxsmkpresenter.cpp

View File

@ -1,5 +1,7 @@
#include "infocenterstate.h"
DECOMP_SIZE_ASSERT(InfocenterState, 0x94);
// OFFSET: LEGO1 0x10071600 STUB
InfocenterState::InfocenterState()
{

View File

@ -3,6 +3,8 @@
#include "legostate.h"
#include "decomp.h"
// VTABLE 0x100d93a8
// SIZE 0x94
class InfocenterState : public LegoState
@ -23,6 +25,40 @@ class InfocenterState : public LegoState
{
return !strcmp(name, InfocenterState::ClassName()) || LegoState::IsA(name);
}
inline MxU32 GetInfocenterBufferElement(MxS32 p_index) { return m_buffer[p_index]; }
private:
// Members should be renamed with their offsets before use
/*
struct UnkStruct
{
undefined4 unk1;
undefined2 unk2;
undefined2 unk3;
undefined2 unk4;
};
undefined2 unk1;
undefined2 unk2;
undefined4 unk3;
undefined4 padding1;
void *unk4;
undefined2 unk5;
undefined2 unk6;
undefined2 unk7;
undefined2 padding2;
void *unk8;
undefined2 unk9;
undefined2 unk10;
undefined2 unk11;
undefined2 padding3;
UnkStruct unk12[6];
undefined4 unk13;
*/
undefined pad[0x70];
MxU32 m_buffer[7]; // 0x78
};
#endif // INFOCENTERSTATE_H

View File

@ -36,14 +36,17 @@ void LegoEntity::Reset()
m_unk59 = 4;
}
// OFFSET: LEGO1 0x100107e0 STUB
void LegoEntity::vtable18()
// OFFSET: LEGO1 0x100107e0
MxResult LegoEntity::InitFromMxDSObject(MxDSObject& p_object)
{
m_mxEntityId = p_object.GetObjectId();
m_atom = p_object.GetAtomId();
AddToCurrentWorld();
return SUCCESS;
}
// OFFSET: LEGO1 0x10010810 STUB
void LegoEntity::Destroy(MxBool)
void LegoEntity::Destroy(MxBool p_fromDestructor)
{
if (m_unk54) {
// TODO
@ -53,6 +56,16 @@ void LegoEntity::Destroy(MxBool)
Reset();
}
// OFFSET: LEGO1 0x10010880 STUB
void LegoEntity::AddToCurrentWorld()
{
LegoWorld* world = GetCurrentWorld();
if (world != NULL && world != (LegoWorld*)this)
{
// TODO: world->vtable58(this);
}
}
// OFFSET: LEGO1 0x10010e10
void LegoEntity::ParseAction(char *p_extra)
{

View File

@ -5,6 +5,7 @@
#include "mxvector.h"
#include "extra.h"
#include "decomp.h"
#include "mxdsobject.h"
// VTABLE 0x100d4858
// SIZE 0x68 (probably)
@ -34,12 +35,13 @@ class LegoEntity : public MxEntity
return !strcmp(name, LegoEntity::ClassName()) || MxEntity::IsA(name);
}
virtual void vtable18(); // vtable+0x18
virtual void Destroy(MxBool); // vtable+0x1c
virtual MxResult InitFromMxDSObject(MxDSObject& p_object); // vtable+0x18
virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c
virtual void ParseAction(char *); // vtable+0x20
protected:
void Reset();
void AddToCurrentWorld();
undefined m_unk10;
undefined m_unk11;

View File

@ -1,17 +1,77 @@
#include "legogamestate.h"
#include "legoomni.h"
#include "legostate.h"
#include "infocenterstate.h"
#include "legostream.h"
#include "mxobjectfactory.h"
#include "mxvariabletable.h"
#include "decomp.h"
#include "mxstring.h"
// Based on the highest dword offset (0x42c) referenced in the constructor.
// There may be other members that come after.
DECOMP_SIZE_ASSERT(LegoGameState, 0x430)
// GLOBAL OFFSET: LEGO1 0x100f3e40
const char *g_fileExtensionGS = ".GS";
// GLOBAL OFFSET: LEGO1 0x100f3e58
ColorStringStruct g_colorSaveData[43] = {
{"c_dbbkfny0", "lego red"},
{"c_dbbkxly0", "lego white"},
{"c_chbasey0", "lego black"},
{"c_chbacky0", "lego black"},
{"c_chdishy0", "lego white"},
{"c_chhorny0", "lego black"},
{"c_chljety1", "lego black"},
{"c_chrjety1", "lego black"},
{"c_chmidly0", "lego black"},
{"c_chmotry0", "lego blue"},
{"c_chsidly0", "lego black"},
{"c_chsidry0", "lego black"},
{"c_chstuty0", "lego black"},
{"c_chtaily0", "lego black"},
{"c_chwindy1", "lego black"},
{"c_dbfbrdy0", "lego red"},
{"c_dbflagy0", "lego yellow"},
{"c_dbfrfny4", "lego red"},
{"c_dbfrxly0", "lego white"},
{"c_dbhndly0", "lego white"},
{"c_dbltbry0", "lego white"},
{"c_jsdashy0", "lego white"},
{"c_jsexhy0", "lego black"},
{"c_jsfrnty5", "lego black"},
{"c_jshndly0", "lego red"},
{"c_jslsidy0", "lego black"},
{"c_jsrsidy0", "lego black"},
{"c_jsskiby0", "lego red"},
{"c_jswnshy5", "lego white"},
{"c_rcbacky6", "lego green"},
{"c_rcedgey0", "lego green"},
{"c_rcfrmey0", "lego red"},
{"c_rcfrnty6", "lego green"},
{"c_rcmotry0", "lego white"},
{"c_rcsidey0", "lego green"},
{"c_rcstery0", "lego white"},
{"c_rcstrpy0", "lego yellow"},
{"c_rctailya", "lego white"},
{"c_rcwhl1y0", "lego white"},
{"c_rcwhl2y0", "lego white"},
{"c_jsbasey0", "lego white"},
{"c_chblady0", "lego black"},
{"c_chseaty0", "lego white"},
};
// NOTE: This offset = the end of the variables table, the last entry
// in that table is a special entry, the string "END_OF_VARIABLES"
// GLOBAL OFFSET: LEGO1 0x100f3e50
extern const char *s_endOfVariables;
// OFFSET: LEGO1 0x10039550
LegoGameState::LegoGameState()
{
// TODO
m_stateCount = 0;
m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68");
VariableTable()->SetVariable(m_backgroundColor);
@ -25,33 +85,93 @@ LegoGameState::LegoGameState()
SerializeScoreHistory(1);
}
// OFFSET: LEGO1 0x10039720
// OFFSET: LEGO1 0x10039720 STUB
LegoGameState::~LegoGameState()
{
// TODO
}
// OFFSET: LEGO1 0x10039c60
// OFFSET: LEGO1 0x10039c60 STUB
MxResult LegoGameState::Load(MxULong)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x10039980
MxResult LegoGameState::Save(MxULong p)
// OFFSET: LEGO1 0x1003a170
void LegoGameState::GetFileSavePath(MxString *p_outPath, MxULong p_slotn)
{
// TODO
return 0;
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
// 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)
{
MxResult result;
InfocenterState *infocenterState = (InfocenterState *)GameState()->GetState("InfocenterState");
if (!infocenterState || infocenterState->GetInfocenterBufferElement(0) == 0)
result = SUCCESS;
else {
result = FAILURE;
MxVariableTable *variableTable = VariableTable();
MxString savePath;
GetFileSavePath(&savePath, p_slot);
LegoFileStream fileStream;
if (fileStream.Open(savePath.GetData(), LegoStream::WriteBit) != FAILURE) {
MxU32 maybeVersion = 0x1000C;
fileStream.Write(&maybeVersion, 4);
fileStream.Write(&m_unk24, 2);
fileStream.Write(&m_unk10, 2);
fileStream.Write(&m_unkC, 1);
for (MxS32 i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i) {
if (LegoStream::WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE)
return result;
}
if (LegoStream::WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE) {
if (LegoStream::WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE) {
WriteEndOfVariables(&fileStream);
// TODO: Calls down to more aggregate writing functions
return SUCCESS;
}
}
}
}
return result;
}
// OFFSET: LEGO1 0x1003a2e0 STUB
void LegoGameState::SerializePlayersInfo(MxS16 p)
{
// TODO
}
// OFFSET: LEGO1 0x1003cdd0
// OFFSET: LEGO1 0x1003cdd0 STUB
void LegoGameState::SerializeScoreHistory(MxS16 p)
{
// TODO
@ -61,16 +181,56 @@ void LegoGameState::SerializeScoreHistory(MxS16 p)
void LegoGameState::SetSavePath(char *p_savePath)
{
if (m_savePath != NULL)
{
delete[] m_savePath;
}
if (p_savePath)
{
if (p_savePath) {
m_savePath = new char[strlen(p_savePath) + 1];
strcpy(m_savePath, p_savePath);
}
else
{
m_savePath = NULL;
}
}
// OFFSET: LEGO1 0x1003bbb0
LegoState *LegoGameState::GetState(char *p_stateName)
{
for (MxS32 i = 0; i < m_stateCount; ++i)
if (m_stateArray[i]->IsA(p_stateName))
return m_stateArray[i];
return NULL;
}
// OFFSET: LEGO1 0x1003bc00
LegoState *LegoGameState::CreateState(char *p_stateName)
{
LegoState* newState = (LegoState*)ObjectFactory()->Create(p_stateName);
RegisterState(newState);
return newState;
}
// OFFSET: LEGO1 0x1003bc30
void LegoGameState::RegisterState(LegoState *p_state)
{
MxS32 targetIndex;
for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex)
if (m_stateArray[targetIndex]->IsA(p_state->ClassName()))
break;
if (targetIndex == m_stateCount) {
LegoState **newBuffer = new LegoState*[m_stateCount + 1];
if (m_stateCount != 0) {
memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*));
delete[] m_stateArray;
}
newBuffer[m_stateCount++] = p_state;
m_stateArray = newBuffer;
return;
}
if (m_stateArray[targetIndex])
delete m_stateArray[targetIndex];
m_stateArray[targetIndex] = p_state;
}

View File

@ -6,6 +6,17 @@
#include "legobackgroundcolor.h"
#include "legofullscreenmovie.h"
class LegoState;
class LegoStream;
class MxVariable;
class MxString;
struct ColorStringStruct
{
const char *m_targetName;
const char *m_colorName;
};
// SIZE 0x430 (at least)
class LegoGameState
{
@ -18,13 +29,27 @@ class LegoGameState
__declspec(dllexport) void SerializeScoreHistory(MxS16 p);
__declspec(dllexport) void SetSavePath(char *p);
LegoState *GetState(char *p_stateName);
LegoState *CreateState(char *p_stateName);
void GetFileSavePath(MxString *p_outPath, MxULong p_slotn);
private:
void RegisterState(LegoState *p_state);
MxResult WriteEndOfVariables(LegoStream *p_stream);
private:
char *m_savePath; // 0x0
undefined m_unk04[20];
MxS16 m_stateCount;
LegoState **m_stateArray;
MxU8 m_unkC;
MxU32 m_unk10;
undefined4 m_unk0x14;
LegoBackgroundColor *m_backgroundColor; // 0x18
LegoBackgroundColor *m_tempBackgroundColor; // 0x1c
LegoFullScreenMovie *m_fullScreenMovie; // 0x20
undefined m_unk24[1036];
MxU16 m_unk24; // 0x24
undefined m_unk28[1032];
};
#endif // LEGOGAMESTATE_H

View File

@ -0,0 +1,6 @@
#include "legometerpresenter.h"
#include "decomp.h"
// Uncomment when member class variables are fleshed out.
// DECOMP_SIZE_ASSERT(LegoMeterPresenter, 0x94); // 0x1000a163

View File

@ -0,0 +1,14 @@
#ifndef LEGOMETERPRESENTER_H
#define LEGOMETERPRESENTER_H
#include "mxstillpresenter.h"
// VTABLE 0x100d7ac8
// SIZE 0x94 (from 0x1000a163)
class LegoMeterPresenter : public MxStillPresenter
{
public:
// MxStillPresenter's `::ClassName` and `::IsA` are used.
};
#endif // LEGOMETERPRESENTER_H

View File

@ -0,0 +1,35 @@
#include "legoobjectfactory.h"
#include "infocenterstate.h"
#include "decomp.h"
// TODO: Uncomment once we have all the relevant types ready
// DECOMP_SIZE_ASSERT(LegoObjectFactory, 0x1c8);
// OFFSET: LEGO1 0x10006e40
LegoObjectFactory::LegoObjectFactory()
{
#define X(V) this->m_id##V = MxAtomId(#V, LookupMode_Exact);
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
}
// OFFSET: LEGO1 0x10009a90
MxCore *LegoObjectFactory::Create(const char *p_name)
{
MxAtomId atom(p_name, LookupMode_Exact);
if (0) {
#define X(V) } else if (this->m_id##V == atom) { return new V;
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
} else {
return MxObjectFactory::Create(p_name);
}
}
// OFFSET: LEGO1 0x1000fb30 STUB
void LegoObjectFactory::Destroy(MxCore *p_object)
{
// TODO
}

22
LEGO1/legoobjectfactory.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef LEGOOBJECTFACTORY_H
#define LEGOOBJECTFACTORY_H
#include "mxobjectfactory.h"
#define FOR_LEGOOBJECTFACTORY_OBJECTS(X) \
X(InfocenterState)
// VTABLE 0x100d4768
class LegoObjectFactory : public MxObjectFactory
{
public:
LegoObjectFactory();
virtual MxCore *Create(const char *p_name) override; // vtable 0x14
virtual void Destroy(MxCore *p_object) override; // vtable 0x18
private:
#define X(V) MxAtomId m_id##V;
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
};
#endif // LEGOOBJECTFACTORY_H

View File

@ -4,6 +4,7 @@
#include "mxdsfile.h"
#include "legogamestate.h"
#include "legoutil.h"
#include "legoobjectfactory.h"
// 0x100f4588
MxAtomId *g_nocdSourceName = NULL;
@ -261,7 +262,7 @@ void LegoOmni::Init()
m_currentWorld = NULL;
m_unk80 = FALSE;
m_isle = NULL;
m_unk8c = 0;
m_unkLegoSaveDataWriter = NULL;
m_plantManager = NULL;
m_gameState = NULL;
m_animationManager = NULL;
@ -271,11 +272,12 @@ void LegoOmni::Init()
m_transitionManager = NULL;
}
// OFFSET: LEGO1 0x10058e70
// OFFSET: LEGO1 0x10058e70 STUB
MxResult LegoOmni::Create(COMPAT_CONST MxOmniCreateParam &p)
{
// FIXME: Stub
MxOmni::Create(p);
m_objectFactory = new LegoObjectFactory();
m_gameState = new LegoGameState();
m_bkgAudioManager = new MxBackgroundAudioManager();

View File

@ -16,6 +16,7 @@ class LegoPathBoundary;
class LegoPlantManager;
class LegoROI;
class LegoSoundManager;
class LegoUnkSaveDataWriter;
class LegoVideoManager;
class LegoWorld;
class MxAtomId;
@ -77,8 +78,8 @@ class LegoOmni : public MxOmni
LegoWorld *GetCurrentWorld() { return m_currentWorld; }
private:
int m_unk68;
int m_unk6c;
undefined4 m_unk68;
undefined4 m_unk6c;
LegoInputManager *m_inputMgr; // 0x70
undefined4 m_unk74;
undefined4 m_unk78;
@ -86,7 +87,7 @@ class LegoOmni : public MxOmni
MxBool m_unk80;
LegoNavController *m_navController; // 0x84
Isle* m_isle; // 0x88
undefined4 m_unk8c;
LegoUnkSaveDataWriter* m_unkLegoSaveDataWriter;
LegoPlantManager* m_plantManager; // 0x90
LegoAnimationManager* m_animationManager;
LegoBuildingManager* m_buildingManager; // 0x98

View File

@ -4,6 +4,14 @@
#include <cstdio>
#include <string>
#include "mxvariabletable.h"
// This is a pointer to the end of the global variable name table, which has
// the text "END_OF_VARIABLES" in it.
// TODO: make s_endOfVariables reference the actual end of the variable array.
// GLOBAL OFFSET: LEGO1 0x100f3e50
const char *s_endOfVariables = "END_OF_VARIABLES";
// Very likely but not certain sizes.
// The classes are only used on the stack in functions we have not 100% matched
// yet, we can confirm the size once we have.
@ -38,7 +46,7 @@ LegoFileStream::~LegoFileStream()
}
// OFFSET: LEGO1 0x100992c0
MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size)
MxResult LegoFileStream::Read(void* p_buffer, MxU32 p_size)
{
if (m_hFile == NULL)
return FAILURE;
@ -47,7 +55,7 @@ MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size)
}
// OFFSET: LEGO1 0x10099300
MxResult LegoFileStream::Write(char* p_buffer, MxU32 p_size)
MxResult LegoFileStream::Write(const void* p_buffer, MxU32 p_size)
{
if (m_hFile == NULL)
return FAILURE;
@ -117,7 +125,7 @@ LegoMemoryStream::LegoMemoryStream(char* p_buffer)
}
// OFFSET: LEGO1 0x10099160
MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size)
MxResult LegoMemoryStream::Read(void* p_buffer, MxU32 p_size)
{
memcpy(p_buffer, m_buffer + m_offset, p_size);
m_offset += p_size;
@ -125,7 +133,7 @@ MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size)
}
// OFFSET: LEGO1 0x10099190
MxResult LegoMemoryStream::Write(char* p_buffer, MxU32 p_size)
MxResult LegoMemoryStream::Write(const void* p_buffer, MxU32 p_size)
{
memcpy(m_buffer + m_offset, p_buffer, p_size);
m_offset += p_size;
@ -146,4 +154,51 @@ MxResult LegoMemoryStream::Seek(MxU32 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

@ -10,6 +10,8 @@
#define LEGOSTREAM_MODE_READ 1
#define LEGOSTREAM_MODE_WRITE 2
class MxVariableTable;
// VTABLE 0x100d7d80
class LegoStream
{
@ -17,8 +19,8 @@ class LegoStream
LegoStream() : m_mode(0) {}
inline virtual ~LegoStream() {};
virtual MxResult Read(char* p_buffer, MxU32 p_size) = 0;
virtual MxResult Write(char* p_buffer, MxU32 p_size) = 0;
virtual MxResult Read(void* p_buffer, MxU32 p_size) = 0;
virtual MxResult Write(const void* p_buffer, MxU32 p_size) = 0;
virtual MxResult Tell(MxU32* p_offset) = 0;
virtual MxResult Seek(MxU32 p_offset) = 0;
@ -32,6 +34,9 @@ class LegoStream
BinaryBit = 4,
};
static MxResult __stdcall WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName);
static MxS32 __stdcall ReadVariable(LegoStream* p_stream, MxVariableTable* p_to);
protected:
MxU8 m_mode;
};
@ -43,8 +48,8 @@ class LegoFileStream : public LegoStream
LegoFileStream();
virtual ~LegoFileStream();
MxResult Read(char* p_buffer, MxU32 p_size) override;
MxResult Write(char* p_buffer, MxU32 p_size) override;
MxResult Read(void* p_buffer, MxU32 p_size) override;
MxResult Write(const void* p_buffer, MxU32 p_size) override;
MxResult Tell(MxU32* p_offset) override;
MxResult Seek(MxU32 p_offset) override;
@ -61,8 +66,8 @@ class LegoMemoryStream : public LegoStream
LegoMemoryStream(char* p_buffer);
~LegoMemoryStream() {}
MxResult Read(char* p_buffer, MxU32 p_size) override;
MxResult Write(char* p_buffer, MxU32 p_size) override;
MxResult Read(void* p_buffer, MxU32 p_size) override;
MxResult Write(const void* p_buffer, MxU32 p_size) override;
MxResult Tell(MxU32* p_offset) override;
MxResult Seek(MxU32 p_offset) override;

View File

@ -0,0 +1,48 @@
#include "legounksavedatawriter.h"
#include "legogamestate.h"
#include "legostream.h"
DECOMP_SIZE_ASSERT(LegoSaveDataEntry3, 0x108);
// GLOBAL OFFSET: LEGO1 0x10104f20
LegoSaveDataEntry3 g_saveData3[66];
// OFFSET: LEGO1 0x10083310
MxResult LegoUnkSaveDataWriter::WriteSaveData3(LegoStream *p_stream)
{
MxResult result = FAILURE;
// This should probably be a for loop but I can't figure out how to
// make it match as a for loop.
LegoSaveDataEntry3 *entry = g_saveData3;
const LegoSaveDataEntry3 *end = &g_saveData3[66];
while (TRUE) {
if (p_stream->Write(&entry->m_savePart1, 4) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart2, 4) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart3, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_currentFrame, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart5, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart6, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart7, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart8, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart9, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart10, 1) != SUCCESS)
break;
if (++entry >= end) {
result = SUCCESS;
break;
}
}
return result;
}

View File

@ -0,0 +1,40 @@
#ifndef LEGOUNKSAVEDATAWRITER_H
#define LEGOUNKSAVEDATAWRITER_H
#include "mxtypes.h"
#include "decomp.h"
class LegoStream;
struct LegoSaveDataEntry3
{
char *m_name;
void *m_unk0x04;
void *m_unk0x08;
MxS32 m_savePart1;
MxS32 m_savePart2;
MxU8 m_savePart3;
undefined4 m_unk0x18[6];
MxU8 m_frameOffsetInDwords; // 0x30
MxS32 *m_pFrameData;
MxU8 m_currentFrame;
undefined4 m_unk0x3c[2];
MxU8 m_savePart5; // 0x44
undefined4 m_unk0x48[5];
MxU8 m_savePart6; // 0x5c
undefined4 m_unk0x60[11];
MxU8 m_savePart7; // 0x8c
undefined4 m_unk0x90[5];
MxU8 m_savePart8; // 0xa4
undefined4 m_unk0xa8[17];
MxU8 m_savePart9; // 0xec
undefined4 m_unk0xf0[5];
MxU8 m_savePart10; // 0x104
};
class LegoUnkSaveDataWriter
{
MxResult WriteSaveData3(LegoStream *p_stream);
};
#endif // LEGOUNKSAVEDATAWRITER_H

View File

@ -0,0 +1,25 @@
#include "legovehiclebuildstate.h"
#include "decomp.h"
DECOMP_SIZE_ASSERT(LegoVehicleBuildState, 0x50); // 1000acd7
DECOMP_SIZE_ASSERT(LegoVehicleBuildState::UnkStruct, 0xc);
// OFFSET: LEGO1 0x10025f30
LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType)
{
this->m_className = p_classType;
this->m_unk4c = 0;
this->m_unk4d = 0;
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

@ -0,0 +1,60 @@
#ifndef LEGOVEHICLEBUILDSTATE_H
#define LEGOVEHICLEBUILDSTATE_H
#include "legostate.h"
#include "mxstring.h"
#include "decomp.h"
#include "decomp.h"
// VTABLE 0x100d66e0
// SIZE 0x50 (from 1000acd7)
class LegoVehicleBuildState : public LegoState
{
public:
LegoVehicleBuildState(char* p_classType);
// OFFSET: LEGO1 0x10025ff0
inline virtual const char *ClassName() const override // vtable+0x0c
{
return this->m_className.GetData();
}
// OFFSET: LEGO1 0x10026000
inline virtual MxBool IsA(const char *p_name) const override // vtable+0x10
{
return !strcmp(p_name, this->m_className.GetData()) || LegoState::IsA(p_name);
}
public:
struct UnkStruct
{
undefined4 m_unk00;
undefined2 m_unk04;
undefined2 m_unk06;
undefined2 m_unk08;
UnkStruct();
};
private:
UnkStruct m_unk08[4]; // 0x08
// This can be one of the following:
// * LegoRaceCarBuildState
// * LegoCopterBuildState
// * LegoDuneCarBuildState
// * LegoJetskiBuildState
MxString m_className; // 0x38
// Known States:
// * 1 == enter(ing) build screen
// * 3 == cutscene/dialogue
// * 6 == exit(ing) build screen
MxU32 m_animationState; // 0x48
undefined m_unk4c; // 0x4c
undefined m_unk4d; // 0x4d
undefined m_unk4e; // 0x4e
MxU8 m_placedPartCount; // 0x4f
};
#endif // LEGOVEHICLEBUILDSTATE_H

View File

@ -14,7 +14,7 @@ MxAudioManager::MxAudioManager()
// OFFSET: LEGO1 0x100b8d90
MxAudioManager::~MxAudioManager()
{
LockedReinitialize(TRUE);
Destroy(TRUE);
}
// OFFSET: LEGO1 0x100b8df0
@ -38,14 +38,14 @@ void MxAudioManager::SetVolume(MxS32 p_volume)
}
// OFFSET: LEGO1 0x100b8e00
void MxAudioManager::LockedReinitialize(MxBool p_skipDestroy)
void MxAudioManager::Destroy(MxBool p_fromDestructor)
{
this->m_criticalSection.Enter();
g_unkCount--;
Init();
this->m_criticalSection.Leave();
if (!p_skipDestroy)
if (!p_fromDestructor)
MxMediaManager::Destroy();
}
@ -74,5 +74,5 @@ MxResult MxAudioManager::InitPresenters()
// OFFSET: LEGO1 0x100b8e90
void MxAudioManager::Destroy()
{
LockedReinitialize(FALSE);
Destroy(FALSE);
}

View File

@ -17,7 +17,7 @@ class MxAudioManager : public MxMediaManager
virtual void SetVolume(MxS32 p_volume); // vtable+2c
private:
void LockedReinitialize(MxBool p_skipDestroy);
void Destroy(MxBool p_fromDestructor);
static MxS32 g_unkCount;

View File

@ -15,7 +15,7 @@ MxU16 g_unkSep = TWOCC(',', ' ');
// OFFSET: LEGO1 0x100ad810
MxDSAction::MxDSAction()
{
this->m_flags = 32;
this->m_flags = MxDSAction::Flag_Enabled;
this->m_startTime = INT_MIN;
this->m_extraData = NULL;
this->m_extraLength = 0;
@ -29,7 +29,7 @@ MxDSAction::MxDSAction()
this->m_unk84 = 0;
this->m_unk88 = 0;
this->m_omni = NULL;
this->m_someTimingField = INT_MIN;
this->m_unkTimingField = INT_MIN;
}
// OFFSET: LEGO1 0x100ada80
@ -55,7 +55,7 @@ void MxDSAction::CopyFrom(MxDSAction &p_dsAction)
this->m_unk84 = p_dsAction.m_unk84;
this->m_unk88 = p_dsAction.m_unk88;
this->m_omni = p_dsAction.m_omni;
this->m_someTimingField = p_dsAction.m_someTimingField;
this->m_unkTimingField = p_dsAction.m_unkTimingField;
}
// OFFSET: LEGO1 0x100adc10
@ -153,7 +153,7 @@ void MxDSAction::MergeFrom(MxDSAction &p_dsAction)
if (p_dsAction.m_direction[1] != FLT_MAX)
this->m_direction[1] = p_dsAction.m_direction[1];
if (p_dsAction.m_direction[2] != FLT_MAX)
this->m_direction[2] = p_dsAction.m_direction[2];
this->m_direction[2] = p_dsAction.m_up[2]; // This is correct
if (p_dsAction.m_up[0] != FLT_MAX)
this->m_up[0] = p_dsAction.m_up[0];
@ -162,9 +162,13 @@ void MxDSAction::MergeFrom(MxDSAction &p_dsAction)
if (p_dsAction.m_up[2] != FLT_MAX)
this->m_up[2] = p_dsAction.m_up[2];
// TODO
MxU16 extraLength = p_dsAction.m_extraLength;
char *extraData = p_dsAction.m_extraData;
// Taking those references forces the compiler to move the values onto the stack.
// The original code most likely looked different, but this yields a 100% match.
MxU16 &_extraLength = extraLength;
char *&_extraData = extraData;
if (extraLength && extraData) {
if (!this->m_extraData || !strncmp("XXX", this->m_extraData, 3)) {
delete[] this->m_extraData;
@ -181,15 +185,15 @@ MxBool MxDSAction::HasId(MxU32 p_objectId)
}
// OFFSET: LEGO1 0x100ada40
void MxDSAction::SetSomeTimingField(MxLong p_someTimingField)
void MxDSAction::SetUnkTimingField(MxLong p_unkTimingField)
{
this->m_someTimingField = p_someTimingField;
this->m_unkTimingField = p_unkTimingField;
}
// OFFSET: LEGO1 0x100ada50
MxLong MxDSAction::GetSomeTimingField()
MxLong MxDSAction::GetUnkTimingField()
{
return this->m_someTimingField;
return this->m_unkTimingField;
}
// Win32 defines GetCurrentTime to GetTickCount
@ -198,7 +202,7 @@ MxLong MxDSAction::GetSomeTimingField()
// OFFSET: LEGO1 0x100adcd0
MxLong MxDSAction::GetCurrentTime()
{
return Timer()->GetTime() - this->m_someTimingField;
return Timer()->GetTime() - this->m_unkTimingField;
}
// OFFSET: LEGO1 0x100ade60

View File

@ -48,8 +48,8 @@ class MxDSAction : public MxDSObject
virtual MxDSAction *Clone(); // vtable+2c;
virtual void MergeFrom(MxDSAction &p_dsAction); // vtable+30;
virtual MxBool HasId(MxU32 p_objectId); // vtable+34;
virtual void SetSomeTimingField(MxLong p_someTimingField); // vtable+38;
virtual MxLong GetSomeTimingField(); // vtable+3c;
virtual void SetUnkTimingField(MxLong p_unkTimingField); // vtable+38;
virtual MxLong GetUnkTimingField(); // vtable+3c;
virtual MxLong GetCurrentTime(); // vtable+40;
void AppendData(MxU16 p_extraLength, const char *p_extraData);
@ -87,7 +87,7 @@ class MxDSAction : public MxDSObject
MxOmni *m_omni; // 0x8c
protected:
MxLong m_someTimingField; // 0x90
MxLong m_unkTimingField; // 0x90
};
#endif // MXDSACTION_H

View File

@ -4,16 +4,16 @@
MxDSChunk::MxDSChunk()
{
this->m_length = 0;
this->m_pStuff = NULL;
this->m_unk18 = NULL;
this->m_buffer = -1;
this->m_long1FromHeader = 0;
this->m_long2FromHeader = 0;
this->m_unk10 = 0;
this->m_unk14 = 0;
}
// OFFSET: LEGO1 0x100be170
MxDSChunk::~MxDSChunk()
{
if ((this->m_length & 1) != 0) {
delete this->m_pStuff;
delete this->m_unk18;
}
}

View File

@ -26,10 +26,10 @@ class MxDSChunk : public MxCore
private:
MxS16 m_length; // 0x8
MxLong m_buffer; // 0xc
MxLong m_long1FromHeader; // 0x10
MxLong m_long2FromHeader; // 0x14
void* m_pStuff; // 0x18
void* m_pSomething; // 0x1c
MxLong m_unk10; // 0x10
MxLong m_unk14; // 0x14
void* m_unk18; // 0x18
void* m_unk1c; // 0x1c
};
#endif // MXDSCHUNK_H

View File

@ -40,14 +40,14 @@ MxDSMultiAction &MxDSMultiAction::operator=(MxDSMultiAction &p_dsMultiAction)
}
// OFFSET: LEGO1 0x100ca290
void MxDSMultiAction::SetSomeTimingField(MxLong p_someTimingField)
void MxDSMultiAction::SetUnkTimingField(MxLong p_unkTimingField)
{
this->m_someTimingField = p_someTimingField;
this->m_unkTimingField = p_unkTimingField;
MxDSActionListCursor cursor(this->m_actions);
MxDSAction *action;
while (cursor.Next(action))
action->SetSomeTimingField(p_someTimingField);
action->SetUnkTimingField(p_unkTimingField);
}
// OFFSET: LEGO1 0x100ca370

View File

@ -35,7 +35,7 @@ class MxDSMultiAction : public MxDSAction
virtual MxDSAction *Clone() override; // vtable+2c;
virtual void MergeFrom(MxDSAction &p_dsAction) override; // vtable+30;
virtual MxBool HasId(MxU32 p_objectId) override; // vtable+34;
virtual void SetSomeTimingField(MxLong p_someTimingField) override; // vtable+38;
virtual void SetUnkTimingField(MxLong p_unkTimingField) override; // vtable+38;
protected:
MxU32 m_sizeOnDisk;

View File

@ -1,9 +1,9 @@
#include "mxdssource.h"
// OFFSET: LEGO1 0x100bffd0
void MxDSSource::SomethingWhichCallsRead(void* pUnknownObject)
void MxDSSource::FUN_100bffd0(void* p_unk)
{
// TODO: Calls read, reading into a buffer somewhere in pUnknownObject.
// TODO: Calls read, reading into a buffer somewhere in p_unk.
Read(NULL, 0);
}

View File

@ -28,7 +28,7 @@ class MxDSSource : public MxCore
virtual MxLong Open(MxULong) = 0;
virtual MxLong Close() = 0;
virtual void SomethingWhichCallsRead(void* pUnknownObject);
virtual void FUN_100bffd0(void* p_unk);
virtual MxResult Read(unsigned char *, MxULong) = 0;
virtual MxLong Seek(MxLong, int) = 0;
virtual MxULong GetBufferSize() = 0;

View File

@ -28,7 +28,7 @@ class MxEntity : public MxCore
}
virtual MxResult SetEntityId(MxS32 p_id, const MxAtomId &p_atom); // vtable+0x14
private:
protected:
MxS32 m_mxEntityId; // 0x8
MxAtomId m_atom; // 0xc
};

View File

@ -13,7 +13,7 @@ MxEventManager::MxEventManager()
// OFFSET: LEGO1 0x100c03f0
MxEventManager::~MxEventManager()
{
TerminateThread(TRUE);
Destroy(TRUE);
}
// OFFSET: LEGO1 0x100c0450
@ -22,45 +22,54 @@ void MxEventManager::Init()
// This is intentionally left blank
}
// OFFSET: LEGO1 0x100c0460
void MxEventManager::Destroy(MxBool p_fromDestructor)
{
if (m_thread != NULL) {
m_thread->Terminate();
delete m_thread;
}
else
TickleManager()->UnregisterClient(this);
if (!p_fromDestructor)
MxMediaManager::Destroy();
}
// OFFSET: LEGO1 0x100c04a0
MxResult MxEventManager::CreateEventThread(MxU32 p_frequencyMS, MxBool p_noRegister)
MxResult MxEventManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
{
MxResult status = FAILURE;
MxBool locked = FALSE;
MxResult result = MxMediaManager::InitPresenters();
if (result == SUCCESS)
{
if (p_noRegister)
{
if (result == SUCCESS) {
if (p_createThread) {
this->m_criticalSection.Enter();
locked = TRUE;
this->m_thread = new MxTickleThread(this, p_frequencyMS);
if (this->m_thread)
{
if (this->m_thread->Start(0, 0) == SUCCESS)
{
status = SUCCESS;
}
}
if (!this->m_thread || this->m_thread->Start(0, 0) != SUCCESS)
goto done;
}
else
{
TickleManager()->RegisterClient(this, p_frequencyMS);
status = SUCCESS;
}
status = SUCCESS;
}
done:
if (status != SUCCESS)
{
Destroy();
}
if (locked)
{
this->m_criticalSection.Leave();
}
return status;
}
// OFFSET: LEGO1 0x100c0590
void MxEventManager::Destroy()
{
Destroy(FALSE);
}

View File

@ -11,9 +11,13 @@ class MxEventManager : public MxMediaManager
public:
MxEventManager();
virtual ~MxEventManager() override;
virtual MxResult CreateEventThread(MxU32 p_frequencyMS, MxBool p_noRegister); // vtable+28
virtual void Destroy() override; // vtable+18
virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+28
private:
void Init();
void Destroy(MxBool p_fromDestructor);
};
#endif // MXEVENTMANAGER_H

View File

@ -25,7 +25,7 @@ void MxLoopingFlcPresenter::Init()
}
// OFFSET: LEGO1 0x100b4432 STUB
void MxLoopingFlcPresenter::Destroy(MxBool p_param)
void MxLoopingFlcPresenter::Destroy(MxBool p_fromDestructor)
{
// TODO
}

View File

@ -22,7 +22,7 @@ class MxLoopingFlcPresenter : public MxFlcPresenter
private:
void Init();
void Destroy(MxBool);
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk68;
};

View File

@ -25,7 +25,6 @@ void MxLoopingSmkPresenter::Init()
}
// OFFSET: LEGO1 0x100b49d0 STUB
void MxLoopingSmkPresenter::Destroy(MxBool p_bool)
void MxLoopingSmkPresenter::Destroy(MxBool p_fromDestructor)
{
// TODO - theres a chain of destroy and free function calls here (FUN_100b4300 -> FUN_100b3900 -> FUN_100c5d40 -> function at 0x100b27b0)
}

View File

@ -22,7 +22,7 @@ class MxLoopingSmkPresenter : public MxSmkPresenter
private:
void Init();
void Destroy(MxBool);
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk720;
};

View File

@ -175,7 +175,7 @@ void MxMatrix::ToQuaternion(MxVector4 *p_outQuat)
// No idea what this function is doing and it will be hard to tell until
// we have a confirmed usage site.
// OFFSET: LEGO1 0x10002710 STUB
MxResult MxMatrix::DoSomethingWithLength(const MxVector3 *p_vec)
MxResult MxMatrix::FUN_10002710(const MxVector3 *p_vec)
{
return FAILURE;
}

View File

@ -36,7 +36,7 @@ class MxMatrix
// vtable + 0x40
virtual void ToQuaternion(MxVector4 *p_resultQuat);
virtual MxResult DoSomethingWithLength(const MxVector3 *p_vec);
virtual MxResult FUN_10002710(const MxVector3 *p_vec);
private:
float *m_data;

View File

@ -98,23 +98,4 @@ void MxMediaManager::StopPresenters()
while (cursor.Next(presenter))
presenter->EndAction();
}
// OFFSET: LEGO1 0x100c0460
void MxMediaManager::TerminateThread(MxBool p_reinit)
{
if(m_thread != NULL)
{
m_thread->Terminate();
delete m_thread;
}
else
{
TickleManager()->UnregisterClient(this);
}
if(!p_reinit)
{
MxMediaManager::Destroy();
}
}
}

View File

@ -23,7 +23,6 @@ class MxMediaManager : public MxCore
virtual void StopPresenters(); // vtable+24
MxResult Init();
void TerminateThread(MxBool p_reinit);
protected:
MxPresenterList *m_presenters;

View File

@ -25,7 +25,7 @@ void MxMediaPresenter::Init()
}
// OFFSET: LEGO1 0x100b54f0 STUB
void MxMediaPresenter::Destroy(MxBool p_destroy)
void MxMediaPresenter::Destroy(MxBool p_fromDestructor)
{
// TODO
}
@ -57,7 +57,7 @@ void MxMediaPresenter::Enable(MxBool p_enable)
}
// OFFSET: LEGO1 0x1000c5b0
void MxMediaPresenter::InitVirtual()
void MxMediaPresenter::Destroy()
{
Destroy(FALSE);
}

View File

@ -33,7 +33,7 @@ class MxMediaPresenter : public MxPresenter
virtual void StreamingTickle() override;
virtual void RepeatingTickle() override;
virtual void DoneTickle() override;
virtual void InitVirtual() override;
virtual void Destroy() override;
virtual MxLong StartAction(MxStreamController *, MxDSAction *) override;
virtual void EndAction() override;
virtual void Enable(MxBool p_enable) override;
@ -43,10 +43,10 @@ class MxMediaPresenter : public MxPresenter
undefined4 m_unk44;
undefined4 m_unk48;
undefined4 m_unk4c;
protected:
void Destroy(MxBool);
private:
void Init();
protected:
void Destroy(MxBool p_fromDestructor);
};

View File

@ -1,16 +1,39 @@
#include "mxmidipresenter.h"
#include "decomp.h"
#include "legoomni.h"
#include "mxmusicmanager.h"
DECOMP_SIZE_ASSERT(MxMIDIPresenter, 0x58);
// OFFSET: LEGO1 0x100c25e0
MxMIDIPresenter::MxMIDIPresenter() {
MxMIDIPresenter::MxMIDIPresenter()
{
Init();
}
// OFFSET: LEGO1 0x100c27c0
MxMIDIPresenter::~MxMIDIPresenter()
{
Destroy(TRUE);
}
// OFFSET: LEGO1 0x100c2820
void MxMIDIPresenter::Init()
{
m_unk54 = 0;
}
// OFFSET: LEGO1 0x100c2830 STUB
void MxMIDIPresenter::Destroy(MxBool p_fromDestructor)
{
// TODO
}
// OFFSET: LEGO1 0x100c2940
void MxMIDIPresenter::DoneTickle()
{
if (!MusicManager()->GetMIDIInitialized()) {
this->EndAction();
}
}

View File

@ -8,6 +8,7 @@ class MxMIDIPresenter : public MxMusicPresenter
{
public:
MxMIDIPresenter();
virtual ~MxMIDIPresenter() override;
// OFFSET: LEGO1 0x100c2650
inline virtual const char *ClassName() const override // vtable+0xc
@ -22,8 +23,12 @@ class MxMIDIPresenter : public MxMusicPresenter
return !strcmp(name, MxMIDIPresenter::ClassName()) || MxMusicPresenter::IsA(name);
}
virtual void DoneTickle() override; // vtable+0x2c
private:
void Init();
void Destroy(MxBool);
undefined4 m_unk54;
};

View File

@ -15,7 +15,7 @@ MxMusicManager::MxMusicManager()
// OFFSET: LEGO1 0x100c0630
MxMusicManager::~MxMusicManager()
{
LockedReinitialize(TRUE);
Destroy(TRUE);
}
// OFFSET: LEGO1 0x100c0b20
@ -23,47 +23,47 @@ void MxMusicManager::DeinitializeMIDI()
{
m_criticalSection.Enter();
if (this->m_MIDIInitialized)
if (m_MIDIInitialized)
{
this->m_MIDIInitialized = FALSE;
midiStreamStop(this->m_MIDIStreamH);
midiOutUnprepareHeader(this->m_MIDIStreamH, this->m_MIDIHdrP, sizeof(MIDIHDR));
midiOutSetVolume(this->m_MIDIStreamH, this->m_MIDIVolume);
midiStreamClose(this->m_MIDIStreamH);
delete this->m_MIDIHdrP;
this->InitData();
m_MIDIInitialized = FALSE;
midiStreamStop(m_MIDIStreamH);
midiOutUnprepareHeader(m_MIDIStreamH, m_MIDIHdrP, sizeof(MIDIHDR));
midiOutSetVolume(m_MIDIStreamH, m_MIDIVolume);
midiStreamClose(m_MIDIStreamH);
delete m_MIDIHdrP;
InitData();
}
this->m_criticalSection.Leave();
m_criticalSection.Leave();
}
// OFFSET: LEGO1 0x100c0690
void MxMusicManager::Init()
{
this->m_multiplier = 100;
m_multiplier = 100;
InitData();
}
// OFFSET: LEGO1 0x100c06a0
void MxMusicManager::InitData()
{
this->m_MIDIStreamH = 0;
this->m_MIDIInitialized = FALSE;
this->m_unk38 = 0;
this->m_unk3c = 0;
this->m_unk40 = 0;
this->m_unk44 = 0;
this->m_unk48 = 0;
this->m_MIDIHdrP = NULL;
m_MIDIStreamH = 0;
m_MIDIInitialized = FALSE;
m_unk38 = 0;
m_unk3c = 0;
m_unk40 = 0;
m_unk44 = 0;
m_unk48 = 0;
m_MIDIHdrP = NULL;
}
// OFFSET: LEGO1 0x100c06c0
void MxMusicManager::LockedReinitialize(MxBool p_skipDestroy)
void MxMusicManager::Destroy(MxBool p_fromDestructor)
{
if (this->m_thread)
if (m_thread)
{
this->m_thread->Terminate();
if (this->m_thread)
m_thread->Terminate();
if (m_thread)
{
delete m_thread;
}
@ -73,12 +73,12 @@ void MxMusicManager::LockedReinitialize(MxBool p_skipDestroy)
TickleManager()->UnregisterClient(this);
}
this->m_criticalSection.Enter();
m_criticalSection.Enter();
DeinitializeMIDI();
Init();
this->m_criticalSection.Leave();
m_criticalSection.Leave();
if (!p_skipDestroy)
if (!p_fromDestructor)
{
MxAudioManager::Destroy();
}
@ -87,7 +87,7 @@ void MxMusicManager::LockedReinitialize(MxBool p_skipDestroy)
// OFFSET: LEGO1 0x100c0930
void MxMusicManager::Destroy()
{
LockedReinitialize(FALSE);
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100c09a0
@ -100,8 +100,8 @@ MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume)
// OFFSET: LEGO1 0x100c07f0
void MxMusicManager::SetMIDIVolume()
{
MxS32 result = (this->m_volume * this->m_multiplier) / 0x64;
HMIDISTRM streamHandle = this->m_MIDIStreamH;
MxS32 result = (m_volume * m_multiplier) / 0x64;
HMIDISTRM streamHandle = m_MIDIStreamH;
if (streamHandle)
{
@ -114,50 +114,38 @@ void MxMusicManager::SetMIDIVolume()
void MxMusicManager::SetVolume(MxS32 p_volume)
{
MxAudioManager::SetVolume(p_volume);
this->m_criticalSection.Enter();
m_criticalSection.Enter();
SetMIDIVolume();
this->m_criticalSection.Leave();
m_criticalSection.Leave();
}
// OFFSET: LEGO1 0x100c0840
MxResult MxMusicManager::StartMIDIThread(MxU32 p_frequencyMS, MxBool p_noRegister)
MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
{
MxResult status = FAILURE;
MxBool locked = FALSE;
MxResult result = MxAudioManager::InitPresenters();
if (result == SUCCESS)
{
if (p_noRegister)
{
this->m_criticalSection.Enter();
if (MxAudioManager::InitPresenters() == SUCCESS) {
if (p_createThread) {
m_criticalSection.Enter();
locked = TRUE;
this->m_thread = new MxTickleThread(this, p_frequencyMS);
m_thread = new MxTickleThread(this, p_frequencyMS);
if (this->m_thread)
{
if (this->m_thread->Start(0, 0) == SUCCESS)
{
status = SUCCESS;
}
}
if (!m_thread || m_thread->Start(0, 0) != SUCCESS)
goto done;
}
else
{
TickleManager()->RegisterClient(this, p_frequencyMS);
status = SUCCESS;
}
status = SUCCESS;
}
done:
if (status != SUCCESS)
{
Destroy();
}
if (locked)
{
this->m_criticalSection.Leave();
}
m_criticalSection.Leave();
return status;
}

View File

@ -14,10 +14,12 @@ class MxMusicManager : public MxAudioManager
virtual void Destroy() override; // vtable+18
virtual void SetVolume(MxS32 p_volume) override; // vtable+2c
virtual MxResult StartMIDIThread(MxU32 p_frequencyMS, MxU8 p_noRegister); // vtable+30
virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+30
inline MxBool GetMIDIInitialized() { return m_MIDIInitialized; }
private:
void LockedReinitialize(MxBool p_skipDestroy);
void Destroy(MxBool p_fromDestructor);
void DeinitializeMIDI();
MxS32 CalculateVolume(MxS32 p_volume);

View File

@ -24,7 +24,7 @@ void MxMusicPresenter::Init()
}
// OFFSET: LEGO1 0x100c2550
void MxMusicPresenter::Destroy(MxBool p_reinit)
void MxMusicPresenter::Destroy(MxBool p_fromDestructor)
{
if (MusicManager()) {
MusicManager()->RemovePresenter(*this);
@ -32,13 +32,13 @@ void MxMusicPresenter::Destroy(MxBool p_reinit)
m_criticalSection.Enter();
Init();
m_criticalSection.Leave();
if (!p_reinit) {
if (!p_fromDestructor) {
MxMediaPresenter::Destroy(FALSE);
}
}
// OFFSET: LEGO1 0x100c25a0
MxResult MxMusicPresenter::AddToMusicManager()
MxResult MxMusicPresenter::AddToManager()
{
MxResult result = FAILURE;
if (MusicManager()) {
@ -49,8 +49,7 @@ MxResult MxMusicPresenter::AddToMusicManager()
}
// OFFSET: LEGO1 0x100c25d0
void MxMusicPresenter::vtable38()
void MxMusicPresenter::Destroy()
{
// TODO: Name this function when we know what the argument to Destroy does
Destroy(FALSE);
}

View File

@ -24,12 +24,12 @@ class MxMusicPresenter : public MxAudioPresenter
MxMusicPresenter();
virtual ~MxMusicPresenter() override;
virtual MxResult AddToMusicManager(); // vtable+0x34
virtual void vtable38(); // vtable+0x38
virtual MxResult AddToManager() override; // vtable+0x34
virtual void Destroy() override; // vtable+0x38
private:
void Init();
void Destroy(MxBool p_reinit);
void Destroy(MxBool p_fromDestructor);
};
#endif // MXMUSICPRESENTER_H

View File

@ -72,7 +72,7 @@ MxResult MxNotificationManager::Tickle()
}
// OFFSET: LEGO1 0x100ac600
MxResult MxNotificationManager::Create(MxS32 p_unk1, MxS32 p_unk2)
MxResult MxNotificationManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
{
MxResult result = SUCCESS;
m_queue = new MxNotificationPtrList();

View File

@ -45,7 +45,7 @@ class MxNotificationManager : public MxCore
virtual MxResult Tickle(); // vtable+0x8
// TODO: Where does this method come from?
virtual MxResult Create(MxS32 p_unk1, MxS32 p_unk2); // vtable+0x14
virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x14
void Register(MxCore *p_listener);
void Unregister(MxCore *p_listener);
MxResult Send(MxCore *p_listener, MxNotificationParam *p_param);

View File

@ -26,20 +26,22 @@ MxObjectFactory::MxObjectFactory()
}
// OFFSET: LEGO1 0x100b12c0
MxCore *MxObjectFactory::Create(const char *name)
MxCore *MxObjectFactory::Create(const char *p_name)
{
MxAtomId atom(name, LookupMode_Exact);
MxCore* object = NULL;
MxAtomId atom(p_name, LookupMode_Exact);
if (0) {
#define X(V) } else if (this->m_id##V == atom) { return new V;
if (0) {}
#define X(V) else if (this->m_id##V == atom) { object = new V; }
FOR_MXOBJECTFACTORY_OBJECTS(X)
#undef X
} else {
return NULL;
}
else {}
return object;
}
// OFFSET: LEGO1 0x100b1a30 STUB
void MxObjectFactory::vtable18(void *) {
// FIXME
// OFFSET: LEGO1 0x100b1a30
void MxObjectFactory::Destroy(MxCore *p_object)
{
delete p_object;
}

View File

@ -23,8 +23,22 @@ class MxObjectFactory : public MxCore
{
public:
MxObjectFactory();
virtual MxCore *Create(const char *name); // vtable 0x14
virtual void vtable18(void *); // vtable 0x18
// OFFSET: LEGO1 0x10008f70
inline virtual const char *ClassName() const override // vtable+0xc
{
// 0x100f0730
return "MxObjectFactory";
}
// OFFSET: LEGO1 0x10008f80
inline virtual MxBool IsA(const char *name) const override // vtable+0x10
{
return !strcmp(name, MxObjectFactory::ClassName()) || MxCore::IsA(name);
}
virtual MxCore *Create(const char *p_name); // vtable 0x14
virtual void Destroy(MxCore *p_object); // vtable 0x18
private:
#define X(V) MxAtomId m_id##V;
FOR_MXOBJECTFACTORY_OBJECTS(X)

View File

@ -189,119 +189,87 @@ void MxOmni::SetInstance(MxOmni *instance)
MxResult MxOmni::Create(MxOmniCreateParam &p)
{
MxResult result = FAILURE;
m_atomIdCounterSet = new MxAtomIdCounterSet();
if (m_atomIdCounterSet == NULL)
{
goto failure;
}
if (!(m_atomIdCounterSet = new MxAtomIdCounterSet()))
goto done;
m_mediaPath = p.GetMediaPath();
m_windowHandle = p.GetWindowHandle();
if (p.CreateFlags().CreateObjectFactory())
{
MxObjectFactory *objectFactory = new MxObjectFactory();
this->m_objectFactory = objectFactory;
if (objectFactory == NULL)
goto failure;
if (p.CreateFlags().CreateObjectFactory()) {
if (!(m_objectFactory = new MxObjectFactory()))
goto done;
}
if (p.CreateFlags().CreateVariableTable())
{
MxVariableTable *variableTable = new MxVariableTable();
this->m_variableTable = variableTable;
if (variableTable == NULL)
goto failure;
if (p.CreateFlags().CreateVariableTable()) {
if (!(m_variableTable = new MxVariableTable()))
goto done;
}
if (p.CreateFlags().CreateTimer())
{
MxTimer *timer = new MxTimer();
this->m_timer = timer;
if (timer == NULL)
return FAILURE;
if (p.CreateFlags().CreateTimer()) {
if (!(m_timer = new MxTimer()))
goto done;
}
if (p.CreateFlags().CreateTickleManager())
{
this->m_tickleManager = new MxTickleManager();
if (m_tickleManager == NULL)
goto failure;
if (p.CreateFlags().CreateTickleManager()) {
if (!(m_tickleManager = new MxTickleManager()))
goto done;
}
if (p.CreateFlags().CreateNotificationManager())
{
MxNotificationManager *notificationManager = new MxNotificationManager();
this->m_notificationManager = notificationManager;
if (notificationManager == NULL || notificationManager->Create(100, 0) != SUCCESS)
goto failure;
if (p.CreateFlags().CreateNotificationManager()) {
if (m_notificationManager = new MxNotificationManager()) {
if (m_notificationManager->Create(100, 0) != SUCCESS)
goto done;
}
else
goto done;
}
if (p.CreateFlags().CreateStreamer())
{
MxStreamer *streamer = new MxStreamer();
this->m_streamer = streamer;
if (streamer == NULL || streamer->Init() != SUCCESS)
goto failure;
if (p.CreateFlags().CreateStreamer()) {
if (!(m_streamer = new MxStreamer()) || m_streamer->Create() != SUCCESS)
goto done;
}
if (p.CreateFlags().CreateVideoManager())
{
MxVideoManager *videoManager = new MxVideoManager();
this->m_videoManager = videoManager;
if (videoManager != NULL && videoManager->vtable0x2c(p.GetVideoParam(), 100, 0) != SUCCESS)
{
delete m_videoManager;
m_videoManager = NULL;
if (p.CreateFlags().CreateVideoManager()) {
if (m_videoManager = new MxVideoManager()) {
if (m_videoManager->Create(p.GetVideoParam(), 100, 0) != SUCCESS) {
delete m_videoManager;
m_videoManager = NULL;
}
}
}
if (p.CreateFlags().CreateSoundManager())
{
MxSoundManager *soundManager = new MxSoundManager();
this->m_soundManager = soundManager;
//TODO
if (soundManager != NULL && soundManager->StartDirectSound(10, 0) != SUCCESS)
{
delete m_soundManager;
m_soundManager = NULL;
if (p.CreateFlags().CreateSoundManager()) {
if (m_soundManager = new MxSoundManager()) {
if (m_soundManager->Create(10, 0) != SUCCESS) {
delete m_soundManager;
m_soundManager = NULL;
}
}
}
if (p.CreateFlags().CreateMusicManager())
{
MxMusicManager *musicManager = new MxMusicManager();
this->m_musicManager = musicManager;
if (musicManager != NULL && musicManager->StartMIDIThread(50, 0) != SUCCESS)
{
delete m_musicManager;
m_musicManager = NULL;
if (p.CreateFlags().CreateMusicManager()) {
if (m_musicManager = new MxMusicManager()) {
if (m_musicManager->Create(50, 0) != SUCCESS) {
delete m_musicManager;
m_musicManager = NULL;
}
}
}
if (p.CreateFlags().CreateEventManager())
{
MxEventManager *eventManager = new MxEventManager();
this->m_eventManager = eventManager;
if (m_eventManager != NULL && m_eventManager->CreateEventThread(50, 0) != SUCCESS)
{
delete m_eventManager;
m_eventManager = NULL;
if (p.CreateFlags().CreateEventManager()) {
if (m_eventManager = new MxEventManager()) {
if (m_eventManager->Create(50, 0) != SUCCESS) {
delete m_eventManager;
m_eventManager = NULL;
}
}
}
result = SUCCESS;
failure:
done:
if (result != SUCCESS)
{
Destroy();
}
return result;
}

View File

@ -93,7 +93,9 @@ __declspec(dllexport) MxVariableTable * VariableTable();
__declspec(dllexport) MxMusicManager * MusicManager();
__declspec(dllexport) MxEventManager * EventManager();
__declspec(dllexport) MxNotificationManager * NotificationManager();
MxVideoManager * MVideoManager();
MxAtomIdCounterSet* AtomIdCounterSet();
MxVideoManager *MVideoManager();
MxAtomIdCounterSet *AtomIdCounterSet();
MxObjectFactory *ObjectFactory();
#endif // MXOMNI_H

View File

@ -14,7 +14,7 @@ class MxOmniCreateParam : public MxParam
__declspec(dllexport) MxOmniCreateParam(const char *mediaPath, struct HWND__ *windowHandle, MxVideoParam &vparam, MxOmniCreateFlags flags);
const MxOmniCreateFlags& CreateFlags() const { return this->m_createFlags; }
const MxString GetMediaPath() const { return m_mediaPath; }
const MxString& GetMediaPath() const { return m_mediaPath; }
const HWND GetWindowHandle() const { return m_windowHandle; }
MxVideoParam& GetVideoParam() { return m_videoParam; }

View File

@ -29,7 +29,6 @@ void MxPresenter::Init()
// OFFSET: LEGO1 0x100b4fc0
void MxPresenter::ParseExtra()
{
MxAutoLocker lock(&m_criticalSection);
MxU32 len = m_action->GetExtraLength();
char *extraData = m_action->GetExtraData();
@ -47,15 +46,13 @@ void MxPresenter::ParseExtra()
strcpy(t_token, token);
token = strtok(NULL, g_parseExtraTokens);
int val = token ? atoi(token) : 0;
int result = MxOmni::GetInstance()->vtable0x30(t_token, val, this);
MxS32 val = token ? atoi(token) : 0;
MxS32 result = MxOmni::GetInstance()->vtable0x30(t_token, val, this);
m_action->SetFlags(m_action->GetFlags() | MxDSAction::Flag_Parsed);
if (result)
SendTo_unkPresenter(MxOmni::GetInstance());
}
}
}
@ -128,8 +125,8 @@ MxLong MxPresenter::StartAction(MxStreamController *, MxDSAction *p_action)
const MxVector3Data& location = this->m_action->GetLocation();
MxS32 previousTickleState = this->m_currentTickleState;
this->m_location = MxPoint32(location[0], location[1]);
this->m_displayZ = location[2];
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;
@ -279,13 +276,13 @@ void MxPresenter::DoneTickle()
}
// OFFSET: LEGO1 0x1000bf70
undefined4 MxPresenter::VTable0x34()
MxResult MxPresenter::AddToManager()
{
return 0;
return SUCCESS;
}
// OFFSET: LEGO1 0x1000bf80
void MxPresenter::InitVirtual()
void MxPresenter::Destroy()
{
Init();
}

View File

@ -56,8 +56,8 @@ class MxPresenter : public MxCore
__declspec(dllexport) virtual void ParseExtra(); // vtable+0x30
public:
virtual undefined4 VTable0x34(); // vtable+0x34
virtual void InitVirtual(); // vtable+0x38
virtual MxResult AddToManager(); // vtable+0x34
virtual void Destroy(); // vtable+0x38
__declspec(dllexport) virtual MxLong StartAction(MxStreamController *, MxDSAction *); // vtable+0x3c
__declspec(dllexport) virtual void EndAction(); // vtable+0x40
virtual void SetTickleState(TickleState p_tickleState); // vtable+0x44

39
LEGO1/mxregion.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "mxregion.h"
DECOMP_SIZE_ASSERT(MxRegion, 0x1c);
// OFFSET: LEGO1 0x100c31c0 STUB
MxRegion::MxRegion()
{
// TODO
}
// OFFSET: LEGO1 0x100c3690 STUB
MxRegion::~MxRegion()
{
// TODO
}
// OFFSET: LEGO1 0x100c3700 STUB
void MxRegion::Reset()
{
// TODO
}
// OFFSET: LEGO1 0x100c3750 STUB
void MxRegion::vtable18()
{
// TODO
}
// OFFSET: LEGO1 0x100c3e20 STUB
void MxRegion::vtable1c()
{
// TODO
}
// OFFSET: LEGO1 0x100c3660 STUB
void MxRegion::vtable20()
{
// TODO
}

View File

@ -2,6 +2,7 @@
#define MXREGION_H
#include "mxcore.h"
#include "decomp.h"
// VTABLE 0x100dcae8
// SIZE 0x1c
@ -21,6 +22,7 @@ class MxRegion : public MxCore
// MxList<MxRect32> *m_rects;
// 4 coordinates (could be MxRect32)
// MxS32 left, top, right, bottom;
undefined pad[0x14];
};
#endif // MXREGION_H

View File

@ -24,7 +24,7 @@ void MxSoundManager::Init()
}
// OFFSET: LEGO1 0x100ae840
void MxSoundManager::Destroy(MxBool p_param)
void MxSoundManager::Destroy(MxBool p_fromDestructor)
{
if (this->m_thread) {
this->m_thread->Terminate();
@ -43,15 +43,15 @@ void MxSoundManager::Destroy(MxBool p_param)
Init();
this->m_criticalSection.Leave();
if (!p_param) {
if (!p_fromDestructor) {
MxAudioManager::Destroy();
}
}
// OFFSET: LEGO1 0x100ae8b0 STUB
MxResult MxSoundManager::StartDirectSound(undefined4 p_unknown1, MxBool p_unknown2)
MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
{
// TODO STUB
// TODO
return FAILURE;
}

View File

@ -14,13 +14,13 @@ class MxSoundManager : public MxAudioManager
MxSoundManager();
virtual ~MxSoundManager() override; // vtable+0x0
virtual MxResult StartDirectSound(undefined4 p_unknown1, MxBool p_unknown2); //vtable+0x30
virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); //vtable+0x30
virtual void vtable0x34(); // vtable+0x34
virtual void vtable0x38(); // vtable+0x38
private:
void Init();
void Destroy(MxBool);
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk30;
LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x34

View File

@ -16,7 +16,7 @@ MxStreamer::MxStreamer()
}
// OFFSET: LEGO1 0x100b9190
MxResult MxStreamer::Init()
MxResult MxStreamer::Create()
{
undefined *b = new undefined[m_subclass1.GetSize() * 0x5800];
m_subclass1.SetBuffer(b);

View File

@ -90,7 +90,7 @@ class MxStreamer : public MxCore
return !strcmp(p_name, MxStreamer::ClassName()) || MxCore::IsA(p_name);
}
virtual MxResult Init(); // vtable+0x14
virtual MxResult Create(); // vtable+0x14
MxStreamController *GetOpenStream(const char *p_name);

View File

@ -56,7 +56,7 @@ void MxString::ToLowerCase()
}
// OFFSET: LEGO1 0x100ae4b0
MxString &MxString::operator=(MxString &param)
MxString &MxString::operator=(const MxString &param)
{
if (this->m_data != param.m_data)
{

View File

@ -15,7 +15,7 @@ class MxString : public MxCore
MxString(const char *);
void ToUpperCase();
void ToLowerCase();
MxString& operator=(MxString &);
MxString& operator=(const MxString &);
MxString operator+(const char *);
MxString& operator+=(const char *);

View File

@ -53,14 +53,13 @@ class MxTickleClient
MxU16 m_flags; // 0xc
};
class MxTickleClientPtrList : public list<MxTickleClient *>
{};
typedef list<MxTickleClient*> MxTickleClientPtrList;
// VTABLE 0x100d86d8
class MxTickleManager : public MxCore
{
public:
inline MxTickleManager() : MxCore(), m_clients() {}
inline MxTickleManager() {}
virtual ~MxTickleManager(); // vtable+0x0 (scalar deleting destructor)
virtual MxResult Tickle(); // vtable+0x8

View File

@ -127,34 +127,34 @@ void MxTransitionManager::Transition_Dissolve()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL);
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
}
if (res == DD_OK) {
SubmitCopyRect(&ddsd);
for (MxS32 i = 0; i < 640; i++) {
for (MxS32 col = 0; col < 640; col++) {
// Select 16 columns on each tick
if (m_animationTimer * 16 > m_columnOrder[i])
if (m_animationTimer * 16 > m_columnOrder[col])
continue;
if (m_animationTimer * 16 + 15 < m_columnOrder[i])
if (m_animationTimer * 16 + 15 < m_columnOrder[col])
continue;
for (MxS32 j = 0; j < 480; j++) {
for (MxS32 row = 0; row < 480; row++) {
// Shift the chosen column a different amount at each scanline.
// We use the same shift for that scanline each time.
// By the end, every pixel gets hit.
MxS32 ofs = (m_randomShift[j] + i) % 640;
MxS32 x_shift = (m_randomShift[row] + col) % 640;
// Set the chosen pixel to black
if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) {
((MxU8*)ddsd.lpSurface)[j * ddsd.lPitch + ofs] = 0;
((MxU8*)ddsd.lpSurface)[row * ddsd.lPitch + x_shift] = 0;
} else {
((MxU16*)ddsd.lpSurface)[j * ddsd.lPitch + ofs] = 0;
((MxU16*)ddsd.lpSurface)[row * ddsd.lPitch + x_shift] = 0;
}
}
}
@ -164,7 +164,7 @@ void MxTransitionManager::Transition_Dissolve()
if (VideoManager()->GetVideoParam().flags().GetFlipSurfaces()) {
LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1();
surf->BltFast(NULL, NULL, m_ddSurface, &g_fullScreenRect, 0x10);
surf->BltFast(NULL, NULL, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT);
}
m_animationTimer++;
@ -230,23 +230,192 @@ void MxTransitionManager::Transition_None()
EndTransition(TRUE);
}
// OFFSET: LEGO1 0x1004bed0 STUB
// OFFSET: LEGO1 0x1004bed0
void MxTransitionManager::Transition_Pixelation()
{
// TODO
if (m_animationTimer == 16) {
m_animationTimer = 0;
EndTransition(TRUE);
return;
}
if (m_animationTimer == 0) {
// Same init/shuffle steps as the dissolve transition, except that
// we are using big blocky pixels and only need 64 columns.
for (MxS32 i = 0; i < 64; i++) {
m_columnOrder[i] = i;
}
for (i = 0; i < 64; i++) {
MxS32 swap = rand() % 64;
MxU16 t = m_columnOrder[i];
m_columnOrder[i] = m_columnOrder[swap];
m_columnOrder[swap] = t;
}
// The same is true here. We only need 48 rows.
for (i = 0; i < 48; i++) {
m_randomShift[i] = rand() % 64;
}
}
// Run one tick of the animation
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL);
}
if (res == DD_OK) {
SubmitCopyRect(&ddsd);
for (MxS32 col = 0; col < 64; col++) {
// Select 4 columns on each tick
if (m_animationTimer * 4 > m_columnOrder[col])
continue;
if (m_animationTimer * 4 + 3 < m_columnOrder[col])
continue;
for (MxS32 row = 0; row < 48; row++) {
MxS32 x_shift = 10 * ((m_randomShift[row] + col) % 64);
// To do the pixelation, we subdivide the 640x480 surface into
// 10x10 pixel blocks. At the chosen block, we sample the top-leftmost
// color and set the other 99 pixels to that value.
// Find the pixel to sample
MxS32 sample_ofs = 10 * row * ddsd.lPitch + x_shift;
MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8;
// Save this cast from void* to save time.
// Seems to help accuracy doing it this way.
MxU8 *surface = (MxU8*)ddsd.lpSurface;
MxU8 *source = surface + sample_ofs * bytesPerPixel;
MxU32 sample = bytesPerPixel == 1 ? *source
: *(MxU16*)source;
for (MxS32 k = 10*row; k < 10*row + 10; k++) {
if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) {
// TODO: This block and the next don't match, but they are
// hopefully correct in principle.
MxU16 color_word = MAKEWORD(LOBYTE(sample), LOBYTE(sample));
MxU32 new_color = MAKELONG(color_word, color_word);
MxU8 *pos = surface + k * ddsd.lPitch + x_shift;
MxU32 *dest = (MxU32*)pos;
// Sets 10 pixels (10 bytes)
dest[0] = new_color;
dest[1] = new_color;
MxU16 *half = (MxU16*)(dest+2);
*half = new_color;
} else {
MxU32 new_color = MAKELONG(sample, sample);
// You might expect a cast to MxU16* instead, but lPitch is
// bytes/scanline, not pixels/scanline. Therefore, we just
// need to double the x_shift to get to the right spot.
MxU8 *pos = surface + k * ddsd.lPitch + 2*x_shift;
MxU32 *dest = (MxU32*)pos;
// Sets 10 pixels (20 bytes)
dest[0] = new_color;
dest[1] = new_color;
dest[2] = new_color;
dest[3] = new_color;
dest[4] = new_color;
}
}
}
}
SetupCopyRect(&ddsd);
m_ddSurface->Unlock(ddsd.lpSurface);
if (VideoManager()->GetVideoParam().flags().GetFlipSurfaces()) {
LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1();
surf->BltFast(NULL, NULL, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT);
}
m_animationTimer++;
}
}
// OFFSET: LEGO1 0x1004c270 STUB
// OFFSET: LEGO1 0x1004c270
void MxTransitionManager::Transition_Windows()
{
// TODO
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);
MxU8 *line = (MxU8 *) ddsd.lpSurface + m_animationTimer * ddsd.lPitch;
MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8;
MxS32 bytesPerLine = bytesPerPixel * 640;
memset(line, 0, bytesPerLine);
for (MxS32 i = m_animationTimer + 1; i < 480 - m_animationTimer; i++) {
line += ddsd.lPitch;
memset(line + m_animationTimer * bytesPerPixel, 0, bytesPerPixel);
memset(line + 640 + (-1 - m_animationTimer) * bytesPerPixel, 0, bytesPerPixel);
}
line += ddsd.lPitch;
memset(line, 0, bytesPerLine);
SetupCopyRect(&ddsd);
m_ddSurface->Unlock(ddsd.lpSurface);
m_animationTimer++;
}
}
// OFFSET: LEGO1 0x1004c3e0 STUB
// OFFSET: LEGO1 0x1004c3e0
void MxTransitionManager::Transition_Broken()
{
// TODO
// This function has no actual animation logic.
// It also never calls EndTransition to
// properly terminate the transition, so
// the game just hangs forever.
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);
SetupCopyRect(&ddsd);
m_ddSurface->Unlock(ddsd.lpSurface);
}
}
// OFFSET: LEGO1 0x1004c170
@ -263,10 +432,10 @@ void MxTransitionManager::Transition_Wipe()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL);
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
}
if (res == DD_OK) {

View File

@ -1,6 +1,8 @@
#include "mxvideomanager.h"
#include "mxautolocker.h"
#include "mxpresenter.h"
#include "mxticklemanager.h"
#include "legoomni.h"
// OFFSET: LEGO1 0x100be1f0
MxVideoManager::MxVideoManager()
@ -8,10 +10,10 @@ MxVideoManager::MxVideoManager()
Init();
}
// OFFSET: LEGO1 0x100be2a0 STUB
// OFFSET: LEGO1 0x100be2a0
MxVideoManager::~MxVideoManager()
{
// TODO
Destroy(TRUE);
}
// OFFSET: LEGO1 0x100bea90
@ -50,6 +52,41 @@ MxResult MxVideoManager::Init()
return SUCCESS;
}
// OFFSET: LEGO1 0x100be340
void MxVideoManager::Destroy(MxBool p_fromDestructor)
{
if (m_thread) {
m_thread->Terminate();
delete m_thread;
}
else
TickleManager()->UnregisterClient(this);
m_criticalSection.Enter();
if (m_displaySurface)
delete m_displaySurface;
if (m_region)
delete m_region;
if (m_videoParam.GetPalette())
delete m_videoParam.GetPalette();
if (m_unk60) {
if (m_pDirectDraw)
m_pDirectDraw->Release();
if (m_pDDSurface)
m_pDDSurface->Release();
}
Init();
m_criticalSection.Leave();
if (!p_fromDestructor)
MxMediaManager::Destroy();
}
// OFFSET: LEGO1 0x100be440
void MxVideoManager::SortPresenterList()
{
@ -89,6 +126,12 @@ void MxVideoManager::UpdateRegion()
// TODO
}
// OFFSET: LEGO1 0x100bea50
void MxVideoManager::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100bea60 STUB
void MxVideoManager::InvalidateRect(MxRect32 &p_rect)
{
@ -96,7 +139,7 @@ void MxVideoManager::InvalidateRect(MxRect32 &p_rect)
}
// OFFSET: LEGO1 0x100bebe0
MxLong MxVideoManager::RealizePalette(MxPalette *p_palette)
MxResult MxVideoManager::RealizePalette(MxPalette *p_palette)
{
PALETTEENTRY paletteEntries[256];
@ -109,19 +152,151 @@ MxLong MxVideoManager::RealizePalette(MxPalette *p_palette)
}
this->m_criticalSection.Leave();
return 0;
return SUCCESS;
}
// OFFSET: LEGO1 0x100be600 STUB
void MxVideoManager::vtable0x28()
// OFFSET: LEGO1 0x100be600
MxResult MxVideoManager::vtable0x28(
MxVideoParam &p_videoParam,
LPDIRECTDRAW p_pDirectDraw,
LPDIRECTDRAWSURFACE p_pDDSurface,
LPDIRECTDRAWSURFACE p_ddSurface1,
LPDIRECTDRAWSURFACE p_ddSurface2,
LPDIRECTDRAWCLIPPER p_ddClipper,
MxU32 p_frequencyMS,
MxBool p_createThread)
{
MxBool locked = FALSE;
MxResult status = FAILURE;
m_unk60 = FALSE;
if (MxMediaManager::InitPresenters() != SUCCESS)
goto done;
m_criticalSection.Enter();
locked = TRUE;
m_videoParam = p_videoParam;
m_region = new MxRegion();
if (!m_region)
goto done;
m_pDirectDraw = p_pDirectDraw;
m_pDDSurface = p_pDDSurface;
MxPalette *palette;
if (p_videoParam.GetPalette() == NULL) {
palette = new MxPalette();
m_videoParam.SetPalette(palette);
if (!palette)
goto done;
}
else {
palette = p_videoParam.GetPalette()->Clone();
m_videoParam.SetPalette(palette);
if (!palette)
goto done;
}
m_displaySurface = new MxDisplaySurface();
if (m_displaySurface && m_displaySurface->Init(m_videoParam, p_ddSurface1, p_ddSurface2, p_ddClipper) == SUCCESS) {
m_displaySurface->SetPalette(m_videoParam.GetPalette());
if (p_createThread) {
m_thread = new MxTickleThread(this, p_frequencyMS);
if (!m_thread || m_thread->Start(0, 0) != SUCCESS)
goto done;
}
else
TickleManager()->RegisterClient(this, p_frequencyMS);
status = SUCCESS;
}
done:
if (status != SUCCESS)
Destroy();
if (locked)
m_criticalSection.Leave();
return status;
}
// OFFSET: LEGO1 0x100bebe0 STUB
MxResult MxVideoManager::vtable0x2c(MxVideoParam& p_videoParam, undefined4 p_unknown1, MxU8 p_unknown2)
// OFFSET: LEGO1 0x100be820
MxResult MxVideoManager::Create(
MxVideoParam &p_videoParam,
MxU32 p_frequencyMS,
MxBool p_createThread)
{
return FAILURE;
MxBool locked = FALSE;
MxResult status = FAILURE;
m_unk60 = TRUE;
if (MxMediaManager::InitPresenters() != SUCCESS)
goto done;
m_criticalSection.Enter();
locked = TRUE;
m_videoParam = p_videoParam;
m_region = new MxRegion();
if (!m_region)
goto done;
if (DirectDrawCreate(NULL, &m_pDirectDraw, NULL) != DD_OK)
goto done;
if (m_pDirectDraw->SetCooperativeLevel(MxOmni::GetInstance()->GetWindowHandle(), DDSCL_NORMAL) != DD_OK)
goto done;
MxPalette *palette;
if (p_videoParam.GetPalette() == NULL) {
palette = new MxPalette();
m_videoParam.SetPalette(palette);
if (!palette)
goto done;
}
else {
palette = p_videoParam.GetPalette()->Clone();
m_videoParam.SetPalette(palette);
if (!palette)
goto done;
}
m_displaySurface = new MxDisplaySurface();
if (m_displaySurface && m_displaySurface->Create(m_videoParam) == SUCCESS) {
m_displaySurface->SetPalette(m_videoParam.GetPalette());
if (p_createThread) {
m_thread = new MxTickleThread(this, p_frequencyMS);
if (!m_thread || m_thread->Start(0, 0) != SUCCESS)
goto done;
}
else
TickleManager()->RegisterClient(this, p_frequencyMS);
status = SUCCESS;
}
done:
if (status != SUCCESS)
Destroy();
if (locked)
m_criticalSection.Leave();
return status;
}
// OFFSET: LEGO1 0x100be270

View File

@ -12,19 +12,30 @@
class MxVideoManager : public MxMediaManager
{
public:
virtual ~MxVideoManager();
virtual ~MxVideoManager() override;
virtual MxResult Tickle() override; // vtable+0x8
virtual void vtable0x28(); // vtable+0x28 (TODO ARGUMENTS)
virtual MxResult vtable0x2c(MxVideoParam& p_videoParam, undefined4 p_unknown1, MxU8 p_unknown2); // vtable+0x2c
virtual void Destroy() override; // vtable+0x18
virtual MxResult vtable0x28(
MxVideoParam& p_videoParam,
LPDIRECTDRAW p_pDirectDraw,
LPDIRECTDRAWSURFACE p_pDDSurface,
LPDIRECTDRAWSURFACE p_ddSurface1,
LPDIRECTDRAWSURFACE p_ddSurface2,
LPDIRECTDRAWCLIPPER p_ddClipper,
MxU32 p_frequencyMS,
MxBool p_createThread
); // vtable+0x28
virtual MxResult Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x2c
__declspec(dllexport) void InvalidateRect(MxRect32 &);
__declspec(dllexport) virtual MxLong RealizePalette(MxPalette *); // vtable+0x30
__declspec(dllexport) virtual MxResult RealizePalette(MxPalette *); // vtable+0x30
virtual void vtable0x34(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height);
MxVideoManager();
MxResult Init();
void Destroy(MxBool p_fromDestructor);
void SortPresenterList();
void UpdateRegion();

View File

@ -65,11 +65,11 @@ MxVideoParam &MxVideoParam::operator=(const MxVideoParam &p_videoParam)
void MxVideoParam::SetDeviceName(char *id)
{
if (this->m_deviceId != 0)
free(this->m_deviceId);
delete[] this->m_deviceId;
if (id != 0)
{
this->m_deviceId = (char *)malloc(strlen(id) + 1);
this->m_deviceId = new char[strlen(id) + 1];
if (this->m_deviceId != 0) {
strcpy(this->m_deviceId, id);
@ -84,5 +84,5 @@ void MxVideoParam::SetDeviceName(char *id)
MxVideoParam::~MxVideoParam()
{
if (this->m_deviceId != 0)
free(this->m_deviceId);
delete[] this->m_deviceId;
}

View File

@ -34,7 +34,7 @@ MxVideoPresenter::~MxVideoPresenter()
}
// OFFSET: LEGO1 0x1000c7a0
void MxVideoPresenter::InitVirtual()
void MxVideoPresenter::Destroy()
{
Destroy(FALSE);
}
@ -85,7 +85,7 @@ void MxVideoPresenter::Init()
}
// OFFSET: LEGO1 0x100b27b0
void MxVideoPresenter::Destroy(MxBool p_reinit)
void MxVideoPresenter::Destroy(MxBool p_fromDestructor)
{
MxRect32 rect;
if (MVideoManager() != NULL)

View File

@ -31,9 +31,9 @@ class MxVideoPresenter : public MxMediaPresenter
}
void Init();
void Destroy(MxBool);
void Destroy(MxBool p_fromDestructor);
virtual void InitVirtual() override; // vtable+0x38
virtual void Destroy() override; // vtable+0x38
virtual void VTable0x5c(undefined4 p_unknown1); // vtable+0x5c
virtual void VTable0x60(); // vtable+0x60