!I (1670414, 1670415, 1670416, 1670424, 1670431):
[CRYENGINE.git] / Code / Sandbox / EditorQt / Objects / MiscEntities.cpp
blob043d0509ba1bd16dd716e61a3fc62c32ea738057
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
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)
17 #endif
18 IMPLEMENT_DYNCREATE(CJointGenEntity, CEntityObject)
20 //////////////////////////////////////////////////////////////////////////
21 // CConstraintEntity
22 //////////////////////////////////////////////////////////////////////////
23 static inline void DrawHingeQuad(DisplayContext& dc, float angle)
25 const float len = 1.0f;
26 Vec3 zero(0, 0, 0);
27 const float halfLen = len * 0.5f;
28 Vec3 vDest(0, len * cos_tpl(angle), len * sin_tpl(angle));
29 Vec3 p1 = zero;
30 p1.x += halfLen;
31 Vec3 p2 = vDest;
32 p2.x += halfLen;
33 Vec3 p3 = vDest;
34 p3.x -= halfLen;
35 Vec3 p4 = zero;
36 p4.x -= halfLen;
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())
45 return;
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);
63 m_body0 = NULL;
64 m_body1 = NULL;
66 if (
67 (pEnts)
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)
77 m_body0 = NULL;
80 if (m_body1 == (IPhysicalEntity*)-1)
82 m_body1 = NULL;
86 // determine the reference frame of the constraint and push it onto the display context stack
87 bool useEntityFrame = GetEntityPropertyBool("bUseEntityFrame");
88 quaternionf qbody0;
89 qbody0.SetIdentity();
90 Vec3 posBody0;
91 if (m_body0)
93 pe_status_pos pos;
94 m_body0->GetStatus(&pos);
95 qbody0 = pos.q;
96 posBody0 = pos.pos;
98 quaternionf qbody1;
99 qbody1.SetIdentity();
100 Vec3 posBody1;
101 if (m_body1)
103 pe_status_pos pos;
104 m_body1->GetStatus(&pos);
105 qbody1 = pos.q;
106 posBody1 = pos.pos;
109 if (!GetIEditorImpl()->GetGameEngine()->GetSimulationMode())
111 if (useEntityFrame)
113 m_qframe = qbody0;
115 else
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)
126 Matrix33 rot;
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;
131 v.Normalize();
132 Vec3 w = v ^ 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)
143 // the limits
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;
149 Ang3 angles(qrel);
150 dc.SetColor(0, 0, 1);
151 DrawHingeQuad(dc, angles.x);
153 // YZ limits
154 minLimit = GetEntityPropertyFloat("yz_min");
155 maxLimit = GetEntityPropertyFloat("yz_max");
156 if (maxLimit > 0 && minLimit < maxLimit)
158 // draw the cone
159 float height, radius;
160 if (maxLimit == 90)
162 height = 0;
163 radius = 1;
165 else
167 const float tanAngle = fabs(tan_tpl(DEG2RAD(maxLimit)));
168 if (tanAngle < 1)
170 height = 1;
171 radius = height * tanAngle;
173 else
175 radius = 1;
176 height = radius / tanAngle;
178 if (sin(DEG2RAD(maxLimit)) < 0)
180 height = -height;
183 const int divs = 20;
184 const float delta = 2.0f * gf_PI / divs;
185 Vec3 apex(0, 0, 0);
186 Vec3 p0(height, radius, 0);
187 float angle = delta;
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);
195 p0 = p;
197 dc.SetFillMode(e_FillModeSolid);
199 dc.PopMatrix();
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)...
210 if (
211 (pEnts)
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();
229 if (pEntity == NULL)
231 return;
234 IPhysicalEntity* pPhysEnt = pEntity->GetPhysics();
235 if (pPhysEnt == NULL || pPhysEnt->GetType() != PE_AREA)
237 return;
240 pe_status_pos pos;
241 if (pPhysEnt->GetStatus(&pos) == 0)
243 return;
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);
252 float len[3] =
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)
259 pe_status_area area;
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())
301 case GEOM_TRIMESH:
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)]]);
311 } break;
312 case GEOM_BOX:
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));
324 } break;
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)
337 return;
339 SmartScriptTable props;
340 pent->GetScriptTable()->GetValue("Properties", props);
341 string str;
342 if (props->GetValue("object_BreakTemplate", str))
344 if (str != m_fname)
346 m_pObj = gEnv->p3DEngine->LoadStatObj(str);
347 m_fname = str;
349 if (!m_pObj)
350 return;
352 Vec3 tplOffs(ZERO);
353 props->GetValue("Offset", tplOffs);
354 float tplScale = 1.0f;
355 props->GetValue("Scale", tplScale);
356 int align;
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);
364 pp.pprim = &sph;
365 geom_contact* pcont;
366 pp.ppcontact = &pcont;
367 intersection_params ip;
368 ip.bNoAreaContacts = ip.bNoBorder = true;
369 pp.pip = &ip;
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]);
376 if (!pentPhys)
377 continue;
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();
383 break;
384 case PHYS_FOREIGN_ID_STATIC:
385 pRN = ((IRenderNode*)pentPhys->GetForeignData(PHYS_FOREIGN_ID_STATIC));
386 break;
387 default:
388 continue;
390 Matrix34A tmW;
391 IStatObj* pObj = pRN->GetEntityStatObj(0, &tmW);
392 if (!pObj)
393 continue;
394 for (; pObj->GetCloneSourceObject(); pObj = pObj->GetCloneSourceObject())
396 if (!m_pSph)
397 (m_pSph = gEnv->pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::sphere::type, &sph))->Release();
398 m_pSph->SetData(&sph);
399 geom_world_data gwd;
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())
408 continue;
409 QuatTS qtsW(tmW * pSubObj->tm);
410 gwd.R = Matrix33(qtsW.q);
411 gwd.offset = qtsW.t;
412 gwd.scale = qtsW.s;
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);
421 break;
423 if (!ncont)
425 dc.SetColor(RGB(160, 160, 160));
426 DrawCutTemplate(dc, m_pObj, pent->GetWorldTM(), campos);