//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2001. // ------------------------------------------------------------------------- // File name: ShapeObject.cpp // Version: v1.00 // Created: 10/10/2001 by Timur. // Compilers: Visual C++ 6.0 // Description: CShapeObject implementation. // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "ShapeObject.h" #include "..\ShapePanel.h" #include "..\Viewport.h" #include "Util\Triangulate.h" #include #include #include #include #include #include "IEntitySystem.h" ////////////////////////////////////////////////////////////////////////// // CBase implementation. ////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNCREATE(CShapeObject,CBaseObject) IMPLEMENT_DYNCREATE(CAIForbiddenAreaObject,CShapeObject) IMPLEMENT_DYNCREATE(CAIPathObject,CShapeObject) IMPLEMENT_DYNCREATE(CAINavigationModifierObject,CShapeObject) IMPLEMENT_DYNCREATE(CAIOcclusionPlaneObject,CShapeObject) #define RAY_DISTANCE 100000.0f ////////////////////////////////////////////////////////////////////////// int CShapeObject::m_rollupId = 0; CShapePanel* CShapeObject::m_panel = 0; ////////////////////////////////////////////////////////////////////////// CShapeObject::CShapeObject() { m_bForce2D = false; mv_closed = false; mv_areaId = 0; mv_groupId = 0; mv_width = 0; mv_height = 0; mv_displayFilled = false; m_bbox.min = m_bbox.max = Vec3(0,0,0); m_selectedPoint = -1; m_lowestHeight = 0; m_IArea = 0; m_bIgnoreGameUpdate = true; m_bAreaModified = true; m_bDisplayFilledWhenSelected = false; AddVariable( mv_width,"Width",functor(*this,&CShapeObject::OnShapeChange) ); AddVariable( mv_height,"Height",functor(*this,&CShapeObject::OnShapeChange) ); AddVariable( mv_areaId,"AreaId",functor(*this,&CShapeObject::OnShapeChange) ); AddVariable( mv_groupId,"GroupId",functor(*this,&CShapeObject::OnShapeChange) ); AddVariable( mv_closed,"Closed",functor(*this,&CShapeObject::OnShapeChange) ); AddVariable( mv_displayFilled,"DisplayFilled" ); SetColor( Vec2Rgb(Vec3(0,0.8f,1)) ); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::Done() { m_entities.Clear(); m_points.clear(); UpdateGameArea(true); CBaseObject::Done(); } ////////////////////////////////////////////////////////////////////////// bool CShapeObject::Init( IEditor *ie,CBaseObject *prev,const CString &file ) { m_ie = ie; m_bIgnoreGameUpdate = true; bool res = CBaseObject::Init( ie,prev,file ); if (prev) { m_points = ((CShapeObject*)prev)->m_points; m_bIgnoreGameUpdate = false; CalcBBox(); } m_bIgnoreGameUpdate = false; return res; } ////////////////////////////////////////////////////////////////////////// bool CShapeObject::CreateGameObject() { return true; }; ////////////////////////////////////////////////////////////////////////// void CShapeObject::SetName( const CString &name ) { CBaseObject::SetName( name ); m_bAreaModified = true; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::InvalidateTM() { CBaseObject::InvalidateTM(); m_bAreaModified = true; // CalcBBox(); if (!IsOnlyUpdateOnUnselect() && !m_bIgnoreGameUpdate) UpdateGameArea(); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::GetBoundBox( BBox &box ) { box = m_bbox; box.Transform( GetWorldTM() ); float s = 1.0f; box.min -= Vec3(s,s,s); box.max += Vec3(s,s,s); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::GetLocalBounds( BBox &box ) { box = m_bbox; } ////////////////////////////////////////////////////////////////////////// bool CShapeObject::HitTest( HitContext &hc ) { // First check if ray intersect our bounding box. float tr = hc.distanceTollerance/2 + SHAPE_CLOSE_DISTANCE; // Find intersection of line with zero Z plane. float minDist = FLT_MAX; Vec3 intPnt; //GetNearestEdge( hc.raySrc,hc.rayDir,p1,p2,minDist,intPnt ); bool bWasIntersection = false; Vec3 ip; Vec3 rayLineP1 = hc.raySrc; Vec3 rayLineP2 = hc.raySrc + hc.rayDir*RAY_DISTANCE; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < m_points.size(); i++) { int j = (i < m_points.size()-1) ? i+1 : 0; if (!mv_closed && j == 0 && i != 0) continue; Vec3 pi = wtm.TransformPointOLD(m_points[i]); Vec3 pj = wtm.TransformPointOLD(m_points[j]); float d = 0; if (RayToLineDistance( rayLineP1,rayLineP2,pi,pj,d,ip )) { if (d < minDist) { bWasIntersection = true; minDist = d; intPnt = ip; } } if (mv_height > 0) { if (RayToLineDistance( rayLineP1,rayLineP2,pi+Vec3(0,0,mv_height),pj+Vec3(0,0,mv_height),d,intPnt )) { if (d < minDist) { bWasIntersection = true; minDist = d; intPnt = ip; } } if (RayToLineDistance( rayLineP1,rayLineP2,pi,pi+Vec3(0,0,mv_height),d,intPnt )) { if (d < minDist) { bWasIntersection = true; minDist = d; intPnt = ip; } } } } float fShapeCloseDistance = SHAPE_CLOSE_DISTANCE*hc.view->GetScreenScaleFactor(intPnt) * 0.01f; if (bWasIntersection && minDist < fShapeCloseDistance+hc.distanceTollerance) { hc.dist = GetDistance(hc.raySrc,intPnt); return true; } return false; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::BeginEditParams( IEditor *ie,int flags ) { m_ie = ie; CBaseObject::BeginEditParams( ie,flags ); if (!m_panel) { m_panel = new CShapePanel; m_rollupId = ie->AddRollUpPage( ROLLUP_OBJECTS,"Shape Parameters",m_panel ); } if (m_panel) m_panel->SetShape( this ); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::EndEditParams( IEditor *ie ) { if (m_rollupId != 0) { ie->RemoveRollUpPage( ROLLUP_OBJECTS,m_rollupId ); CalcBBox(); } m_rollupId = 0; m_panel = 0; CBaseObject::EndEditParams( ie ); } ////////////////////////////////////////////////////////////////////////// int CShapeObject::MouseCreateCallback( CViewport *view,EMouseEvent event,CPoint &point,int flags ) { if (event == eMouseMove || event == eMouseLDown || event == eMouseLDblClick) { Vec3 pos = view->MapViewToCP(point); bool firstTime = false; if (m_points.size() < 2) { SetPos( pos ); } pos.z += SHAPE_Z_OFFSET; if (m_points.size() == 0) { InsertPoint( -1,Vec3(0,0,0) ); firstTime = true; } else { SetPoint( m_points.size()-1,pos - GetWorldPos() ); } if (event == eMouseLDblClick) { if (m_points.size() > 3) { m_points.pop_back(); // Remove last uneeded point. EndCreation(); return MOUSECREATE_OK; } else return MOUSECREATE_ABORT; } if (event == eMouseLDown) { Vec3 vlen = Vec3(pos.x,pos.y,0) - Vec3(GetWorldPos().x,GetWorldPos().y,0); if (m_points.size() > 2 && vlen.Length() < SHAPE_CLOSE_DISTANCE) { EndCreation(); return MOUSECREATE_OK; } if (GetPointCount() >= GetMaxPoints()) { //m_points.pop_back(); // Remove last uneeded point. EndCreation(); return MOUSECREATE_OK; } InsertPoint( -1,pos-GetWorldPos() ); } return MOUSECREATE_CONTINUE; } return CBaseObject::MouseCreateCallback( view,event,point,flags ); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::EndCreation() { SetClosed(true); if (m_panel) m_panel->SetShape(this); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::Display( DisplayContext &dc ) { //dc.renderer->EnableDepthTest(false); const Matrix44 &wtm = GetWorldTM(); COLORREF col; float fPointSize = 0.5f; bool bPointSelected = false; if (m_selectedPoint >= 0 && m_selectedPoint < m_points.size()) { bPointSelected = true; } if (m_points.size() > 1) { if ((IsSelected() || IsHighlighted()) && !bPointSelected) { col = dc.GetSelectedColor(); dc.SetColor( col ); } else { if (IsFrozen()) dc.SetFreezeColor(); else dc.SetColor( GetColor() ); col = GetColor(); } for (int i = 0; i < m_points.size(); i++) { int j = (i < m_points.size()-1) ? i+1 : 0; Vec3 p0 = wtm.TransformPointOLD(m_points[i]); //dc.renderer->DrawBall( p0,0.8f ); float fScale = fPointSize*dc.view->GetScreenScaleFactor(p0) * 0.01f; Vec3 sz(fScale,fScale,fScale); dc.DrawWireBox( p0-sz,p0+sz ); if (!mv_closed && j == 0 && i != 0) continue; Vec3 p1 = wtm.TransformPointOLD(m_points[j]); dc.DrawLine( p0,p1 ); //DrawTerrainLine( dc,pos+m_points[i],pos+m_points[j] ); if (mv_height != 0) { BBox box = m_bbox; box.Transform( GetWorldTM() ); m_lowestHeight = box.min.z; // Draw second capping shape from above. float z = m_lowestHeight + mv_height; dc.DrawLine( p0,Vec3(p0.x,p0.y,z) ); dc.DrawLine( Vec3(p0.x,p0.y,z),Vec3(p1.x,p1.y,z) ); } } // Draw selected point. if (bPointSelected) { dc.SetSelectedColor( 0.5f ); Vec3 selPos = wtm.TransformPointOLD(m_points[m_selectedPoint]); //dc.renderer->DrawBall( selPos,1.0f ); float fScale = fPointSize*dc.view->GetScreenScaleFactor(selPos) * 0.01f; Vec3 sz(fScale,fScale,fScale); dc.DrawWireBox( selPos-sz,selPos+sz ); DrawAxis( dc,m_points[m_selectedPoint],0.15f ); } } if (!m_entities.IsEmpty()) { Vec3 vcol = Rgb2Vec(col); int num = m_entities.GetCount(); for (int i = 0; i < num; i++) { CBaseObject *obj = m_entities.Get(i); if (!obj) continue; int p1,p2; float dist; Vec3 intPnt; GetNearestEdge( obj->GetWorldPos(),p1,p2,dist,intPnt ); dc.DrawLine( intPnt,obj->GetWorldPos(),CFColor(vcol.x,vcol.y,vcol.z,0.7f),CFColor(1,1,1,0.7f) ); } } if (mv_closed && !IsFrozen()) { if (mv_displayFilled || (IsSelected() && m_bDisplayFilledWhenSelected) || IsHighlighted()) { if (IsHighlighted()) dc.SetColor( GetColor(),0.1f ); else dc.SetColor( GetColor(),0.3f ); static std::vector tris; tris.resize(0); tris.reserve( m_points.size()*3 ); if (CTriangulate::Process( m_points,tris )) { for (int i = 0; i < tris.size(); i += 3) { dc.DrawTri( wtm.TransformPointOLD(tris[i]),wtm.TransformPointOLD(tris[i+1]),wtm.TransformPointOLD(tris[i+2]) ); } } } } //dc.renderer->EnableDepthTest(true); DrawDefault(dc,GetColor()); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::DrawTerrainLine( DisplayContext &dc,const Vec3 &p1,const Vec3 &p2 ) { float len = (p2-p1).Length(); int steps = len/2; if (steps <= 1) { dc.DrawLine( p1,p2 ); return; } Vec3 pos1 = p1; Vec3 pos2 = p1; for (int i = 0; i < steps-1; i++) { pos2 = p1 + (1.0f/i)*(p2-p1); pos2.z = dc.engine->GetTerrainElevation(pos2.x,pos2.y); dc.SetColor( i*2,0,0,1 ); dc.DrawLine( pos1,pos2 ); pos1 = pos2; } //dc.DrawLine( pos2,p2 ); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::Serialize( CObjectArchive &ar ) { m_bIgnoreGameUpdate = true; CBaseObject::Serialize( ar ); m_bIgnoreGameUpdate = false; XmlNodeRef xmlNode = ar.node; if (ar.bLoading) { m_bAreaModified = true; m_bIgnoreGameUpdate = true; m_entities.Clear(); GUID entityId; if (xmlNode->getAttr( "EntityId",entityId )) { // For Backward compatability. //m_entities.push_back(entityId); ar.SetResolveCallback( this,entityId,functor(m_entities,&CSafeObjectsArray::Add) ); } // Load Entities. m_points.clear(); XmlNodeRef points = xmlNode->findChild( "Points" ); if (points) { for (int i = 0; i < points->getChildCount(); i++) { XmlNodeRef pnt = points->getChild(i); Vec3 pos; pnt->getAttr( "Pos",pos ); m_points.push_back(pos); } } XmlNodeRef entities = xmlNode->findChild( "Entities" ); if (entities) { for (int i = 0; i < entities->getChildCount(); i++) { XmlNodeRef ent = entities->getChild(i); GUID entityId; if (ent->getAttr( "Id",entityId )) { //m_entities.push_back(id); ar.SetResolveCallback( this,entityId,functor(m_entities,&CSafeObjectsArray::Add) ); } } } if (ar.bUndo) { // Update game area only in undo mode. m_bIgnoreGameUpdate = false; } CalcBBox(); UpdateGameArea(); // Update UI. if (m_panel && m_panel->GetShape() == this) m_panel->SetShape(this); } else { // Saving. // Save Points. if (!m_points.empty()) { XmlNodeRef points = xmlNode->newChild( "Points" ); for (int i = 0; i < m_points.size(); i++) { XmlNodeRef pnt = points->newChild( "Point" ); pnt->setAttr( "Pos",m_points[i] ); } } // Save Entities. if (!m_entities.IsEmpty()) { XmlNodeRef nodes = xmlNode->newChild( "Entities" ); for (int i = 0; i < m_entities.GetCount(); i++) { XmlNodeRef entNode = nodes->newChild( "Entity" ); if (m_entities.Get(i)) entNode->setAttr( "Id",m_entities.Get(i)->GetId() ); } } } m_bIgnoreGameUpdate = false; } ////////////////////////////////////////////////////////////////////////// XmlNodeRef CShapeObject::Export( const CString &levelPath,XmlNodeRef &xmlNode ) { XmlNodeRef objNode = CBaseObject::Export( levelPath,xmlNode ); // Export position in world space. Matrix44 wtmNoScale = GetWorldTM(); wtmNoScale.NoScale(); //QUAT_CHANGED_BY_IVO //Quat q(wtmNoScale); //Quat q = CovertMatToQuat( GetTransposed44(wtmNoScale) ); Quat q = Quat( GetTransposed44(wtmNoScale) ); Vec3 worldPos = wtmNoScale.GetTranslationOLD(); Vec3 worldAngles = Ang3::GetAnglesXYZ(Matrix33(q)) * 180.0f/gf_PI; //if (worldPos != Vec3(0,0,0)) if (!IsEquivalent(worldPos,Vec3(0,0,0))) objNode->setAttr( "Pos",worldPos ); //if (worldAngles != Vec3(0,0,0)) if (!IsEquivalent(worldAngles,Vec3(0,0,0),VEC_EPSILON)) objNode->setAttr( "Angles",worldAngles ); const Matrix44 &wtm = GetWorldTM(); // Export Points if (!m_points.empty()) { XmlNodeRef points = objNode->newChild( "Points" ); for (int i = 0; i < m_points.size(); i++) { XmlNodeRef pnt = points->newChild( "Point" ); pnt->setAttr( "Pos",wtm.TransformPointOLD(m_points[i]) ); } } // Export Entities. if (!m_entities.IsEmpty()) { XmlNodeRef nodes = objNode->newChild( "Entities" ); for (int i = 0; i < m_entities.GetCount(); i++) { XmlNodeRef entNode = nodes->newChild( "Entity" ); CBaseObject *obj = m_entities.Get(i); CString name; if (obj) name = obj->GetName(); entNode->setAttr( "Name",name ); } } return objNode; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::CalcBBox() { if (m_points.empty()) return; // Reposition shape, so that shape object position is in the middle of the shape. Vec3 center = m_points[0]; if (center.x != 0 || center.y != 0 || center.z != 0) { // May not work correctly if shape is transformed. for (int i = 0; i < m_points.size(); i++) { m_points[i] -= center; } const Matrix44 <m = GetLocalTM(); SetPos( GetPos() + ltm.TransformVectorOLD(center) ); } // First point must always be 0,0,0. m_bbox.Reset(); for (int i = 0; i < m_points.size(); i++) { m_bbox.Add( m_points[i] ); } if (m_bbox.min.x > m_bbox.max.x) { m_bbox.min = m_bbox.max = Vec3(0,0,0); } BBox box = m_bbox; box.Transform( GetWorldTM() ); m_lowestHeight = box.min.z; m_bbox.max.z = max( m_bbox.max.z,mv_height ); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::SetSelected( bool bSelect ) { bool bWasSelected = IsSelected(); CBaseObject::SetSelected( bSelect ); if (!bSelect && bWasSelected) { // When unselecting shape, update area in game. if (m_bAreaModified) UpdateGameArea(); m_bAreaModified = false; } } ////////////////////////////////////////////////////////////////////////// int CShapeObject::InsertPoint( int index,const Vec3 &point ) { if (GetPointCount() >= GetMaxPoints()) return GetPointCount()-1; int newindex; StoreUndo( "Insert Point" ); m_bAreaModified = true; if (index < 0 || index >= m_points.size()) { m_points.push_back( point ); newindex = m_points.size()-1; } else { m_points.insert( m_points.begin()+index,point ); newindex = index; } SetPoint( newindex,point ); CalcBBox(); return newindex; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::RemovePoint( int index ) { if ((index >= 0 || index < m_points.size()) && m_points.size() > 3) { m_bAreaModified = true; StoreUndo( "Remove Point" ); m_points.erase( m_points.begin()+index ); CalcBBox(); } } ////////////////////////////////////////////////////////////////////////// void CShapeObject::PostClone( CBaseObject *pFromObject,CObjectCloneContext &ctx ) { CBaseObject::PostClone( pFromObject,ctx ); CShapeObject *pFromShape = (CShapeObject*)pFromObject; // Clone event targets. if (!pFromShape->m_entities.IsEmpty()) { int numEntities = pFromShape->m_entities.GetCount(); for (int i = 0; i < numEntities; i++) { CBaseObject *pTarget = pFromShape->m_entities.Get(i); CBaseObject *pClonedTarget = ctx.FindClone( pTarget ); if (!pClonedTarget) pClonedTarget = pTarget; // If target not cloned, link to original target. // Add cloned event. if (pClonedTarget) AddEntity( pClonedTarget ); } } } ////////////////////////////////////////////////////////////////////////// void CShapeObject::AddEntity( CBaseObject *entity ) { assert( entity ); m_bAreaModified = true; StoreUndo( "Add Entity" ); m_entities.Add( entity ); UpdateGameArea(); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::RemoveEntity( int index ) { assert( index >= 0 && index < m_entities.GetCount() ); StoreUndo( "Remove Entity" ); m_bAreaModified = true; if (index < m_entities.GetCount()) m_entities.Remove( m_entities.Get(index) ); UpdateGameArea(); } ////////////////////////////////////////////////////////////////////////// CBaseObject* CShapeObject::GetEntity( int index ) { assert( index >= 0 && index < m_entities.GetCount() ); return m_entities.Get(index); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::SetClosed( bool bClosed ) { StoreUndo( "Set Closed" ); mv_closed = bClosed; m_bAreaModified = true; if (m_IArea && !mv_closed) { GetIEditor()->GetGame()->GetAreaManager()->DeleteArea( m_IArea ); m_IArea = 0; } if (!m_IArea && mv_closed) { UpdateGameArea(); } } ////////////////////////////////////////////////////////////////////////// int CShapeObject::GetAreaId() { return mv_areaId; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::SelectPoint( int index ) { m_selectedPoint = index; } void CShapeObject::SetPoint( int index,const Vec3 &pos ) { Vec3 p = pos; if (m_bForce2D) { if (!m_points.empty()) p.z = m_points[0].z; // Keep original Z. } if (index >= 0 && index < m_points.size()) { m_points[index] = p; } m_bAreaModified = true; if (!IsOnlyUpdateOnUnselect()) UpdateGameArea(); } ////////////////////////////////////////////////////////////////////////// int CShapeObject::GetNearestPoint( const Vec3 &raySrc,const Vec3 &rayDir,float &distance ) { int index = -1; float minDist = FLT_MAX; Vec3 rayLineP1 = raySrc; Vec3 rayLineP2 = raySrc + rayDir*RAY_DISTANCE; Vec3 intPnt; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < m_points.size(); i++) { float d = PointToLineDistance( rayLineP1,rayLineP2,wtm.TransformPointOLD(m_points[i]),intPnt ); if (d < minDist) { minDist = d; index = i; } } distance = minDist; return index; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::GetNearestEdge( const Vec3 &pos,int &p1,int &p2,float &distance,Vec3 &intersectPoint ) { p1 = -1; p2 = -1; float minDist = FLT_MAX; Vec3 intPnt; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < m_points.size(); i++) { int j = (i < m_points.size()-1) ? i+1 : 0; if (!mv_closed && j == 0 && i != 0) continue; float d = PointToLineDistance( wtm.TransformPointOLD(m_points[i]),wtm.TransformPointOLD(m_points[j]),pos,intPnt ); if (d < minDist) { minDist = d; p1 = i; p2 = j; intersectPoint = intPnt; } } distance = minDist; } ////////////////////////////////////////////////////////////////////////// bool CShapeObject::RayToLineDistance( const Vec3 &rayLineP1,const Vec3 &rayLineP2,const Vec3 &pi,const Vec3 &pj,float &distance,Vec3 &intPnt ) { Vec3 pa,pb; float ua,ub; if (!LineLineIntersect( pi,pj, rayLineP1,rayLineP2, pa,pb,ua,ub )) return false; // If before ray origin. if (ub < 0) return false; float d = 0; if (ua < 0) d = PointToLineDistance( rayLineP1,rayLineP2,pi,intPnt ); else if (ua > 1) d = PointToLineDistance( rayLineP1,rayLineP2,pj,intPnt ); else { intPnt = rayLineP1 + ub*(rayLineP2-rayLineP1); d = (pb-pa).Length(); } distance = d; return true; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::GetNearestEdge( const Vec3 &raySrc,const Vec3 &rayDir,int &p1,int &p2,float &distance,Vec3 &intersectPoint ) { p1 = -1; p2 = -1; float minDist = FLT_MAX; Vec3 intPnt; Vec3 rayLineP1 = raySrc; Vec3 rayLineP2 = raySrc + rayDir*RAY_DISTANCE; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < m_points.size(); i++) { int j = (i < m_points.size()-1) ? i+1 : 0; if (!mv_closed && j == 0 && i != 0) continue; Vec3 pi = wtm.TransformPointOLD(m_points[i]); Vec3 pj = wtm.TransformPointOLD(m_points[j]); float d = 0; if (!RayToLineDistance( rayLineP1,rayLineP2,pi,pj,d,intPnt )) continue; if (d < minDist) { minDist = d; p1 = i; p2 = j; intersectPoint = intPnt; } } distance = minDist; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::UpdateGameArea( bool bRemove ) { if (m_bIgnoreGameUpdate) return; if (!IsCreateGameObjects()) return; if (bRemove) { if (m_IArea) { GetIEditor()->GetGame()->GetAreaManager()->DeleteArea( m_IArea ); m_IArea = 0; } return; } if (m_IArea && !mv_closed) { GetIEditor()->GetGame()->GetAreaManager()->DeleteArea( m_IArea ); m_IArea = 0; } if (!mv_closed) return; const Matrix44 &wtm = GetWorldTM(); BBox box = m_bbox; box.Transform(wtm); m_lowestHeight = box.min.z; std::vector points; if (GetPointCount() > 0) { points.resize(GetPointCount()); for (int i = 0; i < GetPointCount(); i++) { points[i] = wtm.TransformPointOLD( GetPoint(i) ); } } if (m_IArea) { m_IArea->SetPoints( &points[0],points.size() ); } else if (GetPointCount() > 2) { std::vector entitiesName; entitiesName.clear(); m_IArea = GetIEditor()->GetGame()->GetAreaManager()->CreateArea( &points[0], points.size(), entitiesName, mv_areaId, mv_groupId, mv_width ); } if (m_IArea) { m_IArea->SetID(mv_areaId); m_IArea->SetProximity(mv_width); m_IArea->SetVSize(mv_height); m_IArea->SetVOrigin(m_lowestHeight); m_IArea->SetGroup(mv_groupId); m_IArea->ClearEntities(); for (int i = 0; i < GetEntityCount(); i++) { CBaseObject *obj = GetEntity(i); if (obj) m_IArea->AddEntity( obj->GetName() ); } } m_bAreaModified = false; } ////////////////////////////////////////////////////////////////////////// void CShapeObject::OnShapeChange( IVariable *var ) { m_bAreaModified = true; if (!m_bIgnoreGameUpdate) UpdateGameArea(); } ////////////////////////////////////////////////////////////////////////// void CShapeObject::OnEvent( ObjectEvent event ) { if (event == EVENT_AFTER_LOAD) { // After loading Update game structure. UpdateGameArea(); } } ////////////////////////////////////////////////////////////////////////// bool CShapeObject::HitTestRect( HitContext &hc ) { BBox box; // Retrieve world space bound box. GetBoundBox( box ); // Project all edges to viewport. const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < m_points.size(); i++) { int j = (i < m_points.size()-1) ? i+1 : 0; if (!mv_closed && j == 0 && i != 0) continue; Vec3 p0 = wtm.TransformPointOLD(m_points[i]); Vec3 p1 = wtm.TransformPointOLD(m_points[j]); CPoint pnt0 = hc.view->WorldToView( p0 ); CPoint pnt1 = hc.view->WorldToView( p1 ); // See if pnt0 to pnt1 line intersects with rectangle. // check see if one point is inside rect and other outside, or both inside. bool in0 = hc.rect.PtInRect(pnt0); bool in1 = hc.rect.PtInRect(pnt0); if ((in0 && in1) || (in0 && !in1) || (!in0 && in1)) { hc.object = this; return true; } } return false; /* // transform all 8 vertices into world 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; */ } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // CAIForbiddenAreaObject ////////////////////////////////////////////////////////////////////////// CAIForbiddenAreaObject::CAIForbiddenAreaObject() { m_bDisplayFilledWhenSelected = true; SetColor( RGB(255,0,0) ); } ////////////////////////////////////////////////////////////////////////// void CAIForbiddenAreaObject::UpdateGameArea( bool bRemove ) { if (m_bIgnoreGameUpdate) return; if (!IsCreateGameObjects()) return; IAISystem *ai = GetIEditor()->GetSystem()->GetAISystem(); if (ai) { ai->DeletePath( GetName() ); ai->CreatePath( GetName() , AREATYPE_FORBIDDEN); if (bRemove) return; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < GetPointCount(); i++) { ai->AddPointToPath( wtm.TransformPointOLD(GetPoint(i)),GetName(),AREATYPE_FORBIDDEN ); } } m_bAreaModified = false; } ////////////////////////////////////////////////////////////////////////// // CAIPathObject. ////////////////////////////////////////////////////////////////////////// CAIPathObject::CAIPathObject() { SetColor( RGB(180,180,180) ); } void CAIPathObject::UpdateGameArea( bool bRemove ) { if (m_bIgnoreGameUpdate) return; if (!IsCreateGameObjects()) return; IAISystem *ai = GetIEditor()->GetSystem()->GetAISystem(); if (ai) { ai->DeletePath( GetName() ); ai->CreatePath( GetName() ); if (bRemove) return; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < GetPointCount(); i++) { ai->AddPointToPath( wtm.TransformPointOLD(GetPoint(i)),GetName() ); } } m_bAreaModified = false; } ////////////////////////////////////////////////////////////////////////// // CAINavigationModifierObject ////////////////////////////////////////////////////////////////////////// CAINavigationModifierObject::CAINavigationModifierObject() { m_bDisplayFilledWhenSelected = true; SetColor( RGB(24,128,231) ); } void CAINavigationModifierObject::UpdateGameArea( bool bRemove ) { if (m_bIgnoreGameUpdate) return; if (!IsCreateGameObjects()) return; IAISystem *ai = GetIEditor()->GetSystem()->GetAISystem(); if (ai) { ai->DeletePath( GetName() ); ai->CreatePath( GetName(),AREATYPE_NAVIGATIONMODIFIER,GetHeight()); if (bRemove) return; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < GetPointCount(); i++) { ai->AddPointToPath( wtm.TransformPointOLD(GetPoint(i)),GetName(),AREATYPE_NAVIGATIONMODIFIER ); } } m_bAreaModified = false; } ////////////////////////////////////////////////////////////////////////// // CAIOclussionPlaneObject ////////////////////////////////////////////////////////////////////////// CAIOcclusionPlaneObject::CAIOcclusionPlaneObject() { m_bDisplayFilledWhenSelected = true; SetColor( RGB(24,90,231) ); m_bForce2D = true; mv_closed = true; mv_displayFilled = true; } void CAIOcclusionPlaneObject::UpdateGameArea( bool bRemove ) { if (m_bIgnoreGameUpdate) return; if (!IsCreateGameObjects()) return; IAISystem *ai = GetIEditor()->GetSystem()->GetAISystem(); if (ai) { ai->DeletePath( GetName() ); ai->CreatePath( GetName(),AREATYPE_OCCLUSION_PLANE,GetHeight()); if (bRemove) return; const Matrix44 &wtm = GetWorldTM(); for (int i = 0; i < GetPointCount(); i++) { ai->AddPointToPath( wtm.TransformPointOLD(GetPoint(i)),GetName(),AREATYPE_OCCLUSION_PLANE ); } } m_bAreaModified = false; }