1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
9 #include "physicalplaceholder.h"
10 #include "physicalentity.h"
12 #include "physicalworld.h"
13 #include "tetrlattice.h"
16 #include "singleboxtree.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()
53 CPhysicalEntity::CPhysicalEntity(CPhysicalWorld
*pworld
, IGeneralMemoryHeap
* pHeap
)
56 , m_flags(pef_pushable_by_players
| pef_traceable
| pef_never_affect_triggers
| pef_never_break
)
68 , m_next_coll(nullptr)
69 , m_next_coll1(nullptr)
70 , m_next_coll2(nullptr)
73 , m_pColliders(nullptr)
75 , m_nCollidersAlloc(0)
78 , m_pOuterEntity(nullptr)
82 , m_timeStructUpdate(0.0f
)
92 , m_pUsedParts(nullptr)
94 , m_pStructure(nullptr)
96 //CPhysicalPlaceholder
97 static_assert(CRY_ARRAY_COUNT(m_BBox
) == 2, "Invalid array size!");
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
;
106 m_pForeignData
= nullptr;
107 m_iForeignData
= m_iForeignFlags
= 0;
108 m_pEntBuddy
= nullptr;
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()
124 m_pHeap
->Free(m_pUsedParts
);
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
)
141 m_pHeap
->Free(m_parts
);
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
;
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();
178 int CPhysicalEntity::AddRef() {
179 if (IsPODThread(m_pWorld
) && m_pWorld
->m_lockPODGrid
) {
180 if (m_iLastPODUpdate
==m_pWorld
->m_iLastPODUpdate
)
182 m_iLastPODUpdate
= m_pWorld
->m_iLastPODUpdate
;
185 AtomicAdd(&m_nRefCount
, 1);
189 int CPhysicalEntity::Release() {
190 if (IsPODThread(m_pWorld
) && m_pWorld
->m_lockPODGrid
) {
191 if (m_iLastPODUpdate
==m_pWorld
->m_iLastPODUpdate
)
193 m_iLastPODUpdate
= m_pWorld
->m_iLastPODUpdate
;
194 if (m_nRefCountPOD
<=0)
198 AtomicAdd(&m_nRefCount
, -1);
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
;
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
);
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
);
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
);
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);
266 switch((pGeom
[0] = m_parts
[i
].pPhysGeom
->pGeom
)->GetType()) {
268 CSphereGeom
*pSph
= (CSphereGeom
*)pGeom
[0]; sph
.center
=pSph
->m_sphere
.center
; sph
.r
=pSph
->m_sphere
.r
;
271 CCapsuleGeom
*pCaps
= (CCapsuleGeom
*)pGeom
[0]; sph
.center
=pCaps
->m_cyl
.center
; sph
.r
=pCaps
->m_cyl
.hh
+pCaps
->m_cyl
.r
;
274 box abox
; pGeom
[0]->GetBBox(&abox
); sph
.center
=abox
.center
; sph
.r
=max(max(abox
.size
.x
,abox
.size
.y
),abox
.size
.z
);
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];
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();
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
++) {
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
);
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
++;
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
);
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
;
395 *(m_pSyncCoords
= new coord_block
) = { m_pos
,m_qrot
};
397 if (!is_unused(params
->scale
)) {
398 if (params
->bRecalcBounds
) {
402 BBox
[0]=Vec3(VMAX
); BBox
[1]=Vec3(VMIN
);
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
;
409 pGeom
[j
]->GetBBox(&abox
);
410 R
= Matrix33(cnew
.q
*m_parts
[i
].q
);
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
);
417 } while(pGeom
[j
]!=pGeom
[j
-1]);
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
;
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
) {
449 if (params
->bEntGridUseOBB
&& !m_pStructure
)
450 bPosChanged
= m_pWorld
->RepositionEntity(this,5,BBox
);
453 m_pWorld
->UnlockGrid(this,-bPosChanged
);
456 if (params
->bRecalcBounds
)
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);
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
);
476 m_pWorld
->UnlockGrid(this,-bPosChanged
);
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
];
495 if (params
->pMatMapping
&& params
->nMats
>0)
496 memcpy(m_parts
[i
].pMatMapping
, params
->pMatMapping
, params
->nMats
*sizeof(int));
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
)
509 if (is_unused(params
->ipart
))
510 for(i
=0;i
<m_nParts
&& m_parts
[i
].id
!=params
->partid
;i
++);
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
);
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
;
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
];
591 if (params
->pMatMapping
&& params
->nMats
>0)
592 memcpy(m_parts
[i
].pMatMapping
, params
->pMatMapping
, params
->nMats
*sizeof(int));
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
)
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) {
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;
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
;
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
) {
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
)
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();
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
;
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
);
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
;
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
;
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
;
722 m_pWorld
->RepositionEntity(this,1|8);
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
;
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) {
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
;
750 if (_params
->type
==pe_params_structural_joint::type_id
) {
751 pe_params_structural_joint
*params
= (pe_params_structural_joint
*)_params
;
754 if (!is_unused(params
->idx
) && params
->idx
==-1) {
756 if (!is_unused(params
->partidEpicenter
)) m_pStructure
->idpartBreakOrg
= params
->partidEpicenter
;
757 m_pWorld
->MarkEntityAsDeforming(this);
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
)
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
;
824 m_pStructure
->pJoints
[i
].bBroken
= params
->bBroken
;
825 m_pStructure
->idpartBreakOrg
= params
->partidEpicenter
;
827 m_pWorld
->MarkEntityAsDeforming(this);
830 m_pStructure
->pJoints
[i
].bBroken
= 0;
831 MEMSTAT_USAGE(m_pStructure
->pJoints
, sizeof(m_pStructure
->pJoints
[0]) * m_pStructure
->nJoints
);
835 if (_params
->type
==pe_params_structural_initial_velocity::type_id
) {
836 pe_params_structural_initial_velocity
*params
= (pe_params_structural_initial_velocity
*)_params
;
839 for(i
=0; i
<m_nParts
&& m_parts
[i
].id
!=params
->partid
; i
++);
841 m_pStructure
->pParts
[i
].initialVel
= params
->v
;
842 m_pStructure
->pParts
[i
].initialAngVel
= params
->w
;
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
;
855 if (_params
->type
==pe_params_skeleton::type_id
) {
856 pe_params_skeleton
*params
= (pe_params_skeleton
*)_params
;
858 if (!is_unused(params
->ipart
))
860 else if (!is_unused(params
->partid
))
861 for(i
=m_nParts
-1;i
>=0 && params
->partid
!=m_parts
[i
].id
;i
--);
864 if ((unsigned int)i
>=(unsigned int)m_nParts
|| !m_pStructure
|| !m_pStructure
->defparts
|| !m_pStructure
->defparts
[i
].pSkelEnt
)
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
);
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];
900 if (_params
->type
==pe_params_outer_entity::type_id
) {
901 ((pe_params_outer_entity
*)_params
)->pOuterEntity
= m_pOuterEntity
;
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
;
914 if (_params
->type
==pe_params_pos::type_id
) {
915 pe_params_pos
*params
= (pe_params_pos
*)_params
;
919 params
->iSimClass
= m_iSimClass
;
920 params
->pGridRefEnt
= m_pWorld
->GetGrid(this);
921 params
->doubleBufCoords
= m_pSyncCoords
!=(coord_block
*)&m_pos
;
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
);
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
)
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
;
939 (*params
->pMtx3x4
= Matrix33(m_parts
[i
].q
)*m_parts
[i
].scale
).SetTranslation(m_parts
[i
].pos
);
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
);
962 if (_params
->type
==pe_params_flags::type_id
) {
963 ((pe_params_flags
*)_params
)->flags
= m_flags
;
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
;
974 if (_params
->type
==pe_params_ground_plane::type_id
) {
975 pe_params_ground_plane
*params
= (pe_params_ground_plane
*)_params
;
977 if (params
->iPlane
>=m_nGroundPlanes
)
979 params
->ground
.origin
= m_ground
[params
->iPlane
].origin
;
980 params
->ground
.n
= m_ground
[params
->iPlane
].n
;
984 if (_params
->type
==pe_params_structural_joint::type_id
) {
985 pe_params_structural_joint
*params
= (pe_params_structural_joint
*)_params
;
989 if (!is_unused(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
)
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
;
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
;
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
;
1025 if (_params
->type
==pe_params_skeleton::type_id
) {
1026 pe_params_skeleton
*params
= (pe_params_skeleton
*)_params
;
1028 if (!is_unused(params
->ipart
))
1030 else if (!is_unused(params
->partid
))
1031 for(i
=m_nParts
-1;i
>=0 && params
->partid
!=m_parts
[i
].id
;i
--);
1034 if ((unsigned int)i
>=(unsigned int)m_nParts
|| !m_pStructure
|| !m_pStructure
->defparts
|| !m_pStructure
->defparts
[i
].pSkelEnt
)
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
;
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
);
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;
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
;
1074 status
->pGeom
= m_parts
[0].pPhysGeom
->pGeom
;
1075 status
->pGeomProxy
= m_parts
[0].pPhysGeomProxy
->pGeom
;
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
;
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
;
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
;
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
)));
1115 status
->pGridRefEnt
= m_pWorld
->GetGrid(this);
1117 status
->pos
= respos
;
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
);
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
;
1134 for(ipart
=0;ipart
<m_nParts
-1 && m_parts
[ipart
].id
!=status
->partid
;ipart
++);
1135 if (ipart
>=m_nParts
)
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)
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;
1146 if (_status
->type
==pe_status_nparts::type_id
)
1149 if (_status
->type
==pe_status_awake::type_id
)
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;
1161 if (_status
->type
==pe_status_constraint::type_id
&& IsPortal(this)) {
1162 ((pe_status_constraint
*)_status
)->pBuddyEntity
= m_pEntBuddy
;
1166 if (_status
->type
==pe_status_extent::type_id
)
1168 pe_status_extent
*status
= (pe_status_extent
*)_status
;
1169 status
->extent
= GetExtent(status
->eForm
);
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
);
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
;
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
)) {
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
)
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
);
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
;
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
);
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);
1282 if (_action
->type
==pe_action_awake::type_id
&& m_iSimClass
>=0 && m_iSimClass
<7) {
1283 Awake(((pe_action_awake
*)_action
)->bAwake
,1);
1286 if (_action
->type
==pe_action_remove_all_parts::type_id
) {
1288 RemoveGeometry(m_parts
[m_nParts
-1].id
);
1292 if (_action
->type
==pe_action_reset_part_mtx::type_id
) {
1293 pe_action_reset_part_mtx
*action
= (pe_action_reset_part_mtx
*)_action
;
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
))
1301 pp
.pos
= m_pos
+m_qrot
*m_parts
[i
].pos
;
1302 pp
.q
= m_qrot
*m_parts
[i
].q
;
1303 pp
.bRecalcBounds
= 2;
1309 ppt
.q
.SetIdentity();
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
;
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
;
1331 m_flags
|= aef_recorded_physics
;
1333 if (m_pStructure
&& m_flags
& aef_recorded_physics
)
1334 m_pStructure
->autoDetachmentDist
= action
->autoDetachmentDist
;
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
;
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
;
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
) {
1367 psj
.partid
[iop
^1] = m_parts
[ibuddy
].id
+action
->idOffset
;
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
;
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
);
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;
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
);
1412 float CPhysicalEntity::GetExtent(EGeomForm eForm
) const
1414 CGeomExtent
& ext
= m_Extents
.Make(eForm
);
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
) );
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
)
1444 bool CPhysicalEntity::OccupiesEntityGridSquare(const AABB
&bbox
)
1446 if (m_pWorld
->m_vars
.bEntGridUseOBB
) {
1447 const Vec3
*BBox
= (const Vec3
*)&bbox
;
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
;
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
);
1466 if (box_box_overlap_check(&abox
,&bbox
,&Overlapper
))
1469 } while(pGeom
[j
]!=pGeom
[j
-1]);
1476 void CPhysicalEntity::UpdatePartIdmatBreakable(int ipart
, int nParts
)
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);
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);
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);
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
)
1518 ChangeRequest
<pe_geomparams
> req(this,m_pWorld
,params
,bThreadSafe
,pgeom
,id
);
1519 if (req
.IsQueued()) {
1520 WriteLock
lock(m_lockPartIdx
);
1522 *((int*)req
.GetQueuedStruct()-1) = id
= m_iLastIdx
++;
1524 m_iLastIdx
= max(m_iLastIdx
,id
+1);
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
++);
1531 if (params
->flags
& geom_proxy
) {
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
);
1539 m_pWorld
->UnlockGrid(this,-bPosChanged
);
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
;
1568 m_pHeap
->Free(pparts
);
1570 m_pWorld
->FreeEntityParts(pparts
, nPartsAlloc
);
1571 if (m_nPartsAlloc
!=1) { MEMSTAT_USAGE(m_parts
, sizeof(geom
) * m_nParts
); }
1573 { WriteLock
lock(m_lockPartIdx
);
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
));
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));
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);
1609 UpdatePartIdmatBreakable(0,2);
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
);
1617 pMesh
->RebuildBVTree();
1618 //pMesh->m_lockUpdate;
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
;
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;
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
) {
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
);
1650 WriteLock
lock(m_lockUpdate
);
1654 if (m_nPartsAlloc
!=1) { MEMSTAT_USAGE(m_parts
, sizeof(geom
) * m_nParts
); }
1662 void CPhysicalEntity::RemoveGeometry(int id
, int bThreadSafe
)
1664 ChangeRequest
<void> req(this,m_pWorld
,0,bThreadSafe
,0,id
);
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();
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
;
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);
1725 m_pWorld
->DestroyPhysicalEntity(ppc
,0,1);
1729 // keep the original bounding box while RepositionEntity emits the signal and substitute at the end
1731 ComputeBBox(newBBox
);
1732 m_pWorld
->RepositionEntity(this,1|8,newBBox
);
1733 m_BBox
[0] = newBBox
[0];
1734 m_BBox
[1] = newBBox
[1];
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
))
1759 void CPhysicalEntity::AlertNeighbourhoodND(int mode
)
1761 if (m_pOuterEntity
&& !m_pWorld
->m_bMassDestruction
) {
1762 m_pOuterEntity
->Release();
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();
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);
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
;
1814 int CPhysicalEntity::AddCollider(CPhysicalEntity
*pCollider
)
1816 PREFAST_ASSUME(pCollider
);
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
++);
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();
1835 void CPhysicalEntity::DrawHelperInformation(IPhysRenderer
*pRenderer
, int flags
)
1837 //ReadLock lock(m_lockUpdate);
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
;
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;
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) {
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
) {
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};
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
) {
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;
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
) {
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
);
1977 pSizer
->AddObject(m_pColliders
, m_nCollidersAlloc
*sizeof(m_pColliders
[0]));
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]));
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
);
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
) {}
2035 int CPhysicalEntity::GetStateSnapshotTxt(char *txtbuf
,int szbuf
, float time_back
)
2037 const int version
= 0;
2038 SMemSerializer mser
;
2040 for(int i
=0,j
=version
,j10
; i
<4; i
++,j
=j10
)
2041 j10
=j
/10, txtbuf
[3-i
]=j
-(j10
*10)+'0';
2045 if (txtbuf
) *txtbuf
++='~'; szbuf
--;
2046 CPhysicalEntity::GetStateSnapshot(TSerialize(&mser
));
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];
2064 CPhysicalEntity::SetStateFromSnapshot(TSerialize(&mser
));
2066 SetStateFromSnapshot(TSerialize(&mser
));
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
;
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
);
2093 g_parts
[i
].isle
= nIsles
;
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
;
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
)
2112 int i
,j
,iprim
,iClosest
,iter
=0;
2113 float dist
,minDist
,tol
,maxDist
,massCheck
=0.0f
;
2114 geom_world_data gwd
;
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
));
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
;
2140 } while (minDist
>tol
&& ++iter
<2);
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
;
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
;
2166 Vec3 org
,sz
,n
,P
,L
,dw
,dv
,Ptang
,Pmax
,Lmax
,BBoxNew
[2];
2168 CSphereGeom sphGeom
;
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
;
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
;
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)
2202 { ReadLock
lockUpd(m_lockUpdate
);
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;
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
);
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
);
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;
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
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
++);
2329 g_parts
[ihead
].idx
= i
;
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
;
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
;
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
;
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;
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;
2467 bBroken
-= nIsles
-1>>31;
2469 if (ihead
>=m_nParts
+1)
2471 for(i
=0;i
<m_nParts
&& (g_parts
[i
].bProcessed
|| g_parts
[i
].Minv
>0);i
++);
2473 for(i
=0;i
<m_nParts
&& g_parts
[i
].bProcessed
;i
++);
2478 g_parts
[g_parts
[ihead
].idx
= i
].bProcessed
= 1;
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
))
2491 epcep
.pLastUpdate
= 0;
2493 epcep
.iReason
= EventPhysCreateEntityPart::ReasonJointsBroken
;
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
)
2504 epcep
.pEntNew
= m_pWorld
->CreatePhysicalEntity(PE_RIGID
,&pp
,0,0x5AFE);
2505 asv
.v
.zero(); asv
.w
.zero(); t
=0;
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
;
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
);
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;
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);
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
)) {
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
;
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
)
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);
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
)) {
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
]);
2706 epjb
.partid
[j
^i0
] = epjb
.partmat
[j
^i0
] = -1;
2707 m_pWorld
->OnEvent(m_pWorld
->m_vars
.bLogStructureChanges
+1,&epjb
);
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
;
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)
2726 eprep
.idOffs
= min(eprep
.idOffs
,m_parts
[i
].id
);
2728 idRemoveGeoms
[nRemoveGeoms
] = m_parts
[i
].id
; pRemoveGeoms
[nRemoveGeoms
++] = m_parts
[i
].pPhysGeom
; j
++;
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
);
2742 m_pStructure
->bModified
+= bBroken
;
2743 if (m_nParts
-nRemoveGeoms
==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
;
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
;
2784 expl
.rmin
= m_pExpl
->rmin
;
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
);
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"))));
2806 if (pMeshNew
= ((CTriMesh
*)m_parts
[i
].pPhysGeomProxy
->pGeom
)->SplitIntoIslands(ground
,nPlanes
,GetType()==PE_RIGID
)) {
2808 if (m_parts
[i
].pLattice
) {
2809 for(j
=0,pMesh
=pMeshNew
; pMesh
; pMesh
=(CTriMesh
*)pMesh
->GetForeignData(-2),j
++);
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;
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);
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;
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 ||
2864 gp
.flags
=gp
.flagsCollider
=0; gp
.idmatBreakable
=-1;
2865 gp
.density
=0, epcep
.bInvalid
=1;
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
));
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);
2880 epcep
.partidNew
= 0;
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;
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;
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);
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;
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
) {
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
;
2988 asv
.v
= sd
.v
+(sd
.w
^org
-sd
.centerOfMass
);
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();
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
;
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
;
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
;
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
;
3069 m_parts
[i
].flags
&= ~geom_constraint_on_break
;
3071 epcep
.cutDirLoc
[1].zero();
3074 pe_simulation_params sp
;
3076 epcep
.pEntNew
->SetParams(&sp
);
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;
3098 pents
[i1
]->OnNeighbourSplit(this,(CPhysicalEntity
*)epcep
.pEntNew
);
3099 } else if (epcep
.pEntNew
&& epcep
.pEntNew
!=this)
3100 m_pWorld
->DestroyPhysicalEntity(epcep
.pEntNew
,0,1);
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
;
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;
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
++;
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
)
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);
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
;
3185 memcpy(&ppos
.pos
, &m_pos
, sizeof(m_pos
)); // gcc workaround
3186 memcpy(&ppos
.q
, &m_qrot
, sizeof(m_qrot
));
3187 pent
->SetParams(&ppos
);
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();
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;
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();
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
);
3235 return (i0
==0 && m_updStage
==0) || flags
& geom_structure_changes
;
3239 void CPhysicalEntity::OnContactResolved(entity_contact
*pContact
, int iop
, int iGroupId
)
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);
3251 n
= pContact
->vreq
*pContact
->nloc
.x
;//pContact->K(0,0);
3253 rope_solver_vtx
&svtx
= ((rope_solver_vtx
*)pContact
->pBounceCount
)[iop
-2];
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
);
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();
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');
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
);
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));
3343 ser
.Value("usedParts", (const char*)buf
);
3346 if (!m_pStructure
|| !m_pStructure
->defparts
)
3347 ser
.Value("hasDfm", bVal
=false);
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
);
3358 int CPhysicalEntity::SetStateFromSnapshot(TSerialize ser
, int flags
)
3360 if (ser
.GetSerializationTarget()!=eST_Network
)
3363 ser
.Value("hasJoints", bVal
, 'bool');
3366 pe_params_structural_joint psj
;
3367 psj
.bReplaceExisting
= true;
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
);
3395 m_pStructure
->bModified
= 1;
3396 string str
; ser
.Value("usedParts", str
);
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
);
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
);
3431 int CPhysicalEntity::TouchesSphere(const Vec3
¢er
, float r
)
3433 ReadLock
lock(m_lockUpdate
);
3435 geom_world_data gwd
[2];
3436 intersection_params ip
;
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
))
3459 CTriMesh
*g_pSliceMesh
= 0;
3461 int CPhysicalEntity::CapsulizePart(int ipart
)
3464 caps_piece pieceBuf
[16],*pieces
=pieceBuf
;
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)
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
;
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);
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
);
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;
3511 if (pGeom
->Intersect(g_pSliceMesh
, 0,&gwd
, &ip
,pcont
)) {
3512 if (!pcont
[0].nborderpt
)
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());
3519 r0
/= pcont
[0].nborderpt
;
3520 if (r0
-rmin
> r0
*0.4f
&& i
==0)
3521 gwd
.offset
+= axis
*(bbox
.size
[iax
]*0.9f
);
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
;
3532 for(i
=0; i
<nSlices
; i
++,gwd
.offset
+=axis
*step
) {
3533 if (!(icnt
=pGeom
->Intersect(g_pSliceMesh
, 0,&gwd
, &ip
,pcont
)))
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
];
3542 ptcPrev
= pcont
[0].center
;
3543 ptcPrev
= m_parts
[ipart
].q
*ptcPrev
*m_parts
[ipart
].scale
;
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
);
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
)
3563 caps
.hh
= (ptcCur
-ptcPrev
).len()*0.5f
;
3566 gp
.pos
= (ptcPrev
+ptcCur
)*0.5f
;
3567 axcaps
= (ptcCur
-ptcPrev
)/(caps
.hh
*2);
3568 gp
.q
= Quat::CreateRotationV0V1(Vec3(0,0,1), axcaps
);
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
));
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
;
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
)
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)
3601 CryInterlockedDecrement((volatile int*) &pgeom
->nRefCount
);
3603 m_parts
[ipart
].flags
&= ~geom_colltype_solid
;
3604 m_parts
[ipart
].flagsCollider
= 0;
3606 if (pieces
!=pieceBuf
)
3612 bool CPhysicalEntity::MakeDeformable(int ipart
, int iskel
, float r
)
3614 if (((CGeometry
*)m_parts
[iskel
].pPhysGeom
->pGeom
)->IsAPrimitive())
3616 int i
,j
,bPrimitive
=((CGeometry
*)m_parts
[ipart
].pPhysGeom
->pGeom
)->IsAPrimitive();
3617 geom_world_data gwd
[2];
3618 float thickness
=0,r0
;
3621 geom_contact
*pcontact
;
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
);
3628 if (!(m_parts
[ipart
].flags
& geom_can_modify
))
3630 m_pWorld
->ClonePhysGeomInEntity(this, ipart
, m_pWorld
->CloneGeometry(m_parts
[ipart
].pPhysGeom
->pGeom
));
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
;
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];
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();
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]));
3662 pski
->pSkinInfo
[i
].itri
= -1;
3665 m_pStructure
->defparts
[ipart
].pSkinInfo
= new SSkinInfo
[1];
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
);
3680 aap
.partid
= m_parts
[ipart
].id
;
3684 pe_simulation_params sp
;
3685 pe_params_softbody psb
;
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
;
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
;
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
;
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
;
3731 void CPhysicalEntity::UpdateDeformablePart(int ipart
)
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;
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);
3798 if (!m_pUsedParts
) {
3800 m_pUsedParts
= (int(*)[16])m_pHeap
->Malloc(sizeof(int) * MAX_TOT_THREADS
* 16, "Used parts");
3802 m_pUsedParts
= new int[MAX_TOT_THREADS
][16];
3803 memset(m_pUsedParts
, 0, sizeof(*m_pUsedParts
));
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
);
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
;
3844 edgeitem edge2d
[64];
3847 ushort idxGnd
[] = { 0,1,2 };
3849 for(i
=m_nParts
-1;i
>=0 && m_parts
[i
].mass
>0;i
--);
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
;
3853 for(j
=0;j
<m_nParts
;j
++) {
3854 Vec3 gpart
= g
*m_parts
[j
].q
;
3855 switch (m_parts
[j
].pPhysGeom
->pGeom
->GetType()) {
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
;
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
;
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
;
3871 const sphere
*psph
= (const sphere
*)m_parts
[j
].pPhysGeom
->pGeom
->GetData();
3872 ptbott
= psph
->center
+gpart
*psph
->r
;
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
]];
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
;
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
)
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
))
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;
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
)
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
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
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
)
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
;