37 #ifdef SPEEDTREE_OPENGL
38 #include <glew/glew.h>
39 #endif // SPEEDTREE_OPENGL
41 #ifdef SPEEDTREE_DIRECTX9
49 double SpeedTreeNode::_global_time_delta = 0.0;
50 bool SpeedTreeNode::_authorized;
51 bool SpeedTreeNode::_done_first_init;
53 TypeHandle SpeedTreeNode::DrawCallback::_type_handle;
55 PStatCollector SpeedTreeNode::_cull_speedtree_pcollector(
"Cull:SpeedTree");
56 PStatCollector SpeedTreeNode::_cull_speedtree_shadows_pcollector(
"Cull:SpeedTree:Shadows");
57 PStatCollector SpeedTreeNode::_cull_speedtree_trees_pcollector(
"Cull:SpeedTree:Trees");
58 PStatCollector SpeedTreeNode::_cull_speedtree_terrain_pcollector(
"Cull:SpeedTree:Terrain");
59 PStatCollector SpeedTreeNode::_draw_speedtree_pcollector(
"Draw:SpeedTree");
60 PStatCollector SpeedTreeNode::_draw_speedtree_shadows_pcollector(
"Draw:SpeedTree:Shadows");
61 PStatCollector SpeedTreeNode::_draw_speedtree_trees_pcollector(
"Draw:SpeedTree:Trees");
62 PStatCollector SpeedTreeNode::_draw_speedtree_terrain_pcollector(
"Draw:SpeedTree:Terrain");
63 PStatCollector SpeedTreeNode::_draw_speedtree_terrain_update_pcollector(
"Draw:SpeedTree:Terrain:Update");
69 SpeedTreeNode(
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()) {
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;
707 set_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]));
1095 PandaNode::output(out);
1104 void SpeedTreeNode::
1105 write(ostream &out,
int indent_level)
const {
1106 PandaNode::write(out, indent_level);
1125 const char *error = SpeedTree::CCore::GetError();
1126 if (error !=
nullptr) {
1135 void SpeedTreeNode::
1136 set_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);
1162 void SpeedTreeNode::
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);
1190 void SpeedTreeNode::
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);
1210 void SpeedTreeNode::
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);
1268 void SpeedTreeNode::
1269 update_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);
1312 bool SpeedTreeNode::
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()
1342 void SpeedTreeNode::
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();
1444 void SpeedTreeNode::
1445 render_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";
1499 void SpeedTreeNode::
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";
1526 #endif // SPEEDTREE_OPENGL
1528 _done_first_init =
true;
1531 #ifdef SPEEDTREE_DIRECTX9
1534 SpeedTree::DX9::SetDevice(dxgsg->_screen->_d3d_device);
1535 #endif // SPEEDTREE_DIRECTX9
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();
1624 void SpeedTreeNode::
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);
1655 void SpeedTreeNode::
1656 print_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);
1720 void SpeedTreeNode::
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;
1743 void SpeedTreeNode::InstanceList::
1744 output(ostream &out)
const {
1745 out << *_tree <<
": " << _instances.size() <<
" instances";
1751 void SpeedTreeNode::InstanceList::
1752 write(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);
1832 void SpeedTreeNode::DrawCallback::
1834 _node->draw_callback(data);