Panda3D
 All Classes Functions Variables Enumerations
cullBinManager.cxx
1 // Filename: cullBinManager.cxx
2 // Created by: drose (28Feb02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "cullBinManager.h"
16 #include "renderState.h"
17 #include "cullResult.h"
18 #include "config_pgraph.h"
19 #include "string_utils.h"
20 #include "configVariableColor.h"
21 
22 CullBinManager *CullBinManager::_global_ptr = (CullBinManager *)NULL;
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: CullBinManager::Constructor
26 // Access: Protected
27 // Description: The constructor is not intended to be called
28 // directly; there is only one CullBinManager and it
29 // constructs itself. This could have been a private
30 // constructor, but gcc issues a spurious warning if the
31 // constructor is private and the class has no friends.
32 ////////////////////////////////////////////////////////////////////
33 CullBinManager::
34 CullBinManager() {
35  _bins_are_sorted = true;
36  _unused_bin_index = false;
37 
38  setup_initial_bins();
39 }
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: CullBinManager::Destructor
43 // Access: Protected
44 // Description: Don't call the destructor.
45 ////////////////////////////////////////////////////////////////////
46 CullBinManager::
47 ~CullBinManager() {
48 }
49 
50 ////////////////////////////////////////////////////////////////////
51 // Function: CullBinManager::add_bin
52 // Access: Published
53 // Description: Defines a new bin with the indicated name, and
54 // returns the new bin_index. If there is already a bin
55 // with the same name returns its bin_index if it had
56 // the same properties; otherwise, reports an error and
57 // returns -1.
58 ////////////////////////////////////////////////////////////////////
60 add_bin(const string &name, BinType type, int sort) {
61  BinsByName::const_iterator bni = _bins_by_name.find(name);
62  if (bni != _bins_by_name.end()) {
63  // We already have such a bin. This is not a problem if the bin
64  // has the same properties.
65  int bin_index = (*bni).second;
66  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), -1);
67  const BinDefinition &def = _bin_definitions[bin_index];
68  nassertr(def._in_use, -1);
69  if (def._type == type && def._sort == sort) {
70  return bin_index;
71  }
72 
73  // Nope, the old bin had different properties. Too bad.
74  pgraph_cat.warning()
75  << "Cannot create a bin named " << name
76  << "; already have a bin by that name.\n";
77  return -1;
78  }
79 
80  // No bin by that name already; choose a bin_index to assign to the
81  // newly created bin.
82  int new_bin_index = -1;
83  if (_unused_bin_index) {
84  // If there is some bin index that's not being used, we can claim
85  // it.
86  int i = 0;
87  for (i = 0; i < (int)_bin_definitions.size() && new_bin_index == -1; i++) {
88  if (!_bin_definitions[i]._in_use) {
89  new_bin_index = i;
90  }
91  }
92 
93  if (new_bin_index == -1) {
94  // Oops, maybe we've used up all the unused indices already.
95  _unused_bin_index = false;
96  }
97  }
98 
99  if (new_bin_index == -1) {
100  // Slot a new index on the end of the vector.
101  new_bin_index = _bin_definitions.size();
102  _bin_definitions.push_back(BinDefinition());
103  }
104 
105  BinDefinition &def = _bin_definitions[new_bin_index];
106  def._in_use = true;
107  def._name = name;
108  def._type = type;
109  def._sort = sort;
110  def._active = true;
111 
112 #ifndef NDEBUG
113  // Check if there was a flash color configured for this bin name.
114  ConfigVariableColor flash_bin
115  ("flash-bin-" + name, "", "", ConfigVariable::F_dynamic);
116  if (flash_bin.get_num_words() == 0) {
117  def._flash_active = false;
118  } else {
119  def._flash_active = true;
120  def._flash_color = flash_bin.get_value();
121  }
122 #endif
123 
124  _bins_by_name.insert(BinsByName::value_type(name, new_bin_index));
125  _sorted_bins.push_back(new_bin_index);
126  _bins_are_sorted = false;
127 
128  return new_bin_index;
129 }
130 
131 ////////////////////////////////////////////////////////////////////
132 // Function: CullBinManager::remove_bin
133 // Access: Published
134 // Description: Permanently removes the indicated bin. This
135 // operation is not protected from the pipeline and will
136 // disturb whatever is currently rendering in draw. You
137 // should not call this during the normal course of
138 // rendering a frame; it is intended only as an aid to
139 // development, to allow the developer to interactively
140 // fiddle with the set of bins.
141 ////////////////////////////////////////////////////////////////////
142 void CullBinManager::
143 remove_bin(int bin_index) {
144  nassertv(bin_index >= 0 && bin_index < (int)_bin_definitions.size());
145  nassertv(_bin_definitions[bin_index]._in_use);
146 
147  _bin_definitions[bin_index]._in_use = false;
148  SortedBins::iterator si =
149  find(_sorted_bins.begin(), _sorted_bins.end(), bin_index);
150  nassertv(si != _sorted_bins.end());
151  _sorted_bins.erase(si);
152  _bins_by_name.erase(_bin_definitions[bin_index]._name);
153 
154  // Now we have to make sure all of the data objects in the world
155  // that had cached this bin index or have a bin object are correctly
156  // updated.
157 
158  // First, tell all the RenderStates in the world to reset their bin
159  // index cache.
160  RenderState::bin_removed(bin_index);
161 
162  // Now tell all the CullResults to clear themselves up too.
163  CullResult::bin_removed(bin_index);
164 }
165 
166 ////////////////////////////////////////////////////////////////////
167 // Function: CullBinManager::find_bin
168 // Access: Published
169 // Description: Returns the bin_index associated with the bin of the
170 // given name, or -1 if no bin has that name.
171 ////////////////////////////////////////////////////////////////////
173 find_bin(const string &name) const {
174  BinsByName::const_iterator bni;
175  bni = _bins_by_name.find(name);
176  if (bni != _bins_by_name.end()) {
177  return (*bni).second;
178  }
179  return -1;
180 }
181 
182 ////////////////////////////////////////////////////////////////////
183 // Function: CullBinManager::write
184 // Access: Published
185 // Description:
186 ////////////////////////////////////////////////////////////////////
187 void CullBinManager::
188 write(ostream &out) const {
189  if (!_bins_are_sorted) {
190  ((CullBinManager *)this)->do_sort_bins();
191  }
192  SortedBins::const_iterator sbi;
193  for (sbi = _sorted_bins.begin(); sbi != _sorted_bins.end(); ++sbi) {
194  int bin_index = (*sbi);
195  out << get_bin_name(bin_index) << ", " << get_bin_type(bin_index)
196  << ", " << get_bin_sort(bin_index) << "\n";
197  }
198 }
199 
200 ////////////////////////////////////////////////////////////////////
201 // Function: CullBinManager::make_new_bin
202 // Access: Public
203 // Description: Intended to be called by CullResult when a new
204 // CullBin pointer corresponding to the indicated
205 // bin_index is required. It allocates and returns a
206 // brand new CullBin object of the appropriate type.
207 ////////////////////////////////////////////////////////////////////
209 make_new_bin(int bin_index, GraphicsStateGuardianBase *gsg,
210  const PStatCollector &draw_region_pcollector) {
211  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), NULL);
212  nassertr(_bin_definitions[bin_index]._in_use, NULL);
213  string name = get_bin_name(bin_index);
214 
215  BinType type = _bin_definitions[bin_index]._type;
216  BinConstructors::const_iterator ci = _bin_constructors.find(type);
217  if (ci != _bin_constructors.end()) {
218  BinConstructor *constructor = (*ci).second;
219  return constructor(name, gsg, draw_region_pcollector);
220  }
221 
222  // Hmm, unknown (or unregistered) bin type.
223  nassertr(false, NULL);
224  return NULL;
225 }
226 
227 ////////////////////////////////////////////////////////////////////
228 // Function: CullBinManager::register_bin_type
229 // Access: Public
230 // Description: Intended to be called at startup type by each CullBin
231 // type, to register the constructor for each type.
232 ////////////////////////////////////////////////////////////////////
233 void CullBinManager::
234 register_bin_type(BinType type, CullBinManager::BinConstructor *constructor) {
235  bool inserted = _bin_constructors.insert(BinConstructors::value_type(type, constructor)).second;
236  nassertv(inserted);
237 }
238 
239 ////////////////////////////////////////////////////////////////////
240 // Function: CullBinManager::do_sort_bins
241 // Access: Private
242 // Description: Puts the _sorted_bins vector in proper rendering
243 // order.
244 ////////////////////////////////////////////////////////////////////
245 void CullBinManager::
246 do_sort_bins() {
247  sort(_sorted_bins.begin(), _sorted_bins.end(), SortBins(this));
248  _bins_are_sorted = true;
249 }
250 
251 ////////////////////////////////////////////////////////////////////
252 // Function: CullBinManager::setup_initial_bins
253 // Access: Private
254 // Description: Called only at construction time to create the
255 // default bins and the bins specified in the Configrc
256 // file.
257 ////////////////////////////////////////////////////////////////////
258 void CullBinManager::
259 setup_initial_bins() {
260  ConfigVariableList cull_bin
261  ("cull-bin",
262  PRC_DESC("Creates a new cull bin by name, with the specified properties. "
263  "This is a string in three tokens, separated by whitespace: "
264  "'bin_name sort type'."));
265 
266  // First, add all of the bins specified in the Configrc file.
267  int num_bins = cull_bin.get_num_unique_values();
268 
269  for (int bi = 0; bi < num_bins; bi++) {
270  string def = cull_bin.get_unique_value(bi);
271 
272  // This is a string in three tokens, separated by whitespace:
273  // bin_name sort type
274 
275  vector_string words;
276  extract_words(def, words);
277 
278  if (words.size() != 3) {
279  pgraph_cat.error()
280  << "Invalid cull-bin definition: " << def << "\n"
281  << "Definition should be three words: bin_name sort type\n";
282  } else {
283  int sort;
284  if (!string_to_int(words[1], sort)) {
285  pgraph_cat.error()
286  << "Invalid cull-bin definition: " << def << "\n"
287  << "Sort token " << words[1] << " is not an integer.\n";
288 
289  } else {
290  BinType type = parse_bin_type(words[2]);
291  if (type == BT_invalid) {
292  pgraph_cat.error()
293  << "Invalid cull-bin definition: " << def << "\n"
294  << "Bin type " << words[2] << " is not known.\n";
295  } else {
296  add_bin(words[0], type, sort);
297  }
298  }
299  }
300  }
301 
302  // Now add the default bins, unless the names have already been
303  // specified explicitly in the Config file, above.
304  if (find_bin("background") == -1) {
305  add_bin("background", BT_fixed, 10);
306  }
307  if (find_bin("opaque") == -1) {
308  add_bin("opaque", BT_state_sorted, 20);
309  }
310  if (find_bin("transparent") == -1) {
311  add_bin("transparent", BT_back_to_front, 30);
312  }
313  if (find_bin("fixed") == -1) {
314  add_bin("fixed", BT_fixed, 40);
315  }
316  if (find_bin("unsorted") == -1) {
317  add_bin("unsorted", BT_unsorted, 50);
318  }
319 }
320 
321 ////////////////////////////////////////////////////////////////////
322 // Function: CullBinManager::parse_bin_type
323 // Access: Private, Static
324 // Description: Given the name of a bin type, returns the
325 // corresponding BinType value, or BT_invalid if it is
326 // an unknown type.
327 ////////////////////////////////////////////////////////////////////
328 CullBinManager::BinType CullBinManager::
329 parse_bin_type(const string &bin_type) {
330  if (cmp_nocase_uh(bin_type, "unsorted") == 0) {
331  return BT_unsorted;
332 
333  } else if (cmp_nocase_uh(bin_type, "state_sorted") == 0) {
334  return BT_state_sorted;
335 
336  } else if (cmp_nocase_uh(bin_type, "fixed") == 0) {
337  return BT_fixed;
338 
339  } else if (cmp_nocase_uh(bin_type, "back_to_front") == 0) {
340  return BT_back_to_front;
341 
342  } else if (cmp_nocase_uh(bin_type, "front_to_back") == 0) {
343  return BT_front_to_back;
344 
345  } else {
346  return BT_invalid;
347  }
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: CullBinManager::BinType output operator
352 // Description:
353 ////////////////////////////////////////////////////////////////////
354 ostream &
355 operator << (ostream &out, CullBinManager::BinType bin_type) {
356  switch (bin_type) {
357  case CullBinManager::BT_invalid:
358  return out << "invalid";
359 
360  case CullBinManager::BT_unsorted:
361  return out << "unsorted";
362 
363  case CullBinManager::BT_state_sorted:
364  return out << "state_sorted";
365 
366  case CullBinManager::BT_back_to_front:
367  return out << "back_to_front";
368 
369  case CullBinManager::BT_front_to_back:
370  return out << "front_to_back";
371 
372  case CullBinManager::BT_fixed:
373  return out << "fixed";
374  }
375 
376  return out << "**invalid BinType(" << (int)bin_type << ")**";
377 }
int get_num_words() const
Returns the number of words in the variable&#39;s value.
A collection of Geoms and their associated state, for a particular scene.
Definition: cullBin.h:44
BinType get_bin_type(int bin_index) const
Returns the type of the bin with the indicated bin_index (where bin_index was retrieved by get_bin() ...
This is a convenience class to specialize ConfigVariable as a set of floating-point types representin...
This class is similar to ConfigVariable, but it reports its value as a list of strings.
int find_bin(const string &name) const
Returns the bin_index associated with the bin of the given name, or -1 if no bin has that name...
A lightweight class that represents a single element that may be timed and/or counted via stats...
string get_bin_name(int bin_index) const
Returns the name of the bin with the indicated bin_index (where bin_index was retrieved by get_bin() ...
void register_bin_type(BinType type, BinConstructor *constructor)
Intended to be called at startup type by each CullBin type, to register the constructor for each type...
const LColor & get_value() const
Returns the variable&#39;s value.
static void bin_removed(int bin_index)
Intended to be called by CullBinManager::remove_bin(), this informs all the CullResults in the world ...
Definition: cullResult.cxx:359
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
int add_bin(const string &name, BinType type, int sort)
Defines a new bin with the indicated name, and returns the new bin_index.
int get_bin_sort(int bin_index) const
Returns the sort order of the bin with the indicated bin_index (where bin_index was retrieved by get_...
void remove_bin(int bin_index)
Permanently removes the indicated bin.
This is a global object that maintains the collection of named CullBins in the world.
static void bin_removed(int bin_index)
Intended to be called by CullBinManager::remove_bin(), this informs all the RenderStates in the world...