Panda3D
|
00001 // Filename: speedTreeNode.cxx 00002 // Created by: drose (13Mar09) 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 "pandabase.h" 00016 #include "speedTreeNode.h" 00017 #include "stBasicTerrain.h" 00018 #include "virtualFileSystem.h" 00019 #include "config_util.h" 00020 #include "cullTraverser.h" 00021 #include "cullableObject.h" 00022 #include "cullHandler.h" 00023 #include "omniBoundingVolume.h" 00024 #include "boundingSphere.h" 00025 #include "boundingBox.h" 00026 #include "clockObject.h" 00027 #include "geomDrawCallbackData.h" 00028 #include "graphicsStateGuardian.h" 00029 #include "textureAttrib.h" 00030 #include "lightAttrib.h" 00031 #include "directionalLight.h" 00032 #include "ambientLight.h" 00033 #include "loader.h" 00034 #include "deg_2_rad.h" 00035 #include "sceneGraphReducer.h" 00036 #include "pStatTimer.h" 00037 00038 #ifdef SPEEDTREE_OPENGL 00039 #include "glew/glew.h" 00040 #endif // SPEEDTREE_OPENGL 00041 00042 #ifdef SPEEDTREE_DIRECTX9 00043 #include "dxGraphicsStateGuardian9.h" 00044 #endif 00045 00046 double SpeedTreeNode::_global_time_delta = 0.0; 00047 bool SpeedTreeNode::_authorized; 00048 bool SpeedTreeNode::_done_first_init; 00049 TypeHandle SpeedTreeNode::_type_handle; 00050 TypeHandle SpeedTreeNode::DrawCallback::_type_handle; 00051 00052 PStatCollector SpeedTreeNode::_cull_speedtree_pcollector("Cull:SpeedTree"); 00053 PStatCollector SpeedTreeNode::_cull_speedtree_shadows_pcollector("Cull:SpeedTree:Shadows"); 00054 PStatCollector SpeedTreeNode::_cull_speedtree_trees_pcollector("Cull:SpeedTree:Trees"); 00055 PStatCollector SpeedTreeNode::_cull_speedtree_terrain_pcollector("Cull:SpeedTree:Terrain"); 00056 PStatCollector SpeedTreeNode::_draw_speedtree_pcollector("Draw:SpeedTree"); 00057 PStatCollector SpeedTreeNode::_draw_speedtree_shadows_pcollector("Draw:SpeedTree:Shadows"); 00058 PStatCollector SpeedTreeNode::_draw_speedtree_trees_pcollector("Draw:SpeedTree:Trees"); 00059 PStatCollector SpeedTreeNode::_draw_speedtree_terrain_pcollector("Draw:SpeedTree:Terrain"); 00060 PStatCollector SpeedTreeNode::_draw_speedtree_terrain_update_pcollector("Draw:SpeedTree:Terrain:Update"); 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: SpeedTreeNode::Constructor 00064 // Access: Published 00065 // Description: 00066 //////////////////////////////////////////////////////////////////// 00067 SpeedTreeNode:: 00068 SpeedTreeNode(const string &name) : 00069 PandaNode(name), 00070 #ifdef ST_DELETE_FOREST_HACK 00071 // Early versions of SpeedTree don't destruct unused CForestRender 00072 // objects correctly. To avoid crashes, we have to leak these 00073 // things. 00074 _forest_render(*(new SpeedTree::CForestRender)), 00075 #endif 00076 _time_delta(0.0) 00077 { 00078 init_node(); 00079 // For now, set an infinite bounding volume. Maybe in the future 00080 // we'll change this to match whatever set of trees we're holding, 00081 // though it probably doesn't really matter too much. 00082 //set_internal_bounds(new OmniBoundingVolume); 00083 // set_internal_bounds(new BoundingSphere(LPoint3::zero(), 10.0f)); 00084 00085 // Intialize the render params. First, get the shader directory. 00086 Filename shaders_dir = speedtree_shaders_dir; 00087 00088 // We expect the shader directory to contain at least this one token 00089 // filename (to prove it's the right directory). 00090 Filename token_filename = "Branch.hlsl"; 00091 if (!Filename(shaders_dir, token_filename).exists()) { 00092 // If that shader directory doesn't work, look along the model-path. 00093 if (token_filename.resolve_filename(get_model_path())) { 00094 shaders_dir = token_filename.get_dirname(); 00095 } else { 00096 if (!shaders_dir.is_directory()) { 00097 speedtree_cat.warning() 00098 << "speedtree-shaders-dir is set to " << shaders_dir 00099 << ", which doesn't exist.\n"; 00100 } else { 00101 speedtree_cat.warning() 00102 << "speedtree-shaders-dir is set to " << shaders_dir 00103 << ", which exists but doesn't contain " << token_filename 00104 << ".\n"; 00105 } 00106 } 00107 } 00108 00109 _os_shaders_dir = shaders_dir.to_os_specific(); 00110 // Ensure the path ends with a terminal slash; SpeedTree requires this. 00111 #if defined(WIN32) || defined(WIN64) 00112 if (!_os_shaders_dir.empty() && _os_shaders_dir[_os_shaders_dir.length() - 1] != '\\') { 00113 _os_shaders_dir += "\\"; 00114 } 00115 #else 00116 if (!_os_shaders_dir.empty() && _os_shaders_dir[_os_shaders_dir.length() - 1] != '/') { 00117 _os_shaders_dir += "/"; 00118 } 00119 #endif 00120 00121 SpeedTree::SForestRenderInfo render_info; 00122 render_info.m_strShaderPath = _os_shaders_dir.c_str(); 00123 _forest_render.SetRenderInfo(render_info); 00124 00125 // Now apply the rest of the config settings. 00126 reload_config(); 00127 } 00128 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: SpeedTreeNode::count_total_instances 00131 // Access: Published 00132 // Description: Returns the total number of trees that will be 00133 // rendered by this node, counting all instances of all 00134 // trees. 00135 //////////////////////////////////////////////////////////////////// 00136 int SpeedTreeNode:: 00137 count_total_instances() const { 00138 int total_instances = 0; 00139 Trees::const_iterator ti; 00140 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 00141 InstanceList *instance_list = (*ti); 00142 total_instances += instance_list->get_num_instances(); 00143 } 00144 00145 return total_instances; 00146 } 00147 00148 //////////////////////////////////////////////////////////////////// 00149 // Function: SpeedTreeNode::add_tree 00150 // Access: Published 00151 // Description: Adds a new tree for rendering. Returns the 00152 // InstanceList which can be used to add to the 00153 // instances for this tree. If the tree has previously 00154 // been added, returns the existing InstanceList. 00155 //////////////////////////////////////////////////////////////////// 00156 SpeedTreeNode::InstanceList &SpeedTreeNode:: 00157 add_tree(const STTree *tree) { 00158 nassertr(is_valid(), *(InstanceList *)NULL); 00159 nassertr(tree->is_valid(), *(InstanceList *)NULL); 00160 00161 InstanceList ilist(tree); 00162 Trees::iterator ti = _trees.find(&ilist); 00163 if (ti == _trees.end()) { 00164 // This is the first time that this particular tree has been 00165 // added. 00166 InstanceList *instance_list = new InstanceList(tree); 00167 pair<Trees::iterator, bool> result = _trees.insert(instance_list); 00168 ti = result.first; 00169 bool inserted = result.second; 00170 nassertr(inserted, *(*ti)); 00171 00172 if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->get_tree())) { 00173 speedtree_cat.warning() 00174 << "Failed to register tree " << tree->get_fullpath() << "\n"; 00175 write_error(speedtree_cat.warning()); 00176 } 00177 } 00178 00179 _needs_repopulate = true; 00180 mark_internal_bounds_stale(); 00181 InstanceList *instance_list = (*ti); 00182 return *instance_list; 00183 } 00184 00185 //////////////////////////////////////////////////////////////////// 00186 // Function: SpeedTreeNode::remove_tree 00187 // Access: Published 00188 // Description: Removes all instances of the indicated tree. Returns 00189 // the number of instances removed. 00190 //////////////////////////////////////////////////////////////////// 00191 int SpeedTreeNode:: 00192 remove_tree(const STTree *tree) { 00193 InstanceList ilist(tree); 00194 Trees::iterator ti = _trees.find(&ilist); 00195 if (ti == _trees.end()) { 00196 // The tree was not already present. 00197 return 0; 00198 } 00199 00200 if (!_forest_render.UnregisterTree(tree->get_tree())) { 00201 speedtree_cat.warning() 00202 << "Failed to unregister tree " << tree->get_fullpath() << "\n"; 00203 write_error(speedtree_cat.warning()); 00204 } 00205 00206 _needs_repopulate = true; 00207 mark_internal_bounds_stale(); 00208 00209 InstanceList *instance_list = (*ti); 00210 int num_removed = instance_list->get_num_instances(); 00211 _trees.erase(ti); 00212 delete instance_list; 00213 00214 return num_removed; 00215 } 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: SpeedTreeNode::remove_all_trees 00219 // Access: Published 00220 // Description: Removes all instances of all trees from the node. 00221 //////////////////////////////////////////////////////////////////// 00222 void SpeedTreeNode:: 00223 remove_all_trees() { 00224 Trees::iterator ti; 00225 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 00226 InstanceList *instance_list = (*ti); 00227 const STTree *tree = instance_list->get_tree(); 00228 if (!_forest_render.UnregisterTree(tree->get_tree())) { 00229 speedtree_cat.warning() 00230 << "Failed to unregister tree " << tree->get_fullpath() << "\n"; 00231 write_error(speedtree_cat.warning()); 00232 } 00233 delete instance_list; 00234 } 00235 00236 _trees.clear(); 00237 _needs_repopulate = true; 00238 mark_internal_bounds_stale(); 00239 } 00240 00241 //////////////////////////////////////////////////////////////////// 00242 // Function: SpeedTreeNode::has_instance_list 00243 // Access: Published 00244 // Description: Returns true if the indicated tree has any instances 00245 // within this node, false otherwise. 00246 //////////////////////////////////////////////////////////////////// 00247 bool SpeedTreeNode:: 00248 has_instance_list(const STTree *tree) const { 00249 InstanceList ilist(tree); 00250 Trees::const_iterator ti = _trees.find(&ilist); 00251 return (ti != _trees.end()); 00252 } 00253 00254 //////////////////////////////////////////////////////////////////// 00255 // Function: SpeedTreeNode::get_instance_list 00256 // Access: Published 00257 // Description: Returns a list of transforms that corresponds to the 00258 // instances at which the indicated tree appears. You 00259 // should ensure that has_instance_list() returns true 00260 // before calling this method. 00261 //////////////////////////////////////////////////////////////////// 00262 const SpeedTreeNode::InstanceList &SpeedTreeNode:: 00263 get_instance_list(const STTree *tree) const { 00264 InstanceList ilist(tree); 00265 Trees::const_iterator ti = _trees.find(&ilist); 00266 if (ti == _trees.end()) { 00267 // The tree was not already present. 00268 static InstanceList empty_list((STTree *)NULL); 00269 return empty_list; 00270 } 00271 00272 InstanceList *instance_list = (*ti); 00273 return *instance_list; 00274 } 00275 00276 //////////////////////////////////////////////////////////////////// 00277 // Function: SpeedTreeNode::modify_instance_list 00278 // Access: Published 00279 // Description: Returns a modifiable list of transforms that 00280 // corresponds to the instances of this tree. This is 00281 // equivalent to add_tree(). 00282 //////////////////////////////////////////////////////////////////// 00283 SpeedTreeNode::InstanceList &SpeedTreeNode:: 00284 modify_instance_list(const STTree *tree) { 00285 return add_tree(tree); 00286 } 00287 00288 //////////////////////////////////////////////////////////////////// 00289 // Function: SpeedTreeNode::add_instance 00290 // Access: Published 00291 // Description: Adds a new instance of the indicated tree at the 00292 // indicated transform. 00293 //////////////////////////////////////////////////////////////////// 00294 void SpeedTreeNode:: 00295 add_instance(const STTree *tree, const STTransform &transform) { 00296 if (speedtree_follow_terrain && has_terrain()) { 00297 STTransform new_transform = transform; 00298 new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]); 00299 add_tree(tree).add_instance(new_transform); 00300 } else { 00301 add_tree(tree).add_instance(transform); 00302 } 00303 } 00304 00305 //////////////////////////////////////////////////////////////////// 00306 // Function: SpeedTreeNode::add_instances 00307 // Access: Published 00308 // Description: Walks the scene graph beginning at root, looking for 00309 // nested SpeedTreeNodes. For each SpeedTreeNode found, 00310 // adds all of the instances defined within that 00311 // SpeedTreeNode as instances of this node, after 00312 // applying the indicated scene-graph transform. 00313 //////////////////////////////////////////////////////////////////// 00314 void SpeedTreeNode:: 00315 add_instances(const NodePath &root, const TransformState *transform) { 00316 nassertv(!root.is_empty()); 00317 r_add_instances(root.node(), transform->compose(root.get_transform()), 00318 Thread::get_current_thread()); 00319 } 00320 00321 //////////////////////////////////////////////////////////////////// 00322 // Function: SpeedTreeNode::add_instances_from 00323 // Access: Published 00324 // Description: Adds all of the instances defined within the 00325 // indicated SpeedTreeNode as instances of this node. 00326 // Does not recurse to children. 00327 //////////////////////////////////////////////////////////////////// 00328 void SpeedTreeNode:: 00329 add_instances_from(const SpeedTreeNode *other) { 00330 int num_trees = other->get_num_trees(); 00331 for (int ti = 0; ti < num_trees; ++ti) { 00332 const InstanceList &other_instance_list = other->get_instance_list(ti); 00333 const STTree *tree = other_instance_list.get_tree(); 00334 InstanceList &this_instance_list = add_tree(tree); 00335 00336 int num_instances = other_instance_list.get_num_instances(); 00337 for (int i = 0; i < num_instances; ++i) { 00338 STTransform other_trans = other_instance_list.get_instance(i); 00339 this_instance_list.add_instance(other_trans); 00340 } 00341 } 00342 } 00343 00344 //////////////////////////////////////////////////////////////////// 00345 // Function: SpeedTreeNode::add_instances_from 00346 // Access: Published 00347 // Description: Adds all of the instances defined within the 00348 // indicated SpeedTreeNode as instances of this node, 00349 // after applying the indicated scene-graph transform. 00350 // Does not recurse to children. 00351 //////////////////////////////////////////////////////////////////// 00352 void SpeedTreeNode:: 00353 add_instances_from(const SpeedTreeNode *other, const TransformState *transform) { 00354 int num_trees = other->get_num_trees(); 00355 for (int ti = 0; ti < num_trees; ++ti) { 00356 const InstanceList &other_instance_list = other->get_instance_list(ti); 00357 const STTree *tree = other_instance_list.get_tree(); 00358 InstanceList &this_instance_list = add_tree(tree); 00359 00360 int num_instances = other_instance_list.get_num_instances(); 00361 for (int i = 0; i < num_instances; ++i) { 00362 CPT(TransformState) other_trans = other_instance_list.get_instance(i); 00363 CPT(TransformState) new_trans = transform->compose(other_trans); 00364 00365 if (speedtree_follow_terrain && has_terrain()) { 00366 STTransform new_transform = new_trans; 00367 new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]); 00368 this_instance_list.add_instance(new_transform); 00369 00370 } else { 00371 this_instance_list.add_instance(new_trans.p()); 00372 } 00373 } 00374 } 00375 } 00376 00377 //////////////////////////////////////////////////////////////////// 00378 // Function: SpeedTreeNode::add_random_instances 00379 // Access: Published 00380 // Description: Creates a number of random instances of the indicated 00381 // true, within the indicated range. If a terrain is 00382 // present, height_min and height_max restrict trees to 00383 // the (x, y) positions that fall within the indicated 00384 // terrain, and slope_min and slope_max restrict trees 00385 // to the (x, y) positions that have a matching slope. 00386 // If a terrain is not present, height_min and 00387 // height_max specify a random range of Z heights, and 00388 // slope_min and slope_max are ignored. 00389 //////////////////////////////////////////////////////////////////// 00390 void SpeedTreeNode:: 00391 add_random_instances(const STTree *tree, int quantity, 00392 PN_stdfloat x_min, PN_stdfloat x_max, 00393 PN_stdfloat y_min, PN_stdfloat y_max, 00394 PN_stdfloat scale_min, PN_stdfloat scale_max, 00395 PN_stdfloat height_min, PN_stdfloat height_max, 00396 PN_stdfloat slope_min, PN_stdfloat slope_max, 00397 Randomizer &randomizer) { 00398 InstanceList &instance_list = add_tree(tree); 00399 _needs_repopulate = true; 00400 00401 for (int i = 0; i < quantity; ++i) { 00402 STTransform transform; 00403 transform._pos[0] = randomizer.random_real(x_max - x_min) + x_min; 00404 transform._pos[1] = randomizer.random_real(y_max - y_min) + y_min; 00405 transform._rotate = randomizer.random_real(360.0); 00406 transform._scale = randomizer.random_real(scale_max - scale_min) + scale_min; 00407 00408 if (has_terrain()) { 00409 // Spin till we find a valid match with terrain. 00410 int repeat_count = speedtree_max_random_try_count; 00411 while (!_terrain->placement_is_acceptable(transform._pos[0], transform._pos[1], height_min, height_max, slope_min, slope_max)) { 00412 transform._pos[0] = randomizer.random_real(x_max - x_min) + x_min; 00413 transform._pos[1] = randomizer.random_real(y_max - y_min) + y_min; 00414 if (--repeat_count == 0) { 00415 nassert_raise("Exceeded speedtree-max-random-try-count; bad placement parameters?"); 00416 return; 00417 } 00418 } 00419 transform._pos[2] = _terrain->get_height(transform._pos[0], transform._pos[1]); 00420 00421 } else { 00422 // No terrain; just pick a random height. 00423 transform._pos[2] = randomizer.random_real(height_max - height_min) + height_min; 00424 } 00425 instance_list.add_instance(transform); 00426 } 00427 } 00428 00429 //////////////////////////////////////////////////////////////////// 00430 // Function: SpeedTreeNode::add_from_stf 00431 // Access: Published 00432 // Description: Opens and reads the named STF (SpeedTree Forest) 00433 // file, and adds the SRT files named within as 00434 // instances of this node. Returns true on success, 00435 // false on failure. 00436 //////////////////////////////////////////////////////////////////// 00437 bool SpeedTreeNode:: 00438 add_from_stf(const Filename &stf_filename, const LoaderOptions &options) { 00439 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00440 00441 Filename fullpath = Filename::text_filename(stf_filename); 00442 vfs->resolve_filename(fullpath, get_model_path()); 00443 00444 if (!vfs->exists(fullpath)) { 00445 speedtree_cat.warning() 00446 << "Couldn't find " << stf_filename << "\n"; 00447 return false; 00448 } 00449 00450 PT(VirtualFile) file = vfs->get_file(fullpath); 00451 if (file == (VirtualFile *)NULL) { 00452 // No such file. 00453 speedtree_cat.error() 00454 << "Could not find " << stf_filename << "\n"; 00455 return false; 00456 } 00457 00458 if (speedtree_cat.is_debug()) { 00459 speedtree_cat.debug() 00460 << "Reading STF file " << fullpath << "\n"; 00461 } 00462 00463 istream *in = file->open_read_file(true); 00464 bool success = add_from_stf(*in, fullpath, options); 00465 vfs->close_read_file(in); 00466 00467 return success; 00468 } 00469 00470 //////////////////////////////////////////////////////////////////// 00471 // Function: SpeedTreeNode::add_from_stf 00472 // Access: Published 00473 // Description: Reads text data from the indicated stream, which is 00474 // understood to represent the named STF (SpeedTree 00475 // Forest) file, and adds the SRT files named within as 00476 // instances of this node. Returns true on success, 00477 // false on failure. 00478 // 00479 // The pathname is used for reference only; if nonempty, 00480 // it provides a search directory for named SRT files. 00481 // 00482 // The Loader and LoaderOptions, if provided, are used 00483 // to load the SRT files. If the Loader pointer is 00484 // NULL, the default global Loader is used instead. 00485 //////////////////////////////////////////////////////////////////// 00486 bool SpeedTreeNode:: 00487 add_from_stf(istream &in, const Filename &pathname, 00488 const LoaderOptions &options, Loader *loader) { 00489 if (loader == NULL) { 00490 loader = Loader::get_global_ptr(); 00491 } 00492 string os_filename; 00493 00494 Filename dirname = pathname.get_dirname(); 00495 dirname.make_absolute(); 00496 DSearchPath search; 00497 search.append_directory(dirname); 00498 00499 typedef pmap<Filename, CPT(STTree) > AlreadyLoaded; 00500 AlreadyLoaded already_loaded; 00501 00502 // The STF file format doesn't allow for spaces in the SRT filename. 00503 in >> os_filename; 00504 while (in && !in.eof()) { 00505 CPT(STTree) tree; 00506 Filename srt_filename = Filename::from_os_specific(os_filename); 00507 AlreadyLoaded::iterator ai = already_loaded.find(srt_filename); 00508 if (ai != already_loaded.end()) { 00509 tree = (*ai).second; 00510 } else { 00511 // Resolve the SRT filename relative to the STF file first. 00512 srt_filename.resolve_filename(search); 00513 00514 // Now load up the SRT file using the Panda loader (which will 00515 // also search the model-path if necessary). 00516 PT(PandaNode) srt_root = loader->load_sync(srt_filename); 00517 00518 if (srt_root != NULL) { 00519 NodePath srt(srt_root); 00520 NodePath srt_np = srt.find("**/+SpeedTreeNode"); 00521 if (!srt_np.is_empty()) { 00522 SpeedTreeNode *srt_node = DCAST(SpeedTreeNode, srt_np.node()); 00523 if (srt_node->get_num_trees() >= 1) { 00524 tree = srt_node->get_tree(0); 00525 } 00526 } 00527 } 00528 already_loaded[srt_filename] = tree; 00529 } 00530 00531 // Now we've loaded the SRT data, so apply it the appropriate 00532 // number of times to the locations specified. 00533 int num_instances; 00534 in >> num_instances; 00535 for (int ni = 0; ni < num_instances && in && !in.eof(); ++ni) { 00536 LPoint3 pos; 00537 PN_stdfloat rotate, scale; 00538 in >> pos[0] >> pos[1] >> pos[2] >> rotate >> scale; 00539 00540 if (!speedtree_5_2_stf) { 00541 // 5.1 or earlier stf files also included these additional 00542 // values, which we will ignore: 00543 PN_stdfloat height_min, height_max, slope_min, slope_max; 00544 in >> height_min >> height_max >> slope_min >> slope_max; 00545 } 00546 00547 if (tree != NULL) { 00548 add_instance(tree, STTransform(pos, rad_2_deg(rotate), scale)); 00549 } 00550 } 00551 in >> os_filename; 00552 } 00553 00554 // Consume any whitespace at the end of the file. 00555 in >> ws; 00556 00557 if (!in.eof()) { 00558 // If we didn't read all the way to end-of-file, there was an 00559 // error. 00560 in.clear(); 00561 string text; 00562 in >> text; 00563 speedtree_cat.error() 00564 << "Unexpected text in " << pathname << " at \"" << text << "\"\n"; 00565 return false; 00566 } 00567 00568 // Return true if we successfully read all the way to end-of-file. 00569 return true; 00570 } 00571 00572 //////////////////////////////////////////////////////////////////// 00573 // Function: SpeedTreeNode::setup_terrain 00574 // Access: Published 00575 // Description: A convenience function to set up terrain geometry by 00576 // reading a terrain.txt file as defined by SpeedTree. 00577 // This file names the various map files that define the 00578 // terrain, as well as defining parameters size as its 00579 // size and color. 00580 // 00581 // This method implicitly creates a STBasicTerrain 00582 // object and passes it to set_terrain(). 00583 //////////////////////////////////////////////////////////////////// 00584 bool SpeedTreeNode:: 00585 setup_terrain(const Filename &terrain_file) { 00586 PT(STBasicTerrain) terrain = new STBasicTerrain; 00587 if (terrain->setup_terrain(terrain_file)) { 00588 set_terrain(terrain); 00589 return true; 00590 } 00591 00592 return false; 00593 } 00594 00595 //////////////////////////////////////////////////////////////////// 00596 // Function: SpeedTreeNode::set_terrain 00597 // Access: Published 00598 // Description: Associated a terrain with the node. If the terrain 00599 // has not already been loaded prior to this call, 00600 // load_data() will be called immediately. 00601 // 00602 // The terrain will be rendered using SpeedTree 00603 // callbacks, and trees may be repositioned with a call 00604 // to snap_to_terrain(). 00605 //////////////////////////////////////////////////////////////////// 00606 void SpeedTreeNode:: 00607 set_terrain(STTerrain *terrain) { 00608 _terrain = NULL; 00609 _needs_repopulate = true; 00610 00611 if (terrain == (STTerrain *)NULL) { 00612 return; 00613 } 00614 00615 if (!terrain->is_valid()) { 00616 // If the terrain was not already loaded, load it immediately. 00617 terrain->load_data(); 00618 } 00619 00620 nassertv(terrain->is_valid()); 00621 nassertv(terrain->get_num_splat_layers() == SpeedTree::c_nNumTerrainSplatLayers); 00622 _terrain = terrain; 00623 00624 _terrain_render.SetShaderLoader(_forest_render.GetShaderLoader()); 00625 00626 SpeedTree::STerrainRenderInfo trender_info; 00627 trender_info.m_strShaderPath = _os_shaders_dir.c_str(); 00628 00629 string os_specific = terrain->get_normal_map().to_os_specific(); 00630 trender_info.m_strNormalMap = os_specific.c_str(); 00631 os_specific = terrain->get_splat_map().to_os_specific(); 00632 trender_info.m_strSplatMap = os_specific.c_str(); 00633 00634 for (int i = 0; i < SpeedTree::c_nNumTerrainSplatLayers; ++i) { 00635 os_specific = terrain->get_splat_layer(i).to_os_specific(); 00636 trender_info.m_astrSplatLayers[i] = os_specific.c_str(); 00637 trender_info.m_afSplatTileValues[i] = terrain->get_splat_layer_tiling(i); 00638 } 00639 00640 trender_info.m_fNormalMapBlueScale = 1.0f; 00641 trender_info.m_bShadowsEnabled = false; // what does this do? 00642 trender_info.m_bZPrePass = false; 00643 00644 _terrain_render.SetRenderInfo(trender_info); 00645 00646 _terrain_render.SetHeightHints(terrain->get_min_height(), terrain->get_max_height()); 00647 00648 if (speedtree_follow_terrain) { 00649 snap_to_terrain(); 00650 } 00651 } 00652 00653 //////////////////////////////////////////////////////////////////// 00654 // Function: SpeedTreeNode::snap_to_terrain 00655 // Access: Published 00656 // Description: Adjusts all the trees in this node so that their Z 00657 // position matches the height of the terrain at their 00658 // X, Y position. 00659 //////////////////////////////////////////////////////////////////// 00660 void SpeedTreeNode:: 00661 snap_to_terrain() { 00662 Trees::iterator ti; 00663 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 00664 InstanceList *instance_list = (*ti); 00665 00666 int num_instances = instance_list->get_num_instances(); 00667 if (_terrain != (STTerrain *)NULL) { 00668 for (int i = 0; i < num_instances; ++i) { 00669 STTransform trans = instance_list->get_instance(i); 00670 LPoint3 pos = trans.get_pos(); 00671 pos[2] = _terrain->get_height(pos[0], pos[1]); 00672 trans.set_pos(pos); 00673 instance_list->set_instance(i, trans); 00674 } 00675 } else { 00676 for (int i = 0; i < num_instances; ++i) { 00677 STTransform trans = instance_list->get_instance(i); 00678 LPoint3 pos = trans.get_pos(); 00679 pos[2] = 0.0f; 00680 trans.set_pos(pos); 00681 instance_list->set_instance(i, trans); 00682 } 00683 } 00684 } 00685 00686 _needs_repopulate = true; 00687 } 00688 00689 //////////////////////////////////////////////////////////////////// 00690 // Function: SpeedTreeNode::reload_config 00691 // Access: Published 00692 // Description: Re-reads the current setting of all of the relevant 00693 // config variables and applies them to this node. This 00694 // can be called after changing config settings, to make 00695 // them apply to this particular node. 00696 //////////////////////////////////////////////////////////////////// 00697 void SpeedTreeNode:: 00698 reload_config() { 00699 00700 _shadow_infos.clear(); 00701 int num_shadow_maps = speedtree_cascading_shadow_splits.get_num_words(); 00702 if (num_shadow_maps > SpeedTree::c_nMaxNumShadowMaps) { 00703 speedtree_cat.warning() 00704 << "SpeedTree is current compiled to support a maximum of " 00705 << SpeedTree::c_nMaxNumShadowMaps << " shadow maps.\n"; 00706 num_shadow_maps = SpeedTree::c_nMaxNumShadowMaps; 00707 } 00708 _shadow_infos.insert(_shadow_infos.begin(), num_shadow_maps, ShadowInfo()); 00709 for (int smi = 0; smi < num_shadow_maps; ++smi) { 00710 _shadow_infos[smi]._shadow_split = speedtree_cascading_shadow_splits[smi]; 00711 } 00712 00713 SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo(); 00714 00715 render_info.m_nMaxAnisotropy = speedtree_max_anisotropy; 00716 render_info.m_bHorizontalBillboards = speedtree_horizontal_billboards; 00717 render_info.m_fAlphaTestScalar = speedtree_alpha_test_scalar; 00718 render_info.m_bZPrePass = speedtree_z_pre_pass; 00719 render_info.m_nMaxBillboardImagesByBase = speedtree_max_billboard_images_by_base; 00720 render_info.m_fVisibility = speedtree_visibility; 00721 render_info.m_fGlobalLightScalar = speedtree_global_light_scalar; 00722 render_info.m_sLightMaterial.m_vSpecular = SpeedTree::Vec4(speedtree_specular_color[0], speedtree_specular_color[1], speedtree_specular_color[2], 1.0f); 00723 render_info.m_sLightMaterial.m_vEmissive = SpeedTree::Vec4(speedtree_emissive_color[0], speedtree_emissive_color[1], speedtree_emissive_color[2], 1.0f); 00724 render_info.m_bSpecularLighting = speedtree_specular_lighting; 00725 render_info.m_bTransmissionLighting = speedtree_transmission_lighting; 00726 render_info.m_bDetailLayer = speedtree_detail_layer; 00727 render_info.m_bDetailNormalMapping = speedtree_detail_normal_mapping; 00728 render_info.m_bAmbientContrast = speedtree_ambient_contrast; 00729 render_info.m_fTransmissionScalar = speedtree_transmission_scalar; 00730 render_info.m_fFogStartDistance = speedtree_fog_distance[0]; 00731 render_info.m_fFogEndDistance = speedtree_fog_distance[1]; 00732 render_info.m_vFogColor = SpeedTree::Vec3(speedtree_fog_color[0], speedtree_fog_color[1], speedtree_fog_color[2]); 00733 render_info.m_vSkyColor = SpeedTree::Vec3(speedtree_sky_color[0], speedtree_sky_color[1], speedtree_sky_color[2]); 00734 render_info.m_fSkyFogMin = speedtree_sky_fog[0]; 00735 render_info.m_fSkyFogMax = speedtree_sky_fog[1]; 00736 render_info.m_vSunColor = SpeedTree::Vec3(speedtree_sun_color[0], speedtree_sun_color[1], speedtree_sun_color[2]); 00737 render_info.m_fSunSize = speedtree_sun_size; 00738 render_info.m_fSunSpreadExponent = speedtree_sun_spread_exponent; 00739 render_info.m_fSunFogBloom = speedtree_sun_fog_bloom; 00740 render_info.m_nNumShadowMaps = num_shadow_maps; 00741 render_info.m_nShadowMapResolution = speedtree_shadow_map_resolution; 00742 render_info.m_bSmoothShadows = speedtree_smooth_shadows; 00743 render_info.m_bShowShadowSplitsOnTerrain = speedtree_show_shadow_splits_on_terrain; 00744 render_info.m_bWindEnabled = speedtree_wind_enabled; 00745 render_info.m_bFrondRippling = speedtree_frond_rippling; 00746 00747 _forest_render.SetRenderInfo(render_info); 00748 00749 _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy); 00750 _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS, 00751 speedtree_max_num_visible_cells); 00752 _visible_terrain.Reserve(speedtree_max_num_visible_cells); 00753 00754 _needs_repopulate = true; 00755 } 00756 00757 //////////////////////////////////////////////////////////////////// 00758 // Function: SpeedTreeNode::set_wind 00759 // Access: Published 00760 // Description: Specifies the overall wind strength and direction. 00761 // Gusts are controlled internally. 00762 //////////////////////////////////////////////////////////////////// 00763 void SpeedTreeNode:: 00764 set_wind(double strength, const LVector3 &direction) { 00765 _forest_render.SetGlobalWindStrength(strength); 00766 _forest_render.SetGlobalWindDirection(SpeedTree::Vec3(direction[0], direction[1], direction[2])); 00767 } 00768 00769 //////////////////////////////////////////////////////////////////// 00770 // Function: SpeedTreeNode::authorize 00771 // Access: Published, Static 00772 // Description: Make this call to initialized the SpeedTree API and 00773 // verify the license. If an empty string is passed for 00774 // the license, the config variable speedtree-license is 00775 // consulted. Returns true on success, false on 00776 // failure. If this call is not made explicitly, it 00777 // will be made implicitly the first time a 00778 // SpeedTreeNode is created. 00779 //////////////////////////////////////////////////////////////////// 00780 bool SpeedTreeNode:: 00781 authorize(const string &license) { 00782 if (!_authorized) { 00783 if (!license.empty()) { 00784 SpeedTree::CCore::Authorize(license.c_str()); 00785 } else { 00786 if (!speedtree_license.empty()) { 00787 SpeedTree::CCore::Authorize(speedtree_license.c_str()); 00788 } 00789 } 00790 00791 _authorized = SpeedTree::CCore::IsAuthorized(); 00792 00793 SpeedTree::CCore::SetTextureFlip(true); 00794 } 00795 00796 return _authorized; 00797 } 00798 00799 //////////////////////////////////////////////////////////////////// 00800 // Function: SpeedTreeNode::Copy Constructor 00801 // Access: Protected 00802 // Description: 00803 //////////////////////////////////////////////////////////////////// 00804 SpeedTreeNode:: 00805 SpeedTreeNode(const SpeedTreeNode ©) : 00806 PandaNode(copy), 00807 _os_shaders_dir(copy._os_shaders_dir), 00808 _shadow_infos(copy._shadow_infos), 00809 #ifdef ST_DELETE_FOREST_HACK 00810 // Early versions of SpeedTree don't destruct unused CForestRender 00811 // objects correctly. To avoid crashes, we have to leak these 00812 // things. 00813 _forest_render(*(new SpeedTree::CForestRender)), 00814 #endif 00815 _time_delta(copy._time_delta) 00816 { 00817 init_node(); 00818 00819 _forest_render.SetRenderInfo(copy._forest_render.GetRenderInfo()); 00820 _terrain_render.SetRenderInfo(copy._terrain_render.GetRenderInfo()); 00821 00822 // No way to copy these parameters, so we just re-assign them. 00823 _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy); 00824 _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS, 00825 speedtree_max_num_visible_cells); 00826 _visible_terrain.Reserve(speedtree_max_num_visible_cells); 00827 00828 Trees::const_iterator ti; 00829 for (ti = copy._trees.begin(); ti != copy._trees.end(); ++ti) { 00830 InstanceList *instance_list = (*ti); 00831 const STTree *tree = instance_list->get_tree(); 00832 if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->get_tree())) { 00833 speedtree_cat.warning() 00834 << "Failed to register tree " << tree->get_fullpath() << "\n"; 00835 write_error(speedtree_cat.warning()); 00836 } 00837 00838 _trees.push_back(new InstanceList(*instance_list)); 00839 } 00840 _trees.sort(); 00841 00842 set_terrain(copy._terrain); 00843 00844 _needs_repopulate = true; 00845 mark_internal_bounds_stale(); 00846 } 00847 00848 //////////////////////////////////////////////////////////////////// 00849 // Function: SpeedTreeNode::Destructor 00850 // Access: Published, Virtual 00851 // Description: 00852 //////////////////////////////////////////////////////////////////// 00853 SpeedTreeNode:: 00854 ~SpeedTreeNode() { 00855 remove_all_trees(); 00856 // Help reduce memory waste from ST_DELETE_FOREST_HACK. 00857 _forest_render.ClearInstances(); 00858 } 00859 00860 //////////////////////////////////////////////////////////////////// 00861 // Function: SpeedTreeNode::make_copy 00862 // Access: Public, Virtual 00863 // Description: Returns a newly-allocated Node that is a shallow copy 00864 // of this one. It will be a different Node pointer, 00865 // but its internal data may or may not be shared with 00866 // that of the original Node. 00867 //////////////////////////////////////////////////////////////////// 00868 PandaNode *SpeedTreeNode:: 00869 make_copy() const { 00870 return new SpeedTreeNode(*this); 00871 } 00872 00873 //////////////////////////////////////////////////////////////////// 00874 // Function: SpeedTreeNode::combine_with 00875 // Access: Public, Virtual 00876 // Description: Collapses this node with the other node, if possible, 00877 // and returns a pointer to the combined node, or NULL 00878 // if the two nodes cannot safely be combined. 00879 // 00880 // The return value may be this, other, or a new node 00881 // altogether. 00882 // 00883 // This function is called from GraphReducer::flatten(), 00884 // and need not deal with children; its job is just to 00885 // decide whether to collapse the two nodes and what the 00886 // collapsed node should look like. 00887 //////////////////////////////////////////////////////////////////// 00888 PandaNode *SpeedTreeNode:: 00889 combine_with(PandaNode *other) { 00890 if (is_exact_type(get_class_type()) && 00891 other->is_exact_type(get_class_type())) { 00892 // Two SpeedTreeNodes can combine by moving trees from one to the 00893 // other, similar to the way GeomNodes combine. 00894 SpeedTreeNode *gother = DCAST(SpeedTreeNode, other); 00895 00896 // But, not if they both have a terrain set. 00897 if (has_terrain() && gother->has_terrain()) { 00898 return NULL; 00899 00900 } else if (gother->has_terrain()) { 00901 set_terrain(gother->get_terrain()); 00902 } 00903 00904 add_instances_from(gother); 00905 return this; 00906 } 00907 00908 return PandaNode::combine_with(other); 00909 } 00910 00911 //////////////////////////////////////////////////////////////////// 00912 // Function: SpeedTreeNode::apply_attribs_to_vertices 00913 // Access: Public, Virtual 00914 // Description: Applies whatever attributes are specified in the 00915 // AccumulatedAttribs object (and by the attrib_types 00916 // bitmask) to the vertices on this node, if 00917 // appropriate. If this node uses geom arrays like a 00918 // GeomNode, the supplied GeomTransformer may be used to 00919 // unify shared arrays across multiple different nodes. 00920 // 00921 // This is a generalization of xform(). 00922 //////////////////////////////////////////////////////////////////// 00923 void SpeedTreeNode:: 00924 apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, 00925 GeomTransformer &transformer) { 00926 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) { 00927 STTransform xform = attribs._transform; 00928 Trees::iterator ti; 00929 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 00930 InstanceList *instance_list = (*ti); 00931 STInstances &instances = instance_list->_instances; 00932 STInstances::iterator sti; 00933 for (sti = instances.begin(); sti != instances.end(); ++sti) { 00934 STTransform orig_transform = *sti; 00935 (*sti) = orig_transform * xform; 00936 } 00937 } 00938 } 00939 mark_internal_bounds_stale(); 00940 } 00941 00942 //////////////////////////////////////////////////////////////////// 00943 // Function: SpeedTreeNode::cull_callback 00944 // Access: Public, Virtual 00945 // Description: This function will be called during the cull 00946 // traversal to perform any additional operations that 00947 // should be performed at cull time. This may include 00948 // additional manipulation of render state or additional 00949 // visible/invisible decisions, or any other arbitrary 00950 // operation. 00951 // 00952 // Note that this function will *not* be called unless 00953 // set_cull_callback() is called in the constructor of 00954 // the derived class. It is necessary to call 00955 // set_cull_callback() to indicated that we require 00956 // cull_callback() to be called. 00957 // 00958 // By the time this function is called, the node has 00959 // already passed the bounding-volume test for the 00960 // viewing frustum, and the node's transform and state 00961 // have already been applied to the indicated 00962 // CullTraverserData object. 00963 // 00964 // The return value is true if this node should be 00965 // visible, or false if it should be culled. 00966 //////////////////////////////////////////////////////////////////// 00967 bool SpeedTreeNode:: 00968 cull_callback(CullTraverser *trav, CullTraverserData &data) { 00969 if (!_is_valid) { 00970 return false; 00971 } 00972 PStatTimer timer(_cull_speedtree_pcollector); 00973 00974 GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, trav->get_gsg()); 00975 nassertr(gsg != (GraphicsStateGuardian *)NULL, true); 00976 if (!validate_api(gsg)) { 00977 return false; 00978 } 00979 00980 ClockObject *clock = ClockObject::get_global_clock(); 00981 _forest_render.SetGlobalTime(clock->get_frame_time() + _time_delta + _global_time_delta); 00982 _forest_render.AdvanceGlobalWind(); 00983 00984 // Compute the modelview and camera transforms, to pass to the 00985 // SpeedTree CView structure. 00986 CPT(TransformState) orig_modelview = data.get_modelview_transform(trav); 00987 CPT(TransformState) modelview = gsg->get_cs_transform()->compose(orig_modelview); 00988 CPT(TransformState) camera_transform = modelview->invert_compose(TransformState::make_identity()); 00989 LMatrix4f modelview_mat = LCAST(float, modelview->get_mat()); 00990 const LPoint3 &camera_pos = camera_transform->get_pos(); 00991 const Lens *lens = trav->get_scene()->get_lens(); 00992 00993 LMatrix4f projection_mat = 00994 LCAST(float, LMatrix4::convert_mat(gsg->get_internal_coordinate_system(), lens->get_coordinate_system()) * 00995 lens->get_projection_mat()); 00996 00997 _view.Set(SpeedTree::Vec3(camera_pos[0], camera_pos[1], camera_pos[2]), 00998 SpeedTree::Mat4x4(projection_mat.get_data()), 00999 SpeedTree::Mat4x4(modelview_mat.get_data()), 01000 lens->get_near(), lens->get_far()); 01001 01002 // Convert the render state to SpeedTree's input. 01003 const RenderState *state = data._state; 01004 01005 // Check texture state. If all textures are disabled, then we ask 01006 // SpeedTree to disable textures. 01007 bool show_textures = true; 01008 const TextureAttrib *ta = DCAST(TextureAttrib, state->get_attrib(TextureAttrib::get_class_slot())); 01009 if (ta != (TextureAttrib *)NULL) { 01010 show_textures = !ta->has_all_off(); 01011 } 01012 _forest_render.EnableTexturing(show_textures); 01013 _terrain_render.EnableTexturing(show_textures); 01014 01015 // Check lighting state. SpeedTree only supports a single 01016 // directional light; we look for a directional light in the 01017 // lighting state and pass its direction and color to SpeedTree. We 01018 // also accumulate the ambient light colors. 01019 LColor ambient_color(0.0f, 0.0f, 0.0f, 0.0f); 01020 DirectionalLight *dlight = NULL; 01021 NodePath dlight_np; 01022 LColor diffuse_color; 01023 01024 int diffuse_priority = 0; 01025 const LightAttrib *la = DCAST(LightAttrib, state->get_attrib(LightAttrib::get_class_slot())); 01026 if (la != (LightAttrib *)NULL) { 01027 for (int i = 0; i < la->get_num_on_lights(); ++i) { 01028 NodePath light = la->get_on_light(i); 01029 if (!light.is_empty() && light.node()->is_of_type(DirectionalLight::get_class_type())) { 01030 // A directional light. 01031 DirectionalLight *light_obj = DCAST(DirectionalLight, light.node()); 01032 if (dlight == NULL || light_obj->get_priority() > dlight->get_priority()) { 01033 // Here's the most important directional light. 01034 dlight = light_obj; 01035 dlight_np = light; 01036 } 01037 } else if (!light.is_empty() && light.node()->is_of_type(AmbientLight::get_class_type())) { 01038 // An ambient light. We keep the color only. 01039 AmbientLight *light_obj = DCAST(AmbientLight, light.node()); 01040 ambient_color += light_obj->get_color(); 01041 } 01042 } 01043 } 01044 01045 if (dlight != (DirectionalLight *)NULL) { 01046 CPT(TransformState) transform = dlight_np.get_transform(trav->get_scene()->get_scene_root().get_parent()); 01047 LVector3 dir = dlight->get_direction() * transform->get_mat(); 01048 dir.normalize(); 01049 _light_dir = SpeedTree::Vec3(dir[0], dir[1], dir[2]); 01050 diffuse_color = dlight->get_color(); 01051 01052 } else { 01053 // No light. But there's no way to turn off lighting in 01054 // SpeedTree. In lieu of this, we just shine a light from 01055 // above. 01056 _light_dir = SpeedTree::Vec3(0.0, 0.0, -1.0); 01057 01058 // Also, we set ambient and diffuse colors to the same full-white 01059 // value. 01060 ambient_color.set(1.0f, 1.0f, 1.0f, 1.0f); 01061 diffuse_color.set(1.0f, 1.0f, 1.0f, 1.0f); 01062 } 01063 01064 SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo(); 01065 render_info.m_sLightMaterial.m_vAmbient = SpeedTree::Vec4(ambient_color[0], ambient_color[1], ambient_color[2], 1.0f); 01066 render_info.m_sLightMaterial.m_vDiffuse = SpeedTree::Vec4(diffuse_color[0], diffuse_color[1], diffuse_color[2], 1.0f); 01067 _forest_render.SetRenderInfo(render_info); 01068 01069 _forest_render.SetLightDir(_light_dir); 01070 01071 SpeedTree::st_float32 updated_splits[SpeedTree::c_nMaxNumShadowMaps]; 01072 memset(updated_splits, 0, sizeof(updated_splits)); 01073 for (int smi = 0; smi < (int)_shadow_infos.size(); ++smi) { 01074 updated_splits[smi] = _shadow_infos[smi]._shadow_split; 01075 }; 01076 01077 _forest_render.SetCascadedShadowMapDistances(updated_splits, lens->get_far()); 01078 _forest_render.SetShadowFadePercentage(speedtree_shadow_fade); 01079 01080 if (!_needs_repopulate) { 01081 // Don't bother culling now unless we're correctly fully 01082 // populated. (Culling won't be accurate unless the forest has 01083 // been populated, but we have to be in the draw traversal to 01084 // populate.) 01085 cull_forest(); 01086 } 01087 01088 // Recurse onto the node's children. 01089 return true; 01090 } 01091 01092 //////////////////////////////////////////////////////////////////// 01093 // Function: SpeedTreeNode::is_renderable 01094 // Access: Public, Virtual 01095 // Description: Returns true if there is some value to visiting this 01096 // particular node during the cull traversal for any 01097 // camera, false otherwise. This will be used to 01098 // optimize the result of get_net_draw_show_mask(), so 01099 // that any subtrees that contain only nodes for which 01100 // is_renderable() is false need not be visited. 01101 //////////////////////////////////////////////////////////////////// 01102 bool SpeedTreeNode:: 01103 is_renderable() const { 01104 return true; 01105 } 01106 01107 //////////////////////////////////////////////////////////////////// 01108 // Function: SpeedTreeNode::add_for_draw 01109 // Access: Public, Virtual 01110 // Description: Adds the node's contents to the CullResult we are 01111 // building up during the cull traversal, so that it 01112 // will be drawn at render time. For most nodes other 01113 // than GeomNodes, this is a do-nothing operation. 01114 //////////////////////////////////////////////////////////////////// 01115 void SpeedTreeNode:: 01116 add_for_draw(CullTraverser *trav, CullTraverserData &data) { 01117 if (_is_valid) { 01118 // We create a CullableObject that has an explicit draw_callback 01119 // into this node, so that we can make the appropriate calls into 01120 // SpeedTree to render the forest during the actual draw. 01121 CullableObject *object = 01122 new CullableObject(NULL, data._state, 01123 TransformState::make_identity(), 01124 TransformState::make_identity(), 01125 trav->get_gsg()); 01126 object->set_draw_callback(new DrawCallback(this)); 01127 trav->get_cull_handler()->record_object(object, trav); 01128 } 01129 } 01130 01131 //////////////////////////////////////////////////////////////////// 01132 // Function: SpeedTreeNode::prepare_scene 01133 // Access: Published 01134 // Description: Walks through the scene graph beginning at this node, 01135 // and does whatever initialization is required to 01136 // render the scene properly with the indicated GSG. It 01137 // is not strictly necessary to call this, since the GSG 01138 // will initialize itself when the scene is rendered, 01139 // but this may take some of the overhead away from that 01140 // process. 01141 // 01142 // In particular, this will ensure that textures within 01143 // the scene are loaded in texture memory, and display 01144 // lists are built up from static geometry. 01145 //////////////////////////////////////////////////////////////////// 01146 void SpeedTreeNode:: 01147 prepare_scene(GraphicsStateGuardianBase *gsgbase, const RenderState *) { 01148 GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, gsgbase); 01149 if (validate_api(gsg)) { 01150 setup_for_render(gsg); 01151 } 01152 } 01153 01154 //////////////////////////////////////////////////////////////////// 01155 // Function: SpeedTreeNode::compute_internal_bounds 01156 // Access: Protected, Virtual 01157 // Description: Returns a newly-allocated BoundingVolume that 01158 // represents the internal contents of the node. Should 01159 // be overridden by PandaNode classes that contain 01160 // something internally. 01161 //////////////////////////////////////////////////////////////////// 01162 void SpeedTreeNode:: 01163 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, 01164 int &internal_vertices, 01165 int pipeline_stage, 01166 Thread *current_thread) const { 01167 internal_vertices = 0; 01168 01169 SpeedTree::CExtents extents; 01170 Trees::const_iterator ti; 01171 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 01172 InstanceList *instance_list = (*ti); 01173 const STTree *tree = instance_list->get_tree(); 01174 01175 const STInstances &st_instances = instance_list->_instances; 01176 STInstances::const_iterator ii; 01177 for (ii = st_instances.begin(); ii != st_instances.end(); ++ii) { 01178 SpeedTree::CExtents tree_extents = tree->get_tree()->GetExtents(); 01179 tree_extents.Rotate((*ii).GetRotationAngle()); 01180 tree_extents.Scale((*ii).GetScale()); 01181 tree_extents.Translate((*ii).GetPos()); 01182 extents.ExpandAround(tree_extents); 01183 } 01184 } 01185 01186 const SpeedTree::Vec3 &emin = extents.Min(); 01187 const SpeedTree::Vec3 &emax = extents.Max(); 01188 internal_bounds = new BoundingBox(LPoint3(emin[0], emin[1], emin[2]), 01189 LPoint3(emax[0], emax[1], emax[2])); 01190 } 01191 01192 //////////////////////////////////////////////////////////////////// 01193 // Function: SpeedTreeNode::output 01194 // Access: Public, Virtual 01195 // Description: Writes a brief description of the node to the 01196 // indicated output stream. This is invoked by the << 01197 // operator. It may be overridden in derived classes to 01198 // include some information relevant to the class. 01199 //////////////////////////////////////////////////////////////////// 01200 void SpeedTreeNode:: 01201 output(ostream &out) const { 01202 PandaNode::output(out); 01203 out 01204 << " (" << get_num_trees() << " unique trees with " 01205 << count_total_instances() << " total instances)"; 01206 } 01207 01208 //////////////////////////////////////////////////////////////////// 01209 // Function: SpeedTreeNode::write 01210 // Access: Public, Virtual 01211 // Description: 01212 //////////////////////////////////////////////////////////////////// 01213 void SpeedTreeNode:: 01214 write(ostream &out, int indent_level) const { 01215 PandaNode::write(out, indent_level); 01216 01217 // This makes NodePath.ls() too confusing. 01218 /* 01219 Trees::const_iterator ti; 01220 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 01221 InstanceList *instance_list = (*ti); 01222 indent(out, indent_level + 2) 01223 << *instance_list << "\n"; 01224 } 01225 */ 01226 } 01227 01228 01229 //////////////////////////////////////////////////////////////////// 01230 // Function: SpeedTreeNode::write_error 01231 // Access: Public, Static 01232 // Description: Writes the current SpeedTree error message to the 01233 // indicated stream. 01234 //////////////////////////////////////////////////////////////////// 01235 void SpeedTreeNode:: 01236 write_error(ostream &out) { 01237 const char *error = SpeedTree::CCore::GetError(); 01238 if (error != (const char *)NULL) { 01239 out << error; 01240 } 01241 out << "\n"; 01242 } 01243 01244 //////////////////////////////////////////////////////////////////// 01245 // Function: SpeedTreeNode::set_transparent_texture_mode 01246 // Access: Protected 01247 // Description: Uses SpeedTree::CRenderState to set the indicated 01248 // transparency mode. 01249 //////////////////////////////////////////////////////////////////// 01250 void SpeedTreeNode:: 01251 set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode eMode) const { 01252 // turn all modes off (no telling what render state the client 01253 // application might be in before this call) 01254 SpeedTree::CRenderState::SetBlending(false); 01255 SpeedTree::CRenderState::SetAlphaTesting(false); 01256 SpeedTree::CRenderState::SetAlphaToCoverage(false); 01257 01258 switch (eMode) { 01259 case SpeedTree::TRANS_TEXTURE_ALPHA_TESTING: 01260 SpeedTree::CRenderState::SetAlphaTesting(true); 01261 break; 01262 case SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE: 01263 SpeedTree::CRenderState::SetAlphaToCoverage(true); 01264 break; 01265 case SpeedTree::TRANS_TEXTURE_BLENDING: 01266 SpeedTree::CRenderState::SetBlending(true); 01267 break; 01268 default: 01269 // intentionally do nothing (TRANS_TEXTURE_NOTHING) 01270 break; 01271 } 01272 } 01273 01274 //////////////////////////////////////////////////////////////////// 01275 // Function: SpeedTreeNode::init_node 01276 // Access: Private 01277 // Description: Called from the constructor to initialize some 01278 // internal values. 01279 //////////////////////////////////////////////////////////////////// 01280 void SpeedTreeNode:: 01281 init_node() { 01282 PandaNode::set_cull_callback(); 01283 01284 _is_valid = false; 01285 _needs_repopulate = false; 01286 01287 // Ensure we have a license. 01288 if (!authorize()) { 01289 speedtree_cat.warning() 01290 << "SpeedTree license not available.\n"; 01291 return; 01292 } 01293 01294 _forest_render.SetHint(SpeedTree::CForest::HINT_MAX_NUM_VISIBLE_CELLS, 01295 speedtree_max_num_visible_cells); 01296 01297 _forest_render.SetCullCellSize(speedtree_cull_cell_size); 01298 01299 // Doesn't appear to be necessary to call this explicitly. 01300 //_forest_render.EnableWind(true); 01301 01302 _is_valid = true; 01303 } 01304 01305 //////////////////////////////////////////////////////////////////// 01306 // Function: SpeedTreeNode::r_add_instances 01307 // Access: Private 01308 // Description: The recursive implementation of add_instances(). 01309 //////////////////////////////////////////////////////////////////// 01310 void SpeedTreeNode:: 01311 r_add_instances(PandaNode *node, const TransformState *transform, 01312 Thread *current_thread) { 01313 if (node->is_of_type(SpeedTreeNode::get_class_type()) && node != this) { 01314 SpeedTreeNode *other = DCAST(SpeedTreeNode, node); 01315 add_instances_from(other, transform); 01316 } 01317 01318 Children children = node->get_children(current_thread); 01319 for (int i = 0; i < children.get_num_children(); i++) { 01320 PandaNode *child = children.get_child(i); 01321 CPT(TransformState) child_transform = transform->compose(child->get_transform()); 01322 r_add_instances(child, child_transform, current_thread); 01323 } 01324 } 01325 01326 01327 //////////////////////////////////////////////////////////////////// 01328 // Function: SpeedTreeNode::repopulate 01329 // Access: Private 01330 // Description: Rebuilds the internal structures as necessary for 01331 // rendering. 01332 //////////////////////////////////////////////////////////////////// 01333 void SpeedTreeNode:: 01334 repopulate() { 01335 _forest_render.ClearInstances(); 01336 01337 Trees::iterator ti; 01338 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 01339 InstanceList *instance_list = (*ti); 01340 const STTree *tree = instance_list->get_tree(); 01341 const STInstances &instances = instance_list->_instances; 01342 if (instances.empty()) { 01343 // There are no instances, so don't bother. (This shouldn't 01344 // happen often, because we remove trees from the SpeedTreeNode 01345 // when their instance list goes empty, though it's possible if 01346 // the user has explicitly removed all of the instances.) 01347 continue; 01348 } 01349 01350 if (!_forest_render.AddInstances(tree->get_tree(), &instances[0], instances.size())) { 01351 speedtree_cat.warning() 01352 << "Failed to add " << instances.size() 01353 << " instances for " << *tree << "\n"; 01354 write_error(speedtree_cat.warning()); 01355 } 01356 } 01357 01358 _forest_render.GetPopulationStats(_population_stats); 01359 print_forest_stats(_population_stats); 01360 01361 // setup billboard caps based on instances-per-cell stats 01362 int max_instances_by_cell = 1; 01363 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 01364 InstanceList *instance_list = (*ti); 01365 const STTree *tree = instance_list->get_tree(); 01366 const STInstances &instances = instance_list->_instances; 01367 if (instances.empty()) { 01368 continue; 01369 } 01370 01371 int max_instances = 1; 01372 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si; 01373 si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->get_tree()); 01374 if (si != _population_stats.m_mMaxNumInstancesPerCellPerBase.end()) { 01375 max_instances = max(max_instances, (int)si->second); 01376 } 01377 01378 max_instances_by_cell = max(max_instances_by_cell, max_instances); 01379 } 01380 01381 _visible_trees.Reserve(_forest_render.GetBaseTrees(), 01382 _forest_render.GetBaseTrees().size(), 01383 speedtree_max_num_visible_cells, 01384 max_instances_by_cell, 01385 speedtree_horizontal_billboards); 01386 } 01387 01388 //////////////////////////////////////////////////////////////////// 01389 // Function: SpeedTreeNode::update_terrain_cells 01390 // Access: Private 01391 // Description: Called once a frame to load vertex data for 01392 // newly-visible terrain cells. 01393 //////////////////////////////////////////////////////////////////// 01394 void SpeedTreeNode:: 01395 update_terrain_cells() { 01396 nassertv(has_terrain()); 01397 01398 SpeedTree::TTerrainCellArray &cells = _visible_terrain.m_aCellsToUpdate; 01399 01400 int num_tile_res = _terrain_render.GetMaxTileRes(); 01401 PN_stdfloat cell_size = _terrain_render.GetCellSize(); 01402 01403 // A temporary vertex data object for populating terrain. 01404 PT(GeomVertexData) vertex_data = 01405 new GeomVertexData("terrain", _terrain->get_vertex_format(), 01406 GeomEnums::UH_static); 01407 int num_vertices = num_tile_res * num_tile_res; 01408 vertex_data->set_num_rows(num_vertices); 01409 size_t num_bytes = vertex_data->get_array(0)->get_data_size_bytes(); 01410 01411 int num_cells = (int)cells.size(); 01412 for (int ci = 0; ci < num_cells; ++ci) { 01413 SpeedTree::CTerrainCell *cell = cells[ci]; 01414 nassertv(cell != NULL && cell->GetVbo() != NULL); 01415 int cell_yi = cell->Row(); 01416 int cell_xi = cell->Col(); 01417 //cerr << "populating cell " << cell_xi << " " << cell_yi << "\n"; 01418 01419 _terrain->fill_vertices(vertex_data, 01420 cell_xi * cell_size, cell_yi * cell_size, 01421 cell_size, num_tile_res); 01422 01423 const GeomVertexArrayData *array_data = vertex_data->get_array(0); 01424 CPT(GeomVertexArrayDataHandle) handle = array_data->get_handle(); 01425 const unsigned char *data_pointer = handle->get_read_pointer(true); 01426 SpeedTree::CGeometryBuffer *vbo = (SpeedTree::CGeometryBuffer *)cell->GetVbo(); 01427 01428 nassertv(vbo->NumVertices() == num_tile_res * num_tile_res); 01429 nassertv(vbo->NumVertices() * vbo->VertexSize() == handle->get_data_size_bytes()); 01430 vbo->OverwriteVertices(data_pointer, num_vertices, 0); 01431 } 01432 } 01433 01434 //////////////////////////////////////////////////////////////////// 01435 // Function: SpeedTreeNode::validate_api 01436 // Access: Private 01437 // Description: Returns true if the indicated GSG shares the 01438 // appropriate API for this SpeedTreeNode, false 01439 // otherwise. 01440 //////////////////////////////////////////////////////////////////// 01441 bool SpeedTreeNode:: 01442 validate_api(GraphicsStateGuardian *gsg) { 01443 GraphicsPipe *pipe = gsg->get_pipe(); 01444 nassertr(pipe != (GraphicsPipe *)NULL, true); 01445 01446 #if defined(SPEEDTREE_OPENGL) 01447 static const string compiled_api = "OpenGL"; 01448 #elif defined(SPEEDTREE_DIRECTX9) 01449 static const string compiled_api = "DirectX9"; 01450 #else 01451 #error Unexpected graphics API. 01452 #endif 01453 01454 if (pipe->get_interface_name() != compiled_api) { 01455 speedtree_cat.error() 01456 << "SpeedTree is compiled for " << compiled_api 01457 << ", cannot render with " << pipe->get_interface_name() 01458 << "\n"; 01459 _is_valid = false; 01460 return false; 01461 } 01462 01463 return true; 01464 } 01465 01466 //////////////////////////////////////////////////////////////////// 01467 // Function: SpeedTreeNode::draw_callback 01468 // Access: Private 01469 // Description: Called when the node is visited during the draw 01470 // traversal, by virtue of our DrawCallback construct. 01471 // This makes the calls into SpeedTree to perform the 01472 // actual rendering. 01473 //////////////////////////////////////////////////////////////////// 01474 void SpeedTreeNode:: 01475 draw_callback(CallbackData *data) { 01476 PStatTimer timer(_draw_speedtree_pcollector); 01477 GeomDrawCallbackData *geom_cbdata; 01478 DCAST_INTO_V(geom_cbdata, data); 01479 01480 GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, geom_cbdata->get_gsg()); 01481 01482 setup_for_render(gsg); 01483 01484 // Set some initial state requirements. 01485 SpeedTree::CRenderState::SetAlphaFunction(SpeedTree::ALPHAFUNC_GREATER, 0.0f); 01486 01487 // start the forest render 01488 _forest_render.StartRender(); 01489 01490 if (_forest_render.ShadowsAreEnabled()) { 01491 // Update the shadow maps. TODO: consider updating these only 01492 // every once in a while, instead of every frame, as a simple 01493 // optimization. 01494 PStatTimer timer(_draw_speedtree_shadows_pcollector); 01495 render_forest_into_shadow_maps(); 01496 _forest_render.ClearBoundTextures( ); 01497 } 01498 01499 if (!_forest_render.UploadViewShaderParameters(_view)) { 01500 speedtree_cat.warning() 01501 << "Couldn't set view parameters\n"; 01502 write_error(speedtree_cat.warning()); 01503 } 01504 01505 if (has_terrain()) { 01506 PStatTimer timer1(_draw_speedtree_terrain_pcollector); 01507 // Is this needed for terrain? 01508 _terrain_render.UploadShaderConstants 01509 (&_forest_render, _light_dir, 01510 _forest_render.GetRenderInfo().m_sLightMaterial); 01511 01512 // set terrain render states 01513 set_transparent_texture_mode(SpeedTree::TRANS_TEXTURE_NOTHING); 01514 01515 // render actual terrain 01516 bool terrain = _terrain_render.Render 01517 (&_forest_render, _visible_terrain, SpeedTree::RENDER_PASS_STANDARD, 01518 _light_dir, _forest_render.GetRenderInfo().m_sLightMaterial, 01519 &_forest_render.GetRenderStats()); 01520 01521 if (!terrain) { 01522 speedtree_cat.warning() 01523 << "Failed to render terrain\n"; 01524 write_error(speedtree_cat.warning()); 01525 01526 // Clear the terrain so we don't keep spamming error messages. 01527 _terrain = NULL; 01528 } 01529 } 01530 01531 { 01532 // Now draw the actual trees. 01533 PStatTimer timer1(_draw_speedtree_trees_pcollector); 01534 01535 // SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_ALPHA_TESTING; 01536 SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE; 01537 //SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_BLENDING; 01538 //SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_NOTHING; 01539 set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode(mode)); 01540 01541 bool branches = _forest_render.RenderBranches(_visible_trees, SpeedTree::RENDER_PASS_STANDARD); 01542 bool fronds = _forest_render.RenderFronds(_visible_trees, SpeedTree::RENDER_PASS_STANDARD); 01543 bool leaf_meshes = _forest_render.RenderLeafMeshes(_visible_trees, SpeedTree::RENDER_PASS_STANDARD); 01544 bool leaf_cards = _forest_render.RenderLeafCards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view); 01545 bool billboards = _forest_render.RenderBillboards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view); 01546 01547 // Sometimes billboards comes back false, particularly if wind is 01548 // disabled; but the billboards appear to have been rendered 01549 // successfully. Weird. Just removing this test from the 01550 // condition. 01551 01552 if (!branches || !fronds || !leaf_meshes || !leaf_cards /* || !billboards */) { 01553 speedtree_cat.warning() 01554 << "Failed to render forest completely: " 01555 << branches << " " << fronds << " " << leaf_meshes << " " << leaf_cards << " " << billboards << "\n"; 01556 write_error(speedtree_cat.warning()); 01557 } 01558 } 01559 01560 _forest_render.EndRender(); 01561 01562 if (_forest_render.ShadowsAreEnabled() && speedtree_show_overlays) { 01563 _forest_render.RenderOverlays(); 01564 } 01565 01566 // SpeedTree leaves the graphics state indeterminate. Make sure 01567 // Panda doesn't rely on anything in the state. 01568 geom_cbdata->set_lost_state(true); 01569 } 01570 01571 01572 //////////////////////////////////////////////////////////////////// 01573 // Function: SpeedTreeNode::render_forest_into_shadow_maps 01574 // Access: Private 01575 // Description: Renders the forest from the point of view of the 01576 // light, to fill up the shadow map(s). 01577 //////////////////////////////////////////////////////////////////// 01578 void SpeedTreeNode:: 01579 render_forest_into_shadow_maps() { 01580 bool success = true; 01581 01582 // d3d10 allows A2C on render targets, so make sure to turn it off 01583 SpeedTree::CRenderState::SetMultisampling(false); 01584 SpeedTree::CRenderState::SetAlphaToCoverage(false); 01585 01586 #if defined(SPEEDTREE_OPENGL) 01587 // Ensure the viewport is not constrained. SpeedTree doesn't expect 01588 // that. 01589 glDisable(GL_SCISSOR_TEST); 01590 #endif 01591 01592 for (int smi = 0; smi < (int)_shadow_infos.size(); ++smi) { 01593 const SpeedTree::CView &light_view = _shadow_infos[smi]._light_view; 01594 const SpeedTree::SForestCullResults &light_cull = _shadow_infos[smi]._light_cull; 01595 01596 if (_forest_render.BeginShadowMap(smi, light_view)) { 01597 success &= _forest_render.UploadViewShaderParameters(light_view); 01598 01599 // branch geometry can be rendered with backfacing triangle 01600 // removed, so a closer tolerance can be used 01601 SpeedTree::CRenderState::SetPolygonOffset(1.0f, 0.125f); 01602 01603 success &= _forest_render.RenderBranches(light_cull, SpeedTree::RENDER_PASS_SHADOW); 01604 01605 // the remaining geometry types cannot be backface culled, so we 01606 // need a much more aggressive offset 01607 SpeedTree::CRenderState::SetPolygonOffset(10.0f, 1.0f); 01608 01609 success &= _forest_render.RenderFronds(light_cull, SpeedTree::RENDER_PASS_SHADOW); 01610 success &= _forest_render.RenderLeafMeshes(light_cull, SpeedTree::RENDER_PASS_SHADOW); 01611 success &= _forest_render.RenderLeafCards(light_cull, SpeedTree::RENDER_PASS_SHADOW, light_view); 01612 01613 // We don't bother to render billboard geometry into the shadow 01614 // map(s). 01615 01616 success &= _forest_render.EndShadowMap(smi); 01617 } 01618 } 01619 01620 // SpeedTree::CRenderState::SetMultisampling(m_sUserSettings.m_nSampleCount > 0); 01621 01622 if (!success) { 01623 speedtree_cat.warning() 01624 << "Failed to render shadow maps\n"; 01625 write_error(speedtree_cat.warning()); 01626 } 01627 } 01628 01629 //////////////////////////////////////////////////////////////////// 01630 // Function: SpeedTreeNode::setup_for_render 01631 // Access: Private 01632 // Description: Does whatever calls are necessary to set up the 01633 // forest for rendering--create vbuffers, load shaders, 01634 // and whatnot. Primarily, this is the calls to 01635 // InitTreeGraphics and the like. 01636 //////////////////////////////////////////////////////////////////// 01637 void SpeedTreeNode:: 01638 setup_for_render(GraphicsStateGuardian *gsg) { 01639 if (!_done_first_init) { 01640 // This is the first time we have entered the draw callback since 01641 // creating any SpeedTreeNode. Now we have an opportunity to do 01642 // any initial setup that requires a graphics context. 01643 01644 #ifdef SPEEDTREE_OPENGL 01645 // For OpenGL, we have to ensure GLEW has been initialized. 01646 // (SpeedTree uses it, though Panda doesn't.) 01647 GLenum err = glewInit(); 01648 if (err != GLEW_OK) { 01649 speedtree_cat.error() 01650 << "GLEW initialization failed: %s\n", glewGetErrorString(err); 01651 // Can't proceed without GLEW. 01652 _is_valid = false; 01653 return; 01654 } 01655 01656 // Insist that OpenGL 2.0 is available as the SpeedTree renderer 01657 // requires it. 01658 if (!GLEW_VERSION_2_0) { 01659 speedtree_cat.error() 01660 << "The SpeedTree OpenGL implementation requires OpenGL 2.0 or better to run; this system has version " << glGetString(GL_VERSION) << "\n"; 01661 _is_valid = false; 01662 return; 01663 } 01664 #endif // SPEEDTREE_OPENGL 01665 01666 _done_first_init = true; 01667 } 01668 01669 #ifdef SPEEDTREE_DIRECTX9 01670 // In DirectX, we have to tell SpeedTree our device pointer. 01671 DXGraphicsStateGuardian9 *dxgsg = DCAST(DXGraphicsStateGuardian9, gsg); 01672 SpeedTree::DX9::SetDevice(dxgsg->_screen->_d3d_device); 01673 #endif // SPEEDTREE_DIRECTX9 01674 01675 if (_needs_repopulate) { 01676 repopulate(); 01677 01678 // Now init per-tree graphics 01679 Trees::const_iterator ti; 01680 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 01681 InstanceList *instance_list = (*ti); 01682 const STTree *tree = instance_list->get_tree(); 01683 const STInstances &instances = instance_list->_instances; 01684 if (instances.empty()) { 01685 continue; 01686 } 01687 01688 int max_instances = 2; 01689 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si; 01690 si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->get_tree()); 01691 if (si != _population_stats.m_mMaxNumInstancesPerCellPerBase.end()) { 01692 max_instances = max(max_instances, (int)si->second); 01693 } 01694 01695 // Get the speedtree-textures-dir to pass for initialization. 01696 string os_textures_dir; 01697 if (!speedtree_textures_dir.empty()) { 01698 os_textures_dir = speedtree_textures_dir.get_value().to_os_specific(); 01699 // Ensure the path ends with a terminal slash; SpeedTree requires this. 01700 #if defined(WIN32) || defined(WIN64) 01701 if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] != '\\') { 01702 os_textures_dir += "\\"; 01703 } 01704 #else 01705 if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] != '/') { 01706 os_textures_dir += "/"; 01707 } 01708 #endif 01709 } 01710 01711 if (!_forest_render.InitTreeGraphics((SpeedTree::CTreeRender *)tree->get_tree(), 01712 max_instances, speedtree_horizontal_billboards, 01713 os_textures_dir.c_str())) { 01714 if (speedtree_cat.is_debug()) { 01715 speedtree_cat.debug() 01716 << "Failed to init tree graphics for " << *tree << "\n"; 01717 write_error(speedtree_cat.debug()); 01718 } 01719 } 01720 } 01721 01722 // Init overall graphics 01723 if (!_forest_render.InitGraphics(false)) { 01724 speedtree_cat.warning() 01725 << "Failed to init graphics\n"; 01726 write_error(speedtree_cat.warning()); 01727 _is_valid = false; 01728 return; 01729 } 01730 01731 // This call apparently must be made at draw time, not earlier, 01732 // because it might attempt to create OpenGL index buffers and 01733 // such. 01734 _forest_render.UpdateTreeCellExtents(); 01735 01736 if (has_terrain()) { 01737 // Now initialize the terrain. 01738 if (!_terrain_render.Init(speedtree_terrain_num_lods, 01739 speedtree_terrain_resolution, 01740 speedtree_terrain_cell_size, 01741 _terrain->get_st_vertex_format())) { 01742 speedtree_cat.warning() 01743 << "Failed to init terrain\n"; 01744 write_error(speedtree_cat.warning()); 01745 } 01746 } 01747 01748 // If we needed to repopulate, it means we didn't cull in the cull 01749 // traversal. Do it now. 01750 cull_forest(); 01751 _needs_repopulate = false; 01752 } 01753 if (has_terrain()) { 01754 PStatTimer timer1(_draw_speedtree_terrain_update_pcollector); 01755 update_terrain_cells(); 01756 } 01757 } 01758 01759 //////////////////////////////////////////////////////////////////// 01760 // Function: SpeedTreeNode::cull_forest 01761 // Access: Private 01762 // Description: Calls the SpeedTree methods to perform the needed 01763 // cull calculations. 01764 //////////////////////////////////////////////////////////////////// 01765 void SpeedTreeNode:: 01766 cull_forest() { 01767 { 01768 PStatTimer timer1(_cull_speedtree_trees_pcollector); 01769 _forest_render.CullAndComputeLOD(_view, _visible_trees); 01770 } 01771 if (has_terrain()) { 01772 PStatTimer timer1(_cull_speedtree_terrain_pcollector); 01773 _terrain_render.CullAndComputeLOD(_view, _visible_terrain); 01774 } 01775 01776 if (_forest_render.ShadowsAreEnabled()) { 01777 PStatTimer timer1(_cull_speedtree_shadows_pcollector); 01778 for (int smi = 0; smi < (int)_shadow_infos.size(); ++smi) { 01779 SpeedTree::CView &light_view = _shadow_infos[smi]._light_view; 01780 SpeedTree::SForestCullResultsRender &light_cull = _shadow_infos[smi]._light_cull; 01781 01782 _forest_render.ComputeLightView 01783 (_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi, 01784 light_view, 0.0f); 01785 01786 light_view.SetLodRefPoint(_view.GetCameraPos()); 01787 _forest_render.CullAndComputeLOD(light_view, light_cull, false); 01788 } 01789 } 01790 } 01791 01792 01793 //////////////////////////////////////////////////////////////////// 01794 // Function: SpeedTreeNode::print_forest_stats 01795 // Access: Private 01796 // Description: 01797 //////////////////////////////////////////////////////////////////// 01798 void SpeedTreeNode:: 01799 print_forest_stats(const SpeedTree::CForest::SPopulationStats &forest_stats) const { 01800 fprintf(stderr, "\n Forest Population Statistics\n"); 01801 fprintf(stderr, " ---------------------------------------------------\n"); 01802 fprintf(stderr, " # of tree cull cells: %d\n", forest_stats.m_nNumCells); 01803 fprintf(stderr, " # of unique base trees: %d\n", forest_stats.m_nNumBaseTrees); 01804 fprintf(stderr, " total # of instances: %d\n", forest_stats.m_nNumInstances); 01805 fprintf(stderr, " average # of instances per base: %g\n", forest_stats.m_fAverageNumInstancesPerBase); 01806 fprintf(stderr, " max # of billboards/instances per cell: %d\n", forest_stats.m_nMaxNumBillboardsPerCell); 01807 fprintf(stderr, " max # of instances per cell per base:\n"); 01808 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator i; 01809 for (i = forest_stats.m_mMaxNumInstancesPerCellPerBase.begin( ); i != forest_stats.m_mMaxNumInstancesPerCellPerBase.end( ); ++i) { 01810 fprintf(stderr, " %35s: %4d\n", SpeedTree::CFixedString(i->first->GetFilename( )).NoPath( ).c_str( ), i->second); 01811 } 01812 fprintf(stderr, " average # instances per cell: %g\n", forest_stats.m_fAverageInstancesPerCell); 01813 fprintf(stderr, " max # of billboard images: %d\n", forest_stats.m_nMaxNumBillboardImages); 01814 fprintf(stderr, "\n"); 01815 } 01816 01817 //////////////////////////////////////////////////////////////////// 01818 // Function: SpeedTreeNode::register_with_read_factory 01819 // Access: Public, Static 01820 // Description: Tells the BamReader how to create objects of type 01821 // SpeedTreeNode. 01822 //////////////////////////////////////////////////////////////////// 01823 void SpeedTreeNode:: 01824 register_with_read_factory() { 01825 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 01826 } 01827 01828 //////////////////////////////////////////////////////////////////// 01829 // Function: SpeedTreeNode::write_datagram 01830 // Access: Public, Virtual 01831 // Description: Writes the contents of this object to the datagram 01832 // for shipping out to a Bam file. 01833 //////////////////////////////////////////////////////////////////// 01834 void SpeedTreeNode:: 01835 write_datagram(BamWriter *manager, Datagram &dg) { 01836 PandaNode::write_datagram(manager, dg); 01837 01838 int num_trees = _trees.size(); 01839 dg.add_uint32(num_trees); 01840 Trees::const_iterator ti; 01841 for (ti = _trees.begin(); ti != _trees.end(); ++ti) { 01842 InstanceList *instance_list = (*ti); 01843 instance_list->write_datagram(manager, dg); 01844 } 01845 } 01846 01847 //////////////////////////////////////////////////////////////////// 01848 // Function: SpeedTreeNode::make_from_bam 01849 // Access: Protected, Static 01850 // Description: This function is called by the BamReader's factory 01851 // when a new object of type SpeedTreeNode is encountered 01852 // in the Bam file. It should create the SpeedTreeNode 01853 // and extract its information from the file. 01854 //////////////////////////////////////////////////////////////////// 01855 TypedWritable *SpeedTreeNode:: 01856 make_from_bam(const FactoryParams ¶ms) { 01857 SpeedTreeNode *node = new SpeedTreeNode(""); 01858 DatagramIterator scan; 01859 BamReader *manager; 01860 01861 parse_params(params, scan, manager); 01862 node->fillin(scan, manager); 01863 01864 return node; 01865 } 01866 01867 //////////////////////////////////////////////////////////////////// 01868 // Function: SpeedTreeNode::fillin 01869 // Access: Protected 01870 // Description: This internal function is called by make_from_bam to 01871 // read in all of the relevant data from the BamFile for 01872 // the new SpeedTreeNode. 01873 //////////////////////////////////////////////////////////////////// 01874 void SpeedTreeNode:: 01875 fillin(DatagramIterator &scan, BamReader *manager) { 01876 PandaNode::fillin(scan, manager); 01877 01878 int num_trees = scan.get_uint32(); 01879 _trees.reserve(num_trees); 01880 for (int i = 0; i < num_trees; i++) { 01881 InstanceList *instance_list = new InstanceList(NULL); 01882 instance_list->fillin(scan, manager); 01883 if (instance_list->get_tree() == (STTree *)NULL) { 01884 // The tree wasn't successfully loaded. Don't keep it. 01885 delete instance_list; 01886 } else { 01887 _trees.push_back(instance_list); 01888 } 01889 } 01890 01891 _trees.sort(); 01892 } 01893 01894 //////////////////////////////////////////////////////////////////// 01895 // Function: SpeedTreeNode::InstanceList::output 01896 // Access: Published 01897 // Description: 01898 //////////////////////////////////////////////////////////////////// 01899 void SpeedTreeNode::InstanceList:: 01900 output(ostream &out) const { 01901 out << *_tree << ": " << _instances.size() << " instances"; 01902 } 01903 01904 //////////////////////////////////////////////////////////////////// 01905 // Function: SpeedTreeNode::InstanceList::write 01906 // Access: Published 01907 // Description: 01908 //////////////////////////////////////////////////////////////////// 01909 void SpeedTreeNode::InstanceList:: 01910 write(ostream &out, int indent_level) const { 01911 indent(out, indent_level) 01912 << *_tree << ": " << _instances.size() << " instances.\n"; 01913 STInstances::const_iterator ii; 01914 for (ii = _instances.begin(); ii != _instances.end(); ++ii) { 01915 indent(out, indent_level + 2) 01916 << STTransform(*ii) << "\n"; 01917 } 01918 } 01919 01920 //////////////////////////////////////////////////////////////////// 01921 // Function: SpeedTreeNode::InstanceList::write_datagram 01922 // Access: Public 01923 // Description: Writes the contents of this object to the datagram 01924 // for shipping out to a Bam file. 01925 //////////////////////////////////////////////////////////////////// 01926 void SpeedTreeNode::InstanceList:: 01927 write_datagram(BamWriter *manager, Datagram &dg) { 01928 // Compute the relative pathname to the SRT file. 01929 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 01930 01931 bool has_bam_dir = !manager->get_filename().empty(); 01932 Filename bam_dir = manager->get_filename().get_dirname(); 01933 Filename srt_filename = _tree->get_fullpath(); 01934 01935 bam_dir.make_absolute(vfs->get_cwd()); 01936 if (!has_bam_dir || !srt_filename.make_relative_to(bam_dir, true)) { 01937 srt_filename.find_on_searchpath(get_model_path()); 01938 } 01939 01940 dg.add_string(srt_filename); 01941 01942 // Now record the instances. 01943 int num_instances = _instances.size(); 01944 dg.add_uint32(num_instances); 01945 STInstances::const_iterator ii; 01946 for (ii = _instances.begin(); ii != _instances.end(); ++ii) { 01947 STTransform transform = (*ii); 01948 transform.write_datagram(manager, dg); 01949 } 01950 } 01951 01952 //////////////////////////////////////////////////////////////////// 01953 // Function: SpeedTreeNode::InstanceList::fillin 01954 // Access: Public 01955 // Description: This internal function is called by make_from_bam to 01956 // read in all of the relevant data from the BamFile for 01957 // the new SpeedTreeNode. 01958 //////////////////////////////////////////////////////////////////// 01959 void SpeedTreeNode::InstanceList:: 01960 fillin(DatagramIterator &scan, BamReader *manager) { 01961 // Get the relative pathname to the SRT file. 01962 string srt_filename = scan.get_string(); 01963 01964 // Now load up the SRT file using the Panda loader (which will 01965 // also search the model-path if necessary). 01966 Loader *loader = Loader::get_global_ptr(); 01967 PT(PandaNode) srt_root = loader->load_sync(srt_filename); 01968 01969 if (srt_root != NULL) { 01970 NodePath srt(srt_root); 01971 NodePath srt_np = srt.find("**/+SpeedTreeNode"); 01972 if (!srt_np.is_empty()) { 01973 SpeedTreeNode *srt_node = DCAST(SpeedTreeNode, srt_np.node()); 01974 if (srt_node->get_num_trees() >= 1) { 01975 _tree = (STTree *)srt_node->get_tree(0); 01976 } 01977 } 01978 } 01979 01980 // Now read the instances. 01981 int num_instances = scan.get_uint32(); 01982 _instances.reserve(num_instances); 01983 for (int i = 0; i < num_instances; i++) { 01984 STTransform transform; 01985 transform.fillin(scan, manager); 01986 _instances.push_back(transform); 01987 } 01988 } 01989 01990 //////////////////////////////////////////////////////////////////// 01991 // Function: SpeedTreeNode::DrawCallback::do_callback 01992 // Access: Public, Virtual 01993 // Description: This method called when the callback is triggered; it 01994 // *replaces* the original function. To continue 01995 // performing the original function, you must call 01996 // cbdata->upcall() during the callback. 01997 //////////////////////////////////////////////////////////////////// 01998 void SpeedTreeNode::DrawCallback:: 01999 do_callback(CallbackData *data) { 02000 _node->draw_callback(data); 02001 }