/* * PlanetPenguin Racer * Copyright (C) 2004-2005 Volker Stroebel * * Copyright (C) 1999-2001 Jasmin F. Patry * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "viewfrustum.h" #include "loop.h" #include "ppogl/base/defs.h" #define DOT_PRODUCT( v1, v2 ) (double(v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z())) static pp::Plane frustum_planes[6]; /* This will be used as a bitfield to select the "n" and "p" vertices of the bounding boxes wrt to each plane. */ //static char p_vertex_code[6]; static bool p_vertex_code_x[6]; static bool p_vertex_code_y[6]; static bool p_vertex_code_z[6]; void setup_view_frustum(const Player& plyr, double near_dist, double far_dist, int multiscreen) { double aspect = double(GameMode::resolutionX) / double(GameMode::resolutionY); int i; ppogl::Vec3d pt; ppogl::Vec3d origin(0., 0., 0.); double half_fov = ANGLES_TO_RADIANS( GameConfig::fov * 0.5 ); double half_fov_horiz = atan(tan(half_fov) * aspect); if(multiscreen>=0){ //in multiscreen mode we have to double the horizontal aspect half_fov_horiz*=2; } // create frustum in viewing coordinates // near frustum_planes[0] = pp::Plane(0, 0, 1, near_dist); // far frustum_planes[1] = pp::Plane(0, 0, -1, -far_dist); // left frustum_planes[2] = pp::Plane( -cos(half_fov_horiz), 0, sin(half_fov_horiz), 0 ); // right frustum_planes[3] = pp::Plane( cos(half_fov_horiz), 0, sin(half_fov_horiz), 0 ); // top frustum_planes[4] = pp::Plane( 0, cos(half_fov), sin(half_fov), 0 ); // bottom frustum_planes[5] = pp::Plane( 0, -cos(half_fov), sin(half_fov), 0 ); // We now transform frustum to world coordinates for (i=0; i<6; i++) { pt = plyr.view.inv_view_mat.transformPoint( origin + (-frustum_planes[i].d*frustum_planes[i].nml) ); frustum_planes[i].nml = plyr.view.inv_view_mat.transformVector( frustum_planes[i].nml ); frustum_planes[i].d = -( frustum_planes[i].nml* (pt-origin)); } for (i=0; i<6; i++) { p_vertex_code_x[i] = false; p_vertex_code_y[i] = false; p_vertex_code_z[i] = false; if ( frustum_planes[i].nml.x() > 0 ) { p_vertex_code_x[i] = true; } if ( frustum_planes[i].nml.y() > 0 ) { p_vertex_code_y[i] = true; } if ( frustum_planes[i].nml.z() > 0 ) { p_vertex_code_z[i] = true; } } } /** View frustum clipping for AABB (axis-aligned bounding box). See Assarsson, Ulf and Tomas M\"oller, "Optimized View Frustum Culling Algorithms", unpublished, http://www.ce.chalmers.se/staff/uffe/ . */ ClipResult clip_aabb_to_view_frustum( const ppogl::Vec3d& min, const ppogl::Vec3d& max ) { ppogl::Vec3d n, p; ClipResult intersect = NoClip; for (int i=5; i>=0; i--) { p = min; n = max; if ( p_vertex_code_x[i]) { p.x() = max.x(); n.x() = min.x(); } if ( p_vertex_code_y[i]) { p.y() = max.y(); n.y() = min.y(); } if ( p_vertex_code_z[i]) { p.z() = max.z(); n.z() = min.z(); } if ( DOT_PRODUCT( n, frustum_planes[i].nml ) + frustum_planes[i].d > 0 ) { return NotVisible; } if ( DOT_PRODUCT( p, frustum_planes[i].nml ) + frustum_planes[i].d > 0 ) { intersect = SomeClip; } } return intersect; } const pp::Plane& get_far_clip_plane() { return frustum_planes[1]; } const pp::Plane& get_left_clip_plane() { return frustum_planes[2]; } const pp::Plane& get_right_clip_plane() { return frustum_planes[3]; } const pp::Plane& get_bottom_clip_plane() { return frustum_planes[5]; }