Merge branch 'master' into order-tool

This commit is contained in:
MS 2023-11-19 10:46:05 -05:00 committed by GitHub
commit ba5da854d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 2378 additions and 634 deletions

View File

@ -17,4 +17,6 @@ jobs:
--style=file \
ISLE/*.cpp ISLE/*.h \
LEGO1/*.cpp LEGO1/*.h \
LEGO1/realtime/*.cpp LEGO1/realtime/*.h
LEGO1/realtime/*.cpp LEGO1/realtime/*.h \
LEGO1/tgl/*.h \
LEGO1/viewmanager/*.cpp LEGO1/viewmanager/*.h

View File

@ -83,6 +83,7 @@ add_library(lego1 SHARED
LEGO1/legopartpresenter.cpp
LEGO1/legopathactor.cpp
LEGO1/legopathcontroller.cpp
LEGO1/legopathcontrollerlist.cpp
LEGO1/legopathpresenter.cpp
LEGO1/legophonemepresenter.cpp
LEGO1/legoplantmanager.cpp
@ -144,7 +145,6 @@ add_library(lego1 SHARED
LEGO1/mxloopingflcpresenter.cpp
LEGO1/mxloopingmidipresenter.cpp
LEGO1/mxloopingsmkpresenter.cpp
LEGO1/mxmatrix.cpp
LEGO1/mxmediamanager.cpp
LEGO1/mxmediapresenter.cpp
LEGO1/mxmidipresenter.cpp
@ -183,7 +183,6 @@ add_library(lego1 SHARED
LEGO1/mxtype17notificationparam.cpp
LEGO1/mxvariable.cpp
LEGO1/mxvariabletable.cpp
LEGO1/mxvector.cpp
LEGO1/mxvideomanager.cpp
LEGO1/mxvideoparam.cpp
LEGO1/mxvideoparamflags.cpp
@ -201,23 +200,27 @@ add_library(lego1 SHARED
LEGO1/racestate.cpp
LEGO1/radio.cpp
LEGO1/radiostate.cpp
LEGO1/realtime/matrix.cpp
LEGO1/realtime/orientableroi.cpp
LEGO1/realtime/realtime.cpp
LEGO1/realtime/realtimeview.cpp
LEGO1/realtime/vector.cpp
LEGO1/registrationbook.cpp
LEGO1/score.cpp
LEGO1/scorestate.cpp
LEGO1/skateboard.cpp
LEGO1/towtrack.cpp
LEGO1/towtrackmissionstate.cpp
LEGO1/viewmanager.cpp
LEGO1/viewmanager/viewmanager.cpp
LEGO1/viewmanager/viewroi.cpp
)
if (MINGW)
target_compile_definitions(lego1 PRIVATE DIRECTINPUT_VERSION=0x0500)
endif()
# Additional include directories
include_directories("${CMAKE_SOURCE_DIR}/3rdparty/vec")
include_directories("${CMAKE_SOURCE_DIR}/3rdparty/smk")
target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/3rdparty/vec")
target_include_directories(lego1 PRIVATE "${CMAKE_SOURCE_DIR}/3rdparty/smk")
if (ISLE_USE_SMARTHEAP)
add_library(SmartHeap::SmartHeap STATIC IMPORTED)

View File

@ -21,6 +21,12 @@ Please keep your pull requests small and understandable; you may be able to shoo
This repository currently has only one goal: accuracy to the original executables. We are byte/instruction matching as much as possible, which means the priority is making the original compiler (MSVC 4.20) produce code that matches the original game. As such, modernizations and bug fixes will probably be rejected for the time being.
## Overview
* `3rdparty`: Contains code obtained from third parties, not including Mindscape. Generally, these are libraries that have been placed in the public domain or are freely available on the web. As these are unaltered files, our style guide (see below) does not apply.
* `ISLE`: Decompilation of `ISLE.EXE`. It depends on some code in `LEGO1`.
* `LEGO1`: Decompilation of `LEGO1.DLL`. This folder contains code from Mindscape's custom in-house engine called **Omni** (file pattern: `mx*`), the LEGO Island-specific extensions for Omni and the game's code (file pattern: `lego*`) as well as several utility libraries (`realtime`, `tgl`, `viewmanager`) developed by Mindscape.
## Code Style
In general, we're not exhaustively strict about coding style, but there are some preferable guidelines to follow that have been adopted from what we know about the original codebase:
@ -31,11 +37,13 @@ We are currently using [clang-format](https://clang.llvm.org/docs/ClangFormat.ht
### Naming conventions
The following conventions should generally be applied everywhere except for the utility libraries (`LEGO1/realtime`, `LEGO1/tgl`, `LEGO1/viewmanager`) and any 3rd party libraries (`3rdparty`).
- `PascalCase` for classes, function names, and enumerations.
- `m_camelCase` for member variables.
- `g_camelCase` for global variables.
- `p_camelCase` for function parameters.
- Instead of C++ primitives (e.g. `int`, `long`, etc.), use types in [`mxtypes.h`](LEGO1/mxtypes.h) instead. This will help us ensure that variables will be the correct size regardless of the underlying compiler/platform/architecture.
- Within the Omni engine (file pattern: `mx*`), instead of C++ primitives (e.g. `int`, `long`, etc.), use types in [`mxtypes.h`](LEGO1/mxtypes.h) instead. This will help us ensure that variables will be the correct size regardless of the underlying compiler/platform/architecture.
## Questions?

View File

@ -24,9 +24,9 @@ Helicopter::~Helicopter()
}
// OFFSET: LEGO1 0x100032c0
MxResult Helicopter::InitFromMxDSObject(MxDSObject& p_dsObject)
MxResult Helicopter::Create(MxDSObject& p_dsObject)
{
MxResult result = IslePathActor::InitFromMxDSObject(p_dsObject);
MxResult result = IslePathActor::Create(p_dsObject);
LegoWorld* world = GetCurrentWorld();
SetWorld(world);
if (world->IsA("Act3")) {

View File

@ -3,7 +3,7 @@
#include "helicopterstate.h"
#include "islepathactor.h"
#include "mxmatrix.h"
#include "realtime/matrix.h"
// VTABLE 0x100d40f8
// SIZE 0x230
@ -24,7 +24,7 @@ class Helicopter : public IslePathActor {
return !strcmp(name, Helicopter::ClassName()) || IslePathActor::IsA(name);
}
virtual MxResult InitFromMxDSObject(MxDSObject& p_dsObject) override; // vtable+0x18
virtual MxResult Create(MxDSObject& p_dsObject) override; // vtable+0x18
virtual void VTable0xe4() override;
// OFFSET: LEGO1 0x10003210 TEMPLATE
@ -32,11 +32,11 @@ class Helicopter : public IslePathActor {
virtual ~Helicopter() override; // vtable+0x0
protected:
MxMatrixData m_unk160;
MxMatrixData m_unk1a8;
Matrix4Data m_unk160;
Matrix4Data m_unk1a8;
undefined4 m_unk1f0;
MxVector4Data m_unk1f4;
MxVector4Data m_unk20c;
Vector4Data m_unk1f4;
Vector4Data m_unk20c;
undefined4 m_unk224;
HelicopterState* m_state;
MxAtomId m_unk22c;

View File

@ -44,9 +44,9 @@ IslePathActor::IslePathActor()
}
// OFFSET: LEGO1 0x1001a280
MxResult IslePathActor::InitFromMxDSObject(MxDSObject& p_dsObject)
MxResult IslePathActor::Create(MxDSObject& p_dsObject)
{
return MxEntity::InitFromMxDSObject(p_dsObject);
return MxEntity::Create(p_dsObject);
}
// OFFSET: LEGO1 0x1001a350 STUB

View File

@ -28,16 +28,16 @@ class IslePathActor : public LegoPathActor {
// IslePathActor::`scalar deleting destructor'
inline virtual ~IslePathActor() override { IslePathActor::Destroy(TRUE); }
virtual MxResult InitFromMxDSObject(MxDSObject& p_dsObject) override; // vtable+0x18
virtual void VTable0xcc(); // vtable+0xcc
virtual void VTable0xd0(); // vtable+0xd0
virtual void VTable0xd4(); // vtable+0xd4
virtual void VTable0xd8(); // vtable+0xd8
virtual void VTable0xdc(); // vtable+0xdc
virtual void VTable0xe0(); // vtable+0xe0
virtual void VTable0xe4(); // vtable+0xe4
virtual void VTable0xe8(MxU32 p_1, MxBool p_2, MxU8 p_3); // vtable+0xe8
virtual void VTable0xec(); // vtable+0xec
virtual MxResult Create(MxDSObject& p_dsObject) override; // vtable+0x18
virtual void VTable0xcc(); // vtable+0xcc
virtual void VTable0xd0(); // vtable+0xd0
virtual void VTable0xd4(); // vtable+0xd4
virtual void VTable0xd8(); // vtable+0xd8
virtual void VTable0xdc(); // vtable+0xdc
virtual void VTable0xe0(); // vtable+0xe0
virtual void VTable0xe4(); // vtable+0xe4
virtual void VTable0xe8(MxU32 p_1, MxBool p_2, MxU8 p_3); // vtable+0xe8
virtual void VTable0xec(); // vtable+0xec
inline void SetWorld(LegoWorld* p_world) { m_pLegoWorld = p_world; }
inline LegoWorld* GetWorld() { return m_pLegoWorld; }

View File

@ -1,7 +1,7 @@
#ifndef LEGO3DVIEW_H
#define LEGO3DVIEW_H
#include "viewmanager.h"
#include "viewmanager/viewmanager.h"
class Lego3DView {
public:

View File

@ -36,13 +36,13 @@ void LegoEntity::ResetWorldTransform(MxBool p_inVehicle)
}
// OFFSET: LEGO1 0x10010790 STUB
void LegoEntity::SetWorldTransform(MxVector3& p_loc, MxVector3& p_dir, MxVector3& p_up)
void LegoEntity::SetWorldTransform(Vector3Impl& p_loc, Vector3Impl& p_dir, Vector3Impl& p_up)
{
// TODO
}
// OFFSET: LEGO1 0x100107e0
MxResult LegoEntity::InitFromMxDSObject(MxDSObject& p_dsObject)
MxResult LegoEntity::Create(MxDSObject& p_dsObject)
{
m_mxEntityId = p_dsObject.GetObjectId();
m_atom = p_dsObject.GetAtomId();

View File

@ -6,7 +6,7 @@
#include "legoroi.h"
#include "mxdsobject.h"
#include "mxentity.h"
#include "mxvector.h"
#include "realtime/vector.h"
// VTABLE 0x100d4858
// SIZE 0x68 (probably)
@ -32,12 +32,12 @@ class LegoEntity : public MxEntity {
return !strcmp(name, LegoEntity::ClassName()) || MxEntity::IsA(name);
}
virtual MxResult InitFromMxDSObject(MxDSObject& p_dsObject); // vtable+0x18
virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c
virtual void ParseAction(char*); // vtable+0x20
virtual void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2); // vtable+0x24
virtual void SetWorldTransform(MxVector3& p_loc, MxVector3& p_dir, MxVector3& p_up); // vtable+0x28
virtual void ResetWorldTransform(MxBool p_inVehicle); // vtable+0x2c
virtual MxResult Create(MxDSObject& p_dsObject); // vtable+0x18
virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c
virtual void ParseAction(char*); // vtable+0x20
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
@ -54,12 +54,12 @@ class LegoEntity : public MxEntity {
undefined m_unk10;
undefined m_unk11;
MxVector3Data m_worldLocation; // 0x14
MxVector3Data m_worldDirection; // 0x28
MxVector3Data m_worldUp; // 0x3c
MxFloat m_worldSpeed; // 0x50
LegoROI* m_roi; // 0x54
MxBool m_cameraFlag; // 0x58
Vector3Data m_worldLocation; // 0x14
Vector3Data m_worldDirection; // 0x28
Vector3Data m_worldUp; // 0x3c
MxFloat m_worldSpeed; // 0x50
LegoROI* m_roi; // 0x54
MxBool m_cameraFlag; // 0x58
undefined m_unk59;
// For tokens from the extra string that look like this:
// "Action:openram;\lego\scripts\Race\CarRaceR;0"

View File

@ -5,6 +5,7 @@
#include "mxautolocker.h"
DECOMP_SIZE_ASSERT(LegoInputManager, 0x338);
DECOMP_SIZE_ASSERT(LegoEventQueue, 0x18);
// OFFSET: LEGO1 0x1005b790
LegoInputManager::LegoInputManager()
@ -55,6 +56,27 @@ MxResult LegoInputManager::Create(HWND p_hwnd)
return SUCCESS;
}
// OFFSET: LEGO1 0x1005bb80 TEMPLATE
// MxCollection<LegoEventNotificationParam>::Compare
// OFFSET: LEGO1 0x1005bc30 TEMPLATE
// MxCollection<LegoEventNotificationParam>::Destroy
// OFFSET: LEGO1 0x1005bc80 TEMPLATE
// MxList<LegoEventNotificationParam>::~MxList<LegoEventNotificationParam>
// OFFSET: LEGO1 0x1005bd50 TEMPLATE
// MxCollection<LegoEventNotificationParam>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005bdc0 TEMPLATE
// MxList<LegoEventNotificationParam>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005beb0 TEMPLATE
// LegoEventQueue::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005bf70 TEMPLATE
// MxQueue<LegoEventNotificationParam>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005bfe0
void LegoInputManager::Destroy()
{
@ -270,3 +292,6 @@ void LegoInputManager::KillTimer()
::KillTimer(omni->GetWindowHandle(), m_timer);
}
}
// OFFSET: LEGO1 0x1005d010 TEMPLATE
// MxListEntry<LegoEventNotificationParam>::GetValue

View File

@ -12,7 +12,17 @@
class LegoControlManager;
// VTABLE 0x100d87b8 TEMPLATE
// class MxCollection<LegoEventNotificationParam>
// VTABLE 0x100d87d0 TEMPLATE
// class MxList<LegoEventNotificationParam>
// VTABLE 0x100d87e8 TEMPLATE
// class MxQueue<LegoEventNotificationParam>
// VTABLE 0x100d8800
// SIZE 0x18
class LegoEventQueue : public MxQueue<LegoEventNotificationParam> {};
// VTABLE 0x100d8760
@ -80,37 +90,4 @@ class LegoInputManager : public MxPresenter {
MxBool m_unk0x336;
};
// OFFSET: LEGO1 0x1005bb80 TEMPLATE
// MxListParent<LegoEventNotificationParam>::Compare
// OFFSET: LEGO1 0x1005bc30 TEMPLATE
// MxListParent<LegoEventNotificationParam>::Destroy
// OFFSET: LEGO1 0x1005bc80 TEMPLATE
// MxList<LegoEventNotificationParam>::~MxList<LegoEventNotificationParam>
// OFFSET: LEGO1 0x1005bd50 TEMPLATE
// MxListParent<LegoEventNotificationParam>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005bdc0 TEMPLATE
// MxList<LegoEventNotificationParam>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005beb0 TEMPLATE
// LegoEventQueue::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005bf70 TEMPLATE
// MxQueue<LegoEventNotificationParam>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1005d010 TEMPLATE
// MxListEntry<LegoEventNotificationParam>::GetValue
// VTABLE 0x100d87e8 TEMPLATE
// class MxQueue<LegoEventNotificationParam>
// VTABLE 0x100d87d0 TEMPLATE
// class MxList<LegoEventNotificationParam>
// VTABLE 0x100d87b8 TEMPLATE
// class MxListParent<LegoEventNotificationParam>
#endif // LEGOINPUTMANAGER_H

View File

@ -8,14 +8,34 @@ LegoPalettePresenter::LegoPalettePresenter()
Init();
}
// OFFSET: LEGO1 0x1007a070 STUB
// OFFSET: LEGO1 0x1007a070
LegoPalettePresenter::~LegoPalettePresenter()
{
// TODO
Destroy(TRUE);
}
// OFFSET: LEGO1 0x1007a0d0
void LegoPalettePresenter::Init()
{
this->m_unk64 = 0;
m_palette = NULL;
}
// OFFSET: LEGO1 0x1007a0e0
void LegoPalettePresenter::Destroy(MxBool p_fromDestructor)
{
m_criticalSection.Enter();
if (m_palette) {
delete m_palette;
}
Init();
m_criticalSection.Leave();
if (!p_fromDestructor) {
MxVideoPresenter::Destroy(FALSE);
}
}
// OFFSET: LEGO1 0x1007a120
void LegoPalettePresenter::Destroy()
{
Destroy(FALSE);
}

View File

@ -2,6 +2,7 @@
#define LEGOPALETTEPRESENTER_H
#include "decomp.h"
#include "mxpalette.h"
#include "mxvideopresenter.h"
// VTABLE 0x100d9aa0
@ -9,7 +10,7 @@
class LegoPalettePresenter : public MxVideoPresenter {
public:
LegoPalettePresenter();
virtual ~LegoPalettePresenter(); // vtable+0x0
virtual ~LegoPalettePresenter() override; // vtable+0x0
// OFFSET: LEGO1 0x10079f30
inline const char* ClassName() const override // vtable+0xc
@ -24,10 +25,12 @@ class LegoPalettePresenter : public MxVideoPresenter {
return !strcmp(name, ClassName()) || MxVideoPresenter::IsA(name);
}
virtual void Destroy() override; // vtable+0x38
private:
void Init();
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk64;
MxPalette* m_palette;
};
#endif // LEGOPALETTEPRESENTER_H

View File

@ -0,0 +1,42 @@
#include "legopathcontrollerlist.h"
#include "decomp.h"
#include "legopathcontroller.h"
DECOMP_SIZE_ASSERT(LegoPathControllerList, 0x18);
// OFFSET: LEGO1 0x1001d210
MxS8 LegoPathControllerList::Compare(LegoPathController* p_a, LegoPathController* p_b)
{
return p_a == p_b ? 0 : p_a < p_b ? -1 : 1;
}
// OFFSET: LEGO1 0x1001d230 TEMPLATE
// MxCollection<LegoPathController *>::Compare
// OFFSET: LEGO1 0x1001d240 TEMPLATE
// MxList<LegoPathController *>::MxList<LegoPathController *>
// OFFSET: LEGO1 0x1001d2d0 TEMPLATE
// MxCollection<LegoPathController *>::~MxCollection<LegoPathController *>
// OFFSET: LEGO1 0x1001d320 TEMPLATE
// MxCollection<LegoPathController *>::Destroy
// OFFSET: LEGO1 0x1001d330 TEMPLATE
// MxList<LegoPathController *>::~MxList<LegoPathController *>
// OFFSET: LEGO1 0x1001d3c0
void LegoPathControllerList::Destroy(LegoPathController* p_controller)
{
delete p_controller;
}
// OFFSET: LEGO1 0x1001d490 TEMPLATE
// MxCollection<LegoPathController *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1001d500 TEMPLATE
// MxList<LegoPathController *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1001d5b0 TEMPLATE
// MxPtrList<LegoPathController>::`scalar deleting destructor'

View File

@ -0,0 +1,26 @@
#ifndef LEGOPATHCONTROLLERLIST_H
#define LEGOPATHCONTROLLERLIST_H
#include "legopathcontroller.h"
#include "mxlist.h"
#include "mxtypes.h"
// VTABLE 0x100d6320 TEMPLATE
// class MxPtrList<LegoPathController>
// VTABLE 0x100d6338
// SIZE 0x18
class LegoPathControllerList : public MxPtrList<LegoPathController> {
public:
LegoPathControllerList() : MxPtrList<LegoPathController>(Destroy) {}
virtual MxS8 Compare(LegoPathController*, LegoPathController*) override; // vtable+0x14
static void Destroy(LegoPathController*);
};
// VTABLE 0x100d6380 TEMPLATE
// class MxCollection<LegoPathController *>
// VTABLE 0x100d6398 TEMPLATE
// class MxList<LegoPathController *>
#endif // LEGOPATHCONTROLLERLIST_H

View File

@ -3,7 +3,9 @@
#include "legocameracontroller.h"
#include "legoentity.h"
#include "legopathcontrollerlist.h"
#include "mxpresenter.h"
#include "mxpresenterlist.h"
// VTABLE 0x100d6280
// SIZE 0xf8
@ -39,9 +41,12 @@ class LegoWorld : public LegoEntity {
void EndAction(MxPresenter* p_presenter);
protected:
undefined m_unk68[0x30];
LegoCameraController* m_camera;
undefined m_unk9c[0x5a];
LegoPathControllerList m_list0x68; // 0x68
MxPresenterList m_list0x80; // 0x80
LegoCameraController* m_camera; // 0x98
undefined m_unk9c[0x1c];
MxPresenterList m_list0xb8; // 0xb8
undefined m_unkd0[0x26];
undefined m_unkf6;
undefined m_unkf7;
};

View File

@ -5,13 +5,13 @@
DECOMP_SIZE_ASSERT(MxAudioPresenter, 0x54);
// OFFSET: LEGO1 0x1000d260
undefined4 MxAudioPresenter::vtable5c()
MxU32 MxAudioPresenter::GetVolume()
{
return this->m_unk50;
return m_volume;
}
// OFFSET: LEGO1 0x1000d270
void MxAudioPresenter::vtable60(undefined4 p_unk50)
void MxAudioPresenter::SetVolume(MxU32 p_volume)
{
this->m_unk50 = p_unk50;
m_volume = p_volume;
}

View File

@ -5,9 +5,10 @@
#include "mxmediapresenter.h"
// VTABLE 0x100d4c70
// SIZE 0x54
class MxAudioPresenter : public MxMediaPresenter {
public:
MxAudioPresenter() { m_unk50 = 100; }
MxAudioPresenter() { m_volume = 100; }
// OFFSET: LEGO1 0x1000d280
inline virtual const char* ClassName() const override // vtable+0x0c
@ -22,10 +23,11 @@ class MxAudioPresenter : public MxMediaPresenter {
return !strcmp(name, MxAudioPresenter::ClassName()) || MxMediaPresenter::IsA(name);
}
virtual undefined4 vtable5c();
virtual void vtable60(undefined4);
virtual MxU32 GetVolume(); // vtable+0x5c
virtual void SetVolume(MxU32 p_volume); // vtable+0x60
undefined4 m_unk50;
private:
MxU32 m_volume;
};
#endif // MXAUDIOPRESENTER_H

View File

@ -159,7 +159,7 @@ void MxBackgroundAudioManager::StartAction(MxParam& p)
m_action2.SetAtomId(m_unk138->GetAction()->GetAtomId());
m_action2.SetObjectId(m_unk138->GetAction()->GetObjectId());
m_targetVolume = ((MxDSSound*) (m_unk138->GetAction()))->GetVolume();
m_unk138->vtable60(0);
m_unk138->SetVolume(0);
}
// OFFSET: LEGO1 0x1007f200
@ -257,15 +257,15 @@ void MxBackgroundAudioManager::FUN_1007ef40()
if (m_unk148 == 0) {
compare = m_unk148;
}
volume = m_unk138->vtable5c();
volume = m_unk138->GetVolume();
if (volume < compare) {
if (m_unk140 + m_unk138->vtable5c() <= compare) {
if (m_unk140 + m_unk138->GetVolume() <= compare) {
compare = m_unk140 + compare;
}
m_unk138->vtable60(compare);
m_unk138->SetVolume(compare);
}
else {
m_unk138->vtable60(compare);
m_unk138->SetVolume(compare);
m_unka0 = m_unk138;
m_action1 = m_action2;
m_unk138 = NULL;
@ -276,16 +276,16 @@ void MxBackgroundAudioManager::FUN_1007ef40()
}
}
else if (m_unka0->GetAction() != NULL) {
if (m_unka0->vtable5c() == 0) {
if (m_unka0->GetVolume() == 0) {
DeleteObject(*m_unka0->GetAction());
}
else {
compare = m_unka0->vtable5c();
compare = m_unka0->GetVolume();
volume = 0;
if (compare != m_unk140 && -1 < compare - m_unk140) {
volume = m_unka0->vtable5c() - m_unk140;
volume = m_unka0->GetVolume() - m_unk140;
}
m_unk138->vtable60(volume);
m_unk138->SetVolume(volume);
}
}
}
@ -295,7 +295,7 @@ void MxBackgroundAudioManager::FadeInOrFadeOut()
{
// This function probably is the fade in/out routine
if (m_unka0 != NULL) {
undefined4 volume = m_unka0->vtable5c();
undefined4 volume = m_unka0->GetVolume();
MxU32 compare = 30;
if (m_unk148 == 0) {
compare = m_targetVolume;
@ -306,17 +306,17 @@ void MxBackgroundAudioManager::FadeInOrFadeOut()
if (compare <= volume) {
volume = compare;
}
m_unka0->vtable60(volume);
m_unka0->SetVolume(volume);
}
else if (compare < volume) {
volume = volume - m_unk140;
if (volume <= compare) {
volume = compare;
}
m_unka0->vtable60(volume);
m_unka0->SetVolume(volume);
}
else {
m_unka0->vtable60(volume);
m_unka0->SetVolume(volume);
m_unk13c = 0;
}
}

View File

@ -18,8 +18,8 @@ class MxCollection : public MxCore {
virtual MxS8 Compare(T, T) { return 0; }
protected:
MxU32 m_count; // +0x8
void (*m_customDestructor)(T); // +0xc
MxU32 m_count; // 0x8
void (*m_customDestructor)(T); // 0xc
};
#endif // MXCOLLECTION_H

View File

@ -3,7 +3,7 @@
#include "mxdsobject.h"
#include "mxtypes.h"
#include "mxvector.h"
#include "realtime/vector.h"
class MxOmni;
@ -62,7 +62,7 @@ class MxDSAction : public MxDSObject {
inline MxLong GetStartTime() const { return m_startTime; }
inline MxS32 GetLoopCount() { return m_loopCount; }
inline void SetLoopCount(MxS32 p_loopCount) { m_loopCount = p_loopCount; }
inline const MxVector3Data& GetLocation() const { return m_location; }
inline const Vector3Data& GetLocation() const { return m_location; }
inline void SetUnknown84(MxCore* p_unk84) { m_unk84 = p_unk84; }
inline MxCore* GetUnknown8c() { return m_unk8c; }
inline void SetUnknown8c(MxCore* p_unk8c) { m_unk8c = p_unk8c; }
@ -70,26 +70,20 @@ class MxDSAction : public MxDSObject {
inline MxBool IsLooping() const { return m_flags & Flag_Looping; }
inline MxBool IsBit3() const { return m_flags & Flag_Bit3; }
private:
MxU32 m_sizeOnDisk;
MxU32 m_flags;
MxLong m_startTime;
protected:
MxLong m_duration;
MxS32 m_loopCount;
private:
MxVector3Data m_location;
MxVector3Data m_direction;
MxVector3Data m_up;
char* m_extraData;
MxU16 m_extraLength;
MxCore* m_unk84;
undefined4 m_unk88;
MxCore* m_unk8c;
protected:
MxU32 m_sizeOnDisk; // 0x2c
MxU32 m_flags; // 0x30
MxLong m_startTime; // 0x34
MxLong m_duration; // 0x38
MxS32 m_loopCount; // 0x3c
Vector3Data m_location; // 0x40
Vector3Data m_direction; // 0x54
Vector3Data m_up; // 0x68
char* m_extraData; // 0x7c
MxU16 m_extraLength; // 0x80
MxCore* m_unk84; // 0x84
undefined4 m_unk88; // 0x88
MxCore* m_unk8c; // 0x8c
MxLong m_unkTimingField; // 0x90
};

View File

@ -17,3 +17,18 @@ void MxDSActionList::Destroy(MxDSAction* p_action)
if (p_action)
delete p_action;
}
// OFFSET: LEGO1 0x100c9cc0 TEMPLATE
// MxCollection<MxDSAction *>::Compare
// OFFSET: LEGO1 0x100c9d20 TEMPLATE
// MxCollection<MxDSAction *>::Destroy
// OFFSET: LEGO1 0x100c9d30 TEMPLATE
// MxList<MxDSAction *>::~MxList<MxDSAction *>
// OFFSET: LEGO1 0x100c9e30 TEMPLATE
// MxCollection<MxDSAction *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100c9ea0 TEMPLATE
// MxList<MxDSAction *>::`scalar deleting destructor'

View File

@ -6,13 +6,19 @@
class MxDSAction;
// VTABLE 0x100dcea8 TEMPLATE
// class MxCollection<MxDSAction *>
// VTABLE 0x100dcec0 TEMPLATE
// class MxList<MxDSAction *>
// VTABLE 0x100dced8
// SIZE 0x1c
class MxDSActionList : public MxList<MxDSAction*> {
public:
MxDSActionList() { this->m_unk18 = 0; }
virtual MxS8 Compare(MxDSAction*, MxDSAction*) override; // +0x14
virtual MxS8 Compare(MxDSAction*, MxDSAction*) override; // vtable+0x14
static void Destroy(MxDSAction* p_action);
@ -22,13 +28,4 @@ class MxDSActionList : public MxList<MxDSAction*> {
typedef MxListCursorChild<MxDSAction*> MxDSActionListCursor;
// OFFSET: LEGO1 0x100c9cc0 TEMPLATE
// MxListParent<MxDSAction *>::Compare
// OFFSET: LEGO1 0x100c9d20 TEMPLATE
// MxListParent<MxDSAction *>::Destroy
// OFFSET: LEGO1 0x100c9d30 TEMPLATE
// MxList<MxDSAction *>::~MxList<MxDSAction *>
#endif // MXDSACTIONLIST_H

View File

@ -37,17 +37,17 @@ class MxDSMediaAction : public MxDSAction {
inline MxLong GetSustainTime() const { return this->m_sustainTime; }
private:
MxU32 m_sizeOnDisk;
char* m_mediaSrcPath;
MxU32 m_sizeOnDisk; // 0x94
char* m_mediaSrcPath; // 0x98
struct {
undefined4 m_unk00;
undefined4 m_unk04;
} m_unk9c;
MxS32 m_framesPerSecond;
MxS32 m_mediaFormat;
MxS32 m_paletteManagement;
MxLong m_sustainTime;
undefined4 m_unkb4;
} m_unk9c; // 0x9c
MxS32 m_framesPerSecond; // 0xa4
MxS32 m_mediaFormat; // 0xa8
MxS32 m_paletteManagement; // 0xac
MxLong m_sustainTime; // 0xb0
undefined4 m_unkb4; // 0xb4
};
#endif // MXDSMEDIAACTION_H

View File

@ -14,7 +14,7 @@ MxEntity::~MxEntity()
}
// OFFSET: LEGO1 0x10001070
MxResult MxEntity::SetEntityId(MxS32 p_id, const MxAtomId& p_atom)
MxResult MxEntity::Create(MxS32 p_id, const MxAtomId& p_atom)
{
this->m_mxEntityId = p_id;
this->m_atom = p_atom;

View File

@ -27,8 +27,8 @@ class MxEntity : public MxCore {
return !strcmp(name, MxEntity::ClassName()) || MxCore::IsA(name);
}
virtual MxResult SetEntityId(MxS32 p_id, const MxAtomId& p_atom); // vtable+0x14
inline MxResult InitFromMxDSObject(MxDSObject& p_dsObject)
virtual MxResult Create(MxS32 p_id, const MxAtomId& p_atom); // vtable+0x14
inline MxResult Create(MxDSObject& p_dsObject)
{
m_mxEntityId = p_dsObject.GetObjectId();
m_atom = p_dsObject.GetAtomId();

View File

@ -1,6 +1,10 @@
#include "mxflcpresenter.h"
#include "decomp.h"
#include "mxbitmap.h"
#include "mxomni.h"
#include "mxpalette.h"
#include "mxvideomanager.h"
DECOMP_SIZE_ASSERT(MxFlcPresenter, 0x68);
@ -19,3 +23,13 @@ MxFlcPresenter::~MxFlcPresenter()
delete this->m_unk64;
}
}
// OFFSET: LEGO1 0x100b3620
void MxFlcPresenter::VTable0x70()
{
MxPalette* pal = m_bitmap->CreatePalette();
MVideoManager()->RealizePalette(pal);
if (pal)
delete pal;
}

View File

@ -24,6 +24,8 @@ class MxFlcPresenter : public MxVideoPresenter {
return !strcmp(name, MxFlcPresenter::ClassName()) || MxVideoPresenter::IsA(name);
}
virtual void VTable0x70() override; // vtable+0x70
undefined4* m_unk64;
};

View File

@ -59,16 +59,16 @@ class MxHashTable : protected MxCollection<T> {
protected:
void _NodeInsert(MxHashTableNode<T>*);
MxHashTableNode<T>** m_slots; // +0x10
MxU32 m_numSlots; // +0x14
MxU32 m_autoResizeRatio; // +0x18
HashTableOpt m_resizeOption; // +0x1c
MxHashTableNode<T>** m_slots; // 0x10
MxU32 m_numSlots; // 0x14
MxU32 m_autoResizeRatio; // 0x18
HashTableOpt m_resizeOption; // 0x1c
// FIXME: or FIXME? This qword is used as an integer or double depending
// on the value of m_resizeOption. Hard to say whether this is how the devs
// did it, but a simple cast in either direction doesn't match.
union {
MxU32 m_increaseAmount; // +0x20
double m_increaseFactor; // +0x20
MxU32 m_increaseAmount; // 0x20
double m_increaseFactor; // 0x20
};
};
@ -156,13 +156,13 @@ void MxHashTable<T>::DeleteAll()
while (t) {
MxHashTableNode<T>* next = t->m_next;
m_customDestructor(t->m_obj);
this->m_customDestructor(t->m_obj);
delete t;
t = next;
}
}
m_count = 0;
this->m_count = 0;
memset(m_slots, 0, sizeof(MxHashTableNode<T>*) * m_numSlots);
delete[] m_slots;
@ -188,7 +188,7 @@ inline void MxHashTable<T>::Resize()
MxHashTableNode<T>** new_table = new MxHashTableNode<T>*[m_numSlots];
m_slots = new_table;
memset(m_slots, 0, sizeof(MxHashTableNode<T>*) * m_numSlots);
m_count = 0;
this->m_count = 0;
for (MxS32 i = 0; i != old_size; i++) {
MxHashTableNode<T>* t = old_table[i];
@ -214,13 +214,13 @@ inline void MxHashTable<T>::_NodeInsert(MxHashTableNode<T>* p_node)
m_slots[bucket]->m_prev = p_node;
m_slots[bucket] = p_node;
m_count++;
this->m_count++;
}
template <class T>
inline void MxHashTable<T>::Add(T p_newobj)
{
if (m_resizeOption && ((m_count + 1) / m_numSlots) > m_autoResizeRatio)
if (m_resizeOption && ((this->m_count + 1) / m_numSlots) > m_autoResizeRatio)
MxHashTable<T>::Resize();
MxU32 hash = Hash(p_newobj);

View File

@ -1,6 +1,7 @@
#ifndef MXLIST_H
#define MXLIST_H
#include "mxcollection.h"
#include "mxcore.h"
#include "mxtypes.h"
@ -9,6 +10,12 @@ class MxList;
template <class T>
class MxListCursor;
template <class T>
class MxPtrList : public MxList<T*> {
public:
MxPtrList(void (*p_destroy)(T*) = Destroy) { m_customDestructor = p_destroy; }
};
template <class T>
class MxListEntry {
public:
@ -40,29 +47,9 @@ class MxListEntry {
MxListEntry* m_next;
};
// SIZE 0x10
template <class T>
class MxListParent : public MxCore {
public:
MxListParent()
{
m_count = 0;
m_customDestructor = Destroy;
}
virtual ~MxListParent() {}
virtual MxS8 Compare(T, T) { return 0; };
static void Destroy(T){};
protected:
MxU32 m_count; // +0x8
void (*m_customDestructor)(T); // +0xc
};
// SIZE 0x18
template <class T>
class MxList : protected MxListParent<T> {
class MxList : protected MxCollection<T> {
public:
MxList()
{
@ -80,8 +67,8 @@ class MxList : protected MxListParent<T> {
friend class MxListCursor<T>;
protected:
MxListEntry<T>* m_first; // +0x10
MxListEntry<T>* m_last; // +0x14
MxListEntry<T>* m_first; // 0x10
MxListEntry<T>* m_last; // 0x14
void _DeleteEntry(MxListEntry<T>* match);
MxListEntry<T>* _InsertEntry(T, MxListEntry<T>*, MxListEntry<T>*);

View File

@ -1,68 +0,0 @@
#ifndef MXMATRIX_H
#define MXMATRIX_H
#include "mxvector.h"
// VTABLE 0x100d4350
// SIZE 0x8
class MxMatrix {
public:
inline MxMatrix(float* p_data) : m_data(p_data) {}
// vtable + 0x00
virtual void EqualsMxMatrix(const MxMatrix* p_other);
virtual void EqualsMatrixData(const float* p_matrix);
virtual void SetData(float* p_data);
virtual void AnotherSetData(float* p_data);
// vtable + 0x10
virtual float* GetData();
virtual const float* GetData() const;
virtual float* Element(int p_row, int p_col);
virtual const float* Element(int p_row, int p_col) const;
// vtable + 0x20
virtual void Clear();
virtual void SetIdentity();
virtual void operator=(const MxMatrix& p_other);
virtual MxMatrix* operator+=(const float* p_matrix);
// vtable + 0x30
virtual void TranslateBy(const float* p_x, const float* p_y, const float* p_z);
virtual void SetTranslation(const float* p_x, const float* p_y, const float* p_z);
virtual void EqualsMxProduct(const MxMatrix* p_a, const MxMatrix* p_b);
virtual void EqualsDataProduct(const float* p_a, const float* p_b);
// vtable + 0x40
virtual void ToQuaternion(MxVector4* p_resultQuat);
virtual MxResult FUN_10002710(const MxVector3* p_vec);
inline float& operator[](size_t idx) { return m_data[idx]; }
private:
float* m_data;
};
// VTABLE 0x100d4300
// SIZE 0x48
class MxMatrixData : public MxMatrix {
public:
inline MxMatrixData() : MxMatrix(e) {}
// No idea why there's another equals. Maybe to some other type like the
// DirectX Retained Mode Matrix type which is also a float* alias?
// vtable + 0x44
virtual void operator=(const MxMatrixData& p_other);
// Alias an easy way to access the translation part of the matrix, because
// various members / other functions benefit from the clarity.
union {
float e[16];
struct {
float _[12];
float x, y, z, w;
};
};
};
#endif // MXMATRIX_H

View File

@ -129,7 +129,7 @@ void MxMediaPresenter::StreamingTickle()
else if (m_action->GetFlags() & MxDSAction::Flag_Looping) {
AppendChunk(m_currentChunk);
if (!MxPresenter::IsEnabled()) {
if (!IsEnabled()) {
m_subscriber->FUN_100b8390(m_currentChunk);
m_currentChunk = NULL;
}
@ -141,7 +141,7 @@ void MxMediaPresenter::StreamingTickle()
// OFFSET: LEGO1 0x100b5e10
void MxMediaPresenter::RepeatingTickle()
{
if (MxPresenter::IsEnabled() && !m_currentChunk) {
if (IsEnabled() && !m_currentChunk) {
if (m_cursor)
if (!m_cursor->Next(m_currentChunk))
m_cursor->Next(m_currentChunk);
@ -173,7 +173,7 @@ void MxMediaPresenter::DoneTickle()
// OFFSET: LEGO1 0x100b6030
void MxMediaPresenter::Enable(MxBool p_enable)
{
if (MxPresenter::IsEnabled() != p_enable) {
if (IsEnabled() != p_enable) {
MxPresenter::Enable(p_enable);
if (p_enable) {

View File

@ -6,6 +6,13 @@
DECOMP_SIZE_ASSERT(MxMIDIPresenter, 0x58);
// OFFSET: LEGO1 0x100c25a0 STUB
MxResult MxMIDIPresenter::AddToManager()
{
// TODO
return SUCCESS;
}
// OFFSET: LEGO1 0x100c25e0
MxMIDIPresenter::MxMIDIPresenter()
{
@ -30,10 +37,46 @@ void MxMIDIPresenter::Destroy(MxBool p_fromDestructor)
// TODO
}
// OFFSET: LEGO1 0x100c2890 STUB
void MxMIDIPresenter::ReadyTickle()
{
// TODO
}
// OFFSET: LEGO1 0x100c28d0 STUB
void MxMIDIPresenter::StartingTickle()
{
// TODO
}
// OFFSET: LEGO1 0x100c2910 STUB
void MxMIDIPresenter::StreamingTickle()
{
// TODO
}
// OFFSET: LEGO1 0x100c2940
void MxMIDIPresenter::DoneTickle()
{
if (!MusicManager()->GetMIDIInitialized()) {
this->EndAction();
}
if (!MusicManager()->GetMIDIInitialized())
EndAction();
}
// OFFSET: LEGO1 0x100c2960 STUB
void MxMIDIPresenter::Destroy()
{
// TODO
}
// OFFSET: LEGO1 0x100c2970 STUB
undefined4 MxMIDIPresenter::PutData()
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x100c29e0 STUB
void MxMIDIPresenter::EndAction()
{
// TODO
}

View File

@ -4,6 +4,7 @@
#include "mxmusicpresenter.h"
// VTABLE 0x100dca20
// SIZE 0x58
class MxMIDIPresenter : public MxMusicPresenter {
public:
MxMIDIPresenter();
@ -22,11 +23,18 @@ class MxMIDIPresenter : public MxMusicPresenter {
return !strcmp(name, MxMIDIPresenter::ClassName()) || MxMusicPresenter::IsA(name);
}
virtual void DoneTickle() override; // vtable+0x2c
virtual void ReadyTickle() override; // vtable+0x18
virtual void StartingTickle() override; // vtable+0x1c
virtual void StreamingTickle() override; // vtable+0x20
virtual void DoneTickle() override; // vtable+0x2c
virtual MxResult AddToManager() override; // vtable+0x34
virtual void Destroy() override; // vtable+0x38
virtual void EndAction() override; // vtable+0x40
virtual undefined4 PutData() override; // vtable+0x4c
private:
void Init();
void Destroy(MxBool);
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk54;
};

View File

@ -7,6 +7,9 @@
// SIZE 0x54
class MxMusicPresenter : public MxAudioPresenter {
public:
MxMusicPresenter();
virtual ~MxMusicPresenter() override;
// OFFSET: LEGO1 0x100c23a0
inline virtual const char* ClassName() const override // vtable+0xc
{
@ -20,9 +23,6 @@ class MxMusicPresenter : public MxAudioPresenter {
return !strcmp(name, MxMusicPresenter::ClassName()) || MxAudioPresenter::IsA(name);
}
MxMusicPresenter();
virtual ~MxMusicPresenter() override;
virtual MxResult AddToManager() override; // vtable+0x34
virtual void Destroy() override; // vtable+0x38

View File

@ -123,7 +123,7 @@ MxResult MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action)
this->m_action = p_action;
const MxVector3Data& location = this->m_action->GetLocation();
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]);

View File

@ -10,3 +10,27 @@ MxS8 MxPresenterList::Compare(MxPresenter* p_a, MxPresenter* p_b)
{
return p_a == p_b ? 0 : p_a < p_b ? -1 : 1;
}
// OFFSET: LEGO1 0x1001cd20 TEMPLATE
// MxCollection<MxPresenter *>::Compare
// OFFSET: LEGO1 0x1001cd30 TEMPLATE
// MxCollection<MxPresenter *>::Destroy
// OFFSET: LEGO1 0x1001cd40 TEMPLATE
// MxList<MxPresenter *>::MxList<MxPresenter *>
// OFFSET: LEGO1 0x1001cdd0 TEMPLATE
// MxCollection<MxPresenter *>::~MxCollection<MxPresenter *>
// OFFSET: LEGO1 0x1001ce20 TEMPLATE
// MxList<MxPresenter *>::~MxList<MxPresenter *>
// OFFSET: LEGO1 0x1001cf70 TEMPLATE
// MxCollection<MxPresenter *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1001cfe0 TEMPLATE
// MxList<MxPresenter *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x1001d090 TEMPLATE
// MxPtrList<MxPresenter>::`scalar deleting destructor'

View File

@ -5,30 +5,22 @@
class MxPresenter;
// Unclear what the purpose of this class is
// VTABLE 0x100d62f0
// SIZE 0x18
class MxPresenterListParent : public MxList<MxPresenter*> {
public:
MxPresenterListParent() { m_customDestructor = Destroy; }
};
// VTABLE 0x100d62f0 TEMPLATE
// class MxPtrList<MxPresenter>
// VTABLE 0x100d6308
// SIZE 0x18
class MxPresenterList : public MxPresenterListParent {
class MxPresenterList : public MxPtrList<MxPresenter> {
public:
virtual MxS8 Compare(MxPresenter*, MxPresenter*) override; // +0x14
virtual MxS8 Compare(MxPresenter*, MxPresenter*) override; // vtable+0x14
};
typedef MxListCursorChildChild<MxPresenter*> MxPresenterListCursor;
// OFFSET: LEGO1 0x1001cd20 TEMPLATE
// MxListParent<MxPresenter *>::Compare
// VTABLE 0x100d6350 TEMPLATE
// class MxCollection<MxPresenter *>
// OFFSET: LEGO1 0x1001cd30 TEMPLATE
// MxListParent<MxPresenter *>::Destroy
// OFFSET: LEGO1 0x1001ce20 TEMPLATE
// MxList<MxPresenter *>::~MxList<MxPresenter *>
// VTABLE 0x100d6368 TEMPLATE
// class MxList<MxPresenter *>
#endif // MXPRESENTERLIST_H

View File

@ -21,7 +21,7 @@ struct MxRegionTopBottom {
inline void SetTop(MxS32 p_top) { m_top = p_top; }
inline void SetBottom(MxS32 p_bottom) { m_bottom = p_bottom; }
friend class MxRegionListParent;
friend class MxRegionList;
private:
MxS32 m_top;

View File

@ -3,7 +3,7 @@
#include "mxregion.h"
// OFFSET: LEGO1 0x100c33e0
void MxRegionListParent::Destroy(MxRegionTopBottom* p_topBottom)
void MxRegionList::Destroy(MxRegionTopBottom* p_topBottom)
{
if (p_topBottom) {
if (p_topBottom->m_leftRightList)
@ -13,7 +13,52 @@ void MxRegionListParent::Destroy(MxRegionTopBottom* p_topBottom)
}
// OFFSET: LEGO1 0x100c4e80
void MxRegionLeftRightListParent::Destroy(MxRegionLeftRight* p_leftRight)
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'
// OFFSET: LEGO1 0x100c3540 TEMPLATE
// MxList<MxRegionTopBottom *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100c35f0 TEMPLATE
// MxPtrList<MxRegionTopBottom>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100c4d80 TEMPLATE
// MxCollection<MxRegionLeftRight *>::Compare
// OFFSET: LEGO1 0x100c4de0 TEMPLATE
// MxCollection<MxRegionLeftRight *>::Destroy
// OFFSET: LEGO1 0x100c4f50 TEMPLATE
// MxCollection<MxRegionLeftRight *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100c4fc0 TEMPLATE
// MxList<MxRegionLeftRight *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100c5070 TEMPLATE
// MxPtrList<MxRegionLeftRight>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100c54f0 TEMPLATE
// MxListCursor<MxRegionLeftRight *>::MxListCursor<MxRegionLeftRight *>
// OFFSET: LEGO1 0x100c58c0 TEMPLATE
// MxList<MxRegionLeftRight *>::_InsertEntry
// OFFSET: LEGO1 0x100c5970 TEMPLATE
// MxList<MxRegionTopBottom *>::_InsertEntry
// OFFSET: LEGO1 0x100c5a20 TEMPLATE
// MxListEntry<MxRegionTopBottom *>::MxListEntry<MxRegionTopBottom *>
// OFFSET: LEGO1 0x100c5a40 TEMPLATE
// MxList<MxRegionLeftRight *>::_DeleteEntry

View File

@ -6,51 +6,44 @@
struct MxRegionTopBottom;
struct MxRegionLeftRight;
// VTABLE 0x100dcb40
// SIZE 0x18
class MxRegionListParent : public MxList<MxRegionTopBottom*> {
public:
static void Destroy(MxRegionTopBottom* p_topBottom);
// VTABLE 0x100dcb10 TEMPLATE
// class MxCollection<MxRegionTopBottom *>
MxRegionListParent() { m_customDestructor = Destroy; }
};
// VTABLE 0x100dcb28 TEMPLATE
// class MxList<MxRegionTopBottom *>
// VTABLE 0x100dcb40 TEMPLATE
// class MxPtrList<MxRegionTopBottom>
// VTABLE 0x100dcb58
// SIZE 0x18
class MxRegionList : public MxRegionListParent {};
class MxRegionList : public MxPtrList<MxRegionTopBottom> {
public:
MxRegionList() : MxPtrList<MxRegionTopBottom>(Destroy) {}
static void Destroy(MxRegionTopBottom*);
};
// VTABLE 0x100dcb88
typedef MxListCursorChildChild<MxRegionTopBottom*> MxRegionListCursor;
// OFFSET: LEGO1 0x100c5970 TEMPLATE
// MxList<MxRegionTopBottom *>::_InsertEntry
// OFFSET: LEGO1 0x100c5a20 TEMPLATE
// MxListEntry<MxRegionTopBottom *>::MxListEntry<MxRegionTopBottom *>
// VTABLE 0x100dcc70
// SIZE 0x18
class MxRegionLeftRightListParent : public MxList<MxRegionLeftRight*> {
public:
static void Destroy(MxRegionLeftRight* p_leftRight);
MxRegionLeftRightListParent() { m_customDestructor = Destroy; }
};
// VTABLE 0x100dcc88
// SIZE 0x18
class MxRegionLeftRightList : public MxRegionLeftRightListParent {};
// VTABLE 0x100dcc10
typedef MxListCursorChildChild<MxRegionLeftRight*> MxRegionLeftRightListCursor;
// OFFSET: LEGO1 0x100c54f0 TEMPLATE
// MxListCursor<MxRegionLeftRight *>::MxListCursor<MxRegionLeftRight *>
// VTABLE 0x100dcc40 TEMPLATE
// class MxCollection<MxRegionLeftRight *>
// OFFSET: LEGO1 0x100c58c0 TEMPLATE
// MxList<MxRegionLeftRight *>::_InsertEntry
// VTABLE 0x100dcc58 TEMPLATE
// class MxList<MxRegionLeftRight *>
// OFFSET: LEGO1 0x100c5a40 TEMPLATE
// MxList<MxRegionLeftRight *>::_DeleteEntry
// VTABLE 0x100dcc70 TEMPLATE
// class MxPtrList<MxRegionLeftRight>
// VTABLE 0x100dcc88
// SIZE 0x18
class MxRegionLeftRightList : public MxPtrList<MxRegionLeftRight> {
public:
MxRegionLeftRightList() : MxPtrList<MxRegionLeftRight>(Destroy) {}
static void Destroy(MxRegionLeftRight*);
};
#endif // MXREGIONLIST_H

View File

@ -145,7 +145,7 @@ void MxSoundManager::SetVolume(MxS32 p_volume)
MxPresenterListCursor cursor(m_presenters);
while (cursor.Next(presenter))
((MxAudioPresenter*) presenter)->vtable60(((MxAudioPresenter*) presenter)->vtable5c());
((MxAudioPresenter*) presenter)->SetVolume(((MxAudioPresenter*) presenter)->GetVolume());
m_criticalSection.Leave();
}

View File

@ -11,6 +11,12 @@ MxSoundPresenter::~MxSoundPresenter()
Destroy(TRUE);
}
// OFFSET: LEGO1 0x1000d490
void MxSoundPresenter::Destroy()
{
Destroy(FALSE);
}
// OFFSET: LEGO1 0x100b1a50
void MxSoundPresenter::Destroy(MxBool p_fromDestructor)
{
@ -37,9 +43,3 @@ MxResult MxSoundPresenter::AddToManager()
return ret;
}
// OFFSET: LEGO1 0x1000d490
void MxSoundPresenter::Destroy()
{
Destroy(FALSE);
}

View File

@ -5,6 +5,7 @@
#include "mxomni.h"
// VTABLE 0x100d4b08
// SIZE 0x54
class MxSoundPresenter : public MxAudioPresenter {
public:
virtual ~MxSoundPresenter() override;
@ -26,7 +27,7 @@ class MxSoundPresenter : public MxAudioPresenter {
virtual void Destroy() override; // vtable+0x38
private:
void Destroy(MxBool);
void Destroy(MxBool p_fromDestructor);
};
#endif // MXSOUNDPRESENTER_H

View File

@ -17,3 +17,18 @@ void MxStreamChunkList::Destroy(MxStreamChunk* p_chunk)
if (p_chunk)
delete p_chunk;
}
// OFFSET: LEGO1 0x100b5930 TEMPLATE
// MxCollection<MxStreamChunk *>::Compare
// OFFSET: LEGO1 0x100b5990 TEMPLATE
// MxCollection<MxStreamChunk *>::Destroy
// OFFSET: LEGO1 0x100b59a0 TEMPLATE
// MxList<MxStreamChunk *>::~MxList<MxStreamChunk *>
// OFFSET: LEGO1 0x100b5aa0 TEMPLATE
// MxCollection<MxStreamChunk *>::`scalar deleting destructor'
// OFFSET: LEGO1 0x100b5b10 TEMPLATE
// MxList<MxStreamChunk *>::`scalar deleting destructor'

View File

@ -6,29 +6,23 @@
class MxStreamChunk;
// VTABLE 0x100dc5d0 TEMPLATE
// class MxCollection<MxStreamChunk *>
// VTABLE 0x100dc5e8 TEMPLATE
// class MxList<MxStreamChunk *>
// VTABLE 0x100dc600
// SIZE 0x18
class MxStreamChunkList : public MxList<MxStreamChunk*> {
public:
MxStreamChunkList() { m_customDestructor = Destroy; }
virtual MxS8 Compare(MxStreamChunk*, MxStreamChunk*) override; // +0x14
virtual MxS8 Compare(MxStreamChunk*, MxStreamChunk*) override; // vtable+0x14
static void Destroy(MxStreamChunk* p_chunk);
};
typedef MxListCursorChild<MxStreamChunk*> MxStreamChunkListCursor;
// OFFSET: LEGO1 0x100b5930 TEMPLATE
// MxListParent<MxStreamChunk *>::Compare
// OFFSET: LEGO1 0x100b5990 TEMPLATE
// MxListParent<MxStreamChunk *>::Destroy
// OFFSET: LEGO1 0x100b59a0 TEMPLATE
// MxList<MxStreamChunk *>::~MxList<MxStreamChunk *>
// OFFSET: LEGO1 0x100b5b10 TEMPLATE
// MxList<MxStreamChunk *>::`scalar deleting destructor'
#endif // MXSTREAMCHUNKLIST_H

View File

@ -3,3 +3,24 @@
#include "decomp.h"
DECOMP_SIZE_ASSERT(MxListEntry<MxString>, 0x18)
// OFFSET: LEGO1 0x100cb3c0 TEMPLATE
// MxCollection<MxString>::Compare
// OFFSET: LEGO1 0x100cb470 TEMPLATE
// MxCollection<MxString>::Destroy
// OFFSET: LEGO1 0x100cb4c0 TEMPLATE
// MxList<MxString>::~MxList<MxString>
// OFFSET: LEGO1 0x100cbb40 TEMPLATE
// MxList<MxString>::Append
// OFFSET: LEGO1 0x100cc2d0 TEMPLATE
// MxList<MxString>::_InsertEntry
// OFFSET: LEGO1 0x100cc3c0 TEMPLATE
// MxListEntry<MxString>::MxListEntry<MxString>
// OFFSET: LEGO1 0x100cc450 TEMPLATE
// MxListEntry<MxString>::GetValue

View File

@ -11,25 +11,4 @@ class MxStringList : public MxList<MxString> {};
// VTABLE 0x100dd058
typedef MxListCursorChild<MxString> MxStringListCursor;
// OFFSET: LEGO1 0x100cb3c0 TEMPLATE
// MxListParent<MxString>::Compare
// OFFSET: LEGO1 0x100cb470 TEMPLATE
// MxListParent<MxString>::Destroy
// OFFSET: LEGO1 0x100cb4c0 TEMPLATE
// MxList<MxString>::~MxList<MxString>
// OFFSET: LEGO1 0x100cbb40 TEMPLATE
// MxList<MxString>::Append
// OFFSET: LEGO1 0x100cc2d0 TEMPLATE
// MxList<MxString>::_InsertEntry
// OFFSET: LEGO1 0x100cc3c0 TEMPLATE
// MxListEntry<MxString>::MxListEntry<MxString>
// OFFSET: LEGO1 0x100cc450 TEMPLATE
// MxListEntry<MxString>::GetValue
#endif // MXSTRINGLIST_H

View File

@ -33,8 +33,14 @@ typedef unsigned int MxULong;
typedef MxS32 MxTime;
typedef MxLong MxResult;
const MxResult SUCCESS = 0;
const MxResult FAILURE = -1;
#ifndef SUCCESS
#define SUCCESS 0
#endif
#ifndef FAILURE
#define FAILURE -1
#endif
typedef MxU8 MxBool;

View File

@ -17,8 +17,8 @@ class MxVariableTable : public MxHashTable<MxVariable*> {
// OFFSET: LEGO1 0x100afdb0
static void Destroy(MxVariable* p_obj) { p_obj->Destroy(); }
virtual MxS8 Compare(MxVariable*, MxVariable*) override; // +0x14
virtual MxU32 Hash(MxVariable*) override; // +0x18
virtual MxS8 Compare(MxVariable*, MxVariable*) override; // vtable+0x14
virtual MxU32 Hash(MxVariable*) override; // vtable+0x18
};
// OFFSET: LEGO1 0x100afcd0 TEMPLATE

View File

@ -1,12 +1,14 @@
#include "mxvideopresenter.h"
#include "mxautolocker.h"
#include "mxdsmediaaction.h"
#include "mxvideomanager.h"
DECOMP_SIZE_ASSERT(MxVideoPresenter, 0x64);
DECOMP_SIZE_ASSERT(MxVideoPresenter::AlphaMask, 0xc);
// OFFSET: LEGO1 0x1000c700
void MxVideoPresenter::VTable0x5c(undefined4 p_unknown1)
void MxVideoPresenter::VTable0x5c(MxStreamChunk* p_chunk)
{
// Empty
}
@ -18,7 +20,7 @@ void MxVideoPresenter::VTable0x60()
}
// OFFSET: LEGO1 0x1000c720
void MxVideoPresenter::VTable0x68(undefined4 p_unknown1)
void MxVideoPresenter::VTable0x68(MxStreamChunk* p_chunk)
{
// Empty
}
@ -232,10 +234,20 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor)
MxMediaPresenter::Destroy(FALSE);
}
// OFFSET: LEGO1 0x100b28b0 STUB
// OFFSET: LEGO1 0x100b28b0
void MxVideoPresenter::VTable0x64()
{
// TODO
MxStreamChunk* chunk = NextChunk();
if (chunk->GetFlags() & MxStreamChunk::Flag_Bit2) {
m_subscriber->FUN_100b8390(chunk);
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Repeating;
}
else {
VTable0x68(chunk);
m_subscriber->FUN_100b8390(chunk);
}
}
// OFFSET: LEGO1 0x100b2900
@ -306,6 +318,175 @@ void MxVideoPresenter::VTable0x6c()
// TODO
}
// OFFSET: LEGO1 0x100b2f60
void MxVideoPresenter::ReadyTickle()
{
MxStreamChunk* chunk = NextChunk();
if (chunk) {
VTable0x5c(chunk);
m_subscriber->FUN_100b8390(chunk);
ParseExtra();
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Starting;
}
}
// OFFSET: LEGO1 0x100b2fa0
void MxVideoPresenter::StartingTickle()
{
MxStreamChunk* chunk = FUN_100b5650();
if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) {
VTable0x60();
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Streaming;
}
}
// OFFSET: LEGO1 0x100b2fe0
void MxVideoPresenter::StreamingTickle()
{
if (m_action->GetFlags() & MxDSAction::Flag_Bit9) {
if (!m_currentChunk)
MxMediaPresenter::StreamingTickle();
if (m_currentChunk) {
VTable0x68(m_currentChunk);
m_currentChunk = NULL;
}
}
else {
for (MxS16 i = 0; i < m_unk5c; i++) {
if (!m_currentChunk) {
MxMediaPresenter::StreamingTickle();
if (!m_currentChunk)
break;
}
if (m_action->GetElapsedTime() < m_currentChunk->GetTime())
break;
VTable0x68(m_currentChunk);
m_subscriber->FUN_100b8390(m_currentChunk);
m_currentChunk = NULL;
m_flags |= Flag_Bit1;
if (m_currentTickleState != TickleState_Streaming)
break;
}
if (m_flags & Flag_Bit1)
m_unk5c = 5;
}
}
// OFFSET: LEGO1 0x100b3080
void MxVideoPresenter::RepeatingTickle()
{
if (IsEnabled()) {
if (m_action->GetFlags() & MxDSAction::Flag_Bit9) {
if (!m_currentChunk)
MxMediaPresenter::RepeatingTickle();
if (m_currentChunk) {
VTable0x68(m_currentChunk);
m_currentChunk = NULL;
}
}
else {
for (MxS16 i = 0; i < m_unk5c; i++) {
if (!m_currentChunk) {
MxMediaPresenter::RepeatingTickle();
if (!m_currentChunk)
break;
}
if (m_action->GetElapsedTime() % m_action->GetLoopCount() < m_currentChunk->GetTime())
break;
VTable0x68(m_currentChunk);
m_currentChunk = NULL;
m_flags |= Flag_Bit1;
if (m_currentTickleState != TickleState_Repeating)
break;
}
if (m_flags & Flag_Bit1)
m_unk5c = 5;
}
}
}
// OFFSET: LEGO1 0x100b3130
void MxVideoPresenter::Unk5Tickle()
{
MxLong sustainTime = ((MxDSMediaAction*) m_action)->GetSustainTime();
if (sustainTime != -1) {
if (sustainTime) {
if (m_unk60 == -1)
m_unk60 = m_action->GetElapsedTime();
if (m_action->GetElapsedTime() >= m_unk60 + ((MxDSMediaAction*) m_action)->GetSustainTime()) {
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Done;
}
}
else {
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Done;
}
}
}
// OFFSET: LEGO1 0x100b31a0
MxResult MxVideoPresenter::AddToManager()
{
MxResult result = FAILURE;
if (MVideoManager()) {
result = SUCCESS;
MVideoManager()->AddPresenter(*this);
}
return result;
}
// OFFSET: LEGO1 0x100b31d0
void MxVideoPresenter::EndAction()
{
if (m_action) {
MxMediaPresenter::EndAction();
MxAutoLocker lock(&m_criticalSection);
if (m_bitmap) {
MxLong height = m_bitmap->GetBmiHeightAbs();
MxLong width = m_bitmap->GetBmiWidth();
MxS32 x = m_location.m_x;
MxS32 y = m_location.m_y;
MxRect32 rect(x, y, x + width, y + height);
MVideoManager()->InvalidateRect(rect);
}
}
}
// OFFSET: LEGO1 0x100b3280
undefined4 MxVideoPresenter::PutData()
{
MxAutoLocker lock(&m_criticalSection);
if (IsEnabled() && m_currentTickleState >= TickleState_Streaming && m_currentTickleState <= TickleState_unk5)
VTable0x6c();
return 0;
}
// OFFSET: LEGO1 0x100b3300
undefined MxVideoPresenter::VTable0x74()
{

View File

@ -6,10 +6,14 @@
#include "mxmediapresenter.h"
// VTABLE 0x100d4be8
// SIZE 0x64
class MxVideoPresenter : public MxMediaPresenter {
public:
MxVideoPresenter() { Init(); }
enum {
Flag_Bit1 = 0x01,
};
MxVideoPresenter() { Init(); }
virtual ~MxVideoPresenter() override; // vtable+0x0
// OFFSET: LEGO1 0x1000c820
@ -28,13 +32,20 @@ class MxVideoPresenter : public MxMediaPresenter {
void Init();
void Destroy(MxBool p_fromDestructor);
virtual void Destroy() override; // vtable+0x38
virtual void ReadyTickle() override; // vtable+0x18
virtual void StartingTickle() override; // vtable+0x1c
virtual void StreamingTickle() override; // vtable+0x20
virtual void RepeatingTickle() override; // vtable+0x24
virtual void Unk5Tickle() override; // vtable+0x28
virtual MxResult AddToManager() override; // vtable+0x34
virtual void Destroy() override; // vtable+0x38
virtual void EndAction() override; // vtable+0x40
virtual undefined4 PutData() override; // vtable+0x4c
virtual MxBool IsHit(MxS32 p_x, MxS32 p_y) override; // vtable+0x50
virtual void VTable0x5c(undefined4 p_unknown1); // vtable+0x5c
virtual void VTable0x5c(MxStreamChunk* p_chunk); // vtable+0x5c
virtual void VTable0x60(); // vtable+0x60
virtual void VTable0x64(); // vtable+0x64
virtual void VTable0x68(undefined4 p_unknown1); // vtable+0x68
virtual void VTable0x68(MxStreamChunk* p_chunk); // vtable+0x68
virtual void VTable0x6c(); // vtable+0x6c
virtual void VTable0x70(); // vtable+0x70
virtual undefined VTable0x74(); // vtable+0x74
@ -56,12 +67,12 @@ class MxVideoPresenter : public MxMediaPresenter {
MxS32 IsHit(MxU32 p_x, MxU32 p_y);
};
MxBitmap* m_bitmap;
AlphaMask* m_alpha;
LPDIRECTDRAWSURFACE m_unk58;
undefined2 m_unk5c;
unsigned char m_flags; // 0x5e
MxLong m_unk60;
MxBitmap* m_bitmap; // 0x50
AlphaMask* m_alpha; // 0x54
LPDIRECTDRAWSURFACE m_unk58; // 0x58
MxS16 m_unk5c; // 0x5c
MxU8 m_flags; // 0x5e
MxLong m_unk60; // 0x60
};
#endif // MXVIDEOPRESENTER_H

180
LEGO1/realtime/lodlist.h Normal file
View File

@ -0,0 +1,180 @@
#ifndef LODLIST_H
#define LODLIST_H
#include "assert.h"
#include <stddef.h> // size_t
class LODObject;
// disable: identifier was truncated to '255' characters in the debug information
#pragma warning(disable : 4786)
//////////////////////////////////////////////////////////////////////////////
//
// LODListBase
//
// An LODListBase is an ordered list of LODObjects
// where each successive object in the list has a more complex
// geometric representation than the one preceeding it.
//
class LODListBase {
protected:
LODListBase(size_t capacity);
const LODObject* PushBack(const LODObject*);
const LODObject* PopBack();
public:
virtual ~LODListBase();
const LODObject* operator[](int) const;
// current number of LODObject* in LODListBase
size_t Size() const;
// maximum number of LODObject* LODListBase can hold
size_t Capacity() const;
#ifdef _DEBUG
virtual void Dump(void (*pTracer)(const char*, ...)) const;
#endif
private:
// not implemented
LODListBase(const LODListBase&);
LODListBase& operator=(const LODListBase&);
private:
const LODObject** m_ppLODObject;
size_t m_capacity;
size_t m_size;
};
//////////////////////////////////////////////////////////////////////////////
//
// LODList
//
template <class T>
class LODList : public LODListBase {
public:
LODList(size_t capacity);
const T* operator[](int) const;
const T* PushBack(const T*);
const T* PopBack();
};
//////////////////////////////////////////////////////////////////////////////
//
// LODListBase implementation
inline LODListBase::LODListBase(size_t capacity)
: m_capacity(capacity), m_size(0), m_ppLODObject(new const LODObject*[capacity])
{
#ifdef _DEBUG
int i;
for (i = 0; i < (int) m_capacity; i++) {
m_ppLODObject[i] = 0;
}
#endif
}
inline LODListBase::~LODListBase()
{
// all LODObject* should have been popped by client
assert(m_size == 0);
delete[] m_ppLODObject;
}
inline size_t LODListBase::Size() const
{
return m_size;
}
inline size_t LODListBase::Capacity() const
{
return m_capacity;
}
inline const LODObject* LODListBase::operator[](int i) const
{
assert((0 <= i) && (i < (int) m_size));
return m_ppLODObject[i];
}
inline const LODObject* LODListBase::PushBack(const LODObject* pLOD)
{
assert(m_size < m_capacity);
m_ppLODObject[m_size++] = pLOD;
return pLOD;
}
inline const LODObject* LODListBase::PopBack()
{
const LODObject* pLOD;
assert(m_size > 0);
pLOD = m_ppLODObject[--m_size];
#ifdef _DEBUG
m_ppLODObject[m_size] = 0;
#endif
return pLOD;
}
#ifdef _DEBUG
inline void LODListBase::Dump(void (*pTracer)(const char*, ...)) const
{
int i;
pTracer("LODListBase<0x%x>: Capacity=%d, Size=%d\n", (void*) this, m_capacity, m_size);
for (i = 0; i < (int) m_size; i++) {
pTracer(" [%d]: LOD<0x%x>\n", i, m_ppLODObject[i]);
}
for (i = (int) m_size; i < (int) m_capacity; i++) {
assert(m_ppLODObject[i] == 0);
}
}
#endif
//////////////////////////////////////////////////////////////////////////////
//
// LODList implementation
template <class T>
inline LODList<T>::LODList(size_t capacity) : LODListBase(capacity)
{
}
template <class T>
inline const T* LODList<T>::operator[](int i) const
{
return static_cast<const T*>(LODListBase::operator[](i));
}
template <class T>
inline const T* LODList<T>::PushBack(const T* pLOD)
{
return static_cast<const T*>(LODListBase::PushBack(pLOD));
}
template <class T>
inline const T* LODList<T>::PopBack()
{
return static_cast<const T*>(LODListBase::PopBack());
}
// re-enable: identifier was truncated to '255' characters in the debug information
#pragma warning(default : 4786)
#endif // LODLIST_H

View File

@ -1,137 +1,133 @@
#include "mxmatrix.h"
#include "matrix.h"
#include "decomp.h"
#include "../decomp.h"
#include "math.h"
#include <memory.h>
DECOMP_SIZE_ASSERT(MxMatrix, 0x8);
DECOMP_SIZE_ASSERT(MxMatrixData, 0x48);
// OFFSET: LEGO1 0x10002340
void MxMatrix::EqualsMxMatrix(const MxMatrix* p_other)
{
memcpy(m_data, p_other->m_data, 16 * sizeof(float));
}
DECOMP_SIZE_ASSERT(Matrix4, 0x40);
DECOMP_SIZE_ASSERT(Matrix4Impl, 0x8);
DECOMP_SIZE_ASSERT(Matrix4Data, 0x48);
// OFFSET: LEGO1 0x10002320
void MxMatrix::EqualsMatrixData(const float* p_matrix)
void Matrix4Impl::EqualsMatrixData(const Matrix4& p_matrix)
{
memcpy(m_data, p_matrix, 16 * sizeof(float));
*m_data = p_matrix;
}
// OFFSET: LEGO1 0x10002370
void MxMatrix::SetData(float* p_data)
// OFFSET: LEGO1 0x10002340
void Matrix4Impl::EqualsMatrixImpl(const Matrix4Impl* p_other)
{
m_data = p_data;
*m_data = *p_other->m_data;
}
// OFFSET: LEGO1 0x10002360
void MxMatrix::AnotherSetData(float* p_data)
void Matrix4Impl::AnotherSetData(Matrix4& p_data)
{
m_data = p_data;
m_data = &p_data;
}
// OFFSET: LEGO1 0x10002390
float* MxMatrix::GetData()
// OFFSET: LEGO1 0x10002370
void Matrix4Impl::SetData(Matrix4& p_data)
{
return m_data;
m_data = &p_data;
}
// OFFSET: LEGO1 0x10002380
const float* MxMatrix::GetData() const
const Matrix4* Matrix4Impl::GetData() const
{
return m_data;
}
// OFFSET: LEGO1 0x100023c0
float* MxMatrix::Element(int p_row, int p_col)
// OFFSET: LEGO1 0x10002390
Matrix4* Matrix4Impl::GetData()
{
return &m_data[p_row * 4 + p_col];
return m_data;
}
// OFFSET: LEGO1 0x100023a0
const float* MxMatrix::Element(int p_row, int p_col) const
const float* Matrix4Impl::Element(int p_row, int p_col) const
{
return &m_data[p_row * 4 + p_col];
return &(*m_data)[p_row][p_col];
}
// OFFSET: LEGO1 0x100023c0
float* Matrix4Impl::Element(int p_row, int p_col)
{
return &(*m_data)[p_row][p_col];
}
// OFFSET: LEGO1 0x100023e0
void MxMatrix::Clear()
void Matrix4Impl::Clear()
{
memset(m_data, 0, 16 * sizeof(float));
}
// OFFSET: LEGO1 0x100023f0
void MxMatrix::SetIdentity()
void Matrix4Impl::SetIdentity()
{
Clear();
m_data[0] = 1.0f;
m_data[5] = 1.0f;
m_data[10] = 1.0f;
m_data[15] = 1.0f;
}
// OFFSET: LEGO1 0x10002850
void MxMatrix::operator=(const MxMatrix& p_other)
{
EqualsMxMatrix(&p_other);
(*m_data)[0][0] = 1.0f;
(*m_data)[1][1] = 1.0f;
(*m_data)[2][2] = 1.0f;
(*m_data)[3][3] = 1.0f;
}
// OFFSET: LEGO1 0x10002430
MxMatrix* MxMatrix::operator+=(const float* p_matrix)
Matrix4Impl* Matrix4Impl::operator+=(const Matrix4& p_matrix)
{
for (int i = 0; i < 16; ++i)
m_data[i] += p_matrix[i];
((float*) m_data)[i] += ((float*) &p_matrix)[i];
return this;
}
// Matches but instructions are significantly out of order. Probably not wrong
// code given that the very similar SetTranslation does match.
// OFFSET: LEGO1 0x10002460
void MxMatrix::TranslateBy(const float* p_x, const float* p_y, const float* p_z)
void Matrix4Impl::TranslateBy(const float* p_x, const float* p_y, const float* p_z)
{
m_data[12] += *p_x;
m_data[13] += *p_y;
m_data[14] += *p_z;
((float*) m_data)[12] += *p_x;
((float*) m_data)[13] += *p_y;
((float*) m_data)[14] += *p_z;
}
// OFFSET: LEGO1 0x100024a0
void MxMatrix::SetTranslation(const float* p_x, const float* p_y, const float* p_z)
void Matrix4Impl::SetTranslation(const float* p_x, const float* p_y, const float* p_z)
{
m_data[12] = *p_x;
m_data[13] = *p_y;
m_data[14] = *p_z;
}
// OFFSET: LEGO1 0x10002530
void MxMatrix::EqualsMxProduct(const MxMatrix* p_a, const MxMatrix* p_b)
{
EqualsDataProduct(p_a->m_data, p_b->m_data);
(*m_data)[3][0] = *p_x;
(*m_data)[3][1] = *p_y;
(*m_data)[3][2] = *p_z;
}
// OFFSET: LEGO1 0x100024d0
void MxMatrix::EqualsDataProduct(const float* p_a, const float* p_b)
void Matrix4Impl::EqualsDataProduct(const Matrix4& p_a, const Matrix4& p_b)
{
float* cur = m_data;
float* cur = (float*) m_data;
for (int row = 0; row < 4; ++row) {
for (int col = 0; col < 4; ++col) {
*cur = 0.0f;
for (int k = 0; k < 4; ++k) {
*cur += p_a[row * 4 + k] * p_b[k * 4 + col];
*cur += p_a[row][k] * p_b[k][col];
}
cur++;
}
}
}
// OFFSET: LEGO1 0x10002530
void Matrix4Impl::EqualsMxProduct(const Matrix4Impl* p_a, const Matrix4Impl* p_b)
{
EqualsDataProduct(*p_a->m_data, *p_b->m_data);
}
// Not close, Ghidra struggles understinging this method so it will have to
// be manually worked out. Included since I at least figured out what it was
// doing with rotateIndex and what overall operation it's trying to do.
// OFFSET: LEGO1 0x10002550 STUB
void MxMatrix::ToQuaternion(MxVector4* p_outQuat)
void Matrix4Impl::ToQuaternion(Vector4Impl* p_outQuat)
{
/*
float trace = m_data[0] + m_data[5] + m_data[10];
if (trace > 0) {
trace = sqrt(trace + 1.0);
@ -166,18 +162,25 @@ void MxMatrix::ToQuaternion(MxVector4* p_outQuat)
p_outQuat->GetData()[3] = (m_data[next + 4 * nextNext] - m_data[nextNext + 4 * next]) * traceValue;
p_outQuat->GetData()[next] = (m_data[next + 4 * largest] + m_data[largest + 4 * next]) * traceValue;
p_outQuat->GetData()[nextNext] = (m_data[nextNext + 4 * largest] + m_data[largest + 4 * nextNext]) * traceValue;
*/
}
// No idea what this function is doing and it will be hard to tell until
// we have a confirmed usage site.
// OFFSET: LEGO1 0x10002710 STUB
MxResult MxMatrix::FUN_10002710(const MxVector3* p_vec)
int Matrix4Impl::FUN_10002710(const Vector3Impl* p_vec)
{
return FAILURE;
return -1;
}
// OFFSET: LEGO1 0x10002850
void Matrix4Impl::operator=(const Matrix4Impl& p_other)
{
EqualsMatrixImpl(&p_other);
}
// OFFSET: LEGO1 0x10002860
void MxMatrixData::operator=(const MxMatrixData& p_other)
void Matrix4Data::operator=(const Matrix4Data& p_other)
{
EqualsMxMatrix(&p_other);
EqualsMatrixImpl(&p_other);
}

