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