Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/egg/eggBinMaker.cxx

Go to the documentation of this file.
00001 // Filename: eggBinMaker.cxx
00002 // Created by:  drose (21Jan99)
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 "eggBinMaker.h"
00020 #include "eggGroupNode.h"
00021 #include "eggGroup.h"
00022 #include "eggBin.h"
00023 
00024 #include "dcast.h"
00025 #include "notify.h"
00026 
00027 TypeHandle EggBinMaker::_type_handle;
00028 
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: EggBinMakerCompareNodes::Function operator
00032 //       Access: Public
00033 //  Description: Called by the SortedNodes set to put nodes into bin
00034 //               order.  Returns true if the first node falls into an
00035 //               earlier bin than the second node, false otherwise.
00036 ////////////////////////////////////////////////////////////////////
00037 bool EggBinMakerCompareNodes::
00038 operator ()(const EggNode *a, const EggNode *b) const {
00039   int bin_number_a = _ebm->get_bin_number(a);
00040   int bin_number_b = _ebm->get_bin_number(b);
00041 
00042   if (bin_number_a != bin_number_b) {
00043     // If the two nodes return different bin numbers, then they
00044     // sort based on those numbers.
00045     return bin_number_a < bin_number_b;
00046   }
00047 
00048   // The two nodes fell into the same bin number, so fall back on the
00049   // comparison function to see if they should be differentiated.
00050   return _ebm->sorts_less(bin_number_a, a, b);
00051 }
00052 
00053 ////////////////////////////////////////////////////////////////////
00054 //     Function: EggBinMaker::Constructor
00055 //       Access: Public
00056 //  Description: 
00057 ////////////////////////////////////////////////////////////////////
00058 EggBinMaker::
00059 EggBinMaker() {
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: EggBinMaker::Destructor
00064 //       Access: Public
00065 //  Description: 
00066 ////////////////////////////////////////////////////////////////////
00067 EggBinMaker::
00068 ~EggBinMaker() {
00069 }
00070 
00071 
00072 ////////////////////////////////////////////////////////////////////
00073 //     Function: EggBinMaker::make_bins
00074 //       Access: Public
00075 //  Description: The main entry point to EggBinMaker.  Walks the egg
00076 //               scene graph beginning at the indicated root node, and
00077 //               moves all binnable nodes into EggBin objects.
00078 //               Returns the number of EggBins created.
00079 ////////////////////////////////////////////////////////////////////
00080 int EggBinMaker::
00081 make_bins(EggGroupNode *root_group) {
00082   _group_nodes.clear();
00083 
00084   collect_nodes(root_group);
00085 
00086   int num_bins = 0;
00087   GroupNodes::const_iterator gi;
00088   for (gi = _group_nodes.begin(); gi != _group_nodes.end(); ++gi) {
00089     num_bins += get_bins_for_group(gi);
00090   }
00091 
00092   return num_bins;
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: EggBinMaker::sorts_less
00097 //       Access: Public, Virtual
00098 //  Description: May be overridden in derived classes to create
00099 //               additional bins within a particular bin number, based
00100 //               on some arbitrary property of nodes.  This function
00101 //               establishes an arbitrary but fixed ordering between
00102 //               nodes; if two nodes do not sort to the same position,
00103 //               different bins are created for each one (with the
00104 //               same bin number on each bin).
00105 ////////////////////////////////////////////////////////////////////
00106 bool EggBinMaker::
00107 sorts_less(int, const EggNode *, const EggNode *) {
00108   return false;
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: EggBinMaker::collapse_group
00113 //       Access: Public, Virtual
00114 //  Description: May be overridden in derived classes to specify
00115 //               whether a particular group node, apparently
00116 //               redundant, may be safely collapsed out.
00117 ////////////////////////////////////////////////////////////////////
00118 bool EggBinMaker::
00119 collapse_group(const EggGroup *, int) {
00120   return false;
00121 }
00122 
00123 ////////////////////////////////////////////////////////////////////
00124 //     Function: EggBinMaker::get_bin_name
00125 //       Access: Public, Virtual
00126 //  Description: May be overridden in derived classes to define a name
00127 //               for each new bin, based on its bin number.
00128 ////////////////////////////////////////////////////////////////////
00129 string EggBinMaker::
00130 get_bin_name(int) {
00131   return string();
00132 }
00133 
00134 ////////////////////////////////////////////////////////////////////
00135 //     Function: EggBinMaker::collect_nodes
00136 //       Access: Private
00137 //  Description: Walks the egg scene graph, identifying nodes to be
00138 //               binned and moving them from the scene graph into the
00139 //               internal bin structure.
00140 ////////////////////////////////////////////////////////////////////
00141 void EggBinMaker::
00142 collect_nodes(EggGroupNode *group) {
00143   // We have to play games with this next iterator, because we might
00144   // be destructively operating on the child list as we traverse it.
00145   EggGroupNode::iterator i, next;
00146 
00147   bool first_in_group = true;
00148   GroupNodes::iterator gni = _group_nodes.end();
00149 
00150   i = group->begin();
00151   next = i;
00152   while (i != group->end()) {
00153     EggNode *node = (*i);
00154     ++next;
00155 
00156     if (get_bin_number(node) != 0) {
00157       // Ok, here's a node to be binned.  Add it to the appropriate
00158       // bin.
00159       if (first_in_group) {
00160         // If this is the first time this group has been encountered,
00161         // we need to create a new entry in _group_nodes for it.
00162 
00163         pair<GroupNodes::iterator, bool> result;
00164         result = _group_nodes.insert
00165           (GroupNodes::value_type
00166            (group, SortedNodes(EggBinMakerCompareNodes(this))));
00167 
00168         nassertv(result.second);
00169         gni = result.first;
00170         first_in_group = false;
00171       }
00172 
00173       // Add this node to the set of all nodes being binned for the
00174       // group.  This also puts the nodes into bin order.
00175       nassertv(gni != _group_nodes.end());
00176       (*gni).second.insert(node);
00177 
00178       // And remove it from the scene graph.
00179       group->erase(i);
00180 
00181     } else if (node->is_of_type(EggGroupNode::get_class_type())) {
00182       // Here's a normal group node, not to be binned.  Traverse.
00183       collect_nodes(DCAST(EggGroupNode, node));
00184     }
00185 
00186     i = next;
00187   }
00188 }
00189 
00190 
00191 ////////////////////////////////////////////////////////////////////
00192 //     Function: EggBinMaker::get_bins_for_group
00193 //       Access: Private
00194 //  Description: Breaks the set of nodes for a given group up into
00195 //               individual bins.
00196 ////////////////////////////////////////////////////////////////////
00197 int EggBinMaker::
00198 get_bins_for_group(GroupNodes::const_iterator gi) {
00199   EggGroupNode *group = (*gi).first;
00200   const SortedNodes &nodes = (*gi).second;
00201 
00202   // It shouldn't be possible for this to be empty.
00203   nassertr(!nodes.empty(), 0);
00204 
00205   Bins bins;
00206   EggBinMakerCompareNodes cn(this);
00207   SortedNodes::const_iterator sni, last;
00208   sni = nodes.begin();
00209   last = sni;
00210 
00211   bins.push_back(Nodes());
00212   bins.back().push_back(*sni);
00213   ++sni;
00214   while (sni != nodes.end()) {
00215     if (cn(*last, *sni)) {
00216       // Begin a new bin.
00217       bins.push_back(Nodes());
00218     }
00219     bins.back().push_back(*sni);
00220 
00221     last = sni;
00222     ++sni;
00223   }
00224 
00225   make_bins_for_group(group, bins);
00226   return bins.size();
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: EggBinMaker::make_bins_for_group
00231 //       Access: Private
00232 //  Description: Creates the EggBin nodes indicated by the internal
00233 //               bin structure for each group.
00234 ////////////////////////////////////////////////////////////////////
00235 void EggBinMaker::
00236 make_bins_for_group(EggGroupNode *group, const Bins &bins) {
00237   // We shouldn't be able to get here if we have no bins!
00238   nassertv(!bins.empty());
00239 
00240   // If the group will have only one bin, and no other children, and
00241   // the group is not the root node (and it is not some funny
00242   // group-like node like a <Table>), maybe we should collapse the
00243   // group and its bin together.
00244 
00245   bool collapse = false;
00246 
00247   if (group->empty() &&
00248       bins.size() == 1 &&
00249       group->get_parent() != NULL &&
00250       group->is_of_type(EggGroup::get_class_type())) {
00251     const Nodes &nodes = bins.front();
00252     nassertv(!nodes.empty());
00253     int bin_number = get_bin_number(nodes.front());
00254     collapse = collapse_group(DCAST(EggGroup, group), bin_number);
00255   }
00256 
00257   if (collapse) {
00258     EggBin *bin = new EggBin(*DCAST(EggGroup, group));
00259     setup_bin(bin, bins.front());
00260 
00261     EggGroupNode *parent = group->get_parent();
00262     parent->remove_child(group);
00263     parent->add_child(bin);
00264 
00265   } else {
00266     Bins::const_iterator bi;
00267     for (bi = bins.begin(); bi != bins.end(); ++bi) {
00268       EggBin *bin = new EggBin;
00269       setup_bin(bin, *bi);
00270 
00271       group->add_child(bin);
00272     }
00273   }
00274 }
00275 
00276 
00277 ////////////////////////////////////////////////////////////////////
00278 //     Function: EggBinMaker::setup_bin
00279 //       Access: Private
00280 //  Description: Sets up a recently-created EggBin structure with all
00281 //               of its children.
00282 ////////////////////////////////////////////////////////////////////
00283 void EggBinMaker::
00284 setup_bin(EggBin *bin, const Nodes &nodes) {
00285   nassertv(!nodes.empty());
00286   int bin_number = get_bin_number(nodes.front());
00287   bin->set_bin_number(bin_number);
00288 
00289   string bin_name = get_bin_name(bin_number);
00290   if (!bin_name.empty()) {
00291     bin->set_name(bin_name);
00292   }
00293 
00294   Nodes::const_iterator ni;
00295   for (ni = nodes.begin(); ni != nodes.end(); ++ni) {
00296     bin->add_child(*ni);
00297   }
00298 }
00299 

Generated on Fri May 2 00:37:28 2003 for Panda by doxygen1.3