91
LEGO1/realtime/matrix.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef MATRIX_H
#define MATRIX_H
#include "vector.h"
/*
* A simple array of four Vector4s that can be indexed into.
*/
class Matrix4 {
public:
float rows[4][4]; // storage is public for easy access
inline Matrix4() {}
/*
Matrix4(const Vector4& x_axis, const Vector4& y_axis, const Vector4& z_axis, const Vector4& position)
{
rows[0] = x_axis;
rows[1] = y_axis;
rows[2] = z_axis;
rows[3] = position;
}
Matrix4(const float m[4][4])
{
rows[0] = m[0];
rows[1] = m[1];
rows[2] = m[2];
rows[3] = m[3];
}
*/
const float* operator[](long i) const { return rows[i]; }
float* operator[](long i) { return rows[i]; }
};
// VTABLE 0x100d4350
// SIZE 0x8
class Matrix4Impl {
public:
inline Matrix4Impl(Matrix4& p_data) : m_data(&p_data) {}
// vtable + 0x00
virtual void EqualsMatrixImpl(const Matrix4Impl* p_other);
virtual void EqualsMatrixData(const Matrix4& p_matrix);
virtual void SetData(Matrix4& p_data);
virtual void AnotherSetData(Matrix4& p_data);
// vtable + 0x10
virtual Matrix4* GetData();
virtual const Matrix4* GetData() const;
virtual float* Element(int p_row, int p_col);
virtual const float* Element(int p_row, int p_col) const;
// vtable + 0x20
virtual void Clear();
virtual void SetIdentity();
virtual void operator=(const Matrix4Impl& p_other);
virtual Matrix4Impl* operator+=(const Matrix4& p_matrix);
// vtable + 0x30
virtual void TranslateBy(const float* p_x, const float* p_y, const float* p_z);
virtual void SetTranslation(const float* p_x, const float* p_y, const float* p_z);
virtual void EqualsMxProduct(const Matrix4Impl* p_a, const Matrix4Impl* p_b);
virtual void EqualsDataProduct(const Matrix4& p_a, const Matrix4& p_b);
// vtable + 0x40
virtual void ToQuaternion(Vector4Impl* p_resultQuat);
virtual int FUN_10002710(const Vector3Impl* p_vec);
inline float& operator[](size_t idx) { return ((float*) m_data)[idx]; }
protected:
// TODO: Currently unclear whether this class contains a Matrix4* or float*.
Matrix4* m_data;
};
// VTABLE 0x100d4300
// SIZE 0x48
class Matrix4Data : public Matrix4Impl {
public:
inline Matrix4Data() : Matrix4Impl(m_matrix) {}
inline Matrix4Data(Matrix4Data& p_other) : Matrix4Impl(m_matrix) { m_matrix = *p_other.m_data; }
inline Matrix4& GetMatrix() { return *m_data; }
// No idea why there's another equals. Maybe to some other type like the
// DirectX Retained Mode Matrix type which is also a float* alias?
// vtable + 0x44
virtual void operator=(const Matrix4Data& p_other);
Matrix4 m_matrix;
};
#endif // MATRIX_H

