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->LoadStatObj( sGeometryFile,"#ForceBreakable",NULL,false ); if (!pObj || pObj->IsDefaultObject()) { ScriptWarning( "<RegisterExplosionShape> 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->LoadStatObj(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(); }
//------------------------------------------------------------------------ bool CVehiclePartAnimated::ChangeState(EVehiclePartState state, int flags) { if ((state == eVGS_Default) && m_initialiseOnChangeState) { // Initialise! // Having to do this because of the way the glass code // swaps a cstatobj. The way the vehicle code stores its // statobj in m_intactStatObjs is going to need reviewing if (m_pCharInstance) { ISkeletonPose* pSkeletonPose = m_pCharInstance->GetISkeletonPose(); IDefaultSkeleton &rIDefaultSkeleton = m_pCharInstance->GetIDefaultSkeleton(); ISkeletonPose* pSkeletonPoseDestroyed = m_pCharInstanceDestroyed ? m_pCharInstanceDestroyed->GetISkeletonPose() : NULL; IDefaultSkeleton* pICharacterModelSkeletonDestroyed = m_pCharInstanceDestroyed ? &m_pCharInstanceDestroyed->GetIDefaultSkeleton() : NULL; if (pSkeletonPose) { const bool bDestroyedSkelExists = pSkeletonPoseDestroyed && pICharacterModelSkeletonDestroyed; for (uint32 i = 0; i < rIDefaultSkeleton.GetJointCount(); i++) { if (IStatObj* pStatObjIntact = pSkeletonPose->GetStatObjOnJoint(i)) { const char* jointName = rIDefaultSkeleton.GetJointNameByID(i); if (m_intactStatObjs.find(CONST_TEMP_STRING(jointName)) == m_intactStatObjs.end()) { m_intactStatObjs.insert(TStringStatObjMap::value_type(jointName, pStatObjIntact)); } // tell the streaming engine to stream destroyed version together with non destroyed if (bDestroyedSkelExists && i < pICharacterModelSkeletonDestroyed->GetJointCount()) { if (IStatObj* pStatObjIntactDestroyed = pSkeletonPoseDestroyed->GetStatObjOnJoint(i)) { pStatObjIntact->SetStreamingDependencyFilePath(pStatObjIntactDestroyed->GetFilePath()); } } } } } } m_initialiseOnChangeState = false; } bool change = CVehiclePartBase::ChangeState(state, flags); if (state == eVGS_Default && !change) { // need to restore state if one of the children is in higher state EVehiclePartState maxState = GetMaxState(); if (maxState > m_state) change = true; } if (!change) { return false; } if (state == eVGS_Destroyed) { if (m_ignoreDestroyedState) return false; if (m_pCharInstance && m_pCharInstanceDestroyed) { ISkeletonPose* pSkeletonPose = m_pCharInstance->GetISkeletonPose(); IDefaultSkeleton &rIDefaultSkeleton = m_pCharInstance->GetIDefaultSkeleton(); if (pSkeletonPose) { IMaterial* pDestroyedMaterial = m_pVehicle->GetDestroyedMaterial(); for (uint32 i = 0; i < rIDefaultSkeleton.GetJointCount(); i++) { if (IStatObj* pStatObjIntact = pSkeletonPose->GetStatObjOnJoint(i)) { const char* jointName = rIDefaultSkeleton.GetJointNameByID(i); IStatObj* pStatObj = GetDestroyedGeometry(jointName); // sets new StatObj to joint, if null, removes it. // object whose name includes "proxy" are not removed. if (pStatObj || !strstr(jointName, "proxy")) { SetCGASlot(i, pStatObj); if (pStatObj && !pDestroyedMaterial) { if (IMaterial* pMaterial = pStatObj->GetMaterial()) SetMaterial(pMaterial); } #if ENABLE_VEHICLE_DEBUG if (IsDebugParts()) { CryLog("swapping StatObj on joint %u (%s) -> %s", i, jointName, pStatObj ? pStatObj->GetGeoName() : "<NULL>"); } #endif } } } FlagSkeleton(pSkeletonPose, rIDefaultSkeleton); for (TStringVehiclePartMap::iterator ite = m_jointParts.begin(); ite != m_jointParts.end(); ++ite) { IVehiclePart* pPart = ite->second; pPart->ChangeState(state, flags | eVPSF_Physicalize); } CryCharAnimationParams animParams; animParams.m_nFlags |= CA_LOOP_ANIMATION; // pSkeleton->SetRedirectToLayer0(1); // pSkeleton->StartAnimation("Default",0, 0,0, animParams); // [MR: commented out on Ivos request] if (pDestroyedMaterial) { SetMaterial(pDestroyedMaterial); } } } } else if (state == eVGS_Default) { if (m_pCharInstance && m_pCharInstanceDestroyed) { // reset material (in case we replaced it with the destroyed material) IMaterial* pMaterial = m_pVehicle->GetPaintMaterial(); if (!pMaterial) { // no paint, so revert to the material already set on the character pMaterial = m_pCharInstance->GetIMaterial(); } if (pMaterial) { SetMaterial(pMaterial); } IDefaultSkeleton &rIDefaultSkeleton = m_pCharInstance->GetIDefaultSkeleton(); { for (TStringStatObjMap::iterator ite = m_intactStatObjs.begin(); ite != m_intactStatObjs.end(); ++ite) { const string &jointName = ite->first; IStatObj* pStatObj = ite->second; int16 jointId = rIDefaultSkeleton.GetJointIDByName(jointName.c_str()); if (jointId > -1) { // if compound StatObj (from deformation), use first SubObj for restoring if (pStatObj != NULL) { if (!pStatObj->GetRenderMesh() && pStatObj->GetSubObjectCount() > 0) { pStatObj = pStatObj->GetSubObject(0)->pStatObj; } SetCGASlot(jointId, pStatObj); #if ENABLE_VEHICLE_DEBUG if (IsDebugParts()) CryLog("restoring StatObj on joint %i (%s) -> %s", jointId, jointName.c_str(), pStatObj ? pStatObj->GetGeoName() : "<NULL>"); #endif } TStringVehiclePartMap::iterator it = m_jointParts.find(jointName); if (it != m_jointParts.end()) { it->second->ChangeState(state, flags & ~eVPSF_Physicalize | eVPSF_Force); } } } flags |= eVPSF_Physicalize; } } } m_state = state; // physicalize after all parts have been restored if (flags & eVPSF_Physicalize && GetEntity()->GetPhysics()) { Physicalize(); for (TStringVehiclePartMap::iterator it = m_jointParts.begin(); it != m_jointParts.end(); ++it) { it->second->Physicalize(); } } return true; }
//-------------------------------------------------------------------------------------------------- // Name: ExtractPhysDataFromEvent // Desc: Extracts collider's physical data from an event // Note 1: Ideally *ALL* of this should be calculated offline and the minimal data loaded // Note 2: We're currently duplicating some work done in CryAction, so should be reading that in //-------------------------------------------------------------------------------------------------- bool CBreakableGlassSystem::ExtractPhysDataFromEvent(const EventPhysCollision& physEvent, SBreakableGlassPhysData& data, SBreakableGlassInitParams& initParams) { if (IPhysicalEntity* pPhysEntity = physEvent.pEntity[PHYSEVENT_COLLIDEE]) { // Get collider entity data const int entType = pPhysEntity->GetiForeignData(); const int entPart = physEvent.partid[PHYSEVENT_COLLIDEE]; // Local output data IStatObj* pStatObj = NULL; IMaterial* pRenderMat = NULL; phys_geometry* pPhysGeom = NULL; uint renderFlags = 0; Matrix34A entityMat; entityMat.SetIdentity(); // Only handling simple objects at the moment const pe_type physType = pPhysEntity->GetType(); if (physType == PE_STATIC || physType == PE_RIGID) { // Entity or static object? if (entType == PHYS_FOREIGN_ID_ENTITY) { IEntity* pEntity = (IEntity*)pPhysEntity->GetForeignData(PHYS_FOREIGN_ID_ENTITY); pStatObj = pEntity->GetStatObj(entPart); entityMat = pEntity->GetSlotWorldTM(entPart); if (IEntityRenderProxy* pRenderProxy = (IEntityRenderProxy*)pEntity->GetProxy(ENTITY_PROXY_RENDER)) { pRenderMat = pRenderProxy->GetRenderMaterial(entPart); IRenderNode* pRenderNode = pRenderProxy->GetRenderNode(); renderFlags = pRenderNode ? pRenderNode->GetRndFlags() : 0; // Fall back to top level material if sub-object fails to find it if (!pRenderMat) { pRenderMat = pRenderProxy->GetRenderMaterial(); if (!pRenderMat && pStatObj) { pRenderMat = pStatObj->GetMaterial(); } } } } else if (entType == PHYS_FOREIGN_ID_STATIC) { if (IRenderNode* pBrush = (IRenderNode*)physEvent.pForeignData[PHYSEVENT_COLLIDEE]) { pStatObj = pBrush->GetEntityStatObj(0, 0, &entityMat); pRenderMat = pBrush->GetMaterial(); renderFlags = pBrush->GetRndFlags(); // May need to get sub-object and it's material if (pStatObj && pStatObj->GetFlags() & STATIC_OBJECT_COMPOUND) { if (IStatObj::SSubObject* pSubObj = pStatObj->GetSubObject(entPart)) { pStatObj = pSubObj->pStatObj; if (!pSubObj->bIdentityMatrix) { entityMat = entityMat * pSubObj->tm; } // Find the correct sub-material // Note: We loop as the slots don't always line up const int subMtlCount = pRenderMat->GetSubMtlCount(); for (int i = 0; i < subMtlCount; ++i) { if (IMaterial* pSubMat = pRenderMat->GetSubMtl(i)) { if (pSubMat->GetSurfaceTypeId() == initParams.surfaceTypeId) { pRenderMat = pSubMat; break; } } } } } } } } // Validate geometry of collided object pPhysGeom = pStatObj ? pStatObj->GetPhysGeom() : NULL; IGeometry* pGeom = pPhysGeom ? pPhysGeom->pGeom : NULL; bool validGeom = false; primitives::box bbox; int thinAxis; if (pGeom) { // Determine thin geometry axis for glass alignment pGeom->GetBBox(&bbox); thinAxis = idxmin3((float*)&bbox.size); // Handle geometry mesh type switch (pGeom->GetType()) { case GEOM_TRIMESH: // Perform full mesh analysis and extraction if (mesh_data* pPhysMeshData = (mesh_data*)pGeom->GetData()) { if (ValidatePhysMesh(pPhysMeshData, thinAxis) && ExtractPhysMesh(pPhysMeshData, thinAxis, bbox, data.defaultFrag)) { validGeom = true; } } break; case GEOM_BOX: // Simple box, so assume valid validGeom = true; break; default: // Only support boxes and tri-meshes break; } } // Invalid geometry, so can't continue if (!validGeom) { pPhysGeom = NULL; } // Attempt UV coord extraction from render mesh else { ExtractUVCoords(pStatObj, bbox, thinAxis, data); } // Copy final data data.pStatObj = pStatObj; data.pPhysGeom = pPhysGeom; data.renderFlags = renderFlags; data.entityMat = entityMat; initParams.pGlassMaterial = pRenderMat; } return data.pStatObj && data.pPhysGeom && initParams.pGlassMaterial; }//-------------------------------------------------------------------------------------------------
// TODO: this whole function should be removed and FindHelperObject_Basic integrated back into FindHelperObject. // It manages some undefined cases that appeared in C2, but it should not be needed with a strict definition of how the grabAndThrow helpers have to be defined in the objects IStatObj::SSubObject* FindHelperObject_Extended( const char* pHelperName, EntityId objectId, int slot ) { IStatObj::SSubObject* pSObjHelper = NULL; IEntity* pEntity = gEnv->pEntitySystem->GetEntity( objectId ); SEntitySlotInfo info; if (pEntity && pEntity->GetSlotInfo( slot, info )) { if (info.pStatObj) { IStatObj* pStatObj = info.pStatObj->GetCloneSourceObject(); // we use the clone source in case it exists. Because when it is cloned, only geometries are cloned. the helpers are NOT cloned. if (!pStatObj) pStatObj = info.pStatObj; // special case: when the pStatObj is the root, we look for the first helper that does not have a hidden parent, whatever is its name as long as it includes pHelperName // because: it can be child of a visible geometry (usually "main"...) even when that geometry is not the root if (!pSObjHelper && !pStatObj->GetParentObject()) { const int subObjectCount = pStatObj->GetSubObjectCount(); for (int sid = 0; sid < subObjectCount; ++sid) { IStatObj::SSubObject* pLocSObjHelper = pStatObj->GetSubObject( sid ); if ( pLocSObjHelper && (pLocSObjHelper->nType==STATIC_SUB_OBJECT_DUMMY) && strstr( pLocSObjHelper->name.c_str(), pHelperName )) { pLocSObjHelper = pStatObj->GetSubObject( pLocSObjHelper->nParent ); if (pLocSObjHelper && (pLocSObjHelper->nType==STATIC_SUB_OBJECT_MESH) && !pLocSObjHelper->bHidden) { pSObjHelper = pStatObj->GetSubObject( sid ); break; } } } } // if all failed, we look from the parent, but by id // because: helpers are not necesarily a subobject of their geometry, but just a child if (!pSObjHelper && pStatObj->GetParentObject()) { IStatObj* pParent = pStatObj->GetParentObject(); IStatObj::SSubObject* pMeSubObject = pParent->FindSubObject( pStatObj->GetGeoName() ); if (pMeSubObject) { const int subObjectCount = pParent->GetSubObjectCount(); for (int sid=0; sid < subObjectCount; ++sid) { IStatObj::SSubObject* pLocSObjHelper = pParent->GetSubObject( sid ); if ( pLocSObjHelper && (pLocSObjHelper->nType==STATIC_SUB_OBJECT_DUMMY) && (pLocSObjHelper->name==pHelperName) && (pParent->GetSubObject( pLocSObjHelper->nParent )==pMeSubObject) ) { pSObjHelper = pLocSObjHelper; break; } } } } //If STILL we don't find the object, try with composed name based on geometry name (for destroyed pieces), and look on the whole hierarchy if (!pSObjHelper) { CryFixedStringT<128> helperNameBuffer; helperNameBuffer.Format("%s_%s", pStatObj->GetGeoName(), pHelperName); pSObjHelper = pStatObj->FindSubObject( helperNameBuffer.c_str() ); if (!pSObjHelper) { IStatObj* pObj = pStatObj; while (pObj->GetParentObject()) pObj = pObj->GetParentObject(); pSObjHelper = FindHelperObject_RecursivePart( pObj, helperNameBuffer.c_str() ); } } } } return pSObjHelper; }
virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo ) { switch (event) { case eFE_Initialize: break; case eFE_Activate: IGameFramework* pGameFramework = gEnv->pGame->GetIGameFramework(); if(IsPortActive(pActInfo, EIP_Cast)) { // setup ray + optionally skip 1 entity ray_hit rayHit; static const float maxRayDist = 100.f; const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; IPhysicalEntity *skipList[1]; int skipCount = 0; IEntity* skipEntity = gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, EIP_SkipEntity)); if(skipEntity) { skipList[0] = skipEntity->GetPhysics(); skipCount = 1; } Vec3 rayPos = GetPortVec3(pActInfo, EIP_RayPos); Vec3 rayDir = GetPortVec3(pActInfo, EIP_RayDir); // Check if the ray hits an entity if(gEnv->pSystem->GetIPhysicalWorld()->RayWorldIntersection(rayPos, rayDir * 100, ent_all, flags, &rayHit, 1, skipList, skipCount)) { int type = rayHit.pCollider->GetiForeignData(); if (type == PHYS_FOREIGN_ID_ENTITY) { IEntity* pEntity = (IEntity*)rayHit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); IEntityRenderProxy* pRenderProxy = pEntity ? (IEntityRenderProxy*)pEntity->GetProxy(ENTITY_PROXY_RENDER) : 0; // Get the renderproxy, and use it to check if the material is a DynTex, and get the UIElement if so if(pRenderProxy) { IRenderNode *pRenderNode = pRenderProxy->GetRenderNode(); IMaterial* pMaterial = pRenderProxy->GetRenderMaterial(); SEfResTexture* texture = 0; if(pMaterial && pMaterial->GetShaderItem().m_pShaderResources) texture= pMaterial->GetShaderItem().m_pShaderResources->GetTexture(EFTT_DIFFUSE); IUIElement* pElement = texture ? gEnv->pFlashUI->GetUIElementByInstanceStr(texture->m_Name) : 0; if(pElement && pRenderNode) { int m_dynTexGeomSlot = 0; IStatObj* pObj = pRenderNode->GetEntityStatObj(m_dynTexGeomSlot); // result bool hasHit = false; Vec2 uv0, uv1, uv2; Vec3 p0, p1, p2; Vec3 hitpos; // calculate ray dir CCamera cam = gEnv->pRenderer->GetCamera(); if (pEntity->GetSlotFlags(m_dynTexGeomSlot) & ENTITY_SLOT_RENDER_NEAREST) { ICVar *r_drawnearfov = gEnv->pConsole->GetCVar("r_DrawNearFoV"); assert(r_drawnearfov); cam.SetFrustum(cam.GetViewSurfaceX(),cam.GetViewSurfaceZ(),DEG2RAD(r_drawnearfov->GetFVal()),cam.GetNearPlane(),cam.GetFarPlane(), cam.GetPixelAspectRatio()); } Vec3 vPos0 = rayPos; Vec3 vPos1 = rayPos + rayDir; // translate into object space const Matrix34 m = pEntity->GetWorldTM().GetInverted(); vPos0 = m * vPos0; vPos1 = m * vPos1; // walk through all sub objects const int objCount = pObj->GetSubObjectCount(); for (int obj = 0; obj <= objCount && !hasHit; ++obj) { Vec3 vP0, vP1; IStatObj* pSubObj = NULL; if (obj == objCount) { vP0 = vPos0; vP1 = vPos1; pSubObj = pObj; } else { IStatObj::SSubObject* pSub = pObj->GetSubObject(obj); const Matrix34 mm = pSub->tm.GetInverted(); vP0 = mm * vPos0; vP1 = mm * vPos1; pSubObj = pSub->pStatObj; } IRenderMesh* pMesh = pSubObj ? pSubObj->GetRenderMesh() : NULL; if (pMesh) { const Ray ray(vP0, (vP1-vP0).GetNormalized() * maxRayDist); hasHit = RayIntersectMesh(pMesh, pMaterial, pElement, ray, hitpos, p0, p1, p2, uv0, uv1, uv2); } } // skip if not hit if (!hasHit) { ActivateOutput(pActInfo, EOP_Failed, 1); return; } // calculate vectors from hitpos to vertices p0, p1 and p2: const Vec3 v0 = p0-hitpos; const Vec3 v1 = p1-hitpos; const Vec3 v2 = p2-hitpos; // calculate factors const float h = (p0-p1).Cross(p0-p2).GetLength(); const float f0 = v1.Cross(v2).GetLength() / h; const float f1 = v2.Cross(v0).GetLength() / h; const float f2 = v0.Cross(v1).GetLength() / h; // find the uv corresponding to hitpos Vec3 uv = uv0 * f0 + uv1 * f1 + uv2 * f2; // translate to flash space int x, y, width, height; float aspect; pElement->GetFlashPlayer()->GetViewport(x, y, width, height, aspect); int iX = int_round(uv.x * (float)width); int iY = int_round(uv.y * (float)height); // call the function provided if it is present in the UIElement description string funcName = GetPortString(pActInfo, EIP_CallFunction); const SUIEventDesc* eventDesc = pElement->GetFunctionDesc(funcName); if(eventDesc) { SUIArguments arg; arg.AddArgument(iX); arg.AddArgument(iY); pElement->CallFunction(eventDesc->sName, arg); } ActivateOutput(pActInfo, EOP_Success, 1); } } } } ActivateOutput(pActInfo, EOP_Failed, 1); } break; } }