add time_delta interfaces

This commit is contained in:
David Rose 2011-06-02 18:21:33 +00:00
parent 33886780c4
commit a552cfa859
3 changed files with 208 additions and 123 deletions

View File

@ -111,6 +111,58 @@ get_terrain() const {
return _terrain;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::set_time_delta
// Access: Published
// Description: Specifies an offset that is to be added each frame to
// the global clock's frame_time for the purpose of
// animating the trees in this particular node. Also
// see set_global_time_delta().
////////////////////////////////////////////////////////////////////
INLINE void SpeedTreeNode::
set_time_delta(double delta) {
_time_delta = delta;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::get_time_delta
// Access: Published
// Description: Returns an offset that is to be added each frame to
// the global clock's frame_time for the purpose of
// animating the trees in this particular node. Also
// see get_global_time_delta().
////////////////////////////////////////////////////////////////////
INLINE double SpeedTreeNode::
get_time_delta() const {
return _time_delta;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::set_global_time_delta
// Access: Published, Static
// Description: Specifies an offset that is to be added each frame to
// the global clock's frame_time for the purpose of
// animating the trees in all SpeedTreeNodes. Also
// see set_time_delta().
////////////////////////////////////////////////////////////////////
INLINE void SpeedTreeNode::
set_global_time_delta(double delta) {
_global_time_delta = delta;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::get_global_time_delta
// Access: Published, Static
// Description: Returns an offset that is to be added each frame to
// the global clock's frame_time for the purpose of
// animating the trees in all SpeedTreeNodes. Also
// see get_time_delta().
////////////////////////////////////////////////////////////////////
INLINE double SpeedTreeNode::
get_global_time_delta() {
return _global_time_delta;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::InstanceList::Constructor
// Access: Public

View File

@ -43,6 +43,7 @@
#include "dxGraphicsStateGuardian9.h"
#endif
double SpeedTreeNode::_global_time_delta = 0.0;
bool SpeedTreeNode::_authorized;
bool SpeedTreeNode::_done_first_init;
TypeHandle SpeedTreeNode::_type_handle;
@ -65,13 +66,14 @@ PStatCollector SpeedTreeNode::_draw_speedtree_terrain_update_pcollector("Draw:Sp
////////////////////////////////////////////////////////////////////
SpeedTreeNode::
SpeedTreeNode(const string &name) :
PandaNode(name)
PandaNode(name),
#ifdef ST_DELETE_FOREST_HACK
// Early versions of SpeedTree don't destruct unused CForestRender
// objects correctly. To avoid crashes, we have to leak these
// things.
, _forest_render(*(new SpeedTree::CForestRender))
_forest_render(*(new SpeedTree::CForestRender)),
#endif
_time_delta(0.0)
{
init_node();
// For now, set an infinite bounding volume. Maybe in the future
@ -92,14 +94,14 @@ SpeedTreeNode(const string &name) :
shaders_dir = token_filename.get_dirname();
} else {
if (!shaders_dir.is_directory()) {
speedtree_cat.warning()
<< "speedtree-shaders-dir is set to " << shaders_dir
<< ", which doesn't exist.\n";
speedtree_cat.warning()
<< "speedtree-shaders-dir is set to " << shaders_dir
<< ", which doesn't exist.\n";
} else {
speedtree_cat.warning()
<< "speedtree-shaders-dir is set to " << shaders_dir
<< ", which exists but doesn't contain " << token_filename
<< ".\n";
speedtree_cat.warning()
<< "speedtree-shaders-dir is set to " << shaders_dir
<< ", which exists but doesn't contain " << token_filename
<< ".\n";
}
}
}
@ -169,7 +171,7 @@ add_tree(const STTree *tree) {
if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->get_tree())) {
speedtree_cat.warning()
<< "Failed to register tree " << tree->get_fullpath() << "\n";
<< "Failed to register tree " << tree->get_fullpath() << "\n";
write_error(speedtree_cat.warning());
}
}
@ -225,7 +227,7 @@ remove_all_trees() {
const STTree *tree = instance_list->get_tree();
if (!_forest_render.UnregisterTree(tree->get_tree())) {
speedtree_cat.warning()
<< "Failed to unregister tree " << tree->get_fullpath() << "\n";
<< "Failed to unregister tree " << tree->get_fullpath() << "\n";
write_error(speedtree_cat.warning());
}
delete instance_list;
@ -313,7 +315,7 @@ void SpeedTreeNode::
add_instances(const NodePath &root, const TransformState *transform) {
nassertv(!root.is_empty());
r_add_instances(root.node(), transform->compose(root.get_transform()),
Thread::get_current_thread());
Thread::get_current_thread());
}
////////////////////////////////////////////////////////////////////
@ -361,12 +363,12 @@ add_instances_from(const SpeedTreeNode *other, const TransformState *transform)
CPT(TransformState) new_trans = transform->compose(other_trans);
if (speedtree_follow_terrain && has_terrain()) {
STTransform new_transform = new_trans;
new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
this_instance_list.add_instance(new_transform);
STTransform new_transform = new_trans;
new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
this_instance_list.add_instance(new_transform);
} else {
this_instance_list.add_instance(new_trans.p());
this_instance_list.add_instance(new_trans.p());
}
}
}
@ -387,12 +389,12 @@ add_instances_from(const SpeedTreeNode *other, const TransformState *transform)
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
add_random_instances(const STTree *tree, int quantity,
float x_min, float x_max,
float y_min, float y_max,
float scale_min, float scale_max,
float height_min, float height_max,
float slope_min, float slope_max,
Randomizer &randomizer) {
float x_min, float x_max,
float y_min, float y_max,
float scale_min, float scale_max,
float height_min, float height_max,
float slope_min, float slope_max,
Randomizer &randomizer) {
InstanceList &instance_list = add_tree(tree);
_needs_repopulate = true;
@ -407,12 +409,12 @@ add_random_instances(const STTree *tree, int quantity,
// Spin till we find a valid match with terrain.
int repeat_count = speedtree_max_random_try_count;
while (!_terrain->placement_is_acceptable(transform._pos[0], transform._pos[1], height_min, height_max, slope_min, slope_max)) {
transform._pos[0] = randomizer.random_real(x_max - x_min) + x_min;
transform._pos[1] = randomizer.random_real(y_max - y_min) + y_min;
if (--repeat_count == 0) {
nassert_raise("Exceeded speedtree-max-random-try-count; bad placement parameters?");
return;
}
transform._pos[0] = randomizer.random_real(x_max - x_min) + x_min;
transform._pos[1] = randomizer.random_real(y_max - y_min) + y_min;
if (--repeat_count == 0) {
nassert_raise("Exceeded speedtree-max-random-try-count; bad placement parameters?");
return;
}
}
transform._pos[2] = _terrain->get_height(transform._pos[0], transform._pos[1]);
@ -483,7 +485,7 @@ add_from_stf(const Filename &stf_filename, const LoaderOptions &options) {
////////////////////////////////////////////////////////////////////
bool SpeedTreeNode::
add_from_stf(istream &in, const Filename &pathname,
const LoaderOptions &options, Loader *loader) {
const LoaderOptions &options, Loader *loader) {
if (loader == NULL) {
loader = Loader::get_global_ptr();
}
@ -514,14 +516,14 @@ add_from_stf(istream &in, const Filename &pathname,
PT(PandaNode) srt_root = loader->load_sync(srt_filename);
if (srt_root != NULL) {
NodePath srt(srt_root);
NodePath srt_np = srt.find("**/+SpeedTreeNode");
if (!srt_np.is_empty()) {
SpeedTreeNode *srt_node = DCAST(SpeedTreeNode, srt_np.node());
if (srt_node->get_num_trees() >= 1) {
tree = srt_node->get_tree(0);
}
}
NodePath srt(srt_root);
NodePath srt_np = srt.find("**/+SpeedTreeNode");
if (!srt_np.is_empty()) {
SpeedTreeNode *srt_node = DCAST(SpeedTreeNode, srt_np.node());
if (srt_node->get_num_trees() >= 1) {
tree = srt_node->get_tree(0);
}
}
}
already_loaded[srt_filename] = tree;
}
@ -536,14 +538,14 @@ add_from_stf(istream &in, const Filename &pathname,
in >> pos[0] >> pos[1] >> pos[2] >> rotate >> scale;
if (!speedtree_5_2_stf) {
// 5.1 or earlier stf files also included these additional
// values, which we will ignore:
float height_min, height_max, slope_min, slope_max;
in >> height_min >> height_max >> slope_min >> slope_max;
// 5.1 or earlier stf files also included these additional
// values, which we will ignore:
float height_min, height_max, slope_min, slope_max;
in >> height_min >> height_max >> slope_min >> slope_max;
}
if (tree != NULL) {
add_instance(tree, STTransform(pos, rad_2_deg(rotate), scale));
add_instance(tree, STTransform(pos, rad_2_deg(rotate), scale));
}
}
in >> os_filename;
@ -664,19 +666,19 @@ snap_to_terrain() {
int num_instances = instance_list->get_num_instances();
if (_terrain != (STTerrain *)NULL) {
for (int i = 0; i < num_instances; ++i) {
STTransform trans = instance_list->get_instance(i);
LPoint3f pos = trans.get_pos();
pos[2] = _terrain->get_height(pos[0], pos[1]);
trans.set_pos(pos);
instance_list->set_instance(i, trans);
STTransform trans = instance_list->get_instance(i);
LPoint3f pos = trans.get_pos();
pos[2] = _terrain->get_height(pos[0], pos[1]);
trans.set_pos(pos);
instance_list->set_instance(i, trans);
}
} else {
for (int i = 0; i < num_instances; ++i) {
STTransform trans = instance_list->get_instance(i);
LPoint3f pos = trans.get_pos();
pos[2] = 0.0f;
trans.set_pos(pos);
instance_list->set_instance(i, trans);
STTransform trans = instance_list->get_instance(i);
LPoint3f pos = trans.get_pos();
pos[2] = 0.0f;
trans.set_pos(pos);
instance_list->set_instance(i, trans);
}
}
}
@ -746,12 +748,24 @@ reload_config() {
_terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
_terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
speedtree_max_num_visible_cells);
speedtree_max_num_visible_cells);
_visible_terrain.Reserve(speedtree_max_num_visible_cells);
_needs_repopulate = true;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::set_wind
// Access: Published
// Description: Specifies the overall wind strength and direction.
// Gusts are controlled internally.
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
set_wind(double strength, const LVector3f &direction) {
_forest_render.SetGlobalWindStrength(strength);
_forest_render.SetGlobalWindDirection(SpeedTree::Vec3(direction[0], direction[1], direction[2]));
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::authorize
// Access: Published, Static
@ -770,10 +784,10 @@ authorize(const string &license) {
SpeedTree::CCore::Authorize(license.c_str());
} else {
if (!speedtree_license.empty()) {
SpeedTree::CCore::Authorize(speedtree_license.c_str());
SpeedTree::CCore::Authorize(speedtree_license.c_str());
}
}
_authorized = SpeedTree::CCore::IsAuthorized();
SpeedTree::CCore::SetTextureFlip(true);
@ -791,13 +805,14 @@ SpeedTreeNode::
SpeedTreeNode(const SpeedTreeNode &copy) :
PandaNode(copy),
_os_shaders_dir(copy._os_shaders_dir),
_shadow_infos(copy._shadow_infos)
_shadow_infos(copy._shadow_infos),
#ifdef ST_DELETE_FOREST_HACK
// Early versions of SpeedTree don't destruct unused CForestRender
// objects correctly. To avoid crashes, we have to leak these
// things.
, _forest_render(*(new SpeedTree::CForestRender))
_forest_render(*(new SpeedTree::CForestRender)),
#endif
_time_delta(copy._time_delta)
{
init_node();
@ -807,7 +822,7 @@ SpeedTreeNode(const SpeedTreeNode &copy) :
// No way to copy these parameters, so we just re-assign them.
_terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
_terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
speedtree_max_num_visible_cells);
speedtree_max_num_visible_cells);
_visible_terrain.Reserve(speedtree_max_num_visible_cells);
Trees::const_iterator ti;
@ -816,7 +831,7 @@ SpeedTreeNode(const SpeedTreeNode &copy) :
const STTree *tree = instance_list->get_tree();
if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->get_tree())) {
speedtree_cat.warning()
<< "Failed to register tree " << tree->get_fullpath() << "\n";
<< "Failed to register tree " << tree->get_fullpath() << "\n";
write_error(speedtree_cat.warning());
}
@ -916,8 +931,8 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
STInstances &instances = instance_list->_instances;
STInstances::iterator sti;
for (sti = instances.begin(); sti != instances.end(); ++sti) {
STTransform orig_transform = *sti;
(*sti) = orig_transform * xform;
STTransform orig_transform = *sti;
(*sti) = orig_transform * xform;
}
}
}
@ -963,7 +978,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
}
ClockObject *clock = ClockObject::get_global_clock();
_forest_render.SetGlobalTime(clock->get_frame_time());
_forest_render.SetGlobalTime(clock->get_frame_time() + _time_delta + _global_time_delta);
_forest_render.AdvanceGlobalWind();
// Compute the modelview and camera transforms, to pass to the
@ -980,9 +995,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
lens->get_projection_mat();
_view.Set(SpeedTree::Vec3(camera_pos[0], camera_pos[1], camera_pos[2]),
SpeedTree::Mat4x4(projection_mat.get_data()),
SpeedTree::Mat4x4(modelview_mat.get_data()),
lens->get_near(), lens->get_far());
SpeedTree::Mat4x4(projection_mat.get_data()),
SpeedTree::Mat4x4(modelview_mat.get_data()),
lens->get_near(), lens->get_far());
// Convert the render state to SpeedTree's input.
const RenderState *state = data._state;
@ -1012,17 +1027,17 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
for (int i = 0; i < la->get_num_on_lights(); ++i) {
NodePath light = la->get_on_light(i);
if (!light.is_empty() && light.node()->is_of_type(DirectionalLight::get_class_type())) {
// A directional light.
DirectionalLight *light_obj = DCAST(DirectionalLight, light.node());
if (dlight == NULL || light_obj->get_priority() > dlight->get_priority()) {
// Here's the most important directional light.
dlight = light_obj;
dlight_np = light;
}
// A directional light.
DirectionalLight *light_obj = DCAST(DirectionalLight, light.node());
if (dlight == NULL || light_obj->get_priority() > dlight->get_priority()) {
// Here's the most important directional light.
dlight = light_obj;
dlight_np = light;
}
} else if (!light.is_empty() && light.node()->is_of_type(AmbientLight::get_class_type())) {
// An ambient light. We keep the color only.
AmbientLight *light_obj = DCAST(AmbientLight, light.node());
ambient_color += light_obj->get_color();
// An ambient light. We keep the color only.
AmbientLight *light_obj = DCAST(AmbientLight, light.node());
ambient_color += light_obj->get_color();
}
}
}
@ -1105,9 +1120,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
// SpeedTree to render the forest during the actual draw.
CullableObject *object =
new CullableObject(NULL, data._state,
TransformState::make_identity(),
TransformState::make_identity(),
trav->get_gsg());
TransformState::make_identity(),
TransformState::make_identity(),
trav->get_gsg());
object->set_draw_callback(new DrawCallback(this));
trav->get_cull_handler()->record_object(object, trav);
}
@ -1171,7 +1186,7 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
const SpeedTree::Vec3 &emin = extents.Min();
const SpeedTree::Vec3 &emax = extents.Max();
internal_bounds = new BoundingBox(LPoint3f(emin[0], emin[1], emin[2]),
LPoint3f(emax[0], emax[1], emax[2]));
LPoint3f(emax[0], emax[1], emax[2]));
}
////////////////////////////////////////////////////////////////////
@ -1277,10 +1292,13 @@ init_node() {
}
_forest_render.SetHint(SpeedTree::CForest::HINT_MAX_NUM_VISIBLE_CELLS,
speedtree_max_num_visible_cells);
speedtree_max_num_visible_cells);
_forest_render.SetCullCellSize(speedtree_cull_cell_size);
// Doesn't appear to be necessary to call this explicitly.
//_forest_render.EnableWind(true);
_is_valid = true;
}
@ -1291,7 +1309,7 @@ init_node() {
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
r_add_instances(PandaNode *node, const TransformState *transform,
Thread *current_thread) {
Thread *current_thread) {
if (node->is_of_type(SpeedTreeNode::get_class_type()) && node != this) {
SpeedTreeNode *other = DCAST(SpeedTreeNode, node);
add_instances_from(other, transform);
@ -1331,8 +1349,8 @@ repopulate() {
if (!_forest_render.AddInstances(tree->get_tree(), &instances[0], instances.size())) {
speedtree_cat.warning()
<< "Failed to add " << instances.size()
<< " instances for " << *tree << "\n";
<< "Failed to add " << instances.size()
<< " instances for " << *tree << "\n";
write_error(speedtree_cat.warning());
}
}
@ -1361,10 +1379,10 @@ repopulate() {
}
_visible_trees.Reserve(_forest_render.GetBaseTrees(),
_forest_render.GetBaseTrees().size(),
speedtree_max_num_visible_cells,
max_instances_by_cell,
speedtree_horizontal_billboards);
_forest_render.GetBaseTrees().size(),
speedtree_max_num_visible_cells,
max_instances_by_cell,
speedtree_horizontal_billboards);
}
////////////////////////////////////////////////////////////////////
@ -1385,7 +1403,7 @@ update_terrain_cells() {
// A temporary vertex data object for populating terrain.
PT(GeomVertexData) vertex_data =
new GeomVertexData("terrain", _terrain->get_vertex_format(),
GeomEnums::UH_static);
GeomEnums::UH_static);
int num_vertices = num_tile_res * num_tile_res;
vertex_data->set_num_rows(num_vertices);
size_t num_bytes = vertex_data->get_array(0)->get_data_size_bytes();
@ -1399,8 +1417,8 @@ update_terrain_cells() {
//cerr << "populating cell " << cell_xi << " " << cell_yi << "\n";
_terrain->fill_vertices(vertex_data,
cell_xi * cell_size, cell_yi * cell_size,
cell_size, num_tile_res);
cell_xi * cell_size, cell_yi * cell_size,
cell_size, num_tile_res);
const GeomVertexArrayData *array_data = vertex_data->get_array(0);
CPT(GeomVertexArrayDataHandle) handle = array_data->get_handle();
@ -1502,7 +1520,7 @@ draw_callback(CallbackData *data) {
if (!terrain) {
speedtree_cat.warning()
<< "Failed to render terrain\n";
<< "Failed to render terrain\n";
write_error(speedtree_cat.warning());
// Clear the terrain so we don't keep spamming error messages.
@ -1525,11 +1543,16 @@ draw_callback(CallbackData *data) {
bool leaf_meshes = _forest_render.RenderLeafMeshes(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
bool leaf_cards = _forest_render.RenderLeafCards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
bool billboards = _forest_render.RenderBillboards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
// Sometimes billboards comes back false, particularly if wind is
// disabled; but the billboards appear to have been rendered
// successfully. Weird. Just removing this test from the
// condition.
if (!branches || !fronds || !leaf_meshes || !leaf_cards || !billboards) {
if (!branches || !fronds || !leaf_meshes || !leaf_cards /* || !billboards */) {
speedtree_cat.warning()
<< "Failed to render forest completely: "
<< branches << " " << fronds << " " << leaf_meshes << " " << leaf_cards << " " << billboards << "\n";
<< "Failed to render forest completely: "
<< branches << " " << fronds << " " << leaf_meshes << " " << leaf_cards << " " << billboards << "\n";
write_error(speedtree_cat.warning());
}
}
@ -1624,7 +1647,7 @@ setup_for_render(GraphicsStateGuardian *gsg) {
GLenum err = glewInit();
if (err != GLEW_OK) {
speedtree_cat.error()
<< "GLEW initialization failed: %s\n", glewGetErrorString(err);
<< "GLEW initialization failed: %s\n", glewGetErrorString(err);
// Can't proceed without GLEW.
_is_valid = false;
return;
@ -1634,7 +1657,7 @@ setup_for_render(GraphicsStateGuardian *gsg) {
// requires it.
if (!GLEW_VERSION_2_0) {
speedtree_cat.error()
<< "The SpeedTree OpenGL implementation requires OpenGL 2.0 or better to run; this system has version " << glGetString(GL_VERSION) << "\n";
<< "The SpeedTree OpenGL implementation requires OpenGL 2.0 or better to run; this system has version " << glGetString(GL_VERSION) << "\n";
_is_valid = false;
return;
}
@ -1659,47 +1682,47 @@ setup_for_render(GraphicsStateGuardian *gsg) {
const STTree *tree = instance_list->get_tree();
const STInstances &instances = instance_list->_instances;
if (instances.empty()) {
continue;
continue;
}
int max_instances = 2;
SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si;
si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->get_tree());
if (si != _population_stats.m_mMaxNumInstancesPerCellPerBase.end()) {
max_instances = max(max_instances, (int)si->second);
max_instances = max(max_instances, (int)si->second);
}
// Get the speedtree-textures-dir to pass for initialization.
string os_textures_dir;
if (!speedtree_textures_dir.empty()) {
os_textures_dir = speedtree_textures_dir.get_value().to_os_specific();
// Ensure the path ends with a terminal slash; SpeedTree requires this.
os_textures_dir = speedtree_textures_dir.get_value().to_os_specific();
// Ensure the path ends with a terminal slash; SpeedTree requires this.
#if defined(WIN32) || defined(WIN64)
if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] != '\\') {
os_textures_dir += "\\";
}
if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] != '\\') {
os_textures_dir += "\\";
}
#else
if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] != '/') {
os_textures_dir += "/";
}
if (!os_textures_dir.empty() && os_textures_dir[os_textures_dir.length() - 1] != '/') {
os_textures_dir += "/";
}
#endif
}
if (!_forest_render.InitTreeGraphics((SpeedTree::CTreeRender *)tree->get_tree(),
max_instances, speedtree_horizontal_billboards,
os_textures_dir.c_str())) {
if (speedtree_cat.is_debug()) {
speedtree_cat.debug()
<< "Failed to init tree graphics for " << *tree << "\n";
write_error(speedtree_cat.debug());
}
max_instances, speedtree_horizontal_billboards,
os_textures_dir.c_str())) {
if (speedtree_cat.is_debug()) {
speedtree_cat.debug()
<< "Failed to init tree graphics for " << *tree << "\n";
write_error(speedtree_cat.debug());
}
}
}
// Init overall graphics
if (!_forest_render.InitGraphics(false)) {
speedtree_cat.warning()
<< "Failed to init graphics\n";
<< "Failed to init graphics\n";
write_error(speedtree_cat.warning());
_is_valid = false;
return;
@ -1713,12 +1736,12 @@ setup_for_render(GraphicsStateGuardian *gsg) {
if (has_terrain()) {
// Now initialize the terrain.
if (!_terrain_render.Init(speedtree_terrain_num_lods,
speedtree_terrain_resolution,
speedtree_terrain_cell_size,
_terrain->get_st_vertex_format())) {
speedtree_cat.warning()
<< "Failed to init terrain\n";
write_error(speedtree_cat.warning());
speedtree_terrain_resolution,
speedtree_terrain_cell_size,
_terrain->get_st_vertex_format())) {
speedtree_cat.warning()
<< "Failed to init terrain\n";
write_error(speedtree_cat.warning());
}
}
@ -1757,8 +1780,8 @@ cull_forest() {
SpeedTree::SForestCullResultsRender &light_cull = _shadow_infos[smi]._light_cull;
_forest_render.ComputeLightView
(_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi,
light_view, 0.0f);
(_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi,
light_view, 0.0f);
light_view.SetLodRefPoint(_view.GetCameraPos());
_forest_render.CullAndComputeLOD(light_view, light_cull, false);
@ -1949,7 +1972,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
if (!srt_np.is_empty()) {
SpeedTreeNode *srt_node = DCAST(SpeedTreeNode, srt_np.node());
if (srt_node->get_num_trees() >= 1) {
_tree = (STTree *)srt_node->get_tree(0);
_tree = (STTree *)srt_node->get_tree(0);
}
}
}

View File

@ -140,6 +140,13 @@ PUBLISHED:
void reload_config();
void set_wind(double strength, const LVector3f &direction);
INLINE void set_time_delta(double delta);
INLINE double get_time_delta() const;
INLINE static void set_global_time_delta(double delta);
INLINE static double get_global_time_delta();
static bool authorize(const string &license = "");
public:
@ -248,6 +255,9 @@ private:
typedef pvector<ShadowInfo> ShadowInfos;
ShadowInfos _shadow_infos;
double _time_delta;
static double _global_time_delta;
static bool _authorized;
static bool _done_first_init;