add show_switch() debugging mode

This commit is contained in:
David Rose 2006-09-08 17:01:27 +00:00
parent d596a4a2af
commit 3d415c4e0f
6 changed files with 833 additions and 207 deletions

View File

@ -152,6 +152,34 @@ get_cull_center() const {
return _cull_center;
}
////////////////////////////////////////////////////////////////////
// Function: Camera::set_lod_center
// Access: Published
// Description: Specifies the point from which the LOD distances
// are measured. Normally, this is the same as the
// camera, and that is the default if this is not
// specified; but it may sometimes be useful to perform
// the distance test from some other viewpoint. This
// may be used, for instance, to reduce LOD popping when
// the camera rotates in a small circle about an avatar.
////////////////////////////////////////////////////////////////////
INLINE void Camera::
set_lod_center(const NodePath &lod_center) {
_lod_center = lod_center;
}
////////////////////////////////////////////////////////////////////
// Function: Camera::get_lod_center
// Access: Published
// Description: Returns the point from which the LOD distances will
// be measured, if it was set by set_lod_center(), or
// the empty NodePath otherwise.
////////////////////////////////////////////////////////////////////
INLINE const NodePath &Camera::
get_lod_center() const {
return _lod_center;
}
////////////////////////////////////////////////////////////////////
// Function: Camera::set_initial_state
// Access: Published

View File

@ -67,6 +67,9 @@ PUBLISHED:
INLINE void set_cull_center(const NodePath &cull_center);
INLINE const NodePath &get_cull_center() const;
INLINE void set_lod_center(const NodePath &lod_center);
INLINE const NodePath &get_lod_center() const;
INLINE void set_initial_state(const RenderState *state);
INLINE CPT(RenderState) get_initial_state() const;
@ -91,6 +94,7 @@ private:
bool _active;
NodePath _scene;
NodePath _cull_center;
NodePath _lod_center;
DrawMask _camera_mask;

View File

