Panda3D
Loading...
Searching...
No Matches
textureReference.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 textureReference.cxx
10 * @author drose
11 * @date 2000-11-29
12 */
13
14#include "textureReference.h"
15#include "textureImage.h"
16#include "paletteImage.h"
17#include "sourceTextureImage.h"
18#include "destTextureImage.h"
19#include "texturePlacement.h"
20#include "palettizer.h"
21#include "eggFile.h"
22
23#include "indent.h"
24#include "eggTexture.h"
25#include "eggData.h"
26#include "eggGroupNode.h"
27#include "eggGroup.h"
28#include "eggNurbsSurface.h"
29#include "eggVertexPool.h"
30#include "datagram.h"
31#include "datagramIterator.h"
32#include "bamReader.h"
33#include "bamWriter.h"
34#include "string_utils.h"
35
36#include <math.h>
37
38using std::max;
39using std::min;
40using std::string;
41
42TypeHandle TextureReference::_type_handle;
43
44/**
45 *
46 */
47TextureReference::
48TextureReference() {
49 _egg_file = nullptr;
50 _egg_tex = nullptr;
51 _tex_mat = LMatrix3d::ident_mat();
52 _inv_tex_mat = LMatrix3d::ident_mat();
53 _source_texture = nullptr;
54 _placement = nullptr;
55 _uses_alpha = false;
56 _any_uvs = false;
57 _min_uv.set(0.0, 0.0);
58 _max_uv.set(0.0, 0.0);
59 _wrap_u = EggTexture::WM_unspecified;
60 _wrap_v = EggTexture::WM_unspecified;
61}
62
63/**
64 *
65 */
66TextureReference::
67~TextureReference() {
69}
70
71/**
72 * Sets up the TextureReference using information extracted from an egg file.
73 */
75from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex) {
76 _egg_file = egg_file;
77 _egg_tex = egg_tex;
78 _egg_data = data;
79 _tref_name = egg_tex->get_name();
80
81 if (_egg_tex->has_transform2d()) {
82 _tex_mat = _egg_tex->get_transform2d();
83 if (!_inv_tex_mat.invert_from(_tex_mat)) {
84 _inv_tex_mat = LMatrix3d::ident_mat();
85 }
86 } else {
87 _tex_mat = LMatrix3d::ident_mat();
88 _inv_tex_mat = LMatrix3d::ident_mat();
89 }
90
91 Filename filename = _egg_tex->get_filename();
92 Filename alpha_filename;
93 if (_egg_tex->has_alpha_filename()) {
94 alpha_filename = _egg_tex->get_alpha_filename();
95 }
96 int alpha_file_channel = _egg_tex->get_alpha_file_channel();
97
98 _properties._format = _egg_tex->get_format();
99 _properties._minfilter = _egg_tex->get_minfilter();
100 _properties._magfilter = _egg_tex->get_magfilter();
101 _properties._quality_level = _egg_tex->get_quality_level();
102 _properties._anisotropic_degree = _egg_tex->get_anisotropic_degree();
103
104 string name = filename.get_basename_wo_extension();
105 TextureImage *texture = pal->get_texture(name);
106 if (texture->get_name() != name) {
107 nout << "Texture name conflict: \"" << name
108 << "\" conflicts with existing texture named \""
109 << texture->get_name() << "\".\n";
110
111 // Make this a hard error; refuse to do anything else until the user fixes
112 // it. Case conflicts can be very bad, especially if CVS is involved on a
113 // Windows machine.
114 exit(1);
115 }
116 _source_texture = texture->get_source(filename, alpha_filename,
117 alpha_file_channel);
118 _source_texture->update_properties(_properties);
119
120 _uses_alpha = false;
121 EggRenderMode::AlphaMode alpha_mode = _egg_tex->get_alpha_mode();
122 if (alpha_mode == EggRenderMode::AM_unspecified) {
123 if (_source_texture->get_size()) {
124 _uses_alpha =
125 _egg_tex->has_alpha_channel(_source_texture->get_num_channels());
126 }
127
128 } else if (alpha_mode == EggRenderMode::AM_off) {
129 _uses_alpha = false;
130
131 } else {
132 _uses_alpha = true;
133 }
134
135 get_uv_range(_egg_data, pal->_remap_uv);
136
137 _wrap_u = _egg_tex->determine_wrap_u();
138 _wrap_v = _egg_tex->determine_wrap_v();
139}
140
141/**
142 * Sets up the pointers within the TextureReference to the same egg file
143 * pointers indicated by the other TextureReference object, without changing
144 * any of the other internal data stored here regarding the egg structures.
145 * This is intended for use when we have already shown that the two
146 * TextureReferences describe equivalent data.
147 */
149from_egg_quick(const TextureReference &other) {
150 nassertv(_tref_name == other._tref_name);
151 _egg_file = other._egg_file;
152 _egg_tex = other._egg_tex;
153 _egg_data = other._egg_data;
154}
155
156/**
157 * Called to indicate that the EggData previously passed to from_egg() is
158 * about to be deallocated, and all of its pointers should be cleared.
159 */
162 _egg_tex = nullptr;
163 _egg_data = nullptr;
164}
165
166/**
167 * After an EggData has previously been released via release_egg_data(), this
168 * can be called to indicate that the egg file has been reloaded and we should
169 * assign the indicated pointers.
170 */
172rebind_egg_data(EggData *data, EggTexture *egg_tex) {
173 nassertv(_tref_name == egg_tex->get_name());
174 _egg_data = data;
175 _egg_tex = egg_tex;
176}
177
178/**
179 * Returns the EggFile that references this texture.
180 */
182get_egg_file() const {
183 return _egg_file;
184}
185
186/**
187 * Returns the SourceTextureImage that this object refers to.
188 */
190get_source() const {
191 return _source_texture;
192}
193
194/**
195 * Returns the TextureImage that this object refers to.
196 */
198get_texture() const {
199 nassertr(_source_texture != nullptr, nullptr);
200 return _source_texture->get_texture();
201}
202
203/**
204 * Returns the name of the EggTexture entry that references this texture.
205 */
207get_tref_name() const {
208 return _tref_name;
209}
210
211/**
212 * Defines an ordering of TextureReference pointers in alphabetical order by
213 * their tref name.
214 */
216operator < (const TextureReference &other) const {
217 return _tref_name < other._tref_name;
218}
219
220/**
221 * Returns true if this TextureReference actually uses the texture on
222 * geometry, with UV's and everything, or false otherwise. Strictly speaking,
223 * this should always return true.
224 */
226has_uvs() const {
227 return _any_uvs;
228}
229
230/**
231 * Returns the minimum UV coordinate in use for the texture by this reference.
232 */
233const LTexCoordd &TextureReference::
234get_min_uv() const {
235 nassertr(_any_uvs, _min_uv);
236 return _min_uv;
237}
238
239/**
240 * Returns the maximum UV coordinate in use for the texture by this reference.
241 */
242const LTexCoordd &TextureReference::
243get_max_uv() const {
244 nassertr(_any_uvs, _max_uv);
245 return _max_uv;
246}
247
248/**
249 * Returns the specification for the wrapping in the U direction.
250 */
251EggTexture::WrapMode TextureReference::
252get_wrap_u() const {
253 return _wrap_u;
254}
255
256/**
257 * Returns the specification for the wrapping in the V direction.
258 */
259EggTexture::WrapMode TextureReference::
260get_wrap_v() const {
261 return _wrap_v;
262}
263
264/**
265 * Returns true if all essential properties of this TextureReference are the
266 * same as that of the other, or false if any of them differ. This is useful
267 * when reading a new egg file and comparing its references to its previously-
268 * defined references.
269 */
271is_equivalent(const TextureReference &other) const {
272 if (_source_texture != other._source_texture) {
273 return false;
274 }
275 if (!_properties.egg_properties_match(other._properties)) {
276 return false;
277 }
278 if (_uses_alpha != other._uses_alpha) {
279 return false;
280 }
281 if (_any_uvs != other._any_uvs) {
282 return false;
283 }
284 if (_wrap_u != other._wrap_u ||
285 _wrap_v != other._wrap_v) {
286 return false;
287 }
288 if (_any_uvs) {
289 if (!_min_uv.almost_equal(other._min_uv, 0.00001)) {
290 return false;
291 }
292 if (!_max_uv.almost_equal(other._max_uv, 0.00001)) {
293 return false;
294 }
295 }
296 if (!_tex_mat.almost_equal(other._tex_mat, 0.00001)) {
297 return false;
298 }
299
300 return true;
301}
302
303/**
304 * Sets the particular TexturePlacement that is appropriate for this egg file.
305 * This is called by EggFile::choose_placements().
306 */
309 if (_placement != placement) {
310 if (_placement != nullptr) {
311 // Remove our reference from the old placement object.
312 _placement->remove_egg(this);
313 }
314 _placement = placement;
315 if (_placement != nullptr) {
316 // Add our reference to the new placement object.
317 _placement->add_egg(this);
318 }
319 }
320}
321
322/**
323 * Removes any reference to a TexturePlacement.
324 */
327 set_placement(nullptr);
328}
329
330/**
331 * Returns the particular TexturePlacement that is appropriate for this egg
332 * file. This will not be filled in until EggFile::choose_placements() has
333 * been called.
334 */
336get_placement() const {
337 return _placement;
338}
339
340/**
341 * Marks the egg file that shares this reference as stale.
342 */
345 if (_egg_file != nullptr) {
346 _egg_file->mark_stale();
347 }
348}
349
350/**
351 * Updates the egg file with all the relevant information to reference the
352 * texture in its new home, wherever that might be.
353 */
355update_egg() {
356 if (_egg_tex == nullptr) {
357 // Not much we can do if we don't have an actual egg file to reference.
358 return;
359 }
360
361 if (_placement == nullptr) {
362 // Nor if we don't have an actual placement yet. This is possible if the
363 // egg was assigned to the "null" group, and the texture hasn't been re-
364 // assigned yet.
365 return;
366 }
367
368 TextureImage *texture = get_texture();
369 if (texture != nullptr) {
370 // Make sure the alpha mode is set according to what the texture image
371 // wants.
372 if (texture->has_num_channels() &&
373 !_egg_tex->has_alpha_channel(texture->get_num_channels())) {
374 // The egg file doesn't want to use the alpha on the texture; leave it
375 // unspecified so the egg loader can figure out whether to enable alpha
376 // or not based on the object color.
377 _egg_tex->set_alpha_mode(EggRenderMode::AM_unspecified);
378
379 } else {
380 // The egg file does want alpha, so get the alpha mode from the texture.
381 EggRenderMode::AlphaMode am = texture->get_alpha_mode();
382 if (am != EggRenderMode::AM_unspecified) {
383 _egg_tex->set_alpha_mode(am);
384 }
385 }
386
387 // Also make sure the wrap mode is set properly.
388 if (texture->get_txa_wrap_u() != EggTexture::WM_unspecified) {
389 _egg_tex->set_wrap_u(texture->get_txa_wrap_u());
390 }
391 if (texture->get_txa_wrap_v() != EggTexture::WM_unspecified) {
392 _egg_tex->set_wrap_v(texture->get_txa_wrap_v());
393 }
394 }
395
396 // We check for an OmitReason of OR_none, rather than asking is_placed(),
397 // because in this case we don't want to consider an OR_solitary texture as
398 // having been placed.
399 if (_placement->get_omit_reason() == OR_unknown) {
400 // The texture doesn't even exist. We can't update the egg to point to
401 // any meaningful path; just leave it pointing to the source texture's
402 // basename. Maybe it will be found along the texture path later.
403 Filename orig_filename = _egg_tex->get_filename();
404 texture->update_egg_tex(_egg_tex);
405 _egg_tex->set_filename(orig_filename.get_basename());
406 return;
407 }
408 if (_placement->get_omit_reason() != OR_none) {
409 // The texture exists but is not on a palette. This is the easy case; we
410 // simply have to update the texture reference to the new texture
411 // location.
412 DestTextureImage *dest = _placement->get_dest();
413 nassertv(dest != nullptr);
414 dest->update_egg_tex(_egg_tex);
415 return;
416 }
417
418 // The texture *does* appear on a palette. This means we need to not only
419 // update the texture reference, but also adjust the UV's. In most cases,
420 // we can do this by simply applying a texture matrix to the reference.
421 PaletteImage *image = _placement->get_image();
422 nassertv(image != nullptr);
423
424 image->update_egg_tex(_egg_tex);
425
426 // Palette images never wrap, so the wrap mode doesn't matter. We let this
427 // default to unspecified, which means the images will wrap by default,
428 // which is the fastest mode for tinydisplay anyway.
429 _egg_tex->set_wrap_mode(EggTexture::WM_unspecified);
430 _egg_tex->set_wrap_u(EggTexture::WM_unspecified);
431 _egg_tex->set_wrap_v(EggTexture::WM_unspecified);
432
433 LMatrix3d new_tex_mat;
434 _placement->compute_tex_matrix(new_tex_mat);
435
436 // Compose the new texture matrix with whatever matrix was already there, if
437 // any.
438 _egg_tex->set_transform2d(_tex_mat * new_tex_mat);
439
440 // Finally, go back and actually adjust the UV's to match what we claimed
441 // they could be.
442 if (_egg_tex->get_tex_gen() == EggTexture::TG_unspecified) {
443 update_uv_range(_egg_data, pal->_remap_uv);
444 }
445}
446
447/**
448 * Applies the texture properties as read from the egg file to the source
449 * image's properties. This updates the source image with the now-known
450 * properties indicated with in the tref block of the egg file.
451 */
454 nassertv(_source_texture != nullptr);
455 _source_texture->update_properties(_properties);
456}
457
458/**
459 *
460 */
461void TextureReference::
462output(std::ostream &out) const {
463 out << *_source_texture;
464}
465
466/**
467 *
468 */
469void TextureReference::
470write(std::ostream &out, int indent_level) const {
471 indent(out, indent_level)
472 << get_texture()->get_name();
473
474 if (_uses_alpha) {
475 out << " (uses alpha)";
476 }
477
478 if (_any_uvs) {
479 // Compute the fraction of the image that is covered by the UV's minmax
480 // rectangle.
481 LTexCoordd box = _max_uv - _min_uv;
482 double area = box[0] * box[1];
483
484 out << " coverage " << area;
485 }
486
487 if (_wrap_u != EggTexture::WM_unspecified ||
488 _wrap_v != EggTexture::WM_unspecified) {
489 if (_wrap_u != _wrap_v) {
490 out << " (" << _wrap_u << ", " << _wrap_v << ")";
491 } else {
492 out << " " << _wrap_u;
493 }
494 }
495
496 if (_properties._format != EggTexture::F_unspecified) {
497 out << " " << _properties._format;
498 }
499
500 switch (_properties._minfilter) {
501 case EggTexture::FT_nearest_mipmap_nearest:
502 case EggTexture::FT_linear_mipmap_nearest:
503 case EggTexture::FT_nearest_mipmap_linear:
504 case EggTexture::FT_linear_mipmap_linear:
505 out << " mipmap";
506 break;
507
508 default:
509 break;
510 }
511
512 if(_properties._anisotropic_degree>1) {
513 out << " aniso " << _properties._anisotropic_degree;
514 }
515
516 out << "\n";
517}
518
519
520/**
521 * Checks the geometry in the egg file to see what range of UV's are requested
522 * for this particular texture reference.
523 *
524 * If pal->_remap_uv is not RU_never, this will also attempt to remap the UV's
525 * found so that the midpoint lies in the unit square (0,0) - (1,1), in the
526 * hopes of maximizing overlap of UV coordinates between different polygons.
527 * However, the hypothetical translations are not actually applied to the egg
528 * file at this point (because we might decide not to place the texture in a
529 * palette); they will actually be applied when update_uv_range(), below, is
530 * called later.
531 *
532 * The return value is true if the search should continue, or false if it
533 * should abort prematurely.
534 */
535bool TextureReference::
536get_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) {
537 if (group->is_of_type(EggGroup::get_class_type())) {
538 EggGroup *egg_group;
539 DCAST_INTO_R(egg_group, group, false);
540
541 if (egg_group->get_dart_type() != EggGroup::DT_none) {
542 // If it's a character, we might change the kind of remapping we do.
543 remap = pal->_remap_char_uv;
544 }
545 }
546
547 bool group_any_uvs = false;
548 LTexCoordd group_min_uv, group_max_uv;
549
550 EggGroupNode::iterator ci;
551 for (ci = group->begin(); ci != group->end(); ci++) {
552 EggNode *child = (*ci);
553 if (child->is_of_type(EggNurbsSurface::get_class_type())) {
554 EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, child);
555 if (nurbs->has_texture(_egg_tex)) {
556 // Here's a NURBS surface that references the texture. Unlike other
557 // kinds of geometries, NURBS don't store UV's; they're implicit in
558 // the surface. NURBS UV's will always run in the range (0, 0) - (1,
559 // 1). However, we do need to apply the texture matrix.
560
561 // We also don't count the NURBS surfaces in with the group's UV's,
562 // because we can't adjust the UV's on a NURBS, so counting them up
563 // would be misleading (the reason we count up the group UV's is so we
564 // can consider adjusting them later). Instead, we just accumulate
565 // the NURBS UV's directly into our total.
566 collect_nominal_uv_range();
567 }
568
569 } else if (child->is_of_type(EggPrimitive::get_class_type())) {
570 EggPrimitive *geom = DCAST(EggPrimitive, child);
571 if (geom->has_texture(_egg_tex)) {
572 // Here's a piece of geometry that references this texture. Walk
573 // through its vertices and get its UV's.
574
575 if (_egg_tex->get_tex_gen() != EggTexture::TG_unspecified) {
576 // If the texture has a TexGen mode, we don't check the UV range on
577 // the model, since that doesn't matter. Instead, we assume the
578 // texture is used in the range (0, 0) - (1, 1), which will be true
579 // for a sphere map, although the effective range is a little less
580 // clear for the TG_world_position and similar modes.
581 collect_nominal_uv_range();
582
583 // In fact, now we can return, having found at least one model that
584 // references the texture; there's no need to search further.
585 return false;
586
587 } else {
588 LTexCoordd geom_min_uv, geom_max_uv;
589
590 if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) {
591 if (remap == Palettizer::RU_poly) {
592 LVector2d trans = translate_uv(geom_min_uv, geom_max_uv);
593 geom_min_uv += trans;
594 geom_max_uv += trans;
595 }
596 collect_uv(group_any_uvs, group_min_uv, group_max_uv,
597 geom_min_uv, geom_max_uv);
598 }
599 }
600 }
601
602 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
603 EggGroupNode *cg = DCAST(EggGroupNode, child);
604 if (!get_uv_range(cg, remap)) {
605 return false;
606 }
607 }
608 }
609
610 if (group_any_uvs) {
611 if (remap == Palettizer::RU_group) {
612 LVector2d trans = translate_uv(group_min_uv, group_max_uv);
613 group_min_uv += trans;
614 group_max_uv += trans;
615 }
616 collect_uv(_any_uvs, _min_uv, _max_uv, group_min_uv, group_max_uv);
617 }
618
619 return true;
620}
621
622/**
623 * Actually applies the UV translates that were assumed in the previous call
624 * to get_uv_range().
625 */
626void TextureReference::
627update_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) {
628 if (group->is_of_type(EggGroup::get_class_type())) {
629 EggGroup *egg_group;
630 DCAST_INTO_V(egg_group, group);
631
632 if (egg_group->get_dart_type() != EggGroup::DT_none) {
633 // If it's a character, we might change the kind of remapping we do.
634 remap = pal->_remap_char_uv;
635 }
636 }
637
638 bool group_any_uvs = false;
639 LTexCoordd group_min_uv, group_max_uv;
640
641 EggGroupNode::iterator ci;
642 for (ci = group->begin(); ci != group->end(); ci++) {
643 EggNode *child = (*ci);
644 if (child->is_of_type(EggNurbsSurface::get_class_type())) {
645 // We do nothing at this point for a Nurbs. Nothing we can do about
646 // these things.
647
648 } else if (child->is_of_type(EggPrimitive::get_class_type())) {
649 if (remap != Palettizer::RU_never) {
650 EggPrimitive *geom = DCAST(EggPrimitive, child);
651 if (geom->has_texture(_egg_tex)) {
652 LTexCoordd geom_min_uv, geom_max_uv;
653
654 if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) {
655 if (remap == Palettizer::RU_poly) {
656 LVector2d trans = translate_uv(geom_min_uv, geom_max_uv);
657 trans = trans * _inv_tex_mat;
658 if (!trans.almost_equal(LVector2d::zero())) {
659 translate_geom_uvs(geom, trans);
660 }
661 } else {
662 collect_uv(group_any_uvs, group_min_uv, group_max_uv,
663 geom_min_uv, geom_max_uv);
664 }
665 }
666 }
667 }
668
669 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
670 EggGroupNode *cg = DCAST(EggGroupNode, child);
671 update_uv_range(cg, remap);
672 }
673 }
674
675 if (group_any_uvs && remap == Palettizer::RU_group) {
676 LVector2d trans = translate_uv(group_min_uv, group_max_uv);
677 trans = trans * _inv_tex_mat;
678 if (!trans.almost_equal(LVector2d::zero())) {
679 for (ci = group->begin(); ci != group->end(); ci++) {
680 EggNode *child = (*ci);
681 if (child->is_of_type(EggPrimitive::get_class_type())) {
682 EggPrimitive *geom = DCAST(EggPrimitive, child);
683 if (geom->has_texture(_egg_tex)) {
684 translate_geom_uvs(geom, trans);
685 }
686 }
687 }
688 }
689 }
690}
691
692/**
693 * Determines the minimum and maximum UV range for a particular primitive.
694 * Returns true if it has any UV's, false otherwise.
695 */
696bool TextureReference::
697get_geom_uvs(EggPrimitive *geom,
698 LTexCoordd &geom_min_uv, LTexCoordd &geom_max_uv) {
699 string uv_name = _egg_tex->get_uv_name();
700 bool geom_any_uvs = false;
701
702 EggPrimitive::iterator pi;
703 for (pi = geom->begin(); pi != geom->end(); ++pi) {
704 EggVertex *vtx = (*pi);
705 if (vtx->has_uv(uv_name)) {
706 LTexCoordd uv = vtx->get_uv(uv_name) * _tex_mat;
707 collect_uv(geom_any_uvs, geom_min_uv, geom_max_uv, uv, uv);
708 }
709 }
710
711 return geom_any_uvs;
712}
713
714/**
715 * Applies the indicated translation to each UV in the primitive.
716 */
717void TextureReference::
718translate_geom_uvs(EggPrimitive *geom, const LTexCoordd &trans) const {
719 string uv_name = _egg_tex->get_uv_name();
720
721 EggPrimitive::iterator pi;
722 for (pi = geom->begin(); pi != geom->end(); ++pi) {
723 EggVertex *vtx = (*pi);
724 if (vtx->has_uv(uv_name)) {
725 EggVertex vtx_copy(*vtx);
726 vtx_copy.set_uv(uv_name, vtx_copy.get_uv(uv_name) + trans);
727 EggVertex *new_vtx = vtx->get_pool()->create_unique_vertex(vtx_copy);
728
729 if (new_vtx->gref_size() != vtx->gref_size()) {
730 new_vtx->copy_grefs_from(*vtx);
731 }
732
733 geom->replace(pi, new_vtx);
734 }
735 }
736}
737
738/**
739 * Updates _any_uvs, _min_uv, and _max_uv with the range (0, 0) - (1, 1),
740 * adjusted by the texture matrix.
741 */
742void TextureReference::
743collect_nominal_uv_range() {
744 static const int num_nurbs_uvs = 4;
745 static LTexCoordd nurbs_uvs[num_nurbs_uvs] = {
746 LTexCoordd(0.0, 0.0),
747 LTexCoordd(0.0, 1.0),
748 LTexCoordd(1.0, 1.0),
749 LTexCoordd(1.0, 0.0)
750 };
751
752 for (int i = 0; i < num_nurbs_uvs; i++) {
753 LTexCoordd uv = nurbs_uvs[i] * _tex_mat;
754 collect_uv(_any_uvs, _min_uv, _max_uv, uv, uv);
755 }
756}
757
758/**
759 * Updates any_uvs, min_uv, and max_uv with the indicated min and max UV's
760 * already determined.
761 */
762void TextureReference::
763collect_uv(bool &any_uvs, LTexCoordd &min_uv, LTexCoordd &max_uv,
764 const LTexCoordd &got_min_uv, const LTexCoordd &got_max_uv) {
765 if (any_uvs) {
766 min_uv.set(min(min_uv[0], got_min_uv[0]),
767 min(min_uv[1], got_min_uv[1]));
768 max_uv.set(max(max_uv[0], got_max_uv[0]),
769 max(max_uv[1], got_max_uv[1]));
770 } else {
771 // The first UV.
772 min_uv = got_min_uv;
773 max_uv = got_max_uv;
774 any_uvs = true;
775 }
776}
777
778/**
779 * Returns the needed adjustment to translate the given bounding box so that
780 * its center lies in the unit square (0,0) - (1,1).
781 */
782LVector2d TextureReference::
783translate_uv(const LTexCoordd &min_uv, const LTexCoordd &max_uv) {
784 LTexCoordd center = (min_uv + max_uv) / 2;
785 return LVector2d(-floor(center[0]), -floor(center[1]));
786}
787
788/**
789 * Registers the current object as something that can be read from a Bam file.
790 */
794 register_factory(get_class_type(), make_TextureReference);
795}
796
797/**
798 * Fills the indicated datagram up with a binary representation of the current
799 * object, in preparation for writing to a Bam file.
800 */
802write_datagram(BamWriter *writer, Datagram &datagram) {
803 TypedWritable::write_datagram(writer, datagram);
804 writer->write_pointer(datagram, _egg_file);
805
806 // We don't write _egg_tex or _egg_data; that's specific to the session.
807
808 datagram.add_string(_tref_name);
809
810 _tex_mat.write_datagram(datagram);
811 _inv_tex_mat.write_datagram(datagram);
812
813 writer->write_pointer(datagram, _source_texture);
814 writer->write_pointer(datagram, _placement);
815
816 datagram.add_bool(_uses_alpha);
817 datagram.add_bool(_any_uvs);
818 datagram.add_float64(_min_uv[0]);
819 datagram.add_float64(_min_uv[1]);
820 datagram.add_float64(_max_uv[0]);
821 datagram.add_float64(_max_uv[1]);
822 datagram.add_int32((int)_wrap_u);
823 datagram.add_int32((int)_wrap_v);
824 _properties.write_datagram(writer, datagram);
825}
826
827/**
828 * Called after the object is otherwise completely read from a Bam file, this
829 * function's job is to store the pointers that were retrieved from the Bam
830 * file for each pointer object written. The return value is the number of
831 * pointers processed from the list.
832 */
834complete_pointers(TypedWritable **p_list, BamReader *manager) {
835 int pi = TypedWritable::complete_pointers(p_list, manager);
836
837 if (p_list[pi] != nullptr) {
838 DCAST_INTO_R(_egg_file, p_list[pi], pi);
839 }
840 pi++;
841
842 if (p_list[pi] != nullptr) {
843 DCAST_INTO_R(_source_texture, p_list[pi], pi);
844 }
845 pi++;
846
847 if (p_list[pi] != nullptr) {
848 DCAST_INTO_R(_placement, p_list[pi], pi);
849 }
850 pi++;
851
852 pi += _properties.complete_pointers(p_list + pi, manager);
853
854 return pi;
855}
856
857/**
858 * This method is called by the BamReader when an object of this type is
859 * encountered in a Bam file; it should allocate and return a new object with
860 * all the data read.
861 */
862TypedWritable* TextureReference::
863make_TextureReference(const FactoryParams &params) {
865 DatagramIterator scan;
866 BamReader *manager;
867
868 parse_params(params, scan, manager);
869 me->fillin(scan, manager);
870 return me;
871}
872
873/**
874 * Reads the binary data from the given datagram iterator, which was written
875 * by a previous call to write_datagram().
876 */
877void TextureReference::
878fillin(DatagramIterator &scan, BamReader *manager) {
879 TypedWritable::fillin(scan, manager);
880 manager->read_pointer(scan); // _egg_file
881
882 if (Palettizer::_read_pi_version >= 11) {
883 _tref_name = scan.get_string();
884 }
885
886 _tex_mat.read_datagram(scan);
887 _inv_tex_mat.read_datagram(scan);
888
889 manager->read_pointer(scan); // _source_texture
890 manager->read_pointer(scan); // _placement
891
892 _uses_alpha = scan.get_bool();
893 _any_uvs = scan.get_bool();
894 _min_uv[0] = scan.get_float64();
895 _min_uv[1] = scan.get_float64();
896 _max_uv[0] = scan.get_float64();
897 _max_uv[1] = scan.get_float64();
898 _wrap_u = (EggTexture::WrapMode)scan.get_int32();
899 _wrap_v = (EggTexture::WrapMode)scan.get_int32();
900 _properties.fillin(scan, manager);
901}
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.
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.
A class to retrieve the individual data elements previously stored in a Datagram.
PN_float64 get_float64()
Extracts a 64-bit floating-point number.
bool get_bool()
Extracts a boolean value.
std::string get_string()
Extracts a variable-length string.
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_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition datagram.I:219
void add_float64(PN_float64 value)
Adds a 64-bit floating-point number to the datagram.
Definition datagram.I:123
This represents a texture filename as it has been resized and copied to the map directory (e....
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
This represents a single egg file known to the palettizer.
Definition eggFile.h:36
void mark_stale()
Marks this particular egg file as stale, meaning that something has changed, such as the location of ...
Definition eggFile.cxx:304
const Filename & get_filename() const
Returns a nonmodifiable reference to the filename.
A base class for nodes in the hierarchy that are not leaf nodes.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition eggGroup.h:34
A base class for things that may be directly added into the egg hierarchy.
Definition eggNode.h:36
A parametric NURBS surface.
A base class for any of a number of kinds of geometry primitives: polygons, point lights,...
bool has_texture() const
Returns true if the primitive has any textures specified, false otherwise.
void replace(iterator position, EggVertex *vertex)
Replaces the vertex at the indicated position with the indicated vertex.
void set_alpha_mode(AlphaMode mode)
Specifies precisely how the transparency for this geometry should be achieved, or if it should be use...
AlphaMode get_alpha_mode() const
Returns the alpha mode that was set, or AM_unspecified if nothing was set.
Defines a texture map that may be applied to geometry.
Definition eggTexture.h:30
WrapMode determine_wrap_u() const
Determines the appropriate wrap in the U direction.
Definition eggTexture.I:107
get_uv_name
Returns the texcoord name that has been specified for this texture, or the empty string if no texcoor...
Definition eggTexture.h:341
get_alpha_file_channel
Returns the particular channel that has been specified for the alpha-file image, or 0 if no channel h...
Definition eggTexture.h:350
bool has_alpha_channel(int num_components) const
Given the number of color components (channels) in the image file as actually read from the disk,...
WrapMode determine_wrap_v() const
Determines the appropriate wrap in the V direction.
Definition eggTexture.I:134
get_anisotropic_degree
Returns the anisotropic filtering degree that has been specified for this texture,...
Definition eggTexture.h:327
get_alpha_filename
Returns the separate file assigned for the alpha channel.
Definition eggTexture.h:347
has_alpha_filename
Returns true if a separate file for the alpha component has been applied, false otherwise.
Definition eggTexture.h:347
bool has_transform2d() const
Returns true if the transform is specified as a 2-d transform, e.g.
void set_transform2d(const LMatrix3d &mat)
Sets the overall transform as a 3x3 matrix.
LMatrix3d get_transform2d() const
Returns the overall transform as a 3x3 matrix.
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition eggVertex.h:39
bool has_uv() const
Returns true if the vertex has an unnamed UV coordinate pair, false otherwise.
Definition eggVertex.I:158
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition eggVertex.I:19
LTexCoordd get_uv() const
Returns the unnamed UV coordinate pair on the vertex.
Definition eggVertex.I:179
GroupRef::size_type gref_size() const
Returns the number of elements between gref_begin() and gref_end().
void copy_grefs_from(const EggVertex &other)
Copies all the group references from the other vertex onto this one.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
std::string get_basename() const
Returns the basename part of the filename.
Definition filename.I:367
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition filename.I:386
void update_egg_tex(EggTexture *egg_tex) const
Sets the indicated EggTexture to refer to this file.
int get_num_channels() const
Returns the number of channels of the image.
void update_properties(const TextureProperties &properties)
If the indicate TextureProperties structure is more specific than this one, updates this one.
bool has_num_channels() const
Returns true if the number of channels in the image is known, false otherwise.
This is a single palette image, one of several within a PalettePage, which is in turn one of several ...
TextureImage * get_texture(const std::string &name)
Returns the TextureImage with the given name.
This is a texture image reference as it appears in an egg file: the source image of the texture.
bool get_size()
Determines the size of the SourceTextureImage, if it is not already known.
TextureImage * get_texture() const
Returns the particular texture that this image is one of the sources for.
This represents a single source texture that is referenced by one or more egg files.
EggTexture::WrapMode get_txa_wrap_v() const
Returns the wrap mode specified in the v direction in the txa file, or WM_unspecified.
EggRenderMode::AlphaMode get_alpha_mode() const
Returns the alpha mode that should be used to render objects with this texture, as specified by the u...
SourceTextureImage * get_source(const Filename &filename, const Filename &alpha_filename, int alpha_file_channel)
Returns the SourceTextureImage corresponding to the given filename(s).
EggTexture::WrapMode get_txa_wrap_u() const
Returns the wrap mode specified in the u direction in the txa file, or WM_unspecified.
This corresponds to a particular assignment of a TextureImage with a PaletteGroup,...
OmitReason get_omit_reason() const
Returns the reason the texture has been omitted from a palette image, or OR_none if it has not.
DestTextureImage * get_dest() const
Returns the DestTextureImage that corresponds to this texture as it was copied to the install directo...
void remove_egg(TextureReference *reference)
Notes that a particular egg file is no longer using this particular TexturePlacement.
void add_egg(TextureReference *reference)
Records the fact that a particular egg file is using this particular TexturePlacement.
PaletteImage * get_image() const
Returns the particular PaletteImage on which the texture has been placed.
void compute_tex_matrix(LMatrix3d &transform)
Stores in the indicated matrix the appropriate texture matrix transform for the new placement of the ...
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Called after the object is otherwise completely read from a Bam file, this function's job is to store...
bool egg_properties_match(const TextureProperties &other) const
Returns true if all of the properties that are reflected directly in an egg file match between this T...
void fillin(DatagramIterator &scan, BamReader *manager)
Reads the binary data from the given datagram iterator, which was written by a previous call to write...
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object,...
This is the particular reference of a texture filename by an egg file.
bool has_uvs() const
Returns true if this TextureReference actually uses the texture on geometry, with UV's and everything...
const std::string & get_tref_name() const
Returns the name of the EggTexture entry that references this texture.
bool is_equivalent(const TextureReference &other) const
Returns true if all essential properties of this TextureReference are the same as that of the other,...
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
void apply_properties_to_source()
Applies the texture properties as read from the egg file to the source image's properties.
void update_egg()
Updates the egg file with all the relevant information to reference the texture in its new home,...
const LTexCoordd & get_max_uv() const
Returns the maximum UV coordinate in use for the texture by this reference.
void from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex)
Sets up the TextureReference using information extracted from an egg file.
void clear_placement()
Removes any reference to a TexturePlacement.
void rebind_egg_data(EggData *data, EggTexture *egg_tex)
After an EggData has previously been released via release_egg_data(), this can be called to indicate ...
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Called after the object is otherwise completely read from a Bam file, this function's job is to store...
EggTexture::WrapMode get_wrap_u() const
Returns the specification for the wrapping in the U direction.
void set_placement(TexturePlacement *placement)
Sets the particular TexturePlacement that is appropriate for this egg file.
bool operator<(const TextureReference &other) const
Defines an ordering of TextureReference pointers in alphabetical order by their tref name.
EggFile * get_egg_file() const
Returns the EggFile that references this texture.
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object,...
EggTexture::WrapMode get_wrap_v() const
Returns the specification for the wrapping in the V direction.
TexturePlacement * get_placement() const
Returns the particular TexturePlacement that is appropriate for this egg file.
const LTexCoordd & get_min_uv() const
Returns the minimum UV coordinate in use for the texture by this reference.
TextureImage * get_texture() const
Returns the TextureImage that this object refers to.
SourceTextureImage * get_source() const
Returns the SourceTextureImage that this object refers to.
void from_egg_quick(const TextureReference &other)
Sets up the pointers within the TextureReference to the same egg file pointers indicated by the other...
void release_egg_data()
Called to indicate that the EggData previously passed to from_egg() is about to be deallocated,...
void mark_egg_stale()
Marks the egg file that shares this reference as stale.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
Base class for objects that can be written to and read from Bam files.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
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 int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.