1 ////////////////////////////////////////////////////////////////////////////////
2 //    Scorched3D (c) 2000-2011
3 //
4 //    This file is part of Scorched3D.
5 //
6 //    Scorched3D is free software; you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation; either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    Scorched3D is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License along
17 //    with this program; if not, write to the Free Software Foundation, Inc.,
18 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20 
21 #include <math.h>
22 #include <GLEXT/GLState.h>
23 #include <GLEXT/GLCameraFrustum.h>
24 #include <graph/OptionsDisplay.h>
25 
26 Vector GLCameraFrustum::FrustrumRed(1.0f, 0.0f, 0.0f);
27 Vector GLCameraFrustum::FrustrumBlue(0.0f, 0.0f, 1.0f);
28 Vector GLCameraFrustum::FrustrumGreen(0.0f, 1.0f, 0.0f);
29 Vector GLCameraFrustum::FrustrumWhite(1.0f, 1.0f, 1.0f);
30 
31 GLCameraFrustum *GLCameraFrustum::instance_ = 0;
32 
instance()33 GLCameraFrustum *GLCameraFrustum::instance()
34 {
35 	if (!instance_)
36 	{
37 		instance_ = new GLCameraFrustum;
38 	}
39 
40 	return instance_;
41 }
42 
GLCameraFrustum()43 GLCameraFrustum::GLCameraFrustum() :
44 	GameStateI("GLCameraFrustum")
45 {
46 
47 }
48 
~GLCameraFrustum()49 GLCameraFrustum::~GLCameraFrustum()
50 {
51 
52 }
53 
normalize(float vector[4])54 void GLCameraFrustum::normalize(float vector[4])
55 {
56    float fT = (float) sqrt(
57 	   vector[0] * vector[0] +
58 	   vector[1] * vector[1] +
59 	   vector[2] * vector[2]);
60 
61    vector[0] /= fT;
62    vector[1] /= fT;
63    vector[2] /= fT;
64    vector[3] /= fT;
65 }
66 
getBilboardVectorX()67 Vector &GLCameraFrustum::getBilboardVectorX()
68 {
69 	static Vector bil;
70 	bil[0] = s.fClip[0];
71 	bil[1] = s.fClip[4];
72 	bil[2] = s.fClip[8];
73 	bil *= s.aspect * 0.8f;
74 
75 	return bil;
76 }
77 
getBilboardVectorY()78 Vector &GLCameraFrustum::getBilboardVectorY()
79 {
80 	static Vector bil;
81 	bil[0] = s.fClip[1];
82 	bil[1] = s.fClip[5];
83 	bil[2] = s.fClip[9];
84 	bil *= 0.8f;
85 
86 	return bil;
87 }
88 
draw(const unsigned state)89 void GLCameraFrustum::draw(const unsigned state)
90 {
91 	// Get the current projection matrix from OpenGL
92 	// Get the current modelview matrix from OpenGL
93 	glGetFloatv(GL_PROJECTION_MATRIX, s.fProj);
94 	glGetFloatv(GL_MODELVIEW_MATRIX, s.fView);
95 	glGetFloatv(GL_VIEWPORT, s.viewport);
96 	s.aspect = s.viewport[2] / s.viewport[3];
97 
98 	// Concenate the two matrices
99 	s.fClip[ 0] = s.fView[ 0] * s.fProj[ 0] + s.fView[ 1] * s.fProj[ 4] + s.fView[ 2] * s.fProj[ 8] + s.fView[ 3] * s.fProj[12];
100 	s.fClip[ 1] = s.fView[ 0] * s.fProj[ 1] + s.fView[ 1] * s.fProj[ 5] + s.fView[ 2] * s.fProj[ 9] + s.fView[ 3] * s.fProj[13];
101 	s.fClip[ 2] = s.fView[ 0] * s.fProj[ 2] + s.fView[ 1] * s.fProj[ 6] + s.fView[ 2] * s.fProj[10] + s.fView[ 3] * s.fProj[14];
102 	s.fClip[ 3] = s.fView[ 0] * s.fProj[ 3] + s.fView[ 1] * s.fProj[ 7] + s.fView[ 2] * s.fProj[11] + s.fView[ 3] * s.fProj[15];
103 
104 	s.fClip[ 4] = s.fView[ 4] * s.fProj[ 0] + s.fView[ 5] * s.fProj[ 4] + s.fView[ 6] * s.fProj[ 8] + s.fView[ 7] * s.fProj[12];
105 	s.fClip[ 5] = s.fView[ 4] * s.fProj[ 1] + s.fView[ 5] * s.fProj[ 5] + s.fView[ 6] * s.fProj[ 9] + s.fView[ 7] * s.fProj[13];
106 	s.fClip[ 6] = s.fView[ 4] * s.fProj[ 2] + s.fView[ 5] * s.fProj[ 6] + s.fView[ 6] * s.fProj[10] + s.fView[ 7] * s.fProj[14];
107 	s.fClip[ 7] = s.fView[ 4] * s.fProj[ 3] + s.fView[ 5] * s.fProj[ 7] + s.fView[ 6] * s.fProj[11] + s.fView[ 7] * s.fProj[15];
108 
109 	s.fClip[ 8] = s.fView[ 8] * s.fProj[ 0] + s.fView[ 9] * s.fProj[ 4] + s.fView[10] * s.fProj[ 8] + s.fView[11] * s.fProj[12];
110 	s.fClip[ 9] = s.fView[ 8] * s.fProj[ 1] + s.fView[ 9] * s.fProj[ 5] + s.fView[10] * s.fProj[ 9] + s.fView[11] * s.fProj[13];
111 	s.fClip[10] = s.fView[ 8] * s.fProj[ 2] + s.fView[ 9] * s.fProj[ 6] + s.fView[10] * s.fProj[10] + s.fView[11] * s.fProj[14];
112 	s.fClip[11] = s.fView[ 8] * s.fProj[ 3] + s.fView[ 9] * s.fProj[ 7] + s.fView[10] * s.fProj[11] + s.fView[11] * s.fProj[15];
113 
114 	s.fClip[12] = s.fView[12] * s.fProj[ 0] + s.fView[13] * s.fProj[ 4] + s.fView[14] * s.fProj[ 8] + s.fView[15] * s.fProj[12];
115 	s.fClip[13] = s.fView[12] * s.fProj[ 1] + s.fView[13] * s.fProj[ 5] + s.fView[14] * s.fProj[ 9] + s.fView[15] * s.fProj[13];
116 	s.fClip[14] = s.fView[12] * s.fProj[ 2] + s.fView[13] * s.fProj[ 6] + s.fView[14] * s.fProj[10] + s.fView[15] * s.fProj[14];
117 	s.fClip[15] = s.fView[12] * s.fProj[ 3] + s.fView[13] * s.fProj[ 7] + s.fView[14] * s.fProj[11] + s.fView[15] * s.fProj[15];
118 
119 	// Bilboard matrix
120 	s.fBilboard[0] = s.fClip[0];
121 	s.fBilboard[1] = s.fClip[4];
122 	s.fBilboard[2] = s.fClip[8];
123 	s.fBilboard[3] = 0.0f; // x
124 
125 	s.fBilboard[4] = s.fClip[1];
126 	s.fBilboard[5] = s.fClip[5];
127 	s.fBilboard[6] = s.fClip[9];
128 	s.fBilboard[7] = 0.0f; // y
129 
130 	s.fBilboard[8] = s.fClip[2];
131 	s.fBilboard[9] = s.fClip[6];
132 	s.fBilboard[10] = s.fClip[10];
133 	s.fBilboard[11] = 0.0f; // z
134 
135 	s.fBilboard[12] = 0.0f;
136 	s.fBilboard[13] = 0.0f;
137 	s.fBilboard[14] = 0.0f;
138 	s.fBilboard[15] = 1.0f;
139 
140 	// Extract the right plane
141 	s.frustum_[0][0] = s.fClip[ 3] - s.fClip[ 0];
142 	s.frustum_[0][1] = s.fClip[ 7] - s.fClip[ 4];
143 	s.frustum_[0][2] = s.fClip[11] - s.fClip[ 8];
144 	s.frustum_[0][3] = s.fClip[15] - s.fClip[12];
145 	normalize(s.frustum_[0]);
146 
147 	// Extract the left plane
148 	s.frustum_[1][0] = s.fClip[ 3] + s.fClip[ 0];
149 	s.frustum_[1][1] = s.fClip[ 7] + s.fClip[ 4];
150 	s.frustum_[1][2] = s.fClip[11] + s.fClip[ 8];
151 	s.frustum_[1][3] = s.fClip[15] + s.fClip[12];
152 	normalize(s.frustum_[1]);
153 
154 	// Extract the bottom plane
155 	s.frustum_[2][0] = s.fClip[ 3] + s.fClip[ 1];
156 	s.frustum_[2][1] = s.fClip[ 7] + s.fClip[ 5];
157 	s.frustum_[2][2] = s.fClip[11] + s.fClip[ 9];
158 	s.frustum_[2][3] = s.fClip[15] + s.fClip[13];
159 	normalize(s.frustum_[2]);
160 
161 	// Extract the top plane
162 	s.frustum_[3][0] = s.fClip[ 3] - s.fClip[ 1];
163 	s.frustum_[3][1] = s.fClip[ 7] - s.fClip[ 5];
164 	s.frustum_[3][2] = s.fClip[11] - s.fClip[ 9];
165 	s.frustum_[3][3] = s.fClip[15] - s.fClip[13];
166 	normalize(s.frustum_[3]);
167 
168 	// Extract the far plane
169 	s.frustum_[4][0] = s.fClip[ 3] - s.fClip[ 2];
170 	s.frustum_[4][1] = s.fClip[ 7] - s.fClip[ 6];
171 	s.frustum_[4][2] = s.fClip[11] - s.fClip[10];
172 	s.frustum_[4][3] = s.fClip[15] - s.fClip[14];
173 	normalize(s.frustum_[4]);
174 
175 	// Extract the near plane
176 	s.frustum_[5][0] = s.fClip[ 3] + s.fClip[ 2];
177 	s.frustum_[5][1] = s.fClip[ 7] + s.fClip[ 6];
178 	s.frustum_[5][2] = s.fClip[11] + s.fClip[10];
179 	s.frustum_[5][3] = s.fClip[15] + s.fClip[14];
180 	normalize(s.frustum_[5]);
181 }
182 
sphereInFrustum(Vector & point,float fRadius,Vector & color)183 bool GLCameraFrustum::sphereInFrustum(Vector &point,
184 	float fRadius, Vector &color)
185 {
186 	if (OptionsDisplay::instance()->getDrawBoundingSpheres())
187 	{
188 		static GLUquadric *obj = 0;
189 		if (!obj)
190 		{
191 			obj = gluNewQuadric();
192 			gluQuadricDrawStyle(obj, GLU_LINE);
193 		}
194 
195 		GLState glState(GLState::TEXTURE_OFF);
196 		glColor3fv(color);
197 		glPushMatrix();
198 			glTranslatef(point[0], point[1], point[2]);
199 			gluSphere(obj, fRadius, 6, 6);
200 		glPopMatrix();
201 	}
202 
203 	return sphereInFrustumThreadSafe(point, fRadius);
204 }
205 
sphereInFrustumThreadSafe(Vector & point,float fRadius)206 bool GLCameraFrustum::sphereInFrustumThreadSafe(Vector &point, float fRadius)
207 {
208 	for (int iCurPlane = 0; iCurPlane<6; iCurPlane++)
209 	{
210 		float value =
211 			s.frustum_[iCurPlane][0] * point[0] +
212 			s.frustum_[iCurPlane][1] * point[1] +
213 			s.frustum_[iCurPlane][2] * point[2] +
214 			s.frustum_[iCurPlane][3];
215 		if (value <= -fRadius)
216 		{
217 			return false;
218 		}
219 	}
220 
221 	return true;
222 }
223 
backupFrustum()224 void GLCameraFrustum::backupFrustum()
225 {
226 	memcpy(&b, &s, sizeof(b));
227 }
228 
restoreFrustum()229 void GLCameraFrustum::restoreFrustum()
230 {
231 	memcpy(&s, &b, sizeof(b));
232 }
233 
drawBilboard(Vector & position,Vector & color,float alpha,float width,float height,bool additive,int textureCoord)234 void GLCameraFrustum::drawBilboard(Vector &position, Vector &color, float alpha,
235 	float width, float height, bool additive, int textureCoord)
236 {
237 	if (additive) glBlendFunc(GL_SRC_ALPHA, GL_ONE);
238 
239 	Vector &bilX = getBilboardVectorX();
240 	Vector &bilY = getBilboardVectorY();
241 
242 	float bilXX = bilX[0] * width;
243 	float bilXY = bilX[1] * width;
244 	float bilXZ = bilX[2] * width;
245 	float bilYX = bilY[0] * height;
246 	float bilYY = bilY[1] * height;
247 	float bilYZ = bilY[2] * height;
248 
249 	glColor4f(color[0], color[1], color[2], alpha);
250 	glBegin(GL_QUADS);
251 	switch(textureCoord)
252 	{
253 	default: glTexCoord2d(1.0f, 1.0f); break;
254 	case 1:  glTexCoord2d(0.0f, 1.0f); break;
255 	case 2:  glTexCoord2d(0.0f, 0.0f); break;
256 	case 3:  glTexCoord2d(1.0f, 0.0f); break;
257 	}
258 	glVertex3f(
259 		position[0] + bilXX + bilYX,
260 		position[1] + bilXY + bilYY,
261 		position[2] + bilXZ + bilYZ);
262 	switch(textureCoord)
263 	{
264 	default: glTexCoord2d(0.0f, 1.0f); break;
265 	case 1:  glTexCoord2d(0.0f, 0.0f); break;
266 	case 2:  glTexCoord2d(1.0f, 0.0f); break;
267 	case 3:  glTexCoord2d(1.0f, 1.0f); break;
268 	}
269 	glVertex3f(
270 		position[0] - bilXX + bilYX,
271 		position[1] - bilXY + bilYY,
272 		position[2] - bilXZ + bilYZ);
273 	switch(textureCoord)
274 	{
275 	default: glTexCoord2d(0.0f, 0.0f); break;
276 	case 1:  glTexCoord2d(1.0f, 0.0f); break;
277 	case 2:  glTexCoord2d(1.0f, 1.0f); break;
278 	case 3:  glTexCoord2d(0.0f, 1.0f); break;
279 	}
280 	glVertex3f(
281 		position[0] - bilXX - bilYX,
282 		position[1] - bilXY - bilYY,
283 		position[2] - bilXZ - bilYZ);
284 	switch(textureCoord)
285 	{
286 	default: glTexCoord2d(1.0f, 0.0f); break;
287 	case 1:  glTexCoord2d(1.0f, 1.0f); break;
288 	case 2:  glTexCoord2d(0.0f, 1.0f); break;
289 	case 3:  glTexCoord2d(0.0f, 0.0f); break;
290 	}
291 	glVertex3f(
292 		position[0] + bilXX - bilYX,
293 		position[1] + bilXY - bilYY,
294 		position[2] + bilXZ - bilYZ);
295 	glEnd();
296 
297 	if (additive) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
298 }
299 
300