642 lines
16 KiB
C++
642 lines
16 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Engine Source File.
|
|
// Copyright (C), Crytek Studios, 2001.
|
|
// -------------------------------------------------------------------------
|
|
// File name: Building.cpp
|
|
// Version: v1.00
|
|
// Created: 10/10/2001 by Timur.
|
|
// Compilers: Visual C++ 6.0
|
|
// Description: StaticObject implementation.
|
|
// -------------------------------------------------------------------------
|
|
// History:
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "StdAfx.h"
|
|
#include "Building.h"
|
|
#include "Entity.h"
|
|
|
|
#include "..\BuildingPanel.h"
|
|
#include "..\Viewport.h"
|
|
|
|
#include <I3DEngine.h>
|
|
#include "IPhysics.h"
|
|
#include <I3DIndoorEngine.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CBase implementation.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IMPLEMENT_DYNCREATE(CBuilding,CGroup)
|
|
|
|
int CBuilding::m_rollupId;
|
|
CBuildingPanel* CBuilding::m_panel = 0;
|
|
|
|
bool CBuilding::m_portals = true;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CBuilding::CBuilding()
|
|
{
|
|
// Initial area size.
|
|
m_bbox.min=Vec3d(-1,-1,-1);
|
|
m_bbox.max=Vec3d(1,1,1);
|
|
|
|
m_buildingId = -1;
|
|
m_bAlwaysDrawBox = false;
|
|
m_wireFrame = false;
|
|
|
|
// Building is initially open.
|
|
Open();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::Done()
|
|
{
|
|
if (ValidBuildingId(m_buildingId))
|
|
{
|
|
// Delete indoor building.
|
|
GetBuildMgr()->DeleteBuilding( m_buildingId );
|
|
m_buildingId = 0;
|
|
}
|
|
UnbindAllHelpers();
|
|
m_helpers.clear();
|
|
|
|
CGroup::Done();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::ReleaseBuilding()
|
|
{
|
|
if (ValidBuildingId(m_buildingId))
|
|
{
|
|
// Delete indoor building.
|
|
GetBuildMgr()->DeleteBuilding( m_buildingId );
|
|
}
|
|
m_buildingId = -1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CBuilding::Init( IEditor *ie,CBaseObject *prev,const CString &file )
|
|
{
|
|
m_ie = ie;
|
|
|
|
SetColor( RGB(255,255,255) );
|
|
|
|
CGroup::Init( ie,prev,file );
|
|
if (prev)
|
|
{
|
|
LoadBuilding( ((CBuilding*)prev)->GetObjectName() );
|
|
}
|
|
else if (!file.IsEmpty())
|
|
{
|
|
LoadBuilding( file );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::SetPos( const Vec3d &pos )
|
|
{
|
|
CGroup::SetPos(pos);
|
|
if (ValidBuildingId(m_buildingId))
|
|
{
|
|
// Move indoor building.
|
|
GetBuildMgr()->SetBuildingPos( GetWorldPos(),m_buildingId );
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::SetAngles( const Vec3d &angles )
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::SetScale( const Vec3d &scale )
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
void CBuilding::BeginEditParams( IEditor *ie,int flags )
|
|
{
|
|
m_ie = ie;
|
|
CGroup::BeginEditParams( ie,flags );
|
|
|
|
if (!m_panel)
|
|
{
|
|
m_panel = new CBuildingPanel(0);
|
|
m_panel->Create( CBuildingPanel::IDD,AfxGetMainWnd() );
|
|
m_rollupId = ie->AddRollUpPage( ROLLUP_OBJECTS,"Building Parameters",m_panel );
|
|
}
|
|
|
|
m_panel->SetBuilding( this );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::EndEditParams( IEditor *ie )
|
|
{
|
|
if (m_rollupId != 0)
|
|
ie->RemoveRollUpPage( ROLLUP_OBJECTS,m_rollupId );
|
|
m_rollupId = 0;
|
|
m_panel = 0;
|
|
|
|
CGroup::EndEditParams( ie );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::GetBoundBox( BBox &box )
|
|
{
|
|
CGroup::GetBoundBox( box );
|
|
/*
|
|
box = m_box;
|
|
box.min += GetPos();
|
|
box.max += GetPos();
|
|
*/
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CBuilding::HitTest( HitContext &hc )
|
|
{
|
|
bool bHit = CGroup::HitTestChilds( hc );
|
|
if (bHit)
|
|
return true;
|
|
|
|
Vec3 p;
|
|
|
|
float tr = hc.distanceTollerance/2;
|
|
BBox box;
|
|
box.min = GetWorldPos() + m_bbox.min - Vec3(tr,tr,tr);
|
|
box.max = GetWorldPos() + m_bbox.max + Vec3(tr,tr,tr);
|
|
if (box.IsIntersectRay(hc.raySrc,hc.rayDir,p ))
|
|
{
|
|
//hc.dist = Vec3(hc.raySrc - p).Length();
|
|
|
|
if (ValidBuildingId(m_buildingId))
|
|
{
|
|
//! If camera source is inside building dont select it.
|
|
if (GetBuildMgr()->CheckInside( hc.raySrc,m_buildingId))
|
|
return false;
|
|
|
|
//Vec3d src = hc.raySrc;
|
|
//Vec3d trg = hc.raySrc + hc.rayDir*10000.0f;
|
|
// IndoorRayIntInfo hit;
|
|
//ASSERT(0);
|
|
//return (false);
|
|
//please use the physics code for ray-inters.
|
|
//if (!GetBuildMgr()->RayIntersection( src,trg,hit,m_buildingId ))
|
|
// return false;
|
|
|
|
vectorf vPos(hc.raySrc);
|
|
vectorf vDir(hc.rayDir);
|
|
int objTypes = ent_static;
|
|
int flags = rwi_stop_at_pierceable|rwi_ignore_terrain_holes;
|
|
ray_hit hit;
|
|
int col = GetIEditor()->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection( vPos,vDir,objTypes,flags,&hit,1 );
|
|
if (col > 0)
|
|
{
|
|
IStatObj *pStatObj = (IStatObj*)hit.pCollider->GetForeignData();
|
|
if (GetBuildMgr()->GetBuildingIdFromObj( pStatObj ) == m_buildingId)
|
|
{
|
|
hc.dist = hit.dist;
|
|
return true;
|
|
}
|
|
}
|
|
//hc.geometryHit = true;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::Display( DisplayContext &dc )
|
|
{
|
|
CGroup::Display( dc );
|
|
|
|
/*
|
|
// Create buildling if not done already.
|
|
DrawDefault(dc,GetColor());
|
|
|
|
if (IsSelected())
|
|
{
|
|
float t = m_ie->GetSystem()->GetITimer()->GetCurrTime();
|
|
float r1 = (float)fabs(sin(t*8.0f));
|
|
// float r2 = cos(t*3);
|
|
dc.renderer->SetMaterialColor( 1,0,r1,0.5f );
|
|
//dc.renderer->DrawBall( GetPos(),1.3f );
|
|
|
|
dc.renderer->PushMatrix();
|
|
dc.renderer->TranslateMatrix( GetPos() );
|
|
dc.renderer->RotateMatrix( GetAngles() );
|
|
dc.renderer->Draw3dBBox( m_bbox.min,m_bbox.max );
|
|
dc.renderer->PopMatrix();
|
|
}
|
|
*/
|
|
|
|
Vec3 origin = GetWorldPos();
|
|
// Display helpers.
|
|
dc.SetColor( 0,1,1,0.3f );
|
|
for (int i = 0; i < m_helpers.size(); i++)
|
|
{
|
|
if (m_helpers[i].object == 0)
|
|
{
|
|
dc.renderer->DrawBall( origin+m_helpers[i].pos,0.3f );
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::OnEvent( ObjectEvent event )
|
|
{
|
|
CGroup::OnEvent(event);
|
|
|
|
switch (event)
|
|
{
|
|
case EVENT_INGAME:
|
|
GetBuildMgr()->EnableVisibility( true );
|
|
break;
|
|
|
|
case EVENT_OUTOFGAME:
|
|
GetBuildMgr()->EnableVisibility( m_portals );
|
|
break;
|
|
|
|
case EVENT_RELOAD_GEOM:
|
|
LoadBuilding( m_objectName,true );
|
|
break;
|
|
|
|
case EVENT_UNLOAD_GEOM:
|
|
ReleaseBuilding();
|
|
break;
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::Serialize( CObjectArchive &ar )
|
|
{
|
|
CGroup::Serialize( ar );
|
|
XmlNodeRef xmlNode = ar.node;
|
|
if (ar.bLoading)
|
|
{
|
|
bool wireFrame = false;
|
|
xmlNode->getAttr( "Wireframe",wireFrame );
|
|
//xmlNode->getAttr( "Portals",portals );
|
|
SetWireframe( wireFrame );
|
|
|
|
for (int i = 0; i < xmlNode->getChildCount(); i++)
|
|
{
|
|
XmlNodeRef cgf = xmlNode->getChild(i);
|
|
CString name;
|
|
if (cgf->isTag("Cgf") && cgf->getAttr("Name",name))
|
|
{
|
|
LoadBuilding( name );
|
|
// Only one object.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Load information about objects attached to helpers.
|
|
SerializeHelpers( ar );
|
|
}
|
|
else
|
|
{
|
|
// Saving.
|
|
xmlNode->setAttr( "Wireframe",m_wireFrame );
|
|
//xmlNode->setAttr( "Portals",m_portals );
|
|
// Only one object.
|
|
XmlNodeRef cgf = xmlNode->newChild("Cgf");
|
|
cgf->setAttr( "Name",m_objectName );
|
|
|
|
// Serialize helpers that have attached objects.
|
|
SerializeHelpers( ar );
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::SerializeHelpers( CObjectArchive &ar )
|
|
{
|
|
XmlNodeRef xmlNode = ar.node;
|
|
if (ar.bLoading)
|
|
{
|
|
// Load information about objects attached to helpers.
|
|
XmlNodeRef helpersNode = xmlNode->findChild( "Helperes" );
|
|
if (helpersNode)
|
|
{
|
|
for (int i = 0; i < helpersNode->getChildCount(); i++)
|
|
{
|
|
XmlNodeRef helperNode = helpersNode->getChild(i);
|
|
CString helperName;
|
|
GUID objectId = GUID_NULL;
|
|
helperNode->getAttr( "Id",objectId );
|
|
helperNode->getAttr( "Name",helperName );
|
|
for (int j = 0; j < m_helpers.size(); j++)
|
|
{
|
|
if (stricmp(m_helpers[j].name,helperName)==0)
|
|
{
|
|
ar.SetResolveCallback( objectId,functor(*this,ResolveHelper),j );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XmlNodeRef helpersNode = xmlNode->newChild( "Helperes" );
|
|
|
|
// Serialize helpers that have attached objects.
|
|
for (int i = 0; i < m_helpers.size(); i++)
|
|
{
|
|
ObjectHelper &helper = m_helpers[i];
|
|
if (helper.object != 0)
|
|
{
|
|
XmlNodeRef helperNode = helpersNode->newChild( "Helper" );
|
|
helperNode->setAttr( "Id",helper.object->GetId() );
|
|
helperNode->setAttr( "Name",helper.name );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::ResolveHelper( CBaseObject *object,uint helperIndex )
|
|
{
|
|
if (helperIndex >= 0 && helperIndex < m_helpers.size())
|
|
{
|
|
BindToHelper( helperIndex,object );
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
XmlNodeRef CBuilding::Export( const CString &levelPath,XmlNodeRef &xmlNode )
|
|
{
|
|
XmlNodeRef node = CGroup::Export( levelPath,xmlNode );
|
|
node->setTag( "Building" );
|
|
node->setAttr( "Geometry",m_objectName );
|
|
/*
|
|
//for (int i = 0; i < m_objectNames.size(); i++)
|
|
{
|
|
XmlNodeRef cgf = node->newChild("Cgf");
|
|
cgf->setAttr( "Name",m_objectName );
|
|
}
|
|
*/
|
|
return node;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::LoadBuilding( const CString &object,bool bForceReload )
|
|
{
|
|
if (stricmp(object,m_objectName)==0 && ValidBuildingId(m_buildingId) && !bForceReload)
|
|
{
|
|
return;
|
|
}
|
|
m_objectName = object;
|
|
|
|
if (!IsCreateGameObjects())
|
|
return;
|
|
|
|
ReleaseBuilding();
|
|
m_sectorHidden.clear();
|
|
|
|
if (m_objectName.IsEmpty())
|
|
return;
|
|
|
|
IndoorBaseInterface IndInterface;
|
|
ISystem *pISystem = GetIEditor()->GetSystem();
|
|
IndInterface.m_pSystem = pISystem;
|
|
IndInterface.m_p3dEngine = pISystem->GetI3DEngine(); //(I3DEngine *)pISystem->GetIProcess();
|
|
IndInterface.m_pLog = pISystem->GetILog();
|
|
IndInterface.m_pRenderer = pISystem->GetIRenderer();
|
|
IndInterface.m_pConsole = pISystem->GetIConsole();
|
|
|
|
IIndoorBase *buildManager = GetBuildMgr();
|
|
|
|
if (ValidBuildingId(m_buildingId))
|
|
buildManager->DeleteBuilding( m_buildingId );
|
|
|
|
m_buildingId = buildManager->CreateBuilding( IndInterface );
|
|
if (!ValidBuildingId(m_buildingId))
|
|
return;
|
|
|
|
int numSectors = buildManager->AddBuilding( m_objectName,m_buildingId );
|
|
|
|
buildManager->SetBuildingPos( GetWorldPos(),m_buildingId );
|
|
|
|
m_sectorHidden.resize(numSectors);
|
|
|
|
// Save info about objects to helpers attachment.
|
|
XmlNodeRef helpers = new CXmlNode( "Helpers" );
|
|
CObjectArchive saveAr( GetObjectManager(),helpers,false );
|
|
SerializeHelpers( saveAr );
|
|
UnbindAllHelpers();
|
|
m_helpers.clear();
|
|
|
|
const char *helperName = 0;
|
|
int i = 0;
|
|
do {
|
|
Vec3 pos;
|
|
Matrix HelperMat;
|
|
helperName = buildManager->GetHelper( i,m_buildingId,pos,&HelperMat );
|
|
if (helperName)
|
|
{
|
|
ObjectHelper eh;
|
|
eh.object = 0;
|
|
eh.pos = pos;
|
|
// eh.angles = rot.GetEulerAngles();
|
|
|
|
assert(0); // not tested !!!
|
|
AffineParts affineParts;
|
|
affineParts.SpectralDecompose(HelperMat);
|
|
eh.angles = RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(affineParts.rot)));
|
|
|
|
eh.name = CString(helperName).SpanExcluding( "/" );
|
|
if (strchr(helperName,'/') != 0)
|
|
{
|
|
eh.className = CString(helperName).Mid( eh.name.GetLength()+1 );
|
|
}
|
|
m_helpers.push_back(eh);
|
|
}
|
|
i++;
|
|
} while (helperName != NULL);
|
|
|
|
// Load info about objects to helpers attachment.
|
|
CObjectArchive loadAr( GetObjectManager(),helpers,true );
|
|
SerializeHelpers( loadAr );
|
|
|
|
GetBuildMgr()->EnableVisibility( m_portals );
|
|
|
|
CalcBoundBox();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::CalcBoundBox()
|
|
{
|
|
// Bounding box of building is an intersection of all objects bounding boxes
|
|
m_bbox.Reset();
|
|
|
|
if (ValidBuildingId(m_buildingId))
|
|
{
|
|
GetBuildMgr()->GetBBox( m_bbox.min,m_bbox.max,m_buildingId );
|
|
}
|
|
else
|
|
{
|
|
m_bbox.min=Vec3d(-1,-1,-1);
|
|
m_bbox.max=Vec3d(1,1,1);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::SpawnEntities()
|
|
{
|
|
CEntityClassDesc entClassDesc;
|
|
|
|
// Spawn entities using Class Name given in helper.
|
|
for (int i = 0; i < m_helpers.size(); i++)
|
|
{
|
|
ObjectHelper &eh = m_helpers[i];
|
|
if (eh.object == 0)
|
|
{
|
|
//
|
|
CEntity *entity = (CEntity*)GetIEditor()->NewObject( entClassDesc.ClassName(),eh.className );
|
|
if (!entity)
|
|
{
|
|
CLogFile::FormatLine( "Building: Entity Spawn failed, Unknown class: %s",(const char*)eh.className );
|
|
continue;
|
|
}
|
|
entity->SetPos( GetWorldPos()+eh.pos );
|
|
entity->SetAngles( eh.angles );
|
|
eh.object = entity;
|
|
AttachChild( entity );
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::HideSector( int index,bool bHide )
|
|
{
|
|
if (ValidBuildingId(m_buildingId))
|
|
{
|
|
if (index >= 0 && index < GetNumSectors())
|
|
{
|
|
m_sectorHidden[index] = bHide;
|
|
GetBuildMgr()->HideSector( bHide,m_buildingId,index );
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CBuilding::IsSectorHidden( int index ) const
|
|
{
|
|
if (index >= 0 && index < GetNumSectors())
|
|
return m_sectorHidden[index];
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::SetWireframe( bool bEnable )
|
|
{
|
|
StoreUndo( "Set Wireframe" );
|
|
m_wireFrame = bEnable;
|
|
|
|
GetBuildMgr()->EnableWireframe( bEnable );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CBuilding::IsWireframe() const
|
|
{
|
|
return m_wireFrame;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::BindToHelper( int helperIndex,CBaseObject *obj )
|
|
{
|
|
assert( helperIndex >= 0 && helperIndex < m_helpers.size() );
|
|
|
|
if (obj->IsChildOf(this) || obj == m_helpers[helperIndex].object)
|
|
return;
|
|
|
|
StoreUndo( "Bind Helper" );
|
|
|
|
obj->AddEventListener( functor(*this,OnHelperEvent) );
|
|
m_helpers[helperIndex].object = obj;
|
|
obj->SetPos( GetWorldPos() + m_helpers[helperIndex].pos );
|
|
//obj->SetAngles( m_helpers[helperIndex].angles );
|
|
|
|
AttachChild( obj );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::UnbindHelper( int helperIndex )
|
|
{
|
|
assert( helperIndex >= 0 && helperIndex < m_helpers.size() );
|
|
|
|
if (m_helpers[helperIndex].object)
|
|
{
|
|
StoreUndo( "Unbind Helper" );
|
|
|
|
m_helpers[helperIndex].object->RemoveEventListener( functor(*this,&CBuilding::OnHelperEvent) );
|
|
|
|
RemoveChild( m_helpers[helperIndex].object );
|
|
m_helpers[helperIndex].object = 0;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::UnbindAllHelpers()
|
|
{
|
|
for (int i = 0; i < m_helpers.size(); i++)
|
|
{
|
|
if (m_helpers[i].object)
|
|
{
|
|
UnbindHelper(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::OnHelperEvent( CBaseObject *object,int event )
|
|
{
|
|
if (event == CBaseObject::ON_DELETE)
|
|
{
|
|
// Find helper to unbind.
|
|
for (int i = 0; i < m_helpers.size(); i++)
|
|
{
|
|
if (m_helpers[i].object == object)
|
|
{
|
|
UnbindHelper(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IIndoorBase* CBuilding::GetBuildMgr()
|
|
{
|
|
return GetIEditor()->Get3DEngine()->GetBuildingManager();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::UpdateVisibility( bool visible )
|
|
{
|
|
CGroup::UpdateVisibility(visible);
|
|
if (ValidBuildingId(m_buildingId))
|
|
GetBuildMgr()->HideBuilding( !visible,m_buildingId );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::InvalidateTM()
|
|
{
|
|
CGroup::InvalidateTM();
|
|
// Move window to new world position.
|
|
if (ValidBuildingId(m_buildingId))
|
|
{
|
|
// Move indoor building.
|
|
GetBuildMgr()->SetBuildingPos( GetWorldPos(),m_buildingId );
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBuilding::SetPortals( bool enable )
|
|
{
|
|
m_portals = enable;
|
|
if (ValidBuildingId(m_buildingId))
|
|
GetBuildMgr()->EnableVisibility(enable);
|
|
} |