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