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