Panda3D
Loading...
Searching...
No Matches
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
21using std::string;
22
23CullBinManager *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 */
31CullBinManager::
32CullBinManager() {
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 */
42CullBinManager::
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 */
52add_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 */
130remove_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 */
157find_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 */
169void CullBinManager::
170write(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 */
187PT(CullBin) CullBinManager::
188make_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 */
211register_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 */
219void CullBinManager::
220do_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 */
229void CullBinManager::
230setup_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 */
296CullBinManager::BinType CullBinManager::
297parse_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 */
321std::ostream &
322operator << (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 ...
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.
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.