diff --git a/direct/src/gui/DirectGuiBase.py b/direct/src/gui/DirectGuiBase.py index 539c738de6..17943c44ad 100644 --- a/direct/src/gui/DirectGuiBase.py +++ b/direct/src/gui/DirectGuiBase.py @@ -697,7 +697,7 @@ class DirectGuiWidget(DirectGuiBase, NodePath): DirectGuiBase.__init__(self) NodePath.__init__(self) # Create a button - self.guiItem = self['pgFunc']() + self.guiItem = self['pgFunc']('') # Override automatically generated guiId if self['guiId']: self.guiItem.setId(self['guiId']) diff --git a/direct/src/gui/OnscreenText.py b/direct/src/gui/OnscreenText.py index ccea27f3ec..77a56a7a34 100644 --- a/direct/src/gui/OnscreenText.py +++ b/direct/src/gui/OnscreenText.py @@ -91,7 +91,7 @@ class OnscreenText(PandaObject, NodePath): """ # make a text node - textNode = TextNode() + textNode = TextNode('') self.textNode = textNode # We ARE a node path. Initially, we're an empty node path. diff --git a/panda/src/pgraph/qpnodePath.cxx b/panda/src/pgraph/qpnodePath.cxx index ac5758c2c7..8e07f08e70 100644 --- a/panda/src/pgraph/qpnodePath.cxx +++ b/panda/src/pgraph/qpnodePath.cxx @@ -33,6 +33,8 @@ #include "look_at.h" #include "compose_matrix.h" #include "plist.h" +#include "boundingSphere.h" +#include "qpgeomNode.h" // stack seems to overflow on Intel C++ at 7000. If we need more than // 7000, need to increase stack size. @@ -2219,11 +2221,267 @@ verify_complete() const { return length == 0 && node->get_num_parents() == 0; } +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::prepare_scene +// Access: Published +// Description: Walks through the scene graph beginning at the bottom +// 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. +// +// If force_retained_mode is true, retained mode is set +// on the geometry encountered, regardless of the +// setting of the retained-mode Config variable. +// Otherwise, retained mode is set only if the +// retained-mode Config variable is true. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode) { + nassertv_always(!is_empty()); + + // **** do something. +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::show_bounds +// Access: Published +// Description: Causes the bounding volume of the bottom node and all +// of its descendants (that is, the bounding volume +// associated with the the bottom arc) to be rendered, +// if possible. The rendering method is less than +// optimal; this is intended primarily for debugging. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +show_bounds() { + nassertv_always(!is_empty()); + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::hide_bounds +// Access: Published +// Description: Stops the rendering of the bounding volume begun with +// show_bounds(). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +hide_bounds() { + nassertv_always(!is_empty()); + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_bounds +// Access: Published +// Description: Returns a newly-allocated bounding volume containing +// the bottom node and all of its descendants. This is +// the bounding volume on the bottom arc, converted to +// the local coordinate space of the node. +//////////////////////////////////////////////////////////////////// +PT(BoundingVolume) qpNodePath:: +get_bounds() const { + nassertr(!is_empty(), new BoundingSphere); + + PandaNode *this_node = node(); + PT(BoundingVolume) bv = this_node->get_bound().make_copy(); + if (bv->is_of_type(GeometricBoundingVolume::get_class_type()) && + !this_node->get_transform()->is_identity()) { + + // The bounding volume has already been transformed by the node's + // matrix. We'd rather return a bounding volume in the node's + // space, so we have to untransform it now. Ick. + GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bv); + const LMatrix4f &mat = get_parent().get_mat(*this); + gbv->xform(mat); + } + + return bv; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::write_bounds +// Access: Published +// Description: Writes a description of the bounding volume +// containing the bottom node and all of its descendants +// to the indicated output stream. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +write_bounds(ostream &out) const { + get_bounds()->write(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::calc_tight_bounds +// Access: Published +// Description: Calculates the minimum and maximum vertices of all +// Geoms at this qpNodePath's bottom node and below. This +// is a tight bounding box; it will generally be tighter +// than the bounding volume returned by get_bounds() +// (but it is more expensive to compute). +// +// The return value is true if any points are within the +// bounding volume, or false if none are. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) { + min_point.set(0.0f, 0.0f, 0.0f); + max_point.set(0.0f, 0.0f, 0.0f); + nassertr_always(!is_empty(), false); + + bool found_any = false; + r_calc_tight_bounds(node(), min_point, max_point, found_any, + TransformState::make_identity()); + + return found_any; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::flatten_light +// Access: Published +// Description: Lightly flattens out the hierarchy below this node by +// applying transforms, colors, and texture matrices +// from the arcs onto the vertices, but does not remove +// any nodes. +// +// This can result in improved rendering performance +// because there will be fewer transforms in the +// resulting scene graph, but the number of nodes will +// remain the same. +// +// Particularly, any qpNodePaths that reference nodes +// within this hierarchy will not be damaged. However, +// since this operation will remove transforms from the +// scene graph, it may be dangerous to apply to arcs +// where you expect to dynamically modify the transform, +// or where you expect the geometry to remain in a +// particular local coordinate system. +// +// The return value is always 0, since flatten_light +// does not remove any arcs. +//////////////////////////////////////////////////////////////////// +int qpNodePath:: +flatten_light() { + nassertr(!is_empty(), 0); + /* + SceneGraphReducer gr(_graph_type); + gr.apply_transitions(arc()); + */ + + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::flatten_medium +// Access: Published +// Description: A more thorough flattening than flatten_light(), this +// first applies all the transforms, colors, and texture +// matrices from the arcs onto the vertices, and then +// removes unneeded grouping nodes--nodes that have +// exactly one child, for instance, but have no special +// properties in themselves. +// +// This results in improved perforamance over +// flatten_light() because the number of nodes in the +// scene graph is reduced. +// +// If max_children is specified, it represents the +// maximum number of children a node is allowed to have +// and still be flattened. Normally, this is 1; we +// don't typically want to flatten a node that has +// multiple children. However, sometimes this may be +// desirable; set this parameter to control the limit. +// If this is set to -1, there is no limit. +// +// The return value is the number of arcs removed. +//////////////////////////////////////////////////////////////////// +int qpNodePath:: +flatten_medium(int max_children) { + nassertr(!is_empty(), 0); + /* + SceneGraphReducer gr(_graph_type); + gr.set_max_children(max_children); + gr.apply_transitions(arc()); + int num_removed = gr.flatten(node(), false); + + return num_removed; + */ + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::flatten_strong +// Access: Published +// Description: The strongest possible flattening. This first +// applies all of the transforms to the vertices, as in +// flatten_medium(), but then it will combine sibling +// nodes together when possible, in addition to removing +// unnecessary parent-child nodes. This can result in +// substantially fewer nodes, but any nicely-grouped +// hierachical bounding volumes may be lost. +// +// It is generally a good idea to apply this kind of +// flattening only to nodes that will be culled largely +// as a single unit, like a car. Applying this to an +// entire scene may result in overall poorer performance +// because of less-effective culling. +//////////////////////////////////////////////////////////////////// +int qpNodePath:: +flatten_strong(int max_children) { + nassertr(!is_empty(), 0); + /* + SceneGraphReducer gr(_graph_type); + gr.set_max_children(max_children); + gr.apply_transitions(arc()); + int num_removed = gr.flatten(node(), true); + + return num_removed; + */ + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::write_bam_file +// Access: Published +// Description: Writes the contents of this node and below out to a +// bam file with the indicated filename. This file may +// then be read in again, as is, at some later point. +// Returns true if successful, false on some kind of +// error. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +write_bam_file(const string &filename) const { + nassertr(!is_empty(), false); + + /* + BamFile bam_file; + + bool okflag = false; + + if (bam_file.open_write(filename)) { + if (bam_file.write_object(node())) { + okflag = true; + } + bam_file.close(); + } + return okflag; + */ + + // At the moment, we can't do this because BamFile is defined in + // loader and loader depends on pgraph. + nassertr(false, false); + return false; +} + //////////////////////////////////////////////////////////////////// // Function: qpNodePath::uncollapse_head // Access: Private // Description: Quietly and transparently uncollapses the _head -// pointer if it needs it. +// pointer if it needs it. This can happen only when +// two distinct NodePaths are collapsed into the same +// path after the removal of an instance somewhere +// higher up the chain. //////////////////////////////////////////////////////////////////// void qpNodePath:: uncollapse_head() const { @@ -2490,3 +2748,55 @@ r_adjust_all_priorities(PandaNode *node, int adjustment) { r_adjust_all_priorities(cr.get_child(i), adjustment); } } + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::r_calc_tight_bounds +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +r_calc_tight_bounds(PandaNode *node, LPoint3f &min_point, LPoint3f &max_point, + bool &found_any, const TransformState *transform) { + CPT(TransformState) next_transform = + transform->compose(node->get_transform()); + if (node->is_geom_node()) { + qpGeomNode *gnode; + DCAST_INTO_V(gnode, node); + + const LMatrix4f &mat = next_transform->get_mat(); + int num_geoms = gnode->get_num_geoms(); + for (int i = 0; i < num_geoms; i++) { + Geom *geom = gnode->get_geom(i); + Geom::VertexIterator vi = geom->make_vertex_iterator(); + int num_prims = geom->get_num_prims(); + + for (int p = 0; p < num_prims; p++) { + int length = geom->get_length(p); + for (int v = 0; v < length; v++) { + Vertexf vertex = geom->get_next_vertex(vi) * mat; + + if (found_any) { + min_point.set(min(min_point[0], vertex[0]), + min(min_point[1], vertex[1]), + min(min_point[2], vertex[2])); + max_point.set(max(max_point[0], vertex[0]), + max(max_point[1], vertex[1]), + max(max_point[2], vertex[2])); + } else { + min_point = vertex; + max_point = vertex; + found_any = true; + } + } + } + } + } + + // Now consider children. + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + r_calc_tight_bounds(cr.get_child(i), min_point, max_point, + found_any, next_transform); + } +} diff --git a/panda/src/pgraph/qpnodePath.h b/panda/src/pgraph/qpnodePath.h index a57d7484f7..8872429d89 100644 --- a/panda/src/pgraph/qpnodePath.h +++ b/panda/src/pgraph/qpnodePath.h @@ -465,8 +465,23 @@ PUBLISHED: INLINE bool operator < (const qpNodePath &other) const; INLINE int compare_to(const qpNodePath &other) const; + // Miscellaneous bool verify_complete() const; + void prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode = false); + + void show_bounds(); + void hide_bounds(); + PT(BoundingVolume) get_bounds() const; + void write_bounds(ostream &out) const; + bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point); + + int flatten_light(); + int flatten_medium(int max_children = 1); + int flatten_strong(int max_children = 1); + + bool write_bam_file(const string &filename) const; + private: void uncollapse_head() const; static void find_common_ancestor(const qpNodePath &a, const qpNodePath &b, @@ -490,6 +505,10 @@ private: void r_adjust_all_priorities(PandaNode *node, int adjustment); + void r_calc_tight_bounds(PandaNode *node, + LPoint3f &min_point, LPoint3f &max_point, + bool &found_any, const TransformState *transform); + PT(qpNodePathComponent) _head; ErrorType _error_type; static int _max_search_depth;