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