Panda3D
textureAttrib.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 textureAttrib.cxx
10  * @author drose
11  * @date 2002-02-21
12  */
13 
14 #include "textureAttrib.h"
16 #include "internalName.h"
17 #include "bamReader.h"
18 #include "bamWriter.h"
19 #include "datagram.h"
20 #include "datagramIterator.h"
21 #include "dcast.h"
22 #include "textureStagePool.h"
23 
24 CPT(RenderAttrib) TextureAttrib::_empty_attrib;
25 CPT(RenderAttrib) TextureAttrib::_all_off_attrib;
26 TypeHandle TextureAttrib::_type_handle;
27 int TextureAttrib::_attrib_slot;
28 
29 
30 /**
31  * Constructs a new TextureAttrib object suitable for rendering the indicated
32  * texture onto geometry, using the default TextureStage.
33  */
34 CPT(RenderAttrib) TextureAttrib::
35 make(Texture *texture) {
36  return DCAST(TextureAttrib, make())->add_on_stage(TextureStage::get_default(), texture);
37 }
38 
39 /**
40  * Constructs a new TextureAttrib object suitable for rendering untextured
41  * geometry.
42  */
43 CPT(RenderAttrib) TextureAttrib::
44 make_off() {
45  return make_all_off();
46 }
47 
48 /**
49  * Constructs a new TextureAttrib object that does nothing.
50  */
51 CPT(RenderAttrib) TextureAttrib::
52 make() {
53  // We make it a special case and store a pointer to the empty attrib forever
54  // once we find it the first time, as an optimization.
55  if (_empty_attrib == nullptr) {
56  _empty_attrib = return_new(new TextureAttrib);
57  }
58 
59  return _empty_attrib;
60 }
61 
62 /**
63  * Constructs a new TextureAttrib object that turns off all stages (and hence
64  * disables texturing).
65  */
66 CPT(RenderAttrib) TextureAttrib::
67 make_all_off() {
68  // We make it a special case and store a pointer to the off attrib forever
69  // once we find it the first time, as an optimization.
70  if (_all_off_attrib == nullptr) {
71  TextureAttrib *attrib = new TextureAttrib;
72  attrib->_off_all_stages = true;
73  _all_off_attrib = return_new(attrib);
74  }
75 
76  return _all_off_attrib;
77 }
78 
79 /**
80  * Returns a RenderAttrib that corresponds to whatever the standard default
81  * properties for render attributes of this type ought to be.
82  */
83 CPT(RenderAttrib) TextureAttrib::
84 make_default() {
85  return make();
86 }
87 
88 
89 /**
90  * Returns the index number of the indicated TextureStage within the list of
91  * on_stages, or -1 if the indicated stage is not listed.
92  */
94 find_on_stage(const TextureStage *stage) const {
95  Stages::const_iterator si = _on_stages.find(StageNode(stage));
96  if (si != _on_stages.end()) {
97  return (int)(si - _on_stages.begin());
98  }
99 
100  return -1;
101 }
102 
103 /**
104  * Returns a new TextureAttrib, just like this one, but with the indicated
105  * stage added to the list of stages turned on by this attrib.
106  */
107 CPT(RenderAttrib) TextureAttrib::
108 add_on_stage(TextureStage *stage, Texture *tex, int override) const {
109  nassertr(tex != nullptr, this);
110 
111  TextureAttrib *attrib = new TextureAttrib(*this);
112  auto result = attrib->_on_stages.insert(StageNode(stage));
113  StageNode &sn = *result.first;
114  sn._override = override;
115  sn._texture = tex;
116  sn._has_sampler = false;
117 
118  // Only bump this if it doesn't already have the highest implicit sort.
119  // This prevents replacing a texture from creating a unique TextureAttrib.
120  if (result.second || sn._implicit_sort + 1 != attrib->_next_implicit_sort) {
121  sn._implicit_sort = attrib->_next_implicit_sort;
122  ++(attrib->_next_implicit_sort);
123  }
124 
125  return return_new(attrib);
126 }
127 
128 /**
129  * Returns a new TextureAttrib, just like this one, but with the indicated
130  * stage added to the list of stages turned on by this attrib.
131  */
132 CPT(RenderAttrib) TextureAttrib::
133 add_on_stage(TextureStage *stage, Texture *tex, const SamplerState &sampler, int override) const {
134  nassertr(tex != nullptr, this);
135 
136  TextureAttrib *attrib = new TextureAttrib(*this);
137  auto result = attrib->_on_stages.insert(StageNode(stage));
138  StageNode &sn = *result.first;
139  sn._override = override;
140  sn._texture = tex;
141  sn._sampler = sampler;
142  sn._has_sampler = true;
143 
144  // Only bump this if it doesn't already have the highest implicit sort.
145  // This prevents replacing a texture from creating a unique TextureAttrib.
146  if (result.second || sn._implicit_sort + 1 != attrib->_next_implicit_sort) {
147  sn._implicit_sort = attrib->_next_implicit_sort;
148  ++(attrib->_next_implicit_sort);
149  }
150 
151  return return_new(attrib);
152 }
153 
154 /**
155  * Returns a new TextureAttrib, just like this one, but with the indicated
156  * stage removed from the list of stages turned on by this attrib.
157  */
158 CPT(RenderAttrib) TextureAttrib::
159 remove_on_stage(TextureStage *stage) const {
160  TextureAttrib *attrib = new TextureAttrib(*this);
161 
162  Stages::iterator si = attrib->_on_stages.find(StageNode(stage));
163  if (si != attrib->_on_stages.end()) {
164  attrib->_on_stages.erase(si);
165  }
166 
167  return return_new(attrib);
168 }
169 
170 /**
171  * Returns a new TextureAttrib, just like this one, but with the indicated
172  * stage added to the list of stages turned off by this attrib.
173  */
174 CPT(RenderAttrib) TextureAttrib::
175 add_off_stage(TextureStage *stage, int override) const {
176  TextureAttrib *attrib = new TextureAttrib(*this);
177  if (!_off_all_stages) {
178  StageNode sn(stage);
179  Stages::iterator sfi = attrib->_off_stages.insert(sn).first;
180  (*sfi)._override = override;
181 
182  // Also ensure it is removed from the on_stages list.
183  Stages::iterator si = attrib->_on_stages.find(sn);
184  if (si != attrib->_on_stages.end()) {
185  attrib->_on_stages.erase(si);
186  }
187  }
188  return return_new(attrib);
189 }
190 
191 /**
192  * Returns a new TextureAttrib, just like this one, but with the indicated
193  * stage removed from the list of stages turned off by this attrib.
194  */
195 CPT(RenderAttrib) TextureAttrib::
196 remove_off_stage(TextureStage *stage) const {
197  TextureAttrib *attrib = new TextureAttrib(*this);
198  attrib->_off_stages.erase(StageNode(stage));
199  return return_new(attrib);
200 }
201 
202 /**
203  * Returns a new TextureAttrib, just like this one, but with any included
204  * TextureAttribs that happen to have the same name as the given object
205  * replaced with the object.
206  */
207 CPT(RenderAttrib) TextureAttrib::
208 unify_texture_stages(TextureStage *stage) const {
209  PT(TextureAttrib) attrib = new TextureAttrib;
210 
211  attrib->_off_all_stages = _off_all_stages;
212  bool any_changed = false;
213 
214  Stages::const_iterator si;
215  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
216  TextureStage *this_stage = (*si)._stage;
217 
218  if (this_stage->get_name() == stage->get_name()) {
219  this_stage = stage;
220  any_changed = true;
221  }
222 
223  Stages::iterator osi = attrib->_on_stages.insert(StageNode(this_stage)).first;
224  (*osi)._texture = (*si)._texture;
225  (*osi)._ff_tc_index = (*si)._ff_tc_index;
226  (*osi)._implicit_sort = (*si)._implicit_sort;
227  (*osi)._override = (*si)._override;
228  }
229 
230  attrib->_next_implicit_sort = _next_implicit_sort;
231 
232  Stages::const_iterator fsi;
233  for (fsi = _off_stages.begin(); fsi != _off_stages.end(); ++fsi) {
234  TextureStage *this_stage = (*fsi)._stage;
235 
236  if (this_stage != stage &&
237  this_stage->get_name() == stage->get_name()) {
238  this_stage = stage;
239  any_changed = true;
240  }
241 
242  attrib->_off_stages.insert(StageNode(this_stage));
243  }
244 
245  if (!any_changed) {
246  return this;
247  }
248 
249  return return_new(attrib);
250 }
251 
252 /**
253  * Returns a new TextureAttrib, just like this one, but with all references to
254  * the given texture replaced with the new texture.
255  *
256  * @since 1.10.4
257  */
258 CPT(RenderAttrib) TextureAttrib::
259 replace_texture(Texture *tex, Texture *new_tex) const {
260  TextureAttrib *attrib = nullptr;
261 
262  for (size_t i = 0; i < _on_stages.size(); ++i) {
263  const StageNode &sn = _on_stages[i];
264  if (sn._texture == tex) {
265  if (attrib == nullptr) {
266  attrib = new TextureAttrib(*this);
267  }
268 
269  attrib->_on_stages[i]._texture = new_tex;
270  }
271  }
272 
273  if (attrib != nullptr) {
274  return return_new(attrib);
275  } else {
276  return this;
277  }
278 }
279 
280 /**
281  * Returns a new TextureAttrib, very much like this one, but with the number
282  * of on_stages reduced to be no more than max_texture_stages. The number of
283  * off_stages in the new TextureAttrib is undefined.
284  */
285 CPT(TextureAttrib) TextureAttrib::
286 filter_to_max(int max_texture_stages) const {
287  if ((int)_on_stages.size() <= max_texture_stages) {
288  // Trivial case: this TextureAttrib qualifies.
289  return this;
290  }
291 
292  if (_filtered_seq != TextureStage::get_sort_seq()) {
293  ((TextureAttrib *)this)->_filtered.clear();
294  ((TextureAttrib *)this)->_filtered_seq = TextureStage::get_sort_seq();
295  }
296 
297  Filtered::const_iterator fi;
298  fi = _filtered.find(max_texture_stages);
299  if (fi != _filtered.end()) {
300  // Easy case: we have already computed this for this particular
301  // TextureAttrib.
302  return (*fi).second;
303  }
304 
305  // Harder case: we have to compute it now. We must choose the n stages with
306  // the highest priority in our list of stages. In the case of equal
307  // priority, we prefer the stage with the lower sort.
308  check_sorted();
309 
310  RenderStages priority_stages = _render_stages;
311 
312  // This sort function uses the STL function object defined above.
313  sort(priority_stages.begin(), priority_stages.end(),
314  CompareTextureStagePriorities());
315 
316  // Now lop off all of the stages after the first max_texture_stages.
317  priority_stages.erase(priority_stages.begin() + max_texture_stages,
318  priority_stages.end());
319 
320  // And create a new attrib reflecting these stages.
321  PT(TextureAttrib) attrib = new TextureAttrib;
322 
323  RenderStages::const_iterator ri;
324  for (ri = priority_stages.begin(); ri != priority_stages.end(); ++ri) {
325  attrib->_on_stages.insert(*(*ri));
326  }
327 
328  attrib->_next_implicit_sort = _next_implicit_sort;
329 
330  CPT(RenderAttrib) new_attrib = return_new(attrib);
331 
332  // Finally, record this newly-created attrib in the map for next time.
333 
334  // TODO: if new_attrib == this, have we just created a circular reference
335  // count? Whoops! Fix this!
336 
337  CPT(TextureAttrib) tex_attrib = (const TextureAttrib *)new_attrib.p();
338  ((TextureAttrib *)this)->_filtered[max_texture_stages] = tex_attrib;
339  return tex_attrib;
340 }
341 
342 /**
343  * Intended to be overridden by derived RenderAttrib types to specify how two
344  * consecutive RenderAttrib objects of the same type interact.
345  *
346  * This should return false if a RenderAttrib on a higher node will compose
347  * into a RenderAttrib on a lower node that has a higher override value, or
348  * false if the lower RenderAttrib will completely replace the state.
349  *
350  * The default behavior is false: normally, a RenderAttrib in the graph cannot
351  * completely override a RenderAttrib above it, regardless of its override
352  * value--instead, the two attribs are composed. But for some kinds of
353  * RenderAttribs, it is useful to allow this kind of override.
354  *
355  * This method only handles the one special case of a lower RenderAttrib with
356  * a higher override value. If the higher RenderAttrib has a higher override
357  * value, it always completely overrides. And if both RenderAttribs have the
358  * same override value, they are always composed.
359  */
360 bool TextureAttrib::
362  // A TextureAttrib doesn't compose through an override. Normally, there
363  // won't be a scene-graph override on a TextureAttrib anyway, since the
364  // NodePath::set_texture() override is applied to the per-TextureStage
365  // override value. But there might be a scene-graph override if
366  // NodePath::adjust_all_priorities() is used, and in this case, we'd like
367  // for it to stick.
368  return true;
369 }
370 
371 /**
372  *
373  */
374 void TextureAttrib::
375 output(std::ostream &out) const {
376  check_sorted();
377 
378  out << get_type() << ":";
379  if (_off_stages.empty()) {
380  if (_on_stages.empty()) {
381  if (_off_all_stages) {
382  out << "all off";
383  } else {
384  out << "identity";
385  }
386  } else {
387  if (_off_all_stages) {
388  out << "set";
389  } else {
390  out << "on";
391  }
392  }
393 
394  } else {
395  out << "off";
396  Stages::const_iterator fi;
397  for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) {
398  TextureStage *stage = (*fi)._stage;
399  out << " " << stage->get_name();
400  if ((*fi)._override != 0) {
401  out << "^" << (*fi)._override;
402  }
403  }
404 
405  if (!_on_stages.empty()) {
406  out << " on";
407  }
408  }
409 
410  RenderStages::const_iterator ri;
411  for (ri = _render_stages.begin(); ri != _render_stages.end(); ++ri) {
412  const StageNode &sn = *(*ri);
413  TextureStage *stage = sn._stage;
414  Texture *tex = sn._texture;
415  out << " " << stage->get_name();
416  if (tex != nullptr) {
417  out << ":" << tex->get_name();
418  }
419  if (sn._override != 0) {
420  out << "^" << sn._override;
421  }
422  }
423 }
424 
425 /**
426  * Should be overridden by derived classes to return true if cull_callback()
427  * has been defined. Otherwise, returns false to indicate cull_callback()
428  * does not need to be called for this node during the cull traversal.
429  */
430 bool TextureAttrib::
431 has_cull_callback() const {
432  Stages::const_iterator si;
433  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
434  Texture *texture = (*si)._texture;
435  if (texture->has_cull_callback()) {
436  return true;
437  }
438  }
439 
440  return false;
441 }
442 
443 /**
444  * If has_cull_callback() returns true, this function will be called during
445  * the cull traversal to perform any additional operations that should be
446  * performed at cull time.
447  *
448  * This is called each time the RenderAttrib is discovered applied to a Geom
449  * in the traversal. It should return true if the Geom is visible, false if
450  * it should be omitted.
451  */
452 bool TextureAttrib::
453 cull_callback(CullTraverser *trav, const CullTraverserData &data) const {
454  Stages::const_iterator si;
455  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
456  Texture *texture = (*si)._texture;
457  if (!texture->cull_callback(trav, data)) {
458  return false;
459  }
460  }
461 
462  return true;
463 }
464 
465 /**
466  * Intended to be overridden by derived TextureAttrib types to return a unique
467  * number indicating whether this TextureAttrib is equivalent to the other
468  * one.
469  *
470  * This should return 0 if the two TextureAttrib objects are equivalent, a
471  * number less than zero if this one should be sorted before the other one,
472  * and a number greater than zero otherwise.
473  *
474  * This will only be called with two TextureAttrib objects whose get_type()
475  * functions return the same.
476  */
477 int TextureAttrib::
478 compare_to_impl(const RenderAttrib *other) const {
479  const TextureAttrib *ta = (const TextureAttrib *)other;
480 
481  if (_off_all_stages != ta->_off_all_stages) {
482  return (int)_off_all_stages - (int)ta->_off_all_stages;
483  }
484 
485  Stages::const_iterator si = _on_stages.begin();
486  Stages::const_iterator osi = ta->_on_stages.begin();
487 
488  while (si != _on_stages.end() && osi != ta->_on_stages.end()) {
489  TextureStage *stage = (*si)._stage;
490  TextureStage *other_stage = (*osi)._stage;
491 
492  if (stage != other_stage) {
493  return stage < other_stage ? -1 : 1;
494  }
495 
496  Texture *texture = (*si)._texture;
497  Texture *other_texture = (*osi)._texture;
498 
499  if (texture != other_texture) {
500  return texture < other_texture ? -1 : 1;
501  }
502 
503  int implicit_sort = (*si)._implicit_sort;
504  int other_implicit_sort = (*osi)._implicit_sort;
505 
506  if (implicit_sort != other_implicit_sort) {
507  return implicit_sort < other_implicit_sort ? -1 : 1;
508  }
509 
510  int override = (*si)._override;
511  int other_override = (*osi)._override;
512 
513  if (override != other_override) {
514  return override < other_override ? -1 : 1;
515  }
516 
517  int has_sampler = (*si)._has_sampler;
518  int other_has_sampler = (*osi)._has_sampler;
519 
520  if (has_sampler != other_has_sampler) {
521  return has_sampler < other_has_sampler ? -1 : 1;
522  }
523 
524  if (has_sampler) {
525  const SamplerState &sampler = (*si)._sampler;
526  const SamplerState &other_sampler = (*osi)._sampler;
527 
528  if (sampler != other_sampler) {
529  return sampler < other_sampler ? -1 : 1;
530  }
531  }
532 
533  ++si;
534  ++osi;
535  }
536 
537  if (si != _on_stages.end()) {
538  return 1;
539  }
540  if (osi != ta->_on_stages.end()) {
541  return -1;
542  }
543 
544  // Finally, ensure that the set of off stages is the same.
545  Stages::const_iterator fi = _off_stages.begin();
546  Stages::const_iterator ofi = ta->_off_stages.begin();
547 
548  while (fi != _off_stages.end() && ofi != ta->_off_stages.end()) {
549  TextureStage *stage = (*fi)._stage;
550  TextureStage *other_stage = (*ofi)._stage;
551 
552  if (stage != other_stage) {
553  return stage < other_stage ? -1 : 1;
554  }
555 
556  int override = (*fi)._override;
557  int other_override = (*ofi)._override;
558 
559  if (override != other_override) {
560  return override < other_override ? -1 : 1;
561  }
562 
563  ++fi;
564  ++ofi;
565  }
566 
567  if (fi != _off_stages.end()) {
568  return 1;
569  }
570  if (ofi != ta->_off_stages.end()) {
571  return -1;
572  }
573 
574  return 0;
575 }
576 
577 /**
578  * Intended to be overridden by derived RenderAttrib types to return a unique
579  * hash for these particular properties. RenderAttribs that compare the same
580  * with compare_to_impl(), above, should return the same hash; RenderAttribs
581  * that compare differently should return a different hash.
582  */
583 size_t TextureAttrib::
584 get_hash_impl() const {
585  check_sorted();
586 
587  size_t hash = 0;
588  Stages::const_iterator si;
589  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
590  const StageNode &sn = (*si);
591 
592  hash = pointer_hash::add_hash(hash, sn._stage);
593  hash = pointer_hash::add_hash(hash, sn._texture);
594  hash = int_hash::add_hash(hash, (int)sn._implicit_sort);
595  hash = int_hash::add_hash(hash, sn._override);
596  }
597 
598  // This bool value goes here, between the two lists, to differentiate
599  // between the two.
600  hash = int_hash::add_hash(hash, (int)_off_all_stages);
601 
602  for (si = _off_stages.begin(); si != _off_stages.end(); ++si) {
603  const StageNode &sn = (*si);
604 
605  hash = pointer_hash::add_hash(hash, sn._stage);
606  hash = int_hash::add_hash(hash, sn._override);
607  }
608 
609  return hash;
610 }
611 
612 /**
613  * Intended to be overridden by derived RenderAttrib types to specify how two
614  * consecutive RenderAttrib objects of the same type interact.
615  *
616  * This should return the result of applying the other RenderAttrib to a node
617  * in the scene graph below this RenderAttrib, which was already applied. In
618  * most cases, the result is the same as the other RenderAttrib (that is, a
619  * subsequent RenderAttrib completely replaces the preceding one). On the
620  * other hand, some kinds of RenderAttrib (for instance, ColorTransformAttrib)
621  * might combine in meaningful ways.
622  */
623 CPT(RenderAttrib) TextureAttrib::
624 compose_impl(const RenderAttrib *other) const {
625  const TextureAttrib *ta = (const TextureAttrib *)other;
626 
627  if (ta->_off_all_stages) {
628  // If the other type turns off all stages, it doesn't matter what we are.
629  return ta;
630  }
631 
632  // This is a three-way merge between ai, bi, and ci, except that bi and ci
633  // should have no intersection and therefore needn't be compared to each
634  // other.
635  Stages::const_iterator ai = _on_stages.begin();
636  Stages::const_iterator bi = ta->_on_stages.begin();
637  Stages::const_iterator ci = ta->_off_stages.begin();
638 
639  // Create a new TextureAttrib that will hold the result.
640  TextureAttrib *attrib = new TextureAttrib;
641 
642  while (ai != _on_stages.end() &&
643  bi != ta->_on_stages.end() &&
644  ci != ta->_off_stages.end()) {
645  if ((*ai)._stage < (*bi)._stage) {
646  if ((*ai)._stage < (*ci)._stage) {
647  // Here is a stage that we have in the original, which is not present
648  // in the secondary.
649  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
650  ++ai;
651 
652  } else if ((*ci)._stage < (*ai)._stage) {
653  // Here is a stage that is turned off in the secondary, but was not
654  // present in the original.
655  ++ci;
656 
657  } else { // (*ci)._stage == (*ai)._stage
658  // Here is a stage that is turned off in the secondary, and was
659  // present in the original.
660  if ((*ai)._override > (*ci)._override) {
661  // But never mind, keep it anyway.
662  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
663  }
664 
665  ++ai;
666  ++ci;
667  }
668 
669  } else if ((*bi)._stage < (*ai)._stage) {
670  // Here is a new stage we have in the secondary, that was not present in
671  // the original.
672  attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
673  ++bi;
674 
675  } else { // (*bi)._stage == (*ai)._stage
676  // Here is a stage we have in both.
677  if ((*ai)._override > (*bi)._override) {
678  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
679  } else {
680  attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
681  }
682  ++ai;
683  ++bi;
684  }
685  }
686 
687  while (ai != _on_stages.end() && bi != ta->_on_stages.end()) {
688  if ((*ai)._stage < (*bi)._stage) {
689  // Here is a stage that we have in the original, which is not present in
690  // the secondary.
691  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
692  ++ai;
693 
694  } else if ((*bi)._stage < (*ai)._stage) {
695  // Here is a new stage we have in the secondary, that was not present in
696  // the original.
697  attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
698  ++bi;
699 
700  } else {
701  // Here is a stage we have in both.
702  if ((*ai)._override > (*bi)._override) {
703  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
704  } else {
705  attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
706  }
707  ++ai;
708  ++bi;
709  }
710  }
711 
712  while (ai != _on_stages.end() && ci != ta->_off_stages.end()) {
713  if ((*ai)._stage < (*ci)._stage) {
714  // Here is a stage that we have in the original, which is not present in
715  // the secondary.
716  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
717  ++ai;
718 
719  } else if ((*ci)._stage < (*ai)._stage) {
720  // Here is a stage that is turned off in the secondary, but was not
721  // present in the original.
722  ++ci;
723 
724  } else { // (*ci)._stage == (*ai)._stage
725  // Here is a stage that is turned off in the secondary, and was present
726  // in the original.
727  if ((*ai)._override > (*ci)._override) {
728  // But never mind, keep it anyway.
729  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
730  }
731  ++ai;
732  ++ci;
733  }
734  }
735 
736  while (ai != _on_stages.end()) {
737  attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
738  ++ai;
739  }
740 
741  while (bi != ta->_on_stages.end()) {
742  attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
743  ++bi;
744  }
745 
746  attrib->_next_implicit_sort = _next_implicit_sort + ta->_next_implicit_sort;
747  attrib->_sort_seq = UpdateSeq::old();
748  attrib->_filtered_seq = UpdateSeq::old();
749 
750  return return_new(attrib);
751 }
752 
753 /**
754  * Intended to be overridden by derived RenderAttrib types to specify how two
755  * consecutive RenderAttrib objects of the same type interact.
756  *
757  * See invert_compose() and compose_impl().
758  */
759 CPT(RenderAttrib) TextureAttrib::
760 invert_compose_impl(const RenderAttrib *other) const {
761  // I think in this case the other attrib always wins. Maybe this needs a
762  // bit more thought. It's hard to imagine that it's even important to
763  // compute this properly.
764  return other;
765 }
766 
767 /**
768  * Tells the BamReader how to create objects of type TextureAttrib.
769  */
770 void TextureAttrib::
771 register_with_read_factory() {
772  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
773 }
774 
775 /**
776  * Writes the contents of this object to the datagram for shipping out to a
777  * Bam file.
778  */
780 write_datagram(BamWriter *manager, Datagram &dg) {
781  RenderAttrib::write_datagram(manager, dg);
782 
783  // Write the off_stages information
784  dg.add_bool(_off_all_stages);
786  Stages::const_iterator fi;
787  for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) {
788  TextureStage *stage = (*fi)._stage;
789  manager->write_pointer(dg, stage);
790  }
791 
792  // Write the on_stages information
794  Stages::const_iterator si;
795  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
796  TextureStage *stage = (*si)._stage;
797  Texture *tex = (*si)._texture;
798  nassertv(tex != nullptr);
799 
800  manager->write_pointer(dg, stage);
801  manager->write_pointer(dg, tex);
802  dg.add_uint16((*si)._implicit_sort);
803 
804  if (manager->get_file_minor_ver() >= 23) {
805  dg.add_int32((*si)._override);
806  }
807 
808  if (manager->get_file_minor_ver() >= 36) {
809  dg.add_bool((*si)._has_sampler);
810  if ((*si)._has_sampler) {
811  (*si)._sampler.write_datagram(dg);
812  }
813  }
814  }
815 }
816 
817 /**
818  * Receives an array of pointers, one for each time manager->read_pointer()
819  * was called in fillin(). Returns the number of pointers processed.
820  */
822 complete_pointers(TypedWritable **p_list, BamReader *manager) {
823  int pi = RenderAttrib::complete_pointers(p_list, manager);
824 
825  Stages::iterator ci;
826  for (ci = _off_stages.begin(); ci != _off_stages.end(); ++ci) {
827  TextureStage *ts = DCAST(TextureStage, p_list[pi++]);
828  *ci = StageNode(ts);
829  }
830 
831  size_t sni = 0;
832  while (sni < _on_stages.size()) {
833  // Filter the TextureStage through the TextureStagePool.
834  PT(TextureStage) ts = DCAST(TextureStage, p_list[pi++]);
836 
837  // The Texture pointer filters itself through the TexturePool, so we don't
838  // have to do anything special here.
839  Texture *tex = DCAST(Texture, p_list[pi++]);
840 
841  if (tex != nullptr) {
842  StageNode &sn = _on_stages[sni];
843  sn._stage = ts;
844  sn._texture = tex;
845  ++sni;
846 
847  } else {
848  // If we couldn't load a texture pointer, turn off that particular
849  // texture stage.
850  _off_stages.push_back(StageNode(ts));
851  _on_stages.erase(_on_stages.begin() + sni);
852  }
853  }
854  _on_stages.sort();
855  _off_stages.sort();
856  _sort_seq = UpdateSeq::old();
857  _filtered_seq = UpdateSeq::old();
858 
859  return pi;
860 }
861 
862 /**
863  * This function is called by the BamReader's factory when a new object of
864  * type TextureAttrib is encountered in the Bam file. It should create the
865  * TextureAttrib and extract its information from the file.
866  */
867 TypedWritable *TextureAttrib::
868 make_from_bam(const FactoryParams &params) {
869  TextureAttrib *attrib = new TextureAttrib;
870  DatagramIterator scan;
871  BamReader *manager;
872 
873  parse_params(params, scan, manager);
874  attrib->fillin(scan, manager);
875 
876  return attrib;
877 }
878 
879 /**
880  * This internal function is called by make_from_bam to read in all of the
881  * relevant data from the BamFile for the new TextureAttrib.
882  */
883 void TextureAttrib::
884 fillin(DatagramIterator &scan, BamReader *manager) {
885  RenderAttrib::fillin(scan, manager);
886 
887  // read the _off_stages data.
888  _off_all_stages = scan.get_bool();
889  int num_off_stages = scan.get_uint16();
890 
891  // Push back a NULL pointer for each off TextureStage for now, until we get
892  // the actual list of pointers later in complete_pointers().
893  int i;
894  _off_stages.reserve(num_off_stages);
895  for (i = 0; i < num_off_stages; i++) {
896  manager->read_pointer(scan);
897  _off_stages.push_back(StageNode(nullptr));
898  }
899 
900  // Read the _on_stages data.
901  int num_on_stages = scan.get_uint16();
902 
903  // Push back a NULL pointer for each off TextureStage and Texture for now,
904  // until we get the actual list of pointers later in complete_pointers().
905  _on_stages.reserve(num_on_stages);
906  _next_implicit_sort = 0;
907  for (i = 0; i < num_on_stages; i++) {
908  manager->read_pointer(scan);
909  manager->read_pointer(scan);
910  unsigned int implicit_sort;
911  if (manager->get_file_minor_ver() >= 15) {
912  implicit_sort = scan.get_uint16();
913  } else {
914  implicit_sort = (unsigned int)i;
915  }
916  int override = 0;
917  if (manager->get_file_minor_ver() >= 23) {
918  override = scan.get_int32();
919  }
920 
921  _next_implicit_sort = std::max(_next_implicit_sort, implicit_sort + 1);
922  Stages::iterator si =
923  _on_stages.insert_nonunique(StageNode(nullptr, _next_implicit_sort, override));
924  ++_next_implicit_sort;
925 
926  if (manager->get_file_minor_ver() >= 36) {
927  (*si)._has_sampler = scan.get_bool();
928  if ((*si)._has_sampler) {
929  (*si)._sampler.read_datagram(scan, manager);
930  }
931  }
932  }
933 }
934 
935 /**
936  * Sorts the list of stages so that they are listed in render order. Also
937  * clears the _filtered map and recalculates the list of fixed-function
938  * stages.
939  */
940 void TextureAttrib::
941 sort_on_stages() {
942  typedef pmap<const InternalName *, int> UsedTexcoordIndex;
943  UsedTexcoordIndex used_texcoord_index;
944 
945  _render_stages.clear();
946  _render_ff_stages.clear();
947 
948  Stages::iterator si;
949  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
950  StageNode &sn = (*si);
951  TextureStage *stage = sn._stage;
952  Texture *texture = sn._texture;
953  nassertv(stage != nullptr);
954  nassertv(texture != nullptr);
955  if (stage->is_fixed_function() && texture->get_texture_type() != Texture::TT_2d_texture_array) {
956  const InternalName *name = stage->get_texcoord_name();
957 
958  // This pair of lines will get the next consecutive texcoord index
959  // number if this is the first time we have referenced this particular
960  // texcoord name; otherwise, it will return the same index number it
961  // returned before.
962  UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first;
963  (*si)._ff_tc_index = (*ti).second;
964 
965  _render_ff_stages.push_back(&sn);
966  } else {
967  (*si)._ff_tc_index = -1;
968  }
969 
970  _render_stages.push_back(&sn);
971  }
972 
973  sort(_render_stages.begin(), _render_stages.end(), CompareTextureStageSort());
974  sort(_render_ff_stages.begin(), _render_ff_stages.end(), CompareTextureStageSort());
975 
976  // We'd like to clear the _filtered map, in case the TextureStage priority
977  // values have changed as well, but we can't do that here: it's too
978  // dangerous. Clearing _filtered might cause TextureAttribs to be deleted,
979  // and hence removed from the map that we might be in the middle of
980  // traversing!
981 
982  _sort_seq = TextureStage::get_sort_seq();
983 }
ordered_vector::size
size_type_0 size() const
Returns the number of elements in the ordered vector.
Definition: ordered_vector.I:221
DatagramIterator::get_int32
int32_t get_int32()
Extracts a signed 32-bit integer.
Definition: datagramIterator.I:107
internalName.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
Texture::get_texture_type
get_texture_type
Returns the overall interpretation of the texture.
Definition: texture.h:357
ov_set::sort
void sort()
Maps to sort_unique().
Definition: ordered_vector.I:731
ordered_vector::reserve
void reserve(size_type_0 n)
Informs the vector of a planned change in size; ensures that the capacity of the vector is greater th...
Definition: ordered_vector.I:572
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
dcast.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable::complete_pointers
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: typedWritable.cxx:81
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
ordered_vector::empty
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
Definition: ordered_vector.I:240
RenderAttrib::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: renderAttrib.cxx:527
ordered_vector::begin
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
Definition: ordered_vector.I:41
textureStagePool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureAttrib::has_cull_callback
virtual bool has_cull_callback() const
Should be overridden by derived classes to return true if cull_callback() has been defined.
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
BamWriter::write_pointer
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
RenderAttrib
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
TextureStage::get_name
get_name
Returns the name of this texture stage.
Definition: textureStage.h:188
pointer_hash::add_hash
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:110
Texture
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureStagePool::get_stage
static TextureStage * get_stage(TextureStage *temp)
Returns a TextureStage pointer that represents the same TextureStage described by temp,...
Definition: textureStagePool.I:31
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
ordered_vector::end
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
Definition: ordered_vector.I:50
BamWriter::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
SamplerState
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:36
DatagramIterator::get_bool
bool get_bool()
Extracts a boolean value.
Definition: datagramIterator.I:48
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
CPT
CPT(RenderAttrib) TextureAttrib
Constructs a new TextureAttrib object suitable for rendering the indicated texture onto geometry,...
Definition: textureAttrib.cxx:34
ordered_vector::push_back
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
Definition: ordered_vector.I:614
TextureAttrib::find_on_stage
int find_on_stage(const TextureStage *stage) const
Returns the index number of the indicated TextureStage within the list of on_stages,...
Definition: textureAttrib.cxx:94
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
TextureAttrib::complete_pointers
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: textureAttrib.cxx:822
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Factory::register_factory
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
TextureAttrib::get_num_on_stages
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.h:55
Texture::cull_callback
virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const
If has_cull_callback() returns true, this function will be called during the cull traversal to perfor...
Definition: texture.cxx:2529
Datagram::add_int32
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:67
textureAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureAttrib::get_num_off_stages
get_num_off_stages
Returns the number of stages that are turned off by the attribute.
Definition: textureAttrib.h:77
integer_hash::add_hash
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:101
TextureAttrib::cull_callback
virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const
If has_cull_callback() returns true, this function will be called during the cull traversal to perfor...
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
TextureStage::is_fixed_function
bool is_fixed_function() const
Returns true if the TextureStage is relevant to the classic fixed function pipeline.
Definition: textureStage.I:193
TextureStage::get_texcoord_name
get_texcoord_name
See set_texcoord_name.
Definition: textureStage.h:192
Datagram::add_bool
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureStage::get_default
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Definition: textureStage.h:205
TextureAttrib::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: textureAttrib.cxx:780
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureAttrib
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
graphicsStateGuardianBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureStage
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
TextureStage::get_sort_seq
static UpdateSeq get_sort_seq()
Returns a global sequence number that is incremented any time any TextureStage in the world changes s...
Definition: textureStage.I:675
TextureAttrib::lower_attrib_can_override
virtual bool lower_attrib_can_override() const
Intended to be overridden by derived RenderAttrib types to specify how two consecutive RenderAttrib o...
parse_params
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
Texture::has_cull_callback
virtual bool has_cull_callback() const
Should be overridden by derived classes to return true if cull_callback() has been defined.
Definition: texture.cxx:2515