mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
SpeedTree: first pass
This commit is contained in:
parent
910e71660e
commit
d0db1d1f07
47
panda/src/speedtree/Sources.pp
Normal file
47
panda/src/speedtree/Sources.pp
Normal file
@ -0,0 +1,47 @@
|
||||
#define BUILD_DIRECTORY $[HAVE_SPEEDTREE]
|
||||
|
||||
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
|
||||
dtoolutil:c dtoolbase:c dtool:m prc:c
|
||||
|
||||
#define USE_PACKAGES speedtree $[if $[eq $[SPEEDTREE_API],opengl],gl cg cggl] $[if $[eq $[SPEEDTREE_API],directx9],dx9 cg cgdx9]
|
||||
#define BUILDING_DLL BUILDING_PANDASKEL
|
||||
|
||||
#begin lib_target
|
||||
#define TARGET pandaspeedtree
|
||||
#define LOCAL_LIBS \
|
||||
display text pgraph gobj linmath putil
|
||||
|
||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx
|
||||
|
||||
#define SOURCES \
|
||||
config_speedtree.h \
|
||||
loaderFileTypeSrt.h \
|
||||
speedtree_api.h \
|
||||
speedTreeNode.h \
|
||||
stTransform.h \
|
||||
stTree.h
|
||||
|
||||
// A generated file
|
||||
#define SOURCES $[SOURCES] speedtree_parameters.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
config_speedtree.cxx \
|
||||
loaderFileTypeSrt.cxx \
|
||||
speedtree_api.cxx \
|
||||
speedTreeNode.cxx \
|
||||
stTransform.cxx \
|
||||
stTree.cxx
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
speedtree_parameters.h \
|
||||
speedtree_api.h \
|
||||
speedTreeNode.h \
|
||||
stTransform.h \
|
||||
stTree.h
|
||||
|
||||
#define IGATESCAN all
|
||||
|
||||
#end lib_target
|
||||
|
||||
|
||||
#include $[THISDIRPREFIX]speedtree_parameters.h.pp
|
107
panda/src/speedtree/config_speedtree.cxx
Normal file
107
panda/src/speedtree/config_speedtree.cxx
Normal file
@ -0,0 +1,107 @@
|
||||
// Filename: config_speedtree.cxx
|
||||
// Created by: drose (30Sep10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "config_speedtree.h"
|
||||
#include "speedTreeNode.h"
|
||||
#include "stTree.h"
|
||||
#include "loaderFileTypeSrt.h"
|
||||
#include "loaderFileTypeRegistry.h"
|
||||
#include "dconfig.h"
|
||||
|
||||
Configure(config_speedtree);
|
||||
NotifyCategoryDef(speedtree, "");
|
||||
|
||||
ConfigureFn(config_speedtree) {
|
||||
init_libspeedtree();
|
||||
}
|
||||
|
||||
ConfigVariableString speedtree_license
|
||||
("speedtree-license", "",
|
||||
PRC_DESC("Specify the license string to pass to SpeedTreeNode::authorize() by default."));
|
||||
|
||||
ConfigVariableFilename speedtree_shaders_dir
|
||||
("speedtree-shaders-dir", Filename(Filename::from_os_specific(SPEEDTREE_BIN_DIR), "Shaders"),
|
||||
PRC_DESC("Specifies the directory in which to locate SpeedTree's system "
|
||||
"shaders at runtime. If this is empty, the default is based on "
|
||||
"SPEEDTREE_BIN_DIR, as provided at compile time."));
|
||||
|
||||
ConfigVariableBool speedtree_allow_horizontal_billboards
|
||||
("speedtree-allow-horizontal-billboards", true,
|
||||
PRC_DESC("Set this true to allow the use of horizontal billboards in "
|
||||
"SpeedTree, or false to disallow them. Documentation on this "
|
||||
"feature is sparse, but presumably enabling them increases "
|
||||
"visual quality and also causes a greater performance impact."));
|
||||
|
||||
ConfigVariableInt speedtree_max_num_visible_cells
|
||||
("speedtree-max-num-visible-cells", 75,
|
||||
PRC_DESC("Specifies the maximum number of cells in a single SpeedTree forest "
|
||||
"frustum. This is used internally by SpeedTree's billboard system."));
|
||||
|
||||
ConfigVariableInt speedtree_max_billboard_images_by_base
|
||||
("speedtree-max-billboard-images-by-base", 20,
|
||||
PRC_DESC("Specifies the maximum number of billboard images used by any single "
|
||||
"tree."));
|
||||
|
||||
ConfigVariableDouble speedtree_cull_cell_size
|
||||
("speedtree-cull-cell-size", 1200,
|
||||
PRC_DESC("Specifies the size of a single SpeedTree cull cell, in Panda "
|
||||
"units. Increasing this number decreases the number of "
|
||||
"individual calls that must be made to render geometry, "
|
||||
"while increasing the number of trees that are rendered "
|
||||
"per call."));
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libspeedtree
|
||||
// Description: Initializes the library. This must be called at
|
||||
// least once before any of the functions or classes in
|
||||
// this library can be used. Normally it will be
|
||||
// called by the static initializers and need not be
|
||||
// called explicitly, but special cases exist.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
init_libspeedtree() {
|
||||
static bool initialized = false;
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
SpeedTreeNode::init_type();
|
||||
STTree::init_type();
|
||||
LoaderFileTypeSrt::init_type();
|
||||
|
||||
LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
|
||||
reg->register_type(new LoaderFileTypeSrt);
|
||||
}
|
||||
|
||||
// We need a SpeedTree custom allocator to integrate with Panda's
|
||||
// memory management.
|
||||
class STCustomAllocator : public SpeedTree::CAllocator {
|
||||
public:
|
||||
void *Alloc(size_t block_size) {
|
||||
return PANDA_MALLOC_ARRAY(block_size);
|
||||
}
|
||||
|
||||
void Free(void *block) {
|
||||
if (block != NULL) {
|
||||
PANDA_FREE_ARRAY(block);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Hook our custom allocator into SpeedTree.
|
||||
#ifndef CPPPARSER
|
||||
static STCustomAllocator custom_allocator;
|
||||
static SpeedTree::CAllocatorInterface allocator_interface(&custom_allocator);
|
||||
#endif // CPPPARSER
|
39
panda/src/speedtree/config_speedtree.h
Normal file
39
panda/src/speedtree/config_speedtree.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Filename: config_speedtree.h
|
||||
// Created by: drose (30Sep10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CONFIG_SPEEDTREE_H
|
||||
#define CONFIG_SPEEDTREE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "notifyCategoryProxy.h"
|
||||
#include "configVariableBool.h"
|
||||
#include "configVariableDouble.h"
|
||||
#include "configVariableString.h"
|
||||
#include "configVariableInt.h"
|
||||
#include "configVariableFilename.h"
|
||||
|
||||
NotifyCategoryDecl(speedtree, EXPCL_PANDASKEL, EXPTP_PANDASKEL);
|
||||
|
||||
extern ConfigVariableString speedtree_license;
|
||||
extern ConfigVariableFilename speedtree_shaders_dir;
|
||||
extern ConfigVariableBool speedtree_allow_horizontal_billboards;
|
||||
extern ConfigVariableInt speedtree_max_num_visible_cells;
|
||||
extern ConfigVariableInt speedtree_max_billboard_images_by_base;
|
||||
extern ConfigVariableDouble speedtree_cull_cell_size;
|
||||
|
||||
extern EXPCL_PANDASKEL void init_libspeedtree();
|
||||
|
||||
#endif
|
||||
|
||||
|
85
panda/src/speedtree/loaderFileTypeSrt.cxx
Normal file
85
panda/src/speedtree/loaderFileTypeSrt.cxx
Normal file
@ -0,0 +1,85 @@
|
||||
// Filename: loaderFileTypeSrt.cxx
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "loaderFileTypeSrt.h"
|
||||
#include "speedTreeNode.h"
|
||||
#include "stTree.h"
|
||||
|
||||
TypeHandle LoaderFileTypeSrt::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LoaderFileTypeSrt::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LoaderFileTypeSrt::
|
||||
LoaderFileTypeSrt() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LoaderFileTypeSrt::get_name
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string LoaderFileTypeSrt::
|
||||
get_name() const {
|
||||
return "SpeedTree compiled tree";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LoaderFileTypeSrt::get_extension
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string LoaderFileTypeSrt::
|
||||
get_extension() const {
|
||||
return "srt";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LoaderFileTypeSrt::supports_compressed
|
||||
// Access: Published, Virtual
|
||||
// Description: Returns true if this file type can transparently load
|
||||
// compressed files (with a .pz extension), false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool LoaderFileTypeSrt::
|
||||
supports_compressed() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LoaderFileTypeSrt::load_file
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(PandaNode) LoaderFileTypeSrt::
|
||||
load_file(const Filename &path, const LoaderOptions &,
|
||||
BamCacheRecord *record) const {
|
||||
if (!path.is_regular_file()) {
|
||||
// Quietly fail if the file doesn't exist. The Loader expects
|
||||
// this.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PT(STTree) tree = new STTree(path);
|
||||
if (!tree->is_valid()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PT(SpeedTreeNode) st = new SpeedTreeNode(path.get_basename());
|
||||
st->add_instance(tree, STTransform());
|
||||
|
||||
return st.p();
|
||||
}
|
59
panda/src/speedtree/loaderFileTypeSrt.h
Normal file
59
panda/src/speedtree/loaderFileTypeSrt.h
Normal file
@ -0,0 +1,59 @@
|
||||
// Filename: loaderFileTypeSrt.h
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LOADERFILETYPESRT_H
|
||||
#define LOADERFILETYPESRT_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "loaderFileType.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : LoaderFileTypeSrt
|
||||
// Description : This defines the Loader interface to read SpeedTree
|
||||
// SRT files, which describe a single tree. It actually
|
||||
// returns a SpeedTreeNode with just a single tree
|
||||
// within it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDASKEL LoaderFileTypeSrt : public LoaderFileType {
|
||||
public:
|
||||
LoaderFileTypeSrt();
|
||||
|
||||
virtual string get_name() const;
|
||||
virtual string get_extension() const;
|
||||
virtual bool supports_compressed() const;
|
||||
|
||||
virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options,
|
||||
BamCacheRecord *record) const;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
LoaderFileType::init_type();
|
||||
register_type(_type_handle, "LoaderFileTypeSrt",
|
||||
LoaderFileType::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
6
panda/src/speedtree/pandaspeedtree_composite1.cxx
Normal file
6
panda/src/speedtree/pandaspeedtree_composite1.cxx
Normal file
@ -0,0 +1,6 @@
|
||||
#include "config_speedtree.cxx"
|
||||
#include "loaderFileTypeSrt.cxx"
|
||||
#include "speedTreeNode.cxx"
|
||||
#include "speedtree_api.cxx"
|
||||
#include "stTransform.cxx"
|
||||
#include "stTree.cxx"
|
164
panda/src/speedtree/speedTreeNode.I
Normal file
164
panda/src/speedtree/speedTreeNode.I
Normal file
@ -0,0 +1,164 @@
|
||||
// Filename: speedTreeNode.I
|
||||
// Created by: drose (30Sep10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::is_valid
|
||||
// Access: Published
|
||||
// Description: Returns true if the node is valid and ready to
|
||||
// render, false otherwise. Note that this might not
|
||||
// become false until after the first time the node is
|
||||
// rendered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool SpeedTreeNode::
|
||||
is_valid() const {
|
||||
return _is_valid;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::get_num_trees
|
||||
// Access: Published
|
||||
// Description: Returns the number of unique tree objects that have
|
||||
// been added to the node. This count does not include
|
||||
// multiple instances of the same tree that appear in
|
||||
// different transforms.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int SpeedTreeNode::
|
||||
get_num_trees() const {
|
||||
return (int)_trees.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::get_tree
|
||||
// Access: Published
|
||||
// Description: Returns the STTree pointer for the nth tree.
|
||||
// See get_num_trees().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const STTree *SpeedTreeNode::
|
||||
get_tree(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_trees.size(), NULL);
|
||||
InstanceList *instance_list = _trees[n];
|
||||
return instance_list->get_tree();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::get_instance_list
|
||||
// Access: Published
|
||||
// Description: Returns a list of transforms that corresponds to the
|
||||
// instances at which the nth tree appears.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const SpeedTreeNode::InstanceList &SpeedTreeNode::
|
||||
get_instance_list(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_trees.size(), *(InstanceList *)NULL);
|
||||
InstanceList *instance_list = _trees[n];
|
||||
return *instance_list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::modify_tree
|
||||
// Access: Published
|
||||
// Description: Returns a modifiable STTree pointer for the nth tree
|
||||
// instance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTree *SpeedTreeNode::
|
||||
modify_tree(int n) {
|
||||
nassertr(n >= 0 && n < (int)_trees.size(), NULL);
|
||||
InstanceList *instance_list = _trees[n];
|
||||
_needs_repopulate = true;
|
||||
return (STTree *)instance_list->get_tree();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SpeedTreeNode::InstanceList::
|
||||
InstanceList(const STTree *tree) : _tree((STTree *)tree) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::operator <
|
||||
// Access: Public
|
||||
// Description: Used for comparison for ov_set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool SpeedTreeNode::InstanceList::
|
||||
operator < (const InstanceList &other) const {
|
||||
return _tree < other._tree;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::get_tree
|
||||
// Access: Published
|
||||
// Description: Returns the particular tree this list refers to.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const STTree *SpeedTreeNode::InstanceList::
|
||||
get_tree() const {
|
||||
return _tree;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::get_num_instances
|
||||
// Access: Published
|
||||
// Description: Returns the number of instances of this tree.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int SpeedTreeNode::InstanceList::
|
||||
get_num_instances() const {
|
||||
return (int)_instances.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::get_instance
|
||||
// Access: Published
|
||||
// Description: Returns the transform of the nth instance of this
|
||||
// tree.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform SpeedTreeNode::InstanceList::
|
||||
get_instance(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_instances.size(), STTransform::ident_mat());
|
||||
return _instances[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::add_instance
|
||||
// Access: Published
|
||||
// Description: Adds a new instance of this tree at the indicated
|
||||
// transform. Returns the index number of the new
|
||||
// instance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int SpeedTreeNode::InstanceList::
|
||||
add_instance(const STTransform &transform) {
|
||||
_instances.push_back(transform);
|
||||
return ((int)_instances.size() - 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::remove_instance
|
||||
// Access: Published
|
||||
// Description: Removes the nth instance of this tree.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void SpeedTreeNode::InstanceList::
|
||||
remove_instance(int n) {
|
||||
nassertv(n >= 0 && n < (int)_instances.size());
|
||||
_instances.erase(_instances.begin() + n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::DrawCallback::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SpeedTreeNode::DrawCallback::
|
||||
DrawCallback(SpeedTreeNode *node) : _node(node) {
|
||||
}
|
981
panda/src/speedtree/speedTreeNode.cxx
Normal file
981
panda/src/speedtree/speedTreeNode.cxx
Normal file
@ -0,0 +1,981 @@
|
||||
// Filename: speedTreeNode.cxx
|
||||
// Created by: drose (13Mar09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "speedTreeNode.h"
|
||||
#include "virtualFileSystem.h"
|
||||
#include "config_util.h"
|
||||
#include "cullTraverser.h"
|
||||
#include "cullableObject.h"
|
||||
#include "cullHandler.h"
|
||||
#include "omniBoundingVolume.h"
|
||||
#include "boundingSphere.h"
|
||||
#include "boundingBox.h"
|
||||
#include "clockObject.h"
|
||||
#include "geomDrawCallbackData.h"
|
||||
#include "graphicsStateGuardian.h"
|
||||
#include "textureAttrib.h"
|
||||
|
||||
#ifdef SPEEDTREE_OPENGL
|
||||
#include "glew/glew.h"
|
||||
#endif // SPEEDTREE_OPENGL
|
||||
|
||||
bool SpeedTreeNode::_authorized;
|
||||
bool SpeedTreeNode::_done_first_init;
|
||||
TypeHandle SpeedTreeNode::_type_handle;
|
||||
TypeHandle SpeedTreeNode::DrawCallback::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SpeedTreeNode::
|
||||
SpeedTreeNode(const string &name) :
|
||||
PandaNode(name),
|
||||
_forest(*(new SpeedTree::CForestRender)) // HACK! SpeedTree doesn't destruct unused CForestRender objects correctly. Temporarily leaking these things until SpeedTree is fixed.
|
||||
{
|
||||
init_node();
|
||||
// For now, set an infinite bounding volume. Maybe in the future
|
||||
// we'll change this to match whatever set of trees we're holding,
|
||||
// though it probably doesn't really matter too much.
|
||||
//set_internal_bounds(new OmniBoundingVolume);
|
||||
// set_internal_bounds(new BoundingSphere(LPoint3f::zero(), 10.0f));
|
||||
|
||||
// Intialize the render params.
|
||||
SpeedTree::SForestRenderInfo render_info;
|
||||
|
||||
// First, get the shader directory.
|
||||
if (!speedtree_shaders_dir.get_value().is_directory()) {
|
||||
speedtree_cat.warning()
|
||||
<< "speedtree-shaders-dir is set to " << speedtree_shaders_dir
|
||||
<< ", which doesn't exist.\n";
|
||||
}
|
||||
|
||||
string shaders_dir = speedtree_shaders_dir.get_value().to_os_specific();
|
||||
// Ensure the path ends with a terminal slash; SpeedTree requires this.
|
||||
#ifdef WIN32
|
||||
if (!shaders_dir.empty() && shaders_dir[shaders_dir.length() - 1] != '\\') {
|
||||
shaders_dir += "\\";
|
||||
}
|
||||
#else
|
||||
if (!shaders_dir.empty() && shaders_dir[shaders_dir.length() - 1] != '/') {
|
||||
shaders_dir += "/";
|
||||
}
|
||||
#endif
|
||||
|
||||
render_info.m_strShaderPath = shaders_dir.c_str();
|
||||
render_info.m_nMaxBillboardImagesByBase = speedtree_max_billboard_images_by_base;
|
||||
render_info.m_nNumShadowMaps = 1;
|
||||
render_info.m_nShadowMapResolution = 0;
|
||||
_forest.SetRenderInfo(render_info);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::count_total_instances
|
||||
// Access: Published
|
||||
// Description: Returns the total number of trees that will be
|
||||
// rendered by this node, counting all instances of all
|
||||
// trees.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int SpeedTreeNode::
|
||||
count_total_instances() const {
|
||||
int total_instances = 0;
|
||||
Trees::const_iterator ti;
|
||||
for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
total_instances += instance_list->get_num_instances();
|
||||
}
|
||||
|
||||
return total_instances;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::add_tree
|
||||
// Access: Published
|
||||
// Description: Adds a new tree for rendering. Returns the
|
||||
// InstanceList which can be used to add to the
|
||||
// instances for this tree. If the tree has previously
|
||||
// been added, returns the existing InstanceList.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SpeedTreeNode::InstanceList &SpeedTreeNode::
|
||||
add_tree(const STTree *tree) {
|
||||
nassertr(is_valid(), *(InstanceList *)NULL);
|
||||
nassertr(tree->is_valid(), *(InstanceList *)NULL);
|
||||
|
||||
InstanceList ilist(tree);
|
||||
Trees::iterator ti = _trees.find(&ilist);
|
||||
if (ti == _trees.end()) {
|
||||
// This is the first time that this particular tree has been
|
||||
// added.
|
||||
InstanceList *instance_list = new InstanceList(tree);
|
||||
pair<Trees::iterator, bool> result = _trees.insert(instance_list);
|
||||
ti = result.first;
|
||||
bool inserted = result.second;
|
||||
nassertr(inserted, *(*ti));
|
||||
|
||||
if (!_forest.RegisterTree((SpeedTree::CTree *)tree->get_tree())) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to register tree " << tree->get_filename() << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
_needs_repopulate = true;
|
||||
mark_internal_bounds_stale();
|
||||
InstanceList *instance_list = (*ti);
|
||||
return *instance_list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::remove_tree
|
||||
// Access: Published
|
||||
// Description: Removes all instances of the indicated tree. Returns
|
||||
// the number of instances removed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int SpeedTreeNode::
|
||||
remove_tree(const STTree *tree) {
|
||||
InstanceList ilist(tree);
|
||||
Trees::iterator ti = _trees.find(&ilist);
|
||||
if (ti == _trees.end()) {
|
||||
// The tree was not already present.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_forest.UnregisterTree(tree->get_tree())) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to unregister tree " << tree->get_filename() << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
|
||||
_needs_repopulate = true;
|
||||
mark_internal_bounds_stale();
|
||||
|
||||
InstanceList *instance_list = (*ti);
|
||||
int num_removed = instance_list->get_num_instances();
|
||||
_trees.erase(ti);
|
||||
delete instance_list;
|
||||
|
||||
return num_removed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::remove_all_trees
|
||||
// Access: Published
|
||||
// Description: Removes all instances of all trees from the node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
remove_all_trees() {
|
||||
Trees::iterator ti;
|
||||
for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
const STTree *tree = instance_list->get_tree();
|
||||
if (!_forest.UnregisterTree(tree->get_tree())) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to unregister tree " << tree->get_filename() << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
delete instance_list;
|
||||
}
|
||||
|
||||
_trees.clear();
|
||||
_needs_repopulate = true;
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::has_instance_list
|
||||
// Access: Published
|
||||
// Description: Returns true if the indicated tree has any instances
|
||||
// within this node, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SpeedTreeNode::
|
||||
has_instance_list(const STTree *tree) const {
|
||||
InstanceList ilist(tree);
|
||||
Trees::const_iterator ti = _trees.find(&ilist);
|
||||
return (ti != _trees.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::get_instance_list
|
||||
// Access: Published
|
||||
// Description: Returns a list of transforms that corresponds to the
|
||||
// instances at which the indicated tree appears. You
|
||||
// should ensure that has_instance_list() returns true
|
||||
// before calling this method.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const SpeedTreeNode::InstanceList &SpeedTreeNode::
|
||||
get_instance_list(const STTree *tree) const {
|
||||
InstanceList ilist(tree);
|
||||
Trees::const_iterator ti = _trees.find(&ilist);
|
||||
if (ti == _trees.end()) {
|
||||
// The tree was not already present.
|
||||
static InstanceList empty_list((STTree *)NULL);
|
||||
return empty_list;
|
||||
}
|
||||
|
||||
InstanceList *instance_list = (*ti);
|
||||
return *instance_list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::modify_instance_list
|
||||
// Access: Published
|
||||
// Description: Returns a modifiable list of transforms that
|
||||
// corresponds to the instances of this tree. This is
|
||||
// equivalent to add_tree().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SpeedTreeNode::InstanceList &SpeedTreeNode::
|
||||
modify_instance_list(const STTree *tree) {
|
||||
return add_tree(tree);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::add_instance
|
||||
// Access: Published
|
||||
// Description: Adds a new instance of the indicated tree at the
|
||||
// indicated transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
add_instance(const STTree *tree, const STTransform &transform) {
|
||||
add_tree(tree).add_instance(transform);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::add_instances
|
||||
// Access: Published
|
||||
// Description: Walks the scene graph beginning at root, looking for
|
||||
// nested SpeedTreeNodes. For each SpeedTreeNode found,
|
||||
// adds all of the instances defined within that
|
||||
// SpeedTreeNode as instances of this node, after
|
||||
// applying the indicated scene-graph transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::authorize
|
||||
// Access: Published, Static
|
||||
// Description: Make this call to initialized the SpeedTree API and
|
||||
// verify the license. If an empty string is passed for
|
||||
// the license, the config variable speedtree-license is
|
||||
// consulted. Returns true on success, false on
|
||||
// failure. If this call is not made explicitly, it
|
||||
// will be made implicitly the first time a
|
||||
// SpeedTreeNode is created.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SpeedTreeNode::
|
||||
authorize(const string &license) {
|
||||
if (!_authorized) {
|
||||
if (!license.empty()) {
|
||||
SpeedTree::CCore::Authorize(license.c_str());
|
||||
} else {
|
||||
if (!speedtree_license.empty()) {
|
||||
SpeedTree::CCore::Authorize(speedtree_license.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
_authorized = SpeedTree::CCore::IsAuthorized();
|
||||
|
||||
SpeedTree::CCore::SetTextureFlip(true);
|
||||
}
|
||||
|
||||
return _authorized;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::Copy Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SpeedTreeNode::
|
||||
SpeedTreeNode(const SpeedTreeNode ©) :
|
||||
PandaNode(copy),
|
||||
_forest(*(new SpeedTree::CForestRender)) // HACK! SpeedTree doesn't destruct unused CForestRender objects correctly. Temporarily leaking these things until SpeedTree is fixed.
|
||||
{
|
||||
init_node();
|
||||
|
||||
_forest.SetRenderInfo(copy._forest.GetRenderInfo());
|
||||
|
||||
Trees::const_iterator ti;
|
||||
for (ti = copy._trees.begin(); ti != copy._trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
const STTree *tree = instance_list->get_tree();
|
||||
if (!_forest.RegisterTree((SpeedTree::CTree *)tree->get_tree())) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to register tree " << tree->get_filename() << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
|
||||
_trees.push_back(new InstanceList(*instance_list));
|
||||
}
|
||||
|
||||
_needs_repopulate = true;
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *SpeedTreeNode::
|
||||
make_copy() const {
|
||||
return new SpeedTreeNode(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::safe_to_combine
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if it is generally safe to combine this
|
||||
// particular kind of PandaNode with other kinds of
|
||||
// PandaNodes of compatible type, adding children or
|
||||
// whatever. For instance, an LODNode should not be
|
||||
// combined with any other PandaNode, because its set of
|
||||
// children is meaningful.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SpeedTreeNode::
|
||||
safe_to_combine() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::cull_callback
|
||||
// Access: Public, Virtual
|
||||
// Description: This function will be called during the cull
|
||||
// traversal to perform any additional operations that
|
||||
// should be performed at cull time. This may include
|
||||
// additional manipulation of render state or additional
|
||||
// visible/invisible decisions, or any other arbitrary
|
||||
// operation.
|
||||
//
|
||||
// Note that this function will *not* be called unless
|
||||
// set_cull_callback() is called in the constructor of
|
||||
// the derived class. It is necessary to call
|
||||
// set_cull_callback() to indicated that we require
|
||||
// cull_callback() to be called.
|
||||
//
|
||||
// By the time this function is called, the node has
|
||||
// already passed the bounding-volume test for the
|
||||
// viewing frustum, and the node's transform and state
|
||||
// have already been applied to the indicated
|
||||
// CullTraverserData object.
|
||||
//
|
||||
// The return value is true if this node should be
|
||||
// visible, or false if it should be culled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SpeedTreeNode::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, trav->get_gsg());
|
||||
nassertr(gsg != (GraphicsStateGuardian *)NULL, true);
|
||||
if (!validate_api(gsg)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ClockObject *clock = ClockObject::get_global_clock();
|
||||
_forest.SetGlobalTime(clock->get_frame_time());
|
||||
_forest.AdvanceGlobalWind();
|
||||
|
||||
// Compute the modelview and camera transforms, to pass to the
|
||||
// SpeedTree CView structure.
|
||||
CPT(TransformState) modelview = data.get_modelview_transform(trav);
|
||||
modelview = gsg->get_cs_transform()->compose(modelview);
|
||||
CPT(TransformState) camera_transform = modelview->invert_compose(TransformState::make_identity());
|
||||
const LMatrix4f &modelview_mat = modelview->get_mat();
|
||||
const LPoint3f &camera_pos = camera_transform->get_pos();
|
||||
const Lens *lens = trav->get_scene()->get_lens();
|
||||
|
||||
LMatrix4f projection_mat =
|
||||
LMatrix4f::convert_mat(gsg->get_internal_coordinate_system(), lens->get_coordinate_system()) *
|
||||
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());
|
||||
|
||||
if (!_forest.UploadViewShaderParameters(_view)) {
|
||||
speedtree_cat.warning()
|
||||
<< "Couldn't set view parameters\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
|
||||
if (!_needs_repopulate) {
|
||||
// Don't bother culling now unless we're correctly fully
|
||||
// populated. (Culling won't be accurate unless the forest has
|
||||
// been populated, but we have to be in the draw traversal to
|
||||
// populate.)
|
||||
_forest.CullAndComputeLOD(_view, _visible_trees);
|
||||
}
|
||||
// cerr << _visible_trees.m_aVisibleCells.size() << " visible cells\n";
|
||||
|
||||
// Recurse onto the node's children.
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::is_renderable
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if there is some value to visiting this
|
||||
// particular node during the cull traversal for any
|
||||
// camera, false otherwise. This will be used to
|
||||
// optimize the result of get_net_draw_show_mask(), so
|
||||
// that any subtrees that contain only nodes for which
|
||||
// is_renderable() is false need not be visited.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SpeedTreeNode::
|
||||
is_renderable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::add_for_draw
|
||||
// Access: Public, Virtual
|
||||
// Description: 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. For most nodes other
|
||||
// than GeomNodes, this is a do-nothing operation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
add_for_draw(CullTraverser *trav, CullTraverserData &data) {
|
||||
if (_is_valid) {
|
||||
// We create a CullableObject that has an explicit draw_callback
|
||||
// into this node, so that we can make the appropriate calls into
|
||||
// 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());
|
||||
object->set_draw_callback(new DrawCallback(this));
|
||||
trav->get_cull_handler()->record_object(object, trav);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::prepare_scene
|
||||
// Access: Published
|
||||
// Description: Walks through the scene graph beginning at this node,
|
||||
// and does whatever initialization is required to
|
||||
// render the scene properly with the indicated GSG. It
|
||||
// is not strictly necessary to call this, since the GSG
|
||||
// will initialize itself when the scene is rendered,
|
||||
// but this may take some of the overhead away from that
|
||||
// process.
|
||||
//
|
||||
// In particular, this will ensure that textures within
|
||||
// the scene are loaded in texture memory, and display
|
||||
// lists are built up from static geometry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
prepare_scene(GraphicsStateGuardianBase *gsgbase, const RenderState *) {
|
||||
GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, gsgbase);
|
||||
if (validate_api(gsg)) {
|
||||
setup_for_render(gsg);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description: Returns a newly-allocated BoundingVolume that
|
||||
// represents the internal contents of the node. Should
|
||||
// be overridden by PandaNode classes that contain
|
||||
// something internally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
internal_vertices = 0;
|
||||
|
||||
SpeedTree::CExtents extents;
|
||||
Trees::const_iterator ti;
|
||||
for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
const STTree *tree = instance_list->get_tree();
|
||||
|
||||
const STInstances &st_instances = instance_list->_instances;
|
||||
STInstances::const_iterator ii;
|
||||
for (ii = st_instances.begin(); ii != st_instances.end(); ++ii) {
|
||||
SpeedTree::CExtents tree_extents = tree->get_tree()->GetExtents();
|
||||
tree_extents.Rotate((*ii).GetRotationAngle());
|
||||
tree_extents.Scale((*ii).GetScale());
|
||||
tree_extents.Translate((*ii).GetPos());
|
||||
extents.ExpandAround(tree_extents);
|
||||
}
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::output
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes a brief description of the node to the
|
||||
// indicated output stream. This is invoked by the <<
|
||||
// operator. It may be overridden in derived classes to
|
||||
// include some information relevant to the class.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
output(ostream &out) const {
|
||||
PandaNode::output(out);
|
||||
out
|
||||
<< " (" << get_num_trees() << " unique trees with "
|
||||
<< count_total_instances() << " total instances)";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::write
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
write(ostream &out, int indent_level) const {
|
||||
PandaNode::write(out, indent_level);
|
||||
|
||||
Trees::const_iterator ti;
|
||||
for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
instance_list->write(out, indent_level + 2);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::init_node
|
||||
// Access: Private
|
||||
// Description: Called from the constructor to initialize some
|
||||
// internal values.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
init_node() {
|
||||
PandaNode::set_cull_callback();
|
||||
|
||||
_is_valid = false;
|
||||
_needs_repopulate = false;
|
||||
|
||||
// Ensure we have a license.
|
||||
if (!authorize()) {
|
||||
speedtree_cat.warning()
|
||||
<< "SpeedTree license not available.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
_forest.SetHint(SpeedTree::CForest::HINT_MAX_NUM_VISIBLE_CELLS, speedtree_max_num_visible_cells);
|
||||
|
||||
_forest.SetCullCellSize(speedtree_cull_cell_size);
|
||||
|
||||
_is_valid = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::r_add_instances
|
||||
// Access: Private
|
||||
// Description: The recursive implementation of add_instances().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
r_add_instances(PandaNode *node, const TransformState *transform,
|
||||
Thread *current_thread) {
|
||||
if (node->is_of_type(SpeedTreeNode::get_class_type()) && node != this) {
|
||||
SpeedTreeNode *other = DCAST(SpeedTreeNode, node);
|
||||
|
||||
int num_trees = other->get_num_trees();
|
||||
for (int ti = 0; ti < num_trees; ++ti) {
|
||||
const InstanceList &other_instance_list = other->get_instance_list(ti);
|
||||
const STTree *tree = other_instance_list.get_tree();
|
||||
InstanceList &this_instance_list = add_tree(tree);
|
||||
|
||||
int num_instances = other_instance_list.get_num_instances();
|
||||
for (int i = 0; i < num_instances; ++i) {
|
||||
CPT(TransformState) other_trans = other_instance_list.get_instance(i);
|
||||
CPT(TransformState) new_trans = transform->compose(other_trans);
|
||||
this_instance_list.add_instance(new_trans.p());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Children children = node->get_children(current_thread);
|
||||
for (int i = 0; i < children.get_num_children(); i++) {
|
||||
PandaNode *child = children.get_child(i);
|
||||
CPT(TransformState) child_transform = transform->compose(child->get_transform());
|
||||
r_add_instances(child, child_transform, current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::repopulate
|
||||
// Access: Private
|
||||
// Description: Rebuilds the internal structures as necessary for
|
||||
// rendering.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
repopulate() {
|
||||
_forest.ClearInstances();
|
||||
|
||||
Trees::iterator ti;
|
||||
for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
const STTree *tree = instance_list->get_tree();
|
||||
const STInstances &instances = instance_list->_instances;
|
||||
if (instances.empty()) {
|
||||
// There are no instances, so don't bother. (This shouldn't
|
||||
// happen often, because we remove trees from the SpeedTreeNode
|
||||
// when their instance list goes empty, though it's possible if
|
||||
// the user has explicitly removed all of the instances.)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_forest.AddInstances(tree->get_tree(), &instances[0], instances.size())) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to add " << instances.size()
|
||||
<< " instances for " << *tree << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
_forest.GetPopulationStats(_population_stats);
|
||||
print_forest_stats(_population_stats);
|
||||
|
||||
// setup billboard caps based on instances-per-cell stats
|
||||
int max_instances_by_cell = 1;
|
||||
for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
const STTree *tree = instance_list->get_tree();
|
||||
const STInstances &instances = instance_list->_instances;
|
||||
if (instances.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int max_instances = 1;
|
||||
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_by_cell = max(max_instances_by_cell, max_instances);
|
||||
}
|
||||
|
||||
_visible_trees.Reserve(_forest.GetBaseTrees(),
|
||||
_forest.GetBaseTrees().size(),
|
||||
speedtree_max_num_visible_cells,
|
||||
max_instances_by_cell,
|
||||
speedtree_allow_horizontal_billboards);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::validate_api
|
||||
// Access: Private
|
||||
// Description: Returns true if the indicated GSG shares the
|
||||
// appropriate API for this SpeedTreeNode, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SpeedTreeNode::
|
||||
validate_api(GraphicsStateGuardian *gsg) {
|
||||
GraphicsPipe *pipe = gsg->get_pipe();
|
||||
nassertr(pipe != (GraphicsPipe *)NULL, true);
|
||||
|
||||
#if defined(SPEEDTREE_OPENGL)
|
||||
static const string compiled_api = "OpenGL";
|
||||
#elif defined(SPEEDTREE_DIRECTX9)
|
||||
static const string compiled_api = "DirectX9";
|
||||
#else
|
||||
#error Unexpected graphics API.
|
||||
#endif
|
||||
|
||||
if (pipe->get_interface_name() != compiled_api) {
|
||||
ostringstream stream;
|
||||
stream
|
||||
<< "SpeedTree is compiled for " << compiled_api
|
||||
<< ", cannot render with " << pipe->get_interface_name();
|
||||
nassert_raise(stream.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::draw_callback
|
||||
// Access: Private
|
||||
// Description: Called when the node is visited during the draw
|
||||
// traversal, by virtue of our DrawCallback construct.
|
||||
// This makes the calls into SpeedTree to perform the
|
||||
// actual rendering.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
draw_callback(CallbackData *data) {
|
||||
GeomDrawCallbackData *geom_cbdata;
|
||||
DCAST_INTO_V(geom_cbdata, data);
|
||||
|
||||
// Check the input state.
|
||||
const RenderState *state = geom_cbdata->get_object()->_state;
|
||||
|
||||
bool show_textures = true;
|
||||
const TextureAttrib *texattrib = DCAST(TextureAttrib, state->get_attrib(TextureAttrib::get_class_slot()));
|
||||
if (texattrib != (TextureAttrib *)NULL) {
|
||||
show_textures = !texattrib->has_all_off();
|
||||
}
|
||||
_forest.EnableTexturing(show_textures);
|
||||
|
||||
GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, geom_cbdata->get_gsg());
|
||||
|
||||
setup_for_render(gsg);
|
||||
|
||||
// start the forest render
|
||||
_forest.StartRender();
|
||||
|
||||
bool branches = _forest.RenderBranches(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
|
||||
bool fronds = _forest.RenderFronds(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
|
||||
bool leaf_meshes = _forest.RenderLeafMeshes(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
|
||||
bool leaf_cards = _forest.RenderLeafCards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
|
||||
bool billboards = _forest.RenderBillboards(_visible_trees, SpeedTree::RENDER_PASS_STANDARD, _view);
|
||||
|
||||
if (!branches || !fronds || !leaf_meshes || !leaf_cards || !billboards) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to render forest completely: "
|
||||
<< branches << " " << fronds << " " << leaf_meshes << " " << leaf_cards << " " << billboards << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
|
||||
_forest.EndRender();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::setup_for_render
|
||||
// Access: Private
|
||||
// Description: Does whatever calls are necessary to set up the
|
||||
// forest for rendering--create vbuffers, load shaders,
|
||||
// and whatnot. Primarily, this is the calls to
|
||||
// InitTreeGraphics and the like.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
setup_for_render(GraphicsStateGuardian *gsg) {
|
||||
if (!_done_first_init) {
|
||||
// This is the first time we have entered the draw callback since
|
||||
// creating any SpeedTreeNode. Now we have an opportunity to do
|
||||
// any initial setup that requires a graphics context.
|
||||
|
||||
#ifdef SPEEDTREE_OPENGL
|
||||
// For OpenGL, we have to ensure GLEW has been initialized.
|
||||
// (SpeedTree uses it, though Panda doesn't.)
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK) {
|
||||
speedtree_cat.error()
|
||||
<< "GLEW initialization failed: %s\n", glewGetErrorString(err);
|
||||
// Can't proceed without GLEW.
|
||||
_is_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Insist that OpenGL 2.0 is available as the SpeedTree renderer
|
||||
// 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";
|
||||
_is_valid = false;
|
||||
return;
|
||||
}
|
||||
#endif // SPEEDTREE_OPENGL
|
||||
|
||||
_done_first_init = true;
|
||||
}
|
||||
|
||||
if (_needs_repopulate) {
|
||||
repopulate();
|
||||
|
||||
// Now init per-tree graphics
|
||||
Trees::const_iterator ti;
|
||||
for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
|
||||
InstanceList *instance_list = (*ti);
|
||||
const STTree *tree = instance_list->get_tree();
|
||||
const STInstances &instances = instance_list->_instances;
|
||||
if (instances.empty()) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (!_forest.InitTreeGraphics((SpeedTree::CTreeRender *)tree->get_tree(),
|
||||
max_instances, speedtree_allow_horizontal_billboards)) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to init tree graphics for " << *tree << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Init overall graphics
|
||||
if (!_forest.InitGraphics(false)) {
|
||||
speedtree_cat.warning()
|
||||
<< "Failed to init graphics\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
_is_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// This call apparently must be made at draw time, not earlier,
|
||||
// because it might attempt to create OpenGL index buffers and
|
||||
// such.
|
||||
_forest.UpdateTreeCellExtents();
|
||||
|
||||
// If we needed to repopulate, it means we didn't cull in the cull
|
||||
// traversal. Do it now.
|
||||
_forest.CullAndComputeLOD(_view, _visible_trees);
|
||||
|
||||
_needs_repopulate = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::print_forest_stats
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
print_forest_stats(const SpeedTree::CForest::SPopulationStats &forest_stats) const {
|
||||
fprintf(stderr, "\n Forest Population Statistics\n");
|
||||
fprintf(stderr, " ---------------------------------------------------\n");
|
||||
fprintf(stderr, " # of tree cull cells: %d\n", forest_stats.m_nNumCells);
|
||||
fprintf(stderr, " # of unique base trees: %d\n", forest_stats.m_nNumBaseTrees);
|
||||
fprintf(stderr, " total # of instances: %d\n", forest_stats.m_nNumInstances);
|
||||
fprintf(stderr, " average # of instances per base: %g\n", forest_stats.m_fAverageNumInstancesPerBase);
|
||||
fprintf(stderr, " max # of billboards/instances per cell: %d\n", forest_stats.m_nMaxNumBillboardsPerCell);
|
||||
fprintf(stderr, " max # of instances per cell per base:\n");
|
||||
SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator i;
|
||||
for (i = forest_stats.m_mMaxNumInstancesPerCellPerBase.begin( ); i != forest_stats.m_mMaxNumInstancesPerCellPerBase.end( ); ++i) {
|
||||
fprintf(stderr, " %35s: %4d\n", SpeedTree::CFixedString(i->first->GetFilename( )).NoPath( ).c_str( ), i->second);
|
||||
}
|
||||
fprintf(stderr, " average # instances per cell: %g\n", forest_stats.m_fAverageInstancesPerCell);
|
||||
fprintf(stderr, " max # of billboard images: %d\n", forest_stats.m_nMaxNumBillboardImages);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
// Description: Tells the BamReader how to create objects of type
|
||||
// SpeedTreeNode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
register_with_read_factory() {
|
||||
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||
PandaNode::write_datagram(manager, dg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::make_from_bam
|
||||
// Access: Protected, Static
|
||||
// Description: This function is called by the BamReader's factory
|
||||
// when a new object of type SpeedTreeNode is encountered
|
||||
// in the Bam file. It should create the SpeedTreeNode
|
||||
// and extract its information from the file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TypedWritable *SpeedTreeNode::
|
||||
make_from_bam(const FactoryParams ¶ms) {
|
||||
SpeedTreeNode *node = new SpeedTreeNode("");
|
||||
DatagramIterator scan;
|
||||
BamReader *manager;
|
||||
|
||||
parse_params(params, scan, manager);
|
||||
node->fillin(scan, manager);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::fillin
|
||||
// Access: Protected
|
||||
// Description: This internal function is called by make_from_bam to
|
||||
// read in all of the relevant data from the BamFile for
|
||||
// the new SpeedTreeNode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
PandaNode::fillin(scan, manager);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::InstanceList::
|
||||
output(ostream &out) const {
|
||||
out << *_tree << ": " << _instances.size() << " instances.";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::InstanceList::write
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::InstanceList::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< *_tree << ": " << _instances.size() << " instances.\n";
|
||||
STInstances::const_iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
indent(out, indent_level + 2)
|
||||
<< STTransform(*ii) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SpeedTreeNode::DrawCallback::do_callback
|
||||
// Access: Public, Virtual
|
||||
// Description: This method called when the callback is triggered; it
|
||||
// *replaces* the original function. To continue
|
||||
// performing the original function, you must call
|
||||
// cbdata->upcall() during the callback.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SpeedTreeNode::DrawCallback::
|
||||
do_callback(CallbackData *data) {
|
||||
_node->draw_callback(data);
|
||||
}
|
198
panda/src/speedtree/speedTreeNode.h
Normal file
198
panda/src/speedtree/speedTreeNode.h
Normal file
@ -0,0 +1,198 @@
|
||||
// Filename: speedTreeNode.h
|
||||
// Created by: drose (30Sep10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SPEEDTREENODE_H
|
||||
#define SPEEDTREENODE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "pandaNode.h"
|
||||
#include "pointerTo.h"
|
||||
#include "stTree.h"
|
||||
#include "stTransform.h"
|
||||
#include "callbackObject.h"
|
||||
|
||||
#include "speedtree_api.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : SpeedTreeNode
|
||||
// Description : Interfaces with the SpeedTree library to render
|
||||
// SpeedTree objects like a collection of trees,
|
||||
// terrain, or grass within the Panda3D scene graph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDASKEL SpeedTreeNode : public PandaNode {
|
||||
private:
|
||||
// This definition is required by InstanceList, below.
|
||||
typedef pvector<SpeedTree::CInstance> STInstances;
|
||||
|
||||
PUBLISHED:
|
||||
// This nested class keeps a linear list of transforms, for the
|
||||
// purpose of recording instances of a particular STTree. It is
|
||||
// used below.
|
||||
class InstanceList {
|
||||
public:
|
||||
INLINE InstanceList(const STTree *tree);
|
||||
INLINE bool operator < (const InstanceList &other) const;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE const STTree *get_tree() const;
|
||||
|
||||
INLINE int get_num_instances() const;
|
||||
INLINE STTransform get_instance(int n) const;
|
||||
MAKE_SEQ(get_instances, get_num_instances, get_instance);
|
||||
|
||||
INLINE int add_instance(const STTransform &transform);
|
||||
INLINE void remove_instance(int n);
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
private:
|
||||
PT(STTree) _tree;
|
||||
STInstances _instances;
|
||||
friend class SpeedTreeNode;
|
||||
};
|
||||
|
||||
PUBLISHED:
|
||||
SpeedTreeNode(const string &name);
|
||||
|
||||
INLINE bool is_valid() const;
|
||||
|
||||
INLINE int get_num_trees() const;
|
||||
INLINE const STTree *get_tree(int n) const;
|
||||
MAKE_SEQ(get_trees, get_num_trees, get_tree);
|
||||
const InstanceList &get_instance_list(int n) const;
|
||||
MAKE_SEQ(get_instance_lists, get_num_trees, get_instance_list);
|
||||
INLINE STTree *modify_tree(int n);
|
||||
|
||||
int count_total_instances() const;
|
||||
|
||||
InstanceList &add_tree(const STTree *tree);
|
||||
int remove_tree(const STTree *tree);
|
||||
void remove_all_trees();
|
||||
|
||||
bool has_instance_list(const STTree *tree) const;
|
||||
const InstanceList &get_instance_list(const STTree *tree) const;
|
||||
InstanceList &modify_instance_list(const STTree *tree);
|
||||
|
||||
void add_instance(const STTree *tree, const STTransform &transform);
|
||||
void add_instances(const NodePath &root, const TransformState *transform = TransformState::make_identity());
|
||||
|
||||
static bool authorize(const string &license = "");
|
||||
|
||||
public:
|
||||
SpeedTreeNode(const SpeedTreeNode ©);
|
||||
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual bool safe_to_combine() const;
|
||||
|
||||
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
|
||||
virtual bool is_renderable() const;
|
||||
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
void prepare_scene(GraphicsStateGuardianBase *gsgbase, const RenderState *net_state);
|
||||
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
private:
|
||||
void init_node();
|
||||
void r_add_instances(PandaNode *node, const TransformState *transform,
|
||||
Thread *current_thread);
|
||||
|
||||
void repopulate();
|
||||
bool validate_api(GraphicsStateGuardian *gsg);
|
||||
void draw_callback(CallbackData *cbdata);
|
||||
void setup_for_render(GraphicsStateGuardian *gsg);
|
||||
void print_forest_stats(const SpeedTree::CForest::SPopulationStats &forest_stats) const;
|
||||
|
||||
private:
|
||||
class DrawCallback : public CallbackObject {
|
||||
public:
|
||||
ALLOC_DELETED_CHAIN(DrawCallback);
|
||||
INLINE DrawCallback(SpeedTreeNode *node);
|
||||
virtual void do_callback(CallbackData *cbdata);
|
||||
|
||||
private:
|
||||
PT(SpeedTreeNode) _node;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
CallbackObject::init_type();
|
||||
register_type(_type_handle, "SpeedTreeNode::DrawCallback",
|
||||
CallbackObject::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
private:
|
||||
// A list of instances per each unique tree.
|
||||
typedef ov_set<InstanceList *, IndirectLess<InstanceList> > Trees;
|
||||
Trees _trees;
|
||||
|
||||
SpeedTree::CForestRender &_forest; // Hack!
|
||||
SpeedTree::CView _view;
|
||||
SpeedTree::SForestCullResultsRender _visible_trees;
|
||||
SpeedTree::CForest::SPopulationStats _population_stats;
|
||||
bool _needs_repopulate;
|
||||
bool _is_valid;
|
||||
|
||||
static bool _authorized;
|
||||
static bool _done_first_init;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||
|
||||
protected:
|
||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||
void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PandaNode::init_type();
|
||||
register_type(_type_handle, "SpeedTreeNode",
|
||||
PandaNode::get_class_type());
|
||||
DrawCallback::init_type();
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class SpeedTreeNode::DrawCallback;
|
||||
};
|
||||
|
||||
#include "speedTreeNode.I"
|
||||
|
||||
#endif
|
15
panda/src/speedtree/speedtree_api.cxx
Normal file
15
panda/src/speedtree/speedtree_api.cxx
Normal file
@ -0,0 +1,15 @@
|
||||
// Filename: speedtree_api.cxx
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "speedtree_api.h"
|
27
panda/src/speedtree/speedtree_api.h
Normal file
27
panda/src/speedtree/speedtree_api.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Filename: speedtree_api.h
|
||||
// Created by: drose (05Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SPEEDTREE_API_H
|
||||
#define SPEEDTREE_API_H
|
||||
|
||||
// This header file should be included first, to pull in any of the
|
||||
// required headers from the SpeedTree API, needed in this directory.
|
||||
|
||||
#include "speedtree_parameters.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Forest/Forest.h"
|
||||
#include "Renderers/OpenGL/OpenGLRenderer.h"
|
||||
|
||||
#endif // SPEEDTREE_API_H
|
||||
|
18
panda/src/speedtree/speedtree_parameters.h.pp
Normal file
18
panda/src/speedtree/speedtree_parameters.h.pp
Normal file
@ -0,0 +1,18 @@
|
||||
// This file is read and processed by ppremake to generate
|
||||
// speedtree_parameters.h, which is #included by speedtree_api.h.
|
||||
|
||||
#output speedtree_parameters.h notouch
|
||||
/* speedtree_parameters.h. Generated automatically by $[PPREMAKE] $[PPREMAKE_VERSION] from $[notdir $[THISFILENAME]]. */
|
||||
/********************************** DO NOT EDIT ****************************/
|
||||
|
||||
/* We need to define the appropriate macro to tell the SpeedTree
|
||||
headers which API we intend to use. This should be one of
|
||||
SPEEDTREE_OPENGL or SPEEDTREE_DIRECTX9 (or, when Panda supports it,
|
||||
SPEEDTREE_DIRECTX10). */
|
||||
# define SPEEDTREE_$[upcase $[SPEEDTREE_API]]
|
||||
|
||||
/* The default directory in which to search for SpeedTree's provided
|
||||
shaders and terrain files. */
|
||||
# define SPEEDTREE_BIN_DIR "$[SPEEDTREE_BIN_DIR]"
|
||||
|
||||
#end speedtree_parameters.h
|
130
panda/src/speedtree/stTransform.I
Normal file
130
panda/src/speedtree/stTransform.I
Normal file
@ -0,0 +1,130 @@
|
||||
// Filename: stTransform.I
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::Default Constructor
|
||||
// Access: Published
|
||||
// Description: The default constructor creates an identity transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform::
|
||||
STTransform() :
|
||||
_pos(0.0f, 0.0f, 0.0f),
|
||||
_rotate(0.0f),
|
||||
_scale(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::Constructor
|
||||
// Access: Published
|
||||
// Description: Construct a transform with componentwise inputs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform::
|
||||
STTransform(const LPoint3f &pos, float rotate, float scale) :
|
||||
_pos(pos),
|
||||
_rotate(rotate),
|
||||
_scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::Constructor
|
||||
// Access: Published
|
||||
// Description: Construct a transform with componentwise inputs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform::
|
||||
STTransform(float x, float y, float z, float rotate, float scale) :
|
||||
_pos(x, y, z),
|
||||
_rotate(rotate),
|
||||
_scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::Copy Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform::
|
||||
STTransform(const STTransform ©) :
|
||||
_pos(copy._pos),
|
||||
_rotate(copy._rotate),
|
||||
_scale(copy._scale)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void STTransform::
|
||||
operator = (const STTransform ©) {
|
||||
_pos = copy._pos;
|
||||
_rotate = copy._rotate;
|
||||
_scale = copy._scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::CInstance constructor
|
||||
// Access: Public
|
||||
// Description: This is used internally to construct an STTransform
|
||||
// from a SpeedTree::CInstance object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform::
|
||||
STTransform(const SpeedTree::CInstance &instance) {
|
||||
const SpeedTree::Vec3 &pos = instance.GetPos();
|
||||
_pos.set(pos[0], pos[1], pos[2]);
|
||||
_rotate = rad_2_deg(instance.GetRotationAngle());
|
||||
_scale = instance.GetScale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::CInstance operator
|
||||
// Access: Public
|
||||
// Description: This is used internally to convert an STTransform
|
||||
// into a SpeedTree::CInstance object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform::
|
||||
operator SpeedTree::CInstance () const {
|
||||
SpeedTree::CInstance instance;
|
||||
instance.SetPos(SpeedTree::Vec3(_pos[0], _pos[1], _pos[2]));
|
||||
instance.SetRotation(deg_2_rad(_rotate));
|
||||
instance.SetScale(_scale);
|
||||
return instance;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::TransformState operator
|
||||
// Access: Public
|
||||
// Description: This is used internally to convert an STTransform
|
||||
// into a TransformState pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE STTransform::
|
||||
operator CPT(TransformState) () const {
|
||||
return TransformState::make_pos_hpr_scale(_pos,
|
||||
LVecBase3f(_rotate, 0.0f, 0.0f),
|
||||
LVecBase3f(_scale, _scale, _scale));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::ident_mat
|
||||
// Access: Published, Static
|
||||
// Description: Returns a global identity transform object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const STTransform &STTransform::
|
||||
ident_mat() {
|
||||
return _ident_mat;
|
||||
}
|
54
panda/src/speedtree/stTransform.cxx
Normal file
54
panda/src/speedtree/stTransform.cxx
Normal file
@ -0,0 +1,54 @@
|
||||
// Filename: stTransform.cxx
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stTransform.h"
|
||||
|
||||
STTransform STTransform::_ident_mat;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::Constructor
|
||||
// Access: Published
|
||||
// Description: This constructor accepts a Panda TransformState, for
|
||||
// instance as extracted from the scene graph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
STTransform::
|
||||
STTransform(const TransformState *trans) {
|
||||
#ifndef NDEBUG
|
||||
// Ensure these are initialized to reasonable values in case we fail
|
||||
// an assertion below.
|
||||
_pos.set(0.0f, 0.0f, 0.0f);
|
||||
_rotate = 0.0f;
|
||||
_scale = 1.0f;
|
||||
#endif
|
||||
|
||||
nassertv(trans->has_components());
|
||||
_pos = trans->get_pos();
|
||||
|
||||
const LVecBase3f &hpr = trans->get_hpr();
|
||||
nassertv(IS_NEARLY_ZERO(hpr[1]) && IS_NEARLY_ZERO(hpr[2]));
|
||||
_rotate = hpr[0];
|
||||
|
||||
nassertv(trans->has_uniform_scale());
|
||||
_scale = trans->get_uniform_scale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTransform::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void STTransform::
|
||||
output(ostream &out) const {
|
||||
out << "STTransform(" << _pos << ", " << _rotate << ", " << _scale << ")";
|
||||
}
|
67
panda/src/speedtree/stTransform.h
Normal file
67
panda/src/speedtree/stTransform.h
Normal file
@ -0,0 +1,67 @@
|
||||
// Filename: stTransform.h
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef STTRANSFORM_H
|
||||
#define STTRANSFORM_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "transformState.h"
|
||||
#include "speedtree_api.h"
|
||||
#include "deg_2_rad.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : STTransform
|
||||
// Description : Represents a transform that may be applied to a
|
||||
// particular instance of a tree when added to the
|
||||
// SpeedTreeNode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDASKEL STTransform {
|
||||
PUBLISHED:
|
||||
INLINE STTransform();
|
||||
STTransform(const TransformState *trans);
|
||||
INLINE STTransform(const LPoint3f &pos, float rotate = 0.0f, float scale = 1.0f);
|
||||
INLINE STTransform(float x, float y, float z, float rotate, float scale);
|
||||
INLINE STTransform(const STTransform ©);
|
||||
INLINE void operator = (const STTransform ©);
|
||||
|
||||
public:
|
||||
INLINE STTransform(const SpeedTree::CInstance &instance);
|
||||
INLINE operator SpeedTree::CInstance () const;
|
||||
INLINE operator CPT(TransformState) () const;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE static const STTransform &ident_mat();
|
||||
|
||||
INLINE const LPoint3f &get_pos() const;
|
||||
INLINE float get_rotate() const;
|
||||
INLINE float get_scale() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
LPoint3f _pos;
|
||||
float _rotate;
|
||||
float _scale;
|
||||
|
||||
static STTransform _ident_mat;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const STTransform &transform) {
|
||||
transform.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "stTransform.I"
|
||||
|
||||
#endif
|
70
panda/src/speedtree/stTree.I
Normal file
70
panda/src/speedtree/stTree.I
Normal file
@ -0,0 +1,70 @@
|
||||
// Filename: stTree.I
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::get_fullpath
|
||||
// Access: Published
|
||||
// Description: Returns the full pathname to the SRT file that was
|
||||
// loaded for this tree, as passed to the constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const Filename &STTree::
|
||||
get_fullpath() const {
|
||||
return _fullpath;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::get_filename
|
||||
// Access: Published
|
||||
// Description: Returns the original filename given for the SRT file
|
||||
// for this tree, before resolving it along the
|
||||
// model-path, as passed to the constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const Filename &STTree::
|
||||
get_filename() const {
|
||||
return _filename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::is_valid
|
||||
// Access: Published
|
||||
// Description: Returns true if the tree was successfully loaded and
|
||||
// is ready to be used, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool STTree::
|
||||
is_valid() const {
|
||||
return _is_valid;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::get_tree
|
||||
// Access: Public
|
||||
// Description: Returns a const pointer to the internal SpeedTree
|
||||
// object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const SpeedTree::CTreeRender *STTree::
|
||||
get_tree() const {
|
||||
return &_tree;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::modify_tree
|
||||
// Access: Public
|
||||
// Description: Returns a modifiable pointer to the internal SpeedTree
|
||||
// object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SpeedTree::CTreeRender *STTree::
|
||||
modify_tree() {
|
||||
return &_tree;
|
||||
}
|
100
panda/src/speedtree/stTree.cxx
Normal file
100
panda/src/speedtree/stTree.cxx
Normal file
@ -0,0 +1,100 @@
|
||||
// Filename: stTree.cxx
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stTree.h"
|
||||
#include "speedTreeNode.h"
|
||||
|
||||
TypeHandle STTree::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::Constructor
|
||||
// Access: Published
|
||||
// Description: The constructor reads the indicated SRT file
|
||||
// immediately. Check is_valid() to determine whether
|
||||
// the read was successful or not. Note that the
|
||||
// filename must be a fully-qualified pathname; the
|
||||
// STTree constructor does not search the model-path.
|
||||
// (However, the user-specified relative filename may be
|
||||
// specified as an optional second parameter, which is
|
||||
// used for documentary purposes only.)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
STTree::
|
||||
STTree(const Filename &fullpath, const Filename &filename) :
|
||||
Namable(fullpath.get_basename_wo_extension()),
|
||||
_fullpath(fullpath),
|
||||
_filename(filename)
|
||||
{
|
||||
if (_filename.empty()) {
|
||||
_filename = fullpath;
|
||||
}
|
||||
|
||||
_is_valid = false;
|
||||
|
||||
// Ensure we have a license.
|
||||
if (!SpeedTreeNode::authorize()) {
|
||||
speedtree_cat.warning()
|
||||
<< "SpeedTree license not available.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't use VFS, due to SpeedTree's insistence on using fopen() to
|
||||
// load dds textures and such. So we go ahead and use the low-level
|
||||
// Filename interface directly.
|
||||
/*
|
||||
Filename tree_filename = filename;
|
||||
if (!tree_filename.resolve_filename(get_model_path(), "srt")) {
|
||||
speedtree_cat.warning()
|
||||
<< "Couldn't find: " << filename << "\n";
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
string os_fullpath = _fullpath.to_os_specific();
|
||||
if (!_tree.LoadTree(os_fullpath.c_str())) {
|
||||
speedtree_cat.warning()
|
||||
<< "Couldn't read: " << _fullpath << "\n";
|
||||
speedtree_cat.warning()
|
||||
<< SpeedTree::CCore::GetError() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
speedtree_cat.info()
|
||||
<< "Read " << _filename << "\n";
|
||||
_is_valid = true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: An STTree copy constructor is not supported.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
STTree::
|
||||
STTree(const STTree ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: STTree::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void STTree::
|
||||
output(ostream &out) const {
|
||||
if (!is_valid()) {
|
||||
out << "(invalid STTree)";
|
||||
} else {
|
||||
out << "STTree(" << get_name() << ")";
|
||||
}
|
||||
}
|
79
panda/src/speedtree/stTree.h
Normal file
79
panda/src/speedtree/stTree.h
Normal file
@ -0,0 +1,79 @@
|
||||
// Filename: stTree.h
|
||||
// Created by: drose (06Oct10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef STTREE_H
|
||||
#define STTREE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "typedReferenceCount.h"
|
||||
#include "namable.h"
|
||||
#include "speedtree_api.h"
|
||||
|
||||
class SpeedTreeNode;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : STTree
|
||||
// Description : Encapsulates a single tree model in the SpeedTree
|
||||
// library, as loaded from an SRT file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDASKEL STTree : public TypedReferenceCount, public Namable {
|
||||
PUBLISHED:
|
||||
STTree(const Filename &fullpath, const Filename &filename = Filename());
|
||||
private:
|
||||
STTree(const STTree ©);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE const Filename &get_fullpath() const;
|
||||
INLINE const Filename &get_filename() const;
|
||||
|
||||
INLINE bool is_valid() const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
public:
|
||||
INLINE const SpeedTree::CTreeRender *get_tree() const;
|
||||
INLINE SpeedTree::CTreeRender *modify_tree();
|
||||
|
||||
private:
|
||||
Filename _fullpath;
|
||||
Filename _filename;
|
||||
bool _is_valid;
|
||||
SpeedTree::CTreeRender _tree;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
TypedReferenceCount::init_type();
|
||||
register_type(_type_handle, "STTree",
|
||||
TypedReferenceCount::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const STTree &tree) {
|
||||
tree.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "stTree.I"
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user