summaryrefslogtreecommitdiffstats
path: root/src/entities/Entity.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/entities/Entity.cpp391
1 files changed, 391 insertions, 0 deletions
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
new file mode 100644
index 00000000..11fa9ab2
--- /dev/null
+++ b/src/entities/Entity.cpp
@@ -0,0 +1,391 @@
+#include "common.h"
+#include "rpworld.h"
+#include "Placeable.h"
+#include "Entity.h"
+#include "Lights.h"
+#include "World.h"
+#include "Camera.h"
+#include "References.h"
+#include "TxdStore.h"
+#include "Zones.h"
+#include "patcher.h"
+
+int gBuildings;
+
+void
+CEntity::GetBoundCentre(CVector &out)
+{
+ out = m_matrix * CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.center;
+};
+
+bool
+CEntity::GetIsTouching(CVector const &center, float radius)
+{
+ return sq(GetBoundRadius()+radius) > (GetBoundCentre()-center).MagnitudeSqr();
+}
+
+bool
+CEntity::GetIsOnScreen(void)
+{
+ return TheCamera.IsSphereVisible(GetBoundCentre(), GetBoundRadius(),
+ &TheCamera.GetCameraMatrix());
+}
+
+bool
+CEntity::GetIsOnScreenComplex(void)
+{
+ RwV3d boundBox[8];
+
+ if(TheCamera.IsPointVisible(GetBoundCentre(), &TheCamera.GetCameraMatrix()))
+ return true;
+
+ CRect rect = GetBoundRect();
+ CColModel *colmodel = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel();
+ float z = GetPosition().z;
+ float minz = z + colmodel->boundingBox.min.z;
+ float maxz = z + colmodel->boundingBox.max.z;
+ boundBox[0].x = rect.left;
+ boundBox[0].y = rect.top;
+ boundBox[0].z = minz;
+ boundBox[1].x = rect.left;
+ boundBox[1].y = rect.bottom;
+ boundBox[1].z = minz;
+ boundBox[2].x = rect.right;
+ boundBox[2].y = rect.top;
+ boundBox[2].z = minz;
+ boundBox[3].x = rect.right;
+ boundBox[3].y = rect.bottom;
+ boundBox[3].z = minz;
+ boundBox[4].x = rect.left;
+ boundBox[4].y = rect.top;
+ boundBox[4].z = maxz;
+ boundBox[5].x = rect.left;
+ boundBox[5].y = rect.bottom;
+ boundBox[5].z = maxz;
+ boundBox[6].x = rect.right;
+ boundBox[6].y = rect.top;
+ boundBox[6].z = maxz;
+ boundBox[7].x = rect.right;
+ boundBox[7].y = rect.bottom;
+ boundBox[7].z = maxz;
+
+ return TheCamera.IsBoxVisible(boundBox, &TheCamera.GetCameraMatrix());
+}
+
+void
+CEntity::Add(void)
+{
+ int x, xstart, xmid, xend;
+ int y, ystart, ymid, yend;
+ CSector *s;
+ CPtrList *list;
+
+ CRect bounds = GetBoundRect();
+ xstart = CWorld::GetSectorIndexX(bounds.left);
+ xend = CWorld::GetSectorIndexX(bounds.right);
+ xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
+ ystart = CWorld::GetSectorIndexY(bounds.bottom);
+ yend = CWorld::GetSectorIndexY(bounds.top);
+ ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
+ assert(xstart >= 0);
+ assert(xend < NUMSECTORS_X);
+ assert(ystart >= 0);
+ assert(yend < NUMSECTORS_Y);
+
+ for(y = ystart; y <= yend; y++)
+ for(x = xstart; x <= xend; x++){
+ s = CWorld::GetSector(x, y);
+ if(x == xmid && y == ymid) switch(m_type){
+ case ENTITY_TYPE_BUILDING:
+ list = &s->m_lists[ENTITYLIST_BUILDINGS];
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ list = &s->m_lists[ENTITYLIST_VEHICLES];
+ break;
+ case ENTITY_TYPE_PED:
+ list = &s->m_lists[ENTITYLIST_PEDS];
+ break;
+ case ENTITY_TYPE_OBJECT:
+ list = &s->m_lists[ENTITYLIST_OBJECTS];
+ break;
+ case ENTITY_TYPE_DUMMY:
+ list = &s->m_lists[ENTITYLIST_DUMMIES];
+ break;
+ }else switch(m_type){
+ case ENTITY_TYPE_BUILDING:
+ list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP];
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
+ break;
+ case ENTITY_TYPE_PED:
+ list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
+ break;
+ case ENTITY_TYPE_OBJECT:
+ list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
+ break;
+ case ENTITY_TYPE_DUMMY:
+ list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP];
+ break;
+ }
+ list->InsertItem(this);
+ }
+}
+
+void
+CEntity::Remove(void)
+{
+ int x, xstart, xmid, xend;
+ int y, ystart, ymid, yend;
+ CSector *s;
+ CPtrList *list;
+
+ CRect bounds = GetBoundRect();
+ xstart = CWorld::GetSectorIndexX(bounds.left);
+ xend = CWorld::GetSectorIndexX(bounds.right);
+ xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
+ ystart = CWorld::GetSectorIndexY(bounds.bottom);
+ yend = CWorld::GetSectorIndexY(bounds.top);
+ ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
+ assert(xstart >= 0);
+ assert(xend < NUMSECTORS_X);
+ assert(ystart >= 0);
+ assert(yend < NUMSECTORS_Y);
+
+ for(y = ystart; y <= yend; y++)
+ for(x = xstart; x <= xend; x++){
+ s = CWorld::GetSector(x, y);
+ if(x == xmid && y == ymid) switch(m_type){
+ case ENTITY_TYPE_BUILDING:
+ list = &s->m_lists[ENTITYLIST_BUILDINGS];
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ list = &s->m_lists[ENTITYLIST_VEHICLES];
+ break;
+ case ENTITY_TYPE_PED:
+ list = &s->m_lists[ENTITYLIST_PEDS];
+ break;
+ case ENTITY_TYPE_OBJECT:
+ list = &s->m_lists[ENTITYLIST_OBJECTS];
+ break;
+ case ENTITY_TYPE_DUMMY:
+ list = &s->m_lists[ENTITYLIST_DUMMIES];
+ break;
+ }else switch(m_type){
+ case ENTITY_TYPE_BUILDING:
+ list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP];
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
+ break;
+ case ENTITY_TYPE_PED:
+ list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
+ break;
+ case ENTITY_TYPE_OBJECT:
+ list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
+ break;
+ case ENTITY_TYPE_DUMMY:
+ list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP];
+ break;
+ }
+ list->RemoveItem(this);
+ }
+}
+
+void
+CEntity::CreateRwObject(void)
+{
+ CBaseModelInfo *mi;
+
+ mi = CModelInfo::GetModelInfo(m_modelIndex);
+ m_rwObject = mi->CreateInstance();
+ if(m_rwObject){
+ if(IsBuilding())
+ gBuildings++;
+ if(RwObjectGetType(m_rwObject) == rpATOMIC)
+ m_matrix.AttachRW(RwFrameGetMatrix(RpAtomicGetFrame(m_rwObject)), false);
+ else if(RwObjectGetType(m_rwObject) == rpCLUMP)
+ m_matrix.AttachRW(RwFrameGetMatrix(RpClumpGetFrame(m_rwObject)), false);
+ mi->AddRef();
+ }
+}
+
+void
+CEntity::DeleteRwObject(void)
+{
+ RwFrame *f;
+
+ m_matrix.Detach();
+ if(m_rwObject){
+ if(RwObjectGetType(m_rwObject) == rpATOMIC){
+ f = RpAtomicGetFrame(m_rwObject);
+ RpAtomicDestroy((RpAtomic*)m_rwObject);
+ RwFrameDestroy(f);
+ }else if(RwObjectGetType(m_rwObject) == rpCLUMP)
+ RpClumpDestroy((RpClump*)m_rwObject);
+ m_rwObject = nil;
+ CModelInfo::GetModelInfo(m_modelIndex)->RemoveRef();
+ if(IsBuilding())
+ gBuildings--;
+ }
+}
+
+void
+CEntity::UpdateRwFrame(void)
+{
+ if(m_rwObject){
+ if(RwObjectGetType(m_rwObject) == rpATOMIC)
+ RwFrameUpdateObjects(RpAtomicGetFrame(m_rwObject));
+ else if(RwObjectGetType(m_rwObject) == rpCLUMP)
+ RwFrameUpdateObjects(RpClumpGetFrame(m_rwObject));
+ }
+}
+
+void
+CEntity::SetupBigBuilding(void)
+{
+ CSimpleModelInfo *mi;
+
+ mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_modelIndex);
+ bIsBIGBuilding = true;
+ m_flagC20 = true;
+ bUsesCollision = false;
+ m_level = CTheZones::GetLevelFromPosition(GetPosition());
+ if(m_level == LEVEL_NONE){
+ if(mi->GetTxdSlot() != CTxdStore::FindTxdSlot("generic")){
+ mi->SetTexDictionary("generic");
+ printf("%d:%s txd has been set to generic\n", m_modelIndex, mi->GetName());
+ }
+ }
+ if(mi->m_lodDistances[0] > 2000.0f)
+ m_level = LEVEL_NONE;
+}
+
+CRect
+CEntity::GetBoundRect(void)
+{
+ CRect rect;
+ CVector v;
+ CColModel *col = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel();
+
+ rect.ContainPoint(m_matrix * col->boundingBox.min);
+ rect.ContainPoint(m_matrix * col->boundingBox.max);
+
+ v = col->boundingBox.min;
+ v.x = col->boundingBox.max.x;
+ rect.ContainPoint(m_matrix * v);
+
+ v = col->boundingBox.max;
+ v.x = col->boundingBox.min.x;
+ rect.ContainPoint(m_matrix * v);
+
+ return rect;
+}
+
+void
+CEntity::PreRender(void)
+{
+}
+
+void
+CEntity::Render(void)
+{
+ if(m_rwObject){
+ bImBeingRendered = true;
+ if(RwObjectGetType(m_rwObject) == rpATOMIC)
+ RpAtomicRender((RpAtomic*)m_rwObject);
+ else
+ RpClumpRender((RpClump*)m_rwObject);
+ bImBeingRendered = false;
+ }
+}
+
+bool
+CEntity::SetupLighting(void)
+{
+ DeActivateDirectional();
+ SetAmbientColours();
+ return false;
+}
+
+void
+CEntity::RegisterReference(CEntity **pent)
+{
+ if(IsBuilding())
+ return;
+ CReference *ref;
+ // check if already registered
+ for(ref = m_pFirstReference; ref; ref = ref->next)
+ if(ref->pentity == pent)
+ return;
+ // have to allocate new reference
+ ref = CReferences::pEmptyList;
+ if(ref){
+ CReferences::pEmptyList = ref->next;
+
+ ref->pentity = pent;
+ ref->next = m_pFirstReference;
+ m_pFirstReference = ref;
+ return;
+ }
+ return;
+}
+
+// Clear all references to this entity
+void
+CEntity::ResolveReferences(void)
+{
+ CReference *ref;
+ // clear pointers to this entity
+ for(ref = m_pFirstReference; ref; ref = ref->next)
+ if(*ref->pentity == this)
+ *ref->pentity = nil;
+ // free list
+ if(m_pFirstReference){
+ for(ref = m_pFirstReference; ref->next; ref = ref->next)
+ ;
+ ref->next = CReferences::pEmptyList;
+ CReferences::pEmptyList = ref;
+ m_pFirstReference = nil;
+ }
+}
+
+// Free all references that no longer point to this entity
+void
+CEntity::PruneReferences(void)
+{
+ CReference *ref, *next, **lastnextp;
+ lastnextp = &m_pFirstReference;
+ for(ref = m_pFirstReference; ref; ref = next){
+ next = ref->next;
+ if(*ref->pentity == this)
+ lastnextp = &ref->next;
+ else{
+ *lastnextp = ref->next;
+ ref->next = CReferences::pEmptyList;
+ CReferences::pEmptyList = ref;
+ }
+ }
+}
+
+STARTPATCHES
+ InjectHook(0x4742C0, (void (CEntity::*)(CVector&))&CEntity::GetBoundCentre, PATCH_JUMP);
+ InjectHook(0x474310, &CEntity::GetBoundRadius, PATCH_JUMP);
+ InjectHook(0x474C10, &CEntity::GetIsTouching, PATCH_JUMP);
+ InjectHook(0x474CC0, &CEntity::GetIsOnScreen, PATCH_JUMP);
+ InjectHook(0x474D20, &CEntity::GetIsOnScreenComplex, PATCH_JUMP);
+ InjectHook(0x474CA0, &CEntity::IsVisible, PATCH_JUMP);
+ InjectHook(0x474330, &CEntity::UpdateRwFrame, PATCH_JUMP);
+ InjectHook(0x4755E0, &CEntity::SetupBigBuilding, PATCH_JUMP);
+ InjectHook(0x4A7480, &CEntity::RegisterReference, PATCH_JUMP);
+ InjectHook(0x4A74E0, &CEntity::ResolveReferences, PATCH_JUMP);
+ InjectHook(0x4A7530, &CEntity::PruneReferences, PATCH_JUMP);
+
+ InjectHook(0x475080, &CEntity::Add_, PATCH_JUMP);
+ InjectHook(0x475310, &CEntity::Remove_, PATCH_JUMP);
+ InjectHook(0x473EA0, &CEntity::CreateRwObject_, PATCH_JUMP);
+ InjectHook(0x473F90, &CEntity::DeleteRwObject_, PATCH_JUMP);
+ InjectHook(0x474000, &CEntity::GetBoundRect_, PATCH_JUMP);
+ InjectHook(0x474BD0, &CEntity::Render_, PATCH_JUMP);
+ InjectHook(0x4A7C60, &CEntity::SetupLighting_, PATCH_JUMP);
+ENDPATCHES