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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
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
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
bool get_bool()
Extracts a boolean value.
int32_t get_int32()
Extracts a signed 32-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:67
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:36
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
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...
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.h:55
virtual bool has_cull_callback() const
Should be overridden by derived classes to return true if cull_callback() has been defined.
virtual bool lower_attrib_can_override() const
Intended to be overridden by derived RenderAttrib types to specify how two consecutive RenderAttrib o...
int find_on_stage(const TextureStage *stage) const
Returns the index number of the indicated TextureStage within the list of on_stages,...
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
get_num_off_stages
Returns the number of stages that are turned off by the attribute.
Definition: textureAttrib.h:77
static TextureStage * get_stage(TextureStage *temp)
Returns a TextureStage pointer that represents the same TextureStage described by temp,...
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Definition: textureStage.h:207
get_name
Returns the name of this texture stage.
Definition: textureStage.h:190
bool is_fixed_function() const
Returns true if the TextureStage is relevant to the classic fixed function pipeline.
Definition: textureStage.I:193
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
get_texcoord_name
See set_texcoord_name.
Definition: textureStage.h:194
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
get_texture_type
Returns the overall interpretation of the texture.
Definition: texture.h:365
virtual bool has_cull_callback() const
Should be overridden by derived classes to return true if cull_callback() has been defined.
Definition: texture.cxx:2574
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:2588
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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().
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:101
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...
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
size_type_0 size() const
Returns the number of elements in the ordered vector.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void sort()
Maps to sort_unique().
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:110
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.
CPT(RenderAttrib) TextureAttrib
Constructs a new TextureAttrib object suitable for rendering the indicated texture onto geometry,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.