1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "RoadObject.h"
6 #include "Terrain/Heightmap.h"
7 #include "Material/Material.h"
8 #include "../Vegetation/VegetationMap.h"
9 #include "../Vegetation/VegetationObject.h"
10 #include "Objects/ObjectLoader.h"
11 #include "Objects/InspectorWidgetCreator.h"
12 #include <Cry3DEngine/I3DEngine.h>
13 #include <CryCore/Containers/CryArray.h>
14 #include "Util/MFCUtil.h"
15 #include "Serialization/Decorators/EditorActionButton.h"
16 #include <Preferences/ViewportPreferences.h>
18 #include "CryEditDoc.h"
20 //////////////////////////////////////////////////////////////////////////
23 void CRoadSector::Release()
26 GetIEditorImpl()->Get3DEngine()->DeleteRenderNode(m_pRoadSector
);
30 //////////////////////////////////////////////////////////////////////////
31 // CRoadObject implementation.
32 //////////////////////////////////////////////////////////////////////////
33 IMPLEMENT_DYNCREATE(CRoadObject
, CSplineObject
)
35 #define RAY_DISTANCE 100000.0f
37 //////////////////////////////////////////////////////////////////////////
38 CRoadObject::CRoadObject()
40 m_bNeedUpdateSectors
= true;
42 mv_borderWidth
= 6.0f
;
43 mv_eraseVegWidth
= 3.f
;
44 mv_eraseVegWidthVar
= 0.f
;
48 m_ignoreTerrainHoles
= false;
49 m_physicalize
= false;
51 m_bIgnoreParamUpdate
= false;
53 SetColor(CMFCUtils::Vec2Rgb(Vec3(0, 0.8f
, 1)));
54 mv_ratioViewDist
= 100;
57 //////////////////////////////////////////////////////////////////////////
58 void CRoadObject::Done()
64 //////////////////////////////////////////////////////////////////////////
65 void CRoadObject::InitBaseVariables()
67 if (m_pVarObject
== nullptr)
69 m_pVarObject
= stl::make_unique
<CVarObject
>();
72 m_pVarObject
->AddVariable(mv_width
, "Width", functor(*this, &CRoadObject::OnParamChange
));
73 m_pVarObject
->AddVariable(mv_borderWidth
, "BorderWidth", functor(*this, &CRoadObject::OnParamChange
));
74 m_pVarObject
->AddVariable(mv_eraseVegWidth
, "EraseVegWidth");
75 m_pVarObject
->AddVariable(mv_eraseVegWidthVar
, "EraseVegWidthVar");
76 m_pVarObject
->AddVariable(mv_step
, "StepSize", functor(*this, &CRoadObject::OnParamChange
));
77 m_pVarObject
->AddVariable(mv_ratioViewDist
, "ViewDistRatio", functor(*this, &CRoadObject::OnParamChange
));
78 mv_ratioViewDist
.SetLimits(0, 255);
79 m_pVarObject
->AddVariable(mv_tileLength
, "TileLength", functor(*this, &CRoadObject::OnParamChange
));
80 mv_step
.SetLimits(0.25f
, 10.f
);
81 mv_tileLength
.SetLimits(0.001f
, 1000.f
);
84 //////////////////////////////////////////////////////////////////////////
85 void CRoadObject::InitVariables()
89 m_pVarObject
->AddVariable(mv_sortPrio
, "SortPriority", functor(*this, &CRoadObject::OnParamChange
));
90 mv_sortPrio
.SetLimits(0, 255);
92 m_pVarObject
->AddVariable(m_ignoreTerrainHoles
, "IgnoreTerrainHoles", functor(*this, &CRoadObject::OnParamChange
));
93 m_pVarObject
->AddVariable(m_physicalize
, "Physicalize", functor(*this, &CRoadObject::OnParamChange
));
96 //////////////////////////////////////////////////////////////////////////
97 void CRoadObject::InvalidateTM(int nWhyFlags
)
99 __super::InvalidateTM(nWhyFlags
);
103 //////////////////////////////////////////////////////////////////////////
104 void CRoadObject::CreateInspectorWidgets(CInspectorWidgetCreator
& creator
)
106 CSplineObject::CreateInspectorWidgets(creator
);
108 creator
.AddPropertyTree
<CRoadObject
>("Road", [](CRoadObject
* pObject
, Serialization::IArchive
& ar
, bool bMultiEdit
)
110 pObject
->m_pVarObject
->SerializeVariable(&pObject
->mv_width
, ar
);
111 pObject
->m_pVarObject
->SerializeVariable(&pObject
->mv_borderWidth
, ar
);
112 pObject
->m_pVarObject
->SerializeVariable(&pObject
->mv_eraseVegWidth
, ar
);
113 pObject
->m_pVarObject
->SerializeVariable(&pObject
->mv_eraseVegWidthVar
, ar
);
114 pObject
->m_pVarObject
->SerializeVariable(&pObject
->mv_step
, ar
);
115 pObject
->m_pVarObject
->SerializeVariable(&pObject
->mv_ratioViewDist
, ar
);
116 pObject
->m_pVarObject
->SerializeVariable(&pObject
->mv_tileLength
, ar
);
118 if (ar
.openBlock("operators", "<operators"))
120 ar(Serialization::ActionButton(std::bind(&CRoadObject::AlignHeightMap
, pObject
)), "align_heightmap", "^Align Height Map");
121 ar(Serialization::ActionButton(std::bind(&CRoadObject::EraseVegetation
, pObject
)), "erase_vegetation", "^Erase Vegetation");
127 //////////////////////////////////////////////////////////////////////////
128 float CRoadObject::GetLocalWidth(int index
, float t
)
133 if (index
>= m_points
.size() - 1)
136 i
= m_points
.size() - 2;
141 float an1
= m_points
[i
].isDefaultWidth
? mv_width
: m_points
[i
].width
;
142 float an2
= m_points
[i
+ 1].isDefaultWidth
? mv_width
: m_points
[i
+ 1].width
;
147 float af
= kof
* 2 - 1.0f
;
154 af
= (af
+ 1.0f
) / 2;
155 return ((1.0f
- af
) * an1
+ af
* an2
);
158 //////////////////////////////////////////////////////////////////////////
159 void CRoadObject::OnUpdate()
164 //////////////////////////////////////////////////////////////////////////
165 void CRoadObject::SetRoadSectors()
167 const Matrix34
& wtm
= GetWorldTM();
169 int sizeOld
= m_sectors
.size();
172 int points_size
= m_points
.size();
174 float fSegLen
= 0.0f
;
176 for (int i
= 0; i
< points_size
- 1; ++i
)
178 int kn
= GetRoadSectorCount(i
);
180 for (int k
= 0; k
<= kn
; ++k
)
182 if (i
!= points_size
- 2 && k
== kn
)
184 float t
= float(k
) / kn
;
185 Vec3 p
= GetBezierPos(i
, t
);
186 Vec3 n
= GetLocalBezierNormal(i
, t
);
188 float fWidth
= GetLocalWidth(i
, t
);
190 Vec3 r
= p
- 0.5f
* fWidth
* n
;
191 Vec3 l
= p
+ 0.5f
* fWidth
* n
;
193 if (sizeNew
>= sizeOld
)
196 m_sectors
.push_back(sector
);
199 m_sectors
[sizeNew
].points
.clear();
200 m_sectors
[sizeNew
].points
.push_back(l
);
201 m_sectors
[sizeNew
].points
.push_back(r
);
202 m_sectors
[sizeNew
].points
.push_back(l
);
203 m_sectors
[sizeNew
].points
.push_back(r
);
205 m_sectors
[sizeNew
].t0
= (fSegLen
+ GetBezierSegmentLength(i
, t
)) / mv_tileLength
;
209 fSegLen
+= GetBezierSegmentLength(i
);
212 if (sizeNew
< sizeOld
)
213 m_sectors
.resize(sizeNew
);
215 for (size_t i
= 0; i
< m_sectors
.size(); ++i
)
217 m_sectors
[i
].points
[0] = wtm
.TransformPoint(m_sectors
[i
].points
[0]);
218 m_sectors
[i
].points
[1] = wtm
.TransformPoint(m_sectors
[i
].points
[1]);
223 m_sectors
[i
- 1].points
[2] = m_sectors
[i
].points
[0];
224 m_sectors
[i
- 1].points
[3] = m_sectors
[i
].points
[1];
225 m_sectors
[i
- 1].t1
= m_sectors
[i
].t0
;
229 if (m_sectors
.size() > 0)
230 m_sectors
.pop_back();
232 // mark end of the road for road alpha fading
233 if (m_sectors
.size() > 0)
234 m_sectors
[m_sectors
.size() - 1].t1
*= -1.f
;
236 // call only in the end of this function
240 //////////////////////////////////////////////////////////////////////////
241 int CRoadObject::GetRoadSectorCount(int index
)
243 int kn
= int((GetBezierSegmentLength(index
) + 0.5f
) / GetStepSize());
249 //////////////////////////////////////////////////////////////////////////
250 void CRoadObject::UpdateSectors()
252 if (!m_bNeedUpdateSectors
)
257 if (!m_sectors
.size())
260 for (size_t i
= 0; i
< m_sectors
.size(); ++i
)
262 if (m_sectors
[i
].m_pRoadSector
)
263 GetIEditorImpl()->Get3DEngine()->DeleteRenderNode(m_sectors
[i
].m_pRoadSector
);
264 m_sectors
[i
].m_pRoadSector
= 0;
267 int MAX_TRAPEZOIDS_IN_CHUNK
= 16;
268 int nChunksNum
= m_sectors
.size() / MAX_TRAPEZOIDS_IN_CHUNK
+ 1;
270 CRoadSector
& sectorFirstGlobal
= m_sectors
[0];
271 CRoadSector
& sectorLastGlobal
= m_sectors
[m_sectors
.size() - 1];
273 for (int nChunkId
= 0; nChunkId
< nChunksNum
; ++nChunkId
)
275 int nStartSecId
= nChunkId
* MAX_TRAPEZOIDS_IN_CHUNK
;
276 int nSectorsNum
= min(MAX_TRAPEZOIDS_IN_CHUNK
, (int)m_sectors
.size() - nStartSecId
);
281 CRoadSector
& sectorFirst
= m_sectors
[nStartSecId
];
284 if (!sectorFirst
.m_pRoadSector
)
285 sectorFirst
.m_pRoadSector
= GetIEditorImpl()->Get3DEngine()->CreateRenderNode(eERType_Road
);
286 if (!sectorFirst
.m_pRoadSector
)
289 if (CheckFlags(OBJFLAG_INVISIBLE
) || IsHiddenBySpec())
290 renderFlags
= ERF_HIDDEN
;
291 sectorFirst
.m_pRoadSector
->SetRndFlags(renderFlags
);
292 sectorFirst
.m_pRoadSector
->SetViewDistRatio(mv_ratioViewDist
);
293 sectorFirst
.m_pRoadSector
->SetMinSpec(GetMinSpec());
294 sectorFirst
.m_pRoadSector
->SetMaterialLayers(GetMaterialLayersMask());
295 sectorFirst
.m_pRoadSector
->SetEditorObjectId(GetId().hipart
>> 32);
297 // make list of verts
298 PodArray
<Vec3
> lstPoints
;
299 for (int i
= 0; i
< nSectorsNum
; ++i
)
301 lstPoints
.Add(m_sectors
[nStartSecId
+ i
].points
[0]);
302 lstPoints
.Add(m_sectors
[nStartSecId
+ i
].points
[1]);
305 CRoadSector
& sectorLast
= m_sectors
[nStartSecId
+ nSectorsNum
- 1];
307 // Extend final boundary to cover holes in roads caused by f16 meshes.
308 // Overlapping the roads slightly seems to be the nicest way to fix the issue
309 Vec3 sectorLastOffset2
= sectorLast
.points
[2] - sectorLast
.points
[0];
310 Vec3 sectorLastOffset3
= sectorLast
.points
[3] - sectorLast
.points
[1];
312 sectorLastOffset2
.Normalize();
313 sectorLastOffset3
.Normalize();
315 const float sectorLastOffset
= 0.075f
;
316 sectorLastOffset2
*= sectorLastOffset
;
317 sectorLastOffset3
*= sectorLastOffset
;
319 lstPoints
.Add(sectorLast
.points
[2] + sectorLastOffset2
);
320 lstPoints
.Add(sectorLast
.points
[3] + sectorLastOffset3
);
322 //assert(lstPoints.Count()>=4);
323 assert(!(lstPoints
.Count() & 1));
325 IRoadRenderNode
* pRoadRN
= static_cast<IRoadRenderNode
*>(sectorFirst
.m_pRoadSector
);
326 pRoadRN
->SetVertices(lstPoints
.GetElements(), lstPoints
.Count(), fabs(sectorFirst
.t0
), fabs(sectorLast
.t1
), fabs(sectorFirstGlobal
.t0
), fabs(sectorLastGlobal
.t1
));
327 pRoadRN
->SetSortPriority(mv_sortPrio
);
328 pRoadRN
->SetIgnoreTerrainHoles(m_ignoreTerrainHoles
);
329 pRoadRN
->SetPhysicalize(m_physicalize
);
332 ((CMaterial
*)GetMaterial())->AssignToEntity(sectorFirst
.m_pRoadSector
);
334 sectorFirst
.m_pRoadSector
->SetMaterial(NULL
);
338 void CRoadObject::OnEvent(ObjectEvent event
)
340 if (event
== EVENT_CONFIG_SPEC_CHANGE
)
342 m_bNeedUpdateSectors
= true;
345 __super::OnEvent(event
);
348 //////////////////////////////////////////////////////////////////////////
349 void CRoadObject::SetHidden(bool bHidden
)
351 __super::SetHidden(bHidden
);
355 //////////////////////////////////////////////////////////////////////////
356 void CRoadObject::UpdateVisibility(bool visible
)
358 if (visible
== CheckFlags(OBJFLAG_INVISIBLE
))
360 __super::UpdateVisibility(visible
);
365 //////////////////////////////////////////////////////////////////////////
367 void CRoadObject::RegisterOnEngine()
369 for (CRoadSectorVector::size_type i
= 0; i
< m_sectors
.size(); ++i
)
371 if (m_sectors
[i
].m_pRoadSector
)
373 GetIEditorImpl()->Get3DEngine()->RegisterEntity(m_sectors
[i
].m_pRoadSector
);
378 //////////////////////////////////////////////////////////////////////////
380 void CRoadObject::UnRegisterFromEngine()
382 for (CRoadSectorVector::size_type i
= 0; i
< m_sectors
.size(); ++i
)
384 if (m_sectors
[i
].m_pRoadSector
)
386 GetIEditorImpl()->Get3DEngine()->UnRegisterEntityAsJob(m_sectors
[i
].m_pRoadSector
);
391 //////////////////////////////////////////////////////////////////////////
392 void CRoadObject::SetMaterial(IEditorMaterial
* pMaterial
)
394 CMaterial
* pPrevMaterial
= (CMaterial
*)GetMaterial();
395 __super::SetMaterial(pMaterial
);
397 if (pPrevMaterial
!= pMaterial
)
401 //////////////////////////////////////////////////////////////////////////
402 void CRoadObject::DrawSectorLines(DisplayContext
& dc
)
404 const Matrix34
& wtm
= GetWorldTM();
405 float fPointSize
= 0.5f
;
407 dc
.SetColor(RGB(127, 127, 255));
408 for (size_t i
= 0; i
< m_sectors
.size(); ++i
)
410 dc
.DrawLine(m_sectors
[i
].points
[0], m_sectors
[i
].points
[1]);
411 for (size_t k
= 0; k
< m_sectors
[i
].points
.size(); k
+= 2)
413 if (k
+ 3 < m_sectors
[i
].points
.size())
415 dc
.DrawLine(m_sectors
[i
].points
[k
+ 1], m_sectors
[i
].points
[k
+ 3]);
416 dc
.DrawLine(m_sectors
[i
].points
[k
+ 3], m_sectors
[i
].points
[k
+ 2]);
417 dc
.DrawLine(m_sectors
[i
].points
[k
+ 2], m_sectors
[i
].points
[k
]);
423 //////////////////////////////////////////////////////////////////////////
424 void CRoadObject::DrawRoadObject(DisplayContext
& dc
, COLORREF col
)
432 //////////////////////////////////////////////////////////////////////////
433 void CRoadObject::Display(CObjectRenderHelper
& objRenderHelper
)
435 DisplayContext
& dc
= objRenderHelper
.GetDisplayContextRef();
437 if (!gViewportDebugPreferences
.showRoadObjectHelper
)
442 if (m_points
.size() > 1)
444 if ((IsSelected() || IsHighlighted()))
446 col
= dc
.GetSelectedColor();
454 dc
.SetColor(GetColor());
458 DrawRoadObject(dc
, col
);
460 __super::Display(objRenderHelper
);
463 //////////////////////////////////////////////////////////////////////////
464 void CRoadObject::Serialize(CObjectArchive
& ar
)
466 m_bIgnoreParamUpdate
= true;
467 m_bNeedUpdateSectors
= false;
468 __super::Serialize(ar
);
469 m_bNeedUpdateSectors
= true;
470 m_bIgnoreParamUpdate
= false;
475 //////////////////////////////////////////////////////////////////////////
476 XmlNodeRef
CRoadObject::Export(const string
& levelPath
, XmlNodeRef
& xmlNode
)
478 //XmlNodeRef objNode = __super::Export( levelPath,xmlNode );
483 //////////////////////////////////////////////////////////////////////////
484 void CRoadObject::OnParamChange(IVariable
* var
)
486 if (!m_bIgnoreParamUpdate
)
490 //////////////////////////////////////////////////////////////////////////
491 void CRoadObject::SetSelected(bool bSelect
)
493 __super::SetSelected(bSelect
);
497 //////////////////////////////////////////////////////////////////////////
498 void CRoadObject::AlignHeightMap()
500 if (!GetIEditorImpl()->GetIUndoManager()->IsUndoRecording())
501 GetIEditorImpl()->GetIUndoManager()->Begin();
503 CHeightmap
* heightmap
= GetIEditorImpl()->GetHeightmap();
504 float unitSize
= heightmap
->GetUnitSize();
505 const Matrix34
& wtm
= GetWorldTM();
507 int minx
= 0, miny
= 0, maxx
= 0, maxy
= 0;
508 bool bIsInitMinMax
= false;
510 const int nPoints
= GetPointCount();
512 for (int i
= 0; i
< nPoints
- 1; ++i
)
514 float fminx
= 0, fminy
= 0, fmaxx
= 0, fmaxy
= 0;
515 bool bIsInitminmax
= false;
516 int kn
= int (0.5f
+ (GetBezierSegmentLength(i
) + 1) * 4);
520 for (int k
= 0; k
<= kn
; ++k
)
522 float t
= float(k
) / kn
;
523 Vec3 p
= GetBezierPos(i
, t
);
524 Vec3 n
= GetLocalBezierNormal(i
, t
);
526 float fWidth
= GetLocalWidth(i
, t
);
530 Vec3 p1
= p
- (0.5f
* fWidth
+ mv_borderWidth
+ 0.5f
* unitSize
) * n
;
531 Vec3 p2
= p
+ (0.5f
* fWidth
+ mv_borderWidth
+ 0.5f
* unitSize
) * n
;
533 p1
= wtm
.TransformPoint(p1
);
534 p2
= wtm
.TransformPoint(p2
);
544 bIsInitminmax
= true;
546 fminx
= min(fminx
, p1
.x
);
547 fminx
= min(fminx
, p2
.x
);
548 fminy
= min(fminy
, p1
.y
);
549 fminy
= min(fminy
, p2
.y
);
550 fmaxx
= max(fmaxx
, p1
.x
);
551 fmaxx
= max(fmaxx
, p2
.x
);
552 fmaxy
= max(fmaxy
, p1
.y
);
553 fmaxy
= max(fmaxy
, p2
.y
);
556 heightmap
->RecordUndo(int(fminy
/ unitSize
) - 1, int(fminx
/ unitSize
) - 1, int(fmaxy
/ unitSize
) + unitSize
- int(fminy
/ unitSize
) + 1, int(fmaxx
/ unitSize
) + unitSize
- int(fminx
/ unitSize
) + 1);
558 for (int ty
= int(fminx
/ unitSize
); ty
<= int(fmaxx
/ unitSize
) + unitSize
; ++ty
)
559 for (int tx
= int(fminy
/ unitSize
); tx
<= int(fmaxy
/ unitSize
) + unitSize
; ++tx
)
561 int x
= ty
* unitSize
;
562 int y
= tx
* unitSize
;
564 Vec3 p3
= Vec3(x
, y
, 0.0f
);
567 float fWidth
= GetLocalWidth(i
, 0);
568 float fWidth1
= GetLocalWidth(i
, 1);
569 if (fWidth
< fWidth1
)
571 float mind
= 0.5f
* fWidth
+ mv_borderWidth
+ 0.5f
* unitSize
;
573 for (int k
= 0; k
< kn
; ++k
)
575 float t
= float(k
) / kn
;
576 Vec3 p1
= wtm
.TransformPoint(GetBezierPos(i
, t
));
577 Vec3 p2
= wtm
.TransformPoint(GetBezierPos(i
, t
+ 1.0f
/ kn
));
582 //float u = d.Dot(p3-p1) / (d).GetLengthSquared();
583 //if (-0.1f <= u && u <=1.1f)
585 float d
= PointToLineDistance(p1
, p2
, p3
);
596 float t
= float(findk
) / kn
;
598 float st
= 1.0f
/ kn
;
600 for (int tt
= 0; tt
< 24; ++tt
)
602 Vec3 p0
= wtm
.TransformPoint(GetBezierPos(i
, t
));
606 Vec3 ploc
= GetBezierPos(i
, t
);
607 Vec3 nloc
= GetLocalBezierNormal(i
, t
);
609 Vec3 p1
= wtm
.TransformPoint(ploc
- nloc
);
612 if (((p0
- p1
).Cross(p3
- p1
).z
) < 0.0f
)
621 if (t
< 0.0f
|| t
> 1.0f
)
624 Vec3 p1
= wtm
.TransformPoint(GetBezierPos(i
, t
));
625 Vec3 p2
= wtm
.TransformPoint(GetBezierPos(i
, t
+ 1.0f
/ kn
));
630 Vec3 p
= Vec3(x
, y
, 0.0f
);
631 Vec3 e
= (p2
- p1_0
).Cross(p1_0
- p
);
633 Vec3 p1loc
= GetBezierPos(i
, t
);
634 Vec3 nloc
= GetLocalBezierNormal(i
, t
);
636 Vec3 n
= wtm
.TransformPoint(p1loc
- nloc
) - p1
;
642 float kof
= nproj
.GetLength();
644 float length
= (p1_0
- p
).GetLength() / kof
;
649 pos
= p1
- length
* n
;
651 pos
= p1
+ length
* n
;
653 float fWidth
= GetLocalWidth(i
, t
);
654 if (length
<= fWidth
/ 2 + mv_borderWidth
+ 0.5 * unitSize
)
656 //int tx = pos_directed_rounding(y / unitSize);
657 //int ty = pos_directed_rounding(x / unitSize);
660 if (length
<= fWidth
/ 2 + 0.5 * unitSize
)
665 float kof
= (length
- (fWidth
/ 2 + 0.5 * unitSize
)) / mv_borderWidth
;
666 kof
= 1.0f
- (cos(kof
* 3.141593f
) + 1.0f
) / 2;
667 float z1
= heightmap
->GetXY(tx
, ty
);
668 z
= kof
* z1
+ (1.0f
- kof
) * pos
.z
;
671 heightmap
->SetXY(tx
, ty
, clamp_tpl(z
, 0.0f
, heightmap
->GetMaxHeight()));
679 bIsInitMinMax
= true;
681 if (minx
> tx
) minx
= tx
;
682 if (miny
> ty
) miny
= ty
;
683 if (maxx
< tx
) maxx
= tx
;
684 if (maxy
< ty
) maxy
= ty
;
692 if (w
< maxy
- miny
) w
= maxy
- miny
;
693 heightmap
->UpdateEngineTerrain(minx
, miny
, w
, w
, CHeightmap::ETerrainUpdateType::Elevation
);
695 if (GetIEditorImpl()->GetIUndoManager()->IsUndoRecording())
696 GetIEditorImpl()->GetIUndoManager()->Accept("Heightmap Aligning");
701 //////////////////////////////////////////////////////////////////////////
702 void CRoadObject::EraseVegetation()
704 if (CVegetationMap
* vegetationMap
= GetIEditorImpl()->GetVegetationMap())
706 if (!GetIEditorImpl()->GetIUndoManager()->IsUndoRecording())
707 GetIEditorImpl()->GetIUndoManager()->Begin();
709 bool bModified
= false;
711 vegetationMap
->StoreBaseUndo(CVegetationMap::eStoreUndo_Begin
);
713 const Matrix34
& wtm
= GetWorldTM();
714 const int nPoints
= GetPointCount();
715 const float fEraseWidth
= mv_eraseVegWidth
+ mv_eraseVegWidthVar
* 0.5f
;
716 const float fSpareWidth
= 5.0f
;
718 for (int i
= 0; i
< nPoints
- 1; ++i
)
720 const int nSegment
= GetBezierSegmentLength(i
);
721 const int nSector
= GetRoadSectorCount(i
);
723 for (int k
= 0; k
< nSector
; ++k
)
725 const float t1
= float(k
) / nSector
;
726 const float t2
= float(k
+ 1) / nSector
;
728 const Vec3 p1
= GetBezierPos(i
, t1
);
729 const Vec3 n1
= GetLocalBezierNormal(i
, t1
);
730 const Vec3 p2
= GetBezierPos(i
, t2
);
731 const Vec3 n2
= GetLocalBezierNormal(i
, t2
);
733 const float fRoadWidth1
= GetLocalWidth(i
, t1
);
734 const float fRoadWidth2
= GetLocalWidth(i
, t2
);
736 const Vec3
r1(wtm
.TransformPoint(p1
- (0.5f
* fRoadWidth1
+ fEraseWidth
+ fSpareWidth
) * n1
));
737 const Vec3
l1(wtm
.TransformPoint(p1
+ (0.5f
* fRoadWidth1
+ fEraseWidth
+ fSpareWidth
) * n1
));
738 const Vec3
r2(wtm
.TransformPoint(p2
- (0.5f
* fRoadWidth2
+ fEraseWidth
+ fSpareWidth
) * n2
));
739 const Vec3
l2(wtm
.TransformPoint(p2
+ (0.5f
* fRoadWidth2
+ fEraseWidth
+ fSpareWidth
) * n2
));
741 const float fminx
= min(r1
.x
, min(l1
.x
, min(r2
.x
, l2
.x
)));
742 const float fminy
= min(r1
.y
, min(l1
.y
, min(r2
.y
, l2
.y
)));
743 const float fmaxx
= max(r1
.x
, max(l1
.x
, max(r2
.x
, l2
.x
)));
744 const float fmaxy
= max(r1
.y
, max(l1
.y
, max(r2
.y
, l2
.y
)));
746 std::vector
<CVegetationInstance
*> instances
;
747 vegetationMap
->GetObjectInstances(fminx
, fminy
, fmaxx
, fmaxy
, instances
);
749 const int segmentStart
= k
* nSegment
/ nSector
;
750 const int segmentEnd
= (k
+ 1) * nSegment
/ nSector
;
752 for (std::vector
<CVegetationInstance
*>::iterator it
= instances
.begin(); it
!= instances
.end(); ++it
)
754 float fFinalEraseWidth
= fEraseWidth
;
756 if (mv_eraseVegWidthVar
!= 0.f
)
758 fFinalEraseWidth
-= float(rand() % int(mv_eraseVegWidthVar
* 10.f
)) * 0.1f
;
760 if (CVegetationObject
* obj
= (*it
)->object
)
762 fFinalEraseWidth
+= obj
->GetObjectSize() * 0.5f
;
764 for (int l
= segmentStart
; l
< segmentEnd
; ++l
)
766 const float ts
= float(l
) / nSegment
;
767 const float fWidth
= 0.5f
* GetLocalWidth(i
, ts
) + fFinalEraseWidth
;
769 const Vec2
pos1(wtm
.TransformPoint(GetBezierPos(i
, ts
)));
770 const Vec2
pos2((*it
)->pos
);
772 const float fDistance
= pos1
.GetDistance(pos2
);
774 if (fDistance
<= fWidth
)
776 vegetationMap
->StoreBaseUndo(CVegetationMap::eStoreUndo_Once
);
777 vegetationMap
->DeleteObjInstance(*it
);
781 GetIEditorImpl()->SetModifiedFlag();
790 vegetationMap
->StoreBaseUndo(CVegetationMap::eStoreUndo_End
);
792 if (GetIEditorImpl()->GetIUndoManager()->IsUndoRecording())
796 GetIEditorImpl()->GetIUndoManager()->Accept("Erase Vegetation On Road");
800 GetIEditorImpl()->GetIUndoManager()->Cancel();
806 //////////////////////////////////////////////////////////////////////////
807 void CRoadObject::SetMinSpec(uint32 nSpec
, bool bSetChildren
)
809 __super::SetMinSpec(nSpec
, bSetChildren
);
813 //////////////////////////////////////////////////////////////////////////
814 void CRoadObject::SetMaterialLayersMask(uint32 nLayersMask
)
816 __super::SetMaterialLayersMask(nLayersMask
);
820 //////////////////////////////////////////////////////////////////////////
821 void CRoadObject::SetLayerId(uint16 nLayerId
)
823 for (size_t i
= 0; i
< m_sectors
.size(); ++i
)
825 if (m_sectors
[i
].m_pRoadSector
)
826 m_sectors
[i
].m_pRoadSector
->SetLayerId(nLayerId
);
830 void CRoadObject::UpdateHighlightPassState(bool bSelected
, bool bHighlighted
)
832 for (size_t i
= 0; i
< m_sectors
.size(); ++i
)
834 if (m_sectors
[i
].m_pRoadSector
)
835 m_sectors
[i
].m_pRoadSector
->SetEditorObjectInfo(bSelected
, bHighlighted
);
840 //////////////////////////////////////////////////////////////////////////
841 void CRoadObject::SetPhysics(bool isPhysics
)
843 for (size_t i
= 0; i
< m_sectors
.size(); ++i
)
845 IRenderNode
* pRenderNode
= m_sectors
[i
].m_pRoadSector
;
849 pRenderNode
->SetRndFlags(pRenderNode
->GetRndFlags() & ~ERF_NO_PHYSICS
);
851 pRenderNode
->SetRndFlags(pRenderNode
->GetRndFlags() | ERF_NO_PHYSICS
);
856 //////////////////////////////////////////////////////////////////////////
857 // Class Description of RoadObject.
859 //////////////////////////////////////////////////////////////////////////
860 class CRoadObjectClassDesc
: public CObjectClassDesc
863 ObjectType
GetObjectType() { return OBJTYPE_ROAD
; };
864 const char* ClassName() { return "Road"; };
865 const char* Category() { return "Misc"; };
866 CRuntimeClass
* GetRuntimeClass() { return RUNTIME_CLASS(CRoadObject
); };
869 REGISTER_CLASS_DESC(CRoadObjectClassDesc
);