//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2001. // ------------------------------------------------------------------------- // File name: BaseObject.cpp // Version: v1.00 // Created: 10/10/2001 by Timur. // Compilers: Visual C++ 6.0 // Description: CBaseObject implementation. // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "BaseObject.h" #include "ObjectManager.h" #include "Group.h" #include "..\Viewport.h" #include "..\ObjectPanel.h" #include "..\PropertiesPanel.h" #include "..\DisplaySettings.h" #include "..\Settings.h" #include "GizmoManager.h" #include #include #define AXIS_SIZE 0.15f #define LINK_COLOR_PARENT RGB(0,255,255) #define LINK_COLOR_CHILD RGB(0,0,255) #define INVALID_POSITION_EPSILON 100000 ////////////////////////////////////////////////////////////////////////// // CBase implementation. ////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CBaseObject,CObject); namespace { int s_rollupIndex = 0; CObjectPanel* s_objectPanel = 0; int s_varsIndex = 0; CPropertiesPanel* s_varsPanel = 0; //! Which axis to highlight. int s_highlightAxis = 0; struct AutoReleaseAll { AutoReleaseAll() {}; ~AutoReleaseAll() { delete s_objectPanel; delete s_varsPanel; } } s_autoReleaseAll; }; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// //! Undo object for CBaseObject. class CUndoBaseObject : public IUndoObject { public: CUndoBaseObject( CBaseObject *obj,const char *undoDescription ) { // Stores the current state of this object. assert( obj != 0 ); m_undoDescription = undoDescription; m_object = obj; m_redo = 0; m_undo = new CXmlNode("Undo"); CObjectArchive ar(GetIEditor()->GetObjectManager(),m_undo,false ); ar.bUndo = true; obj->Serialize( ar ); } protected: virtual int GetSize() { /* CString m_undoStr,m_redoStr; if (m_undo) m_undoStr = m_undo->getXML(); if (m_redo) m_redoStr = m_redo->getXML(); return sizeof(CUndoBaseObject) + m_undoStr.GetLength() + m_redoStr.GetLength() + m_undoDescription.GetLength(); */ return sizeof(CUndoBaseObject); } virtual const char* GetDescription() { return m_undoDescription; }; virtual void Undo( bool bUndo ) { GetIEditor()->SuspendUndo(); if (bUndo) { m_redo = new CXmlNode("Redo"); // Save current object state. CObjectArchive ar(GetIEditor()->GetObjectManager(),m_redo,false ); ar.bUndo = true; m_object->Serialize( ar ); } // Undo object state. CObjectArchive ar(GetIEditor()->GetObjectManager(),m_undo,true ); ar.bUndo = true; m_object->Serialize( ar ); GetIEditor()->ResumeUndo(); } virtual void Redo() { GetIEditor()->SuspendUndo(); CObjectArchive ar(GetIEditor()->GetObjectManager(),m_redo,true ); ar.bUndo = true; m_object->Serialize( ar ); GetIEditor()->ResumeUndo(); } private: CString m_undoDescription; CBaseObjectPtr m_object; XmlNodeRef m_undo; XmlNodeRef m_redo; }; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// //! Undo object for CBaseObject. class CUndoBaseObjectPos : public IUndoObject { public: CUndoBaseObjectPos( CBaseObject *obj,const char *undoDescription ) { // Stores the current state of this object. assert( obj != 0 ); m_undoDescription = undoDescription; m_object = obj; ZeroStruct(m_redo); m_undo.pos = obj->GetPos(); m_undo.angles = obj->GetAngles(); m_undo.scale = obj->GetScale(); m_undo.color = obj->GetColor(); m_undo.area = obj->GetArea(); } protected: virtual int GetSize() { return sizeof(*this); } virtual const char* GetDescription() { return m_undoDescription; }; virtual void Undo( bool bUndo ) { if (bUndo) { m_redo.pos = m_object->GetPos(); m_redo.angles = m_object->GetAngles(); m_redo.scale = m_object->GetScale(); m_redo.color = m_object->GetColor(); m_redo.area = m_object->GetArea(); } m_object->SetPos(m_undo.pos); m_object->SetAngles(m_undo.angles); m_object->SetScale(m_undo.scale); m_object->SetColor(m_undo.color); m_object->SetArea(m_undo.area); } virtual void Redo() { m_object->SetPos(m_redo.pos); m_object->SetAngles(m_redo.angles); m_object->SetScale(m_redo.scale); m_object->SetColor(m_redo.color); m_object->SetArea(m_redo.area); } private: CBaseObjectPtr m_object; CString m_undoDescription; struct StateStruct { Vec3 pos,angles,scale; COLORREF color; float area; }; StateStruct m_undo; StateStruct m_redo; }; ////////////////////////////////////////////////////////////////////////// void CObjectCloneContext::AddClone( CBaseObject *pFromObject,CBaseObject *pToObject ) { m_objectsMap[pFromObject] = pToObject; } ////////////////////////////////////////////////////////////////////////// CBaseObject* CObjectCloneContext::FindClone( CBaseObject *pFromObject ) { CBaseObject *pTarget = stl::find_in_map( m_objectsMap,pFromObject, (CBaseObject*) NULL ); return pTarget; } ////////////////////////////////////////////////////////////////////////// // CBaseObject implementation. ////////////////////////////////////////////////////////////////////////// CBaseObject::CBaseObject() { m_pos(0,0,0); m_angles(0,0,0); m_scale(1,1,1); m_color = RGB(255,255,255); m_group = 0; m_flags = 0; m_flattenArea = 0; m_ie = 0; m_numRefs = 0; m_guid = GUID_NULL; m_layer = 0; m_parent = 0; m_lookat = 0; m_lookatSource = 0; m_bMatrixInWorldSpace = false; m_bMatrixValid = false; m_ie = 0; m_nextListener = m_eventListeners.end(); } void CBaseObject::SetClassDesc( CObjectClassDesc *classDesc ) { m_classDesc = classDesc; } //! Initialize Object. bool CBaseObject::Init( IEditor *ie,CBaseObject *prev,const CString &file ) { SetFlags( m_flags&(~OBJFLAG_DELETED) ); m_ie = ie; if (prev != 0) { // Same layer. SetLayer( prev->GetLayer() ); SetUniqName( prev->GetName() ); SetPos( prev->GetPos() ); SetAngles( prev->GetAngles() ); SetScale( prev->GetScale() ); SetArea( prev->GetArea() ); SetColor( prev->GetColor() ); SetMaterial( prev->GetMaterial() ); /* // Clone important flags. if (prev->CheckFlags(OBJFLAG_SHARED)) SetFlags(OBJFLAG_SHARED); else CheckFlags(OBJFLAG_SHARED); */ // Copy all basic variables. CopyVariableValues(prev); } return true; } ////////////////////////////////////////////////////////////////////////// CBaseObject::~CBaseObject() { for (Childs::iterator c = m_childs.begin(); c != m_childs.end(); c++) { CBaseObject* child = *c; child->m_parent = 0; } m_childs.clear(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::Done() { DetachAll(); SetLookAt(0); if (m_lookatSource) { m_lookatSource->SetLookAt(0); } SetFlags( m_flags|OBJFLAG_DELETED ); NotifyListeners( CBaseObject::ON_DELETE ); m_eventListeners.clear(); m_group = 0; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetName( const CString &name ) { if (name == m_name) return; StoreUndo( "Name" ); m_name = name; GetObjectManager()->RegisterObjectName( name ); SetModified(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetUniqName( const CString &name ) { if (name == m_name) return; SetName( GetObjectManager()->GenUniqObjectName(name) ); } ////////////////////////////////////////////////////////////////////////// const CString& CBaseObject::GetName() const { return m_name; } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::IsSameClass( CBaseObject *obj ) { return GetClassDesc() == obj->GetClassDesc(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetPos( const Vec3d &pos ) { if (IsVectorsEqual(m_pos,pos)) return; ////////////////////////////////////////////////////////////////////////// // Check if position is bad. if (fabs(pos.x) > INVALID_POSITION_EPSILON || fabs(pos.y) > INVALID_POSITION_EPSILON || fabs(pos.z) > INVALID_POSITION_EPSILON) { Log( "Invalid Position = %f,%f,%f",pos.x,pos.y,pos.z ); Warning( "Object %s, SetPos called with invalid position.\r\nPosition change ignored.\r\nCheck Log for more info.",(const char*)GetName() ); return; } ////////////////////////////////////////////////////////////////////////// StoreUndo( "Position",true ); m_pos = pos; m_height = pos.z - GetIEditor()->GetTerrainElevation(pos.x,pos.y); if (m_bMatrixValid) InvalidateTM(); SetModified(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetAngles( const Vec3d &angles ) { if (IsVectorsEqual(m_angles,angles)) return; StoreUndo( "Angles",true ); m_angles = angles; if (m_bMatrixValid) InvalidateTM(); SetModified(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetScale( const Vec3d &scale ) { if (IsVectorsEqual(m_scale,scale)) return; ////////////////////////////////////////////////////////////////////////// // Check if position is bad. if (scale.x < 0.01 || scale.y < 0.01 || scale.z < 0.01) { Log( "Invalid Scale = %f,%f,%f",scale.x,scale.y,scale.z ); Warning( "Object %s, SetScale called with invalid scale.\r\nScale change ignored.\r\nCheck Log for more info.",(const char*)GetName() ); return; } ////////////////////////////////////////////////////////////////////////// StoreUndo( "Scale",true ); m_scale = scale; if (m_bMatrixValid) InvalidateTM(); SetModified(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetColor( COLORREF color ) { if (color == m_color) return; StoreUndo( "Color",true ); m_color = color; SetModified(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetArea( float area ) { if (m_flattenArea == area) return; StoreUndo( "Area",true ); m_flattenArea = area; SetModified(); }; /* ////////////////////////////////////////////////////////////////////////// void CBaseObject::GetWorldBounds( BBox &box ) { GetLocalBounds( box ); m_box = box; Vec3d v[8]; v[0] = Vec3d(box.min.x,box.min.y,box.min.z); v[1] = Vec3d(box.min.x,box.min.y,box.max.z); v[2] = Vec3d(box.min.x,box.max.y,box.min.z); v[3] = Vec3d(box.min.x,box.max.y,box.max.z); v[4] = Vec3d(box.max.x,box.min.y,box.min.z); v[5] = Vec3d(box.max.x,box.min.y,box.max.z); v[6] = Vec3d(box.max.x,box.max.y,box.min.z); v[7] = Vec3d(box.max.x,box.max.y,box.max.z); box.min.Set(FLT_MAX,FLT_MAX,FLT_MAX); box.max.Set(FLT_MIN,FLT_MIN,FLT_MIN); for (int i = 0; i < 8; i++) { box.min.x = std::min(box.min.x,v[i].x); box.min.y = std::min(box.min.y,v[i].y); box.min.z = std::min(box.min.z,v[i].z); box.max.x = std::max(box.max.x,v[i].x); box.max.y = std::max(box.max.y,v[i].y); box.max.z = std::max(box.max.z,v[i].z); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::GetLocalBounds( BBox &box ) { box = m_box; } */ //! Get bounding box of object in world coordinate space. void CBaseObject::GetBoundBox( BBox &box ) { // Transform local bounding box into world space. GetLocalBounds( box ); box.Transform( GetWorldTM() ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::GetLocalBounds( BBox &box ) { box.min.Set(0,0,0); box.max.Set(0,0,0); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::BeginEditParams( IEditor *ie,int flags ) { if (!s_objectPanel) { s_objectPanel = new CObjectPanel(AfxGetMainWnd()); s_objectPanel->Create( CObjectPanel::IDD,AfxGetMainWnd() ); s_rollupIndex = ie->AddRollUpPage( ROLLUP_OBJECTS,GetTypeName(),s_objectPanel ); } if (GetVarBlock()) { if (!s_varsPanel) s_varsPanel = new CPropertiesPanel( AfxGetMainWnd() ); else s_varsPanel->DeleteVars(); s_varsPanel->AddVars( GetVarBlock() ); if (!s_varsIndex) s_varsIndex = ie->AddRollUpPage( ROLLUP_OBJECTS,CString(GetTypeName()) + " Params",s_varsPanel ); } assert( s_objectPanel != 0 ); if (s_objectPanel) { CObjectPanel::SParams uip; uip.name = m_name; uip.color = m_color; uip.area = m_flattenArea; //uip.flatten = CheckFlags(OBJFLAG_FLATTEN); //uip.shared = CheckFlags(OBJFLAG_SHARED); uip.layer = m_layer->GetName(); uip.helperScale = GetHelperScale(); s_objectPanel->SetParams( this,uip ); } SetFlags( OBJFLAG_EDITING ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::EndEditParams( IEditor *ie ) { OnUIUpdate(); ClearFlags( OBJFLAG_EDITING ); if (s_rollupIndex != 0) ie->RemoveRollUpPage( ROLLUP_OBJECTS,s_rollupIndex ); s_rollupIndex = 0; s_objectPanel = 0; if (s_varsIndex != 0) ie->RemoveRollUpPage( ROLLUP_OBJECTS,s_varsIndex ); s_varsIndex = 0; s_varsPanel = 0; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::BeginEditMultiSelParams( bool bAllOfSameType ) { if (!s_objectPanel) { s_objectPanel = new CObjectPanel(AfxGetMainWnd()); s_objectPanel->Create( CObjectPanel::IDD,AfxGetMainWnd() ); s_rollupIndex = m_ie->AddRollUpPage( ROLLUP_OBJECTS,GetTypeName(),s_objectPanel ); s_objectPanel->SetMultiSelect( true ); } if (bAllOfSameType) { if (GetVarBlock()) { if (!s_varsPanel) s_varsPanel = new CPropertiesPanel( AfxGetMainWnd() ); else s_varsPanel->DeleteVars(); // Add all selected objects. CSelectionGroup *grp = GetIEditor()->GetSelection(); for (int i = 0; i < grp->GetCount(); i++) { CVarBlock *vb = grp->GetObject(i)->GetVarBlock(); if (vb) s_varsPanel->AddVars( vb ); } if (!s_varsIndex) s_varsIndex = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,CString(GetTypeName()) + " Params",s_varsPanel ); } /* if (m_params != 0 && GetPropertiesTemplate() != 0) { if (!s_paramsPanel) { s_paramsPanel = new CPropertiesPanel( AfxGetMainWnd() ); s_paramsPanel->SetMultiSelect(true); s_paramsPanel->SetObject( this ); // Have to be before AddRollup. s_paramsIndex = m_ie->AddRollUpPage( ROLLUP_OBJECTS,GetTypeName() + " Properties",s_paramsPanel ); } else { s_paramsPanel->SetMultiSelect(true); s_paramsPanel->SetObject( this ); } } */ } SetFlags( OBJFLAG_EDITING ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::EndEditMultiSelParams() { ClearFlags( OBJFLAG_EDITING ); if (s_rollupIndex != 0) m_ie->RemoveRollUpPage( ROLLUP_OBJECTS,s_rollupIndex ); s_rollupIndex = 0; s_objectPanel = 0; if (s_varsIndex != 0) m_ie->RemoveRollUpPage( ROLLUP_OBJECTS,s_varsIndex ); s_varsIndex = 0; s_varsPanel = 0; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::OnUIUpdate() { if (s_objectPanel && !s_objectPanel->IsMultiSelect()) { CObjectPanel::SParams uip; s_objectPanel->GetParams( uip ); if (uip.area != m_flattenArea) SetArea( uip.area ); /* // First flags. if (uip.flatten) SetFlags(OBJFLAG_FLATTEN); else ClearFlags(OBJFLAG_FLATTEN); */ SetHelperScale( uip.helperScale ); //Timur[9/11/2002] /* if (uip.shared) SetFlags(OBJFLAG_SHARED); else ClearFlags(OBJFLAG_SHARED); */ if (uip.name != m_name) { // This may also change object id. GetObjectManager()->ChangeObjectName( this,uip.name ); } if (uip.color != m_color ) SetColor( uip.color ); CObjectLayer *pLayer = GetObjectManager()->GetLayersManager()->FindLayerByName(uip.layer); if (pLayer != m_layer) SetLayer( pLayer ); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::UpdateEditParams() { if (s_objectPanel && s_objectPanel->GetObject() == this) { // If its current object update its panel. CObjectPanel::SParams uip; uip.name = m_name; uip.color = m_color; uip.area = m_flattenArea; //uip.flatten = CheckFlags(OBJFLAG_FLATTEN); //uip.shared = CheckFlags(OBJFLAG_SHARED); uip.layer = m_layer->GetName(); uip.helperScale = GetHelperScale(); s_objectPanel->SetParams( this,uip ); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetModified() { /* Not needed! causes refresh of UI everytime object is moved. if (CheckFlags(OBJFLAG_EDITING) && s_objectPanel != 0) { CObjectPanel::SParams uip; uip.name = m_name; uip.color = m_color; uip.area = m_flattenArea; uip.flatten = CheckFlags(OBJFLAG_FLATTEN); uip.shared = CheckFlags(OBJFLAG_SHARED); uip.layer = m_layer; s_objectPanel->SetParams( uip ); } */ } void CBaseObject::DrawDefault( DisplayContext &dc,COLORREF labelColor ) { // Draw if (dc.flags & DISPLAY_LINKS) { if (GetParent() && !(GetParent()->GetType() == OBJTYPE_GROUP) && !CheckFlags(OBJFLAG_PREFAB)) { // Draw link between parent and child. Vec3 parentPos = GetParent()->GetWorldPos(); dc.DrawLine( parentPos,GetWorldPos(),LINK_COLOR_PARENT,LINK_COLOR_CHILD ); } } if (dc.flags & DISPLAY_BBOX) { BBox box; GetBoundBox( box ); dc.SetColor( Vec3(1,1,1) ); dc.DrawWireBox( box.min,box.max ); } if (IsHighlighted()) { DrawHighlight( dc ); } if (IsSelected()) { DrawArea( dc ); // Draw Axis. //DrawAxis( dc,Vec3(0,0,0),AXIS_SIZE ); } if (!(dc.flags & DISPLAY_HIDENAMES)) { // Check if our group is not closed. if (!m_group || m_group->IsOpen()) { BBox box; GetBoundBox( box ); Vec3 p = GetWorldPos(); p.z = box.max.z + 0.2f; if ((dc.flags & DISPLAY_2D) && labelColor == RGB(255,255,255)) { labelColor = RGB(0,0,0); } DrawLabel( dc,p,labelColor ); } } } void CBaseObject::DrawLabel( DisplayContext &dc,const Vec3 &pos,COLORREF labelColor ) { float camDist = GetDistance(dc.camera->GetPos(), pos ); float maxDist = dc.settings->GetLabelsDistance(); if (camDist < dc.settings->GetLabelsDistance()) { float range = maxDist / 2.0f; Vec3 c = Rgb2Vec(labelColor); if (IsSelected()) c = Rgb2Vec(dc.GetSelectedColor()); float col[4] = { c.x,c.y,c.z,1 }; if (camDist > range) { col[3] = col[3] * (1.0f - (camDist - range)/range); } dc.SetColor( col[0],col[1],col[2],col[3] ); //dc.renderer->DrawLabelEx( GetPos()+Vec3(0,0,1),1.0f,col,true,true,"%s",(const char*)GetName() ); //dc.renderer->DrawLabelEx( pos,1.0f,col,true,true,"%s",(const char*)GetName() ); dc.DrawTextLabel( pos,1,GetName() ); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::DrawHighlight( DisplayContext &dc ) { //static int sizeRunner = 0; BBox box; GetLocalBounds( box ); dc.SetColor( RGB(255,120,0),0.8f ); //float s = 0.05f * sin( GetIEditor()->GetSystem()->GetITimer()->GetCurrTime() ); float s = 0.01f; dc.PushMatrix( GetWorldTM() ); dc.DrawWireBox( box.min-Vec3(s,s,s),box.max+Vec3(s,s,s) ); dc.PopMatrix(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::DrawAxis( DisplayContext &dc,const Vec3 &pos,float size ) { /* dc.renderer->EnableDepthTest(false); Vec3 x(size,0,0); Vec3 y(0,size,0); Vec3 z(0,0,size); bool bWorldSpace = false; if (dc.flags & DISPLAY_WORLDSPACEAXIS) bWorldSpace = true; Matrix tm = GetWorldTM(); Vec3 org = tm.TransformPoint( pos ); if (!bWorldSpace) { tm.NoScale(); x = tm.TransformVector(x); y = tm.TransformVector(y); z = tm.TransformVector(z); } float fScreenScale = dc.view->GetScreenScaleFactor(org); x = x * fScreenScale; y = y * fScreenScale; z = z * fScreenScale; float col[4] = { 1,1,1,1 }; float hcol[4] = { 1,0,0,1 }; dc.renderer->DrawLabelEx( org+x,1.2f,col,true,true,"X" ); dc.renderer->DrawLabelEx( org+y,1.2f,col,true,true,"Y" ); dc.renderer->DrawLabelEx( org+z,1.2f,col,true,true,"Z" ); Vec3 colX(1,0,0),colY(0,1,0),colZ(0,0,1); if (s_highlightAxis) { float col[4] = { 1,0,0,1 }; if (s_highlightAxis == 1) { colX.Set(1,1,0); dc.renderer->DrawLabelEx( org+x,1.2f,col,true,true,"X" ); } if (s_highlightAxis == 2) { colY.Set(1,1,0); dc.renderer->DrawLabelEx( org+y,1.2f,col,true,true,"Y" ); } if (s_highlightAxis == 3) { colZ.Set(1,1,0); dc.renderer->DrawLabelEx( org+z,1.2f,col,true,true,"Z" ); } } x = x * 0.8f; y = y * 0.8f; z = z * 0.8f; float fArrowScale = fScreenScale * 0.07f; dc.SetColor( colX ); dc.DrawArrow( org,org+x,fArrowScale ); dc.SetColor( colY ); dc.DrawArrow( org,org+y,fArrowScale ); dc.SetColor( colZ ); dc.DrawArrow( org,org+z,fArrowScale ); //dc.DrawLine( org,org+x,colX,colX ); //dc.DrawLine( org,org+y,colY,colY ); //dc.DrawLine( org,org+z,colZ,colZ ); dc.renderer->EnableDepthTest(true); ///dc.SetColor( 0,1,1,1 ); //dc.DrawLine( p,p+dc.view->m_constructionPlane.m_normal*10.0f ); */ } void CBaseObject::DrawArea( DisplayContext &dc ) { float area = m_flattenArea; if (area > 0) { dc.renderer->SetMaterialColor( 0,1,0,1 ); Vec3 wp = GetWorldPos(); float z = GetIEditor()->GetTerrainElevation( wp.x,wp.y ); if (fabs(wp.z-z) < 5) dc.DrawTerrainCircle( wp,area,0.2f ); else dc.DrawCircle( wp,area ); /* // Draw area radius. dc.renderer->SetPolygonMode(R_WIREFRAME_MODE); dc.renderer->SetMaterialColor( 0,1,1,0.2f ); //dc.renderer->DrawBall( areaPos,area ); dc.renderer->SetPolygonMode(R_SOLID_MODE); */ } } /* void CBaseObject::GetMatrix( Matrix &tm,bool noScale ) { tm.Identity(); tm.RotateMatrix( GetAngles() ); if (!noScale) { Vec3 s = GetScale(); if (s.x != 1 && s.y != 1 && s.z != 1) { Matrix tms; tms.Identity(); tms[0][0] = s.x; tms[1][0] = 0; tms[2][0] = 0; tms[0][1] = 0; tms[1][1] = s.y; tms[2][1] = 0; tms[0][2] = 0; tms[1][2] = 0; tms[2][2] = s.z; tm = tm*tms; } } Vec3 p = GetPos(); tm[3][0] = p.x; tm[3][1] = p.y; tm[3][2] = p.z; } */ int CBaseObject::MouseCreateCallback( CViewport *view,EMouseEvent event,CPoint &point,int flags ) { if (event == eMouseMove || event == eMouseLDown) { Vec3 pos = view->MapViewToCP(point); SetPos( pos ); if (event == eMouseMove) return MOUSECREATE_CONTINUE; if (event == eMouseLDown) return MOUSECREATE_OK; } return MOUSECREATE_CONTINUE; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::OnEvent( ObjectEvent event ) { switch (event) { case EVENT_KEEP_HEIGHT: { float h = m_height; float newz = m_ie->GetTerrainElevation( m_pos.x,m_pos.y ) + m_height; SetPos( Vec3(m_pos.x,m_pos.y,newz) ); m_height = h; } break; case EVENT_AFTER_LOAD: // Attach this to parent object. //ResolveParent(); //ResolveLookAt(); break; } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetShared( bool bShared ) { //Timur[9/11/2002] /* if (!GetGroup()) { if (bShared) SetFlags(OBJFLAG_SHARED); else ClearFlags(OBJFLAG_SHARED); } */ } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetHidden( bool bHidden ) { if (CheckFlags(OBJFLAG_HIDDEN) != bHidden) { StoreUndo( "Hide Object" ); if (bHidden) SetFlags(OBJFLAG_HIDDEN); else ClearFlags(OBJFLAG_HIDDEN); GetObjectManager()->InvalidateVisibleList(); UpdateVisibility( !IsHidden() ); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetFrozen( bool bFrozen ) { if (CheckFlags(OBJFLAG_FROZEN) != bFrozen) { StoreUndo( "Freeze Object" ); if (bFrozen) SetFlags(OBJFLAG_FROZEN); else ClearFlags(OBJFLAG_FROZEN); } if (bFrozen && IsSelected()) { // If frozen must be unselected. SetSelected(false); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetHighlight( bool bHighlight ) { if (bHighlight) SetFlags(OBJFLAG_HIGHLIGHT); else ClearFlags(OBJFLAG_HIGHLIGHT); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetSelected( bool bSelect ) { if (bSelect) { SetFlags(OBJFLAG_SELECTED); NotifyListeners( ON_SELECT ); //CLogFile::FormatLine( "Selected: %s, ID=%u",(const char*)m_name,m_id ); } else { ClearFlags(OBJFLAG_SELECTED); NotifyListeners( ON_UNSELECT ); } } ////////////////////////////////////////////////////////////////////////// //! Returns true if object hidden. bool CBaseObject::IsHidden() const { return (CheckFlags(OBJFLAG_HIDDEN)) || (!m_layer->IsVisible()) || (gSettings.objectHideMask & GetType()); } ////////////////////////////////////////////////////////////////////////// //! Returns true if object frozen. bool CBaseObject::IsFrozen() const { return CheckFlags(OBJFLAG_FROZEN) || m_layer->IsFrozen(); } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::IsSelectable() const { // Not selectable if hidden. if (IsHidden()) return false; // Not selectable if frozen. if (IsFrozen()) return false; // Not selectable if in closed group. CGroup* group = GetGroup(); if (group) { if (!group->IsOpen()) return false; } // Parts of prefab cannot be selected. if (CheckFlags(OBJFLAG_PREFAB)) return false; return true; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::Serialize( CObjectArchive &ar ) { XmlNodeRef xmlNode = ar.node; if (ar.bLoading) { // Loading. int flags = 0; int oldFlags = m_flags; ///xmlNode->getAttr( "Id",m_id ); CObjectLayer *pLayer = 0; // Find layer name. CString layerName; if (xmlNode->getAttr( "Layer",layerName )) { pLayer = GetObjectManager()->GetLayersManager()->FindLayerByName(layerName); } CString name = m_name; Vec3 pos = m_pos,angles=m_angles,scale=m_scale; COLORREF color = m_color; float flattenArea = m_flattenArea; GUID parentId = GUID_NULL; GUID lookatId = GUID_NULL; xmlNode->getAttr( "Name",name ); xmlNode->getAttr( "Pos",pos ); xmlNode->getAttr( "Angles",angles ); xmlNode->getAttr( "Scale",scale ); xmlNode->getAttr( "ColorRGB",color ); xmlNode->getAttr( "FlattenArea",flattenArea ); xmlNode->getAttr( "Flags",flags ); xmlNode->getAttr( "Parent",parentId ); xmlNode->getAttr( "LookAt",lookatId ); bool bHidden = flags & OBJFLAG_HIDDEN; bool bFrozen = flags & OBJFLAG_FROZEN; m_flags = flags; m_flags &= ~OBJFLAG_PERSISTMASK; m_flags |= (oldFlags) & (~OBJFLAG_PERSISTMASK); //SetFlags( flags & OBJFLAG_PERSISTMASK ); m_flags &= ~OBJFLAG_SHARED; // clear shared flag m_flags &= ~OBJFLAG_DELETED; // clear deleted flag ar.SetResolveCallback( this,parentId,functor(*this,&CBaseObject::ResolveParent) ); ar.SetResolveCallback( this,lookatId,functor(*this,&CBaseObject::SetLookAt) ); if (name != m_name) { // This may change object id. SetName( name ); } ////////////////////////////////////////////////////////////////////////// // Check if position is bad. if (fabs(pos.x) > INVALID_POSITION_EPSILON || fabs(pos.y) > INVALID_POSITION_EPSILON || fabs(pos.z) > INVALID_POSITION_EPSILON) { // File Not found. CErrorRecord err; err.error.Format( "Object %s have invalid position (%f,%f,%f)",(const char*)GetName(),pos.x,pos.y,pos.z ); err.pObject = this; err.severity = CErrorRecord::ESEVERITY_WARNING; GetIEditor()->GetErrorReport()->ReportError(err); } ////////////////////////////////////////////////////////////////////////// bool bMatrixWasValid = m_bMatrixValid; m_bMatrixValid = false; SetPos( pos ); SetAngles( angles ); SetScale( scale ); m_bMatrixValid = bMatrixWasValid; SetColor( color ); SetArea( flattenArea ); SetFrozen( bFrozen ); SetHidden( bHidden ); if (pLayer) SetLayer( pLayer ); InvalidateTM(); SetModified(); if (ar.bUndo) { // If we are selected update UI Panel. UpdateEditParams(); } } else { // Saving. // This attributed only readed by ObjectManager. xmlNode->setAttr( "Type",GetTypeName() ); if (m_layer) xmlNode->setAttr( "Layer",m_layer->GetName() ); xmlNode->setAttr( "Id",m_guid ); xmlNode->setAttr( "Name",GetName() ); if (m_parent) xmlNode->setAttr( "Parent",m_parent->GetId() ); if (m_lookat) xmlNode->setAttr( "LookAt",m_lookat->GetId() ); if (!IsEquivalent(GetPos(),Vec3(0,0,0),0)) xmlNode->setAttr( "Pos",GetPos() ); if (!IsEquivalent(GetAngles(),Vec3(0,0,0),0)) xmlNode->setAttr( "Angles",GetAngles() ); if (!IsEquivalent(GetScale(),Vec3(1,1,1),0)) xmlNode->setAttr( "Scale",GetScale() ); xmlNode->setAttr( "ColorRGB",GetColor() ); if (GetArea() != 0) xmlNode->setAttr( "FlattenArea",GetArea() ); int flags = m_flags & OBJFLAG_PERSISTMASK; if (flags != 0) xmlNode->setAttr( "Flags",flags ); } // Serialize variables after default entity parameters. CVarObject::Serialize( xmlNode,ar.bLoading ); } XmlNodeRef CBaseObject::Export( const CString &levelPath,XmlNodeRef &xmlNode ) { XmlNodeRef objNode = xmlNode->newChild( "Object" ); objNode->setAttr( "Type",GetTypeName() ); objNode->setAttr( "Name",GetName() ); Vec3 pos,angles,scale; if (m_parent) { // Export world coordinates. AffineParts ap; ap.SpectralDecompose( GetWorldTM() ); pos = ap.pos; angles = RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(ap.rot))); scale = ap.scale; } else { pos = m_pos; angles = m_angles; scale = m_scale; } if (!IsEquivalent(pos,Vec3(0,0,0),0)) objNode->setAttr( "Pos",pos ); if (!IsEquivalent(angles,Vec3(0,0,0),0)) objNode->setAttr( "Angles",angles ); if (!IsEquivalent(scale,Vec3(1,1,1),0)) objNode->setAttr( "Scale",scale ); // Save variables. CVarObject::Serialize( objNode,false ); return objNode; } ////////////////////////////////////////////////////////////////////////// CBaseObject* CBaseObject::FindObject( REFGUID id ) const { return GetObjectManager()->FindObject( id ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::StoreUndo( const char *UndoDescription,bool minimal ) { if (m_ie != 0 && m_ie->IsUndoRecording()) { if (minimal) m_ie->RecordUndo( new CUndoBaseObjectPos(this,UndoDescription) ); else m_ie->RecordUndo( new CUndoBaseObject(this,UndoDescription) ); } } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::IsCreateGameObjects() const { return GetObjectManager()->IsCreateGameObjects(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetLayer( CObjectLayer *layer ) { if (layer == m_layer) return; assert( layer != 0 ); StoreUndo( "Set Layer" ); m_layer = layer; // Set layer for all childs. for (int i = 0; i < m_childs.size(); i++) { m_childs[i]->SetLayer(layer); } // If object have target, target must also go into this layer. if (m_lookat) { m_lookat->SetLayer(layer); } } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::HitTestRect( HitContext &hc ) { BBox box; // Retrieve world space bound box. GetBoundBox( box ); // transform all 8 vertices into view space. CPoint p[8] = { hc.view->WorldToView(Vec3d(box.min.x,box.min.y,box.min.z)), hc.view->WorldToView(Vec3d(box.min.x,box.max.y,box.min.z)), hc.view->WorldToView(Vec3d(box.max.x,box.min.y,box.min.z)), hc.view->WorldToView(Vec3d(box.max.x,box.max.y,box.min.z)), hc.view->WorldToView(Vec3d(box.min.x,box.min.y,box.max.z)), hc.view->WorldToView(Vec3d(box.min.x,box.max.y,box.max.z)), hc.view->WorldToView(Vec3d(box.max.x,box.min.y,box.max.z)), hc.view->WorldToView(Vec3d(box.max.x,box.max.y,box.max.z)) }; CRect objrc,temprc; objrc.left = 10000; objrc.top = 10000; objrc.right = -10000; objrc.bottom = -10000; // find new min/max values for(int i=0; i<8; i++) { objrc.left = min(objrc.left,p[i].x); objrc.right = max(objrc.right,p[i].x); objrc.top = min(objrc.top,p[i].y); objrc.bottom = max(objrc.bottom,p[i].y); } if (objrc.IsRectEmpty()) { // Make objrc at least of size 1. objrc.bottom += 1; objrc.right += 1; } if (temprc.IntersectRect( objrc,hc.rect )) { hc.object = this; return true; } return false; /* // Return false if point lies outside selection rectangle. for(int i=0; i<8; i++) { if (p[i].x < hc.rect.left || p[i].x > hc.rect.right) return false; if (p[i].y < hc.rect.top || p[i].y > hc.rect.bottom) return false; } hc.object = this; return true; */ } ////////////////////////////////////////////////////////////////////////// int CBaseObject::HitTestAxis( HitContext &hc ) { return 0; if (hc.distanceTollerance != 0) return 0; bool bWorldSpace = GetIEditor()->GetReferenceCoordSys() == COORDS_WORLD; s_highlightAxis = 0; Vec3 x(AXIS_SIZE,0,0); Vec3 y(0,AXIS_SIZE,0); Vec3 z(0,0,AXIS_SIZE); Matrix44 tm = GetWorldTM(); Vec3 org = tm.TransformPointOLD( Vec3(0,0,0) ); if (!bWorldSpace) { tm.NoScale(); //CHANGED_BY_IVO x = tm.TransformVectorOLD(x); y = tm.TransformVectorOLD(y); z = tm.TransformVectorOLD(z); } float camDist = GetDistance( GetIEditor()->GetViewerPos(), org ); x = x * camDist; y = y * camDist; z = z * camDist; float hitDist = 0.01f * camDist; Vec3 p = tm.TransformPointOLD( Vec3(0,0,0) ); Vec3 np1,np2,np3; Vec3 rayTrg = hc.raySrc + hc.rayDir*10000.0f; float d1 = RayToLineDistance( hc.raySrc,rayTrg,p,p+x,np1 ); float d2 = RayToLineDistance( hc.raySrc,rayTrg,p,p+y,np2 ); float d3 = RayToLineDistance( hc.raySrc,rayTrg,p,p+z,np3 ); if (d1 < hitDist && d1 < d2 && d1 < d3) { // X-Axis. s_highlightAxis = AXIS_X; hc.dist = GetDistance(hc.raySrc,np1); } else if (d2 < hitDist && d2 < d1 && d2 < d3) { // Y-Axis. s_highlightAxis = AXIS_Y; hc.dist = GetDistance(hc.raySrc,np2); } else if (d3 < hitDist && d3 < d1 && d3 < d2) { // Z-Axis. s_highlightAxis = AXIS_Z; hc.dist = GetDistance(hc.raySrc,np3); } return s_highlightAxis; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// CBaseObject* CBaseObject::GetChild( int i ) const { assert( i >= 0 && i < m_childs.size() ); return m_childs[i]; } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::IsChildOf( CBaseObject *node ) { CBaseObject *p = m_parent; while (p && p != node) { p = p->m_parent; } if (p == node) return true; return false; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::AttachChild( CBaseObject* child,bool bKeepPos ) { assert( child ); if (!child) return; child->StoreUndo( "Attach Child" ); Matrix44 childTM; if (bKeepPos) { childTM = child->GetWorldTM(); } // If not already attached to this node. if (child->m_parent == this) return; // Add to child list first to make sure node not get deleted while reattaching. m_childs.push_back( child ); if (child->m_parent) child->DetachThis(bKeepPos); // Detach node if attached to other parent. ////////////////////////////////////////////////////////////////////////// child->m_parent = this; // Assign this node as parent to child node. //Timur[14/11/2003] Removed change of layer for child object. // child->SetLayer( GetLayer() ); //Timur[9/11/2002] /* // All child object must have same sharing flag. if (CheckFlags(OBJFLAG_SHARED)) child->SetFlags(OBJFLAG_SHARED); else child->ClearFlags(OBJFLAG_SHARED); */ if (bKeepPos) { ////////////////////////////////////////////////////////////////////////// // Keep old world space transformation. child->SetWorldTM( childTM ); } //else child->InvalidateTM(); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::DetachAll( bool bKeepPos ) { while (!m_childs.empty()) { CBaseObject* child = *m_childs.begin(); child->DetachThis(bKeepPos); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::DetachThis( bool bKeepPos ) { if (m_parent) { StoreUndo( "DetachThis" ); Matrix44 worldTM; if (bKeepPos) { worldTM = GetWorldTM(); } // Copy parent to temp var, erasing child from parent may delete this node if child referenced only from parent. CBaseObject* parent = m_parent; m_parent = 0; parent->RemoveChild( this ); if (bKeepPos) { // Keep old world space transformation. SetLocalTM( worldTM ); } else InvalidateTM(); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::RemoveChild( CBaseObject *node ) { Childs::iterator it = std::find( m_childs.begin(),m_childs.end(),node ); if (it != m_childs.end()) m_childs.erase( it ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::ResolveParent( CBaseObject *parent ) { if (parent != m_parent) { if (parent) parent->AttachChild( this,false ); else DetachThis(false); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::CalcLocalTM( Matrix44 &tm ) const { tm.SetIdentity(); if (m_lookat) { Vec3 pos = m_pos; if (m_parent) { // Get our world position. pos = m_parent->GetWorldTM().TransformPointOLD(pos); } // Calculate local TM matrix differently. tm = MatrixFromVector( m_lookat->GetWorldPos() - pos,Vec3(0,0,-1),0 ); // Positive Z up. // Translate matrix. tm.SetTranslationOLD(pos); } else { tm=Matrix44::CreateRotationZYX(-m_angles*gf_DEGTORAD)*tm; //NOTE: angles in radians and negated tm=Matrix33::CreateScale( Vec3d(m_scale.x,m_scale.y,m_scale.z) ) * tm; // Translate matrix. tm.SetTranslationOLD(m_pos); } } ////////////////////////////////////////////////////////////////////////// const Matrix44& CBaseObject::GetLocalTM() const { if (!m_bMatrixInWorldSpace && m_bMatrixValid) { return m_worldTM; } CalcLocalTM( m_worldTM ); m_bMatrixInWorldSpace = false; m_bMatrixValid = true; if (m_lookat) m_bMatrixInWorldSpace = true; return m_worldTM; } ////////////////////////////////////////////////////////////////////////// const Matrix44& CBaseObject::GetWorldTM() const { if (!m_bMatrixValid) { m_worldTM = GetLocalTM(); } if (!m_bMatrixInWorldSpace) { CBaseObject *parent = GetParent(); if (parent) { m_worldTM = m_worldTM * parent->GetWorldTM(); } m_bMatrixInWorldSpace = true; } return m_worldTM; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::InvalidateTM() { bool bMatrixWasValid = m_bMatrixValid; m_bMatrixInWorldSpace = false; m_bMatrixValid = false; // If matrix was valid, ivalidate all childs. if (bMatrixWasValid) { if (m_lookatSource) m_lookatSource->InvalidateTM(); // Invalidate matrices off all child objects. for (int i = 0; i < m_childs.size(); i++) { if (m_childs[i] != 0 && m_childs[i]->m_bMatrixValid) { m_childs[i]->InvalidateTM(); } } NotifyListeners( ON_TRANSFORM ); } // Notify parent that we were modified. if (m_parent) { m_parent->OnChildModified(); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetLocalTM( const Matrix44 &tm ) { if (m_lookat) { SetPos( tm.GetTranslationOLD() ); // Calculate local TM matrix differently. CalcLocalTM(m_worldTM); m_bMatrixInWorldSpace = true; m_bMatrixValid = true; } else { bool bMatrixWasValid = m_bMatrixValid; m_bMatrixValid = false; m_bMatrixInWorldSpace = false; m_worldTM = tm; AffineParts affineParts; affineParts.SpectralDecompose(m_worldTM); Vec3 angles = RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(affineParts.rot))); if (!IsVectorsEqual(m_pos,affineParts.pos)) SetPos( affineParts.pos ); if (!IsVectorsEqual(m_angles,angles)) SetAngles( angles ); if (!IsVectorsEqual(m_scale,affineParts.scale)) SetScale( affineParts.scale ); // Only now invalidate matrix. m_bMatrixValid = bMatrixWasValid; InvalidateTM(); } /* Matrix m(tm); m.NoScale(); Quat q(m); SetAngles( q.GetEulerAngles()*180.0f/PI ); m_worldTM = tm; } */ } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetWorldTM( const Matrix44 &tm ) { if (GetParent()) { Matrix44 invParentTM = GetParent()->GetWorldTM(); invParentTM.Invert44(); Matrix44 localTM = tm * invParentTM; SetLocalTM( localTM ); } else { SetLocalTM( tm ); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::UpdateVisibility( bool visible ) { /* for (int i = 0; i < m_childs.size(); i++) { m_childs[i]->UpdateVisibility( visible ); } */ if (visible) m_flags |= OBJFLAG_VISIBLE; else m_flags &= ~OBJFLAG_VISIBLE; NotifyListeners( ON_VISIBILITY ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::AddGizmo( CGizmo *gizmo ) { GetObjectManager()->GetGizmoManager()->AddGizmo( gizmo ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::RemoveGizmo( CGizmo *gizmo ) { GetObjectManager()->GetGizmoManager()->RemoveGizmo( gizmo ); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::SetLookAt( CBaseObject *target ) { if (m_lookat == target) return; StoreUndo( "Change LookAt" ); if (m_lookat) { // Unbind current lookat. m_lookat->m_lookatSource = 0; } m_lookat = target; if (m_lookat) { m_lookat->m_lookatSource = this; } InvalidateTM(); } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::IsLookAtTarget() const { return m_lookatSource != 0; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::AddEventListener( const EventCallback &cb ) { if (std::find(m_eventListeners.begin(),m_eventListeners.end(),cb) == m_eventListeners.end()) m_eventListeners.push_back(cb); } ////////////////////////////////////////////////////////////////////////// void CBaseObject::RemoveEventListener( const EventCallback &cb ) { std::list::iterator it = std::find(m_eventListeners.begin(),m_eventListeners.end(),cb); if (it != m_eventListeners.end()) { m_nextListener = m_eventListeners.erase(it); } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::NotifyListeners( EObjectListenerEvent event ) { for (std::list::iterator it = m_eventListeners.begin(); it != m_eventListeners.end(); it = m_nextListener) { m_nextListener = it; m_nextListener++; // Call listener callback. (*it)( this,event ); } m_nextListener = m_eventListeners.end(); /* std::list::iterator next; for (std::list::iterator it = m_eventListeners.begin(); it != m_eventListeners.end(); it = next) { next = it; ++next; // Call listener callback. (*it)( this,event ); } */ } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::ConvertFromObject( CBaseObject *object ) { SetLocalTM( object->GetLocalTM() ); SetName( object->GetName() ); SetLayer( object->GetLayer() ); SetColor( object->GetColor() ); m_flattenArea = object->m_flattenArea; if (object->GetParent()) { object->GetParent()->AttachChild( this ); } SetMaterial( object->GetMaterial() ); return true; } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::IsPotentiallyVisible() const { if (!m_layer->IsVisible()) return false; if (CheckFlags(OBJFLAG_HIDDEN)) return false; if (gSettings.objectHideMask & GetType()) return false; CGroup *pGroup = GetGroup(); if (pGroup) { if (!pGroup->IsPotentiallyVisible()) return false; } return true; } ////////////////////////////////////////////////////////////////////////// //! Analyze errors for this object. void CBaseObject::Validate( CErrorReport *report ) { // Checks for invalid values in base object. ////////////////////////////////////////////////////////////////////////// // Check if position is bad. if (fabs(m_pos.x) > INVALID_POSITION_EPSILON || fabs(m_pos.y) > INVALID_POSITION_EPSILON || fabs(m_pos.z) > INVALID_POSITION_EPSILON) { // File Not found. CErrorRecord err; err.error.Format( "Object %s have invalid position (%f,%f,%f)",(const char*)GetName(),m_pos.x,m_pos.y,m_pos.z ); err.pObject = this; report->ReportError(err); } ////////////////////////////////////////////////////////////////////////// float minScale = 0.01f; float maxScale = 1000.0f; ////////////////////////////////////////////////////////////////////////// // Check if position is bad. if (m_scale.x < minScale || m_scale.x > maxScale || m_scale.y < minScale || m_scale.y > maxScale || m_scale.z < minScale || m_scale.z > maxScale) { // File Not found. CErrorRecord err; err.error.Format( "Object %s have invalid scale (%f,%f,%f)",(const char*)GetName(),m_scale.x,m_scale.y,m_scale.z ); err.pObject = this; report->ReportError(err); } ////////////////////////////////////////////////////////////////////////// }; ////////////////////////////////////////////////////////////////////////// Vec3 CBaseObject::GetWorldAngles() const { if (m_scale == Vec3(1,1,1)) { Quat q = Quat( GetTransposed44(GetWorldTM()) ); Vec3 angles = RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(q))); return angles; } else { Matrix44 tm = GetWorldTM(); tm.NoScale(); Quat q = Quat(tm); Vec3 angles = RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(q))); return angles; } }; ////////////////////////////////////////////////////////////////////////// void CBaseObject::PostClone( CBaseObject *pFromObject,CObjectCloneContext &ctx ) { CBaseObject *pFromParent = pFromObject->GetParent(); if (pFromParent) { CBaseObject *pChildParent = ctx.FindClone( pFromParent ); if (pChildParent) pChildParent->AttachChild( this,false ); else pFromParent->AttachChild( this,false ); } for (int i = 0; i < pFromObject->GetChildCount(); i++) { CBaseObject *pChildObject = pFromObject->GetChild(i); CBaseObject *pClonedChild = GetObjectManager()->CloneObject( pChildObject ); ctx.AddClone( pChildObject,pClonedChild ); } for (int i = 0; i < pFromObject->GetChildCount(); i++) { CBaseObject *pChildObject = pFromObject->GetChild(i); CBaseObject *pClonedChild = ctx.FindClone( pChildObject ); if (pClonedChild) { pClonedChild->PostClone( pChildObject,ctx ); } } } ////////////////////////////////////////////////////////////////////////// void CBaseObject::OnChangeGUID( REFGUID newGUID ) { m_guid = newGUID; } ////////////////////////////////////////////////////////////////////////// void CBaseObject::GatherUsedResources( CUsedResources &resources ) { if (GetVarBlock()) GetVarBlock()->GatherUsedResources( resources ); } ////////////////////////////////////////////////////////////////////////// bool CBaseObject::IsSimilarObject( CBaseObject *pObject ) { if (pObject->GetClassDesc() == GetClassDesc() && pObject->GetRuntimeClass() == GetRuntimeClass()) { return true; } return false; }