15 #include "pandabase.h"
16 #include "speedTreeNode.h"
17 #include "stBasicTerrain.h"
18 #include "virtualFileSystem.h"
19 #include "config_util.h"
20 #include "cullTraverser.h"
21 #include "cullableObject.h"
22 #include "cullHandler.h"
23 #include "omniBoundingVolume.h"
24 #include "boundingSphere.h"
25 #include "boundingBox.h"
26 #include "clockObject.h"
27 #include "geomDrawCallbackData.h"
28 #include "graphicsStateGuardian.h"
29 #include "textureAttrib.h"
30 #include "lightAttrib.h"
31 #include "directionalLight.h"
32 #include "ambientLight.h"
34 #include "deg_2_rad.h"
35 #include "sceneGraphReducer.h"
36 #include "pStatTimer.h"
38 #ifdef SPEEDTREE_OPENGL
39 #include "glew/glew.h"
40 #endif // SPEEDTREE_OPENGL
42 #ifdef SPEEDTREE_DIRECTX9
43 #include "dxGraphicsStateGuardian9.h"
46 double SpeedTreeNode::_global_time_delta = 0.0;
47 bool SpeedTreeNode::_authorized;
48 bool SpeedTreeNode::_done_first_init;
50 TypeHandle SpeedTreeNode::DrawCallback::_type_handle;
52 PStatCollector SpeedTreeNode::_cull_speedtree_pcollector(
"Cull:SpeedTree");
53 PStatCollector SpeedTreeNode::_cull_speedtree_shadows_pcollector(
"Cull:SpeedTree:Shadows");
54 PStatCollector SpeedTreeNode::_cull_speedtree_trees_pcollector(
"Cull:SpeedTree:Trees");
55 PStatCollector SpeedTreeNode::_cull_speedtree_terrain_pcollector(
"Cull:SpeedTree:Terrain");
56 PStatCollector SpeedTreeNode::_draw_speedtree_pcollector(
"Draw:SpeedTree");
57 PStatCollector SpeedTreeNode::_draw_speedtree_shadows_pcollector(
"Draw:SpeedTree:Shadows");
58 PStatCollector SpeedTreeNode::_draw_speedtree_trees_pcollector(
"Draw:SpeedTree:Trees");
59 PStatCollector SpeedTreeNode::_draw_speedtree_terrain_pcollector(
"Draw:SpeedTree:Terrain");
60 PStatCollector SpeedTreeNode::_draw_speedtree_terrain_update_pcollector(
"Draw:SpeedTree:Terrain:Update");
68 SpeedTreeNode(
const string &name) :
70 #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);
138 int total_instances = 0;
139 Trees::const_iterator ti;
140 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
145 return total_instances;
162 Trees::iterator ti = _trees.find(&ilist);
163 if (ti == _trees.
end()) {
167 pair<Trees::iterator, bool> result = _trees.insert(instance_list);
169 bool inserted = result.second;
170 nassertr(inserted, *(*ti));
172 if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->
get_tree())) {
173 speedtree_cat.warning()
174 <<
"Failed to register tree " << tree->
get_fullpath() <<
"\n";
179 _needs_repopulate =
true;
182 return *instance_list;
194 Trees::iterator ti = _trees.find(&ilist);
195 if (ti == _trees.
end()) {
200 if (!_forest_render.UnregisterTree(tree->
get_tree())) {
201 speedtree_cat.warning()
202 <<
"Failed to unregister tree " << tree->
get_fullpath() <<
"\n";
206 _needs_repopulate =
true;
212 delete instance_list;
225 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
228 if (!_forest_render.UnregisterTree(tree->
get_tree())) {
229 speedtree_cat.warning()
230 <<
"Failed to unregister tree " << tree->
get_fullpath() <<
"\n";
233 delete instance_list;
237 _needs_repopulate =
true;
250 Trees::const_iterator ti = _trees.find(&ilist);
251 return (ti != _trees.
end());
265 Trees::const_iterator ti = _trees.find(&ilist);
266 if (ti == _trees.
end()) {
273 return *instance_list;
298 new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
331 for (
int ti = 0; ti < num_trees; ++ti) {
337 for (
int i = 0; i < num_instances; ++i) {
355 for (
int ti = 0; ti < num_trees; ++ti) {
361 for (
int i = 0; i < num_instances; ++i) {
362 CPT(TransformState) other_trans = other_instance_list.
get_instance(i);
363 CPT(TransformState) new_trans = transform->compose(other_trans);
367 new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
392 PN_stdfloat x_min, PN_stdfloat x_max,
393 PN_stdfloat y_min, PN_stdfloat y_max,
394 PN_stdfloat scale_min, PN_stdfloat scale_max,
395 PN_stdfloat height_min, PN_stdfloat height_max,
396 PN_stdfloat slope_min, PN_stdfloat slope_max,
399 _needs_repopulate =
true;
401 for (
int i = 0; i < quantity; ++i) {
403 transform._pos[0] = randomizer.
random_real(x_max - x_min) + x_min;
404 transform._pos[1] = randomizer.
random_real(y_max - y_min) + y_min;
406 transform._scale = randomizer.
random_real(scale_max - scale_min) + scale_min;
410 int repeat_count = speedtree_max_random_try_count;
411 while (!_terrain->placement_is_acceptable(transform._pos[0], transform._pos[1], height_min, height_max, slope_min, slope_max)) {
412 transform._pos[0] = randomizer.
random_real(x_max - x_min) + x_min;
413 transform._pos[1] = randomizer.
random_real(y_max - y_min) + y_min;
414 if (--repeat_count == 0) {
415 nassert_raise(
"Exceeded speedtree-max-random-try-count; bad placement parameters?");
419 transform._pos[2] = _terrain->get_height(transform._pos[0], transform._pos[1]);
423 transform._pos[2] = randomizer.
random_real(height_max - height_min) + height_min;
441 Filename fullpath = Filename::text_filename(stf_filename);
444 if (!vfs->
exists(fullpath)) {
445 speedtree_cat.warning()
446 <<
"Couldn't find " << stf_filename <<
"\n";
453 speedtree_cat.error()
454 <<
"Could not find " << stf_filename <<
"\n";
458 if (speedtree_cat.is_debug()) {
459 speedtree_cat.debug()
460 <<
"Reading STF file " << fullpath <<
"\n";
463 istream *in = file->open_read_file(
true);
489 if (loader == NULL) {
500 AlreadyLoaded already_loaded;
504 while (in && !in.eof()) {
507 AlreadyLoaded::iterator ai = already_loaded.find(srt_filename);
508 if (ai != already_loaded.end()) {
516 PT(
PandaNode) srt_root = loader->load_sync(srt_filename);
518 if (srt_root != NULL) {
528 already_loaded[srt_filename] = tree;
535 for (
int ni = 0; ni < num_instances && in && !in.eof(); ++ni) {
537 PN_stdfloat rotate, scale;
538 in >> pos[0] >> pos[1] >> pos[2] >> rotate >> scale;
540 if (!speedtree_5_2_stf) {
543 PN_stdfloat height_min, height_max, slope_min, slope_max;
544 in >> height_min >> height_max >> slope_min >> slope_max;
563 speedtree_cat.error()
564 <<
"Unexpected text in " << pathname <<
" at \"" << text <<
"\"\n";
587 if (terrain->setup_terrain(terrain_file)) {
609 _needs_repopulate =
true;
624 _terrain_render.SetShaderLoader(_forest_render.GetShaderLoader());
626 SpeedTree::STerrainRenderInfo trender_info;
627 trender_info.m_strShaderPath = _os_shaders_dir.c_str();
630 trender_info.m_strNormalMap = os_specific.c_str();
632 trender_info.m_strSplatMap = os_specific.c_str();
634 for (
int i = 0; i < SpeedTree::c_nNumTerrainSplatLayers; ++i) {
636 trender_info.m_astrSplatLayers[i] = os_specific.c_str();
640 trender_info.m_fNormalMapBlueScale = 1.0f;
641 trender_info.m_bShadowsEnabled =
false;
642 trender_info.m_bZPrePass =
false;
644 _terrain_render.SetRenderInfo(trender_info);
648 if (speedtree_follow_terrain) {
663 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
668 for (
int i = 0; i < num_instances; ++i) {
671 pos[2] = _terrain->get_height(pos[0], pos[1]);
676 for (
int i = 0; i < num_instances; ++i) {
686 _needs_repopulate =
true;
700 _shadow_infos.clear();
701 int num_shadow_maps = speedtree_cascading_shadow_splits.
get_num_words();
702 if (num_shadow_maps > SpeedTree::c_nMaxNumShadowMaps) {
703 speedtree_cat.warning()
704 <<
"SpeedTree is current compiled to support a maximum of "
705 << SpeedTree::c_nMaxNumShadowMaps <<
" shadow maps.\n";
706 num_shadow_maps = SpeedTree::c_nMaxNumShadowMaps;
708 _shadow_infos.insert(_shadow_infos.begin(), num_shadow_maps, ShadowInfo());
709 for (
int smi = 0; smi < num_shadow_maps; ++smi) {
710 _shadow_infos[smi]._shadow_split = speedtree_cascading_shadow_splits[smi];
713 SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo();
715 render_info.m_nMaxAnisotropy = speedtree_max_anisotropy;
716 render_info.m_bHorizontalBillboards = speedtree_horizontal_billboards;
717 render_info.m_fAlphaTestScalar = speedtree_alpha_test_scalar;
718 render_info.m_bZPrePass = speedtree_z_pre_pass;
719 render_info.m_nMaxBillboardImagesByBase = speedtree_max_billboard_images_by_base;
720 render_info.m_fVisibility = speedtree_visibility;
721 render_info.m_fGlobalLightScalar = speedtree_global_light_scalar;
722 render_info.m_sLightMaterial.m_vSpecular = SpeedTree::Vec4(speedtree_specular_color[0], speedtree_specular_color[1], speedtree_specular_color[2], speedtree_specular_color[3]);
723 render_info.m_sLightMaterial.m_vEmissive = SpeedTree::Vec4(speedtree_emissive_color[0], speedtree_emissive_color[1], speedtree_emissive_color[2], speedtree_emissive_color[3]);
724 render_info.m_bSpecularLighting = speedtree_specular_lighting;
725 render_info.m_bTransmissionLighting = speedtree_transmission_lighting;
726 render_info.m_bDetailLayer = speedtree_detail_layer;
727 render_info.m_bDetailNormalMapping = speedtree_detail_normal_mapping;
728 render_info.m_bAmbientContrast = speedtree_ambient_contrast;
729 render_info.m_fTransmissionScalar = speedtree_transmission_scalar;
730 render_info.m_fFogStartDistance = speedtree_fog_distance[0];
731 render_info.m_fFogEndDistance = speedtree_fog_distance[1];
732 render_info.m_vFogColor = SpeedTree::Vec3(speedtree_fog_color[0], speedtree_fog_color[1], speedtree_fog_color[2]);
733 render_info.m_vSkyColor = SpeedTree::Vec3(speedtree_sky_color[0], speedtree_sky_color[1], speedtree_sky_color[2]);
734 render_info.m_fSkyFogMin = speedtree_sky_fog[0];
735 render_info.m_fSkyFogMax = speedtree_sky_fog[1];
736 render_info.m_vSunColor = SpeedTree::Vec3(speedtree_sun_color[0], speedtree_sun_color[1], speedtree_sun_color[2]);
737 render_info.m_fSunSize = speedtree_sun_size;
738 render_info.m_fSunSpreadExponent = speedtree_sun_spread_exponent;
739 render_info.m_fSunFogBloom = speedtree_sun_fog_bloom;
740 render_info.m_nNumShadowMaps = num_shadow_maps;
741 render_info.m_nShadowMapResolution = speedtree_shadow_map_resolution;
742 render_info.m_bSmoothShadows = speedtree_smooth_shadows;
743 render_info.m_bShowShadowSplitsOnTerrain = speedtree_show_shadow_splits_on_terrain;
744 render_info.m_bWindEnabled = speedtree_wind_enabled;
745 render_info.m_bFrondRippling = speedtree_frond_rippling;
747 _forest_render.SetRenderInfo(render_info);
749 _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
750 _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
751 speedtree_max_num_visible_cells);
752 _visible_terrain.Reserve(speedtree_max_num_visible_cells);
754 _needs_repopulate =
true;
765 _forest_render.SetGlobalWindStrength(strength);
766 _forest_render.SetGlobalWindDirection(SpeedTree::Vec3(direction[0], direction[1], direction[2]));
783 if (!license.empty()) {
784 SpeedTree::CCore::Authorize(license.c_str());
786 if (!speedtree_license.empty()) {
787 SpeedTree::CCore::Authorize(speedtree_license.c_str());
791 _authorized = SpeedTree::CCore::IsAuthorized();
793 SpeedTree::CCore::SetTextureFlip(
true);
807 _os_shaders_dir(copy._os_shaders_dir),
808 _shadow_infos(copy._shadow_infos),
809 #ifdef ST_DELETE_FOREST_HACK
813 _forest_render(*(new SpeedTree::CForestRender)),
815 _time_delta(copy._time_delta)
819 _forest_render.SetRenderInfo(copy._forest_render.GetRenderInfo());
820 _terrain_render.SetRenderInfo(copy._terrain_render.GetRenderInfo());
823 _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
824 _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
825 speedtree_max_num_visible_cells);
826 _visible_terrain.Reserve(speedtree_max_num_visible_cells);
828 Trees::const_iterator ti;
829 for (ti = copy._trees.
begin(); ti != copy._trees.
end(); ++ti) {
830 InstanceList *instance_list = (*ti);
832 if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->
get_tree())) {
833 speedtree_cat.warning()
834 <<
"Failed to register tree " << tree->
get_fullpath() <<
"\n";
838 _trees.
push_back(
new InstanceList(*instance_list));
844 _needs_repopulate =
true;
857 _forest_render.ClearInstances();
926 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
929 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
931 STInstances &instances = instance_list->_instances;
932 STInstances::iterator sti;
933 for (sti = instances.begin(); sti != instances.end(); ++sti) {
935 (*sti) = orig_transform *
xform;
976 if (!validate_api(gsg)) {
981 _forest_render.SetGlobalTime(clock->
get_frame_time() + _time_delta + _global_time_delta);
982 _forest_render.AdvanceGlobalWind();
986 CPT(TransformState) orig_modelview = data.get_modelview_transform(trav);
988 CPT(TransformState) camera_transform = modelview->invert_compose(TransformState::make_identity());
989 LMatrix4f modelview_mat = LCAST(
float, modelview->get_mat());
990 const LPoint3 &camera_pos = camera_transform->get_pos();
997 _view.Set(SpeedTree::Vec3(camera_pos[0], camera_pos[1], camera_pos[2]),
998 SpeedTree::Mat4x4(projection_mat.
get_data()),
999 SpeedTree::Mat4x4(modelview_mat.
get_data()),
1007 bool show_textures =
true;
1012 _forest_render.EnableTexturing(show_textures);
1013 _terrain_render.EnableTexturing(show_textures);
1019 LColor ambient_color(0.0f, 0.0f, 0.0f, 0.0f);
1024 int diffuse_priority = 0;
1040 ambient_color += light_obj->
get_color();
1049 _light_dir = SpeedTree::Vec3(dir[0], dir[1], dir[2]);
1056 _light_dir = SpeedTree::Vec3(0.0, 0.0, -1.0);
1060 ambient_color.set(1.0f, 1.0f, 1.0f, 1.0f);
1061 diffuse_color.set(1.0f, 1.0f, 1.0f, 1.0f);
1064 SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo();
1065 render_info.m_sLightMaterial.m_vAmbient = SpeedTree::Vec4(ambient_color[0], ambient_color[1], ambient_color[2], 1.0f);
1066 render_info.m_sLightMaterial.m_vDiffuse = SpeedTree::Vec4(diffuse_color[0], diffuse_color[1], diffuse_color[2], 1.0f);
1067 _forest_render.SetRenderInfo(render_info);
1069 _forest_render.SetLightDir(_light_dir);
1071 SpeedTree::st_float32 updated_splits[SpeedTree::c_nMaxNumShadowMaps];
1072 memset(updated_splits, 0,
sizeof(updated_splits));
1073 for (
int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
1074 updated_splits[smi] = _shadow_infos[smi]._shadow_split;
1077 _forest_render.SetCascadedShadowMapDistances(updated_splits, lens->
get_far());
1078 _forest_render.SetShadowFadePercentage(speedtree_shadow_fade);
1080 if (!_needs_repopulate) {
1123 TransformState::make_identity());
1124 object->set_draw_callback(
new DrawCallback(
this));
1147 if (validate_api(gsg)) {
1148 setup_for_render(gsg);
1162 int &internal_vertices,
1164 Thread *current_thread)
const {
1165 internal_vertices = 0;
1167 SpeedTree::CExtents extents;
1168 Trees::const_iterator ti;
1169 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1173 const STInstances &st_instances = instance_list->_instances;
1174 STInstances::const_iterator ii;
1175 for (ii = st_instances.begin(); ii != st_instances.end(); ++ii) {
1176 SpeedTree::CExtents tree_extents = tree->
get_tree()->GetExtents();
1177 tree_extents.Rotate((*ii).GetRotationAngle());
1178 tree_extents.Scale((*ii).GetScale());
1179 tree_extents.Translate((*ii).GetPos());
1180 extents.ExpandAround(tree_extents);
1184 const SpeedTree::Vec3 &emin = extents.Min();
1185 const SpeedTree::Vec3 &emax = extents.Max();
1187 LPoint3(emax[0], emax[1], emax[2]));
1200 PandaNode::output(out);
1211 void SpeedTreeNode::
1212 write(ostream &out,
int indent_level)
const {
1213 PandaNode::write(out, indent_level);
1235 const char *error = SpeedTree::CCore::GetError();
1236 if (error != (
const char *)NULL) {
1248 void SpeedTreeNode::
1249 set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode eMode)
const {
1252 SpeedTree::CRenderState::SetBlending(
false);
1253 SpeedTree::CRenderState::SetAlphaTesting(
false);
1254 SpeedTree::CRenderState::SetAlphaToCoverage(
false);
1257 case SpeedTree::TRANS_TEXTURE_ALPHA_TESTING:
1258 SpeedTree::CRenderState::SetAlphaTesting(
true);
1260 case SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE:
1261 SpeedTree::CRenderState::SetAlphaToCoverage(
true);
1263 case SpeedTree::TRANS_TEXTURE_BLENDING:
1264 SpeedTree::CRenderState::SetBlending(
true);
1278 void SpeedTreeNode::
1280 PandaNode::set_cull_callback();
1283 _needs_repopulate =
false;
1287 speedtree_cat.warning()
1288 <<
"SpeedTree license not available.\n";
1292 _forest_render.SetHint(SpeedTree::CForest::HINT_MAX_NUM_VISIBLE_CELLS,
1293 speedtree_max_num_visible_cells);
1295 _forest_render.SetCullCellSize(speedtree_cull_cell_size);
1308 void SpeedTreeNode::
1309 r_add_instances(
PandaNode *node,
const TransformState *transform,
1310 Thread *current_thread) {
1311 if (node->
is_of_type(SpeedTreeNode::get_class_type()) && node !=
this) {
1316 Children children = node->
get_children(current_thread);
1317 for (
int i = 0; i < children.get_num_children(); i++) {
1319 CPT(TransformState) child_transform = transform->compose(child->get_transform());
1320 r_add_instances(child, child_transform, current_thread);
1333 _forest_render.ClearInstances();
1336 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1337 InstanceList *instance_list = (*ti);
1339 const STInstances &instances = instance_list->_instances;
1340 if (instances.empty()) {
1348 if (!_forest_render.AddInstances(tree->
get_tree(), &instances[0], instances.size())) {
1349 speedtree_cat.warning()
1350 <<
"Failed to add " << instances.size()
1351 <<
" instances for " << *tree <<
"\n";
1356 _forest_render.GetPopulationStats(_population_stats);
1357 print_forest_stats(_population_stats);
1360 int max_instances_by_cell = 1;
1361 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1362 InstanceList *instance_list = (*ti);
1364 const STInstances &instances = instance_list->_instances;
1365 if (instances.empty()) {
1369 int max_instances = 1;
1370 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si;
1371 si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->
get_tree());
1372 if (si != _population_stats.m_mMaxNumInstancesPerCellPerBase.end()) {
1373 max_instances = max(max_instances, (
int)si->second);
1376 max_instances_by_cell = max(max_instances_by_cell, max_instances);
1379 _visible_trees.Reserve(_forest_render.GetBaseTrees(),
1380 _forest_render.GetBaseTrees().size(),
1381 speedtree_max_num_visible_cells,
1382 max_instances_by_cell,
1383 speedtree_horizontal_billboards);
1392 void SpeedTreeNode::
1393 update_terrain_cells() {
1396 SpeedTree::TTerrainCellArray &cells = _visible_terrain.m_aCellsToUpdate;
1398 int num_tile_res = _terrain_render.GetMaxTileRes();
1399 PN_stdfloat cell_size = _terrain_render.GetCellSize();
1405 int num_vertices = num_tile_res * num_tile_res;
1406 vertex_data->set_num_rows(num_vertices);
1407 size_t num_bytes = vertex_data->get_array(0)->get_data_size_bytes();
1409 int num_cells = (
int)cells.size();
1410 for (
int ci = 0; ci < num_cells; ++ci) {
1411 SpeedTree::CTerrainCell *cell = cells[ci];
1412 nassertv(cell != NULL && cell->GetVbo() != NULL);
1413 int cell_yi = cell->Row();
1414 int cell_xi = cell->Col();
1417 _terrain->fill_vertices(vertex_data,
1418 cell_xi * cell_size, cell_yi * cell_size,
1419 cell_size, num_tile_res);
1423 const
unsigned char *data_pointer = handle->get_read_pointer(true);
1424 SpeedTree::CGeometryBuffer *vbo = (SpeedTree::CGeometryBuffer *)cell->GetVbo();
1426 nassertv(vbo->NumVertices() == num_tile_res * num_tile_res);
1427 nassertv(vbo->NumVertices() * vbo->VertexSize() == handle->get_data_size_bytes());
1428 vbo->OverwriteVertices(data_pointer, num_vertices, 0);
1444 #if defined(SPEEDTREE_OPENGL)
1445 static const string compiled_api =
"OpenGL";
1446 #elif defined(SPEEDTREE_DIRECTX9)
1447 static const string compiled_api =
"DirectX9";
1449 #error Unexpected graphics API.
1452 if (pipe->get_interface_name() != compiled_api) {
1453 speedtree_cat.error()
1454 <<
"SpeedTree is compiled for " << compiled_api
1455 <<
", cannot render with " << pipe->get_interface_name()
1472 void SpeedTreeNode::
1474 PStatTimer timer(_draw_speedtree_pcollector);
1476 DCAST_INTO_V(geom_cbdata, data);
1480 setup_for_render(gsg);
1483 SpeedTree::CRenderState::SetAlphaFunction(SpeedTree::ALPHAFUNC_GREATER, 0.0f);
1486 _forest_render.StartRender();
1488 if (_forest_render.ShadowsAreEnabled()) {
1492 PStatTimer timer(_draw_speedtree_shadows_pcollector);
1493 render_forest_into_shadow_maps();
1494 _forest_render.ClearBoundTextures( );
1497 if (!_forest_render.UploadViewShaderParameters(_view)) {
1498 speedtree_cat.warning()
1499 <<
"Couldn't set view parameters\n";
1504 PStatTimer timer1(_draw_speedtree_terrain_pcollector);
1506 _terrain_render.UploadShaderConstants
1507 (&_forest_render, _light_dir,
1508 _forest_render.GetRenderInfo().m_sLightMaterial);
1511 set_transparent_texture_mode(SpeedTree::TRANS_TEXTURE_NOTHING);
1514 bool terrain = _terrain_render.Render
1515 (&_forest_render, _visible_terrain, SpeedTree::RENDER_PASS_STANDARD,
1516 _light_dir, _forest_render.GetRenderInfo().m_sLightMaterial,
1517 &_forest_render.GetRenderStats());
1520 speedtree_cat.warning()
1521 <<
"Failed to render terrain\n";
1531 PStatTimer timer1(_draw_speedtree_trees_pcollector);
1534 SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE;
1537 set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode(mode));
1539 bool branches = _forest_render.RenderBranches(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
1540 bool fronds = _forest_render.RenderFronds(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
1541 bool leaf_meshes = _forest_render.RenderLeafMeshes(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
1542 bool leaf_cards = _forest_render.RenderLeafCards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
1543 bool billboards = _forest_render.RenderBillboards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
1550 if (!branches || !fronds || !leaf_meshes || !leaf_cards ) {
1551 speedtree_cat.warning()
1552 <<
"Failed to render forest completely: "
1553 << branches <<
" " << fronds <<
" " << leaf_meshes <<
" " << leaf_cards <<
" " << billboards <<
"\n";
1558 _forest_render.EndRender();
1560 if (_forest_render.ShadowsAreEnabled() && speedtree_show_overlays) {
1561 _forest_render.RenderOverlays();
1576 void SpeedTreeNode::
1577 render_forest_into_shadow_maps() {
1578 bool success =
true;
1581 SpeedTree::CRenderState::SetMultisampling(
false);
1582 SpeedTree::CRenderState::SetAlphaToCoverage(
false);
1584 #if defined(SPEEDTREE_OPENGL)
1587 glDisable(GL_SCISSOR_TEST);
1590 for (
int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
1591 const SpeedTree::CView &light_view = _shadow_infos[smi]._light_view;
1592 const SpeedTree::SForestCullResults &light_cull = _shadow_infos[smi]._light_cull;
1594 if (_forest_render.BeginShadowMap(smi, light_view)) {
1595 success &= _forest_render.UploadViewShaderParameters(light_view);
1599 SpeedTree::CRenderState::SetPolygonOffset(1.0f, 0.125f);
1601 success &= _forest_render.RenderBranches(light_cull, SpeedTree::RENDER_PASS_SHADOW);
1605 SpeedTree::CRenderState::SetPolygonOffset(10.0f, 1.0f);
1607 success &= _forest_render.RenderFronds(light_cull, SpeedTree::RENDER_PASS_SHADOW);
1608 success &= _forest_render.RenderLeafMeshes(light_cull, SpeedTree::RENDER_PASS_SHADOW);
1609 success &= _forest_render.RenderLeafCards(light_cull, SpeedTree::RENDER_PASS_SHADOW, light_view);
1614 success &= _forest_render.EndShadowMap(smi);
1621 speedtree_cat.warning()
1622 <<
"Failed to render shadow maps\n";
1635 void SpeedTreeNode::
1637 if (!_done_first_init) {
1642 #ifdef SPEEDTREE_OPENGL
1645 GLenum err = glewInit();
1646 if (err != GLEW_OK) {
1647 speedtree_cat.error()
1648 <<
"GLEW initialization failed: %s\n", glewGetErrorString(err);
1656 if (!GLEW_VERSION_2_0) {
1657 speedtree_cat.error()
1658 <<
"The SpeedTree OpenGL implementation requires OpenGL 2.0 or better to run; this system has version " << glGetString(GL_VERSION) <<
"\n";
1662 #endif // SPEEDTREE_OPENGL
1664 _done_first_init =
true;
1667 #ifdef SPEEDTREE_DIRECTX9
1670 SpeedTree::DX9::SetDevice(dxgsg->_screen->_d3d_device);
1671 #endif // SPEEDTREE_DIRECTX9
1673 if (_needs_repopulate) {
1677 Trees::const_iterator ti;
1678 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1679 InstanceList *instance_list = (*ti);
1681 const STInstances &instances = instance_list->_instances;
1682 if (instances.empty()) {
1686 int max_instances = 2;
1687 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si;
1688 si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->
get_tree());
1689 if (si != _population_stats.m_mMaxNumInstancesPerCellPerBase.end()) {
1690 max_instances = max(max_instances, (
int)si->second);
1694 string os_textures_dir;
1695 if (!speedtree_textures_dir.empty()) {
1698 #if defined(WIN32) || defined(WIN64)
1699 if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] !=
'\\') {
1700 os_textures_dir +=
"\\";
1703 if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] !=
'/') {
1704 os_textures_dir +=
"/";
1709 if (!_forest_render.InitTreeGraphics((SpeedTree::CTreeRender *)tree->
get_tree(),
1710 max_instances, speedtree_horizontal_billboards,
1711 os_textures_dir.c_str())) {
1712 if (speedtree_cat.is_debug()) {
1713 speedtree_cat.debug()
1714 <<
"Failed to init tree graphics for " << *tree <<
"\n";
1721 if (!_forest_render.InitGraphics(
false)) {
1722 speedtree_cat.warning()
1723 <<
"Failed to init graphics\n";
1732 _forest_render.UpdateTreeCellExtents();
1736 if (!_terrain_render.Init(speedtree_terrain_num_lods,
1737 speedtree_terrain_resolution,
1738 speedtree_terrain_cell_size,
1739 _terrain->get_st_vertex_format())) {
1740 speedtree_cat.warning()
1741 <<
"Failed to init terrain\n";
1749 _needs_repopulate =
false;
1752 PStatTimer timer1(_draw_speedtree_terrain_update_pcollector);
1753 update_terrain_cells();
1763 void SpeedTreeNode::
1766 PStatTimer timer1(_cull_speedtree_trees_pcollector);
1767 _forest_render.CullAndComputeLOD(_view, _visible_trees);
1770 PStatTimer timer1(_cull_speedtree_terrain_pcollector);
1771 _terrain_render.CullAndComputeLOD(_view, _visible_terrain);
1774 if (_forest_render.ShadowsAreEnabled()) {
1775 PStatTimer timer1(_cull_speedtree_shadows_pcollector);
1776 for (
int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
1777 SpeedTree::CView &light_view = _shadow_infos[smi]._light_view;
1778 SpeedTree::SForestCullResultsRender &light_cull = _shadow_infos[smi]._light_cull;
1780 _forest_render.ComputeLightView
1781 (_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi,
1784 light_view.SetLodRefPoint(_view.GetCameraPos());
1785 _forest_render.CullAndComputeLOD(light_view, light_cull,
false);
1796 void SpeedTreeNode::
1797 print_forest_stats(
const SpeedTree::CForest::SPopulationStats &forest_stats)
const {
1798 fprintf(stderr,
"\n Forest Population Statistics\n");
1799 fprintf(stderr,
" ---------------------------------------------------\n");
1800 fprintf(stderr,
" # of tree cull cells: %d\n", forest_stats.m_nNumCells);
1801 fprintf(stderr,
" # of unique base trees: %d\n", forest_stats.m_nNumBaseTrees);
1802 fprintf(stderr,
" total # of instances: %d\n", forest_stats.m_nNumInstances);
1803 fprintf(stderr,
" average # of instances per base: %g\n", forest_stats.m_fAverageNumInstancesPerBase);
1804 fprintf(stderr,
" max # of billboards/instances per cell: %d\n", forest_stats.m_nMaxNumBillboardsPerCell);
1805 fprintf(stderr,
" max # of instances per cell per base:\n");
1806 SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator i;
1807 for (i = forest_stats.m_mMaxNumInstancesPerCellPerBase.begin( ); i != forest_stats.m_mMaxNumInstancesPerCellPerBase.end( ); ++i) {
1808 fprintf(stderr,
" %35s: %4d\n", SpeedTree::CFixedString(i->first->GetFilename( )).NoPath( ).c_str( ), i->second);
1810 fprintf(stderr,
" average # instances per cell: %g\n", forest_stats.m_fAverageInstancesPerCell);
1811 fprintf(stderr,
" max # of billboard images: %d\n", forest_stats.m_nMaxNumBillboardImages);
1812 fprintf(stderr,
"\n");
1836 int num_trees = _trees.
size();
1838 Trees::const_iterator ti;
1839 for (ti = _trees.
begin(); ti != _trees.
end(); ++ti) {
1859 parse_params(params, scan, manager);
1860 node->fillin(scan, manager);
1872 void SpeedTreeNode::
1874 PandaNode::fillin(scan, manager);
1878 for (
int i = 0; i < num_trees; i++) {
1879 InstanceList *instance_list =
new InstanceList(NULL);
1880 instance_list->fillin(scan, manager);
1881 if (instance_list->get_tree() == (
STTree *)NULL) {
1883 delete instance_list;
1897 void SpeedTreeNode::InstanceList::
1898 output(ostream &out)
const {
1899 out << *_tree <<
": " << _instances.size() <<
" instances";
1907 void SpeedTreeNode::InstanceList::
1908 write(ostream &out,
int indent_level)
const {
1909 indent(out, indent_level)
1910 << *_tree <<
": " << _instances.size() <<
" instances.\n";
1911 STInstances::const_iterator ii;
1912 for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
1913 indent(out, indent_level + 2)
1941 int num_instances = _instances.size();
1943 STInstances::const_iterator ii;
1944 for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
1965 PT(
PandaNode) srt_root = loader->load_sync(srt_filename);
1967 if (srt_root != NULL) {
1980 _instances.reserve(num_instances);
1981 for (
int i = 0; i < num_instances; i++) {
1983 transform.
fillin(scan, manager);
1984 _instances.push_back(transform);
1996 void SpeedTreeNode::DrawCallback::
1998 _node->draw_callback(data);
PN_stdfloat get_splat_layer_tiling(int n) const
Returns the tiling value of the nth splat layer.
A GraphicsStateGuardian for rendering into DirectX9 contexts.
const STTree * get_tree(int n) const
Returns the STTree pointer for the nth tree.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
A light shining from infinitely far away in a particular direction, like sunlight.
bool is_valid() const
Returns true if the tree was successfully loaded and is ready to be used, false otherwise.
string get_fullpath() const
Returns the entire filename: directory, basename, extension.
This specialization on CallbackData is passed when the callback is initiated from deep within the dra...
A basic node of the scene graph or data graph.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
A specific implementation of STTerrain that supports basic heightmaps loaded from an image file...
This is our own Panda specialization on the default STL map.
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
int get_num_words() const
Returns the number of words in the variable's value.
const Filename & get_splat_map() const
Returns the splat map that should be applied to the terrain.
NodePath find(const string &path) const
Searches for a node below the referenced node that matches the indicated string.
void add_string(const string &str)
Adds a variable-length string to the datagram.
A base class for any number of different kinds of lenses, linear and otherwise.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
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 CoordinateSystem get_internal_coordinate_system() const
Returns the coordinate system used internally by the GSG.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
NodePath get_parent(Thread *current_thread=Thread::get_current_thread()) const
Returns the NodePath to the parent of the referenced node: that is, this NodePath, shortened by one node.
void clear()
Removes all elements from the ordered vector.
Specifies parameters that may be passed to the loader.
static bool authorize(const string &license="")
Make this call to initialized the SpeedTree API and verify the license.
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS's file system.
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
void add_instances(const NodePath &root, const TransformState *transform=TransformState::make_identity())
Walks the scene graph beginning at root, looking for nested SpeedTreeNodes.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
PN_stdfloat get_max_height() const
Returns the largest height value that might be returned by get_height().
Base class for objects that can be written to and read from Bam files.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
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...
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
PandaNode * node() const
Returns the referenced node of the path.
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 is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
int get_priority() const
Returns the priority associated with this light.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
int remove_tree(const STTree *tree)
Removes all instances of the indicated tree.
A light source that seems to illuminate all points in space at once.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This is the abstract base class that defines the interface needed to describe a terrain for rendering...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
virtual PandaNode * combine_with(PandaNode *other)
Collapses this node with the other node, if possible, and returns a pointer to the combined node...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
This is a generic data block that is passed along to a CallbackObject when a callback is made...
string get_dirname() const
Returns the directory part of the filename.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
Filename get_value() const
Returns the variable's value.
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
PN_uint32 get_uint32()
Extracts an unsigned 32-bit integer.
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
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...
The abstract base class for a file or directory within the VirtualFileSystem.
static const LMatrix4f & convert_mat(CoordinateSystem from, CoordinateSystem to)
Returns a matrix that transforms from the indicated coordinate system to the indicated coordinate sys...
SceneSetup * get_scene() const
Returns the SceneSetup object.
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
const NodePath & get_scene_root() const
Returns the root node of the scene.
string get_string()
Extracts a variable-length string.
const float * get_data() const
Returns the address of the first of the nine data elements in the matrix.
bool has_all_off() const
Returns true if this attrib turns off all stages (although it may also turn some on).
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
void snap_to_terrain()
Adjusts all the trees in this node so that their Z position matches the height of the terrain at thei...
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
bool resolve_filename(const DSearchPath &searchpath, const string &default_extension=string())
Searches the given search path for the filename.
bool has_instance_list(const STTree *tree) const
Returns true if the indicated tree has any instances within this node, false otherwise.
GraphicsStateGuardianBase * get_gsg() const
Returns the GraphicsStateGuardian in effect.
virtual void output(ostream &out) const
Writes a brief description of the node to the indicated output stream.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Filename get_cwd() const
Returns the current directory name.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so...
A lightweight class that represents a single element that may be timed and/or counted via stats...
static Loader * get_global_ptr()
Returns a pointer to the global Loader.
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 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...
bool is_valid() const
Returns true if the terrain data is well-defined and ready to use.
const Filename & get_fullpath() const
Returns the full pathname to the SRT file that was loaded for this tree, as passed to the constructor...
void set_terrain(STTerrain *terrain)
Associated a terrain with the node.
void mark_internal_bounds_stale(Thread *current_thread=Thread::get_current_thread())
Should be called by a derived class to mark the internal bounding volume stale, so that compute_inter...
GraphicsStateGuardianBase * get_gsg() const
Returns a pointer to the current GSG.
const Filename & get_normal_map() const
Returns the normal map that should be applied to the terrain.
double random_real(double range)
Returns a random double in the range [0, range).
void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
The smallest atom of cull.
The name of a file, such as a texture file or an Egg file.
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
void set_instance(int n, const STTransform &transform)
Replaces the transform of the nth instance of this tree.
This is a 4-by-4 transform matrix.
virtual void record_object(CullableObject *object, const CullTraverser *traverser)
This callback function is intended to be overridden by a derived class.
double get_frame_time(Thread *current_thread=Thread::get_current_thread()) const
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
const LVector3 & get_direction() const
Returns the direction in which the light is aimed.
int get_num_splat_layers() const
Returns the number of splat layers that are to be applied to the terrain.
void add_instance(const STTree *tree, const STTransform &transform)
Adds a new instance of the indicated tree at the indicated transform.
A ClockObject keeps track of elapsed real time and discrete time.
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
const STTree * get_tree() const
Returns the particular tree this list refers to.
An object to create GraphicsOutputs that share a particular 3-D API.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
void remove_all_trees()
Removes all instances of all trees from the node.
void sort()
Maps to sort_unique().
An instance of this class is passed to the Factory when requesting it to do its business and construc...
STTerrain * get_terrain() const
Returns the terrain associated with the node, or NULL if there is no terrain.
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const string &default_extension=string()) const
Searches the given search path for the filename.
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
Interfaces with the SpeedTree library to render SpeedTree objects, especially trees, within the Panda3D scene graph.
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...
const InstanceList & get_instance_list(int n) const
Returns a list of transforms that corresponds to the instances at which the nth tree appears...
int get_num_trees() const
Returns the number of unique tree objects that have been added to the node.
const RenderAttrib * get_attrib(TypeHandle type) const
Looks for a RenderAttrib of the indicated type in the state, and returns it if it is found...
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
int get_num_on_lights() const
Returns the number of lights that are turned on by the attribute.
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...
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
bool has_terrain() const
Returns true if a valid terrain has been associated with the node, false otherwise.
const Filename & get_splat_layer(int n) const
Returns the nth splat layer that is to be applied to the terrain.
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash, to make it a relative filename, relative to the fully-specified directory indicated (which must also begin with, and may or may not end with, a slash–a terminating slash is ignored).
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
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...
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
const Filename & get_filename() const
If a BAM is a file, then the BamWriter should contain the name of the 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.
This is the base class for all three-component vectors and points.
void reload_config()
Re-reads the current setting of all of the relevant config variables and applies them to this node...
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname)...
bool is_valid() const
Returns true if the node is valid and ready to render, false otherwise.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
A thread; that is, a lightweight process.
int find_on_searchpath(const DSearchPath &searchpath)
Performs the reverse of the resolve_filename() operation: assuming that the current filename is fully...
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
A handy class to return random numbers.
Encapsulates all the communication with a particular instance of a given rendering backend...
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, so that it will be drawn at render time.
bool is_empty() const
Returns true if the NodePath contains no nodes.
const TransformState * get_cs_transform() const
Returns the transform from the camera's coordinate system to the GSG's internal coordinate system...
const LColor & get_color() const
Returns the basic color of the light.
This class stores a list of directories that can be searched, in order, to locate a particular file...
void add_instances_from(const SpeedTreeNode *other)
Adds all of the instances defined within the indicated SpeedTreeNode as instances of this node...
size_type_0 size() const
Returns the number of elements in the ordered vector.
static void register_with_read_factory()
Tells the BamReader how to create objects of type SpeedTreeNode.
int add_instance(const STTransform &transform)
Adds a new instance of this tree at the indicated transform.
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...
virtual void load_data()=0
This will be called at some point after initialization.
A class to retrieve the individual data elements previously stored in a Datagram. ...
InstanceList & modify_instance_list(const STTree *tree)
Returns a modifiable list of transforms that corresponds to the instances of this tree...
TypeHandle is the identifier used to differentiate C++ class types.
static void write_error(ostream &out)
Writes the current SpeedTree error message to the indicated stream.
NodePath get_on_light(int n) const
Returns the nth light turned on by the attribute, sorted in render order.
PN_stdfloat get_min_height() const
Returns the smallest height value that might be returned by get_height().
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.
InstanceList & add_tree(const STTree *tree)
Adds a new tree for rendering.
const SpeedTree::CTreeRender * get_tree() const
Returns a const pointer to the internal SpeedTree object.
bool normalize()
Normalizes the vector in place.
STTransform get_instance(int n) const
Returns the transform of the nth instance of this tree.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
void set_lost_state(bool lost_state)
Sets the lost_state flag.
CoordinateSystem get_coordinate_system() const
Returns the coordinate system that all 3-d computations are performed within for this Lens...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
const Lens * get_lens() const
Returns the particular Lens used for rendering.
int get_num_instances() const
Returns the number of instances of this tree.
Encapsulates a single tree model in the SpeedTree library, as loaded from an SRT file.
This is the data for one array of a GeomVertexData structure.
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
void set_wind(double strength, const LVector3 &direction)
Specifies the overall wind strength and direction.
PN_stdfloat get_far() const
Returns the position of the far plane (or cylinder, sphere, whatever).
PN_stdfloat get_near() const
Returns the position of the near plane (or cylinder, sphere, whatever).
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).