#include "legoanimpresenter.h" #include "legoanimmmpresenter.h" #include "legocharactermanager.h" #include "legovideomanager.h" #include "legoworld.h" #include "misc.h" #include "mxcompositepresenter.h" #include "mxdsanim.h" #include "mxmisc.h" #include "mxstreamchunk.h" #include "mxtimer.h" #include "mxvideomanager.h" #include "realtime/realtime.h" DECOMP_SIZE_ASSERT(LegoAnimPresenter, 0xbc) // FUNCTION: LEGO1 0x10068420 LegoAnimPresenter::LegoAnimPresenter() { Init(); } // FUNCTION: LEGO1 0x10068670 LegoAnimPresenter::~LegoAnimPresenter() { Destroy(TRUE); } // FUNCTION: LEGO1 0x100686f0 void LegoAnimPresenter::Init() { m_anim = NULL; m_roiMap = NULL; m_roiMapSize = 0; m_unk0x74 = NULL; m_unk0x70 = NULL; m_unk0x78 = NULL; m_unk0x7c = 0; m_unk0xa8.Clear(); m_unk0xa4 = 0; m_currentWorld = NULL; m_unk0x95 = 0; m_unk0x88 = -1; m_unk0x98 = 0; m_animAtom.Clear(); m_unk0x9c = 0; m_unk0x8c = NULL; m_unk0x90 = NULL; m_unk0x94 = 0; m_unk0x96 = TRUE; m_unk0xa0 = 0; } // STUB: LEGO1 0x10068770 void LegoAnimPresenter::Destroy(MxBool p_fromDestructor) { // TODO MxVideoPresenter::Destroy(p_fromDestructor); } // FUNCTION: LEGO1 0x10068fb0 MxResult LegoAnimPresenter::CreateAnim(MxStreamChunk* p_chunk) { MxResult result = FAILURE; LegoMemory storage(p_chunk->GetData()); MxS32 magicSig; LegoS32 parseScene = 0; MxS32 val3; if (storage.Read(&magicSig, sizeof(magicSig)) != SUCCESS || magicSig != 0x11) { goto done; } if (storage.Read(&m_unk0xa4, sizeof(m_unk0xa4)) != SUCCESS) { goto done; } if (storage.Read(&m_unk0xa8[0], sizeof(m_unk0xa8[0])) != SUCCESS) { goto done; } if (storage.Read(&m_unk0xa8[1], sizeof(m_unk0xa8[1])) != SUCCESS) { goto done; } if (storage.Read(&m_unk0xa8[2], sizeof(m_unk0xa8[2])) != SUCCESS) { goto done; } if (storage.Read(&parseScene, sizeof(parseScene)) != SUCCESS) { goto done; } if (storage.Read(&val3, sizeof(val3)) != SUCCESS) { goto done; } m_anim = new LegoAnim(); if (!m_anim) { goto done; } if (m_anim->Read(&storage, parseScene) != SUCCESS) { goto done; } result = SUCCESS; done: if (result != SUCCESS) { delete m_anim; Init(); } return result; } // FUNCTION: LEGO1 0x10069150 LegoChar* LegoAnimPresenter::FUN_10069150(const LegoChar* p_und1) { LegoChar* str; if (LegoCharacterManager::Exists(p_und1 + 1)) { str = new LegoChar[strlen(p_und1)]; if (str != NULL) { strcpy(str, p_und1 + 1); } } else { LegoChar buffer[32]; sprintf(buffer, "%d", m_action->GetUnknown24()); str = new LegoChar[strlen(p_und1) + strlen(buffer) + strlen(GetActionObjectName()) + 1]; if (str != NULL) { strcpy(str, p_und1); strcat(str, buffer); strcat(str, GetActionObjectName()); } } return str; } // FUNCTION: LEGO1 0x100692b0 void LegoAnimPresenter::FUN_100692b0() { m_unk0x74 = new LegoROIList(); if (m_unk0x74) { LegoU32 numActors = m_anim->GetNumActors(); for (LegoU32 i = 0; i < numActors; i++) { LegoChar* str = FUN_100697c0(m_anim->GetActorName(i), NULL); undefined4 unk0x04 = m_anim->GetActorUnknown0x04(i); LegoROI* roi = NULL; if (unk0x04 == 2) { LegoChar* src; if (str[0] == '*') { src = str + 1; } else { src = str; } roi = CharacterManager()->GetROI(src, TRUE); if (roi != NULL && str[0] == '*') { roi->SetVisibility(FALSE); } } else if (unk0x04 == 4) { LegoChar* baseName = new LegoChar[strlen(str)]; strcpy(baseName, str + 1); strlwr(baseName); LegoChar* und = FUN_10069150(str); roi = CharacterManager()->FUN_10085a80(und, baseName, TRUE); if (roi != NULL) { roi->SetVisibility(FALSE); } delete[] baseName; delete[] und; } else if (unk0x04 == 3) { LegoChar* lodName = new LegoChar[strlen(str)]; strcpy(lodName, str + 1); for (LegoChar* i = &lodName[strlen(lodName) - 1]; i > lodName; i--) { if ((*i < '0' || *i > '9') && *i != '_') { break; } *i = '\0'; } strlwr(lodName); LegoChar* und = FUN_10069150(str); roi = CharacterManager()->FUN_10085210(und, lodName, TRUE); if (roi != NULL) { roi->SetVisibility(FALSE); } delete[] lodName; delete[] und; } if (roi != NULL) { m_unk0x74->Append(roi); } delete[] str; } } } // FUNCTION: LEGO1 0x100695c0 void LegoAnimPresenter::FUN_100695c0() { m_unk0x70 = new LegoROIList(); if (m_unk0x70) { const CompoundObject& rois = VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->GetROIs(); LegoU32 numActors = m_anim->GetNumActors(); for (LegoU32 i = 0; i < numActors; i++) { if (FUN_100698b0(rois, m_anim->GetActorName(i)) == FALSE) { undefined4 unk0x04 = m_anim->GetActorUnknown0x04(i); if (unk0x04 == 5 || unk0x04 == 6) { LegoChar lodName[256]; const LegoChar* actorName = m_anim->GetActorName(i); LegoU32 len = strlen(actorName); strcpy(lodName, actorName); for (LegoChar* i = &lodName[len - 1]; isdigit(*i) || *i == '_'; i--) { *i = '\0'; } strlwr(lodName); CharacterManager()->FUN_10085210(actorName, lodName, FALSE); FUN_100698b0(rois, actorName); } } } } } // FUNCTION: LEGO1 0x100697c0 LegoChar* LegoAnimPresenter::FUN_100697c0(const LegoChar* p_und1, const LegoChar* p_und2) { const LegoChar* str = p_und1; const char* var = VariableTable()->GetVariable(p_und1); if (*var) { str = var; } LegoU32 len = strlen(str) + (p_und2 ? strlen(p_und2) : 0) + 2; LegoChar* result = new LegoChar[len]; if (result != NULL) { *result = '\0'; if (p_und2) { strcpy(result, p_und2); strcat(result, ":"); } strcat(result, str); } return result; } // FUNCTION: LEGO1 0x100698b0 LegoBool LegoAnimPresenter::FUN_100698b0(const CompoundObject& p_rois, const LegoChar* p_und2) { LegoBool result = FALSE; LegoChar* str; if (*(str = FUN_100697c0(p_und2, NULL)) == '*') { LegoChar* tmp = FUN_10069150(str); delete[] str; str = tmp; } if (str != NULL && *str != '\0' && p_rois.size() > 0) { for (CompoundObject::const_iterator it = p_rois.begin(); it != p_rois.end(); it++) { LegoROI* roi = (LegoROI*) *it; const char* name = roi->GetName(); if (name != NULL) { if (!strcmpi(name, str)) { m_unk0x70->Append(roi); result = TRUE; break; } } } } delete[] str; return result; } // FUNCTION: LEGO1 0x100699e0 LegoROI* LegoAnimPresenter::FUN_100699e0(const LegoChar* p_und) { LegoROIListCursor cursor(m_unk0x70); LegoROI* roi; while (cursor.Next(roi)) { LegoChar* und = FUN_100697c0(roi->GetName(), NULL); if (und != NULL && !strcmpi(und, p_und)) { delete[] und; return roi; } delete[] und; } return NULL; } // FUNCTION: LEGO1 0x10069b10 void LegoAnimPresenter::FUN_10069b10() { LegoAnimPresenterMap map; if (m_unk0x8c != NULL) { memset(m_unk0x8c, 0, m_unk0x94 * sizeof(*m_unk0x8c)); } FUN_1006a3c0(map, m_anim->GetRoot(), NULL); if (m_roiMap != NULL) { delete[] m_roiMap; m_roiMapSize = 0; } m_roiMapSize = 0; m_roiMap = new LegoROI*[map.size() + 1]; memset(m_roiMap, 0, (map.size() + 1) * sizeof(*m_roiMap)); for (LegoAnimPresenterMap::iterator it = map.begin(); it != map.end();) { MxU32 index = (*it).second.m_index; m_roiMap[index] = (*it).second.m_roi; if (m_roiMap[index]->GetName() != NULL) { for (MxS32 i = 0; i < m_unk0x94; i++) { if (m_unk0x8c[i] == NULL && m_unk0x90[i] != NULL) { if (!strcmpi(m_unk0x90[i], m_roiMap[index]->GetName())) { m_unk0x8c[i] = m_roiMap[index]; break; } } } } delete[] const_cast((*it).first); it++; m_roiMapSize++; } } // FUNCTION: LEGO1 0x1006a3c0 void LegoAnimPresenter::FUN_1006a3c0(LegoAnimPresenterMap& p_map, LegoTreeNode* p_node, LegoROI* p_roi) { LegoROI* roi = p_roi; LegoChar* und = NULL; LegoChar* und2 = NULL; LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); const LegoChar* name = data->GetName(); if (name != NULL && *name != '-') { if (*name == '*') { name = und2 = FUN_10069150(name); } und = FUN_100697c0(name, p_roi != NULL ? p_roi->GetName() : NULL); if (p_roi == NULL) { roi = FUN_100699e0(und); if (roi != NULL) { FUN_1006a4f0(p_map, data, und, roi); } else { data->SetUnknown0x20(0); } } else { LegoROI* child = p_roi->FindChildROI(name, p_roi); if (child != NULL) { FUN_1006a4f0(p_map, data, und, child); } else { if (FUN_100699e0(name) != NULL) { FUN_1006a3c0(p_map, p_node, NULL); delete[] und; delete[] und2; return; } } } } delete[] und; delete[] und2; MxS32 count = p_node->GetNumChildren(); for (MxS32 i = 0; i < count; i++) { FUN_1006a3c0(p_map, p_node->GetChild(i), roi); } } // FUNCTION: LEGO1 0x1006a4f0 void LegoAnimPresenter::FUN_1006a4f0( LegoAnimPresenterMap& p_map, LegoAnimNodeData* p_data, const LegoChar* p_und, LegoROI* p_roi ) { LegoAnimPresenterMap::iterator it; it = p_map.find(p_und); if (it == p_map.end()) { LegoAnimStruct animStruct; animStruct.m_index = p_map.size() + 1; animStruct.m_roi = p_roi; p_data->SetUnknown0x20(animStruct.m_index); LegoChar* und = new LegoChar[strlen(p_und) + 1]; strcpy(und, p_und); p_map[und] = animStruct; } else { p_data->SetUnknown0x20((*it).second.m_index); } } // FUNCTION: LEGO1 0x1006aba0 LegoBool LegoAnimPresenter::FUN_1006aba0() { return FUN_1006abb0(m_anim->GetRoot(), 0); } // FUNCTION: LEGO1 0x1006abb0 MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi) { MxBool result = FALSE; LegoROI* roi = p_roi; LegoChar* und = NULL; const LegoChar* name = ((LegoAnimNodeData*) p_node->GetData())->GetName(); MxS32 i, count; if (name != NULL && *name != '-') { und = FUN_100697c0(name, p_roi != NULL ? p_roi->GetName() : NULL); if (p_roi == NULL) { roi = FUN_100699e0(und); if (roi == NULL) { goto done; } } else { LegoROI* child = p_roi->FindChildROI(name, p_roi); if (child == NULL) { if (FUN_100699e0(name) != NULL) { if (FUN_1006abb0(p_node, NULL)) { result = TRUE; } } goto done; } } } count = p_node->GetNumChildren(); for (i = 0; i < count; i++) { if (!FUN_1006abb0(p_node->GetChild(i), roi)) { goto done; } } result = TRUE; done: if (und != NULL) { delete[] und; } return result; } // STUB: LEGO1 0x1006ac90 void LegoAnimPresenter::FUN_1006ac90() { // TODO } // FUNCTION: LEGO1 0x1006ad30 void LegoAnimPresenter::PutFrame() { if (m_currentTickleState == e_streaming) { MxLong time; if (m_action->GetStartTime() <= m_action->GetElapsedTime()) { time = m_action->GetElapsedTime() - m_action->GetStartTime(); } else { time = 0; } FUN_1006b9a0(m_anim, time, m_unk0x78); if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCamera() != NULL) { for (MxS32 i = 0; i < m_unk0x94; i++) { if (m_unk0x8c[i] != NULL) { MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); Vector3 pos(mat[0]); Vector3 dir(mat[1]); Vector3 up(mat[2]); Vector3 und(mat[3]); float possqr = sqrt(pos.LenSquared()); float dirsqr = sqrt(dir.LenSquared()); float upsqr = sqrt(up.LenSquared()); up = und; #ifdef COMPAT_MODE Mx3DPointFloat location = m_currentWorld->GetCamera()->GetWorldLocation(); ((Vector3&) up).Sub(&location); #else ((Vector3&) up).Sub(&m_currentWorld->GetCamera()->GetWorldLocation()); #endif ((Vector3&) dir).Div(dirsqr); pos.EqualsCross(&dir, &up); pos.Unitize(); up.EqualsCross(&pos, &dir); ((Vector3&) pos).Mul(possqr); ((Vector3&) dir).Mul(dirsqr); ((Vector3&) up).Mul(upsqr); m_unk0x8c[i]->FUN_100a58f0(mat); m_unk0x8c[i]->VTable0x14(); } } } } } // STUB: LEGO1 0x1006afc0 // FUNCTION: BETA10 0x1005059a MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*&, undefined4) { // TODO return SUCCESS; } // STUB: LEGO1 0x1006b140 // FUNCTION: BETA10 0x100507e0 MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) { // TODO return FAILURE; } // FUNCTION: LEGO1 0x1006b550 void LegoAnimPresenter::ReadyTickle() { m_currentWorld = CurrentWorld(); if (m_currentWorld) { MxStreamChunk* chunk = m_subscriber->PeekData(); if (chunk && chunk->GetTime() + m_action->GetStartTime() <= m_action->GetElapsedTime()) { chunk = m_subscriber->PopData(); MxResult result = CreateAnim(chunk); m_subscriber->FreeDataChunk(chunk); if (result == SUCCESS) { ProgressTickleState(e_starting); ParseExtra(); } else { EndAction(); } } } } // FUNCTION: LEGO1 0x1006b5e0 void LegoAnimPresenter::StartingTickle() { FUN_1006ac90(); FUN_100692b0(); FUN_100695c0(); if (m_unk0x7c & c_bit2 && !FUN_1006aba0()) { goto done; } FUN_10069b10(); FUN_1006c8a0(TRUE); if (m_unk0x78 == NULL) { if (fabs(m_action->GetDirection().GetX()) >= 0.00000047683716F || fabs(m_action->GetDirection().GetY()) >= 0.00000047683716F || fabs(m_action->GetDirection().GetZ()) >= 0.00000047683716F) { m_unk0x78 = new MxMatrix(); CalcLocalTransform(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), *m_unk0x78); } else if (m_roiMap != NULL) { LegoROI* roi = m_roiMap[1]; if (roi != NULL) { MxMatrix mat; mat = roi->GetLocal2World(); m_unk0x78 = new MxMatrix(mat); } } } if ((m_action->GetDuration() == -1 || ((MxDSMediaAction*) m_action)->GetSustainTime() == -1) && m_compositePresenter) { m_compositePresenter->VTable0x60(this); } else { m_action->SetUnknown90(Timer()->GetTime()); } ProgressTickleState(e_streaming); if (m_compositePresenter && m_compositePresenter->IsA("LegoAnimMMPresenter")) { m_unk0x96 = ((LegoAnimMMPresenter*) m_compositePresenter)->FUN_1004b8b0(); m_compositePresenter->VTable0x60(this); } VTable0x8c(); done: if (m_unk0x70 != NULL) { delete m_unk0x70; m_unk0x70 = NULL; } } // FUNCTION: LEGO1 0x1006b840 void LegoAnimPresenter::StreamingTickle() { if (m_subscriber->PeekData()) { MxStreamChunk* chunk = m_subscriber->PopData(); m_subscriber->FreeDataChunk(chunk); } if (m_unk0x95) { ProgressTickleState(e_done); if (m_compositePresenter) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { m_compositePresenter->VTable0x60(this); } } } else { if (m_action->GetElapsedTime() > m_anim->GetDuration() + m_action->GetStartTime()) { m_unk0x95 = 1; } } } // FUNCTION: LEGO1 0x1006b8c0 void LegoAnimPresenter::DoneTickle() { MxVideoPresenter::DoneTickle(); } // FUNCTION: LEGO1 0x1006b8d0 MxResult LegoAnimPresenter::AddToManager() { return MxVideoPresenter::AddToManager(); } // FUNCTION: LEGO1 0x1006b8e0 void LegoAnimPresenter::Destroy() { Destroy(FALSE); } // FUNCTION: LEGO1 0x1006b8f0 const char* LegoAnimPresenter::GetActionObjectName() { return m_action->GetObjectName(); } // FUNCTION: LEGO1 0x1006b9a0 void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) { LegoTreeNode* root = p_anim->GetRoot(); MxMatrix mat; LegoAnimNodeData* data = (LegoAnimNodeData*) root->GetData(); if (p_matrix != NULL) { mat = *p_matrix; } else { LegoROI* roi = m_roiMap[data->GetUnknown0x20()]; if (roi != NULL) { mat = roi->GetLocal2World(); } else { mat.SetIdentity(); } } if (p_anim->GetScene() != NULL) { MxMatrix transform(mat); p_anim->GetScene()->FUN_1009f490(p_time, transform); if (m_currentWorld != NULL && m_currentWorld->GetCamera() != NULL) { m_currentWorld->GetCamera()->FUN_100123e0(transform, 0); } } LegoROI::FUN_100a8e80(root, mat, p_time, m_roiMap); } // STUB: LEGO1 0x1006bac0 void LegoAnimPresenter::ParseExtra() { // TODO } // STUB: LEGO1 0x1006c570 void LegoAnimPresenter::VTable0xa0(Matrix4*) { // TODO } // FUNCTION: LEGO1 0x1006c620 MxResult LegoAnimPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) { MxResult result = MxVideoPresenter::StartAction(p_controller, p_action); m_displayZ = 0; return result; } // STUB: LEGO1 0x1006c640 void LegoAnimPresenter::EndAction() { if (m_action) { // TODO if (m_currentWorld) { m_currentWorld->Remove(this); } FUN_1006c8a0(FALSE); MxVideoPresenter::EndAction(); } } // FUNCTION: LEGO1 0x1006c7d0 void LegoAnimPresenter::VTable0x8c() { if (m_unk0x78) { m_unk0xa8.Add((*m_unk0x78)[3]); } else { m_unk0xa8.Add(&m_action->GetLocation()); } if (m_currentWorld == NULL) { m_currentWorld = m_unk0x88 != -1 ? FindWorld(m_animAtom, m_unk0x88) : CurrentWorld(); } if (m_currentWorld) { m_currentWorld->FUN_1001fda0(this); if (!m_compositePresenter || !m_compositePresenter->IsA("LegoAnimMMPresenter")) { m_currentWorld->Add(this); } } } // STUB: LEGO1 0x1006c860 void LegoAnimPresenter::VTable0x90() { // TODO } // FUNCTION: LEGO1 0x1006c8a0 void LegoAnimPresenter::FUN_1006c8a0(MxBool p_bool) { if (m_roiMapSize != 0 && m_roiMap != NULL) { for (MxU32 i = 1; i <= m_roiMapSize; i++) { LegoEntity* entity = m_roiMap[i]->GetEntity(); if (entity != NULL) { if (p_bool) { entity->SetUnknown0x10Flag(LegoEntity::c_altBit1); } else { entity->ClearUnknown0x10Flag(LegoEntity::c_altBit1); } } } } } // STUB: LEGO1 0x1006c8f0 MxResult LegoAnimPresenter::VTable0x94(Vector3&, Vector3&, float, float, Vector3&) { // TODO return SUCCESS; } // STUB: LEGO1 0x1006ca50 void LegoAnimPresenter::VTable0x98() { // TODO } // STUB: LEGO1 0x1006d680 void LegoAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value) { // TODO }