//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2001. // ------------------------------------------------------------------------- // File name: StatObj.cpp // Version: v1.00 // Created: 10/10/2001 by Timur. // Compilers: Visual C++ 6.0 // Description: StaticObject implementation. // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "Entity.h" #include "EntityPanel.h" #include "PanelTreeBrowser.h" #include "PropertiesPanel.h" #include "Viewport.h" #include "Settings.h" #include "LineGizmo.h" #include "Settings.h" #include #include #include #include #include #include "EntityPrototype.h" #include "Material\MaterialManager.h" #include "BrushObject.h" ////////////////////////////////////////////////////////////////////////// // CBase implementation. ////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNCREATE(CEntity,CBaseObject) IMPLEMENT_DYNCREATE(CSimpleEntity,CEntity) int CEntity::m_rollupId = 0; CEntityPanel* CEntity::m_panel = 0; float CEntity::m_helperScale = 1; namespace { int s_propertiesPanelIndex = 0; CPropertiesPanel* s_propertiesPanel = 0; int s_propertiesPanelIndex2 = 0; CPropertiesPanel* s_propertiesPanel2 = 0; // Prevent OnPropertyChange to be executed when loading many properties at one time. static bool s_ignorePropertiesUpdate = false; CPanelTreeBrowser* s_treePanel = NULL; int s_treePanelId = 0; struct AutoReleaseAll { AutoReleaseAll() {}; ~AutoReleaseAll() { delete s_propertiesPanel; delete s_propertiesPanel2; delete s_treePanel; } } s_autoReleaseAll; }; ////////////////////////////////////////////////////////////////////////// CEntity::CEntity() { m_entity = 0; m_loadFailed = false; m_script = 0; m_visualObject = 0; m_box.min.Set(0,0,0); m_box.max.Set(0,0,0); m_proximityRadius = 0; m_innerRadius = 0; m_outerRadius = 0; m_animNode = 0; m_displayBBox = true; m_entityId = 0; m_visible = true; m_bCalcPhysics = true; //m_staticEntity = false; m_bEntityXfromValid = false; ZeroStruct( m_materialGUID ); SetColor( RGB(255,255,0) ); // Init Variables. mv_castShadows = false; mv_selfShadowing = false; mv_recvShadowMaps = true; mv_castShadowMaps = true; mv_castLightmap = false; mv_recvLightmap = false; mv_hiddenInGame = false; mv_ratioLOD = 100; mv_ratioViewDist = 100; mv_UpdateVisLevel = eUT_Always; mv_notOnLowSpec = false; AddVariable( mv_castShadows,"CastShadows",_T("CastShadowVolume"),functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_selfShadowing,"SelfShadowing",functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_castShadowMaps,"CastShadowMaps",functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_recvShadowMaps,"RecvShadowMaps",functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_castLightmap,"PreCalcShadows",_T("CastLightmap"),functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_recvLightmap,"ReceiveLightmap",functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_ratioLOD,"LodRatio",functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_ratioViewDist,"ViewDistRatio",functor(*this,&CEntity::OnRenderFlagsChange) ); AddVariable( mv_notOnLowSpec,"SkipOnLowSpec" ); AddVariable( mv_hiddenInGame,"HiddenInGame" ); // AddVariable( mv_UpdateVisLevel, "UpdateVisLevel", functor(*this,&CEntity::OnRenderFlagsChange) ); // waiting comboboxes support mv_ratioLOD.SetLimits( 0,255 ); mv_ratioViewDist.SetLimits( 0,255 ); } ////////////////////////////////////////////////////////////////////////// void CEntity::Done() { DeleteEntity(); UnloadScript(); if (m_trackGizmo) { RemoveGizmo( m_trackGizmo ); m_trackGizmo = 0; } if (m_animNode) { m_animNode->UnregisterCallback(this); GetIEditor()->GetMovieSystem()->RemoveNode( m_animNode ); m_animNode = 0; } ReleaseEventTargets(); CBaseObject::Done(); } ////////////////////////////////////////////////////////////////////////// bool CEntity::Init( IEditor *ie,CBaseObject *prev,const CString &file ) { CBaseObject::Init( ie,prev,file ); if (IsCreateGameObjects()) { m_animNode = CreateAnimNode(); if (m_animNode) { m_animNode->SetName( GetName() ); m_animNode->RegisterCallback(this); } m_trackGizmo = new CTrackGizmo; m_trackGizmo->SetAnimNode( m_animNode ); AddGizmo( m_trackGizmo ); } if (prev) { CEntity *pe = (CEntity*)prev; m_pMaterial = pe->m_pMaterial; m_materialGUID = pe->m_materialGUID; // Clone Properties. if (pe->m_properties) { m_properties = CloneProperties(pe->m_properties); } if (pe->m_properties2) { m_properties2 = CloneProperties(pe->m_properties2); } // When cloning entity, do not get properties from script. LoadScript( pe->GetEntityClass(),false,false ); SpawnEntity(); UpdatePropertyPanel(); } else if (!file.IsEmpty()) { SetUniqName( file ); m_entityClass = file; } return true; } ////////////////////////////////////////////////////////////////////////// IAnimNode* CEntity::CreateAnimNode() { //GUID guid = GetId(); //int nodeId = Crc32Gen::GetCRC32( (const char*)&guid,sizeof(guid),0xffffffff ); //int entityId = Crc32Gen::GetCRC32( GetId(); int nodeId = GetId().Data1; return GetIEditor()->GetMovieSystem()->CreateNode( ANODE_ENTITY,nodeId ); } ////////////////////////////////////////////////////////////////////////// bool CEntity::IsSameClass( CBaseObject *obj ) { if (GetClassDesc() == obj->GetClassDesc()) { CEntity *ent = (CEntity*)obj; return GetScript() == ent->GetScript(); } return false; } ////////////////////////////////////////////////////////////////////////// bool CEntity::ConvertFromObject( CBaseObject *object ) { return false; } ////////////////////////////////////////////////////////////////////////// void CEntity::SetLookAt( CBaseObject *target ) { CBaseObject::SetLookAt(target); if (m_animNode) { IAnimNode *trgAnimNode = 0; if (target) trgAnimNode = target->GetAnimNode(); m_animNode->SetTarget( trgAnimNode ); } } ////////////////////////////////////////////////////////////////////////// IPhysicalEntity* CEntity::GetCollisionEntity() const { // Returns physical object of entity. if (m_entity) return m_entity->GetPhysics(); return 0; } ////////////////////////////////////////////////////////////////////////// void CEntity::GetBoundBox( BBox &box ) { box = m_box; box.Transform( GetWorldTM() ); } ////////////////////////////////////////////////////////////////////////// void CEntity::GetLocalBounds( BBox &box ) { box = m_box; } ////////////////////////////////////////////////////////////////////////// bool CEntity::HitTestEntity( HitContext &hc,bool &bHavePhysics ) { bHavePhysics = true; IPhysicalWorld *pPhysWorld = GetIEditor()->GetSystem()->GetIPhysicalWorld(); // Test 3D viewport. IPhysicalEntity *physic = 0; ICryCharInstance *pCharacter = m_entity->GetCharInterface()->GetCharacter(0); if (pCharacter) { physic = pCharacter->GetCharacterPhysics(); if (physic) { int type = physic->GetType(); if (type == PE_NONE || type == PE_PARTICLE || type == PE_ROPE || type == PE_SOFT) physic = 0; else if (physic->GetStatus( &pe_status_nparts() ) == 0) physic = 0; } if (physic) { ray_hit hit; int col = pPhysWorld->RayTraceEntity( physic,hc.raySrc,hc.rayDir*10000.0f,&hit ); if (col <= 0) return false; hc.dist = hit.dist; return true; } } physic = m_entity->GetPhysics(); if (physic) { int type = physic->GetType(); if (type == PE_NONE || type == PE_PARTICLE || type == PE_ROPE || type == PE_SOFT) physic = 0; else if (physic->GetStatus( &pe_status_nparts() ) == 0) physic = 0; } // Now if box intersected try real geometry ray test. if (physic) { ray_hit hit; int col = pPhysWorld->RayTraceEntity( physic,hc.raySrc,hc.rayDir*10000.0f,&hit ); if (col <= 0) return false; hc.dist = hit.dist; return true; } else { bHavePhysics = false; } return false; } ////////////////////////////////////////////////////////////////////////// bool CEntity::HitTest( HitContext &hc ) { if (!hc.b2DViewport) { // Test 3D viewport. if (m_entity) { bool bHavePhysics = false; if (HitTestEntity( hc,bHavePhysics )) return true; if (bHavePhysics) { return false; } } if (m_visualObject) { Matrix44 tm = GetWorldTM(); float sz = m_helperScale * gSettings.gizmo.helpersScale; tm.ScaleMatRow( Vec3(sz,sz,sz) ); primitives::ray aray; aray.origin = hc.raySrc; aray.dir = hc.rayDir*10000.0f; IGeomManager *pGeomMgr = GetIEditor()->GetSystem()->GetIPhysicalWorld()->GetGeomManager(); IGeometry *pRay = pGeomMgr->CreatePrimitive(primitives::ray::type, &aray); geom_world_data gwd; gwd.R.extract_from4x4T( tm, gwd.offset,gwd.scale); geom_contact *pcontacts = 0; int col = (m_visualObject->GetPhysGeom() && m_visualObject->GetPhysGeom()->pGeom) ? m_visualObject->GetPhysGeom()->pGeom->Intersect(pRay, &gwd,0, 0, pcontacts) : 0; pGeomMgr->DestroyGeometry(pRay); if (col > 0) { if (pcontacts) hc.dist = pcontacts[col-1].t; return true; } } } /* else if (m_entity) { float dist = FLT_MAX; bool bHaveHit = false; CEntityObject entobj; IPhysicalWorld *physWorld = GetIEditor()->GetSystem()->GetIPhysicalWorld(); int numobj = m_entity->GetNumObjects(); if (numobj == 0) { hc.weakHit = true; return true; } vector origin = hc.raySrc; vector dir = hc.rayDir*10000.0f; Matrix tm; GetMatrix( tm ); tm.Transpose(); for (int i = 0; i < numobj; i++) { m_entity->GetEntityObject(i,entobj); if (entobj.object && entobj.object->GetPhysGeom()) { ray_hit hit; int col = physWorld->RayTraceGeometry( entobj.object->GetPhysGeom(),(float*)tm.m_values,origin,dir,&hit ); if (col > 0) { dist = __min(dist,hit.dist); bHaveHit = true; } } } if (bHaveHit) { hc.dist = dist; return true; } else { return false; } } */ float hitEpsilon = hc.view->GetScreenScaleFactor( GetWorldPos() ) * 0.01f; float hitDist; float fScale = GetScale().x; BBox boxScaled; boxScaled.min = m_box.min*fScale; boxScaled.max = m_box.max*fScale; Matrix44 invertWTM = GetWorldTM(); invertWTM.Invert44(); //Vec3 xformedRaySrc = invertWTM*hc.raySrc; //Vec3 xformedRayDir = GetNormalized( invertWTM*hc.rayDir ); Vec3 xformedRaySrc = invertWTM.TransformPointOLD(hc.raySrc); Vec3 xformedRayDir = invertWTM.TransformVectorOLD(hc.rayDir); xformedRayDir.Normalize(); /* if (m_staticEntity) { // Collided with bbox of entity. hc.dist = GetDistance(xformedRaySrc,pntContact); return true; } else */ { Vec3 intPnt; // Check intersection with bbox edges. if (boxScaled.RayEdgeIntersection( xformedRaySrc,xformedRayDir,hitEpsilon,hitDist,intPnt )) { hc.dist = GetDistance(xformedRaySrc,intPnt); return true; } } return false; } ////////////////////////////////////////////////////////////////////////// int CEntity::MouseCreateCallback( CViewport *view,EMouseEvent event,CPoint &point,int flags ) { if (event == eMouseMove || event == eMouseLDown) { Vec3 pos; // Rise Entity above ground on Bounding box ammount. if (GetIEditor()->GetAxisConstrains() != AXIS_TERRAIN) { pos = view->MapViewToCP(point); } else { // Snap to terrain. bool hitTerrain; pos = view->ViewToWorld( point,&hitTerrain ); if (hitTerrain) { pos.z = GetIEditor()->GetTerrainElevation(pos.x,pos.y); pos.z = pos.z - m_box.min.z; } pos = view->SnapToGrid(pos); } SetPos( pos ); if (event == eMouseLDown) return MOUSECREATE_OK; return MOUSECREATE_CONTINUE; } return CBaseObject::MouseCreateCallback( view,event,point,flags ); } ////////////////////////////////////////////////////////////////////////// bool CEntity::CreateGameObject() { if (!m_script) { if (!m_entityClass.IsEmpty()) LoadScript( m_entityClass,true ); } if (!m_entity) { if (!m_entityClass.IsEmpty()) SpawnEntity(); } return true; } ////////////////////////////////////////////////////////////////////////// bool CEntity::LoadScript( const CString &entityClass,bool bForceReload,bool bGetScriptProperties,XmlNodeRef xmlProperties,XmlNodeRef xmlProperties2 ) { if (entityClass == m_entityClass && m_script != 0 && !bForceReload) return true; m_entityClass = entityClass; m_loadFailed = false; UnloadScript(); if (!IsCreateGameObjects()) return false; //HACK // Special case to ignore static entities. if (entityClass == "StaticEntity") { OnLoadFailed(); return false; } m_script = CEntityScriptRegistry::Instance()->Find( m_entityClass ); if (!m_script) { OnLoadFailed(); return false; } // Load script if its not loaded yet. if (!m_script->IsValid()) { if (!m_script->Load()) { OnLoadFailed(); return false; } } ////////////////////////////////////////////////////////////////////////// // Make visual editor object for this entity. ////////////////////////////////////////////////////////////////////////// if (!m_script->GetVisualObject().IsEmpty()) { //m_entity->LoadObject( 0,m_script->GetVisualObject(),1 ); //m_entity->DrawObject( 0,ETY_DRAW_NORMAL ); m_visualObject = GetIEditor()->Get3DEngine()->MakeObject( m_script->GetVisualObject() ); if (m_visualObject) m_visualObject->SetShaderTemplate( EFT_USER_FIRST+1,"s_ObjectColor",NULL ); } bool bUpdateUI = false; // Create Entity properties from Script properties.. if (bGetScriptProperties && m_prototype == NULL && m_script->GetProperties() != NULL) { bUpdateUI = true; CVarBlockPtr oldProperties = m_properties; m_properties = CloneProperties( m_script->GetProperties() ); if (xmlProperties) { s_ignorePropertiesUpdate = true; m_properties->Serialize( xmlProperties,true ); s_ignorePropertiesUpdate = false; } else if (oldProperties) { // If we had propertied before copy thier values to new script. s_ignorePropertiesUpdate = true; m_properties->CopyValuesByName(oldProperties); s_ignorePropertiesUpdate = false; } } // Create Entity properties from Script properties.. if (bGetScriptProperties && m_script->GetProperties2() != NULL) { bUpdateUI = true; CVarBlockPtr oldProperties = m_properties2; m_properties2 = CloneProperties( m_script->GetProperties2() ); if (xmlProperties2) { s_ignorePropertiesUpdate = true; m_properties2->Serialize( xmlProperties2,true ); s_ignorePropertiesUpdate = false; } else if (oldProperties) { // If we had propertied before copy thier values to new script. s_ignorePropertiesUpdate = true; m_properties2->CopyValuesByName(oldProperties); s_ignorePropertiesUpdate = false; } } return true; } ////////////////////////////////////////////////////////////////////////// void CEntity::SpawnEntity() { if (!m_script) return; // Do not spawn second time. if (m_entity) return; m_loadFailed = false; EntityClassId ClassId = m_script->GetClsId(); //CLogFile::FormatLine( "Loading Entity %s (%s)",(const char*)entityClass,(const char*)GetName() ); if (m_entityId != 0) { if (GetIEditor()->GetSystem()->GetIEntitySystem()->IsIDUsed( m_entityId )) m_entityId = 0; } CEntityDesc ed; ed.ClassId = ClassId; ed.name = (const char*)GetName(); ed.pos = GetWorldPos(); ed.angles = GetAngles(); ed.id = m_entityId; if (ed.id == 0) ed.id = -1; // Tells to Entity system to genrate new static id. IEntitySystem *pEntitySystem = GetIEditor()->GetSystem()->GetIEntitySystem(); // Spawn Entity but not initialize it. m_entity = pEntitySystem->SpawnEntity( ed,false ); if (m_entity) { m_entityId = m_entity->GetId(); // Bind to parent. BindToParent(); BindIEntityChilds(); m_entity->Hide( !m_visible ); //m_script->SetCurrentProperties( this ); m_script->SetEventsTable( this ); // Mark this entity non destroyable. m_entity->SetDestroyable(false); ////////////////////////////////////////////////////////////////////////// // If have material, assign it to the entity. if (m_pMaterial) m_pMaterial->AssignToEntity( m_entity ); // Force transformation on entity. XFormGameEntity(); if (m_properties != NULL) { m_script->SetProperties( m_entity,m_properties,false ); } if (m_properties2 != NULL) { m_script->SetProperties2( m_entity,m_properties2,false ); } ////////////////////////////////////////////////////////////////////////// // Now initialize entity. ////////////////////////////////////////////////////////////////////////// if (!pEntitySystem->InitEntity( m_entity,ed )) { m_entity = 0; OnLoadFailed(); return; } // Update render flags of entity (Must be after InitEntity). OnRenderFlagsChange(0); if (!m_physicsState.IsEmpty()) { m_entity->SetPhysicsState( m_physicsState ); } ////////////////////////////////////////////////////////////////////////// // Check if needs to display bbox for this entity. ////////////////////////////////////////////////////////////////////////// m_bCalcPhysics = true; if (m_entity->GetPhysics() != 0) { m_displayBBox = false; if (m_entity->GetPhysics()->GetType() == PE_SOFT) { m_bCalcPhysics = false; //! Ignore entity being updated from physics. m_entity->SetFlags(ETY_FLAG_IGNORE_PHYSICS_UPDATE); } } else m_displayBBox = true; ////////////////////////////////////////////////////////////////////////// // Calculate entity bounding box. CalcBBox(); ////////////////////////////////////////////////////////////////////////// // Assign entity pointer to animation node. if (m_animNode) m_animNode->SetEntity(m_entity); } else { OnLoadFailed(); } //? UpdatePropertyPanel(); } ////////////////////////////////////////////////////////////////////////// void CEntity::DeleteEntity() { if (m_entity) { UnbindIEntity(); m_entity->SetDestroyable(true); GetIEditor()->GetSystem()->GetIEntitySystem()->RemoveEntity( m_entity->GetId(),true ); } m_entity = 0; } ////////////////////////////////////////////////////////////////////////// void CEntity::UnloadScript() { if (m_entity) { DeleteEntity(); } if (m_visualObject) GetIEditor()->Get3DEngine()->ReleaseObject(m_visualObject); m_visualObject = 0; m_script = 0; } ////////////////////////////////////////////////////////////////////////// void CEntity::XFormGameEntity() { if (!m_entity) return; m_entity->SetPos( GetPos(),false ); m_entity->SetAngles( GetAngles() ); m_entity->SetScale( GetScale().x ); // Make sure this entity is succesfully registered in correct sectors after loading. m_entity->ForceRegisterInSectors(); /* const Matrix &tm = GetWorldTM(); //m_entity->SetPos( Vec3(tm[3][0],tm[3][1],tm[3][2]) ); Quat rotate(tm); //m_entity->SetAngles( rotate.GetEulerAngles()*180.0f/PI ); m_bEntityXfromValid = true; */ } ////////////////////////////////////////////////////////////////////////// void CEntity::CalcBBox() { if (m_entity) { // Get Local bounding box of entity. m_entity->GetLocalBBox( m_box.min,m_box.max ); if (m_box.IsEmpty()) m_displayBBox = true; if (m_visualObject) { Vec3 minp = m_visualObject->GetBoxMin()*m_helperScale*gSettings.gizmo.helpersScale; Vec3 maxp = m_visualObject->GetBoxMax()*m_helperScale*gSettings.gizmo.helpersScale; m_box.Add( minp ); m_box.Add( maxp ); } float minSize = 0.1f; if (fabs(m_box.max.x-m_box.min.x)+fabs(m_box.max.y-m_box.min.y)+fabs(m_box.max.z-m_box.min.z) < minSize) { m_box.min = -Vec3( minSize,minSize,minSize ); m_box.max = Vec3( minSize,minSize,minSize ); } } } ////////////////////////////////////////////////////////////////////////// void CEntity::SetName( const CString &name ) { if (name == GetName()) return; CBaseObject::SetName( name ); if (m_entity) m_entity->SetName( (const char*)GetName() ); if (m_animNode) { m_animNode->SetName( name ); } } ////////////////////////////////////////////////////////////////////////// void CEntity::SetPos( const Vec3d &pos ) { if (IsVectorsEqual(GetPos(),pos)) return; CBaseObject::SetPos( pos ); if (m_entity) { //m_entity->SetPos( GetWorldPos() ); m_entity->SetPos( GetPos(),false ); m_entity->ForceRegisterInSectors(); } if (m_animNode) { m_animNode->SetPos( GetIEditor()->GetAnimation()->GetTime(),pos ); } } ////////////////////////////////////////////////////////////////////////// void CEntity::SetAngles( const Vec3d &angles ) { if (IsVectorsEqual(GetAngles(),angles)) return; CBaseObject::SetAngles( angles ); if (m_entity) { m_entity->SetAngles( GetAngles() ); } if (m_animNode) { m_rotate.SetRotationXYZ( angles*gf_PI/180.0f ); m_animNode->SetRotate( GetIEditor()->GetAnimation()->GetTime(),m_rotate ); } } void CEntity::SetScale( const Vec3d &scale ) { if (IsVectorsEqual(GetScale(),scale)) return; CBaseObject::SetScale( scale ); if (m_entity) { m_entity->SetScale( GetScale().x ); CalcBBox(); } if (m_animNode) { m_animNode->SetScale( GetIEditor()->GetAnimation()->GetTime(),scale ); } /* if (m_entity) m_entity->SetScale(scale); */ // CBaseObject::SetScale( scale ); } ////////////////////////////////////////////////////////////////////////// void CEntity::BeginEditParams( IEditor *ie,int flags ) { CBaseObject::BeginEditParams( ie,flags ); if (m_properties2 != NULL) { if (!s_propertiesPanel2) s_propertiesPanel2 = new CPropertiesPanel( AfxGetMainWnd() ); else s_propertiesPanel2->DeleteVars(); s_propertiesPanel2->AddVars( m_properties2 ); if (!s_propertiesPanelIndex2) s_propertiesPanelIndex2 = ie->AddRollUpPage( ROLLUP_OBJECTS,CString(GetTypeName()) + " Properties2",s_propertiesPanel2 ); } if (!m_prototype) { if (m_properties != NULL) { if (!s_propertiesPanel) s_propertiesPanel = new CPropertiesPanel( AfxGetMainWnd() ); else s_propertiesPanel->DeleteVars(); s_propertiesPanel->AddVars( m_properties ); if (!s_propertiesPanelIndex) s_propertiesPanelIndex = ie->AddRollUpPage( ROLLUP_OBJECTS,CString(GetTypeName()) + " Properties",s_propertiesPanel ); } } if (!m_panel && m_entity) { m_panel = new CEntityPanel(AfxGetMainWnd()); m_panel->Create( CEntityPanel::IDD,AfxGetMainWnd() ); m_rollupId = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,m_entityClass,m_panel ); } if (m_panel) m_panel->SetEntity( this ); } ////////////////////////////////////////////////////////////////////////// void CEntity::EndEditParams( IEditor *ie ) { if (m_rollupId != 0) GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,m_rollupId ); m_rollupId = 0; m_panel = 0; if (s_propertiesPanelIndex != 0) GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,s_propertiesPanelIndex ); s_propertiesPanelIndex = 0; s_propertiesPanel = 0; if (s_propertiesPanelIndex2 != 0) GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,s_propertiesPanelIndex2 ); s_propertiesPanelIndex2 = 0; s_propertiesPanel2 = 0; CBaseObject::EndEditParams( GetIEditor() ); } ////////////////////////////////////////////////////////////////////////// void CEntity::UpdatePropertyPanel() { // If user interface opened reload properties. if (s_propertiesPanel && m_properties != 0) { s_propertiesPanel->DeleteVars(); s_propertiesPanel->AddVars( m_properties ); } // If user interface opened reload properties. if (s_propertiesPanel2 && m_properties2 != 0) { s_propertiesPanel2->DeleteVars(); s_propertiesPanel2->AddVars( m_properties2 ); } } ////////////////////////////////////////////////////////////////////////// void CEntity::BeginEditMultiSelParams( bool bAllOfSameType ) { CBaseObject::BeginEditMultiSelParams(bAllOfSameType); if (!bAllOfSameType) return; if (m_properties2 != NULL) { if (!s_propertiesPanel2) s_propertiesPanel2 = new CPropertiesPanel( AfxGetMainWnd() ); else s_propertiesPanel2->DeleteVars(); // Add all selected objects. CSelectionGroup *grp = GetIEditor()->GetSelection(); for (int i = 0; i < grp->GetCount(); i++) { CEntity *ent = (CEntity*)grp->GetObject(i); if (ent->m_properties2) s_propertiesPanel2->AddVars( ent->m_properties2 ); } if (!s_propertiesPanelIndex2) s_propertiesPanelIndex2 = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,CString(GetTypeName()) + " Properties",s_propertiesPanel2 ); } if (m_properties != NULL && m_prototype == NULL) { if (!s_propertiesPanel) s_propertiesPanel = new CPropertiesPanel( AfxGetMainWnd() ); else s_propertiesPanel->DeleteVars(); // Add all selected objects. CSelectionGroup *grp = GetIEditor()->GetSelection(); for (int i = 0; i < grp->GetCount(); i++) { CEntity *ent = (CEntity*)grp->GetObject(i); CVarBlock *vb = ent->m_properties; if (vb) s_propertiesPanel->AddVars( vb ); } if (!s_propertiesPanelIndex) s_propertiesPanelIndex = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,CString(GetTypeName()) + " Properties",s_propertiesPanel ); } } ////////////////////////////////////////////////////////////////////////// void CEntity::EndEditMultiSelParams() { if (s_propertiesPanelIndex != 0) GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,s_propertiesPanelIndex ); s_propertiesPanelIndex = 0; s_propertiesPanel = 0; if (s_propertiesPanelIndex2 != 0) GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,s_propertiesPanelIndex2 ); s_propertiesPanelIndex2 = 0; s_propertiesPanel2 = 0; CBaseObject::EndEditMultiSelParams(); } ////////////////////////////////////////////////////////////////////////// void CEntity::SetSelected( bool bSelect ) { CBaseObject::SetSelected( bSelect ); if (m_entity) { int flags = m_entity->GetRndFlags(); if (bSelect) flags |= ERF_SELECTED; else flags &= ~ERF_SELECTED; m_entity->SetRndFlags( flags ); } if (m_animNode) m_animNode->SetFlags( (bSelect) ? (m_animNode->GetFlags()|ANODE_FLAG_SELECTED) : (m_animNode->GetFlags()&(~ANODE_FLAG_SELECTED)) ); } ////////////////////////////////////////////////////////////////////////// void CEntity::OnPropertyChange( IVariable *var ) { if (s_ignorePropertiesUpdate) return; if (m_script != 0 && m_entity != 0) { if (m_properties) m_script->SetProperties( m_entity,m_properties,true ); if (m_properties2) m_script->SetProperties2( m_entity,m_properties2,true ); // After change of properties bounding box of entity may change. CalcBBox(); } } ////////////////////////////////////////////////////////////////////////// void CEntity::Display( DisplayContext &dc ) { if (!m_entity) return; //XFormEntity(); Matrix44 wtm = GetWorldTM(); COLORREF col = GetColor(); if (IsFrozen()) col = dc.GetFreezeColor(); //Vec3 scale = GetScale(); dc.PushMatrix( wtm ); if (IsSelected()) { dc.SetSelectedColor( 0.5f ); //dc.renderer->Draw3dBBox( GetPos()-Vec3(m_radius,m_radius,m_radius),GetPos()+Vec3(m_radius,m_radius,m_radius)); dc.DrawWireBox( m_box.min,m_box.max ); } else { if (m_displayBBox || (dc.flags & DISPLAY_2D)) { dc.SetColor( col,0.3f ); dc.DrawWireBox( m_box.min,m_box.max ); } } /* // Only display solid BBox if visual object is associated with the entity. if (m_displayBBox && m_visualObject) { dc.renderer->EnableDepthWrites(false); dc.SetColor(col,0.05f); dc.DrawSolidBox( m_box.min,m_box.max ); dc.renderer->EnableDepthWrites(true); } */ /* if (m_entity && m_proximityRadius >= 0) { float r = m_proximityRadius; dc.SetColor( 1,1,0,1 ); dc.DrawWireBox( GetPos()-Vec3(r,r,r),GetPos()+Vec3(r,r,r) ); } */ // Draw radiuses if present and object selected. if (gSettings.viewports.bAlwaysShowRadiuses || IsSelected()) { float fScale = GetScale().x; // Ignore matrix scale. if (fScale == 0) fScale = 1; if (m_innerRadius > 0) { dc.SetColor( 0,1,0,0.3f ); dc.DrawWireSphere( Vec3(0,0,0),m_innerRadius/fScale ); } if (m_outerRadius > 0) { dc.SetColor( 1,1,0,0.8f ); dc.DrawWireSphere( Vec3(0,0,0),m_outerRadius/fScale ); } } dc.PopMatrix(); // Entities themself are rendered by 3DEngine. if (m_visualObject) { /* float fScale = dc.view->GetScreenScaleFactor(wtm.GetTranslation()) * 0.04f; wtm[0][0] *= fScale; wtm[0][1] *= fScale; wtm[0][2] *= fScale; wtm[1][0] *= fScale; wtm[1][1] *= fScale; wtm[1][2] *= fScale; wtm[2][0] *= fScale; wtm[2][1] *= fScale; wtm[2][2] *= fScale; */ Matrix44 tm(wtm); float sz = m_helperScale*gSettings.gizmo.helpersScale; tm.ScaleMatRow( Vec3(sz,sz,sz) ); SRendParams rp; if (IsSelected()) rp.vColor = Rgb2Vec(dc.GetSelectedColor()); else rp.vColor = Rgb2Vec(col); rp.dwFObjFlags |= FOB_TRANS_MASK; rp.fAlpha = 1; rp.nDLightMask = GetIEditor()->Get3DEngine()->GetLightMaskFromPosition(wtm.GetTranslationOLD(),1.f) & 0xFFFF; rp.pMatrix = &tm; m_visualObject->Render( rp,Vec3(zero),0 ); } if (IsSelected()) { if (m_entity) { IAIObject *pAIObj = m_entity->GetAI(); if (pAIObj) DrawAIInfo( dc,pAIObj ); } } /* if ((dc.flags & DISPLAY_LINKS) && !m_eventTargets.empty()) { DrawTargets(dc); } */ DrawDefault(dc,col); } ////////////////////////////////////////////////////////////////////////// void CEntity::DrawAIInfo( DisplayContext &dc,IAIObject *aiObj ) { assert( aiObj ); IPuppet *pPuppet; if (aiObj->CanBeConvertedTo( AIOBJECT_PUPPET,(void**)&pPuppet)) { AgentParameters &ap = pPuppet->GetPuppetParameters(); // Draw ranges. bool bTerrainCircle = false; Vec3 wp = GetWorldPos(); float z = GetIEditor()->GetTerrainElevation( wp.x,wp.y ); if (fabs(wp.z-z) < 5) bTerrainCircle = true; dc.SetColor( RGB(0,255,0) ); if (bTerrainCircle) dc.DrawTerrainCircle( wp,ap.m_fSoundRange,0.2f ); else dc.DrawCircle( wp,ap.m_fSoundRange ); dc.SetColor( RGB(255,255,0) ); if (bTerrainCircle) dc.DrawTerrainCircle( wp,ap.m_fCommRange,0.2f ); else dc.DrawCircle( wp,ap.m_fCommRange ); dc.SetColor( RGB(255,0,0) ); if (bTerrainCircle) dc.DrawTerrainCircle( wp,ap.m_fSightRange,0.2f ); else dc.DrawCircle( wp,ap.m_fSightRange ); dc.SetColor( RGB(255/2,0,0) ); if (bTerrainCircle) dc.DrawTerrainCircle( wp,ap.m_fSightRange/2,0.2f ); else dc.DrawCircle( wp,ap.m_fSightRange/2 ); dc.SetColor( RGB(0,0,255) ); if (bTerrainCircle) dc.DrawTerrainCircle( wp,ap.m_fAttackRange,0.2f ); else dc.DrawCircle( wp,ap.m_fAttackRange ); //dc.SetColor( 0,1,0,0.3f ); //dc.DrawWireSphere( Vec3(0,0,0),m_innerRadius ); } } ////////////////////////////////////////////////////////////////////////// void CEntity::DrawTargets( DisplayContext &dc ) { /* BBox box; for (int i = 0; i < m_eventTargets.size(); i++) { CBaseObject *target = m_eventTargets[i].target; if (!target) return; dc.SetColor( 0.8f,0.4f,0.4f,1 ); GetBoundBox( box ); Vec3 p1 = 0.5f*Vec3(box.max+box.min); target->GetBoundBox( box ); Vec3 p2 = 0.5f*Vec3(box.max+box.min); dc.DrawLine( p1,p2 ); Vec3 p3 = 0.5f*(p2+p1); if (!(dc.flags & DISPLAY_HIDENAMES)) { float col[4] = { 0.8f,0.4f,0.4f,1 }; dc.renderer->DrawLabelEx( p3+Vec3(0,0,0.3f),1.2f,col,true,true,m_eventTargets[i].event ); } } */ } ////////////////////////////////////////////////////////////////////////// void CEntity::Serialize( CObjectArchive &ar ) { CBaseObject::Serialize( ar ); XmlNodeRef xmlNode = ar.node; if (ar.bLoading) { m_entityId = 0; m_physicsState = ""; // Load CString entityClass = m_entityClass; m_loadFailed = false; if (!m_prototype) xmlNode->getAttr( "EntityClass",entityClass ); xmlNode->getAttr( "EntityId",m_entityId ); xmlNode->getAttr( "PhysicsState",m_physicsState ); ZeroStruct(m_materialGUID); if (xmlNode->getAttr( "MaterialGUID",m_materialGUID )) { m_pMaterial = (CMaterial*)GetIEditor()->GetMaterialManager()->FindItem( m_materialGUID ); if (!m_pMaterial) { CErrorRecord err; err.error.Format( "Material %s for Entity %s not found,",GuidUtil::ToString(m_materialGUID),(const char*)GetName() ); err.pObject = this; err.severity = CErrorRecord::ESEVERITY_WARNING; ar.ReportError(err); //Warning( "Material %s for Entity %s not found,",GuidUtil::ToString(m_materialGUID),(const char*)GetName() ); } else { if (m_pMaterial->GetParent()) SetMaterial( m_pMaterial->GetParent() ); m_pMaterial->SetUsed(); } UpdateMaterialInfo(); } else m_pMaterial = 0; // Load Event Targets. ReleaseEventTargets(); XmlNodeRef eventTargets = xmlNode->findChild( "EventTargets" ); if (eventTargets) { for (int i = 0; i < eventTargets->getChildCount(); i++) { XmlNodeRef eventTarget = eventTargets->getChild(i); CEntityEventTarget et; et.target = 0; GUID targetId = GUID_NULL; eventTarget->getAttr( "TargetId",targetId ); eventTarget->getAttr( "Event",et.event ); eventTarget->getAttr( "SourceEvent",et.sourceEvent ); m_eventTargets.push_back( et ); if (targetId != GUID_NULL) ar.SetResolveCallback( this,targetId,functor(*this,&CEntity::ResolveEventTarget),i ); } } XmlNodeRef propsNode; XmlNodeRef props2Node = xmlNode->findChild("Properties2"); if (!m_prototype) { propsNode = xmlNode->findChild("Properties"); } bool bLoaded = LoadScript( entityClass,!ar.bUndo,true,propsNode,props2Node ); if (ar.bUndo) { SpawnEntity(); } } else { // Saving. if (!m_entityClass.IsEmpty() && m_prototype == NULL) xmlNode->setAttr( "EntityClass",m_entityClass ); if (m_entityId != 0) xmlNode->setAttr( "EntityId",m_entityId ); if (!GuidUtil::IsEmpty(m_materialGUID)) { xmlNode->setAttr( "MaterialGUID",m_materialGUID ); } if (!m_physicsState.IsEmpty()) xmlNode->setAttr( "PhysicsState",m_physicsState ); if (!m_prototype) { //! Save properties. if (m_properties) { XmlNodeRef propsNode = xmlNode->newChild("Properties"); m_properties->Serialize( propsNode,ar.bLoading ); } } //! Save properties. if (m_properties2) { XmlNodeRef propsNode = xmlNode->newChild("Properties2"); m_properties2->Serialize( propsNode,ar.bLoading ); } // Save Event Targets. if (!m_eventTargets.empty()) { XmlNodeRef eventTargets = xmlNode->newChild( "EventTargets" ); for (int i = 0; i < m_eventTargets.size(); i++) { CEntityEventTarget &et = m_eventTargets[i]; GUID targetId = GUID_NULL; if (et.target != 0) targetId = et.target->GetId(); XmlNodeRef eventTarget = eventTargets->newChild( "EventTarget" ); eventTarget->setAttr( "TargetId",targetId ); eventTarget->setAttr( "Event",et.event ); eventTarget->setAttr( "SourceEvent",et.sourceEvent ); } } } } XmlNodeRef CEntity::Export( const CString &levelPath,XmlNodeRef &xmlNode ) { if (m_loadFailed) return 0; //@HACK //[Timur] This is the worst ever Hack! unfortunatly Have to be here because of our fabolus game programmers, sigh. if (m_entityClass == "DynamicLight") { // If dynamic light and casts lightmap do not export this. if (mv_castLightmap) return 0; } // Export entities to entities.ini XmlNodeRef objNode = CBaseObject::Export( levelPath,xmlNode ); objNode->setTag( "Entity" ); objNode->setAttr( "EntityClass",m_entityClass ); objNode->setAttr( "EntityId",m_entityId ); if (m_pMaterial) { objNode->setAttr( "Material",m_pMaterial->GetFullName() ); } if (!m_physicsState.IsEmpty()) objNode->setAttr( "PhysicsState",m_physicsState ); objNode->setAttr( "Layer",GetLayer()->GetName() ); // Store parent entity. if (GetParent()) { if (GetParent()->IsKindOf( RUNTIME_CLASS(CEntity) )) { CEntity *parentEntity = (CEntity*)GetParent(); if (parentEntity) objNode->setAttr( "ParentId",parentEntity->GetEntityId() ); Vec3 pos = GetPos(); Vec3 angles = GetAngles(); Vec3 scale = GetScale(); // When exporting optimize for 0,0,0 condition. // Export local coords. if (!IsEquivalent(pos,Vec3(0,0,0),0)) objNode->setAttr( "Pos",pos ); else objNode->delAttr( "Pos" ); // Export local angles. if (!IsEquivalent(angles,Vec3(0,0,0),0)) objNode->setAttr( "Angles",angles ); else objNode->delAttr( "Angles" ); // Export local scale. if (!IsEquivalent(scale,Vec3(1,1,1),0)) objNode->setAttr( "Scale",scale ); else objNode->delAttr( "Scale" ); } } // Export Event Targets. if (!m_eventTargets.empty()) { XmlNodeRef eventTargets = objNode->newChild( "EventTargets" ); for (int i = 0; i < m_eventTargets.size(); i++) { CEntityEventTarget &et = m_eventTargets[i]; int entityId = 0; if (et.target) { if (et.target->IsKindOf( RUNTIME_CLASS(CEntity) )) { entityId = ((CEntity*)et.target)->GetEntityId(); } } XmlNodeRef eventTarget = eventTargets->newChild( "EventTarget" ); //eventTarget->setAttr( "Target",obj->GetName() ); eventTarget->setAttr( "Target",entityId ); eventTarget->setAttr( "Event",et.event ); eventTarget->setAttr( "SourceEvent",et.sourceEvent ); } } //! Export properties. if (m_properties) { XmlNodeRef propsNode = objNode->newChild("Properties"); m_properties->Serialize( propsNode,false ); } //! Export properties. if (m_properties2) { XmlNodeRef propsNode = objNode->newChild("Properties2"); m_properties2->Serialize( propsNode,false ); } return objNode; } ////////////////////////////////////////////////////////////////////////// void CEntity::OnEvent( ObjectEvent event ) { CBaseObject::OnEvent(event); switch (event) { case EVENT_INGAME: case EVENT_OUTOFGAME: if (m_entity) { if (event == EVENT_INGAME) { if (!m_bCalcPhysics) m_entity->ClearFlags(ETY_FLAG_IGNORE_PHYSICS_UPDATE); // Entity must be hidden when going to game. if (m_visible) m_entity->Hide( mv_hiddenInGame ); } else if (event == EVENT_OUTOFGAME) { // Entity must be returned to editor visibility state. m_entity->Hide( !m_visible ); m_entity->SetGarbageFlag(false); // If marked as garbage, unmark it. } XFormGameEntity(); if (!m_physicsState.IsEmpty()) { IPhysicalEntity *physic = m_entity->GetPhysics(); if (physic) { const char *str = m_physicsState; physic->SetStateFromSnapshotTxt( const_cast(str),m_physicsState.GetLength() ); physic->PostSetStateFromSnapshot(); } } if (event == EVENT_OUTOFGAME) { if (!m_bCalcPhysics) m_entity->SetFlags(ETY_FLAG_IGNORE_PHYSICS_UPDATE); } } break; case EVENT_REFRESH: if (m_entity) { // force entity to be registered in terrain sectors again. //-- little hack to force reregistration of entities //<> when issue with registration in editor is resolved Vec3d pos = GetPos(); pos.z+=1.f; m_entity->SetPos( pos,false ); //---------------------------------------------------- XFormGameEntity(); } break; case EVENT_AFTER_LOAD: if (m_entity) { // Force entities to register them-self in sectors. // force entity to be registered in terrain sectors again. XFormGameEntity(); BindToParent(); BindIEntityChilds(); if (m_script) { //m_script->SetCurrentProperties( this ); m_script->SetEventsTable( this ); } } break; case EVENT_UNLOAD_GEOM: case EVENT_UNLOAD_ENTITY: if (m_script) m_script = 0; if (m_entity) { UnloadScript(); } break; case EVENT_RELOAD_ENTITY: GetIEditor()->GetErrorReport()->SetCurrentValidatorObject( this ); if (m_script) m_script->Reload(); Reload(); break; case EVENT_RELOAD_GEOM: GetIEditor()->GetErrorReport()->SetCurrentValidatorObject( this ); Reload(); break; case EVENT_PHYSICS_GETSTATE: AcceptPhysicsState(); break; case EVENT_PHYSICS_RESETSTATE: ResetPhysicsState(); break; } } ////////////////////////////////////////////////////////////////////////// void CEntity::Reload( bool bReloadScript ) { if (!m_script || bReloadScript) LoadScript( m_entityClass,true ); if (m_entity) DeleteEntity(); SpawnEntity(); } ////////////////////////////////////////////////////////////////////////// void CEntity::UpdateVisibility( bool visible ) { CBaseObject::UpdateVisibility(visible); if (visible != m_visible) { if (!visible && m_entity) { m_entity->Hide(true); // Unload entity. //OnEvent(EVENT_UNLOAD_ENTITY); } if (visible && m_entity) { m_entity->Hide(false); } } m_visible = visible; }; /* class StaticInit { public: StaticInit() { Vec3 angles(20,11.51,112); Vec3 a1,a2; Matrix tm; tm.Identity(); tm.RotateMatrix( angles ); quaternionf qq( angles.z*PI/180.0f,angles.y*PI/180.0f,angles.x*PI/180.0f ); float mtx[3][3]; qq.getmatrix_buf( (float*)mtx ); Quat q(tm); Quat q1; q1.SetEulerAngles( angles*PI/180.0f ); Matrix tm1; q1.GetMatrix(tm1); a1 = q.GetEulerAngles() * 180.0f/PI; a2 = q1.GetEulerAngles() * 180.0f/PI; } }; StaticInit ss; */ ////////////////////////////////////////////////////////////////////////// void CEntity::OnNodeAnimated() { if (!m_animNode) return; Vec3 pos = m_animNode->GetPos(); Vec3 scale = m_animNode->GetScale(); Quat rotate = m_animNode->GetRotate(); //m_entity->SetPos( GetPos(),false ); //m_entity->SetAngles( GetAngles() ); //m_entity->SetScale( GetScale().x ); bool bModified = false; if (!IsVectorsEqual(pos,GetPos())) { CBaseObject::SetPos( pos ); bModified = true; if (m_entity) m_entity->SetPos( GetPos(),false ); } if (rotate.w != m_rotate.w || rotate.v.x != m_rotate.v.x || rotate.v.y != m_rotate.v.y || rotate.v.z != m_rotate.v.z) { m_rotate = rotate; Vec3 angles = RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(m_rotate))); CBaseObject::SetAngles( angles ); bModified = true; if (m_entity) m_entity->SetAngles( GetAngles() ); } if (!IsVectorsEqual(scale,GetScale())) { CBaseObject::SetScale( scale ); bModified = true; if (m_entity) m_entity->SetScale( GetScale().x ); } //if (bModified) //XFormGameEntity(); } ////////////////////////////////////////////////////////////////////////// void CEntity::InvalidateTM() { CBaseObject::InvalidateTM(); // If matrix changes. if (m_trackGizmo) { //m_trackGizmo->SetMatrix( GetWorldTM() ); if (GetParent()) { m_trackGizmo->SetMatrix( GetParent()->GetWorldTM() ); } else { Matrix44 tm; tm.SetIdentity(); m_trackGizmo->SetMatrix(tm); } } if (m_entity && GetParent()) { if (!m_entity->IsBound()) { m_entity->ForceBindCalculation(true); m_entity->SetParentLocale( GetParent()->GetWorldTM() ); XFormGameEntity(); } } m_bEntityXfromValid = false; } ////////////////////////////////////////////////////////////////////////// //! Attach new child node. void CEntity::AttachChild( CBaseObject* child,bool bKeepPos ) { CBaseObject::AttachChild( child,bKeepPos ); if (child && child->IsKindOf(RUNTIME_CLASS(CEntity))) { ((CEntity*)child)->BindToParent(); } } //! Detach all childs of this node. void CEntity::DetachAll( bool bKeepPos ) { //@FIXME: Unbind all childs. CBaseObject::DetachAll(bKeepPos); } // Detach this node from parent. void CEntity::DetachThis( bool bKeepPos ) { UnbindIEntity(); CBaseObject::DetachThis(bKeepPos); } ////////////////////////////////////////////////////////////////////////// void CEntity::BindToParent() { if (!m_entity) return; CBaseObject *parent = GetParent(); if (parent) { if (parent->IsKindOf(RUNTIME_CLASS(CEntity))) { CEntity *parentEntity = (CEntity*)parent; IEntity *ientParent = parentEntity->GetIEntity(); if (ientParent) { XFormGameEntity(); ientParent->Bind( m_entity->GetId(),0 ); XFormGameEntity(); } } else { m_entity->ForceBindCalculation(true); m_entity->SetParentLocale( GetParent()->GetWorldTM() ); XFormGameEntity(); } } } ////////////////////////////////////////////////////////////////////////// void CEntity::BindIEntityChilds() { if (!m_entity) return; int numChilds = GetChildCount(); for (int i = 0; i < numChilds; i++) { CBaseObject *child = GetChild(i); if (child && child->IsKindOf(RUNTIME_CLASS(CEntity))) { IEntity *ientChild = ((CEntity*)child)->GetIEntity(); if (ientChild) { ((CEntity*)child)->XFormGameEntity(); m_entity->Bind( ientChild->GetId(),0 ); ((CEntity*)child)->XFormGameEntity(); } } } } ////////////////////////////////////////////////////////////////////////// void CEntity::UnbindIEntity() { if (!m_entity) return; m_entity->ForceBindCalculation(false); CBaseObject *parent = GetParent(); if (parent && parent->IsKindOf(RUNTIME_CLASS(CEntity))) { CEntity *parentEntity = (CEntity*)parent; IEntity *ientParent = parentEntity->GetIEntity(); if (ientParent) { //m_entity->ForceBindCalculation(false); ientParent->Unbind( m_entity->GetId(),0 ); } } } ////////////////////////////////////////////////////////////////////////// void CEntity::PostClone( CBaseObject *pFromObject,CObjectCloneContext &ctx ) { CBaseObject::PostClone( pFromObject,ctx ); CEntity *pFromEntity = (CEntity*)pFromObject; // Clone event targets. if (!pFromEntity->m_eventTargets.empty()) { int numTargets = pFromEntity->m_eventTargets.size(); for (int i = 0; i < numTargets; i++) { CEntityEventTarget &et = pFromEntity->m_eventTargets[i]; CBaseObject *pClonedTarget = ctx.FindClone( et.target ); if (!pClonedTarget) pClonedTarget = et.target; // If target not cloned, link to original target. // Add cloned event. AddEventTarget( pClonedTarget,et.event,et.sourceEvent,true ); } } } ////////////////////////////////////////////////////////////////////////// void CEntity::ResolveEventTarget( CBaseObject *object,unsigned int index ) { // Find targetid. assert( index >= 0 && index < m_eventTargets.size() ); if (object) object->AddEventListener( functor(*this,&CEntity::OnEventTargetEvent) ); m_eventTargets[index].target = object; if (!m_eventTargets.empty() && m_script != 0) m_script->SetEventsTable( this ); // Make line gizmo. if (!m_eventTargets[index].pLineGizmo && object) { CLineGizmo *pLineGizmo = new CLineGizmo; pLineGizmo->SetObjects( this,object ); pLineGizmo->SetColor( Vec3(0.8f,0.4f,0.4f),Vec3(0.8f,0.4f,0.4f) ); pLineGizmo->SetName( m_eventTargets[index].event ); AddGizmo( pLineGizmo ); m_eventTargets[index].pLineGizmo = pLineGizmo; } } ////////////////////////////////////////////////////////////////////////// void CEntity::ReleaseEventTargets() { while (!m_eventTargets.empty()) RemoveEventTarget( m_eventTargets.size()-1,false ); m_eventTargets.clear(); } ////////////////////////////////////////////////////////////////////////// void CEntity::OnEventTargetEvent( CBaseObject *target,int event ) { // When event target is deleted. if (event == CBaseObject::ON_DELETE) { // Find this target in events list and remove. int numTargets = m_eventTargets.size(); for (int i = 0; i < numTargets; i++) { if (m_eventTargets[i].target == target) { RemoveEventTarget( i ); numTargets = m_eventTargets.size(); i--; } } } } ////////////////////////////////////////////////////////////////////////// int CEntity::AddEventTarget( CBaseObject *target,const CString &event,const CString &sourceEvent,bool bUpdateScript ) { StoreUndo( "Add EventTarget" ); CEntityEventTarget et; et.target = target; et.event = event; et.sourceEvent = sourceEvent; // Assign event target. if (et.target) et.target->AddEventListener( functor(*this,&CEntity::OnEventTargetEvent) ); if (target) { // Make line gizmo. CLineGizmo *pLineGizmo = new CLineGizmo; pLineGizmo->SetObjects( this,target ); pLineGizmo->SetColor( Vec3(0.8f,0.4f,0.4f),Vec3(0.8f,0.4f,0.4f) ); pLineGizmo->SetName( event ); AddGizmo( pLineGizmo ); et.pLineGizmo = pLineGizmo; } m_eventTargets.push_back( et ); // Update event table in script. if (bUpdateScript && m_script != 0) m_script->SetEventsTable( this ); return m_eventTargets.size()-1; } ////////////////////////////////////////////////////////////////////////// void CEntity::RemoveEventTarget( int index,bool bUpdateScript ) { if (index >= 0 && index < m_eventTargets.size()) { StoreUndo( "Remove EventTarget" ); if (m_eventTargets[index].pLineGizmo) { RemoveGizmo( m_eventTargets[index].pLineGizmo ); } if (m_eventTargets[index].target) m_eventTargets[index].target->RemoveEventListener( functor(*this,&CEntity::OnEventTargetEvent) ); m_eventTargets.erase( m_eventTargets.begin()+index ); // Update event table in script. if (bUpdateScript && m_script != 0 && m_entity != 0) m_script->SetEventsTable( this ); } } ////////////////////////////////////////////////////////////////////////// void CEntity::OnRenderFlagsChange( IVariable *var ) { if (m_entity) { m_entity->SetRndFlags(ERF_CASTSHADOWVOLUME, mv_castShadows); m_entity->SetRndFlags(ERF_SELFSHADOW, mv_selfShadowing);; m_entity->SetRndFlags(ERF_CASTSHADOWMAPS, mv_castShadowMaps); m_entity->SetRndFlags(ERF_RECVSHADOWMAPS, mv_recvShadowMaps); m_entity->SetRndFlags(ERF_CASTSHADOWINTOLIGHTMAP,mv_castLightmap); m_entity->SetRndFlags(ERF_USELIGHTMAPS,mv_recvLightmap); m_entity->SetRndFlags(ERF_SELECTED,IsSelected()); m_entity->SetLodRatio(mv_ratioLOD); m_entity->SetViewDistRatio(mv_ratioViewDist); //m_entity->SetUpdateVisLevel((EEntityUpdateVisLevel)(int)mv_UpdateVisLevel); } } ////////////////////////////////////////////////////////////////////////// void CEntity::OnRadiusChange( IVariable *var ) { var->Get(m_proximityRadius); } ////////////////////////////////////////////////////////////////////////// void CEntity::OnInnerRadiusChange( IVariable *var ) { var->Get(m_innerRadius); } ////////////////////////////////////////////////////////////////////////// void CEntity::OnOuterRadiusChange( IVariable *var ) { var->Get(m_outerRadius); } ////////////////////////////////////////////////////////////////////////// CVarBlock* CEntity::CloneProperties( CVarBlock *srcProperties ) { assert( srcProperties ); CVarBlock *properties = srcProperties->Clone(true); //@FIXME Hack to dispay radiuses of properties. // wires properties from param block, to this entity internal variables. IVariable *var = 0; var = properties->FindVariable( "Radius",false ); if (var && (var->GetType() == IVariable::FLOAT || var->GetType() == IVariable::INT)) { var->Get(m_proximityRadius); var->AddOnSetCallback( functor(*this,&CEntity::OnRadiusChange) ); } var = properties->FindVariable( "InnerRadius",false ); if (var && (var->GetType() == IVariable::FLOAT || var->GetType() == IVariable::INT)) { var->Get(m_innerRadius); var->AddOnSetCallback( functor(*this,&CEntity::OnInnerRadiusChange) ); } var = properties->FindVariable( "OuterRadius",false ); if (var && (var->GetType() == IVariable::FLOAT || var->GetType() == IVariable::INT)) { var->Get(m_outerRadius); var->AddOnSetCallback( functor(*this,&CEntity::OnOuterRadiusChange) ); } // Each property must have callback to our OnPropertyChange. properties->AddOnSetCallback( functor(*this,&CEntity::OnPropertyChange) ); return properties; } ////////////////////////////////////////////////////////////////////////// void CEntity::OnLoadFailed() { m_loadFailed = true; CErrorRecord err; err.error.Format( "Entity %s Failed to Spawn (Script: %s)",(const char*)GetName(),(const char*)m_entityClass ); err.pObject = this; GetIEditor()->GetErrorReport()->ReportError(err); } ////////////////////////////////////////////////////////////////////////// void CEntity::SetMaterial( CMaterial *mtl ) { StoreUndo( "Assign Material" ); m_pMaterial = mtl; if (m_pMaterial) { m_pMaterial->SetUsed(); m_materialGUID = m_pMaterial->GetGUID(); } else { ZeroStruct(m_materialGUID); } UpdateMaterialInfo(); } ////////////////////////////////////////////////////////////////////////// void CEntity::UpdateMaterialInfo() { if (m_entity) { if (m_pMaterial) m_pMaterial->AssignToEntity( m_entity ); else m_entity->SetMaterial(0); } } ////////////////////////////////////////////////////////////////////////// void CEntity::AcceptPhysicsState() { if (m_entity) { //StoreUndo( "Accept Physics State" ); // [Anton] - StoreUndo sends EVENT_AFTER_LOAD, which forces position and angles to editor's position and // angles, which are not updated with the physics value Vec3 pos = m_entity->GetPos(); Vec3 angles = m_entity->GetAngles(); SetPos( pos ); SetAngles( angles ); IPhysicalEntity *physic = m_entity->GetPhysics(); if (physic && physic->GetType() == PE_ARTICULATED) { // Only get state snapshot for articulated characters. char str[4096*4]; int len = physic->GetStateSnapshotTxt( str,sizeof(str) ); if (len > sizeof(str)-1) len = sizeof(str)-1; str[len] = 0; m_physicsState = str; } } } ////////////////////////////////////////////////////////////////////////// void CEntity::ResetPhysicsState() { if (m_entity) { //StoreUndo( "Reset Physics State" ); m_physicsState = ""; Reload(); } } void CEntity::SetHelperScale( float scale ) { bool bChanged = m_helperScale != scale; m_helperScale = scale; if (bChanged) { CalcBBox(); } } ////////////////////////////////////////////////////////////////////////// //! Analyze errors for this object. void CEntity::Validate( CErrorReport *report ) { CBaseObject::Validate( report ); // Checks for invalid values in base object. if (!GuidUtil::IsEmpty(m_materialGUID) && m_pMaterial == NULL) { CErrorRecord err; err.error.Format( "Material %s for Entity %s not found,",GuidUtil::ToString(m_materialGUID),(const char*)GetName() ); err.pObject = this; report->ReportError(err); //Warning( "Material %s for Entity %s not found,",GuidUtil::ToString(m_materialGUID),(const char*)GetName() ); } if (!m_entity) { CErrorRecord err; err.error.Format( "Entity %s Failed to Spawn (Script: %s)",(const char*)GetName(),(const char*)m_entityClass ); err.pObject = this; report->ReportError(err); return; } int slot; // Check Entity. int numObj = m_entity->GetNumObjects(); for (slot = 0; slot < numObj; slot++) { CEntityObject obj; if (!m_entity->GetEntityObject( slot,obj )) continue; if (obj.object != NULL && obj.object->IsDefaultObject()) { //const char *filename = obj.object->GetFileName(); // File Not found. CErrorRecord err; err.error.Format( "Geometry File in Slot %d for Entity %s not found",slot,(const char*)GetName() ); //err.file = filename; err.pObject = this; err.flags = CErrorRecord::FLAG_NOFILE; report->ReportError(err); } } /* IEntityCharacter *pIChar = m_entity->GetCharInterface(); pIChar->GetCharacter(0); for (slot = 0; slot < MAX_ANIMATED_MODELS; slot++) { ICryCharInstance *pCharacter = pIChar->GetCharacter(slot); pCharacter->IsDe } */ } ////////////////////////////////////////////////////////////////////////// void CEntity::GatherUsedResources( CUsedResources &resources ) { CBaseObject::GatherUsedResources( resources ); if (m_properties) m_properties->GatherUsedResources( resources ); if (m_properties2) m_properties2->GatherUsedResources( resources ); } ////////////////////////////////////////////////////////////////////////// bool CEntity::IsSimilarObject( CBaseObject *pObject ) { if (pObject->GetClassDesc() == GetClassDesc() && pObject->GetRuntimeClass() == GetRuntimeClass()) { CEntity *pEntity = (CEntity*)pObject; if (m_entityClass == pEntity->m_entityClass && m_proximityRadius == pEntity->m_proximityRadius && m_innerRadius == pEntity->m_innerRadius && m_outerRadius == pEntity->m_outerRadius) { return true; } } return false; } ////////////////////////////////////////////////////////////////////////// // CSimple Entity. ////////////////////////////////////////////////////////////////////////// bool CSimpleEntity::Init( IEditor *ie,CBaseObject *prev,const CString &file ) { bool bRes = false; if (file.IsEmpty()) { bRes = CEntity::Init( ie,prev,"" ); } else { bRes = CEntity::Init( ie,prev,"BasicEntity" ); LoadScript( m_entityClass ); SetGeometryFile( file ); } return bRes; } void CSimpleEntity::SetGeometryFile( const CString &filename ) { if (m_properties) { IVariable* pModelVar = m_properties->FindVariable( "object_Model" ); if (pModelVar) { pModelVar->Set( filename ); } } } CString CSimpleEntity::GetGeometryFile() const { CString filename; if (m_properties) { IVariable* pModelVar = m_properties->FindVariable( "object_Model" ); if (pModelVar) { pModelVar->Get( filename ); } } return filename; } ////////////////////////////////////////////////////////////////////////// bool CSimpleEntity::ConvertFromObject( CBaseObject *object ) { CBaseObject::ConvertFromObject( object ); if (object->IsKindOf(RUNTIME_CLASS(CBrushObject))) { CBrushObject *pBrushObject = (CBrushObject*)object; IStatObj *prefab = pBrushObject->GetPrefabGeom(); if (!prefab) return false; // Copy entity shadow parameters. int rndFlags = pBrushObject->GetRenderFlags(); mv_castShadows = (rndFlags & ERF_CASTSHADOWVOLUME) != 0; mv_selfShadowing = (rndFlags & ERF_SELFSHADOW) != 0; mv_castShadowMaps = (rndFlags & ERF_CASTSHADOWMAPS) != 0; mv_recvShadowMaps = (rndFlags & ERF_RECVSHADOWMAPS) != 0; mv_castLightmap = (rndFlags & ERF_CASTSHADOWINTOLIGHTMAP) != 0; mv_recvLightmap = (rndFlags & ERF_USELIGHTMAPS) != 0; mv_ratioLOD = pBrushObject->GetRatioLod(); mv_ratioViewDist = pBrushObject->GetRatioViewDist(); LoadScript( "BasicEntity" ); SpawnEntity(); SetGeometryFile( prefab->GetFileName() ); } return true; } ////////////////////////////////////////////////////////////////////////// void CSimpleEntity::BeginEditParams( IEditor *ie,int flags ) { CEntity::BeginEditParams( ie,flags ); CString filename = GetGeometryFile(); if (gSettings.bGeometryBrowserPanel) { if (!filename.IsEmpty()) { if (!s_treePanel) { s_treePanel = new CPanelTreeBrowser; int flags = CPanelTreeBrowser::NO_DRAGDROP|CPanelTreeBrowser::NO_PREVIEW|CPanelTreeBrowser::SELECT_ONCLICK; s_treePanel->Create( functor(*this,&CSimpleEntity::OnFileChange),GetClassDesc()->GetFileSpec(),AfxGetMainWnd(),flags ); } if (s_treePanelId == 0) s_treePanelId = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,_T("Geometry"),s_treePanel,false ); } if (s_treePanel) { s_treePanel->SetSelectCallback( functor(*this,&CSimpleEntity::OnFileChange) ); s_treePanel->SelectFile( filename ); } } } ////////////////////////////////////////////////////////////////////////// void CSimpleEntity::EndEditParams( IEditor *ie ) { if (s_treePanelId != 0) { GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,s_treePanelId ); s_treePanelId = 0; } CEntity::EndEditParams( ie ); } ////////////////////////////////////////////////////////////////////////// void CSimpleEntity::OnFileChange( CString filename ) { CUndo undo("Entity Geom Modify"); StoreUndo( "Entity Geom Modify" ); SetGeometryFile( filename ); } ////////////////////////////////////////////////////////////////////////// //! Analyze errors for this object. void CSimpleEntity::Validate( CErrorReport *report ) { CEntity::Validate( report ); // Checks if object loaded. } ////////////////////////////////////////////////////////////////////////// bool CSimpleEntity::IsSimilarObject( CBaseObject *pObject ) { if (pObject->GetClassDesc() == GetClassDesc() && pObject->GetRuntimeClass() == GetRuntimeClass()) { CSimpleEntity *pEntity = (CSimpleEntity*)pObject; if (GetGeometryFile() == pEntity->GetGeometryFile()) { return true; } } return false; }