00001 // Filename: geoMipTerrain.I 00002 // Created by: rdb (29Jun07) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "config_grutil.h" 00016 00017 //////////////////////////////////////////////////////////////////// 00018 // Function: GeoMipTerrain::Constructor 00019 // Access: Published 00020 // Description: 00021 //////////////////////////////////////////////////////////////////// 00022 INLINE GeoMipTerrain:: 00023 GeoMipTerrain(const string &name) { 00024 _root = NodePath(name); 00025 _root_flattened = false; 00026 _xsize = 0; 00027 _ysize = 0; 00028 _block_size = 16; 00029 _max_level = 4; // Always log(_block_size) / log(2.0) 00030 _min_level = 0; 00031 _factor = 100.0; 00032 _near = 16.0; 00033 _far = 128.0; 00034 _use_near_far = false; 00035 _has_color_map = false; 00036 PT(PandaNode) tmpnode = new PandaNode("tmp_focal"); 00037 _auto_flatten = AFM_off; 00038 _focal_point = NodePath(tmpnode); 00039 _focal_is_temporary = true; 00040 _is_dirty = true; 00041 _bruteforce = false; 00042 _stitching = false; 00043 } 00044 00045 //////////////////////////////////////////////////////////////////// 00046 // Function: GeoMipTerrain::Destructor 00047 // Access: Published 00048 // Description: This will not remove the terrain node itself. 00049 // To have the terrain itself also deleted, please 00050 // call remove_node() prior to destruction. 00051 //////////////////////////////////////////////////////////////////// 00052 INLINE GeoMipTerrain:: 00053 ~GeoMipTerrain() { 00054 } 00055 00056 //////////////////////////////////////////////////////////////////// 00057 // Function: GeoMipTerrain::heightfield 00058 // Access: Published 00059 // Description: Returns a reference to the heightfield (a PNMImage) 00060 // contained inside GeoMipTerrain. You can use 00061 // the reference to alter the heightfield. 00062 //////////////////////////////////////////////////////////////////// 00063 INLINE PNMImage &GeoMipTerrain:: 00064 heightfield() { 00065 return _heightfield; 00066 } 00067 00068 //////////////////////////////////////////////////////////////////// 00069 // Function: GeoMipTerrain::color_map 00070 // Access: Published 00071 // Description: Returns a reference to the color map (a PNMImage) 00072 // contained inside GeoMipTerrain. You can use 00073 // the reference to alter the color map. 00074 //////////////////////////////////////////////////////////////////// 00075 INLINE PNMImage &GeoMipTerrain:: 00076 color_map() { 00077 return _color_map; 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: GeoMipTerrain::set_bruteforce 00082 // Access: Published 00083 // Description: Sets a boolean specifying whether the terrain will 00084 // be rendered bruteforce. If the terrain is rendered 00085 // bruteforce, there will be no Level of Detail, and 00086 // the update() call will only update the 00087 // terrain if it is marked dirty. 00088 //////////////////////////////////////////////////////////////////// 00089 INLINE void GeoMipTerrain:: 00090 set_bruteforce(bool bf) { 00091 if (bf == true && _bruteforce == false) { 00092 _is_dirty = true; 00093 } 00094 _bruteforce = bf; 00095 } 00096 00097 //////////////////////////////////////////////////////////////////// 00098 // Function: GeoMipTerrain::get_bruteforce 00099 // Access: Published 00100 // Description: Returns a boolean whether the terrain is rendered 00101 // bruteforce or not. See set_bruteforce for more 00102 // information. 00103 //////////////////////////////////////////////////////////////////// 00104 INLINE bool GeoMipTerrain:: 00105 get_bruteforce() { 00106 return _bruteforce; 00107 } 00108 00109 //////////////////////////////////////////////////////////////////// 00110 // Function: GeoMipTerrain::set_auto_flatten 00111 // Access: Private 00112 // Description: The terrain can be automatically flattened (using 00113 // flatten_light, flatten_medium, or flatten_strong) 00114 // after each update. This only affects future 00115 // updates, it doesn't flatten the current terrain. 00116 //////////////////////////////////////////////////////////////////// 00117 INLINE void GeoMipTerrain:: 00118 set_auto_flatten(int mode) { 00119 _auto_flatten = mode; 00120 } 00121 00122 //////////////////////////////////////////////////////////////////// 00123 // Function: GeoMipTerrain::set_focal_point 00124 // Access: Published 00125 // Description: Sets the focal point. GeoMipTerrain generates 00126 // high-resolution terrain around the focal point, and 00127 // progressively lower and lower resolution terrain 00128 // as you get farther away. If a point is supplied 00129 // and not a NodePath, make sure it's relative to 00130 // the terrain. Only the x and y coordinates of 00131 // the focal point are taken in respect. 00132 //////////////////////////////////////////////////////////////////// 00133 INLINE void GeoMipTerrain:: 00134 set_focal_point(double x, double y) { 00135 if (!_focal_is_temporary) { 00136 PT(PandaNode) tmpnode = new PandaNode("tmp_focal"); 00137 _focal_point = NodePath(tmpnode); 00138 } 00139 _focal_point.set_pos(_root, x, y, 0); 00140 _focal_is_temporary = true; 00141 } 00142 INLINE void GeoMipTerrain:: 00143 set_focal_point(const LPoint2d &fp) { 00144 set_focal_point(fp.get_x(), fp.get_y()); 00145 } 00146 INLINE void GeoMipTerrain:: 00147 set_focal_point(const LPoint2f &fp) { 00148 set_focal_point(double(fp.get_x()), double(fp.get_y())); 00149 } 00150 INLINE void GeoMipTerrain:: 00151 set_focal_point(const LPoint3d &fp) { 00152 set_focal_point(fp.get_x(), fp.get_y()); 00153 } 00154 INLINE void GeoMipTerrain:: 00155 set_focal_point(const LPoint3f &fp) { 00156 set_focal_point(double(fp.get_x()), double(fp.get_y())); 00157 } 00158 INLINE void GeoMipTerrain:: 00159 set_focal_point(NodePath fp) { 00160 if (_focal_is_temporary) { 00161 _focal_point.remove_node(); 00162 } 00163 _focal_point = fp; 00164 _focal_is_temporary = false; 00165 } 00166 00167 //////////////////////////////////////////////////////////////////// 00168 // Function: GeoMipTerrain::get_focal_point 00169 // Access: Published 00170 // Description: Returns the focal point, as a NodePath. 00171 // If you have set it to be just a point, it will 00172 // return an empty node at the focal position. 00173 //////////////////////////////////////////////////////////////////// 00174 INLINE NodePath GeoMipTerrain:: 00175 get_focal_point() const { 00176 return _focal_point; 00177 } 00178 00179 //////////////////////////////////////////////////////////////////// 00180 // Function: GeoMipTerrain::get_root 00181 // Access: Published 00182 // Description: Returns the root of the terrain. This is a 00183 // single PandaNode to which all the rest of the 00184 // terrain is parented. The generate and update 00185 // operations replace the nodes which are parented 00186 // to this root, but they don't replace this root 00187 // itself. 00188 //////////////////////////////////////////////////////////////////// 00189 INLINE NodePath GeoMipTerrain:: 00190 get_root() const { 00191 return _root; 00192 } 00193 00194 //////////////////////////////////////////////////////////////////// 00195 // Function: GeoMipTerrain::set_min_level 00196 // Access: Published 00197 // Description: Sets the minimum level of detail at which blocks 00198 // may be generated by generate() or update(). 00199 // The default value is 0, which is the highest 00200 // quality. This value is also taken in respect when 00201 // generating the terrain bruteforce. 00202 //////////////////////////////////////////////////////////////////// 00203 INLINE void GeoMipTerrain:: 00204 set_min_level(unsigned short minlevel) { 00205 _min_level = minlevel; 00206 } 00207 00208 //////////////////////////////////////////////////////////////////// 00209 // Function: GeoMipTerrain::get_min_level 00210 // Access: Published 00211 // Description: Gets the minimum level of detail at which blocks 00212 // may be generated by generate() or update(). 00213 // The default value is 0, which is the highest 00214 // quality. 00215 //////////////////////////////////////////////////////////////////// 00216 INLINE unsigned short GeoMipTerrain:: 00217 get_min_level() { 00218 return _min_level; 00219 } 00220 00221 //////////////////////////////////////////////////////////////////// 00222 // Function: GeoMipTerrain::get_max_level 00223 // Access: Published 00224 // Description: Returns the highest level possible for this block 00225 // size. When a block is at this level, it will be 00226 // the worst quality possible. 00227 //////////////////////////////////////////////////////////////////// 00228 INLINE unsigned short GeoMipTerrain:: 00229 get_max_level() { 00230 return _max_level; 00231 } 00232 00233 //////////////////////////////////////////////////////////////////// 00234 // Function: GeoMipTerrain::get_block_size 00235 // Access: Published 00236 // Description: Gets the block size. 00237 //////////////////////////////////////////////////////////////////// 00238 INLINE unsigned short GeoMipTerrain:: 00239 get_block_size() { 00240 return _block_size; 00241 } 00242 00243 //////////////////////////////////////////////////////////////////// 00244 // Function: GeoMipTerrain::set_block_size 00245 // Access: Published 00246 // Description: Sets the block size. If it is not a power of two, 00247 // the closest power of two is used. 00248 //////////////////////////////////////////////////////////////////// 00249 INLINE void GeoMipTerrain:: 00250 set_block_size(unsigned short newbs) { 00251 if (is_power_of_two(newbs)) { 00252 _block_size = newbs; 00253 } else { 00254 if (is_power_of_two(newbs - 1)) { 00255 _block_size = newbs - 1; 00256 } else { 00257 if (is_power_of_two(newbs + 1)) { 00258 _block_size = newbs + 1; 00259 } else { 00260 _block_size = (unsigned short) pow(2.0, 00261 floor(log((double) newbs) / log(2.0) + 0.5)); 00262 } 00263 } 00264 } 00265 _max_level = (unsigned short) (log((double) _block_size) / log(2.0)); 00266 _is_dirty = true; 00267 } 00268 00269 //////////////////////////////////////////////////////////////////// 00270 // Function: GeoMipTerrain::is_dirty 00271 // Access: Published 00272 // Description: Returns a bool indicating whether the terrain is 00273 // marked 'dirty', that means the terrain has to be 00274 // regenerated on the next update() call, because 00275 // for instance the heightfield has changed. 00276 // Once the terrain has been regenerated, the dirty 00277 // flag automatically gets reset internally. 00278 //////////////////////////////////////////////////////////////////// 00279 INLINE bool GeoMipTerrain:: 00280 is_dirty() { 00281 return _is_dirty; 00282 } 00283 00284 //////////////////////////////////////////////////////////////////// 00285 // Function: GeoMipTerrain::set_factor 00286 // Access: Published 00287 // Description: DEPRECATED method. Use set_near/far instead. 00288 // Sets the quality factor at which blocks must be 00289 // generated. The higher this level, the better 00290 // quality the terrain will be, but more expensive 00291 // to render. A value of 0 makes the terrain the 00292 // lowest quality possible, depending on blocksize. 00293 // The default value is 100. 00294 //////////////////////////////////////////////////////////////////// 00295 INLINE void GeoMipTerrain:: 00296 set_factor(PN_stdfloat factor) { 00297 grutil_cat.debug() << "Using deprecated method set_factor, use set_near and set_far instead!\n"; 00298 _use_near_far = false; 00299 _factor = factor; 00300 } 00301 00302 //////////////////////////////////////////////////////////////////// 00303 // Function: GeoMipTerrain::set_near_far 00304 // Access: Published 00305 // Description: Sets the near and far LOD distances in one call. 00306 //////////////////////////////////////////////////////////////////// 00307 INLINE void GeoMipTerrain:: 00308 set_near_far(double input_near, double input_far) { 00309 _use_near_far = true; 00310 _near = input_near; 00311 _far = input_far; 00312 } 00313 00314 //////////////////////////////////////////////////////////////////// 00315 // Function: GeoMipTerrain::set_near 00316 // Access: Published 00317 // Description: Sets the near LOD distance, at which the terrain 00318 // will be rendered at highest quality. 00319 // This distance is in the terrain's coordinate space! 00320 //////////////////////////////////////////////////////////////////// 00321 INLINE void GeoMipTerrain:: 00322 set_near(double input_near) { 00323 _use_near_far = true; 00324 _near = input_near; 00325 } 00326 00327 //////////////////////////////////////////////////////////////////// 00328 // Function: GeoMipTerrain::set_far 00329 // Access: Published 00330 // Description: Sets the far LOD distance, at which the terrain 00331 // will be rendered at lowest quality. 00332 // This distance is in the terrain's coordinate space! 00333 //////////////////////////////////////////////////////////////////// 00334 INLINE void GeoMipTerrain:: 00335 set_far(double input_far) { 00336 _use_near_far = true; 00337 _far = input_far; 00338 } 00339 00340 //////////////////////////////////////////////////////////////////// 00341 // Function: GeoMipTerrain::get_far 00342 // Access: Published 00343 // Description: Returns the far LOD distance in the terrain coordinate 00344 // space 00345 //////////////////////////////////////////////////////////////////// 00346 INLINE double GeoMipTerrain:: 00347 get_far() { 00348 return _far; 00349 } 00350 00351 //////////////////////////////////////////////////////////////////// 00352 // Function: GeoMipTerrain::get_near 00353 // Access: Published 00354 // Description: Returns the near LOD distance in the terrain coordinate 00355 // space 00356 //////////////////////////////////////////////////////////////////// 00357 INLINE double GeoMipTerrain:: 00358 get_near() { 00359 return _near; 00360 } 00361 00362 //////////////////////////////////////////////////////////////////// 00363 // Function: GeoMipTerrain::get_flatten_mode 00364 // Access: Published 00365 // Description: Returns the automatic-flatten mode (e.g., off, 00366 // flatten_light, flatten_medium, or flatten_strong) 00367 //////////////////////////////////////////////////////////////////// 00368 INLINE int GeoMipTerrain:: 00369 get_flatten_mode() { 00370 return _auto_flatten; 00371 } 00372 00373 //////////////////////////////////////////////////////////////////// 00374 // Function: GeoMipTerrain::get_block_node_path 00375 // Access: Published 00376 // Description: Returns the NodePath of the specified block. 00377 // If auto-flatten is enabled and the node is 00378 // getting removed during the flattening process, 00379 // it will still return a NodePath with the 00380 // appropriate terrain chunk, but it will be in 00381 // a temporary scenegraph. 00382 // Please note that this returns a const object and 00383 // you can not modify the node. Modify the heightfield 00384 // instead. 00385 //////////////////////////////////////////////////////////////////// 00386 INLINE const NodePath GeoMipTerrain:: 00387 get_block_node_path(unsigned short mx, unsigned short my) { 00388 return _blocks[mx][my]; 00389 } 00390 //////////////////////////////////////////////////////////////////// 00391 // Function: GeoMipTerrain::get_block_from_pos 00392 // Access: Published 00393 // Description: Gets the coordinates of the block at the specified 00394 // position. This position must be relative to the 00395 // terrain, not to render. Returns an array containing 00396 // two values: the block x and the block y coords. 00397 // If the positions are out of range, the closest 00398 // block is taken. 00399 // Note that the VecBase returned does not represent 00400 // a vector, position, or rotation, but it contains 00401 // the block index of the block which you can use 00402 // in GeoMipTerrain::get_block_node_path. 00403 //////////////////////////////////////////////////////////////////// 00404 INLINE LVecBase2 GeoMipTerrain:: 00405 get_block_from_pos(double x, double y) { 00406 if (x < 0) x = 0; 00407 if (y < 0) y = 0; 00408 if (x > _xsize - 1) x = _xsize - 1; 00409 if (y > _ysize - 1) y = _ysize - 1; 00410 x = floor(x / _block_size); 00411 y = floor(y / _block_size); 00412 return LVecBase2(x, y); 00413 } 00414 //////////////////////////////////////////////////////////////////// 00415 // Function: GeoMipTerrain::lod_decide 00416 // Access: Private 00417 // Description: Calculates the level for the given mipmap. 00418 //////////////////////////////////////////////////////////////////// 00419 INLINE unsigned short GeoMipTerrain:: 00420 lod_decide(unsigned short mx, unsigned short my) { 00421 PN_stdfloat cx = mx; 00422 PN_stdfloat cy = my; 00423 cx = (cx * _block_size + _block_size / 2) * _root.get_sx(); 00424 cy = (cy * _block_size + _block_size / 2) * _root.get_sy(); 00425 PN_stdfloat d; 00426 if (_use_near_far) { 00427 d = sqrt(pow(_focal_point.get_x(_root) - cx, 2) + 00428 pow(_focal_point.get_y(_root) - cy, 2)); 00429 if (d < _near) { 00430 return 0; 00431 } else if (d > _far) { 00432 return _max_level; 00433 } else { 00434 return (unsigned short)((d - _near) / (_far - _near) * _max_level * (1.0 - (_min_level / _max_level)) + _min_level); 00435 } 00436 } else { 00437 if (_factor > 0.0) { 00438 d = sqrt(pow(_focal_point.get_x(_root) - cx, 2) + 00439 pow(_focal_point.get_y(_root) - cy, 2)) / _factor; 00440 } else { 00441 d = _max_level; 00442 } 00443 return short(floor(d)); 00444 } 00445 } 00446 00447 //////////////////////////////////////////////////////////////////// 00448 // Function: GeoMipTerrain::set_heightfield 00449 // Access: Published 00450 // Description: Loads the specified heightmap image file into 00451 // the heightfield. Returns true if succeeded, or 00452 // false if an error has occured. 00453 // If the heightmap is not a power of two plus one, 00454 // it is scaled up using a gaussian filter. 00455 //////////////////////////////////////////////////////////////////// 00456 INLINE bool GeoMipTerrain:: 00457 set_heightfield(const PNMImage &image) { 00458 // Before we apply anything, validate the size. 00459 if(is_power_of_two(image.get_x_size() - 1) && is_power_of_two(image.get_y_size() - 1)) { 00460 _heightfield = image; 00461 _is_dirty = true; 00462 _xsize = _heightfield.get_x_size(); 00463 _ysize = _heightfield.get_y_size(); 00464 return true; 00465 } else { 00466 grutil_cat.error() << "Specified image does not have a power-of-two-plus-one size!\n"; 00467 } 00468 return false; 00469 } 00470 00471 INLINE bool GeoMipTerrain:: 00472 set_heightfield(const string &path) { 00473 return set_heightfield(Filename(path)); 00474 } 00475 00476 //////////////////////////////////////////////////////////////////// 00477 // Function: GeoMipTerrain::set_color_map 00478 // Access: Published 00479 // Description: Loads the specified image as color map. The next 00480 // time generate() is called, the terrain is painted 00481 // with this color map using the vertex color column. 00482 // Returns a boolean indicating whether the operation 00483 // has succeeded. 00484 //////////////////////////////////////////////////////////////////// 00485 INLINE bool GeoMipTerrain:: 00486 set_color_map(const Filename &filename, PNMFileType *ftype) { 00487 if (_color_map.read(filename, ftype)) { 00488 _is_dirty = true; 00489 _has_color_map = true; 00490 return true; 00491 } 00492 return false; 00493 } 00494 00495 INLINE bool GeoMipTerrain:: 00496 set_color_map(const PNMImage &image) { 00497 _color_map.copy_from(image); 00498 _is_dirty = true; 00499 _has_color_map = true; 00500 return true; 00501 } 00502 00503 INLINE bool GeoMipTerrain:: 00504 set_color_map(const Texture *tex) { 00505 tex->store(_color_map); 00506 _is_dirty = true; 00507 return true; 00508 } 00509 00510 INLINE bool GeoMipTerrain:: 00511 set_color_map(const string &path) { 00512 return set_color_map(Filename(path)); 00513 } 00514 00515 //////////////////////////////////////////////////////////////////// 00516 // Function: GeoMipTerrain::has_color_map 00517 // Access: Published 00518 // Description: Returns whether a color map has been set. 00519 //////////////////////////////////////////////////////////////////// 00520 INLINE bool GeoMipTerrain:: 00521 has_color_map() const { 00522 return _has_color_map; 00523 } 00524 00525 //////////////////////////////////////////////////////////////////// 00526 // Function: GeoMipTerrain::clear_color_map 00527 // Access: Published 00528 // Description: Clears the color map. 00529 //////////////////////////////////////////////////////////////////// 00530 INLINE void GeoMipTerrain:: 00531 clear_color_map() { 00532 if (_has_color_map) { 00533 _color_map.clear(); 00534 _has_color_map = false; 00535 } 00536 } 00537 00538 //////////////////////////////////////////////////////////////////// 00539 // Function: GeoMipTerrain::set_border_stitching 00540 // Access: Published 00541 // Description: If this value is true, the LOD level at the 00542 // borders of the terrain will be 0. This is useful 00543 // if you have multiple terrains attached and you 00544 // want to stitch them together, to fix seams. 00545 // This setting also has effect when bruteforce is 00546 // enabled, although in that case you are probably 00547 // better off with setting the minlevels to the same 00548 // value. 00549 //////////////////////////////////////////////////////////////////// 00550 INLINE void GeoMipTerrain:: 00551 set_border_stitching(bool stitching) { 00552 if (stitching && !_stitching) { 00553 _is_dirty = true; 00554 } 00555 _stitching = stitching; 00556 } 00557 00558 //////////////////////////////////////////////////////////////////// 00559 // Function: GeoMipTerrain::get_stitching 00560 // Access: Published 00561 // Description: Returns the current stitching setting. False by 00562 // default, unless set_stitching has been set. 00563 //////////////////////////////////////////////////////////////////// 00564 INLINE bool GeoMipTerrain:: 00565 get_border_stitching() { 00566 return _stitching; 00567 } 00568 00569 //////////////////////////////////////////////////////////////////// 00570 // Function: GeoMipTerrain::get_pixel_value 00571 // Access: Private 00572 // Description: Get the elevation at a certain pixel of the image. 00573 // This function does NOT linearly interpolate. 00574 // For that, use GeoMipTerrain::get_elevation() instead. 00575 //////////////////////////////////////////////////////////////////// 00576 INLINE double GeoMipTerrain:: 00577 get_pixel_value(int x, int y) { 00578 x = max(min(x,int(_xsize-1)),0); 00579 y = max(min(y,int(_ysize-1)),0); 00580 if (_heightfield.is_grayscale()) { 00581 return double(_heightfield.get_bright(x, y)); 00582 } else { 00583 return double(_heightfield.get_red(x, y)) 00584 + double(_heightfield.get_green(x, y)) / 256.0 00585 + double(_heightfield.get_blue(x, y)) / 65536.0; 00586 } 00587 } 00588 INLINE double GeoMipTerrain:: 00589 get_pixel_value(unsigned short mx, unsigned short my, int x, int y) { 00590 nassertr_always(mx < (_xsize - 1) / _block_size, false); 00591 nassertr_always(my < (_ysize - 1) / _block_size, false); 00592 return get_pixel_value(mx * _block_size + x, (_ysize - 1) - 00593 (my * _block_size + y)); 00594 } 00595 00596 //////////////////////////////////////////////////////////////////// 00597 // Function: GeoMipTerrain::get_normal 00598 // Access: Published 00599 // Description: Fetches the terrain normal at (x,y), where the input 00600 // coordinate is specified in pixels. This ignores the 00601 // current LOD level and instead provides an 00602 // accurate number. 00603 // Terrain scale is NOT taken into account! To get 00604 // accurate normals, please divide it by the 00605 // terrain scale and normalize it again! 00606 //////////////////////////////////////////////////////////////////// 00607 INLINE LVector3 GeoMipTerrain:: 00608 get_normal(unsigned short mx, unsigned short my, int x, int y) { 00609 nassertr_always(mx < (_xsize - 1) / _block_size, false); 00610 nassertr_always(my < (_ysize - 1) / _block_size, false); 00611 return get_normal(mx * _block_size + x, (_ysize - 1) - 00612 (my * _block_size + y)); 00613 } 00614 00615 //////////////////////////////////////////////////////////////////// 00616 // Function: GeoMipTerrain::is_power_of_two 00617 // Access: Private 00618 // Description: Returns a bool whether the given int i is a 00619 // power of two or not. 00620 //////////////////////////////////////////////////////////////////// 00621 INLINE bool GeoMipTerrain:: 00622 is_power_of_two(unsigned int i) { 00623 return !((i - 1) & i); 00624 } 00625 00626 //////////////////////////////////////////////////////////////////// 00627 // Function: GeoMipTerrain::f_part 00628 // Access: Private 00629 // Description: Returns the part of the number right of the 00630 // floating-point. 00631 //////////////////////////////////////////////////////////////////// 00632 INLINE float GeoMipTerrain:: 00633 f_part(float i) { 00634 return i - floor(i); 00635 } 00636 INLINE double GeoMipTerrain:: 00637 f_part(double i) { 00638 return i - floor(i); 00639 } 00640 00641 //////////////////////////////////////////////////////////////////// 00642 // Function: GeoMipTerrain::sfav 00643 // Access: Private 00644 // Description: Used to calculate vertex numbers. Only to 00645 // be used internally. 00646 //////////////////////////////////////////////////////////////////// 00647 INLINE int GeoMipTerrain:: 00648 sfav(int n, int powlevel, int mypowlevel) { 00649 double t = n - 1; 00650 t /= pow(2.0, powlevel - mypowlevel); 00651 t = double(int(t > 0.0 ? t + 0.5 : t - 0.5)); 00652 t *= pow(2.0, powlevel - mypowlevel); 00653 return int(t); 00654 } 00655