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