00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "sceneGraphReducer.h"
00020 #include "config_pgraph.h"
00021 #include "colorAttrib.h"
00022 #include "texMatrixAttrib.h"
00023 #include "colorScaleAttrib.h"
00024 #include "accumulatedAttribs.h"
00025
00026 #include "geomNode.h"
00027 #include "pointerTo.h"
00028 #include "geom.h"
00029 #include "indent.h"
00030 #include "plist.h"
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 int SceneGraphReducer::
00051 flatten(PandaNode *root, bool combine_siblings) {
00052 int num_total_nodes = 0;
00053 int num_pass_nodes;
00054
00055 do {
00056 num_pass_nodes = 0;
00057
00058
00059
00060 PandaNode::ChildrenCopy cr = root->get_children_copy();
00061
00062
00063 int num_children = cr.get_num_children();
00064 for (int i = 0; i < num_children; i++) {
00065 PandaNode *child_node = cr.get_child(i);
00066 num_pass_nodes += r_flatten(root, child_node, combine_siblings);
00067 }
00068
00069 if (combine_siblings && root->get_num_children() >= 2) {
00070 num_pass_nodes += flatten_siblings(root);
00071 }
00072
00073 num_total_nodes += num_pass_nodes;
00074
00075
00076
00077
00078
00079
00080
00081 } while (combine_siblings && num_pass_nodes != 0);
00082
00083 return num_total_nodes;
00084 }
00085
00086
00087
00088
00089
00090
00091 void SceneGraphReducer::
00092 r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
00093 int attrib_types, GeomTransformer &transformer) {
00094 if (pgraph_cat.is_debug()) {
00095 pgraph_cat.debug()
00096 << "r_apply_attribs(" << *node << "), node's attribs are:\n";
00097 node->get_transform()->write(pgraph_cat.debug(false), 2);
00098 node->get_state()->write(pgraph_cat.debug(false), 2);
00099 node->get_effects()->write(pgraph_cat.debug(false), 2);
00100 }
00101
00102 AccumulatedAttribs next_attribs(attribs);
00103 next_attribs.collect(node, attrib_types);
00104
00105 if (pgraph_cat.is_debug()) {
00106 pgraph_cat.debug()
00107 << "Got attribs from " << *node << "\n"
00108 << "Accumulated attribs are:\n";
00109 next_attribs.write(pgraph_cat.debug(false), attrib_types, 2);
00110 }
00111
00112
00113
00114 int apply_types = 0;
00115
00116 const RenderEffects *effects = node->get_effects();
00117 if (!effects->safe_to_transform()) {
00118 if (pgraph_cat.is_debug()) {
00119 pgraph_cat.debug()
00120 << "Node " << *node
00121 << " contains a non-transformable effect; leaving transform here.\n";
00122 }
00123 apply_types |= TT_transform;
00124 }
00125 if (!node->safe_to_transform()) {
00126 if (pgraph_cat.is_debug()) {
00127 pgraph_cat.debug()
00128 << "Cannot safely transform nodes of type " << node->get_type()
00129 << "; leaving a transform here but carrying on otherwise.\n";
00130 }
00131 apply_types |= TT_transform;
00132 }
00133 apply_types |= node->get_unsafe_to_apply_attribs();
00134
00135
00136
00137
00138 int num_children = node->get_num_children();
00139 int i;
00140 if ((apply_types & TT_transform) == 0) {
00141 bool children_transform_friendly = true;
00142 for (i = 0; i < num_children && children_transform_friendly; i++) {
00143 PandaNode *child_node = node->get_child(i);
00144 children_transform_friendly = child_node->safe_to_modify_transform();
00145 }
00146
00147 if (!children_transform_friendly) {
00148 if (pgraph_cat.is_debug()) {
00149 pgraph_cat.debug()
00150 << "Node " << *node
00151 << " has a child that cannot modify its transform; leaving transform here.\n";
00152 }
00153 apply_types |= TT_transform;
00154 }
00155 }
00156
00157
00158 next_attribs.apply_to_node(node, attrib_types & apply_types);
00159
00160
00161 node->apply_attribs_to_vertices(next_attribs, attrib_types, transformer);
00162
00163
00164 bool resist_copy = false;
00165 for (i = 0; i < num_children; i++) {
00166 PandaNode *child_node = node->get_child(i);
00167
00168 if (child_node->get_num_parents() > 1) {
00169 if (!child_node->safe_to_flatten()) {
00170 if (pgraph_cat.is_debug()) {
00171 pgraph_cat.debug()
00172 << "Cannot duplicate nodes of type " << child_node->get_type()
00173 << ".\n";
00174 resist_copy = true;
00175 }
00176
00177 } else {
00178 PT(PandaNode) new_node = child_node->make_copy();
00179 if (new_node->get_type() != child_node->get_type()) {
00180 pgraph_cat.error()
00181 << "Don't know how to copy nodes of type "
00182 << child_node->get_type() << "\n";
00183 resist_copy = true;
00184
00185 } else {
00186 if (pgraph_cat.is_debug()) {
00187 pgraph_cat.debug()
00188 << "Duplicated " << *child_node << "\n";
00189 }
00190
00191 new_node->copy_children(child_node);
00192 node->replace_child(child_node, new_node);
00193 child_node = new_node;
00194 }
00195 }
00196 }
00197 }
00198
00199 if (resist_copy) {
00200
00201
00202 next_attribs.apply_to_node(node, attrib_types);
00203 }
00204
00205
00206 nassertv(num_children == node->get_num_children());
00207 for (i = 0; i < num_children; i++) {
00208 PandaNode *child_node = node->get_child(i);
00209 r_apply_attribs(child_node, next_attribs, attrib_types, transformer);
00210 }
00211 }
00212
00213
00214
00215
00216
00217
00218
00219 int SceneGraphReducer::
00220 r_flatten(PandaNode *grandparent_node, PandaNode *parent_node,
00221 bool combine_siblings) {
00222 int num_nodes = 0;
00223
00224
00225 {
00226 PandaNode::ChildrenCopy cr = parent_node->get_children_copy();
00227 int num_children = cr.get_num_children();
00228 for (int i = 0; i < num_children; i++) {
00229 PandaNode *child_node = cr.get_child(i);
00230 num_nodes += r_flatten(parent_node, child_node, combine_siblings);
00231 }
00232 }
00233
00234
00235
00236
00237 if (combine_siblings && parent_node->get_num_children() >= 2) {
00238 if (parent_node->safe_to_combine()) {
00239 num_nodes += flatten_siblings(parent_node);
00240 }
00241 }
00242
00243 if (parent_node->get_num_children() == 1) {
00244
00245
00246 PT(PandaNode) child_node = parent_node->get_child(0);
00247 int child_sort = parent_node->get_child_sort(0);
00248
00249 if (consider_child(grandparent_node, parent_node, child_node)) {
00250
00251 parent_node->remove_child(0);
00252
00253 if (do_flatten_child(grandparent_node, parent_node, child_node)) {
00254
00255 num_nodes++;
00256 } else {
00257
00258 parent_node->add_child(child_node, child_sort);
00259 }
00260 }
00261 }
00262
00263 return num_nodes;
00264 }
00265
00266 class SortByState {
00267 public:
00268 INLINE bool
00269 operator () (const PandaNode *node1, const PandaNode *node2) const;
00270 };
00271
00272 INLINE bool SortByState::
00273 operator () (const PandaNode *node1, const PandaNode *node2) const {
00274 if (node1->get_transform() != node2->get_transform()) {
00275 return node1->get_transform() < node2->get_transform();
00276 }
00277 if (node1->get_state() != node2->get_state()) {
00278 return node1->get_state() < node2->get_state();
00279 }
00280 if (node1->get_effects() != node2->get_effects()) {
00281 return node1->get_effects() < node2->get_effects();
00282 }
00283 if (node1->get_draw_mask() != node2->get_draw_mask()) {
00284 return node1->get_draw_mask() < node2->get_draw_mask();
00285 }
00286
00287 return 0;
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297 int SceneGraphReducer::
00298 flatten_siblings(PandaNode *parent_node) {
00299 int num_nodes = 0;
00300
00301
00302
00303 typedef plist< PT(PandaNode) > NodeList;
00304 typedef pmap<PandaNode *, NodeList, SortByState> Collected;
00305 Collected collected;
00306
00307 {
00308
00309
00310
00311 PandaNode::Children cr = parent_node->get_children();
00312 int num_children = cr.get_num_children();
00313 for (int i = 0; i < num_children; i++) {
00314 PandaNode *child_node = cr.get_child(i);
00315 if (child_node->safe_to_combine()) {
00316 collected[child_node].push_back(child_node);
00317 }
00318 }
00319 }
00320
00321
00322
00323
00324
00325 Collected::iterator ci;
00326 for (ci = collected.begin(); ci != collected.end(); ++ci) {
00327 const RenderEffects *effects = (*ci).first->get_effects();
00328 if (effects->safe_to_combine()) {
00329 NodeList &nodes = (*ci).second;
00330
00331 NodeList::iterator ai1;
00332 ai1 = nodes.begin();
00333 while (ai1 != nodes.end()) {
00334 NodeList::iterator ai1_hold = ai1;
00335 PandaNode *child1 = (*ai1);
00336 ++ai1;
00337 NodeList::iterator ai2 = ai1;
00338 while (ai2 != nodes.end()) {
00339 NodeList::iterator ai2_hold = ai2;
00340 PandaNode *child2 = (*ai2);
00341 ++ai2;
00342
00343 if (consider_siblings(parent_node, child1, child2)) {
00344 PT(PandaNode) new_node =
00345 do_flatten_siblings(parent_node, child1, child2);
00346 if (new_node != (PandaNode *)NULL) {
00347
00348 nodes.erase(ai2_hold);
00349 nodes.erase(ai1_hold);
00350 nodes.push_back(new_node);
00351 ai1 = nodes.begin();
00352 ai2 = nodes.end();
00353 num_nodes++;
00354 }
00355 }
00356 }
00357 }
00358 }
00359 }
00360
00361 return num_nodes;
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371 bool SceneGraphReducer::
00372 consider_child(PandaNode *grandparent_node, PandaNode *parent_node,
00373 PandaNode *child_node) {
00374 if (!parent_node->safe_to_combine() || !child_node->safe_to_combine()) {
00375
00376
00377 return false;
00378 }
00379
00380 if (parent_node->get_transform() != child_node->get_transform() ||
00381 parent_node->get_state() != child_node->get_state() ||
00382 parent_node->get_effects() != child_node->get_effects() ||
00383 parent_node->get_draw_mask() != child_node->get_draw_mask()) {
00384
00385 return false;
00386 }
00387
00388 if (!parent_node->get_effects()->safe_to_combine()) {
00389
00390 return false;
00391 }
00392
00393 return true;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 bool SceneGraphReducer::
00405 consider_siblings(PandaNode *parent_node, PandaNode *child1,
00406 PandaNode *child2) {
00407
00408
00409
00410 return true;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 bool SceneGraphReducer::
00422 do_flatten_child(PandaNode *grandparent_node, PandaNode *parent_node,
00423 PandaNode *child_node) {
00424 if (pgraph_cat.is_debug()) {
00425 pgraph_cat.debug()
00426 << "Collapsing " << *parent_node << " and " << *child_node << "\n";
00427 }
00428
00429 PT(PandaNode) new_parent = collapse_nodes(parent_node, child_node, false);
00430 if (new_parent == (PandaNode *)NULL) {
00431 if (pgraph_cat.is_debug()) {
00432 pgraph_cat.debug()
00433 << "Decided not to collapse " << *parent_node
00434 << " and " << *child_node << "\n";
00435 }
00436 return false;
00437 }
00438
00439 choose_name(new_parent, parent_node, child_node);
00440
00441 if (new_parent != child_node) {
00442 new_parent->steal_children(child_node);
00443 }
00444
00445 if (new_parent != parent_node) {
00446 grandparent_node->replace_child(parent_node, new_parent);
00447 }
00448
00449 return true;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 PandaNode *SceneGraphReducer::
00465 do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
00466 PandaNode *child2) {
00467 if (pgraph_cat.is_debug()) {
00468 pgraph_cat.debug()
00469 << "Collapsing " << *child1 << " and " << *child2 << "\n";
00470 }
00471
00472 PT(PandaNode) new_child = collapse_nodes(child2, child1, true);
00473 if (new_child == (PandaNode *)NULL) {
00474 if (pgraph_cat.is_debug()) {
00475 pgraph_cat.debug()
00476 << "Decided not to collapse " << *child1 << " and " << *child2 << "\n";
00477 }
00478 return NULL;
00479 }
00480
00481 choose_name(new_child, child2, child1);
00482
00483 if (new_child == child1) {
00484 new_child->steal_children(child2);
00485 parent_node->remove_child(child2);
00486
00487 } else if (new_child == child2) {
00488 new_child->steal_children(child1);
00489 parent_node->remove_child(child1);
00490
00491 } else {
00492 new_child->steal_children(child1);
00493 new_child->steal_children(child2);
00494 parent_node->remove_child(child2);
00495 parent_node->replace_child(child1, new_child);
00496 }
00497
00498 return new_child;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 PT(PandaNode) SceneGraphReducer::
00513 collapse_nodes(PandaNode *node1, PandaNode *node2, bool siblings) {
00514 return node2->combine_with(node1);
00515 }
00516
00517
00518
00519
00520
00521
00522
00523
00524 void SceneGraphReducer::
00525 choose_name(PandaNode *preserve, PandaNode *source1, PandaNode *source2) {
00526 string name;
00527 bool got_name = false;
00528
00529 name = source1->get_name();
00530 got_name = !name.empty() || source1->preserve_name();
00531
00532 if (source2->preserve_name() || !got_name) {
00533 name = source2->get_name();
00534 got_name = !name.empty() || source2->preserve_name();
00535 }
00536
00537 if (got_name) {
00538 preserve->set_name(name);
00539 }
00540 }