37#ifdef SPEEDTREE_OPENGL
41#ifdef SPEEDTREE_DIRECTX9
49double SpeedTreeNode::_global_time_delta = 0.0;
50bool SpeedTreeNode::_authorized;
51bool SpeedTreeNode::_done_first_init;
53TypeHandle SpeedTreeNode::DrawCallback::_type_handle;
55PStatCollector SpeedTreeNode::_cull_speedtree_pcollector(
"Cull:SpeedTree");
56PStatCollector SpeedTreeNode::_cull_speedtree_shadows_pcollector(
"Cull:SpeedTree:Shadows");
57PStatCollector SpeedTreeNode::_cull_speedtree_trees_pcollector(
"Cull:SpeedTree:Trees");
58PStatCollector SpeedTreeNode::_cull_speedtree_terrain_pcollector(
"Cull:SpeedTree:Terrain");
59PStatCollector SpeedTreeNode::_draw_speedtree_pcollector(
"Draw:SpeedTree");
60PStatCollector SpeedTreeNode::_draw_speedtree_shadows_pcollector(
"Draw:SpeedTree:Shadows");
61PStatCollector SpeedTreeNode::_draw_speedtree_trees_pcollector(
"Draw:SpeedTree:Trees");
62PStatCollector SpeedTreeNode::_draw_speedtree_terrain_pcollector(
"Draw:SpeedTree:Terrain");
63PStatCollector SpeedTreeNode::_draw_speedtree_terrain_update_pcollector(
"Draw:SpeedTree:Terrain:Update");
69SpeedTreeNode(
const string &name) :
71#ifdef ST_DELETE_FOREST_HACK
74 _forest_render(*(new SpeedTree::CForestRender)),
86 Filename shaders_dir = speedtree_shaders_dir;
90 Filename token_filename =
"Branch.hlsl";
91 if (!
Filename(shaders_dir, token_filename).exists()) {
97 speedtree_cat.warning()
98 <<
"speedtree-shaders-dir is set to " << shaders_dir
99 <<
", which doesn't exist.\n";
101 speedtree_cat.warning()
102 <<
"speedtree-shaders-dir is set to " << shaders_dir
103 <<
", which exists but doesn't contain " << token_filename
111#if defined(WIN32) || defined(WIN64)
112 if (!_os_shaders_dir.empty() && _os_shaders_dir[_os_shaders_dir.length() - 1] !=
'\\') {
113 _os_shaders_dir +=
"\\";
116 if (!_os_shaders_dir.empty() && _os_shaders_dir[_os_shaders_dir.length() - 1] !=
'/') {
117 _os_shaders_dir +=
"/";
121 SpeedTree::SForestRenderInfo render_info;
122 render_info.m_strShaderPath = _os_shaders_dir.c_str();
123 _forest_render.SetRenderInfo(render_info);
135 int total_instances = 0;
136 Trees::const_iterator ti;
137 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
142 return total_instances;
158 Trees::iterator ti = _trees.find(&ilist);
159 if (ti == _trees.
end()) {
162 std::pair<Trees::iterator, bool> result = _trees.insert(instance_list);
164 bool inserted = result.second;
165 nassertr(inserted, *(*ti));
167 if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->
get_tree())) {
168 speedtree_cat.warning()
169 <<
"Failed to register tree " << tree->
get_fullpath() <<
"\n";
174 _needs_repopulate =
true;
175 mark_internal_bounds_stale();
177 return *instance_list;
187 Trees::iterator ti = _trees.find(&ilist);
188 if (ti == _trees.
end()) {
193 if (!_forest_render.UnregisterTree(tree->
get_tree())) {
194 speedtree_cat.warning()
195 <<
"Failed to unregister tree " << tree->
get_fullpath() <<
"\n";
199 _needs_repopulate =
true;
200 mark_internal_bounds_stale();
205 delete instance_list;
216 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
219 if (!_forest_render.UnregisterTree(tree->
get_tree())) {
220 speedtree_cat.warning()
221 <<
"Failed to unregister tree " << tree->
get_fullpath() <<
"\n";
224 delete instance_list;
228 _needs_repopulate =
true;
229 mark_internal_bounds_stale();
239 Trees::const_iterator ti = _trees.find(&ilist);
240 return (ti != _trees.
end());
250 InstanceList ilist(tree);
251 Trees::const_iterator ti = _trees.find(&ilist);
252 if (ti == _trees.
end()) {
254 static InstanceList empty_list(
nullptr);
258 InstanceList *instance_list = (*ti);
259 return *instance_list;
278 new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
305 for (
int ti = 0; ti < num_trees; ++ti) {
311 for (
int i = 0; i < num_instances; ++i) {
326 for (
int ti = 0; ti < num_trees; ++ti) {
332 for (
int i = 0; i < num_instances; ++i) {
338 new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
359 PN_stdfloat x_min, PN_stdfloat x_max,
360 PN_stdfloat y_min, PN_stdfloat y_max,
361 PN_stdfloat scale_min, PN_stdfloat scale_max,
362 PN_stdfloat height_min, PN_stdfloat height_max,
363 PN_stdfloat slope_min, PN_stdfloat slope_max,
366 _needs_repopulate =
true;
368 for (
int i = 0; i < quantity; ++i) {
370 transform._pos[0] = randomizer.
random_real(x_max - x_min) + x_min;
371 transform._pos[1] = randomizer.
random_real(y_max - y_min) + y_min;
373 transform._scale = randomizer.
random_real(scale_max - scale_min) + scale_min;
377 int repeat_count = speedtree_max_random_try_count;
378 while (!_terrain->placement_is_acceptable(transform._pos[0], transform._pos[1], height_min, height_max, slope_min, slope_max)) {
379 transform._pos[0] = randomizer.
random_real(x_max - x_min) + x_min;
380 transform._pos[1] = randomizer.
random_real(y_max - y_min) + y_min;
381 if (--repeat_count == 0) {
382 nassert_raise(
"Exceeded speedtree-max-random-try-count; bad placement parameters?");
386 transform._pos[2] = _terrain->get_height(transform._pos[0], transform._pos[1]);
390 transform._pos[2] = randomizer.
random_real(height_max - height_min) + height_min;
405 Filename fullpath = Filename::text_filename(stf_filename);
408 if (!vfs->
exists(fullpath)) {
409 speedtree_cat.warning()
410 <<
"Couldn't find " << stf_filename <<
"\n";
415 if (file ==
nullptr) {
417 speedtree_cat.error()
418 <<
"Could not find " << stf_filename <<
"\n";
422 if (speedtree_cat.is_debug()) {
423 speedtree_cat.debug()
424 <<
"Reading STF file " << fullpath <<
"\n";
427 istream *in = file->open_read_file(
true);
448 if (loader ==
nullptr) {
459 AlreadyLoaded already_loaded;
463 while (in && !in.eof()) {
465 Filename srt_filename = Filename::from_os_specific(os_filename);
466 AlreadyLoaded::iterator ai = already_loaded.find(srt_filename);
467 if (ai != already_loaded.end()) {
475 PT(
PandaNode) srt_root = loader->load_sync(srt_filename);
477 if (srt_root !=
nullptr) {
487 already_loaded[srt_filename] = tree;
494 for (
int ni = 0; ni < num_instances && in && !in.eof(); ++ni) {
496 PN_stdfloat rotate, scale;
497 in >> pos[0] >> pos[1] >> pos[2] >> rotate >> scale;
499 if (!speedtree_5_2_stf) {
502 PN_stdfloat height_min, height_max, slope_min, slope_max;
503 in >> height_min >> height_max >> slope_min >> slope_max;
506 if (tree !=
nullptr) {
521 speedtree_cat.error()
522 <<
"Unexpected text in " << pathname <<
" at \"" << text <<
"\"\n";
542 if (terrain->setup_terrain(terrain_file)) {
560 _needs_repopulate =
true;
562 if (terrain ==
nullptr) {
575 _terrain_render.SetShaderLoader(_forest_render.GetShaderLoader());
577 SpeedTree::STerrainRenderInfo trender_info;
578 trender_info.m_strShaderPath = _os_shaders_dir.c_str();
581 trender_info.m_strNormalMap = os_specific.c_str();
583 trender_info.m_strSplatMap = os_specific.c_str();
585 for (
int i = 0; i < SpeedTree::c_nNumTerrainSplatLayers; ++i) {
587 trender_info.m_astrSplatLayers[i] = os_specific.c_str();
591 trender_info.m_fNormalMapBlueScale = 1.0f;
592 trender_info.m_bShadowsEnabled =
false;
593 trender_info.m_bZPrePass =
false;
595 _terrain_render.SetRenderInfo(trender_info);
599 if (speedtree_follow_terrain) {
611 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
615 if (_terrain !=
nullptr) {
616 for (
int i = 0; i < num_instances; ++i) {
619 pos[2] = _terrain->get_height(pos[0], pos[1]);
624 for (
int i = 0; i < num_instances; ++i) {
634 _needs_repopulate =
true;
645 _shadow_infos.clear();
646 int num_shadow_maps = speedtree_cascading_shadow_splits.
get_num_words();
647 if (num_shadow_maps > SpeedTree::c_nMaxNumShadowMaps) {
648 speedtree_cat.warning()
649 <<
"SpeedTree is current compiled to support a maximum of "
650 << SpeedTree::c_nMaxNumShadowMaps <<
" shadow maps.\n";
651 num_shadow_maps = SpeedTree::c_nMaxNumShadowMaps;
653 _shadow_infos.insert(_shadow_infos.begin(), num_shadow_maps, ShadowInfo());
654 for (
int smi = 0; smi < num_shadow_maps; ++smi) {
655 _shadow_infos[smi]._shadow_split = speedtree_cascading_shadow_splits[smi];
658 SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo();
660 render_info.m_nMaxAnisotropy = speedtree_max_anisotropy;
661 render_info.m_bHorizontalBillboards = speedtree_horizontal_billboards;
662 render_info.m_fAlphaTestScalar = speedtree_alpha_test_scalar;
663 render_info.m_bZPrePass = speedtree_z_pre_pass;
664 render_info.m_nMaxBillboardImagesByBase = speedtree_max_billboard_images_by_base;
665 render_info.m_fVisibility = speedtree_visibility;
666 render_info.m_fGlobalLightScalar = speedtree_global_light_scalar;
667 render_info.m_sLightMaterial.m_vSpecular = SpeedTree::Vec4(speedtree_specular_color[0], speedtree_specular_color[1], speedtree_specular_color[2], speedtree_specular_color[3]);
668 render_info.m_sLightMaterial.m_vEmissive = SpeedTree::Vec4(speedtree_emissive_color[0], speedtree_emissive_color[1], speedtree_emissive_color[2], speedtree_emissive_color[3]);
669 render_info.m_bSpecularLighting = speedtree_specular_lighting;
670 render_info.m_bTransmissionLighting = speedtree_transmission_lighting;
671 render_info.m_bDetailLayer = speedtree_detail_layer;
672 render_info.m_bDetailNormalMapping = speedtree_detail_normal_mapping;
673 render_info.m_bAmbientContrast = speedtree_ambient_contrast;
674 render_info.m_fTransmissionScalar = speedtree_transmission_scalar;
675 render_info.m_fFogStartDistance = speedtree_fog_distance[0];
676 render_info.m_fFogEndDistance = speedtree_fog_distance[1];
677 render_info.m_vFogColor = SpeedTree::Vec3(speedtree_fog_color[0], speedtree_fog_color[1], speedtree_fog_color[2]);
678 render_info.m_vSkyColor = SpeedTree::Vec3(speedtree_sky_color[0], speedtree_sky_color[1], speedtree_sky_color[2]);
679 render_info.m_fSkyFogMin = speedtree_sky_fog[0];
680 render_info.m_fSkyFogMax = speedtree_sky_fog[1];
681 render_info.m_vSunColor = SpeedTree::Vec3(speedtree_sun_color[0], speedtree_sun_color[1], speedtree_sun_color[2]);
682 render_info.m_fSunSize = speedtree_sun_size;
683 render_info.m_fSunSpreadExponent = speedtree_sun_spread_exponent;
684 render_info.m_fSunFogBloom = speedtree_sun_fog_bloom;
685 render_info.m_nNumShadowMaps = num_shadow_maps;
686 render_info.m_nShadowMapResolution = speedtree_shadow_map_resolution;
687 render_info.m_bSmoothShadows = speedtree_smooth_shadows;
688 render_info.m_bShowShadowSplitsOnTerrain = speedtree_show_shadow_splits_on_terrain;
689 render_info.m_bWindEnabled = speedtree_wind_enabled;
690 render_info.m_bFrondRippling = speedtree_frond_rippling;
692 _forest_render.SetRenderInfo(render_info);
694 _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
695 _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
696 speedtree_max_num_visible_cells);
697 _visible_terrain.Reserve(speedtree_max_num_visible_cells);
699 _needs_repopulate =
true;
707set_wind(
double strength,
const LVector3 &direction) {
708 _forest_render.SetGlobalWindStrength(strength);
709 _forest_render.SetGlobalWindDirection(SpeedTree::Vec3(direction[0], direction[1], direction[2]));
722 if (!license.empty()) {
723 SpeedTree::CCore::Authorize(license.c_str());
725 if (!speedtree_license.empty()) {
726 SpeedTree::CCore::Authorize(speedtree_license.c_str());
730 _authorized = SpeedTree::CCore::IsAuthorized();
732 SpeedTree::CCore::SetTextureFlip(
true);
744 _os_shaders_dir(copy._os_shaders_dir),
745 _shadow_infos(copy._shadow_infos),
746#ifdef ST_DELETE_FOREST_HACK
749 _forest_render(*(new SpeedTree::CForestRender)),
751 _time_delta(copy._time_delta)
755 _forest_render.SetRenderInfo(copy._forest_render.GetRenderInfo());
756 _terrain_render.SetRenderInfo(copy._terrain_render.GetRenderInfo());
759 _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
760 _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
761 speedtree_max_num_visible_cells);
762 _visible_terrain.Reserve(speedtree_max_num_visible_cells);
764 Trees::const_iterator ti;
765 for (ti = copy._trees.
begin(); ti != copy._trees.
end(); ++ti) {
766 InstanceList *instance_list = (*ti);
768 if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->
get_tree())) {
769 speedtree_cat.warning()
770 <<
"Failed to register tree " << tree->
get_fullpath() <<
"\n";
774 _trees.
push_back(
new InstanceList(*instance_list));
780 _needs_repopulate =
true;
781 mark_internal_bounds_stale();
791 _forest_render.ClearInstances();
849 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
852 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
854 STInstances &instances = instance_list->_instances;
855 STInstances::iterator sti;
856 for (sti = instances.begin(); sti != instances.end(); ++sti) {
858 (*sti) = orig_transform *
xform;
862 mark_internal_bounds_stale();
891 nassertr(gsg !=
nullptr,
true);
892 if (!validate_api(gsg)) {
897 _forest_render.SetGlobalTime(clock->
get_frame_time() + _time_delta + _global_time_delta);
898 _forest_render.AdvanceGlobalWind();
902 CPT(
TransformState) orig_modelview = data.get_modelview_transform(trav);
904 CPT(
TransformState) camera_transform = modelview->invert_compose(TransformState::make_identity());
905 LMatrix4f modelview_mat = LCAST(
float, modelview->get_mat());
906 const LPoint3 &camera_pos = camera_transform->get_pos();
909 LMatrix4f projection_mat =
913 _view.Set(SpeedTree::Vec3(camera_pos[0], camera_pos[1], camera_pos[2]),
914 SpeedTree::Mat4x4(projection_mat.get_data()),
915 SpeedTree::Mat4x4(modelview_mat.get_data()),
923 bool show_textures =
true;
928 _forest_render.EnableTexturing(show_textures);
929 _terrain_render.EnableTexturing(show_textures);
935 LColor ambient_color(0.0f, 0.0f, 0.0f, 0.0f);
938 LColor diffuse_color;
940 int diffuse_priority = 0;
961 if (dlight !=
nullptr) {
965 _light_dir = SpeedTree::Vec3(dir[0], dir[1], dir[2]);
971 _light_dir = SpeedTree::Vec3(0.0, 0.0, -1.0);
974 ambient_color.set(1.0f, 1.0f, 1.0f, 1.0f);
975 diffuse_color.set(1.0f, 1.0f, 1.0f, 1.0f);
978 SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo();
979 render_info.m_sLightMaterial.m_vAmbient = SpeedTree::Vec4(ambient_color[0], ambient_color[1], ambient_color[2], 1.0f);
980 render_info.m_sLightMaterial.m_vDiffuse = SpeedTree::Vec4(diffuse_color[0], diffuse_color[1], diffuse_color[2], 1.0f);
981 _forest_render.SetRenderInfo(render_info);
983 _forest_render.SetLightDir(_light_dir);
985 SpeedTree::st_float32 updated_splits[SpeedTree::c_nMaxNumShadowMaps];
986 memset(updated_splits, 0,
sizeof(updated_splits));
987 for (
int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
988 updated_splits[smi] = _shadow_infos[smi]._shadow_split;
991 _forest_render.SetCascadedShadowMapDistances(updated_splits, lens->
get_far());
992 _forest_render.SetShadowFadePercentage(speedtree_shadow_fade);
994 if (!_needs_repopulate) {
1029 TransformState::make_identity());
1030 object->set_draw_callback(
new DrawCallback(
this));
1048 if (validate_api(gsg)) {
1049 setup_for_render(gsg);
1060 int &internal_vertices,
1062 Thread *current_thread)
const {
1063 internal_vertices = 0;
1065 SpeedTree::CExtents extents;
1066 Trees::const_iterator ti;
1067 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1071 const STInstances &st_instances = instance_list->_instances;
1072 STInstances::const_iterator ii;
1073 for (ii = st_instances.begin(); ii != st_instances.end(); ++ii) {
1074 SpeedTree::CExtents tree_extents = tree->
get_tree()->GetExtents();
1075 tree_extents.Rotate((*ii).GetRotationAngle());
1076 tree_extents.Scale((*ii).GetScale());
1077 tree_extents.Translate((*ii).GetPos());
1078 extents.ExpandAround(tree_extents);
1082 const SpeedTree::Vec3 &emin = extents.Min();
1083 const SpeedTree::Vec3 &emax = extents.Max();
1084 internal_bounds =
new BoundingBox(LPoint3(emin[0], emin[1], emin[2]),
1085 LPoint3(emax[0], emax[1], emax[2]));
1094output(ostream &out)
const {
1095 PandaNode::output(out);
1105write(ostream &out,
int indent_level)
const {
1106 PandaNode::write(out, indent_level);
1125 const char *error = SpeedTree::CCore::GetError();
1126 if (error !=
nullptr) {
1136set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode eMode)
const {
1139 SpeedTree::CRenderState::SetBlending(
false);
1140 SpeedTree::CRenderState::SetAlphaTesting(
false);
1141 SpeedTree::CRenderState::SetAlphaToCoverage(
false);
1144 case SpeedTree::TRANS_TEXTURE_ALPHA_TESTING:
1145 SpeedTree::CRenderState::SetAlphaTesting(
true);
1147 case SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE:
1148 SpeedTree::CRenderState::SetAlphaToCoverage(
true);
1150 case SpeedTree::TRANS_TEXTURE_BLENDING:
1151 SpeedTree::CRenderState::SetBlending(
true);
1164 PandaNode::set_cull_callback();
1167 _needs_repopulate =
false;
1171 speedtree_cat.warning()
1172 <<
"SpeedTree license not available.\n";
1176 _forest_render.SetHint(SpeedTree::CForest::HINT_MAX_NUM_VISIBLE_CELLS,
1177 speedtree_max_num_visible_cells);
1179 _forest_render.SetCullCellSize(speedtree_cull_cell_size);
1192 Thread *current_thread) {
1193 if (node->
is_of_type(SpeedTreeNode::get_class_type()) && node !=
this) {
1198 Children children = node->
get_children(current_thread);
1199 for (
int i = 0; i < children.get_num_children(); i++) {
1201 CPT(
TransformState) child_transform = transform->compose(child->get_transform());
1202 r_add_instances(child, child_transform, current_thread);
1212 _forest_render.ClearInstances();
1215 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1216 InstanceList *instance_list = (*ti);
1218 const STInstances &instances = instance_list->_instances;
1219 if (instances.empty()) {
1227 if (!_forest_render.AddInstances(tree->
get_tree(), &instances[0], instances.size())) {
1228 speedtree_cat.warning()
1229 <<
"Failed to add " << instances.size()
1230 <<
" instances for " << *tree <<
"\n";
1235 _forest_render.GetPopulationStats(_population_stats);
1236 print_forest_stats(_population_stats);
1239 int max_instances_by_cell = 1;
1240 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1241 InstanceList *instance_list = (*ti);
1243 const STInstances &instances = instance_list->_instances;
1244 if (instances.empty()) {
1248 int max_instances = 1;
1249 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si;
1250 si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->
get_tree());
1251 if (si != _population_stats.m_mMaxNumInstancesPerCellPerBase.end()) {
1252 max_instances = std::max(max_instances, (
int)si->second);
1255 max_instances_by_cell = std::max(max_instances_by_cell, max_instances);
1258 _visible_trees.Reserve(_forest_render.GetBaseTrees(),
1259 _forest_render.GetBaseTrees().size(),
1260 speedtree_max_num_visible_cells,
1261 max_instances_by_cell,
1262 speedtree_horizontal_billboards);
1269update_terrain_cells() {
1272 SpeedTree::TTerrainCellArray &cells = _visible_terrain.m_aCellsToUpdate;
1274 int num_tile_res = _terrain_render.GetMaxTileRes();
1275 PN_stdfloat cell_size = _terrain_render.GetCellSize();
1280 GeomEnums::UH_static);
1281 int num_vertices = num_tile_res * num_tile_res;
1282 vertex_data->set_num_rows(num_vertices);
1283 size_t num_bytes = vertex_data->get_array(0)->get_data_size_bytes();
1285 int num_cells = (int)cells.size();
1286 for (
int ci = 0; ci < num_cells; ++ci) {
1287 SpeedTree::CTerrainCell *cell = cells[ci];
1288 nassertv(cell !=
nullptr && cell->GetVbo() !=
nullptr);
1289 int cell_yi = cell->Row();
1290 int cell_xi = cell->Col();
1293 _terrain->fill_vertices(vertex_data,
1294 cell_xi * cell_size, cell_yi * cell_size,
1295 cell_size, num_tile_res);
1299 const unsigned char *data_pointer = handle->get_read_pointer(
true);
1300 SpeedTree::CGeometryBuffer *vbo = (SpeedTree::CGeometryBuffer *)cell->GetVbo();
1302 nassertv(vbo->NumVertices() == num_tile_res * num_tile_res);
1303 nassertv(vbo->NumVertices() * vbo->VertexSize() == handle->get_data_size_bytes());
1304 vbo->OverwriteVertices(data_pointer, num_vertices, 0);
1315 nassertr(pipe !=
nullptr,
true);
1317#if defined(SPEEDTREE_OPENGL)
1318 static const string compiled_api =
"OpenGL";
1319#elif defined(SPEEDTREE_DIRECTX9)
1320 static const string compiled_api =
"DirectX9";
1322 #error Unexpected graphics API.
1325 if (pipe->get_interface_name() != compiled_api) {
1326 speedtree_cat.error()
1327 <<
"SpeedTree is compiled for " << compiled_api
1328 <<
", cannot render with " << pipe->get_interface_name()
1344 PStatTimer timer(_draw_speedtree_pcollector);
1346 DCAST_INTO_V(geom_cbdata, data);
1350 setup_for_render(gsg);
1353 SpeedTree::CRenderState::SetAlphaFunction(SpeedTree::ALPHAFUNC_GREATER, 0.0f);
1356 _forest_render.StartRender();
1358 if (_forest_render.ShadowsAreEnabled()) {
1361 PStatTimer timer(_draw_speedtree_shadows_pcollector);
1362 render_forest_into_shadow_maps();
1363 _forest_render.ClearBoundTextures( );
1366 if (!_forest_render.UploadViewShaderParameters(_view)) {
1367 speedtree_cat.warning()
1368 <<
"Couldn't set view parameters\n";
1373 PStatTimer timer1(_draw_speedtree_terrain_pcollector);
1375 _terrain_render.UploadShaderConstants
1376 (&_forest_render, _light_dir,
1377 _forest_render.GetRenderInfo().m_sLightMaterial);
1380 set_transparent_texture_mode(SpeedTree::TRANS_TEXTURE_NOTHING);
1383 bool terrain = _terrain_render.Render
1384 (&_forest_render, _visible_terrain, SpeedTree::RENDER_PASS_STANDARD,
1385 _light_dir, _forest_render.GetRenderInfo().m_sLightMaterial,
1386 &_forest_render.GetRenderStats());
1389 speedtree_cat.warning()
1390 <<
"Failed to render terrain\n";
1400 PStatTimer timer1(_draw_speedtree_trees_pcollector);
1404 SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE;
1408 set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode(mode));
1410 bool branches = _forest_render.RenderBranches(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
1411 bool fronds = _forest_render.RenderFronds(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
1412 bool leaf_meshes = _forest_render.RenderLeafMeshes(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
1413 bool leaf_cards = _forest_render.RenderLeafCards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
1414 bool billboards = _forest_render.RenderBillboards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
1420 if (!branches || !fronds || !leaf_meshes || !leaf_cards ) {
1421 speedtree_cat.warning()
1422 <<
"Failed to render forest completely: "
1423 << branches <<
" " << fronds <<
" " << leaf_meshes <<
" " << leaf_cards <<
" " << billboards <<
"\n";
1428 _forest_render.EndRender();
1430 if (_forest_render.ShadowsAreEnabled() && speedtree_show_overlays) {
1431 _forest_render.RenderOverlays();
1445render_forest_into_shadow_maps() {
1446 bool success =
true;
1449 SpeedTree::CRenderState::SetMultisampling(
false);
1450 SpeedTree::CRenderState::SetAlphaToCoverage(
false);
1452#if defined(SPEEDTREE_OPENGL)
1454 glDisable(GL_SCISSOR_TEST);
1457 for (
int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
1458 const SpeedTree::CView &light_view = _shadow_infos[smi]._light_view;
1459 const SpeedTree::SForestCullResults &light_cull = _shadow_infos[smi]._light_cull;
1461 if (_forest_render.BeginShadowMap(smi, light_view)) {
1462 success &= _forest_render.UploadViewShaderParameters(light_view);
1466 SpeedTree::CRenderState::SetPolygonOffset(1.0f, 0.125f);
1468 success &= _forest_render.RenderBranches(light_cull, SpeedTree::RENDER_PASS_SHADOW);
1472 SpeedTree::CRenderState::SetPolygonOffset(10.0f, 1.0f);
1474 success &= _forest_render.RenderFronds(light_cull, SpeedTree::RENDER_PASS_SHADOW);
1475 success &= _forest_render.RenderLeafMeshes(light_cull, SpeedTree::RENDER_PASS_SHADOW);
1476 success &= _forest_render.RenderLeafCards(light_cull, SpeedTree::RENDER_PASS_SHADOW, light_view);
1480 success &= _forest_render.EndShadowMap(smi);
1488 speedtree_cat.warning()
1489 <<
"Failed to render shadow maps\n";
1501 if (!_done_first_init) {
1506#ifdef SPEEDTREE_OPENGL
1509 GLenum err = glewInit();
1510 if (err != GLEW_OK) {
1511 speedtree_cat.error()
1512 <<
"GLEW initialization failed: %s\n", glewGetErrorString(err);
1520 if (!GLEW_VERSION_2_0) {
1521 speedtree_cat.error()
1522 <<
"The SpeedTree OpenGL implementation requires OpenGL 2.0 or better to run; this system has version " << glGetString(GL_VERSION) <<
"\n";
1528 _done_first_init =
true;
1531#ifdef SPEEDTREE_DIRECTX9
1534 SpeedTree::DX9::SetDevice(dxgsg->_screen->_d3d_device);
1537 if (_needs_repopulate) {
1541 Trees::const_iterator ti;
1542 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1543 InstanceList *instance_list = (*ti);
1545 const STInstances &instances = instance_list->_instances;
1546 if (instances.empty()) {
1550 int max_instances = 2;
1551 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si;
1552 si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->
get_tree());
1553 if (si != _population_stats.m_mMaxNumInstancesPerCellPerBase.end()) {
1554 max_instances = std::max(max_instances, (
int)si->second);
1558 string os_textures_dir;
1559 if (!speedtree_textures_dir.empty()) {
1560 os_textures_dir = speedtree_textures_dir.
get_value().to_os_specific();
1563#if defined(WIN32) || defined(WIN64)
1564 if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] !=
'\\') {
1565 os_textures_dir +=
"\\";
1568 if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] !=
'/') {
1569 os_textures_dir +=
"/";
1574 if (!_forest_render.InitTreeGraphics((SpeedTree::CTreeRender *)tree->
get_tree(),
1575 max_instances, speedtree_horizontal_billboards,
1576 os_textures_dir.c_str())) {
1577 if (speedtree_cat.is_debug()) {
1578 speedtree_cat.debug()
1579 <<
"Failed to init tree graphics for " << *tree <<
"\n";
1586 if (!_forest_render.InitGraphics(
false)) {
1587 speedtree_cat.warning()
1588 <<
"Failed to init graphics\n";
1596 _forest_render.UpdateTreeCellExtents();
1600 if (!_terrain_render.Init(speedtree_terrain_num_lods,
1601 speedtree_terrain_resolution,
1602 speedtree_terrain_cell_size,
1603 _terrain->get_st_vertex_format())) {
1604 speedtree_cat.warning()
1605 <<
"Failed to init terrain\n";
1613 _needs_repopulate =
false;
1616 PStatTimer timer1(_draw_speedtree_terrain_update_pcollector);
1617 update_terrain_cells();
1627 PStatTimer timer1(_cull_speedtree_trees_pcollector);
1628 _forest_render.CullAndComputeLOD(_view, _visible_trees);
1631 PStatTimer timer1(_cull_speedtree_terrain_pcollector);
1632 _terrain_render.CullAndComputeLOD(_view, _visible_terrain);
1635 if (_forest_render.ShadowsAreEnabled()) {
1636 PStatTimer timer1(_cull_speedtree_shadows_pcollector);
1637 for (
int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
1638 SpeedTree::CView &light_view = _shadow_infos[smi]._light_view;
1639 SpeedTree::SForestCullResultsRender &light_cull = _shadow_infos[smi]._light_cull;
1641 _forest_render.ComputeLightView
1642 (_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi,
1645 light_view.SetLodRefPoint(_view.GetCameraPos());
1646 _forest_render.CullAndComputeLOD(light_view, light_cull,
false);
1656print_forest_stats(
const SpeedTree::CForest::SPopulationStats &forest_stats)
const {
1657 fprintf(stderr,
"\n Forest Population Statistics\n");
1658 fprintf(stderr,
" ---------------------------------------------------\n");
1659 fprintf(stderr,
" # of tree cull cells: %d\n", forest_stats.m_nNumCells);
1660 fprintf(stderr,
" # of unique base trees: %d\n", forest_stats.m_nNumBaseTrees);
1661 fprintf(stderr,
" total # of instances: %d\n", forest_stats.m_nNumInstances);
1662 fprintf(stderr,
" average # of instances per base: %g\n", forest_stats.m_fAverageNumInstancesPerBase);
1663 fprintf(stderr,
" max # of billboards/instances per cell: %d\n", forest_stats.m_nMaxNumBillboardsPerCell);
1664 fprintf(stderr,
" max # of instances per cell per base:\n");
1665 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator i;
1666 for (i = forest_stats.m_mMaxNumInstancesPerCellPerBase.begin( ); i != forest_stats.m_mMaxNumInstancesPerCellPerBase.end( ); ++i) {
1667 fprintf(stderr,
" %35s: %4d\n", SpeedTree::CFixedString(i->first->GetFilename( )).NoPath( ).c_str( ), i->second);
1669 fprintf(stderr,
" average # instances per cell: %g\n", forest_stats.m_fAverageInstancesPerCell);
1670 fprintf(stderr,
" max # of billboard images: %d\n", forest_stats.m_nMaxNumBillboardImages);
1671 fprintf(stderr,
"\n");
1690 int num_trees = _trees.
size();
1692 Trees::const_iterator ti;
1693 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1711 node->fillin(scan, manager);
1722 PandaNode::fillin(scan, manager);
1726 for (
int i = 0; i < num_trees; i++) {
1727 InstanceList *instance_list =
new InstanceList(
nullptr);
1728 instance_list->fillin(scan, manager);
1729 if (instance_list->get_tree() ==
nullptr) {
1731 delete instance_list;
1743void SpeedTreeNode::InstanceList::
1744output(ostream &out)
const {
1745 out << *_tree <<
": " << _instances.size() <<
" instances";
1751void SpeedTreeNode::InstanceList::
1752write(ostream &out,
int indent_level)
const {
1753 indent(out, indent_level)
1754 << *_tree <<
": " << _instances.size() <<
" instances.\n";
1755 STInstances::const_iterator ii;
1756 for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
1757 indent(out, indent_level + 2)
1783 int num_instances = _instances.size();
1785 STInstances::const_iterator ii;
1786 for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
1804 PT(
PandaNode) srt_root = loader->load_sync(srt_filename);
1806 if (srt_root !=
nullptr) {
1819 _instances.reserve(num_instances);
1820 for (
int i = 0; i < num_instances; i++) {
1822 transform.
fillin(scan, manager);
1823 _instances.push_back(transform);
1832void SpeedTreeNode::DrawCallback::
1834 _node->draw_callback(data);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
A light source that seems to illuminate all points in space at once.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
get_filename
If a BAM is a file, then the BamWriter should contain the name of the file.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
This is a generic data block that is passed along to a CallbackObject when a callback is made.
A ClockObject keeps track of elapsed real time and discrete time.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
get_value
Returns the variable's value.
size_t get_num_words() const
Returns the number of words in the variable's value.
virtual void record_object(CullableObject *object, const CullTraverser *traverser)
This callback function is intended to be overridden by a derived class.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
SceneSetup * get_scene() const
Returns the SceneSetup object.
GraphicsStateGuardianBase * get_gsg() const
Returns the GraphicsStateGuardian in effect.
The smallest atom of cull.
This class stores a list of directories that can be searched, in order, to locate a particular file.
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
A GraphicsStateGuardian for rendering into DirectX9 contexts.
A class to retrieve the individual data elements previously stored in a Datagram.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
std::string get_string()
Extracts a variable-length string.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
A light shining from infinitely far away in a particular direction, like sunlight.
get_direction
Returns the direction in which the light is aimed.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
The name of a file, such as a texture file or an Egg file.
bool resolve_filename(const DSearchPath &searchpath, const std::string &default_extension=std::string())
Searches the given search path for the filename.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
int find_on_searchpath(const DSearchPath &searchpath)
Performs the reverse of the resolve_filename() operation: assuming that the current filename is fully...
bool is_directory() const
Returns true if the filename exists on the physical disk and is a directory name, false otherwise.
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash,...
std::string get_dirname() const
Returns the directory part of the filename.
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname),...
This specialization on CallbackData is passed when the callback is initiated from deep within the dra...
void set_lost_state(bool lost_state)
Sets the lost_state flag.
GraphicsStateGuardianBase * get_gsg() const
Returns a pointer to the current GSG.
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
This is the data for one array of a GeomVertexData structure.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
An object to create GraphicsOutputs that share a particular 3-D API.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Encapsulates all the communication with a particular instance of a given rendering backend.
get_pipe
Returns the graphics pipe on which this GSG was created.
virtual CoordinateSystem get_internal_coordinate_system() const
Returns the coordinate system used internally by the GSG.
A base class for any number of different kinds of lenses, linear and otherwise.
get_far
Returns the position of the far plane (or cylinder, sphere, whatever).
get_near
Returns the position of the near plane (or cylinder, sphere, whatever).
get_coordinate_system
Returns the coordinate system that all 3-d computations are performed within for this Lens.
const LMatrix4 & get_projection_mat(StereoChannel channel=SC_mono) const
Returns the complete transformation matrix from a 3-d point in space to a point on the film,...
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
get_num_on_lights
Returns the number of lights that are turned on by the attribute.
get_on_light
Returns the nth light turned on by the attribute, sorted in render order.
get_color
Returns the basic color of the light.
get_priority
Returns the priority associated with this light.
Specifies parameters that may be passed to the loader.
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
static Loader * get_global_ptr()
Returns a pointer to the global Loader.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
NodePath find(const std::string &path) const
Searches for a node below the referenced node that matches the indicated string.
bool is_empty() const
Returns true if the NodePath contains no nodes.
PandaNode * node() const
Returns the referenced node of the path.
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
A basic node of the scene graph or data graph.
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so.
get_child
Returns the nth child node of this node.
get_children
Returns an object that can be used to walk through the list of children of the node.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
A handy class to return random numbers.
double random_real(double range)
Returns a random double in the range [0, range).
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
A specific implementation of STTerrain that supports basic heightmaps loaded from an image file,...
This is the abstract base class that defines the interface needed to describe a terrain for rendering...
const Filename & get_splat_layer(int n) const
Returns the nth splat layer that is to be applied to the terrain.
PN_stdfloat get_max_height() const
Returns the largest height value that might be returned by get_height().
PN_stdfloat get_min_height() const
Returns the smallest height value that might be returned by get_height().
int get_num_splat_layers() const
Returns the number of splat layers that are to be applied to the terrain.
const Filename & get_normal_map() const
Returns the normal map that should be applied to the terrain.
bool is_valid() const
Returns true if the terrain data is well-defined and ready to use.
const Filename & get_splat_map() const
Returns the splat map that should be applied to the terrain.
PN_stdfloat get_splat_layer_tiling(int n) const
Returns the tiling value of the nth splat layer.
virtual void load_data()=0
This will be called at some point after initialization.
Encapsulates a single tree model in the SpeedTree library, as loaded from an SRT file.
bool is_valid() const
Returns true if the tree was successfully loaded and is ready to be used, false otherwise.
const SpeedTree::CTreeRender * get_tree() const
Returns a const pointer to the internal SpeedTree object.
const Filename & get_fullpath() const
Returns the full pathname to the SRT file that was loaded for this tree, as passed to the constructor...
const Lens * get_lens() const
Returns the particular Lens used for rendering.
const NodePath & get_scene_root() const
Returns the root node of the scene.
const TransformState * get_cs_transform() const
Returns the transform from the camera's coordinate system to the GSG's internal coordinate system.
int add_instance(const STTransform &transform)
Adds a new instance of this tree at the indicated transform.
void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void set_instance(int n, const STTransform &transform)
Replaces the transform of the nth instance of this tree.
const STTree * get_tree() const
Returns the particular tree this list refers to.
get_num_instances
Returns the number of instances of this tree.
void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is called by make_from_bam to read in all of the relevant data from the BamFil...
get_instance
Returns the transform of the nth instance of this tree.
Interfaces with the SpeedTree library to render SpeedTree objects, especially trees,...
void add_instances_from(const SpeedTreeNode *other)
Adds all of the instances defined within the indicated SpeedTreeNode as instances of this node.
bool has_terrain() const
Returns true if a valid terrain has been associated with the node, false otherwise.
void add_random_instances(const STTree *tree, int quantity, PN_stdfloat x_min, PN_stdfloat x_max, PN_stdfloat y_min, PN_stdfloat y_max, PN_stdfloat scale_min, PN_stdfloat scale_max, PN_stdfloat height_min, PN_stdfloat height_max, PN_stdfloat slope_min, PN_stdfloat slope_max, Randomizer &randomizer=Randomizer())
Creates a number of random instances of the indicated true, within the indicated range.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
get_num_trees
Returns the number of unique tree objects that have been added to the node.
static void register_with_read_factory()
Tells the BamReader how to create objects of type SpeedTreeNode.
bool is_valid() const
Returns true if the node is valid and ready to render, false otherwise.
void set_terrain(STTerrain *terrain)
Associated a terrain with the node.
get_instance_list
Returns a list of transforms that corresponds to the instances at which the indicated tree appears.
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data)
Adds the node's contents to the CullResult we are building up during the cull traversal,...
void add_instance(const STTree *tree, const STTransform &transform)
Adds a new instance of the indicated tree at the indicated transform.
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, GeomTransformer &transformer)
Applies whatever attributes are specified in the AccumulatedAttribs object (and by the attrib_types b...
get_tree
Returns the STTree pointer for the nth tree.
static void write_error(std::ostream &out)
Writes the current SpeedTree error message to the indicated stream.
static bool authorize(const std::string &license="")
Make this call to initialized the SpeedTree API and verify the license.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
bool setup_terrain(const Filename &terrain_file)
A convenience function to set up terrain geometry by reading a terrain.txt file as defined by SpeedTr...
bool has_instance_list(const STTree *tree) const
Returns true if the indicated tree has any instances within this node, false otherwise.
void reload_config()
Re-reads the current setting of all of the relevant config variables and applies them to this node.
bool add_from_stf(const Filename &stf_filename, const LoaderOptions &options=LoaderOptions())
Opens and reads the named STF (SpeedTree Forest) file, and adds the SRT files named within as instanc...
virtual PandaNode * combine_with(PandaNode *other)
Collapses this node with the other node, if possible, and returns a pointer to the combined node,...
int count_total_instances() const
Returns the total number of trees that will be rendered by this node, counting all instances of all t...
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, int &internal_vertices, int pipeline_stage, Thread *current_thread) const
Returns a newly-allocated BoundingVolume that represents the internal contents of the node.
InstanceList & modify_instance_list(const STTree *tree)
Returns a modifiable list of transforms that corresponds to the instances of this tree.
STTerrain * get_terrain() const
Returns the terrain associated with the node, or NULL if there is no terrain.
void remove_all_trees()
Removes all instances of all trees from the node.
void add_instances(const NodePath &root, const TransformState *transform=TransformState::make_identity())
Walks the scene graph beginning at root, looking for nested SpeedTreeNodes.
InstanceList & add_tree(const STTree *tree)
Adds a new tree for rendering.
int remove_tree(const STTree *tree)
Removes all instances of the indicated tree.
virtual void output(std::ostream &out) const
Writes a brief description of the node to the indicated output stream.
void prepare_scene(GraphicsStateGuardianBase *gsgbase, const RenderState *net_state)
Walks through the scene graph beginning at this node, and does whatever initialization is required to...
void snap_to_terrain()
Adjusts all the trees in this node so that their Z position matches the height of the terrain at thei...
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
void set_wind(double strength, const LVector3 &direction)
Specifies the overall wind strength and direction.
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
bool has_all_off() const
Returns true if this attrib turns off all stages (although it may also turn some on).
A thread; that is, a lightweight process.
get_current_thread
Returns a pointer to the currently-executing Thread object.
TypeHandle is the identifier used to differentiate C++ class types.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Base class for objects that can be written to and read from Bam files.
A hierarchy of directories and files that appears to be one continuous file system,...
Filename get_cwd() const
Returns the current directory name.
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists in the virtual file system hierarchy.
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
void reserve(size_type_0 n)
Informs the vector of a planned change in size; ensures that the capacity of the vector is greater th...
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
size_type_0 size() const
Returns the number of elements in the ordered vector.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void clear()
Removes all elements from the ordered vector.
void sort()
Maps to sort_unique().
This is our own Panda specialization on the default STL map.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.