View File

@ -0,0 +1,68 @@
#include "orientableroi.h"
#include "../decomp.h"
DECOMP_SIZE_ASSERT(OrientableROI, 0xdc)
// OFFSET: LEGO1 0x100a5910
void OrientableROI::VTable0x1c()
{
UpdateWorldBoundingVolumes();
UpdateWorldVelocity();
}
// OFFSET: LEGO1 0x100a5930
void OrientableROI::SetLocalTransform(const Matrix4Impl& p_transform)
{
reinterpret_cast<Matrix4Impl&>(m_local2world) = p_transform;
UpdateWorldBoundingVolumes();
UpdateWorldVelocity();
}
// OFFSET: LEGO1 0x100a5960
void OrientableROI::VTable0x24(const Matrix4Data& p_transform)
{
Matrix4Data l_matrix(m_local2world);
m_local2world.EqualsMxProduct(&p_transform, &l_matrix);
UpdateWorldBoundingVolumes();
UpdateWorldVelocity();
}
// OFFSET: LEGO1 0x100a59b0
void OrientableROI::UpdateWorldData(const Matrix4Data& p_transform)
{
Matrix4Data l_matrix(m_local2world);
m_local2world.EqualsMxProduct(&l_matrix, &p_transform);
UpdateWorldBoundingVolumes();
UpdateWorldVelocity();
// iterate over comps
if (m_comp)
for (CompoundObject::iterator iter = m_comp->begin(); !(iter == m_comp->end()); iter++) {
ROI* child = *iter;
static_cast<OrientableROI*>(child)->UpdateWorldData(p_transform);
}
}
// OFFSET: LEGO1 0x100a5a50
void OrientableROI::UpdateWorldVelocity()
{
}
// OFFSET: LEGO1 0x100a5d80
const Vector3& OrientableROI::GetWorldVelocity() const
{
return (Vector3&) *m_world_velocity.GetData();
}
// OFFSET: LEGO1 0x100a5d90
const BoundingBox& OrientableROI::GetWorldBoundingBox() const
{
return m_world_bounding_box;
}
// OFFSET: LEGO1 0x100a5da0
const BoundingSphere& OrientableROI::GetWorldBoundingSphere() const
{
return m_world_bounding_sphere;
}

