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