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  */
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  */
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 }
This is a convenience class to specialize ConfigVariable as a set of floating-point types representin...
const LColor & get_value() const
Returns the variable's value.
This class is similar to ConfigVariable, but it reports its value as a list of strings.
size_t get_num_words() const
Returns the number of words in the variable's value.
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() ...
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...
void remove_bin(int bin_index)
Permanently removes the indicated bin.
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_...
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() ...
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.
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.
A collection of Geoms and their associated state, for a particular scene.
Definition: cullBin.h:40
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:344
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
A lightweight class that represents a single element that may be timed and/or counted via stats.
static void bin_removed(int bin_index)
Intended to be called by CullBinManager::remove_bin(), this informs all the RenderStates in the world...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
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.