View File

@ -0,0 +1,49 @@
#ifndef ORIENTABLEROI_H
#define ORIENTABLEROI_H
#include "matrix.h"
#include "roi.h"
class OrientableROI : public ROI {
public:
// OFFSET: LEGO1 0x100a4420
OrientableROI()
{
FILLVEC3(m_world_bounding_box.Min(), 888888.8);
FILLVEC3(m_world_bounding_box.Max(), -888888.8);
ZEROVEC3(m_world_bounding_sphere.Center());
m_world_bounding_sphere.Radius() = 0.0;
ZEROVEC3(m_world_velocity);
IDENTMAT4(m_local2world.GetMatrix());
}
// OFFSET: LEGO1 0x100a4630 TEMPLATE
// OrientableROI::`scalar deleting destructor'
virtual const Vector3& GetWorldVelocity() const;
virtual const BoundingBox& GetWorldBoundingBox() const;
virtual const BoundingSphere& GetWorldBoundingSphere() const;
protected:
// vtable + 0x14
virtual void VTable0x14() { VTable0x1c(); }
virtual void UpdateWorldBoundingVolumes() = 0;
public:
virtual void VTable0x1c();
// vtable + 0x20
virtual void SetLocalTransform(const Matrix4Impl& p_transform);
virtual void VTable0x24(const Matrix4Data& p_transform);
virtual void UpdateWorldData(const Matrix4Data& p_transform);
virtual void UpdateWorldVelocity();
protected:
char m_unkc;
Matrix4Data m_local2world; // 0x10
BoundingBox m_world_bounding_box; // 0x58
BoundingSphere m_world_bounding_sphere; // 0xa8
Vector3Data m_world_velocity; // 0xc0
unsigned int m_unkd4;
unsigned int m_unkd8;
};
#endif // ORIENTABLEROI_H