@ -73,6 +73,10 @@ make_copy() const {
////////////////////////////////////////////////////////////////////
bool FadeLODNode::
cull_callback(CullTraverser *trav, CullTraverserData &data) {
if (is_any_shown()) {
return show_switches_cull_callback(trav, data);
}
Camera *camera = trav->get_scene()->get_camera_node();
NodePath this_np = data._node_path.get_node_path();
FadeLODNodeData *ldata =

View File

@ -17,126 +17,6 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE LODNode::CData::
CData() :
_center(0.0f, 0.0f, 0.0f),
_lowest(0),
_highest(0),
_got_force_switch(false),
_force_switch(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE LODNode::CData::
CData(const LODNode::CData &copy) :
_center(copy._center),
_switch_vector(copy._switch_vector),
_lowest(copy._lowest),
_highest(copy._highest),
_got_force_switch(copy._got_force_switch),
_force_switch(copy._force_switch)
{
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE LODNode::Switch::
Switch(float in, float out) {
set_range(in, out);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::get_in
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE float LODNode::Switch::
get_in() const {
return _in;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::get_out
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE float LODNode::Switch::
get_out() const {
return _out;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::set_range
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
set_range(float in, float out) {
_in = in;
_out = out;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::in_range
// Access: Public
// Description: Computes the distance between two points and returns
// true if the result is within the range for the LOD.
////////////////////////////////////////////////////////////////////
INLINE bool LODNode::Switch::
in_range(float dist) const {
return (dist >= _out && dist < _in);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::rescale
// Access: Public
// Description: Scales the switching distances by the indicated factor.
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
rescale(float factor) {
_in *= factor;
_out *= factor;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::write_datagram
// Access: Public
// Description: Writes the contents of the Switch out to the
// datagram, presumably in preparation to writing to a
// Bam file.
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
write_datagram(Datagram &destination) const {
destination.add_float32(_in);
destination.add_float32(_out);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::read_datagram
// Access: Public
// Description: Reads the contents of the Switch from the datagram,
// presumably in response to reading a Bam file.
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
read_datagram(DatagramIterator &source) {
_in = source.get_float32();
_out = source.get_float32();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Constructor
@ -179,6 +59,10 @@ add_switch(float in, float out) {
CDWriter cdata(_cycler);
cdata->_switch_vector.push_back(Switch(in, out));
cdata->check_limits();
if (cdata->_num_shown != 0) {
mark_internal_bounds_stale();
}
}
////////////////////////////////////////////////////////////////////
@ -193,6 +77,11 @@ set_switch(int index, float in, float out) {
nassertr(index >= 0 && index < (int)cdata->_switch_vector.size(), false);
cdata->_switch_vector[index].set_range(in, out);
cdata->check_limits();
if (cdata->_num_shown != 0) {
mark_internal_bounds_stale();
}
return true;
}
@ -209,6 +98,10 @@ clear_switches() {
cdata->_switch_vector.clear();
cdata->_lowest = 0;
cdata->_highest = 0;
if (cdata->_num_shown != 0) {
mark_internal_bounds_stale();
}
}
////////////////////////////////////////////////////////////////////
@ -319,6 +212,10 @@ INLINE void LODNode::
set_center(const LPoint3f &center) {
CDWriter cdata(_cycler);
cdata->_center = center;
if (cdata->_num_shown != 0) {
mark_internal_bounds_stale();
}
}
////////////////////////////////////////////////////////////////////
@ -333,3 +230,216 @@ get_center() const {
CDReader cdata(_cycler);
return cdata->_center;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::is_any_shown
// Access: Published
// Description: Returns true if any switch has been shown with
// show_switch(), indicating the LODNode is in debug
// show mode; or false if it is in the normal mode.
////////////////////////////////////////////////////////////////////
INLINE bool LODNode::
is_any_shown() const {
CDReader cdata(_cycler);
return (cdata->_num_shown != 0);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE LODNode::CData::
CData() :
_center(0.0f, 0.0f, 0.0f),
_lowest(0),
_highest(0),
_got_force_switch(false),
_force_switch(0),
_num_shown(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE LODNode::CData::
CData(const LODNode::CData &copy) :
_center(copy._center),
_switch_vector(copy._switch_vector),
_lowest(copy._lowest),
_highest(copy._highest),
_got_force_switch(copy._got_force_switch),
_force_switch(copy._force_switch),
_num_shown(copy._num_shown)
{
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE LODNode::Switch::
Switch(float in, float out) : _shown(false) {
set_range(in, out);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::get_in
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE float LODNode::Switch::
get_in() const {
return _in;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::get_out
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE float LODNode::Switch::
get_out() const {
return _out;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::set_range
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
set_range(float in, float out) {
_in = in;
_out = out;
_ring_viz.clear();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::in_range
// Access: Public
// Description: Returns true if the indicated distance is within the
// range for the LOD.
////////////////////////////////////////////////////////////////////
INLINE bool LODNode::Switch::
in_range(float dist) const {
return (dist >= _out && dist < _in);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::in_range_2
// Access: Public
// Description: Returns true if the indicated distance squared is
// within the range for the LOD. (The distance value is
// understood to be the square of the distance from the
// camera to the object.)
////////////////////////////////////////////////////////////////////
INLINE bool LODNode::Switch::
in_range_2(float dist2) const {
return (dist2 >= _out * _out && dist2 < _in * _in);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::rescale
// Access: Public
// Description: Scales the switching distances by the indicated factor.
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
rescale(float factor) {
_in *= factor;
_out *= factor;
_ring_viz.clear();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::is_shown
// Access: Public
// Description: Returns true if show() has been called.
////////////////////////////////////////////////////////////////////
INLINE bool LODNode::Switch::
is_shown() const {
return _shown;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::show
// Access: Public
// Description: Shows this ring in debug mode using the indicated
// color.
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
show(const Colorf &color) {
_shown = true;
_show_color = color;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::hide
// Access: Public
// Description: Undoes a previous call to show().
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
hide() {
_shown = false;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::get_ring_viz
// Access: Public
// Description: Returns a PandaNode suitable for rendering the ring
// associated with this switch.
////////////////////////////////////////////////////////////////////
INLINE PandaNode *LODNode::Switch::
get_ring_viz() const {
if (_ring_viz.is_null()) {
((Switch *)this)->compute_ring_viz();
}
return _ring_viz;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::get_viz_model_state
// Access: Public
// Description: Returns a RenderState suitable for drawing the
// visible children of this switch level when the
// show_switch() debugging mode is enabled.
////////////////////////////////////////////////////////////////////
INLINE const RenderState *LODNode::Switch::
get_viz_model_state() const {
if (_viz_model_state.is_null()) {
((Switch *)this)->compute_ring_viz();
}
return _viz_model_state;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::write_datagram
// Access: Public
// Description: Writes the contents of the Switch out to the
// datagram, presumably in preparation to writing to a
// Bam file.
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
write_datagram(Datagram &destination) const {
destination.add_float32(_in);
destination.add_float32(_out);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::read_datagram
// Access: Public
// Description: Reads the contents of the Switch from the datagram,
// presumably in response to reading a Bam file.
////////////////////////////////////////////////////////////////////
INLINE void LODNode::Switch::
read_datagram(DatagramIterator &source) {
_in = source.get_float32();
_out = source.get_float32();
}

View File

@ -20,82 +20,25 @@
#include "cullTraverserData.h"
#include "cullTraverser.h"
#include "config_pgraph.h"
#include "geomVertexData.h"
#include "geomVertexWriter.h"
#include "geomVertexFormat.h"
#include "geomTristrips.h"
#include "mathNumbers.h"
#include "geom.h"
#include "geomNode.h"
#include "transformState.h"
#include "material.h"
#include "materialAttrib.h"
#include "materialPool.h"
#include "renderState.h"
#include "cullFaceAttrib.h"
#include "textureAttrib.h"
#include "boundingSphere.h"
#include "look_at.h"
TypeHandle LODNode::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::make_copy
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CycleData *LODNode::CData::
make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::check_limits
// Access: Public
// Description: Ensures that the _lowest and _highest members are set
// appropriately after a change to the set of switches.
////////////////////////////////////////////////////////////////////
void LODNode::CData::
check_limits() {
_lowest = 0;
_highest = 0;
for (size_t i = 1; i < _switch_vector.size(); ++i) {
if (_switch_vector[i].get_out() > _switch_vector[_lowest].get_out()) {
_lowest = i;
}
if (_switch_vector[i].get_in() < _switch_vector[_highest].get_in()) {
_highest = i;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void LODNode::CData::
write_datagram(BamWriter *manager, Datagram &dg) const {
_center.write_datagram(dg);
dg.add_uint16(_switch_vector.size());
SwitchVector::const_iterator si;
for (si = _switch_vector.begin();
si != _switch_vector.end();
++si) {
(*si).write_datagram(dg);
}
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::fillin
// Access: Public, Virtual
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new LODNode.
////////////////////////////////////////////////////////////////////
void LODNode::CData::
fillin(DatagramIterator &scan, BamReader *manager) {
_center.read_datagram(scan);
_switch_vector.clear();
int num_switches = scan.get_uint16();
_switch_vector.reserve(num_switches);
for (int i = 0; i < num_switches; i++) {
Switch sw(0, 0);
sw.read_datagram(scan);
_switch_vector.push_back(sw);
}
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::make_copy
// Access: Public, Virtual
@ -185,6 +128,10 @@ has_cull_callback() const {
////////////////////////////////////////////////////////////////////
bool LODNode::
cull_callback(CullTraverser *trav, CullTraverserData &data) {
if (is_any_shown()) {
return show_switches_cull_callback(trav, data);
}
int index = compute_child(trav, data);
if (index >= 0 && index < get_num_children()) {
CullTraverserData next_data(data, get_child(index));
@ -235,6 +182,93 @@ is_lod_node() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::show_switch
// Access: Published
// Description: This is provided as a debugging aid. show_switch()
// will put the LODNode into a special mode where rather
// than computing and drawing the appropriate level of
// the LOD, a ring is drawn around the LODNode center
// indicating the switch distances from the camera for
// the indicated level, and the geometry of the
// indicated level is drawn in wireframe.
//
// Multiple different levels can be visualized this way
// at once. Call hide_switch() or hide_all_switches() to
// undo this mode and restore the LODNode to its normal
// behavior.
////////////////////////////////////////////////////////////////////
void LODNode::
show_switch(int index) {
CDWriter cdata(_cycler);
do_show_switch(cdata, index, get_default_show_color(index));
mark_internal_bounds_stale();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::show_switch
// Access: Published
// Description: This is provided as a debugging aid. show_switch()
// will put the LODNode into a special mode where rather
// than computing and drawing the appropriate level of
// the LOD, a ring is drawn around the LODNode center
// indicating the switch distances from the camera for
// the indicated level, and the geometry of the
// indicated level is drawn in wireframe.
//
// Multiple different levels can be visualized this way
// at once. Call hide_switch() or hide_all_switches() to
// undo this mode and restore the LODNode to its normal
// behavior.
////////////////////////////////////////////////////////////////////
void LODNode::
show_switch(int index, const Colorf &color) {
CDWriter cdata(_cycler);
do_show_switch(cdata, index, color);
mark_internal_bounds_stale();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::hide_switch
// Access: Published
// Description: Disables a previous call to show_switch().
////////////////////////////////////////////////////////////////////
void LODNode::
hide_switch(int index) {
CDWriter cdata(_cycler);
do_hide_switch(cdata, index);
mark_internal_bounds_stale();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::show_all_switches
// Access: Published
// Description: Shows all levels in their default colors.
////////////////////////////////////////////////////////////////////
void LODNode::
show_all_switches() {
CDWriter cdata(_cycler);
for (int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
do_show_switch(cdata, i, get_default_show_color(i));
}
mark_internal_bounds_stale();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::hide_all_switches
// Access: Published
// Description: Hides all levels, restoring the LODNode to normal
// operation.
////////////////////////////////////////////////////////////////////
void LODNode::
hide_all_switches() {
CDWriter cdata(_cycler);
for (int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
do_hide_switch(cdata, i);
}
mark_internal_bounds_stale();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::compute_child
// Access: Protected
@ -255,27 +289,42 @@ compute_child(CullTraverser *trav, CullTraverserData &data) {
if (cdata->_got_force_switch) {
return cdata->_force_switch;
}
// Get a pointer to the camera node.
Camera *camera = trav->get_scene()->get_camera_node();
// Get the LOD center in camera space
// CPT(TransformState) rel_transform =
// trav->get_camera_transform()->invert_compose(data._net_transform);
// Get the LOD center in camera space. If the camera has a special
// LOD center defined, use that; otherwise, if it has a cull center,
// use that; otherwise, use the modelview transform (which is camera
// space).
CPT(TransformState) rel_transform;
// CPT(TransformState) rel_transform =
// trav->get_scene()->get_cull_center().get_net_transform()->
// invert_compose(data._net_transform);
NodePath lod_center = camera->get_lod_center();
if (!lod_center.is_empty()) {
rel_transform =
lod_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
} else {
NodePath cull_center = camera->get_cull_center();
if (!cull_center.is_empty()) {
rel_transform =
cull_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
} else {
rel_transform = data.get_modelview_transform(trav);
}
}
CPT(TransformState) rel_transform = data.get_modelview_transform(trav);
LPoint3f center = cdata->_center * rel_transform->get_mat();
// Determine which child to traverse
float dist = fabs(dot(center, LVector3f::forward()));
// Now measure the distance to the LOD center, and use that to
// determine which child to display.
float dist2 = center.dot(center);
for (int index = 0; index < (int)cdata->_switch_vector.size(); index++) {
if (cdata->_switch_vector[index].in_range(dist)) {
if (cdata->_switch_vector[index].in_range_2(dist2)) {
if (pgraph_cat.is_debug()) {
pgraph_cat.debug()
<< data._node_path << " at distance " << dist << ", selected child "
<< index << "\n";
<< data._node_path << " at distance " << sqrt(dist2)
<< ", selected child " << index << "\n";
}
return index;
@ -284,12 +333,194 @@ compute_child(CullTraverser *trav, CullTraverserData &data) {
if (pgraph_cat.is_debug()) {
pgraph_cat.debug()
<< data._node_path << " at distance " << dist << ", no children in range.\n";
<< data._node_path << " at distance " << sqrt(dist2)
<< ", no children in range.\n";
}
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::show_switches_cull_callback
// Access: Protected
// Description: A special version of cull_callback() that is to be
// invoked when the LODNode is in show_switch() mode.
// This just draws the rings and the wireframe geometry
// for the selected switches.
////////////////////////////////////////////////////////////////////
bool LODNode::
show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data) {
CDReader cdata(_cycler);
// Get a pointer to the camera node.
Camera *camera = trav->get_scene()->get_camera_node();
// Get the camera space transform. This bit is the same as the code
// in compute_child(), above.
CPT(TransformState) rel_transform;
NodePath lod_center = camera->get_lod_center();
if (!lod_center.is_empty()) {
rel_transform =
lod_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
} else {
NodePath cull_center = camera->get_cull_center();
if (!cull_center.is_empty()) {
rel_transform =
cull_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
} else {
rel_transform = data.get_modelview_transform(trav);
}
}
LPoint3f center = cdata->_center * rel_transform->get_mat();
float dist2 = center.dot(center);
// Now orient the disk(s) in camera space such that their origin is
// at center, and the (0, 0, 0) point in camera space is on the disk.
LMatrix4f mat;
look_at(mat, -center, LVector3f(0.0f, 0.0f, 1.0f));
mat.set_row(3, center);
CPT(TransformState) viz_transform = TransformState::make_mat(mat);
viz_transform = rel_transform->invert_compose(viz_transform);
viz_transform = data.get_net_transform(trav)->compose(viz_transform);
SwitchVector::const_iterator si;
for (si = cdata->_switch_vector.begin();
si != cdata->_switch_vector.end();
++si) {
const Switch &sw = (*si);
if (sw.is_shown()) {
PT(PandaNode) ring_viz = sw.get_ring_viz();
CullTraverserData next_data(data, ring_viz);
next_data._net_transform = viz_transform;
trav->traverse(next_data);
if (sw.in_range_2(dist2)) {
// This switch level is in range. Draw its children in the
// funny wireframe mode.
int index = (si - cdata->_switch_vector.begin());
if (index < get_num_children()) {
CullTraverserData next_data(data, get_child(index));
next_data._state = next_data._state->compose(sw.get_viz_model_state());
trav->traverse(next_data);
}
}
}
}
// Finally, draw the visible child(ren) in the appropriate state as
// well.
for (int index = 0; index < (int)cdata->_switch_vector.size(); index++) {
if (cdata->_switch_vector[index].in_range_2(dist2)) {
}
}
// Now return false indicating that we have already taken care of
// the traversal from here.
return false;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::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.
////////////////////////////////////////////////////////////////////
PT(BoundingVolume) LODNode::
compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
// First, get ourselves a fresh, empty bounding volume.
PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage, current_thread);
nassertr(bound != (BoundingVolume *)NULL, bound);
// If we have any visible rings, those count in the bounding volume.
if (is_any_shown()) {
// Now actually compute the bounding volume by putting it around all
// of our geoms' bounding volumes.
pvector<const BoundingVolume *> child_volumes;
pvector<PT(BoundingVolume) > pt_volumes;
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
SwitchVector::const_iterator si;
for (si = cdata->_switch_vector.begin();
si != cdata->_switch_vector.end();
++si) {
const Switch &sw = (*si);
if (sw.is_shown()) {
PT(BoundingVolume) sphere = new BoundingSphere(cdata->_center, sw.get_in());
child_volumes.push_back(sphere);
pt_volumes.push_back(sphere);
}
}
const BoundingVolume **child_begin = &child_volumes[0];
const BoundingVolume **child_end = child_begin + child_volumes.size();
bound->around(child_begin, child_end);
}
return bound;
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::do_show_switch
// Access: Private
// Description: The private implementation of show_switch().
////////////////////////////////////////////////////////////////////
void LODNode::
do_show_switch(LODNode::CData *cdata, int index, const Colorf &color) {
nassertv(index >= 0 && index < (int)cdata->_switch_vector.size());
if (!cdata->_switch_vector[index].is_shown()) {
++cdata->_num_shown;
}
cdata->_switch_vector[index].show(color);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::do_hide_switch
// Access: Private
// Description: The private implementation of hide_switch().
////////////////////////////////////////////////////////////////////
void LODNode::
do_hide_switch(LODNode::CData *cdata, int index) {
nassertv(index >= 0 && index < (int)cdata->_switch_vector.size());
if (cdata->_switch_vector[index].is_shown()) {
--cdata->_num_shown;
}
cdata->_switch_vector[index].hide();
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::get_default_show_color
// Access: Private, Static
// Description: Returns a default color appropriate for showing the
// indicated level.
////////////////////////////////////////////////////////////////////
const Colorf &LODNode::
get_default_show_color(int index) {
static Colorf default_colors[] = {
Colorf(1.0f, 0.0f, 0.0f, 0.7f),
Colorf(0.0f, 1.0f, 0.0f, 0.7f),
Colorf(0.0f, 0.0f, 1.0f, 0.7f),
Colorf(0.0f, 1.0f, 1.0f, 0.7f),
Colorf(1.0f, 0.0f, 1.0f, 0.7f),
Colorf(1.0f, 1.0f, 0.0f, 0.7f),
};
static const int num_default_colors = sizeof(default_colors) / sizeof(Colorf);
return default_colors[index % num_default_colors];
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::register_with_read_factory
// Access: Public, Static
@ -345,3 +576,214 @@ fillin(DatagramIterator &scan, BamReader *manager) {
PandaNode::fillin(scan, manager);
manager->read_cdata(scan, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::make_copy
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CycleData *LODNode::CData::
make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::check_limits
// Access: Public
// Description: Ensures that the _lowest and _highest members are set
// appropriately after a change to the set of switches.
////////////////////////////////////////////////////////////////////
void LODNode::CData::
check_limits() {
_lowest = 0;
_highest = 0;
for (size_t i = 1; i < _switch_vector.size(); ++i) {
if (_switch_vector[i].get_out() > _switch_vector[_lowest].get_out()) {
_lowest = i;
}
if (_switch_vector[i].get_in() < _switch_vector[_highest].get_in()) {
_highest = i;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void LODNode::CData::
write_datagram(BamWriter *manager, Datagram &dg) const {
_center.write_datagram(dg);
dg.add_uint16(_switch_vector.size());
SwitchVector::const_iterator si;
for (si = _switch_vector.begin();
si != _switch_vector.end();
++si) {
(*si).write_datagram(dg);
}
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::CData::fillin
// Access: Public, Virtual
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new LODNode.
////////////////////////////////////////////////////////////////////
void LODNode::CData::
fillin(DatagramIterator &scan, BamReader *manager) {
_center.read_datagram(scan);
_switch_vector.clear();
int num_switches = scan.get_uint16();
_switch_vector.reserve(num_switches);
for (int i = 0; i < num_switches; i++) {
Switch sw(0, 0);
sw.read_datagram(scan);
_switch_vector.push_back(sw);
}
}
////////////////////////////////////////////////////////////////////
// Function: LODNode::Switch::compute_ring_viz
// Access: Private
// Description: Computes a Geom suitable for rendering the ring
// associated with this switch.
////////////////////////////////////////////////////////////////////
void LODNode::Switch::
compute_ring_viz() {
static const int num_slices = 50;
static const int num_rings = 1;
static const float edge_ratio = 0.1; // ratio of edge height to diameter.
const GeomVertexFormat *format = GeomVertexFormat::get_v3n3cp();
PT(GeomVertexData) vdata = new GeomVertexData("LOD", format, Geom::UH_static);
// Fill up the vertex table with all of the vertices.
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
GeomVertexWriter normal(vdata, InternalName::get_normal());
GeomVertexWriter color(vdata, InternalName::get_color());
// First, the vertices for the flat ring.
int ri, si;
for (ri = 0; ri <= num_rings; ++ri) {
// r is in the range [0.0, 1.0].
float r = (float)ri / (float)num_rings;
// d is in the range [_out, _in].
float d = r * (_in - _out) + _out;
for (si = 0; si < num_slices; ++si) {
// s is in the range [0.0, 1.0).
float s = (float)si / (float)num_slices;
// t is in the range [0.0, 2pi).
float t = MathNumbers::pi_f * 2.0f * s;
float x = cosf(t);
float y = sinf(t);
vertex.add_data3f(x * d, y * d, 0.0f);
normal.add_data3f(0.0f, 0.0f, 1.0f);
color.add_data4f(_show_color);
}
}
// Next, the vertices for the inner and outer edges.
for (ri = 0; ri <= 1; ++ri) {
float r = (float)ri;
float d = r * (_in - _out) + _out;
// Invert the direction of Z on the outer ring, to invert the
// vertex winding order (and thereby invert the facing of the
// polygons). We want the outer ring to face inward, and the
// inner ring to face outward.
float sign = 1.0f - (ri * 2);
for (si = 0; si < num_slices; ++si) {
float s = (float)si / (float)num_slices;
float t = MathNumbers::pi_f * 2.0f * s;
float x = cosf(t);
float y = sinf(t);
vertex.add_data3f(x * d, y * d, 0.5f * edge_ratio * d * sign);
normal.add_data3f(x * sign, y * sign, 0.0f);
color.add_data4f(_show_color);
}
for (si = 0; si < num_slices; ++si) {
float s = (float)si / (float)num_slices;
float t = MathNumbers::pi_f * 2.0f * s;
float x = cosf(t);
float y = sinf(t);
vertex.add_data3f(x * d, y * d, -0.5f * edge_ratio * d * sign);
normal.add_data3f(x * sign, y * sign, 0.0f);
color.add_data4f(_show_color);
}
}
// Now create the triangle strips. One tristrip for each ring.
PT(GeomTristrips) strips = new GeomTristrips(Geom::UH_static);
for (ri = 0; ri < num_rings; ++ri) {
for (si = 0; si < num_slices; ++si) {
strips->add_vertex(ri * num_slices + si);
strips->add_vertex((ri + 1) * num_slices + si);
}
strips->add_vertex(ri * num_slices);
strips->add_vertex((ri + 1) * num_slices);
strips->close_primitive();
}
// And then one triangle strip for each of the inner and outer
// edges.
for (ri = 0; ri <= 1; ++ri) {
for (si = 0; si < num_slices; ++si) {
strips->add_vertex((num_rings + 1 + ri * 2) * num_slices + si);
strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices + si);
}
strips->add_vertex((num_rings + 1 + ri * 2) * num_slices);
strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices);
strips->close_primitive();
}
PT(Geom) ring_geom = new Geom(vdata);
ring_geom->add_primitive(strips);
PT(GeomNode) geom_node = new GeomNode("ring");
geom_node->add_geom(ring_geom);
// Get a material for two-sided lighting.
PT(Material) material = new Material();
material->set_twoside(true);
material = MaterialPool::get_material(material);
CPT(RenderState) viz_state = RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_none),
TextureAttrib::make_off(),
MaterialAttrib::make(material),
RenderState::get_max_priority());
if (_show_color[3] != 1.0f) {
viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
RenderState::get_max_priority());
}
geom_node->set_state(viz_state);
_ring_viz = geom_node.p();
// Also compute a RenderState for rendering the children in
// wireframe mode.
_viz_model_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
TextureAttrib::make_off(),
ColorAttrib::make_flat(_show_color),
TransparencyAttrib::make(TransparencyAttrib::M_none),
RenderState::get_max_priority());
}

View File

@ -22,6 +22,8 @@
#include "pandabase.h"
#include "pandaNode.h"
#include "luse.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : LODNode
@ -70,9 +72,26 @@ PUBLISHED:
INLINE void set_center(const LPoint3f &center);
INLINE const LPoint3f &get_center() const;
void show_switch(int index);
void show_switch(int index, const Colorf &color);
void hide_switch(int index);
void show_all_switches();
void hide_all_switches();
INLINE bool is_any_shown() const;
protected:
int compute_child(CullTraverser *trav, CullTraverserData &data);
bool show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data);
virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
private:
class CData;
void do_show_switch(CData *cdata, int index, const Colorf &color);
void do_hide_switch(CData *cdata, int index);
static const Colorf &get_default_show_color(int index);
protected:
class Switch {
public:
@ -82,18 +101,34 @@ protected:
INLINE void set_range(float in, float out);
INLINE bool in_range(float dist) const;
INLINE bool in_range_2(float dist2) const;
INLINE void rescale(float factor);
INLINE bool is_shown() const;
INLINE void show(const Colorf &color);
INLINE void hide();
INLINE PandaNode *get_ring_viz() const;
INLINE const RenderState *get_viz_model_state() const;
INLINE void write_datagram(Datagram &destination) const;
INLINE void read_datagram(DatagramIterator &source);
private:
void compute_ring_viz();
private:
float _in;
float _out;
bool _shown;
Colorf _show_color;
PT(PandaNode) _ring_viz;
CPT(RenderState) _viz_model_state;
};
typedef pvector<Switch> SwitchVector;
private:
class EXPCL_PANDA CData : public CycleData {
public:
INLINE CData();
@ -114,11 +149,14 @@ protected:
bool _got_force_switch;
int _force_switch;
int _num_shown;
};
PipelineCycler<CData> _cycler;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageReader<CData> CDStageReader;
typedef CycleDataStageWriter<CData> CDStageWriter;
public:
static void register_with_read_factory();