/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "CryLegacy_precompiled.h" #include "ScriptBind_Physics.h" #include #include #if ENABLE_CRY_PHYSICS #include #include ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CScriptBind_Physics::CScriptBind_Physics(IScriptSystem* pScriptSystem, ISystem* pSystem) { m_pSystem = NULL; m_p3DEngine = NULL; CScriptableBase::Init(pScriptSystem, pSystem); SetGlobalName("Physics"); m_pSystem = pSystem; m_p3DEngine = gEnv->p3DEngine; m_pPhysicalWorld = m_pSystem->GetIPhysicalWorld(); #undef SCRIPT_REG_CLASSNAME #define SCRIPT_REG_CLASSNAME &CScriptBind_Physics:: SCRIPT_REG_TEMPLFUNC(SimulateExplosion, "tableExplosion"); SCRIPT_REG_TEMPLFUNC(RegisterExplosionShape, "sGeometryFile,fSize,nIdMaterial,fProbability,sSplintersFile,fSplintersOffset,sSplintersCloudEffect"); SCRIPT_REG_TEMPLFUNC(RegisterExplosionCrack, "sGeometryFile,nIdMaterial"); SCRIPT_REG_FUNC(RayWorldIntersection); SCRIPT_REG_TEMPLFUNC(RayTraceCheck, "vSrc,vTrg,hSkipEntityId1,hSkipEntityId2"); SCRIPT_REG_TEMPLFUNC(SamplePhysEnvironment, "vPoint,fRadius"); } ////////////////////////////////////////////////////////////////////////// CScriptBind_Physics::~CScriptBind_Physics() { } ////////////////////////////////////////////////////////////////////////// int CScriptBind_Physics::SimulateExplosion(IFunctionHandler* pH, SmartScriptTable explisionTable) { { // Must be in local scope. CScriptSetGetChain params(explisionTable); pe_explosion expl; params.GetValue("pos", expl.epicenter); params.GetValue("radius", expl.r); params.GetValue("direction", expl.explDir); params.GetValue("impulse_pos", expl.epicenterImp); params.GetValue("impulse_pressure", expl.impulsivePressureAtR); params.GetValue("rmin", expl.rmin); params.GetValue("rmax", expl.rmax); params.GetValue("hole_size", expl.holeSize); m_pPhysicalWorld->SimulateExplosion(&expl); } return pH->EndFunction(); } ////////////////////////////////////////////////////////////////////////// int CScriptBind_Physics::RegisterExplosionShape(IFunctionHandler* pH, const char* sGeometryFile, float fSize, int nIdMaterial, float fProbability, const char* sSplintersFile, float fSplintersOffset, const char* sSplintersCloudEffect) { ////////////////////////////////////////////////////////////////////////// // Remove all this. ////////////////////////////////////////////////////////////////////////// IStatObj* pObj = gEnv->p3DEngine->LoadStatObjUnsafeManualRef(sGeometryFile, "#ForceBreakable", NULL, false); if (!pObj || pObj->IsDefaultObject()) { ScriptWarning(" Object file %s not found", sGeometryFile); return pH->EndFunction(); } pObj->AddRef(); pObj->GetIndexedMesh(true); // prepare idxMesh now if (sSplintersFile && *sSplintersFile != 0) // if sSplintersFile was specified { IStatObj* pSplinters = gEnv->p3DEngine->LoadStatObjUnsafeManualRef(sSplintersFile, NULL, NULL, false); if (pSplinters) { pObj->SetSubObjectCount(pObj->GetSubObjectCount() + 1); IStatObj::SSubObject* pSubObj = pObj->GetSubObject(pObj->GetSubObjectCount() - 1); pSubObj->nType = STATIC_SUB_OBJECT_MESH; pSubObj->bHidden = true; pSubObj->name = "splinters"; (pSubObj->pStatObj = pSplinters)->AddRef(); pSubObj->helperSize.x = fSplintersOffset; nIdMaterial |= 1 << 16; if (*sSplintersCloudEffect) { pSplinters->SetSubObjectCount(pSplinters->GetSubObjectCount() + 1); pSplinters->SetFlags(pSplinters->GetFlags() & ~STATIC_OBJECT_COMPOUND); pSubObj = pSplinters->GetSubObject(pSplinters->GetSubObjectCount() - 1); pSubObj->nType = STATIC_SUB_OBJECT_DUMMY; pSubObj->bHidden = true; pSubObj->name = "splinters_cloud"; pSubObj->properties = sSplintersCloudEffect; } } } phys_geometry* pPhysGeom = pObj->GetPhysGeom(); if (pPhysGeom) { m_pPhysicalWorld->AddExplosionShape(pPhysGeom->pGeom, fSize, nIdMaterial, fProbability); } return pH->EndFunction(); } ////////////////////////////////////////////////////////////////////////// int CScriptBind_Physics::RegisterExplosionCrack(IFunctionHandler* pH, const char* sGeometryFile, int nIdMaterial) { #if ENABLE_CRY_PHYSICS IStatObj* pObj = gEnv->p3DEngine->LoadStatObjUnsafeManualRef(sGeometryFile, "#ForceBreakable", NULL, false); if (!pObj || pObj->IsDefaultObject()) { ScriptWarning(" Object file %s not found", sGeometryFile); return pH->EndFunction(); } pObj->AddRef(); Vec3 vtx[3] = { pObj->GetHelperPos("1"), pObj->GetHelperPos("2"), pObj->GetHelperPos("3") }; //@TODO: restore it. m_pPhysicalWorld->GetGeomManager()->RegisterCrack(pObj->GetPhysGeom()->pGeom, vtx, 0); #endif // ENABLE_CRY_PHYSICS return pH->EndFunction(); } ////////////////////////////////////////////////////////////////////////// int CScriptBind_Physics::RayWorldIntersection(IFunctionHandler* pH) { assert(pH->GetParamCount() >= 3 && pH->GetParamCount() <= 7); Vec3 vPos(0, 0, 0); Vec3 vDir(0, 0, 0); ScriptHandle skipId1; ScriptHandle skipId2; IEntity* skipEnt1 = 0; IEntity* skipEnt2 = 0; int nMaxHits, iEntTypes = ent_all; SmartScriptTable hitTable(m_pSS); if (!pH->GetParams(vPos, vDir, nMaxHits, iEntTypes)) { return pH->EndFunction(); } int nParams = pH->GetParamCount(); if (nParams >= 5 && pH->GetParamType(5) != svtNull && pH->GetParam(5, skipId1)) { skipEnt1 = gEnv->pEntitySystem->GetEntity((EntityId)skipId1.n); } if (nParams >= 6 && pH->GetParamType(6) != svtNull && pH->GetParam(6, skipId2)) { skipEnt2 = gEnv->pEntitySystem->GetEntity((EntityId)skipId2.n); } bool bHitTablePassed = (nParams >= 7); if (bHitTablePassed) { pH->GetParam(7, hitTable); } if (nMaxHits > 10) { nMaxHits = 10; } ray_hit RayHit[10]; //filippo: added support for skip certain entities. int skipIdCount = 0; IPhysicalEntity* skipPhys[2] = {0, 0}; if (skipEnt1) { ++skipIdCount; skipPhys[0] = skipEnt1->GetPhysics(); } if (skipEnt2) { ++skipIdCount; skipPhys[1] = skipEnt2->GetPhysics(); } Vec3 src = vPos; Vec3 dir = vDir; int nHits = m_pSystem->GetIPhysicalWorld()->RayWorldIntersection(src, dir, iEntTypes, geom_colltype0 << rwi_colltype_bit | rwi_stop_at_pierceable, RayHit, nMaxHits, skipPhys, skipIdCount); for (int i = 0; i < nHits; i++) { SmartScriptTable pHitObj(m_pSS); ray_hit& Hit = RayHit[i]; pHitObj->SetValue("pos", Hit.pt); pHitObj->SetValue("normal", Hit.n); pHitObj->SetValue("dist", Hit.dist); pHitObj->SetValue("surface", Hit.surface_idx); IEntity* pEntity = (IEntity*) Hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); if (pEntity) { pHitObj->SetValue("entity", pEntity->GetScriptTable()); } else { if (Hit.pCollider->GetiForeignData() == PHYS_FOREIGN_ID_STATIC) { IRenderNode* pRN = (IRenderNode*)Hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC); if (pRN) { pHitObj->SetValue("renderNode", ScriptHandle(pRN)); } } else if (Hit.pCollider->GetiForeignData() == PHYS_FOREIGN_ID_FOLIAGE) { IRenderNode* pRN = ((IFoliage*)Hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_FOLIAGE))->GetIRenderNode(); if (pRN) { pHitObj->SetValue("renderNode", ScriptHandle(pRN)); } } } hitTable->SetAt(i + 1, pHitObj); } if (bHitTablePassed) { return pH->EndFunction(nHits); } return pH->EndFunction(*hitTable); } ////////////////////////////////////////////////////////////////////////// int CScriptBind_Physics::RayTraceCheck(IFunctionHandler* pH, Vec3 src, Vec3 dst, ScriptHandle skipEntityId1, ScriptHandle skipEntityId2) { SCRIPT_CHECK_PARAMETERS(4); IEntity* skipEnt1 = gEnv->pEntitySystem->GetEntity((EntityId)skipEntityId1.n); IEntity* skipEnt2 = gEnv->pEntitySystem->GetEntity((EntityId)skipEntityId2.n); IPhysicalEntity* skipPhys[2] = {0, 0}; if (skipEnt1) { skipPhys[0] = skipEnt1->GetPhysics(); } if (skipEnt2) { skipPhys[1] = skipEnt2->GetPhysics(); } ray_hit RayHit; //TODO? add an extraparam to specify what kind of objects to check? now its world and static int nHits = m_pSystem->GetIPhysicalWorld()->RayWorldIntersection(src, dst - src, ent_static | ent_terrain, rwi_ignore_noncolliding | rwi_stop_at_pierceable, &RayHit, 1, skipPhys, 2); return pH->EndFunction((bool)(nHits == 0)); } ////////////////////////////////////////////////////////////////////////// int CScriptBind_Physics::SamplePhysEnvironment(IFunctionHandler* pH) { int nEnts, i, nHits = 0, objtypes = ent_static | ent_rigid | ent_sleeping_rigid | ent_sort_by_mass; pe_status_nparts snp; pe_status_pos sp; IPhysicalEntity** pEnts; geom_world_data gwd; IGeometry* pSphere; primitives::sphere sph; intersection_params ip; geom_contact* pcontacts; IPhysicalWorld* pWorld = m_pSystem->GetIPhysicalWorld(); IEntity* pEntity; SmartScriptTable pObj(m_pSS); ip.bStopAtFirstTri = ip.bNoBorder = ip.bNoAreaContacts = true; ip.bThreadSafe = true; if (!pH->GetParams(sph.center, sph.r)) { return pH->EndFunction(); } if (pH->GetParamCount() > 2) { pH->GetParam(3, objtypes); } pSphere = pWorld->GetGeomManager()->CreatePrimitive(primitives::sphere::type, &sph); nEnts = pWorld->GetEntitiesInBox(sph.center - Vec3(sph.r), sph.center + Vec3(sph.r), pEnts, objtypes); for (i = 0; i < nEnts; i++) { for (sp.ipart = pEnts[i]->GetStatus(&snp) - 1; sp.ipart >= 0; sp.ipart--) { sp.partid = -1; pEnts[i]->GetStatus(&sp); gwd.offset = sp.pos; gwd.R = Matrix33(sp.q); gwd.scale = sp.scale; WriteLockCond lock; if ((sp.flagsOR & (geom_colltype0 | geom_no_coll_response)) == geom_colltype0 && sp.pGeomProxy->IntersectLocked(pSphere, &gwd, 0, &ip, pcontacts, lock)) { ++nHits; if (pEntity = (IEntity*)pEnts[i]->GetForeignData(PHYS_FOREIGN_ID_ENTITY)) { pObj->SetAt(nHits * 3 - 2, pEntity->GetScriptTable()); } else { pObj->SetNullAt(nHits * 3 - 2); } pObj->SetAt(nHits * 3 - 1, sp.partid); pObj->SetAt(nHits * 3, pWorld->GetPhysicalEntityId(pEnts[i])); if (pEnts[i]->GetType() != PE_ARTICULATED) { break; } } } } pSphere->Release(); return pH->EndFunction(*pObj); } #endif // ENABLE_CRY_PHYSICS