Panda3D
 All Classes Functions Variables Enumerations
eggBinMaker.cxx
1 // Filename: eggBinMaker.cxx
2 // Created by: drose (21Jan99)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "eggBinMaker.h"
16 #include "eggGroupNode.h"
17 #include "eggGroup.h"
18 #include "eggBin.h"
19 
20 #include "dcast.h"
21 #include "pnotify.h"
22 
23 TypeHandle EggBinMaker::_type_handle;
24 
25 
26 ////////////////////////////////////////////////////////////////////
27 // Function: EggBinMakerCompareNodes::Function operator
28 // Access: Public
29 // Description: Called by the SortedNodes set to put nodes into bin
30 // order. Returns true if the first node falls into an
31 // earlier bin than the second node, false otherwise.
32 ////////////////////////////////////////////////////////////////////
34 operator ()(const EggNode *a, const EggNode *b) const {
35  int bin_number_a = _ebm->get_bin_number(a);
36  int bin_number_b = _ebm->get_bin_number(b);
37 
38  if (bin_number_a != bin_number_b) {
39  // If the two nodes return different bin numbers, then they
40  // sort based on those numbers.
41  return bin_number_a < bin_number_b;
42  }
43 
44  // The two nodes fell into the same bin number, so fall back on the
45  // comparison function to see if they should be differentiated.
46  return _ebm->sorts_less(bin_number_a, a, b);
47 }
48 
49 ////////////////////////////////////////////////////////////////////
50 // Function: EggBinMaker::Constructor
51 // Access: Public
52 // Description:
53 ////////////////////////////////////////////////////////////////////
54 EggBinMaker::
55 EggBinMaker() {
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: EggBinMaker::Destructor
60 // Access: Public
61 // Description:
62 ////////////////////////////////////////////////////////////////////
63 EggBinMaker::
64 ~EggBinMaker() {
65 }
66 
67 
68 ////////////////////////////////////////////////////////////////////
69 // Function: EggBinMaker::make_bins
70 // Access: Public
71 // Description: The main entry point to EggBinMaker. Walks the egg
72 // scene graph beginning at the indicated root node, and
73 // moves all binnable nodes into EggBin objects.
74 // Returns the number of EggBins created.
75 ////////////////////////////////////////////////////////////////////
76 int EggBinMaker::
77 make_bins(EggGroupNode *root_group) {
78  _group_nodes.clear();
79 
80  collect_nodes(root_group);
81 
82  int num_bins = 0;
83  GroupNodes::const_iterator gi;
84  for (gi = _group_nodes.begin(); gi != _group_nodes.end(); ++gi) {
85  num_bins += get_bins_for_group(gi);
86  }
87 
88  return num_bins;
89 }
90 
91 ////////////////////////////////////////////////////////////////////
92 // Function: EggBinMaker::prepare_node
93 // Access: Public, Virtual
94 // Description: May be overridden in derived classes to perform some
95 // setup work as each node is encountered. This will be
96 // called once for each node in the egg hierarchy.
97 ////////////////////////////////////////////////////////////////////
98 void EggBinMaker::
100 }
101 
102 ////////////////////////////////////////////////////////////////////
103 // Function: EggBinMaker::sorts_less
104 // Access: Public, Virtual
105 // Description: May be overridden in derived classes to create
106 // additional bins within a particular bin number, based
107 // on some arbitrary property of nodes. This function
108 // establishes an arbitrary but fixed ordering between
109 // nodes; if two nodes do not sort to the same position,
110 // different bins are created for each one (with the
111 // same bin number on each bin).
112 ////////////////////////////////////////////////////////////////////
113 bool EggBinMaker::
114 sorts_less(int, const EggNode *, const EggNode *) {
115  return false;
116 }
117 
118 ////////////////////////////////////////////////////////////////////
119 // Function: EggBinMaker::collapse_group
120 // Access: Public, Virtual
121 // Description: May be overridden in derived classes to specify
122 // whether a particular group node, apparently
123 // redundant, may be safely collapsed out.
124 ////////////////////////////////////////////////////////////////////
125 bool EggBinMaker::
126 collapse_group(const EggGroup *, int) {
127  return false;
128 }
129 
130 ////////////////////////////////////////////////////////////////////
131 // Function: EggBinMaker::get_bin_name
132 // Access: Public, Virtual
133 // Description: May be overridden in derived classes to define a name
134 // for each new bin, based on its bin number, and a
135 // sample child.
136 ////////////////////////////////////////////////////////////////////
137 string EggBinMaker::
138 get_bin_name(int, const EggNode *) {
139  return string();
140 }
141 
142 ////////////////////////////////////////////////////////////////////
143 // Function: EggBinMaker::make_bin
144 // Access: Public, Virtual
145 // Description: May be overridden in derived classes to construct a
146 // new EggBin object (or some derived class, if needed),
147 // and preload some initial data into as required.
148 //
149 // child is an arbitrary child of the bin, and
150 // collapse_from is the group the bin is being collapsed
151 // with, if any (implying collapse_group() returned
152 // true), or NULL if not.
153 ////////////////////////////////////////////////////////////////////
154 PT(EggBin) EggBinMaker::
155 make_bin(int, const EggNode *, EggGroup *collapse_from) {
156  if (collapse_from == (EggGroup *)NULL) {
157  return new EggBin;
158  } else {
159  return new EggBin(*collapse_from);
160  }
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: EggBinMaker::collect_nodes
165 // Access: Private
166 // Description: Walks the egg scene graph, identifying nodes to be
167 // binned and moving them from the scene graph into the
168 // internal bin structure.
169 ////////////////////////////////////////////////////////////////////
170 void EggBinMaker::
171 collect_nodes(EggGroupNode *group) {
172  // We have to play games with this next iterator, because we might
173  // be destructively operating on the child list as we traverse it.
174  EggGroupNode::iterator i, next;
175 
176  bool first_in_group = true;
177  GroupNodes::iterator gni = _group_nodes.end();
178 
179  i = group->begin();
180  next = i;
181  while (i != group->end()) {
182  EggNode *node = (*i);
183  ++next;
184 
185  prepare_node(node);
186 
187  if (get_bin_number(node) != 0) {
188  // Ok, here's a node to be binned. Add it to the appropriate
189  // bin.
190  if (first_in_group) {
191  // If this is the first time this group has been encountered,
192  // we need to create a new entry in _group_nodes for it.
193 
194  pair<GroupNodes::iterator, bool> result;
195  result = _group_nodes.insert
196  (GroupNodes::value_type
197  (group, SortedNodes(EggBinMakerCompareNodes(this))));
198 
199  nassertv(result.second);
200  gni = result.first;
201  first_in_group = false;
202  }
203 
204  // Add this node to the set of all nodes being binned for the
205  // group. This also puts the nodes into bin order.
206  nassertv(gni != _group_nodes.end());
207  (*gni).second.insert(node);
208 
209  // And remove it from the scene graph.
210  group->erase(i);
211  }
212 
213  if (node->is_of_type(EggGroupNode::get_class_type())) {
214  // Recursively traverse.
215  collect_nodes(DCAST(EggGroupNode, node));
216  }
217 
218  i = next;
219  }
220 }
221 
222 
223 ////////////////////////////////////////////////////////////////////
224 // Function: EggBinMaker::get_bins_for_group
225 // Access: Private
226 // Description: Breaks the set of nodes for a given group up into
227 // individual bins.
228 ////////////////////////////////////////////////////////////////////
229 int EggBinMaker::
230 get_bins_for_group(GroupNodes::const_iterator gi) {
231  EggGroupNode *group = (*gi).first;
232  const SortedNodes &nodes = (*gi).second;
233 
234  // It shouldn't be possible for this to be empty.
235  nassertr(!nodes.empty(), 0);
236 
237  Bins bins;
238  EggBinMakerCompareNodes cn(this);
239  SortedNodes::const_iterator sni, last;
240  sni = nodes.begin();
241  last = sni;
242 
243  bins.push_back(Nodes());
244  bins.back().push_back(*sni);
245  ++sni;
246  while (sni != nodes.end()) {
247  if (cn(*last, *sni)) {
248  // Begin a new bin.
249  bins.push_back(Nodes());
250  }
251  bins.back().push_back(*sni);
252 
253  last = sni;
254  ++sni;
255  }
256 
257  make_bins_for_group(group, bins);
258  return bins.size();
259 }
260 
261 ////////////////////////////////////////////////////////////////////
262 // Function: EggBinMaker::make_bins_for_group
263 // Access: Private
264 // Description: Creates the EggBin nodes indicated by the internal
265 // bin structure for each group.
266 ////////////////////////////////////////////////////////////////////
267 void EggBinMaker::
268 make_bins_for_group(EggGroupNode *group, const Bins &bins) {
269  // We shouldn't be able to get here if we have no bins!
270  nassertv(!bins.empty());
271 
272  // If the group will have only one bin, and no other children, and
273  // the group is not the root node (and it is not some funny
274  // group-like node like a <Table>), maybe we should collapse the
275  // group and its bin together.
276 
277  bool collapse = false;
278 
279  if (group->empty() &&
280  bins.size() == 1 &&
281  group->get_parent() != NULL &&
282  group->is_of_type(EggGroup::get_class_type())) {
283  const Nodes &nodes = bins.front();
284  nassertv(!nodes.empty());
285  int bin_number = get_bin_number(nodes.front());
286  collapse = collapse_group(DCAST(EggGroup, group), bin_number);
287  }
288 
289  if (collapse) {
290  const Nodes &nodes = bins.front();
291  nassertv(!nodes.empty());
292  int bin_number = get_bin_number(nodes.front());
293  PT(EggBin) bin = make_bin(bin_number, nodes.front(), DCAST(EggGroup, group));
294  setup_bin(bin, nodes);
295 
296  EggGroupNode *parent = group->get_parent();
297  parent->remove_child(group);
298  parent->add_child(bin);
299 
300  } else {
301  Bins::const_iterator bi;
302  for (bi = bins.begin(); bi != bins.end(); ++bi) {
303  const Nodes &nodes = (*bi);
304  nassertv(!nodes.empty());
305  int bin_number = get_bin_number(nodes.front());
306  PT(EggBin) bin = make_bin(bin_number, nodes.front(), NULL);
307  setup_bin(bin, nodes);
308 
309  group->add_child(bin);
310  }
311  }
312 }
313 
314 
315 ////////////////////////////////////////////////////////////////////
316 // Function: EggBinMaker::setup_bin
317 // Access: Private
318 // Description: Sets up a recently-created EggBin structure with all
319 // of its children.
320 ////////////////////////////////////////////////////////////////////
321 void EggBinMaker::
322 setup_bin(EggBin *bin, const Nodes &nodes) {
323  nassertv(!nodes.empty());
324  int bin_number = get_bin_number(nodes.front());
325  bin->set_bin_number(bin_number);
326 
327  string bin_name = get_bin_name(bin_number, nodes.front());
328  if (!bin_name.empty()) {
329  bin->set_name(bin_name);
330  }
331 
332  Nodes::const_iterator ni;
333  for (ni = nodes.begin(); ni != nodes.end(); ++ni) {
334  bin->add_child(*ni);
335  }
336 }
337 
virtual void prepare_node(EggNode *node)
May be overridden in derived classes to perform some setup work as each node is encountered.
Definition: eggBinMaker.cxx:99
virtual string get_bin_name(int bin_number, const EggNode *child)
May be overridden in derived classes to define a name for each new bin, based on its bin number...
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
bool operator()(const EggNode *a, const EggNode *b) const
Called by the SortedNodes set to put nodes into bin order.
Definition: eggBinMaker.cxx:34
virtual bool sorts_less(int bin_number, const EggNode *a, const EggNode *b)
May be overridden in derived classes to create additional bins within a particular bin number...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
This is a handy class for collecting related nodes together.
Definition: eggBinMaker.h:254
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
int make_bins(EggGroupNode *root_group)
The main entry point to EggBinMaker.
Definition: eggBinMaker.cxx:77
virtual bool collapse_group(const EggGroup *group, int bin_number)
May be overridden in derived classes to specify whether a particular group node, apparently redundant...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This is just an STL function object, used to sort nodes within EggBinMaker.
Definition: eggBinMaker.h:233
A type of group node that holds related subnodes.
Definition: eggBin.h:30