00001 // Filename: builder.cxx 00002 // Created by: drose (09Sep97) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "builderFuncs.h" 00020 #include "builderMisc.h" 00021 #include "notify.h" 00022 #include "pmap.h" 00023 #include "builder.h" 00024 #include "pandaNode.h" 00025 #include "geomNode.h" 00026 #include "dcast.h" 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: Builder::Constructor 00030 // Access: Public 00031 // Description: 00032 //////////////////////////////////////////////////////////////////// 00033 Builder:: 00034 Builder() { 00035 _bi = _buckets.end(); 00036 } 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: Builder::Destructor 00040 // Access: Public 00041 // Description: 00042 //////////////////////////////////////////////////////////////////// 00043 Builder:: 00044 ~Builder() { 00045 // Free all the buckets we allocated. We allocated 'em, we free 00046 // 'em. 00047 Buckets::iterator bi; 00048 for (bi = _buckets.begin(); 00049 bi != _buckets.end(); 00050 ++bi) { 00051 BuilderBucket *bucket = (*bi).get_bucket(); 00052 delete bucket; 00053 } 00054 } 00055 00056 00057 // We use the NodeMap class to build up a map of Nodes to GeomNodes. 00058 // There may be several buckets that point to the same Node; these 00059 // should all be given the same GeomNode, when possible. 00060 00061 // However, if two buckets have different sets of scene graph 00062 // properties--that is, the _trans member is different--they must be 00063 // given separate GeomNodes. 00064 00065 // Furthermore, it's possible to name each bucket. If two buckets 00066 // with the same Node pointer have different names, then they should 00067 // be given two different GeomNodes. 00068 00069 class NodeMap : public Namable { 00070 public: 00071 NodeMap(PandaNode *node, const BuilderBucket *bucket) 00072 : _node(node), _bucket(bucket) { } 00073 00074 bool operator < (const NodeMap &other) const { 00075 if (_node != other._node) { 00076 return _node < other._node; 00077 } 00078 if (_bucket->get_name() != other._bucket->get_name()) { 00079 return _bucket->get_name() < other._bucket->get_name(); 00080 } 00081 return 0; 00082 } 00083 00084 PandaNode *_node; 00085 00086 // Although a bucket pointer is stored here in the NodeMap class, 00087 // you should not use it except to extract the name and/or the 00088 // _trans member. Remember, this bucket pointer stands for any of 00089 // possibly several bucket pointers, all different, except that they 00090 // share the same name. 00091 const BuilderBucket *_bucket; 00092 }; 00093 00094 00095 00096 //////////////////////////////////////////////////////////////////// 00097 // Function: Builder::build 00098 // Access: Public 00099 // Description: Creates Geoms for all the primitives added to all 00100 // buckets, and adds them where appropriate to place 00101 // them in the scene graph under their respective 00102 // parents, and/or returns a single GeomNode that 00103 // contains all geometry whose bucket did not reference 00104 // a particular scene graph node to parent them to. 00105 // 00106 // If a bucket's _node pointer was a GeomNode, the 00107 // geometry will be added directly to that node. If the 00108 // _node pointer was any other kind of node, a GeomNode 00109 // will be created and parented to that node, and its 00110 // name will be the name of the bucket. In this case, 00111 // the name of the bucket can also be used to different 00112 // nodes: if two buckets reference the same node, but 00113 // have different names, then two different GeomNodes 00114 // are created, one with each name. 00115 //////////////////////////////////////////////////////////////////// 00116 GeomNode *Builder:: 00117 build(const string &default_name) { 00118 typedef pmap<NodeMap, GeomNode *> GeomNodeMap; 00119 GeomNodeMap geom_nodes; 00120 00121 // First, build all the Geoms and create GeomNodes for them. Each 00122 // unique Node gets its own GeomNode. If the Node is itself a 00123 // GeomNode, that GeomNode is used directly. 00124 Buckets::iterator i; 00125 for (i = _buckets.begin(); 00126 i != _buckets.end(); 00127 ++i) { 00128 BuilderBucket *bucket = (*i).get_bucket(); 00129 PandaNode *node = bucket->_node; 00130 // const string &name = bucket->get_name(); 00131 GeomNode *geom_node = NULL; 00132 00133 if (node!=NULL && node->is_of_type(GeomNode::get_class_type())) { 00134 // The node is a GeomNode. In this case, we simply use that 00135 // node. We can't separate them out by name in this case; we'll 00136 // just assign to it the first nonempty name we encounter. 00137 geom_node = DCAST(GeomNode, node); 00138 00139 // Since the caller already created this GeomNode and passed it 00140 // in, we'll leave it up to the caller to name the node and set 00141 // up the state transitions leading into it. 00142 00143 } else { 00144 // The node is not a GeomNode, so look it up in the map. 00145 GeomNodeMap::iterator f = geom_nodes.find(NodeMap(node, bucket)); 00146 if (f != geom_nodes.end()) { 00147 geom_node = (*f).second; 00148 00149 } else { 00150 // No such node/name combination. Create a new one. 00151 geom_node = bucket->make_geom_node(); 00152 if (geom_node != NULL) { 00153 geom_nodes[NodeMap(node, bucket)] = geom_node; 00154 } 00155 } 00156 } 00157 00158 if (geom_node != NULL) { 00159 (*i).build(geom_node); 00160 } 00161 } 00162 00163 // Now go through and parent the geom_nodes under their respective 00164 // group nodes. Save out the geom_node associated with a NULL Node; 00165 // this one is returned from this function. 00166 00167 GeomNode *base_geom_node = NULL; 00168 00169 GeomNodeMap::iterator gi; 00170 00171 for (gi = geom_nodes.begin(); 00172 gi != geom_nodes.end(); 00173 ++gi) { 00174 const NodeMap &nm = (*gi).first; 00175 GeomNode *geom_node = (*gi).second; 00176 00177 PandaNode *node = nm._node; 00178 const string &name = nm._bucket->get_name(); 00179 00180 // Assign the name to the geom, if it doesn't have one already. 00181 if (!geom_node->has_name()) { 00182 if (!name.empty()) { 00183 geom_node->set_name(name); 00184 00185 } else if (!default_name.empty()) { 00186 geom_node->set_name(default_name); 00187 } 00188 } 00189 00190 // Only reparent the geom_node if it has no parent already. 00191 int num_parents = geom_node->get_num_parents(); 00192 if (num_parents == 0) { 00193 if (geom_node->get_num_geoms() == 0) { 00194 // If there was nothing added, never mind. 00195 delete geom_node; 00196 00197 } else if (node==NULL) { 00198 nassertr(base_geom_node == NULL, NULL); 00199 base_geom_node = geom_node; 00200 00201 } else { 00202 node->add_child(geom_node); 00203 } 00204 } 00205 } 00206 00207 return base_geom_node; 00208 } 00209 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: Builder::add_bucket 00213 // Access: Protected 00214 // Description: Adds a new BuilderBucket just like the given one to 00215 // the set of all used BuilderBuckets, and makes it the 00216 // current bucket. Future primitives will be added to 00217 // this bucket. 00218 //////////////////////////////////////////////////////////////////// 00219 void Builder:: 00220 add_bucket(const BuilderBucket &bucket) { 00221 // Optimization: maybe it's the same bucket we used last time. 00222 if (_bi != _buckets.end() && 00223 (*_bi) == BuilderBucketNode((BuilderBucket *)&bucket)) { 00224 return; 00225 } 00226 00227 // Nope. Look again. 00228 _bi = _buckets.find((BuilderBucket *)&bucket); 00229 if (_bi == _buckets.end()) { 00230 BuilderBucket *new_bucket = bucket.make_copy(); 00231 _bi = _buckets.insert(new_bucket).first; 00232 } 00233 } 00234