| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- // Filename: builder.cxx
- // Created by: drose (09Sep97)
- //
- ////////////////////////////////////////////////////////////////////
- //
- // PANDA 3D SOFTWARE
- // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
- //
- // All use of this software is subject to the terms of the Panda 3d
- // Software license. You should have received a copy of this license
- // along with this source code; you will also find a current copy of
- // the license at http://www.panda3d.org/license.txt .
- //
- // To contact the maintainers of this program write to
- // [email protected] .
- //
- ////////////////////////////////////////////////////////////////////
- #include "builderFuncs.h"
- #include "builderMisc.h"
- #include "notify.h"
- #include "pmap.h"
- #include "builder.h"
- #include "pandaNode.h"
- #include "geomNode.h"
- #include "dcast.h"
- ////////////////////////////////////////////////////////////////////
- // Function: Builder::Constructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- Builder::
- Builder() {
- _bi = _buckets.end();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: Builder::Destructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- Builder::
- ~Builder() {
- // Free all the buckets we allocated. We allocated 'em, we free
- // 'em.
- Buckets::iterator bi;
- for (bi = _buckets.begin();
- bi != _buckets.end();
- ++bi) {
- BuilderBucket *bucket = (*bi).get_bucket();
- delete bucket;
- }
- }
- // We use the NodeMap class to build up a map of Nodes to GeomNodes.
- // There may be several buckets that point to the same Node; these
- // should all be given the same GeomNode, when possible.
- // However, if two buckets have different sets of scene graph
- // properties--that is, the _trans member is different--they must be
- // given separate GeomNodes.
- // Furthermore, it's possible to name each bucket. If two buckets
- // with the same Node pointer have different names, then they should
- // be given two different GeomNodes.
- class NodeMap : public Namable {
- public:
- NodeMap(PandaNode *node, const BuilderBucket *bucket)
- : _node(node), _bucket(bucket) { }
- bool operator < (const NodeMap &other) const {
- if (_node != other._node) {
- return _node < other._node;
- }
- if (_bucket->get_name() != other._bucket->get_name()) {
- return _bucket->get_name() < other._bucket->get_name();
- }
- return 0;
- }
- PandaNode *_node;
- // Although a bucket pointer is stored here in the NodeMap class,
- // you should not use it except to extract the name and/or the
- // _trans member. Remember, this bucket pointer stands for any of
- // possibly several bucket pointers, all different, except that they
- // share the same name.
- const BuilderBucket *_bucket;
- };
- ////////////////////////////////////////////////////////////////////
- // Function: Builder::build
- // Access: Public
- // Description: Creates Geoms for all the primitives added to all
- // buckets, and adds them where appropriate to place
- // them in the scene graph under their respective
- // parents, and/or returns a single GeomNode that
- // contains all geometry whose bucket did not reference
- // a particular scene graph node to parent them to.
- //
- // If a bucket's _node pointer was a GeomNode, the
- // geometry will be added directly to that node. If the
- // _node pointer was any other kind of node, a GeomNode
- // will be created and parented to that node, and its
- // name will be the name of the bucket. In this case,
- // the name of the bucket can also be used to different
- // nodes: if two buckets reference the same node, but
- // have different names, then two different GeomNodes
- // are created, one with each name.
- ////////////////////////////////////////////////////////////////////
- GeomNode *Builder::
- build(const string &default_name) {
- typedef pmap<NodeMap, GeomNode *> GeomNodeMap;
- GeomNodeMap geom_nodes;
- // First, build all the Geoms and create GeomNodes for them. Each
- // unique Node gets its own GeomNode. If the Node is itself a
- // GeomNode, that GeomNode is used directly.
- Buckets::iterator i;
- for (i = _buckets.begin();
- i != _buckets.end();
- ++i) {
- BuilderBucket *bucket = (*i).get_bucket();
- PandaNode *node = bucket->_node;
- // const string &name = bucket->get_name();
- GeomNode *geom_node = NULL;
- if (node!=NULL && node->is_of_type(GeomNode::get_class_type())) {
- // The node is a GeomNode. In this case, we simply use that
- // node. We can't separate them out by name in this case; we'll
- // just assign to it the first nonempty name we encounter.
- geom_node = DCAST(GeomNode, node);
- // Since the caller already created this GeomNode and passed it
- // in, we'll leave it up to the caller to name the node and set
- // up the state transitions leading into it.
- } else {
- // The node is not a GeomNode, so look it up in the map.
- GeomNodeMap::iterator f = geom_nodes.find(NodeMap(node, bucket));
- if (f != geom_nodes.end()) {
- geom_node = (*f).second;
- } else {
- // No such node/name combination. Create a new one.
- geom_node = bucket->make_geom_node();
- if (geom_node != NULL) {
- geom_nodes[NodeMap(node, bucket)] = geom_node;
- }
- }
- }
- if (geom_node != NULL) {
- (*i).build(geom_node);
- }
- }
- // Now go through and parent the geom_nodes under their respective
- // group nodes. Save out the geom_node associated with a NULL Node;
- // this one is returned from this function.
- GeomNode *base_geom_node = NULL;
- GeomNodeMap::iterator gi;
- for (gi = geom_nodes.begin();
- gi != geom_nodes.end();
- ++gi) {
- const NodeMap &nm = (*gi).first;
- GeomNode *geom_node = (*gi).second;
- PandaNode *node = nm._node;
- const string &name = nm._bucket->get_name();
- // Assign the name to the geom, if it doesn't have one already.
- if (!geom_node->has_name()) {
- if (!name.empty()) {
- geom_node->set_name(name);
- } else if (!default_name.empty()) {
- geom_node->set_name(default_name);
- }
- }
- // Only reparent the geom_node if it has no parent already.
- int num_parents = geom_node->get_num_parents();
- if (num_parents == 0) {
- if (geom_node->get_num_geoms() == 0) {
- // If there was nothing added, never mind.
- delete geom_node;
- } else if (node==NULL) {
- nassertr(base_geom_node == NULL, NULL);
- base_geom_node = geom_node;
- } else {
- node->add_child(geom_node);
- }
- }
- }
- return base_geom_node;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: Builder::add_bucket
- // Access: Protected
- // Description: Adds a new BuilderBucket just like the given one to
- // the set of all used BuilderBuckets, and makes it the
- // current bucket. Future primitives will be added to
- // this bucket.
- ////////////////////////////////////////////////////////////////////
- void Builder::
- add_bucket(const BuilderBucket &bucket) {
- // Optimization: maybe it's the same bucket we used last time.
- if (_bi != _buckets.end() &&
- (*_bi) == BuilderBucketNode((BuilderBucket *)&bucket)) {
- return;
- }
- // Nope. Look again.
- _bi = _buckets.find((BuilderBucket *)&bucket);
- if (_bi == _buckets.end()) {
- BuilderBucket *new_bucket = bucket.make_copy();
- _bi = _buckets.insert(new_bucket).first;
- }
- }
|