Implement LegoCarBuildAnimPresenter::StreamingTickle() (#1109)

* Implement LegoCarBuildAnimPresenter::StreamingTickle and dependents

* Fix naming issue

* Address review comment

---------

Co-authored-by: jonschz <jonschz@users.noreply.github.com>
This commit is contained in:
jonschz 2024-10-06 01:20:45 +02:00 committed by GitHub
parent e6474b7fcd
commit 1a15981324
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 216 additions and 15 deletions

View file

@ -45,7 +45,11 @@ class LegoCarBuildAnimPresenter : public LegoAnimPresenter {
void EndAction() override; // vtable+0x40
void PutFrame() override; // vtable+0x6c
void FUN_10079050(MxS16 p_index);
void FUN_10079090(LegoChar* p_param1, LegoChar* p_param2);
void FUN_10079160();
void FUN_100795d0(LegoChar* p_param);
void FUN_10079680(LegoChar* p_param);
void RotateAroundYAxis(MxFloat p_angle);
MxBool FUN_10079c30(const LegoChar* p_name);
MxBool FUN_10079ca0(const LegoChar* p_name);
@ -77,7 +81,9 @@ class LegoCarBuildAnimPresenter : public LegoAnimPresenter {
LegoEntity* m_unk0x140; // 0x140
MxS32 m_unk0x144; // 0x144
MxS32 m_unk0x148; // 0x148
undefined* m_unk0x14c; // 0x14c
// name verified by BETA10 0x10070d63
LegoChar* m_mainSourceId; // 0x14c
};
#endif // LEGOCARBUILDPRESENTER_H

View file

@ -43,6 +43,7 @@ void FUN_1003dde0(LegoROI* p_param1, MxFloat p_param2);
MxBool FUN_1003ded0(MxFloat p_param1[2], MxFloat p_param2[3], MxFloat p_param3[3]);
MxBool TransformWorldToScreen(const MxFloat p_world[3], MxFloat p_screen[4]);
MxS16 CountTotalTreeNodes(LegoTreeNode* p_node);
LegoTreeNode* GetTreeNode(LegoTreeNode* p_node, MxU32 p_index);
void FUN_1003e050(LegoAnimPresenter* p_presenter);
Extra::ActionType MatchActionString(const char*);
void InvokeAction(Extra::ActionType p_actionId, const MxAtomId& p_pAtom, MxS32 p_targetEntityId, LegoEntity* p_sender);

View file

@ -53,7 +53,9 @@ class LegoVideoManager : public MxVideoManager {
// FUNCTION: BETA10 0x100117e0
Lego3DManager* Get3DManager() { return m_3dManager; }
// FUNCTION: BETA10 0x1003a380
LegoROI* GetViewROI() { return m_viewROI; }
MxDirect3D* GetDirect3D() { return m_direct3d; }
MxBool GetRender3D() { return m_render3d; }
double GetElapsedSeconds() { return m_elapsedSeconds; }

View file

@ -1,7 +1,13 @@
#include "legocarbuildpresenter.h"
#include "3dmanager/lego3dmanager.h"
#include "legoentity.h"
#include "legogamestate.h"
#include "legoutils.h"
#include "legovideomanager.h"
#include "misc.h"
#include "mxautolock.h"
#include "realtime/realtime.h"
DECOMP_SIZE_ASSERT(LegoCarBuildAnimPresenter::UnknownListEntry, 0x0c)
DECOMP_SIZE_ASSERT(LegoCarBuildAnimPresenter, 0x150)
@ -23,7 +29,7 @@ LegoCarBuildAnimPresenter::LegoCarBuildAnimPresenter()
m_unk0x140 = NULL;
m_unk0x144 = -1;
m_unk0x148 = -1;
m_unk0x14c = NULL;
m_mainSourceId = NULL;
}
// FUNCTION: LEGO1 0x10078500
@ -47,8 +53,8 @@ LegoCarBuildAnimPresenter::~LegoCarBuildAnimPresenter()
m_unk0xc8.GetRoot()->SetNumChildren(0);
*m_unk0xc8.GetRoot()->GetChildren() = NULL;
if (m_unk0x14c) {
delete m_unk0x14c;
if (m_mainSourceId) {
delete[] m_mainSourceId;
}
}
@ -65,11 +71,103 @@ void LegoCarBuildAnimPresenter::ReadyTickle()
// TODO
}
// STUB: LEGO1 0x100789e0
// STUB: BETA10 0x10070cdd
// FUNCTION: LEGO1 0x100789e0
// FUNCTION: BETA10 0x10070cdd
void LegoCarBuildAnimPresenter::StreamingTickle()
{
// TODO
if (!m_unk0x140->GetROI()) {
return;
}
m_mainSourceId = new LegoChar[strlen(m_action->GetAtomId().GetInternal()) + 1];
assert(m_mainSourceId);
strcpy(m_mainSourceId, m_action->GetAtomId().GetInternal());
m_mainSourceId[strlen(m_mainSourceId) - 1] = 'M';
FUN_10079160();
if (GameState()->GetCurrentAct() == LegoGameState::e_act2) {
m_unk0xc0 = 10;
}
MxS16 i;
for (i = 0; i < m_unk0xbe; i++) {
if (m_unk0xc0 == i) {
FUN_10079680(m_unk0x128[i].m_unk0x04);
}
else {
FUN_100795d0(m_unk0x128[i].m_unk0x04);
}
if (i < m_unk0xc0) {
FUN_10079050(i);
FUN_10079680(m_unk0x128[i].m_unk0x00);
}
LegoChar* name = m_unk0x128[i].m_unk0x04;
if (name) {
for (MxS32 j = 0; j <= m_roiMapSize; j++) {
LegoROI* roi = m_roiMap[j];
if (roi && roi->GetName() && (strcmpi(name, roi->GetName()) == 0)) {
roi->FUN_100a9dd0();
roi->FUN_100a9350("lego red");
}
}
}
}
LegoVideoManager* videoManager = VideoManager();
assert(videoManager); // verifies variable name 'videoManager'
Lego3DView* lego3dview = videoManager->Get3DManager()->GetLego3DView();
LegoROI* videoManagerROI = videoManager->GetViewROI();
LegoROI* local60 = m_unk0x140->GetROI();
LegoROI* camera = NULL;
MxFloat fov;
MxS16 totalNodes = CountTotalTreeNodes(m_anim->GetRoot());
for (i = 0; i < totalNodes; i++) {
LegoAnimNodeData* animNodeData = (LegoAnimNodeData*) GetTreeNode(m_anim->GetRoot(), i)->GetData();
if (strnicmp(animNodeData->GetName(), "CAM", strlen("CAM")) == 0) {
camera = local60->FindChildROI(animNodeData->GetName(), local60);
fov = atof(&animNodeData->GetName()[strlen(animNodeData->GetName()) - 2]);
break;
}
}
assert(camera); // verifies variable name 'camera'
LegoROI* targetROI = local60->FindChildROI("TARGET", local60);
Mx3DPointFloat dirVec;
Vector3 cameraPosition(camera->GetWorldPosition());
Vector3 upVec(camera->GetWorldUp());
Vector3 targetPosition(targetROI->GetWorldPosition());
MxMatrix localTransform;
dirVec[0] = targetPosition[0] - cameraPosition[0];
dirVec[1] = targetPosition[1] - cameraPosition[1];
dirVec[2] = targetPosition[2] - cameraPosition[2];
dirVec.Unitize();
CalcLocalTransform(cameraPosition, dirVec, upVec, localTransform);
videoManagerROI->WrappedSetLocalTransform(localTransform);
lego3dview->Moved(*videoManagerROI);
videoManager->Get3DManager()->SetFrustrum(fov, 0.1, 250.0);
m_unk0xe0 = local60->FindChildROI("VIEW", local60)->GetLocal2World();
m_previousTickleStates |= 1 << m_currentTickleState;
m_currentTickleState = e_repeating;
}
// FUNCTION: LEGO1 0x10078db0
@ -83,13 +181,43 @@ void LegoCarBuildAnimPresenter::EndAction()
}
}
// FUNCTION: LEGO1 0x10079050
// FUNCTION: BETA10 0x1007151e
void LegoCarBuildAnimPresenter::FUN_10079050(MxS16 p_index)
{
FUN_10079090(m_unk0x128[p_index].m_unk0x04, m_unk0x128[p_index].m_unk0x00);
FUN_100795d0(m_unk0x128[p_index].m_unk0x04);
}
// STUB: LEGO1 0x10079090
// STUB: BETA10 0x10071584
void LegoCarBuildAnimPresenter::FUN_10079090(LegoChar* p_param1, LegoChar* p_param2)
{
// TODO
}
// STUB: LEGO1 0x10079160
// STUB: BETA10 0x1007165d
void LegoCarBuildAnimPresenter::FUN_10079160()
{
// called from LegoCarBuildAnimPresenter::StreamingTickle()
// TODO
}
// STUB: LEGO1 0x100795d0
// STUB: BETA10 0x10071d96
void LegoCarBuildAnimPresenter::FUN_100795d0(LegoChar* p_param)
{
// TODO
}
// STUB: LEGO1 0x10079680
// STUB: BETA10 0x10071ec5
void LegoCarBuildAnimPresenter::FUN_10079680(LegoChar* p_param)
{
// TODO
}
// FUNCTION: LEGO1 0x10079920
// FUNCTION: BETA10 0x1007225d
void LegoCarBuildAnimPresenter::RotateAroundYAxis(MxFloat p_angle)

