235 lines
7.6 KiB
C++
235 lines
7.6 KiB
C++
// 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
|
|
// panda3d@yahoogroups.com .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#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;
|
|
}
|
|
}
|
|
|