diff options
Diffstat (limited to 'src/entities/Entity.cpp')
-rw-r--r-- | src/entities/Entity.cpp | 391 |
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 ¢er, 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 |