//------------------------------------------------------------------------ const Matrix33 &CItem::GetSlotHelperRotation(int slot, const char *helper, bool worldSpace, bool relative) { static Matrix33 rotation; rotation.SetIdentity(); IEntity* pEntity = GetEntity(); if(!pEntity) return rotation; SEntitySlotInfo info; if (pEntity->GetSlotInfo(slot, info)) { if (info.pStatObj) { IStatObj *pStatObj = info.pStatObj; rotation = Matrix33(pStatObj->GetHelperTM(helper)); rotation.OrthonormalizeFast(); rotation = Matrix33(GetEntity()->GetSlotLocalTM(slot, false))*rotation; } else if (info.pCharacter) { ICharacterInstance *pCharacter = info.pCharacter; if(!pCharacter) return rotation; IAttachment* pAttachment = pCharacter->GetIAttachmentManager()->GetInterfaceByName(helper); if(pAttachment) { rotation = Matrix33(worldSpace ? pAttachment->GetAttWorldAbsolute().q : pAttachment->GetAttModelRelative().q); return rotation; } else { ICharacterModelSkeleton* pICharacterModelSkeleton = pCharacter->GetICharacterModel()->GetICharacterModelSkeleton(); ISkeletonPose* pSkeletonPose = pCharacter->GetISkeletonPose(); int16 id = pICharacterModelSkeleton->GetJointIDByName(helper); if (id > -1) { rotation = relative ? Matrix33(pSkeletonPose->GetRelJointByID(id).q) : Matrix33(pSkeletonPose->GetAbsJointByID(id).q); } } if (!relative) { rotation = Matrix33(pEntity->GetSlotLocalTM(slot, false)) * rotation; } } } if (worldSpace) { rotation = Matrix33(pEntity->GetWorldTM()) * rotation; } return rotation; }
//------------------------------------------------------------------------ const Matrix33 &CItem::GetSlotHelperRotation(int slot, const char *helper, bool worldSpace, bool relative) { // if mounted force the slot to be 1st person if(m_stats.mounted) slot=eIGS_FirstPerson; static Matrix33 rotation; rotation.SetIdentity(); IEntity *pEntity = GetEntity(); if(!pEntity) return rotation; SEntitySlotInfo info; if(pEntity->GetSlotInfo(slot, info)) { if(info.pStatObj) { IStatObj *pStatObj = info.pStatObj; rotation = Matrix33(pStatObj->GetHelperTM(helper)); rotation.OrthonormalizeFast(); rotation = Matrix33(GetEntity()->GetSlotLocalTM(slot, false))*rotation; } else if(info.pCharacter) { ICharacterInstance *pCharacter = info.pCharacter; if(!pCharacter) return rotation; int16 id = pCharacter->GetISkeletonPose()->GetJointIDByName(helper); // if (id > -1) rotation = Matrix33(pCharacter->GetISkeleton()->GetAbsJMatrixByID(id)); if(id > -1) { if(relative) rotation = Matrix33(pCharacter->GetISkeletonPose()->GetRelJointByID(id).q); else rotation = Matrix33(pCharacter->GetISkeletonPose()->GetAbsJointByID(id).q); } if(!relative) rotation = Matrix33(pEntity->GetSlotLocalTM(slot, false))*rotation; } } if(worldSpace) rotation=Matrix33(pEntity->GetWorldTM())*rotation; return rotation; }
//------------------------------------------------------------------------ Vec3 CItem::GetSlotHelperPos(int slot, const char *helper, bool worldSpace, bool relative) const { Vec3 position(0,0,0); SEntitySlotInfo info; if (GetEntity()->GetSlotInfo(slot, info)) { if (info.pStatObj) { IStatObj *pStatsObj = info.pStatObj; position = pStatsObj->GetHelperPos(helper); position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position); } else if (info.pCharacter) { ICharacterInstance *pCharacter = info.pCharacter; IAttachment* pAttachment = pCharacter->GetIAttachmentManager()->GetInterfaceByName(helper); if (pAttachment) { position = worldSpace ? pAttachment->GetAttWorldAbsolute().t : pAttachment->GetAttModelRelative().t; return position; } else { ICharacterModelSkeleton* pICharacterModelSkeleton = pCharacter->GetICharacterModel()->GetICharacterModelSkeleton(); ISkeletonPose* pSkeletonPose = pCharacter->GetISkeletonPose(); int16 id = pICharacterModelSkeleton->GetJointIDByName(helper); if (id > -1) { position = relative ? pSkeletonPose->GetRelJointByID(id).t : pSkeletonPose->GetAbsJointByID(id).t; } } if (!relative) { position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position); } } } if (worldSpace) { position = GetWorldTM().TransformPoint(position); } return position; }
//------------------------------------------------------------------------ Vec3 CItem::GetSlotHelperPos(int slot, const char *helper, bool worldSpace, bool relative) { Vec3 position(0,0,0); // if mounted force the slot to be 1st person if(m_stats.mounted) slot=eIGS_FirstPerson; SEntitySlotInfo info; if(GetEntity()->GetSlotInfo(slot, info)) { if(info.pStatObj) { IStatObj *pStatsObj = info.pStatObj; position = pStatsObj->GetHelperPos(helper); position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position); } else if(info.pCharacter) { ICharacterInstance *pCharacter = info.pCharacter; int16 id = pCharacter->GetISkeletonPose()->GetJointIDByName(helper); if(id > -1) { if(relative) position = pCharacter->GetISkeletonPose()->GetRelJointByID(id).t; else position = pCharacter->GetISkeletonPose()->GetAbsJointByID(id).t; } if(!relative) position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position); } } if(worldSpace) return GetEntity()->GetWorldTM().TransformPoint(position); return position; }
IStatObj::SSubObject* FindHelperObject_Basic( const char* pHelperName, const EntityId objectId, const int slot ) { IStatObj::SSubObject* pSObjHelper = NULL; IEntity* pEntity = gEnv->pEntitySystem->GetEntity( objectId ); SEntitySlotInfo info; if ((pEntity != NULL) && pEntity->GetSlotInfo( slot, info )) { if (info.pStatObj) // TODO: this code is getting too much complicated, we should restrict how and where to place the helpers. But too late now. { 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; pSObjHelper = pStatObj->FindSubObject( pHelperName ); // first try an easy look in the current object // if not success, look recursively. if (!pSObjHelper) { pSObjHelper = FindHelperObject_RecursivePart( pStatObj, pHelperName ); } } } return pSObjHelper; }
//------------------------------------------------------------------------ bool CVehicleDamageBehaviorDetachPart::MovePartToTheNewEntity(IEntity* pTargetEntity, CVehiclePartBase* pPartBase) { if (!pPartBase) return false; IEntity* pVehicleEntity = m_pVehicle->GetEntity(); CRY_ASSERT(pVehicleEntity); assert(m_detachedEntityId == pTargetEntity->GetId()); IStatObj *pStatObj = pPartBase->GetStatObj(); if(pStatObj) { pStatObj->AddRef(); } m_detachedStatObjs.push_back(TPartObjectPair(pPartBase, pStatObj)); // place the geometry on the new entity int slot = pTargetEntity->SetStatObj(pStatObj, -1, true, pPartBase->GetMass()); const Matrix34& partTM = pPartBase->GetWorldTM(); Matrix34 localTM = pTargetEntity->GetWorldTM().GetInverted() * partTM; pTargetEntity->SetSlotLocalTM(slot, localTM); pPartBase->SetStatObj(NULL); TVehiclePartVector& parts = m_pVehicle->GetParts(); const CVehiclePartBase::TVehicleChildParts& children = pPartBase->GetChildParts(); for (CVehiclePartBase::TVehicleChildParts::const_iterator ite = children.begin(), end = children.end(); ite != end; ++ite) { MovePartToTheNewEntity(pTargetEntity, (*ite)); } return true; }
int CScriptBind_Physics::RegisterExplosionCrack(IFunctionHandler *pH,const char *sGeometryFile,int nIdMaterial ) { IStatObj *pObj = gEnv->p3DEngine->LoadStatObj( sGeometryFile,"#ForceBreakable",NULL,false); if (!pObj || pObj->IsDefaultObject()) { ScriptWarning( "<RegisterExplosionCrack> 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 ); return pH->EndFunction(); }
//------------------------------------------------------------------------ void CItem::SpawnEffect(int slot, const char *effectName, const char *helper, const Vec3 &offset, const Vec3 &dir, float scale) { if (m_stats.mounted) slot=eIGS_FirstPerson; Vec3 position(0,0,0); Vec3 finalOffset = offset; SEntitySlotInfo slotInfo; if (GetEntity()->GetSlotInfo(slot, slotInfo)) { if (slotInfo.pStatObj) // entity slot { // get helper position IStatObj *pStatsObj = slotInfo.pStatObj; position = pStatsObj->GetHelperPos(helper); position = GetEntity()->GetSlotWorldTM(slot).TransformPoint(position); } else if (slotInfo.pCharacter) // bone attachment { ICharacterInstance *pCharacter = slotInfo.pCharacter; IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(helper); if (pAttachment) { const Matrix34 m = Matrix34(pAttachment->GetAttWorldAbsolute()); position = m.GetTranslation(); } else { int16 id = pCharacter->GetISkeletonPose()->GetJointIDByName(helper); if (id>=0) position = pCharacter->GetISkeletonPose()->GetAbsJointByID(id).t; position = GetEntity()->GetSlotWorldTM(slot).TransformPoint(position); } } } else if(m_stats.mounted && !m_stats.fp) { if(GetIWeapon()) { // if no helper specified, try getting pos from firing locator IWeaponFiringLocator *pLocator = GetIWeapon()->GetFiringLocator(); if (pLocator) { if(!pLocator->GetFiringPos(GetEntityId(), NULL, position)) position.Set(0.0f,0.0f,0.0f); else finalOffset = GetEntity()->GetWorldTM().TransformVector(finalOffset); } } } position += finalOffset; IParticleEffect *pParticleEffect = gEnv->pParticleManager->FindEffect(effectName); if (pParticleEffect) pParticleEffect->Spawn(true, IParticleEffect::ParticleLoc(position, dir, scale)); }
//------------------------------------------------------------------------ //Above function is almost the same, just some special stuff for flashlight //------------------------------------------------------------------------ uint32 CItem::AttachLightEx(int slot, uint32 id, bool attach, bool fakeLight /*= false */, bool castShadows /*= false*/, IRenderNode* pCasterException, float radius, const Vec3 &color, const float fSpecularMult, const char *projectTexture, float projectFov, const char *helper, const Vec3 &offset, const Vec3 &dir, const char* material, float fHDRDynamic) { if (m_stats.mounted) slot=eIGS_FirstPerson; if (radius<0.1f) return 0; if (attach) { CDLight light; light.SetLightColor(ColorF(color.x, color.y, color.z, 1.0f)); light.SetSpecularMult( fSpecularMult ); light.m_nLightStyle = 0; light.m_fLightFrustumAngle = 45.0f; light.m_fRadius = radius; light.m_fLightFrustumAngle = projectFov*0.5f; light.m_fHDRDynamic = fHDRDynamic; if(fakeLight) light.m_Flags |= DLF_FAKE; //Only on hight/very hight spec if(castShadows && (g_pGameCVars->i_lighteffects!=0)) light.m_Flags |= DLF_CASTSHADOW_MAPS; if (projectTexture && projectTexture[0]) { int flags = 0; light.m_pLightImage = gEnv->pRenderer->EF_LoadTexture(projectTexture, flags); if (!light.m_pLightImage || !light.m_pLightImage->IsTextureLoaded()) { GameWarning("Item '%s' failed to load projecting light texture '%s'!", GetEntity()->GetName(), projectTexture); return 0; } } if (light.m_fLightFrustumAngle && (light.m_pLightImage != NULL) && light.m_pLightImage->IsTextureLoaded()) light.m_Flags |= DLF_PROJECT; else { if (light.m_pLightImage) light.m_pLightImage->Release(); light.m_pLightImage = 0; light.m_Flags |= DLF_POINT; } IMaterial* pMaterial = 0; if (material && material[0]) pMaterial = gEnv->p3DEngine->GetMaterialManager()->LoadMaterial(material); // generate id ++m_effectGenId; while (!m_effectGenId || (m_effects.find(m_effectGenId) != m_effects.end())) ++m_effectGenId; SEntitySlotInfo slotInfo; SEffectInfo effectInfo; effectInfo.slot = -1; bool validSlot = GetEntity()->GetSlotInfo(slot, slotInfo) && (slotInfo.pCharacter || slotInfo.pStatObj); if (!validSlot || slotInfo.pStatObj) { // get helper position Vec3 position(0,0,0); if (validSlot) { IStatObj *pStatsObj = slotInfo.pStatObj; position = pStatsObj->GetHelperPos(helper); position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position); } position+=offset; // find a free slot SEntitySlotInfo dummy; int i=0; while (GetEntity()->GetSlotInfo(eIGS_Last+i, dummy)) i++; // move light slot to the helper position+offset effectInfo.helper = helper; effectInfo.slot = GetEntity()->LoadLight(eIGS_Last+i, &light); if (effectInfo.slot != -1 && pMaterial) GetEntity()->SetSlotMaterial(effectInfo.slot, pMaterial); Matrix34 tm = Matrix34(Matrix33::CreateRotationVDir(dir)); tm.SetTranslation(position); GetEntity()->SetSlotLocalTM(effectInfo.slot, tm); } else if (slotInfo.pCharacter) // bone attachment { effectInfo.helper = helper; effectInfo.characterSlot = slot; ICharacterInstance *pCharacter = slotInfo.pCharacter; IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(helper); if (!pAttachment) { GameWarning("Item '%s' trying to attach light to attachment '%s' which does not exist!", GetEntity()->GetName(), helper); return 0; } CLightAttachment *pLightAttachment = new CLightAttachment(); pLightAttachment->LoadLight(light); if (pMaterial) { if (ILightSource* pLightSource = pLightAttachment->GetLightSource()) pLightSource->SetMaterial(pMaterial); } if(light.m_Flags&DLF_CASTSHADOW_MAPS) { if (ILightSource* pLightSource = pLightAttachment->GetLightSource()) pLightSource->SetCastingException(pCasterException); } Matrix34 tm =Matrix34(Matrix33::CreateRotationVDir(dir)); tm.SetTranslation(offset); pAttachment->AddBinding(pLightAttachment); pAttachment->SetAttRelativeDefault(QuatT(tm)); } m_effects.insert(TEffectInfoMap::value_type(m_effectGenId, effectInfo)); return m_effectGenId; } else if (id) { TEffectInfoMap::iterator it = m_effects.find(id); if (it == m_effects.end()) return 0; SEffectInfo &info = it->second; if (info.slot>-1) { GetEntity()->FreeSlot(info.slot); } else { ICharacterInstance *pCharacter = GetEntity()->GetCharacter(info.characterSlot); if (pCharacter) { IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(info.helper.c_str()); pAttachment->ClearBinding(); } } m_effects.erase(it); } return 0; }
//------------------------------------------------------------------------ uint32 CItem::AttachEffect(int slot, uint32 id, bool attach, const char *effectName, const char *helper, const Vec3 &offset, const Vec3 &dir, float scale, bool prime) { if (m_stats.mounted) slot=eIGS_FirstPerson; if (attach) { if (!g_pGameCVars->i_particleeffects) return 0; IParticleEffect *pParticleEffect = gEnv->pParticleManager->FindEffect(effectName); if (!pParticleEffect) return 0; // generate id ++m_effectGenId; while (!m_effectGenId || (m_effects.find(m_effectGenId) != m_effects.end())) ++m_effectGenId; SEntitySlotInfo slotInfo; SEffectInfo effectInfo; bool validSlot = GetEntity()->GetSlotInfo(slot, slotInfo) && (slotInfo.pCharacter || slotInfo.pStatObj); if (!validSlot || slotInfo.pStatObj || (!helper || !helper[0])) { // get helper position Vec3 position(0,0,0); if (validSlot && helper && helper[0]) { IStatObj *pStatsObj = slotInfo.pStatObj; position = pStatsObj->GetHelperPos(helper); position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position); } position+=offset; // find a free slot SEntitySlotInfo dummy; int i=0; while (GetEntity()->GetSlotInfo(eIGS_Last+i, dummy)) i++; // move particle slot to the helper position+offset effectInfo.helper = helper; effectInfo.slot = GetEntity()->LoadParticleEmitter(eIGS_Last+i, pParticleEffect, 0, prime, true); Matrix34 tm = IParticleEffect::ParticleLoc(position, dir, scale); GetEntity()->SetSlotLocalTM(effectInfo.slot, tm); } else if (slotInfo.pCharacter) // bone attachment { effectInfo.helper = helper; effectInfo.characterSlot = slot; ICharacterInstance *pCharacter = slotInfo.pCharacter; IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(helper); if (!pAttachment) { GameWarning("Item '%s' trying to attach effect '%s' to attachment '%s' which does not exist!", GetEntity()->GetName(), effectName, helper); return 0; } CEffectAttachment *pEffectAttachment = new CEffectAttachment(effectName, Vec3(0,0,0), Vec3(0,1,0), scale); Matrix34 tm = Matrix34(Matrix33::CreateRotationVDir(dir)); tm.SetTranslation(offset); pAttachment->AddBinding(pEffectAttachment); pAttachment->SetAttRelativeDefault(QuatT(tm)); pEffectAttachment->UpdateAttachment(pAttachment); if (pEffectAttachment->GetEmitter()) { if (prime) pEffectAttachment->GetEmitter()->Prime(); } } m_effects.insert(TEffectInfoMap::value_type(m_effectGenId, effectInfo)); return m_effectGenId; } else if (id) { TEffectInfoMap::iterator it = m_effects.find(id); if (it == m_effects.end()) return 0; SEffectInfo &info = it->second; if (info.slot>-1) { GetEntity()->FreeSlot(info.slot); } else { ICharacterInstance *pCharacter = GetEntity()->GetCharacter(info.characterSlot); if (pCharacter) { IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(info.helper.c_str()); if(pAttachment) pAttachment->ClearBinding(); } } m_effects.erase(it); } return 0; }
//------------------------------------------------------------------------ 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; }
void CVehicleWeaponControlled::Update3PAnim(CPlayer *player, float goalTime, float frameTime, const Matrix34 &mat) { if (player) { if (IEntity *entity = player->GetEntity()) { const float ANIM_ANGLE_RANGE = gf_PI*0.25f; static float dir = 0.05f; static float pos = 0.5f; pos += dir; if (pos > 1.0f) { pos = 1.0f; dir = -dir; } else if (pos < 0.0f) { pos = 0.0f; dir = -dir; } m_CurrentTime = LERP(m_CurrentTime, goalTime, frameTime); if (ICharacterInstance *character = entity->GetCharacter(0)) { ISkeletonAnim *pSkeletonAnim = character->GetISkeletonAnim(); assert(pSkeletonAnim); //Update manually animation time, to match current weapon orientation uint32 numAnimsLayer = pSkeletonAnim->GetNumAnimsInFIFO(0); for(uint32 i=0; i<numAnimsLayer; i++) { CAnimation &animation = pSkeletonAnim->GetAnimFromFIFO(0, i); if (animation.HasStaticFlag( CA_MANUAL_UPDATE )) { float time = m_CurrentTime; //pos; //fmod_tpl(aimRad / ANIM_ANGLE_RANGE, 1.0f); time = (float)__fsel(time, time, 1.0f + time); pSkeletonAnim->SetAnimationNormalizedTime(&animation, time); animation.ClearStaticFlag( CA_DISABLE_MULTILAYER ); } } } const SMountParams* pMountParams = GetMountedParams(); SEntitySlotInfo info; if (GetEntity()->GetSlotInfo(eIGS_ThirdPerson, info)) { if (info.pStatObj) { IStatObj *pStatsObj = info.pStatObj; const Vec3 &leftHandPos = pStatsObj->GetHelperPos(pMountParams->left_hand_helper.c_str()); const Vec3 &rightHandPos = pStatsObj->GetHelperPos(pMountParams->right_hand_helper.c_str()); const Vec3 leftIKPos = mat.TransformPoint(leftHandPos); const Vec3 rightIKPos = mat.TransformPoint(rightHandPos); player->SetIKPos("leftArm", leftIKPos, 1); player->SetIKPos("rightArm", rightIKPos, 1); } } } } }
// 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; }
//-------------------------------------------------------------------------------------------------- // 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; }//-------------------------------------------------------------------------------------------------
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; } }
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(); }
//------------------------------------------------------------------------ void CVehicleDamageBehaviorDetachPart::OnDamageEvent(EVehicleDamageBehaviorEvent event, const SVehicleDamageBehaviorEventParams& behaviorParams) { if (event == eVDBE_Repair) return; if (!m_detachedEntityId && behaviorParams.componentDamageRatio >= 1.0f) { CVehiclePartBase* pPart = (CVehiclePartBase*)m_pVehicle->GetPart(m_partName.c_str()); if (!pPart || !pPart->GetStatObj()) return; if (max(1.f-behaviorParams.randomness, pPart->GetDetachProbability()) < cry_random(0.0f, 1.0f)) return; IEntity* pDetachedEntity = SpawnDetachedEntity(); if (!pDetachedEntity) return; m_detachedEntityId = pDetachedEntity->GetId(); const Matrix34& partWorldTM = pPart->GetWorldTM(); pDetachedEntity->SetWorldTM(partWorldTM); MovePartToTheNewEntity(pDetachedEntity, pPart); SEntityPhysicalizeParams physicsParams; physicsParams.mass = pPart->GetMass(); physicsParams.type = PE_RIGID; physicsParams.nSlot = 0; pDetachedEntity->Physicalize(physicsParams); IPhysicalEntity* pPhysics = pDetachedEntity->GetPhysics(); if (pPhysics) { pe_params_part params; params.flagsOR = geom_collides|geom_floats; params.flagsColliderAND = ~geom_colltype3; params.flagsColliderOR = geom_colltype0; pPhysics->SetParams(¶ms); pe_action_add_constraint ac; ac.flags = constraint_inactive|constraint_ignore_buddy; ac.pBuddy = m_pVehicle->GetEntity()->GetPhysics(); ac.pt[0].Set(0,0,0); pPhysics->Action(&ac); // after 1s, remove the constraint again m_pVehicle->SetTimer(-1, 1000, this); // set the impulse const Vec3& velocity = m_pVehicle->GetStatus().vel; Vec3 baseForce = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(pPart->GetDetachBaseForce()); baseForce *= cry_random(6.0f, 10.0f); pe_action_impulse actionImpulse; actionImpulse.impulse = physicsParams.mass * (velocity + baseForce); actionImpulse.angImpulse = physicsParams.mass * Vec3(cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f)); actionImpulse.iApplyTime = 1; pPhysics->Action(&actionImpulse); } // copy vehicle's material to new entity (fixes detaching parts from vehicles with different paints), // or specify the destroyed material if it exists IStatObj* pExternalStatObj = pPart->GetExternalGeometry(false); // Get undamaged external geometry (if any) IMaterial *pMaterial = pExternalStatObj ? pExternalStatObj->GetMaterial() : m_pVehicle->GetEntity()->GetMaterial(); if(event == eVDBE_VehicleDestroyed || event == eVDBE_Hit) { if (pExternalStatObj) { if (IStatObj* pStatObj = pPart->GetExternalGeometry(true)) // Try to get the destroyed, external geometry material pMaterial = pStatObj->GetMaterial(); } else if (m_pVehicle->GetDestroyedMaterial()) // If there is no external geometry, try the vehicle's destroyed material { pMaterial = m_pVehicle->GetDestroyedMaterial(); } } pDetachedEntity->SetMaterial(pMaterial); AttachParticleEffect(pDetachedEntity, m_pEffect); if (m_notifyMovement) { SVehicleMovementEventParams params; params.iValue = pPart->GetIndex(); m_pVehicle->GetMovement()->OnEvent(IVehicleMovement::eVME_PartDetached, params); } } }