/* * 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 "course_load.h" #include "quadtree.h" #include "gameconfig.h" #include "ppogl/base/defs.h" #define CULL_DETAIL_FACTOR 25 static quadsquare *root = NULL; static quadcornerdata root_corner_data = { NULL }; void reset_course_quadtree() { delete root; root = NULL; } static int get_root_level(int nx, int nz) { PP_REQUIRE( nx > 0, "heightmap has x dimension of 0 size" ); PP_REQUIRE( nz > 0, "heightmap has z dimension of 0 size" ); int xlev, zlev; xlev = int( log(double(nx) ) / log (double(2.0) ) ); zlev = int( log(double(nz) ) / log (double(2.0) ) ); /* Check to see if nx, nz are powers of 2 */ if ( ( nx >> xlev ) << xlev == nx ) { /* do nothing */ } else { nx += 1; } if ( ( nz >> zlev ) << zlev == nz ) { /* do nothing */ } else { nz += 1; } return MAX( xlev, zlev ); } static void Vec3fo_float_array(float dest[3],const ppogl::Vec3d& src) { dest[0] = src.x(); dest[1] = src.y(); dest[2] = src.z(); } void init_course_quadtree(const float *elevation, int nx, int nz, double scalex, double scalez, const ppogl::Vec3d& view_pos) { HeightMapInfo hm; hm.Data = elevation; hm.XOrigin = 0; hm.ZOrigin = 0; hm.XSize = nx; hm.ZSize = nz; hm.RowWidth = hm.XSize; hm.Scale = 0; root_corner_data.Square = NULL; root_corner_data.ChildIndex = 0; root_corner_data.Level = get_root_level( nx, nz ); root_corner_data.xorg = 0; root_corner_data.zorg = 0; for(int i=0; i<4; i++){ root_corner_data.Verts[i] = 0; root_corner_data.Verts[i] = 0; } root = new quadsquare( &root_corner_data ); root->AddHeightMap( root_corner_data, hm ); root->SetScale( scalex, scalez ); root->SetTerrain(Course::getTerrainData() ); //update static configuration GameConfig::update(); // Debug info. //print_debug( DEBUG_QUADTREE, "nodes = %d\n", root->CountNodes()); PP_LOG( DEBUG_QUADTREE, "max error = " << root->RecomputeError(root_corner_data)); // Get rid of unnecessary nodes in flat-ish areas. PP_LOG( DEBUG_QUADTREE, "Culling unnecessary nodes (detail factor = " << CULL_DETAIL_FACTOR << ")..."); root->StaticCullData(root_corner_data, CULL_DETAIL_FACTOR); // Post-cull debug info. PP_LOG( DEBUG_QUADTREE, "nodes = " << root->CountNodes()); PP_LOG( DEBUG_QUADTREE, "max error = " << root->RecomputeError(root_corner_data)); // Run the update function a few times before we start rendering // to disable unnecessary quadsquares, so the first frame won't // be overloaded with tons of triangles. float ViewerLoc[3]; Vec3fo_float_array( ViewerLoc, view_pos ); for(int i = 0; i < 10; i++){ root->Update(root_corner_data, reinterpret_cast(ViewerLoc)); } } void update_course_quadtree(const ppogl::Vec3d& view_pos) { float ViewerLoc[3]; Vec3fo_float_array(ViewerLoc, view_pos); root->Update(root_corner_data, ViewerLoc); } void render_course_quadtree() { GLubyte *vnc_array; Course::getGLArrays( &vnc_array ); root->Render( root_corner_data, vnc_array ); }