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