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