View file

@ -106,6 +106,7 @@ MxBool TransformWorldToScreen(const MxFloat p_world[3], MxFloat p_screen[4])
}
// FUNCTION: LEGO1 0x1003df90
// FUNCTION: BETA10 0x100d39a3
MxS16 CountTotalTreeNodes(LegoTreeNode* p_node)
{
MxS16 result = 1;
@ -118,6 +119,7 @@ MxS16 CountTotalTreeNodes(LegoTreeNode* p_node)
}
// FUNCTION: LEGO1 0x1003dfd0
// FUNCTION: BETA10 0x100d3a09
LegoTreeNode* GetTreeNode(LegoTreeNode* p_node, MxU32 p_index)
{
LegoTreeNode* result = NULL;

View file

@ -213,6 +213,7 @@ Mx3DPointFloat LegoEntity::GetWorldUp()
}
// FUNCTION: LEGO1 0x10010d80
// FUNCTION: BETA10 0x1007ebbe
Mx3DPointFloat LegoEntity::GetWorldPosition()
{
if (m_roi != NULL) {

View file

@ -380,6 +380,7 @@ void LegoWorld::AddPath(LegoPathController* p_controller)
}
// FUNCTION: LEGO1 0x10020020
// FUNCTION: BETA10 0x100da77c
LegoPathBoundary* LegoWorld::FindPathBoundary(const char* p_name)
{
LegoPathControllerListCursor cursor(&m_list0x68);

View file

@ -97,6 +97,7 @@ double Lego3DManager::Render(double p_und)
}
// FUNCTION: LEGO1 0x100ab4d0
// FUNCTION: BETA10 0x1017baeb
int Lego3DManager::SetFrustrum(float p_fov, float p_front, float p_back)
{
m_pLego3DView->GetView()->SetFrustrum(p_front, p_back, p_fov);

View file

@ -119,6 +119,7 @@ BOOL Lego3DView::SetPointOfView(ViewROI& rROI)
}
// FUNCTION: LEGO1 0x100ab210
// FUNCTION: BETA10 0x1017d230
BOOL Lego3DView::Moved(ViewROI& rROI)
{
assert(m_pViewManager);

View file

@ -148,7 +148,9 @@ class LegoAnimNodeData : public LegoTreeNodeData {
LegoResult CreateLocalTransform(LegoFloat p_time, Matrix4& p_matrix);
LegoBool FUN_100a0990(LegoFloat p_time);
// FUNCTION: BETA10 0x100595d0
const LegoChar* GetName() { return m_name; }
LegoU32 GetTranslationIndex() { return m_translationIndex; }
LegoU32 GetRotationIndex() { return m_rotationIndex; }
LegoU32 GetScaleIndex() { return m_scaleIndex; }
@ -164,6 +166,8 @@ class LegoAnimNodeData : public LegoTreeNodeData {
void SetScaleIndex(LegoU32 p_scaleIndex) { m_scaleIndex = p_scaleIndex; }
void SetMorphIndex(LegoU32 p_morphIndex) { m_morphIndex = p_morphIndex; }
void SetUnknown0x20(LegoU16 p_unk0x20) { m_unk0x20 = p_unk0x20; }
// FUNCTION: BETA10 0x1005f2e0
void SetUnknown0x22(LegoU16 p_unk0x22) { m_unk0x22 = p_unk0x22; }
LegoResult CreateLocalTransform(LegoTime p_time, Matrix4& p_matrix)

View file

@ -32,14 +32,21 @@ class LegoTreeNode {
public:
LegoTreeNode();
virtual ~LegoTreeNode();
// FUNCTION: BETA10 0x100595a0
LegoTreeNodeData* GetData() { return m_data; }
void SetData(LegoTreeNodeData* p_data) { m_data = p_data; }
// FUNCTION: BETA10 0x10012150
LegoU32 GetNumChildren() { return m_numChildren; }
// FUNCTION: BETA10 0x10073370
void SetNumChildren(LegoU32 p_numChildren) { m_numChildren = p_numChildren; }
// FUNCTION: BETA10 0x10012180
LegoTreeNode* GetChild(LegoU32 p_i) { return m_children[p_i]; }
void SetChild(LegoU32 p_i, LegoTreeNode* p_child) { m_children[p_i] = p_child; }
// FUNCTION: BETA10 0x100733a0

View file

@ -341,6 +341,7 @@ LegoResult LegoROI::FUN_100a8cb0(LegoAnimNodeData* p_data, LegoTime p_time, Matr
}
// FUNCTION: LEGO1 0x100a8ce0
// FUNCTION: BETA10 0x1018a815
LegoROI* LegoROI::FindChildROI(const LegoChar* p_name, LegoROI* p_roi)
{
CompoundObject::iterator it;
@ -551,6 +552,18 @@ LegoResult LegoROI::GetTexture(LegoTextureInfo*& p_textureInfo)
return FAILURE;
}
// FUNCTION: LEGO1 0x100a9350
// FUNCTION: BETA10 0x1018b25c
LegoResult LegoROI::FUN_100a9350(const LegoChar* p_color)
{
MxFloat red, green, blue, alpha;
if (ColorAliasLookup(p_color, red, green, blue, alpha)) {
return FUN_100a9170(red, green, blue, alpha);
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100a9410
// FUNCTION: BETA10 0x1018b324
LegoU32 LegoROI::FUN_100a9410(
@ -778,6 +791,13 @@ void LegoROI::SetName(const LegoChar* p_name)
}
}
// STUB: LEGO1 0x100a9dd0
// STUB: BETA10 0x1018bfdb
void LegoROI::FUN_100a9dd0()
{
// TODO
}
// FUNCTION: LEGO1 0x100a9e10
void LegoROI::SetDisplayBB(int p_displayBB)
{

View file

@ -38,12 +38,14 @@ class LegoROI : public ViewROI {
LegoResult FUN_100a9170(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha);
LegoResult FUN_100a9210(LegoTextureInfo* p_textureInfo);
LegoResult GetTexture(LegoTextureInfo*& p_textureInfo);
LegoResult FUN_100a9350(const LegoChar* p_color);
LegoU32 FUN_100a9410(Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3, LegoBool p_collideBox);
void SetName(const LegoChar* p_name);
float IntrinsicImportance() const override; // vtable+0x04
void UpdateWorldBoundingVolumes() override; // vtable+0x18
void FUN_100a9dd0();
void SetDisplayBB(int p_displayBB);
static LegoResult FUN_100a8cb0(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix);

View file

@ -482,6 +482,7 @@
// __setmode_lk
// LIBRARY: LEGO1 0x100d1ed0
// LIBRARY: BETA10 0x1018ec70
// _strnicmp
// LIBRARY: LEGO1 0x100d1fd0
@ -682,6 +683,9 @@
// LIBRARY: BETA10 0x100f9780
// strlen
// LIBRARY: BETA10 0x100fa200
// strcpy
// LIBRARY: BETA10 0x100f8a88
// operator new
@ -703,6 +707,9 @@
// LIBRARY: BETA10 0x100fe5a0
// abort
// LIBRARY: BETA10 0x100fa0e0
// atof
// LIBRARY: BETA10 0x100ff82b
// __ctrandisp1

View file

@ -6,10 +6,15 @@
#include "realtime/vector.h"
// VTABLE: LEGO1 0x100d4488
// VTABLE: BETA10 0x101b84d0
// SIZE 0x14
class Mx3DPointFloat : public Vector3 {
public:
// FUNCTION: LEGO1 0x1001d170
// FUNCTION: BETA10 0x10011990
Mx3DPointFloat() : Vector3(m_elements) {}
// FUNCTION: BETA10 0x10011870
Mx3DPointFloat(float p_x, float p_y, float p_z) : Vector3(m_elements)
{
m_elements[0] = p_x;
@ -24,9 +29,6 @@ class Mx3DPointFloat : public Vector3 {
// FUNCTION: BETA10 0x100151e0
Mx3DPointFloat(const Vector3& p_other) : Vector3(m_elements) { EqualsImpl(p_other.m_data); }
// SYNTHETIC: LEGO1 0x1001d170
// Mx3DPointFloat::Mx3DPointFloat
// FUNCTION: LEGO1 0x10003c10
virtual void operator=(const Vector3& p_impl) { EqualsImpl(p_impl.m_data); } // vtable+0x88
@ -34,7 +36,9 @@ class Mx3DPointFloat : public Vector3 {
float GetY() { return m_data[1]; }
float GetZ() { return m_data[2]; }
// FUNCTION: BETA10 0x10013460
float& operator[](int idx) { return m_data[idx]; }
const float& operator[](int idx) const { return m_data[idx]; }
// SYNTHETIC: LEGO1 0x10010c00

View file

@ -69,7 +69,9 @@ class MxDSObject : public MxCore {
// FUNCTION: BETA10 0x10017910
MxU32 GetObjectId() { return m_objectId; }
// FUNCTION: BETA10 0x10017940
const MxAtomId& GetAtomId() { return m_atomId; }
MxS16 GetUnknown24() { return m_unk0x24; }
MxPresenter* GetUnknown28() { return m_unk0x28; }

View file

@ -183,6 +183,7 @@ class Matrix4 {
};
// FUNCTION: LEGO1 0x10002550
// FUNCTION: BETA10 0x100101c0
inline void Matrix4::ToQuaternion(Vector4& p_outQuat)
{
float trace = m_data[0][0] + m_data[1][1] + m_data[2][2];
@ -223,6 +224,7 @@ inline void Matrix4::ToQuaternion(Vector4& p_outQuat)
}
// FUNCTION: LEGO1 0x10002710
// FUNCTION: BETA10 0x10010550
inline int Matrix4::FromQuaternion(const Vector4& p_vec)
{
float len = p_vec.LenSquared();

View file

@ -48,7 +48,9 @@ class OrientableROI : public ROI {
// FUNCTION: BETA10 0x10011780
const float* GetWorldDirection() const { return m_local2world[2]; }
// FUNCTION: BETA10 0x1004aa70
const float* GetWorldUp() const { return m_local2world[1]; }
OrientableROI* GetParentROI() const { return m_parentROI; }
void SetParentROI(OrientableROI* p_parentROI) { m_parentROI = p_parentROI; }

View file

@ -3,6 +3,7 @@
#include <vec.h>
// FUNCTION: LEGO1 0x100a5b40
// FUNCTION: BETA10 0x10168127
void CalcLocalTransform(const Vector3& p_posVec, const Vector3& p_dirVec, const Vector3& p_upVec, Matrix4& p_outMatrix)
{
float x_axis[3], y_axis[3], z_axis[3];

View file

@ -163,13 +163,18 @@ class Vector2 {
return *this;
}
// SYNTHETIC: BETA10 0x10013460
// Vector3::operator[]
// FUNCTION: BETA10 0x10010890
float& operator[](int idx) { return m_data[idx]; }
// There is another candidate for `Vector2::operator[]` at BETA10 0x10010890, which is called from only three
// functions in BETA10:
// - `Matrix4::FromQuaternion()`
// - `Matrix4::ToQuaternion()`
// - `UnknownMx4DPointFloat::FUN_100040a0()`
// Maybe there is another subclass of `Vector4` involved that has the same VTABLE but a different `operator[]`.
// It is also interesting that `Matrix4::operator[]` is located right above at BETA10 0x10010860.
// FUNCTION: BETA10 0x1001d140
float& operator[](int idx) { return m_data[idx]; }
// FUNCTION: BETA10 0x1001d170
const float& operator[](int idx) const { return m_data[idx]; }
protected:
@ -189,6 +194,8 @@ class Vector3 : public Vector2 {
// Example: LegoCameraController::GetWorldUp
// Vector3 however is a class that can mutate its underlying source, making
// initialization with a const source fundamentally incompatible.
// FUNCTION: BETA10 0x100109a0
Vector3(const float* p_data) : Vector2((float*) p_data) {}
// Note: virtual function overloads appear in the virtual table