summaryrefslogtreecommitdiff
path: root/src/modelinfo
diff options
context:
space:
mode:
Diffstat (limited to 'src/modelinfo')
-rw-r--r--src/modelinfo/BaseModelInfo.cpp102
-rw-r--r--src/modelinfo/BaseModelInfo.h74
-rw-r--r--src/modelinfo/ClumpModelInfo.cpp205
-rw-r--r--src/modelinfo/ClumpModelInfo.h60
-rw-r--r--src/modelinfo/ModelIndices.cpp34
-rw-r--r--src/modelinfo/ModelIndices.h621
-rw-r--r--src/modelinfo/ModelInfo.cpp258
-rw-r--r--src/modelinfo/ModelInfo.h48
-rw-r--r--src/modelinfo/PedModelInfo.cpp162
-rw-r--r--src/modelinfo/PedModelInfo.h52
-rw-r--r--src/modelinfo/SimpleModelInfo.cpp194
-rw-r--r--src/modelinfo/SimpleModelInfo.h61
-rw-r--r--src/modelinfo/TimeModelInfo.cpp33
-rw-r--r--src/modelinfo/TimeModelInfo.h20
-rw-r--r--src/modelinfo/VehicleModelInfo.cpp1193
-rw-r--r--src/modelinfo/VehicleModelInfo.h166
-rw-r--r--src/modelinfo/WeaponModelInfo.cpp53
-rw-r--r--src/modelinfo/WeaponModelInfo.h23
18 files changed, 3359 insertions, 0 deletions
diff --git a/src/modelinfo/BaseModelInfo.cpp b/src/modelinfo/BaseModelInfo.cpp
new file mode 100644
index 0000000..765469b
--- /dev/null
+++ b/src/modelinfo/BaseModelInfo.cpp
@@ -0,0 +1,102 @@
+#include "common.h"
+
+#include "templates.h"
+#include "TxdStore.h"
+#include "2dEffect.h"
+#include "BaseModelInfo.h"
+#include "ModelInfo.h"
+#include "ColModel.h"
+
+CBaseModelInfo::CBaseModelInfo(ModelInfoType type)
+{
+ m_colModel = nil;
+ m_2dEffectsID = -1;
+ m_objectId = -1;
+ m_refCount = 0;
+ m_txdSlot = -1;
+ m_type = type;
+ m_num2dEffects = 0;
+ m_bOwnsColModel = false;
+}
+
+void
+CBaseModelInfo::Shutdown(void)
+{
+ DeleteCollisionModel();
+ DeleteRwObject();
+ m_2dEffectsID = -1;
+ m_num2dEffects = 0;
+ m_txdSlot = -1;
+}
+
+void
+CBaseModelInfo::DeleteCollisionModel(void)
+{
+ if(m_colModel && m_bOwnsColModel){
+ 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 == -1)
+ 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_2dEffectsID = -1;
+ m_num2dEffects = 0;
+}
+
+void
+CBaseModelInfo::Add2dEffect(C2dEffect *fx)
+{
+ if(m_2dEffectsID >= 0)
+ m_num2dEffects++;
+ else{
+ m_2dEffectsID = CModelInfo::Get2dEffectStore().GetIndex(fx);
+ m_num2dEffects = 1;
+ }
+}
+
+C2dEffect*
+CBaseModelInfo::Get2dEffect(int n)
+{
+ if(m_2dEffectsID >= 0)
+ return CModelInfo::Get2dEffectStore().GetItem(m_2dEffectsID+n);
+ else
+ return nil;
+}
diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h
new file mode 100644
index 0000000..2d1dc8a
--- /dev/null
+++ b/src/modelinfo/BaseModelInfo.h
@@ -0,0 +1,74 @@
+#pragma once
+
+struct CColModel;
+
+#define MAX_MODEL_NAME (21)
+
+enum ModelInfoType
+{
+ MITYPE_NA,
+ MITYPE_SIMPLE,
+ MITYPE_MLO, // unused but still in enum
+ MITYPE_TIME,
+ MITYPE_WEAPON,
+ MITYPE_CLUMP,
+ MITYPE_VEHICLE,
+ MITYPE_PED,
+ MITYPE_XTRACOMPS, // unused but still in enum
+ MITYPE_HAND // xbox and mobile
+};
+
+class C2dEffect;
+
+class CBaseModelInfo
+{
+protected:
+ char m_name[MAX_MODEL_NAME];
+ uint8 m_type;
+ uint8 m_num2dEffects;
+ bool m_bOwnsColModel;
+ CColModel *m_colModel;
+ int16 m_2dEffectsID;
+ int16 m_objectId;
+ uint16 m_refCount;
+ int16 m_txdSlot;
+
+public:
+ CBaseModelInfo(ModelInfoType type);
+ virtual ~CBaseModelInfo() {}
+ virtual void Shutdown(void);
+ virtual void DeleteRwObject(void) = 0;
+ virtual RwObject *CreateInstance(void) = 0;
+ virtual RwObject *CreateInstance(RwMatrix *) = 0;
+ virtual RwObject *GetRwObject(void) = 0;
+ virtual void SetAnimFile(const char *file) {}
+ virtual void ConvertAnimFileIndex(void) {}
+ virtual int GetAnimFileIndex(void) { return -1; }
+
+ // one day it becomes virtual
+ uint8 GetModelType() const { return m_type; }
+ bool IsBuilding(void) { return m_type == MITYPE_SIMPLE || m_type == MITYPE_TIME; }
+ bool IsSimple(void) { return m_type == MITYPE_SIMPLE || m_type == MITYPE_TIME || m_type == MITYPE_WEAPON; }
+ bool IsClump(void) { return m_type == MITYPE_CLUMP || m_type == MITYPE_PED || m_type == MITYPE_VEHICLE; }
+ char *GetModelName(void) { return m_name; }
+ void SetModelName(const char *name) { strncpy(m_name, name, MAX_MODEL_NAME); }
+ void SetColModel(CColModel *col, bool owns = false){
+ m_colModel = col; m_bOwnsColModel = owns; }
+ CColModel *GetColModel(void) { return m_colModel; }
+ bool DoesOwnColModel(void) { return m_bOwnsColModel; }
+ void DeleteCollisionModel(void);
+ void ClearTexDictionary(void) { m_txdSlot = -1; }
+ int16 GetObjectID(void) { return m_objectId; }
+ void SetObjectID(int16 id) { m_objectId = id; }
+ int16 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);
+ uint8 GetNum2dEffects() const { return m_num2dEffects; }
+ uint16 GetNumRefs() const { return m_refCount; }
+};
diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp
new file mode 100644
index 0000000..ba18bfa
--- /dev/null
+++ b/src/modelinfo/ClumpModelInfo.cpp
@@ -0,0 +1,205 @@
+#include "common.h"
+
+#include "RwHelper.h"
+#include "General.h"
+#include "NodeName.h"
+#include "VisibilityPlugins.h"
+#include "ModelInfo.h"
+#include "AnimManager.h"
+
+void
+CClumpModelInfo::DeleteRwObject(void)
+{
+ if(m_clump){
+ RpClumpDestroy(m_clump);
+ m_clump = nil;
+ RemoveTexDictionaryRef();
+ if(GetAnimFileIndex() != -1)
+ CAnimManager::RemoveAnimBlockRef(GetAnimFileIndex());
+ }
+}
+
+static RpAtomic*
+SetHierarchyForSkinAtomic(RpAtomic *atomic, void *data)
+{
+ RpSkinAtomicSetHAnimHierarchy(atomic, (RpHAnimHierarchy*)data);
+ return nil;
+}
+
+RwObject*
+CClumpModelInfo::CreateInstance(void)
+{
+ if(m_clump == nil)
+ return nil;
+ RpClump *clone = RpClumpClone(m_clump);
+ if(IsClumpSkinned(clone)){
+ RpHAnimHierarchy *hier;
+ RpHAnimAnimation *anim;
+
+ hier = GetAnimHierarchyFromClump(clone);
+ assert(hier);
+ RpClumpForAllAtomics(clone, SetHierarchyForSkinAtomic, hier);
+ anim = HAnimAnimationCreateForHierarchy(hier);
+ RpHAnimHierarchySetCurrentAnim(hier, anim);
+ RpHAnimHierarchySetFlags(hier, (RpHAnimHierarchyFlag)(rpHANIMHIERARCHYUPDATEMODELLINGMATRICES|rpHANIMHIERARCHYUPDATELTMS));
+ }
+ return (RwObject*)clone;
+}
+
+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();
+ if(GetAnimFileIndex() != -1)
+ CAnimManager::AddAnimBlockRef(GetAnimFileIndex());
+ if(IsClumpSkinned(clump)){
+ int i;
+ RpHAnimHierarchy *hier;
+ RpAtomic *skinAtomic;
+ RpSkin *skin;
+
+ hier = GetAnimHierarchyFromClump(clump);
+ assert(hier);
+ RpClumpForAllAtomics(clump, SetHierarchyForSkinAtomic, hier);
+ skinAtomic = GetFirstAtomic(clump);
+
+ assert(skinAtomic);
+ skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(skinAtomic));
+ // ignore const
+ for(i = 0; i < RpGeometryGetNumVertices(RpAtomicGetGeometry(skinAtomic)); i++){
+ RwMatrixWeights *weights = (RwMatrixWeights*)&RpSkinGetVertexBoneWeights(skin)[i];
+ float sum = weights->w0 + weights->w1 + weights->w2 + weights->w3;
+ weights->w0 /= sum;
+ weights->w1 /= sum;
+ weights->w2 /= sum;
+ weights->w3 /= sum;
+ }
+ RpHAnimHierarchySetFlags(hier, (RpHAnimHierarchyFlag)(rpHANIMHIERARCHYUPDATEMODELLINGMATRICES|rpHANIMHIERARCHYUPDATELTMS));
+ }
+}
+
+void
+CClumpModelInfo::SetAnimFile(const char *file)
+{
+ if(strcasecmp(file, "null") == 0)
+ return;
+
+ m_animFileName = new char[strlen(file)+1];
+ strcpy(m_animFileName, file);
+}
+
+void
+CClumpModelInfo::ConvertAnimFileIndex(void)
+{
+ if(m_animFileIndex != -1){
+ // we have a string pointer in that union
+ int32 index = CAnimManager::GetAnimationBlockIndex(m_animFileName);
+ delete[] m_animFileName;
+ m_animFileIndex = index;
+ }
+}
+
+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){
+ assoc->frame = frame;
+ return nil;
+ }
+ RwFrameForAllChildren(frame, FindFrameFromIdCB, assoc);
+ return assoc->frame ? nil : frame;
+}
+
+// unused
+RwFrame*
+CClumpModelInfo::FindFrameFromNameCB(RwFrame *frame, void *data)
+{
+ RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data;
+
+ if(!CGeneral::faststricmp(GetFrameNodeName(frame), assoc->name)){
+ assoc->frame = frame;
+ return nil;
+ }
+ RwFrameForAllChildren(frame, FindFrameFromNameCB, assoc);
+ return assoc->frame ? nil : frame;
+}
+
+RwFrame*
+CClumpModelInfo::FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data)
+{
+ RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data;
+
+ if(CVisibilityPlugins::GetFrameHierarchyId(frame) == 0 &&
+ !CGeneral::faststricmp(GetFrameNodeName(frame), assoc->name)){
+ assoc->frame = frame;
+ return nil;
+ }
+ RwFrameForAllChildren(frame, FindFrameFromNameWithoutIdCB, assoc);
+ return assoc->frame ? nil : frame;
+}
+
+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;
+}
diff --git a/src/modelinfo/ClumpModelInfo.h b/src/modelinfo/ClumpModelInfo.h
new file mode 100644
index 0000000..0113d34
--- /dev/null
+++ b/src/modelinfo/ClumpModelInfo.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "BaseModelInfo.h"
+
+struct RwObjectNameIdAssocation
+{
+ const char *name;
+ int32 hierId;
+ uint32 flags;
+};
+
+struct RwObjectNameAssociation
+{
+ const char *name;
+ RwFrame *frame;
+};
+
+struct RwObjectIdAssociation
+{
+ int32 id;
+ RwFrame *frame;
+};
+
+enum {
+ CLUMP_FLAG_NO_HIERID = 0x1,
+};
+
+
+class CClumpModelInfo : public CBaseModelInfo
+{
+public:
+ RpClump *m_clump;
+ union {
+ int32 m_animFileIndex;
+ char *m_animFileName;
+ };
+
+ CClumpModelInfo(void) : CBaseModelInfo(MITYPE_CLUMP) { m_animFileIndex = -1; }
+ CClumpModelInfo(ModelInfoType id) : CBaseModelInfo(id) { m_animFileIndex = -1; }
+ ~CClumpModelInfo() {}
+ void DeleteRwObject(void);
+ RwObject *CreateInstance(void);
+ RwObject *CreateInstance(RwMatrix *);
+ RwObject *GetRwObject(void) { return (RwObject*)m_clump; }
+
+ virtual void SetClump(RpClump *);
+ virtual void SetAnimFile(const char *file);
+ virtual void ConvertAnimFileIndex(void);
+ virtual int GetAnimFileIndex(void) { return m_animFileIndex; }
+
+ 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);
+};
+//static_assert(sizeof(CClumpModelInfo) == 0x34, "CClumpModelInfo: error");
diff --git a/src/modelinfo/ModelIndices.cpp b/src/modelinfo/ModelIndices.cpp
new file mode 100644
index 0000000..98c7fb3
--- /dev/null
+++ b/src/modelinfo/ModelIndices.cpp
@@ -0,0 +1,34 @@
+#include "common.h"
+
+#include "General.h"
+#include "ModelIndices.h"
+
+#define X(name, var) int16 var = -1;
+ MODELINDICES
+#undef X
+
+void
+InitModelIndices(void)
+{
+#define X(name, var) var = -1;
+ MODELINDICES
+#undef X
+}
+
+void
+MatchModelString(const char *modelname, int16 id)
+{
+#define X(name, var) \
+ if(!CGeneral::faststrcmp(name, modelname)){ \
+ var = id; \
+ return; \
+ }
+ MODELINDICES
+#undef X
+}
+
+void
+TestModelIndices(void)
+{
+ ;
+}
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
new file mode 100644
index 0000000..836c409
--- /dev/null
+++ b/src/modelinfo/ModelIndices.h
@@ -0,0 +1,621 @@
+#pragma once
+
+#include "ModelInfo.h"
+
+#define MODELINDICES \
+ X("fire_hydrant", MI_FIRE_HYDRANT) \
+ X("phonesign", MI_PHONESIGN) \
+ X("noparkingsign1", MI_NOPARKINGSIGN1) \
+ X("bussign1", MI_BUSSIGN1) \
+ X("roadworkbarrier1", MI_ROADWORKBARRIER1) \
+ X("dump1", MI_DUMP1) \
+ X("trafficcone", MI_TRAFFICCONE) \
+ X("newsstand1", MI_NEWSSTAND) \
+ X("postbox1", MI_POSTBOX1) \
+ X("bin1", MI_BIN) \
+ X("wastebin", MI_WASTEBIN) \
+ X("phonebooth1", MI_PHONEBOOTH1) \
+ X("parkingmeter", MI_PARKINGMETER) \
+ X("parkingmeterg", MI_PARKINGMETER2) \
+ X("mall_fans", MI_MALLFAN) \
+ X("htl_fan_rotate_nt", MI_HOTELFAN_NIGHT) \
+ X("htl_fan_rotate_dy", MI_HOTELFAN_DAY) \
+ X("hotroomfan", MI_HOTROOMFAN) \
+ X("trafficlight1", MI_TRAFFICLIGHTS) \
+ X("MTraffic4", MI_TRAFFICLIGHTS_VERTICAL) \
+ X("MTraffic1", MI_TRAFFICLIGHTS_MIAMI) \
+ X("MTraffic2", MI_TRAFFICLIGHTS_TWOVERTICAL) \
+ X("lamppost1", MI_SINGLESTREETLIGHTS1) \
+ X("lamppost2", MI_SINGLESTREETLIGHTS2) \
+ X("lamppost3", MI_SINGLESTREETLIGHTS3) \
+ X("doublestreetlght1", MI_DOUBLESTREETLIGHTS) \
+ X("Streetlamp1", MI_STREETLAMP1) \
+ X("Streetlamp2", MI_STREETLAMP2) \
+ X("veg_tree3", MI_TREE2) \
+ X("veg_treea1", MI_TREE3) \
+ X("veg_treeb1", MI_TREE6) \
+ X("veg_treea3", MI_TREE8) \
+ X("doc_crane_cab0", MODELID_CRANE_1) \
+ X("doc_crane_cab01", MODELID_CRANE_2) \
+ X("doc_crane_cab02", MODELID_CRANE_3) \
+ X("doc_crane_cab03", MODELID_CRANE_4) \
+ X("boatcranelg0", MODELID_CRANE_5) \
+ X("LODnetopa0", MODELID_CRANE_6) \
+ X("package1", MI_COLLECTABLE1) \
+ X("Money", MI_MONEY) \
+ X("barrel1", MI_CARMINE) \
+ X("dk_paynspraydoor", MI_GARAGEDOOR2) \
+ X("dk_waretankdoor1", MI_GARAGEDOOR3) \
+ X("hav_garagedoor1", MI_GARAGEDOOR4) \
+ X("hav_garagedoor02", MI_GARAGEDOOR5) \
+ X("hav_garagedoor03", MI_GARAGEDOOR6) \
+ X("hav_garagedoor04", MI_GARAGEDOOR7) \
+ X("lh_showdoor03", MI_GARAGEDOOR9) \
+ X("lh_showdoor1", MI_GARAGEDOOR10) \
+ X("lhtankdoor", MI_GARAGEDOOR11) \
+ X("nbtgardoor", MI_GARAGEDOOR12) \
+ X("dk_camjonesdoor", MI_GARAGEDOOR13) \
+ X("nbtgardoor02", MI_GARAGEDOOR14) \
+ X("dt_savedra", MI_GARAGEDOOR15) \
+ X("dt_savedrb", MI_GARAGEDOOR16) \
+ X("dk_bombdoor", MI_GARAGEDOOR18) \
+ X("haiwshpnsdoor", MI_GARAGEDOOR19) \
+ X("wshpnsdoor", MI_GARAGEDOOR20) \
+ X("nbecpnsdoor", MI_GARAGEDOOR21) \
+ X("nbtgardoor03", MI_GARAGEDOOR22) \
+ X("dt_savedrc", MI_GARAGEDOOR23) \
+ X("dt_savedrd", MI_GARAGEDOOR24) \
+ X("man_frntstepGD", MI_GARAGEDOOR25) \
+ X("svegrgedoor", MI_GARAGEDOOR26) \
+ X("barrel2", MI_NAUTICALMINE) \
+ X("briefcase", MI_BRIEFCASE) \
+ X("wglasssmash", MI_GLASS1) \
+ X("glassfx_composh", MI_GLASS8) \
+ X("barrel4", MI_EXPLODINGBARREL) \
+ X("adrenaline", MI_PICKUP_ADRENALINE) \
+ X("bodyarmour", MI_PICKUP_BODYARMOUR) \
+ X("info", MI_PICKUP_INFO) \
+ X("health", MI_PICKUP_HEALTH) \
+ X("bonus", MI_PICKUP_BONUS) \
+ X("bribe", MI_PICKUP_BRIBE) \
+ X("killfrenzy", MI_PICKUP_KILLFRENZY) \
+ X("camerapickup", MI_PICKUP_CAMERA) \
+ X("bigdollar", MI_PICKUP_REVENUE) \
+ X("pickupsave", MI_PICKUP_SAVEGAME) \
+ X("property_locked", MI_PICKUP_PROPERTY) \
+ X("property_fsale", MI_PICKUP_PROPERTY_FORSALE) \
+ X("clothesp", MI_PICKUP_CLOTHES) \
+ X("bollardlight", MI_BOLLARDLIGHT) \
+ X("bar_barrier10", MI_FENCE) \
+ X("bar_barrier12", MI_FENCE2) \
+ X("petrolpump", MI_PETROLPUMP) \
+ X("washgaspump", MI_PETROLPUMP2) \
+ X("bouy", MI_BUOY) \
+ X("parktable1", MI_PARKTABLE) \
+ X("lamppost1", MI_LAMPPOST1) \
+ X("veg_palm04", MI_VEG_PALM01) \
+ X("veg_palwee02", MI_VEG_PALM02) \
+ X("veg_palmkbb11", MI_VEG_PALM03) \
+ X("veg_palmkb4", MI_VEG_PALM04) \
+ X("veg_palm02", MI_VEG_PALM05) \
+ X("veg_palmkb3", MI_VEG_PALM06) \
+ X("veg_palmbig14", MI_VEG_PALM07) \
+ X("veg_palm01", MI_VEG_PALM08) \
+ X("mlamppost", MI_MLAMPPOST) \
+ X("roadworkbarrier1", MI_BARRIER1) \
+ X("littleha_police", MI_LITTLEHA_POLICE) \
+ X("telgrphpole02", MI_TELPOLE02) \
+ X("trafficlight1", MI_TRAFFICLIGHT01) \
+ X("parkbench1", MI_PARKBENCH) \
+ X("plc_stinger", MI_PLC_STINGER) \
+ X("od_lightbeam", MI_LIGHTBEAM) \
+ X("ap_radar1_01", MI_AIRPORTRADAR) \
+ X("rcbomb", MI_RCBOMB) \
+ X("beachball", MI_BEACHBALL) \
+ X("sandcastle1", MI_SANDCASTLE1) \
+ X("sandcastle2", MI_SANDCASTLE2) \
+ X("jellyfish", MI_JELLYFISH) \
+ X("jellyfish01", MI_JELLYFISH01) \
+ X("fish1single", MI_FISH1SINGLE) \
+ X("fish1s", MI_FISH1S) \
+ X("fish2single", MI_FISH2SINGLE) \
+ X("fish2s", MI_FISH2S) \
+ X("fish3single", MI_FISH3SINGLE) \
+ X("fish3s", MI_FISH3S) \
+ X("turtle", MI_TURTLE) \
+ X("dolphin", MI_DOLPHIN) \
+ X("shark", MI_SHARK) \
+ X("submarine", MI_SUBMARINE) \
+ X("Esc_step", MI_ESCALATORSTEP) \
+ X("lounge_wood_up", MI_LOUNGE_WOOD_UP) \
+ X("lounge_towel_up", MI_LOUNGE_TOWEL_UP) \
+ X("lounge_wood_dn", MI_LOUNGE_WOOD_DN) \
+ X("lotion", MI_LOTION) \
+ X("beachtowel01", MI_BEACHTOWEL01) \
+ X("beachtowel02", MI_BEACHTOWEL02) \
+ X("beachtowel03", MI_BEACHTOWEL03) \
+ X("beachtowel04", MI_BEACHTOWEL04) \
+ X("blimp_night", MI_BLIMP_NIGHT) \
+ X("blimp_day", MI_BLIMP_DAY) \
+ X("yt_main_body", MI_YT_MAIN_BODY) \
+ X("yt_main_body2", MI_YT_MAIN_BODY2)
+
+#define X(name, var) extern int16 var;
+ MODELINDICES
+#undef X
+
+// and some hardcoded ones
+// expand as needed
+enum
+{
+ MI_PLAYER = 0,
+ MI_COP,
+ MI_SWAT,
+ MI_FBI,
+ MI_ARMY,
+ MI_MEDIC,
+ MI_FIREMAN,
+ MI_MALE01,
+
+ MI_HFYST = 9,
+ MI_HFOST,
+ MI_HMYST,
+ MI_HMOST,
+ MI_HFYRI,
+ MI_HFORI,
+ MI_HMYRI,
+ MI_HMORI,
+ MI_HFYBE,
+ MI_HFOBE,
+ MI_HMYBE,
+ MI_HMOBE,
+ MI_HFYBU,
+ MI_HFYMD,
+ MI_HFYCG,
+ MI_HFYPR,
+ MI_HFOTR,
+ MI_HMOTR,
+ MI_HMYAP,
+ MI_HMOCA,
+ MI_TAXI_D = MI_HMOCA,
+ MI_BMODK,
+ MI_BMYKR,
+ MI_BFYST,
+ MI_BFOST,
+ MI_BMYST,
+ MI_BMOST,
+ MI_BFYRI,
+ MI_BFORI,
+ MI_BMYRI,
+ MI_BFYBE,
+ MI_BMYBE,
+ MI_BFOBE,
+ MI_BMOBE,
+ MI_BMYBU,
+ MI_BFYPR,
+ MI_BFOTR,
+ MI_BMOTR,
+ MI_BMYPI,
+ MI_BMYBB,
+ MI_WMYCR,
+ MI_WFYST,
+ MI_WFOST,
+ MI_WMYST,
+ MI_WMOST,
+ MI_WFYRI,
+ MI_WFORI,
+ MI_WMYRI,
+ MI_WMORI,
+ MI_WFYBE,
+ MI_WMYBE,
+ MI_WFOBE,
+ MI_WMOBE,
+ MI_WMYCW,
+ MI_WMYGO,
+ MI_WFOGO,
+ MI_WMOGO,
+ MI_WFYLG,
+ MI_WMYLG,
+ MI_WFYBU,
+ MI_WMYBU,
+ MI_WMOBU,
+ MI_WFYPR,
+ MI_WFOTR,
+ MI_WMOTR,
+ MI_WMYPI,
+ MI_WMOCA,
+ MI_WFYJG,
+ MI_WMYJG,
+ MI_WFYSK,
+ MI_WMYSK,
+ MI_WFYSH,
+ MI_WFOSH,
+ MI_JFOTO,
+ MI_JMOTO,
+
+ MI_CBA,// = 83,
+ MI_CBB,
+ MI_HNA,
+ MI_HNB,
+ MI_SGA,
+ MI_SGB,
+ MI_CLA,
+ MI_CLB,
+ MI_GDA,
+ MI_GDB,
+ MI_BKA,
+ MI_BKB,
+ MI_PGA,
+ MI_PGB,
+ MI_VICE1,
+ MI_VICE2,
+ MI_VICE3,
+ MI_VICE4,
+ MI_VICE5,
+ MI_VICE6,
+ MI_VICE7,
+ MI_VICE8,
+ MI_WFYG1,
+ MI_WFYG2,// = 106, // last regular ped
+ // three more peds possible
+ MI_SPECIAL01 = 109,
+ MI_SPECIAL02,
+ MI_SPECIAL03,
+ MI_SPECIAL04,
+ MI_SPECIAL05,
+ MI_SPECIAL06,
+ MI_SPECIAL07,
+ MI_SPECIAL08,
+ MI_SPECIAL09,
+ MI_SPECIAL10,
+ MI_SPECIAL11,
+ MI_SPECIAL12,
+ MI_SPECIAL13,
+ MI_SPECIAL14,
+ MI_SPECIAL15,
+ MI_SPECIAL16,
+ MI_SPECIAL17,
+ MI_SPECIAL18,
+ MI_SPECIAL19,
+ MI_SPECIAL20,
+ MI_SPECIAL21,// = 129,
+
+ MI_LAST_PED = MI_SPECIAL21,
+ MI_FIRST_VEHICLE,
+
+ MI_LANDSTAL = MI_FIRST_VEHICLE,
+ MI_IDAHO,
+ MI_STINGER,
+ MI_LINERUN,
+ MI_PEREN,
+ MI_SENTINEL,
+ MI_RIO,
+ MI_FIRETRUCK,
+ MI_TRASH,
+ MI_STRETCH,
+ MI_MANANA,
+ MI_INFERNUS,
+ MI_VOODOO,
+ MI_PONY,
+ MI_MULE,
+ MI_CHEETAH,
+ MI_AMBULAN,
+ MI_FBICAR,
+ MI_MOONBEAM,
+ MI_ESPERANT,
+ MI_TAXI,
+ MI_WASHING,
+ MI_BOBCAT,
+ MI_MRWHOOP,
+ MI_BFINJECT,
+ MI_HUNTER,
+ MI_POLICE,
+ MI_ENFORCER,
+ MI_SECURICA,
+ MI_BANSHEE,
+ MI_PREDATOR,
+ MI_BUS,
+ MI_RHINO,
+ MI_BARRACKS,
+ MI_CUBAN,
+ MI_CHOPPER,
+ MI_ANGEL,
+ MI_COACH,
+ MI_CABBIE,
+ MI_STALLION,
+ MI_RUMPO,
+ MI_RCBANDIT,
+ MI_ROMERO,
+ MI_PACKER,
+ MI_SENTXS,
+ MI_ADMIRAL,
+ MI_SQUALO,
+ MI_SEASPAR,
+ MI_PIZZABOY,
+ MI_GANGBUR,
+ MI_AIRTRAIN,
+ MI_DEADDODO,
+ MI_SPEEDER,
+ MI_REEFER,
+ MI_TROPIC,
+ MI_FLATBED,
+ MI_YANKEE,
+ MI_CADDY,
+ MI_ZEBRA,
+ MI_TOPFUN,
+ MI_SKIMMER,
+ MI_PCJ600,
+ MI_FAGGIO,
+ MI_FREEWAY,
+ MI_RCBARON,
+ MI_RCRAIDER,
+ MI_GLENDALE,
+ MI_OCEANIC,
+ MI_SANCHEZ,
+ MI_SPARROW,
+ MI_PATRIOT,
+ MI_LOVEFIST,
+ MI_COASTG,
+ MI_DINGHY,
+ MI_HERMES,
+ MI_SABRE,
+ MI_SABRETUR,
+ MI_PHEONIX,
+ MI_WALTON,
+ MI_REGINA,
+ MI_COMET,
+ MI_DELUXO,
+ MI_BURRITO,
+ MI_SPAND,
+ MI_MARQUIS,
+ MI_BAGGAGE,
+ MI_KAUFMAN,
+ MI_MAVERICK,
+ MI_VCNMAV,
+ MI_RANCHER,
+ MI_FBIRANCH,
+ MI_VIRGO,
+ MI_GREENWOO,
+ MI_JETMAX,
+ MI_HOTRING,
+ MI_SANDKING,
+ MI_BLISTAC,
+ MI_POLMAV,
+ MI_BOXVILLE,
+ MI_BENSON,
+ MI_MESA,
+ MI_RCGOBLIN,
+ MI_HOTRINA,
+ MI_HOTRINB,
+ MI_BLOODRA,
+ MI_BLOODRB,
+ MI_VICECHEE,
+
+ // HACK
+ MI_TRAIN = -1,
+ MI_DODO = -2,
+
+ MI_LAST_VEHICLE = MI_VICECHEE,
+
+ MI_WHEEL_RIM,
+ MI_WHEEL_OFFROAD,
+ MI_WHEEL_TRUCK,
+
+ MI_CAR_DOOR,// = 240,
+ MI_CAR_BUMPER,
+ MI_CAR_PANEL,
+ MI_CAR_BONNET,
+ MI_CAR_BOOT,
+ MI_CAR_WHEEL,
+ MI_BODYPARTA,
+ MI_BODYPARTB,
+
+ MI_WHEEL_SPORT = 250,
+ MI_WHEEL_SALOON,
+ MI_WHEEL_LIGHTVAN,
+ MI_WHEEL_CLASSIC,
+ MI_WHEEL_ALLOY,
+ MI_WHEEL_LIGHTTRUCK,
+ MI_WHEEL_SMALLCAR,
+
+ MI_AIRTRAIN_VLO, // = 257,
+ MI_MOBILE,
+
+ MI_BRASS_KNUCKLES, // 259
+ MI_SCREWDRIVER,
+ MI_GOLFCLUB,
+ MI_NIGHTSTICK,
+ MI_KNIFE,
+ MI_BASEBALL_BAT,
+ MI_HAMMER,
+ MI_MEAT_CLEAVER,
+ MI_MACHETE,
+ MI_KATANA,
+ MI_CHAINSAW,
+ MI_GRENADE,
+ MI_TEARGAS,
+ MI_MOLOTOV,
+ MI_MISSILE,
+ MI_COLT45,
+ MI_PYTHON,
+ MI_RUGER,
+ MI_SHOTGUN,
+ MI_SPAS12_SHOTGUN,
+ MI_STUBBY_SHOTGUN,
+ MI_M4,
+ MI_TEC9,
+ MI_UZI,
+ MI_SILENCEDINGRAM,
+ MI_MP5,
+ MI_SNIPERRIFLE,
+ MI_LASERSCOPE,
+ MI_ROCKETLAUNCHER,
+ MI_FLAMETHROWER,
+ MI_M60,
+ MI_MINIGUN,
+ MI_BOMB,
+ MI_CAMERA,
+ MI_FINGERS,
+ MI_MINIGUN2,
+
+ MI_CUTOBJ01,// = 295,
+ MI_CUTOBJ02,
+ MI_CUTOBJ03,
+ MI_CUTOBJ04,
+ MI_CUTOBJ05,
+
+
+ NUM_DEFAULT_MODELS,// = 300
+};
+
+enum{
+ NUM_OF_SPECIAL_CHARS = 21,
+ NUM_OF_CUTSCENE_OBJECTS = 5
+};
+
+void InitModelIndices(void);
+void MatchModelString(const char *name, int16 id);
+void TestModelIndices(void);
+
+inline bool
+IsGlass(int16 id)
+{
+ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
+ return mi->IsBuilding() && (mi->m_isCodeGlass || mi->m_isArtistGlass);
+}
+
+inline bool
+IsTrafficLight(int16 id)
+{
+ return id == MI_TRAFFICLIGHTS ||
+ id == MI_TRAFFICLIGHTS_VERTICAL ||
+ id == MI_TRAFFICLIGHTS_MIAMI ||
+ id == MI_TRAFFICLIGHTS_TWOVERTICAL;
+}
+
+inline bool
+IsLightWithoutShift(int16 id)
+{
+ return id == MI_TRAFFICLIGHTS ||
+ id == MI_SINGLESTREETLIGHTS1 ||
+ id == MI_SINGLESTREETLIGHTS2 ||
+ id == MI_SINGLESTREETLIGHTS3 ||
+ id == MI_DOUBLESTREETLIGHTS;
+}
+
+inline bool
+IsLightWithPreRenderEffects(int16 id)
+{
+ return IsTrafficLight(id) ||
+ id == MI_SINGLESTREETLIGHTS1 ||
+ id == MI_SINGLESTREETLIGHTS2 ||
+ id == MI_SINGLESTREETLIGHTS3 ||
+ id == MI_DOUBLESTREETLIGHTS;
+}
+
+inline bool
+IsLightThatNeedsRepositioning(int16 id)
+{
+ return id == MI_SINGLESTREETLIGHTS1 ||
+ id == MI_SINGLESTREETLIGHTS2 ||
+ id == MI_SINGLESTREETLIGHTS3 ||
+ id == MI_TRAFFICLIGHTS_MIAMI ||
+ id == MI_TRAFFICLIGHTS_TWOVERTICAL ||
+ id == MI_MLAMPPOST ||
+ id == MI_STREETLAMP1 ||
+ id == MI_STREETLAMP2;
+}
+
+inline bool
+IsLightObject(int16 id)
+{
+ return id == MI_TRAFFICLIGHTS_MIAMI ||
+ id == MI_MLAMPPOST ||
+ id == MI_SINGLESTREETLIGHTS1 ||
+ id == MI_SINGLESTREETLIGHTS2 ||
+ id == MI_SINGLESTREETLIGHTS3 ||
+ id == MI_DOUBLESTREETLIGHTS ||
+ id == MI_TRAFFICLIGHTS_TWOVERTICAL;
+}
+
+inline bool
+IsLampPost(int16 id)
+{
+ return id == MI_SINGLESTREETLIGHTS1 ||
+ id == MI_SINGLESTREETLIGHTS2 ||
+ id == MI_SINGLESTREETLIGHTS3 ||
+ id == MI_BOLLARDLIGHT ||
+ id == MI_MLAMPPOST ||
+ id == MI_STREETLAMP1 ||
+ id == MI_STREETLAMP2 ||
+ id == MI_TELPOLE02 ||
+ id == MI_TRAFFICLIGHTS_MIAMI ||
+ id == MI_TRAFFICLIGHTS_TWOVERTICAL;
+}
+
+inline bool
+IsBodyPart(int16 id)
+{
+ return id == MI_BODYPARTA || id == MI_BODYPARTB;
+}
+
+inline bool
+IsPedModel(int16 id)
+{
+ return id >= MI_PLAYER && id <= MI_LAST_PED;
+}
+inline bool
+IsPalmTreeModel(int16 id)
+{
+ return id == MI_VEG_PALM01 ||
+ id == MI_VEG_PALM02 ||
+ id == MI_VEG_PALM03 ||
+ id == MI_VEG_PALM04 ||
+ id == MI_VEG_PALM05 ||
+ id == MI_VEG_PALM06 ||
+ id == MI_VEG_PALM07 ||
+ id == MI_VEG_PALM08;
+}
+
+inline bool
+IsTreeModel(int16 id)
+{
+ return id == MI_TREE2 ||
+ id == MI_TREE3 ||
+ id == MI_TREE6 ||
+ id == MI_TREE8 ||
+ IsPalmTreeModel(id);
+}
+
+inline bool
+IsPolicePedModel(int16 id)
+{
+ return id == MI_COP ||
+ id == MI_SWAT ||
+ id == MI_FBI ||
+ id == MI_ARMY;
+}
+
+inline bool
+IsPoliceVehicleModel(int16 id)
+{
+ return id == MI_CHOPPER ||
+ id == MI_PREDATOR ||
+ id == MI_POLICE ||
+ id == MI_ENFORCER;
+}
+
+inline bool
+IsExplosiveThingModel(int16 id)
+{
+ return id == MI_EXPLODINGBARREL ||
+ id == MI_PETROLPUMP ||
+ id == MI_PETROLPUMP2;
+}
+
+inline bool
+IsFence(int16 id)
+{
+ return id == MI_FENCE ||
+ id == MI_FENCE2;
+}
diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp
new file mode 100644
index 0000000..41515e2
--- /dev/null
+++ b/src/modelinfo/ModelInfo.cpp
@@ -0,0 +1,258 @@
+#include "common.h"
+
+#include "General.h"
+#include "TempColModels.h"
+#include "ModelIndices.h"
+#include "ModelInfo.h"
+
+CBaseModelInfo *CModelInfo::ms_modelInfoPtrs[MODELINFOSIZE];
+
+CStore<CSimpleModelInfo, SIMPLEMODELSIZE> CModelInfo::ms_simpleModelStore;
+CStore<CTimeModelInfo, TIMEMODELSIZE> CModelInfo::ms_timeModelStore;
+CStore<CWeaponModelInfo, WEAPONMODELSIZE> CModelInfo::ms_weaponModelStore;
+CStore<CClumpModelInfo, CLUMPMODELSIZE> CModelInfo::ms_clumpModelStore;
+CStore<CPedModelInfo, PEDMODELSIZE> CModelInfo::ms_pedModelStore;
+CStore<CVehicleModelInfo, VEHICLEMODELSIZE> CModelInfo::ms_vehicleModelStore;
+CStore<C2dEffect, TWODFXSIZE> CModelInfo::ms_2dEffectStore;
+
+void
+CModelInfo::Initialise(void)
+{
+ int i;
+ CSimpleModelInfo *m;
+
+ debug("sizeof SimpleModelStore %d\n", sizeof(ms_simpleModelStore));
+ debug("sizeof TimeModelStore %d\n", sizeof(ms_timeModelStore));
+ debug("sizeof WeaponModelStore %d\n", sizeof(ms_weaponModelStore));
+ debug("sizeof ClumpModelStore %d\n", sizeof(ms_clumpModelStore));
+ debug("sizeof VehicleModelStore %d\n", sizeof(ms_vehicleModelStore));
+ debug("sizeof PedModelStore %d\n", sizeof(ms_pedModelStore));
+ debug("sizeof 2deffectsModelStore %d\n", sizeof(ms_2dEffectStore));
+
+ for(i = 0; i < MODELINFOSIZE; i++)
+ ms_modelInfoPtrs[i] = nil;
+ ms_2dEffectStore.Clear();
+ ms_simpleModelStore.Clear();
+ ms_timeModelStore.Clear();
+ ms_weaponModelStore.Clear();
+ ms_clumpModelStore.Clear();
+ ms_pedModelStore.Clear();
+ ms_vehicleModelStore.Clear();
+
+ m = AddSimpleModel(MI_CAR_DOOR);
+ m->SetColModel(&CTempColModels::ms_colModelDoor1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_BUMPER);
+ m->SetColModel(&CTempColModels::ms_colModelBumper1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_PANEL);
+ m->SetColModel(&CTempColModels::ms_colModelPanel1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_BONNET);
+ m->SetColModel(&CTempColModels::ms_colModelBonnet1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_BOOT);
+ m->SetColModel(&CTempColModels::ms_colModelBoot1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_CAR_WHEEL);
+ m->SetColModel(&CTempColModels::ms_colModelWheel1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_BODYPARTA);
+ m->SetColModel(&CTempColModels::ms_colModelBodyPart1);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+
+ m = AddSimpleModel(MI_BODYPARTB);
+ m->SetColModel(&CTempColModels::ms_colModelBodyPart2);
+ m->SetTexDictionary("generic");
+ m->SetNumAtomics(1);
+ m->m_lodDistances[0] = 80.0f;
+}
+
+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_weaponModelStore.allocPtr; i++)
+ ms_weaponModelStore.store[i].Shutdown();
+ for(i = 0; i < ms_clumpModelStore.allocPtr; i++)
+ ms_clumpModelStore.store[i].Shutdown();
+ for(i = 0; i < ms_vehicleModelStore.allocPtr; i++)
+ ms_vehicleModelStore.store[i].Shutdown();
+ for(i = 0; i < ms_pedModelStore.allocPtr; i++)
+ ms_pedModelStore.store[i].Shutdown();
+ for(i = 0; i < ms_2dEffectStore.allocPtr; i++)
+ ms_2dEffectStore.store[i].Shutdown();
+
+ ms_2dEffectStore.Clear();
+ ms_simpleModelStore.Clear();
+ ms_timeModelStore.Clear();
+ ms_weaponModelStore.Clear();
+ ms_pedModelStore.Clear();
+ ms_clumpModelStore.Clear();
+ ms_vehicleModelStore.Clear();
+}
+
+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;
+}
+
+CWeaponModelInfo*
+CModelInfo::AddWeaponModel(int id)
+{
+ CWeaponModelInfo *modelinfo;
+ modelinfo = CModelInfo::ms_weaponModelStore.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 && !CGeneral::faststricmp(modelinfo->GetModelName(), name)){
+ if(id)
+ *id = i;
+ return modelinfo;
+ }
+ }
+ return nil;
+}
+
+CBaseModelInfo*
+CModelInfo::GetModelInfo(const char *name, int minIndex, int maxIndex)
+{
+ if (minIndex > maxIndex)
+ return 0;
+
+ CBaseModelInfo *modelinfo;
+ for(int i = minIndex; i <= maxIndex; i++){
+ modelinfo = CModelInfo::ms_modelInfoPtrs[i];
+ if(modelinfo && !CGeneral::faststricmp(modelinfo->GetModelName(), name))
+ return modelinfo;
+ }
+ return nil;
+}
+
+bool
+CModelInfo::IsBoatModel(int32 id)
+{
+ return GetModelInfo(id)->GetModelType() == MITYPE_VEHICLE &&
+ ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BOAT;
+}
+
+bool
+CModelInfo::IsBikeModel(int32 id)
+{
+ return GetModelInfo(id)->GetModelType() == MITYPE_VEHICLE &&
+ ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BIKE;
+}
+
+bool
+CModelInfo::IsCarModel(int32 id)
+{
+ return GetModelInfo(id)->GetModelType() == MITYPE_VEHICLE &&
+ ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_CAR;
+}
+
+bool
+CModelInfo::IsHeliModel(int32 id)
+{
+ return GetModelInfo(id)->GetModelType() == MITYPE_VEHICLE &&
+ ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_HELI;
+}
+
+bool
+CModelInfo::IsPlaneModel(int32 id)
+{
+ return GetModelInfo(id)->GetModelType() == MITYPE_VEHICLE &&
+ ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_PLANE;
+}
+
+void
+CModelInfo::ReInit2dEffects()
+{
+ ms_2dEffectStore.Clear();
+
+ for (int i = 0; i < MODELINFOSIZE; i++) {
+ if (ms_modelInfoPtrs[i])
+ ms_modelInfoPtrs[i]->Init2dEffects();
+ }
+}
diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h
new file mode 100644
index 0000000..30f4c01
--- /dev/null
+++ b/src/modelinfo/ModelInfo.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "2dEffect.h"
+#include "SimpleModelInfo.h"
+#include "TimeModelInfo.h"
+#include "WeaponModelInfo.h"
+#include "ClumpModelInfo.h"
+#include "PedModelInfo.h"
+#include "VehicleModelInfo.h"
+#include "templates.h"
+
+class CModelInfo
+{
+ static CBaseModelInfo *ms_modelInfoPtrs[MODELINFOSIZE];
+ static CStore<CSimpleModelInfo, SIMPLEMODELSIZE> ms_simpleModelStore;
+ static CStore<CTimeModelInfo, TIMEMODELSIZE> ms_timeModelStore;
+ static CStore<CWeaponModelInfo, WEAPONMODELSIZE> ms_weaponModelStore;
+ static CStore<CClumpModelInfo, CLUMPMODELSIZE> ms_clumpModelStore;
+ static CStore<CPedModelInfo, PEDMODELSIZE> ms_pedModelStore;
+ static CStore<CVehicleModelInfo, VEHICLEMODELSIZE> ms_vehicleModelStore;
+ static CStore<C2dEffect, TWODFXSIZE> ms_2dEffectStore;
+
+public:
+ static void Initialise(void);
+ static void ShutDown(void);
+
+ static CSimpleModelInfo *AddSimpleModel(int id);
+ static CTimeModelInfo *AddTimeModel(int id);
+ static CWeaponModelInfo *AddWeaponModel(int id);
+ static CClumpModelInfo *AddClumpModel(int id);
+ static CPedModelInfo *AddPedModel(int id);
+ static CVehicleModelInfo *AddVehicleModel(int id);
+
+ static CStore<C2dEffect, TWODFXSIZE> &Get2dEffectStore(void) { return ms_2dEffectStore; }
+
+ static CBaseModelInfo *GetModelInfo(const char *name, int *id);
+ static CBaseModelInfo *GetModelInfo(int id){
+ return ms_modelInfoPtrs[id];
+ }
+ static CBaseModelInfo *GetModelInfo(const char *name, int minIndex, int maxIndex);
+
+ static bool IsBoatModel(int32 id);
+ static bool IsBikeModel(int32 id);
+ static bool IsCarModel(int32 id);
+ static bool IsHeliModel(int32 id);
+ static bool IsPlaneModel(int32 id);
+ static void ReInit2dEffects();
+};
diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp
new file mode 100644
index 0000000..28de250
--- /dev/null
+++ b/src/modelinfo/PedModelInfo.cpp
@@ -0,0 +1,162 @@
+#include "common.h"
+
+#include "RwHelper.h"
+#include "General.h"
+#include "Bones.h"
+#include "SurfaceTable.h"
+#include "Ped.h"
+#include "NodeName.h"
+#include "VisibilityPlugins.h"
+#include "ModelInfo.h"
+#include "custompipes.h"
+
+void
+CPedModelInfo::DeleteRwObject(void)
+{
+ CClumpModelInfo::DeleteRwObject();
+ if(m_hitColModel)
+ delete m_hitColModel;
+ m_hitColModel = nil;
+}
+
+// leftover...
+RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[PED_NODE_MAX] = {
+ { "Smid", PED_MID, 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, },
+ { nil, 0, 0, },
+};
+
+void
+CPedModelInfo::SetClump(RpClump *clump)
+{
+#ifdef EXTENDED_PIPELINES
+ CustomPipes::AttachRimPipe(clump);
+#endif
+ CClumpModelInfo::SetClump(clump);
+ SetFrameIds(m_pPedIds); // not needed in VC actually
+ if(m_hitColModel == nil)
+ CreateHitColModelSkinned(clump);
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPedCB);
+ if(strcmp(GetModelName(), "player") == 0)
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB);
+}
+
+struct ColNodeInfo
+{
+ Const char *name;
+ int pedNode;
+ int pieceType;
+ float x, z;
+ float radius;
+};
+
+#define NUMPEDINFONODES 10
+ColNodeInfo m_pColNodeInfos[NUMPEDINFONODES] = {
+ { nil, PED_HEAD, PEDPIECE_HEAD, 0.0f, 0.05f, 0.15f },
+ { nil, PED_MID, PEDPIECE_TORSO, 0.0f, 0.15f, 0.2f },
+ { nil, PED_MID, PEDPIECE_TORSO, 0.0f, -0.05f, 0.25f },
+ { nil, PED_MID, PEDPIECE_MID, 0.0f, -0.25f, 0.25f },
+ { nil, PED_UPPERARML, PEDPIECE_LEFTARM, 0.03f, -0.05f, 0.16f },
+ { nil, PED_UPPERARMR, PEDPIECE_RIGHTARM, -0.03f, -0.05f, 0.16f },
+ { nil, PED_LOWERLEGL, PEDPIECE_LEFTLEG, 0.0f, 0.15f, 0.2f },
+ { nil, PED_LOWERLEGR, PEDPIECE_RIGHTLEG, 0.0f, 0.15f, 0.2f },
+ { nil, PED_FOOTL, PEDPIECE_LEFTLEG, 0.0f, 0.15f, 0.15f },
+ { nil, PED_FOOTR, PEDPIECE_RIGHTLEG, 0.0f, 0.15f, 0.15f },
+};
+
+void
+CPedModelInfo::CreateHitColModelSkinned(RpClump *clump)
+{
+ RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump);
+ CColModel *colmodel = new CColModel;
+ CColSphere *spheres = (CColSphere*)RwMalloc(NUMPEDINFONODES*sizeof(CColSphere));
+ RwFrame *root = RpClumpGetFrame(m_clump);
+ RwMatrix *invmat = RwMatrixCreate();
+ RwMatrix *mat = RwMatrixCreate();
+ RwMatrixInvert(invmat, RwFrameGetMatrix(RpClumpGetFrame(clump)));
+
+ for(int i = 0; i < NUMPEDINFONODES; i++){
+ *mat = *invmat;
+ int id = ConvertPedNode2BoneTag(m_pColNodeInfos[i].pedNode); // this is wrong, wtf R* ???
+ int idx = RpHAnimIDGetIndex(hier, id);
+
+ // This doesn't really work as the positions are not initialized yet
+ RwMatrixTransform(mat, &RpHAnimHierarchyGetMatrixArray(hier)[idx], rwCOMBINEPRECONCAT);
+ RwV3d pos = { 0.0f, 0.0f, 0.0f };
+ RwV3dTransformPoints(&pos, &pos, 1, mat);
+
+ spheres[i].center = pos + CVector(m_pColNodeInfos[i].x, 0.0f, m_pColNodeInfos[i].z);
+ spheres[i].radius = m_pColNodeInfos[i].radius;
+ spheres[i].surface = SURFACE_PED;
+ spheres[i].piece = m_pColNodeInfos[i].pieceType;
+ }
+ RwMatrixDestroy(invmat);
+ RwMatrixDestroy(mat);
+ colmodel->spheres = spheres;
+ colmodel->numSpheres = NUMPEDINFONODES;
+ colmodel->boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f));
+ colmodel->boundingBox.Set(CVector(-0.5f, -0.5f, -1.2f), CVector(0.5f, 0.5f, 1.2f));
+ colmodel->level = LEVEL_GENERIC;
+ m_hitColModel = colmodel;
+}
+
+CColModel*
+CPedModelInfo::AnimatePedColModelSkinned(RpClump *clump)
+{
+ if(m_hitColModel == nil){
+ CreateHitColModelSkinned(clump);
+ return m_hitColModel;
+ }
+ RwMatrix *invmat, *mat;
+ CColSphere *spheres = m_hitColModel->spheres;
+ RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump);
+ invmat = RwMatrixCreate();
+ mat = RwMatrixCreate();
+ RwMatrixInvert(invmat, RwFrameGetMatrix(RpClumpGetFrame(clump)));
+
+ for(int i = 0; i < NUMPEDINFONODES; i++){
+ *mat = *invmat;
+ int id = ConvertPedNode2BoneTag(m_pColNodeInfos[i].pedNode);
+ int idx = RpHAnimIDGetIndex(hier, id);
+
+ RwMatrixTransform(mat, &RpHAnimHierarchyGetMatrixArray(hier)[idx], rwCOMBINEPRECONCAT);
+ RwV3d pos = { 0.0f, 0.0f, 0.0f };
+ RwV3dTransformPoints(&pos, &pos, 1, mat);
+
+ spheres[i].center = pos + CVector(m_pColNodeInfos[i].x, 0.0f, m_pColNodeInfos[i].z);
+ }
+ RwMatrixDestroy(invmat);
+ RwMatrixDestroy(mat);
+ return m_hitColModel;
+}
+
+CColModel*
+CPedModelInfo::AnimatePedColModelSkinnedWorld(RpClump *clump)
+{
+ if(m_hitColModel == nil)
+ CreateHitColModelSkinned(clump);
+ CColSphere *spheres = m_hitColModel->spheres;
+ RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump);
+ RwMatrix *mat;
+
+ for(int i = 0; i < NUMPEDINFONODES; i++){
+ int id = ConvertPedNode2BoneTag(m_pColNodeInfos[i].pedNode);
+ int idx = RpHAnimIDGetIndex(hier, id);
+
+ mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx];
+ RwV3d pos = { 0.0f, 0.0f, 0.0f };
+ RwV3dTransformPoints(&pos, &pos, 1, mat);
+
+ spheres[i].center = pos + CVector(m_pColNodeInfos[i].x, 0.0f, m_pColNodeInfos[i].z);
+ }
+ return m_hitColModel;
+}
diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h
new file mode 100644
index 0000000..79bd7ea
--- /dev/null
+++ b/src/modelinfo/PedModelInfo.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "ClumpModelInfo.h"
+#include "ColModel.h"
+#include "PedType.h"
+
+enum PedNode {
+ PED_TORSO = 0, // has no bone!
+ PED_MID,
+ PED_HEAD,
+ PED_UPPERARML,
+ PED_UPPERARMR,
+ PED_HANDL,
+ PED_HANDR,
+ PED_UPPERLEGL,
+ PED_UPPERLEGR,
+ PED_FOOTL,
+ PED_FOOTR,
+ PED_LOWERLEGR,
+ PED_LOWERLEGL,
+
+ PED_FOREARML,
+ PED_FOREARMR,
+ PED_CLAVICLEL,
+ PED_CLAVICLER,
+ PED_NECK,
+
+ PED_NODE_MAX
+};
+
+class CPedModelInfo : public CClumpModelInfo
+{
+public:
+ uint32 m_animGroup;
+ ePedType m_pedType;
+ ePedStats m_pedStatType;
+ uint32 m_carsCanDrive;
+ CColModel *m_hitColModel;
+ int8 radio1, radio2;
+
+ static RwObjectNameIdAssocation m_pPedIds[PED_NODE_MAX];
+
+ CPedModelInfo(void) : CClumpModelInfo(MITYPE_PED) { m_hitColModel = nil; }
+ ~CPedModelInfo(void) { delete m_hitColModel; }
+ void DeleteRwObject(void);
+ void SetClump(RpClump *);
+
+ void CreateHitColModelSkinned(RpClump *clump);
+ CColModel *GetHitColModel(void) { return m_hitColModel; }
+ CColModel *AnimatePedColModelSkinned(RpClump *clump);
+ CColModel *AnimatePedColModelSkinnedWorld(RpClump *clump);
+};
diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp
new file mode 100644
index 0000000..18eb7e5
--- /dev/null
+++ b/src/modelinfo/SimpleModelInfo.cpp
@@ -0,0 +1,194 @@
+#include "common.h"
+
+#include "General.h"
+#include "Camera.h"
+#include "Renderer.h"
+#include "ModelInfo.h"
+#include "AnimManager.h"
+#include "custompipes.h"
+
+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();
+ if(GetAnimFileIndex() != -1)
+ CAnimManager::RemoveAnimBlockRef(GetAnimFileIndex());
+ }
+}
+
+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_firstDamaged = 0;
+ m_wetRoadReflection = 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;
+ m_noShadows = 0;
+ m_ignoreDrawDist = 0;
+ m_isCodeGlass = 0;
+ m_isArtistGlass = 0;
+}
+
+void
+CSimpleModelInfo::SetAtomic(int n, RpAtomic *atomic)
+{
+ AddTexDictionaryRef();
+ m_atomics[n] = atomic;
+ if(GetAnimFileIndex() != -1)
+ CAnimManager::AddAnimBlockRef(GetAnimFileIndex());
+ RpGeometry *geo = RpAtomicGetGeometry(atomic);
+ if(m_ignoreLight)
+ RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) & ~rpGEOMETRYLIGHT);
+ if(RpGeometryGetFlags(geo) & rpGEOMETRYNORMALS &&
+ RpGeometryGetNumTriangles(geo) > 200)
+ debug("%s has %d polys\n", m_name, RpGeometryGetNumTriangles(geo));
+
+#ifdef EXTENDED_PIPELINES
+ if(m_wetRoadReflection)
+ CustomPipes::AttachGlossPipe(atomic);
+ else
+ CustomPipes::AttachWorldPipe(atomic);
+#endif
+}
+
+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::GetLodDistance(int i)
+{
+ return m_lodDistances[i] * TheCamera.LODDistMultiplier;
+}
+
+float
+CSimpleModelInfo::GetNearDistance(void)
+{
+ return m_lodDistances[2] * TheCamera.LODDistMultiplier;
+}
+
+float
+CSimpleModelInfo::GetLargestLodDistance(void)
+{
+ float d;
+ if(m_firstDamaged == 0 || m_isDamaged)
+ d = m_lodDistances[m_numAtomics-1];
+ else
+ d = m_lodDistances[m_firstDamaged-1];
+ return d * TheCamera.LODDistMultiplier;
+}
+
+RpAtomic*
+CSimpleModelInfo::GetAtomicFromDistance(float dist)
+{
+ int i;
+ i = 0;
+ if(m_isDamaged)
+ i = m_firstDamaged;
+ for(; i < m_numAtomics; i++)
+ if(dist < m_lodDistances[i] * TheCamera.LODDistMultiplier)
+ return m_atomics[i];
+ return nil;
+}
+
+RpAtomic*
+CSimpleModelInfo::GetFirstAtomicFromDistance(float dist)
+{
+ if(dist < m_lodDistances[0] * TheCamera.LODDistMultiplier)
+ return m_atomics[0];
+ return nil;
+}
+
+void
+CSimpleModelInfo::FindRelatedModel(int32 minID, int32 maxID)
+{
+ int i;
+ CBaseModelInfo *mi;
+ for(i = minID; i <= maxID; i++){
+ mi = CModelInfo::GetModelInfo(i);
+ if(mi && mi != this &&
+ !CGeneral::faststrcmp(GetModelName()+3, mi->GetModelName()+3)){
+ assert(mi->IsSimple());
+ this->SetRelatedModel((CSimpleModelInfo*)mi);
+ return;
+ }
+ }
+}
+
+#define NEAR_DRAW_DIST 0.0f // 100.0f in liberty city
+
+void
+CSimpleModelInfo::SetupBigBuilding(int32 minID, int32 maxID)
+{
+ CSimpleModelInfo *related;
+ if(m_lodDistances[0] > LOD_DISTANCE && GetRelatedModel() == nil){
+ m_isBigBuilding = 1;
+ FindRelatedModel(minID, maxID);
+ related = GetRelatedModel();
+ if(related){
+ m_lodDistances[2] = related->GetLargestLodDistance()/TheCamera.LODDistMultiplier;
+ if(m_drawLast){
+ m_drawLast = false;
+ debug("%s was draw last\n", GetModelName());
+ }
+ }else
+ m_lodDistances[2] = NEAR_DRAW_DIST;
+ }
+}
diff --git a/src/modelinfo/SimpleModelInfo.h b/src/modelinfo/SimpleModelInfo.h
new file mode 100644
index 0000000..986cb88
--- /dev/null
+++ b/src/modelinfo/SimpleModelInfo.h
@@ -0,0 +1,61 @@
+#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_firstDamaged : 2; // 0: no damage model
+ // 1: 1 and 2 are damage models
+ // 2: 2 is damage model
+ uint16 m_wetRoadReflection : 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;
+ uint16 m_noShadows : 1;
+
+ uint16 m_ignoreDrawDist : 1;
+ uint16 m_isCodeGlass : 1;
+ uint16 m_isArtistGlass : 1;
+
+ CSimpleModelInfo(void) : CBaseModelInfo(MITYPE_SIMPLE) {}
+ CSimpleModelInfo(ModelInfoType id) : CBaseModelInfo(id) {}
+ ~CSimpleModelInfo() {}
+ void DeleteRwObject(void);
+ RwObject *CreateInstance(void);
+ RwObject *CreateInstance(RwMatrix *);
+ RwObject *GetRwObject(void) { return (RwObject*)m_atomics[0]; }
+
+ virtual void SetAtomic(int n, RpAtomic *atomic);
+
+ void Init(void);
+ void IncreaseAlpha(void);
+ void SetLodDistances(float *dist);
+ float GetLodDistance(int i);
+ float GetNearDistance(void);
+ float GetLargestLodDistance(void);
+ RpAtomic *GetAtomicFromDistance(float dist);
+ RpAtomic *GetFirstAtomicFromDistance(float dist);
+ void FindRelatedModel(int32 minID, int32 maxID);
+ void SetupBigBuilding(int32 minID, int32 maxID);
+
+ void SetNumAtomics(int n) { m_numAtomics = n; }
+ CSimpleModelInfo *GetRelatedModel(void){
+ return (CSimpleModelInfo*)m_atomics[2]; }
+ void SetRelatedModel(CSimpleModelInfo *m){
+ m_atomics[2] = (RpAtomic*)m; }
+};
+//static_assert(sizeof(CSimpleModelInfo) == 0x4C, "CSimpleModelInfo: error");
diff --git a/src/modelinfo/TimeModelInfo.cpp b/src/modelinfo/TimeModelInfo.cpp
new file mode 100644
index 0000000..0db5fb7
--- /dev/null
+++ b/src/modelinfo/TimeModelInfo.cpp
@@ -0,0 +1,33 @@
+#include "common.h"
+
+#include "Camera.h"
+#include "ModelInfo.h"
+#include "General.h"
+
+CTimeModelInfo*
+CTimeModelInfo::FindOtherTimeModel(void)
+{
+ char name[40];
+ char *p;
+ int i;
+
+ strcpy(name, GetModelName());
+ // 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->GetModelType() == MITYPE_TIME &&
+ !CGeneral::faststrncmp(name, mi->GetModelName(), MAX_MODEL_NAME)){
+ m_otherTimeModelID = i;
+ return (CTimeModelInfo*)mi;
+ }
+ }
+ return nil;
+}
diff --git a/src/modelinfo/TimeModelInfo.h b/src/modelinfo/TimeModelInfo.h
new file mode 100644
index 0000000..6e3c64f
--- /dev/null
+++ b/src/modelinfo/TimeModelInfo.h
@@ -0,0 +1,20 @@
+#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; }
+ void SetTimes(int32 on, int32 off) { m_timeOn = on; m_timeOff = off; }
+ int32 GetOtherTimeModel(void) { return m_otherTimeModelID; }
+ void SetOtherTimeModel(int32 other) { m_otherTimeModelID = other; }
+ 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 0000000..d31962c
--- /dev/null
+++ b/src/modelinfo/VehicleModelInfo.cpp
@@ -0,0 +1,1193 @@
+#include "common.h"
+#include <rpmatfx.h>
+
+#include "RwHelper.h"
+#include "General.h"
+#include "NodeName.h"
+#include "TxdStore.h"
+#include "Weather.h"
+#include "HandlingMgr.h"
+#include "VisibilityPlugins.h"
+#include "FileMgr.h"
+#include "World.h"
+#include "Vehicle.h"
+#include "Automobile.h"
+#include "Boat.h"
+#include "Train.h"
+#include "Plane.h"
+#include "Heli.h"
+#include "Bike.h"
+#include "ModelIndices.h"
+#include "ModelInfo.h"
+#include "custompipes.h"
+
+int8 CVehicleModelInfo::ms_compsToUse[2] = { -2, -2 };
+int8 CVehicleModelInfo::ms_compsUsed[2];
+RwRGBA CVehicleModelInfo::ms_vehicleColourTable[256];
+RwTexture *CVehicleModelInfo::ms_colourTextureTable[256];
+
+RwTexture *gpWhiteTexture;
+RwFrame *pMatFxIdentityFrame;
+
+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", BOAT_MOVING, 0 },
+ { "boat_rudder_hi", BOAT_RUDDER, 0 },
+ { "boat_flap_left", BOAT_FLAP_LEFT, 0 },
+ { "boat_flap_right", BOAT_FLAP_RIGHT, 0 },
+ { "boat_rearflap_left", BOAT_REARFLAP_LEFT, 0 },
+ { "boat_rearflap_right", BOAT_REARFLAP_RIGHT, 0 },
+#ifdef FIX_BUGS
+ // let's just accept both
+ { "windscreen", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
+ { "windscreen_hi_ok", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
+#else
+#ifdef GTA_PS2
+ { "windscreen", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
+#else
+ { "windscreen_hi_ok", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST },
+#endif
+#endif
+ { "ped_frontseat", BOAT_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { nil, 0, 0 }
+};
+
+RwObjectNameIdAssocation trainIds[] = {
+ { "door_lhs_dummy", TRAIN_DOOR_LHS, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
+ { "door_rhs_dummy", TRAIN_DOOR_RHS, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
+ { "light_front", TRAIN_POS_LIGHT_FRONT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { "light_rear", TRAIN_POS_LIGHT_REAR, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { "ped_left_entry", TRAIN_POS_LEFT_ENTRY, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { "ped_mid_entry", TRAIN_POS_MID_ENTRY, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { "ped_right_entry", TRAIN_POS_RIGHT_ENTRY, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { nil, 0, 0 }
+};
+
+RwObjectNameIdAssocation heliIds[] = {
+ { "chassis_dummy", HELI_CHASSIS, VEHICLE_FLAG_COLLAPSE },
+ { "toprotor", HELI_TOPROTOR, 0 },
+ { "backrotor", HELI_BACKROTOR, 0 },
+ { "tail", HELI_TAIL, 0 },
+ { "topknot", HELI_TOPKNOT, 0 },
+ { "skid_left", HELI_SKID_LEFT, 0 },
+ { "skid_right", HELI_SKID_RIGHT, 0 },
+ { nil, 0, 0 }
+};
+
+RwObjectNameIdAssocation planeIds[] = {
+ { "wheel_front_dummy", PLANE_WHEEL_FRONT, 0 },
+ { "wheel_rear_dummy", PLANE_WHEEL_READ, 0 },
+ { "light_tailplane", PLANE_POS_LIGHT_TAIL, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { "light_left", PLANE_POS_LIGHT_LEFT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { "light_right", PLANE_POS_LIGHT_RIGHT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { nil, 0, 0 }
+};
+
+RwObjectNameIdAssocation bikeIds[] = {
+ { "chassis_dummy", BIKE_CHASSIS, 0 },
+ { "forks_front", BIKE_FORKS_FRONT, 0 },
+ { "forks_rear", BIKE_FORKS_REAR, 0 },
+ { "wheel_front", BIKE_WHEEL_FRONT, 0 },
+ { "wheel_rear", BIKE_WHEEL_REAR, 0 },
+ { "mudguard", BIKE_MUDGUARD, 0 },
+ { "handlebars", BIKE_HANDLEBARS, 0 },
+ { "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 *CVehicleModelInfo::ms_vehicleDescs[] = {
+ carIds,
+ boatIds,
+ trainIds,
+ heliIds,
+ planeIds,
+ bikeIds
+};
+
+bool gbBlackCars;
+bool gbPinkCars;
+
+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;
+ m_animFileIndex = -1;
+}
+
+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 && m_comps[comp1]){
+ 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 && m_comps[comp2]){
+ 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();
+ SetEnvironmentMap();
+}
+
+void
+CVehicleModelInfo::SetAnimFile(const char *file)
+{
+ if(strcasecmp(file, "null") == 0)
+ return;
+
+ m_animFileName = new char[strlen(file)+1];
+ strcpy(m_animFileName, file);
+}
+
+void
+CVehicleModelInfo::ConvertAnimFileIndex(void)
+{
+ if(m_animFileIndex != -1){
+ // we have a string pointer in that union
+ int32 index = CAnimManager::GetAnimationBlockIndex(m_animFileName);
+ delete[] m_animFileName;
+ m_animFileIndex = index;
+ }
+}
+
+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;
+}
+
+RpAtomic*
+CVehicleModelInfo::HideAllComponentsAtomicCB(RpAtomic *atomic, void *data)
+{
+ if(CVisibilityPlugins::GetAtomicId(atomic) & (uintptr)data)
+ RpAtomicSetFlags(atomic, 0);
+ else
+ RpAtomicSetFlags(atomic, rpATOMICRENDER);
+ 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") || !CGeneral::faststrncmp(name, "extra", 5)) {
+ 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: nil in 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") || !CGeneral::faststrncmp(name, "extra", 5)) {
+ 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;
+ bool alpha;
+
+ clump = (RpClump*)data;
+ name = GetFrameNodeName(RpAtomicGetFrame(atomic));
+ alpha = false;
+ RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha);
+ if(strcmp(name, "boat_hi") == 0 || !CGeneral::faststrncmp(name, "extra", 5))
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB_Boat);
+ else if(strstr(name, "_hi")){
+ if(alpha)
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_Boat);
+ 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::RenderVehicleLoDetailCB_Boat);
+ else{
+ if(alpha)
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_Boat);
+ else
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+ }
+ HideDamagedAtomicCB(atomic, nil);
+ return atomic;
+}
+
+RpAtomic*
+CVehicleModelInfo::SetAtomicRendererCB_Heli(RpAtomic *atomic, void *data)
+{
+ char *name;
+
+ name = GetFrameNodeName(RpAtomicGetFrame(atomic));
+ if(strncmp(name, "toprotor", 8) == 0)
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleRotorAlphaCB);
+ else if(strncmp(name, "rearrotor", 9) == 0)
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleTailRotorAlphaCB);
+ else
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+ return atomic;
+}
+
+RpAtomic*
+CVehicleModelInfo::SetAtomicRendererCB_RealHeli(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(strncmp(name, "toprotor", 8) == 0)
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleRotorAlphaCB);
+ else if(strncmp(name, "rearrotor", 9) == 0)
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleTailRotorAlphaCB);
+ else if(strstr(name, "_hi") || !CGeneral::faststrncmp(name, "extra", 5)) {
+ 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: nil in gta
+ }else if(strstr(name, "_vlo"))
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB);
+ else
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+ HideDamagedAtomicCB(atomic, nil);
+ return atomic;
+}
+
+void
+CVehicleModelInfo::SetAtomicRenderCallbacks(void)
+{
+#ifdef GTA_TRAIN
+ if(m_vehicleType == VEHICLE_TYPE_TRAIN)
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Train, nil);
+ else
+#endif
+ if(m_vehicleType == VEHICLE_TYPE_HELI)
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Heli, nil);
+ else if(m_vehicleType == VEHICLE_TYPE_PLANE)
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_BigVehicle, nil);
+ else if(m_vehicleType == VEHICLE_TYPE_BOAT)
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Boat, m_clump);
+ else if(mod_HandlingManager.GetHandlingData((tVehicleType)m_handlingId)->Flags & HANDLING_IS_HELI)
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_RealHeli, m_clump);
+ else
+ RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, m_clump);
+}
+
+RwObject*
+CVehicleModelInfo::SetAtomicFlagCB(RwObject *object, void *data)
+{
+ RpAtomic *atomic = (RpAtomic*)object;
+ assert(RwObjectGetType(object) == rpATOMIC);
+ CVisibilityPlugins::SetAtomicFlag(atomic, (uintptr)data);
+ return object;
+}
+
+RwObject*
+CVehicleModelInfo::ClearAtomicFlagCB(RwObject *object, void *data)
+{
+ RpAtomic *atomic = (RpAtomic*)object;
+ assert(RwObjectGetType(object) == rpATOMIC);
+ CVisibilityPlugins::ClearAtomicFlag(atomic, (uintptr)data);
+ return object;
+}
+
+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 = &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);
+ }
+ }
+ }
+}
+
+void
+CVehicleModelInfo::SetVehicleComponentFlags(RwFrame *frame, uint32 flags)
+{
+ tHandlingData *handling;
+
+ handling = mod_HandlingManager.GetHandlingData((tVehicleType)m_handlingId);
+
+#define SETFLAGS(f) RwFrameForAllObjects(frame, SetAtomicFlagCB, (void*)(f))
+
+ if(flags & VEHICLE_FLAG_WINDSCREEN){
+ if(this == CModelInfo::GetModelInfo(MI_RHINO))
+ return;
+ SETFLAGS(ATOMIC_FLAG_WINDSCREEN);
+ }
+
+ if(flags & VEHICLE_FLAG_ANGLECULL)
+ SETFLAGS(ATOMIC_FLAG_ANGLECULL);
+
+ if(flags & VEHICLE_FLAG_FRONT)
+ SETFLAGS(ATOMIC_FLAG_FRONT);
+ else if(flags & VEHICLE_FLAG_REAR && (handling->Flags & HANDLING_IS_VAN || (flags & (VEHICLE_FLAG_LEFT|VEHICLE_FLAG_RIGHT)) == 0))
+ SETFLAGS(ATOMIC_FLAG_REAR);
+ else if(flags & VEHICLE_FLAG_LEFT)
+ SETFLAGS(ATOMIC_FLAG_LEFT);
+ else if(flags & VEHICLE_FLAG_RIGHT)
+ SETFLAGS(ATOMIC_FLAG_RIGHT);
+
+ if(flags & VEHICLE_FLAG_REARDOOR)
+ SETFLAGS(ATOMIC_FLAG_REARDOOR);
+ else if(flags & VEHICLE_FLAG_FRONTDOOR)
+ SETFLAGS(ATOMIC_FLAG_FRONTDOOR);
+
+ if(flags & VEHICLE_FLAG_DRAWLAST)
+ SETFLAGS(ATOMIC_FLAG_DRAWLAST);
+}
+
+#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);
+ case 3:
+ n = CGeneral::GetRandomNumberInRange(0, 1+CountCompsInRule(comps));
+ if(n != 0)
+ return COMPRULE_COMPN(comps, n-1);
+ return -1;
+ case 4:
+#ifdef FIX_BUGS
+ return CGeneral::GetRandomNumberInRange(0, 6);
+#else
+ return CGeneral::GetRandomNumberInRange(0, 5);
+#endif
+ }
+ 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)
+{
+ RwRGBA white = { 255, 255, 255, 255 };
+ const 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;
+}
+
+static int maxFirstMaterials;
+static int maxSecondMaterials;
+
+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;
+ maxFirstMaterials = Max(maxFirstMaterials, cbdata.numMats1);
+ maxSecondMaterials = Max(maxSecondMaterials, cbdata.numMats2);
+ m_currentColour1 = -1;
+ m_currentColour2 = -1;
+}
+
+void
+CVehicleModelInfo::SetVehicleColour(uint8 c1, uint8 c2)
+{
+ RwRGBA col, *colp;
+ RpMaterial **matp;
+
+ if(c1 != m_currentColour1){
+ col = ms_vehicleColourTable[c1];
+ for(matp = m_materials1; *matp; matp++){
+ colp = (RwRGBA*)RpMaterialGetColor(*matp); // get rid of const
+ colp->red = col.red;
+ colp->green = col.green;
+ colp->blue = col.blue;
+ }
+ m_currentColour1 = c1;
+ }
+
+ if(c2 != m_currentColour2){
+ col = ms_vehicleColourTable[c2];
+ for(matp = m_materials2; *matp; matp++){
+ colp = (RwRGBA*)RpMaterialGetColor(*matp); // get rid of const
+ colp->red = col.red;
+ colp->green = col.green;
+ colp->blue = col.blue;
+ }
+ m_currentColour2 = c2;
+ }
+}
+
+void
+CVehicleModelInfo::ChooseVehicleColour(uint8 &col1, uint8 &col2)
+{
+ if(m_numColours == 0 || gbBlackCars){
+ col1 = 0;
+ col2 = 0;
+ }else if(gbPinkCars){
+ col1 = 68;
+ col2 = 68;
+ }else{
+ m_lastColorVariation = (m_lastColorVariation+1) % m_numColours;
+ col1 = m_colours1[m_lastColorVariation];
+ col2 = m_colours2[m_lastColorVariation];
+ if(m_numColours > 1){
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh && CModelInfo::GetModelInfo(veh->GetModelIndex()) == this &&
+ veh->m_currentColour1 == col1 &&
+ veh->m_currentColour2 == col2){
+ m_lastColorVariation = (m_lastColorVariation+1) % m_numColours;
+ col1 = m_colours1[m_lastColorVariation];
+ col2 = m_colours2[m_lastColorVariation];
+ }
+ }
+ }
+}
+
+void
+CVehicleModelInfo::AvoidSameVehicleColour(uint8 *col1, uint8 *col2)
+{
+ int i, n;
+
+ if(gbBlackCars){
+ *col1 = 0;
+ *col2 = 0;
+ }else if(gbPinkCars){
+ *col1 = 68;
+ *col2 = 68;
+ }else{
+ if(m_numColours > 1)
+ for(i = 0; i < 8; i++){
+ if(*col1 != m_lastColour1 || *col2 != m_lastColour2)
+ break;
+ n = CGeneral::GetRandomNumberInRange(0, m_numColours);
+ *col1 = m_colours1[n];
+ *col2 = m_colours2[n];
+ }
+ m_lastColour1 = *col1;
+ m_lastColour2 = *col2;
+ }
+}
+
+// unused
+RwTexture*
+CreateCarColourTexture(uint8 r, uint8 g, uint8 b)
+{
+ RwImage *img;
+ RwRaster *ras;
+ RwTexture *tex;
+ RwUInt8 *pixels;
+ RwInt32 width, height, depth, format;
+
+ img = RwImageCreate(2, 2, 32);
+ pixels = (RwUInt8*)RwMalloc(2*2*4);
+ pixels[0] = r;
+ pixels[1] = g;
+ pixels[2] = b;
+ pixels[3] = 0xFF;
+ pixels[4] = r;
+ pixels[5] = g;
+ pixels[6] = b;
+ pixels[7] = 0xFF;
+ pixels[8] = r;
+ pixels[9] = g;
+ pixels[10] = b;
+ pixels[11] = 0xFF;
+ pixels[12] = r;
+ pixels[13] = g;
+ pixels[14] = b;
+ pixels[15] = 0xFF;
+ RwImageSetPixels(img, pixels);
+ RwImageSetStride(img, 8);
+ RwImageSetPalette(img, nil);
+ RwImageFindRasterFormat(img, rwRASTERTYPETEXTURE, &width, &height, &depth, &format);
+ ras = RwRasterCreate(width, height, depth, format);
+ RwRasterSetFromImage(ras, img);
+ RwImageDestroy(img);
+ RwFree(pixels);
+ tex = RwTextureCreate(ras);
+ RwTextureGetName(tex)[0] = '@';
+ return tex;
+}
+
+void
+CVehicleModelInfo::LoadVehicleColours(void)
+{
+ int fd;
+ int i;
+ char line[1024];
+ int start, end;
+ int section, numCols;
+ enum {
+ NONE,
+ COLOURS,
+ CARS
+ };
+ int r, g, b;
+ char name[64];
+ int colors[16];
+ int n;
+
+ CFileMgr::ChangeDir("\\DATA\\");
+ fd = CFileMgr::OpenFile("CARCOLS.DAT", "r");
+ CFileMgr::ChangeDir("\\");
+
+ for(i = 0; i < 256; i++)
+ ms_colourTextureTable[i] = nil;
+
+ section = 0;
+ numCols = 0;
+ while(CFileMgr::ReadLine(fd, line, sizeof(line))){
+ // find first valid character in line
+ for(start = 0; ; start++)
+ if(line[start] > ' ' || line[start] == '\0' || line[start] == '\n')
+ break;
+ // find end of line
+ for(end = start; ; end++){
+ if(line[end] == '\0' || line[end] == '\n')
+ break;
+ if(line[end] == ',' || line[end] == '\r')
+ line[end] = ' ';
+ }
+ line[end] = '\0';
+
+ // empty line
+ if(line[start] == '#' || line[start] == '\0')
+ continue;
+
+ if(section == NONE){
+ if(line[start] == 'c' && line[start + 1] == 'o' && line[start + 2] == 'l')
+ section = COLOURS;
+ if(line[start] == 'c' && line[start + 1] == 'a' && line[start + 2] == 'r')
+ section = CARS;
+ }else if(line[start] == 'e' && line[start + 1] == 'n' && line[start + 2] == 'd'){
+ section = NONE;
+ }else if(section == COLOURS){
+ sscanf(&line[start], // BUG: games doesn't add start
+ "%d %d %d", &r, &g, &b);
+ ms_vehicleColourTable[numCols].red = r;
+ ms_vehicleColourTable[numCols].green = g;
+ ms_vehicleColourTable[numCols].blue = b;
+ ms_vehicleColourTable[numCols].alpha = 0xFF;
+ numCols++;
+ }else if(section == CARS){
+ n = sscanf(&line[start], // BUG: games doesn't add start
+ "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
+ name,
+ &colors[0], &colors[1],
+ &colors[2], &colors[3],
+ &colors[4], &colors[5],
+ &colors[6], &colors[7],
+ &colors[8], &colors[9],
+ &colors[10], &colors[11],
+ &colors[12], &colors[13],
+ &colors[14], &colors[15]);
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(name, nil);
+ assert(mi);
+ mi->m_numColours = (n-1)/2;
+ for(i = 0; i < mi->m_numColours; i++){
+ mi->m_colours1[i] = colors[i*2 + 0];
+ mi->m_colours2[i] = colors[i*2 + 1];
+ }
+ }
+ }
+
+ CFileMgr::CloseFile(fd);
+}
+
+void
+CVehicleModelInfo::DeleteVehicleColourTextures(void)
+{
+ int i;
+
+ for(i = 0; i < 256; i++){
+ if(ms_colourTextureTable[i]){
+ RwTextureDestroy(ms_colourTextureTable[i]);
+ ms_colourTextureTable[i] = nil;
+ }
+ }
+}
+
+RpMaterial*
+CVehicleModelInfo::GetMatFXEffectMaterialCB(RpMaterial *material, void *data)
+{
+ if(RpMatFXMaterialGetEffects(material) == rpMATFXEFFECTNULL)
+ return material;
+ *(int*)data = RpMatFXMaterialGetEffects(material);
+ return nil;
+}
+
+RpMaterial*
+CVehicleModelInfo::SetDefaultEnvironmentMapCB(RpMaterial *material, void *data)
+{
+ if(RpMatFXMaterialGetEffects(material) == rpMATFXEFFECTENVMAP){
+ RpMatFXMaterialSetEnvMapFrame(material, pMatFxIdentityFrame);
+ if(RpMaterialGetTexture(material) == nil)
+ RpMaterialSetTexture(material, gpWhiteTexture);
+ RpMatFXMaterialSetEffects(material, rpMATFXEFFECTENVMAP);
+#ifndef PS2_MATFX
+ float coef = RpMatFXMaterialGetEnvMapCoefficient(material);
+ coef *= 0.25f; // Tone down a bit for PC
+ RpMatFXMaterialSetEnvMapCoefficient(material, coef);
+#endif
+ }
+ return material;
+}
+
+RpAtomic*
+CVehicleModelInfo::SetEnvironmentMapCB(RpAtomic *atomic, void *data)
+{
+ int fx;
+ RpGeometry *geo;
+
+ geo = RpAtomicGetGeometry(atomic);
+ fx = rpMATFXEFFECTNULL;
+ RpGeometryForAllMaterials(geo, GetMatFXEffectMaterialCB, &fx);
+ if(fx != rpMATFXEFFECTNULL){
+ RpMatFXAtomicEnableEffects(atomic);
+ RpGeometryForAllMaterials(geo, SetDefaultEnvironmentMapCB, data);
+ }
+ return atomic;
+}
+
+void
+CVehicleModelInfo::SetEnvironmentMap(void)
+{
+ CSimpleModelInfo *wheelmi;
+ int32 i;
+
+ if(pMatFxIdentityFrame == nil){
+ RwV3d axis = { 1.0f, 0.0f, 0.0f };
+ pMatFxIdentityFrame = RwFrameCreate();
+ RwMatrixRotate(RwFrameGetMatrix(pMatFxIdentityFrame), &axis, 60.0f, rwCOMBINEREPLACE);
+ RwFrameUpdateObjects(pMatFxIdentityFrame);
+ RwFrameGetLTM(pMatFxIdentityFrame);
+ }
+
+ RpClumpForAllAtomics(m_clump, SetEnvironmentMapCB, nil);
+ if(m_wheelId != -1){
+ wheelmi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_wheelId);
+ for(i = 0; i < wheelmi->m_numAtomics; i++)
+ SetEnvironmentMapCB(wheelmi->m_atomics[i], nil);
+ }
+
+#ifdef EXTENDED_PIPELINES
+ CustomPipes::AttachVehiclePipe(m_clump);
+#endif
+}
+
+void
+CVehicleModelInfo::LoadEnvironmentMaps(void)
+{
+ int32 txdslot;
+
+ txdslot = CTxdStore::FindTxdSlot("particle");
+ CTxdStore::PushCurrentTxd();
+ CTxdStore::SetCurrentTxd(txdslot);
+ if(gpWhiteTexture == nil){
+ gpWhiteTexture = RwTextureRead("white", nil);
+ RwTextureGetName(gpWhiteTexture)[0] = '@';
+ RwTextureSetFilterMode(gpWhiteTexture, rwFILTERLINEAR);
+ }
+ CTxdStore::PopCurrentTxd();
+}
+
+void
+CVehicleModelInfo::ShutdownEnvironmentMaps(void)
+{
+ RwTextureDestroy(gpWhiteTexture);
+ gpWhiteTexture = nil;
+ RwFrameDestroy(pMatFxIdentityFrame);
+ pMatFxIdentityFrame = nil;
+}
+
+int
+CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(int id)
+{
+ int n;
+
+ switch(id){
+ case MI_TRAIN:
+ n = 3;
+ break;
+ case MI_FIRETRUCK:
+ n = 2;
+ break;
+ case MI_HUNTER:
+ n = 1;
+ break;
+ default:
+ n = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(id))->m_numDoors;
+ }
+
+ if(n == 0)
+ return id == MI_RCBANDIT || id == MI_PIZZABOY || id == MI_BAGGAGE ? 0 : 1;
+
+ if(id == MI_COACH)
+ return 8;
+
+ return n - 1;
+}
diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h
new file mode 100644
index 0000000..c7a4112
--- /dev/null
+++ b/src/modelinfo/VehicleModelInfo.h
@@ -0,0 +1,166 @@
+#pragma once
+
+#include "ClumpModelInfo.h"
+
+enum {
+ NUM_FIRST_MATERIALS = 24,
+ NUM_SECOND_MATERIALS = 20,
+ NUM_VEHICLE_COLOURS = 8,
+};
+
+enum {
+ ATOMIC_FLAG_NONE = 0x0,
+ 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 eVehicleType {
+ VEHICLE_TYPE_CAR,
+ VEHICLE_TYPE_BOAT,
+ VEHICLE_TYPE_TRAIN,
+ VEHICLE_TYPE_HELI,
+ VEHICLE_TYPE_PLANE,
+ VEHICLE_TYPE_BIKE,
+ NUM_VEHICLE_TYPES
+};
+
+enum eCarPositions
+{
+ CAR_POS_HEADLIGHTS,
+ CAR_POS_TAILLIGHTS,
+ CAR_POS_FRONTSEAT,
+ CAR_POS_BACKSEAT,
+ CAR_POS_EXHAUST
+};
+
+enum eBoatPositions
+{
+ BOAT_POS_FRONTSEAT
+};
+
+enum eTrainPositions
+{
+ TRAIN_POS_LIGHT_FRONT,
+ TRAIN_POS_LIGHT_REAR,
+ TRAIN_POS_LEFT_ENTRY,
+ TRAIN_POS_MID_ENTRY,
+ TRAIN_POS_RIGHT_ENTRY
+};
+
+enum ePlanePositions
+{
+ PLANE_POS_LIGHT_LEFT,
+ PLANE_POS_LIGHT_RIGHT,
+ PLANE_POS_LIGHT_TAIL,
+};
+
+enum {
+ NUM_VEHICLE_POSITIONS = 5
+};
+
+class CVehicleModelInfo : public CClumpModelInfo
+{
+public:
+ uint8 m_lastColour1;
+ uint8 m_lastColour2;
+ char m_gameName[10];
+ int32 m_vehicleType;
+ float m_wheelScale;
+ union {
+ int16 m_wheelId;
+ int16 m_planeLodId;
+ };
+ int16 m_handlingId;
+ int8 m_numDoors;
+ int8 m_vehicleClass;
+ int8 m_level;
+ int8 m_numComps;
+ int16 m_frequency;
+ 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_lastColorVariation;
+ uint8 m_currentColour1;
+ uint8 m_currentColour2;
+ RpAtomic *m_comps[6];
+ // This is stupid, CClumpModelInfo already has it!
+ union {
+ int32 m_animFileIndex;
+ char *m_animFileName;
+ };
+
+ static int8 ms_compsToUse[2];
+ static int8 ms_compsUsed[2];
+ 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 *);
+ void SetAnimFile(const char *file);
+ void ConvertAnimFileIndex(void);
+ int GetAnimFileIndex(void) { return m_animFileIndex; }
+
+ static RwFrame *CollapseFramesCB(RwFrame *frame, void *data);
+ static RwObject *MoveObjectsCB(RwObject *object, void *data);
+ static RpAtomic *HideDamagedAtomicCB(RpAtomic *atomic, void *data);
+ static RpAtomic *HideAllComponentsAtomicCB(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);
+ static RpAtomic *SetAtomicRendererCB_RealHeli(RpAtomic *atomic, void *data);
+ void SetAtomicRenderCallbacks(void);
+
+ static RwObject *SetAtomicFlagCB(RwObject *object, void *data);
+ static RwObject *ClearAtomicFlagCB(RwObject *atomic, void *data);
+ void SetVehicleComponentFlags(RwFrame *frame, uint32 flags);
+ void PreprocessHierarchy(void);
+ void GetWheelPosn(int32 n, CVector &pos);
+ const CVector &GetFrontSeatPosn(void) { return m_vehicleType == VEHICLE_TYPE_BOAT ? m_positions[BOAT_POS_FRONTSEAT] : m_positions[CAR_POS_FRONTSEAT]; }
+
+ 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);
+ void ChooseVehicleColour(uint8 &col1, uint8 &col2);
+ void AvoidSameVehicleColour(uint8 *col1, uint8 *col2);
+ static void LoadVehicleColours(void);
+ static void DeleteVehicleColourTextures(void);
+
+ static RpAtomic *SetEnvironmentMapCB(RpAtomic *atomic, void *data);
+ static RpMaterial *SetDefaultEnvironmentMapCB(RpMaterial *material, void *data);
+ static RpMaterial *GetMatFXEffectMaterialCB(RpMaterial *material, void *data);
+ void SetEnvironmentMap(void);
+ static void LoadEnvironmentMaps(void);
+ static void ShutdownEnvironmentMaps(void);
+
+ static int GetMaximumNumberOfPassengersFromNumberOfDoors(int id);
+ static void SetComponentsToUse(int8 c1, int8 c2) { ms_compsToUse[0] = c1; ms_compsToUse[1] = c2; }
+};
+
+extern bool gbBlackCars;
+extern bool gbPinkCars;
diff --git a/src/modelinfo/WeaponModelInfo.cpp b/src/modelinfo/WeaponModelInfo.cpp
new file mode 100644
index 0000000..d9294c3
--- /dev/null
+++ b/src/modelinfo/WeaponModelInfo.cpp
@@ -0,0 +1,53 @@
+#include "common.h"
+
+#include "ModelInfo.h"
+#include "AnimManager.h"
+#include "VisibilityPlugins.h"
+
+void
+CWeaponModelInfo::SetAnimFile(const char *file)
+{
+ if(strcasecmp(file, "null") == 0)
+ return;
+
+ m_animFileName = new char[strlen(file)+1];
+ strcpy(m_animFileName, file);
+}
+
+void
+CWeaponModelInfo::ConvertAnimFileIndex(void)
+{
+ if(m_animFileIndex != -1){
+ // we have a string pointer in that union
+ int32 index = CAnimManager::GetAnimationBlockIndex(m_animFileName);
+ delete[] m_animFileName;
+ m_animFileIndex = index;
+ }
+}
+
+void
+CWeaponModelInfo::Init(void)
+{
+ CSimpleModelInfo::Init();
+ SetWeaponInfo(0);
+}
+
+void
+CWeaponModelInfo::SetWeaponInfo(int32 weaponId)
+{
+ m_atomics[2] = (RpAtomic*)weaponId;
+}
+
+eWeaponType
+CWeaponModelInfo::GetWeaponInfo(void)
+{
+ return (eWeaponType)(uintptr)m_atomics[2];
+}
+
+void
+CWeaponModelInfo::SetAtomic(int n, RpAtomic *atomic)
+{
+ CSimpleModelInfo::SetAtomic(n, atomic);
+ CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderWeaponCB);
+}
+
diff --git a/src/modelinfo/WeaponModelInfo.h b/src/modelinfo/WeaponModelInfo.h
new file mode 100644
index 0000000..548bf8a
--- /dev/null
+++ b/src/modelinfo/WeaponModelInfo.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "SimpleModelInfo.h"
+#include "WeaponType.h"
+
+class CWeaponModelInfo : public CSimpleModelInfo
+{
+ union {
+ int32 m_animFileIndex;
+ char *m_animFileName;
+ };
+public:
+ CWeaponModelInfo(void) : CSimpleModelInfo(MITYPE_WEAPON) { m_animFileIndex = -1; }
+
+ virtual void SetAnimFile(const char *file);
+ virtual void ConvertAnimFileIndex(void);
+ virtual int GetAnimFileIndex(void) { return m_animFileIndex; }
+ virtual void SetAtomic(int n, RpAtomic *atomic);
+
+ void Init(void);
+ void SetWeaponInfo(int32 weaponId);
+ eWeaponType GetWeaponInfo(void);
+};