From 600bf0351476a5a21aabb5429132ddf7f52ac0b9 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 15 May 2019 16:52:37 +0200 Subject: first commit --- src/modelinfo/BaseModelInfo.cpp | 117 +++++ src/modelinfo/BaseModelInfo.h | 66 +++ src/modelinfo/ClumpModelInfo.cpp | 156 +++++++ src/modelinfo/ClumpModelInfo.h | 60 +++ src/modelinfo/ModelIndices.cpp | 32 ++ src/modelinfo/ModelIndices.h | 224 +++++++++ src/modelinfo/ModelInfo.cpp | 124 +++++ src/modelinfo/ModelInfo.h | 35 ++ src/modelinfo/PedModelInfo.cpp | 197 ++++++++ src/modelinfo/PedModelInfo.h | 47 ++ src/modelinfo/SimpleModelInfo.cpp | 174 +++++++ src/modelinfo/SimpleModelInfo.h | 57 +++ src/modelinfo/TimeModelInfo.cpp | 36 ++ src/modelinfo/TimeModelInfo.h | 18 + src/modelinfo/VehicleModelInfo.cpp | 917 +++++++++++++++++++++++++++++++++++++ src/modelinfo/VehicleModelInfo.h | 115 +++++ 16 files changed, 2375 insertions(+) create mode 100644 src/modelinfo/BaseModelInfo.cpp create mode 100644 src/modelinfo/BaseModelInfo.h create mode 100644 src/modelinfo/ClumpModelInfo.cpp create mode 100644 src/modelinfo/ClumpModelInfo.h create mode 100644 src/modelinfo/ModelIndices.cpp create mode 100644 src/modelinfo/ModelIndices.h create mode 100644 src/modelinfo/ModelInfo.cpp create mode 100644 src/modelinfo/ModelInfo.h create mode 100644 src/modelinfo/PedModelInfo.cpp create mode 100644 src/modelinfo/PedModelInfo.h create mode 100644 src/modelinfo/SimpleModelInfo.cpp create mode 100644 src/modelinfo/SimpleModelInfo.h create mode 100644 src/modelinfo/TimeModelInfo.cpp create mode 100644 src/modelinfo/TimeModelInfo.h create mode 100644 src/modelinfo/VehicleModelInfo.cpp create mode 100644 src/modelinfo/VehicleModelInfo.h (limited to 'src/modelinfo') diff --git a/src/modelinfo/BaseModelInfo.cpp b/src/modelinfo/BaseModelInfo.cpp new file mode 100644 index 00000000..f44c86b6 --- /dev/null +++ b/src/modelinfo/BaseModelInfo.cpp @@ -0,0 +1,117 @@ +#include "common.h" +#include "patcher.h" +#include "templates.h" +#include "TxdStore.h" +#include "2dEffect.h" +#include "BaseModelInfo.h" + + +CBaseModelInfo::CBaseModelInfo(ModeInfoType type) +{ + m_colModel = nil; + m_twodEffects = 0; + m_objectId = -1; + m_refCount = 0; + m_txdSlot = -1; + m_type = type; + m_num2dEffects = 0; + m_freeCol = false; +} + +void +CBaseModelInfo::Shutdown(void) +{ + DeleteCollisionModel(); + DeleteRwObject(); + m_twodEffects = 0; + m_num2dEffects = 0; + m_txdSlot = -1; +} + +void +CBaseModelInfo::DeleteCollisionModel(void) +{ + if(m_colModel && m_freeCol){ + if(m_colModel) + delete m_colModel; + m_colModel = nil; + } +} + +void +CBaseModelInfo::AddRef(void) +{ + m_refCount++; + AddTexDictionaryRef(); +} + +void +CBaseModelInfo::RemoveRef(void) +{ + m_refCount--; + RemoveTexDictionaryRef(); +} + +void +CBaseModelInfo::SetTexDictionary(const char *name) +{ + int slot = CTxdStore::FindTxdSlot(name); + if(slot < 0) + slot = CTxdStore::AddTxdSlot(name); + m_txdSlot = slot; +} + +void +CBaseModelInfo::AddTexDictionaryRef(void) +{ + CTxdStore::AddRef(m_txdSlot); +} + +void +CBaseModelInfo::RemoveTexDictionaryRef(void) +{ + CTxdStore::RemoveRef(m_txdSlot); +} + +void +CBaseModelInfo::Init2dEffects(void) +{ + m_twodEffects = nil; + m_num2dEffects = 0; +} + +void +CBaseModelInfo::Add2dEffect(C2dEffect *fx) +{ + if(m_twodEffects) + m_num2dEffects++; + else{ + m_twodEffects = fx; + m_num2dEffects = 1; + } +} + +C2dEffect* +CBaseModelInfo::Get2dEffect(int n) +{ + if(m_twodEffects) + return &m_twodEffects[n]; + else + return nil; +} + + +STARTPATCHES + // can't easily replace ctor at 4F6A50 + InjectHook(0x4F6A90, &CBaseModelInfo::Shutdown_, PATCH_JUMP); + InjectHook(0x4F6AC0, &CBaseModelInfo::DeleteCollisionModel, PATCH_JUMP); + InjectHook(0x4F6B70, &CBaseModelInfo::ClearTexDictionary, PATCH_JUMP); + InjectHook(0x4F6BA0, &CBaseModelInfo::AddRef, PATCH_JUMP); + InjectHook(0x4F6BB0, &CBaseModelInfo::RemoveRef, PATCH_JUMP); + InjectHook(0x4F6B40, &CBaseModelInfo::SetTexDictionary, PATCH_JUMP); + InjectHook(0x4F6B80, &CBaseModelInfo::AddTexDictionaryRef, PATCH_JUMP); + InjectHook(0x4F6B90, &CBaseModelInfo::RemoveTexDictionaryRef, PATCH_JUMP); + InjectHook(0x4F6B20, &CBaseModelInfo::Add2dEffect, PATCH_JUMP); + InjectHook(0x4F6AF0, &CBaseModelInfo::Init2dEffects, PATCH_JUMP); + InjectHook(0x4F6B00, &CBaseModelInfo::Get2dEffect, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h new file mode 100644 index 00000000..fadea18a --- /dev/null +++ b/src/modelinfo/BaseModelInfo.h @@ -0,0 +1,66 @@ +#pragma once + +#include "Collision.h" + +enum ModeInfoType : uint8 +{ + MITYPE_NA = 0, + MITYPE_SIMPLE = 1, + MITYPE_MLO = 2, + MITYPE_TIME = 3, + MITYPE_CLUMP = 4, + MITYPE_VEHICLE = 5, + MITYPE_PED = 6, + MITYPE_XTRACOMPS = 7, +}; +static_assert(sizeof(ModeInfoType) == 1, "ModeInfoType: error"); + +class C2dEffect; + +class CBaseModelInfo +{ +protected: + // TODO?: make more things protected + char m_name[24]; + CColModel *m_colModel; + C2dEffect *m_twodEffects; + int16 m_objectId; +public: + uint16 m_refCount; + int16 m_txdSlot; + ModeInfoType m_type; + uint8 m_num2dEffects; + bool m_freeCol; + + CBaseModelInfo(ModeInfoType type); + virtual ~CBaseModelInfo() {} + virtual void Shutdown(void); + virtual void DeleteRwObject(void) = 0; + virtual RwObject *CreateInstance(RwMatrix *) = 0; + virtual RwObject *CreateInstance(void) = 0; + virtual RwObject *GetRwObject(void) = 0; + + bool IsSimple(void) { return m_type == MITYPE_SIMPLE || m_type == MITYPE_TIME; } + char *GetName(void) { return m_name; } + void SetName(const char *name) { strncpy(m_name, name, 24); } + void SetColModel(CColModel *col, bool free = false){ + m_colModel = col; m_freeCol = free; } + CColModel *GetColModel(void) { return m_colModel; } + void DeleteCollisionModel(void); + void ClearTexDictionary(void) { m_txdSlot = -1; } + short GetObjectID(void) { return m_objectId; } + void SetObjectID(short id) { m_objectId = id; } + short GetTxdSlot(void) { return m_txdSlot; } + void AddRef(void); + void RemoveRef(void); + void SetTexDictionary(const char *name); + void AddTexDictionaryRef(void); + void RemoveTexDictionaryRef(void); + void Init2dEffects(void); + void Add2dEffect(C2dEffect *fx); + C2dEffect *Get2dEffect(int n); + + void Shutdown_(void) { this->CBaseModelInfo::Shutdown(); } +}; + +static_assert(sizeof(CBaseModelInfo) == 0x30, "CBaseModelInfo: error"); diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp new file mode 100644 index 00000000..4a19f1df --- /dev/null +++ b/src/modelinfo/ClumpModelInfo.cpp @@ -0,0 +1,156 @@ +#include "common.h" +#include "patcher.h" +#include "NodeName.h" +#include "VisibilityPlugins.h" +#include "ModelInfo.h" + +void +CClumpModelInfo::DeleteRwObject(void) +{ + if(m_clump){ + RpClumpDestroy(m_clump); + m_clump = nil; + RemoveTexDictionaryRef(); + } +} + +RwObject* +CClumpModelInfo::CreateInstance(void) +{ + if(m_clump) + return (RwObject*)RpClumpClone(m_clump); + return nil; +} + +RwObject* +CClumpModelInfo::CreateInstance(RwMatrix *m) +{ + if(m_clump){ + RpClump *clump = (RpClump*)CreateInstance(); + *RwFrameGetMatrix(RpClumpGetFrame(clump)) = *m; + return (RwObject*)clump; + } + return nil; +} + +RpAtomic* +CClumpModelInfo::SetAtomicRendererCB(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::SetAtomicRenderCallback(atomic, (RpAtomicCallBackRender)data); + return atomic; +} + +void +CClumpModelInfo::SetClump(RpClump *clump) +{ + m_clump = clump; + CVisibilityPlugins::SetClumpModelInfo(m_clump, this); + AddTexDictionaryRef(); + RpClumpForAllAtomics(clump, SetAtomicRendererCB, nil); + if(strncmp(GetName(), "playerh", 8) == 0) + RpClumpForAllAtomics(clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB); +} + +void +CClumpModelInfo::SetFrameIds(RwObjectNameIdAssocation *assocs) +{ + int32 i; + RwObjectNameAssociation objname; + + for(i = 0; assocs[i].name; i++) + if((assocs[i].flags & CLUMP_FLAG_NO_HIERID) == 0){ + objname.frame = nil; + objname.name = assocs[i].name; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), FindFrameFromNameWithoutIdCB, &objname); + if(objname.frame) + CVisibilityPlugins::SetFrameHierarchyId(objname.frame, assocs[i].hierId); + } +} + +RwFrame* +CClumpModelInfo::FindFrameFromIdCB(RwFrame *frame, void *data) +{ + RwObjectIdAssociation *assoc = (RwObjectIdAssociation*)data; + + if(CVisibilityPlugins::GetFrameHierarchyId(frame) != assoc->id){ + RwFrameForAllChildren(frame, FindFrameFromIdCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +RwFrame* +CClumpModelInfo::FindFrameFromNameCB(RwFrame *frame, void *data) +{ + RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; + + if(_strcmpi(GetFrameNodeName(frame), assoc->name) != 0){ + RwFrameForAllChildren(frame, FindFrameFromNameCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +RwFrame* +CClumpModelInfo::FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data) +{ + RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; + + if(CVisibilityPlugins::GetFrameHierarchyId(frame) || + _strcmpi(GetFrameNodeName(frame), assoc->name) != 0){ + RwFrameForAllChildren(frame, FindFrameFromNameWithoutIdCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +RwFrame* +CClumpModelInfo::FillFrameArrayCB(RwFrame *frame, void *data) +{ + int32 id; + RwFrame **frames = (RwFrame**)data; + id = CVisibilityPlugins::GetFrameHierarchyId(frame); + if(id > 0) + frames[id] = frame; + RwFrameForAllChildren(frame, FillFrameArrayCB, data); + return frame; +} + +void +CClumpModelInfo::FillFrameArray(RpClump *clump, RwFrame **frames) +{ + RwFrameForAllChildren(RpClumpGetFrame(clump), FillFrameArrayCB, frames); +} + +RwFrame* +CClumpModelInfo::GetFrameFromId(RpClump *clump, int32 id) +{ + RwObjectIdAssociation assoc; + assoc.id = id; + assoc.frame = nil; + RwFrameForAllChildren(RpClumpGetFrame(clump), FindFrameFromIdCB, &assoc); + return assoc.frame; +} + + +STARTPATCHES + InjectHook(0x4F8800, &CClumpModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x4F8920, &CClumpModelInfo::CreateInstance_1, PATCH_JUMP); + InjectHook(0x4F88A0, &CClumpModelInfo::CreateInstance_2, PATCH_JUMP); + InjectHook(0x50C1C0, &CClumpModelInfo::GetRwObject_, PATCH_JUMP); + InjectHook(0x4F8830, &CClumpModelInfo::SetClump_, PATCH_JUMP); + InjectHook(0x4F8940, &CClumpModelInfo::SetAtomicRendererCB, PATCH_JUMP); + InjectHook(0x4F8960, &CClumpModelInfo::FindFrameFromNameCB, PATCH_JUMP); + InjectHook(0x4F8A10, &CClumpModelInfo::FindFrameFromNameWithoutIdCB, PATCH_JUMP); + InjectHook(0x4F8AD0, &CClumpModelInfo::FindFrameFromIdCB, PATCH_JUMP); + InjectHook(0x4F8BB0, &CClumpModelInfo::SetFrameIds, PATCH_JUMP); + InjectHook(0x4F8B20, &CClumpModelInfo::FillFrameArrayCB, PATCH_JUMP); + InjectHook(0x4F8B90, &CClumpModelInfo::FillFrameArray, PATCH_JUMP); + InjectHook(0x4F8B50, &CClumpModelInfo::GetFrameFromId, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/ClumpModelInfo.h b/src/modelinfo/ClumpModelInfo.h new file mode 100644 index 00000000..909d241b --- /dev/null +++ b/src/modelinfo/ClumpModelInfo.h @@ -0,0 +1,60 @@ +#pragma once + +#include "BaseModelInfo.h" + +struct RwObjectNameIdAssocation +{ + char *name; + int32 hierId; + uint32 flags; +}; + +struct RwObjectNameAssociation +{ + char *name; + RwFrame *frame; +}; + +struct RwObjectIdAssociation +{ + int32 id; + RwFrame *frame; +}; + +enum { + CLUMP_FLAG_NO_HIERID = 0x1, +}; + + +class CClumpModelInfo : public CBaseModelInfo +{ +public: + RpClump *m_clump; + + CClumpModelInfo(void) : CBaseModelInfo(MITYPE_CLUMP) {} + CClumpModelInfo(ModeInfoType id) : CBaseModelInfo(id) {} + ~CClumpModelInfo() {} + void DeleteRwObject(void); + RwObject *CreateInstance(void); + RwObject *CreateInstance(RwMatrix *); + RwObject *GetRwObject(void) { return (RwObject*)m_clump; } + + virtual void SetClump(RpClump *); + + static RpAtomic *SetAtomicRendererCB(RpAtomic *atomic, void *data); + void SetFrameIds(RwObjectNameIdAssocation *assocs); + static RwFrame *FindFrameFromNameCB(RwFrame *frame, void *data); + static RwFrame *FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data); + static RwFrame *FindFrameFromIdCB(RwFrame *frame, void *data); + static void FillFrameArray(RpClump *clump, RwFrame **frames); + static RwFrame *FillFrameArrayCB(RwFrame *frame, void *data); + static RwFrame *GetFrameFromId(RpClump *clump, int32 id); + + + void DeleteRwObject_(void) { this->CClumpModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_1(void) { return this->CClumpModelInfo::CreateInstance(); } + RwObject *CreateInstance_2(RwMatrix *m) { return this->CClumpModelInfo::CreateInstance(m); } + RwObject *GetRwObject_(void) { return this->CClumpModelInfo::GetRwObject(); } + void SetClump_(RpClump *clump) { this->CClumpModelInfo::SetClump(clump); } +}; +static_assert(sizeof(CClumpModelInfo) == 0x34, "CClumpModelInfo: error"); diff --git a/src/modelinfo/ModelIndices.cpp b/src/modelinfo/ModelIndices.cpp new file mode 100644 index 00000000..9a8aaead --- /dev/null +++ b/src/modelinfo/ModelIndices.cpp @@ -0,0 +1,32 @@ +#include "common.h" +#include "patcher.h" +#include "ModelIndices.h" + +#define X(name, var, addr) int16 &var = *(int16*)addr; + MODELINDICES +#undef X + +void +InitModelIndices(void) +{ +#define X(name, var, addr) var = -1; + MODELINDICES +#undef X +} + +void +MatchModelString(const char *modelname, int16 id) +{ +#define X(name, var, addr) \ + if(strcmp(name, modelname) == 0){ \ + var = id; \ + return; \ + } + MODELINDICES +#undef X +} + +STARTPATCHES + InjectHook(0x48EB60, InitModelIndices, PATCH_JUMP); + InjectHook(0x48F030, MatchModelString, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h new file mode 100644 index 00000000..5de10558 --- /dev/null +++ b/src/modelinfo/ModelIndices.h @@ -0,0 +1,224 @@ +#define MODELINDICES \ + X("fire_hydrant", MI_FIRE_HYDRANT, 0x5F5A00) \ + X("bagelstnd02", MI_BAGELSTAND2, 0x5F59FC) \ + X("fish01", MI_FISHSTALL01, 0x5F59EC) \ + X("fishstall02", MI_FISHSTALL02, 0x5F59F0) \ + X("fishstall03", MI_FISHSTALL03, 0x5F59F4) \ + X("fishstall04", MI_FISHSTALL04, 0x5F59F8) \ + X("taxisign", MI_TAXISIGN, 0x5F59E8) \ + X("phonesign", MI_PHONESIGN, 0x5F59E4) \ + X("noparkingsign1", MI_NOPARKINGSIGN1, 0x5F59E0) \ + X("bussign1", MI_BUSSIGN1, 0x5F59DC) \ + X("roadworkbarrier1", MI_ROADWORKBARRIER1, 0x5F59D8) \ + X("dump1", MI_DUMP1, 0x5F59D4) \ + X("trafficcone", MI_TRAFFICCONE, 0x5F59D0) \ + X("newsstand1", MI_NEWSSTAND, 0x5F59CC) \ + X("postbox1", MI_POSTBOX1, 0x5F59C8) \ + X("bin1", MI_BIN, 0x5F59C4) \ + X("wastebin", MI_WASTEBIN, 0x5F59C0) \ + X("phonebooth1", MI_PHONEBOOTH1, 0x5F59BC) \ + X("parkingmeter", MI_PARKINGMETER, 0x5F59B8) \ + X("trafficlight1", MI_TRAFFICLIGHTS, 0x5F5958) \ + X("lamppost1", MI_SINGLESTREETLIGHTS1, 0x5F595C) \ + X("lamppost2", MI_SINGLESTREETLIGHTS2, 0x5F5960) \ + X("lamppost3", MI_SINGLESTREETLIGHTS3, 0x5F5964) \ + X("doublestreetlght1", MI_DOUBLESTREETLIGHTS, 0x5F5968) \ + X("rd_Road2A10", MI_ROADSFORROADBLOCKSSTART, 0x5F596C) \ + X("rd_Road1A30", MI_ROADSFORROADBLOCKSEND, 0x5F5970) \ + X("veg_tree1", MI_TREE1, 0x5F5974) \ + X("veg_tree3", MI_TREE2, 0x5F5978) \ + X("veg_treea1", MI_TREE3, 0x5F597C) \ + X("veg_treenew01", MI_TREE4, 0x5F5980) \ + X("veg_treenew05", MI_TREE5, 0x5F5984) \ + X("veg_treeb1", MI_TREE6, 0x5F5988) \ + X("veg_treenew10", MI_TREE7, 0x5F598C) \ + X("veg_treea3", MI_TREE8, 0x5F5990) \ + X("veg_treenew09", MI_TREE9, 0x5F5994) \ + X("veg_treenew08", MI_TREE10, 0x5F5998) \ + X("veg_treenew03", MI_TREE11, 0x5F599C) \ + X("veg_treenew16", MI_TREE12, 0x5F59A0) \ + X("veg_treenew17", MI_TREE13, 0x5F59A4) \ + X("veg_treenew06", MI_TREE14, 0x5F59A8) \ + X("doc_crane_cab", MODELID_CRANE_1, 0x5F59AC) \ + X("cranetopb", MODELID_CRANE_2, 0x5F59B0) \ + X("cranetopa", MODELID_CRANE_3, 0x5F59B4) \ + X("package1", MI_COLLECTABLE1, 0x5F5A04) \ + X("Money", MI_MONEY, 0x5F5A08) \ + X("barrel1", MI_CARMINE, 0x5F5A0C) \ + X("oddjgaragdoor", MI_GARAGEDOOR1, 0x5F5A10) \ + X("bombdoor", MI_GARAGEDOOR2, 0x5F5A14) \ + X("door_bombshop", MI_GARAGEDOOR3, 0x5F5A18) \ + X("vheistlocdoor", MI_GARAGEDOOR4, 0x5F5A1C) \ + X("door2_garage", MI_GARAGEDOOR5, 0x5F5A20) \ + X("ind_slidedoor", MI_GARAGEDOOR6, 0x5F5A24) \ + X("bankjobdoor", MI_GARAGEDOOR7, 0x5F5A28) \ + X("door_jmsgrage", MI_GARAGEDOOR9, 0x5F5A2C) \ + X("jamesgrge_kb", MI_GARAGEDOOR10, 0x5F5A30) \ + X("door_sfehousegrge", MI_GARAGEDOOR11, 0x5F5A34) \ + X("shedgaragedoor", MI_GARAGEDOOR12, 0x5F5A38) \ + X("door4_garage", MI_GARAGEDOOR13, 0x5F5A3C) \ + X("door_col_compnd_01", MI_GARAGEDOOR14, 0x5F5A40) \ + X("door_col_compnd_02", MI_GARAGEDOOR15, 0x5F5A44) \ + X("door_col_compnd_03", MI_GARAGEDOOR16, 0x5F5A48) \ + X("door_col_compnd_04", MI_GARAGEDOOR17, 0x5F5A4C) \ + X("door_col_compnd_05", MI_GARAGEDOOR18, 0x5F5A50) \ + X("impex_door", MI_GARAGEDOOR19, 0x5F5A54) \ + X("SalvGarage", MI_GARAGEDOOR20, 0x5F5A58) \ + X("door3_garage", MI_GARAGEDOOR21, 0x5F5A5C) \ + X("leveldoor2", MI_GARAGEDOOR22, 0x5F5A60) \ + X("double_garage_dr", MI_GARAGEDOOR23, 0x5F5A64) \ + X("amcogaragedoor", MI_GARAGEDOOR24, 0x5F5A68) \ + X("towergaragedoor1", MI_GARAGEDOOR25, 0x5F5A6C) \ + X("towergaragedoor2", MI_GARAGEDOOR26, 0x5F5A70) \ + X("towergaragedoor3", MI_GARAGEDOOR27, 0x5F5A74) \ + X("plysve_gragedoor", MI_GARAGEDOOR28, 0x5F5A78) \ + X("impexpsubgrgdoor", MI_GARAGEDOOR29, 0x5F5A7C) \ + X("Sub_sprayshopdoor", MI_GARAGEDOOR30, 0x5F5A80) \ + X("ind_plyrwoor", MI_GARAGEDOOR31, 0x5F5A84) \ + X("8ballsuburbandoor", MI_GARAGEDOOR32, 0x5F5A88) \ + X("barrel2", MI_NAUTICALMINE, 0x5F5A8C) \ + X("crushercrush", MI_CRUSHERBODY, 0x5F5A90) \ + X("crushertop", MI_CRUSHERLID, 0x5F5A94) \ + X("donkeymag", MI_DONKEYMAG, 0x5F5A98) \ + X("bullion", MI_BULLION, 0x5F5A9C) \ + X("floatpackge1", MI_FLOATPACKAGE1, 0x5F5AA0) \ + X("briefcase", MI_BRIEFCASE, 0x5F5AA4) \ + X("chinabanner1", MI_CHINABANNER1, 0x5F5AA8) \ + X("chinabanner2", MI_CHINABANNER2, 0x5F5AAC) \ + X("chinabanner3", MI_CHINABANNER3, 0x5F5AB0) \ + X("chinabanner4", MI_CHINABANNER4, 0x5F5AB4) \ + X("iten_chinatown5", MI_CHINABANNER5, 0x5F5AB8) \ + X("iten_chinatown7", MI_CHINABANNER6, 0x5F5ABC) \ + X("iten_chinatown3", MI_CHINABANNER7, 0x5F5AC0) \ + X("iten_chinatown2", MI_CHINABANNER8, 0x5F5AC4) \ + X("iten_chinatown4", MI_CHINABANNER9, 0x5F5AC8) \ + X("iten_washline01", MI_CHINABANNER10, 0x5F5ACC) \ + X("iten_washline02", MI_CHINABANNER11, 0x5F5AD0) \ + X("iten_washline03", MI_CHINABANNER12, 0x5F5AD4) \ + X("chinalanterns", MI_CHINALANTERN, 0x5F5AD8) \ + X("glassfx1", MI_GLASS1, 0x5F5ADC) \ + X("glassfx2", MI_GLASS2, 0x5F5AE0) \ + X("glassfx3", MI_GLASS3, 0x5F5AE4) \ + X("glassfx4", MI_GLASS4, 0x5F5AE8) \ + X("glassfx55", MI_GLASS5, 0x5F5AEC) \ + X("glassfxsub1", MI_GLASS6, 0x5F5AF0) \ + X("glassfxsub2", MI_GLASS7, 0x5F5AF4) \ + X("glassfx_composh", MI_GLASS8, 0x5F5AF8) \ + X("bridge_liftsec", MI_BRIDGELIFT, 0x5F5AFC) \ + X("bridge_liftweight", MI_BRIDGEWEIGHT, 0x5F5B00) \ + X("subbridge_lift", MI_BRIDGEROADSEGMENT, 0x5F5B04) \ + X("barrel4", MI_EXPLODINGBARREL, 0x5F5B08) \ + X("flagsitaly", MI_ITALYBANNER1, 0x5F5B0C) \ + X("adrenaline", MI_PICKUP_ADRENALINE, 0x5F5B10) \ + X("bodyarmour", MI_PICKUP_BODYARMOUR, 0x5F5B14) \ + X("info", MI_PICKUP_INFO, 0x5F5B18) \ + X("health", MI_PICKUP_HEALTH, 0x5F5B1C) \ + X("bonus", MI_PICKUP_BONUS, 0x5F5B20) \ + X("bribe", MI_PICKUP_BRIBE, 0x5F5B24) \ + X("killfrenzy", MI_PICKUP_KILLFRENZY, 0x5F5B28) \ + X("camerapickup", MI_PICKUP_CAMERA, 0x5F5B2C) \ + X("bollardlight", MI_BOLLARDLIGHT, 0x5F5B30) \ + X("magnet", MI_MAGNET, 0x5F5B34) \ + X("streetlamp1", MI_STREETLAMP1, 0x5F5B38) \ + X("streetlamp2", MI_STREETLAMP2, 0x5F5B3C) \ + X("railtrax_lo4b", MI_RAILTRACKS, 0x5F5B40) \ + X("bar_barrier10", MI_FENCE, 0x5F5B44) \ + X("bar_barrier12", MI_FENCE2, 0x5F5B48) \ + X("petrolpump", MI_PETROLPUMP, 0x5F5B4C) \ + X("bodycast", MI_BODYCAST, 0x5F5B50) \ + X("backdoor", MI_BACKDOOR, 0x5F5B54) \ + X("coffee", MI_COFFEE, 0x5F5B58) \ + X("bouy", MI_BUOY, 0x5F5B5C) \ + X("parktable1", MI_PARKTABLE, 0x5F5B60) \ + X("sbwy_tunl_start", MI_SUBWAY1, 0x5F5B64) \ + X("sbwy_tunl_bit", MI_SUBWAY2, 0x5F5B68) \ + X("sbwy_tunl_bend", MI_SUBWAY3, 0x5F5B6C) \ + X("sbwy_tunl_cstm6", MI_SUBWAY4, 0x5F5B70) \ + X("sbwy_tunl_cstm7", MI_SUBWAY5, 0x5F5B74) \ + X("sbwy_tunl_cstm8", MI_SUBWAY6, 0x5F5B78) \ + X("sbwy_tunl_cstm10", MI_SUBWAY7, 0x5F5B7C) \ + X("sbwy_tunl_cstm9", MI_SUBWAY8, 0x5F5B80) \ + X("sbwy_tunl_cstm11", MI_SUBWAY9, 0x5F5B84) \ + X("sbwy_tunl_cstm1", MI_SUBWAY10, 0x5F5B88) \ + X("sbwy_tunl_cstm2", MI_SUBWAY11, 0x5F5B8C) \ + X("sbwy_tunl_cstm4", MI_SUBWAY12, 0x5F5B90) \ + X("sbwy_tunl_cstm3", MI_SUBWAY13, 0x5F5B94) \ + X("sbwy_tunl_cstm5", MI_SUBWAY14, 0x5F5B98) \ + X("subplatform_n2", MI_SUBWAY15, 0x5F5B9C) \ + X("suby_tunl_start", MI_SUBWAY16, 0x5F5BA0) \ + X("sbwy_tunl_start2", MI_SUBWAY17, 0x5F5BA4) \ + X("indy_tunl_start", MI_SUBWAY18, 0x5F5BA8) \ + X("indsubway03", MI_SUBPLATFORM_IND, 0x5F5BAC) \ + X("comerside_subway", MI_SUBPLATFORM_COMS, 0x5F5BB0) \ + X("subplatform", MI_SUBPLATFORM_COMS2, 0x5F5BB4) \ + X("subplatform_n", MI_SUBPLATFORM_COMN, 0x5F5BB8) \ + X("Otherside_subway", MI_SUBPLATFORM_SUB, 0x5F5BBC) \ + X("subplatform_sub", MI_SUBPLATFORM_SUB2, 0x5F5BC0) \ + X("files", MI_FILES, 0x5F5BC4) + +#define X(name, var, addr) extern int16 &var; + MODELINDICES +#undef X + +// and some hardcoded ones +// expand as needed +enum +{ + MI_COP = 1, + MI_SWAT, + MI_FBI, + MI_ARMY, + MI_MEDIC, + MI_FIREMAN, + MI_MALE01, + MI_TAXI_D, + MI_PIMP, + MI_GANG01, + MI_GANG02, + MI_GANG03, + MI_GANG04, + MI_GANG05, + MI_GANG06, + MI_GANG07, + MI_GANG08, + MI_GANG09, + MI_GANG10, + MI_GANG11, + MI_GANG12, + MI_GANG13, + MI_GANG14, + MI_CRIMINAL01, + MI_CRIMINAL02, + MI_SPECIAL01, + MI_SPECIAL02, + MI_SPECIAL03, + MI_SPECIAL04, + MI_MALE02, + MI_MALE03, + MI_FATMALE01, + MI_FATMALE02, + MI_FEMALE01, + MI_FEMALE02, + MI_FEMALE03, + MI_FATFEMALE01, + MI_FATFEMALE02, + + MI_RHINO = 122, + MI_COACH = 127, +}; + +void InitModelIndices(void); +void MatchModelString(const char *name, int16 id); + +inline bool +IsGlass(int16 id) +{ + return id == MI_GLASS1 || + id == MI_GLASS2 || + id == MI_GLASS3 || + id == MI_GLASS4 || + id == MI_GLASS5 || + id == MI_GLASS6 || + id == MI_GLASS7 || + id == MI_GLASS8; +} diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp new file mode 100644 index 00000000..89fcdee5 --- /dev/null +++ b/src/modelinfo/ModelInfo.cpp @@ -0,0 +1,124 @@ +#include "common.h" +#include "patcher.h" +#include "ModelInfo.h" + +CBaseModelInfo **CModelInfo::ms_modelInfoPtrs = (CBaseModelInfo**)0x83D408; + +//CStore &CModelInfo::ms_simpleModelStore = *(CStore*)0x885BB4; +//CStore &CModelInfo::ms_timeModelStore = *(CStore*)0x94076C; +//CStore &CModelInfo::ms_2dEffectStore = *(CStore*)0x9434F8; +CStore CModelInfo::ms_simpleModelStore; +CStore CModelInfo::ms_timeModelStore; +CStore CModelInfo::ms_clumpModelStore; +CStore CModelInfo::ms_pedModelStore; +CStore CModelInfo::ms_vehicleModelStore; +CStore CModelInfo::ms_2dEffectStore; + +void +CModelInfo::Initialise(void) +{ + int i; + for(i = 0; i < MODELINFOSIZE; i++) + ms_modelInfoPtrs[i] = nil; + ms_2dEffectStore.clear(); + ms_simpleModelStore.clear(); + ms_timeModelStore.clear(); + ms_clumpModelStore.clear(); + ms_pedModelStore.clear(); + ms_vehicleModelStore.clear(); +} + +void +CModelInfo::Shutdown(void) +{ + int i; + for(i = 0; i < ms_simpleModelStore.allocPtr; i++) + ms_simpleModelStore.store[i].Shutdown(); + for(i = 0; i < ms_timeModelStore.allocPtr; i++) + ms_timeModelStore.store[i].Shutdown(); + for(i = 0; i < ms_clumpModelStore.allocPtr; i++) + ms_clumpModelStore.store[i].Shutdown(); + for(i = 0; i < ms_pedModelStore.allocPtr; i++) + ms_pedModelStore.store[i].Shutdown(); + for(i = 0; i < ms_vehicleModelStore.allocPtr; i++) + ms_vehicleModelStore.store[i].Shutdown(); +} + +CSimpleModelInfo* +CModelInfo::AddSimpleModel(int id) +{ + CSimpleModelInfo *modelinfo; + modelinfo = CModelInfo::ms_simpleModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->Init(); + return modelinfo; +} + +CTimeModelInfo* +CModelInfo::AddTimeModel(int id) +{ + CTimeModelInfo *modelinfo; + modelinfo = CModelInfo::ms_timeModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->Init(); + return modelinfo; +} + +CClumpModelInfo* +CModelInfo::AddClumpModel(int id) +{ + CClumpModelInfo *modelinfo; + modelinfo = CModelInfo::ms_clumpModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->m_clump = nil; + return modelinfo; +} + +CPedModelInfo* +CModelInfo::AddPedModel(int id) +{ + CPedModelInfo *modelinfo; + modelinfo = CModelInfo::ms_pedModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->m_clump = nil; + return modelinfo; +} + +CVehicleModelInfo* +CModelInfo::AddVehicleModel(int id) +{ + CVehicleModelInfo *modelinfo; + modelinfo = CModelInfo::ms_vehicleModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->m_clump = nil; + modelinfo->m_vehicleType = -1; + modelinfo->m_wheelId = -1; + modelinfo->m_materials1[0] = nil; + modelinfo->m_materials2[0] = nil; + modelinfo->m_bikeSteerAngle = 999.99f; + return modelinfo; +} + +CBaseModelInfo* +CModelInfo::GetModelInfo(const char *name, int *id) +{ + CBaseModelInfo *modelinfo; + for(int i = 0; i < MODELINFOSIZE; i++){ + modelinfo = CModelInfo::ms_modelInfoPtrs[i]; + if(modelinfo && _strcmpi(modelinfo->GetName(), name) == 0){ + if(id) + *id = i; + return modelinfo; + } + } + return nil; +} + +STARTPATCHES +// InjectHook(0x50B920, CModelInfo::AddSimpleModel, PATCH_JUMP); +// InjectHook(0x50B9C0, CModelInfo::AddTimeModel, PATCH_JUMP); +// InjectHook(0x50BA10, CModelInfo::AddClumpModel, PATCH_JUMP); +// InjectHook(0x50BAD0, CModelInfo::AddPedModel, PATCH_JUMP); +// InjectHook(0x50BA60, CModelInfo::AddPedModel, PATCH_JUMP); + InjectHook(0x50B860, (CBaseModelInfo *(*)(const char*, int*))CModelInfo::GetModelInfo, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h new file mode 100644 index 00000000..a0d30dea --- /dev/null +++ b/src/modelinfo/ModelInfo.h @@ -0,0 +1,35 @@ +#pragma once + +#include "2dEffect.h" +#include "BaseModelInfo.h" +#include "SimpleModelInfo.h" +#include "TimeModelInfo.h" +#include "ClumpModelInfo.h" +#include "PedModelInfo.h" +#include "VehicleModelInfo.h" + +class CModelInfo +{ + static CBaseModelInfo **ms_modelInfoPtrs; //[MODELINFOSIZE]; + static CStore ms_simpleModelStore; + static CStore ms_timeModelStore; + static CStore ms_clumpModelStore; + static CStore ms_pedModelStore; + static CStore ms_vehicleModelStore; + static CStore ms_2dEffectStore; + +public: + static void Initialise(void); + static void Shutdown(void); + + static CSimpleModelInfo *AddSimpleModel(int id); + static CTimeModelInfo *AddTimeModel(int id); + static CClumpModelInfo *AddClumpModel(int id); + static CPedModelInfo *AddPedModel(int id); + static CVehicleModelInfo *AddVehicleModel(int id); + + static CBaseModelInfo *GetModelInfo(const char *name, int *id); + static CBaseModelInfo *GetModelInfo(int id){ + return ms_modelInfoPtrs[id]; + } +}; diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp new file mode 100644 index 00000000..e095902e --- /dev/null +++ b/src/modelinfo/PedModelInfo.cpp @@ -0,0 +1,197 @@ +#include "common.h" +#include "patcher.h" +#include "NodeName.h" +#include "VisibilityPlugins.h" +#include "ModelInfo.h" + +void +CPedModelInfo::DeleteRwObject(void) +{ + CClumpModelInfo::DeleteRwObject(); + if(m_hitColModel) + delete m_hitColModel; + m_hitColModel = nil; +} + +RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[12] = { + { "Smid", PED_TORSO, 0, }, // that is strange... + { "Shead", PED_HEAD, 0, }, + { "Supperarml", PED_UPPERARML, 0, }, + { "Supperarmr", PED_UPPERARMR, 0, }, + { "SLhand", PED_HANDL, 0, }, + { "SRhand", PED_HANDR, 0, }, + { "Supperlegl", PED_UPPERLEGL, 0, }, + { "Supperlegr", PED_UPPERLEGR, 0, }, + { "Sfootl", PED_FOOTL, 0, }, + { "Sfootr", PED_FOOTR, 0, }, + { "Slowerlegr", PED_LOWERLEGR, 0, }, + { NULL, 0, 0, }, +}; + +void +CPedModelInfo::SetClump(RpClump *clump) +{ + CClumpModelInfo::SetClump(clump); + SetFrameIds(m_pPedIds); + if(m_hitColModel == nil) + CreateHitColModel(); + if(strncmp(GetName(), "player", 7) == 0) + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB); +} + +RpAtomic* +CountAtomicsCB(RpAtomic *atomic, void *data) +{ + (*(int32*)data)++; + return atomic; +} + +RpAtomic* +GetAtomicListCB(RpAtomic *atomic, void *data) +{ + **(RpAtomic***)data = atomic; + (*(RpAtomic***)data)++; + return atomic; +} + +RwFrame* +FindPedFrameFromNameCB(RwFrame *frame, void *data) +{ + RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; + + if(_strcmpi(GetFrameNodeName(frame)+1, assoc->name+1) != 0){ + RwFrameForAllChildren(frame, FindPedFrameFromNameCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +void +CPedModelInfo::SetLowDetailClump(RpClump *lodclump) +{ + RpAtomic *atomics[16]; + RpAtomic **pAtm; + int32 numAtm, numLodAtm; + int i; + RwObjectNameAssociation assoc; + + numAtm = 0; + numLodAtm = 0; + RpClumpForAllAtomics(m_clump, CountAtomicsCB, &numAtm); // actually unused + RpClumpForAllAtomics(lodclump, CountAtomicsCB, &numLodAtm); + + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPedHiDetailCB); + RpClumpForAllAtomics(lodclump, SetAtomicRendererCB, CVisibilityPlugins::RenderPedLowDetailCB); + + pAtm = atomics; + RpClumpForAllAtomics(lodclump, GetAtomicListCB, &pAtm); + + for(i = 0; i < numLodAtm; i++){ + assoc.name = GetFrameNodeName(RpAtomicGetFrame(atomics[i])); + assoc.frame = nil; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), FindPedFrameFromNameCB, &assoc); + if(assoc.frame){ + RpAtomicSetFrame(atomics[i], assoc.frame); + RpClumpRemoveAtomic(lodclump, atomics[i]); + RpClumpAddAtomic(m_clump, atomics[i]); + } + } +} + +struct ColNodeInfo +{ + char *name; + int pedNode; + int pieceType; + float x, z; + float radius; +}; + +// TODO: find out piece types +#define NUMPEDINFONODES 8 +ColNodeInfo m_pColNodeInfos[NUMPEDINFONODES] = { + { NULL, PED_HEAD, 6, 0.0f, 0.05f, 0.2f }, + { "Storso", 0, 0, 0.0f, 0.15f, 0.2f }, + { "Storso", 0, 0, 0.0f, -0.05f, 0.3f }, + { NULL, PED_TORSO, 1, 0.0f, -0.07f, 0.3f }, + { NULL, PED_UPPERARML, 2, 0.07f, -0.1f, 0.2f }, + { NULL, PED_UPPERARMR, 3, -0.07f, -0.1f, 0.2f }, + { "Slowerlegl", 0, 4, 0.0f, 0.07f, 0.25f }, + { NULL, PED_LOWERLEGR, 5, 0.0f, 0.07f, 0.25f }, +}; + +RwObject* +FindHeadRadiusCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + *(float*)data = RpAtomicGetBoundingSphere(atomic)->radius; + return nil; +} + +void +CPedModelInfo::CreateHitColModel(void) +{ + RwObjectNameAssociation nameAssoc; + RwObjectIdAssociation idAssoc; + CVector center; + RwFrame *nodeFrame; + CColModel *colmodel = new CColModel; + CColSphere *spheres = (CColSphere*)RwMalloc(NUMPEDINFONODES*sizeof(CColSphere)); + RwFrame *root = RpClumpGetFrame(m_clump); + RwMatrix *mat = RwMatrixCreate(); + for(int i = 0; i < NUMPEDINFONODES; i++){ + nodeFrame = nil; + if(m_pColNodeInfos[i].name){ + nameAssoc.name = m_pColNodeInfos[i].name; + nameAssoc.frame = nil; + RwFrameForAllChildren(root, FindFrameFromNameCB, &nameAssoc); + nodeFrame = nameAssoc.frame; + }else{ + idAssoc.id = m_pColNodeInfos[i].pedNode; + idAssoc.frame = nil; + RwFrameForAllChildren(root, FindFrameFromIdCB, &idAssoc); + nodeFrame = idAssoc.frame; + } + if(nodeFrame){ + float radius = m_pColNodeInfos[i].radius; + if(m_pColNodeInfos[i].pieceType == 6) + RwFrameForAllObjects(nodeFrame, FindHeadRadiusCB, &radius); + RwMatrixTransform(mat, RwFrameGetMatrix(nodeFrame), rwCOMBINEREPLACE); + const char *name = GetFrameNodeName(nodeFrame); + for(nodeFrame = RwFrameGetParent(nodeFrame); + nodeFrame; + nodeFrame = RwFrameGetParent(nodeFrame)){ + name = GetFrameNodeName(nodeFrame); + RwMatrixTransform(mat, RwFrameGetMatrix(nodeFrame), rwCOMBINEPOSTCONCAT); + if(RwFrameGetParent(nodeFrame) == root) + break; + } + center.x = mat->pos.x + m_pColNodeInfos[i].x; + center.y = mat->pos.y + 0.0f; + center.z = mat->pos.z + m_pColNodeInfos[i].z; + spheres[i].Set(radius, center, 17, m_pColNodeInfos[i].pieceType); + } + } + RwMatrixDestroy(mat); + colmodel->spheres = spheres; + colmodel->numSpheres = NUMPEDINFONODES; + center.x = center.y = center.z = 0.0f; + colmodel->boundingSphere.Set(2.0f, center, 0, 0); + CVector min, max; + min.x = min.y = -0.5f; + min.z = -1.2f; + max.x = max.y = 0.5f; + max.z = 1.2f; + colmodel->boundingBox.Set(min, max, 0, 0); + colmodel->level = 0; + m_hitColModel = colmodel; +} + +STARTPATCHES + InjectHook(0x510210, &CPedModelInfo::SetClump_, PATCH_JUMP); + InjectHook(0x510280, &CPedModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x510390, &CPedModelInfo::SetLowDetailClump, PATCH_JUMP); + InjectHook(0x5104D0, &CPedModelInfo::CreateHitColModel, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h new file mode 100644 index 00000000..e917b6b2 --- /dev/null +++ b/src/modelinfo/PedModelInfo.h @@ -0,0 +1,47 @@ +#pragma once + +#include "ClumpModelInfo.h" + +enum PedNode { + PED_WAIST, + PED_TORSO, // Smid on PS2/PC, Storso on mobile/xbox + PED_HEAD, + PED_UPPERARML, + PED_UPPERARMR, + PED_HANDL, + PED_HANDR, + PED_UPPERLEGL, + PED_UPPERLEGR, + PED_FOOTL, + PED_FOOTR, + PED_LOWERLEGR, + // This is not valid apparently + PED_LOWERLEGL, +}; + +class CPedModelInfo : public CClumpModelInfo +{ +public: + void *m_animGroup; // TODO + int32 m_pedType; + int32 m_pedStatType; + uint32 m_carsCanDrive; + CColModel *m_hitColModel; + RpAtomic *m_head; + RpAtomic *m_lhand; + RpAtomic *m_rhand; + + static RwObjectNameIdAssocation m_pPedIds[12]; + + CPedModelInfo(void) : CClumpModelInfo(MITYPE_PED) { } + void DeleteRwObject(void); + void SetClump(RpClump *); + + void SetLowDetailClump(RpClump*); + void CreateHitColModel(void); + + + void DeleteRwObject_(void) { this->CPedModelInfo::DeleteRwObject(); } + void SetClump_(RpClump *clump) { this->CPedModelInfo::SetClump(clump); } +}; +static_assert(sizeof(CPedModelInfo) == 0x54, "CPedModelInfo: error"); diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp new file mode 100644 index 00000000..a5853d6f --- /dev/null +++ b/src/modelinfo/SimpleModelInfo.cpp @@ -0,0 +1,174 @@ +#include "common.h" +#include "patcher.h" +#include "Camera.h" +#include "ModelInfo.h" + +#define LOD_DISTANCE (300.0f) + +void +CSimpleModelInfo::DeleteRwObject(void) +{ + int i; + RwFrame *f; + for(i = 0; i < m_numAtomics; i++) + if(m_atomics[i]){ + f = RpAtomicGetFrame(m_atomics[i]); + RpAtomicDestroy(m_atomics[i]); + RwFrameDestroy(f); + m_atomics[i] = nil; + RemoveTexDictionaryRef(); + } +} + +RwObject* +CSimpleModelInfo::CreateInstance(void) +{ + RpAtomic *atomic; + if(m_atomics[0] == nil) + return nil; + atomic = RpAtomicClone(m_atomics[0]); + RpAtomicSetFrame(atomic, RwFrameCreate()); + return (RwObject*)atomic; +} + +RwObject* +CSimpleModelInfo::CreateInstance(RwMatrix *matrix) +{ + RpAtomic *atomic; + RwFrame *frame; + + if(m_atomics[0] == nil) + return nil; + atomic = RpAtomicClone(m_atomics[0]); + frame = RwFrameCreate(); + *RwFrameGetMatrix(frame) = *matrix; + RpAtomicSetFrame(atomic, frame); + return (RwObject*)atomic; +} + +void +CSimpleModelInfo::Init(void) +{ + m_atomics[0] = nil; + m_atomics[1] = nil; + m_atomics[2] = nil; + m_numAtomics = 0; + m_furthest = 0; + m_normalCull = 0; + m_isDamaged = 0; + m_isBigBuilding = 0; + m_noFade = 0; + m_drawLast = 0; + m_additive = 0; + m_isSubway = 0; + m_ignoreLight = 0; + m_noZwrite = 0; +} + +void +CSimpleModelInfo::SetAtomic(int n, RpAtomic *atomic) +{ + AddTexDictionaryRef(); + m_atomics[n] = atomic; + if(m_ignoreLight){ + RpGeometry *geo = RpAtomicGetGeometry(atomic); + RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) & ~rpGEOMETRYLIGHT); + } +} + +void +CSimpleModelInfo::SetLodDistances(float *dist) +{ + m_lodDistances[0] = dist[0]; + m_lodDistances[1] = dist[1]; + m_lodDistances[2] = dist[2]; +} + +void +CSimpleModelInfo::IncreaseAlpha(void) +{ + if(m_alpha >= 0xEF) + m_alpha = 0xFF; + else + m_alpha += 0x10; +} + +float +CSimpleModelInfo::GetNearDistance(void) +{ + return m_lodDistances[2] * TheCamera.LODDistMultiplier; +} + +float +CSimpleModelInfo::GetLargestLodDistance(void) +{ + float d; + // TODO: what exactly is going on here? + if(m_furthest != 0 && !m_isDamaged) + d = m_lodDistances[m_furthest-1]; + else + d = m_lodDistances[m_numAtomics-1]; + return d * TheCamera.LODDistMultiplier; +} + +RpAtomic* +CSimpleModelInfo::GetAtomicFromDistance(float dist) +{ + int i; + i = 0; + // TODO: what exactly is going on here? + if(m_isDamaged) + i = m_furthest; + for(; i < m_numAtomics; i++) + if(dist < m_lodDistances[i] *TheCamera.LODDistMultiplier) + return m_atomics[i]; + return nil; +} + +void +CSimpleModelInfo::FindRelatedModel(void) +{ + int i; + CBaseModelInfo *mi; + for(i = 0; i < MODELINFOSIZE; i++){ + mi = CModelInfo::GetModelInfo(i); + if(mi && mi != this && + strcmp(GetName()+3, mi->GetName()+3) == 0){ + assert(mi->IsSimple()); + this->SetRelatedModel((CSimpleModelInfo*)mi); + return; + } + } +} + +void +CSimpleModelInfo::SetupBigBuilding(void) +{ + CSimpleModelInfo *related; + if(m_lodDistances[0] > LOD_DISTANCE && m_atomics[2] == nil){ + m_isBigBuilding = 1; + FindRelatedModel(); + related = GetRelatedModel(); + if(related) + m_lodDistances[2] = related->GetLargestLodDistance()/TheCamera.LODDistMultiplier; + else + m_lodDistances[2] = 100.0f; + } +} + + +STARTPATCHES + InjectHook(0x5179B0, &CSimpleModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x517B60, &CSimpleModelInfo::CreateInstance_1, PATCH_JUMP); + InjectHook(0x517AC0, &CSimpleModelInfo::CreateInstance_2, PATCH_JUMP); + InjectHook(0x4A9BA0, &CSimpleModelInfo::GetRwObject_, PATCH_JUMP); + InjectHook(0x517990, &CSimpleModelInfo::Init, PATCH_JUMP); + InjectHook(0x517C60, &CSimpleModelInfo::IncreaseAlpha, PATCH_JUMP); + InjectHook(0x517950, &CSimpleModelInfo::SetAtomic, PATCH_JUMP); + InjectHook(0x517AA0, &CSimpleModelInfo::SetLodDistances, PATCH_JUMP); + InjectHook(0x517A90, &CSimpleModelInfo::GetNearDistance, PATCH_JUMP); + InjectHook(0x517A60, &CSimpleModelInfo::GetLargestLodDistance, PATCH_JUMP); + InjectHook(0x517A00, &CSimpleModelInfo::GetAtomicFromDistance, PATCH_JUMP); + InjectHook(0x517C00, &CSimpleModelInfo::FindRelatedModel, PATCH_JUMP); + InjectHook(0x517B90, &CSimpleModelInfo::SetupBigBuilding, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/SimpleModelInfo.h b/src/modelinfo/SimpleModelInfo.h new file mode 100644 index 00000000..186a517c --- /dev/null +++ b/src/modelinfo/SimpleModelInfo.h @@ -0,0 +1,57 @@ +#pragma once + +#include "BaseModelInfo.h" + +class CSimpleModelInfo : public CBaseModelInfo +{ +public: + // atomics[2] is often a pointer to the non-LOD modelinfo + RpAtomic *m_atomics[3]; + // m_lodDistances[2] holds the near distance for LODs + float m_lodDistances[3]; + uint8 m_numAtomics; + uint8 m_alpha; + uint16 m_furthest : 2; // 0: numAtomics-1 is furthest visible + // 1: atomic 0 is furthest + // 2: atomic 1 is furthest + uint16 m_normalCull : 1; + uint16 m_isDamaged : 1; + uint16 m_isBigBuilding : 1; + uint16 m_noFade : 1; + uint16 m_drawLast : 1; + uint16 m_additive : 1; + uint16 m_isSubway : 1; + uint16 m_ignoreLight : 1; + uint16 m_noZwrite : 1; + + CSimpleModelInfo(void) : CBaseModelInfo(MITYPE_SIMPLE) {} + CSimpleModelInfo(ModeInfoType id) : CBaseModelInfo(id) {} + ~CSimpleModelInfo() {} + void DeleteRwObject(void); + RwObject *CreateInstance(void); + RwObject *CreateInstance(RwMatrix *); + RwObject *GetRwObject(void) { return (RwObject*)m_atomics[0]; } + + void Init(void); + void IncreaseAlpha(void); + void SetAtomic(int n, RpAtomic *atomic); + void SetLodDistances(float *dist); + float GetLodDistance(int i) { return m_lodDistances[i]; } + float GetNearDistance(void); + float GetLargestLodDistance(void); + RpAtomic *GetAtomicFromDistance(float dist); + void FindRelatedModel(void); + void SetupBigBuilding(void); + + void SetNumAtomics(int n) { m_numAtomics = n; } + CSimpleModelInfo *GetRelatedModel(void){ + return (CSimpleModelInfo*)m_atomics[2]; } + void SetRelatedModel(CSimpleModelInfo *m){ + m_atomics[2] = (RpAtomic*)m; } + + void DeleteRwObject_(void) { this->CSimpleModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_1(void) { return this->CSimpleModelInfo::CreateInstance(); } + RwObject *CreateInstance_2(RwMatrix *m) { return this->CSimpleModelInfo::CreateInstance(m); } + RwObject *GetRwObject_(void) { return this->CSimpleModelInfo::GetRwObject(); } +}; +static_assert(sizeof(CSimpleModelInfo) == 0x4C, "CSimpleModelInfo: error"); diff --git a/src/modelinfo/TimeModelInfo.cpp b/src/modelinfo/TimeModelInfo.cpp new file mode 100644 index 00000000..3ab3e13a --- /dev/null +++ b/src/modelinfo/TimeModelInfo.cpp @@ -0,0 +1,36 @@ +#include "common.h" +#include "patcher.h" +#include "Camera.h" +#include "ModelInfo.h" + +CTimeModelInfo* +CTimeModelInfo::FindOtherTimeModel(void) +{ + char name[40]; + char *p; + int i; + + strcpy(name, GetName()); + // change _nt to _dy + if(p = strstr(name, "_nt")) + strncpy(p, "_dy", 4); + // change _dy to _nt + else if(p = strstr(name, "_dy")) + strncpy(p, "_nt", 4); + else + return nil; + + for(i = 0; i < MODELINFOSIZE; i++){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(i); + if(mi && mi->m_type == MITYPE_TIME && + strncmp(name, mi->GetName(), 24) == 0){ + m_otherTimeModelID = i; + return (CTimeModelInfo*)mi; + } + } + return nil; +} + +STARTPATCHES + InjectHook(0x517C80, &CTimeModelInfo::FindOtherTimeModel, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/TimeModelInfo.h b/src/modelinfo/TimeModelInfo.h new file mode 100644 index 00000000..08e46bd3 --- /dev/null +++ b/src/modelinfo/TimeModelInfo.h @@ -0,0 +1,18 @@ +#pragma once + +#include "SimpleModelInfo.h" + +class CTimeModelInfo : public CSimpleModelInfo +{ + int32 m_timeOn; + int32 m_timeOff; + int32 m_otherTimeModelID; +public: + CTimeModelInfo(void) : CSimpleModelInfo(MITYPE_TIME) { m_otherTimeModelID = -1; } + + int32 GetTimeOn(void) { return m_timeOn; } + int32 GetTimeOff(void) { return m_timeOff; } + int32 GetOtherTimeModel(void) { return m_otherTimeModelID; } + CTimeModelInfo *FindOtherTimeModel(void); +}; +static_assert(sizeof(CTimeModelInfo) == 0x58, "CTimeModelInfo: error"); diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp new file mode 100644 index 00000000..575d0360 --- /dev/null +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -0,0 +1,917 @@ +#include "common.h" +#include +#include "patcher.h" +#include "RwHelper.h" +#include "General.h" +#include "NodeName.h" +#include "TxdStore.h" +#include "Weather.h" +#include "VisibilityPlugins.h" +#include "ModelInfo.h" + +int8 *CVehicleModelInfo::ms_compsToUse = (int8*)0x5FF2EC; // -2, -2 +int8 *CVehicleModelInfo::ms_compsUsed = (int8*)0x95CCB2; +RwTexture **CVehicleModelInfo::ms_pEnvironmentMaps = (RwTexture **)0x8F1A30; +RwRGBA *CVehicleModelInfo::ms_vehicleColourTable = (RwRGBA*)0x86BA88; +RwTexture **CVehicleModelInfo::ms_colourTextureTable = (RwTexture**)0x711C40; + +RwTexture *&gpWhiteTexture = *(RwTexture**)0x64C4F8; +RwFrame *&pMatFxIdentityFrame = *(RwFrame**)0x64C510; + +// TODO This depends on handling +WRAPPER void CVehicleModelInfo::SetVehicleComponentFlags(RwFrame *frame, uint32 flags) { EAXJMP(0x5203C0); } + +enum { + CAR_WHEEL_RF = 1, + CAR_WHEEL_RM = 2, + CAR_WHEEL_RB = 3, + CAR_WHEEL_LF = 4, + CAR_WHEEL_LM = 5, + CAR_WHEEL_LB = 6, + CAR_BUMP_FRONT = 7, + CAR_BUMP_REAR = 8, + CAR_WING_RF = 9, + CAR_WING_RR = 10, + CAR_DOOR_RF = 11, + CAR_DOOR_RR = 12, + CAR_WING_LF = 13, + CAR_WING_LR = 14, + CAR_DOOR_LF = 15, + CAR_DOOR_LR = 16, + CAR_BONNET = 17, + CAR_BOOT = 18, + CAR_WINDSCREEN = 19, + + CAR_POS_HEADLIGHTS = 0, + CAR_POS_TAILLIGHTS = 1, + CAR_POS_FRONTSEAT = 2, + CAR_POS_BACKSEAT = 3, + CAR_POS_EXHAUST = 9, +}; + +enum { + VEHICLE_FLAG_COLLAPSE = 0x2, + VEHICLE_FLAG_ADD_WHEEL = 0x4, + VEHICLE_FLAG_POS = 0x8, + VEHICLE_FLAG_DOOR = 0x10, + VEHICLE_FLAG_LEFT = 0x20, + VEHICLE_FLAG_RIGHT = 0x40, + VEHICLE_FLAG_FRONT = 0x80, + VEHICLE_FLAG_REAR = 0x100, + VEHICLE_FLAG_COMP = 0x200, + VEHICLE_FLAG_DRAWLAST = 0x400, + VEHICLE_FLAG_WINDSCREEN = 0x800, + VEHICLE_FLAG_ANGLECULL = 0x1000, + VEHICLE_FLAG_REARDOOR = 0x2000, + VEHICLE_FLAG_FRONTDOOR = 0x4000, +}; + +RwObjectNameIdAssocation carIds[] = { + { "wheel_rf_dummy", CAR_WHEEL_RF, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_rm_dummy", CAR_WHEEL_RM, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_rb_dummy", CAR_WHEEL_RB, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_lf_dummy", CAR_WHEEL_LF, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_lm_dummy", CAR_WHEEL_LM, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_lb_dummy", CAR_WHEEL_LB, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL }, + { "bump_front_dummy", CAR_BUMP_FRONT, VEHICLE_FLAG_FRONT | VEHICLE_FLAG_COLLAPSE }, + { "bonnet_dummy", CAR_BONNET, VEHICLE_FLAG_COLLAPSE }, + { "wing_rf_dummy", CAR_WING_RF, VEHICLE_FLAG_COLLAPSE }, + { "wing_rr_dummy", CAR_WING_RR, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_COLLAPSE }, + { "door_rf_dummy", CAR_DOOR_RF, VEHICLE_FLAG_FRONTDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "door_rr_dummy", CAR_DOOR_RR, VEHICLE_FLAG_REARDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_REAR | VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "wing_lf_dummy", CAR_WING_LF, VEHICLE_FLAG_COLLAPSE }, + { "wing_lr_dummy", CAR_WING_LR, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE }, + { "door_lf_dummy", CAR_DOOR_LF, VEHICLE_FLAG_FRONTDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_LEFT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "door_lr_dummy", CAR_DOOR_LR, VEHICLE_FLAG_REARDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_REAR | VEHICLE_FLAG_LEFT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "boot_dummy", CAR_BOOT, VEHICLE_FLAG_REAR | VEHICLE_FLAG_COLLAPSE }, + { "bump_rear_dummy", CAR_BUMP_REAR, VEHICLE_FLAG_REAR | VEHICLE_FLAG_COLLAPSE }, + { "windscreen_dummy", CAR_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_FRONT | VEHICLE_FLAG_COLLAPSE }, + + { "ped_frontseat", CAR_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_backseat", CAR_POS_BACKSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "headlights", CAR_POS_HEADLIGHTS, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "taillights", CAR_POS_TAILLIGHTS, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "exhaust", CAR_POS_EXHAUST, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "extra1", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra2", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra3", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra4", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra5", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra6", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation boatIds[] = { + { "boat_moving_hi", 1, VEHICLE_FLAG_COLLAPSE }, + { "boat_rudder_hi", 3, VEHICLE_FLAG_COLLAPSE }, + { "windscreen", 2, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE }, + { "ped_frontseat", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation trainIds[] = { + { "door_lhs_dummy", 1, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE }, + { "door_rhs_dummy", 2, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE }, + { "light_front", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "light_rear", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_left_entry", 2, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_mid_entry", 3, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_right_entry", 4, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation heliIds[] = { + { "chassis_dummy", 1, VEHICLE_FLAG_COLLAPSE }, + { "toprotor", 2, 0 }, + { "backrotor", 3, 0 }, + { "tail", 4, 0 }, + { "topknot", 5, 0 }, + { "skid_left", 6, 0 }, + { "skid_right", 7, 0 }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation planeIds[] = { + { "wheel_front_dummy", 2, 0 }, + { "wheel_rear_dummy", 3, 0 }, + { "light_tailplane", 2, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "light_left", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "light_right", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation bikeIds[] = { + { "chassis_dummy", 1, 0 }, + { "forks_front", 2, 0 }, + { "forks_rear", 3, 0 }, + { "wheel_front", 4, 0 }, + { "wheel_rear", 5, 0 }, + { "mudguard", 6, 0 }, + { "ped_frontseat", 2, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "headlights", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "taillights", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "exhaust", 9, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "extra1", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra2", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra3", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra4", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra5", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra6", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation *CVehicleModelInfo::ms_vehicleDescs[] = { + carIds, + boatIds, + trainIds, + heliIds, + planeIds, + bikeIds +}; + + +CVehicleModelInfo::CVehicleModelInfo(void) + : CClumpModelInfo(MITYPE_VEHICLE) +{ + int32 i; + for(i = 0; i < NUM_VEHICLE_POSITIONS; i++){ + m_positions[i].x = 0.0f; + m_positions[i].y = 0.0f; + m_positions[i].z = 0.0f; + } + m_numColours = 0; +} + +void +CVehicleModelInfo::DeleteRwObject(void) +{ + int32 i; + RwFrame *f; + + for(i = 0; i < m_numComps; i++){ + f = RpAtomicGetFrame(m_comps[i]); + RpAtomicDestroy(m_comps[i]); + RwFrameDestroy(f); + } + m_numComps = 0; + CClumpModelInfo::DeleteRwObject(); +} + +RwObject* +CVehicleModelInfo::CreateInstance(void) +{ + RpClump *clump; + RpAtomic *atomic; + RwFrame *clumpframe, *f; + int32 comp1, comp2; + + clump = (RpClump*)CClumpModelInfo::CreateInstance(); + if(m_numComps != 0){ + clumpframe = RpClumpGetFrame(clump); + + comp1 = ChooseComponent(); + if(comp1 != -1){ + atomic = RpAtomicClone(m_comps[comp1]); + f = RwFrameCreate(); + RwFrameTransform(f, + RwFrameGetMatrix(RpAtomicGetFrame(m_comps[comp1])), + rwCOMBINEREPLACE); + RpAtomicSetFrame(atomic, f); + RpClumpAddAtomic(clump, atomic); + RwFrameAddChild(clumpframe, f); + } + ms_compsUsed[0] = comp1; + + comp2 = ChooseSecondComponent(); + if(comp2 != -1){ + atomic = RpAtomicClone(m_comps[comp2]); + f = RwFrameCreate(); + RwFrameTransform(f, + RwFrameGetMatrix(RpAtomicGetFrame(m_comps[comp2])), + rwCOMBINEREPLACE); + RpAtomicSetFrame(atomic, f); + RpClumpAddAtomic(clump, atomic); + RwFrameAddChild(clumpframe, f); + } + ms_compsUsed[1] = comp2; + }else{ + ms_compsUsed[0] = -1; + ms_compsUsed[1] = -1; + } + return (RwObject*)clump; +} + +void +CVehicleModelInfo::SetClump(RpClump *clump) +{ + CClumpModelInfo::SetClump(clump); + SetAtomicRenderCallbacks(); + SetFrameIds(ms_vehicleDescs[m_vehicleType]); + PreprocessHierarchy(); + FindEditableMaterialList(); + m_envMap = nil; + SetEnvironmentMap(); +} + +RwFrame* +CVehicleModelInfo::CollapseFramesCB(RwFrame *frame, void *data) +{ + RwFrameForAllChildren(frame, CollapseFramesCB, data); + RwFrameForAllObjects(frame, MoveObjectsCB, data); + RwFrameDestroy(frame); + return frame; +} + +RwObject* +CVehicleModelInfo::MoveObjectsCB(RwObject *object, void *data) +{ + RpAtomicSetFrame((RpAtomic*)object, (RwFrame*)data); + return object; +} + +RpAtomic* +CVehicleModelInfo::HideDamagedAtomicCB(RpAtomic *atomic, void *data) +{ + if(strstr(GetFrameNodeName(RpAtomicGetFrame(atomic)), "_dam")){ + RpAtomicSetFlags(atomic, 0); + CVisibilityPlugins::SetAtomicFlag(atomic, ATOMIC_FLAG_DAM); + }else if(strstr(GetFrameNodeName(RpAtomicGetFrame(atomic)), "_ok")) + CVisibilityPlugins::SetAtomicFlag(atomic, ATOMIC_FLAG_OK); + return atomic; +} + +RpMaterial* +CVehicleModelInfo::HasAlphaMaterialCB(RpMaterial *material, void *data) +{ + if(RpMaterialGetColor(material)->alpha != 0xFF){ + *(bool*)data = true; + return nil; + } + return material; +} + + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB(RpAtomic *atomic, void *data) +{ + RpClump *clump; + char *name; + bool alpha; + + clump = (RpClump*)data; + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + alpha = false; + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha); + if(strstr(name, "_hi") || strncmp(name, "extra", 5) == 0){ + if(alpha || strncmp(name, "windscreen", 10) == 0) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB); + }else if(strstr(name, "_lo")){ + RpClumpRemoveAtomic(clump, atomic); + RpAtomicDestroy(atomic); + return atomic; // BUG: not done by gta + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_BigVehicle(RpAtomic *atomic, void *data) +{ + char *name; + bool alpha; + + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + alpha = false; + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha); + if(strstr(name, "_hi") || strncmp(name, "extra", 5) == 0){ + if(alpha) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB_BigVehicle); + }else if(strstr(name, "_lo")){ + if(alpha) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleLowDetailAlphaCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleLowDetailCB_BigVehicle); + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_Train(RpAtomic *atomic, void *data) +{ + char *name; + bool alpha; + + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + alpha = false; + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha); + if(strstr(name, "_hi")){ + if(alpha) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderTrainHiDetailAlphaCB); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderTrainHiDetailCB); + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_Boat(RpAtomic *atomic, void *data) +{ + RpClump *clump; + char *name; + + clump = (RpClump*)data; + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + if(strcmp(name, "boat_hi") == 0 || strncmp(name, "extra", 5) == 0) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB_Boat); + else if(strstr(name, "_hi")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB); + else if(strstr(name, "_lo")){ + RpClumpRemoveAtomic(clump, atomic); + RpAtomicDestroy(atomic); + return atomic; // BUG: not done by gta + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_Heli(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + return atomic; +} + +void +CVehicleModelInfo::SetAtomicRenderCallbacks(void) +{ + switch(m_vehicleType){ + case VEHICLE_TYPE_TRAIN: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Train, nil); + break; + case VEHICLE_TYPE_HELI: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Heli, nil); + break; + case VEHICLE_TYPE_PLANE: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_BigVehicle, nil); + break; + case VEHICLE_TYPE_BOAT: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Boat, m_clump); + break; + default: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, m_clump); + break; + } +} + +RpAtomic* +CVehicleModelInfo::SetAtomicFlagCB(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::SetAtomicFlag(atomic, (int)data); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::ClearAtomicFlagCB(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::ClearAtomicFlag(atomic, (int)data); + return atomic; +} + +RwObject* +GetOkAndDamagedAtomicCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + if(CVisibilityPlugins::GetAtomicId(atomic) & ATOMIC_FLAG_OK) + ((RpAtomic**)data)[0] = atomic; + else if(CVisibilityPlugins::GetAtomicId(atomic) & ATOMIC_FLAG_DAM) + ((RpAtomic**)data)[1] = atomic; + return object; +} + +void +CVehicleModelInfo::PreprocessHierarchy(void) +{ + int32 i; + RwObjectNameIdAssocation *desc; + RwFrame *f; + RpAtomic *atomic; + RwV3d *rwvec; + + desc = ms_vehicleDescs[m_vehicleType]; + m_numDoors = 0; + m_numComps = 0; + + for(i = 0; desc[i].name; i++){ + RwObjectNameAssociation assoc; + + if((desc[i].flags & (VEHICLE_FLAG_COMP|VEHICLE_FLAG_POS)) == 0) + continue; + assoc.frame = nil; + assoc.name = desc[i].name; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), + FindFrameFromNameWithoutIdCB, &assoc); + if(assoc.frame == nil) + continue; + + if(desc[i].flags & VEHICLE_FLAG_DOOR) + m_numDoors++; + + if(desc[i].flags & VEHICLE_FLAG_POS){ + f = assoc.frame; + rwvec = (RwV3d*)&m_positions[desc[i].hierId]; + *rwvec = *RwMatrixGetPos(RwFrameGetMatrix(f)); + for(f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) + RwV3dTransformPoints(rwvec, rwvec, 1, RwFrameGetMatrix(f)); + RwFrameDestroy(assoc.frame); + }else{ + atomic = (RpAtomic*)GetFirstObject(assoc.frame); + RpClumpRemoveAtomic(m_clump, atomic); + RwFrameRemoveChild(assoc.frame); + SetVehicleComponentFlags(assoc.frame, desc[i].flags); + m_comps[m_numComps++] = atomic; + } + } + + for(i = 0; desc[i].name; i++){ + RwObjectIdAssociation assoc; + + if(desc[i].flags & (VEHICLE_FLAG_COMP|VEHICLE_FLAG_POS)) + continue; + assoc.frame = nil; + assoc.id = desc[i].hierId; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), + FindFrameFromIdCB, &assoc); + if(assoc.frame == nil) + continue; + + if(desc[i].flags & VEHICLE_FLAG_DOOR) + m_numDoors++; + + if(desc[i].flags & VEHICLE_FLAG_COLLAPSE){ + RpAtomic *okdam[2] = { nil, nil }; + RwFrameForAllChildren(assoc.frame, CollapseFramesCB, assoc.frame); + RwFrameUpdateObjects(assoc.frame); + RwFrameForAllObjects(assoc.frame, GetOkAndDamagedAtomicCB, okdam); + if(okdam[0] && okdam[1]) + RpAtomicSetRenderCallBack(okdam[1], RpAtomicGetRenderCallBack(okdam[0])); + } + + SetVehicleComponentFlags(assoc.frame, desc[i].flags); + + if(desc[i].flags & VEHICLE_FLAG_ADD_WHEEL){ + if(m_wheelId == -1) + RwFrameDestroy(assoc.frame); + else{ + RwV3d scale; + atomic = (RpAtomic*)CModelInfo::GetModelInfo(m_wheelId)->CreateInstance(); + RwFrameDestroy(RpAtomicGetFrame(atomic)); + RpAtomicSetFrame(atomic, assoc.frame); + RpClumpAddAtomic(m_clump, atomic); + CVisibilityPlugins::SetAtomicRenderCallback(atomic, + CVisibilityPlugins::RenderWheelAtomicCB); + scale.x = m_wheelScale; + scale.y = m_wheelScale; + scale.z = m_wheelScale; + RwFrameScale(assoc.frame, &scale, rwCOMBINEPRECONCAT); + } + } + } +} + + +#define COMPRULE_RULE(comprule) (((comprule) >> 12) & 0xF) +#define COMPRULE_COMPS(comprule) ((comprule) & 0xFFF) +#define COMPRULE_COMPN(comps, n) (((comps) >> 4*(n)) & 0xF) +#define COMPRULE2_RULE(comprule) (((comprule) >> (12+16)) & 0xF) +#define COMPRULE2_COMPS(comprule) ((comprule >> 16) & 0xFFF) +#define COMPRULE2_COMPN(comps, n) (((comps >> 16) >> 4*(n)) & 0xF) + +bool +IsValidCompRule(int rule) +{ + if(rule == 2) + return CWeather::OldWeatherType == WEATHER_RAINY || + CWeather::NewWeatherType == WEATHER_RAINY; + return true; +} + +int32 +CountCompsInRule(int comps) +{ + int32 n; + for(n = 0; comps != 0; comps >>= 4) + if((comps & 0xF) != 0xF) + n++; + return n; +} + +int32 +ChooseComponent(int32 rule, int32 comps) +{ + int32 n; + switch(rule){ + // identical cases.... + case 1: + n = CGeneral::GetRandomNumberInRange(0, CountCompsInRule(comps)); + return COMPRULE_COMPN(comps, n); + case 2: + // only valid in rain + n = CGeneral::GetRandomNumberInRange(0, CountCompsInRule(comps)); + return COMPRULE_COMPN(comps, n); + } + return -1; +} + +int32 +GetListOfComponentsNotUsedByRules(uint32 comprules, int32 numComps, int32 *comps) +{ + int32 i, n; + int32 unused[6] = { 0, 1, 2, 3, 4, 5 }; + + // first comprule + if(COMPRULE_RULE(comprules) && IsValidCompRule(COMPRULE_RULE(comprules))) + for(i = 0; i < 3; i++){ + n = COMPRULE_COMPN(comprules, i); + if(n != 0xF) + unused[n] = 0xF; + } + // second comprule + comprules >>= 16; + if(COMPRULE_RULE(comprules) && IsValidCompRule(COMPRULE_RULE(comprules))) + for(i = 0; i < 3; i++){ + n = COMPRULE_COMPN(comprules, i); + if(n != 0xF) + unused[n] = 0xF; + } + + n = 0; + for(i = 0; i < numComps; i++) + if(unused[i] != 0xF) + comps[n++] = unused[i]; + return n; +} + +int32 wheelIds[] = { CAR_WHEEL_LF, CAR_WHEEL_LB, CAR_WHEEL_RF, CAR_WHEEL_RB }; + +void +CVehicleModelInfo::GetWheelPosn(int32 n, CVector &pos) +{ + RwMatrix *m = RwFrameGetMatrix(GetFrameFromId(m_clump, wheelIds[n])); + pos.x = RwMatrixGetPos(m)->x; + pos.y = RwMatrixGetPos(m)->y; + pos.z = RwMatrixGetPos(m)->z; +} + + +int32 +CVehicleModelInfo::ChooseComponent(void) +{ + int32 comp; + int32 comps[8]; + int32 n; + + comp = -1; + if(ms_compsToUse[0] == -2){ + if(COMPRULE_RULE(m_compRules) && IsValidCompRule(COMPRULE_RULE(m_compRules))) + comp = ::ChooseComponent(COMPRULE_RULE(m_compRules), COMPRULE_COMPS(m_compRules)); + else if(CGeneral::GetRandomNumberInRange(0, 3) < 2){ + n = GetListOfComponentsNotUsedByRules(m_compRules, m_numComps, comps); + if(n) + comp = comps[(int)CGeneral::GetRandomNumberInRange(0, n)]; + } + }else{ + comp = ms_compsToUse[0]; + ms_compsToUse[0] = -2; + } + return comp; +} + +int32 +CVehicleModelInfo::ChooseSecondComponent(void) +{ + int32 comp; + int32 comps[8]; + int32 n; + + comp = -1; + if(ms_compsToUse[1] == -2){ + if(COMPRULE2_RULE(m_compRules) && IsValidCompRule(COMPRULE2_RULE(m_compRules))) + comp = ::ChooseComponent(COMPRULE2_RULE(m_compRules), COMPRULE2_COMPS(m_compRules)); + else if(COMPRULE_RULE(m_compRules) && IsValidCompRule(COMPRULE_RULE(m_compRules)) && + CGeneral::GetRandomNumberInRange(0, 3) < 2){ + + n = GetListOfComponentsNotUsedByRules(m_compRules, m_numComps, comps); + if(n) + comp = comps[(int)CGeneral::GetRandomNumberInRange(0, n)]; + } + }else{ + comp = ms_compsToUse[1]; + ms_compsToUse[1] = -2; + } + return comp; +} + +struct editableMatCBData +{ + CVehicleModelInfo *vehicle; + int32 numMats1; + int32 numMats2; +}; + +RpMaterial* +CVehicleModelInfo::GetEditableMaterialListCB(RpMaterial *material, void *data) +{ + static RwRGBA white = { 255, 255, 255, 255 }; + RwRGBA *col; + editableMatCBData *cbdata; + + cbdata = (editableMatCBData*)data; + col = RpMaterialGetColor(material); + if(col->red == 0x3C && col->green == 0xFF && col->blue == 0){ + cbdata->vehicle->m_materials1[cbdata->numMats1++] = material; + RpMaterialSetColor(material, &white); + }else if(col->red == 0xFF && col->green == 0 && col->blue == 0xAF){ + cbdata->vehicle->m_materials2[cbdata->numMats2++] = material; + RpMaterialSetColor(material, &white); + } + return material; +} + +RpAtomic* +CVehicleModelInfo::GetEditableMaterialListCB(RpAtomic *atomic, void *data) +{ + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), GetEditableMaterialListCB, data); + return atomic; +} + +void +CVehicleModelInfo::FindEditableMaterialList(void) +{ + editableMatCBData cbdata; + int32 i; + + cbdata.vehicle = this; + cbdata.numMats1 = 0; + cbdata.numMats2 = 0; + RpClumpForAllAtomics(m_clump, GetEditableMaterialListCB, &cbdata); + for(i = 0; i < m_numComps; i++) + GetEditableMaterialListCB(m_comps[i], &cbdata); + m_materials1[cbdata.numMats1] = nil; + m_materials2[cbdata.numMats2] = nil; + m_currentColour1 = -1; + m_currentColour2 = -1; +} + +void +CVehicleModelInfo::SetVehicleColour(uint8 c1, uint8 c2) +{ + RwRGBA col, *colp; + RwTexture *coltex; + RpMaterial **matp; + + if(c1 != m_currentColour1){ + col = ms_vehicleColourTable[c1]; + coltex = ms_colourTextureTable[c1]; + for(matp = m_materials1; *matp; matp++){ + if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){ + colp = RpMaterialGetColor(*matp); + colp->red = col.red; + colp->green = col.green; + colp->blue = col.blue; + }else + RpMaterialSetTexture(*matp, coltex); + } + m_currentColour1 = c1; + } + + if(c2 != m_currentColour2){ + col = ms_vehicleColourTable[c2]; + coltex = ms_colourTextureTable[c2]; + for(matp = m_materials2; *matp; matp++){ + if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){ + colp = RpMaterialGetColor(*matp); + colp->red = col.red; + colp->green = col.green; + colp->blue = col.blue; + }else + RpMaterialSetTexture(*matp, coltex); + } + m_currentColour2 = c2; + } +} + + +RpMaterial* +CVehicleModelInfo::HasSpecularMaterialCB(RpMaterial *material, void *data) +{ + if(RpMaterialGetSurfaceProperties(material)->specular <= 0.0f) + return material; + *(bool*)data = true; + return nil; +} + +RpMaterial* +CVehicleModelInfo::SetEnvironmentMapCB(RpMaterial *material, void *data) +{ + float spec; + + spec = RpMaterialGetSurfaceProperties(material)->specular; + if(spec <= 0.0f) + RpMatFXMaterialSetEffects(material, rpMATFXEFFECTNULL); + else{ + if(RpMaterialGetTexture(material) == 0) + RpMaterialSetTexture(material, gpWhiteTexture); + RpMatFXMaterialSetEffects(material, rpMATFXEFFECTENVMAP); + spec *= 0.5f; // Tone down a bit for PC + RpMatFXMaterialSetupEnvMap(material, (RwTexture*)data, pMatFxIdentityFrame, false, spec); + } + return material; +} + +RpAtomic* +CVehicleModelInfo::SetEnvironmentMapCB(RpAtomic *atomic, void *data) +{ + bool hasSpec; + RpGeometry *geo; + + geo = RpAtomicGetGeometry(atomic); + hasSpec = 0; + RpGeometryForAllMaterials(geo, HasSpecularMaterialCB, &hasSpec); + if(hasSpec){ + RpGeometryForAllMaterials(geo, SetEnvironmentMapCB, data); + RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) | rpGEOMETRYMODULATEMATERIALCOLOR); + RpMatFXAtomicEnableEffects(atomic); + // PS2 sets of PS2Manager lighting CB here + } + return atomic; +} + +void +CVehicleModelInfo::SetEnvironmentMap(void) +{ + CSimpleModelInfo *wheelmi; + int32 i; + + if(pMatFxIdentityFrame == nil){ + pMatFxIdentityFrame = RwFrameCreate(); + RwMatrixSetIdentity(RwFrameGetMatrix(pMatFxIdentityFrame)); + RwFrameUpdateObjects(pMatFxIdentityFrame); + RwFrameGetLTM(pMatFxIdentityFrame); + } + + if(m_envMap != ms_pEnvironmentMaps[0]){ + m_envMap = ms_pEnvironmentMaps[0]; + RpClumpForAllAtomics(m_clump, SetEnvironmentMapCB, m_envMap); + if(m_wheelId != -1){ + wheelmi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_wheelId); + for(i = 0; i < wheelmi->m_numAtomics; i++) + SetEnvironmentMapCB(wheelmi->m_atomics[i], m_envMap); + } + } +} + +void +CVehicleModelInfo::LoadEnvironmentMaps(void) +{ + char *texnames[] = { + "reflection01", // only one used + "reflection02", + "reflection03", + "reflection04", + "reflection05", + "reflection06", + }; + int32 txdslot; + int32 i; + + txdslot = CTxdStore::FindTxdSlot("particle"); + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(txdslot); + for(i = 0; i < NUM_VEHICLE_ENVMAPS; i++){ + ms_pEnvironmentMaps[i] = RwTextureRead(texnames[i], nil); + RwTextureSetFilterMode(ms_pEnvironmentMaps[i], rwFILTERLINEAR); + } + if(gpWhiteTexture == nil){ + gpWhiteTexture = RwTextureRead("white", nil); + gpWhiteTexture->name[0] = '@'; + RwTextureSetFilterMode(gpWhiteTexture, rwFILTERLINEAR); + } + CTxdStore::PopCurrentTxd(); +} + +void +CVehicleModelInfo::ShutdownEnvironmentMaps(void) +{ + int32 i; + + // ignoring "initialised" as that's a PS2 thing only + RwTextureDestroy(gpWhiteTexture); + gpWhiteTexture = nil; + for(i = 0; i < NUM_VEHICLE_ENVMAPS; i++) + if(ms_pEnvironmentMaps[i]) + RwTextureDestroy(ms_pEnvironmentMaps[i]); + RwFrameDestroy(pMatFxIdentityFrame); + pMatFxIdentityFrame = nil; +} + +STARTPATCHES + InjectHook(0x51FDC0, &CVehicleModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x51FCB0, &CVehicleModelInfo::CreateInstance_, PATCH_JUMP); + InjectHook(0x51FC60, &CVehicleModelInfo::SetClump_, PATCH_JUMP); + + InjectHook(0x51FE10, &CVehicleModelInfo::CollapseFramesCB, PATCH_JUMP); + InjectHook(0x51FE50, &CVehicleModelInfo::MoveObjectsCB, PATCH_JUMP); + InjectHook(0x51FE70, &CVehicleModelInfo::HideDamagedAtomicCB, PATCH_JUMP); + InjectHook(0x51FEF0, &CVehicleModelInfo::HasAlphaMaterialCB, PATCH_JUMP); + + InjectHook(0x51FF10, &CVehicleModelInfo::SetAtomicRendererCB, PATCH_JUMP); + InjectHook(0x520030, &CVehicleModelInfo::SetAtomicRendererCB_BigVehicle, PATCH_JUMP); + InjectHook(0x520230, &CVehicleModelInfo::SetAtomicRendererCB_Train, PATCH_JUMP); + InjectHook(0x520120, &CVehicleModelInfo::SetAtomicRendererCB_Boat, PATCH_JUMP); + InjectHook(0x520210, &CVehicleModelInfo::SetAtomicRendererCB_Heli, PATCH_JUMP); + InjectHook(0x5202C0, &CVehicleModelInfo::SetAtomicRenderCallbacks, PATCH_JUMP); + + InjectHook(0x520340, &CVehicleModelInfo::SetAtomicFlagCB, PATCH_JUMP); + InjectHook(0x520360, &CVehicleModelInfo::ClearAtomicFlagCB, PATCH_JUMP); + + InjectHook(0x5204D0, &CVehicleModelInfo::PreprocessHierarchy, PATCH_JUMP); + + InjectHook(0x520840, &CVehicleModelInfo::GetWheelPosn, PATCH_JUMP); + + InjectHook(0x520880, IsValidCompRule, PATCH_JUMP); + InjectHook(0x520990, CountCompsInRule, PATCH_JUMP); + InjectHook(0x5209C0, ChooseComponent, PATCH_JUMP); + InjectHook(0x5208C0, GetListOfComponentsNotUsedByRules, PATCH_JUMP); + InjectHook(0x520AB0, &CVehicleModelInfo::ChooseComponent, PATCH_JUMP); + InjectHook(0x520BE0, &CVehicleModelInfo::ChooseSecondComponent, PATCH_JUMP); + + InjectHook(0x520DC0, (RpAtomic *(*)(RpAtomic*, void*))CVehicleModelInfo::GetEditableMaterialListCB, PATCH_JUMP); + InjectHook(0x520D30, (RpMaterial *(*)(RpMaterial*, void*))CVehicleModelInfo::GetEditableMaterialListCB, PATCH_JUMP); + InjectHook(0x520DE0, &CVehicleModelInfo::FindEditableMaterialList, PATCH_JUMP); + InjectHook(0x520E70, &CVehicleModelInfo::SetVehicleColour, PATCH_JUMP); + + InjectHook(0x521820, (RpAtomic *(*)(RpAtomic*, void*))CVehicleModelInfo::SetEnvironmentMapCB, PATCH_JUMP); + InjectHook(0x5217A0, (RpMaterial *(*)(RpMaterial*, void*))CVehicleModelInfo::SetEnvironmentMapCB, PATCH_JUMP); + InjectHook(0x521770, CVehicleModelInfo::HasSpecularMaterialCB, PATCH_JUMP); + InjectHook(0x521890, &CVehicleModelInfo::SetEnvironmentMap, PATCH_JUMP); + InjectHook(0x521680, CVehicleModelInfo::LoadEnvironmentMaps, PATCH_JUMP); + InjectHook(0x521720, CVehicleModelInfo::ShutdownEnvironmentMaps, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h new file mode 100644 index 00000000..ccc46f73 --- /dev/null +++ b/src/modelinfo/VehicleModelInfo.h @@ -0,0 +1,115 @@ +#pragma once + +#include "ClumpModelInfo.h" + +enum { + NUM_VEHICLE_POSITIONS = 10, + NUM_FIRST_MATERIALS = 26, + NUM_SECOND_MATERIALS = 26, + NUM_VEHICLE_COLOURS = 8, + NUM_VEHICLE_ENVMAPS = 1 +}; + +enum { + ATOMIC_FLAG_OK = 0x1, + ATOMIC_FLAG_DAM = 0x2, + ATOMIC_FLAG_LEFT = 0x4, + ATOMIC_FLAG_RIGHT = 0x8, + ATOMIC_FLAG_FRONT = 0x10, + ATOMIC_FLAG_REAR = 0x20, + ATOMIC_FLAG_DRAWLAST = 0x40, + ATOMIC_FLAG_WINDSCREEN = 0x80, + ATOMIC_FLAG_ANGLECULL = 0x100, + ATOMIC_FLAG_REARDOOR = 0x200, + ATOMIC_FLAG_FRONTDOOR = 0x400, + ATOMIC_FLAG_NOCULL = 0x800, +}; + +enum { + VEHICLE_TYPE_CAR, + VEHICLE_TYPE_BOAT, + VEHICLE_TYPE_TRAIN, + VEHICLE_TYPE_HELI, + VEHICLE_TYPE_PLANE, + VEHICLE_TYPE_BIKE, + NUM_VEHICLE_TYPES +}; + +class CVehicleModelInfo : public CClumpModelInfo +{ +public: + uint8 m_lastColour1; + uint8 m_lastColour2; + char m_gameName[32]; + int32 m_vehicleType; + int32 m_wheelId; + float m_wheelScale; + int32 m_numDoors; + int32 m_handlingId; + int32 m_vehicleClass; + int32 m_level; + CVector m_positions[NUM_VEHICLE_POSITIONS]; + uint32 m_compRules; + float m_bikeSteerAngle; + RpMaterial *m_materials1[NUM_FIRST_MATERIALS]; + RpMaterial *m_materials2[NUM_SECOND_MATERIALS]; + uint8 m_colours1[NUM_VEHICLE_COLOURS]; + uint8 m_colours2[NUM_VEHICLE_COLOURS]; + uint8 m_numColours; + uint8 m_bLastColorVariation; // + uint8 m_currentColour1; + uint8 m_currentColour2; + RwTexture *m_envMap; + RpAtomic *m_comps[6]; + int32 m_numComps; + + static int8 *ms_compsToUse; // [2]; + static int8 *ms_compsUsed; // [2]; + static RwTexture **ms_pEnvironmentMaps; // [NUM_VEHICLE_ENVMAPS] + static RwRGBA *ms_vehicleColourTable; // [256] + static RwTexture **ms_colourTextureTable; // [256] + static RwObjectNameIdAssocation *ms_vehicleDescs[NUM_VEHICLE_TYPES]; + + CVehicleModelInfo(void); + void DeleteRwObject(void); + RwObject *CreateInstance(void); + void SetClump(RpClump *); + + static RwFrame *CollapseFramesCB(RwFrame *frame, void *data); + static RwObject *MoveObjectsCB(RwObject *object, void *data); + static RpAtomic *HideDamagedAtomicCB(RpAtomic *atomic, void *data); + static RpMaterial *HasAlphaMaterialCB(RpMaterial *material, void *data); + + static RpAtomic *SetAtomicRendererCB(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_BigVehicle(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_Train(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_Boat(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_Heli(RpAtomic *atomic, void *data); + void SetAtomicRenderCallbacks(void); + + static RpAtomic *SetAtomicFlagCB(RpAtomic *atomic, void *data); + static RpAtomic *ClearAtomicFlagCB(RpAtomic *atomic, void *data); + void SetVehicleComponentFlags(RwFrame *frame, uint32 flags); + void PreprocessHierarchy(void); + void GetWheelPosn(int32 n, CVector &pos); + + int32 ChooseComponent(void); + int32 ChooseSecondComponent(void); + + static RpMaterial *GetEditableMaterialListCB(RpMaterial *material, void *data); + static RpAtomic *GetEditableMaterialListCB(RpAtomic *atomic, void *data); + void FindEditableMaterialList(void); + void SetVehicleColour(uint8 c1, uint8 c2); + + static RpAtomic *SetEnvironmentMapCB(RpAtomic *atomic, void *data); + static RpMaterial *SetEnvironmentMapCB(RpMaterial *material, void *data); + static RpMaterial *HasSpecularMaterialCB(RpMaterial *material, void *data); + void SetEnvironmentMap(void); + static void LoadEnvironmentMaps(void); + static void ShutdownEnvironmentMaps(void); + + void DeleteRwObject_(void) { this->CVehicleModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_(void) { return this->CVehicleModelInfo::CreateInstance(); } + void SetClump_(RpClump *clump) { this->CVehicleModelInfo::SetClump(clump); } +}; +static_assert(sizeof(CVehicleModelInfo) == 0x1F8, "CVehicleModelInfo: error"); -- cgit v1.2.3