////////////////////////////////////////////////////////////////////// // // Physical Entity // // File: physicalentity.cpp // Description : PhysicalEntity class implementation // // History: // -:Created by Anton Knyazev // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "bvtree.h" #include "geometry.h" #include "rigidbody.h" #include "physicalplaceholder.h" #include "physicalentity.h" #include "geoman.h" #include "physicalworld.h" RigidBody g_StaticRigidBody; CPhysicalEntity g_StaticPhysicalEntity(0); CPhysicalEntity::CPhysicalEntity(CPhysicalWorld *pworld) { m_pos.zero(); m_qrot.SetIdentity(); m_BBox[0].zero(); m_BBox[1].zero(); m_iSimClass = 0; m_iPrevSimClass = -1; m_nGridThunks = m_nGridThunksAlloc = 0; m_pGridThunks = 0; m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -2; m_prev = m_next = 0; m_bProcessed = 0; m_nRefCount = 0;//1; 0 means that initially no other physical entity references this one m_nParts = 0; m_nPartsAlloc = 1; m_parts = &m_defpart; m_iLastIdx = 0; m_pWorld = pworld; m_pOuterEntity = 0; m_pBoundingGeometry = 0; m_bProcessed_aux = 0; m_nColliders = m_nCollidersAlloc = 0; m_pColliders = 0; m_iGroup = -1; m_bMoved = 0; m_id = -1; m_pForeignData = 0; m_iForeignData = m_iForeignFlags = 0; m_timeIdle = m_maxTimeIdle = 0; m_bPermanent = 1; m_pEntBuddy = 0; m_flags = pef_pushable_by_players|pef_traceable; } CPhysicalEntity::~CPhysicalEntity() { for(int i=0;iGetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom); if (m_parts[i].pPhysGeomProxy!=m_parts[i].pPhysGeom) m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy); } if (m_pGridThunks) delete[] m_pGridThunks; if (m_parts!=&m_defpart) delete[] m_parts; if (m_pColliders) delete[] m_pColliders; } void CPhysicalEntity::ComputeBBox() { if (m_nParts==0) m_BBox[0]=m_BBox[1]=m_pos; else { IGeometry *pGeom[3]; matrix3x3f R; int i,j; box abox; vectorf sz,pos; m_BBox[0]=vectorf(MAX); m_BBox[1]=vectorf(MIN); for(i=0;ipGeom; pGeom[1]=pGeom[2] = m_parts[i].pPhysGeom->pGeom; j=0; do { pGeom[j]->GetBBox(&abox); //(m_qrot*m_parts[i].q).getmatrix(R); //Q2M_IVO R = matrix3x3f(m_qrot*m_parts[i].q); abox.Basis *= R.T(); sz = (abox.size*abox.Basis.Fabs())*m_parts[i].scale; pos = m_pos+m_qrot*(m_parts[i].pos+m_parts[i].q*abox.center*m_parts[i].scale); m_parts[i].BBox[0] = pos-sz; m_parts[i].BBox[1] = pos+sz; m_BBox[0].x = min_safe(m_BBox[0].x, m_parts[i].BBox[0].x); m_BBox[0].y = min_safe(m_BBox[0].y, m_parts[i].BBox[0].y); m_BBox[0].z = min_safe(m_BBox[0].z, m_parts[i].BBox[0].z); m_BBox[1].x = max_safe(m_BBox[1].x, m_parts[i].BBox[1].x); m_BBox[1].y = max_safe(m_BBox[1].y, m_parts[i].BBox[1].y); m_BBox[1].z = max_safe(m_BBox[1].z, m_parts[i].BBox[1].z); j++; } while(pGeom[j]!=pGeom[j-1]); } } if (m_pEntBuddy) { m_pEntBuddy->m_BBox[0] = m_BBox[0]; m_pEntBuddy->m_BBox[1] = m_BBox[1]; } } int CPhysicalEntity::SetParams(pe_params *_params) { if (_params->type==pe_params_pos::type_id) { pe_params_pos *params = (pe_params_pos*)_params; get_xqs_from_matrices(params->pMtx3x3,params->pMtx3x3T,params->pMtx4x4,params->pMtx4x4T, params->pos,params->q,params->scale); ENTITY_VALIDATE("CPhysicalEntity:SetParams(pe_params_pos)",params); int bPosChanged = 0; if (!is_unused(params->pos)) { m_pos = params->pos; bPosChanged=1; } if (!is_unused(params->q)) { m_qrot = params->q; bPosChanged=1; } if (!is_unused(params->iSimClass) && m_iSimClass>=0 && m_iSimClass<7) { m_iSimClass = params->iSimClass; m_pWorld->RepositionEntity(this,2); } if (!is_unused(params->scale)) { for(int i=0;iscale/m_parts[i].scale; m_parts[i].scale = params->scale; } bPosChanged=1; } if (params->bRecalcBounds && bPosChanged) { CPhysicalEntity **pentlist; // make triggers aware of the object's movements if (!(m_flags & pef_never_affect_triggers)) m_pWorld->GetEntitiesAround(m_BBox[0],m_BBox[1],pentlist,ent_triggers,this); ComputeBBox(); m_pWorld->RepositionEntity(this); if (!(m_flags & pef_never_affect_triggers)) m_pWorld->GetEntitiesAround(m_BBox[0],m_BBox[1],pentlist,ent_triggers,this); } return 1; } if (_params->type==pe_params_bbox::type_id) { pe_params_bbox *params = (pe_params_bbox*)_params; ENTITY_VALIDATE("CPhysicalEntity::SetParams(pe_params_bbox)",params); if (!is_unused(params->BBox[0])) m_BBox[0] = params->BBox[0]; if (!is_unused(params->BBox[1])) m_BBox[1] = params->BBox[1]; if (m_pEntBuddy) { m_pEntBuddy->m_BBox[0] = m_BBox[0]; m_pEntBuddy->m_BBox[1] = m_BBox[1]; } m_pWorld->RepositionEntity(this,1); return 1; } if (_params->type==pe_params_part::type_id) { pe_params_part *params = (pe_params_part*)_params; int i = params->ipart; if (i<0) for(i=0;ipartid;i++); if (i>=m_nParts) return 0; get_xqs_from_matrices(params->pMtx3x3,params->pMtx3x3T,params->pMtx4x4,params->pMtx4x4T, params->pos,params->q,params->scale); ENTITY_VALIDATE("CPhysicalEntity:SetParams(pe_params_part)",params); if (!is_unused(params->pos.x)) m_parts[i].pos = params->pos; if (!is_unused(params->q)) m_parts[i].q = params->q; if (!is_unused(params->scale)) m_parts[i].scale = params->scale; if (!is_unused(params->mass)) m_parts[i].mass = params->mass; if (!is_unused(params->density)) m_parts[i].mass = m_parts[i].pPhysGeom->V*cube(m_parts[i].scale)*params->density; if (!is_unused(params->pPhysGeom) && params->pPhysGeom!=m_parts[i].pPhysGeom) { if (m_parts[i].pPhysGeom==m_parts[i].pPhysGeomProxy) m_parts[i].pPhysGeomProxy = params->pPhysGeom; m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom); m_parts[i].pPhysGeom = params->pPhysGeom; m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeom); } if (!is_unused(params->pPhysGeomProxy) && params->pPhysGeomProxy!=m_parts[i].pPhysGeomProxy) { m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy); m_parts[i].pPhysGeomProxy = params->pPhysGeomProxy; m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeomProxy); } m_parts[i].flags = m_parts[i].flags & params->flagsAND | params->flagsOR; m_parts[i].flagsCollider = m_parts[i].flagsCollider & params->flagsColliderAND | params->flagsColliderOR; if (params->bRecalcBBox) ComputeBBox(); return i+1; } if (_params->type==pe_params_outer_entity::type_id) { m_pOuterEntity = (CPhysicalEntity*)((pe_params_outer_entity*)_params)->pOuterEntity; m_pBoundingGeometry = (CGeometry*)((pe_params_outer_entity*)_params)->pBoundingGeometry; return 1; } if (_params->type==pe_params_foreign_data::type_id) { pe_params_foreign_data *params = (pe_params_foreign_data*)_params; if (!is_unused(params->iForeignData)) m_iForeignData = params->iForeignData; if (!is_unused(params->pForeignData)) m_pForeignData = params->pForeignData; if (!is_unused(params->iForeignFlags)) m_iForeignFlags = params->iForeignFlags; if (m_pEntBuddy) { m_pEntBuddy->m_pForeignData = m_pForeignData; m_pEntBuddy->m_iForeignData = m_iForeignData; m_pEntBuddy->m_iForeignFlags = m_iForeignFlags; } return 1; } if (_params->type==pe_params_flags::type_id) { pe_params_flags *params = (pe_params_flags*)_params; int flags = m_flags; if (!is_unused(params->flags)) m_flags = params->flags; if (!is_unused(params->flagsAND)) m_flags &= params->flagsAND; if (!is_unused(params->flagsOR)) m_flags |= params->flagsOR; if (m_flags&pef_traceable && m_ig[0].x==-3) { m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -2; if (m_pos.len2()>0) m_pWorld->RepositionEntity(this,1); } if (!(m_flags&pef_traceable) && m_ig[0].x!=-3) { m_pWorld->DetachEntityGridThunks(this); m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -3; } return 1; } return 0; } int CPhysicalEntity::GetParams(pe_params *_params) { if (_params->type==pe_params_bbox::type_id) { pe_params_bbox *params = (pe_params_bbox*)_params; params->BBox[0] = m_BBox[0]; params->BBox[1] = m_BBox[1]; return 1; } if (_params->type==pe_params_outer_entity::type_id) { ((pe_params_outer_entity*)_params)->pOuterEntity = m_pOuterEntity; ((pe_params_outer_entity*)_params)->pBoundingGeometry = m_pBoundingGeometry; return 1; } if (_params->type==pe_params_foreign_data::type_id) { pe_params_foreign_data *params = (pe_params_foreign_data*)_params; params->iForeignData = m_iForeignData; params->pForeignData = m_pForeignData; params->iForeignFlags = m_iForeignFlags; return 1; } if (_params->type==pe_params_part::type_id) { pe_params_part *params = (pe_params_part*)_params; int i; if (params->ipart==-1 && params->partid>=0) { for(i=0;ipartid;i++); if (i==m_nParts) return 0; } else i = params->ipart; params->partid = m_parts[params->ipart = i].id; params->pos = m_parts[i].pos; params->q = m_parts[i].q; params->scale = m_parts[i].scale; if (params->pMtx3x3) //resq.getmatrix((matrix3x3f&)*status->pMtx3x3) *= resscale; //Q2M_IVO (matrix3x3f&)*params->pMtx3x3 = (matrix3x3f(m_parts[i].q)*m_parts[i].scale); if (params->pMtx3x3T) //resq.getmatrix((matrix3x3Tf&)*params->pMtx3x3T) *= resscale; //Q2M_IVO (matrix3x3Tf&)*params->pMtx3x3T=(matrix3x3f(m_parts[i].q)*m_parts[i].scale); if (params->pMtx4x4) //(resq.getmatrix((matrix3x3in4x4f&)*params->pMtx4x4)*=resscale).SetColumn(3,respos); //Q2M_IVO ((matrix3x3in4x4f&)*params->pMtx4x4 = (matrix3x3f(m_parts[i].q)*m_parts[i].scale)).SetColumn(3,m_parts[i].pos); if (params->pMtx4x4T) //(resq.getmatrix((matrix3x3in4x4Tf&)*params->pMtx4x4T)*=resscale).SetColumn(3,respos); //Q2M_IVO ((matrix3x3in4x4Tf&)*params->pMtx4x4T = (matrix3x3f(m_parts[i].q)*m_parts[i].scale)).SetColumn(3,m_parts[i].pos); params->flagsOR=params->flagsAND = m_parts[i].flags; params->flagsColliderOR=params->flagsColliderAND = m_parts[i].flagsCollider; params->mass = m_parts[i].mass; params->density = m_parts[i].pPhysGeomProxy->V>0 ? m_parts[i].mass/(m_parts[i].pPhysGeomProxy->V*cube(m_parts[i].scale)) : 0; params->pPhysGeom = m_parts[i].pPhysGeom; params->pPhysGeomProxy = m_parts[i].pPhysGeomProxy; } if (_params->type==pe_params_flags::type_id) { ((pe_params_flags*)_params)->flags = m_flags; return 1; } return 0; } int CPhysicalEntity::GetStatus(pe_status *_status) { if (_status->type==pe_status_pos::type_id) { pe_status_pos *status = (pe_status_pos*)_status; vectorf respos; quaternionf resq; float resscale; int i; if (status->ipart==-1 && status->partid>=0) { for(i=0;ipartid;i++); if (i==m_nParts) return 0; } else i = status->ipart; if (i==-1) { respos=m_pos; resq=m_qrot; resscale=1.0f; for(i=0,status->flagsOR=0,status->flagsAND=-1;iflagsOR|=m_parts[i].flags, status->flagsAND&=m_parts[i].flags; if (m_nParts>0) { status->pGeom = m_parts[0].pPhysGeom->pGeom; status->pGeomProxy = m_parts[0].pPhysGeomProxy->pGeom; } else status->pGeom = status->pGeomProxy = 0; } else { if (status->flags & status_local) { respos = m_parts[i].pos; resq = m_parts[i].q; } else { respos = m_pos+m_qrot*m_parts[i].pos; resq = m_qrot*m_parts[i].q; } resscale = m_parts[i].scale; status->flagsOR = status->flagsAND = m_parts[i].flags; status->pGeom = m_parts[i].pPhysGeom->pGeom; status->pGeomProxy = m_parts[i].pPhysGeomProxy->pGeom; } status->pos = respos; status->q = resq; status->scale = resscale; status->iSimClass = m_iSimClass; if (status->pMtx3x3) //resq.getmatrix((matrix3x3f&)*status->pMtx3x3) *= resscale; //Q2M_IVO (matrix3x3f&)*status->pMtx3x3 = (matrix3x3f(resq)*resscale); if (status->pMtx3x3T) //resq.getmatrix((matrix3x3Tf&)*status->pMtx3x3T) *= resscale; //Q2M_IVO (matrix3x3Tf&)*status->pMtx3x3T=(matrix3x3f(resq)*resscale); if (status->pMtx4x4) //(resq.getmatrix((matrix3x3in4x4f&)*status->pMtx4x4)*=resscale).SetColumn(3,respos); //Q2M_IVO ((matrix3x3in4x4f&)*status->pMtx4x4 = (matrix3x3f(resq)*resscale)).SetColumn(3,respos); if (status->pMtx4x4T) //(resq.getmatrix((matrix3x3in4x4Tf&)*status->pMtx4x4T)*=resscale).SetColumn(3,respos); //Q2M_IVO ((matrix3x3in4x4Tf&)*status->pMtx4x4T = (matrix3x3f(resq)*resscale)).SetColumn(3,respos); status->BBox[0] = m_BBox[0]-m_pos; status->BBox[1] = m_BBox[1]-m_pos; return 1; } if (_status->type==pe_status_id::type_id) { pe_status_id *status = (pe_status_id*)_status; int ipart = status->ipart; if (ipart<0) for(ipart=0;ipartpartid;ipart++); if (ipart>=m_nParts) return 0; phys_geometry *pgeom = status->bUseProxy ? m_parts[ipart].pPhysGeomProxy : m_parts[ipart].pPhysGeom; if ((unsigned int)status->iPrim >= (unsigned int)pgeom->pGeom->GetPrimitiveCount() || pgeom->pGeom->GetType()==GEOM_TRIMESH && status->iFeature>2) return 0; status->id = pgeom->pGeom->GetPrimitiveId(status->iPrim, status->iFeature); status->id = status->id&~(status->id>>31) | m_parts[ipart].surface_idx&status->id>>31; return 1; } if (_status->type==pe_status_nparts::type_id) return m_nParts; if (_status->type==pe_status_awake::type_id) return IsAwake(); if (_status->type==pe_status_contains_point::type_id) return IsPointInside(((pe_status_contains_point*)_status)->pt); if (_status->type==pe_status_caps::type_id) { pe_status_caps *status = (pe_status_caps*)_status; status->bCanAlterOrientation = 0; return 1; } return 0; }; int CPhysicalEntity::Action(pe_action *_action) { if (_action->type==pe_action_awake::type_id && m_iSimClass>=0 && m_iSimClass<7) { Awake(((pe_action_awake*)_action)->bAwake,1); return 1; } if (_action->type==pe_action_remove_all_parts::type_id) { for(int i=m_nParts-1;i>=0;i--) RemoveGeometry(m_parts[i].id); return 1; } return 0; } int CPhysicalEntity::AddGeometry(phys_geometry *pgeom, pe_geomparams* params, int id) { if (!pgeom) return -1; box abox; pgeom->pGeom->GetBBox(&abox); float mindim=min(min(abox.size.x,abox.size.y),abox.size.z), mindims=mindim*params->scale; float maxdim=max(max(abox.size.x,abox.size.y),abox.size.z), maxdims=maxdim*params->scale; if (id>=0) { int i; for(i=0;iflags & geom_proxy) { if (pgeom) { if (m_parts[i].pPhysGeomProxy!=pgeom) m_pWorld->GetGeomManager()->AddRefGeometry(pgeom); m_parts[i].pPhysGeomProxy = pgeom; if (mindims<0.15f) m_parts[i].flags |= geom_has_thin_parts; } } else { m_parts[i].pos = params->pos; m_parts[i].q = params->q; } return id; } } get_xqs_from_matrices(params->pMtx3x3,params->pMtx3x3T,params->pMtx4x4,params->pMtx4x4T, params->pos,params->q,params->scale); ENTITY_VALIDATE_ERRCODE("CPhysicalEntity:AddGeometry",params,-1); if (m_nParts==m_nPartsAlloc) { geom *pparts = m_parts; memcpy(m_parts = new geom[m_nPartsAlloc=m_nPartsAlloc+4&~3], pparts, sizeof(geom)*m_nParts); if (pparts!=&m_defpart) delete[] pparts; } m_parts[m_nParts].id = id<0 ? m_iLastIdx++:id; m_parts[m_nParts].pPhysGeom = m_parts[m_nParts].pPhysGeomProxy = pgeom; m_pWorld->GetGeomManager()->AddRefGeometry(pgeom); m_parts[m_nParts].surface_idx = pgeom->surface_idx; if (!is_unused(params->surface_idx)) m_parts[m_nParts].surface_idx = params->surface_idx; m_parts[m_nParts].flags = params->flags & ~geom_proxy; m_parts[m_nParts].flagsCollider = params->flagsCollider; m_parts[m_nParts].pos = params->pos; m_parts[m_nParts].q = params->q; m_parts[m_nParts].scale = params->scale; if (is_unused(params->minContactDist)) { m_parts[m_nParts].minContactDist = max(maxdims*0.03f,mindims*(mindimsminContactDist; m_parts[m_nParts].maxdim = maxdim; m_nParts++; if (params->bRecalcBBox) { ComputeBBox(); m_pWorld->RepositionEntity(this,1); } return m_parts[m_nParts-1].id; } void CPhysicalEntity::RemoveGeometry(int id) { for(int i=0;iGetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom); if (m_parts[i].pPhysGeomProxy!=m_parts[i].pPhysGeom) m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy); for(;iRepositionEntity(this,1); return; } } RigidBody *CPhysicalEntity::GetRigidBody(int ipart) { g_StaticRigidBody.P.zero(); g_StaticRigidBody.v.zero(); g_StaticRigidBody.L.zero(); g_StaticRigidBody.w.zero(); return &g_StaticRigidBody; } int CPhysicalEntity::IsPointInside(vectorf pt) { pt = (pt-m_pos)*m_qrot; if (m_pBoundingGeometry) return m_pBoundingGeometry->PointInsideStatus(pt); for(int i=0;ipGeom->PointInsideStatus((pt-m_parts[i].pos)*m_parts[i].q)) return 1; return 0; } void CPhysicalEntity::AlertNeighbourhoodND() { int i; if (m_iSimClass>3) return; for(i=0;iRemoveCollider(this); m_pColliders[i]->Awake(); m_pColliders[i]->Release(); m_nRefCount--; } m_nColliders = 0; if (m_nRefCount>0 || m_flags&pef_always_notify_on_deletion) { CPhysicalEntity **pentlist; vectorf inflator = (m_BBox[1]-m_BBox[0])*1E-3f+vectorf(4,4,4)*m_pWorld->m_vars.maxContactGap; for(i=m_pWorld->GetEntitiesAround(m_BBox[0]-inflator,m_BBox[1]+inflator, pentlist, ent_sleeping_rigid|ent_rigid|ent_living|ent_independent|ent_triggers)-1; i>=0; i--) pentlist[i]->Awake(); } } int CPhysicalEntity::RemoveCollider(CPhysicalEntity *pCollider, bool bRemoveAlways) { if (m_pColliders && m_iSimClass>0) { int i,islot; for(i=0;iRelease(); m_nColliders--; return islot; } } return -1; } int CPhysicalEntity::AddCollider(CPhysicalEntity *pCollider) { if (m_iSimClass==0) return 1; int i,j; for(i=0;iGetMassInv()>m_pColliders[i]->GetMassInv();i++); for(j=m_nColliders-1; j>=i; j--) m_pColliders[j+1] = m_pColliders[j]; m_pColliders[i] = pCollider; m_nColliders++; if (pCollider!=this) pCollider->AddRef(); } return i; } void CPhysicalEntity::DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags) { if (flags & pe_helper_bbox) { int i,j; vectorf sz,center,pt[8]; center = (m_BBox[1]+m_BBox[0])*0.5f; sz = (m_BBox[1]-m_BBox[0])*0.5f; for(i=0;i<8;i++) pt[i] = vectorf(sz.x*((i<<1&2)-1),sz.y*((i&2)-1),sz.z*((i>>1&2)-1))+center; for(i=0;i<8;i++) for(j=0;j<3;j++) if (i&1<>16; geom_world_data gwd; for(int i=0;ipGeom->DrawWireframe(DrawLineFunc,&gwd, iLevel); if (m_parts[i].pPhysGeomProxy!=m_parts[i].pPhysGeom) m_parts[i].pPhysGeomProxy->pGeom->DrawWireframe(DrawLineFunc,&gwd, iLevel); } } } void CPhysicalEntity::GetMemoryStatistics(ICrySizer *pSizer) { if (GetType()==PE_STATIC) pSizer->AddObject(this, sizeof(CPhysicalEntity)); if (m_parts!=&m_defpart) pSizer->AddObject(m_parts, m_nParts*sizeof(m_parts[0])); pSizer->AddObject(m_pGridThunks, m_nGridThunksAlloc*sizeof(m_pGridThunks[0])); pSizer->AddObject(m_pColliders, m_nCollidersAlloc*sizeof(m_pColliders[0])); } int CPhysicalEntity::GetStateSnapshotTxt(char *txtbuf,int szbuf, float time_back) { CStream stm; GetStateSnapshot(stm,time_back); int size=bin2ascii(stm.GetPtr(),(stm.GetSize()-1>>3)+1,(unsigned char*)txtbuf); /* // debugging static char test[1024*16]; int testsize=ascii2bin((const unsigned char*)txtbuf,size,(unsigned char*)test); if(memcmp(test,stm.GetPtr(),testsize)!=0) { char str[256]; sprintf(str,"%d %d\n",size,testsize); OutputDebugString(str); } */ return size; } void CPhysicalEntity::SetStateFromSnapshotTxt(const char *txtbuf,int szbuf) { CStream stm; stm.SetSize(ascii2bin((const unsigned char*)txtbuf,szbuf,stm.GetPtr())*8); SetStateFromSnapshot(stm); }