1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "MiscEntities.h"
5 #include "GameEngine.h"
6 #include "Objects/DisplayContext.h"
8 REGISTER_CLASS_DESC(CWindAreaEntityClassDesc
);
9 REGISTER_CLASS_DESC(CConstraintEntityClassDesc
);
10 REGISTER_CLASS_DESC(CGeomCacheEntityClassDesc
);
11 REGISTER_CLASS_DESC(CJointGenEntityClassDesc
);
13 IMPLEMENT_DYNCREATE(CConstraintEntity
, CEntityObject
)
14 IMPLEMENT_DYNCREATE(CWindAreaEntity
, CEntityObject
)
15 #if defined(USE_GEOM_CACHES)
16 IMPLEMENT_DYNCREATE(CGeomCacheEntity
, CEntityObject
)
18 IMPLEMENT_DYNCREATE(CJointGenEntity
, CEntityObject
)
20 //////////////////////////////////////////////////////////////////////////
22 //////////////////////////////////////////////////////////////////////////
23 static inline void DrawHingeQuad(DisplayContext
& dc
, float angle
)
25 const float len
= 1.0f
;
27 const float halfLen
= len
* 0.5f
;
28 Vec3
vDest(0, len
* cos_tpl(angle
), len
* sin_tpl(angle
));
37 dc
.DrawQuad(p1
, p2
, p3
, p4
);
38 dc
.DrawQuad(p4
, p3
, p2
, p1
);
41 void CConstraintEntity::Display(DisplayContext
& dc
)
43 // CRYIII-1928: disabled drawing while in AI/Physics mode so it doesn't crash anymore
44 if (GetIEditorImpl()->GetGameEngine()->GetSimulationMode())
47 // The pre-allocated array is used as an optimization, trying to avoid the physics system from allocating an entity list.
48 const int nPreAllocatedListSize(1024); //Magic number, probably big enough for the list.
49 IPhysicalEntity
* pPreAllocatedEntityList
[nPreAllocatedListSize
]; //Pre-allocated list.
50 IPhysicalEntity
** pEnts
= pPreAllocatedEntityList
; // Container for the list of entities.
52 CEntityObject::Display(dc
);
54 // get the entities within the proximity radius of the constraint (only when not simulated)
55 Vec3
center(GetWorldPos());
56 Vec3
radVec(m_proximityRadius
);
57 IPhysicalWorld
* pWorld
= GetIEditorImpl()->GetSystem()->GetIPhysicalWorld();
58 // ent_allocate_list is needed to avoid possible crashes, as it could return an internal list (modifiable by other threads).
59 // Notice that in case of refactoring, there is the need to call the DeletePointer method before returning from this function, or memory will leak.
60 int objtypes
= ent_static
| ent_rigid
| ent_sleeping_rigid
| ent_sort_by_mass
| ent_allocate_list
;
61 int nEnts
= pWorld
->GetEntitiesInBox(center
- radVec
, center
+ radVec
, pEnts
, objtypes
, nPreAllocatedListSize
);
69 (pEnts
!= (IPhysicalEntity
**)(-1))
72 m_body0
= nEnts
> 0 ? pEnts
[0] : NULL
;
73 m_body1
= nEnts
> 1 ? pEnts
[1] : NULL
;
75 if (m_body0
== (IPhysicalEntity
*)-1)
80 if (m_body1
== (IPhysicalEntity
*)-1)
86 // determine the reference frame of the constraint and push it onto the display context stack
87 bool useEntityFrame
= GetEntityPropertyBool("bUseEntityFrame");
94 m_body0
->GetStatus(&pos
);
104 m_body1
->GetStatus(&pos
);
109 if (!GetIEditorImpl()->GetGameEngine()->GetSimulationMode())
117 m_qframe
= quaternionf(GetWorldTM());
119 m_qloc0
= !qbody0
* m_qframe
;
120 m_qloc1
= !qbody1
* m_qframe
;
121 m_posLoc
= !qbody0
* (GetWorldPos() - posBody0
);
123 quaternionf qframe0
= qbody0
* m_qloc0
;
124 quaternionf qframe1
= qbody1
* m_qloc1
;
125 // construct 3 orthonormal vectors using the constraint X axis and the constraint position in body0 space (the link vector)
127 Vec3 u
= qframe0
* Vec3(1, 0, 0);
128 Vec3 posFrame
= posBody0
+ qbody0
* m_posLoc
;
129 Vec3 l
= posFrame
- posBody0
;
130 Vec3 v
= l
- (l
* u
) * u
;
133 rot
.SetFromVectors(u
, v
, w
);
134 Matrix34
transform(rot
);
135 transform
.SetTranslation(posFrame
);
136 dc
.PushMatrix(transform
);
138 // X limits (hinge limits)
139 float minLimit
= GetEntityPropertyFloat("x_min");
140 float maxLimit
= GetEntityPropertyFloat("x_max");
141 if (minLimit
< maxLimit
)
144 dc
.SetColor(0.5f
, 0, 0.5f
);
145 DrawHingeQuad(dc
, DEG2RAD(minLimit
));
146 DrawHingeQuad(dc
, DEG2RAD(maxLimit
));
147 // the current X angle
148 quaternionf qrel
= !qframe1
* qframe0
;
150 dc
.SetColor(0, 0, 1);
151 DrawHingeQuad(dc
, angles
.x
);
154 minLimit
= GetEntityPropertyFloat("yz_min");
155 maxLimit
= GetEntityPropertyFloat("yz_max");
156 if (maxLimit
> 0 && minLimit
< maxLimit
)
159 float height
, radius
;
167 const float tanAngle
= fabs(tan_tpl(DEG2RAD(maxLimit
)));
171 radius
= height
* tanAngle
;
176 height
= radius
/ tanAngle
;
178 if (sin(DEG2RAD(maxLimit
)) < 0)
184 const float delta
= 2.0f
* gf_PI
/ divs
;
186 Vec3
p0(height
, radius
, 0);
188 dc
.SetColor(0, 0.5f
, 0.5f
);
189 dc
.SetFillMode(e_FillModeWireframe
);
190 for (int i
= 0; i
< divs
; i
++, angle
+= delta
)
192 Vec3
p(height
, radius
* cos_tpl(angle
), radius
* sin_tpl(angle
));
193 dc
.DrawTri(apex
, p0
, p
);
194 dc
.DrawTri(apex
, p
, p0
);
197 dc
.SetFillMode(e_FillModeSolid
);
201 // draw the body 1 constraint X axis
202 if (minLimit
< maxLimit
)
204 dc
.SetColor(1.0f
, 0.0f
, 0.0f
);
205 Vec3 x1
= qbody1
* m_qloc1
* Vec3(1, 0, 0);
206 dc
.DrawLine(center
, center
+ 2.0f
* x1
);
209 // If we have an entity list pointer, and this list was allocated in the physics system (not our default list)...
213 (pEnts
!= pPreAllocatedEntityList
)
215 (pEnts
!= (IPhysicalEntity
**)(-1))
218 // Delete it from the physics system.
219 gEnv
->pPhysicalWorld
->GetPhysUtils()->DeletePointer(pEnts
);
223 //////////////////////////////////////////////////////////////////////////
224 void CWindAreaEntity::Display(DisplayContext
& dc
)
226 CEntityObject::Display(dc
);
228 IEntity
* pEntity
= GetIEntity();
234 IPhysicalEntity
* pPhysEnt
= pEntity
->GetPhysics();
235 if (pPhysEnt
== NULL
|| pPhysEnt
->GetType() != PE_AREA
)
241 if (pPhysEnt
->GetStatus(&pos
) == 0)
246 Vec3 samples
[8][8][8];
247 QuatT
transform(pos
.pos
, pos
.q
);
248 AABB bbox
= AABB(pos
.BBox
[0], pos
.BBox
[1]);
249 float frameTime
= gEnv
->pTimer
->GetCurrTime();
250 float theta
= frameTime
- floor(frameTime
);
254 fabs_tpl(bbox
.min
.x
- bbox
.max
.x
),
255 fabs_tpl(bbox
.min
.y
- bbox
.max
.y
),
256 fabs_tpl(bbox
.min
.z
- bbox
.max
.z
)
260 for (size_t i
= 0; i
< 8; ++i
)
261 for (size_t j
= 0; j
< 8; ++j
)
262 for (size_t k
= 0; k
< 8; ++k
)
264 area
.ctr
= transform
* Vec3(
265 bbox
.min
.x
+ i
* (len
[0] / 8.f
)
266 , bbox
.min
.y
+ j
* (len
[1] / 8.f
)
267 , bbox
.min
.z
+ k
* (len
[2] / 8.f
));
268 samples
[i
][j
][k
] = (pPhysEnt
->GetStatus(&area
)) ? area
.pb
.waterFlow
: Vec3(0, 0, 0);
271 for (size_t i
= 0; i
< 8; ++i
)
272 for (size_t j
= 0; j
< 8; ++j
)
273 for (size_t k
= 0; k
< 8; ++k
)
275 Vec3 ctr
= transform
* Vec3(
276 bbox
.min
.x
+ i
* (len
[0] / 8.f
),
277 bbox
.min
.y
+ j
* (len
[1] / 8.f
),
278 bbox
.min
.z
+ k
* (len
[2] / 8.f
));
279 Vec3 dir
= samples
[i
][j
][k
].GetNormalized();
280 dc
.SetColor(Col_Red
);
281 dc
.DrawArrow(ctr
, ctr
+ dir
, 1.f
);
285 //////////////////////////////////////////////////////////////////////////
287 void AlignCutTemplate(const IStatObj
* pSrcObj
, const IStatObj
* pObjTpl
, int align
, const Vec3
& tplOffs
, float tplScale
, Matrix33
& R
, Vec3
& offset
, float& scale
);
289 void DrawCutTemplate(DisplayContext
& dc
, IStatObj
* pObj
, const Matrix34
& tmWorld
, const Vec3
& campos
)
291 for (int i
= 0; i
< pObj
->GetSubObjectCount(); i
++)
293 IStatObj::SSubObject
* pSubObj
= pObj
->GetSubObject(i
);
294 if (pSubObj
->pStatObj
&& pSubObj
->pStatObj
->GetPhysGeom())
296 IGeometry
* pGeom
= pSubObj
->pStatObj
->GetPhysGeom()->pGeom
;
297 Matrix34 tm
= tmWorld
* pSubObj
->tm
;
298 Vec3 camposLoc
= tm
.GetInverted() * campos
;
299 switch (pGeom
->GetType())
303 const mesh_data
* md
= (const mesh_data
*)pGeom
->GetData();
304 for (int itri
= 0; itri
< md
->nTris
; itri
++)
306 float dot
= (md
->pVertices
[md
->pIndices
[itri
* 3]] - camposLoc
) * md
->pNormals
[itri
];
307 for (int j
= 0, itri1
; j
< 3; j
++)
308 if ((itri1
= md
->pTopology
[itri
].ibuddy
[j
]) < 0 || dot
< 0 && (md
->pVertices
[md
->pIndices
[itri1
* 3]] - camposLoc
) * md
->pNormals
[itri1
] >= 0)
309 dc
.DrawLine(tm
* md
->pVertices
[md
->pIndices
[itri
* 3 + j
]], tm
* md
->pVertices
[md
->pIndices
[itri
* 3 + incm3(j
)]]);
314 const primitives::box
* pbox
= (const primitives::box
*)pGeom
->GetData();
315 Vec3 axdot
= pbox
->Basis
* (pbox
->center
- camposLoc
);
316 Vec3i
iax(sgnnz(axdot
.x
), sgnnz(axdot
.y
), sgnnz(axdot
.z
));
317 for (int j
= 0, mask0
= 2, mask1
, bit
= 0; j
< 6; j
++, mask0
= mask1
, bit
= incm3(bit
))
319 mask1
= mask0
^ 1 << bit
;
320 Vec3
pt0(iax
.x
* (1 - (mask0
<< 1 & 2)), iax
.y
* (1 - (mask0
& 2)), iax
.z
* (1 - (mask0
>> 1 & 2)));
321 Vec3
pt1(iax
.x
* (1 - (mask1
<< 1 & 2)), iax
.y
* (1 - (mask1
& 2)), iax
.z
* (1 - (mask1
>> 1 & 2)));
322 dc
.DrawLine(tm
* (pbox
->center
+ (Diag33(pbox
->size
) * pt0
) * pbox
->Basis
), tm
* (pbox
->center
+ (Diag33(pbox
->size
) * pt1
) * pbox
->Basis
));
330 void CJointGenEntity::Display(DisplayContext
& dc
)
332 CEntityObject::Display(dc
);
334 Vec3 campos
= dc
.camera
->GetPosition();
335 IEntity
* pent
= GetIEntity();
336 if (GetIEditorImpl()->GetGameEngine()->GetSimulationMode() || (pent
->GetWorldPos() - campos
).len2() > 100)
339 SmartScriptTable props
;
340 pent
->GetScriptTable()->GetValue("Properties", props
);
342 if (props
->GetValue("object_BreakTemplate", str
))
346 m_pObj
= gEnv
->p3DEngine
->LoadStatObj(str
);
353 props
->GetValue("Offset", tplOffs
);
354 float tplScale
= 1.0f
;
355 props
->GetValue("Scale", tplScale
);
357 props
->GetValue("ei_Alignment", align
);
358 IPhysicalWorld::SPWIParams pp
;
359 pp
.entTypes
= ent_static
| ent_rigid
| ent_sleeping_rigid
;
360 pp
.itype
= primitives::sphere::type
;
361 primitives::sphere sph
;
362 sph
.center
= pent
->GetWorldPos();
363 props
->GetValue("Radius", sph
.r
);
366 pp
.ppcontact
= &pcont
;
367 intersection_params ip
;
368 ip
.bNoAreaContacts
= ip
.bNoBorder
= true;
370 dc
.SetColor(RGB(100, 166, 255));
372 int ncont
= (int)gEnv
->pPhysicalWorld
->PrimitiveWorldIntersection(pp
);
373 for (int i
= 0; i
< ncont
; i
++)
375 IPhysicalEntity
* pentPhys
= gEnv
->pPhysicalWorld
->GetPhysicalEntityById(pcont
[i
].iPrim
[0]);
378 IRenderNode
* pRN
= 0;
379 switch (pentPhys
->GetiForeignData())
381 case PHYS_FOREIGN_ID_ENTITY
:
382 pRN
= (((IEntity
*)pentPhys
->GetForeignData(PHYS_FOREIGN_ID_ENTITY
))->GetRenderInterface())->GetRenderNode();
384 case PHYS_FOREIGN_ID_STATIC
:
385 pRN
= ((IRenderNode
*)pentPhys
->GetForeignData(PHYS_FOREIGN_ID_STATIC
));
391 IStatObj
* pObj
= pRN
->GetEntityStatObj(0, &tmW
);
394 for (; pObj
->GetCloneSourceObject(); pObj
= pObj
->GetCloneSourceObject())
397 (m_pSph
= gEnv
->pPhysicalWorld
->GetGeomManager()->CreatePrimitive(primitives::sphere::type
, &sph
))->Release();
398 m_pSph
->SetData(&sph
);
400 IStatObj::SSubObject subObj
;
401 subObj
.pStatObj
= pObj
;
402 subObj
.tm
.SetIdentity();
404 for (int j
= 0; j
< max(1, pObj
->GetSubObjectCount()); j
++)
406 IStatObj::SSubObject
* pSubObj
= pObj
->GetSubObject(j
) ? pObj
->GetSubObject(j
) : &subObj
;
407 if (!pSubObj
->pStatObj
|| !pSubObj
->pStatObj
->GetPhysGeom())
409 QuatTS
qtsW(tmW
* pSubObj
->tm
);
410 gwd
.R
= Matrix33(qtsW
.q
);
413 if (m_pSph
->Intersect(pSubObj
->pStatObj
->GetPhysGeom()->pGeom
, 0, &gwd
, 0, pcont
))
415 gwd
.R
= align
== -2 ? Matrix33(!pent
->GetRotation() * qtsW
.q
) : Matrix33(IDENTITY
);
416 AlignCutTemplate(pSubObj
->pStatObj
, m_pObj
, align
> 23 ? -1 : align
, tplOffs
, tplScale
, gwd
.R
, gwd
.offset
, gwd
.scale
);
417 gwd
.R
= gwd
.R
.T() / gwd
.scale
;
418 DrawCutTemplate(dc
, m_pObj
, Matrix34(qtsW
) * Matrix34(gwd
.R
, gwd
.R
* -gwd
.offset
), campos
);
425 dc
.SetColor(RGB(160, 160, 160));
426 DrawCutTemplate(dc
, m_pObj
, pent
->GetWorldTM(), campos
);