/// Update light-related shader variables void SetLightsToShader( CCopyEntity& entity, ShaderManager& rShaderMgr ) { shared_ptr<ShaderLightManager> pShaderLightMgr = rShaderMgr.GetShaderLightManager(); int i, num_current_lights = entity.GetNumLights(); LightEntity *pLightEntity = NULL; // clear any lights currenly stored in the shader light manager pShaderLightMgr->ClearLights(); ShaderLightParamsWriter light_params_writer( pShaderLightMgr.get() ); for( i=0; i<num_current_lights; i++ ) { EntityHandle<LightEntity>& light_entity = entity.GetLight( i ); LightEntity *pLightEntity = light_entity.GetRawPtr(); if( !pLightEntity ) continue; // pLightEntity->SetLightToShader( pShaderLightMgr ); // copy light properties to the shader registers pLightEntity->GetLightObject()->Accept( light_params_writer ); } pShaderLightMgr->CommitChanges(); }
/// Update shader params loaders for the entity. /// Shader params loaders are shared by entities, and need to be updated every time an entity is rendered. void UpdateEntityForRendering( CCopyEntity& entity ) { BaseEntity& base_entity = *(entity.pBaseEntity); // light params writer if( entity.GetEntityFlags() & BETYPE_LIGHTING ) { UpdateLightInfo( entity ); if( base_entity.MeshProperty().m_pShaderLightParamsLoader ) { // Set the entity to the light params loader, because a single light params loader // is shared by all the entities of this base entity. base_entity.MeshProperty().m_pShaderLightParamsLoader->SetEntity( entity.Self().lock() ); } } const float offset_world_transform_threshold = 150000.0f; if( square(offset_world_transform_threshold) < Vec3LengthSq(entity.GetWorldPose().vPosition) ) { Camera* pCam = entity.GetStage()->GetCurrentCamera(); if( pCam ) { sg_pWorldTransLoader->SetActive( true ); sg_pWorldTransLoader->SetCameraPosition( pCam->GetPosition() ); } else sg_pWorldTransLoader->SetActive( false ); } else sg_pWorldTransLoader->SetActive( false ); }
void CStage::UpdateListener() { Matrix34 cam_pose; Camera *pCamera; // get the pose of the current camera pCamera = this->GetCurrentCamera(); if( pCamera ) { pCamera->GetPose( cam_pose ); } else { CCopyEntity* pEntity = this->GetEntitySet()->GetCameraEntity(); if( pEntity ) cam_pose = pEntity->GetWorldPose(); else cam_pose.Identity(); } // update listener for sound manager GetSoundManager().SetListenerPose( cam_pose ); CCopyEntity *pCameraEntity = this->GetEntitySet()->GetCameraEntity(); if( pCameraEntity ) GetSoundManager().SetListenerVelocity( pCameraEntity->Velocity() ); GetSoundManager().CommitDeferredSettings(); }
Result::Name RegisterAsPlanarMirror( CCopyEntity& entity, BasicMesh& mesh, int subset_index ) { const AABB3& aabb = mesh.GetAABB(subset_index); EntityRenderManager& entity_render_mgr = *(entity.GetStage()->GetEntitySet()->GetRenderManager()); // >>> TODO: support planes that are not axis-aligned or facing along the negative half-space SPlane plane; int plane_axis = 1; if( aabb.vMax.x - aabb.vMin.x < 0.001f ) plane_axis = 0; else if( aabb.vMax.y - aabb.vMin.y < 0.001f ) plane_axis = 1; else if( aabb.vMax.z - aabb.vMin.z < 0.001f ) plane_axis = 2; else plane_axis = 1; plane.normal = Vector3(0,0,0); plane.normal[plane_axis] = 1; plane.dist = aabb.vMax[plane_axis]; Result::Name res = entity_render_mgr.AddPlanarReflector( EntityHandle<>( entity.Self() ), plane ); if( res != Result::SUCCESS ) return Result::UNKNOWN_ERROR; entity.RaiseEntityFlags( BETYPE_PLANAR_REFLECTOR ); // Create shader variable loader for mirror if( !entity.m_pMeshRenderMethod ) { if( entity.pBaseEntity->MeshProperty().m_pMeshRenderMethod ) { entity.m_pMeshRenderMethod = entity.pBaseEntity->MeshProperty().m_pMeshRenderMethod->CreateCopy(); if( !entity.m_pMeshRenderMethod ) return Result::UNKNOWN_ERROR; } else return Result::UNKNOWN_ERROR; } // create a planar reflection entity // shared_ptr<MeshContainerRenderMethod> pMeshRenderMethodCopy // = entity.m_pMeshRenderMethod->CreateCopy(); shared_ptr<MirroredSceneTextureParam> pTexParam; pTexParam.reset( new MirroredSceneTextureParam( EntityHandle<>( entity.Self() ) ) ); pTexParam->m_fReflection = mesh.GetMaterial(subset_index).m_Mat.fReflection; // pMeshRenderMethodCopy->SetShaderParamsLoaderToAllMeshRenderMethods( pTexParam ); // test - we assume that the entity's mesh is composed of polygons that belong to a single plane. entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pTexParam ); // Move the indices of the planar reflection subset(s) // to the render method of the planar reflection entity return Result::SUCCESS; }
void AlphaEntity::Update( float dt ) { CCopyEntity *pParent = m_pParent; if( !pParent ) return; SetWorldPose( pParent->GetWorldPose() ); }
static Vector3 GetPlayerPosition() { CCopyEntity *pPlayer = GetPlayerEntity(); if( pPlayer ) return pPlayer->GetWorldPosition(); else return Vector3(0,0,0); }
void EntityManager::UpdateGraphics() { if( m_pEntityInUse ) { for( CCopyEntity* pEntity = m_pEntityInUse.get(); pEntity != NULL; pEntity = pEntity->m_pNextRawPtr ) { pEntity->UpdateGraphics(); } } }
void UpdateLightInfo( CCopyEntity& entity ) { if( entity.Lighting() ) { if( entity.sState & CESTATE_LIGHT_INFORMATION_INVALID ) { // need to update light information - find lights that reaches to this entity entity.ClearLights(); entity.GetStage()->GetEntitySet()->UpdateLights( &entity ); entity.sState &= ~CESTATE_LIGHT_INFORMATION_INVALID; } } }
void CBE_GeneralEntity::Act(CCopyEntity* pCopyEnt) { float frametime = m_pStage->GetFrameTime(); if( m_sGEAttribute & GETYPE_LIFETIMER ) { float& rfLifeTimer = LifeTimer(pCopyEnt); rfLifeTimer -= frametime; if( rfLifeTimer <= 0.0f ) { // lifetime has expired - terminate the entity if( 0 < strlen(m_Explosion.GetBaseEntityName()) ) { // create explosion animation m_pStage->CreateEntity( m_Explosion, pCopyEnt->GetWorldPosition(), Vector3(0,0,0), pCopyEnt->GetDirection() ); } m_pStage->TerminateEntity( pCopyEnt ); return; } } if( pCopyEnt->bNoClip && !(pCopyEnt->GetEntityFlags() & BETYPE_RIGIDBODY) ) { // TODO: pose update for collidable enitity pCopyEnt->SetWorldPosition( pCopyEnt->GetWorldPosition() + pCopyEnt->Velocity() * frametime ); } // if( 0 < strlen(m_SmokeTrace.GetBaseEntityName()) ) if( 0 < m_vecSmokeTrail.size() ) { int i, num = (int)m_vecSmokeTrail.size(); for( i=0; i<num; i++ ) { CCopyEntity* pSmokeTrace = pCopyEnt->GetChild(i); if( IsValidEntity( pSmokeTrace ) ) pSmokeTrace->Act(); // update smoke trace } } if( pCopyEnt->GetEntityFlags() & BETYPE_ENVMAPTARGET ) { } /** if( pCopyEnt->GetChild(0) ) pCopyEnt->GetChild(0)->Act();**/ }
void CBE_Enemy::SearchPlayer(CCopyEntity* pCopyEnt, short& rsMode, Vector3& rvDesiredDirection, float* pfSqDistToPlayer) { // ========= enable the following 2 lines to use enemy observation mode ========== // rsMode = CEnemyState::STATE_SEARCH; // return; Vector3 vStart, vMyselfToPlayer; CCopyEntity* pPlayer = SinglePlayerInfo().GetCurrentPlayerBaseEntity()->GetPlayerCopyEntity(); vStart = pCopyEnt->GetWorldPosition() + pCopyEnt->GetDirection() * 1.42f; vMyselfToPlayer = pPlayer->GetWorldPosition() - vStart; // chehck the distance to the player float fSqDist = Vec3LengthSq( vMyselfToPlayer ); if( pfSqDistToPlayer ) *pfSqDistToPlayer = fSqDist; if( 40000 < fSqDist ) { // too far from the player rsMode = CEnemyState::STATE_SEARCH; return; } if( !CheckRayToPlayer(pCopyEnt) ) { rsMode = CEnemyState::STATE_SEARCH; // there is an obstacle between the player return; } // set 'rvDesiredDirection' - unit vector pointing at the target(player) Vec3Normalize( vMyselfToPlayer, vMyselfToPlayer ); rvDesiredDirection = vMyselfToPlayer; float fDotProduct = Vec3Dot( pCopyEnt->GetDirection(), vMyselfToPlayer ); // 'fDotProduct' ranges from -1 through 1 if( 0 < fDotProduct ) { //the player is visible from this entity rsMode = CEnemyState::STATE_ATTACK; // move to attack mode } else { if( fSqDist < 400.0f ) rsMode = CEnemyState::STATE_ATTACK; // close enough to hear the player else rsMode = CEnemyState::STATE_SEARCH; } }
void BaseEntity::RenderEntity( CCopyEntity& entity ) { UpdateEntityForRendering( entity ); // default render states for fixed function pipeline // default alpha-blending settings (premultiplied alpha) GraphicsDevice().Enable( RenderStateType::ALPHA_BLEND ); GraphicsDevice().SetSourceBlendMode( AlphaBlend::One ); GraphicsDevice().SetDestBlendMode( AlphaBlend::InvSrcAlpha ); if( entity.m_pMeshRenderMethod ) { entity.m_pMeshRenderMethod->RenderMesh( entity.m_MeshHandle, entity.GetWorldPose() ); } else if( m_MeshProperty.m_pMeshRenderMethod ) { m_MeshProperty.m_pMeshRenderMethod->RenderMesh( entity.m_MeshHandle, entity.GetWorldPose() ); } // entity.m_pMeshRenderMethod->RenderMeshContainerNode( *(entity.m_pMeshNode.get()), m_vecpShaderParamsWriterBuffer ); }
EntityHandle<> CStage::LoadStaticGeometryFromFile( const std::string filename ) { SafeDelete( m_pStaticGeometry ); m_pStaticGeometry = CreateStaticGeometry( this, filename ); if( !m_pStaticGeometry ) return EntityHandle<>(); // register the static geometry as an entity // - the entity is used to render the static geometry BaseEntityHandle baseentity_handle; baseentity_handle.SetBaseEntityName( "StaticGeometry" ); CCopyEntityDesc desc; desc.strName = filename; desc.pBaseEntityHandle = &baseentity_handle; desc.pUserData = m_pStaticGeometry; CCopyEntity *pStaticGeometryEntity = CreateEntity( desc ); if( !pStaticGeometryEntity ) return EntityHandle<>(); // shared_ptr<CStaticGeometryEntity> pEntity( new CStaticGeometryEntity ); // pEntity->SetStaticGeometry( m_pStaticGeometry ); // EntityHandle<CStaticGeometryEntity> entity // = CreateEntity( pEntity, baseentity_handle ); m_pEntitySet->WriteEntityTreeToFile( "debug/entity_tree - loaded static geometry.txt" ); // load the static geometry from file this->PauseTimer(); bool loaded = m_pStaticGeometry->LoadFromFile( filename ); this->ResumeTimer(); return EntityHandle<>( pStaticGeometryEntity->Self() ); // return entity; }
// sets the following shader params loaders to the render method of an entity // - CEntityShaderLightParamsLoader // - Set if the BETYPE_LIGHTING flag is on // - BlendTransformsLoader // - Set if pEntity->m_MeshHandle is a skeletal mesh void InitMeshRenderMethod( CCopyEntity &entity, shared_ptr<BlendTransformsLoader> pBlendTransformsLoader ) { if( !entity.m_pMeshRenderMethod ) { entity.m_pMeshRenderMethod.reset( new MeshContainerRenderMethod ); // entity.m_pMeshRenderMethod->MeshRenderMethod().resize( 1 ); } if( entity.GetEntityFlags() & BETYPE_LIGHTING ) { shared_ptr<CEntityShaderLightParamsLoader> pLightParamsLoader( new CEntityShaderLightParamsLoader() ); pLightParamsLoader->SetEntity( entity.Self() ); entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pLightParamsLoader ); } // Not used now. // Item entities set this in its own member function ItemEntity::InitMesh(). // Does any entity other than item entty need this? if( pBlendTransformsLoader ) entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pBlendTransformsLoader ); /* shared_ptr<BasicMesh> pMesh = entity.m_MeshHandle.GetMesh(); if( pMesh && pMesh->GetMeshType() == MeshType::SKELETAL ) { // shared_ptr<SkeletalMesh> pSkeletalMesh // = boost::dynamic_pointer_cast<SkeletalMesh,BasicMesh>(pMesh); if( !pBlendTransformsLoader ) pBlendTransformsLoader.reset( new BlendTransformsLoader() ); entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pBlendTransformsLoader ); }*/ if( true /* world position of entity has large values */ ) { entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( sg_pWorldTransLoader ); } }
void CES_Search::Act( CCopyEntity& rEntity, CBE_Enemy& rBaseEntity, float dt ) { // first, get the extra data of 'pCopyEnt' SBE_EnemyExtraData* pExtraData = rBaseEntity.GetExtraData( rEntity.iExtraDataIndex ); short& rsCurrentState = rEntity.s1; float& rfSensoringInterval = rEntity.f1; Vector3& rvDesiredDirection = rEntity.v1; float fSqDistToPlayer; rfSensoringInterval += dt; if( 0.32f <= rfSensoringInterval ) { rfSensoringInterval = 0; // check if the player is in a visible position and update 'rvDesiredDirection' and 'rsMode' short sSearchResult = 0; rBaseEntity.SearchPlayer( &rEntity, sSearchResult, rvDesiredDirection, &fSqDistToPlayer ); if( sSearchResult == STATE_ATTACK ) { // the player is in sight - engage rsCurrentState = STATE_ATTACK; rBaseEntity.UpdateDesiredYawAndPitch( &rEntity, rvDesiredDirection ); pExtraData->vLastCheckedDirectionToPlayer = rvDesiredDirection; pExtraData->fLastCheckedSqDistToPlayer = fSqDistToPlayer; pExtraData->vLastCheckedPlayerPosition = rvDesiredDirection * (float)sqrt(fSqDistToPlayer); return; } else { // lost sight of the player if( pExtraData->vLastCheckedPlayerPosition != Vector3(0,0,0) ) { Vector3 vDir = pExtraData->vLastCheckedPlayerPosition - rEntity.GetWorldPosition(); Vec3Normalize( rvDesiredDirection, vDir ); } } } rBaseEntity.SearchManeuver(&rEntity,pExtraData); }
/// Perhaps this should be a member of CCopyEntity, not BaseEntity /// - m_pStage is the only member of the base entity /// - CCopyEnttiy has m_pStage void BaseEntity::SetAsEnvMapTarget( CCopyEntity& entity ) { if( entity.GetEntityFlags() & BETYPE_ENVMAPTARGET ) { // shared_ptr<CubeTextureParamsLoader> pCubeTexLoader( new CCubeTextureParamsLoader() ); // pCubeTexLoader->SetCubeTexture( 0, m_pStage->GetEntitySet()->GetRenderManager()->GetEnvMapTexture(entity.GetID()) ); // entity.m_pMeshRenderMethod->AddShaderParamsLoaderToAllRenderMethods( pCubeTexLoader ); /* if( 0 < entity.m_pMeshRenderMethod->MeshRenderMethod().size() ) { // shader LOD: fixed to 0 entity.m_pMeshRenderMethod->MeshRenderMethod(0).m_vecpShaderParamsLoader.push_back( pCubeTexLoader ); } else { // alpha entity? }*/ } }
void EntityManager::UpdatePhysics( float frametime ) { PROFILE_FUNCTION(); // frametime *= 0.5f; Scalar total_time = frametime + m_PhysOverlapTime; if (total_time > 0.1f) total_time = 0.1f; // split the timestep into fixed size chunks int num_loops = (int) (total_time / m_PhysTimestep); Scalar timestep = m_PhysTimestep; if ( false /*m_allow_smaller_timesteps*/ ) { if (num_loops == 0) num_loops = 1; timestep = total_time / num_loops; } m_PhysOverlapTime = total_time - num_loops * timestep; // TCPreAllocDynamicLinkList<CJL_PhysicsActor>& rActorList = m_pStage->m_pPhysicsManager->GetActorList(); // TCPreAllocDynamicLinkList<CJL_PhysicsActor>::LinkListIterator itrActor; int i; for (i=0 ; i<num_loops ; ++i) { // m_physics_time += timestep; // apply gravity /* for( itrActor = rActorList.Begin(); itrActor != rActorList.End(); itrActor++ ) { if( !(itrActor->GetActorFlag() & JL_ACTOR_STATIC) ) itrActor->AddWorldForce( itrActor->GetMass() * Vector3(0,-9.8f,0) ); } */ ProfileBegin( "Entity Update (Physics)" ); // update physics properties that are specific to each entity // DO NOT CONFUSE THIS WITH CCopyEntity::UpdatePhysics() CCopyEntity *pEntity; for( pEntity = m_pEntityInUse.get(); pEntity != NULL; pEntity = pEntity->m_pNextRawPtr ) { if( pEntity->GetEntityFlags() & BETYPE_COPY_PARENT_POSE ) pEntity->CopyParentPose(); // if( pEntity->inuse && pEntity->pPhysicsActor ) if( pEntity->inuse && 0 < pEntity->m_vecpPhysicsActor.size() ) pEntity->pBaseEntity->UpdatePhysics( pEntity, timestep ); UpdateEntityAfterMoving( pEntity ); } ProfileEnd( "Entity Update (Physics)" ); { PROFILE_SCOPE( "Physics Simulation" ); // handle the motions and collisions of rigid body entities // m_pStage->m_pPhysicsManager->Integrate( timestep ); m_pStage->GetPhysicsScene()->Simulate( timestep ); while( !m_pStage->GetPhysicsScene()->FetchResults( physics::SimulationStatus::RigidBodyFinished ) ) {} } // clear forces on actors /* for( itrActor = rActorList.Begin(); itrActor != rActorList.End(); itrActor++ ) { itrActor->ClearForces(); } */ } }
void EntityManager::InitEntity( boost::shared_ptr<CCopyEntity> pNewCopyEntPtr, CCopyEntity *pParent, BaseEntity *pBaseEntity, CActorDesc* pPhysActorDesc ) { CCopyEntity* pNewCopyEnt = pNewCopyEntPtr.get(); // Mark the entity as in use pNewCopyEnt->inuse = true; pNewCopyEnt->m_pSelf = pNewCopyEntPtr; pNewCopyEnt->pBaseEntity = pBaseEntity; BaseEntity& rBaseEntity = (*pBaseEntity); pNewCopyEnt->m_pStage = m_pStage; // set id and increment the counter pNewCopyEnt->m_ID = m_EntityIDConter++; // z-sort is disabled by default initialization // Entities that have translucent polygons have to turn on their copy entities' // 'BETYPE_USE_ZSORT' in InitCopyEntity() if( pNewCopyEnt->m_TypeID == CCopyEntityTypeID::ALPHA_ENTITY ) { // For alpha entity, always use the z-sorting pNewCopyEnt->RaiseEntityFlags( BETYPE_USE_ZSORT ); } else { // Otherwise, disable z-sorting by default pNewCopyEnt->ClearEntityFlags( BETYPE_USE_ZSORT ); } // set the glare type if( rBaseEntity.m_EntityFlag & BETYPE_GLARESOURCE ) { pNewCopyEnt->RaiseEntityFlags( BETYPE_GLARESOURCE ); } else if( rBaseEntity.m_EntityFlag & BETYPE_GLAREHINDER ) { pNewCopyEnt->RaiseEntityFlags( BETYPE_GLAREHINDER ); } // update world aabb pNewCopyEnt->world_aabb.TransformCoord( pNewCopyEnt->local_aabb, pNewCopyEnt->GetWorldPosition() ); // link the new copy-entity to the top of 'm_pEntityInUse' if( m_pEntityInUse ) pNewCopyEnt->SetNext( m_pEntityInUse ); else pNewCopyEnt->SetNextToNull(); // first entity in the link list m_pEntityInUse = pNewCopyEntPtr; // set the created time of the entity pNewCopyEnt->m_CreatedTime = m_pStage->GetElapsedTime(); // set parent entity pNewCopyEnt->m_pParent = pParent; if( pNewCopyEnt->m_pParent ) { // 'pNewCopyEnt' is being created as a child of another copy entity pNewCopyEnt->m_pParent->AddChild( pNewCopyEnt->m_pSelf ); // establish link from the parent to this entity } // LOG_PRINT( "linking a copy entity of " + rBaseEntity.GetNameString() + " to the tree" ); // link the new copy-entity to the entity-tree Link( pNewCopyEnt ); // update light information if( pNewCopyEnt->Lighting() ) { pNewCopyEnt->ClearLights(); // UpdateLightInfo( pNewCopyEnt ); pNewCopyEnt->sState |= CESTATE_LIGHT_INFORMATION_INVALID; } // create object for physics simulation if( pNewCopyEnt->GetEntityFlags() & BETYPE_RIGIDBODY ) { CActor *pPhysActor = NULL; if( pPhysActorDesc ) { pPhysActorDesc->WorldPose = pNewCopyEnt->GetWorldPose();// * pNewCopyEnt->GetActorLocalPose(); pPhysActorDesc->BodyDesc.LinearVelocity = pNewCopyEnt->Velocity(); // each entity has its own actor desc pPhysActor = m_pStage->GetPhysicsScene()->CreateActor( *pPhysActorDesc ); } else if( pBaseEntity->GetPhysicsActorDesc().IsValid() ) { // actor desc is defined by entity attributes CActorDesc actor_desc = pBaseEntity->GetPhysicsActorDesc(); actor_desc.WorldPose = pNewCopyEnt->GetWorldPose(); actor_desc.BodyDesc.LinearVelocity = pNewCopyEnt->Velocity(); // pNewCopyEnt->pPhysicsActor = m_pStage->GetPhysicsScene()->CreateActor( actor_desc ); pPhysActor = m_pStage->GetPhysicsScene()->CreateActor( actor_desc ); } if( pPhysActor ) { pNewCopyEnt->m_vecpPhysicsActor.resize( 1 ); pNewCopyEnt->m_vecpPhysicsActor[0] = pPhysActor; pPhysActor->m_pFrameworkData = pNewCopyEnt; } } // When all the basic properties are copied, InitCopyEntity() is called to // do additional initialization specific to each base entity. rBaseEntity.InitCopyEntity( pNewCopyEnt ); }
CCopyEntity *EntityManager::CreateEntity( CCopyEntityDesc& rCopyEntityDesc ) { if( !rCopyEntityDesc.pBaseEntityHandle ) return NULL; BaseEntityHandle& rBaseEntityHandle = *(rCopyEntityDesc.pBaseEntityHandle); // LOG_PRINT( "creating a copy entity of " + string(rBaseEntityHandle.GetBaseEntityName()) ); BaseEntity *pBaseEntity = GetBaseEntity( rBaseEntityHandle ); if( !pBaseEntity ) return NULL; BaseEntity& rBaseEntity = *(pBaseEntity); // LOG_PRINT( "checking the initial position of " + rBaseEntity.GetNameString() ); // determine the entity group id // priority (higher to lower): // (id set to copy entity desc) -> (id set to base entity) int entity_group_id = ENTITY_GROUP_INVALID_ID; if( rCopyEntityDesc.sGroupID != ENTITY_GROUP_INVALID_ID ) { entity_group_id = rCopyEntityDesc.sGroupID; } else { // try the group of base entity entity_group_id = rBaseEntity.GetEntityGroupID(); } if( false ) // if( !rBaseEntity.m_bNoClip ) // && rCopyEntityDesc.DontCreateIfOverlapIsDetected ) { // check for overlaps with other entities // to see if the new entity is in a valid position // if( rCopyEnt.bvType == BVTYPE_AABB || rCopyEnt.bvType == BVTYPE_DOT ) // { STrace tr; tr.sTraceType = TRACETYPE_IGNORE_NOCLIP_ENTITIES; tr.vEnd = rCopyEntityDesc.WorldPose.vPosition; tr.bvType = rBaseEntity.m_BoundingVolumeType; tr.aabb = rBaseEntity.m_aabb; tr.GroupIndex = entity_group_id; if( rBaseEntity.m_bNoClipAgainstMap ) tr.sTraceType |= TRACETYPE_IGNORE_MAP; m_pStage->CheckPosition( tr ); if(tr.in_solid) { LOG_PRINT( " - cannot create a copy entity due to overlaps: " + string(rBaseEntityHandle.GetBaseEntityName()) ); return NULL; // specified position is invalid - cannot create entity } // } } // LOG_PRINT( "the copy entity of " + rBaseEntity.GetNameString() + " is in a valid position" ); // create an entity shared_ptr<CCopyEntity> pNewEntitySharedPtr = m_pEntityFactory->CreateEntity( rCopyEntityDesc.TypeID ); if( !pNewEntitySharedPtr ) { /// too many entities or no entity is defined for rCopyEntityDesc.TypeID LOG_PRINT_ERROR( " - cannot create a copy entity of '" + string(rBaseEntityHandle.GetBaseEntityName()) + "'" ); return NULL; } CCopyEntity *pNewCopyEnt = pNewEntitySharedPtr.get(); pNewCopyEnt->m_TypeID = rCopyEntityDesc.TypeID; // copy parameter values from base entity (entity attributes set) SetBasicEntityAttributes( pNewCopyEnt, rBaseEntity ); // copy parameter values from entity desc pNewCopyEnt->SetName( rCopyEntityDesc.strName ); pNewCopyEnt->SetWorldPose( rCopyEntityDesc.WorldPose ); pNewCopyEnt->Velocity() = rCopyEntityDesc.vVelocity; pNewCopyEnt->fSpeed = rCopyEntityDesc.fSpeed; pNewCopyEnt->m_MeshHandle = rCopyEntityDesc.MeshObjectHandle; pNewCopyEnt->f1 = rCopyEntityDesc.f1; pNewCopyEnt->f2 = rCopyEntityDesc.f2; pNewCopyEnt->f3 = rCopyEntityDesc.f3; pNewCopyEnt->f4 = rCopyEntityDesc.f4; pNewCopyEnt->f5 = 0.0f; pNewCopyEnt->s1 = rCopyEntityDesc.s1; pNewCopyEnt->v1 = rCopyEntityDesc.v1; pNewCopyEnt->v2 = rCopyEntityDesc.v2; pNewCopyEnt->iExtraDataIndex = rCopyEntityDesc.iExtraDataIndex; pNewCopyEnt->pUserData = rCopyEntityDesc.pUserData; pNewCopyEnt->sState = 0; pNewCopyEnt->bInSolid = false; pNewCopyEnt->GroupIndex = entity_group_id; // pNewCopyEnt->GroupIndex = rCopyEntityDesc.sGroupID; pNewCopyEnt->touch_plane.dist = 0; pNewCopyEnt->touch_plane.normal = Vector3(0,0,0); InitEntity( pNewEntitySharedPtr, rCopyEntityDesc.pParent, pBaseEntity, rCopyEntityDesc.pPhysActorDesc ); pNewCopyEnt->Init( rCopyEntityDesc ); LOG_PRINT_VERBOSE( " - created a copy entity of " + rBaseEntity.GetNameString() ); return pNewCopyEnt; }
// Initializes CCopyEntity::m_pMeshRenderMethod // - Initialize the mesh render method // - Initialize shader parameter loaders // - Create alpha entities // - Creates a shader void BaseEntity::InitEntityGraphics( CCopyEntity &entity, ShaderHandle& shader, ShaderTechniqueHandle& tech ) { if( shader.IsLoaded() && tech.GetTechniqueName() && 0 < strlen(tech.GetTechniqueName()) ) { CreateMeshRenderMethod( EntityHandle<>( entity.Self() ), shader, tech ); } else { InitMeshRenderMethod( entity ); } // create transparent parts of the model as separate entities if( m_EntityFlag & BETYPE_SUPPORT_TRANSPARENT_PARTS ) { // Remove any previous alpha entities int next_child_index = 0; while( next_child_index < entity.GetNumChildren() ) // for( int i=0; i<entity.GetNumChildren(); i++ ) { shared_ptr<CCopyEntity> pChild = entity.m_aChild[next_child_index].Get(); if( IsValidEntity(pChild.get()) && pChild->GetEntityTypeID() == CCopyEntityTypeID::ALPHA_ENTITY ) { CCopyEntity *pChildRawPtr = pChild.get(); m_pStage->TerminateEntity( pChildRawPtr ); } else next_child_index += 1; } CreateAlphaEntities( &entity ); } shared_ptr<BasicMesh> pMesh = entity.m_MeshHandle.GetMesh(); if( !pMesh ) return; BasicMesh& mesh = *pMesh; const int num_mesh_materials = mesh.GetNumMaterials(); std::vector<GenericShaderDesc> shader_descs; shader_descs.resize( num_mesh_materials ); std::vector<int> mirror_subsets_indices; // std::vector<int> non_mirror_subsets_indices; if( m_MeshProperty.m_MeshDesc.IsValid() ) // if( true ) { // The mesh is specified in the base entity } else { // base entity has no mesh // - entity's mesh is individual shader_descs.resize( num_mesh_materials ); for( int i=0; i<num_mesh_materials; i++ ) { // Fill out the shader desc based on the parameter values of the material // reflection bool registered_as_mirror = RegisterAsMirrorIfReflective( entity, mesh, i, shader_descs[i] ); if( registered_as_mirror ) mirror_subsets_indices.push_back( i ); // specularity if( 0.001f < mesh.GetMaterial(i).m_Mat.fSpecularity ) shader_descs[i].Specular = SpecularSource::UNIFORM; else shader_descs[i].Specular = SpecularSource::NONE; } vector< pair< GenericShaderDesc, vector<unsigned int> > > grouped_descs; group_elements( shader_descs, grouped_descs ); // Do a NULL check just in case // The mesh render method is initialized by InitMeshRenderMethod() above. if( !entity.m_pMeshRenderMethod ) entity.m_pMeshRenderMethod.reset( new MeshContainerRenderMethod ); bool shader_loaded = false; if( grouped_descs.size() == 1 ) { SubsetRenderMethod& render_method = entity.m_pMeshRenderMethod->PrimaryMeshRenderMethod(); render_method.m_Technique.SetTechniqueName( "Default" ); render_method.m_ShaderDesc.pShaderGenerator.reset( new GenericShaderGenerator( grouped_descs[0].first ) ); // shader_loaded = render_method.Load(); shader_loaded = render_method.m_Shader.Load( render_method.m_ShaderDesc ); } else { LOG_PRINT_WARNING( "Mesh materials need different shaders. This situation is not supported yet (the total number of materials: " + to_string(num_mesh_materials) + ")." ); } } }
bool EntityManager::MakeEntityTree(BSPTree* pSrcBSPTree) { // Reset(); vector<EntityNode> entity_tree; // allocate some memory in advance // not doing this may cause error in Release build entity_tree.reserve( 10000 ); // create the new entity tree on the temporary node buffer entity_tree // - Do not copy the tree to m_paEntityTree until all the entities are unlinked MakeEntityNode_r(0, pSrcBSPTree, &entity_tree); if(entity_tree.size() == 0) return false; // entity tree costruction failed entity_tree[0].sParent = -1; // the root node has no parent // unlink all the entities from the current entity tree if( m_pEntityInUse ) { for( CCopyEntity* pEntity = m_pEntityInUse.get(); pEntity != NULL; pEntity = pEntity->m_pNextRawPtr ) { pEntity->Unlink(); } } // Do this AFTER all the entities are unlinked from the entity nodes SafeDeleteArray( m_paEntityTree ); // copy the new tree m_NumEntityNodes = (int)entity_tree.size(); m_paEntityTree = new EntityNode [ m_NumEntityNodes ]; for(int i=0; i<m_NumEntityNodes; i++) m_paEntityTree[i] = entity_tree[i]; entity_tree.clear(); // set stage and entity set for(int i=0; i<m_NumEntityNodes; i++) { m_paEntityTree[i].m_pStage = m_pStage; m_paEntityTree[i].m_pEntitySet = this; } // update entity tree of the render manager m_pRenderManager->UpdateEntityTree( m_paEntityTree, m_NumEntityNodes ); WriteEntityTreeToFile( "debug/entity_tree - recreated the tree.txt" ); // re-link all the entities to the new tree nodes if( m_pEntityInUse ) { for( CCopyEntity* pEntity = m_pEntityInUse.get(); pEntity != NULL; pEntity = pEntity->m_pNextRawPtr ) { // added: 11:34 PM 5/25/2008 // Do not re-link an entity if it has already been marked as 'not in use' // - Failure to do this leads to an invalid link in the entity tree node // - Caused infinite loops in EntityNode::CheckPosition_r() if( !IsValidEntity( pEntity ) ) continue; Link( pEntity ); } } WriteEntityTreeToFile( "debug/entity_tree - re-linked entities to the tree.txt" ); // re-link all the light entities to the new tree nodes // m_pLightEntityManager->RelinkLightEntities(); return true; }
/** Update all the entities cerrently existing in the stage. This function must be called once per frame. - Basic steps - 1. Call BaseEntity::UpdateBaseEntity( dt ) for each base entity - 2. Save positions of copy entities - 3. Run physics simulator - 4. Remove terminated entities from the active list - 5. Call CCopyEntity::Act() for each copy entity except for child entities - 6. Update link to the entity tree node if an entity has changed its position in Act() TODO: Do 5 & 6 in a single loop to update link for each entity right after is Act(). Current code does this in separate loops. */ void EntityManager::UpdateAllEntities( float dt ) { CCopyEntity *pEntity = NULL; CCopyEntity *pPrevEntity = NULL; CCopyEntity *pTouchedEnt = NULL; ONCE( LOG_PRINT( " - updating base entities" ) ); size_t i, num_base_entities = m_vecpBaseEntity.size(); for( i=0; i<num_base_entities; i++ ) { m_vecpBaseEntity[i]->UpdateBaseEntity( dt ); } // save the current entity positions for( pEntity = m_pEntityInUse.get(); pEntity != NULL; pEntity = pEntity->m_pNextRawPtr ) { pEntity->PrevPosition() = pEntity->GetWorldPosition(); } // run physics simulator // entity position may be modified in this call UpdatePhysics( dt ); ONCE( LOG_PRINT( " - updated physics" ) ); // remove terminated entities from the active entity list ReleaseTerminatedEntities(); ONCE( LOG_PRINT( " - removed terminated entities from the active entity list" ) ); // update active entities for( pEntity = this->m_pEntityInUse.get(), pPrevEntity = NULL; pEntity != NULL; pPrevEntity = pEntity, pEntity = pEntity->m_pNextRawPtr ) { // before updating pEntity, check if it has been terminated. if( !pEntity->inuse ) continue; // set the results of physics simulation to // pose, velocity and angular velocity of the entity // if( pEntity->pPhysicsActor && pEntity->GetEntityFlags() & BETYPE_USE_PHYSSIM_RESULTS ) if( 0 < pEntity->m_vecpPhysicsActor.size() && pEntity->GetEntityFlags() & BETYPE_USE_PHYSSIM_RESULTS ) pEntity->UpdatePhysics(); if( pEntity->sState & CESTATE_ATREST ) continue; if( !pEntity->m_pParent || !pEntity->m_pParent->inuse ) { // 'pEntity' has no parent or its parent is already terminated pEntity->pBaseEntity->Act( pEntity ); } if( !pEntity->inuse ) continue; // terminated in its own update routine UpdateEntityAfterMoving( pEntity ); // deal with entities touched during this frame for(int i=0; i<pEntity->vecpTouchedEntity.size(); i++) { pTouchedEnt = pEntity->vecpTouchedEntity[i]; pEntity->pBaseEntity->Touch( pEntity, pTouchedEnt ); if( pTouchedEnt ) pTouchedEnt->pBaseEntity->Touch( pTouchedEnt, pEntity ); } // clear touched entities for the next frame pEntity->vecpTouchedEntity.clear(); } ONCE( LOG_PRINT( " - updated active entities" ) ); // unlink and link the entity in the entity tree if it changed its position /* for( pEntity = m_pEntityInUse.get(); pEntity != NULL; pPrevEntity = pEntity, pEntity = pEntity->m_pNextRawPtr ) { if( !pEntity->inuse ) continue; UpdateEntityAfterMoving(); } */ }
void CBE_Enemy::OnDestroyed( CCopyEntity* pCopyEnt ) { // explosion - usu. done by texture animation CCopyEntityDesc explosion; explosion.pBaseEntityHandle = &m_Explosion; explosion.SetWorldPose( pCopyEnt->GetWorldPose() ); explosion.vVelocity = Vector3(0,0,0); this->m_pStage->CreateEntity( explosion ); // avoid overlaps with fragment entities pCopyEnt->bNoClip = true; LOG_PRINT( " An enemy entity destroyed - velocity: " + to_string(pCopyEnt->Velocity()) ); CCopyEntity* pFragEntity; // MsgBoxFmt( "%s destroyed - creating %d fragments", pCopyEnt->GetName().c_str(), m_iNumFragments ); const int num_fragments = m_iNumFragments; for(int i=0; i<num_fragments; i++) { const Fragment& frag = m_aFragment[i]; CCopyEntityDesc& rFrag = explosion; // reuse desc object rFrag.pBaseEntityHandle = &m_aFragment[i].BaseEntity; rFrag.SetWorldPosition( pCopyEnt->GetWorldPose() * frag.vOffset ); // D3DXVec3TransformCoord( &vWorldFragmentOffset, &m_avFragmentOffset[i], &pCopyEnt->GetOrientation() ); // rFrag.vPosition = pCopyEnt->GetWorldPosition() + vWorldFragmentOffset; rFrag.SetWorldOrient( pCopyEnt->GetWorldPose().matOrient ); //BSPStageBase rFrag.vVelocity = pCopyEnt->Velocity() * 0.3f + vWorldFragmentOffset * 20.0f //BSPStageBase + Vector3( RangedRand(-10.0f,10.0f), RangedRand(-8.0f,8.0f), RangedRand(-10.0f,10.0f) ); rFrag.vVelocity = Vec3RandDir() * RangedRand( frag.InitVelocity.min, frag.InitVelocity.max ) // rFrag.vVelocity = Vec3RandDir() * RangedRand( 15.5f, 35.0f ) + pCopyEnt->Velocity(); pFragEntity = this->m_pStage->CreateEntity( rFrag ); if( pFragEntity ) { physics::CActor *pPhysicsActor = pFragEntity->GetPrimaryPhysicsActor(); if( pPhysicsActor ) { pPhysicsActor->SetAngularVelocity( Vec3RandDir() * RangedRand( 0.5f, 8.0f ) ); } } } /* int num_items = m_vecRewardItem.size(); float f = 0, rand_val; for(i=0; i<m_iNumFragments; i++) { rand_val = GetRangedRand( 0.0f, 1.0f ); f += m_vecRewardItem[i].m_fProbability; if( rand_val < f ) { } } */ // leave a life item // m_pStage->CreateEntity( "s_Life", pCopyEnt->GetWorldPosition(), // Vector3(0,0,0), Vector3(0,0,1) ); }
bool CBE_Enemy::CheckRayToPlayer( CCopyEntity* pCopyEnt ) { CCopyEntity* pPlayer = SinglePlayerInfo().GetCurrentPlayerBaseEntity()->GetPlayerCopyEntity(); /// CCopyEntity* pPlayer = PlayerShip.GetPlayerCopyEntity(); STrace tr; Vector3 vCurrentPos = pCopyEnt->GetWorldPosition(); Vector3 vGoal = pPlayer->GetWorldPosition(); tr.vStart = vCurrentPos; tr.vGoal = vGoal; tr.bvType = BVTYPE_DOT; tr.fRadius = 0; tr.pSourceEntity = pCopyEnt; tr.sTraceType = TRACETYPE_IGNORE_NOCLIP_ENTITIES; Vector3 vDirToPlayer = vGoal - vCurrentPos; Vec3Normalize( vDirToPlayer, vDirToPlayer ); // normalization short sRadarPenetrationCount = 2; short sRadarState = ERS_NOT_IN_SOLID; while( 0 <= sRadarPenetrationCount ) { if( sRadarState == ERS_NOT_IN_SOLID ) { // check trace to the player // tr.vStart = vCurrentPos; // vGoal = &pPlayer->GetWorldPosition(); tr.in_solid = false; tr.fFraction = 1.0f; this->m_pStage->ClipTrace( tr ); vCurrentPos = tr.vEnd; if( tr.fFraction < 1.0f ) // hit something { if( tr.pTouchedEntity == pPlayer ) return true; // player is in a visible position else { // hit static geometry or another entity sRadarState = ERS_IN_SOLID; vCurrentPos += vDirToPlayer * 0.01f; // put 'vCurrentPos' in solid region sRadarPenetrationCount--; continue; } } else // i.e. tr.fFraction == 1.0f { // no hit - an exception. trace should at least hit the player return false; } } else // i.e. sRadarState == ERS_IN_SOLID { vCurrentPos += vDirToPlayer * CBE_ENEMY_RADAR_PENETRATION_CALC_STEP; tr.vEnd = vCurrentPos; tr.fFraction = 1.0f; tr.in_solid = false; m_pStage->CheckPosition( tr ); if( tr.in_solid ) { // proceeding inside the material sRadarPenetrationCount--; continue; } else { // penetrated through the material // move a little forward so that 'vCurrentPos' can safely get out of the wall vCurrentPos += vDirToPlayer * 0.05f; sRadarState = ERS_NOT_IN_SOLID; continue; } } } // player is not visible to this enemy entity return false; }
bool GravityGun::HandleInput( int input_code, int input_type, float fParam ) { Vector3 vOwnerMuzzlePos = m_MuzzleEndWorldPose.vPosition; switch( input_code ) { case ACTION_ATK_FIRE: if( input_type == ITYPE_KEY_PRESSED ) { m_aTriggerState[0] = 1; CCopyEntity *pTarget = m_Target.GetRawPtr(); if( pTarget ) { physics::CActor *pPhysicsActor = pTarget->GetPrimaryPhysicsActor(); Vector3 vDist = vOwnerMuzzlePos - pTarget->GetWorldPosition(); float fDistSq = Vec3LengthSq(vDist); if( fDistSq < m_fGraspRange * m_fGraspRange ) { Vector3 vImpulse = m_MuzzleEndLocalPose.matOrient.GetColumn(2) * m_fPower; // shoot object // pTarget->ApplyWorldImpulse( vImpulse, m_pTarget->GetWorldPosition() ); pPhysicsActor->SetLinearVelocity( vImpulse ); // release object // m_pTarget->pPhysicsActor->SetAllowFreezing( true ); m_Target.Reset(); m_iHoldingTargetToggle = 0; return true; } } } else if( input_type == ITYPE_KEY_RELEASED ) { m_aTriggerState[0] = 0; return true; } break; case ACTION_ATK_RAISEWEAPON: case ACTION_ATK_UNLOCK_TRIGGER_SAFETY: if( input_type == ITYPE_KEY_PRESSED ) { m_aTriggerState[1] = 1; // the owner pulled the second trigger m_iHoldingTargetToggle = ~m_iHoldingTargetToggle; CCopyEntity *pTarget = m_Target.GetRawPtr(); if( !pTarget ) { // trigger is pulled and the gravity gun is not holding any object right now // - check if there is an object in the aim direction return GraspObjectInAimDirection(); } else { // trigger is pulled when the gun is holding an object // - release the object ReleaseObject(); return true; } } else if( input_type == ITYPE_KEY_RELEASED ) { m_aTriggerState[1] = 0; return true; } break; default: break; } return false; }
void GravityGun::Update( float dt ) { if( !IsWeaponSelected() ) return; // Vector3 vOwnerMuzzlePos = rWeaponSystem.m_vMuzzlePosition + rWeaponSystem.m_vMuzzleDirection * 0.25f // + rWeaponSystem.m_vMuzzleDir_Up * 0.90f; Vector3 vOwnerMuzzlePos = m_MuzzleEndWorldPose.vPosition; CCopyEntity *pTarget = m_Target.GetRawPtr(); if( pTarget ) { // calc the translation from the center of the target to the muzzle position Vector3 vDist = vOwnerMuzzlePos - pTarget->GetWorldPosition(); float fDistSq = Vec3LengthSq(vDist); if( m_fMaxRange * m_fMaxRange < fDistSq ) { m_iHoldingTargetToggle = 0; // m_pTarget->pPhysicsActor->SetAllowFreezing( true ); m_Target.Reset(); return; } STrace tr; tr.bvType = BVTYPE_DOT; tr.vStart = vOwnerMuzzlePos; Vector3 vGoal = pTarget->GetWorldPosition(); tr.vGoal = vGoal; tr.sTraceType = TRACETYPE_IGNORE_NOCLIP_ENTITIES; /* CTrace tr; tr.BVType = BVTYPE_DOT; tr.vStart = &vOwnerMuzzlePos; tr.vGoal = &pTarget->GetWorldPosition(); tr.TypeFlags = CTrace::FLAG_IGNORE_NOCLIP_ENTITIES;//TRACETYPE_IGNORE_NOCLIP_ENTITIES; */ // check trace CStageSharedPtr pStage = m_pStage.lock(); if( pStage ) pStage->ClipTrace( tr ); if( tr.pTouchedEntity != pTarget ) { // found an obstacle between the player and the target object // - unable to hold the target any more m_iHoldingTargetToggle = 0; // m_pTarget->pPhysicsActor->SetAllowFreezing( true ); m_Target.Reset(); return; } if( fDistSq < m_fGraspRange * m_fGraspRange || m_aTriggerState[1] == 1 ) { // the gravity gun is holding the target object // account for the target object's size so that it does not bump into the shooter float fDist = sqrtf(fDistSq); Vector3 vDir = vDist / fDist; // normalization fDist -= ( pTarget->fRadius + 0.2f ); vDist = vDir * fDist; // calc relative velocity Vector3 vRVel = pTarget->Velocity() - m_vMuzzleEndVelocity; Vector3 vForce; // vForce = m_fPosGain * vDist - m_fSpeedGain * vRVel; // m_pTarget->ApplyWorldImpulse( vForce, m_pTarget->GetWorldPosition()); if( 6.0f < fDist ) vForce = vDir * 6.0f * 2.5f; else if( fDist < 0.6f ) vForce = vDir * fDist * 8.0f; else // vForce = vDir * fDist * 2.5f; vForce = vDir * ( fDist * 2.0f + 3.0f ); vForce += m_vMuzzleEndVelocity; physics::CActor *pPhysicsActor = pTarget->GetPrimaryPhysicsActor(); if( pPhysicsActor ) pPhysicsActor->SetLinearVelocity( vForce ); /* Vector3 vPos = m_pTarget->pPhysicsActor->GetPosition(); Vector3 vVel = m_pTarget->pPhysicsActor->GetVelocity(); SmoothCD( vPos, vPos + vDist, vVel, 0.25f, dt ); if( 12.0f * 12.0f < Vec3LengthSq(vVel) ) { Vec3Normalize( vVel, vVel ); vVel *= 12.0f; } m_pTarget->pPhysicsActor->SetVelocity( vVel ); */ return; } else { // lost control of the target m_iHoldingTargetToggle = 0; ReleaseObject(); return; } } }