View File

@ -2,19 +2,19 @@
// OFFSET: LEGO1 0x100a5b40
void CalcLocalTransform(
const MxVector3& p_posVec,
const MxVector3& p_dirVec,
const MxVector3& p_upVec,
MxMatrix& p_outMatrix
const Vector3Impl& p_posVec,
const Vector3Impl& p_dirVec,
const Vector3Impl& p_upVec,
Matrix4Impl& p_outMatrix
)
{
MxFloat x_axis[3], y_axis[3], z_axis[3];
float x_axis[3], y_axis[3], z_axis[3];
// This is an unrolled version of the "NORMVEC3" macro,
// used here to apply a silly hack to get a 100% match
{
const MxFloat dirVec1Operation = (p_dirVec)[1] * (p_dirVec)[1];
MxDouble len = sqrt(((p_dirVec)[0] * (p_dirVec)[0] + dirVec1Operation + (p_dirVec)[2] * (p_dirVec)[2]));
const float dirVec1Operation = (p_dirVec)[1] * (p_dirVec)[1];
double len = sqrt(((p_dirVec)[0] * (p_dirVec)[0] + dirVec1Operation + (p_dirVec)[2] * (p_dirVec)[2]));
((z_axis)[0] = (p_dirVec)[0] / (len), (z_axis)[1] = (p_dirVec)[1] / (len), (z_axis)[2] = (p_dirVec)[2] / (len));
}
@ -24,8 +24,8 @@ void CalcLocalTransform(
// Exact same thing as pointed out by the above comment
{
const MxFloat axis2Operation = (x_axis)[2] * (x_axis)[2];
MxDouble len = sqrt(((x_axis)[0] * (x_axis)[0] + axis2Operation + (x_axis)[1] * (x_axis)[1]));
const float axis2Operation = (x_axis)[2] * (x_axis)[2];
double len = sqrt(((x_axis)[0] * (x_axis)[0] + axis2Operation + (x_axis)[1] * (x_axis)[1]));
((x_axis)[0] = (x_axis)[0] / (len), (x_axis)[1] = (x_axis)[1] / (len), (x_axis)[2] = (x_axis)[2] / (len));
}
@ -33,8 +33,8 @@ void CalcLocalTransform(
// Again, the same thing
{
const MxFloat axis2Operation = (y_axis)[2] * (y_axis)[2];
MxDouble len = sqrt(((y_axis)[0] * (y_axis)[0] + axis2Operation + (y_axis)[1] * (y_axis)[1]));
const float axis2Operation = (y_axis)[2] * (y_axis)[2];
double len = sqrt(((y_axis)[0] * (y_axis)[0] + axis2Operation + (y_axis)[1] * (y_axis)[1]));
((y_axis)[0] = (y_axis)[0] / (len), (y_axis)[1] = (y_axis)[1] / (len), (y_axis)[2] = (y_axis)[2] / (len));
}

View File

@ -1,19 +1,19 @@
#ifndef REALTIME_H
#define REALTIME_H
#include "../mxmatrix.h"
#include "matrix.h"
#define NORMVEC3(dst, src) \
{ \
MxDouble len = sqrt(NORMSQRD3(src)); \
double len = sqrt(NORMSQRD3(src)); \
VDS3(dst, src, len); \
}
void CalcLocalTransform(
const MxVector3& p_posVec,
const MxVector3& p_dirVec,
const MxVector3& p_upVec,
MxMatrix& p_outMatrix
const Vector3Impl& p_posVec,
const Vector3Impl& p_dirVec,
const Vector3Impl& p_upVec,
Matrix4Impl& p_outMatrix
);
#endif // REALTIME_H

107
LEGO1/realtime/roi.h Normal file
View File

@ -0,0 +1,107 @@
#ifndef ROI_H
#define ROI_H
// ROI stands for Real-time Object Instance.
#include "../compat.h"
#include "../mxstl.h"
#include "../realtime/realtime.h"
#include "lodlist.h"
#include "vector.h"
/*
* A simple bounding box object with Min and Max accessor methods.
*/
class BoundingBox {
public:
const Vector3Data& Min() const { return min; }
Vector3Data& Min() { return min; }
const Vector3Data& Max() const { return max; }
Vector3Data& Max() { return max; }
private:
Vector3Data min;
Vector3Data max;
Vector3Data m_unk28;
Vector3Data m_unk3c;
};
/*
* A simple bounding sphere object with center and radius accessor methods.
*/
class BoundingSphere {
public:
const Vector3Data& Center() const { return center; }
Vector3Data& Center() { return center; }
const float& Radius() const { return radius; }
float& Radius() { return radius; }
private:
Vector3Data center;
float radius;
};
/*
* Abstract base class representing a single LOD version of
* a geometric object.
*/
class LODObject {
public:
// LODObject();
virtual ~LODObject() {}
virtual float Cost(float pixels_covered) const = 0;
virtual float AveragePolyArea() const = 0;
virtual int NVerts() const = 0;
};
/*
* A CompoundObject is simply a set of ROI objects which
* all together represent a single object with sub-parts.
*/
class ROI;
// typedef std::set<ROI*, std::less<const ROI*> > CompoundObject;
typedef list<ROI*> CompoundObject;
/*
* A ROIList is a list of ROI objects.
*/
typedef vector<const ROI*> ROIList;
/*
* A simple list of integers.
* Returned by RealtimeView::SelectLODs as indices into an ROIList.
*/
typedef vector<int> IntList;
class ROI {
public:
ROI()
{
m_comp = 0;
m_lods = 0;
}
virtual ~ROI()
{
// if derived class set the comp and lods, it should delete them
assert(!m_comp);
assert(!m_lods);
}
virtual float IntrinsicImportance() const = 0;
virtual const Vector3& GetWorldVelocity() const = 0;
virtual const BoundingBox& GetWorldBoundingBox() const = 0;
virtual const BoundingSphere& GetWorldBoundingSphere() const = 0;
const LODListBase* GetLODs() const { return m_lods; }
const LODObject* GetLOD(int i) const
{
assert(m_lods);
return (*m_lods)[i];
}
int GetLODCount() const { return m_lods ? m_lods->Size() : 0; }
const CompoundObject* GetComp() const { return m_comp; }
protected:
CompoundObject* m_comp;
LODListBase* m_lods;
};
#endif // ROI_H

View File

@ -1,183 +1,183 @@
#include "mxvector.h"
#include "vector.h"
#include "decomp.h"
#include "../decomp.h"
#include <math.h>
#include <memory.h>
DECOMP_SIZE_ASSERT(MxVector2, 0x8);
DECOMP_SIZE_ASSERT(MxVector3, 0x8);
DECOMP_SIZE_ASSERT(MxVector4, 0x8);
DECOMP_SIZE_ASSERT(MxVector3Data, 0x14);
DECOMP_SIZE_ASSERT(MxVector4Data, 0x18);
DECOMP_SIZE_ASSERT(Vector2Impl, 0x8);
DECOMP_SIZE_ASSERT(Vector3Impl, 0x8);
DECOMP_SIZE_ASSERT(Vector4Impl, 0x8);
DECOMP_SIZE_ASSERT(Vector3Data, 0x14);
DECOMP_SIZE_ASSERT(Vector4Data, 0x18);
// OFFSET: LEGO1 0x100020a0
const float* MxVector2::GetData() const
const float* Vector2Impl::GetData() const
{
return m_data;
}
// OFFSET: LEGO1 0x10002090
float* MxVector2::GetData()
float* Vector2Impl::GetData()
{
return m_data;
}
// OFFSET: LEGO1 0x10002130
float MxVector2::Dot(MxVector2* p_a, float* p_b) const
float Vector2Impl::Dot(Vector2Impl* p_a, float* p_b) const
{
return DotImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x10002110
float MxVector2::Dot(float* p_a, MxVector2* p_b) const
float Vector2Impl::Dot(float* p_a, Vector2Impl* p_b) const
{
return DotImpl(p_a, p_b->m_data);
}
// OFFSET: LEGO1 0x100020f0
float MxVector2::Dot(MxVector2* p_a, MxVector2* p_b) const
float Vector2Impl::Dot(Vector2Impl* p_a, Vector2Impl* p_b) const
{
return DotImpl(p_a->m_data, p_b->m_data);
}
// OFFSET: LEGO1 0x100020d0
float MxVector2::Dot(float* p_a, float* p_b) const
float Vector2Impl::Dot(float* p_a, float* p_b) const
{
return DotImpl(p_a, p_b);
}
// OFFSET: LEGO1 0x10002160
MxResult MxVector2::Unitize()
int Vector2Impl::Unitize()
{
float sq = LenSquared();
if (sq > 0.0f) {
float root = sqrt(sq);
if (root > 0) {
DivScalarImpl(&root);
return SUCCESS;
return 0;
}
}
return FAILURE;
return -1;
}
// OFFSET: LEGO1 0x100021e0
void MxVector2::AddVector(MxVector2* p_other)
void Vector2Impl::AddVector(Vector2Impl* p_other)
{
AddVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x100021d0
void MxVector2::AddVector(float* p_other)
void Vector2Impl::AddVector(float* p_other)
{
AddVectorImpl(p_other);
}
// OFFSET: LEGO1 0x100021c0
void MxVector2::AddScalar(float p_value)
void Vector2Impl::AddScalar(float p_value)
{
AddScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002200
void MxVector2::SubVector(MxVector2* p_other)
void Vector2Impl::SubVector(Vector2Impl* p_other)
{
SubVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x100021f0
void MxVector2::SubVector(float* p_other)
void Vector2Impl::SubVector(float* p_other)
{
SubVectorImpl(p_other);
}
// OFFSET: LEGO1 0x10002230
void MxVector2::MullScalar(float* p_value)
void Vector2Impl::MullScalar(float* p_value)
{
MullScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002220
void MxVector2::MullVector(MxVector2* p_other)
void Vector2Impl::MullVector(Vector2Impl* p_other)
{
MullVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10002210
void MxVector2::MullVector(float* p_other)
void Vector2Impl::MullVector(float* p_other)
{
MullVectorImpl(p_other);
}
// OFFSET: LEGO1 0x10002240
void MxVector2::DivScalar(float* p_value)
void Vector2Impl::DivScalar(float* p_value)
{
DivScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002260
void MxVector2::SetVector(MxVector2* p_other)
void Vector2Impl::SetVector(Vector2Impl* p_other)
{
EqualsImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10002250
void MxVector2::SetVector(float* p_other)
void Vector2Impl::SetVector(float* p_other)
{
EqualsImpl(p_other);
}
// OFFSET: LEGO1 0x10001fa0
void MxVector2::AddScalarImpl(float p_value)
void Vector2Impl::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
}
// OFFSET: LEGO1 0x10001f80
void MxVector2::AddVectorImpl(float* p_value)
void Vector2Impl::AddVectorImpl(float* p_value)
{
m_data[0] += p_value[0];
m_data[1] += p_value[1];
}
// OFFSET: LEGO1 0x10001fc0
void MxVector2::SubVectorImpl(float* p_value)
void Vector2Impl::SubVectorImpl(float* p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
}
// OFFSET: LEGO1 0x10002000
void MxVector2::MullScalarImpl(float* p_value)
void Vector2Impl::MullScalarImpl(float* p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
}
// OFFSET: LEGO1 0x10001fe0
void MxVector2::MullVectorImpl(float* p_value)
void Vector2Impl::MullVectorImpl(float* p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
}
// OFFSET: LEGO1 0x10002020
void MxVector2::DivScalarImpl(float* p_value)
void Vector2Impl::DivScalarImpl(float* p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
}
// OFFSET: LEGO1 0x10002040
float MxVector2::DotImpl(float* p_a, float* p_b) const
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 MxVector2::EqualsImpl(float* p_data)
void Vector2Impl::EqualsImpl(float* p_data)
{
float* vec = m_data;
vec[0] = p_data[0];
@ -185,7 +185,7 @@ void MxVector2::EqualsImpl(float* p_data)
}
// OFFSET: LEGO1 0x100020b0
void MxVector2::Clear()
void Vector2Impl::Clear()
{
float* vec = m_data;
vec[0] = 0.0f;
@ -193,13 +193,13 @@ void MxVector2::Clear()
}
// OFFSET: LEGO1 0x10002150
float MxVector2::LenSquared() const
float Vector2Impl::LenSquared() const
{
return m_data[0] * m_data[0] + m_data[1] * m_data[1];
}
// OFFSET: LEGO1 0x10003a90
void MxVector3::AddScalarImpl(float p_value)
void Vector3Impl::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
@ -207,7 +207,7 @@ void MxVector3::AddScalarImpl(float p_value)
}
// OFFSET: LEGO1 0x10003a60
void MxVector3::AddVectorImpl(float* p_value)
void Vector3Impl::AddVectorImpl(float* p_value)
{
m_data[0] += p_value[0];
m_data[1] += p_value[1];
@ -215,7 +215,7 @@ void MxVector3::AddVectorImpl(float* p_value)
}
// OFFSET: LEGO1 0x10003ac0
void MxVector3::SubVectorImpl(float* p_value)
void Vector3Impl::SubVectorImpl(float* p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
@ -223,7 +223,7 @@ void MxVector3::SubVectorImpl(float* p_value)
}
// OFFSET: LEGO1 0x10003b20
void MxVector3::MullScalarImpl(float* p_value)
void Vector3Impl::MullScalarImpl(float* p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
@ -231,7 +231,7 @@ void MxVector3::MullScalarImpl(float* p_value)
}
// OFFSET: LEGO1 0x10003af0
void MxVector3::MullVectorImpl(float* p_value)
void Vector3Impl::MullVectorImpl(float* p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
@ -239,7 +239,7 @@ void MxVector3::MullVectorImpl(float* p_value)
}
// OFFSET: LEGO1 0x10003b50
void MxVector3::DivScalarImpl(float* p_value)
void Vector3Impl::DivScalarImpl(float* p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
@ -247,13 +247,13 @@ void MxVector3::DivScalarImpl(float* p_value)
}
// OFFSET: LEGO1 0x10003b80
float MxVector3::DotImpl(float* p_a, float* p_b) const
float Vector3Impl::DotImpl(float* p_a, float* p_b) const
{
return p_a[0] * p_b[0] + p_a[2] * p_b[2] + p_a[1] * p_b[1];
}
// OFFSET: LEGO1 0x10003ba0
void MxVector3::EqualsImpl(float* p_data)
void Vector3Impl::EqualsImpl(float* p_data)
{
float* vec = m_data;
vec[0] = p_data[0];
@ -262,7 +262,7 @@ void MxVector3::EqualsImpl(float* p_data)
}
// OFFSET: LEGO1 0x10003bc0
void MxVector3::Clear()
void Vector3Impl::Clear()
{
float* vec = m_data;
vec[0] = 0.0f;
@ -271,13 +271,13 @@ void MxVector3::Clear()
}
// OFFSET: LEGO1 0x10003bd0
float MxVector3::LenSquared() const
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 MxVector3::EqualsCrossImpl(float* p_a, float* p_b)
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];
@ -285,25 +285,25 @@ void MxVector3::EqualsCrossImpl(float* p_a, float* p_b)
}
// OFFSET: LEGO1 0x10002300
void MxVector3::EqualsCross(float* p_a, MxVector3* p_b)
void Vector3Impl::EqualsCross(float* p_a, Vector3Impl* p_b)
{
EqualsCrossImpl(p_a, p_b->m_data);
}
// OFFSET: LEGO1 0x100022e0
void MxVector3::EqualsCross(MxVector3* p_a, float* p_b)
void Vector3Impl::EqualsCross(Vector3Impl* p_a, float* p_b)
{
EqualsCrossImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x100022c0
void MxVector3::EqualsCross(MxVector3* p_a, MxVector3* p_b)
void Vector3Impl::EqualsCross(Vector3Impl* p_a, Vector3Impl* p_b)
{
EqualsCrossImpl(p_a->m_data, p_b->m_data);
}
// OFFSET: LEGO1 0x10003bf0
void MxVector3::EqualsScalar(float* p_value)
void Vector3Impl::EqualsScalar(float* p_value)
{
m_data[0] = *p_value;
m_data[1] = *p_value;
@ -311,7 +311,7 @@ void MxVector3::EqualsScalar(float* p_value)
}
// OFFSET: LEGO1 0x100028b0
void MxVector4::AddScalarImpl(float p_value)
void Vector4Impl::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
@ -320,7 +320,7 @@ void MxVector4::AddScalarImpl(float p_value)
}
// OFFSET: LEGO1 0x10002870
void MxVector4::AddVectorImpl(float* p_value)
void Vector4Impl::AddVectorImpl(float* p_value)
{
m_data[0] += p_value[0];
m_data[1] += p_value[1];
@ -329,7 +329,7 @@ void MxVector4::AddVectorImpl(float* p_value)
}
// OFFSET: LEGO1 0x100028f0
void MxVector4::SubVectorImpl(float* p_value)
void Vector4Impl::SubVectorImpl(float* p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
@ -338,7 +338,7 @@ void MxVector4::SubVectorImpl(float* p_value)
}
// OFFSET: LEGO1 0x10002970
void MxVector4::MullScalarImpl(float* p_value)
void Vector4Impl::MullScalarImpl(float* p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
@ -347,7 +347,7 @@ void MxVector4::MullScalarImpl(float* p_value)
}
// OFFSET: LEGO1 0x10002930
void MxVector4::MullVectorImpl(float* p_value)
void Vector4Impl::MullVectorImpl(float* p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
@ -356,7 +356,7 @@ void MxVector4::MullVectorImpl(float* p_value)
}
// OFFSET: LEGO1 0x100029b0
void MxVector4::DivScalarImpl(float* p_value)
void Vector4Impl::DivScalarImpl(float* p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
@ -365,13 +365,13 @@ void MxVector4::DivScalarImpl(float* p_value)
}
// OFFSET: LEGO1 0x100029f0
float MxVector4::DotImpl(float* p_a, float* p_b) const
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 MxVector4::EqualsImpl(float* p_data)
void Vector4Impl::EqualsImpl(float* p_data)
{
float* vec = m_data;
vec[0] = p_data[0];
@ -381,7 +381,7 @@ void MxVector4::EqualsImpl(float* p_data)
}
// OFFSET: LEGO1 0x10002b00
void MxVector4::Clear()
void Vector4Impl::Clear()
{
float* vec = m_data;
vec[0] = 0.0f;
@ -391,13 +391,13 @@ void MxVector4::Clear()
}
// OFFSET: LEGO1 0x10002b20
float MxVector4::LenSquared() const
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 MxVector4::EqualsScalar(float* p_value)
void Vector4Impl::EqualsScalar(float* p_value)
{
m_data[0] = *p_value;
m_data[1] = *p_value;
@ -406,13 +406,13 @@ void MxVector4::EqualsScalar(float* p_value)
}
// OFFSET: LEGO1 0x10002ae0
void MxVector4::SetMatrixProduct(MxVector4* p_a, float* p_b)
void Vector4Impl::SetMatrixProduct(Vector4Impl* p_a, float* p_b)
{
SetMatrixProductImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x10002a40
void MxVector4::SetMatrixProductImpl(float* p_vec, float* p_mat)
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];
@ -423,7 +423,7 @@ void MxVector4::SetMatrixProductImpl(float* p_vec, float* p_mat)
// Note close yet, included because I'm at least confident I know what operation
// it's trying to do.
// OFFSET: LEGO1 0x10002b70 STUB
MxResult MxVector4::NormalizeQuaternion()
int Vector4Impl::NormalizeQuaternion()
{
float* v = m_data;
float magnitude = v[1] * v[1] + v[2] * v[2] + v[0] * v[0];
@ -435,16 +435,16 @@ MxResult MxVector4::NormalizeQuaternion()
v[0] *= magnitude;
v[1] *= magnitude;
v[2] *= magnitude;
return SUCCESS;
return 0;
}
return FAILURE;
return -1;
}
// OFFSET: LEGO1 0x10002bf0
void MxVector4::UnknownQuaternionOp(MxVector4* p_a, MxVector4* p_b)
void Vector4Impl::UnknownQuaternionOp(Vector4Impl* p_a, Vector4Impl* p_b)
{
MxFloat* bDat = p_b->m_data;
MxFloat* aDat = p_a->m_data;
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];

View File

@ -1,16 +1,67 @@
#ifndef MXVECTOR_H
#define MXVECTOR_H
#include "mxtypes.h"
#ifndef VECTOR_H
#define VECTOR_H
#include <vec.h>
/*
* A simple array of three floats that can be indexed into.
*/
class Vector3 {
public:
float elements[3]; // storage is public for easy access
Vector3() {}
Vector3(float x, float y, float z)
{
elements[0] = x;
elements[1] = y;
elements[2] = z;
}
Vector3(const float v[3])
{
elements[0] = v[0];
elements[1] = v[1];
elements[2] = v[2];
}
const float& operator[](long i) const { return elements[i]; }
float& operator[](long i) { return elements[i]; }
};
/*
* A simple array of four floats that can be indexed into.
*/
struct Vector4 {
public:
float elements[4]; // storage is public for easy access
inline Vector4() {}
Vector4(float x, float y, float z, float w)
{
elements[0] = x;
elements[1] = y;
elements[2] = z;
elements[3] = w;
}
Vector4(const float v[4])
{
elements[0] = v[0];
elements[1] = v[1];
elements[2] = v[2];
elements[3] = v[3];
}
const float& operator[](long i) const { return elements[i]; }
float& operator[](long i) { return elements[i]; }
};
// VTABLE 0x100d4288
// SIZE 0x8
class MxVector2 {
class Vector2Impl {
public:
// OFFSET: LEGO1 0x1000c0f0
inline MxVector2(float* p_data) { this->SetData(p_data); }
inline Vector2Impl(float* p_data) { this->SetData(p_data); }
// vtable + 0x00 (no virtual destructor)
virtual void AddScalarImpl(float p_value) = 0;
@ -28,37 +79,37 @@ class MxVector2 {
// vtable + 0x20
virtual void EqualsImpl(float* p_data) = 0;
virtual const float* GetData() const;
virtual float* GetData();
virtual const float* GetData() const;
virtual void Clear() = 0;
// vtable + 0x30
virtual float Dot(MxVector2* p_a, float* p_b) const;
virtual float Dot(float* p_a, MxVector2* p_b) const;
virtual float Dot(MxVector2* p_a, MxVector2* p_b) const;
virtual float Dot(Vector2Impl* p_a, float* p_b) const;
virtual float Dot(float* p_a, Vector2Impl* p_b) const;
virtual float Dot(Vector2Impl* p_a, Vector2Impl* p_b) const;
virtual float Dot(float* p_a, float* p_b) const;
// vtable + 0x40
virtual float LenSquared() const = 0;
virtual MxResult Unitize();
virtual int Unitize();
// vtable + 0x48
virtual void AddVector(MxVector2* p_other);
virtual void AddVector(Vector2Impl* p_other);
virtual void AddVector(float* p_other);
virtual void AddScalar(float p_value);
// vtable + 0x54
virtual void SubVector(MxVector2* p_other);
virtual void SubVector(Vector2Impl* p_other);
virtual void SubVector(float* p_other);
// vtable + 0x5C
virtual void MullScalar(float* p_value);
virtual void MullVector(MxVector2* p_other);
virtual void MullVector(Vector2Impl* p_other);
virtual void MullVector(float* p_other);
virtual void DivScalar(float* p_value);
// vtable + 0x6C
virtual void SetVector(MxVector2* p_other);
virtual void SetVector(Vector2Impl* p_other);
virtual void SetVector(float* p_other);
inline float& operator[](size_t idx) { return m_data[idx]; }
@ -70,9 +121,9 @@ class MxVector2 {
// VTABLE 0x100d4518
// SIZE 0x8
class MxVector3 : public MxVector2 {
class Vector3Impl : public Vector2Impl {
public:
inline MxVector3(float* p_data) : MxVector2(p_data) {}
inline Vector3Impl(float* p_data) : Vector2Impl(p_data) {}
void AddScalarImpl(float p_value);
@ -92,9 +143,9 @@ class MxVector3 : public MxVector2 {
// vtable + 0x74
virtual void EqualsCrossImpl(float* p_a, float* p_b);
virtual void EqualsCross(float* p_a, MxVector3* p_b);
virtual void EqualsCross(MxVector3* p_a, float* p_b);
virtual void EqualsCross(MxVector3* p_a, MxVector3* p_b);
virtual void EqualsCross(float* p_a, Vector3Impl* p_b);
virtual void EqualsCross(Vector3Impl* p_a, float* p_b);
virtual void EqualsCross(Vector3Impl* p_a, Vector3Impl* p_b);
virtual void EqualsScalar(float* p_value);
inline void Fill(float p_value) { EqualsScalar(&p_value); }
@ -102,9 +153,9 @@ class MxVector3 : public MxVector2 {
// VTABLE 0x100d45a0
// SIZE 0x8
class MxVector4 : public MxVector3 {
class Vector4Impl : public Vector3Impl {
public:
inline MxVector4(float* p_data) : MxVector3(p_data) {}
inline Vector4Impl(float* p_data) : Vector3Impl(p_data) {}
void AddScalarImpl(float p_value);
@ -125,53 +176,41 @@ class MxVector4 : public MxVector3 {
void EqualsScalar(float* p_value);
// vtable + 0x84
virtual void SetMatrixProduct(MxVector4* p_a, float* p_b);
virtual void SetMatrixProduct(Vector4Impl* p_a, float* p_b);
virtual void SetMatrixProductImpl(float* p_vec, float* p_mat);
virtual MxResult NormalizeQuaternion();
virtual void UnknownQuaternionOp(MxVector4* p_a, MxVector4* p_b);
virtual int NormalizeQuaternion();
virtual void UnknownQuaternionOp(Vector4Impl* p_a, Vector4Impl* p_b);
};
// VTABLE 0x100d4488
// SIZE 0x14
class MxVector3Data : public MxVector3 {
class Vector3Data : public Vector3Impl {
public:
inline MxVector3Data() : MxVector3(storage) {}
inline MxVector3Data(float p_x, float p_y, float p_z) : MxVector3(storage), x(p_x), y(p_y), z(p_z) {}
inline Vector3Data() : Vector3Impl(m_vector.elements) {}
inline Vector3Data(float p_x, float p_y, float p_z) : Vector3Impl(m_vector.elements), m_vector(p_x, p_y, p_z) {}
union {
float storage[3];
struct {
float x;
float y;
float z;
};
};
void CopyFrom(MxVector3Data& p_other)
void CopyFrom(Vector3Data& p_other)
{
EqualsImpl(p_other.m_data);
float* dest = this->storage;
float* src = p_other.storage;
for (size_t i = sizeof(storage) / sizeof(float); i > 0; --i)
float* dest = m_vector.elements;
float* src = p_other.m_vector.elements;
for (size_t i = sizeof(m_vector) / sizeof(float); i > 0; --i)
*dest++ = *src++;
}
private:
Vector3 m_vector;
};
// VTABLE 0x100d41e8
// SIZE 0x18
class MxVector4Data : public MxVector4 {
class Vector4Data : public Vector4Impl {
public:
inline MxVector4Data() : MxVector4(storage) {}
union {
float storage[4];
struct {
float x;
float y;
float z;
float w;
};
};
inline Vector4Data() : Vector4Impl(m_vector.elements) {}
private:
Vector4 m_vector;
};
#endif // MXVECTOR_H
#endif // VECTOR_H

View File

@ -74,7 +74,7 @@ MxBool Score::VTable0x5c()
}
// OFFSET: LEGO1 0x100012a0
MxResult Score::InitFromMxDSObject(MxDSObject& p_dsObject)
MxResult Score::Create(MxDSObject& p_dsObject)
{
MxResult result = SetAsCurrentWorld(p_dsObject);

View File

@ -29,13 +29,13 @@ class Score : public LegoWorld {
}
// OFFSET: LEGO1 0x100011e0 TEMPLATE
// Helicopter::`scalar deleting destructor'
// Score::`scalar deleting destructor'
virtual MxResult InitFromMxDSObject(MxDSObject& p_dsObject) override; // vtable+18
virtual void Stop() override; // vtable+50
virtual MxBool VTable0x5c() override; // vtable+5c
virtual MxBool VTable0x64() override; // vtable+64
virtual void VTable0x68(MxBool p_add) override; // vtable+68
virtual MxResult Create(MxDSObject& p_dsObject) override; // vtable+18
virtual void Stop() override; // vtable+50
virtual MxBool VTable0x5c() override; // vtable+5c
virtual MxBool VTable0x64() override; // vtable+64
virtual void VTable0x68(MxBool p_add) override; // vtable+68
void Paint();
MxLong FUN_10001510(MxEndActionNotificationParam& p);

365
LEGO1/tgl/tgl.h Normal file
View File

@ -0,0 +1,365 @@
#ifndef TGL_H
#define TGL_H
#ifdef _WIN32
#define NOMINMAX // to avoid conflict with STL
#include <d3d.h>
#include <ddraw.h>
#include <windows.h> // HWND
#endif /* _WIN32 */
#include "tglVector.h"
namespace Tgl
{
// ???
enum ColorModel {
Ramp,
RGB
};
// ???
enum ShadingModel {
Wireframe,
UnlitFlat,
Flat,
Gouraud,
Phong
};
// ?????
enum LightType {
Ambient,
Point,
Spot,
Directional,
ParallelPoint
};
// ???
enum ProjectionType {
Perspective,
Orthographic
};
enum TextureMappingMode {
Linear,
PerspectiveCorrect
};
struct PaletteEntry {
unsigned char m_red;
unsigned char m_green;
unsigned char m_blue;
};
#ifdef _WIN32
struct DeviceDirectDrawCreateData {
const GUID* m_driverGUID;
HWND m_hWnd; // ??? derive from m_pDirectDraw
IDirectDraw* m_pDirectDraw;
IDirectDrawSurface* m_pFrontBuffer; // ??? derive from m_pDirectDraw
IDirectDrawSurface* m_pBackBuffer;
IDirectDrawPalette* m_pPalette; // ??? derive from m_pDirectDraw
int m_isFullScreen; // ??? derive from m_pDirectDraw
};
struct DeviceDirect3DCreateData {
IDirect3D* m_pDirect3D;
IDirect3DDevice* m_pDirect3DDevice;
};
#else
struct DeviceDirectDrawCreateData {};
#endif
//////////////////////////////////////////////////////////////////////////////
//
// Result (return value type)
enum Result {
Error = 0,
Success = 1
};
inline int Succeeded(Result result)
{
return (result == Success);
}
//////////////////////////////////////////////////////////////////////////////
//
// Forward declarations
class Renderer;
class Object;
class Device;
class View;
class Light;
class Camera;
class Group;
class Mesh;
class Texture;
//////////////////////////////////////////////////////////////////////////////
//
// Object
class Object {
public:
virtual ~Object() {}
// returns pointer to implementation data
virtual void* ImplementationDataPtr() = 0;
};
//////////////////////////////////////////////////////////////////////////////
//
// Renderer
// ??? for now until we figured out how an app should pass the Renderer around
Renderer* CreateRenderer();
class Renderer : public Object {
public:
virtual Device* CreateDevice(const DeviceDirectDrawCreateData&) = 0;
virtual Device* CreateDevice(const DeviceDirect3DCreateData&) = 0;
virtual View* CreateView(
const Device*,
const Camera*,
unsigned long x,
unsigned long y,
unsigned long width,
unsigned long height
) = 0;
virtual Camera* CreateCamera() = 0;
virtual Light* CreateLight(LightType, double r, double g, double b) = 0;
virtual Group* CreateGroup(const Group* pParent = 0) = 0;
// pTextureCoordinates is pointer to array of vertexCount elements
// (each element being two floats), or NULL
// pFaceData is faceCount tuples, each of format
// [vertex1index, ... vertexNindex], where N = vertexPerFaceCount
virtual Mesh* CreateMesh(
unsigned long vertexCount,
const float (*pVertices)[3],
const float (*pTextureCoordinates)[2],
unsigned long faceCount,
unsigned long vertexPerFaceCount,
unsigned long* pFaceData
) = 0;
// pTextureCoordinates is pointer to array of vertexCount elements
// (each element being two floats), or NULL
// pFaceData is:
// [face1VertexCount face1Vertex1index, ... face1VertexMindex
// face2VertexCount face2Vertex1index, ... face2VertexNindex
// ...
// 0]
virtual Mesh* CreateMesh(
unsigned long vertexCount,
const float (*pVertices)[3],
const float (*pTextureCoordinates)[2],
unsigned long* pFaceData
) = 0;
virtual Texture* CreateTexture(
int width,
int height,
int bitsPerTexel,
const void* pTexels,
int pTexelsArePersistent,
int paletteEntryCount,
const PaletteEntry* pEntries
) = 0;
virtual Texture* CreateTexture() = 0;
virtual Result SetTextureDefaultShadeCount(unsigned long) = 0;
virtual Result SetTextureDefaultColorCount(unsigned long) = 0;
};
//////////////////////////////////////////////////////////////////////////////
//
// Device
class Device : public Object {
public:
virtual unsigned long GetWidth() = 0;
virtual unsigned long GetHeight() = 0;
virtual Result SetColorModel(ColorModel) = 0;
virtual Result SetShadingModel(ShadingModel) = 0;
virtual Result SetShadeCount(unsigned long) = 0;
virtual Result SetDither(int) = 0;
virtual Result Update() = 0;
// ??? should this be handled by app ???
// ??? this needs to be called when the window on which the device is ...
// is being activated
virtual void HandleActivate(int bActivate) = 0;
// ??? this needs to be called when the window on which this device is based
// needs to be repainted
virtual void HandlePaint(void*) = 0;
#ifdef _DEBUG
virtual unsigned long GetDrawnTriangleCount() = 0;
#endif
};
//////////////////////////////////////////////////////////////////////////////
//
// View
class View : public Object {
public:
virtual Result Add(const Light*) = 0;
virtual Result Remove(const Light*) = 0;
virtual Result SetCamera(const Camera*) = 0;
virtual Result SetProjection(ProjectionType) = 0;
virtual Result SetFrustrum(double frontClippingDistance, double backClippingDistance, double degrees) = 0;
virtual Result SetBackgroundColor(double r, double g, double b) = 0;
virtual Result Clear() = 0;
virtual Result Render(const Group*) = 0;
// ??? needed for fine grain control when using DirectDraw/D3D ???
virtual Result ForceUpdate(unsigned long x, unsigned long y, unsigned long width, unsigned long height) = 0;
// ??? for now: used by Mesh Cost calculation
virtual Result TransformWorldToScreen(const double world[3], double screen[4]) = 0;
// Pick():
// x, y:
// view coordinates
//
// ppGroupsToPickFrom:
// array of (Group*) in any order
// Groups to pick from
//
// groupsToPickFromCount:
// size of ppGroupsToPickFrom
//
// rppPickedGroups:
// output parameter
// array of (Group*) representing a Group hierarchy
// top-down order (element 0 is root/scene)
// caller must deallocate array
// ref count of each element (Group*) has not been increased
// an element will be 0, if a corresponding Group was not found in ppGroupsToPickFrom
//
// rPickedGroupCount:
// output parameter
// size of rppPickedGroups
virtual Result Pick(
unsigned long x,
unsigned long y,
const Group** ppGroupsToPickFrom,
int groupsToPickFromCount,
const Group**& rppPickedGroups,
int& rPickedGroupCount
) = 0;
};
//////////////////////////////////////////////////////////////////////////////
//
// Camera
class Camera : public Object {
public:
#if 0
virtual Result SetPosition(const double[3]) = 0;
virtual Result SetOrientation(const double direction[3],
const double up[3]) = 0;
#endif
virtual Result SetTransformation(const FloatMatrix4&) = 0;
};
//////////////////////////////////////////////////////////////////////////////
//
// Light
class Light : public Object {
public:
#if 0
virtual Result SetPosition(const double[3]) = 0;
virtual Result SetOrientation(const double direction[3],
const double up[3]) = 0;
#endif
virtual Result SetTransformation(const FloatMatrix4&) = 0;
};
//////////////////////////////////////////////////////////////////////////////
//
// Group
class Group : public Object {
public:
#if 0
virtual Result SetPosition(const double[3]) = 0;
virtual Result SetOrientation(const double direction[3],
const double up[3]) = 0;
#endif
// TODO: The type was changed from `FloatMatrix` to `Matrix` to make code in UpdateWorldData match.
// However, this is unlikely to be correct and will have to be figured out at some point.
virtual Result SetTransformation(const Matrix4&) = 0;
// ??? not yet fully implemented
virtual Result SetColor(double r, double g, double b) = 0;
virtual Result SetTexture(const Texture*) = 0;
virtual Result Add(const Group*) = 0;
virtual Result Add(const Mesh*) = 0;
virtual Result Remove(const Group*) = 0;
virtual Result Remove(const Mesh*) = 0;
virtual Result RemoveAll() = 0;
// ??? for now: used by Mesh Cost calculation
virtual Result TransformLocalToWorld(const double local[3], double world[3]) = 0;
};
//////////////////////////////////////////////////////////////////////////////
//
// Mesh
class Mesh : public Object {
public:
// ??? also on Group
virtual Result SetColor(double r, double g, double b) = 0;
virtual Result SetTexture(const Texture*) = 0;
virtual Result SetTextureMappingMode(TextureMappingMode) = 0;
virtual Result SetShadingModel(ShadingModel) = 0;
#ifdef _DEBUG
virtual Result GetBoundingBox(float min[3], float max[3]) = 0;
virtual unsigned long GetFaceCount() = 0;
virtual unsigned long GetVertexCount() = 0;
#endif
};
//////////////////////////////////////////////////////////////////////////////
//
// Texture
class Texture : public Object {
public:
virtual Result SetTexels(
int width,
int height,
int bitsPerTexel,
const void* pTexels,
int pTexelsArePersistent
) = 0;
virtual Result SetPalette(int entryCount, const PaletteEntry* pEntries) = 0;
};
//////////////////////////////////////////////////////////////////////////////
} // namespace Tgl
#endif // TGL_H

277
LEGO1/tgl/tglvector.h Normal file
View File

@ -0,0 +1,277 @@
#ifndef TGLVECTOR_H
#define TGLVECTOR_H
#include "math.h" // ??? sin() in RotateAroundY()
#include <stddef.h> // offsetof()
namespace Tgl
{
namespace Constant
{
const float Pi = 3.14159265358979323846;
};
inline float DegreesToRadians(float degrees)
{
return Constant::Pi * (degrees / 180.0);
}
inline float RadiansToDegrees(float radians)
{
return (radians / Constant::Pi) * 180.0;
}
//////////////////////////////////////////////////////////////////////////////
//
// Array<T, N>
template <class T, int N>
class Array {
public:
Array() {}
Array(const Array& rArray) { *this = rArray; }
~Array() {}
const T& operator[](int i) const { return m_elements[i]; };
T& operator[](int i) { return m_elements[i]; };
Array<T, N>& operator=(const Array<T, N>&);
void operator+=(const Array<T, N>&);
protected:
T m_elements[N];
};
//////////////////////////////////////////////////////////////////////////////
//
// Array<T, N> implementation
template <class T, int N>
inline Array<T, N>& Array<T, N>::operator=(const Array<T, N>& rArray)
{
int i;
for (i = 0; i < N; i++) {
m_elements[i] = rArray.m_elements[i];
}
return *this;
}
template <class T, int N>
inline void Array<T, N>::operator+=(const Array<T, N>& rArray)
{
int i;
for (i = 0; i < N; i++) {
m_elements[i] += rArray.m_elements[i];
}
}
//////////////////////////////////////////////////////////////////////////////
//
// FloatMatrix4
class FloatMatrix4 : public Array<Array<float, 4>, 4> {
public:
FloatMatrix4() {}
FloatMatrix4(const FloatMatrix4& rMatrix) { *this = rMatrix; }
FloatMatrix4(const FloatMatrix4&, const FloatMatrix4&);
void operator*=(const FloatMatrix4&);
};
//////////////////////////////////////////////////////////////////////////////
//
// FloatMatrix4 implementation
inline FloatMatrix4::FloatMatrix4(const FloatMatrix4& rMatrix1, const FloatMatrix4& rMatrix2)
{
for (int row = 0; row < 4; row++) {
for (int column = 0; column < 4; column++) {
float element = 0;
for (int i = 0; i < 4; i++) {
element += rMatrix1[row][i] * rMatrix2[i][column];
}
m_elements[row][column] = element;
}
}
}
inline void FloatMatrix4::operator*=(const FloatMatrix4& rMatrix)
{
FloatMatrix4 temp(*this, rMatrix);
// *this = FloatMatrix4(*this, rMatrix);
*this = temp;
}
//////////////////////////////////////////////////////////////////////////////
//
// Transformation matrices
class Translation : public FloatMatrix4 {
public:
Translation(const float[3]);
Translation(float x, float y, float z);
protected:
void Init(float x, float y, float z);
};
class Scale : public FloatMatrix4 {
public:
Scale(const float[3]);
Scale(float x, float y, float z);
Scale(float);
protected:
void Init(float x, float y, float z);
};
class RotationX : public FloatMatrix4 {
public:
RotationX(float radians);
};
class RotationY : public FloatMatrix4 {
public:
RotationY(float radians);
};
//////////////////////////////////////////////////////////////////////////////
//
// Transformation matrices implementation
inline Translation::Translation(const float vector[3])
{
Init(vector[0], vector[1], vector[2]);
}
inline Translation::Translation(float x, float y, float z)
{
Init(x, y, z);
}
inline void Translation::Init(float x, float y, float z)
{
m_elements[0][0] = 1;
m_elements[0][1] = 0;
m_elements[0][2] = 0;
m_elements[0][3] = 0;
m_elements[1][0] = 0;
m_elements[1][1] = 1;
m_elements[1][2] = 0;
m_elements[1][3] = 0;
m_elements[2][0] = 0;
m_elements[2][1] = 0;
m_elements[2][2] = 1;
m_elements[2][3] = 0;
m_elements[3][0] = x;
m_elements[3][1] = y;
m_elements[3][2] = z;
m_elements[3][3] = 1;
}
inline Scale::Scale(const float vector[3])
{
Init(vector[0], vector[1], vector[2]);
}
inline Scale::Scale(float x, float y, float z)
{
Init(x, y, z);
}
inline Scale::Scale(float scale)
{
Init(scale, scale, scale);
}
inline void Scale::Init(float x, float y, float z)
{
m_elements[0][0] = x;
m_elements[0][1] = 0;
m_elements[0][2] = 0;
m_elements[0][3] = 0;
m_elements[1][0] = 0;
m_elements[1][1] = y;
m_elements[1][2] = 0;
m_elements[1][3] = 0;
m_elements[2][0] = 0;
m_elements[2][1] = 0;
m_elements[2][2] = z;
m_elements[2][3] = 0;
m_elements[3][0] = 0;
m_elements[3][1] = 0;
m_elements[3][2] = 0;
m_elements[3][3] = 1;
}
inline RotationX::RotationX(float radians)
{
float cosRadians = cos(radians);
float sinRadians = sin(radians);
m_elements[0][0] = 1;
m_elements[0][1] = 0;
m_elements[0][2] = 0;
m_elements[0][3] = 0;
m_elements[1][0] = 0;
m_elements[1][1] = cosRadians;
m_elements[1][2] = -sinRadians;
m_elements[1][3] = 0;
m_elements[2][0] = 0;
m_elements[2][1] = sinRadians;
m_elements[2][2] = cosRadians;
m_elements[2][3] = 0;
m_elements[3][0] = 0;
m_elements[3][1] = 0;
m_elements[3][2] = 0;
m_elements[3][3] = 1;
}
inline RotationY::RotationY(float radians)
{
float cosRadians = cos(radians);
float sinRadians = sin(radians);
m_elements[0][0] = cosRadians;
m_elements[0][1] = 0;
m_elements[0][2] = sinRadians;
m_elements[0][3] = 0;
m_elements[1][0] = 0;
m_elements[1][1] = 1;
m_elements[1][2] = 0;
m_elements[1][3] = 0;
m_elements[2][0] = -sinRadians;
m_elements[2][1] = 0;
m_elements[2][2] = cosRadians;
m_elements[2][3] = 0;
m_elements[3][0] = 0;
m_elements[3][1] = 0;
m_elements[3][2] = 0;
m_elements[3][3] = 1;
}
//////////////////////////////////////////////////////////////////////////////
} // namespace Tgl
#endif // TLGVECTOR_H

View File

@ -0,0 +1,116 @@
#ifndef VIEWLODLIST_H
#define VIEWLODLIST_H
#include "../compat.h"
#include "../realtime/lodlist.h"
#include "assert.h"
#pragma warning(disable : 4786)
class ViewLOD;
class ViewLODListManager;
//////////////////////////////////////////////////////////////////////////////
// ViewLODList
//
// An ViewLODList is an LODList that is shared among instances of the "same ROI".
//
// ViewLODLists are managed (created and destroyed) by ViewLODListManager.
//
class ViewLODList : public LODList<ViewLOD> {
friend ViewLODListManager;
protected:
ViewLODList(size_t capacity);
~ViewLODList();
public:
inline int AddRef();
inline int Release();
#ifdef _DEBUG
void Dump(void (*pTracer)(const char*, ...)) const;
#endif
private:
int m_refCount;
ViewLODListManager* m_owner;
};
//////////////////////////////////////////////////////////////////////////////
//
// ??? for now, until we have symbol management
typedef const char* ROIName;
struct ROINameComparator {
bool operator()(const ROIName& rName1, const ROIName& rName2) const
{
return strcmp((const char*) rName1, (const char*) rName2) > 0;
}
};
//////////////////////////////////////////////////////////////////////////////
//
// ViewLODListManager
//
// ViewLODListManager manages creation and sharing of ViewLODLists.
// It stores ViewLODLists under a name, the name of the ROI where
// the ViewLODList belongs.
class ViewLODListManager {
typedef map<ROIName, ViewLODList*, ROINameComparator> ViewLODListMap;
public:
ViewLODListManager();
virtual ~ViewLODListManager();
// ??? should LODList be const
// creates an LODList with room for lodCount LODs for a named ROI
// returned LODList has a refCount of 1, i.e. caller must call Release()
// when it no longer holds on to the list
ViewLODList* Create(const ROIName&, int lodCount);
// returns an LODList for a named ROI
// returned LODList's refCount is increased, i.e. caller must call Release()
// when it no longer holds on to the list
ViewLODList* Lookup(const ROIName&) const;
void Destroy(ViewLODList* lodList);
#ifdef _DEBUG
void Dump(void (*pTracer)(const char*, ...)) const;
#endif
private:
ViewLODListMap m_map;
};
//////////////////////////////////////////////////////////////////////////////
//
// ViewLODList implementation
inline ViewLODList::ViewLODList(size_t capacity) : LODList<ViewLOD>(capacity), m_refCount(0)
{
}
inline ViewLODList::~ViewLODList()
{
assert(m_refCount == 0);
}
inline int ViewLODList::AddRef()
{
return ++m_refCount;
}
inline int ViewLODList::Release()
{
assert(m_refCount > 0);
if (!--m_refCount)
m_owner->Destroy(this);
return m_refCount;
}
#endif // VIEWLODLIST_H

View File

@ -0,0 +1,45 @@
#include "viewroi.h"
#include "../decomp.h"
DECOMP_SIZE_ASSERT(ViewROI, 0xe0)
// OFFSET: LEGO1 0x100a9eb0
float ViewROI::IntrinsicImportance() const
{
return .5;
} // for now
// OFFSET: LEGO1 0x100a9ec0
const Tgl::Group* ViewROI::GetGeometry() const
{
return geometry;
}
// OFFSET: LEGO1 0x100a9ed0
Tgl::Group* ViewROI::GetGeometry()
{
return geometry;
}
// OFFSET: LEGO1 0x100a9ee0
void ViewROI::UpdateWorldData(const Matrix4Data& parent2world)
{
OrientableROI::UpdateWorldData(parent2world);
if (geometry) {
// Tgl::FloatMatrix4 tgl_mat;
Matrix4 mat;
SETMAT4(mat, m_local2world.GetMatrix());
Tgl::Result result = geometry->SetTransformation(mat);
// assert(Tgl::Succeeded(result));
}
}
// OFFSET: LEGO1 0x100aa250 TEMPLATE
// ViewROI::`scalar deleting destructor'
inline ViewROI::~ViewROI()
{
// SetLODList() will decrease refCount of LODList
SetLODList(0);
delete geometry;
}

View File

@ -0,0 +1,47 @@
#ifndef VIEWROI_H
#define VIEWROI_H
#include "../realtime/orientableroi.h"
#include "../tgl/tgl.h"
#include "viewlodlist.h"
/*
ViewROI objects represent view objects, collections of view objects,
etc. Basically, anything which can be placed in a scene and manipilated
by the view manager is a ViewROI.
*/
class ViewROI : public OrientableROI {
public:
inline ViewROI(Tgl::Renderer* pRenderer, ViewLODList* lodList)
{
SetLODList(lodList);
geometry = pRenderer->CreateGroup();
}
inline ~ViewROI();
inline void SetLODList(ViewLODList* lodList)
{
// ??? inherently type unsafe - kind of... because, now, ROI
// does not expose SetLODs() ...
// solution: create pure virtual LODListBase* ROI::GetLODList()
// and let derived ROI classes hold the LODList
if (m_lods) {
reinterpret_cast<ViewLODList*>(m_lods)->Release();
}
m_lods = lodList;
if (m_lods) {
reinterpret_cast<ViewLODList*>(m_lods)->AddRef();
}
}
virtual float IntrinsicImportance() const;
virtual Tgl::Group* GetGeometry();
virtual const Tgl::Group* GetGeometry() const;
protected:
Tgl::Group* geometry;
void UpdateWorldData(const Matrix4Data& parent2world);
};
#endif // VIEWROI_H

View File

@ -14,6 +14,7 @@
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,
description='Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.')
@ -529,50 +530,38 @@ def can_resolve_register_differences(original_asm, new_asm):
htmlinsert.append(f'{{address: "0x{addr:x}", name: "{html.escape(recinfo.name)}", matching: {effective_ratio}, diff: "{escaped}"}}')
def gen_html(html_path, data):
templatedata = None
with open(get_file_in_script_dir('template.html')) as templatefile:
templatedata = templatefile.read()
def gen_html(html_file, data):
output_data = Renderer().render_path(get_file_in_script_dir('template.html'),
{
"data": ','.join(data)
}
)
templatedata = templatedata.replace('/* INSERT DATA HERE */', ','.join(data), 1)
with open(html_path, 'w') as htmlfile:
htmlfile.write(templatedata)
with open(html_file, 'w') as htmlfile:
htmlfile.write(output_data)
def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy):
templatedata = None
with open(get_file_in_script_dir('template.svg')) as templatefile:
templatedata = templatefile.read()
def gen_svg(svg_file, name_svg, icon, svg_implemented_funcs, total_funcs, raw_accuracy):
icon_data = None
if icon:
with open(icon, 'rb') as iconfile:
icon_data = base64.b64encode(iconfile.read()).decode('utf-8')
# TODO: Use templating engine (e.g. pystache)
# Replace icon
if args.svg_icon:
with open(args.svg_icon, 'rb') as iconfile:
templatedata = templatedata.replace('{icon}', base64.b64encode(iconfile.read()).decode('utf-8'), 1)
# Replace name
templatedata = templatedata.replace('{name}', name, 1)
# Replace implemented statistic
templatedata = templatedata.replace('{implemented}', f'{(implemented_funcs / total_funcs * 100):.2f}% ({implemented_funcs}/{total_funcs})', 1)
# Replace accuracy statistic
templatedata = templatedata.replace('{accuracy}', f'{(raw_accuracy / implemented_funcs * 100):.2f}%', 1)
# Generate progress bar width
total_statistic = raw_accuracy / total_funcs
percenttemplate = '{progbar'
percentstart = templatedata.index(percenttemplate)
percentend = templatedata.index('}', percentstart)
progwidth = float(templatedata[percentstart + len(percenttemplate) + 1:percentend]) * total_statistic
templatedata = templatedata[0:percentstart] + str(progwidth) + templatedata[percentend + 1:]
full_percentbar_width = 127.18422
output_data = Renderer().render_path(get_file_in_script_dir('template.svg'),
{
"name": name_svg,
"icon": icon_data,
"implemented": f'{(svg_implemented_funcs / total_funcs * 100):.2f}% ({svg_implemented_funcs}/{total_funcs})',
"accuracy": f'{(raw_accuracy / svg_implemented_funcs * 100):.2f}%',
"progbar": total_statistic * full_percentbar_width,
"percent": f'{(total_statistic * 100):.2f}%',
}
)
with open(svg_file, 'w') as svgfile:
svgfile.write(output_data)
# Replace percentage statistic
templatedata = templatedata.replace('{percent}', f'{(total_statistic * 100):.2f}%', 2)
with open(svg, 'w') as svgfile:
svgfile.write(templatedata)
if html_path:
gen_html(html_path, htmlinsert)

View File

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

View File

@ -75,7 +75,7 @@
}
</style>
<script>
var data = [/* INSERT DATA HERE */];
var data = [{{{data}}}];
function formatAsm(asm) {
var lines = asm.split('\n');

View File

@ -37,7 +37,7 @@
<clipPath
id="progBarCutoff">
<rect
width="{progbar:127.18422}"
width="{{progbar}}"
height="8.6508904"
x="21.118132"
y="134.05507"
@ -50,7 +50,7 @@
height="53.066437"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
xlink:href="data:image/png;base64,{icon}"
xlink:href="data:image/png;base64,{{icon}}"
id="image1060"
x="58.13345"
y="51.967873" /><text
@ -62,7 +62,7 @@
id="tspan738"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:monospace;-inkscape-font-specification:mono;text-align:center;text-anchor:middle;stroke:#000000;stroke-width:1.25161812;stroke-opacity:1;stroke-dasharray:none;paint-order:stroke fill markers"
x="84.666656"
y="118.35877">{name}</tspan></text><g
y="118.35877">{{name}}</tspan></text><g
id="g1250"
transform="translate(-0.04358834,8.1397473)"><rect
style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.50324;stroke-dasharray:none;stroke-opacity:1"
@ -85,7 +85,7 @@
style="font-size:4.23333px;fill:#ffffff;fill-opacity:1;stroke-width:1.05833"
x="76.884926"
y="139.89182"
id="tspan2150">{percent}</tspan></text><rect
id="tspan2150">{{percent}}</tspan></text><rect
style="display:inline;fill:#ffffff;stroke:none;stroke-width:2.6764"
id="rect1169"
width="127.18422"
@ -103,7 +103,7 @@
style="font-size:4.23333px;fill:#000000;fill-opacity:1;stroke-width:1.05833"
x="76.884926"
y="139.89182"
id="tspan16">{percent}</tspan></text></g><text
id="tspan16">{{percent}}</tspan></text></g><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.23333px;font-family:monospace;-inkscape-font-specification:mono;text-align:start;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.83441208;stroke-dasharray:none;stroke-opacity:1;opacity:1;stroke-linejoin:miter;stroke-linecap:butt;paint-order:stroke fill markers"
x="46.947659"
@ -112,8 +112,8 @@
id="tspan1258"
style="font-size:4.23333px;stroke-width:0.83441208;stroke:#000000;stroke-opacity:1;stroke-dasharray:none;stroke-linejoin:miter;stroke-linecap:butt;paint-order:stroke fill markers"
x="46.947659"
y="129.67447">Implemented: {implemented}</tspan><tspan
y="129.67447">Implemented: {{implemented}}</tspan><tspan
style="font-size:4.23333px;stroke-width:0.83441208;stroke:#000000;stroke-opacity:1;stroke-dasharray:none;stroke-linejoin:miter;stroke-linecap:butt;paint-order:stroke fill markers"
x="46.947659"
y="134.96613"
id="tspan1262">Accuracy: {accuracy}</tspan></text></g></svg>
id="tspan1262">Accuracy: {{accuracy}}</tspan></text></g></svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB