Line data Source code
1 : /* Copyright (C) 2009 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : /*
19 : * CFrustum is a collection of planes which define a viewing space.
20 : */
21 :
22 : /*
23 : Usually associated with the camera, there are 6 planes which define the
24 : view pyramid. But we allow more planes per frustum which may be used for
25 : portal rendering, where a portal may have 3 or more edges.
26 : */
27 :
28 : #include "precompiled.h"
29 :
30 : #include "Frustum.h"
31 : #include "maths/BoundingBoxAligned.h"
32 : #include "maths/MathUtil.h"
33 : #include "maths/Matrix3D.h"
34 :
35 33 : CFrustum::CFrustum ()
36 : {
37 3 : m_NumPlanes = 0;
38 3 : }
39 :
40 3 : CFrustum::~CFrustum ()
41 : {
42 3 : }
43 :
44 2 : void CFrustum::SetNumPlanes (size_t num)
45 : {
46 2 : m_NumPlanes = num;
47 :
48 : //clip it
49 2 : if (m_NumPlanes >= MAX_NUM_FRUSTUM_PLANES)
50 : {
51 0 : debug_warn(L"CFrustum::SetNumPlanes: Too many planes");
52 0 : m_NumPlanes = MAX_NUM_FRUSTUM_PLANES-1;
53 : }
54 2 : }
55 :
56 0 : void CFrustum::AddPlane(const CPlane& plane)
57 : {
58 0 : if (m_NumPlanes >= MAX_NUM_FRUSTUM_PLANES)
59 : {
60 0 : debug_warn(L"CFrustum::AddPlane: Too many planes");
61 0 : return;
62 : }
63 :
64 0 : m_aPlanes[m_NumPlanes++] = plane;
65 : }
66 :
67 0 : void CFrustum::Transform(CMatrix3D& m)
68 : {
69 0 : for (size_t i = 0; i < m_NumPlanes; ++i)
70 : {
71 0 : CVector3D n = m.Rotate(m_aPlanes[i].m_Norm);
72 0 : CVector3D p = m.Transform(m_aPlanes[i].m_Norm * -m_aPlanes[i].m_Dist);
73 0 : m_aPlanes[i].Set(n, p);
74 0 : m_aPlanes[i].Normalize();
75 : }
76 0 : }
77 :
78 0 : bool CFrustum::IsPointVisible(const CVector3D& point) const
79 : {
80 0 : for (size_t i=0; i<m_NumPlanes; ++i)
81 : {
82 0 : if (m_aPlanes[i].IsPointOnBackSide(point))
83 : return false;
84 : }
85 :
86 : return true;
87 : }
88 :
89 0 : bool CFrustum::DoesSegmentIntersect(const CVector3D& startRef, const CVector3D& endRef) const
90 : {
91 0 : CVector3D start = startRef;
92 0 : CVector3D end = endRef;
93 :
94 0 : if(IsPointVisible(start) || IsPointVisible(end))
95 : return true;
96 :
97 0 : CVector3D intersect;
98 0 : for (size_t i = 0; i<m_NumPlanes; ++i)
99 : {
100 0 : if (m_aPlanes[i].FindLineSegIntersection(start, end, &intersect))
101 : {
102 0 : if (IsPointVisible(intersect))
103 : return true;
104 : }
105 : }
106 : return false;
107 : }
108 :
109 0 : bool CFrustum::IsSphereVisible(const CVector3D& center, float radius) const
110 : {
111 0 : for (size_t i = 0; i < m_NumPlanes; ++i)
112 : {
113 : // If none of the sphere is in front of the plane, then
114 : // it is outside the frustum
115 0 : if (-m_aPlanes[i].DistanceToPlane(center) > radius)
116 : return false;
117 : }
118 :
119 : return true;
120 : }
121 :
122 0 : bool CFrustum::IsBoxVisible(const CVector3D& position, const CBoundingBoxAligned& bounds) const
123 : {
124 : //basically for every plane we calculate the furthest point
125 : //in the box to that plane. If that point is beyond the plane
126 : //then the box is not visible
127 0 : CVector3D FarPoint;
128 0 : CVector3D Min = position+bounds[0];
129 0 : CVector3D Max = position+bounds[1];
130 :
131 0 : for (size_t i=0; i<m_NumPlanes; ++i)
132 : {
133 0 : FarPoint.X = m_aPlanes[i].m_Norm.X > 0.0f ? Max.X : Min.X;
134 0 : FarPoint.Y = m_aPlanes[i].m_Norm.Y > 0.0f ? Max.Y : Min.Y;
135 0 : FarPoint.Z = m_aPlanes[i].m_Norm.Z > 0.0f ? Max.Z : Min.Z;
136 :
137 0 : if (m_aPlanes[i].IsPointOnBackSide(FarPoint))
138 : return false;
139 : }
140 :
141 : return true;
142 : }
143 :
144 0 : bool CFrustum::IsBoxVisible(const CBoundingBoxAligned& bounds) const
145 : {
146 : //Same as the previous one, but with the position = (0, 0, 0)
147 0 : CVector3D FarPoint;
148 :
149 0 : for (size_t i=0; i<m_NumPlanes; ++i)
150 : {
151 0 : FarPoint.X = m_aPlanes[i].m_Norm.X > 0.0f ? bounds[1].X : bounds[0].X;
152 0 : FarPoint.Y = m_aPlanes[i].m_Norm.Y > 0.0f ? bounds[1].Y : bounds[0].Y;
153 0 : FarPoint.Z = m_aPlanes[i].m_Norm.Z > 0.0f ? bounds[1].Z : bounds[0].Z;
154 :
155 0 : if (m_aPlanes[i].IsPointOnBackSide(FarPoint))
156 : return false;
157 : }
158 :
159 : return true;
160 : }
|