pgraph nodepath fixes, pstats, invalid transforms

This commit is contained in:
David Rose 2002-03-07 19:39:04 +00:00
parent eda5a0383a
commit 33c59b176b
10 changed files with 319 additions and 73 deletions

View File

@ -24,6 +24,13 @@
#include "cullResult.h"
#include "qpcullTraverser.h"
#include "clockObject.h"
#include "pStatTimer.h"
#include "pStatClient.h"
#ifndef CPPPARSER
PStatCollector GraphicsEngine::_cull_pcollector("Cull");
PStatCollector GraphicsEngine::_draw_pcollector("Draw");
#endif // CPPPARSER
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::Constructor
@ -89,6 +96,7 @@ render_frame() {
// **** This doesn't belong here; it really belongs in the Pipeline,
// but here it is for now.
ClockObject::get_global_clock()->tick();
PStatClient::main_tick();
}
////////////////////////////////////////////////////////////////////
@ -199,6 +207,9 @@ cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr) {
void GraphicsEngine::
do_cull(CullHandler *cull_handler, const qpNodePath &camera,
GraphicsStateGuardian *gsg) {
// Statistics
PStatTimer timer(_cull_pcollector);
if (camera.is_empty()) {
// No camera, no draw.
return;
@ -227,12 +238,12 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera,
qpCullTraverser trav;
trav.set_cull_handler(cull_handler);
// We will need both the camera transform (the net transform from
// the scene to the camera) and the world transform (the camera
// transform inverse, or the net transform from the camera to the
// scene).
CPT(TransformState) camera_transform = scene.get_transform(camera);
CPT(TransformState) world_transform = camera.get_transform(scene);
// We will need both the camera transform (the net transform to the
// camera from the scene) and the world transform (the camera
// transform inverse, or the net transform to the scene from the
// camera).
CPT(TransformState) camera_transform = camera.get_transform(scene);
CPT(TransformState) world_transform = scene.get_transform(camera);
// The render transform is the same as the world transform, except
// it is converted into the GSG's internal coordinate system. This
@ -247,7 +258,7 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera,
render_transform = cs_transform->compose(render_transform);
}
trav.set_camera_transform(scene.get_transform(camera));
trav.set_camera_transform(camera_transform);
trav.set_render_transform(render_transform);
if (qpview_frustum_cull) {
@ -281,6 +292,9 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera,
void GraphicsEngine::
do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg,
DisplayRegion *dr) {
// Statistics
PStatTimer timer(_draw_pcollector);
if (set_gsg_lens(gsg, dr)) {
DisplayRegionStack old_dr = gsg->push_display_region(dr);
gsg->prepare_display_region();

View File

@ -23,6 +23,7 @@
#include "graphicsWindow.h"
#include "pointerTo.h"
#include "pset.h"
#include "pStatCollector.h"
class Pipeline;
class DisplayRegion;
@ -68,6 +69,9 @@ private:
typedef pset<PT(GraphicsWindow)> Windows;
Windows _windows;
static PStatCollector _cull_pcollector;
static PStatCollector _draw_pcollector;
};
#include "graphicsEngine.I"

View File

@ -383,6 +383,9 @@ add_child(PandaNode *child_node, int sort) {
}
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
force_bound_stale();
}
////////////////////////////////////////////////////////////////////
@ -430,6 +433,9 @@ remove_child(int n) {
}
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
force_bound_stale();
}
////////////////////////////////////////////////////////////////////
@ -476,6 +482,9 @@ remove_child(PandaNode *child_node) {
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
force_bound_stale();
CDWriter cdata(_cycler);
// Now, look for and remove the child node from our down list.
@ -529,6 +538,9 @@ remove_all_children() {
child_node->fix_chain_lengths();
}
// Mark the bounding volumes stale.
force_bound_stale();
}
////////////////////////////////////////////////////////////////////
@ -732,6 +744,9 @@ detach(qpNodePathComponent *child) {
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
parent_node->force_bound_stale();
// Now look for the child and break the actual connection.
// First, look for and remove the parent node from the child's up
@ -785,6 +800,9 @@ reparent(qpNodePathComponent *new_parent, qpNodePathComponent *child, int sort)
cdata_child->_chains.insert(child);
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
parent_node->force_bound_stale();
}
////////////////////////////////////////////////////////////////////

View File

@ -706,18 +706,6 @@ set_pos(const qpNodePath &other, float x, float y, float z) {
set_pos(other, LPoint3f(x, y, z));
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::get_pos
// Access: Published
// Description: Returns the relative position of the referenced node
// as seen from the other node.
////////////////////////////////////////////////////////////////////
INLINE LPoint3f qpNodePath::
get_pos(const qpNodePath &other) const {
LMatrix4f mat = get_mat(other);
return mat.get_row3(3);
}
INLINE float qpNodePath::
get_x(const qpNodePath &other) const {
return get_pos(other)[0];

View File

@ -322,17 +322,17 @@ set_state(const qpNodePath &other, const RenderState *state) const {
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::get_transform
// Access: Published
// Description: Returns the relative transform from this node to the
// other node; i.e. the transformation of the other node
// as seen from this node.
// Description: Returns the relative transform to this node from the
// other node; i.e. the transformation of this node
// as seen from the other node.
////////////////////////////////////////////////////////////////////
CPT(TransformState) qpNodePath::
get_transform(const qpNodePath &other) const {
if (is_empty()) {
return other.get_net_transform();
}
if (other.is_empty()) {
return get_net_transform()->invert_compose(TransformState::make_identity());
return get_net_transform();
}
if (is_empty()) {
return other.get_net_transform()->invert_compose(TransformState::make_identity());
}
nassertr(verify_complete(), TransformState::make_identity());
@ -343,7 +343,7 @@ get_transform(const qpNodePath &other) const {
CPT(TransformState) a_transform = r_get_partial_transform(_head, a_count);
CPT(TransformState) b_transform = r_get_partial_transform(other._head, b_count);
return a_transform->invert_compose(b_transform);
return b_transform->invert_compose(a_transform);
}
////////////////////////////////////////////////////////////////////
@ -351,8 +351,8 @@ get_transform(const qpNodePath &other) const {
// Access: Published
// Description: Sets the transform object on this node, relative to
// the other node. This computes a new transform object
// that has the indicated value when seen relative to
// the other node.
// that will have the indicated value when seen from the
// other node.
////////////////////////////////////////////////////////////////////
void qpNodePath::
set_transform(const qpNodePath &other, const TransformState *transform) const {
@ -361,7 +361,7 @@ set_transform(const qpNodePath &other, const TransformState *transform) const {
// First, we perform a wrt to the parent, to get the conversion.
qpNodePath parent = get_parent();
CPT(TransformState) rel_trans = parent.get_transform(other);
CPT(TransformState) rel_trans = other.get_transform(parent);
CPT(TransformState) new_trans = rel_trans->compose(transform);
set_transform(new_trans);
@ -491,11 +491,11 @@ get_hpr(float roll) const {
// leaving translation and rotation untouched.
////////////////////////////////////////////////////////////////////
void qpNodePath::
set_scale(const LVecBase3f &sv3) {
set_scale(const LVecBase3f &scale) {
nassertv(!is_empty());
CPT(TransformState) transform = get_transform();
nassertv(transform->has_components());
set_transform(transform->set_scale(sv3));
set_transform(transform->set_scale(scale));
}
void qpNodePath::
@ -794,6 +794,18 @@ set_z(const qpNodePath &other, float z) {
set_pos(other, pos);
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::get_pos
// Access: Published
// Description: Returns the relative position of the referenced node
// as seen from the other node.
////////////////////////////////////////////////////////////////////
LPoint3f qpNodePath::
get_pos(const qpNodePath &other) const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
return get_transform(other)->get_pos();
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::set_hpr
// Access: Published
@ -2254,7 +2266,7 @@ r_output(ostream &out, qpNodePathComponent *comp) const {
} else {
out << "+" << node->get_type();
}
out << "[" << comp->get_length() << "]";
// out << "[" << comp->get_length() << "]";
}
////////////////////////////////////////////////////////////////////

View File

@ -168,7 +168,7 @@ PUBLISHED:
INLINE void set_scale(float scale);
INLINE void set_scale(float sx, float sy, float sz);
void set_scale(const LVecBase3f &sv3);
void set_scale(const LVecBase3f &scale);
void set_sx(float sx);
void set_sy(float sy);
void set_sz(float sz);
@ -232,7 +232,7 @@ PUBLISHED:
void set_x(const qpNodePath &other, float x);
void set_y(const qpNodePath &other, float y);
void set_z(const qpNodePath &other, float z);
INLINE LPoint3f get_pos(const qpNodePath &other) const;
LPoint3f get_pos(const qpNodePath &other) const;
INLINE float get_x(const qpNodePath &other) const;
INLINE float get_y(const qpNodePath &other) const;
INLINE float get_z(const qpNodePath &other) const;

View File

@ -92,6 +92,18 @@ is_identity() const {
return ((_flags & F_is_identity) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::is_invalid
// Access: Published
// Description: Returns true if the transform represents an invalid
// matrix, for instance the result of inverting a
// singular matrix, or false if the transform is valid.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
is_invalid() const {
return ((_flags & F_is_invalid) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::is_singular
// Access: Published
@ -119,8 +131,10 @@ is_singular() const {
// that was constructed with a 4x4 may return true here
// if the matrix is a simple affine matrix with no skew.
//
// If this returns true, you may safely call get_pos(),
// etc., to retrieve the components.
// If this returns true, you may safely call get_hpr()
// and get_scale() to retrieve the components. (You
// may always safely call get_pos() whether this returns
// true or false.)
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
has_components() const {
@ -128,16 +142,32 @@ has_components() const {
return ((_flags & F_has_components) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::components_given
// Access: Published
// Description: Returns true if the transform was specified
// componentwise, or false if it was specified with a
// general 4x4 matrix. If this is true, the components
// returned by get_pos(), get_hpr(), and get_scale()
// will be exactly those that were set; otherwise, these
// functions will return computed values.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
components_given() const {
return ((_flags & F_components_given) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::has_pos
// Access: Published
// Description: Returns true if the transform's pos component can be
// extracted out separately. This is generally always
// true.
// true, unless the transform is invalid
// (i.e. is_invalid() returns true).
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
has_pos() const {
return true;
return !is_invalid();
}
////////////////////////////////////////////////////////////////////
@ -165,6 +195,18 @@ has_scale() const {
return has_components();
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::has_mat
// Access: Published
// Description: Returns true if the transform can be described as a
// matrix. This is generally always true, unless
// is_invalid() is true.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
has_mat() const {
return !is_invalid();
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::get_pos
// Access: Published
@ -174,6 +216,7 @@ has_scale() const {
INLINE const LVecBase3f &TransformState::
get_pos() const {
check_components();
nassertr(has_pos(), _pos);
return _pos;
}
@ -212,6 +255,7 @@ get_scale() const {
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &TransformState::
get_mat() const {
nassertr(has_mat(), LMatrix4f::ident_mat());
check_mat();
return _mat;
}

View File

@ -154,12 +154,22 @@ TransformState::
////////////////////////////////////////////////////////////////////
bool TransformState::
operator < (const TransformState &other) const {
bool components_given = (_flags & F_components_given) != 0;
bool other_components_given = (other._flags & F_components_given) != 0;
if (components_given != other_components_given) {
return components_given < other_components_given;
static const int significant_flags =
(F_is_invalid | F_is_identity | F_components_given);
int flags = (_flags & significant_flags);
int other_flags = (other._flags & significant_flags);
if (flags != other_flags) {
return flags < other_flags;
}
if (components_given) {
if ((_flags & (F_is_invalid | F_is_identity)) != 0) {
// All invalid transforms are equivalent to each other, and all
// identity transforms are equivalent to each other.
return 0;
}
if ((_flags & F_components_given) != 0) {
// If the transform was specified componentwise, compare them
// componentwise.
int c = _pos.compare_to(other._pos);
@ -195,6 +205,19 @@ make_identity() {
return _identity_state;
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::make_invalid
// Access: Published, Static
// Description: Constructs an invalid transform; for instance, the
// result of inverting a singular matrix.
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
make_invalid() {
TransformState *state = new TransformState;
state->_flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
return return_new(state);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::make_pos_hpr_scale
// Access: Published, Static
@ -211,12 +234,12 @@ make_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
return make_identity();
}
TransformState *attrib = new TransformState;
attrib->_pos = pos;
attrib->_hpr = hpr;
attrib->_scale = scale;
attrib->_flags = F_components_given | F_components_known | F_has_components;
return return_new(attrib);
TransformState *state = new TransformState;
state->_pos = pos;
state->_hpr = hpr;
state->_scale = scale;
state->_flags = F_components_given | F_components_known | F_has_components;
return return_new(state);
}
////////////////////////////////////////////////////////////////////
@ -232,10 +255,10 @@ make_mat(const LMatrix4f &mat) {
return make_identity();
}
TransformState *attrib = new TransformState;
attrib->_mat = mat;
attrib->_flags = F_mat_known;
return return_new(attrib);
TransformState *state = new TransformState;
state->_mat = mat;
state->_flags = F_mat_known;
return return_new(state);
}
////////////////////////////////////////////////////////////////////
@ -283,7 +306,7 @@ set_hpr(const LVecBase3f &hpr) const {
CPT(TransformState) TransformState::
set_scale(const LVecBase3f &scale) const {
nassertr(has_components(), this);
return make_pos_hpr_scale(get_pos(), get_scale(), get_hpr());
return make_pos_hpr_scale(get_pos(), get_hpr(), scale);
}
////////////////////////////////////////////////////////////////////
@ -313,6 +336,14 @@ compose(const TransformState *other) const {
return this;
}
// If either transform is invalid, the result is invalid.
if (is_invalid()) {
return this;
}
if (other->is_invalid()) {
return other;
}
if (other == this) {
// compose(this) has to be handled as a special case, because the
// caching problem is so different.
@ -389,6 +420,14 @@ invert_compose(const TransformState *other) const {
// Unlike compose(), the case of other->is_identity() is not quite as
// trivial for invert_compose().
// If either transform is invalid, the result is invalid.
if (is_invalid()) {
return this;
}
if (other->is_invalid()) {
return other;
}
if (other == this) {
// a->invert_compose(a) always produces identity.
return make_identity();
@ -432,10 +471,18 @@ invert_compose(const TransformState *other) const {
void TransformState::
output(ostream &out) const {
out << "T:";
if (is_identity()) {
if (is_invalid()) {
out << "(invalid)";
} else if (is_identity()) {
out << "(identity)";
} else if (has_components()) {
if (components_given()) {
out << "c";
} else {
out << "m";
}
char lead = '(';
if (!get_pos().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) {
out << lead << "pos " << get_pos();
@ -477,11 +524,11 @@ write(ostream &out, int indent_level) const {
// Description: This function is used to share a common TransformState
// pointer for all equivalent TransformState objects.
//
// See the similar logic in RenderAttrib. The idea is
// to create a new TransformState object and pass it
// See the similar logic in RenderState. The idea is to
// create a new TransformState object and pass it
// through this function, which will share the pointer
// with a previously-created TransformState object if it is
// equivalent.
// with a previously-created TransformState object if it
// is equivalent.
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
return_new(TransformState *state) {
@ -517,6 +564,12 @@ return_new(TransformState *state) {
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
do_compose(const TransformState *other) const {
nassertr((_flags & F_is_invalid) == 0, this);
nassertr((other->_flags & F_is_invalid) == 0, other);
// We should do this operation componentwise if both transforms were
// given componentwise.
LMatrix4f new_mat = other->get_mat() * get_mat();
return make_mat(new_mat);
}
@ -528,11 +581,20 @@ do_compose(const TransformState *other) const {
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
do_invert_compose(const TransformState *other) const {
// Perhaps we should cache the inverse matrix operation separately,
// as a further optimization.
nassertr((_flags & F_is_invalid) == 0, this);
nassertr((other->_flags & F_is_invalid) == 0, other);
// We should do this operation componentwise if both transforms were
// given componentwise.
// Perhaps we should cache the result of the inverse matrix
// operation separately, as a further optimization.
LMatrix4f new_mat;
new_mat.invert_from(get_mat());
bool invertible = new_mat.invert_from(get_mat());
if (!invertible) {
return make_invalid();
}
new_mat = other->get_mat() * new_mat;
return make_mat(new_mat);
}
@ -545,6 +607,7 @@ do_invert_compose(const TransformState *other) const {
////////////////////////////////////////////////////////////////////
void TransformState::
calc_singular() {
nassertv((_flags & F_is_invalid) == 0);
bool singular = false;
if (has_components()) {
@ -569,6 +632,7 @@ calc_singular() {
////////////////////////////////////////////////////////////////////
void TransformState::
calc_components() {
nassertv((_flags & F_is_invalid) == 0);
if ((_flags & F_is_identity) != 0) {
_scale.set(1.0f, 1.0f, 1.0f);
_hpr.set(0.0f, 0.0f, 0.0f);
@ -601,6 +665,7 @@ calc_components() {
////////////////////////////////////////////////////////////////////
void TransformState::
calc_mat() {
nassertv((_flags & F_is_invalid) == 0);
if ((_flags & F_is_identity) != 0) {
_mat = LMatrix4f::ident_mat();
@ -639,6 +704,11 @@ write_datagram(BamWriter *manager, Datagram &dg) {
int flags = F_is_identity | F_singular_known;
dg.add_uint16(flags);
} else if ((_flags & F_is_invalid) != 0) {
// Invalid, nothing much to that either.
int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
dg.add_uint16(flags);
} else if ((_flags & F_components_given) != 0) {
// A component-based transform.
int flags = F_components_given | F_components_known | F_has_components;

View File

@ -66,6 +66,7 @@ public:
PUBLISHED:
static CPT(TransformState) make_identity();
INLINE static CPT(TransformState) make_invalid();
INLINE static CPT(TransformState) make_pos(const LVecBase3f &pos);
INLINE static CPT(TransformState) make_hpr(const LVecBase3f &hpr);
INLINE static CPT(TransformState) make_pos_hpr(const LVecBase3f &pos,
@ -78,11 +79,14 @@ PUBLISHED:
static CPT(TransformState) make_mat(const LMatrix4f &mat);
INLINE bool is_identity() const;
INLINE bool is_invalid() const;
INLINE bool is_singular() const;
INLINE bool has_components() const;
INLINE bool components_given() const;
INLINE bool has_pos() const;
INLINE bool has_hpr() const;
INLINE bool has_scale() const;
INLINE bool has_mat() const;
INLINE const LVecBase3f &get_pos() const;
INLINE const LVecBase3f &get_hpr() const;
INLINE const LVecBase3f &get_scale() const;
@ -149,6 +153,7 @@ private:
F_components_known = 0x0010,
F_has_components = 0x0020,
F_mat_known = 0x0040,
F_is_invalid = 0x0080,
};
LVecBase3f _pos, _hpr, _scale;
LMatrix4f _mat;

View File

@ -35,6 +35,10 @@
#include "dSearchPath.h"
#include "loader.h"
#include "auto_bind.h"
#include "pStatClient.h"
#include "notify.h"
#include "qpnodePath.h"
#include "cullBinManager.h"
// These are in support of legacy data graph operations.
#include "namedNode.h"
@ -66,6 +70,12 @@ bool run_flag = true;
static double start_time = 0.0;
static int start_frame_count = 0;
// A priority number high enough to override any model file settings.
static const int override_priority = 100;
// This is the main scene graph.
qpNodePath render;
void
report_frame_rate() {
double now = ClockObject::get_global_clock()->get_frame_time();
@ -95,15 +105,15 @@ make_pipe() {
// load-display Configrc variable.
GraphicsPipe::resolve_modules();
cerr << "Known pipe types:" << endl;
GraphicsPipe::get_factory().write_types(cerr, 2);
nout << "Known pipe types:" << endl;
GraphicsPipe::get_factory().write_types(nout, 2);
PT(GraphicsPipe) pipe;
pipe = GraphicsPipe::get_factory().
make_instance(InteractiveGraphicsPipe::get_class_type());
if (pipe == (GraphicsPipe*)0L) {
cerr << "No interactive pipe is available! Check your Configrc!\n";
nout << "No interactive pipe is available! Check your Configrc!\n";
exit(1);
}
@ -204,7 +214,7 @@ get_models(PandaNode *parent, int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
Filename filename = argv[i];
cerr << "Loading " << filename << "\n";
nout << "Loading " << filename << "\n";
// First, we always try to resolve a filename from the current
// directory. This means a local filename will always be found
@ -213,10 +223,10 @@ get_models(PandaNode *parent, int argc, char *argv[]) {
PT(PandaNode) node = loader.qpload_sync(filename);
if (node == (PandaNode *)NULL) {
cerr << "Unable to load " << filename << "\n";
nout << "Unable to load " << filename << "\n";
} else {
node->ls(cerr, 0);
node->ls(nout, 0);
parent->add_child(node);
}
}
@ -259,9 +269,81 @@ event_esc(CPT_Event) {
void
event_f(CPT_Event) {
// 'f' : report frame rate.
report_frame_rate();
}
void
event_t(CPT_Event) {
// 't' : toggle texture.
static bool texture_off = false;
texture_off = !texture_off;
if (texture_off) {
nout << "Disabling texturing.\n";
render.set_texture_off(override_priority);
} else {
nout << "Enabling texturing.\n";
render.clear_texture();
}
}
void
event_w(CPT_Event) {
// 'w' : toggle wireframe.
static bool wireframe = false;
wireframe = !wireframe;
if (wireframe) {
nout << "Setting wireframe mode.\n";
render.set_render_mode_wireframe(override_priority);
} else {
nout << "Clearing wireframe mode.\n";
render.clear_render_mode();
}
}
void
event_s(CPT_Event) {
// 's' : toggle state sorting by putting everything into an 'unsorted' bin.
static bool sorting_off = false;
sorting_off = !sorting_off;
if (sorting_off) {
nout << "Disabling state sorting.\n";
render.set_bin("unsorted", 0, override_priority);
} else {
nout << "Enabling state sorting.\n";
render.clear_bin();
}
}
void
event_S(CPT_Event) {
// shift 'S' : active PStats.
#ifdef DO_PSTATS
nout << "Connecting to stats host" << endl;
PStatClient::connect();
#else
nout << "Stats host not supported." << endl;
#endif
}
void
event_A(CPT_Event) {
// shift 'A' : deactive PStats.
#ifdef DO_PSTATS
if (PStatClient::is_connected()) {
nout << "Disconnecting from stats host" << endl;
PStatClient::disconnect();
} else {
nout << "Stats host is already disconnected." << endl;
}
#else
nout << "Stats host not supported." << endl;
#endif
}
int
main(int argc, char *argv[]) {
// First, we need a GraphicsPipe, before we can open a window.
@ -275,10 +357,14 @@ main(int argc, char *argv[]) {
PT(qpCamera) camera = make_camera(window);
// Now we just need to make a scene graph for the camera to render.
PT(PandaNode) render = new PandaNode("render");
render->add_child(camera);
render = qpNodePath(new PandaNode("render"));
render.attach_new_node(camera);
camera->set_scene(qpNodePath(render));
// We will take advantage of this bin if the user toggles state
// sorting, above, in event_s().
CullBinManager::get_global_ptr()->add_bin("unsorted", CullBinManager::BT_unsorted, 0);
// Set up a data graph for tracking user input. For now, this uses
// the old-style graph interface.
PT(NamedNode) data_root = new NamedNode("data_root");
@ -290,16 +376,21 @@ main(int argc, char *argv[]) {
event_handler.add_hook("escape", event_esc);
event_handler.add_hook("q", event_esc);
event_handler.add_hook("f", event_f);
event_handler.add_hook("t", event_t);
event_handler.add_hook("w", event_w);
event_handler.add_hook("s", event_s);
event_handler.add_hook("shift-s", event_S);
event_handler.add_hook("shift-a", event_A);
// Put something in the scene graph to look at.
get_models(render, argc, argv);
get_models(render.node(), argc, argv);
// If we happened to load up both a character file and its matching
// animation file, attempt to bind them together now and start the
// animations looping.
AnimControlCollection anim_controls;
auto_bind(render, anim_controls, ~0);
auto_bind(render.node(), anim_controls, ~0);
anim_controls.loop_all(true);