Panda3D
 All Classes Functions Variables Enumerations
cullBinManager.cxx
00001 // Filename: cullBinManager.cxx
00002 // Created by:  drose (28Feb02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "cullBinManager.h"
00016 #include "renderState.h"
00017 #include "cullResult.h"
00018 #include "config_pgraph.h"
00019 #include "string_utils.h"
00020 
00021 
00022 CullBinManager *CullBinManager::_global_ptr = (CullBinManager *)NULL;
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: CullBinManager::Constructor
00026 //       Access: Protected
00027 //  Description: The constructor is not intended to be called
00028 //               directly; there is only one CullBinManager and it
00029 //               constructs itself.  This could have been a private
00030 //               constructor, but gcc issues a spurious warning if the
00031 //               constructor is private and the class has no friends.
00032 ////////////////////////////////////////////////////////////////////
00033 CullBinManager::
00034 CullBinManager() {
00035   _bins_are_sorted = true;
00036   _unused_bin_index = false;
00037 
00038   setup_initial_bins();
00039 }
00040 
00041 ////////////////////////////////////////////////////////////////////
00042 //     Function: CullBinManager::Destructor
00043 //       Access: Protected
00044 //  Description: Don't call the destructor.
00045 ////////////////////////////////////////////////////////////////////
00046 CullBinManager::
00047 ~CullBinManager() {
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: CullBinManager::add_bin
00052 //       Access: Published
00053 //  Description: Defines a new bin with the indicated name, and
00054 //               returns the new bin_index.  If there is already a bin
00055 //               with the same name returns its bin_index if it had
00056 //               the same properties; otherwise, reports an error and
00057 //               returns -1.
00058 ////////////////////////////////////////////////////////////////////
00059 int CullBinManager::
00060 add_bin(const string &name, BinType type, int sort) {
00061   BinsByName::const_iterator bni = _bins_by_name.find(name);
00062   if (bni != _bins_by_name.end()) {
00063     // We already have such a bin.  This is not a problem if the bin
00064     // has the same properties.
00065     int bin_index = (*bni).second;
00066     nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), -1);
00067     const BinDefinition &def = _bin_definitions[bin_index];
00068     nassertr(def._in_use, -1);
00069     if (def._type == type && def._sort == sort) {
00070       return bin_index;
00071     }
00072 
00073     // Nope, the old bin had different properties.  Too bad.
00074     pgraph_cat.warning()
00075       << "Cannot create a bin named " << name
00076       << "; already have a bin by that name.\n";
00077     return -1;
00078   }
00079 
00080   // No bin by that name already; choose a bin_index to assign to the
00081   // newly created bin.
00082   int new_bin_index = -1;
00083   if (_unused_bin_index) {
00084     // If there is some bin index that's not being used, we can claim
00085     // it.
00086     int i = 0;
00087     for (i = 0; i < (int)_bin_definitions.size() && new_bin_index == -1; i++) {
00088       if (!_bin_definitions[i]._in_use) {
00089         new_bin_index = i;
00090       }
00091     }
00092 
00093     if (new_bin_index == -1) {
00094       // Oops, maybe we've used up all the unused indices already.
00095       _unused_bin_index = false;
00096     }
00097   }
00098 
00099   if (new_bin_index == -1) {
00100     // Slot a new index on the end of the vector.
00101     new_bin_index = _bin_definitions.size();
00102     _bin_definitions.push_back(BinDefinition());
00103   }
00104 
00105   BinDefinition &def = _bin_definitions[new_bin_index];
00106   def._in_use = true;
00107   def._name = name;
00108   def._type = type;
00109   def._sort = sort;
00110   def._active = true;
00111 
00112   _bins_by_name.insert(BinsByName::value_type(name, new_bin_index));
00113   _sorted_bins.push_back(new_bin_index);
00114   _bins_are_sorted = false;
00115 
00116   return new_bin_index;
00117 }
00118 
00119 ////////////////////////////////////////////////////////////////////
00120 //     Function: CullBinManager::remove_bin
00121 //       Access: Published
00122 //  Description: Permanently removes the indicated bin.  This
00123 //               operation is not protected from the pipeline and will
00124 //               disturb whatever is currently rendering in draw.  You
00125 //               should not call this during the normal course of
00126 //               rendering a frame; it is intended only as an aid to
00127 //               development, to allow the developer to interactively
00128 //               fiddle with the set of bins.
00129 ////////////////////////////////////////////////////////////////////
00130 void CullBinManager::
00131 remove_bin(int bin_index) {
00132   nassertv(bin_index >= 0 && bin_index < (int)_bin_definitions.size());
00133   nassertv(_bin_definitions[bin_index]._in_use);
00134 
00135   _bin_definitions[bin_index]._in_use = false;
00136   SortedBins::iterator si = 
00137     find(_sorted_bins.begin(), _sorted_bins.end(), bin_index);
00138   nassertv(si != _sorted_bins.end());
00139   _sorted_bins.erase(si);
00140   _bins_by_name.erase(_bin_definitions[bin_index]._name);
00141 
00142   // Now we have to make sure all of the data objects in the world
00143   // that had cached this bin index or have a bin object are correctly
00144   // updated.
00145   
00146   // First, tell all the RenderStates in the world to reset their bin
00147   // index cache.
00148   RenderState::bin_removed(bin_index);
00149 
00150   // Now tell all the CullResults to clear themselves up too.
00151   CullResult::bin_removed(bin_index);
00152 }
00153 
00154 ////////////////////////////////////////////////////////////////////
00155 //     Function: CullBinManager::find_bin
00156 //       Access: Published
00157 //  Description: Returns the bin_index associated with the bin of the
00158 //               given name, or -1 if no bin has that name.
00159 ////////////////////////////////////////////////////////////////////
00160 int CullBinManager::
00161 find_bin(const string &name) const {
00162   BinsByName::const_iterator bni;
00163   bni = _bins_by_name.find(name);
00164   if (bni != _bins_by_name.end()) {
00165     return (*bni).second;
00166   }
00167   return -1;
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: CullBinManager::write
00172 //       Access: Published
00173 //  Description: 
00174 ////////////////////////////////////////////////////////////////////
00175 void CullBinManager::
00176 write(ostream &out) const {
00177   if (!_bins_are_sorted) {
00178     ((CullBinManager *)this)->do_sort_bins();
00179   }
00180   SortedBins::const_iterator sbi;
00181   for (sbi = _sorted_bins.begin(); sbi != _sorted_bins.end(); ++sbi) {
00182     int bin_index = (*sbi);
00183     out << get_bin_name(bin_index) << ", " << get_bin_type(bin_index)
00184         << ", " << get_bin_sort(bin_index) << "\n";
00185   }
00186 }
00187 
00188 ////////////////////////////////////////////////////////////////////
00189 //     Function: CullBinManager::get_global_ptr
00190 //       Access: Published, Static
00191 //  Description: Returns the pointer to the global CullBinManager
00192 //               object.
00193 ////////////////////////////////////////////////////////////////////
00194 CullBinManager *CullBinManager::
00195 get_global_ptr() {
00196   if (_global_ptr == (CullBinManager *)NULL) {
00197     _global_ptr = new CullBinManager;
00198   }
00199   return _global_ptr;
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: CullBinManager::make_new_bin
00204 //       Access: Public
00205 //  Description: Intended to be called by CullResult when a new
00206 //               CullBin pointer corresponding to the indicated
00207 //               bin_index is required.  It allocates and returns a
00208 //               brand new CullBin object of the appropriate type.
00209 ////////////////////////////////////////////////////////////////////
00210 PT(CullBin) CullBinManager::
00211 make_new_bin(int bin_index, GraphicsStateGuardianBase *gsg,
00212              const PStatCollector &draw_region_pcollector) {
00213   nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), NULL);
00214   nassertr(_bin_definitions[bin_index]._in_use, NULL);
00215   string name = get_bin_name(bin_index);
00216 
00217   BinType type = _bin_definitions[bin_index]._type;
00218   BinConstructors::const_iterator ci = _bin_constructors.find(type);
00219   if (ci != _bin_constructors.end()) {
00220     BinConstructor *constructor = (*ci).second;
00221     return constructor(name, gsg, draw_region_pcollector);
00222   }
00223 
00224   // Hmm, unknown (or unregistered) bin type.
00225   nassertr(false, NULL);
00226   return NULL;
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: CullBinManager::register_bin_type
00231 //       Access: Public
00232 //  Description: Intended to be called at startup type by each CullBin
00233 //               type, to register the constructor for each type.
00234 ////////////////////////////////////////////////////////////////////
00235 void CullBinManager::
00236 register_bin_type(BinType type, CullBinManager::BinConstructor *constructor) {
00237   bool inserted = _bin_constructors.insert(BinConstructors::value_type(type, constructor)).second;
00238   nassertv(inserted);
00239 }
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: CullBinManager::do_sort_bins
00243 //       Access: Private
00244 //  Description: Puts the _sorted_bins vector in proper rendering
00245 //               order.
00246 ////////////////////////////////////////////////////////////////////
00247 void CullBinManager::
00248 do_sort_bins() {
00249   sort(_sorted_bins.begin(), _sorted_bins.end(), SortBins(this));
00250   _bins_are_sorted = true;
00251 }
00252 
00253 ////////////////////////////////////////////////////////////////////
00254 //     Function: CullBinManager::setup_initial_bins
00255 //       Access: Private
00256 //  Description: Called only at construction time to create the
00257 //               default bins and the bins specified in the Configrc
00258 //               file.
00259 ////////////////////////////////////////////////////////////////////
00260 void CullBinManager::
00261 setup_initial_bins() {
00262   ConfigVariableList cull_bin
00263     ("cull-bin", 
00264      PRC_DESC("Creates a new cull bin by name, with the specified properties.  "
00265               "This is a string in three tokens, separated by whitespace: "
00266               "'bin_name sort type'."));
00267   
00268   // First, add all of the bins specified in the Configrc file.
00269   int num_bins = cull_bin.get_num_unique_values();
00270 
00271   for (int bi = 0; bi < num_bins; bi++) {
00272     string def = cull_bin.get_unique_value(bi);
00273 
00274     // This is a string in three tokens, separated by whitespace:
00275     //    bin_name sort type
00276 
00277     vector_string words;
00278     extract_words(def, words);
00279 
00280     if (words.size() != 3) {
00281       pgraph_cat.error()
00282         << "Invalid cull-bin definition: " << def << "\n"
00283         << "Definition should be three words: bin_name sort type\n";
00284     } else {
00285       int sort;
00286       if (!string_to_int(words[1], sort)) {
00287         pgraph_cat.error()
00288           << "Invalid cull-bin definition: " << def << "\n"
00289           << "Sort token " << words[1] << " is not an integer.\n";
00290 
00291       } else {
00292         BinType type = parse_bin_type(words[2]);
00293         if (type == BT_invalid) {
00294           pgraph_cat.error()
00295             << "Invalid cull-bin definition: " << def << "\n"
00296             << "Bin type " << words[2] << " is not known.\n";
00297         } else {
00298           add_bin(words[0], type, sort);
00299         }
00300       }
00301     }
00302   }
00303 
00304   // Now add the default bins, unless the names have already been
00305   // specified explicitly in the Config file, above.
00306   if (find_bin("background") == -1) {
00307     add_bin("background", BT_fixed, 10);
00308   }
00309   if (find_bin("opaque") == -1) {
00310     add_bin("opaque", BT_state_sorted, 20);
00311   }
00312   if (find_bin("transparent") == -1) {
00313     add_bin("transparent", BT_back_to_front, 30);
00314   }
00315   if (find_bin("fixed") == -1) {
00316     add_bin("fixed", BT_fixed, 40);
00317   }
00318   if (find_bin("unsorted") == -1) {
00319     add_bin("unsorted", BT_unsorted, 50);
00320   }
00321 }
00322 
00323 ////////////////////////////////////////////////////////////////////
00324 //     Function: CullBinManager::parse_bin_type
00325 //       Access: Private, Static
00326 //  Description: Given the name of a bin type, returns the
00327 //               corresponding BinType value, or BT_invalid if it is
00328 //               an unknown type.
00329 ////////////////////////////////////////////////////////////////////
00330 CullBinManager::BinType CullBinManager::
00331 parse_bin_type(const string &bin_type) {
00332   if (cmp_nocase_uh(bin_type, "unsorted") == 0) {
00333     return BT_unsorted;
00334 
00335   } else if (cmp_nocase_uh(bin_type, "state_sorted") == 0) {
00336     return BT_state_sorted;
00337 
00338   } else if (cmp_nocase_uh(bin_type, "fixed") == 0) {
00339     return BT_fixed;
00340 
00341   } else if (cmp_nocase_uh(bin_type, "back_to_front") == 0) {
00342     return BT_back_to_front;
00343 
00344   } else if (cmp_nocase_uh(bin_type, "front_to_back") == 0) {
00345     return BT_front_to_back;
00346 
00347   } else {
00348     return BT_invalid;
00349   }
00350 }
00351 
00352 ////////////////////////////////////////////////////////////////////
00353 //     Function: CullBinManager::BinType output operator
00354 //  Description: 
00355 ////////////////////////////////////////////////////////////////////
00356 ostream &
00357 operator << (ostream &out, CullBinManager::BinType bin_type) {
00358   switch (bin_type) {
00359   case CullBinManager::BT_invalid:
00360     return out << "invalid";
00361     
00362   case CullBinManager::BT_unsorted:
00363     return out << "unsorted";
00364     
00365   case CullBinManager::BT_state_sorted:
00366     return out << "state_sorted";
00367     
00368   case CullBinManager::BT_back_to_front:
00369     return out << "back_to_front";
00370     
00371   case CullBinManager::BT_front_to_back:
00372     return out << "front_to_back";
00373     
00374   case CullBinManager::BT_fixed:
00375     return out << "fixed";
00376   }
00377 
00378   return out << "**invalid BinType(" << (int)bin_type << ")**";
00379 }
 All Classes Functions Variables Enumerations