!B (CryPhysics) Fix invalid implementation of SMemSerializer::BeginOptionalGroup...
[CRYENGINE.git] / Code / CryEngine / CryPhysics / physicalentity.cpp
blobfd9dda7c3d948ce974bd3b9a23db40ab25918bdd
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
5 #include "bvtree.h"
6 #include "geometry.h"
7 #include "trimesh.h"
8 #include "rigidbody.h"
9 #include "physicalplaceholder.h"
10 #include "physicalentity.h"
11 #include "geoman.h"
12 #include "physicalworld.h"
13 #include "tetrlattice.h"
14 #include "raybv.h"
15 #include "raygeom.h"
16 #include "singleboxtree.h"
17 #include "boxgeom.h"
18 #include "spheregeom.h"
19 #include "cylindergeom.h"
20 #include "capsulegeom.h"
21 #include "rigidentity.h"
22 #include "softentity.h"
24 RigidBody g_StaticRigidBodies[MAX_PHYS_THREADS];
25 CPhysicalEntity g_StaticPhysicalEntity(0);
26 geom CPhysicalEntity::m_defpart;
28 SPartHelper *CPhysicalEntity::g_parts = 0;
29 SStructuralJointHelper *CPhysicalEntity::g_joints = 0;
30 SStructuralJointDebugHelper *CPhysicalEntity::g_jointsDbg = 0;
31 int *CPhysicalEntity::g_jointidx = 0;
32 int CPhysicalEntity::g_nPartsAlloc=0, CPhysicalEntity::g_nJointsAlloc=0;
34 void CPhysicalEntity::CleanupGlobalState()
36 if (g_parts)
37 delete[] (g_parts-1);
38 g_parts = NULL;
40 delete[] g_joints;
41 g_joints = NULL;
43 delete[] g_jointidx;
44 g_jointidx = NULL;
46 delete[] g_jointsDbg;
47 g_jointsDbg = NULL;
49 g_nJointsAlloc = 0;
50 g_nPartsAlloc = 0;
53 CPhysicalEntity::CPhysicalEntity(CPhysicalWorld *pworld, IGeneralMemoryHeap* pHeap)
54 : m_iDeletionTime(0)
55 , m_nRefCount(0)
56 , m_flags(pef_pushable_by_players | pef_traceable | pef_never_affect_triggers | pef_never_break)
57 , m_next(nullptr)
58 , m_prev(nullptr)
59 , m_pWorld(pworld)
60 , m_pHeap(pHeap)
61 , m_nRefCountPOD(0)
62 , m_iLastPODUpdate(0)
63 , m_iPrevSimClass(-1)
64 , m_bMoved(0)
65 , m_bPermanent(1)
66 , m_bPrevPermanent(0)
67 , m_iGroup(-1)
68 , m_next_coll(nullptr)
69 , m_next_coll1(nullptr)
70 , m_next_coll2(nullptr)
71 , m_pos(ZERO)
72 , m_qrot(IDENTITY)
73 , m_pColliders(nullptr)
74 , m_nColliders(0)
75 , m_nCollidersAlloc(0)
76 , m_nSyncColliders(0)
77 , m_lockColliders(0)
78 , m_pOuterEntity(nullptr)
79 , m_bProcessed_aux(0)
80 , m_timeIdle(0.0f)
81 , m_maxTimeIdle(0.0f)
82 , m_timeStructUpdate(0.0f)
83 , m_updStage(1)
84 , m_nUpdTicks(0)
85 , m_pExpl(nullptr)
86 , m_nParts(0)
87 , m_nPartsAlloc(0)
88 , m_iLastIdx(0)
89 , m_lockPartIdx(0)
90 , m_ground(nullptr)
91 , m_nGroundPlanes(0)
92 , m_pUsedParts(nullptr)
93 , m_nUsedParts(0)
94 , m_pStructure(nullptr)
96 //CPhysicalPlaceholder
97 static_assert(CRY_ARRAY_COUNT(m_BBox) == 2, "Invalid array size!");
98 m_BBox[0].zero();
99 m_BBox[1].zero();
100 m_iSimClass = 0;
101 m_iGThunk0 = 0;
102 static_assert(CRY_ARRAY_COUNT(m_ig) == 2, "Invalid array size!");
103 m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = GRID_REG_PENDING;
104 m_bProcessed = 0;
105 m_id = -1;
106 m_pForeignData = nullptr;
107 m_iForeignData = m_iForeignFlags = 0;
108 m_pEntBuddy = nullptr;
109 m_lockUpdate = 0;
111 //CPhysicalEntity
112 m_parts = &m_defpart;
113 m_parts[0].pNewCoords = (coord_block_BBox*)&m_parts[0].pos;
114 m_pNewCoords = m_pSyncCoords = (coord_block*)&m_pos;
116 m_collisionClass.type = m_collisionClass.ignore = 0;
119 CPhysicalEntity::~CPhysicalEntity()
121 if( m_pUsedParts )
123 if (m_pHeap)
124 m_pHeap->Free(m_pUsedParts);
125 else
126 delete[] m_pUsedParts;
128 for(int i=0;i<m_nParts;i++) if (m_parts[i].pPhysGeom) {
129 if (m_parts[i].pMatMapping && m_parts[i].pMatMapping!=m_parts[i].pPhysGeom->pMatMapping)
130 delete[] m_parts[i].pMatMapping;
131 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
132 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
133 if (m_parts[i].flags & geom_can_modify && m_parts[i].pLattice)
134 m_parts[i].pLattice->Release();
135 if (m_parts[i].pPlaceholder)
136 m_pWorld->DestroyPhysicalEntity(ReleasePartPlaceholder(i),0,1);
138 if (m_parts!=&m_defpart)
140 if (m_pHeap)
141 m_pHeap->Free(m_parts);
142 else
143 m_pWorld->FreeEntityParts(m_parts,m_nPartsAlloc);
145 if (m_pColliders) delete[] m_pColliders;
146 if (m_ground) delete[] m_ground;
147 if (m_pExpl) delete[] m_pExpl;
148 if (m_pStructure) {
149 delete[] m_pStructure->pJoints;
150 delete[] m_pStructure->pParts;
151 if (m_pStructure->defparts) {
152 for(int j=0;j<m_nParts;j++) if (m_pStructure->defparts[j].pSkinInfo) {
153 delete[] m_pStructure->defparts[j].pSkinInfo;
154 m_pWorld->DestroyPhysicalEntity(m_pStructure->defparts[j].pSkelEnt,0,1);
156 delete[] m_pStructure->defparts;
158 if (m_pStructure->Pexpl) delete[] m_pStructure->Pexpl;
159 if (m_pStructure->Lexpl) delete[] m_pStructure->Lexpl;
160 delete m_pStructure; m_pStructure = 0;
162 if (m_pSyncCoords!=(coord_block*)&m_pos) delete m_pSyncCoords;
163 if(m_pOuterEntity && !m_pWorld->m_bMassDestruction)m_pOuterEntity->Release();
164 if(m_pWorld && !m_pWorld->m_bMassDestruction)assert(!m_nRefCount && !m_nRefCountPOD);
167 void CPhysicalEntity::Delete() {
168 IGeneralMemoryHeap* pHeap = m_pHeap;
170 this->~CPhysicalEntity();
172 if (pHeap)
173 pHeap->Free(this);
174 else
175 CryModuleFree(this);
178 int CPhysicalEntity::AddRef() {
179 if (IsPODThread(m_pWorld) && m_pWorld->m_lockPODGrid) {
180 if (m_iLastPODUpdate==m_pWorld->m_iLastPODUpdate)
181 return m_nRefCount;
182 m_iLastPODUpdate = m_pWorld->m_iLastPODUpdate;
183 ++m_nRefCountPOD;
185 AtomicAdd(&m_nRefCount, 1);
186 return m_nRefCount;
189 int CPhysicalEntity::Release() {
190 if (IsPODThread(m_pWorld) && m_pWorld->m_lockPODGrid) {
191 if (m_iLastPODUpdate==m_pWorld->m_iLastPODUpdate)
192 return m_nRefCount;
193 m_iLastPODUpdate = m_pWorld->m_iLastPODUpdate;
194 if (m_nRefCountPOD<=0)
195 return m_nRefCount;
196 --m_nRefCountPOD;
198 AtomicAdd(&m_nRefCount, -1);
199 return m_nRefCount;
202 void CPhysicalEntity::GetLocTransform(int ipart, Vec3 &offs, quaternionf &q, float &scale, const CPhysicalPlaceholder *trg) const
204 if ((unsigned int)ipart<(unsigned int)m_nParts) {
205 q = m_qrot*m_parts[ipart].q;
206 offs = m_qrot*m_parts[ipart].pos + m_pos;
207 scale = m_parts[ipart].scale;
208 } else {
209 q.SetIdentity(); offs.zero(); scale=1.0f;
211 m_pWorld->TransformToGrid(this,trg, offs,q);
214 void CPhysicalEntity::ComputeBBox(Vec3 *BBox, int flags)
216 const int numParts = m_nParts+(flags & part_added);
217 if (numParts) {
218 IGeometry *pGeom[3];
219 int i,j;
220 const float fMax = 1.0E15f;
221 const float fMin = -1.0E15f;
222 Vec3 BBoxMin(fMax), BBoxMax(fMin);
223 const Quat& qNewCoords = m_pNewCoords->q;
224 const Vec3& vNewCoords = m_pNewCoords->pos;
226 if (m_iSimClass-4 | m_nParts-10>>31) {
227 for(i=0; i<numParts ; i++) {
228 int inext = min(i+1, numParts-1);
229 PrefetchLine(m_parts[inext].pPhysGeom, 0);
230 PrefetchLine(m_parts[inext].pPhysGeomProxy, 0);
231 PrefetchLine(m_parts[inext].pNewCoords, 0);
232 pGeom[0] = m_parts[i].pPhysGeomProxy->pGeom;
233 pGeom[1]=pGeom[2] = m_parts[i].pPhysGeom->pGeom;
234 const Matrix33 RT = Matrix33(qNewCoords*m_parts[i].pNewCoords->q).T();
235 Vec3 partBBoxMin(fMax),partBBoxMax(fMin);
236 j=0; do {
237 box abox;
238 pGeom[j]->GetBBox(&abox);
239 const Matrix33 boxMat = (abox.Basis * RT).Fabs(); //Put in local var to avoid writes to memory caused by use of abox as an out-reference in the call to GetBBox()
240 Vec3 sz = (abox.size*boxMat)*m_parts[i].pNewCoords->scale;
241 Vec3 pos = vNewCoords + qNewCoords*(m_parts[i].pNewCoords->pos +
242 m_parts[i].pNewCoords->q*abox.center*m_parts[i].pNewCoords->scale);
243 Vec3 boxMin = pos-sz;
244 Vec3 boxMax = pos+sz;
245 partBBoxMin = min_safe(partBBoxMin, boxMin);
246 partBBoxMax = max_safe(partBBoxMax, boxMax);
247 j++;
248 } while(pGeom[j]!=pGeom[j-1]);
250 if (!(m_parts[i].flags & geom_ignore_BBox)) {
251 BBoxMin = min_safe(BBoxMin, partBBoxMin);
252 BBoxMax = max_safe(BBoxMax, partBBoxMax);
255 if(flags & update_part_bboxes) {
256 m_parts[i].pNewCoords->BBox[0] = partBBoxMin;
257 m_parts[i].pNewCoords->BBox[1] = partBBoxMax;
260 } else { // for simclass-4 ents with 10+ parts (typically character skeletons) use a simplified bounding sphere-based calculation
261 for(i=0; i<numParts ; i++) {
262 int inext = min(i+1, numParts-1);
263 PrefetchLine(m_parts[inext].pPhysGeom, 0);
264 PrefetchLine(m_parts[inext].pNewCoords, 0);
265 sphere sph;
266 switch((pGeom[0] = m_parts[i].pPhysGeom->pGeom)->GetType()) {
267 case GEOM_SPHERE: {
268 CSphereGeom *pSph = (CSphereGeom*)pGeom[0]; sph.center=pSph->m_sphere.center; sph.r=pSph->m_sphere.r;
269 } break;
270 case GEOM_CAPSULE: {
271 CCapsuleGeom *pCaps = (CCapsuleGeom*)pGeom[0]; sph.center=pCaps->m_cyl.center; sph.r=pCaps->m_cyl.hh+pCaps->m_cyl.r;
272 } break;
273 default: {
274 box abox; pGeom[0]->GetBBox(&abox); sph.center=abox.center; sph.r=max(max(abox.size.x,abox.size.y),abox.size.z);
275 } break;
277 PrefetchLine(m_parts[inext].pPhysGeom->pGeom, 0);
278 sph.center = qNewCoords*(m_parts[i].pNewCoords->q*sph.center + m_parts[i].pNewCoords->pos) + vNewCoords;
279 sph.r *= m_parts[i].pNewCoords->scale;
280 Vec3 partBBox[2] = { sph.center-Vec3(sph.r), sph.center+Vec3(sph.r) };
282 BBoxMin = min_safe(BBoxMin, partBBox[0]);
283 BBoxMax = max_safe(BBoxMax, partBBox[1]);
285 if(flags & update_part_bboxes) {
286 m_parts[i].pNewCoords->BBox[0] = partBBox[0];
287 m_parts[i].pNewCoords->BBox[1] = partBBox[1];
292 BBox[0] = BBoxMin;
293 BBox[1] = BBoxMax;
294 } else
295 BBox[0]=BBox[1] = m_pNewCoords->pos;
297 if (m_pEntBuddy && BBox==m_BBox)
298 m_pEntBuddy->m_BBox[0]=BBox[0], m_pEntBuddy->m_BBox[1]=BBox[1];
301 int CPhysicalEntity::SetParams(pe_params *_params, int bThreadSafe)
303 if (_params->type==pe_params_part::type_id) {
304 pe_params_part *params = (pe_params_part*)_params;
305 if (!is_unused(params->pPhysGeom) && params->pPhysGeom && params->pPhysGeom->pGeom)
306 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeom);
307 if (!is_unused(params->pPhysGeomProxy) && params->pPhysGeomProxy && params->pPhysGeomProxy->pGeom)
308 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeomProxy);
310 ChangeRequest<pe_params> req(this,m_pWorld,_params,bThreadSafe);
311 if (req.IsQueued()) {
312 if (_params->type==pe_params_pos::type_id && m_pSyncCoords!=(coord_block*)&m_pos) {
313 pe_params_pos *params = (pe_params_pos*)_params;
314 if (!is_unused(params->pos)) m_pSyncCoords->pos = params->pos;
315 if (!is_unused(params->q)) m_pSyncCoords->q = params->q;
316 Vec3 mcol[3]; int i=0;
317 if (!is_unused(params->pMtx3x3) && params->pMtx3x3)
318 for(i=0;i<3;i++) mcol[i] = params->pMtx3x3->GetColumn(i);
319 if (!is_unused(params->pMtx3x4) && params->pMtx3x4) {
320 for(i=0;i<3;i++) mcol[i] = params->pMtx3x4->GetColumn(i);
321 m_pSyncCoords->pos = params->pMtx3x4->GetTranslation();
323 if (i)
324 m_pSyncCoords->q = Quat(fabs(mcol[0].len2()-1)+fabs(mcol[1].len2()-1)+fabs(mcol[2].len2()-1) < 0.01f ?
325 Matrix33(mcol[0],mcol[1],mcol[2]) : Matrix33(mcol[0].normalized(),mcol[1].normalized(),mcol[2].normalized()));
327 return 1+(m_bProcessed>>PENT_QUEUED_BIT);
330 if (_params->type==pe_params_pos::type_id) {
331 pe_params_pos *params = (pe_params_pos*)_params;
332 int i,j,bPosChanged=0,bBBoxReady=0;
333 SEntityGrid *pgridCur = m_pWorld->GetGrid(this), *pgridNew = is_unused(params->pGridRefEnt) ? pgridCur :
334 (!params->pGridRefEnt || params->pGridRefEnt==WORLD_ENTITY ? &m_pWorld->m_entgrid : m_pWorld->GetGrid(params->pGridRefEnt));
335 if (pgridNew != pgridCur) {
336 { WriteLock lockG(m_pWorld->m_lockGrid);
337 m_pWorld->DetachEntityGridThunks(this);
339 QuatT transNew = pgridNew->m_transW.GetInverted() * pgridCur->m_transW * QuatT(m_pNewCoords->q,m_pNewCoords->pos);
340 m_pWorld->SetGrid(this, pgridNew);
341 params->pos = transNew.t; params->q = transNew.q;
342 int nparts = GetType()==PE_ARTICULATED ? m_nParts : 1;
343 pe_status_dynamics sd;
344 pe_action_set_velocity asv;
345 for(asv.ipart=sd.ipart=0; asv.ipart<nparts; asv.ipart++,sd.ipart++) {
346 GetStatus(&sd);
347 asv.v = !pgridNew->m_transW.q*(pgridCur->m_transW.q*sd.v + pgridCur->m_velW - pgridNew->m_velW);
348 asv.w = !pgridNew->m_transW.q*(pgridCur->m_transW.q*sd.w);
349 Action(&asv);
353 Vec3 scale;
354 if ((scale=get_xqs_from_matrices(params->pMtx3x4,params->pMtx3x3, params->pos,params->q,params->scale)).len2()>3.03f) {
355 WriteLock lock(m_lockUpdate);
356 for(i=0;i<m_nParts;i++) {
357 phys_geometry *pgeom;
358 if (m_parts[i].pPhysGeom!=m_parts[i].pPhysGeomProxy) {
359 if (!(pgeom = (phys_geometry*)m_parts[i].pPhysGeomProxy->pGeom->GetForeignData(DATA_UNSCALED_GEOM)))
360 pgeom = m_parts[i].pPhysGeomProxy;
361 if (BakeScaleIntoGeometry(pgeom,m_pWorld->GetGeomManager(),scale)) {
362 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
363 (m_parts[i].pPhysGeomProxy=pgeom)->nRefCount++;
366 bool doBake = true;
367 if (!(pgeom = (phys_geometry*)m_parts[i].pPhysGeom->pGeom->GetForeignData(DATA_UNSCALED_GEOM)))
368 doBake = (pgeom = m_parts[i].pPhysGeom)->nRefCount>1; // can't store DATA_UNSCALED_GEOM ptr to a volatile geom
369 if (doBake && BakeScaleIntoGeometry(pgeom,m_pWorld->GetGeomManager(),scale)) {
370 if (m_parts[i].pPhysGeom==m_parts[i].pPhysGeomProxy) {
371 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
372 (m_parts[i].pPhysGeomProxy = pgeom)->nRefCount++;
374 if (m_parts[i].pMatMapping==m_parts[i].pPhysGeom->pMatMapping)
375 m_parts[i].pMatMapping = pgeom->pMatMapping;
376 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
377 (m_parts[i].pPhysGeom=pgeom)->nRefCount++;
381 ENTITY_VALIDATE("CPhysicalEntity:SetParams(pe_params_pos)",params);
382 Vec3 BBox[2];
383 coord_block cnew,*pcPrev;
384 cnew.pos = m_pos; cnew.q = m_qrot;
385 if (!is_unused(params->pos)) { cnew.pos = params->pos; bPosChanged=1; }
386 if (!is_unused(params->q)) { cnew.q = params->q; bPosChanged=1; }
387 if (!is_unused(params->iSimClass) && m_iSimClass>=0 && m_iSimClass<7) {
388 m_iSimClass = params->iSimClass;
389 m_pWorld->RepositionEntity(this,2);
391 if (!is_unused(params->doubleBufCoords) && params->doubleBufCoords!=(m_pSyncCoords!=(coord_block*)&m_pos))
392 if (!params->doubleBufCoords) {
393 delete m_pSyncCoords; m_pSyncCoords = (coord_block*)&m_pos;
394 } else
395 *(m_pSyncCoords = new coord_block) = { m_pos,m_qrot };
397 if (!is_unused(params->scale)) {
398 if (params->bRecalcBounds) {
399 IGeometry *pGeom[3];
400 Matrix33 R;
401 box abox;
402 BBox[0]=Vec3(VMAX); BBox[1]=Vec3(VMIN);
403 if (m_nParts==0)
404 BBox[0]=BBox[1] = cnew.pos;
405 else for(i=0;i<m_nParts;i++) {
406 pGeom[0] = m_parts[i].pPhysGeomProxy->pGeom;
407 pGeom[1]=pGeom[2] = m_parts[i].pPhysGeom->pGeom;
408 j=0; do {
409 pGeom[j]->GetBBox(&abox);
410 R = Matrix33(cnew.q*m_parts[i].q);
411 abox.Basis *= R.T();
412 Vec3 sz = (abox.size*abox.Basis.Fabs())*params->scale;
413 Vec3 pos = cnew.pos+cnew.q*(m_parts[i].pos*(params->scale/m_parts[i].scale)+m_parts[i].q*abox.center*params->scale);
414 BBox[0] = min_safe(BBox[0], pos-sz);
415 BBox[1] = max_safe(BBox[1], pos+sz);
416 j++;
417 } while(pGeom[j]!=pGeom[j-1]);
419 bBBoxReady = 1;
421 bPosChanged = 1;
424 if (bPosChanged) {
425 if (params->bRecalcBounds) {
426 CPhysicalEntity **pentlist;
427 // make triggers aware of the object's movements
428 if (!(m_flags & pef_never_affect_triggers))
429 m_pWorld->GetEntitiesAround(m_BBox[0],m_BBox[1],pentlist,ent_triggers,this);
430 pcPrev=m_pNewCoords; m_pNewCoords=&cnew;
431 if (!bBBoxReady)
432 ComputeBBox(BBox,0);
433 if (!params->bEntGridUseOBB || m_pStructure)
434 bPosChanged = m_pWorld->RepositionEntity(this,1 | (params->bRecalcBounds&128)>>3,BBox);
435 m_pNewCoords = pcPrev;
438 { WriteLock lock(m_lockUpdate);
439 m_pos=m_pNewCoords->pos = cnew.pos; m_qrot=m_pNewCoords->q = cnew.q;
440 m_pSyncCoords->pos = cnew.pos; m_pSyncCoords->q = cnew.q;
441 if (!is_unused(params->scale)) for(i=0;i<m_nParts;i++) {
442 float dscale = params->scale/m_parts[i].scale;
443 m_parts[i].mass *= cube(dscale);
444 m_parts[i].pNewCoords->pos = (m_parts[i].pos *= dscale);
445 m_parts[i].pNewCoords->scale = (m_parts[i].scale = params->scale);
447 if (params->bRecalcBounds) {
448 ComputeBBox(BBox);
449 if (params->bEntGridUseOBB && !m_pStructure)
450 bPosChanged = m_pWorld->RepositionEntity(this,5,BBox);
451 m_BBox[0] = BBox[0];
452 m_BBox[1] = BBox[1];
453 m_pWorld->UnlockGrid(this,-bPosChanged);
456 if (params->bRecalcBounds)
457 RepositionParts();
458 if (params->bRecalcBounds && !(m_flags & pef_never_affect_triggers)) {
459 CPhysicalEntity **pentlist;
460 m_pWorld->GetEntitiesAround(m_BBox[0],m_BBox[1],pentlist,ent_triggers,this);
464 return 1;
467 if (_params->type==pe_params_bbox::type_id) {
468 pe_params_bbox *params = (pe_params_bbox*)_params;
469 ENTITY_VALIDATE("CPhysicalEntity::SetParams(pe_params_bbox)",params);
470 Vec3 BBox[2] = { m_BBox[0],m_BBox[1] };
471 if (!is_unused(params->BBox[0])) BBox[0] = params->BBox[0];
472 if (!is_unused(params->BBox[1])) BBox[1] = params->BBox[1];
473 int bPosChanged = m_pWorld->RepositionEntity(this,1,BBox);
474 { WriteLock lock(m_lockUpdate);
475 WriteBBox(BBox);
476 m_pWorld->UnlockGrid(this,-bPosChanged);
478 return 1;
481 if (_params->type==pe_params_part::type_id) {
482 pe_params_part *params = (pe_params_part*)_params;
483 int i = params->ipart;
484 if (is_unused(params->ipart) && is_unused(params->partid)) {
485 for(i=0;i<m_nParts;i++) if (is_unused(params->flagsCond) || m_parts[i].flags & params->flagsCond) {
486 m_parts[i].flags = m_parts[i].flags & params->flagsAND | params->flagsOR;
487 m_parts[i].flagsCollider = m_parts[i].flagsCollider & params->flagsColliderAND | params->flagsColliderOR;
488 if (!is_unused(params->mass)) m_parts[i].mass = params->mass;
489 if (!is_unused(params->idmatBreakable)) m_parts[i].idmatBreakable = -1;
490 if (!is_unused(params->pMatMapping)) {
491 int *pMapping0 = m_parts[i].pMatMapping;
492 if ((!pMapping0 || params->nMats!=m_parts[i].nMats || pMapping0==m_parts[i].pPhysGeom->pMatMapping) && params->pMatMapping)
493 m_parts[i].pMatMapping = new int[m_parts[i].nMats = params->nMats];
494 else pMapping0 = 0;
495 if (params->pMatMapping && params->nMats>0)
496 memcpy(m_parts[i].pMatMapping, params->pMatMapping, params->nMats*sizeof(int));
497 else
499 if (m_parts[i].pMatMapping!=pMapping0 && m_parts[i].pMatMapping!=m_parts[i].pPhysGeom->pMatMapping)
500 delete[] m_parts[i].pMatMapping;
501 m_parts[i].pMatMapping=0, m_parts[i].nMats=0;
503 if (pMapping0 && pMapping0!=m_parts[i].pPhysGeom->pMatMapping)
504 delete[] pMapping0;
507 return 1;
509 if (is_unused(params->ipart))
510 for(i=0;i<m_nParts && m_parts[i].id!=params->partid;i++);
511 if (i>=m_nParts)
512 return 0;
513 Vec3 scale;
514 if ((scale=get_xqs_from_matrices(params->pMtx3x4,params->pMtx3x3, params->pos,params->q,params->scale)).len2()>3.03f) {
515 if (is_unused(params->pPhysGeom))
516 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeom=m_parts[i].pPhysGeom);
517 if (is_unused(params->pPhysGeomProxy))
518 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeomProxy=m_parts[i].pPhysGeomProxy);
519 phys_geometry *pgeom0 = params->pPhysGeom;
520 if (BakeScaleIntoGeometry(params->pPhysGeom,m_pWorld->GetGeomManager(),scale,1))
521 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeom);
522 if (pgeom0!=params->pPhysGeomProxy) {
523 if (BakeScaleIntoGeometry(params->pPhysGeomProxy,m_pWorld->GetGeomManager(),scale,1))
524 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeomProxy);
525 } else
526 params->pPhysGeomProxy = params->pPhysGeom;
528 ENTITY_VALIDATE("CPhysicalEntity:SetParams(pe_params_part)",params);
529 coord_block_BBox newCoord,*prevCoord=m_parts[i].pNewCoords;
530 Vec3 BBox[2] = { m_BBox[0],m_BBox[1] };
531 newCoord.pos = newCoord.BBox[0]=newCoord.BBox[1] = m_parts[i].pos;
532 newCoord.q = m_parts[i].q;
533 newCoord.scale = m_parts[i].scale;
534 int bPosChanged=0;
535 if (!is_unused(params->ipart) && !is_unused(params->partid)) m_parts[i].id = params->partid;
536 if (!is_unused(params->pos.x)) newCoord.pos = params->pos;
537 if (!is_unused(params->q)) newCoord.q = params->q;
538 if (!is_unused(params->scale)) m_parts[i].mass *= cube((newCoord.scale = params->scale)/m_parts[i].scale);
539 if (!is_unused(params->mass)) m_parts[i].mass = params->mass;
540 if (!is_unused(params->density)) m_parts[i].mass = m_parts[i].pPhysGeom->V*cube(m_parts[i].scale)*params->density;
541 if (!is_unused(params->minContactDist) && is_unused(params->idSkeleton)) m_parts[i].minContactDist = params->minContactDist;
542 if (!is_unused(params->pPhysGeom) && params->pPhysGeom!=m_parts[i].pPhysGeom && params->pPhysGeom && params->pPhysGeom->pGeom) {
543 WriteLock lock(m_lockUpdate);
544 if (m_parts[i].pMatMapping==m_parts[i].pPhysGeom->pMatMapping) {
545 m_parts[i].pMatMapping = params->pPhysGeom->pMatMapping;
546 m_parts[i].nMats = params->pPhysGeom->nMats;
548 m_parts[i].surface_idx = params->pPhysGeom->surface_idx;
549 if (m_parts[i].pPhysGeom==m_parts[i].pPhysGeomProxy) {
550 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
551 m_pWorld->GetGeomManager()->AddRefGeometry(m_parts[i].pPhysGeomProxy = params->pPhysGeom);
553 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
554 m_parts[i].pPhysGeom = params->pPhysGeom;
555 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeom);
556 if (m_parts[i].flags & geom_can_modify && m_pStructure && m_pStructure->defparts && m_pStructure->defparts[i].pSkelEnt &&
557 !((CGeometry*)m_parts[i].pPhysGeom->pGeom)->IsAPrimitive())
558 m_pWorld->ClonePhysGeomInEntity(this, i, m_pWorld->CloneGeometry(m_parts[i].pPhysGeom->pGeom));
559 if (m_nRefCount && m_iSimClass==0 && m_pWorld->m_vars.lastTimeStep>0.0f) {
560 CPhysicalEntity **pentlist;
561 Vec3 inflator = Vec3(10.0f)*m_pWorld->m_vars.maxContactGap;
562 for(int j=m_pWorld->GetEntitiesAround(m_BBox[0]-inflator,m_BBox[1]+inflator, pentlist, ent_sleeping_rigid|ent_living|ent_independent)-1; j>=0; j--)
563 if (m_iSimClass || pentlist[j]->HasPartContactsWith(this,i))
564 pentlist[j]->Awake();
567 if (!is_unused(params->pPhysGeom) && params->pPhysGeom && params->pPhysGeom->pGeom)
568 m_pWorld->GetGeomManager()->UnregisterGeometry(params->pPhysGeom);
569 if (!is_unused(params->pPhysGeomProxy) && params->pPhysGeomProxy!=m_parts[i].pPhysGeomProxy &&
570 params->pPhysGeomProxy && params->pPhysGeomProxy->pGeom)
572 WriteLock lock(m_lockUpdate);
573 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
574 m_parts[i].pPhysGeomProxy = params->pPhysGeomProxy;
575 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeomProxy);
577 if (!is_unused(params->pPhysGeomProxy) && params->pPhysGeomProxy && params->pPhysGeomProxy->pGeom)
578 m_pWorld->GetGeomManager()->UnregisterGeometry(params->pPhysGeomProxy);
579 if (!is_unused(params->pLattice) && (ITetrLattice*)m_parts[i].pLattice!=params->pLattice &&
580 m_parts[i].pPhysGeomProxy->pGeom->GetType()==GEOM_TRIMESH)
582 if (m_parts[i].flags & geom_can_modify && m_parts[i].pLattice)
583 m_parts[i].pLattice->Release();
584 (m_parts[i].pLattice = (CTetrLattice*)params->pLattice)->SetMesh((CTriMesh*)m_parts[i].pPhysGeomProxy->pGeom);
586 if (!is_unused(params->pMatMapping)) {
587 int *pMapping0 = m_parts[i].pMatMapping;
588 if ((!pMapping0 || params->nMats!=m_parts[i].nMats) && params->pMatMapping)
589 m_parts[i].pMatMapping = new int[m_parts[i].nMats = params->nMats];
590 else pMapping0 = 0;
591 if (params->pMatMapping && params->nMats>0)
592 memcpy(m_parts[i].pMatMapping, params->pMatMapping, params->nMats*sizeof(int));
593 else
595 if (m_parts[i].pMatMapping!=pMapping0 && m_parts[i].pMatMapping!=m_parts[i].pPhysGeom->pMatMapping)
596 delete[] m_parts[i].pMatMapping;
597 m_parts[i].pMatMapping=0, m_parts[i].nMats=0;
599 if (pMapping0 && pMapping0!=m_parts[i].pPhysGeom->pMatMapping)
600 delete[] pMapping0;
602 if (!is_unused(params->idmatBreakable))
603 m_parts[i].idmatBreakable = params->idmatBreakable;
604 else if (!is_unused(params->pMatMapping) || !is_unused(params->pPhysGeom))
605 UpdatePartIdmatBreakable(i);
606 m_parts[i].flags = m_parts[i].flags & params->flagsAND | params->flagsOR;
607 m_parts[i].flagsCollider = m_parts[i].flagsCollider & params->flagsColliderAND | params->flagsColliderOR;
608 if (!is_unused(params->idSkeleton)) {
609 if (m_pStructure && m_pStructure->defparts && m_pStructure->defparts[i].pSkinInfo && params->idSkeleton<0) {
610 delete[] m_pStructure->defparts[i].pSkinInfo;
611 m_pWorld->DestroyPhysicalEntity(m_pStructure->defparts[i].pSkelEnt,0,1);
612 m_pStructure->defparts[i].pSkinInfo = 0;
613 m_pStructure->defparts[i].pSkelEnt = 0;
614 } else if (params->idSkeleton>=0) {
615 int iskel;
616 for(iskel=0; iskel<m_nParts && m_parts[iskel].id!=params->idSkeleton; iskel++);
617 if (iskel<m_nParts && MakeDeformable(i, iskel, is_unused(params->minContactDist) ? 0.0f:params->minContactDist)) {
618 assert(m_pStructure->defparts);
619 m_pStructure->defparts[i].idSkel = params->idSkeleton;
620 m_parts[i].flags |= geom_monitor_contacts;
624 if (!is_unused(params->idParent)) {
625 AllocStructureInfo();
626 int j; for(j=m_nParts-1;j>=0 && m_parts[j].id!=params->idParent;j--);
627 m_pStructure->pParts[i].iParent = j+1;
628 m_pStructure->pParts[j].bGroup = 1;
629 if (j>=0) {
630 m_parts[j].flags &= ~geom_colltype_explosion;
631 m_pStructure->pParts[i].flags0 = m_parts[i].flags;
632 m_pStructure->pParts[i].flagsCollider0 = m_parts[i].flagsCollider;
633 m_parts[i].flags &= geom_colltype_explosion|geom_monitor_contacts;
634 m_parts[i].flagsCollider = 0;
637 if (m_parts[i].pLattice)
638 m_parts[i].flags |= geom_monitor_contacts;
639 if (params->bRecalcBBox) {
640 m_parts[i].pNewCoords = &newCoord;
641 ComputeBBox(BBox);
642 bPosChanged = m_pWorld->RepositionEntity(this,1,BBox);
644 { WriteLock lock(m_lockUpdate);
645 m_parts[i].pNewCoords = prevCoord;
646 m_parts[i].pos = m_parts[i].pNewCoords->pos = newCoord.pos;
647 m_parts[i].q = m_parts[i].pNewCoords->q = newCoord.q;
648 m_parts[i].scale = m_parts[i].pNewCoords->scale = newCoord.scale;
649 if (params->bRecalcBBox) {
650 WriteBBox(BBox);
651 m_parts[i].BBox[0] = m_parts[i].pNewCoords->BBox[0] = newCoord.BBox[0];
652 m_parts[i].BBox[1] = m_parts[i].pNewCoords->BBox[1] = newCoord.BBox[1];
653 for(int j=0;j<m_nParts;j++)
654 if (i!=j && m_parts[j].pNewCoords!=(coord_block_BBox*)&m_parts[j].pos) {
655 m_parts[j].BBox[0] = m_parts[j].pNewCoords->BBox[0];
656 m_parts[j].BBox[1] = m_parts[j].pNewCoords->BBox[1];
659 m_pWorld->UnlockGrid(this,-bPosChanged);
661 if (params->bRecalcBBox)
662 RepositionParts();
663 return i+1;
666 if (_params->type==pe_params_outer_entity::type_id) {
667 if (m_pOuterEntity) m_pOuterEntity->Release();
668 m_pOuterEntity = (CPhysicalEntity*)((pe_params_outer_entity*)_params)->pOuterEntity;
669 if (m_pOuterEntity) m_pOuterEntity->AddRef();
670 return 1;
673 if (_params->type==pe_params_foreign_data::type_id) {
674 //WriteLock lock(m_lockUpdate);
675 pe_params_foreign_data *params = (pe_params_foreign_data*)_params;
677 void* pForeignDataOld = m_pForeignData;
678 if (!is_unused(params->pForeignData)) m_pForeignData = 0;
679 if (!is_unused(params->iForeignData)) m_iForeignData = params->iForeignData;
680 if (!is_unused(params->pForeignData)) m_pForeignData = params->pForeignData;
681 if (!is_unused(params->iForeignFlags)) m_iForeignFlags = params->iForeignFlags;
682 m_iForeignFlags = (m_iForeignFlags & params->iForeignFlagsAND) | params->iForeignFlagsOR;
683 if (m_pEntBuddy) {
684 m_pEntBuddy->m_pForeignData = m_pForeignData;
685 m_pEntBuddy->m_iForeignData = m_iForeignData;
686 m_pEntBuddy->m_iForeignFlags = m_iForeignFlags;
689 if (pForeignDataOld && m_pForeignData && pForeignDataOld!=m_pForeignData)
690 // Changing foreign-data, clear the event queue of potentially stale events
691 m_pWorld->PatchEventsQueue(this, m_pForeignData, m_iForeignData);
693 return 1;
696 if (_params->type==pe_params_collision_class::type_id) {
697 pe_params_collision_class *params = (pe_params_collision_class*)_params;
698 m_collisionClass.type &= params->collisionClassAND.type;
699 m_collisionClass.type |= params->collisionClassOR.type;
700 m_collisionClass.ignore &= params->collisionClassAND.ignore;
701 m_collisionClass.ignore |= params->collisionClassOR.ignore;
702 return 1;
705 if (_params->type==pe_params_flags::type_id) {
706 pe_params_flags *params = (pe_params_flags*)_params;
707 if (!is_unused(params->flags)) m_flags = params->flags;
708 if (!is_unused(params->flagsAND)) m_flags &= params->flagsAND;
709 if (!is_unused(params->flagsOR)) m_flags |= params->flagsOR;
710 if (m_flags & pef_parts_traceable && m_iSimClass<3) {
711 Vec3 gBBox[2]; m_pWorld->GetGrid(this)->BBoxToGrid(m_BBox[0],m_BBox[1],gBBox);
712 Vec3 sz = gBBox[1]-gBBox[0];
713 if (float2int(sz.x*m_pWorld->m_entgrid.stepr.x+0.5f)*float2int(sz.y*m_pWorld->m_entgrid.stepr.y+0.5f)*4 < m_nParts)
714 (m_flags &= ~pef_parts_traceable) |= pef_traceable;
715 else
716 m_flags &= ~pef_traceable;
719 if (m_flags&pef_traceable && m_ig[0].x==NO_GRID_REG) {
720 m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = m_flags & pef_disabled ? GRID_REG_LAST : GRID_REG_PENDING;
721 if (m_pos.len2()>0)
722 m_pWorld->RepositionEntity(this,1|8);
723 RepositionParts();
725 if (!(m_flags&pef_traceable) && m_ig[0].x!=NO_GRID_REG) {
726 { WriteLock lock(m_pWorld->m_lockGrid);
727 m_pWorld->DetachEntityGridThunks(this);
728 m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = NO_GRID_REG;
730 RepositionParts();
733 return 1;
736 if (_params->type==pe_params_ground_plane::type_id) {
737 pe_params_ground_plane *params = (pe_params_ground_plane*)_params;
738 if (params->iPlane<0) {
739 m_nGroundPlanes = 0;
740 if (m_ground) { delete[] m_ground; m_ground=0; }
741 } else if (params->iPlane>=m_nGroundPlanes) {
742 ReallocateList(m_ground,m_nGroundPlanes,params->iPlane+1,true);
743 m_nGroundPlanes = params->iPlane+1;
745 if (!is_unused(params->ground.origin)) m_ground[params->iPlane].origin = params->ground.origin;
746 if (!is_unused(params->ground.n)) m_ground[params->iPlane].n = params->ground.n;
747 return 1;
750 if (_params->type==pe_params_structural_joint::type_id) {
751 pe_params_structural_joint *params = (pe_params_structural_joint*)_params;
752 int i,j,iop;
754 if (!is_unused(params->idx) && params->idx==-1) {
755 if (m_pStructure) {
756 if (!is_unused(params->partidEpicenter)) m_pStructure->idpartBreakOrg = params->partidEpicenter;
757 m_pWorld->MarkEntityAsDeforming(this);
759 return 1;
761 if (params->idx==-2)
762 return GenerateJoints();
763 AllocStructureInfo();
765 if (params->bReplaceExisting)
766 for(i=0; i<m_pStructure->nJoints && m_pStructure->pJoints[i].id!=params->id; i++);
767 else i = m_pStructure->nJoints;
768 if (i>=m_pStructure->nJointsAlloc)
769 ReallocateList(m_pStructure->pJoints, m_pStructure->nJointsAlloc,m_pStructure->nJointsAlloc+4,true), m_pStructure->nJointsAlloc+=4;
770 if (i>=m_pStructure->nJoints)
771 memset(m_pStructure->pJoints+i, 0, sizeof(m_pStructure->pJoints[0]));
773 for(iop=0;iop<2;iop++) if (!is_unused(params->partid[iop]) || i==m_pStructure->nJoints) {
774 for(j=m_nParts-1;j>=0 && m_parts[j].id!=params->partid[iop];j--);
775 if (j>=0 && m_parts[j].mass==0 && (is_unused(params->limitConstraint) || params->limitConstraint.z<=0) && params->id!=joint_impulse)
776 j = -1;
777 m_pStructure->pJoints[i].ipart[iop] = j;
779 if (m_pStructure->pJoints[i].ipart[0]==-1) {
780 j=m_pStructure->pJoints[i].ipart[0]; m_pStructure->pJoints[i].ipart[0]=m_pStructure->pJoints[i].ipart[1]; m_pStructure->pJoints[i].ipart[1]=j;
782 if (!is_unused(params->pt)) m_pStructure->pJoints[i].pt = params->pt;
783 if (!is_unused(params->n)) m_pStructure->pJoints[i].n = params->n;
784 if (!is_unused(params->axisx)) m_pStructure->pJoints[i].axisx = params->axisx;
785 if (!is_unused(params->maxForcePush)) m_pStructure->pJoints[i].maxForcePush = min_safe(1e15f, params->maxForcePush);
786 if (!is_unused(params->maxForcePull)) m_pStructure->pJoints[i].maxForcePull = min_safe(1e15f, params->maxForcePull);
787 if (!is_unused(params->maxForceShift)) m_pStructure->pJoints[i].maxForceShift = min_safe(1e15f, params->maxForceShift);
788 if (!is_unused(params->maxTorqueBend)) m_pStructure->pJoints[i].maxTorqueBend = min_safe(1e15f, params->maxTorqueBend);
789 if (!is_unused(params->maxTorqueTwist)) m_pStructure->pJoints[i].maxTorqueTwist = min_safe(1e15f, params->maxTorqueTwist);
790 if (!is_unused(params->limitConstraint)) m_pStructure->pJoints[i].limitConstr = params->limitConstraint;
791 if (!is_unused(params->dampingConstraint)) m_pStructure->pJoints[i].dampingConstr = params->dampingConstraint;
792 if (!is_unused(params->bBreakable))
793 (m_pStructure->pJoints[i].bBreakable &= ~1) |= params->bBreakable;
794 else if (i==m_pStructure->nJoints)
795 m_pStructure->pJoints[i].bBreakable = 1;
796 if (!is_unused(params->bConstraintWillIgnoreCollisions))
797 (m_pStructure->pJoints[i].bBreakable &= ~2) |= params->bConstraintWillIgnoreCollisions*2^2;
798 if (!is_unused(params->bDirectBreaksOnly)) {
799 (m_pStructure->pJoints[i].bBreakable &= ~(4|params->bDirectBreaksOnly)) |= params->bDirectBreaksOnly*4;
800 m_pStructure->bHasDirectBreaks |= params->bDirectBreaksOnly;
802 if (!is_unused(params->id))
803 m_pStructure->pJoints[i].id = params->id;
804 else if (i==m_pStructure->nJoints)
805 m_pStructure->pJoints[i].id = i;
806 if (!is_unused(params->szSensor))
807 m_pStructure->pJoints[i].size = params->szSensor;
808 else if (i==m_pStructure->nJoints)
809 m_pStructure->pJoints[i].size = m_pWorld->m_vars.maxContactGap*5;
810 if (!is_unused(params->damageAccum)) m_pStructure->pJoints[i].damageAccum = max_safe(0.f,params->damageAccum);
811 else m_pStructure->pJoints[i].damageAccum = m_pWorld->m_vars.jointDmgAccum;
812 if (!is_unused(params->damageAccumThresh)) m_pStructure->pJoints[i].damageAccumThresh = max_safe(0.f,min_safe(1.f, params->damageAccumThresh));
813 else m_pStructure->pJoints[i].damageAccumThresh = m_pWorld->m_vars.jointDmgAccumThresh;
814 m_pStructure->pJoints[i].tension = 0;
815 m_pStructure->pJoints[i].itens = 0;
816 m_pStructure->nJoints = max(i+1,m_pStructure->nJoints);
817 if (!is_unused(params->bBroken)) {
818 if (m_pStructure->pJoints[i].bBroken!=params->bBroken && (m_pStructure->pJoints[i].bBroken=params->bBroken) && i<m_pStructure->nJoints) {
819 if (is_unused(params->partidEpicenter)) {
820 if (i!=m_pStructure->nJoints-1)
821 m_pStructure->pJoints[i] = m_pStructure->pJoints[m_pStructure->nJoints-1];
822 --m_pStructure->nJoints;
823 } else {
824 m_pStructure->pJoints[i].bBroken = params->bBroken;
825 m_pStructure->idpartBreakOrg = params->partidEpicenter;
827 m_pWorld->MarkEntityAsDeforming(this);
829 } else
830 m_pStructure->pJoints[i].bBroken = 0;
831 MEMSTAT_USAGE(m_pStructure->pJoints, sizeof(m_pStructure->pJoints[0]) * m_pStructure->nJoints);
832 return 1;
835 if (_params->type==pe_params_structural_initial_velocity::type_id) {
836 pe_params_structural_initial_velocity *params = (pe_params_structural_initial_velocity*)_params;
837 if (m_pStructure) {
838 int i;
839 for(i=0; i<m_nParts && m_parts[i].id!=params->partid; i++);
840 if (i<m_nParts) {
841 m_pStructure->pParts[i].initialVel = params->v;
842 m_pStructure->pParts[i].initialAngVel = params->w;
843 return 1;
845 return 0;
848 if (_params->type==pe_params_timeout::type_id) {
849 pe_params_timeout *params = (pe_params_timeout*)_params;
850 if (!is_unused(params->timeIdle)) m_timeIdle = params->timeIdle;
851 if (!is_unused(params->maxTimeIdle)) m_maxTimeIdle = params->maxTimeIdle;
852 return 1;
855 if (_params->type==pe_params_skeleton::type_id) {
856 pe_params_skeleton *params = (pe_params_skeleton*)_params;
857 int i;
858 if (!is_unused(params->ipart))
859 i = params->ipart;
860 else if (!is_unused(params->partid))
861 for(i=m_nParts-1;i>=0 && params->partid!=m_parts[i].id;i--);
862 else
863 return 0;
864 if ((unsigned int)i>=(unsigned int)m_nParts || !m_pStructure || !m_pStructure->defparts || !m_pStructure->defparts[i].pSkelEnt)
865 return 0;
866 pe_params_softbody psb;
867 if (!is_unused(params->stiffness)) psb.shapeStiffnessNorm = params->stiffness;
868 if (!is_unused(params->thickness)) psb.thickness = params->thickness;
869 if (!is_unused(params->maxStretch)) psb.maxSafeStep = params->maxStretch;
870 if (!is_unused(params->maxImpulse)) m_pStructure->defparts[i].maxImpulse = params->maxImpulse;
871 if (!is_unused(params->timeStep)) m_pStructure->defparts[i].timeStep = params->timeStep;
872 if (!is_unused(params->nSteps)) m_pStructure->defparts[i].nSteps = params->nSteps;
873 if (!is_unused(params->hardness)) psb.nMaxIters=max(1,min(20,float2int(psb.ks=params->hardness)));
874 if (!is_unused(params->explosionScale)) {
875 psb.explosionScale = params->explosionScale*0.005f;
876 psb.maxCollisionImpulse = 200.0f*params->explosionScale;
878 m_pStructure->defparts[i].pSkelEnt->SetParams(&psb);
879 if (!is_unused(params->bReset) && params->bReset) {
880 pe_action_reset ar; ar.bClearContacts=3;
881 m_pStructure->defparts[i].pSkelEnt->Action(&ar);
883 return 1;
886 return 0;
890 int CPhysicalEntity::GetParams(pe_params *_params) const
892 if (_params->type==pe_params_bbox::type_id) {
893 pe_params_bbox *params = (pe_params_bbox*)_params;
894 ReadLock lock(m_lockUpdate);
895 params->BBox[0] = m_BBox[0];
896 params->BBox[1] = m_BBox[1];
897 return 1;
900 if (_params->type==pe_params_outer_entity::type_id) {
901 ((pe_params_outer_entity*)_params)->pOuterEntity = m_pOuterEntity;
902 return 1;
905 if (_params->type==pe_params_foreign_data::type_id) {
906 pe_params_foreign_data *params = (pe_params_foreign_data*)_params;
907 ReadLock lock(m_lockUpdate);
908 params->iForeignData = m_iForeignData;
909 params->pForeignData = m_pForeignData;
910 params->iForeignFlags = m_iForeignFlags;
911 return 1;
914 if (_params->type==pe_params_pos::type_id) {
915 pe_params_pos *params = (pe_params_pos*)_params;
916 params->pos = m_pos;
917 params->q = m_qrot;
918 params->scale = 1;
919 params->iSimClass = m_iSimClass;
920 params->pGridRefEnt = m_pWorld->GetGrid(this);
921 params->doubleBufCoords = m_pSyncCoords!=(coord_block*)&m_pos;
922 return 1;
925 if (_params->type==pe_params_part::type_id) {
926 pe_params_part *params = (pe_params_part*)_params;
927 ReadLockCond lock(m_lockUpdate,m_pWorld->m_vars.bLogStructureChanges);
928 int i;
929 if ((is_unused(params->ipart) || params->ipart==-1) && params->partid>=0) {
930 for(i=0;i<m_nParts && m_parts[i].id!=params->partid;i++);
931 if (i==m_nParts) return 0;
932 } else if ((unsigned int)(i = params->ipart)>=(unsigned int)m_nParts)
933 return 0;
934 params->partid = m_parts[params->ipart = i].id;
935 params->pos = m_parts[i].pos;
936 params->q = m_parts[i].q;
937 params->scale = m_parts[i].scale;
938 if (params->pMtx3x4)
939 (*params->pMtx3x4 = Matrix33(m_parts[i].q)*m_parts[i].scale).SetTranslation(m_parts[i].pos);
940 if (params->pMtx3x3)
941 *params->pMtx3x3 = Matrix33(m_parts[i].q)*m_parts[i].scale;
942 params->flagsOR=params->flagsAND = m_parts[i].flags;
943 params->flagsColliderOR=params->flagsColliderAND = m_parts[i].flagsCollider;
944 params->mass = m_parts[i].mass;
945 params->density = m_parts[i].pPhysGeomProxy->V>0 ?
946 m_parts[i].mass/(m_parts[i].pPhysGeomProxy->V*cube(m_parts[i].scale)) : 0;
947 params->minContactDist = m_parts[i].minContactDist;
948 params->pPhysGeom = m_parts[i].pPhysGeom;
949 params->pPhysGeomProxy = m_parts[i].pPhysGeomProxy;
950 params->idmatBreakable = m_parts[i].idmatBreakable;
951 params->pLattice = m_parts[i].pLattice;
952 params->pMatMapping = m_parts[i].pMatMapping;
953 params->nMats = m_parts[i].nMats;
954 params->idSkeleton = m_pStructure && m_pStructure->defparts ? m_pStructure->defparts[i].idSkel : -1;
955 if (params->bAddrefGeoms) {
956 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeom);
957 m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeomProxy);
959 return 1;
962 if (_params->type==pe_params_flags::type_id) {
963 ((pe_params_flags*)_params)->flags = m_flags;
964 return 1;
967 if (_params->type==pe_params_collision_class::type_id) {
968 pe_params_collision_class *params = (pe_params_collision_class*)_params;
969 params->collisionClassAND.type = params->collisionClassOR.type = m_collisionClass.type;
970 params->collisionClassAND.ignore = params->collisionClassOR.ignore = m_collisionClass.ignore;
971 return 1;
974 if (_params->type==pe_params_ground_plane::type_id) {
975 pe_params_ground_plane *params = (pe_params_ground_plane*)_params;
976 SIZEOF_ARRAY_OK
977 if (params->iPlane>=m_nGroundPlanes)
978 return 0;
979 params->ground.origin = m_ground[params->iPlane].origin;
980 params->ground.n = m_ground[params->iPlane].n;
981 return 1;
984 if (_params->type==pe_params_structural_joint::type_id) {
985 pe_params_structural_joint *params = (pe_params_structural_joint*)_params;
986 if (!m_pStructure)
987 return 0;
988 int i,iop;
989 if (!is_unused(params->idx))
990 i = params->idx;
991 else for(i=0; i<m_pStructure->nJoints && m_pStructure->pJoints[i].id!=params->id; i++);
992 if ((unsigned int)i>=(unsigned int)m_pStructure->nJoints)
993 return 0;
994 for(iop=0;iop<2;iop++)
995 if ((params->partid[iop] = m_pStructure->pJoints[i].ipart[iop])>=0)
996 params->partid[iop] = m_parts[params->partid[iop]].id;
997 params->idx = i;
998 params->id = m_pStructure->pJoints[i].id;
999 params->pt = m_pStructure->pJoints[i].pt;
1000 params->n = m_pStructure->pJoints[i].n;
1001 params->axisx = m_pStructure->pJoints[i].axisx;
1002 params->maxForcePush = m_pStructure->pJoints[i].maxForcePush;
1003 params->maxForcePull = m_pStructure->pJoints[i].maxForcePull;
1004 params->maxForceShift = m_pStructure->pJoints[i].maxForceShift;
1005 params->maxTorqueBend = m_pStructure->pJoints[i].maxTorqueBend;
1006 params->maxTorqueTwist = m_pStructure->pJoints[i].maxTorqueTwist;
1007 params->damageAccum = m_pStructure->pJoints[i].damageAccum;
1008 params->damageAccumThresh = m_pStructure->pJoints[i].damageAccumThresh;
1009 params->limitConstraint = m_pStructure->pJoints[i].limitConstr;
1010 params->dampingConstraint = m_pStructure->pJoints[i].dampingConstr;
1011 params->bBreakable = m_pStructure->pJoints[i].bBreakable & 1;
1012 params->bConstraintWillIgnoreCollisions = m_pStructure->pJoints[i].bBreakable>>1^1;
1013 params->bDirectBreaksOnly = m_pStructure->pJoints[i].bBreakable>>2;
1014 params->bBroken = m_pStructure->pJoints[i].bBroken;
1015 return 1;
1018 if (_params->type==pe_params_timeout::type_id) {
1019 pe_params_timeout *params = (pe_params_timeout*)_params;
1020 params->timeIdle = m_timeIdle;
1021 params->maxTimeIdle = m_maxTimeIdle;
1022 return 1;
1025 if (_params->type==pe_params_skeleton::type_id) {
1026 pe_params_skeleton *params = (pe_params_skeleton*)_params;
1027 int i;
1028 if (!is_unused(params->ipart))
1029 i = params->ipart;
1030 else if (!is_unused(params->partid))
1031 for(i=m_nParts-1;i>=0 && params->partid!=m_parts[i].id;i--);
1032 else
1033 return 0;
1034 if ((unsigned int)i>=(unsigned int)m_nParts || !m_pStructure || !m_pStructure->defparts || !m_pStructure->defparts[i].pSkelEnt)
1035 return 0;
1036 pe_params_softbody psb;
1037 m_pStructure->defparts[i].pSkelEnt->GetParams(&psb);
1038 params->stiffness = psb.shapeStiffnessNorm;
1039 params->thickness = psb.thickness;
1040 params->maxStretch = psb.maxSafeStep;
1041 params->maxImpulse = m_pStructure->defparts[i].maxImpulse;
1042 params->timeStep = m_pStructure->defparts[i].timeStep;
1043 params->nSteps = m_pStructure->defparts[i].nSteps;
1044 params->hardness = psb.ks;
1045 params->explosionScale = psb.explosionScale;
1046 return 1;
1049 return 0;
1053 int CPhysicalEntity::GetStatus(pe_status *_status) const
1055 if (_status->type==pe_status_pos::type_id) {
1056 pe_status_pos *status = (pe_status_pos*)_status;
1057 ReadLockCond lock(m_lockUpdate, (status->flags^status_thread_safe)&status_thread_safe & -m_pWorld->m_vars.bLogStructureChanges);
1058 Vec3 respos;
1059 quaternionf resq;
1060 float resscale;
1061 int i;
1063 if (status->ipart==-1 && status->partid>=0) {
1064 for(i=0;i<m_nParts && m_parts[i].id!=status->partid;i++);
1065 if (i==m_nParts) return 0;
1066 } else
1067 i = status->ipart;
1069 if (i<0) {
1070 respos=m_pos; resq=m_qrot; resscale=1.0f;
1071 for(i=0,status->flagsOR=0,status->flagsAND=0xFFFFFFFF;i<m_nParts;i++)
1072 status->flagsOR|=m_parts[i].flags, status->flagsAND&=m_parts[i].flags;
1073 if (m_nParts>0) {
1074 status->pGeom = m_parts[0].pPhysGeom->pGeom;
1075 status->pGeomProxy = m_parts[0].pPhysGeomProxy->pGeom;
1076 } else
1077 status->pGeom = status->pGeomProxy = 0;
1078 status->BBox[0] = m_BBox[0]-m_pos;
1079 status->BBox[1] = m_BBox[1]-m_pos;
1080 } else if (i<m_nParts) {
1081 if (status->flags & status_local) {
1082 respos = m_parts[i].pos; resq = m_parts[i].q;
1083 } else {
1084 respos = m_pos+m_qrot*m_parts[i].pos;
1085 resq = m_qrot*m_parts[i].q;
1087 resscale = m_parts[i].scale;
1088 status->partid = m_parts[i].id;
1089 status->flagsOR = status->flagsAND = m_parts[i].flags;
1090 status->pGeom = m_parts[i].pPhysGeom->pGeom;
1091 status->pGeomProxy = m_parts[i].pPhysGeomProxy->pGeom;
1092 if (status->flags & status_addref_geoms) {
1093 if (status->pGeom) status->pGeom->AddRef();
1094 if (status->pGeomProxy) status->pGeomProxy->AddRef();
1096 status->BBox[0] = m_parts[i].BBox[0]-respos;
1097 status->BBox[1] = m_parts[i].BBox[1]-respos;
1098 } else
1099 return 0;
1101 if (status->flags & status_use_sync_coords && m_pSyncCoords!=(coord_block*)&m_pos && (i<0 || !(status->flags & status_local))) {
1102 QuatT diff = QuatT(m_pSyncCoords->q,m_pSyncCoords->pos) * QuatT(m_qrot,m_pos).GetInverted();
1103 respos = diff*respos;
1104 resq = diff.q*resq;
1105 Vec3 center = diff*(status->BBox[0]+status->BBox[1])*0.5f;
1106 Vec3 sz = Matrix33(diff.q).Fabs()*(status->BBox[1]-status->BBox[0])*0.5f;
1107 status->BBox[0] = center-sz; status->BBox[1] = center+sz;
1110 if (!is_unused(status->pGridRefEnt)) {
1111 if (status->pGridRefEnt && m_pWorld->GetGrid(this)!=m_pWorld->GetGrid(status->pGridRefEnt) && (i<0 || !(status->flags & status_local)))
1112 transformBBox(status->BBox[0],status->BBox[1], status->BBox,
1113 QuatT(m_pWorld->TransformToGrid(this,status->pGridRefEnt, respos,resq).q, Vec3(ZERO)));
1114 } else
1115 status->pGridRefEnt = m_pWorld->GetGrid(this);
1117 status->pos = respos;
1118 status->q = resq;
1119 status->scale = resscale;
1120 status->iSimClass = m_iSimClass;
1122 if (status->pMtx3x4)
1123 (*status->pMtx3x4 = Matrix33(resq)*resscale).SetTranslation(respos);
1124 if (status->pMtx3x3)
1125 (Matrix33&)*status->pMtx3x3 = (Matrix33(resq)*resscale);
1126 return 1;
1129 if (_status->type==pe_status_id::type_id) {
1130 pe_status_id *status = (pe_status_id*)_status;
1131 ReadLock lock(m_lockUpdate);
1132 int ipart = status->ipart;
1133 if (ipart<0)
1134 for(ipart=0;ipart<m_nParts-1 && m_parts[ipart].id!=status->partid;ipart++);
1135 if (ipart>=m_nParts)
1136 return 0;
1137 phys_geometry *pgeom = status->bUseProxy ? m_parts[ipart].pPhysGeomProxy : m_parts[ipart].pPhysGeom;
1138 if ((unsigned int)status->iPrim >= (unsigned int)pgeom->pGeom->GetPrimitiveCount() ||
1139 pgeom->pGeom->GetType()==GEOM_TRIMESH && status->iFeature>2)
1140 return 0;
1141 status->id = pgeom->pGeom->GetPrimitiveId(status->iPrim, status->iFeature);
1142 status->id = status->id&~(status->id>>31) | m_parts[ipart].surface_idx&status->id>>31;
1143 return 1;
1146 if (_status->type==pe_status_nparts::type_id)
1147 return m_nParts;
1149 if (_status->type==pe_status_awake::type_id)
1150 return IsAwake();
1152 if (_status->type==pe_status_contains_point::type_id)
1153 return IsPointInside(((pe_status_contains_point*)_status)->pt);
1155 if (_status->type==pe_status_caps::type_id) {
1156 pe_status_caps *status = (pe_status_caps*)_status;
1157 status->bCanAlterOrientation = 0;
1158 return 1;
1161 if (_status->type==pe_status_constraint::type_id && IsPortal(this)) {
1162 ((pe_status_constraint*)_status)->pBuddyEntity = m_pEntBuddy;
1163 return 1;
1166 if (_status->type==pe_status_extent::type_id)
1168 pe_status_extent *status = (pe_status_extent*)_status;
1169 status->extent = GetExtent(status->eForm);
1170 return 1;
1173 if (_status->type==pe_status_random::type_id)
1175 pe_status_random *status = (pe_status_random*)_status;
1176 GetRandomPoints(status->points, status->seed, status->eForm);
1177 return 1;
1180 return 0;
1184 int CPhysicalEntity::Action(pe_action *_action, int bThreadSafe)
1186 ChangeRequest<pe_action> req(this,m_pWorld,_action,bThreadSafe);
1187 if (req.IsQueued()) {
1188 if (_action->type==pe_action_remove_all_parts::type_id) {
1189 WriteLock lock(m_lockUpdate);
1190 for(int i=0;i<m_nParts;i++) m_parts[i].flags |= geom_removed;
1192 return 1;
1195 if (_action->type==pe_action_impulse::type_id) {
1196 pe_action_impulse *action = (pe_action_impulse*)_action;
1197 if (!is_unused(action->ipart) || !is_unused(action->partid)) {
1198 int i;
1199 if (is_unused(action->ipart))
1200 for(i=0; i<m_nParts && m_parts[i].id!=action->partid; i++);
1201 else i = action->ipart;
1202 if ((unsigned int)i>=(unsigned int)m_nParts)
1203 return 0;
1204 if (!is_unused(action->point))
1205 i = MapHitPointFromParent(i,action->point);
1207 float scale = 1.0f+(m_pWorld->m_vars.breakImpulseScale-1.0f)*iszero((int)m_flags & pef_override_impulse_scale);
1208 if (m_pStructure) {
1209 int bMarkEntityAsDeforming = 0;
1210 Vec3 dL(ZERO),dP=action->impulse*scale;
1211 if (!is_unused(action->angImpulse))
1212 dL = action->angImpulse;
1213 else if (!is_unused(action->point)) {
1214 Vec3 bodypos = m_qrot*(m_parts[i].q*m_parts[i].pPhysGeom->origin*m_parts[i].scale+m_parts[i].pos)+m_pos;
1215 dL = action->point-bodypos ^ action->impulse;
1218 Vec3 sz = m_parts[i].BBox[1]-m_parts[i].BBox[0];
1219 if (max((m_pStructure->pParts[i].Pext+dP*scale).len2(), (m_pStructure->pParts[i].Lext+dL*scale).len2()*sqr(sz.x+sz.y+sz.z)*0.1f) > sqr(m_parts[i].mass*0.01f)) {
1220 bMarkEntityAsDeforming=1; m_pStructure->pParts[i].Pext+=dP*scale; m_pStructure->pParts[i].Lext+=dL*scale;
1221 if (m_pStructure->bHasDirectBreaks && !is_unused(action->point) && action->iSource==0) {
1222 Vec3 ptloc = (action->point-m_pos)*m_qrot;
1223 int ijoint=-1; float dist,mindist=1e10f,imp=dP.len2()*sqr(scale);
1224 for(int j=0; j<m_pStructure->nJoints; j++)
1225 if (m_pStructure->pJoints[j].bBreakable & 4 &&
1226 (m_pStructure->pJoints[j].ipart[0]==i || m_pStructure->pJoints[j].ipart[1]==i) &&
1227 imp>sqr(m_pStructure->pJoints[j].maxForcePull*0.01f) &&
1228 (dist=(ptloc-m_pStructure->pJoints[j].pt).len2())<mindist)
1229 mindist=dist, ijoint=j;
1230 if (ijoint>=0) {
1231 m_pStructure->pJoints[ijoint].bBroken = 1;
1232 m_pStructure->idpartBreakOrg = m_parts[i].id;
1237 if (max(action->impulse.len2(), dL.len2()*sqr(sz.x+sz.y+sz.z)*0.1f) >
1238 sqr(m_parts[i].mass*0.01f)*m_pWorld->m_vars.gravity.len2())
1239 if ((action->iSource==0 || action->iSource==3) && m_pStructure->defparts && m_pStructure->defparts[i].pSkelEnt && !is_unused(action->point)) {
1240 pe_action_impulse ai;
1241 ai.impulse = m_pStructure->defparts[i].lastUpdateq*!m_qrot*action->impulse;
1242 ai.point = m_pStructure->defparts[i].lastUpdateq*(!m_qrot*(action->point-m_pos))+m_pStructure->defparts[i].lastUpdatePos;
1243 if (ai.impulse.len2()>sqr(m_pStructure->defparts[i].maxImpulse))
1244 ai.impulse = ai.impulse.normalized()*m_pStructure->defparts[i].maxImpulse;
1245 m_pStructure->defparts[i].pSkelEnt->Action(&ai);
1247 if (bMarkEntityAsDeforming)
1248 m_pWorld->MarkEntityAsDeforming(this);
1249 if (action->iSource==2 && m_pWorld->m_vars.bDebugExplosions) {
1250 if (!m_pStructure->Pexpl) m_pStructure->Pexpl = new Vec3[m_nParts];
1251 if (!m_pStructure->Lexpl) m_pStructure->Lexpl = new Vec3[m_nParts];
1252 if ((m_pStructure->lastExplPos-m_pWorld->m_lastEpicenter).len2()) {
1253 memset(m_pStructure->Pexpl, 0, m_nParts*sizeof(Vec3));
1254 memset(m_pStructure->Lexpl, 0, m_nParts*sizeof(Vec3));
1256 m_pStructure->lastExplPos = m_pWorld->m_lastEpicenter;
1257 m_pStructure->Pexpl[i] += action->impulse*scale;
1258 m_pStructure->Lexpl[i] += dL*scale;
1262 if (m_parts[i].pLattice && m_parts[i].idmatBreakable>=0 && !is_unused(action->point)) {
1263 float rdensity = m_parts[i].pLattice->m_density*m_parts[i].pPhysGeom->V*cube(m_parts[i].scale)/m_parts[i].mass;
1264 Vec3 ptloc = ((action->point-m_pos)*m_qrot-m_parts[i].pos)*m_parts[i].q, P(ZERO),L(ZERO);
1265 rdensity *= scale;
1266 if (m_parts[i].scale!=1.0f)
1267 ptloc /= m_parts[i].scale;
1268 if (!is_unused(action->impulse))
1269 P = ((action->impulse*rdensity)*m_qrot)*m_parts[i].q;
1270 if (!is_unused(action->angImpulse))
1271 L = ((action->angImpulse*rdensity)*m_qrot)*m_parts[i].q;
1272 if (m_parts[i].pLattice->AddImpulse(ptloc, P,L, m_pWorld->m_vars.gravity*(m_pWorld->m_vars.jointGravityStep*m_pWorld->m_updateTimes[0]),
1273 m_pWorld->m_updateTimes[0]) && !(m_flags & pef_deforming))
1274 { m_updStage = 0; m_pWorld->MarkEntityAsDeforming(this);
1279 return 1;
1282 if (_action->type==pe_action_awake::type_id && m_iSimClass>=0 && m_iSimClass<7) {
1283 Awake(((pe_action_awake*)_action)->bAwake,1);
1284 return 1;
1286 if (_action->type==pe_action_remove_all_parts::type_id) {
1287 while(m_nParts)
1288 RemoveGeometry(m_parts[m_nParts-1].id);
1289 return 1;
1292 if (_action->type==pe_action_reset_part_mtx::type_id) {
1293 pe_action_reset_part_mtx *action = (pe_action_reset_part_mtx*)_action;
1294 int i=0;
1295 if (!is_unused(action->partid))
1296 for(i=m_nParts-1;i>0 && m_parts[i].id!=action->partid;i--);
1297 else if (!is_unused(action->ipart))
1298 i = action->ipart;
1300 pe_params_pos pp;
1301 pp.pos = m_pos+m_qrot*m_parts[i].pos;
1302 pp.q = m_qrot*m_parts[i].q;
1303 pp.bRecalcBounds = 2;
1304 SetParams(&pp,1);
1306 pe_params_part ppt;
1307 ppt.ipart = i;
1308 ppt.pos.zero();
1309 ppt.q.SetIdentity();
1310 SetParams(&ppt,1);
1311 return 1;
1314 if (_action->type==pe_action_auto_part_detachment::type_id) {
1315 pe_action_auto_part_detachment *action = (pe_action_auto_part_detachment*)_action;
1316 if (!is_unused(action->threshold)) {
1317 pe_params_structural_joint psj;
1318 pe_params_buoyancy pb;
1319 Vec3 gravity;
1320 float glen;
1321 //if (!m_pWorld->CheckAreas(this,gravity,&pb) || is_unused(gravity))
1322 gravity = m_pWorld->m_vars.gravity;
1323 glen = gravity.len();
1324 psj.partid[1]=-1; psj.pt.zero(); psj.n=gravity/(glen>0 ? -glen:1.0f);
1325 psj.maxTorqueBend=psj.maxTorqueTwist = 1E20f;
1326 for(int i=0;i<m_nParts;i++) {
1327 psj.partid[0] = m_parts[i].id;
1328 psj.maxForcePush=psj.maxForcePull=psj.maxForceShift = m_parts[i].mass*glen*action->threshold;
1329 SetParams(&psj);
1331 m_flags |= aef_recorded_physics;
1333 if (m_pStructure && m_flags & aef_recorded_physics)
1334 m_pStructure->autoDetachmentDist = action->autoDetachmentDist;
1335 return 1;
1338 if (_action->type==pe_action_move_parts::type_id) {
1339 pe_action_move_parts *action = (pe_action_move_parts*)_action;
1340 CPhysicalEntity *pTarget = (CPhysicalEntity*)action->pTarget;
1341 int i,j,iop;
1342 pe_geomparams gp;
1343 pe_params_structural_joint psj;
1344 Matrix34 mtxPart; gp.pMtx3x4=&mtxPart;
1345 if (pTarget) for(i=m_nParts-1;i>=0;i--)
1346 if (m_parts[i].id>=action->idStart && m_parts[i].id<=action->idEnd) {
1347 int idnew = action->MapPartId ? action->MapPartId(m_parts[i].id,action->auxData) : m_parts[i].id+action->idOffset;
1348 if (idnew<0)
1349 continue;
1350 gp.mass = m_parts[i].mass*cube(action->mtxRel.GetColumn0().len()/m_parts[i].scale);
1351 gp.flags=m_parts[i].flags; gp.flagsCollider=m_parts[i].flagsCollider;
1352 mtxPart = action->mtxRel*Matrix34(Vec3(1), m_parts[i].q, m_parts[i].pos);
1353 gp.pLattice=m_parts[i].pLattice; gp.idmatBreakable=m_parts[i].idmatBreakable;
1354 gp.pMatMapping=m_parts[i].pMatMapping; gp.nMats=m_parts[i].nMats;
1355 pTarget->AddGeometry(m_parts[i].pPhysGeom, &gp, idnew, 1);
1357 if (m_pStructure) for(j=0;j<m_pStructure->nJoints;j++)
1358 if ((iop=m_pStructure->pJoints[j].ipart[1]==i) || m_pStructure->pJoints[j].ipart[0]==i) {
1359 psj.id = m_pStructure->pJoints[j].id;
1360 psj.partid[iop] = m_parts[i].id+action->idOffset;
1361 psj.pt = action->mtxRel*m_pStructure->pJoints[j].pt;
1362 psj.n = m_pStructure->pJoints[j].n;
1363 int ibuddy = m_pStructure->pJoints[j].ipart[iop^1];
1364 if (ibuddy>=0 && m_parts[ibuddy].id>=action->idStart && m_parts[ibuddy].id<=action->idEnd) {
1365 if (ibuddy<i)
1366 continue;
1367 psj.partid[iop^1] = m_parts[ibuddy].id+action->idOffset;
1368 } else {
1369 int ipart = pTarget->TouchesSphere(pTarget->m_qrot*psj.pt+pTarget->m_pos, m_pStructure->pJoints[i].size*0.5f);
1370 if (ipart<pTarget->m_nParts-1)
1371 psj.partid[iop^1] = pTarget->m_parts[ipart].id;
1372 else
1373 psj.partid[iop^1] = -1;
1375 psj.axisx = m_pStructure->pJoints[j].axisx;
1376 psj.maxForcePush = m_pStructure->pJoints[j].maxForcePush;
1377 psj.maxForcePull = m_pStructure->pJoints[j].maxForcePull;
1378 psj.maxForceShift = m_pStructure->pJoints[j].maxForceShift;
1379 psj.maxTorqueBend = m_pStructure->pJoints[j].maxTorqueBend;
1380 psj.maxTorqueTwist = m_pStructure->pJoints[j].maxTorqueTwist;
1381 psj.limitConstraint = m_pStructure->pJoints[j].limitConstr;
1382 psj.dampingConstraint = m_pStructure->pJoints[j].dampingConstr;
1383 psj.bBreakable = m_pStructure->pJoints[j].bBreakable & 1;
1384 psj.bConstraintWillIgnoreCollisions = m_pStructure->pJoints[j].bBreakable>>1^1;
1385 psj.bDirectBreaksOnly = m_pStructure->pJoints[j].bBreakable>>2;
1386 psj.szSensor = m_pStructure->pJoints[j].size;
1387 pTarget->SetParams(&psj);
1390 for(i=m_nParts-1;i>=0;i--) if (m_parts[i].id>=action->idStart && m_parts[i].id<=action->idEnd)
1391 if (!action->MapPartId || action->MapPartId(m_parts[i].id,action->auxData)>=0)
1392 RemoveGeometry(m_parts[i].id);
1393 return 1;
1396 if (_action->type==pe_action_add_constraint::type_id && m_iSimClass==SC_TRIGGER && ((pe_action_add_constraint*)_action)->pBuddy) {
1397 m_pEntBuddy = (CPhysicalPlaceholder*)((pe_action_add_constraint*)_action)->pBuddy;
1398 m_pEntBuddy->m_iForeignFlags = (m_iForeignFlags = ent_rigid|ent_sleeping_rigid|ent_living|ent_independent | TRIGGER_PORTAL) | TRIGGER_PORTAL_INV;
1399 m_pEntBuddy->m_pEntBuddy = this;
1400 return 1;
1403 if (_action->type==pe_action_update_constraint::type_id && ((pe_action_update_constraint*)_action)->bRemove && IsPortal(this)) {
1404 m_pEntBuddy = nullptr;
1405 m_iForeignFlags &= ~(TRIGGER_PORTAL | TRIGGER_PORTAL_INV);
1406 return 1;
1409 return 0;
1412 float CPhysicalEntity::GetExtent(EGeomForm eForm) const
1414 CGeomExtent& ext = m_Extents.Make(eForm);
1415 if (!ext) {
1416 // iterate parts, caching extents
1417 ext.ReserveParts(m_nParts);
1418 for(int i=0;i<m_nParts;i++) {
1419 geom const& part = m_parts[i];
1420 if ((part.flags & geom_collides) && part.pPhysGeom && part.pPhysGeom->pGeom)
1421 ext.AddPart( part.pPhysGeom->pGeom->GetExtent(eForm) * ScaleExtent(eForm, part.scale) );
1422 else
1423 ext.AddPart(0.f);
1426 return ext.TotalExtent();
1429 void CPhysicalEntity::GetRandomPoints(Array<PosNorm> points, CRndGen& seed, EGeomForm eForm) const
1431 // choose sub-part, get random pos, transform to world
1432 const CGeomExtent& ext = m_Extents[eForm];
1433 for (auto subPoints : ext.RandomPartsAliasSum(points, seed)) {
1434 if (subPoints.iPart >= 0 && subPoints.iPart < m_nParts) {
1435 geom const& part = m_parts[subPoints.iPart];
1436 part.pPhysGeom->pGeom->GetRandomPoints(subPoints.aPoints, seed, eForm);
1437 QuatTS qts(m_qrot * part.q, m_qrot * part.pos + m_pos, part.scale);
1438 for (auto& ran : subPoints.aPoints)
1439 ran <<= qts;
1444 bool CPhysicalEntity::OccupiesEntityGridSquare(const AABB &bbox)
1446 if (m_pWorld->m_vars.bEntGridUseOBB) {
1447 const Vec3 *BBox = (const Vec3*)&bbox;
1448 int i,j;
1449 if (m_nParts==0)
1450 return PtInAABB(BBox,m_pos);
1451 else for(i=0;i<m_nParts;i++) {
1452 Matrix33 R(m_qrot*m_parts[i].q);
1453 IGeometry *pGeom[3];
1454 COverlapChecker Overlapper; Overlapper.Init();
1455 pGeom[0] = m_parts[i].pPhysGeomProxy->pGeom;
1456 pGeom[1]=pGeom[2] = m_parts[i].pPhysGeom->pGeom;
1457 j=0; do {
1458 box abox,bbox;
1459 bbox.center=(BBox[0]+BBox[1])*0.5f; bbox.size=(BBox[1]-BBox[0])*0.5f;
1460 bbox.Basis.SetIdentity(); bbox.bOriented=0;
1461 pGeom[j]->GetBBox(&abox);
1462 abox.center = m_qrot*(m_parts[i].q*abox.center*m_parts[i].scale+m_parts[i].pos)+m_pos;
1463 abox.size *= m_parts[i].scale;
1464 abox.Basis = abox.Basis*Matrix33(!m_parts[i].q*!m_qrot);
1465 abox.bOriented = 1;
1466 if (box_box_overlap_check(&abox,&bbox,&Overlapper))
1467 return true;
1468 j++;
1469 } while(pGeom[j]!=pGeom[j-1]);
1471 return false;
1473 return true;
1476 void CPhysicalEntity::UpdatePartIdmatBreakable(int ipart, int nParts)
1478 int i,id,flags=0;
1479 m_parts[ipart].idmatBreakable = -1;
1480 m_parts[ipart].flags &= ~geom_manually_breakable;
1481 nParts += m_nParts+1 & nParts>>31;
1483 if (m_parts[ipart].pMatMapping) {
1484 for(i=0;i<(int)m_parts[ipart].nMats;i++) {
1485 id = m_pWorld->m_SurfaceFlagsTable[min(NSURFACETYPES-1,max(0,m_parts[ipart].pMatMapping[i]))];
1486 m_parts[ipart].idmatBreakable = max(m_parts[ipart].idmatBreakable, (id>>sf_matbreakable_bit)-1);
1487 flags |= id;
1489 if ((m_parts[ipart].idmatBreakable>=0 || flags & sf_manually_breakable) && nParts>1) {
1490 m_parts[ipart].idmatBreakable = -1; flags = 0;
1491 for(i=m_parts[ipart].pPhysGeom->pGeom->GetPrimitiveCount()-1; i>=0; i--) {
1492 id = m_parts[ipart].pPhysGeom->pGeom->GetPrimitiveId(i,0x40);
1493 id += m_parts[ipart].surface_idx+1 & id>>31;
1494 id = m_pWorld->m_SurfaceFlagsTable[m_parts[ipart].pMatMapping[min((int)m_parts[ipart].nMats-1,id)]];
1495 m_parts[ipart].idmatBreakable = max(m_parts[ipart].idmatBreakable, (id>>sf_matbreakable_bit)-1);
1496 flags |= id;
1499 } else for(i=m_parts[ipart].pPhysGeom->pGeom->GetPrimitiveCount()-1; i>=0; i--) {
1500 id = m_parts[ipart].pPhysGeom->pGeom->GetPrimitiveId(i,0x40);
1501 id += m_parts[ipart].surface_idx+1 & id>>31;
1502 id = m_pWorld->m_SurfaceFlagsTable[id];
1503 m_parts[ipart].idmatBreakable = max(m_parts[ipart].idmatBreakable, (id>>sf_matbreakable_bit)-1);
1504 flags |= id;
1506 if (m_parts[ipart].idmatBreakable>=0 && m_parts[ipart].pPhysGeom->pGeom->GetType()!=GEOM_TRIMESH)
1507 m_parts[ipart].idmatBreakable=-1, flags &= ~sf_manually_breakable;
1509 if (flags & sf_manually_breakable)
1510 m_parts[ipart].flags |= geom_manually_breakable;
1514 int CPhysicalEntity::AddGeometry(phys_geometry *pgeom, pe_geomparams* params, int id, int bThreadSafe)
1516 if (!pgeom || !pgeom->pGeom)
1517 return -1;
1518 ChangeRequest<pe_geomparams> req(this,m_pWorld,params,bThreadSafe,pgeom,id);
1519 if (req.IsQueued()) {
1520 WriteLock lock(m_lockPartIdx);
1521 if (id<0)
1522 *((int*)req.GetQueuedStruct()-1) = id = m_iLastIdx++;
1523 else
1524 m_iLastIdx = max(m_iLastIdx,id+1);
1525 return id;
1528 if (id>=0 && (!(params->flagsCollider & geom_allow_id_duplicates) || params->flags & geom_proxy)) {
1529 int i; for(i=0;i<m_nParts && m_parts[i].id!=id;i++);
1530 if (i<m_nParts) {
1531 if (params->flags & geom_proxy) {
1532 if (pgeom) {
1533 m_pWorld->GetGeomManager()->AddRefGeometry(m_parts[i].pPhysGeomProxy = pgeom);
1534 if (params->bRecalcBBox) {
1535 Vec3 BBox[2]; ComputeBBox(BBox);
1536 int bPosChanged = m_pWorld->RepositionEntity(this,1,BBox);
1537 { WriteLock lock(m_lockUpdate);
1538 WriteBBox(BBox);
1539 m_pWorld->UnlockGrid(this,-bPosChanged);
1541 RepositionParts();
1545 return id;
1548 get_xqs_from_matrices(params->pMtx3x4,params->pMtx3x3, params->pos,params->q,params->scale, &pgeom,m_pWorld->GetGeomManager());
1549 ENTITY_VALIDATE_ERRCODE("CPhysicalEntity:AddGeometry",params,-1);
1551 box abox; pgeom->pGeom->GetBBox(&abox);
1552 float mindim=min(min(abox.size.x,abox.size.y),abox.size.z), mindims=mindim*params->scale;
1553 float maxdim=max(max(abox.size.x,abox.size.y),abox.size.z), maxdims=maxdim*params->scale;
1555 if (m_nParts==m_nPartsAlloc) {
1556 WriteLock lock(m_lockUpdate);
1557 int nPartsAlloc = m_nPartsAlloc;
1558 int nPartsAllocNew = (nPartsAlloc<2)?nPartsAlloc+1:(nPartsAlloc+4 & ~3); // 0 -> 1 -> 2 -> 4 -> next boundary. 2 is very common in vegetation
1559 geom *pparts = m_parts;
1560 geom *ppartsNew = m_pHeap
1561 ? (geom*)m_pHeap->Malloc(sizeof(geom) * nPartsAllocNew, "Parts")
1562 : m_pWorld->AllocEntityParts(nPartsAllocNew);
1563 memcpy(ppartsNew, pparts, sizeof(geom)*m_nParts);
1564 for(int i=0; i<m_nParts; i++) if (m_parts[i].pNewCoords==(coord_block_BBox*)&pparts[i].pos)
1565 ppartsNew[i].pNewCoords = (coord_block_BBox*)&ppartsNew[i].pos;
1566 m_parts = ppartsNew; m_nPartsAlloc = nPartsAllocNew;
1567 if (m_pHeap)
1568 m_pHeap->Free(pparts);
1569 else
1570 m_pWorld->FreeEntityParts(pparts, nPartsAlloc);
1571 if (m_nPartsAlloc!=1) { MEMSTAT_USAGE(m_parts, sizeof(geom) * m_nParts); }
1573 { WriteLock lock(m_lockPartIdx);
1574 if (id<0)
1575 id = m_iLastIdx++;
1576 else
1577 m_iLastIdx = max(m_iLastIdx,id+1);
1579 m_parts[m_nParts].id = id;
1580 m_parts[m_nParts].pPhysGeom = m_parts[m_nParts].pPhysGeomProxy = pgeom;
1581 for(int j=0;j<2;j++) m_pWorld->GetGeomManager()->AddRefGeometry(pgeom);
1582 m_parts[m_nParts].surface_idx = pgeom->surface_idx;
1583 if (!is_unused(params->surface_idx)) m_parts[m_nParts].surface_idx = params->surface_idx;
1584 m_parts[m_nParts].flags = params->flags & ~geom_proxy;
1585 m_parts[m_nParts].flagsCollider = params->flagsCollider & geom_allow_id_duplicates-1;
1586 m_parts[m_nParts].pos = params->pos;
1587 m_parts[m_nParts].q = params->q;
1588 m_parts[m_nParts].scale = params->scale;
1589 if (is_unused(params->minContactDist)) {
1590 m_parts[m_nParts].minContactDist = max(maxdims*0.03f,mindims*(mindims<maxdims*0.3f ? 0.4f:0.1f));
1591 } else
1592 m_parts[m_nParts].minContactDist = params->minContactDist;
1593 m_parts[m_nParts].maxdim = maxdim;
1594 m_parts[m_nParts].pNewCoords = (coord_block_BBox*)&m_parts[m_nParts].pos;
1595 if (pgeom->pGeom->GetType()==GEOM_TRIMESH && params->pLattice)
1596 (m_parts[m_nParts].pLattice = (CTetrLattice*)params->pLattice)->SetMesh((CTriMesh*)pgeom->pGeom);
1597 else m_parts[m_nParts].pLattice = 0;
1598 if (params->pMatMapping)
1599 memcpy(m_parts[m_nParts].pMatMapping = new int[params->nMats], params->pMatMapping, (m_parts[m_nParts].nMats=params->nMats)*sizeof(int));
1600 else {
1601 m_parts[m_nParts].pMatMapping = pgeom->pMatMapping;
1602 m_parts[m_nParts].nMats = pgeom->nMats;
1604 if (!is_unused(params->idmatBreakable))
1605 m_parts[m_nParts].idmatBreakable = params->idmatBreakable;
1606 else if (m_parts[m_nParts].flags & geom_colltype_solid) {
1607 UpdatePartIdmatBreakable(m_nParts,m_nParts+1);
1608 if (m_nParts==1)
1609 UpdatePartIdmatBreakable(0,2);
1610 } else
1611 m_parts[m_nParts].idmatBreakable = -1;
1612 if (m_parts[m_nParts].idmatBreakable>=0 && m_parts[m_nParts].pPhysGeom->pGeom->GetType()==GEOM_TRIMESH) {
1613 CTriMesh *pMesh = (CTriMesh*)m_parts[m_nParts].pPhysGeom->pGeom;
1614 if (pMesh->m_pTree->GetMaxSkipDim()>0.05f) {
1615 int bNonLockable = isneg(pMesh->m_lockUpdate);
1616 pMesh->Lock();
1617 pMesh->RebuildBVTree();
1618 //pMesh->m_lockUpdate;
1619 pMesh->Unlock();
1620 pMesh->m_lockUpdate -= bNonLockable;
1623 m_parts[m_nParts].mass = params->mass>0 ? params->mass : params->density*pgeom->V*cube(params->scale);
1624 if (m_pStructure || m_parts[m_nParts].pLattice)
1625 m_parts[m_nParts].flags |= geom_monitor_contacts;
1626 if (m_pStructure)
1627 if (m_pStructure->nPartsAlloc<m_nParts+1) {
1628 ReallocateList(m_pStructure->pParts,m_nParts,m_nParts+1,true);
1629 if (m_pStructure->defparts)
1630 ReallocateList(m_pStructure->defparts,m_nParts,m_nParts+1,true);
1631 m_pStructure->nPartsAlloc = m_nParts+1;
1632 } else {
1633 memset(m_pStructure->pParts+m_nParts, 0, sizeof(m_pStructure->pParts[0]));
1634 if (m_pStructure->defparts)
1635 memset(m_pStructure->defparts+m_nParts, 0, sizeof(m_pStructure->defparts[0]));
1637 m_parts[m_nParts].BBox[0].zero(); m_parts[m_nParts].BBox[1].zero();
1638 m_parts[m_nParts].pPlaceholder = 0;
1640 if (params->bRecalcBBox) {
1641 Vec3 BBox[2];
1642 ComputeBBox(BBox, update_part_bboxes|part_added);
1643 int bPosChanged = m_pWorld->RepositionEntity(this,1,BBox);
1644 { WriteLock lock(m_lockUpdate);
1645 WriteBBox(BBox); m_nParts++;
1646 m_pWorld->UnlockGrid(this,-bPosChanged);
1648 RepositionParts();
1649 } else {
1650 WriteLock lock(m_lockUpdate);
1651 m_nParts++;
1654 if (m_nPartsAlloc!=1) { MEMSTAT_USAGE(m_parts, sizeof(geom) * m_nParts); }
1656 m_Extents.Clear();
1658 return id;
1662 void CPhysicalEntity::RemoveGeometry(int id, int bThreadSafe)
1664 ChangeRequest<void> req(this,m_pWorld,0,bThreadSafe,0,id);
1665 if (req.IsQueued())
1666 return;
1667 int i,j,n=0;
1669 for(i=m_nParts-1;i>=0;i--) if (m_parts[i].id==id) {
1670 if (m_nRefCount && m_iSimClass==0 && m_pWorld->m_vars.lastTimeStep>0.0f) {
1671 CPhysicalEntity **pentlist;
1672 Vec3 inflator = Vec3(10.0f)*m_pWorld->m_vars.maxContactGap;
1673 for(j=m_pWorld->GetEntitiesAround(m_BBox[0]-inflator,m_BBox[1]+inflator, pentlist, ent_sleeping_rigid|ent_living|ent_independent)-1; j>=0; j--)
1674 if (m_iSimClass || pentlist[j]->HasPartContactsWith(this,i,1))
1675 pentlist[j]->Awake();
1677 if (m_pStructure) {
1678 for(j=0;j<m_pStructure->nJoints;j++)
1679 if (m_pStructure->pJoints[j].ipart[0]==i || m_pStructure->pJoints[j].ipart[1]==i) {
1680 m_pStructure->pJoints[j] = m_pStructure->pJoints[--m_pStructure->nJoints]; --j;
1681 m_pStructure->bModified++;
1683 for(j=0;j<m_pStructure->nJoints;j++) {
1684 m_pStructure->pJoints[j].ipart[0] -= isneg(i-m_pStructure->pJoints[j].ipart[0]);
1685 m_pStructure->pJoints[j].ipart[1] -= isneg(i-m_pStructure->pJoints[j].ipart[1]);
1687 if (m_pStructure->pParts) {
1688 memmove(m_pStructure->pParts+i, m_pStructure->pParts+i+1, (m_nParts-1-i)*sizeof(SPartInfo));
1689 for(j=0;j<m_nParts;j++) {
1690 m_pStructure->pParts[j].iParent &= ~-iszero(i+1-m_pStructure->pParts[j].iParent);
1691 m_pStructure->pParts[j].iParent -= isneg(i-m_pStructure->pParts[j].iParent);
1694 if (m_pStructure->Pexpl) memmove(m_pStructure->Pexpl+i, m_pStructure->Pexpl+i+1, (m_nParts-1-i)*sizeof(Vec3));
1695 if (m_pStructure->Lexpl) memmove(m_pStructure->Lexpl+i, m_pStructure->Lexpl+i+1, (m_nParts-1-i)*sizeof(Vec3));
1696 if (m_pStructure->defparts) {
1697 if (m_pStructure->defparts[i].pSkelEnt) {
1698 delete[] m_pStructure->defparts[i].pSkinInfo;
1699 m_pWorld->DestroyPhysicalEntity(m_pStructure->defparts[i].pSkelEnt,0,1);
1701 memmove(m_pStructure->defparts+i, m_pStructure->defparts+i+1, (m_nParts-1-i)*sizeof(SSkelInfo));
1704 CPhysicalPlaceholder *ppc=0;
1705 { WriteLockCond lock(m_lockUpdate,m_pWorld->m_vars.bLogStructureChanges);
1706 if (m_parts[i].pMatMapping && m_parts[i].pMatMapping!=m_parts[i].pPhysGeom->pMatMapping)
1707 delete[] m_parts[i].pMatMapping;
1708 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
1709 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
1710 if (m_parts[i].pPlaceholder)
1711 ppc = ReleasePartPlaceholder(i);
1712 for(;i<m_nParts-1;i++) {
1713 m_parts[i] = m_parts[i+1];
1714 if (m_parts[i].pNewCoords==(coord_block_BBox*)&m_parts[i+1].pos)
1715 m_parts[i].pNewCoords = (coord_block_BBox*)&m_parts[i].pos;
1716 if (m_parts[i].pPlaceholder)
1717 m_parts[i].pPlaceholder->m_id = -2-i;
1719 m_nParts--;
1720 if (m_nPartsAlloc!=1) { MEMSTAT_USAGE(m_parts, sizeof(geom) * m_nParts); }
1721 for(m_iLastIdx=i=0;i<m_nParts;i++)
1722 m_iLastIdx = max(m_iLastIdx, m_parts[i].id+1);
1724 if (ppc)
1725 m_pWorld->DestroyPhysicalEntity(ppc,0,1);
1726 n++;
1728 if (n) {
1729 // keep the original bounding box while RepositionEntity emits the signal and substitute at the end
1730 Vec3 newBBox[2];
1731 ComputeBBox(newBBox);
1732 m_pWorld->RepositionEntity(this,1|8,newBBox);
1733 m_BBox[0] = newBBox[0];
1734 m_BBox[1] = newBBox[1];
1735 RepositionParts();
1740 RigidBody *CPhysicalEntity::GetRigidBody(int ipart,int bWillModify)
1742 g_StaticRigidBody.P.zero(); g_StaticRigidBody.v.zero();
1743 g_StaticRigidBody.L.zero(); g_StaticRigidBody.w.zero();
1744 return &g_StaticRigidBody;
1748 int CPhysicalEntity::IsPointInside(Vec3 pt) const
1750 pt = (pt-m_pos)*m_qrot;
1751 ReadLock lock(m_lockUpdate);
1752 for(int i=0;i<m_nParts;i++) if ((m_parts[i].flags & geom_collides) &&
1753 m_parts[i].pPhysGeom->pGeom->PointInsideStatus(((pt-m_parts[i].pos)*m_parts[i].q)/m_parts[i].scale))
1754 return 1;
1755 return 0;
1759 void CPhysicalEntity::AlertNeighbourhoodND(int mode)
1761 if (m_pOuterEntity && !m_pWorld->m_bMassDestruction) {
1762 m_pOuterEntity->Release();
1763 m_pOuterEntity = 0;
1766 int i;
1767 if (m_iSimClass>3)
1768 return;
1770 for(i=0;i<m_nColliders;i++) if (m_pColliders[i]!=this) {
1771 m_pColliders[i]->RemoveColliderMono(this);
1772 m_pColliders[i]->Awake();
1773 m_pColliders[i]->Release();
1775 m_nColliders = 0;
1777 if (!(m_flags & pef_disabled) && (m_nRefCount>0 && m_iSimClass<3 || m_flags&pef_always_notify_on_deletion)) {
1778 CPhysicalEntity **pentlist;
1779 Vec3 inflator = (m_BBox[1]-m_BBox[0])*1E-3f+Vec3(4,4,4)*m_pWorld->m_vars.maxContactGap;
1780 for(i=m_pWorld->GetEntitiesAround(m_BBox[0]-inflator,m_BBox[1]+inflator, pentlist,
1781 ent_sleeping_rigid|ent_rigid|ent_living|ent_independent|ent_triggers)-1; i>=0; i--)
1782 if (pentlist[i]!=this)
1783 pentlist[i]->Awake();
1786 if (m_pStructure && m_pStructure->defparts) {
1787 for(i=0;i<m_nParts;i++) if (m_pStructure->defparts[i].pSkinInfo)
1788 m_pWorld->DestroyPhysicalEntity(m_pStructure->defparts[i].pSkelEnt,mode,1);
1789 if (mode==0) {
1790 for(i=0;i<m_nParts;i++) if (m_pStructure->defparts[i].pSkinInfo)
1791 delete[] m_pStructure->defparts[i].pSkinInfo;
1792 delete[] m_pStructure->defparts;
1793 m_pStructure->defparts = 0;
1799 int CPhysicalEntity::RemoveCollider(CPhysicalEntity *pCollider, bool bRemoveAlways)
1801 PREFAST_ASSUME(pCollider);
1802 if (m_pColliders && m_iSimClass!=0) {
1803 int i,islot; for(i=0;i<m_nColliders && m_pColliders[i]!=pCollider;i++);
1804 if (i<m_nColliders) {
1805 for(islot=i;i<m_nColliders-1;i++) m_pColliders[i] = m_pColliders[i+1];
1806 if (pCollider!=this)
1807 pCollider->Release();
1808 m_nColliders--; return islot;
1811 return -1;
1814 int CPhysicalEntity::AddCollider(CPhysicalEntity *pCollider)
1816 PREFAST_ASSUME(pCollider);
1817 if (m_iSimClass==0)
1818 return 1;
1819 int i,j;
1820 for(i=0;i<m_nColliders && m_pColliders[i]!=pCollider;i++);
1821 if (i==m_nColliders) {
1822 if (m_nColliders==m_nCollidersAlloc)
1823 ReallocateList(m_pColliders, m_nColliders, m_nCollidersAlloc+=8, true);
1824 for(i=0;i<m_nColliders && pCollider->GetMassInv()>m_pColliders[i]->GetMassInv();i++);
1825 NO_BUFFER_OVERRUN
1826 for(j=m_nColliders-1; j>=i; j--) m_pColliders[j+1] = m_pColliders[j];
1827 m_pColliders[i] = pCollider; m_nColliders++;
1828 if (pCollider!=this)
1829 pCollider->AddRef();
1831 return i;
1835 void CPhysicalEntity::DrawHelperInformation(IPhysRenderer *pRenderer, int flags)
1837 //ReadLock lock(m_lockUpdate);
1838 int i,j;
1839 geom_world_data gwd;
1841 if (flags & pe_helper_bbox) {
1842 Vec3 sz,center,pt[8];
1843 center = (m_BBox[1]+m_BBox[0])*0.5f;
1844 sz = (m_BBox[1]-m_BBox[0])*0.5f;
1845 for(i=0;i<8;i++)
1846 pt[i] = Vec3(sz.x*((i<<1&2)-1),sz.y*((i&2)-1),sz.z*((i>>1&2)-1))+center;
1847 for(i=0;i<8;i++) for(j=0;j<3;j++) if (i&1<<j)
1848 pRenderer->DrawLine(pt[i],pt[i^1<<j],m_iSimClass);
1851 if (flags & (pe_helper_geometry|pe_helper_lattice)) {
1852 int iLevel = flags>>16 & 0xFFF, mask=0, bTransp=(m_pStructure && (flags & 16 || m_pWorld->m_vars.bLogLatticeTension)) | flags>>29 & 1;
1853 if (iLevel & 1<<11)
1854 mask=iLevel&0xF7FF,iLevel=0;
1855 for(i=0;i<m_nParts;i++) if ((m_parts[i].flags & mask)==mask && (m_parts[i].flags || m_parts[i].flagsCollider || m_parts[i].mass>0)) {
1856 gwd.R = Matrix33(m_qrot*m_parts[i].q);
1857 gwd.offset = m_pos + m_qrot*m_parts[i].pos;
1858 gwd.scale = m_parts[i].scale;
1859 if (flags & pe_helper_geometry) {
1860 if (m_parts[i].pPhysGeomProxy->pGeom && (m_parts[i].pPhysGeomProxy==m_parts[i].pPhysGeom || mask!=geom_colltype_ray))
1861 m_parts[i].pPhysGeomProxy->pGeom->DrawWireframe(pRenderer,&gwd, iLevel, m_iSimClass | (m_parts[i].flags&1^1|bTransp)<<8);
1862 if (m_parts[i].pPhysGeom->pGeom && m_parts[i].pPhysGeomProxy!=m_parts[i].pPhysGeom && (mask & geom_colltype_ray)==geom_colltype_ray)
1863 m_parts[i].pPhysGeom->pGeom->DrawWireframe(pRenderer,&gwd, iLevel, m_iSimClass | 1<<8);
1865 if ((flags & pe_helper_lattice) && m_parts[i].pLattice)
1866 m_parts[i].pLattice->DrawWireframe(pRenderer,&gwd,m_iSimClass);
1869 if (m_pWorld->m_vars.bLogLatticeTension && !m_pStructure && GetMassInv()>0) {
1870 char txt[32];
1871 cry_sprintf(txt, "%.2fkg" ,1.0f/GetMassInv() );
1872 pRenderer->DrawText((m_BBox[0]+m_BBox[1])*0.5f, txt, 1);
1876 if ((m_pWorld->m_vars.bLogLatticeTension || flags & 16) && m_pStructure) {
1877 CTriMesh mesh;
1878 CBoxGeom boxGeom;
1879 box abox;
1880 Vec3 norms[4], vtx[]={Vec3(0,0.2f,0),Vec3(-0.1732f,-0.1f,0),Vec3(0.1732f,-0.1f,0),Vec3(0,0,1)};
1881 int ipart; index_t idx[]={0,2,1,0,1,3,1,2,3,2,0,3};
1882 trinfo top[4];
1883 box bbox;
1884 for(i=0;i<4;i++) norms[i] = (vtx[idx[i*3+1]]-vtx[idx[i*3]]^vtx[idx[i*3+2]]-vtx[idx[i*3]]).normalized();
1885 memset(top,-1,4*sizeof(top[0]));
1886 mesh.m_flags = mesh_shared_vtx|mesh_shared_idx|mesh_shared_normals|mesh_shared_topology|mesh_SingleBB;
1887 mesh.m_pVertices = strided_pointer<Vec3>(vtx);
1888 mesh.m_pIndices = idx;
1889 mesh.m_pNormals = norms;
1890 mesh.m_pTopology = top;
1891 mesh.m_nTris=mesh.m_nVertices = 4;
1892 mesh.m_ConvexityTolerance[0] = 0.02f; mesh.m_bConvex[0] = 1;
1893 mesh.RebuildBVTree();
1894 abox.Basis.SetIdentity(); abox.center.zero(); abox.size.Set(0.5f,0.5f,0.5f);
1895 boxGeom.CreateBox(&abox);
1896 for(i=0;i<m_pStructure->nJoints;i++) {
1897 gwd.offset = m_qrot*m_pStructure->pJoints[i].pt+m_pos;
1898 gwd.R = Matrix33(m_qrot*Quat::CreateRotationV0V1(Vec3(0,0,1),m_pStructure->pJoints[i].n));
1899 gwd.scale = m_pStructure->pJoints[i].size*2;
1900 j = 4+2*isneg(m_pStructure->pJoints[i].ipart[0]|m_pStructure->pJoints[i].ipart[1]);
1901 pRenderer->DrawGeometry(&mesh,&gwd,j);
1902 gwd.scale = m_pStructure->pJoints[i].size;
1903 pRenderer->DrawGeometry(&boxGeom,&gwd,j);
1904 for(j=0;j<2;j++) if ((unsigned int)(ipart=m_pStructure->pJoints[i].ipart[j])<(unsigned int)m_nParts) {
1905 m_parts[ipart].pPhysGeom->pGeom->GetBBox(&bbox);
1906 pRenderer->DrawLine(gwd.offset, m_qrot*(m_parts[ipart].q*bbox.center*m_parts[ipart].scale+m_parts[ipart].pos)+m_pos, m_iSimClass);
1909 if (m_pWorld->m_vars.bLogLatticeTension) {
1910 char txt[32];
1911 if (m_nParts != 0)
1913 for(i=0;i<m_nParts;i++) {
1914 m_parts[i].pPhysGeom->pGeom->GetBBox(&bbox);
1915 cry_sprintf(txt, "%.2fkg" ,m_parts[i].mass);
1916 pRenderer->DrawText(m_qrot*(m_parts[i].q*bbox.center*m_parts[i].scale+m_parts[i].pos)+m_pos, txt, 1);
1919 if (m_pStructure->nPrevJoints) {
1920 float rdt = 1.0f/m_pStructure->prevdt, tens,maxtens;
1921 for(i=0;i<m_pStructure->nPrevJoints;i++) if (m_pStructure->pJoints[i].tension>0) {
1922 tens = sqrt_tpl(m_pStructure->pJoints[i].tension)*rdt;
1923 switch (m_pStructure->pJoints[i].itens) {
1924 case 0: cry_sprintf(txt, "twist: %.1f/%.1f", tens,maxtens=m_pStructure->pJoints[i].maxTorqueTwist); break;
1925 case 1: cry_sprintf(txt, "bend: %.1f/%.1f", tens,maxtens=m_pStructure->pJoints[i].maxTorqueBend); break;
1926 case 2: cry_sprintf(txt, "push: %.1f/%.1f", tens,maxtens=m_pStructure->pJoints[i].maxForcePush); break;
1927 case 3: cry_sprintf(txt, "pull: %.1f/%.1f", tens,maxtens=m_pStructure->pJoints[i].maxForcePull); break;
1928 case 4: cry_sprintf(txt, "shift: %.1f/%.1f", tens,maxtens=m_pStructure->pJoints[i].maxForceShift); break;
1929 default: continue;
1931 pRenderer->DrawText(m_qrot*m_pStructure->pJoints[i].pt+m_pos, txt, 0, tens/max(tens,maxtens));
1937 if (m_pWorld->m_vars.bDebugExplosions) {
1938 Vec3 imp;
1939 char str[128];
1940 box bbox;
1941 if (!m_pStructure || !m_pStructure->Pexpl) {
1942 if (m_pWorld->IsAffectedByExplosion(this,&imp)) {
1943 cry_sprintf(str, "%.1f", imp.len());
1944 pRenderer->DrawText(imp=(m_BBox[0]+m_BBox[1])*0.5f, str, 1,0.5f);
1945 pRenderer->DrawLine(m_pWorld->m_lastEpicenter, imp, 5);
1947 } else for(i=0;i<m_nParts;i++) if (m_pStructure->Pexpl[i].len2()+m_pStructure->Lexpl[i].len2()>0) {
1948 cry_sprintf(str, "%.1f/%.1f", m_pStructure->Pexpl[i].len(),m_pStructure->Lexpl[i].len());
1949 m_parts[i].pPhysGeom->pGeom->GetBBox(&bbox);
1950 pRenderer->DrawText(imp=m_qrot*(m_parts[i].q*bbox.center*m_parts[i].scale+m_parts[i].pos)+m_pos, str, 1,0.5f);
1951 pRenderer->DrawLine(m_pWorld->m_lastEpicenter, imp, 5);
1955 if (m_pWorld->GetGrid(this) != &m_pWorld->m_entgrid)
1956 pRenderer->DrawLine(m_pos, m_pWorld->GetGrid(this)->origin, m_iSimClass);
1960 void CPhysicalEntity::GetMemoryStatistics(ICrySizer *pSizer) const
1962 if (GetType()==PE_STATIC)
1963 pSizer->AddObject(this, sizeof(CPhysicalEntity));
1964 if (m_pWorld->m_vars.iDrawHelpers & 1<<31 && m_ig[0].x>-1)
1965 pSizer->AddObject(&m_iGThunk0, (m_ig[1].x-m_ig[0].x+1)*(m_ig[1].y-m_ig[0].y+1)*sizeof(pe_gridthunk));
1966 pSizer->AddObject(m_parts, m_nPartsAlloc*sizeof(m_parts[0]));
1967 for(int i=0;i<m_nParts;i++) {
1968 if (CPhysicalPlaceholder *ppc=m_parts[i].pPlaceholder) {
1969 //pSizer->AddObject(ppc, sizeof(CPhysicalPlaceholder));
1970 if (m_pWorld->m_vars.iDrawHelpers & 1<<31 && ppc->m_ig[0].x>-1)
1971 pSizer->AddObject(&ppc->m_iGThunk0, (ppc->m_ig[1].x-ppc->m_ig[0].x+1)*(ppc->m_ig[1].y-ppc->m_ig[0].y+1)*sizeof(pe_gridthunk));
1973 int nMats = m_parts[i].pMatMapping && m_parts[i].pMatMapping!=m_parts[i].pPhysGeom->pMatMapping ? m_parts[i].nMats : 0;
1974 pSizer->AddObject(m_parts[i].pMatMapping, nMats*sizeof(int), nMats);
1976 if(m_pColliders)
1977 pSizer->AddObject(m_pColliders, m_nCollidersAlloc*sizeof(m_pColliders[0]));
1978 if (m_pStructure) {
1979 pSizer->AddObject(m_pStructure, sizeof(*m_pStructure));
1980 pSizer->AddObject(m_pStructure->pParts, sizeof(m_pStructure->pParts[0])*m_nParts);
1981 if (m_pStructure->Pexpl) {
1982 pSizer->AddObject(m_pStructure->Pexpl, sizeof(m_pStructure->Pexpl[0])*m_nParts);
1983 pSizer->AddObject(m_pStructure->Lexpl, sizeof(m_pStructure->Lexpl[0])*m_nParts);
1985 pSizer->AddObject(m_pStructure->pJoints, sizeof(m_pStructure->pJoints[0])*m_pStructure->nJointsAlloc);
1986 if (m_pStructure->defparts) {
1987 pSizer->AddObject(m_pStructure->defparts, sizeof(m_pStructure->defparts[0])*m_nParts);
1988 for(int i=0;i<m_nParts;i++) if (m_pStructure->defparts[i].pSkelEnt) {
1989 //m_pStructure->defparts[i].pSkelEnt->GetMemoryStatistics(pSizer); // already taken into account in global entity lists
1990 pSizer->AddObject(m_pStructure->defparts[i].pSkinInfo, sizeof(SSkinInfo)*(
1991 ((CGeometry*)m_parts[i].pPhysGeom->pGeom)->IsAPrimitive() ? 1 : ((mesh_data*)m_parts[i].pPhysGeom->pGeom->GetData())->nVertices));
1995 pSizer->AddObject(m_ground, m_nGroundPlanes*sizeof(m_ground[0]));
1996 if (m_pUsedParts)
1997 pSizer->AddObject(m_pUsedParts, MAX_TOT_THREADS*sizeof(m_pUsedParts[0]));
2000 struct SMemSerializer : ISerialize {
2001 SMemSerializer(int size0=256) { buf=new char[size=size0]; pos=0; reading=false; }
2002 SMemSerializer(char *buf0, bool read=true) { buf=buf0; size=-1; pos=0; reading=read; }
2003 virtual ~SMemSerializer() { if (size>0) delete[] buf; }
2004 virtual void ReadStringValue(const char * name, SSerializeString &curValue, uint32 policy=0) {}
2005 virtual void WriteStringValue(const char * name, SSerializeString& buffer, uint32 policy=0) {}
2006 virtual void Update( ISerializeUpdateFunction * pUpdate ) {}
2007 virtual void FlagPartialRead() {}
2008 virtual void BeginGroup( const char * szName ) {}
2009 virtual bool BeginOptionalGroup(const char* szName, bool condition)
2011 Value(szName, condition);
2012 return condition;
2014 virtual void EndGroup() {}
2015 virtual bool IsReading() const { return reading!=0; }
2016 virtual bool ShouldCommitValues() const { return true; }
2017 virtual ESerializationTarget GetSerializationTarget() const { return eST_SaveGame; }
2018 virtual bool Ok() const { return true; }
2019 #define SERIALIZATION_TYPE(T) \
2020 virtual void Value( const char * name, T& x, uint32 policy=0 ) { \
2021 if (pos+sizeof(T)>(unsigned int)size) { ReallocateList(buf,size,size+256); size+=256; } \
2022 T *op[2]; op[reading]=(T*)(buf+pos); op[reading^1]=&x; *op[0]=*op[1]; pos+=sizeof(T); \
2024 #include <CryNetwork/SerializationTypes.h>
2025 #undef SERIALIZATION_TYPE
2026 #define SERIALIZATION_TYPE(T) virtual void ValueWithDefault( const char * name, T& x, const T& defaultValue ) { Value(name,x); }
2027 #include <CryNetwork/SerializationTypes.h>
2028 #undef SERIALIZATION_TYPE
2029 virtual void ValueWithDefault( const char * name, SSerializeString& x, const SSerializeString& defaultValue ) {}
2030 int reading;
2031 char* buf;
2032 int pos,size;
2035 int CPhysicalEntity::GetStateSnapshotTxt(char *txtbuf,int szbuf, float time_back)
2037 const int version = 0;
2038 SMemSerializer mser;
2039 if (txtbuf) {
2040 for(int i=0,j=version,j10; i<4; i++,j=j10)
2041 j10=j/10, txtbuf[3-i]=j-(j10*10)+'0';
2042 txtbuf += 4;
2044 if (time_back<0) {
2045 if (txtbuf) *txtbuf++='~'; szbuf--;
2046 CPhysicalEntity::GetStateSnapshot(TSerialize(&mser));
2047 } else
2048 GetStateSnapshot(TSerialize(&mser));
2049 return (txtbuf ? bin2ascii((unsigned char*)mser.buf,mser.pos,(unsigned char*)txtbuf) : (mser.pos*4)/3+2)+4;
2052 void CPhysicalEntity::SetStateFromSnapshotTxt(const char *txtbuf,int szin)
2054 int szbuf=szin, version=0;
2055 for(int i=0; i<4; i++)
2056 version = version*10 + *txtbuf++-'0';
2057 const unsigned char *txtbuf1 = (const unsigned char*)txtbuf+(*txtbuf=='~' ? 1:0);
2058 char *buf = new char[szbuf];
2059 SMemSerializer mser(buf);
2060 while (!ascii2bin(txtbuf1,szbuf,(unsigned char*)buf)) {
2061 delete[] buf; buf=mser.buf=new char[szbuf*=2];
2063 if (*txtbuf=='~')
2064 CPhysicalEntity::SetStateFromSnapshot(TSerialize(&mser));
2065 else
2066 SetStateFromSnapshot(TSerialize(&mser));
2067 delete[] buf;
2071 inline void FillGeomParams(pe_geomparams &dst, geom &src)
2073 dst.flags = (src.flags|geom_can_modify)&~(geom_invalid|geom_removed|geom_constraint_on_break);
2074 dst.flagsCollider = src.flagsCollider;
2075 dst.mass = src.mass;
2076 dst.pos = src.pos;
2077 dst.q = src.q;
2078 dst.scale = src.scale;
2079 dst.idmatBreakable = src.idmatBreakable;
2080 dst.minContactDist = src.minContactDist;
2081 dst.pMatMapping = src.pMatMapping!=src.pPhysGeom->pMatMapping ? src.pMatMapping:0;
2082 dst.nMats = src.nMats;
2086 void CPhysicalEntity::RemoveBrokenParent(int i, int nIsles)
2088 EventPhysRevealEntityPart eprep;
2089 eprep.pEntity=this; eprep.pForeignData=m_pForeignData; eprep.iForeignData=m_iForeignData;
2090 if (m_pStructure->pParts[i].iParent)
2091 RemoveBrokenParent(m_pStructure->pParts[i].iParent-1, nIsles);
2092 if (nIsles)
2093 g_parts[i].isle = nIsles;
2094 else
2095 m_parts[i].flags |= geom_removed;
2096 for(int j=0;j<m_nParts;j++) if (m_pStructure->pParts[j].iParent-1==i) {
2097 eprep.partId = m_parts[j].id;
2098 if (nIsles)
2099 m_pWorld->OnEvent(2,&eprep);
2100 m_parts[j].flags = m_pStructure->pParts[j].flags0;
2101 m_parts[j].flagsCollider = m_pStructure->pParts[j].flagsCollider0;
2102 m_pStructure->pParts[j].iParent = m_pStructure->pParts[i].iParent;
2107 int CPhysicalEntity::MapHitPointFromParent(int iParent, const Vec3 &pt)
2109 if (!m_pStructure || !m_pStructure->pParts)
2110 return iParent;
2112 int i,j,iprim,iClosest,iter=0;
2113 float dist,minDist,tol,maxDist,massCheck=0.0f;
2114 geom_world_data gwd;
2115 box bbox;
2116 CBoxGeom boxGeom;
2117 IGeometry *pGeom;
2118 Vec3 ptloc = (pt-m_pos)*m_qrot, ptres[2];
2119 Vec3 sz = m_BBox[1]-m_BBox[0];
2120 maxDist = max(max(sz.x,sz.y),sz.z);
2121 tol = sqr(max(m_pWorld->m_vars.maxContactGap*5.0f, maxDist*0.05f));
2123 do {
2124 for(i=0,minDist=maxDist*10.0f,iClosest=iParent; i<m_nParts; i++) if (m_parts[i].mass>massCheck)
2125 for(j=m_pStructure->pParts[i].iParent-1; j>=0; j=m_pStructure->pParts[j].iParent-1) if (j==iParent) {
2126 gwd.offset = m_parts[i].pos;
2127 gwd.R = Matrix33(m_parts[i].q);
2128 gwd.scale = m_parts[i].scale;
2129 if ((pGeom = m_parts[i].pPhysGeomProxy->pGeom)->GetPrimitiveCount()>1) {
2130 m_parts[i].pPhysGeomProxy->pGeom->GetBBox(&bbox);
2131 pGeom = boxGeom.CreateBox(&bbox);
2133 pGeom->FindClosestPoint(&gwd, iprim,iprim, ptloc,ptloc, ptres);
2134 int bBest = isneg((dist=(ptres[0]-ptres[1]).len2())-minDist);
2135 minDist += (dist-minDist)*bBest;
2136 iClosest += i-iClosest & -bBest;
2137 break;
2139 massCheck = -1e10f;
2140 } while (minDist>tol && ++iter<2);
2141 return iClosest;
2144 int CPhysicalEntity::UpdateStructure(float time_interval, pe_explosion *pexpl, int iCaller, Vec3 gravity)
2146 int i,j,i0,i1,flags=0,nPlanes,ihead,itail,nIsles,iter,bBroken,nJoints,nJoints0,nMeshSplits=0,iLastIdx=m_iLastIdx;
2147 EventPhysUpdateMesh epum;
2148 EventPhysCreateEntityPart epcep;
2149 EventPhysRemoveEntityParts eprep;
2150 EventPhysJointBroken epjb;
2151 pe_geomparams gp,gpAux;
2152 pe_params_pos pp;
2153 pe_params_part ppt;
2154 pe_status_dynamics psd;
2155 CTriMesh *pMeshNew,*pMeshNext,*pMesh,*pChunkMeshesBuf[16],**pChunkMeshes=pChunkMeshesBuf;
2156 IGeometry *pMeshIsland,*pMeshIslandPrev;
2157 CTetrLattice *pChunkLatticesBuf[16],**pChunkLattices=pChunkLatticesBuf;
2158 CPhysicalEntity **pents;
2159 phys_geometry *pgeom,*pgeom0,*pgeom1;
2160 geom_world_data gwd,gwdAux;
2161 pe_action_impulse shockwave;
2162 pe_action_set_velocity asv;
2163 pe_explosion expl;
2164 plane ground[8];
2165 box bbox,bbox1;
2166 Vec3 org,sz,n,P,L,dw,dv,Ptang,Pmax,Lmax,BBoxNew[2];
2167 Matrix33 R;
2168 CSphereGeom sphGeom;
2169 //CBoxGeom boxGeom;
2170 intersection_params ip;
2171 geom_contact *pcontacts;
2172 bop_meshupdate *pmu=0;
2173 pe_params_buoyancy pb;
2174 pe_params_structural_joint psj;
2175 float t,Pn,vmax,M,V0,dt=time_interval,impTot;
2176 quotientf jtens;
2178 static int idRemoveGeoms[256];
2179 static phys_geometry *pRemoveGeoms[256],*pAddGeoms[64];
2180 static pe_geomparams gpAddGeoms[64];
2181 int nRemoveGeoms=0,nAddGeoms=0,bGeomOverflow=0;
2183 epum.pEntity=epcep.pEntity=eprep.pEntity=epjb.pEntity[0]=epjb.pEntity[1] = this;
2184 epum.pForeignData=epcep.pForeignData=eprep.pForeignData=epjb.pForeignData[0]=epjb.pForeignData[1] = m_pForeignData;
2185 epum.iForeignData=epcep.iForeignData=eprep.iForeignData=epjb.iForeignData[0]=epjb.iForeignData[1] = m_iForeignData;
2186 epum.iReason = EventPhysUpdateMesh::ReasonFracture;
2187 pp.pos = m_pos;
2188 pp.q = m_qrot;
2189 pp.pGridRefEnt = this;
2190 nPlanes = min(m_nGroundPlanes, (int)(CRY_ARRAY_COUNT(ground)));
2191 if (iCaller>=0 && (!m_pWorld->CheckAreas(this,gravity,&pb,1,Vec3(ZERO),iCaller) || is_unused(gravity)))
2192 gravity = m_pWorld->m_vars.gravity;
2193 gravity *= dt*m_pWorld->m_vars.jointGravityStep;
2194 static volatile int g_lockUpdateStructure = 0;
2195 WriteLock lock(g_lockUpdateStructure);
2196 epcep.breakImpulse.zero(); epcep.breakAngImpulse.zero(); epcep.cutRadius=0; epcep.breakSize=0;
2197 MARK_UNUSED epcep.cutPtLoc[0],epcep.cutPtLoc[1];
2198 epjb.bJoint=1; MARK_UNUSED epjb.pNewEntity[0],epjb.pNewEntity[1];
2199 if ((unsigned int)m_iSimClass>=7u)
2200 return 0;
2202 { ReadLock lockUpd(m_lockUpdate);
2203 if (pexpl) {
2204 if (!m_pExpl) m_pExpl = new SExplosionInfo;
2205 m_pExpl->center = pexpl->epicenterImp;
2206 m_pExpl->dir = pexpl->explDir;
2207 m_pExpl->kr = pexpl->impulsivePressureAtR*sqr(pexpl->r);
2208 m_pExpl->rmin = pexpl->rmin;
2209 m_timeStructUpdate = m_pWorld->m_vars.tickBreakable;
2210 m_updStage = 1; m_nUpdTicks = 0;
2211 return 1;
2214 for(i=m_nParts-1;i>=0;i--) if (m_parts[i].idmatBreakable<=-2) {
2215 for(j=0;j<i;j++) if (-2-m_parts[j].id==m_parts[i].idmatBreakable) {
2216 m_parts[j].flags |= m_parts[i].flags;
2217 m_parts[j].flagsCollider |= m_parts[i].flagsCollider;
2219 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
2220 m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
2221 --m_nParts;
2222 } else
2223 flags |= m_parts[i].flags & geom_structure_changes;
2225 if (m_nPartsAlloc!=1) { MEMSTAT_USAGE(m_parts, sizeof(m_parts[0]) * m_nParts); }
2227 PHYS_ENTITY_PROFILER
2229 if (m_pStructure && m_nParts>0 && m_pStructure->nJoints>0) {
2230 if (g_nPartsAlloc < m_nParts+2) {
2231 if (g_parts) delete[] (g_parts-1);
2232 g_parts = (new SPartHelper[g_nPartsAlloc = m_nParts+2])+1;
2234 if (g_nJointsAlloc < m_pStructure->nJoints+1) {
2235 if (g_joints) delete[] g_joints;
2236 if (g_jointidx) delete[] g_jointidx;
2237 g_joints = new SStructuralJointHelper[g_nJointsAlloc = m_pStructure->nJoints+1];
2238 g_jointidx = new int[g_nJointsAlloc*2];
2239 if (g_jointsDbg) delete[] g_jointsDbg;
2240 g_jointsDbg = new SStructuralJointDebugHelper[g_nJointsAlloc];
2242 nJoints0 = m_pStructure->nJoints;
2244 // prepare part infos
2245 for(i=0,M=0,g_parts[0].idx=-1; i<m_nParts; i++) {
2246 g_parts[i].org = m_parts[i].q*m_parts[i].pPhysGeom->origin + m_parts[i].pos;
2247 if (m_parts[i].mass>0) {
2248 g_parts[i].Minv = 1.0f/m_parts[i].mass;
2249 Diag33 invIbody(m_parts[i].pPhysGeom->Ibody*(m_parts[i].mass/m_parts[i].pPhysGeom->V)*sqr(m_parts[i].scale));
2250 g_parts[i].Iinv = Matrix33(m_parts[i].q)*invIbody.invert()*Matrix33(!m_parts[i].q);
2251 } else {
2252 g_parts[i].Minv=0; g_parts[i].Iinv.SetZero();
2254 g_parts[i].bProcessed = 0; g_parts[i].ijoint0 = 0;
2255 M += m_parts[i].mass;
2256 g_parts[i].pent = this;
2258 impTot=0; vmax=-1; Pmax.zero(); Lmax.zero();
2259 if (m_pWorld->m_vars.breakImpulseScale || m_flags & pef_override_impulse_scale) {
2260 for(i=0; i<m_nParts; i++) {
2261 P = m_pStructure->pParts[i].Pext*dt*100+m_pStructure->pParts[i].Fext;
2262 L = m_pStructure->pParts[i].Lext*dt*100+m_pStructure->pParts[i].Text;
2263 j = isneg(Pmax.len()+Lmax.len2()-P.len()-L.len2());
2264 Pmax = Pmax*(1-j)+P*j; Lmax = Lmax*(1-j)+L*j;
2265 g_parts[i].v = (m_pStructure->pParts[i].Pext*dt*100+m_pStructure->pParts[i].Fext)*g_parts[i].Minv;
2266 g_parts[i].w = g_parts[i].Iinv*(m_pStructure->pParts[i].Lext*dt*100+m_pStructure->pParts[i].Text);
2267 g_parts[i].v += gravity*iszero((int)m_flags & aef_recorded_physics);
2268 n = m_parts[i].BBox[1]-m_parts[i].BBox[0];
2269 if ((Pn=g_parts[i].v.len2()+g_parts[i].w.len2()*sqr(n.x+n.y+n.z)*0.01f) > vmax)
2270 vmax=Pn, g_parts[0].idx=i;
2271 impTot += m_pStructure->pParts[i].Pext.len2()+m_pStructure->pParts[i].Lext.len2()+
2272 m_pStructure->pParts[i].Fext.len2()+m_pStructure->pParts[i].Text.len2();
2274 } else for(i=0; i<m_nParts; i++) {
2275 g_parts[i].v.zero();
2276 g_parts[i].w.zero();
2279 g_parts[-1].org.zero();
2280 g_parts[-1].v.zero(); g_parts[-1].w.zero();
2281 g_parts[-1].Minv = 0; g_parts[-1].Iinv.SetZero();
2282 g_parts[-1].bProcessed = 0;
2283 g_parts[-1].ijoint0 = g_parts[m_nParts].ijoint0 = 0;
2284 g_parts[-1].pent = this;
2285 eprep.massOrg = M;
2286 if (M>0) M = 1.0f/M;
2287 if (m_pStructure->idpartBreakOrg>=0)
2288 for(g_parts[0].idx=m_nParts-1; g_parts[0].idx>=0 && m_parts[g_parts[0].idx].id!=m_pStructure->idpartBreakOrg; g_parts[0].idx--);
2289 epjb.partidEpicenter = g_parts[0].idx>=0 ? m_parts[g_parts[0].idx].id : -1;
2291 // for each part, build the list of related joints
2292 for(i=0;i<m_pStructure->nJoints;i++) {
2293 g_parts[m_pStructure->pJoints[i].ipart[0]].ijoint0++;
2294 g_parts[m_pStructure->pJoints[i].ipart[1]].ijoint0++;
2296 for(i=0;i<m_nParts;i++)
2297 g_parts[i].ijoint0 += g_parts[i-1].ijoint0;
2298 for(i=0;i<m_pStructure->nJoints;i++) {
2299 g_jointidx[--g_parts[m_pStructure->pJoints[i].ipart[0]].ijoint0] = i;
2300 g_jointidx[--g_parts[m_pStructure->pJoints[i].ipart[1]].ijoint0] = i;
2302 g_parts[m_nParts].ijoint0 = m_pStructure->nJoints*2;
2304 // iterate parts around the fastest moving part breadth-wise, add connecting joints as we add next part to the queue
2305 ihead=nJoints=0;
2306 if (g_parts[0].idx>=0) do {
2307 for(g_parts[g_parts[ihead].idx].bProcessed=1,itail=ihead+1; ihead<itail; ihead++) {
2308 for(i=g_parts[g_parts[ihead].idx].ijoint0,g_parts[g_parts[ihead].idx].bProcessed++; i<g_parts[g_parts[ihead].idx+1].ijoint0; i++) {
2309 j = m_pStructure->pJoints[g_jointidx[i]].ipart[0] + m_pStructure->pJoints[g_jointidx[i]].ipart[1] - g_parts[ihead].idx;
2310 g_joints[nJoints].idx = g_jointidx[i];
2311 nJoints += -((g_parts[j].bProcessed-2|j)>>31) & (m_pStructure->pJoints[g_jointidx[i]].bBreakable & 1);
2312 if (!g_parts[j].bProcessed) {
2313 g_parts[itail].idx = j; itail += g_parts[j].Minv>0;
2314 g_parts[j].bProcessed = 1;
2315 /*j += g_parts[ihead].idx;
2316 for(i1=i; i1<g_parts[g_parts[ihead].idx+1].ijoint0; i1++) {
2317 g_joints[nJoints].idx = g_jointidx[i1];
2318 nJoints += iszero(m_pStructure->pJoints[g_jointidx[i1]].ipart[0] + m_pStructure->pJoints[g_jointidx[i1]].ipart[1] - j) &
2319 (m_pStructure->pJoints[g_jointidx[i1]].bBreakable & 1);*/
2322 g_parts[-1].bProcessed = 0;
2324 if (ihead<m_nParts) {
2325 for(i=0; i<m_nParts && (g_parts[i].bProcessed || m_parts[i].mass*(m_pStructure->pParts[i].Pext.len2()+
2326 m_pStructure->pParts[i].Lext.len2()+m_pStructure->pParts[i].Fext.len2()+m_pStructure->pParts[i].Text.len2())==0); i++);
2327 if (i==m_nParts)
2328 break;
2329 g_parts[ihead].idx = i;
2330 } else
2331 break;
2332 } while(true);
2334 // prepare joint infos
2335 for(i=0; i<nJoints; i++) {
2336 j = g_joints[i].idx; i0 = m_pStructure->pJoints[j].ipart[0]; i1 = m_pStructure->pJoints[j].ipart[1];
2337 g_joints[i].r0 = g_parts[i0].org - m_pStructure->pJoints[j].pt;
2338 g_joints[i].r1 = g_parts[i1].org - m_pStructure->pJoints[j].pt;
2339 t = g_parts[i0].Minv+g_parts[i1].Minv; g_joints[i].vKinv.SetZero();
2340 g_joints[i].vKinv(0,0)=t; g_joints[i].vKinv(1,1)=t; g_joints[i].vKinv(2,2)=t;
2341 crossproduct_matrix(g_joints[i].r0,R); g_joints[i].vKinv -= R*g_parts[i0].Iinv*R;
2342 crossproduct_matrix(g_joints[i].r1,R); g_joints[i].vKinv -= R*g_parts[i1].Iinv*R;
2343 g_joints[i].vKinv.Invert();
2344 (g_joints[i].wKinv = g_parts[i0].Iinv+g_parts[i1].Iinv).Invert();
2345 g_joints[i].P = m_pStructure->pJoints[j].Paccum;
2346 g_joints[i].L = m_pStructure->pJoints[j].Laccum;
2347 g_joints[i].bBroken = 0;
2348 g_jointsDbg[i].tension.set(-1,0);
2351 // resolve joints, alternating order each iteration; track saturated joints
2352 iter=0; if (m_pStructure->idpartBreakOrg<0) do {
2353 ihead = nJoints-1 & -(iter&1);
2354 itail = nJoints-(nJoints+1 & -(iter&1));
2355 for(i=ihead,bBroken=0; i!=itail; i+=1-(iter<<1&2)) {
2356 j = g_joints[i].idx; i0 = m_pStructure->pJoints[j].ipart[0]; i1 = m_pStructure->pJoints[j].ipart[1];
2357 P = g_joints[i].P; L = g_joints[i].L; n = m_pStructure->pJoints[j].n;
2358 m_pStructure->pJoints[j].bBroken = 0;
2360 dw = g_parts[i0].w-g_parts[i1].w;
2361 g_joints[i].L -= g_joints[i].wKinv*dw;
2362 Pn = g_joints[i].L*n;
2363 if (m_pWorld->m_vars.bLogLatticeTension && jtens.set(Pn*Pn, sqr(m_pStructure->pJoints[j].maxTorqueTwist*dt))>=g_jointsDbg[i].tension)
2364 g_jointsDbg[i].tension=jtens, g_jointsDbg[i].itens=0;
2365 if (fabs_tpl(Pn) > m_pStructure->pJoints[j].maxTorqueTwist*dt) {
2366 g_joints[i].L -= n*(Pn+sgnnz(Pn)*m_pStructure->pJoints[j].maxTorqueTwist*dt);
2367 g_joints[i].bBroken=m_pStructure->pJoints[j].bBroken = 1;
2368 m_pStructure->pJoints[j].itens = 0;
2370 Ptang = g_joints[i].L-n*(Pn=n*g_joints[i].L);
2371 if (m_pWorld->m_vars.bLogLatticeTension && jtens.set(Ptang.len2(), sqr(m_pStructure->pJoints[j].maxTorqueBend*dt))>=g_jointsDbg[i].tension)
2372 g_jointsDbg[i].tension=jtens, g_jointsDbg[i].itens=1;
2373 if (Ptang.len2() > sqr(m_pStructure->pJoints[j].maxTorqueBend*dt)) {
2374 g_joints[i].L = Ptang.normalized()*(m_pStructure->pJoints[j].maxTorqueBend*dt) + n*Pn;
2375 g_joints[i].bBroken=m_pStructure->pJoints[j].bBroken = 1;
2376 m_pStructure->pJoints[j].itens = 1;
2378 L = g_joints[i].L-L;
2379 g_parts[i0].w += g_parts[i0].Iinv*L;
2380 g_parts[i1].w -= g_parts[i1].Iinv*L;
2382 dv = g_parts[i0].v+(g_parts[i0].w^g_joints[i].r0) - g_parts[i1].v-(g_parts[i1].w^g_joints[i].r1);
2383 g_joints[i].P -= g_joints[i].vKinv*dv;
2384 Pn = g_joints[i].P*(n=m_pStructure->pJoints[j].n);
2385 if (m_pWorld->m_vars.bLogLatticeTension)
2386 if (jtens.set(sqr_signed(Pn), sqr(m_pStructure->pJoints[j].maxForcePush*dt))>=g_jointsDbg[i].tension)
2387 g_jointsDbg[i].tension=jtens, g_jointsDbg[i].itens=2;
2388 else if (jtens.set(-sqr_signed(Pn), sqr(m_pStructure->pJoints[j].maxForcePull*dt))>=g_jointsDbg[i].tension)
2389 g_jointsDbg[i].tension=jtens, g_jointsDbg[i].itens=3;
2390 if (Pn > m_pStructure->pJoints[j].maxForcePush*dt) {
2391 g_joints[i].P -= n*(Pn-m_pStructure->pJoints[j].maxForcePush*dt);
2392 g_joints[i].bBroken=m_pStructure->pJoints[j].bBroken = 1;
2393 m_pStructure->pJoints[j].itens = 2;
2394 } else if (Pn < -m_pStructure->pJoints[j].maxForcePull*dt) {
2395 g_joints[i].P -= n*(Pn+m_pStructure->pJoints[j].maxForcePull*dt);
2396 g_joints[i].bBroken=m_pStructure->pJoints[j].bBroken = 1;
2397 m_pStructure->pJoints[j].itens = 3;
2399 Ptang = g_joints[i].P-n*(Pn=n*g_joints[i].P);
2400 if (m_pWorld->m_vars.bLogLatticeTension && jtens.set(Ptang.len2(), sqr(m_pStructure->pJoints[j].maxForceShift*dt))>=g_jointsDbg[i].tension)
2401 g_jointsDbg[i].tension=jtens, g_jointsDbg[i].itens=4;
2402 if (Ptang.len2() > sqr(m_pStructure->pJoints[j].maxForceShift*dt)) {
2403 g_joints[i].P = Ptang.normalized()*(m_pStructure->pJoints[j].maxForceShift*dt) + n*Pn;
2404 g_joints[i].bBroken=m_pStructure->pJoints[j].bBroken = 1;
2405 m_pStructure->pJoints[j].itens = 4;
2407 P = g_joints[i].P-P;
2408 g_parts[i0].v += P*g_parts[i0].Minv; g_parts[i0].w += g_parts[i0].Iinv*(g_joints[i].r0^P);
2409 g_parts[i1].v -= P*g_parts[i1].Minv; g_parts[i1].w -= g_parts[i1].Iinv*(g_joints[i].r1^P);
2411 m_pStructure->pJoints[j].bBroken &= m_pStructure->bTestRun^1;
2412 bBroken += m_pStructure->pJoints[j].bBroken;
2413 #ifdef _DEBUG
2414 dv = g_parts[i0].v+(g_parts[i0].w^g_joints[i].r0) - g_parts[i1].v-(g_parts[i1].w^g_joints[i].r1);
2415 dw = g_parts[i0].w-g_parts[i1].w;
2416 #endif
2418 ++iter;
2419 } while((iter<3 || bBroken) && iter<23);
2421 for(i=0;i<nJoints;i++) for(j=0;j<2;j++)
2422 if ((i0=m_pStructure->pJoints[g_joints[i].idx].ipart[j])>=0 && m_parts[i0].pLattice && m_parts[i0].idmatBreakable>=0) {
2423 t = m_parts[i0].pLattice->m_density*m_parts[i0].pPhysGeom->V*cube(m_parts[i0].scale)/m_parts[i0].mass;
2424 org = (m_pStructure->pJoints[g_joints[i].idx].pt-m_parts[i0].pos)*m_parts[i0].q;
2425 if (m_parts[i0].scale!=1.0f)
2426 org /= m_parts[i0].scale;
2427 m_parts[i0].pLattice->AddImpulse(org, (g_joints[i].P*m_parts[i0].q)*t, (g_joints[i].L*m_parts[i0].q)*t,
2428 gravity,m_pWorld->m_updateTimes[0]);
2431 for(i=0; i<nJoints; i++) if ((1-m_pStructure->bTestRun)*m_pStructure->pJoints[g_joints[i].idx].damageAccum>0.0f)
2432 if (m_pStructure->pJoints[g_joints[i].idx].damageAccumThresh<=0.0f) for(i=0; i<nJoints; i++) {
2433 m_pStructure->pJoints[g_joints[i].idx].Paccum += g_joints[i].P*m_pStructure->pJoints[g_joints[i].idx].damageAccum;
2434 m_pStructure->pJoints[g_joints[i].idx].Laccum += g_joints[i].L*m_pStructure->pJoints[g_joints[i].idx].damageAccum;
2435 } else {
2436 n = m_pStructure->pJoints[j = g_joints[i].idx].n;
2437 Pn = g_joints[i].L*n; Ptang = g_joints[i].L-n*Pn;
2438 jtens = max(quotientf(sqr(Pn), sqr(m_pStructure->pJoints[j].maxTorqueTwist*dt)),
2439 quotientf(Ptang.len2(), sqr(m_pStructure->pJoints[j].maxTorqueBend*dt)));
2440 Pn = g_joints[i].P*n; Ptang = g_joints[i].P-n*Pn;
2441 jtens = max(jtens, quotientf(sqr_signed(Pn), sqr(m_pStructure->pJoints[j].maxForcePush*dt)));
2442 jtens = max(jtens, quotientf(-sqr_signed(Pn), sqr(m_pStructure->pJoints[j].maxForcePull*dt)));
2443 jtens = max(jtens, quotientf(Ptang.len2(), sqr(m_pStructure->pJoints[j].maxForceShift*dt)));
2444 if (jtens > sqr(m_pStructure->pJoints[j].damageAccumThresh)) {
2445 t = (1.0f-m_pStructure->bTestRun)*m_pStructure->pJoints[j].damageAccum;
2446 t *= (1.0f-m_pStructure->pJoints[j].damageAccumThresh*sqrt_tpl(jtens.y/jtens.x));
2447 m_pStructure->pJoints[j].Paccum += g_joints[i].P*t;
2448 m_pStructure->pJoints[j].Laccum += g_joints[i].L*t;
2452 // check connectivity among parts, assign island number to each part (iterate starting from the 'world' part)
2453 for(i=0;i<m_nParts;i++) g_parts[i].bProcessed = 0;
2454 g_parts[-1].bProcessed = 1;
2455 g_parts[g_parts[ihead=0].idx = g_parts[0].ijoint0>0 ? -1:0].bProcessed = 1;
2456 nIsles=0; bBroken=0; iter=0;
2457 do {
2458 for(itail=ihead+1; ihead<itail; ihead++) {
2459 g_parts[g_parts[ihead].idx].isle = nIsles & iter;
2460 for(i=g_parts[g_parts[ihead].idx].ijoint0; i<g_parts[g_parts[ihead].idx+1].ijoint0; i++)
2461 if (!m_pStructure->pJoints[g_jointidx[i]].bBroken) {
2462 j = m_pStructure->pJoints[g_jointidx[i]].ipart[0] + m_pStructure->pJoints[g_jointidx[i]].ipart[1] - g_parts[ihead].idx;
2463 if (!g_parts[j].bProcessed) {
2464 g_parts[itail++].idx = j; g_parts[j].bProcessed = 1;
2466 } else
2467 bBroken -= nIsles-1>>31;
2468 } nIsles++;
2469 if (ihead>=m_nParts+1)
2470 break;
2471 for(i=0;i<m_nParts && (g_parts[i].bProcessed || g_parts[i].Minv>0);i++);
2472 if (i==m_nParts) {
2473 for(i=0;i<m_nParts && g_parts[i].bProcessed;i++);
2474 if (i>=m_nParts)
2475 break;
2476 iter = -1;
2478 g_parts[g_parts[ihead].idx = i].bProcessed = 1;
2479 } while(true);
2481 if (!m_pStructure->bTestRun) for(i=0;i<m_nParts;i++) if (g_parts[i].isle && m_pStructure->pParts[i].iParent)
2482 RemoveBrokenParent(m_pStructure->pParts[i].iParent-1, nIsles);
2484 for(i=m_nParts-1,j=0; i>=0; i--) if (g_parts[i].isle!=0)
2485 if (nRemoveGeoms+j<CRY_ARRAY_COUNT(idRemoveGeoms))
2486 j++;
2487 else
2488 g_parts[i].isle=0;
2490 epcep.pMeshNew = 0;
2491 epcep.pLastUpdate = 0;
2492 epcep.bInvalid = 0;
2493 epcep.iReason = EventPhysCreateEntityPart::ReasonJointsBroken;
2494 pents = 0;
2495 nIsles &= ~-m_pStructure->bTestRun;
2497 if (m_pWorld->m_vars.breakImpulseScale || m_flags & pef_override_impulse_scale || !pexpl ||
2498 (pexpl && pexpl->forceDeformEntities)) for(i=1;i<nIsles;i++)
2500 for(j=0,epcep.nTotParts=0;j<m_nParts;j++)
2501 epcep.nTotParts += iszero(g_parts[j].isle-i);
2502 if (!epcep.nTotParts)
2503 continue;
2504 epcep.pEntNew = m_pWorld->CreatePhysicalEntity(PE_RIGID,&pp,0,0x5AFE);
2505 asv.v.zero(); asv.w.zero(); t=0;
2506 int ipartSrc;
2508 for(j=i1=0,BBoxNew[0]=m_BBox[1],BBoxNew[1]=m_BBox[0];j<m_nParts;j++) if (g_parts[j].isle==i) {
2509 gpAux.flags = m_parts[j].flags;
2510 gpAux.flagsCollider = m_parts[j].flagsCollider;
2511 if (gpAux.flagsCollider & geom_destroyed_on_break && epcep.nTotParts==1)
2512 gpAux.flags=gpAux.flagsCollider = 0;
2513 gpAux.mass = m_parts[j].mass;
2514 gpAux.pos = m_parts[j].pos;
2515 gpAux.q = m_parts[j].q;
2516 gpAux.scale = m_parts[j].scale;
2517 gpAux.idmatBreakable = m_parts[j].idmatBreakable;
2518 gpAux.minContactDist = m_parts[j].minContactDist;
2519 gpAux.pMatMapping = m_parts[j].pMatMapping!=m_parts[j].pPhysGeom->pMatMapping ? m_parts[j].pMatMapping:0;
2520 gpAux.nMats = m_parts[j].nMats;
2521 if (gpAux.mass<=m_pWorld->m_vars.massLimitDebris) {
2522 if (!is_unused(m_pWorld->m_vars.flagsColliderDebris))
2523 gpAux.flagsCollider = m_pWorld->m_vars.flagsColliderDebris;
2524 gpAux.flags &= m_pWorld->m_vars.flagsANDDebris;
2526 /*if (!(m_parts[j].flags & geom_will_be_destroyed) && m_parts[j].pPhysGeom->pGeom->GetType()==GEOM_VOXELGRID) {
2527 (pMeshNew = new CTriMesh())->Clone((CTriMesh*)m_parts[j].pPhysGeom->pGeom,0);
2528 delete pMeshNew->m_pTree; pMeshNew->m_pTree=0;
2529 pMeshNew->m_flags |= mesh_AABB;
2530 pMeshNew->RebuildBVTree();
2531 m_parts[j].pPhysGeom->pGeom->Release();
2532 m_parts[j].pPhysGeom->pGeom = pMeshNew;
2534 epcep.pEntNew->AddGeometry(m_parts[j].pPhysGeom,&gpAux,i1,1);
2535 if (m_parts[j].pPhysGeomProxy!=m_parts[j].pPhysGeom) {
2536 gpAux.flags |= geom_proxy;
2537 epcep.pEntNew->AddGeometry(m_parts[j].pPhysGeomProxy,&gpAux,i1,1);
2538 gpAux.flags &= ~geom_proxy;
2540 if (m_iSimClass>0) {
2541 pe_status_dynamics sd; sd.ipart=j;
2542 GetStatus(&sd);
2543 asv.v += sd.v*m_parts[j].mass;
2544 asv.w += sd.w*m_parts[j].mass;
2545 t += m_parts[j].mass;
2547 shockwave.ipart = g_parts[j].idx = i1++;
2548 shockwave.iApplyTime = 0;
2549 if (g_parts[j].ijoint0>=nJoints ||
2550 min(min(min(min(m_pStructure->pJoints[g_jointidx[g_parts[j].ijoint0]].maxForcePull,
2551 m_pStructure->pJoints[g_jointidx[g_parts[j].ijoint0]].maxForcePush),
2552 m_pStructure->pJoints[g_jointidx[g_parts[j].ijoint0]].maxForceShift),
2553 m_pStructure->pJoints[g_jointidx[g_parts[j].ijoint0]].maxTorqueBend),
2554 m_pStructure->pJoints[g_jointidx[g_parts[j].ijoint0]].maxTorqueTwist) > 0)
2556 shockwave.impulse = ((m_pStructure->pParts[j].Pext*dt*100+m_pStructure->pParts[j].Fext)*0.6f+Pmax*0.4f)*max(0.1f,m_parts[j].mass*M);
2557 shockwave.angImpulse = ((m_pStructure->pParts[j].Lext*dt*100+m_pStructure->pParts[j].Text)*0.6f+Lmax*0.4f)*max(0.1f,m_parts[j].mass*M);
2558 } else {
2559 shockwave.impulse = m_pStructure->pParts[j].Pext*dt*100;
2560 shockwave.angImpulse = m_pStructure->pParts[j].Lext*dt*100;
2562 if (shockwave.impulse.len2() > sqr(m_parts[j].mass*4.0f))
2563 shockwave.impulse*=(vmax=m_parts[j].mass*4.0f/shockwave.impulse.len()), shockwave.angImpulse*=vmax;
2564 epcep.breakImpulse=shockwave.impulse; epcep.breakAngImpulse=shockwave.angImpulse;
2565 if (!(m_flags & aef_recorded_physics))
2566 epcep.pEntNew->Action(&shockwave,1);
2567 epcep.partidSrc = m_parts[ipartSrc = j].id;
2568 epcep.partidNew = shockwave.ipart;
2569 epcep.pEntNew->GetStatus(&psd); epcep.v = psd.v; epcep.w = psd.w;
2570 m_pWorld->OnEvent(m_pWorld->m_vars.bLogStructureChanges+1,&epcep);
2571 g_parts[j].pent = (CPhysicalEntity*)epcep.pEntNew;
2572 BBoxNew[0] = min(BBoxNew[0], m_parts[j].BBox[0]);
2573 BBoxNew[1] = max(BBoxNew[1], m_parts[j].BBox[1]);
2575 for(j=0;j<m_pStructure->nJoints;j++)
2576 if (!m_pStructure->pJoints[j].bBroken && g_parts[m_pStructure->pJoints[j].ipart[0]].isle==i) {
2577 psj.id = m_pStructure->pJoints[j].id;
2578 psj.partid[0] = g_parts[m_pStructure->pJoints[j].ipart[0]].idx;
2579 psj.partid[1] = g_parts[m_pStructure->pJoints[j].ipart[1]].idx;
2580 psj.pt = m_pStructure->pJoints[j].pt;
2581 psj.n = m_pStructure->pJoints[j].n;
2582 psj.axisx = m_pStructure->pJoints[j].axisx;
2583 psj.maxForcePush = m_pStructure->pJoints[j].maxForcePush;
2584 psj.maxForcePull = m_pStructure->pJoints[j].maxForcePull;
2585 psj.maxForceShift = m_pStructure->pJoints[j].maxForceShift;
2586 psj.maxTorqueBend = m_pStructure->pJoints[j].maxTorqueBend;
2587 psj.maxTorqueTwist = m_pStructure->pJoints[j].maxTorqueTwist;
2588 psj.limitConstraint = m_pStructure->pJoints[j].limitConstr;
2589 psj.dampingConstraint = m_pStructure->pJoints[j].dampingConstr;
2590 psj.bBreakable = m_pStructure->pJoints[j].bBreakable & 1;
2591 psj.bConstraintWillIgnoreCollisions = m_pStructure->pJoints[j].bBreakable>>1^1;
2592 psj.bDirectBreaksOnly = m_pStructure->pJoints[j].bBreakable>>2;
2593 psj.szSensor = m_pStructure->pJoints[j].size;
2594 epcep.pEntNew->SetParams(&psj,1);
2595 ((CPhysicalEntity*)epcep.pEntNew)->m_pStructure->bModified = 1;
2597 j = ipartSrc;
2598 if (i1>0 && m_pStructure->pParts[j].initialVel.GetLengthSquared()!=0.f) {
2599 // override the initial velocity
2600 asv.v = m_pStructure->pParts[j].initialVel;
2601 asv.w = m_pStructure->pParts[j].initialAngVel;
2602 m_pStructure->pParts[j].initialVel.zero();
2603 m_pStructure->pParts[j].initialAngVel.zero();
2604 epcep.pEntNew->Action(&asv,1);
2605 } else {
2606 if (m_iSimClass*t>0) {
2607 asv.v*=(t=1.0f/t); asv.w*=t;
2608 epcep.pEntNew->Action(&asv,1);
2612 if (!(m_flags & aef_recorded_physics)) {
2613 if (!pents)
2614 iter = m_pWorld->GetEntitiesAround(m_BBox[0]-Vec3(0.1f),m_BBox[1]+Vec3(0.1f),pents,ent_rigid|ent_sleeping_rigid|ent_independent);
2615 BBoxNew[0] -= Vec3(m_pWorld->m_vars.maxContactGap*5);
2616 BBoxNew[1] += Vec3(m_pWorld->m_vars.maxContactGap*5); // cppcheck-suppress nullPointer
2617 for(j=iter-1; j>=0; j--) if (AABB_overlap(pents[j]->m_BBox, BBoxNew)) // cppcheck-suppress nullPointer
2618 pents[j]->OnNeighbourSplit(this,(CPhysicalEntity*)epcep.pEntNew);
2622 for(i=0;i<m_pStructure->nJoints;i++) if (m_pStructure->pJoints[i].bBroken) {
2623 for(j=0;j<2;j++) if ((i0=m_pStructure->pJoints[i].ipart[j])>=0 && m_parts[i0].flags & geom_manually_breakable) {
2624 EventPhysCollision epc;
2625 epc.pEntity[0]=&g_StaticPhysicalEntity; epc.pForeignData[0]=0; epc.iForeignData[0]=0;
2626 epc.vloc[1].zero(); epc.mass[0] = 1E10f;
2627 epc.partid[0]=0; epc.penetration=epc.normImpulse=0;
2628 epc.pt = (m_parts[i0].BBox[0]+m_parts[i0].BBox[1])*0.5f;
2629 epc.pEntity[1] = g_parts[i0].pent; epc.pForeignData[1] = g_parts[i0].pent->m_pForeignData;
2630 epc.iForeignData[1] = g_parts[i0].pent->m_iForeignData;
2631 m_parts[i0].pPhysGeom->pGeom->GetBBox(&bbox);
2632 epc.n.zero()[idxmin3(bbox.size)] = 1;
2633 epc.n = m_qrot*(m_parts[i0].q*(epc.n*bbox.Basis));
2634 epc.vloc[0] = epc.n*-4.0f;
2635 epc.mass[0]=epc.mass[1] = m_parts[i0].mass;
2636 epc.radius = (m_BBox[1].x+m_BBox[1].y+m_BBox[1].z-m_BBox[0].x-m_BBox[0].y-m_BBox[0].z)*2;
2637 epc.partid[1] = g_parts[i0].pent==this ? m_parts[i0].id:g_parts[i0].idx;
2638 epc.idmat[0] = -2;
2639 for(i1=m_parts[i0].pPhysGeom->pGeom->GetPrimitiveCount()-1; i1>=0; i1--) {
2640 epc.idmat[1] = GetMatId(m_parts[i0].pPhysGeom->pGeom->GetPrimitiveId(i1,0x40), i0);
2641 if (m_pWorld->m_SurfaceFlagsTable[epc.idmat[1]] & sf_manually_breakable)
2642 break;
2644 m_pWorld->OnEvent(pef_log_collisions, &epc);
2646 if (m_pStructure->pJoints[i].itens<2 && m_pStructure->pJoints[i].limitConstr.z>0 &&
2647 g_parts[m_pStructure->pJoints[i].ipart[0]].pent!=g_parts[m_pStructure->pJoints[i].ipart[1]].pent)
2649 j = isneg(g_parts[m_pStructure->pJoints[i].ipart[0]].isle-g_parts[m_pStructure->pJoints[i].ipart[1]].isle);
2650 pe_action_add_constraint aac;
2651 aac.flags = local_frames | constraint_ignore_buddy&~-isneg(-(m_pStructure->pJoints[i].bBreakable&2));
2652 aac.maxBendTorque = m_pStructure->pJoints[i].limitConstr.z;
2653 aac.maxPullForce = min(m_pStructure->pJoints[i].maxForcePull, m_pStructure->pJoints[i].maxForcePush);
2654 aac.partid[0] = g_parts[m_pStructure->pJoints[i].ipart[j]].idx;
2655 aac.partid[1] = g_parts[m_pStructure->pJoints[i].ipart[j^1]].pent==this ?
2656 m_parts[m_pStructure->pJoints[i].ipart[j^1]].id : g_parts[m_pStructure->pJoints[i].ipart[j^1]].idx;
2657 aac.pBuddy = g_parts[m_pStructure->pJoints[i].ipart[j^1]].pent;
2658 aac.pt[0]=aac.pt[1] = m_pStructure->pJoints[i].pt;
2659 aac.qframe[0]=aac.qframe[1] = quaternionf(
2660 Matrix33(m_pStructure->pJoints[i].axisx, m_pStructure->pJoints[i].n^m_pStructure->pJoints[i].axisx, m_pStructure->pJoints[i].n));
2661 aac.sensorRadius = m_pStructure->pJoints[i].size;
2662 if (m_pStructure->pJoints[i].limitConstr.y > m_pStructure->pJoints[i].limitConstr.x) {
2663 aac.yzlimits[0]=aac.yzlimits[1]=aac.xlimits[0]=aac.xlimits[1] = 0;
2664 *(Vec2*)(m_pStructure->pJoints[i].itens ? aac.yzlimits:aac.xlimits) = Vec2(m_pStructure->pJoints[i].limitConstr);
2665 aac.qframe[0]=aac.qframe[1] = aac.qframe[0]*quaternionf(Matrix33(Vec3(0,0,1),Vec3(1,0,0),Vec3(0,1,0)));
2666 aac.damping = m_pStructure->pJoints[i].dampingConstr;
2667 } else if (m_pStructure->pJoints[i].dampingConstr>0) {
2668 pe_simulation_params psp; psp.damping = m_pStructure->pJoints[i].dampingConstr;
2669 g_parts[m_pStructure->pJoints[i].ipart[j]].pent->SetParams(&psp,1);
2671 g_parts[m_pStructure->pJoints[i].ipart[j]].pent->Action(&aac,1);
2672 pe_params_flags pf;
2673 pf.flagsAND = ~pef_never_break;
2674 g_parts[m_pStructure->pJoints[i].ipart[j]].pent->SetParams(&pf,1);
2675 aac.pBuddy->SetParams(&pf,1);
2679 if (m_pWorld->m_vars.bLogLatticeTension && (bBroken || impTot>0 && m_pWorld->m_timePhysics>m_pStructure->minSnapshotTime)) {
2680 if (bBroken)
2681 m_pStructure->minSnapshotTime=m_pWorld->m_timePhysics+2.0f;
2682 m_pStructure->nPrevJoints = nJoints0;
2683 m_pStructure->prevdt = dt;
2684 for(i=0;i<nJoints;i++) {
2685 m_pStructure->pJoints[g_joints[i].idx].tension = g_jointsDbg[i].tension.x;
2686 m_pStructure->pJoints[g_joints[i].idx].itens = g_jointsDbg[i].itens;
2689 m_pStructure->nLastUsedJoints = nJoints;
2691 // move broken or detached joints to the end of the list
2692 for(i=iter=0;i<m_pStructure->nJoints & ~-m_pStructure->bTestRun;i++)
2693 if (m_pStructure->pJoints[i].bBroken+g_parts[m_pStructure->pJoints[i].ipart[0]].isle > 0) {
2694 if (m_pStructure->pJoints[i].bBroken) {
2695 epjb.idJoint = m_pStructure->pJoints[i].id;
2696 epjb.pt = m_qrot*m_pStructure->pJoints[i].pt+m_pos;
2697 epjb.n = m_qrot*m_pStructure->pJoints[i].n;
2698 i0 = (m_pStructure->pJoints[i].ipart[0]|m_pStructure->pJoints[i].ipart[1])>=0 &&
2699 m_parts[m_pStructure->pJoints[i].ipart[0]].pPhysGeom->V*cube(m_parts[m_pStructure->pJoints[i].ipart[0]].scale) <
2700 m_parts[m_pStructure->pJoints[i].ipart[1]].pPhysGeom->V*cube(m_parts[m_pStructure->pJoints[i].ipart[1]].scale);
2701 for(j=0;j<2;j++) if (m_pStructure->pJoints[i].ipart[j]>=0) {
2702 epjb.partid[j^i0] = m_parts[m_pStructure->pJoints[i].ipart[j]].id;
2703 epjb.partmat[j^i0] = GetMatId(m_parts[m_pStructure->pJoints[i].ipart[j]].pPhysGeom->pGeom->GetPrimitiveId(0,0x40),
2704 m_pStructure->pJoints[i].ipart[j]);
2705 } else
2706 epjb.partid[j^i0] = epjb.partmat[j^i0] = -1;
2707 m_pWorld->OnEvent(m_pWorld->m_vars.bLogStructureChanges+1,&epjb);
2708 ++iter;
2710 SStructuralJoint sj = m_pStructure->pJoints[i];
2711 m_pStructure->pJoints[i] = m_pStructure->pJoints[--m_pStructure->nJoints]; --i;
2712 m_pStructure->pJoints[m_pStructure->nJoints] = sj;
2714 i = m_nParts-1 | -m_pStructure->bTestRun;
2715 next_eprep:
2716 for(j=ihead=0,eprep.idOffs=0,i0=-1; i>=0; i--) {
2717 m_pStructure->pParts[i].Pext.zero(); m_pStructure->pParts[i].Lext.zero();
2718 m_pStructure->pParts[i].Fext.zero(); m_pStructure->pParts[i].Text.zero();
2719 if (g_parts[i].isle!=0 && nRemoveGeoms<CRY_ARRAY_COUNT(idRemoveGeoms)) {
2720 i0 += i-i0 & i0>>31;
2721 if (m_parts[i].id-eprep.idOffs>=sizeof(eprep.partIds)*8) {
2722 for(i1=i0,eprep.idOffs=1<<30;i1>i;i1--) if (g_parts[i1].isle!=0)
2723 ihead=max(ihead,m_parts[i1].id), eprep.idOffs=min(eprep.idOffs,m_parts[i1].id);
2724 if (max(ihead,m_parts[i].id)-min(eprep.idOffs,m_parts[i].id) >= sizeof(eprep.partIds)*8)
2725 break;
2726 eprep.idOffs = min(eprep.idOffs,m_parts[i].id);
2728 idRemoveGeoms[nRemoveGeoms] = m_parts[i].id; pRemoveGeoms[nRemoveGeoms++] = m_parts[i].pPhysGeom; j++;
2731 if (j | iter) {
2732 memset(eprep.partIds, 0, sizeof(eprep.partIds));
2733 for(i1=1;i1<=j;i1++) {
2734 int idloc = idRemoveGeoms[nRemoveGeoms-i1]-eprep.idOffs;
2735 eprep.partIds[idloc>>5] |= 1<<idloc;
2737 m_pWorld->OnEvent(m_pWorld->m_vars.bLogStructureChanges+1,&eprep);
2738 if (i>=0)
2739 goto next_eprep;
2742 m_pStructure->bModified += bBroken;
2743 if (m_nParts-nRemoveGeoms==0)
2744 bBroken = 0;
2745 if (bBroken!=m_pStructure->nLastBrokenJoints)
2746 flags = geom_structure_changes;
2747 else if (flags & geom_structure_changes)
2748 m_pStructure->nLastBrokenJoints = bBroken;
2749 if (m_pStructure->idpartBreakOrg>=0) {
2750 flags &= ~geom_structure_changes;
2751 m_pStructure->idpartBreakOrg = -1;
2752 goto SkipMeshUpdates;
2756 if ((m_timeStructUpdate+=time_interval) >= m_pWorld->m_vars.tickBreakable) {
2757 if (m_pStructure) for(m_iLastIdx=i=0;i<m_nParts;i++)
2758 m_iLastIdx = max(m_iLastIdx, m_parts[i].id+1);
2759 epcep.iReason = EventPhysCreateEntityPart::ReasonMeshSplit;
2760 for(i=0;i<m_nParts;i++) if (m_parts[i].flags & geom_structure_changes) {
2761 epum.partid = m_parts[i].id;
2762 epum.pMesh = m_parts[i].pPhysGeomProxy->pGeom;
2763 nPlanes = min(m_nGroundPlanes, (int)(CRY_ARRAY_COUNT(ground)));
2764 for(j=0;j<nPlanes;j++) {
2765 ground[j].origin = (m_ground[j].origin-m_parts[i].pos)*m_parts[i].q;
2766 if (m_parts[i].scale!=1.0f)
2767 ground[j].origin /= m_parts[i].scale;
2768 ground[j].n = m_ground[j].n*m_parts[i].q;
2770 if (m_pStructure && !m_pStructure->nJoints && m_pStructure->bTestRun && !nPlanes) {
2771 ground[0].origin = (m_parts[i].BBox[0]+Vec3(0,0,1)*m_pWorld->m_vars.maxContactGap-(m_pos+m_qrot*m_parts[i].pos))*m_parts[i].q;
2772 if (m_parts[i].scale!=1.0f)
2773 ground[0].origin /= m_parts[i].scale;
2774 ground[0].n = Vec3(0,0,1)*m_parts[i].q*m_qrot;
2775 nPlanes = 1;
2778 if (m_updStage==0) {
2779 if (m_parts[i].pLattice && m_pExpl) {
2780 expl.epicenter=expl.epicenterImp = ((m_pExpl->center-m_pos)*m_qrot-m_parts[i].pos)*m_parts[i].q;
2781 expl.impulsivePressureAtR = max(0.0f,m_pExpl->kr)*m_parts[i].pLattice->m_density*
2782 m_parts[i].pPhysGeom->V*cube(m_parts[i].scale)/m_parts[i].mass;
2783 expl.r = 1.0f;
2784 expl.rmin = m_pExpl->rmin;
2785 expl.rmax = 1E10f;
2786 if (m_parts[i].scale!=1.0f) {
2787 t = 1.0f/m_parts[i].scale;
2788 expl.rmin*=t; expl.r*=t; expl.epicenter*=t; expl.epicenterImp*=t;
2791 if (m_parts[i].pLattice && m_parts[i].pLattice->CheckStructure(time_interval,(gravity*m_qrot)*m_parts[i].q, ground,nPlanes,
2792 m_nUpdTicks<2 && m_pExpl ? &expl:0, m_pWorld->m_vars.nMaxLatticeIters,m_pWorld->m_vars.bLogLatticeTension))
2794 epum.pMesh->Lock(0); epum.pLastUpdate = (bop_meshupdate*)epum.pMesh->GetForeignData(DATA_MESHUPDATE);
2795 for(; epum.pLastUpdate && epum.pLastUpdate->next; epum.pLastUpdate=epum.pLastUpdate->next);
2796 epum.pMesh->Unlock(0);
2797 m_pWorld->OnEvent(m_pWorld->m_vars.bLogStructureChanges+1,&epum);
2798 } else
2799 m_parts[i].flags &= ~geom_structure_changes;
2800 if (m_parts[i].pLattice && m_pWorld->m_pLog && m_pWorld->m_vars.bLogLatticeTension) {
2801 t = m_parts[i].pLattice->GetLastTension(j);
2802 m_pWorld->m_pLog->LogToConsole("Lattice tension: %f (%s)", t,
2803 j==LPush?"push":(j==LPull?"pull":(j==LShift?"shift":(j==LBend?"bend":"twist"))));
2805 } else {
2806 if (pMeshNew = ((CTriMesh*)m_parts[i].pPhysGeomProxy->pGeom)->SplitIntoIslands(ground,nPlanes,GetType()==PE_RIGID)) {
2807 nMeshSplits++;
2808 if (m_parts[i].pLattice) {
2809 for(j=0,pMesh=pMeshNew; pMesh; pMesh=(CTriMesh*)pMesh->GetForeignData(-2),j++);
2810 SIZEOF_ARRAY_OK
2811 if (j>CRY_ARRAY_COUNT(pChunkMeshesBuf)) {
2812 pChunkMeshes = new CTriMesh*[j];
2813 pChunkLattices = new CTetrLattice*[j];
2815 for(j=0,pMesh=pMeshNew; pMesh; pMesh=(CTriMesh*)pMesh->GetForeignData(-2),j++)
2816 pChunkMeshes[j] = pMesh;
2817 m_parts[i].pLattice->Split(pChunkMeshes,j,pChunkLattices);
2820 gp.pos = m_parts[i].pos;
2821 gp.q = m_parts[i].q;
2822 gp.scale = m_parts[i].scale;
2823 gp.pLattice = m_parts[i].pLattice;
2824 gp.pMatMapping = m_parts[i].pMatMapping!=m_parts[i].pPhysGeom->pMatMapping ? m_parts[i].pMatMapping:0;
2825 /*if (m_parts[i].pMatMapping!=m_parts[i].pPhysGeom->pMatMapping) {
2826 pOrgMapping = gp.pMatMapping = m_parts[i].pMatMapping; m_parts[i].pMatMapping = 0;
2827 } else
2828 gp.pMatMapping = pOrgMapping = 0;*/
2829 gp.nMats = m_parts[i].nMats;
2830 pgeom0 = m_parts[i].pPhysGeomProxy;
2831 //t = m_parts[i].mass/((V0=pgeom0->V)*cube(m_parts[i].scale));
2832 //ppt.ipart=i; ppt.density=0; SetParams(&ppt);
2833 V0 = pgeom0->V;
2834 float Imax0 = max(max(pgeom0->Ibody.x,pgeom0->Ibody.y),pgeom0->Ibody.z);
2835 pgeom0->pGeom->CalcPhysicalProperties(pgeom0);
2836 t = max(max(pgeom0->Ibody.x,pgeom0->Ibody.y),pgeom0->Ibody.z)*m_pWorld->m_vars.breakageMinAxisInertia;
2837 pgeom0->Ibody.x = max(pgeom0->Ibody.x, t);
2838 pgeom0->Ibody.y = max(pgeom0->Ibody.y, t);
2839 pgeom0->Ibody.z = max(pgeom0->Ibody.z, t);
2840 pgeom0->pGeom->GetBBox(&bbox);
2841 org = bbox.Basis*(pgeom0->origin-bbox.center);
2842 if (m_iSimClass>0 &&
2843 (max(max(fabs_tpl(org.x)-bbox.size.x,fabs_tpl(org.y)-bbox.size.y),fabs_tpl(org.z)-bbox.size.z)>0 ||
2844 min(min(min(pgeom0->V,pgeom0->Ibody.x),pgeom0->Ibody.y),pgeom0->Ibody.z)<0 ||
2845 pgeom0->V<V0*0.002f))
2847 //((CTriMesh*)pgeom0->pGeom)->Empty();
2848 pgeom0->V=0; pgeom0->Ibody.zero();
2849 m_parts[i].flags |= geom_invalid; epum.bInvalid = 1;
2850 } else
2851 epum.bInvalid = 0;
2852 //ppt.density=t; SetParams(&ppt);
2854 for(j=0; pMeshNew; pMeshNew=pMeshNext,j++) {
2855 pMeshNext = (CTriMesh*)pMeshNew->GetForeignData(-2);
2856 pMeshNew->SetForeignData(0,0);
2857 pgeom = m_pWorld->RegisterGeometry(pMeshNew,pgeom0->surface_idx,pgeom0->pMatMapping,pgeom0->nMats);
2858 pMeshNew->GetBBox(&bbox);
2859 org = bbox.Basis*(pgeom->origin-bbox.center);
2860 if (max(max(fabs_tpl(org.x)-bbox.size.x,fabs_tpl(org.y)-bbox.size.y),fabs_tpl(org.z)-bbox.size.z)>0 ||
2861 min(min(min(pgeom->V,pgeom->Ibody.x),pgeom->Ibody.y),pgeom->Ibody.z)<0 ||
2862 pgeom->V<V0*0.002f)
2864 gp.flags=gp.flagsCollider=0; gp.idmatBreakable=-1;
2865 gp.density=0, epcep.bInvalid=1;
2866 } else {
2867 gp.flags = m_parts[i].flags & ~geom_structure_changes;
2868 gp.flagsCollider = m_parts[i].flagsCollider;
2869 gp.idmatBreakable = m_parts[i].idmatBreakable;
2870 gp.density = m_parts[i].mass/(V0*cube(m_parts[i].scale));
2871 epcep.bInvalid = 0;
2873 t = max(max(pgeom->Ibody.x,pgeom->Ibody.y),pgeom->Ibody.z)*V0 / (pgeom->V*Imax0);
2874 gp.minContactDist = max(m_pWorld->m_vars.maxContactGap*2, m_parts[i].minContactDist*sqrt_fast_tpl(t));
2875 gp.pLattice = m_parts[i].pLattice ? pChunkLattices[j] : 0;
2876 if (!m_pStructure) {
2877 epcep.pEntNew = m_pWorld->CreatePhysicalEntity(PE_RIGID,&pp,0,0x5AFE);
2878 epcep.pEntNew->AddGeometry(pgeom,&gp,-1,1);
2879 pgeom->nRefCount--;
2880 epcep.partidNew = 0;
2881 } else {
2882 epcep.pEntNew = this;
2883 pAddGeoms[nAddGeoms]=pgeom; gpAddGeoms[nAddGeoms]=gp;
2884 bGeomOverflow |= isneg((int)(CRY_ARRAY_COUNT(gpAddGeoms))-nAddGeoms-2);
2885 nAddGeoms += 1-bGeomOverflow;
2886 //nAddGeoms=min(nAddGeoms+1, CRY_ARRAY_COUNT(gpAddGeoms));
2887 epcep.partidNew = iLastIdx+j;
2890 gwd.R = Matrix33(m_parts[i].q);
2891 gwd.offset = m_parts[i].pos;
2892 gwd.scale = m_parts[i].scale;
2893 ip.bStopAtFirstTri=ip.bNoAreaContacts=ip.bNoBorder = true;
2895 for(i1=0;i1<m_nParts;i1++) if (m_parts[i1].idmatBreakable<0) {
2896 m_parts[i1].maxdim = m_parts[i1].pPhysGeom->V;
2897 if (m_parts[i1].pPhysGeom->pGeom->GetType()==GEOM_TRIMESH &&
2898 ((CTriMesh*)m_parts[i1].pPhysGeom->pGeom)->BuildIslandMap()>1 && !m_parts[i1].pLattice)
2899 { // separate non-breakable meshes into islands; store island list in part's pLattice
2900 if (!(m_parts[i1].flags & geom_can_modify))
2901 m_pWorld->ClonePhysGeomInEntity(this,i1,(new CTriMesh())->Clone((CTriMesh*)m_parts[i1].pPhysGeom->pGeom,0));
2902 m_parts[i1].pLattice = (CTetrLattice*)((CTriMesh*)m_parts[i1].pPhysGeom->pGeom)->SplitIntoIslands(0,0,1);
2903 m_parts[i1].pPhysGeom->pGeom->CalcPhysicalProperties(m_parts[i1].pPhysGeom);
2907 if (!m_pStructure) {
2908 // find non-breakable parts that should be moved to the new entity
2909 int partId = m_parts[i].id; // new foliage proxies will have ids main id+1024*n
2910 for(i1=0;i1<m_nParts;i1++) if (i1!=i) {
2911 pMeshIsland = !(m_parts[i1].flags & geom_removed) ? m_parts[i1].pPhysGeom->pGeom :
2912 (m_parts[i1].idmatBreakable<0 ? (CTriMesh*)m_parts[i1].pLattice : 0);
2913 partId = max(partId, m_parts[i1].id);
2914 pMeshIslandPrev = 0;
2915 gwdAux.R = Matrix33(m_parts[i1].q);
2916 gwdAux.offset = m_parts[i1].pos;
2917 gwdAux.scale = m_parts[i1].scale;
2918 if (pMeshIsland) do {
2919 pMeshIsland->GetBBox(&bbox);
2920 t = m_parts[i].scale==1.0f ? 1.0f:1.0f/m_parts[i].scale;
2921 bbox.center = ((m_parts[i1].q*bbox.center*m_parts[i1].scale+m_parts[i1].pos-m_parts[i].pos)*m_parts[i].q)*t;
2922 //bbox.Basis *= Matrix33(!m_parts[i1].q*m_parts[i].q);
2923 //bbox.size *= m_parts[i1].scale*t;
2924 //boxGeom.CreateBox(&bbox);
2925 pMeshNew->GetBBox(&bbox1);
2926 org = bbox.size-(bbox.Basis*(gwd.R*bbox1.center*gwd.scale+gwd.offset-bbox.center)).abs();
2927 //bBroken = 0;//min(min(org.x,org.y),org.z)>0;
2928 bBroken = pMeshIsland->PointInsideStatus(((gwdAux.R*bbox1.center*gwdAux.scale+gwdAux.offset-gwd.offset)*gwd.R)*t);
2929 bBroken |= pMeshNew->Intersect(pMeshIsland, &gwd,&gwdAux, &ip, pcontacts)!=0;
2930 if (bBroken) {
2931 FillGeomParams(gpAux, m_parts[i1]);
2932 gpAux.mass *= (t=pMeshIsland->GetVolume()/m_parts[i1].maxdim);
2933 gpAux.minContactDist = max(m_pWorld->m_vars.maxContactGap*2, gpAux.minContactDist*cubert_approx(t));
2934 if (pMeshIsland==m_parts[i1].pPhysGeom->pGeom) {
2935 if (epcep.pEntNew && !epcep.bInvalid)
2936 epcep.pEntNew->AddGeometry(m_parts[i1].pPhysGeom,&gpAux,m_parts[i1].id,1);
2937 m_parts[i1].flags |= geom_removed; //m_parts[i1].idmatBreakable = -10;
2938 } else {
2939 pgeom1 = m_pWorld->RegisterGeometry(pMeshIsland, m_parts[i1].pPhysGeom->surface_idx,
2940 m_parts[i1].pPhysGeom->pMatMapping,m_parts[i1].pPhysGeom->nMats);
2941 if (epcep.pEntNew && !epcep.bInvalid)
2942 epcep.pEntNew->AddGeometry(pgeom1,&gpAux,partId+=1024,1);
2943 CryInterlockedDecrement((volatile int*) &pgeom1->nRefCount);
2944 if (pMeshIslandPrev)
2945 pMeshIslandPrev->SetForeignData(pMeshIsland->GetForeignData(),-2);
2946 else
2947 m_parts[i1].pLattice = (CTetrLattice*)pMeshIsland->GetForeignData(-2);
2949 if (pmu = (bop_meshupdate*)pMeshNew->GetForeignData(DATA_MESHUPDATE)) {
2950 ReallocateList(pmu->pMovedBoxes, pmu->nMovedBoxes, pmu->nMovedBoxes+1);
2951 pmu->pMovedBoxes[pmu->nMovedBoxes++] = bbox;
2954 if (pMeshIsland==m_parts[i1].pPhysGeom->pGeom)
2955 pMeshIsland = m_parts[i1].idmatBreakable<0 ? (CTriMesh*)m_parts[i1].pLattice : 0;
2956 else {
2957 pMeshIslandPrev = pMeshIsland;
2958 pMeshIsland = (CTriMesh*)pMeshIsland->GetForeignData(-2);
2960 } while(pMeshIsland);
2961 if (m_parts[i1].idmatBreakable<0) {
2962 m_parts[i1].mass *= (t=m_parts[i1].pPhysGeom->V/m_parts[i1].maxdim);
2963 m_parts[i1].minContactDist = max(m_pWorld->m_vars.maxContactGap*2, m_parts[i1].minContactDist*cubert_approx(t));
2966 } else if (!bGeomOverflow) {
2967 // find joints that must be deleted or re-assigned to the new part
2968 for(i1=0; i1<m_pStructure->nJoints; i1++) if (m_pStructure->pJoints[i1].ipart[0]==i || m_pStructure->pJoints[i1].ipart[1]==i) {
2969 sphere sph;
2970 sph.center = m_pStructure->pJoints[i1].pt; sph.r = m_pStructure->pJoints[i1].size*0.5f;
2971 sphGeom.CreateSphere(&sph);
2972 //aray.m_ray.dir = (aray.m_dirn = m_pStructure->pJoints[i1].n)*t;
2973 //aray.m_ray.origin = m_pStructure->pJoints[i1].pt-aray.m_ray.dir*0.5f;
2974 if (pMeshNew->Intersect(&sphGeom,&gwd,0,0,pcontacts)) { // joint touches the new mesh
2975 m_pStructure->pJoints[i1].ipart[iszero(m_pStructure->pJoints[i1].ipart[1]-i)] = m_nParts+j;
2976 m_pStructure->bModified++;
2978 //else if (!m_parts[i].pPhysGeomProxy->pGeom->Intersect(&aray,&gwd,0,0,pcontacts)) // joint doesn't touch neither new nor old
2979 // m_pStructure->pJoints[i1] = m_pStructure->pJoints[--m_pStructure->nJoints], i1--;
2983 if (epcep.pEntNew && !epcep.bInvalid) {
2984 org = m_pos+m_qrot*(m_parts[i].pos+m_parts[i].q*pgeom->origin);
2985 if (m_iSimClass>0) {
2986 pe_status_dynamics sd; sd.ipart=i;
2987 GetStatus(&sd);
2988 asv.v = sd.v+(sd.w^org-sd.centerOfMass);
2989 asv.w = sd.w;
2990 epcep.pEntNew->Action(&asv,1);
2993 // add impulse from the explosion
2994 if (m_nUpdTicks==0 && m_pExpl) {
2995 gwd.R = Matrix33(m_qrot*m_parts[i].q);
2996 gwd.offset = m_pos + m_qrot*m_parts[i].pos;
2997 gwd.scale = m_parts[i].scale;
2998 shockwave.impulse.zero(); shockwave.angImpulse.zero();
2999 if (m_pExpl->kr>0)
3000 pgeom->pGeom->CalcVolumetricPressure(&gwd, m_pExpl->center,m_pExpl->kr,m_pExpl->rmin,
3001 gwd.R*pgeom->origin*gwd.scale+gwd.offset, shockwave.impulse,shockwave.angImpulse);
3002 else if (m_pExpl->kr<0) {
3003 MARK_UNUSED shockwave.point;
3004 shockwave.impulse = m_pExpl->dir*(pgeom->V*cube(gwd.scale)*gp.density);
3005 n = m_pExpl->center-org;
3006 if (n.len2()>0) {
3007 shockwave.impulse -= n*((n*shockwave.impulse)/n.len2());
3008 quaternionf q = m_qrot*m_parts[i].q*pgeom->q;
3009 shockwave.angImpulse = q*(Diag33(pgeom->Ibody)*(!q*(m_pExpl->dir^n)))*(cube(gwd.scale)*gp.density/n.len2());
3012 shockwave.ipart = 0;
3013 epcep.breakImpulse=shockwave.impulse; epcep.breakAngImpulse=shockwave.angImpulse;
3014 shockwave.iApplyTime = (epcep.pEntNew!=this)*2;
3015 epcep.pEntNew->Action(&shockwave, 1);//shockwave.iApplyTime>>1^1);
3016 epcep.breakSize = m_pExpl->rmin;
3017 epcep.cutPtLoc[0]=epcep.cutPtLoc[1] = (m_pExpl->center-m_pos)*m_qrot;
3018 epcep.cutDirLoc[0]=epcep.cutDirLoc[1] = m_pExpl->dir*m_qrot;
3021 //if (m_parts[i].flags & geom_break_approximation && ((CPhysicalEntity*)epcep.pEntNew)->m_nParts)
3022 // ((CPhysicalEntity*)epcep.pEntNew)->CapsulizePart(0);
3023 if (m_parts[i].flags & geom_break_approximation && ((CPhysicalEntity*)epcep.pEntNew)->m_nParts &&
3024 (nJoints=((CPhysicalEntity*)epcep.pEntNew)->CapsulizePart(0)))
3026 CPhysicalEntity *pent = (CPhysicalEntity*)epcep.pEntNew;
3027 Vec3 ptEnd[2];
3028 capsule *pcaps = (capsule*)pent->m_parts[pent->m_nParts-nJoints].pPhysGeom->pGeom->GetData();
3029 epcep.cutRadius = pcaps->r*pent->m_parts[pent->m_nParts-nJoints].scale;
3030 ptEnd[0]=ptEnd[1]=epcep.cutPtLoc[0]=epcep.cutPtLoc[1] = pent->m_parts[pent->m_nParts-nJoints].pos -
3031 pent->m_parts[pent->m_nParts-nJoints].q*Vec3(0,0,pcaps->hh+pcaps->r);
3032 epcep.cutDirLoc[1] = -(epcep.cutDirLoc[0] = pent->m_parts[pent->m_nParts-nJoints].q*(n=pcaps->axis));
3033 if (t=((CTriMesh*)m_parts[i].pPhysGeom->pGeom)->GetIslandDisk(100, ((epcep.cutPtLoc[0]-m_parts[i].pos)*m_parts[i].q)/m_parts[i].scale,
3034 epcep.cutPtLoc[0],n,vmax))
3036 epcep.cutRadius = t*m_parts[i].scale;
3037 epcep.cutPtLoc[0] = m_parts[i].q*epcep.cutPtLoc[0]*m_parts[i].scale + m_parts[i].pos;
3038 epcep.cutDirLoc[0] = m_parts[i].q*n;
3039 ptEnd[0] = epcep.cutPtLoc[0] + epcep.cutDirLoc[0]*(vmax*m_parts[i].scale);
3041 if (t=pMeshNew->GetIslandDisk(100, ((epcep.cutPtLoc[1]-m_parts[i].pos)*m_parts[i].q)/m_parts[i].scale,
3042 epcep.cutPtLoc[1],n,vmax))
3044 epcep.cutRadius = epcep.cutRadius<t*m_parts[i].scale ? epcep.cutRadius : t*m_parts[i].scale;
3045 epcep.cutPtLoc[1] = m_parts[i].q*epcep.cutPtLoc[1]*m_parts[i].scale + m_parts[i].pos;
3046 epcep.cutDirLoc[1] = m_parts[i].q*n;
3047 ptEnd[1] = epcep.cutPtLoc[1] + epcep.cutDirLoc[1]*(vmax*m_parts[i].scale);
3050 if (m_iSimClass==0 && !m_pWorld->m_vars.bMultiplayer &&
3051 (m_parts[i].flags & (geom_constraint_on_break|geom_colltype_vehicle))==(geom_constraint_on_break|geom_colltype_vehicle))
3053 pe_action_add_constraint aac;
3054 aac.pBuddy = this; aac.id = 1000000;
3055 aac.pt[0] = ptEnd[1]; aac.pt[1] = ptEnd[0];
3056 //aac.pt[1] = aac.pt[0]-pent->m_qrot*epcep.cutDirLoc[0]*(pcaps->r*pent->m_parts[pent->m_nParts-nJoints].scale);
3057 aac.qframe[0]=aac.qframe[1] =
3058 pent->m_qrot*pent->m_parts[pent->m_nParts-nJoints].q*Quat::CreateRotationV0V1(Vec3(1,0,0),pcaps->axis);
3059 aac.partid[0] = pent->m_parts[pent->m_nParts-nJoints].id;
3060 aac.partid[1] = m_parts[i].id;
3061 aac.xlimits[0]=aac.xlimits[1] = 0;
3062 aac.yzlimits[0] = 0; aac.yzlimits[1] = 1.1f;
3063 aac.damping = 1;
3064 aac.maxBendTorque = m_parts[i].mass*0.001f;
3065 //aac.maxPullForce = m_parts[i].mass*10.0f;
3066 aac.flags = constraint_ignore_buddy|local_frames;
3067 aac.sensorRadius = 0.5f+pcaps->r;
3068 pent->Action(&aac);
3069 m_parts[i].flags &= ~geom_constraint_on_break;
3070 } else
3071 epcep.cutDirLoc[1].zero();
3073 if (pmu) {
3074 pe_simulation_params sp;
3075 sp.damping = 1.5f;
3076 epcep.pEntNew->SetParams(&sp);
3077 pe_action_awake aa;
3078 aa.minAwakeTime = 2.0f;
3079 epcep.pEntNew->Action(&aa);
3083 epcep.partidSrc = m_parts[i].id;
3084 epcep.pMeshNew = pMeshNew;
3085 epcep.nTotParts = 1;
3086 epcep.pLastUpdate = (bop_meshupdate*)epcep.pMeshNew->GetForeignData(DATA_MESHUPDATE);
3087 for(; epcep.pLastUpdate && epcep.pLastUpdate->next; epcep.pLastUpdate=epcep.pLastUpdate->next);
3088 epcep.pEntNew->GetStatus(&psd); epcep.v = psd.v; epcep.w = psd.w;
3089 m_pWorld->OnEvent(m_pWorld->m_vars.bLogStructureChanges+1,&epcep);
3091 pMeshNew->GetBBox(&bbox1);
3092 bbox.Basis *= Matrix33(!m_parts[i].q*!m_qrot);
3093 sz = (bbox1.size*bbox1.Basis.Fabs())*m_parts[i].scale + Vec3(m_pWorld->m_vars.maxContactGap*5);
3094 BBoxNew[0]=BBoxNew[1] = m_pos + m_qrot*(m_parts[i].pos + m_parts[i].q*bbox1.center*m_parts[i].scale);
3095 BBoxNew[0] -= sz; BBoxNew[1] += sz;
3096 for(i1=m_pWorld->GetEntitiesAround(BBoxNew[0],BBoxNew[1],pents,ent_rigid|ent_sleeping_rigid|ent_independent)-1;
3097 i1>=0; i1--)
3098 pents[i1]->OnNeighbourSplit(this,(CPhysicalEntity*)epcep.pEntNew);
3099 } else if (epcep.pEntNew && epcep.pEntNew!=this)
3100 m_pWorld->DestroyPhysicalEntity(epcep.pEntNew,0,1);
3102 if (V0>0) {
3103 m_parts[i].mass *= pgeom0->V/V0;
3104 t = max(max(pgeom0->Ibody.x,pgeom0->Ibody.y),pgeom0->Ibody.z)*V0 / (pgeom0->V*Imax0);
3105 m_parts[i].minContactDist = max(m_pWorld->m_vars.maxContactGap*2, m_parts[i].minContactDist*sqrt_fast_tpl(max(0.0f,t)));
3107 //if (pOrgMapping) delete[] pOrgMapping;
3109 epum.pMesh->Lock(0); epum.pLastUpdate = (bop_meshupdate*)epum.pMesh->GetForeignData(DATA_MESHUPDATE);
3110 for(; epum.pLastUpdate && epum.pLastUpdate->next; epum.pLastUpdate=epum.pLastUpdate->next);
3111 epum.pMesh->Unlock(0);
3112 m_pWorld->OnEvent(m_pWorld->m_vars.bLogStructureChanges+1,&epum);
3115 flags |= m_parts[i].flags;
3116 iLastIdx = m_iLastIdx+nAddGeoms;
3119 if (nMeshSplits) {
3120 // attach the islands of non-breakable geoms to the original entity if they are not moved to any chunk
3121 for(i=m_nParts-1;i>=0;i--) if (m_parts[i].idmatBreakable<0) {
3122 for(j=0,gpAux.bRecalcBBox=0; j<m_nParts; j++) if (!(m_parts[j].id-m_parts[i].id & 1023))
3123 gpAux.bRecalcBBox = max(gpAux.bRecalcBBox, m_parts[j].id); // use gpAux.bRecalcBBox to store part id for new foliage proxies
3124 for(j=0; j<nAddGeoms; j++) if (!(gpAddGeoms[j].bRecalcBBox-m_parts[i].id & 1023))
3125 gpAux.bRecalcBBox = max(gpAux.bRecalcBBox, gpAddGeoms[j].bRecalcBBox);
3126 for(pMeshIsland=(CTriMesh*)m_parts[i].pLattice; pMeshIsland; pMeshIsland=(CTriMesh*)pMeshIsland->GetForeignData(-2)) {
3127 FillGeomParams(gpAux, m_parts[i]);
3128 gpAux.mass *= pMeshIsland->GetVolume()/m_parts[i].maxdim;
3129 pgeom1 = m_pWorld->RegisterGeometry(pMeshIsland, m_parts[i].pPhysGeom->surface_idx,
3130 m_parts[i].pPhysGeom->pMatMapping,m_parts[i].pPhysGeom->nMats);
3131 //AddGeometry(pgeom1, &gpAux,-1,1); pgeom1->nRefCount--;
3132 gpAux.bRecalcBBox += 1024;
3133 pAddGeoms[nAddGeoms]=pgeom1; gpAddGeoms[nAddGeoms]=gpAux;
3134 nAddGeoms=min(nAddGeoms+1, (int)(CRY_ARRAY_COUNT(gpAddGeoms)-1));
3136 gpAux.bRecalcBBox = 1;
3137 m_parts[i].pPhysGeom->pGeom->GetBBox(&bbox);
3138 m_parts[i].maxdim = max(max(bbox.size.x,bbox.size.y),bbox.size.z)*m_parts[i].scale;
3139 m_parts[i].pLattice = 0;
3141 for(i=m_nParts-1; i>=0; i--)
3142 if (m_parts[i].flags & geom_removed) {
3143 //(pgeom=m_parts[i].pPhysGeom)->nRefCount++; RemoveGeometry(m_parts[i].id); pgeom->nRefCount--;
3144 idRemoveGeoms[nRemoveGeoms] = m_parts[i].id; pRemoveGeoms[nRemoveGeoms] = m_parts[i].pPhysGeom;
3145 nRemoveGeoms = min(nRemoveGeoms+1, (int)(CRY_ARRAY_COUNT(idRemoveGeoms)-1));
3146 } else if (m_parts[i].flags & geom_invalid) {
3147 m_parts[i].flags=m_parts[i].flagsCollider=0; m_parts[i].idmatBreakable=-1;
3149 if (pChunkMeshes!=pChunkMeshesBuf) delete[] pChunkMeshes;
3150 if (pChunkLattices!=pChunkLatticesBuf) delete[] pChunkLattices;
3151 RecomputeMassDistribution();
3152 //pe_action_reset ar; ar.bClearContacts=0;
3153 //Action(&ar,1);
3154 for(j=m_pWorld->GetEntitiesAround(m_BBox[0]-Vec3(0.1f),m_BBox[1]+Vec3(0.1f),pents,ent_rigid|ent_sleeping_rigid|ent_independent)-1; j>=0; j--)
3155 pents[j]->OnNeighbourSplit(this,0);
3158 m_timeStructUpdate = m_updStage*m_pWorld->m_vars.tickBreakable;
3159 m_updStage ^= 1; m_nUpdTicks++;
3163 SkipMeshUpdates:
3164 for(i=0;i<nAddGeoms;i++) {
3165 int id = gpAddGeoms[i].bRecalcBBox | gpAddGeoms[i].bRecalcBBox-2>>31;
3166 gpAddGeoms[i].bRecalcBBox = 1;
3167 AddGeometry(pAddGeoms[i], gpAddGeoms+i,id,1);
3168 CryInterlockedDecrement((volatile int*) &pAddGeoms[i]->nRefCount);
3170 for(i=0;i<nRemoveGeoms;i++) {
3171 CryInterlockedIncrement((volatile int*) &pRemoveGeoms[i]->nRefCount);
3172 RemoveGeometry(idRemoveGeoms[i]);
3173 CryInterlockedDecrement((volatile int*) &pRemoveGeoms[i]->nRefCount);
3175 if (m_iSimClass && m_nParts && m_parts[0].flags & geom_break_approximation)
3176 CapsulizePart(0);
3177 if (!(m_flags & aef_recorded_physics) && (nRemoveGeoms || nMeshSplits))
3178 for(i1=m_pWorld->GetEntitiesAround(m_BBox[0]-Vec3(0.1f),m_BBox[1]+Vec3(0.1f),pents,ent_rigid|ent_sleeping_rigid|ent_independent)-1; i1>=0; i1--)
3179 pents[i1]->OnNeighbourSplit(this,0);
3181 i0 = 0;
3182 if (m_pStructure && m_pStructure->defparts) for(i=0;i<m_nParts;i++) if (m_pStructure->defparts[i].pSkelEnt) {
3183 CPhysicalEntity *pent = m_pStructure->defparts[i].pSkelEnt;
3184 pe_params_pos ppos;
3185 memcpy(&ppos.pos, &m_pos, sizeof(m_pos)); // gcc workaround
3186 memcpy(&ppos.q, &m_qrot, sizeof(m_qrot));
3187 pent->SetParams(&ppos);
3188 pe_params_flags pf;
3189 pf.flagsAND = ~pef_invisible; pent->SetParams(&pf);
3190 i0=m_parts[i].flags; m_parts[i].flags&=geom_colltype_explosion|geom_colltype_ray|geom_monitor_contacts;
3191 RigidBody *pbody = GetRigidBody(i);
3192 Vec3 v=pbody->v, w=pbody->w;
3193 pbody->v.zero(); pbody->w.zero();
3194 pent->Awake();
3195 for(j=0;j<m_pStructure->defparts[i].nSteps;j++) {
3196 pent->StartStep(m_pStructure->defparts[i].timeStep);
3197 pent->Step(m_pStructure->defparts[i].timeStep);
3199 m_parts[i].flags=i0;
3200 pbody->v=v; pbody->w=w;
3201 pf.flagsOR = pef_invisible; pent->SetParams(&pf);
3202 pe_action_reset ar; ar.bClearContacts = 2;
3203 pent->Action(&ar);
3204 UpdateDeformablePart(i);
3205 if (m_pStructure->defparts[i].lastUpdateTime && m_pWorld->m_timePhysics > m_pStructure->defparts[i].lastUpdateTime+2.0f)
3206 ((CSoftEntity*)pent)->BakeCurrentPose();
3207 m_pStructure->defparts[i].lastUpdateTime = m_pWorld->m_timePhysics;
3208 m_pStructure->defparts[i].lastUpdatePos = m_pos;
3209 m_pStructure->defparts[i].lastUpdateq = m_qrot;
3212 if (flags & geom_structure_changes || i0) {
3213 //WriteLock lock(m_lockUpdate);
3214 if (GetType()!=PE_STATIC && flags & geom_structure_changes) {
3215 for(i=0;i<m_nColliders;i++) if (m_pColliders[i]!=this)
3216 m_pColliders[i]->Awake();
3217 }/* else if (m_nRefCount>0) {
3218 CPhysicalEntity **pentlist;
3219 Vec3 inflator = (m_BBox[1]-m_BBox[0])*1E-3f+Vec3(4,4,4)*m_pWorld->m_vars.maxContactGap;
3220 for(i=m_pWorld->GetEntitiesAround(m_BBox[0]-inflator,m_BBox[1]+inflator, pentlist,
3221 ent_sleeping_rigid|ent_rigid|ent_living|ent_independent|ent_triggers)-1; i>=0; i--)
3222 pentlist[i]->Awake();
3225 Vec3 BBox[2];
3226 ComputeBBox(BBox,0);
3227 i = m_pWorld->RepositionEntity(this,1,BBox);
3228 { WriteLock locku(m_lockUpdate);
3229 ComputeBBox(m_BBox);
3230 m_pWorld->UnlockGrid(this,-i);
3232 RepositionParts();
3235 return (i0==0 && m_updStage==0) || flags & geom_structure_changes;
3239 void CPhysicalEntity::OnContactResolved(entity_contact *pContact, int iop, int iGroupId)
3241 int i;
3242 if (iop<2 && (unsigned int)pContact->ipart[iop]<(unsigned int)m_nParts &&
3243 (m_flags & aef_recorded_physics || !(pContact->pent[iop^1]->m_flags & pef_never_break) ||
3244 m_iSimClass>0 && GetRigidBody()->v.len2()>sqr(3.0f)) &&
3245 !(pContact->flags & contact_angular))
3247 Vec3 n,pt=pContact->pt[iop&1];
3248 if (!(pContact->flags & contact_rope) || iop==0)
3249 n = pContact->n*(1-iop*2);
3250 else if (iop==1)
3251 n = pContact->vreq*pContact->nloc.x;//pContact->K(0,0);
3252 else {
3253 rope_solver_vtx &svtx = ((rope_solver_vtx*)pContact->pBounceCount)[iop-2];
3254 n = svtx.P;
3255 pt = svtx.r+svtx.pbody->pos;
3257 float scale = 1.0f+(m_pWorld->m_vars.breakImpulseScale-1.0f)*iszero((int)m_flags & pef_override_impulse_scale);
3258 if (m_pStructure) {
3259 Vec3 dP,r,sz;
3260 float Plen2,Llen2;
3261 /*if (m_pWorld->m_updateTimes[0]!=m_pStructure->timeLastUpdate) {
3262 for(i=0;i<m_nParts;i++)
3263 m_pStructure->Pext[i].zero(),m_pStructure->Lext[i].zero();
3264 m_pStructure->timeLastUpdate = m_pWorld->m_updateTimes[0];
3266 i = MapHitPointFromParent(pContact->ipart[iop], pt);
3267 dP = n*(pContact->Pspare*scale);
3268 r = m_qrot*(m_parts[i].q*m_parts[i].pPhysGeom->origin*m_parts[i].scale+m_parts[i].pos)+m_pos-pt;
3269 if (pContact->flags & contact_rope || pContact->pent[iop^1]->GetType()!=PE_RIGID ||
3270 (((CRigidEntity*)pContact->pent[iop^1])->m_prevv-pContact->pbody[iop^1]->v).len2()<4)
3271 { Plen2 = (m_pStructure->pParts[i].Fext += dP).len2();
3272 Llen2 = (m_pStructure->pParts[i].Text += r^dP).len2();
3273 } else {
3274 Plen2 = (m_pStructure->pParts[i].Pext += dP).len2();
3275 Llen2 = (m_pStructure->pParts[i].Lext += r^dP).len2();
3277 sz = m_parts[i].BBox[1]-m_parts[i].BBox[0];
3278 if (max(Plen2, Llen2*sqr(sz.x+sz.y+sz.z)*0.1f) >
3279 sqr(m_parts[i].mass*0.01f)*m_pWorld->m_vars.gravity.len2()*(0.01f+0.99f*iszero((int)m_flags & aef_recorded_physics)))
3281 m_pWorld->MarkEntityAsDeforming(this), m_iGroup=iGroupId;
3282 if (m_pStructure->defparts && m_pStructure->defparts[i].pSkelEnt &&
3283 (!((CGeometry*)m_parts[i].pPhysGeom->pGeom)->IsAPrimitive() ||
3284 m_pWorld->m_timePhysics > m_pStructure->defparts[i].lastCollTime+2.0f ||
3285 pContact->Pspare > m_pStructure->defparts[i].lastCollImpulse*1.5f))
3287 pe_action_impulse ai;
3288 ai.point = m_pStructure->defparts[i].lastUpdateq*(!m_qrot*(pt-m_pos))+m_pStructure->defparts[i].lastUpdatePos;
3289 ai.impulse = n*min(m_pStructure->defparts[i].maxImpulse, pContact->Pspare);
3290 m_pStructure->defparts[i].pSkelEnt->Action(&ai);
3291 m_pStructure->defparts[i].lastCollTime = m_pWorld->m_timePhysics;
3292 m_pStructure->defparts[i].lastCollImpulse = pContact->Pspare;
3297 if (m_parts[i=pContact->ipart[iop]].pLattice && m_parts[i].idmatBreakable>=0) {
3298 float rdensity = m_parts[i].pLattice->m_density*m_parts[i].pPhysGeom->V*cube(m_parts[i].scale)/m_parts[i].mass;
3299 Vec3 ptloc = ((pContact->pt[iop]-m_pos)*m_qrot-m_parts[i].pos)*m_parts[i].q, dP;
3300 if (m_parts[i].scale!=1.0f)
3301 ptloc /= m_parts[i].scale;
3302 dP = n*(pContact->Pspare*rdensity*scale);
3304 if (m_parts[i].pLattice->AddImpulse(ptloc, (dP*m_qrot)*m_parts[i].q, Vec3(0,0,0),
3305 m_pWorld->m_vars.gravity*m_pWorld->m_vars.jointGravityStep*m_pWorld->m_updateTimes[0],m_pWorld->m_updateTimes[0]) && !(m_flags & pef_deforming))
3306 m_updStage=0,m_iGroup=iGroupId,m_pWorld->MarkEntityAsDeforming(this);
3312 int CPhysicalEntity::GetStateSnapshot(TSerialize ser, float time_back, int flags)
3314 if (ser.GetSerializationTarget()!=eST_Network)
3316 bool bVal; int i,id;
3317 ser.Value("hasJoints", bVal=(m_pStructure!=0 && m_pStructure->bModified>0), 'bool');
3318 if (bVal) {
3319 ser.Value("nJoints", m_pStructure->nJoints);
3320 for(i=0;i<m_pStructure->nJoints;i++) {
3321 ser.BeginGroup("joint");
3322 ser.Value("id",m_pStructure->pJoints[i].id);
3323 ser.Value("ipart0",id=m_pStructure->pJoints[i].ipart[0]>=0 ? m_parts[m_pStructure->pJoints[i].ipart[0]].id:-1);
3324 ser.Value("ipart1",id=m_pStructure->pJoints[i].ipart[1]>=0 ? m_parts[m_pStructure->pJoints[i].ipart[1]].id:-1);
3325 ser.Value("pt",m_pStructure->pJoints[i].pt);
3326 ser.Value("n",m_pStructure->pJoints[i].n);
3327 ser.Value("maxForcePush",m_pStructure->pJoints[i].maxForcePush);
3328 ser.Value("maxForcePull",m_pStructure->pJoints[i].maxForcePull);
3329 ser.Value("maxForceShift",m_pStructure->pJoints[i].maxForceShift);
3330 ser.Value("maxTorqueBend",m_pStructure->pJoints[i].maxTorqueBend);
3331 ser.Value("maxTorqueTwist",m_pStructure->pJoints[i].maxTorqueTwist);
3332 ser.Value("bBreakable",m_pStructure->pJoints[i].bBreakable);
3333 ser.Value("szHelper",m_pStructure->pJoints[i].size);
3334 ser.Value("axisx",m_pStructure->pJoints[i].axisx);
3335 ser.Value("limitConstr",m_pStructure->pJoints[i].limitConstr);
3336 ser.Value("dampingConstr",m_pStructure->pJoints[i].dampingConstr);
3337 ser.EndGroup();
3339 char buf[2048],*ptr;
3340 for(i=0,*(ptr=buf)++='|'; i<m_nParts && ptr<buf+2038; i++,*ptr++=',')
3341 ptr += strlen(ltoa(m_parts[i].id, ptr, 16));
3342 *ptr = 0;
3343 ser.Value("usedParts", (const char*)buf);
3346 if (!m_pStructure || !m_pStructure->defparts)
3347 ser.Value("hasDfm", bVal=false);
3348 else {
3349 ser.Value("hasDfm", bVal=true);
3350 for(i=0;i<m_nParts;i++) if (m_pStructure->defparts[i].pSkelEnt)
3351 m_pStructure->defparts[i].pSkelEnt->GetStateSnapshot(ser,time_back,flags);
3355 return 1;
3358 int CPhysicalEntity::SetStateFromSnapshot(TSerialize ser, int flags)
3360 if (ser.GetSerializationTarget()!=eST_Network)
3362 bool bVal;
3363 ser.Value("hasJoints", bVal, 'bool');
3364 if (bVal) {
3365 int i,nJoints;
3366 pe_params_structural_joint psj;
3367 psj.bReplaceExisting = true;
3368 if (m_pStructure)
3369 m_pStructure->nJoints = 0;
3370 ser.Value("nJoints", nJoints);
3371 for(i=0;i<nJoints;i++) {
3372 ser.BeginGroup("joint");
3373 ser.Value("id",psj.id);
3374 ser.Value("ipart0",psj.partid[0]);
3375 ser.Value("ipart1",psj.partid[1]);
3376 ser.Value("pt",psj.pt);
3377 ser.Value("n",psj.n);
3378 ser.Value("maxForcePush",psj.maxForcePush);
3379 ser.Value("maxForcePull",psj.maxForcePull);
3380 ser.Value("maxForceShift",psj.maxForceShift);
3381 ser.Value("maxTorqueBend",psj.maxTorqueBend);
3382 ser.Value("maxTorqueTwist",psj.maxTorqueTwist);
3383 ser.Value("bBreakable",psj.bBreakable);
3384 psj.bConstraintWillIgnoreCollisions = psj.bBreakable>>1^1;
3385 psj.bDirectBreaksOnly = psj.bBreakable>>2;
3386 psj.bBreakable &= 1;
3387 ser.Value("szHelper",psj.szSensor);
3388 ser.Value("axisx",psj.axisx);
3389 ser.Value("limitConstr",psj.limitConstraint);
3390 ser.Value("dampingConstr",psj.dampingConstraint);
3391 SetParams(&psj);
3392 ser.EndGroup();
3394 if (m_pStructure)
3395 m_pStructure->bModified = 1;
3396 string str; ser.Value("usedParts", str);
3397 if (str.size()) {
3398 for(i=0;i<m_nParts;i++) {
3399 m_parts[i].flags |= geom_will_be_destroyed;
3400 if (m_pStructure) m_pStructure->pParts[i].flags0 |= geom_will_be_destroyed;
3402 const char *ptr=str.c_str()+1, *ptr1;
3403 for(;*ptr;ptr=ptr1+1) {
3404 int id = strtoul(ptr,(char**)&ptr1,16);
3405 for(i=0;i<m_nParts;i++) {
3406 int mask = ~geom_will_be_destroyed | ~-iszero(m_parts[i].id-id);
3407 m_parts[i].flags &= mask;
3408 if (m_pStructure) m_pStructure->pParts[i].flags0 &= mask;
3411 if (m_pStructure) for(i=0;i<m_nParts;i++) if (m_parts[i].flags & geom_will_be_destroyed && m_pStructure->pParts[i].iParent && m_parts[i].mass)
3412 RemoveBrokenParent(m_pStructure->pParts[i].iParent-1, 0);
3413 for(i=m_nParts-1;i>=0;i--) if (m_parts[i].flags & (geom_will_be_destroyed|geom_removed))
3414 RemoveGeometry(m_parts[i].id);
3418 bVal = false;
3419 ser.Value("hasDfm", bVal, 'bool');
3420 if (m_pStructure && m_pStructure->defparts && bVal)
3421 for(int i=0;i<m_nParts;i++) if (m_pStructure->defparts[i].pSkelEnt) {
3422 m_pStructure->defparts[i].pSkelEnt->SetStateFromSnapshot(ser,flags);
3423 if (((CSoftEntity*)m_pStructure->defparts[i].pSkelEnt)->m_bMeshUpdated)
3424 UpdateDeformablePart(i);
3427 return 1;
3431 int CPhysicalEntity::TouchesSphere(const Vec3 &center, float r)
3433 ReadLock lock(m_lockUpdate);
3434 int i;
3435 geom_world_data gwd[2];
3436 intersection_params ip;
3437 sphere sph;
3438 geom_contact *pcont;
3439 CSphereGeom sphGeom;
3440 sph.center.zero(); sph.r=r;
3441 sphGeom.CreateSphere(&sph);
3442 gwd[0].offset = center;
3443 ip.bStopAtFirstTri=ip.bNoBorder=ip.bNoAreaContacts = true;
3445 for(i=0;i<m_nParts;i++) if (m_parts[i].flags & (geom_colltype_solid|geom_colltype_ray)) {
3446 gwd[1].offset=m_pos+m_qrot*m_parts[i].pos; gwd[1].R=Matrix33(m_qrot*m_parts[i].q); gwd[1].scale=m_parts[i].scale;
3447 if (sphGeom.Intersect(m_parts[i].pPhysGeomProxy->pGeom, gwd,gwd+1, &ip, pcont))
3448 return i;
3450 return -1;
3453 struct caps_piece {
3454 capsule caps;
3455 Vec3 pos;
3456 quaternionf q;
3459 CTriMesh *g_pSliceMesh = 0;
3461 int CPhysicalEntity::CapsulizePart(int ipart)
3463 IGeometry *pGeom;
3464 caps_piece pieceBuf[16],*pieces=pieceBuf;
3465 pe_geomparams gp;
3466 int i,j,nSlices,nParts=0;
3468 { ReadLock lock(m_lockUpdate);
3469 if (ipart>=m_nParts || (pGeom = m_parts[ipart].pPhysGeom->pGeom)->GetPrimitiveCount()<50 || m_pWorld->m_vars.approxCapsLen<=0)
3470 return 0;
3472 if (!g_pSliceMesh) {
3473 static Vec3 vtx[] = { Vec3(-1,-1,0), Vec3(1,-1,0), Vec3(1,1,0), Vec3(-1,1,0) };
3474 static index_t indices[] = { 0,1,2, 0,2,3 };
3475 g_pSliceMesh = (CTriMesh*)m_pWorld->CreateMesh(vtx, indices,0,0, 2, mesh_shared_idx|mesh_shared_vtx|mesh_no_vtx_merge|mesh_SingleBB, 0);
3477 int iax,icnt,nLastParts=0,nNewParts,nPartsAlloc=CRY_ARRAY_COUNT(pieceBuf);
3478 Vec3 axis,axcaps,ptc,ptcPrev,ptcCur;
3479 quotientf t,dist,mindist;
3480 float step,r0;
3481 box bbox;
3482 capsule caps;
3483 geom_world_data gwd;
3484 intersection_params ip;
3486 ip.bNoAreaContacts = true;
3487 ip.maxUnproj = 0.01f;
3488 geom_contact *pcont;
3489 pGeom->GetBBox(&bbox);
3490 axis = bbox.Basis.GetRow(iax=idxmax3(bbox.size));
3491 nSlices = min(m_pWorld->m_vars.nMaxApproxCaps+1, float2int(bbox.size[iax]*2/m_pWorld->m_vars.approxCapsLen-0.5f)+2);
3492 if (nSlices<4)
3493 return 0;
3494 axis *= sgnnz(axis[idxmax3(axis.abs())]);
3495 axcaps.zero()[iax] = 1;
3496 gwd.R = bbox.Basis.T()*Matrix33::CreateRotationV0V1(Vec3(0,0,1),axcaps);
3497 gwd.scale = max(bbox.size[inc_mod3[iax]],bbox.size[dec_mod3[iax]])*1.1f;
3498 gwd.offset = bbox.center-axis*(bbox.size[iax]*0.9f);
3499 caps.center.zero();
3500 caps.axis.Set(0,0,1);
3501 gp.flagsCollider = m_parts[ipart].flagsCollider;
3502 gp.flags = m_parts[ipart].flags & geom_colltype_solid;
3503 gp.density = gp.mass = 0;
3504 gp.surface_idx = m_parts[ipart].surface_idx;
3505 if (m_parts[ipart].pMatMapping)
3506 gp.surface_idx = m_parts[ipart].pMatMapping[gp.surface_idx];
3507 gp.idmatBreakable = -2-m_parts[ipart].id;
3508 //gp.scale = m_parts[ipart].scale;
3510 for(i=0;;i++) {
3511 if (pGeom->Intersect(g_pSliceMesh, 0,&gwd, &ip,pcont)) {
3512 if (!pcont[0].nborderpt)
3513 return 0;
3514 float r,rmin;
3515 for(j=0,r0=0,rmin=bbox.size[iax]; j<pcont[0].nborderpt; j++) {
3516 r0 += (r=(pcont[0].ptborder[j]-pcont[0].center).len());
3517 rmin = min(rmin,r);
3519 r0 /= pcont[0].nborderpt;
3520 if (r0-rmin > r0*0.4f && i==0)
3521 gwd.offset += axis*(bbox.size[iax]*0.9f);
3522 else {
3523 gwd.offset = bbox.center-axis*(bbox.size[iax]-r0);
3524 step = (bbox.size[iax]*2-r0-m_pWorld->m_vars.maxContactGap*5)/(nSlices-1);
3525 r0 *= m_parts[ipart].scale;
3526 break;
3528 } else
3529 return 0;
3532 for(i=0; i<nSlices; i++,gwd.offset+=axis*step) {
3533 if (!(icnt=pGeom->Intersect(g_pSliceMesh, 0,&gwd, &ip,pcont)))
3534 break;
3535 nNewParts = 0;
3536 if (!i) {
3537 for(--icnt,ptcPrev.zero(); icnt>=0; i+=pcont[icnt--].nborderpt) for(j=0; j<pcont[icnt].nborderpt; j++)
3538 ptcPrev += pcont[icnt].ptborder[j];
3539 if (i>0)
3540 ptcPrev /= i;
3541 else
3542 ptcPrev = pcont[0].center;
3543 ptcPrev = m_parts[ipart].q*ptcPrev*m_parts[ipart].scale;
3544 i = 0;
3545 } else for(--icnt,nNewParts=0; icnt>=0; icnt--) {
3546 if (!pcont[icnt].bClosed)
3547 continue; // failure
3548 ptcCur = m_parts[ipart].q*pcont[icnt].center*m_parts[ipart].scale;
3549 for(j=nParts-nNewParts-nLastParts,mindist.set(1,0); j<nParts-nNewParts; j++) {
3550 axcaps = pieces[j].q*Vec3(0,0,1);
3551 ptc = pieces[j].pos+axcaps*(pieces[j].caps.hh*gp.scale);
3552 t.set((m_parts[ipart].pos+m_parts[ipart].q*gwd.offset*m_parts[ipart].scale-ptc)*axcaps, axcaps*axis);
3553 dist.set(((ptc-ptcCur)*t.y+axcaps*t.x).len2(), t.y*t.y);
3554 if (dist<mindist) {
3555 mindist=dist; ptcPrev=ptc;
3558 for(j=0,caps.r=0; j<pcont[icnt].nborderpt; j++)
3559 caps.r += (pcont[icnt].ptborder[j]-pcont[icnt].center).len();
3560 caps.r = caps.r/pcont[icnt].nborderpt*m_parts[ipart].scale;
3561 if (i==1 && fabs_tpl(caps.r-r0)<min(caps.r,r0)*0.5f)
3562 caps.r = r0;
3563 caps.hh = (ptcCur-ptcPrev).len()*0.5f;
3564 if (caps.hh==0)
3565 continue;
3566 gp.pos = (ptcPrev+ptcCur)*0.5f;
3567 axcaps = (ptcCur-ptcPrev)/(caps.hh*2);
3568 gp.q = Quat::CreateRotationV0V1(Vec3(0,0,1), axcaps);
3569 /*if (i==1) {
3570 caps.hh-=caps.r*0.5f;
3571 gp.pos += axcaps*(caps.r*0.5f);
3573 if (nParts==nPartsAlloc)
3574 if (pieces==pieceBuf)
3575 memcpy(pieces=new caps_piece[nPartsAlloc+=4], pieceBuf, nParts*sizeof(caps_piece));
3576 else
3577 ReallocateList(pieces, nParts, nPartsAlloc+=4);
3578 pieces[nParts].caps = caps;
3579 pieces[nParts].pos = gp.pos;
3580 pieces[nParts].q = gp.q;
3581 nParts++; nNewParts++;
3583 nLastParts = nNewParts;
3587 if (i<nSlices)
3588 return 0;
3589 float V0=m_parts[ipart].pPhysGeom->V*cube(m_parts[ipart].scale), V1=0;
3590 for(j=0;j<nParts;j++)
3591 V1 += g_PI*sqr(pieces[j].caps.r)*pieces[j].caps.hh*2*cube(gp.scale);
3592 if (fabs_tpl(V0-V1)>max(V0,V1)*0.2f)
3593 return 0;
3594 for(j=0;j<nParts;j++) {
3595 gp.pos = pieces[j].pos; gp.q = pieces[j].q;
3596 pieces[j].caps.r = max(0.03f, pieces[j].caps.r);
3597 phys_geometry *pgeom = m_pWorld->RegisterGeometry(m_pWorld->CreatePrimitive(capsule::type, &pieces[j].caps));
3598 pgeom->pGeom->Release();
3599 if (AddGeometry(pgeom, &gp)<0)
3600 goto exitcp;
3601 CryInterlockedDecrement((volatile int*) &pgeom->nRefCount);
3603 m_parts[ipart].flags &= ~geom_colltype_solid;
3604 m_parts[ipart].flagsCollider = 0;
3605 exitcp:
3606 if (pieces!=pieceBuf)
3607 delete[] pieces;
3608 return j;
3612 bool CPhysicalEntity::MakeDeformable(int ipart, int iskel, float r)
3614 if (((CGeometry*)m_parts[iskel].pPhysGeom->pGeom)->IsAPrimitive())
3615 return false;
3616 int i,j,bPrimitive=((CGeometry*)m_parts[ipart].pPhysGeom->pGeom)->IsAPrimitive();
3617 geom_world_data gwd[2];
3618 float thickness=0,r0;
3619 mesh_data *md[2];
3620 Vec3 vtx[4],n;
3621 geom_contact *pcontact;
3622 box bbox;
3623 m_parts[ipart].pPhysGeom->pGeom->GetBBox(&bbox);
3624 sphere sph; sph.center.zero(); sph.r=r0= r>0.0f ? r:min(min(bbox.size.x,bbox.size.y),bbox.size.z)*2.0f*m_parts[ipart].scale;
3625 CSphereGeom sphGeom; sphGeom.CreateSphere(&sph);
3626 SSkelInfo *pski;
3628 if (!(m_parts[ipart].flags & geom_can_modify))
3629 if (!bPrimitive)
3630 m_pWorld->ClonePhysGeomInEntity(this, ipart, m_pWorld->CloneGeometry(m_parts[ipart].pPhysGeom->pGeom));
3631 else
3632 m_parts[ipart].pPhysGeom->pGeom->SetForeignData(0,0);
3633 if (!(m_parts[iskel].flags & geom_can_modify))
3634 m_pWorld->ClonePhysGeomInEntity(this, iskel, m_pWorld->CloneGeometry(m_parts[iskel].pPhysGeom->pGeom));
3636 AllocStructureInfo();
3637 if (!m_pStructure->defparts)
3638 memset(m_pStructure->defparts = new SSkelInfo[m_nParts], 0, sizeof(SSkelInfo)*m_nParts);
3639 md[0] = (mesh_data*)m_parts[ipart].pPhysGeom->pGeom->GetData();
3640 md[1] = (mesh_data*)m_parts[iskel].pPhysGeom->pGeom->GetData();
3641 gwd[1].offset=m_parts[iskel].pos; gwd[1].R=Matrix33(m_parts[iskel].q); gwd[1].scale=m_parts[iskel].scale;
3642 pski = m_pStructure->defparts+ipart;
3643 if (!bPrimitive) {
3644 m_pStructure->defparts[ipart].pSkinInfo = new SSkinInfo[md[0]->nVertices];
3645 for(i=0; i<md[0]->nVertices; i++) {
3646 gwd[0].offset = m_parts[ipart].pos + m_parts[ipart].q*md[0]->pVertices[i]*m_parts[ipart].scale;
3647 if ((sphGeom.m_Tree.m_Box.size=Vec3(sphGeom.m_sphere.r=r0),
3648 sphGeom.Intersect(m_parts[iskel].pPhysGeom->pGeom, gwd,gwd+1, 0, pcontact)) ||
3649 (sphGeom.m_Tree.m_Box.size=Vec3(sphGeom.m_sphere.r=r0*3),
3650 sphGeom.Intersect(m_parts[iskel].pPhysGeom->pGeom, gwd,gwd+1, 0, pcontact)))
3652 pski->pSkinInfo[i].itri = pcontact->iPrim[1];
3653 for(j=0;j<3;j++)
3654 vtx[j] = m_parts[iskel].pos + m_parts[iskel].q*md[1]->pVertices[md[1]->pIndices[pcontact->iPrim[1]*3+j]]*m_parts[iskel].scale;
3655 n = m_parts[iskel].q*md[1]->pNormals[pcontact->iPrim[1]];
3656 vtx[3] = gwd[0].offset - n*(pski->pSkinInfo[i].w[3]=n*(gwd[0].offset-vtx[0]));
3657 n = vtx[1]-vtx[0]^vtx[2]-vtx[0]; n *= 1.0f/n.len2();
3658 for(j=0;j<3;j++)
3659 pski->pSkinInfo[i].w[j] = (vtx[inc_mod3[j]]-vtx[3]^vtx[dec_mod3[j]]-vtx[3])*n;
3660 thickness = max(thickness, fabs_tpl(pski->pSkinInfo[i].w[3]));
3661 } else
3662 pski->pSkinInfo[i].itri = -1;
3664 } else {
3665 m_pStructure->defparts[ipart].pSkinInfo = new SSkinInfo[1];
3666 thickness = 0.1f;
3669 pe_action_attach_points aap;
3670 aap.piVtx = new int[md[1]->nVertices];
3671 gwd[0].R = Matrix33(!m_parts[ipart].q*m_parts[iskel].q);
3672 gwd[0].scale = 1.0f/m_parts[ipart].scale;
3673 gwd[0].offset = !m_parts[ipart].q*(m_parts[iskel].pos-m_parts[ipart].pos)*gwd[0].scale;
3674 gwd[0].scale *= m_parts[iskel].scale;
3675 for(i=aap.nPoints=0; i<md[1]->nVertices; i++) {
3676 aap.piVtx[aap.nPoints] = i;
3677 aap.nPoints += 1-m_parts[ipart].pPhysGeom->pGeom->PointInsideStatus(gwd[0].R*md[1]->pVertices[i]*gwd[0].scale+gwd[0].offset);
3679 aap.pEntity = this;
3680 aap.partid = m_parts[ipart].id;
3682 pe_params_pos pp;
3683 pe_geomparams gp;
3684 pe_simulation_params sp;
3685 pe_params_softbody psb;
3686 pe_params_flags pf;
3687 pp.pos = m_pos; pp.q = m_qrot;
3688 pf.flagsAND = ~(pef_traceable|se_skip_longest_edges); pf.flagsOR = pef_invisible|pef_ignore_areas|sef_skeleton;
3689 psb.thickness = 0.0f;//thickness;
3690 for(i=1,j=m_parts[0].flags; i<m_nParts; j&=m_parts[i++].flags);
3691 if (j & geom_colltype0)
3692 psb.collTypes = ent_static|ent_rigid|ent_sleeping_rigid;
3693 else {
3694 psb.collTypes = 0; gp.flagsCollider = geom_colltype_obstruct|geom_colltype_foliage_proxy;
3696 psb.maxSafeStep = 0.01f;
3697 psb.impulseScale = 0.002f;
3698 psb.explosionScale = 0.005f;
3699 psb.shapeStiffnessNorm=10.0f; psb.shapeStiffnessTang=0.0f;
3700 psb.nMaxIters = 3;
3701 sp.gravity.zero();
3702 gp.pos = m_parts[iskel].pos; gp.q = m_parts[iskel].q; gp.scale = m_parts[iskel].scale;
3703 for(i=0,gp.mass=0.0f; i<md[1]->nTris; i++)
3704 gp.mass += fabs_tpl(md[1]->pNormals[i]*
3705 (md[1]->pVertices[md[1]->pIndices[i*3+1]]-md[1]->pVertices[md[1]->pIndices[i*3]] ^
3706 md[1]->pVertices[md[1]->pIndices[i*3+2]]-md[1]->pVertices[md[1]->pIndices[i*3]]));
3707 if (m_parts[iskel].mass>1e-6f)
3708 gp.mass *= m_parts[iskel].mass;
3709 gp.density = 1000.0f;
3710 m_pStructure->defparts[ipart].maxImpulse = 500.0f;
3711 psb.maxCollisionImpulse = 200.0f;
3712 pski->pSkelEnt = (CPhysicalEntity*)m_pWorld->CreatePhysicalEntity(PE_SOFT,&pp,0,0x5AFE);
3713 pski->pSkelEnt->SetParams(&pf);
3714 pski->pSkelEnt->SetParams(&sp);
3715 pski->pSkelEnt->SetParams(&psb);
3716 pski->pSkelEnt->AddGeometry(m_parts[iskel].pPhysGeom, &gp);
3717 pski->pSkelEnt->Action(&aap);
3718 pski->pSkelEnt->m_pForeignData = m_pForeignData;
3719 pski->pSkelEnt->m_iForeignData = m_iForeignData;
3720 delete[] aap.piVtx;
3721 RemoveGeometry(m_parts[iskel].id);
3722 m_pStructure->defparts[ipart].timeStep = 0.005f;
3723 m_pStructure->defparts[ipart].nSteps = 7;
3724 m_pStructure->defparts[ipart].lastUpdateTime = m_pWorld->m_timePhysics;
3725 m_pStructure->defparts[ipart].lastUpdatePos = m_pos;
3726 m_pStructure->defparts[ipart].lastUpdateq = m_qrot;
3727 m_parts[ipart].flags |= geom_monitor_contacts;
3728 return true;
3731 void CPhysicalEntity::UpdateDeformablePart(int ipart)
3733 int i,j;
3734 mesh_data *md[2];
3735 Vec3 vtx[3],doffs;
3736 quaternionf dq;
3737 float dscale;
3738 SSkelInfo *psi = m_pStructure->defparts+ipart;
3740 dscale = m_parts[ipart].scale==1.0f ? 1.0f:1.0f/m_parts[ipart].scale;
3741 dq = !m_parts[ipart].q*!m_qrot*psi->pSkelEnt->m_qrot*psi->pSkelEnt->m_parts[0].q;
3742 doffs = !m_parts[ipart].q*(!m_qrot*(psi->pSkelEnt->m_qrot*psi->pSkelEnt->m_parts[0].pos+psi->pSkelEnt->m_pos-m_pos)-m_parts[ipart].pos)*dscale;
3743 dscale *= psi->pSkelEnt->m_parts[0].scale;
3745 if (!((CGeometry*)m_parts[ipart].pPhysGeom->pGeom)->IsAPrimitive()) {
3746 { WriteLock lock(((CGeometry*)m_parts[ipart].pPhysGeom->pGeom)->m_lockUpdate);
3747 md[0] = (mesh_data*)m_parts[ipart].pPhysGeom->pGeom->GetData();
3748 md[1] = (mesh_data*)psi->pSkelEnt->m_parts[0].pPhysGeom->pGeom->GetData();
3750 for(i=0; i<md[0]->nVertices; i++) if (psi->pSkinInfo[i].itri>=0) {
3751 for(j=0,md[0]->pVertices[i].zero(); j<3; j++)
3752 md[0]->pVertices[i] += psi->pSkinInfo[i].w[j]*(vtx[j] = doffs + dq*md[1]->pVertices[md[1]->pIndices[psi->pSkinInfo[i].itri*3+j]]*dscale);
3753 md[0]->pVertices[i] += (vtx[1]-vtx[0]^vtx[2]-vtx[0]).normalized()*psi->pSkinInfo[i].w[3];
3755 for(i=0; i<md[0]->nTris; i++)
3756 md[0]->pNormals[i] = (md[0]->pVertices[md[0]->pIndices[i*3+1]]-md[0]->pVertices[md[0]->pIndices[i*3]] ^
3757 md[0]->pVertices[md[0]->pIndices[i*3+2]]-md[0]->pVertices[md[0]->pIndices[i*3]]).normalized();
3758 ((CTriMesh*)m_parts[ipart].pPhysGeom->pGeom)->RebuildBVTree();
3760 if (m_iSimClass>0) {
3761 m_parts[ipart].pPhysGeom->pGeom->CalcPhysicalProperties(m_parts[ipart].pPhysGeom);
3762 RecomputeMassDistribution(ipart);
3766 EventPhysUpdateMesh epum;
3767 epum.pEntity=this; epum.pForeignData=m_pForeignData; epum.iForeignData=m_iForeignData;
3768 epum.iReason = EventPhysUpdateMesh::ReasonDeform;
3769 epum.partid = m_parts[ipart].id;
3770 epum.bInvalid = 0; epum.pLastUpdate = 0;
3771 epum.pMesh = m_parts[ipart].pPhysGeom->pGeom;
3772 epum.pMeshSkel = psi->pSkelEnt->m_parts[0].pPhysGeom->pGeom;
3773 epum.mtxSkelToMesh = Matrix34(Vec3(dscale),dq,doffs);
3774 m_pWorld->OnEvent(m_pWorld->m_vars.bLogStructureChanges+1,&epum);
3778 CPhysicalPlaceholder *CPhysicalEntity::ReleasePartPlaceholder(int i)
3780 CPhysicalPlaceholder *res = m_parts[i].pPlaceholder;
3781 m_parts[i].pPlaceholder->m_BBox[0] = Vec3(1e20f); // make sure rwi and geb don't notice it
3782 m_parts[i].pPlaceholder->m_BBox[1] = Vec3(-1e20f);
3783 int64 timeout = CryGetTicks()+m_pWorld->m_vars.ticksPerSecond*5;
3784 while(m_parts[i].pPlaceholder->m_bProcessed & 0xFFFF && CryGetTicks()<timeout); // make sure no external rwi/geb references it
3785 m_parts[i].pPlaceholder->m_pEntBuddy = 0;
3786 m_parts[i].pPlaceholder = 0;
3787 return res;
3790 void CPhysicalEntity::RepositionParts()
3792 if (!(m_flags & pef_parts_traceable) || (unsigned int)m_iSimClass>2u) {
3793 for(int i=0;i<m_nParts;i++) if (m_parts[i].pPlaceholder)
3794 m_pWorld->DestroyPhysicalEntity(ReleasePartPlaceholder(i),0,1);
3795 m_nUsedParts = 0;
3796 return;
3798 if (!m_pUsedParts) {
3799 if (m_pHeap)
3800 m_pUsedParts = (int(*)[16])m_pHeap->Malloc(sizeof(int) * MAX_TOT_THREADS * 16, "Used parts");
3801 else
3802 m_pUsedParts = new int[MAX_TOT_THREADS][16];
3803 memset(m_pUsedParts, 0, sizeof(*m_pUsedParts));
3806 pe_params_bbox pbb;
3807 pe_type type=GetType();
3808 for(int i=0;i<m_nParts;i++) {
3809 pbb.BBox[0]=m_parts[i].BBox[0]; pbb.BBox[1]=m_parts[i].BBox[1];
3810 if (!m_parts[i].pPlaceholder)
3811 (m_parts[i].pPlaceholder = (CPhysicalPlaceholder*)m_pWorld->CreatePhysicalPlaceholder(
3812 type,0,m_pForeignData,m_iForeignData,-2-i))->m_pEntBuddy = this;
3813 m_parts[i].pPlaceholder->SetParams(&pbb);
3814 m_Extents.Clear();
3819 void CPhysicalEntity::AllocStructureInfo()
3821 if (!m_pStructure) {
3822 memset(m_pStructure = new SStructureInfo, 0, sizeof(SStructureInfo));
3823 m_pStructure->idpartBreakOrg = -1;
3824 memset(m_pStructure->pParts = new SPartInfo[m_nParts], 0, m_nParts*sizeof(SPartInfo));
3825 m_pStructure->pJoints = 0;
3826 m_pStructure->nPartsAlloc = m_nParts;
3827 for(int i=0;i<m_nParts;i++)
3828 m_parts[i].flags |= geom_monitor_contacts;
3833 int CPhysicalEntity::GenerateJoints()
3835 int i,j,i1,j1,ncont,ihead,itail,nFakeJoints,idGnd=-1,iCaller=get_iCaller();
3836 CPhysicalEntity **pentlist;
3837 geom_world_data gwd[2];
3838 intersection_params ip;
3839 geom_contact *pcontacts;
3840 pe_params_structural_joint psj;
3841 SStructuralJoint sampleJoint,*pJoint,*pFakeJoints;
3842 float rareaAvg;
3843 ptitem2d pt2d[64];
3844 edgeitem edge2d[64];
3845 box abox;
3847 ushort idxGnd[] = { 0,1,2 };
3848 Vec3 ptGnd[3];
3849 for(i=m_nParts-1;i>=0 && m_parts[i].mass>0;i--);
3850 if (i<0) {
3851 Vec3 g=m_pWorld->m_vars.gravity.normalized()*m_qrot, c=((m_BBox[1]+m_BBox[0])*0.5f-m_pos)*m_qrot, r,ptbott;
3852 float bott = 0;
3853 for(j=0;j<m_nParts;j++) {
3854 Vec3 gpart = g*m_parts[j].q;
3855 switch (m_parts[j].pPhysGeom->pGeom->GetType()) {
3856 case GEOM_BOX: {
3857 const box *pbox = (const box*)m_parts[j].pPhysGeom->pGeom->GetData();
3858 Vec3 gloc = pbox->Basis*gpart, sz;
3859 for(i1=0;i1<3;i1++) sz[i1] = pbox->size[i1]*sgnnz(gloc[i1]);
3860 ptbott = pbox->center + sz*pbox->Basis;
3861 } break;
3862 case GEOM_CAPSULE: {
3863 const capsule *pcaps = (const capsule*)m_parts[j].pPhysGeom->pGeom->GetData();
3864 ptbott = pcaps->center + pcaps->axis*(pcaps->hh*sgnnz(pcaps->axis*gpart)) + gpart*pcaps->r;
3865 } break;
3866 case GEOM_CYLINDER: {
3867 const cylinder *pcyl = (const cylinder*)m_parts[j].pPhysGeom->pGeom->GetData();
3868 ptbott = pcyl->center + pcyl->axis*(pcyl->hh*sgnnz(pcyl->axis*gpart)) + (pcyl->axis^gpart).normalized()^pcyl->axis*pcyl->r;
3869 } break;
3870 case GEOM_SPHERE: {
3871 const sphere *psph = (const sphere*)m_parts[j].pPhysGeom->pGeom->GetData();
3872 ptbott = psph->center+gpart*psph->r;
3873 } break;
3874 case GEOM_TRIMESH: {
3875 const mesh_data *pmd = (const mesh_data*)m_parts[j].pPhysGeom->pGeom->GetData();
3876 for(j1=0,i1=1; i1<pmd->nTris*3; i1++)
3877 j1 += (i1-j1)*isneg(pmd->pVertices[pmd->pIndices[j1]]*gpart-pmd->pVertices[pmd->pIndices[i1]]*gpart);
3878 ptbott = pmd->pVertices[pmd->pIndices[j1]];
3879 } break;
3881 bott = max(bott, (m_parts[j].q*ptbott*m_parts[j].scale+m_parts[j].pos-c)*g);
3883 for(i=0,r.Set((m_BBox[1]-m_BBox[0]).len()*1.1f,0,0); i<3; i++,r=r.GetRotated(Vec3(0,0,1),-0.5f,sqrt3*0.5f)) ptGnd[i]=r;
3884 IGeometry *pMesh = m_pWorld->CreateMesh(ptGnd,idxGnd,0,0,1,mesh_shared_vtx|mesh_shared_idx|mesh_no_filter|mesh_no_vtx_merge|mesh_SingleBB,0);
3885 phys_geometry *pgeom = m_pWorld->RegisterGeometry(pMesh); pMesh->Release(); pgeom->nRefCount=0; pgeom->V=1e10f;
3886 pe_geomparams gp; gp.pos=c+g*bott; gp.q=Quat::CreateRotationV0V1(Vec3(0,0,-1),g);
3887 idGnd = AddGeometry(pgeom,&gp);
3890 AllocStructureInfo();
3891 sampleJoint.maxForcePull=1e5f; sampleJoint.maxForcePush=4e5f; sampleJoint.maxForceShift=2e5f;
3892 sampleJoint.maxTorqueBend=1e5f; sampleJoint.maxTorqueTwist=2e5f;
3893 sampleJoint.size=0.05f;
3894 for(i=0,nFakeJoints=m_pStructure->nJoints; i<m_pStructure->nJoints; i++) if (m_pStructure->pJoints[i].bBroken) {
3895 SStructuralJoint jnt = m_pStructure->pJoints[i];
3896 m_pStructure->pJoints[i--] = m_pStructure->pJoints[m_pStructure->nJoints-1];
3897 m_pStructure->pJoints[--m_pStructure->nJoints] = jnt;
3899 nFakeJoints-=m_pStructure->nJoints;
3900 pFakeJoints = new SStructuralJoint[max(1,nFakeJoints)];
3901 memcpy(pFakeJoints, m_pStructure->pJoints+m_pStructure->nJoints, nFakeJoints*sizeof(SStructuralJoint));
3902 for(i=0;i<nFakeJoints;i++) for(j=0;j<2;j++) {
3903 i1 = pFakeJoints[i].ipart[j]<0 ? 0 :
3904 GetMatId(m_parts[pFakeJoints[i].ipart[j]].pPhysGeom->pGeom->GetPrimitiveId(0,0), pFakeJoints[i].ipart[j]);
3905 (pFakeJoints[i].bBreakable<<=16) |= i1;
3907 for(i=j=0,rareaAvg=1e-10f;i<m_nParts;i++) if (m_parts[i].mass>0) {
3908 m_parts[i].pPhysGeom->pGeom->GetBBox(&abox); j++;
3909 rareaAvg += min(min(abox.size.x*abox.size.y,abox.size.x*abox.size.z),abox.size.y*abox.size.z)*sqr(m_parts[i].scale);
3911 rareaAvg = j*0.25f/rareaAvg;
3912 psj.id = 1000;
3914 for(i=0;i<m_nParts;i++) if (m_parts[i].mass>0) {
3915 gwd[0].R = Matrix33(m_parts[i].q);
3916 m_pWorld->GetEntitiesAround(m_parts[i].BBox[0],m_parts[i].BBox[1],pentlist,1<<m_iSimClass);
3917 for(int j0=GetUsedPartsCount(iCaller)-1; j0>=0; j0--) {
3918 j = GetUsedPart(iCaller,j0);
3919 if (m_parts[i].mass>m_parts[j].mass && m_parts[j].mass>0 || m_pStructure->pParts[j].bGroup)
3920 continue;
3921 for(i1=m_pStructure->nJoints-1; i1>=0; i1--) {
3922 int icode = m_pStructure->pJoints[i1].ipart[1]<<16 | m_pStructure->pJoints[i1].ipart[0];
3923 if (icode==(i<<16|j) || icode==(j<<16|i))
3924 break;
3926 if (i1>=0 || i==j)
3927 continue;
3928 gwd[0].offset=m_parts[i].pos;
3929 gwd[1].offset=m_parts[j].pos; gwd[1].R=Matrix33(m_parts[j].q);
3930 gwd[0].scale=m_parts[i].scale; gwd[1].scale=m_parts[j].scale;
3931 i1 = isneg(m_parts[j].pPhysGeom->V-m_parts[i].pPhysGeom->V);
3932 float dscale = 0.01f;
3933 gwd[i1].offset -= gwd[i1].R*m_parts[i+(j-i&-i1)].pPhysGeom->origin*(gwd[i1].scale*dscale);
3934 gwd[i1].scale *= 1+dscale;
3935 float areai,areaj,area;
3936 m_parts[i].pPhysGeom->pGeom->GetBBox(&abox);
3937 areai = min(min(abox.size.x*abox.size.y,abox.size.x*abox.size.z),abox.size.y*abox.size.z)*sqr(m_parts[i].scale)*4;
3938 if (ncont=m_parts[i].pPhysGeom->pGeom->Intersect(m_parts[j].pPhysGeom->pGeom, gwd,gwd+1, &ip, pcontacts)) {
3939 psj.partid[0]=m_parts[i].id; psj.partid[1]=m_parts[j].id;
3940 if (m_parts[j].mass>0) {
3941 m_parts[j].pPhysGeom->pGeom->GetBBox(&abox);
3942 areaj = min(min(abox.size.x*abox.size.y,abox.size.x*abox.size.z),abox.size.y*abox.size.z)*sqr(m_parts[j].scale)*4;
3943 } else
3944 areaj = areai;
3945 for(psj.pt.zero(),psj.n.zero(),i1=0,area=0; i1<ncont; i1++) {
3946 Vec3 axx=pcontacts[i1].n.GetOrthogonal().normalized(), axy=pcontacts[i1].n^axx, pt;
3947 int npt = min(pcontacts[i1].nborderpt, (int)(CRY_ARRAY_COUNT(pt2d)));
3948 for(j1=0; j1<npt; j1++)
3949 pt=pcontacts[i1].ptborder[j1]-pcontacts[i1].center, pt2d[j1].pt.set(axx*pt,axy*pt);
3950 if (!pcontacts[i1].bBorderConsecutive)
3951 npt = qhull2d(pt2d,npt,edge2d);
3952 else for(j1=0,edge2d[npt-1].next=edge2d,edge2d[npt-1].pvtx=pt2d+npt-1; j1<npt-1; j1++)
3953 edge2d[j1].pvtx=pt2d+j1, edge2d[j1].next=edge2d+j1+1;
3954 for(edgeitem *edge=edge2d+(j1=0); j1<npt; j1++,edge=edge->next)
3955 area += fabs_tpl(edge->next->pvtx->pt^edge->pvtx->pt);
3956 psj.pt += pcontacts[i1].center; psj.n -= pcontacts[i1].n;
3958 if ((area*=0.5f) < min(areai,areaj)*0.1f)
3959 continue;
3960 psj.pt /= ncont; psj.n.normalize();
3961 int icodeMat = GetMatId(m_parts[i].pPhysGeom->pGeom->GetPrimitiveId(0,0),i)<<16 |
3962 GetMatId(m_parts[j].pPhysGeom->pGeom->GetPrimitiveId(0,0),j);
3963 int icodeMat1 = icodeMat>>16 | icodeMat<<16;
3964 for(i1=0,pJoint=&sampleJoint,ihead=5; i1<nFakeJoints; i1++) if (pFakeJoints[i1].id!=joint_impulse) {
3965 int icode = pFakeJoints[i1].ipart[1]<<16 | pFakeJoints[i1].ipart[0];
3966 if (icode==(i<<16|j) || icode==(j<<16|i)) {
3967 pJoint=pFakeJoints+i1; break; // same two parts
3969 if ((icode&0xFFFF)==i || (icode&0xFFFF)==j || (icode>>16)==i || (icode>>16)==j) {
3970 pJoint=pFakeJoints+i1; ihead=1; continue; // either of the parts is the same
3972 icode = 0;
3973 if (pFakeJoints[i1].ipart[0]>=0)
3974 icode = GetMatId(m_parts[pFakeJoints[i1].ipart[0]].pPhysGeom->pGeom->GetPrimitiveId(0,0), pFakeJoints[i1].ipart[0]);
3975 if (pFakeJoints[i1].ipart[1]>=0)
3976 icode |=GetMatId(m_parts[pFakeJoints[i1].ipart[1]].pPhysGeom->pGeom->GetPrimitiveId(0,0), pFakeJoints[i1].ipart[1])<<16;
3977 if (ihead>2 && (pFakeJoints[i].bBreakable==icodeMat || pFakeJoints[i].bBreakable==(icodeMat>>16|icodeMat<<16)))
3978 pJoint=pFakeJoints+i1, ihead=2; // both mat.ids are the same
3979 else if (((pFakeJoints[i1].bBreakable&0xFFFF)==(icodeMat&0xFFFF) || (pFakeJoints[i1].bBreakable>>16)==(icodeMat>>16) ||
3980 (pFakeJoints[i1].bBreakable>>16)==(icodeMat&0xFFFF) || (pFakeJoints[i1].bBreakable&0xFFFF)==(icodeMat>>16)) && ihead>3)
3981 pJoint=pFakeJoints+i1, ihead=3; // either of mat.ids is the same
3982 else if (ihead>4)
3983 pJoint=pFakeJoints+i1, ihead=4; // just any sample joint
3985 float s = min(10.0f,max(0.1f,area*rareaAvg));
3986 psj.maxForcePull=pJoint->maxForcePull*s; psj.maxForcePush=pJoint->maxForcePush*s; psj.maxForceShift=pJoint->maxForceShift*s;
3987 psj.maxTorqueBend=pJoint->maxTorqueBend*s; psj.maxTorqueTwist=pJoint->maxTorqueTwist*s;
3988 psj.szSensor=pJoint->size;
3989 SetParams(&psj); psj.id++;
3994 float *pScale,*pScaleNorm,weight;
3995 memset(pScale=new float[m_pStructure->nJoints+1], 0, m_pStructure->nJoints*sizeof(float));
3996 memset(pScaleNorm=new float[m_pStructure->nJoints+1], 0, m_pStructure->nJoints*sizeof(float));
3997 ++m_pWorld->m_vars.bLogLatticeTension;
3998 m_pStructure->bTestRun = 1;
4000 for(i=0; i<nFakeJoints; i++) if (pFakeJoints[i].id==joint_impulse) {
4001 j = pFakeJoints[i].ipart[0];
4002 Vec3 impulse = m_qrot*pFakeJoints[i].n*pFakeJoints[i].maxTorqueBend;
4003 m_pStructure->pParts[j].Pext += impulse;
4004 m_pStructure->pParts[j].Lext += m_qrot*(pFakeJoints[i].pt-m_parts[j].q*m_parts[j].pPhysGeom->origin*m_parts[j].scale-m_parts[j].pos) ^ impulse;
4005 UpdateStructure(0.01f,0,-1,m_pWorld->m_vars.gravity);
4006 if (g_nPartsAlloc < m_nParts || !m_pStructure->nJoints)
4007 break;
4009 quotientf maxtens(0.0f,1.0f);
4010 for(i1=0; i1<m_pStructure->nLastUsedJoints; i1++)
4011 maxtens = max(maxtens, g_jointsDbg[i1].tension);
4012 maxtens.x = sqrt_tpl(maxtens.val());
4013 for(i1=0;i1<m_nParts;i1++) g_parts[i1].bProcessed=0;
4014 g_parts[g_parts[ihead=0].idx = j].isle = 0;
4015 g_parts[-1].bProcessed = 1;
4016 for(g_parts[g_parts[ihead].idx].bProcessed=1,itail=ihead+1; ihead<itail; ihead++) {
4017 for(j=g_parts[g_parts[ihead].idx].ijoint0,weight=1.0f/max(1e-10f,(float)g_parts[g_parts[ihead].idx].isle); j<g_parts[g_parts[ihead].idx+1].ijoint0; j++) {
4018 i1 = m_pStructure->pJoints[g_jointidx[j]].ipart[0] + m_pStructure->pJoints[g_jointidx[j]].ipart[1] - g_parts[ihead].idx;
4019 pScale[g_jointidx[j]]+=maxtens.x*weight; pScaleNorm[g_jointidx[j]]+=weight;
4020 if (!g_parts[i1].bProcessed) {
4021 g_parts[itail++].idx=i1; g_parts[i1].bProcessed=1; g_parts[i1].isle=g_parts[g_parts[ihead].idx].isle+1;
4024 if (ihead+1==itail && itail<m_nParts) for(i1=0;i1<m_nParts;i1++) {
4025 g_parts[itail].idx=i1; itail += (g_parts[i1].bProcessed^1);
4026 g_parts[i1].bProcessed=1; g_parts[i1].isle=m_nParts;
4030 --m_pWorld->m_vars.bLogLatticeTension;
4031 m_pStructure->bTestRun = 0;
4032 m_pWorld->UnmarkEntityAsDeforming(this);
4034 for(i=0; i<m_pStructure->nJoints; i++) if (pScaleNorm[i]>0) {
4035 float scale = pScale[i]/pScaleNorm[i];
4036 m_pStructure->pJoints[i].maxForcePull*=scale; m_pStructure->pJoints[i].maxForcePush*=scale; m_pStructure->pJoints[i].maxForceShift*=scale;
4037 m_pStructure->pJoints[i].maxTorqueBend*=scale; m_pStructure->pJoints[i].maxTorqueTwist*=scale;
4039 delete[] pFakeJoints; delete[] pScale; delete[] pScaleNorm;
4040 RemoveGeometry(idGnd);
4041 m_pStructure->bModified = 1;
4042 return m_pStructure->nJoints;