//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2001. // ------------------------------------------------------------------------- // File name: BrushObject.cpp // Version: v1.00 // Created: 10/10/2001 by Timur. // Compilers: Visual C++ 6.0 // Description: CBrushObject implementation. // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "BrushObject.h" #include "ObjectManager.h" #include "..\Viewport.h" #include "..\Brush\BrushPanel.h" #include "..\Brush\Brush.h" #include "PanelTreeBrowser.h" #include "Entity.h" #include "EdMesh.h" #include "Material\Material.h" #include "Material\MaterialManager.h" #include "Settings.h" #include #include #define MIN_BOUNDS_SIZE 0.01f ////////////////////////////////////////////////////////////////////////// // CBase implementation. ////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNCREATE(CBrushObject,CBaseObject) namespace { CBrushPanel* s_brushPanel = NULL; int s_brushPanelId = 0; CPanelTreeBrowser s_treePanel; CPanelTreeBrowser* s_treePanelPtr = NULL; int s_treePanelId = 0; } ////////////////////////////////////////////////////////////////////////// CBrushObject::CBrushObject() { m_prefabGeom = 0; m_indoor = 0; m_engineNode = 0; m_renderFlags = 0; AddVariable( mv_prefabName,"Prefab",functor(*this,&CBrushObject::OnPrefabChange),IVariable::DT_OBJECT ); // Init Variables. mv_outdoor = false; mv_castShadows = false; mv_selfShadowing = false; mv_castShadowMaps = false; mv_recvShadowMaps = true; mv_castLightmap = true; mv_recvLightmap = true; mv_hideable = false; mv_ratioLOD = 100; mv_ratioViewDist = 100; mv_excludeFromTriangulation = false; mv_lightmapQuality = 1; mv_lightmapQuality.SetLimits( 0,100 ); ZeroStruct(m_materialGUID); static CString sVarName_OutdoorOnly = "OutdoorOnly"; static CString sVarName_CastShadows = "CastShadows"; static CString sVarName_CastShadows2 = _T("CastShadowVolume"); static CString sVarName_SelfShadowing = "SelfShadowing"; static CString sVarName_CastShadowMaps = "CastShadowMaps"; static CString sVarName_RecvShadowMaps = "RecvShadowMaps"; static CString sVarName_CastLightmap = "CastLightmap"; static CString sVarName_ReceiveLightmap = "ReceiveLightmap"; static CString sVarName_Hideable = "Hideable"; static CString sVarName_LodRatio = "LodRatio"; static CString sVarName_ViewDistRatio = "ViewDistRatio"; static CString sVarName_NotTriangulate = "NotTriangulate"; static CString sVarName_LightmapQuality = "LightmapQuality"; ReserveNumVariables( 11 ); AddVariable( mv_outdoor,sVarName_OutdoorOnly,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_castShadows,sVarName_CastShadows,sVarName_CastShadows2,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_selfShadowing,sVarName_SelfShadowing,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_castShadowMaps,sVarName_CastShadowMaps,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_recvShadowMaps,sVarName_RecvShadowMaps,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_castLightmap,sVarName_CastLightmap,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_recvLightmap,sVarName_ReceiveLightmap,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_hideable,sVarName_Hideable,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_ratioLOD,sVarName_LodRatio,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_ratioViewDist,sVarName_ViewDistRatio,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_excludeFromTriangulation,sVarName_NotTriangulate,functor(*this, &CBrushObject::OnRenderVarChange) ); AddVariable( mv_lightmapQuality,sVarName_LightmapQuality ); mv_ratioLOD.SetLimits( 0,255 ); mv_ratioViewDist.SetLimits( 0,255 ); m_bIgnoreNodeUpdate = false; } ////////////////////////////////////////////////////////////////////////// void CBrushObject::Done() { if (m_engineNode) { GetIEditor()->Get3DEngine()->DeleteEntityRender(m_engineNode); m_engineNode = 0; } // Release Mesh. m_prefabGeom = 0; //free brush. m_brush = 0; CBaseObject::Done(); } ////////////////////////////////////////////////////////////////////////// bool CBrushObject::Init( IEditor *ie,CBaseObject *prev,const CString &file ) { SetColor( RGB(255,255,255) ); if (IsCreateGameObjects()) { if (prev) { CBrushObject *brushObj = (CBrushObject*)prev; if (brushObj->GetBrush()) { SetBrush( brushObj->GetBrush()->Clone(true) ); } } else if (!file.IsEmpty()) { // Create brush from prefab. mv_prefabName = file; CString name = Path::GetFileName( file ); SetUniqName( name ); } //m_indoor->AddBrush( this ); } // Must be after SetBrush call. bool res = CBaseObject::Init( ie,prev,file ); if (prev) { CBrushObject *brushObj = (CBrushObject*)prev; // Copy material GUID. m_materialGUID = brushObj->m_materialGUID; m_bbox = brushObj->m_bbox; } return res; } ////////////////////////////////////////////////////////////////////////// bool CBrushObject::CreateGameObject() { if (!m_engineNode) { m_engineNode = GetIEditor()->Get3DEngine()->CreateEntityRender(); m_engineNode->SetEditorObjectId( GetId().Data1 ); OnRenderVarChange(0); UpdateEngineNode(); } return true; } ////////////////////////////////////////////////////////////////////////// void CBrushObject::BeginEditParams( IEditor *ie,int flags ) { CBaseObject::BeginEditParams( ie,flags ); if (!s_brushPanel) { s_brushPanel = new CBrushPanel; s_brushPanelId = ie->AddRollUpPage( ROLLUP_OBJECTS,_T("Brush Parameters"),s_brushPanel ); } if (gSettings.bGeometryBrowserPanel) { CString prefabName = mv_prefabName; if (!prefabName.IsEmpty()) { if (!s_treePanelPtr) { s_treePanelPtr = &s_treePanel; //s_treePanel = new CPanelTreeBrowser; int flags = CPanelTreeBrowser::NO_DRAGDROP|CPanelTreeBrowser::NO_PREVIEW|CPanelTreeBrowser::SELECT_ONCLICK; s_treePanelPtr->Create( functor(*this, &CBrushObject::OnFileChange),GetClassDesc()->GetFileSpec(),AfxGetMainWnd(),flags ); } if (s_treePanelId == 0) s_treePanelId = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,_T("Prefab"),s_treePanelPtr,false ); } if (s_treePanelPtr) { s_treePanelPtr->SetSelectCallback( functor(*this, &CBrushObject::OnFileChange) ); s_treePanelPtr->SelectFile( prefabName ); } } if (s_brushPanel) s_brushPanel->SetBrush( this ); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::EndEditParams( IEditor *ie ) { CBaseObject::EndEditParams( ie ); if (s_treePanelId != 0) { GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,s_treePanelId ); s_treePanelId = 0; } if (s_brushPanel) { ie->RemoveRollUpPage( ROLLUP_OBJECTS,s_brushPanelId ); s_brushPanel = 0; s_brushPanelId = 0; } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::BeginEditMultiSelParams( bool bAllOfSameType ) { CBaseObject::BeginEditMultiSelParams( bAllOfSameType ); if (bAllOfSameType) { if (!s_brushPanel) { s_brushPanel = new CBrushPanel; s_brushPanelId = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,_T("Brush Parameters"),s_brushPanel ); } if (s_brushPanel) s_brushPanel->SetBrush(0); } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::EndEditMultiSelParams() { CBaseObject::EndEditMultiSelParams(); if (s_brushPanel) { GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,s_brushPanelId ); s_brushPanel = 0; s_brushPanelId = 0; } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::OnFileChange( CString filename ) { CUndo undo("Brush Prefab Modify"); StoreUndo( "Brush Prefab Modify" ); mv_prefabName = filename; if (m_brush) m_brush->ResetToPrefabSize(); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::SetScale( const Vec3d &scale ) { // Ignore scale; CBaseObject::SetScale( scale ); }; ////////////////////////////////////////////////////////////////////////// void CBrushObject::SetSelected( bool bSelect ) { CBaseObject::SetSelected( bSelect ); if (m_engineNode) { if (bSelect) m_renderFlags |= ERF_SELECTED; else m_renderFlags &= ~ERF_SELECTED; m_engineNode->SetRndFlags( m_renderFlags ); } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::GetBoundBox( BBox &box ) { box = m_bbox; box.Transform( GetWorldTM() ); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::GetLocalBounds( BBox &box ) { box = m_bbox; } ////////////////////////////////////////////////////////////////////////// int CBrushObject::MouseCreateCallback( CViewport *view,EMouseEvent event,CPoint &point,int flags ) { if (event == eMouseMove || event == eMouseLDown) { Vec3 pos = view->MapViewToCP( point ); SetPos( pos ); if (event == eMouseLDown) return MOUSECREATE_OK; return MOUSECREATE_CONTINUE; } return CBaseObject::MouseCreateCallback( view,event,point,flags ); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::Display( DisplayContext &dc ) { if (dc.flags & DISPLAY_2D) { int flags = 0; if (IsSelected()) { dc.SetLineWidth(2); flags = 1; //dc.SetSelectedColor(); dc.SetColor( RGB(225,0,0) ); } else { flags = 0; dc.SetColor( GetColor() ); } dc.PushMatrix( GetWorldTM() ); dc.DrawWireBox( m_bbox.min,m_bbox.max ); dc.PopMatrix(); //if (m_brush) //dc.view->DrawBrush( dc,m_brush,GetWorldTM(),flags ); if (IsSelected()) dc.SetLineWidth(1); return; } /* if (m_brush != 0 && m_indoor != 0) { if (!(m_brush->m_flags&BRF_RE_VALID)) { m_indoor->UpdateObject( m_brush->GetIndoorGeom() ); m_indoor->RecalcBounds(); } Vec3 invCamSrc = dc.camera->GetPos(); invCamSrc = m_invertTM.TransformPoint(invCamSrc); m_brush->Render( dc.renderer,invCamSrc ) } */ if (IsSelected()) { dc.SetSelectedColor(); dc.PushMatrix( GetWorldTM() ); dc.DrawWireBox( m_bbox.min,m_bbox.max ); //dc.SetColor( RGB(255,255,0),0.1f ); // Yellow selected color. //dc.DrawSolidBox( m_bbox.min,m_bbox.max ); dc.PopMatrix(); } DrawDefault( dc ); } ////////////////////////////////////////////////////////////////////////// XmlNodeRef CBrushObject::Export( const CString &levelPath,XmlNodeRef &xmlNode ) { return 0; } ////////////////////////////////////////////////////////////////////////// void CBrushObject::Serialize( CObjectArchive &ar ) { XmlNodeRef xmlNode = ar.node; m_bIgnoreNodeUpdate = true; CBaseObject::Serialize( ar ); m_bIgnoreNodeUpdate = false; if (ar.bLoading) { ZeroStruct(m_materialGUID); if (ar.node->getAttr( "MaterialGUID",m_materialGUID )) { m_pMaterial = (CMaterial*)GetIEditor()->GetMaterialManager()->FindItem( m_materialGUID ); if (!m_pMaterial) { CErrorRecord err; err.error.Format( "Material %s for Brush %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 Brush %s not found,",GuidUtil::ToString(m_materialGUID),(const char*)GetName() ); } else { if (m_pMaterial->GetParent()) SetMaterial( m_pMaterial->GetParent() ); m_pMaterial->SetUsed(); } //if (m_engineNode) //UpdateEngineNode(); } else m_pMaterial = 0; /* if (ar.bUndo) { OnPrefabChange(0); } */ if (!m_prefabGeom) { CString mesh = mv_prefabName; if (!mesh.IsEmpty()) CreateBrushFromPrefab( mesh ); } if (!m_prefabGeom) { XmlNodeRef brushNode = xmlNode->findChild( "Brush" ); if (brushNode) { SBrush *brush = m_brush; if (!brush) brush = new SBrush; if (!m_prefabGeom) brush->Serialize( brushNode,ar.bLoading ); if (!m_brush) SetBrush( brush ); } } UpdateEngineNode(); } else { ar.node->setAttr( "RndFlags",m_renderFlags ); if (!GuidUtil::IsEmpty(m_materialGUID)) { ar.node->setAttr( "MaterialGUID",m_materialGUID ); } if (m_brush) { if (!m_prefabGeom) { XmlNodeRef brushNode = xmlNode->newChild( "Brush" ); m_brush->Serialize( brushNode,ar.bLoading ); } } } } ////////////////////////////////////////////////////////////////////////// bool CBrushObject::HitTest( HitContext &hc ) { Vec3 pnt; Vec3 raySrc = hc.raySrc; Vec3 rayDir = hc.rayDir; WorldToLocalRay( raySrc,rayDir ); if (m_bbox.IsIntersectRay( raySrc,rayDir,pnt )) { if (hc.b2DViewport) { // World space distance. hc.dist = GetDistance(hc.raySrc, GetWorldTM().TransformPointOLD(pnt)); return true; } IPhysicalEntity *physics = 0; if (m_engineNode) { physics = m_engineNode->GetPhysics(); if (physics) { if (physics->GetStatus( &pe_status_nparts() ) == 0) physics = 0; } } if (physics) { vectorr origin = hc.raySrc; vectorr dir = hc.rayDir*10000.0f; ray_hit hit; int col = GetIEditor()->GetSystem()->GetIPhysicalWorld()->RayTraceEntity( physics,origin,dir,&hit ); if (col <= 0) return false; // World space distance. hc.dist = hit.dist; return true; } else { // World space distance. hc.dist = GetDistance(hc.raySrc, GetWorldTM().TransformPointOLD(pnt)); return true; /* // No physics collision. SBrushFace *face = m_brush->Ray( raySrc,rayDir,&dist ); //SBrushFace *face = m_brush->Ray( hc.raySrc,hc.rayDir,&dist ); if (face) { hc.dist = dist; return true; } */ } } return false; } ////////////////////////////////////////////////////////////////////////// int CBrushObject::HitTestAxis( HitContext &hc ) { //@HACK Temporary hack. return 0; } ////////////////////////////////////////////////////////////////////////// void CBrushObject::SetBrush( SBrush *brush ) { if (m_brush == brush) return; /* if (m_brush) { m_indoor->RemoveObject( m_brush->GetIndoorGeom() ); } */ m_brush = brush; if (m_brush) { m_brush->SetMatrix( GetWorldTM() ); UpdateEngineNode(); m_bbox = m_brush->m_bounds; } // Add brush indoor geometry to indoors. //m_indoor->AddObject( m_brush->GetIndoorGeom() ); } //! Retrieve brush assigned to object. SBrush* CBrushObject::GetBrush() { return m_brush; } ////////////////////////////////////////////////////////////////////////// //! Invalidates cached transformation matrix. void CBrushObject::InvalidateTM() { CBaseObject::InvalidateTM(); if (m_brush) { m_brush->SetMatrix( GetWorldTM() ); } if (m_engineNode) UpdateEngineNode(true); m_invertTM = GetWorldTM(); m_invertTM.Invert44(); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::WorldToLocalRay( Vec3 &raySrc,Vec3 &rayDir ) { raySrc = m_invertTM.TransformPointOLD( raySrc ); rayDir = GetNormalized( m_invertTM.TransformVectorOLD( rayDir ) ); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::SelectBrushSide( const Vec3 &raySrc,const Vec3 &rayDir,bool shear ) { if (!m_brush) return; m_subSelection.Clear(); Vec3 rSrc = raySrc; Vec3 rDir = rayDir; Vec3 rTrg; WorldToLocalRay( rSrc,rDir ); rTrg = rSrc + rDir*32768.0f; m_brush->SelectSide( rSrc,rDir,shear,m_subSelection ); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::MoveSelectedPoints( const Vec3 &worldOffset ) { if (!m_brush) return; // Store undo. StoreUndo( "Stretch Brush" ); BBox prevBounds = m_brush->m_bounds; std::vector prevPoints; prevPoints.resize( m_subSelection.points.size() ); const Matrix44 &tm = GetWorldTM(); //CHANGED_BY_IVO Vec3 ofs = m_invertTM.TransformVectorOLD( worldOffset ); for (int i = 0; i < m_subSelection.points.size(); i++) { Vec3 pnt = *m_subSelection.points[i]; prevPoints[i] = pnt; // Remember previous point. pnt = m_invertTM.TransformPointOLD(pnt) + ofs; *m_subSelection.points[i] = tm.TransformPointOLD(pnt); } if (m_brush->BuildSolid(false)) { // Now optimize brush if it correctly created. // Now move brush. to make position center of the brush again. //Vec3 halfSize = (m_brush->m_bounds.max - m_brush->m_bounds.min)/2; Vec3 prevMid = (prevBounds.max + prevBounds.min)/2; Vec3 mid = (m_brush->m_bounds.max + m_brush->m_bounds.min)/2; Vec3 ofs = mid - prevMid; m_brush->Move( -ofs ); SetPos( GetPos() + GetWorldTM().TransformVectorOLD(ofs) ); m_bbox = m_brush->m_bounds; } else { // Restore previous brush. for (int i = 0; i < m_subSelection.points.size(); i++) { *m_subSelection.points[i] = prevPoints[i]; } m_brush->BuildSolid(false); CLogFile::WriteLine( "Invalid brush, operation aborted." ); } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::OnPrefabChange( IVariable *var ) { // Load new prefab model. CString objName = mv_prefabName; CreateBrushFromPrefab( objName ); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::CreateBrushFromPrefab( const char *meshFilname ) { if (m_prefabGeom) { if (m_prefabGeom->IsSameObject(meshFilname)) { return; } } GetIEditor()->GetErrorReport()->SetCurrentFile( meshFilname ); m_prefabGeom = CEdMesh::LoadMesh( meshFilname,false ); GetIEditor()->GetErrorReport()->SetCurrentFile( "" ); if (m_prefabGeom) { if (m_brush) { // If brush already created, assign it with geometry and update IEntityRender m_brush->SetPrefabGeom( m_prefabGeom ); m_brush->ResetToPrefabSize(); m_bbox = m_brush->m_bounds; } else { m_prefabGeom->GetBounds( m_bbox ); //[Timur] Do not create real brush now. // If brush not yet created, make a new brush. //SBrush *brush = new SBrush; //brush->SetPrefabGeom( m_prefabGeom ); //SetBrush( brush ); } UpdateEngineNode(); } else if (m_engineNode) { // Remove this object from engine node. m_engineNode->SetEntityStatObj( 0,0,0 ); } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::ResetToPrefabSize() { if (m_brush) { m_brush->ResetToPrefabSize(); m_bbox = m_brush->m_bounds; UpdateEngineNode(); } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::ReloadPrefabGeometry() { if (m_prefabGeom) { m_prefabGeom->ReloadGeometry(); } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::OnRenderVarChange( IVariable *var ) { UpdateEngineNode(); } ////////////////////////////////////////////////////////////////////////// IPhysicalEntity* CBrushObject::GetCollisionEntity() const { // Returns physical object of entity. if (m_engineNode) return m_engineNode->GetPhysics(); return 0; } ////////////////////////////////////////////////////////////////////////// bool CBrushObject::ConvertFromObject( CBaseObject *object ) { CBaseObject::ConvertFromObject( object ); if (object->IsKindOf(RUNTIME_CLASS(CEntity))) { CEntity *entity = (CEntity*)object; IEntity *pIEntity = entity->GetIEntity(); if (!pIEntity) return false; IStatObj *prefab = pIEntity->GetIStatObj(0); if (!prefab) return false; // Copy entity shadow parameters. mv_castShadows = entity->IsCastShadow(); mv_selfShadowing = entity->IsSelfShadowing(); mv_castShadowMaps = entity->IsCastShadowMaps(); mv_recvShadowMaps = entity->IsRecvShadowMaps(); mv_castLightmap = entity->IsCastLightmap(); mv_recvLightmap = entity->IsRecvLightmap(); mv_ratioLOD = entity->GetRatioLod(); mv_ratioViewDist = entity->GetRatioViewDist(); mv_prefabName = prefab->GetFileName(); } /* if (object->IsKindOf(RUNTIME_CLASS(CStaticObject))) { CStaticObject *pStatObject = (CStaticObject*)object; mv_hideable = pStatObject->IsHideable(); } */ return true; } ////////////////////////////////////////////////////////////////////////// void CBrushObject::UpdateEngineNode( bool bOnlyTransform ) { if (m_bIgnoreNodeUpdate) return; if (!m_engineNode) return; ////////////////////////////////////////////////////////////////////////// // Set brush render flags. ////////////////////////////////////////////////////////////////////////// m_renderFlags = 0; if (mv_outdoor) m_renderFlags |= ERF_OUTDOORONLY; if (mv_castShadows) m_renderFlags |= ERF_CASTSHADOWVOLUME; if (mv_selfShadowing) m_renderFlags |= ERF_SELFSHADOW; if (mv_castShadowMaps) m_renderFlags |= ERF_CASTSHADOWMAPS; if (mv_recvShadowMaps) m_renderFlags |= ERF_RECVSHADOWMAPS; if (mv_castLightmap) m_renderFlags |= ERF_CASTSHADOWINTOLIGHTMAP; if (mv_recvLightmap) m_renderFlags |= ERF_USELIGHTMAPS; if (mv_hideable) m_renderFlags |= ERF_HIDABLE; if (mv_excludeFromTriangulation) m_renderFlags |= ERF_EXCLUDE_FROM_TRIANGULATION; if (IsSelected()) m_renderFlags |= ERF_SELECTED; int flags = GetRenderFlags(); m_engineNode->SetRndFlags( m_renderFlags ); m_engineNode->SetViewDistRatio( mv_ratioViewDist ); m_engineNode->SetLodRatio( mv_ratioLOD ); if (m_prefabGeom) { Matrix44 tm = GetBrushMatrix(); m_engineNode->SetEntityStatObj( 0,m_prefabGeom->GetGeometry(),&tm ); } // Fast exit if only transformation needs to be changed. if (bOnlyTransform) return; if (m_pMaterial) { m_pMaterial->AssignToEntity( m_engineNode ); } else { // Reset all material settings for this node. m_engineNode->SetMaterial(0); } return; } ////////////////////////////////////////////////////////////////////////// Matrix44 CBrushObject::GetBrushMatrix() const { if (m_prefabGeom == NULL || m_brush == NULL) { return GetWorldTM(); } BBox box; m_prefabGeom->GetBounds( box ); Vec3 omin = box.min; Vec3 omax = box.max; if (omax.x - omin.x == 0) omax.x = omin.x + MIN_BOUNDS_SIZE; if (omax.y - omin.y == 0) omax.y = omin.y + MIN_BOUNDS_SIZE; if (omax.z - omin.z == 0) omax.z = omin.z + MIN_BOUNDS_SIZE; Matrix44 mov1; Matrix44 mov2; mov1.SetIdentity(); mov2.SetIdentity(); mov1.SetTranslationOLD( -omin ); mov2.SetTranslationOLD( m_brush->m_bounds.min ); Vec3 bb = (m_brush->m_bounds.max - m_brush->m_bounds.min); Vec3 ob = (omax - omin); Vec3 scl; scl.x = bb.x / ob.x; scl.y = bb.y / ob.y; scl.z = bb.z / ob.z; Matrix44 stm; stm.SetIdentity(); stm=Matrix33::CreateScale( Vec3d(scl.x,scl.y,scl.z) )*stm; Matrix44 tm = mov1 * stm * mov2; tm = tm * GetWorldTM(); return tm; } ////////////////////////////////////////////////////////////////////////// IStatObj* CBrushObject::GetPrefabGeom() const { if (!m_prefabGeom) return 0; return m_prefabGeom->GetGeometry(); } ////////////////////////////////////////////////////////////////////////// void CBrushObject::UpdateVisibility( bool visible ) { CBaseObject::UpdateVisibility( visible ); if (m_engineNode) { if (!visible) m_renderFlags |= ERF_HIDDEN; else m_renderFlags &= ~ERF_HIDDEN; m_engineNode->SetRndFlags( m_renderFlags ); } } ////////////////////////////////////////////////////////////////////////// void CBrushObject::SetMaterial( CMaterial *mtl ) { StoreUndo( "Assign Material" ); if (m_prefabGeom) m_prefabGeom->SetMaterial( mtl ); m_pMaterial = mtl; if (m_pMaterial) { m_pMaterial->SetUsed(); m_materialGUID = m_pMaterial->GetGUID(); } else { ZeroStruct(m_materialGUID); } if (m_engineNode) UpdateEngineNode(); } ////////////////////////////////////////////////////////////////////////// CMaterial* CBrushObject::GetMaterial() const { /* if (!m_pMaterial) { if (m_prefabGeom != NULL && m_prefabGeom->GetMaterial()) return m_prefabGeom->GetMaterial(); } */ return m_pMaterial; } ////////////////////////////////////////////////////////////////////////// void CBrushObject::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 Brush %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_prefabGeom) { CString file = mv_prefabName; CErrorRecord err; err.error.Format( "No Geometry for Brush %s",(const char*)file,(const char*)GetName() ); err.file = file; err.pObject = this; report->ReportError(err); } else if (m_prefabGeom->IsDefaultObject()) { CString file = mv_prefabName; CErrorRecord err; err.error.Format( "Geometry file %s for Brush %s Failed to Load",(const char*)file,(const char*)GetName() ); err.file = file; err.pObject = this; report->ReportError(err); } } ////////////////////////////////////////////////////////////////////////// bool CBrushObject::IsSimilarObject( CBaseObject *pObject ) { if (pObject->GetClassDesc() == GetClassDesc() && GetRuntimeClass() == pObject->GetRuntimeClass()) { CBrushObject *pBrush = (CBrushObject*)pObject; if ((CString)mv_prefabName == (CString)pBrush->mv_prefabName) return true; } return false; }