1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
|
/************************************************************************************
AstroMenace (Hardcore 3D space shooter with spaceship upgrade possibilities)
Copyright © 2006-2013 Michael Kurinnoy, Viewizard
AstroMenace is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
AstroMenace is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with AstroMenace. If not, see <http://www.gnu.org/licenses/>.
Web Site: http://www.viewizard.com/
Project: http://sourceforge.net/projects/openastromenace/
E-mail: viewizard@viewizard.com
*************************************************************************************/
#include "Camera.h"
#include "../RendererInterface/RendererInterface.h"
//-----------------------------------------------------------------------------
// локальные/защищенные переменные
//-----------------------------------------------------------------------------
// видимый объем пространства
float Frustum[6][4];
enum PlaneData
{
A = 0, // The X value of the plane's normal
B = 1, // The Y value of the plane's normal
C = 2, // The Z value of the plane's normal
D = 3 // The distance the plane is from the origin
};
enum Side
{
RIGHT = 0, // The RIGHT side
LEFT = 1, // The LEFT side
BOTTOM = 2, // The BOTTOM side
TOP = 3, // The TOP side
BACK = 4, // The BACK side
FRONT = 5 // The FRONT side
};
//-----------------------------------------------------------------------------
// This normalizes a plane (A side) from a given frustum.
//-----------------------------------------------------------------------------
void vw_NormalizePlane(float frustum[6][4], int side)
{
// Here we calculate the magnitude of the normal to the plane (point A B C)
// Remember that (A, B, C) is that same thing as the normal's (X, Y, Z).
// To calculate magnitude you use the equation: magnitude = sqrt( x^2 + y^2 + z^2)
float magnitude = vw_sqrtf( frustum[side][A] * frustum[side][A] +
frustum[side][B] * frustum[side][B] +
frustum[side][C] * frustum[side][C] );
// Then we divide the plane's values by it's magnitude.
// This makes it easier to work with.
frustum[side][A] /= magnitude;
frustum[side][B] /= magnitude;
frustum[side][C] /= magnitude;
frustum[side][D] /= magnitude;
}
//-----------------------------------------------------------------------------
// Call this every time the camera moves to update the frustum
//-----------------------------------------------------------------------------
void vw_CalculateFrustum(void)
{
float proj[16]; // This will hold our projection matrix
float modl[16]; // This will hold our modelview matrix
float clip[16]; // This will hold the clipping planes
// glGetFloatv() is used to extract information about our OpenGL world.
// Below, we pass in GL_PROJECTION_MATRIX to abstract our projection matrix.
// It then stores the matrix into an array of [16].
vw_GetMatrix(RI_PROJECTION_MATRIX, proj);
// By passing in GL_MODELVIEW_MATRIX, we can abstract our model view matrix.
// This also stores it in an array of [16].
vw_GetMatrix(RI_MODELVIEW_MATRIX, modl);
// Now that we have our modelview and projection matrix, if we combine these 2 matrices,
// it will give us our clipping planes. To combine 2 matrices, we multiply them.
clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
// Now we actually want to get the sides of the frustum. To do this we take
// the clipping planes we received above and extract the sides from them.
// This will extract the RIGHT side of the frustum
Frustum[RIGHT][A] = clip[ 3] - clip[ 0];
Frustum[RIGHT][B] = clip[ 7] - clip[ 4];
Frustum[RIGHT][C] = clip[11] - clip[ 8];
Frustum[RIGHT][D] = clip[15] - clip[12];
// Now that we have a normal (A,B,C) and a distance (D) to the plane,
// we want to normalize that normal and distance.
// Normalize the RIGHT side
vw_NormalizePlane(Frustum, RIGHT);
// This will extract the LEFT side of the frustum
Frustum[LEFT][A] = clip[ 3] + clip[ 0];
Frustum[LEFT][B] = clip[ 7] + clip[ 4];
Frustum[LEFT][C] = clip[11] + clip[ 8];
Frustum[LEFT][D] = clip[15] + clip[12];
// Normalize the LEFT side
vw_NormalizePlane(Frustum, LEFT);
// This will extract the BOTTOM side of the frustum
Frustum[BOTTOM][A] = clip[ 3] + clip[ 1];
Frustum[BOTTOM][B] = clip[ 7] + clip[ 5];
Frustum[BOTTOM][C] = clip[11] + clip[ 9];
Frustum[BOTTOM][D] = clip[15] + clip[13];
// Normalize the BOTTOM side
vw_NormalizePlane(Frustum, BOTTOM);
// This will extract the TOP side of the frustum
Frustum[TOP][A] = clip[ 3] - clip[ 1];
Frustum[TOP][B] = clip[ 7] - clip[ 5];
Frustum[TOP][C] = clip[11] - clip[ 9];
Frustum[TOP][D] = clip[15] - clip[13];
// Normalize the TOP side
vw_NormalizePlane(Frustum, TOP);
// This will extract the BACK side of the frustum
Frustum[BACK][A] = clip[ 3] - clip[ 2];
Frustum[BACK][B] = clip[ 7] - clip[ 6];
Frustum[BACK][C] = clip[11] - clip[10];
Frustum[BACK][D] = clip[15] - clip[14];
// Normalize the BACK side
vw_NormalizePlane(Frustum, BACK);
// This will extract the FRONT side of the frustum
Frustum[FRONT][A] = clip[ 3] + clip[ 2];
Frustum[FRONT][B] = clip[ 7] + clip[ 6];
Frustum[FRONT][C] = clip[11] + clip[10];
Frustum[FRONT][D] = clip[15] + clip[14];
// Normalize the FRONT side
vw_NormalizePlane(Frustum, FRONT);
}
//-----------------------------------------------------------------------------
// This takes a 3D point and returns TRUE if it's inside of the frustum
//-----------------------------------------------------------------------------
bool vw_PointInFrustum(VECTOR3D Point)
{
// Go through all the sides of the frustum
for(int i = 0; i < 6; i++ )
{
// Calculate the plane equation and check if the point is behind a side of the frustum
if(Frustum[i][A] * Point.x + Frustum[i][B] * Point.y + Frustum[i][C] * Point.z + Frustum[i][D] <= 0)
{
// The point was behind a side, so it ISN'T in the frustum
return false;
}
}
// The point was inside of the frustum (In front of ALL the sides of the frustum)
return true;
}
//-----------------------------------------------------------------------------
// This takes a 3D point and a radius and returns TRUE if the sphere is inside of the frustum
//-----------------------------------------------------------------------------
bool vw_SphereInFrustum(VECTOR3D Point, float radius)
{
// Go through all the sides of the frustum
for(int i = 0; i < 6; i++ )
{
// If the center of the sphere is farther away from the plane than the radius
if( Frustum[i][A] * Point.x + Frustum[i][B] * Point.y + Frustum[i][C] * Point.z + Frustum[i][D] <= -radius )
{
// The distance was greater than the radius so the sphere is outside of the frustum
return false;
}
}
// The sphere was inside of the frustum!
return true;
}
//-----------------------------------------------------------------------------
// This takes the center and half the length of the cube.
//-----------------------------------------------------------------------------
bool vw_CubeInFrustum(VECTOR3D CenterPoint, float size)
{
// Basically, what is going on is, that we are given the center of the cube,
// and half the length. Think of it like a radius. Then we checking each point
// in the cube and seeing if it is inside the frustum. If a point is found in front
// of a side, then we skip to the next side. If we get to a plane that does NOT have
// a point in front of it, then it will return false.
// *Note* - This will sometimes say that a cube is inside the frustum when it isn't.
// This happens when all the corners of the bounding box are not behind any one plane.
// This is rare and shouldn't effect the overall rendering speed.
// поставить доп проверку...
for(int i = 0; i < 6; i++ )
{
if(Frustum[i][A] * (CenterPoint.x - size) + Frustum[i][B] * (CenterPoint.y - size) + Frustum[i][C] * (CenterPoint.z - size) + Frustum[i][D] > 0)
continue;
if(Frustum[i][A] * (CenterPoint.x + size) + Frustum[i][B] * (CenterPoint.y - size) + Frustum[i][C] * (CenterPoint.z - size) + Frustum[i][D] > 0)
continue;
if(Frustum[i][A] * (CenterPoint.x - size) + Frustum[i][B] * (CenterPoint.y + size) + Frustum[i][C] * (CenterPoint.z - size) + Frustum[i][D] > 0)
continue;
if(Frustum[i][A] * (CenterPoint.x + size) + Frustum[i][B] * (CenterPoint.y + size) + Frustum[i][C] * (CenterPoint.z - size) + Frustum[i][D] > 0)
continue;
if(Frustum[i][A] * (CenterPoint.x - size) + Frustum[i][B] * (CenterPoint.y - size) + Frustum[i][C] * (CenterPoint.z + size) + Frustum[i][D] > 0)
continue;
if(Frustum[i][A] * (CenterPoint.x + size) + Frustum[i][B] * (CenterPoint.y - size) + Frustum[i][C] * (CenterPoint.z + size) + Frustum[i][D] > 0)
continue;
if(Frustum[i][A] * (CenterPoint.x - size) + Frustum[i][B] * (CenterPoint.y + size) + Frustum[i][C] * (CenterPoint.z + size) + Frustum[i][D] > 0)
continue;
if(Frustum[i][A] * (CenterPoint.x + size) + Frustum[i][B] * (CenterPoint.y + size) + Frustum[i][C] * (CenterPoint.z + size) + Frustum[i][D] > 0)
continue;
// If we get here, it isn't in the frustum
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// This checks if a box is in the frustum
//-----------------------------------------------------------------------------
bool vw_BoxInFrustum(VECTOR3D MinPoint, VECTOR3D MaxPoint)
{
// Go through all of the corners of the box and check then again each plane
// in the frustum. If all of them are behind one of the planes, then it most
// like is not in the frustum.
// *Note* - This will sometimes say that a box is inside the frustum when it isn't.
// This happens when all the corners of the bounding box are not behind any one plane.
// This is rare and shouldn't effect the overall rendering speed.
// поставить доп проверку...
for(int i = 0; i < 6; i++ )
{
if(Frustum[i][A] * MinPoint.x + Frustum[i][B] * MinPoint.y + Frustum[i][C] * MinPoint.z + Frustum[i][D] > 0) continue;
if(Frustum[i][A] * MaxPoint.x + Frustum[i][B] * MinPoint.y + Frustum[i][C] * MinPoint.z + Frustum[i][D] > 0) continue;
if(Frustum[i][A] * MinPoint.x + Frustum[i][B] * MaxPoint.y + Frustum[i][C] * MinPoint.z + Frustum[i][D] > 0) continue;
if(Frustum[i][A] * MaxPoint.x + Frustum[i][B] * MaxPoint.y + Frustum[i][C] * MinPoint.z + Frustum[i][D] > 0) continue;
if(Frustum[i][A] * MinPoint.x + Frustum[i][B] * MinPoint.y + Frustum[i][C] * MaxPoint.z + Frustum[i][D] > 0) continue;
if(Frustum[i][A] * MaxPoint.x + Frustum[i][B] * MinPoint.y + Frustum[i][C] * MaxPoint.z + Frustum[i][D] > 0) continue;
if(Frustum[i][A] * MinPoint.x + Frustum[i][B] * MaxPoint.y + Frustum[i][C] * MaxPoint.z + Frustum[i][D] > 0) continue;
if(Frustum[i][A] * MaxPoint.x + Frustum[i][B] * MaxPoint.y + Frustum[i][C] * MaxPoint.z + Frustum[i][D] > 0) continue;
// If we get here, it isn't in the frustum
return false;
}
// Return a true for the box being inside of the frustum
return true;
}
|