Panda3D
|
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 }