// Filename: textureReference.cxx // Created by: drose (29Nov00) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://www.panda3d.org/license.txt . // // To contact the maintainers of this program write to // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// #include "textureReference.h" #include "textureImage.h" #include "paletteImage.h" #include "sourceTextureImage.h" #include "destTextureImage.h" #include "texturePlacement.h" #include "palettizer.h" #include "eggFile.h" #include "indent.h" #include "eggTexture.h" #include "eggData.h" #include "eggGroupNode.h" #include "eggGroup.h" #include "eggNurbsSurface.h" #include "eggVertexPool.h" #include "datagram.h" #include "datagramIterator.h" #include "bamReader.h" #include "bamWriter.h" #include "string_utils.h" #include TypeHandle TextureReference::_type_handle; //////////////////////////////////////////////////////////////////// // Function: TextureReference::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// TextureReference:: TextureReference() { _egg_file = (EggFile *)NULL; _egg_tex = (EggTexture *)NULL; _tex_mat = LMatrix3d::ident_mat(); _inv_tex_mat = LMatrix3d::ident_mat(); _source_texture = (SourceTextureImage *)NULL; _placement = (TexturePlacement *)NULL; _uses_alpha = false; _any_uvs = false; _min_uv.set(0.0, 0.0); _max_uv.set(0.0, 0.0); _wrap_u = EggTexture::WM_unspecified; _wrap_v = EggTexture::WM_unspecified; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::Destructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// TextureReference:: ~TextureReference() { clear_placement(); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::from_egg // Access: Public // Description: Sets up the TextureReference using information // extracted from an egg file. //////////////////////////////////////////////////////////////////// void TextureReference:: from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex) { _egg_file = egg_file; _egg_tex = egg_tex; _egg_data = data; _tref_name = egg_tex->get_name(); if (_egg_tex->has_transform()) { _tex_mat = _egg_tex->get_transform(); if (!_inv_tex_mat.invert_from(_tex_mat)) { _inv_tex_mat = LMatrix3d::ident_mat(); } } else { _tex_mat = LMatrix3d::ident_mat(); _inv_tex_mat = LMatrix3d::ident_mat(); } Filename filename = _egg_tex->get_filename(); Filename alpha_filename; if (_egg_tex->has_alpha_filename()) { alpha_filename = _egg_tex->get_alpha_filename(); } int alpha_file_channel = _egg_tex->get_alpha_file_channel(); _properties._format = _egg_tex->get_format(); _properties._minfilter = _egg_tex->get_minfilter(); _properties._magfilter = _egg_tex->get_magfilter(); _properties._anisotropic_degree = _egg_tex->get_anisotropic_degree(); string name = filename.get_basename_wo_extension(); TextureImage *texture = pal->get_texture(name); _source_texture = texture->get_source(filename, alpha_filename, alpha_file_channel); _source_texture->update_properties(_properties); _uses_alpha = false; EggRenderMode::AlphaMode alpha_mode = _egg_tex->get_alpha_mode(); if (alpha_mode == EggRenderMode::AM_unspecified) { if (_source_texture->get_size()) { _uses_alpha = _egg_tex->has_alpha_channel(_source_texture->get_num_channels()); } } else if (alpha_mode == EggRenderMode::AM_off) { _uses_alpha = false; } else { _uses_alpha = true; } get_uv_range(_egg_data, pal->_remap_uv); _wrap_u = egg_tex->determine_wrap_u(); _wrap_v = egg_tex->determine_wrap_v(); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_egg_file // Access: Public // Description: Returns the EggFile that references this texture. //////////////////////////////////////////////////////////////////// EggFile *TextureReference:: get_egg_file() const { return _egg_file; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_source // Access: Public // Description: Returns the SourceTextureImage that this object // refers to. //////////////////////////////////////////////////////////////////// SourceTextureImage *TextureReference:: get_source() const { return _source_texture; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_texture // Access: Public // Description: Returns the TextureImage that this object refers to. //////////////////////////////////////////////////////////////////// TextureImage *TextureReference:: get_texture() const { nassertr(_source_texture != (SourceTextureImage *)NULL, (TextureImage *)NULL); return _source_texture->get_texture(); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_tref_name // Access: Public // Description: Returns the name of the EggTexture entry that // references this texture. //////////////////////////////////////////////////////////////////// const string &TextureReference:: get_tref_name() const { return _tref_name; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::operator < // Access: Public // Description: Defines an ordering of TextureReference pointers in // alphabetical order by their tref name. //////////////////////////////////////////////////////////////////// bool TextureReference:: operator < (const TextureReference &other) const { return _tref_name < other._tref_name; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::has_uvs // Access: Public // Description: Returns true if this TextureReference actually uses // the texture on geometry, with UV's and everything, or // false otherwise. Strictly speaking, this should // always return true. //////////////////////////////////////////////////////////////////// bool TextureReference:: has_uvs() const { return _any_uvs; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_min_uv // Access: Public // Description: Returns the minimum UV coordinate in use for the // texture by this reference. //////////////////////////////////////////////////////////////////// const TexCoordd &TextureReference:: get_min_uv() const { nassertr(_any_uvs, _min_uv); return _min_uv; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_max_uv // Access: Public // Description: Returns the maximum UV coordinate in use for the // texture by this reference. //////////////////////////////////////////////////////////////////// const TexCoordd &TextureReference:: get_max_uv() const { nassertr(_any_uvs, _max_uv); return _max_uv; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_wrap_u // Access: Public // Description: Returns the specification for the wrapping in the U // direction. //////////////////////////////////////////////////////////////////// EggTexture::WrapMode TextureReference:: get_wrap_u() const { return _wrap_u; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_wrap_v // Access: Public // Description: Returns the specification for the wrapping in the V // direction. //////////////////////////////////////////////////////////////////// EggTexture::WrapMode TextureReference:: get_wrap_v() const { return _wrap_v; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::is_equivalent // Access: Public // Description: Returns true if all essential properties of this // TextureReference are the same as that of the other, // or false if any of them differ. This is useful when // reading a new egg file and comparing its references // to its previously-defined references. //////////////////////////////////////////////////////////////////// bool TextureReference:: is_equivalent(const TextureReference &other) const { if (_source_texture != other._source_texture) { return false; } if (!_properties.egg_properties_match(other._properties)) { return false; } if (_uses_alpha != other._uses_alpha) { return false; } if (_any_uvs != other._any_uvs) { return false; } if (_wrap_u != other._wrap_u || _wrap_v != other._wrap_v) { return false; } if (_any_uvs) { if (!_min_uv.almost_equal(other._min_uv, 0.00001)) { return false; } if (!_max_uv.almost_equal(other._max_uv, 0.00001)) { return false; } } if (!_tex_mat.almost_equal(other._tex_mat, 0.00001)) { return false; } return true; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::set_placement // Access: Public // Description: Sets the particular TexturePlacement that is // appropriate for this egg file. This is called by // EggFile::choose_placements(). //////////////////////////////////////////////////////////////////// void TextureReference:: set_placement(TexturePlacement *placement) { if (_placement != placement) { if (_placement != (TexturePlacement *)NULL) { // Remove our reference from the old placement object. _placement->remove_egg(this); } _placement = placement; if (_placement != (TexturePlacement *)NULL) { // Add our reference to the new placement object. _placement->add_egg(this); } } } //////////////////////////////////////////////////////////////////// // Function: TextureReference::clear_placement // Access: Public // Description: Removes any reference to a TexturePlacement. //////////////////////////////////////////////////////////////////// void TextureReference:: clear_placement() { set_placement((TexturePlacement *)NULL); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_placement // Access: Public // Description: Returns the particular TexturePlacement that is // appropriate for this egg file. This will not be // filled in until EggFile::choose_placements() has been // called. //////////////////////////////////////////////////////////////////// TexturePlacement *TextureReference:: get_placement() const { return _placement; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::mark_egg_stale // Access: Public // Description: Marks the egg file that shares this reference as // stale. //////////////////////////////////////////////////////////////////// void TextureReference:: mark_egg_stale() { if (_egg_file != (EggFile *)NULL) { _egg_file->mark_stale(); } } //////////////////////////////////////////////////////////////////// // Function: TextureReference::update_egg // Access: Public // Description: Updates the egg file with all the relevant // information to reference the texture in its new home, // wherever that might be. //////////////////////////////////////////////////////////////////// void TextureReference:: update_egg() { if (_egg_tex == (EggTexture *)NULL) { // Not much we can do if we don't have an actual egg file to // reference. return; } nassertv(_placement != (TexturePlacement *)NULL); // Make sure the alpha mode is set according to what the texture // image wants. TextureImage *texture = get_texture(); if (texture != (TextureImage *)NULL) { if (texture->has_num_channels() && !_egg_tex->has_alpha_channel(texture->get_num_channels())) { // The egg file doesn't want to use the alpha on the texture; // leave it unspecified so the egg loader can figure out whether // to enable alpha or not based on the object color. _egg_tex->set_alpha_mode(EggRenderMode::AM_unspecified); } else { // The egg file does want alpha, so get the alpha mode from the // texture. EggRenderMode::AlphaMode am = texture->get_alpha_mode(); if (am != EggRenderMode::AM_unspecified) { _egg_tex->set_alpha_mode(am); } } } // We check for an OmitReason of OR_none, rather than asking // is_placed(), because in this case we don't want to consider an // OR_solitary texture as having been placed. if (_placement->get_omit_reason() == OR_unknown) { // The texture doesn't even exist. We can't update the egg to // point to any meaningful path; just leave it pointing to the // source texture's basename. Maybe it will be found along the // texture path later. Filename orig_filename = _egg_tex->get_filename(); texture->update_egg_tex(_egg_tex); _egg_tex->set_filename(orig_filename.get_basename()); return; } if (_placement->get_omit_reason() != OR_none) { // The texture exists but is not on a palette. This is the easy // case; we simply have to update the texture reference to the new // texture location. DestTextureImage *dest = _placement->get_dest(); nassertv(dest != (DestTextureImage *)NULL); dest->update_egg_tex(_egg_tex); return; } // The texture *does* appear on a palette. This means we need to // not only update the texture reference, but also adjust the UV's. // In most cases, we can do this by simply applying a texture matrix // to the reference. PaletteImage *image = _placement->get_image(); nassertv(image != (PaletteImage *)NULL); image->update_egg_tex(_egg_tex); // Palette images never wrap. _egg_tex->set_wrap_mode(EggTexture::WM_clamp); _egg_tex->set_wrap_u(EggTexture::WM_unspecified); _egg_tex->set_wrap_v(EggTexture::WM_unspecified); LMatrix3d new_tex_mat; _placement->compute_tex_matrix(new_tex_mat); // Compose the new texture matrix with whatever matrix was already // there, if any. _egg_tex->set_transform(_tex_mat * new_tex_mat); // Finally, go back and actually adjust the UV's to match what we // claimed they could be. update_uv_range(_egg_data, pal->_remap_uv); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::apply_properties_to_source // Access: Public // Description: Applies the texture properties as read from the egg // file to the source image's properties. This updates // the source image with the now-known properties // indicated with in the tref block of the egg file. //////////////////////////////////////////////////////////////////// void TextureReference:: apply_properties_to_source() { nassertv(_source_texture != (SourceTextureImage *)NULL); _source_texture->update_properties(_properties); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::output // Access: Public // Description: //////////////////////////////////////////////////////////////////// void TextureReference:: output(ostream &out) const { out << *_source_texture; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::write // Access: Public // Description: //////////////////////////////////////////////////////////////////// void TextureReference:: write(ostream &out, int indent_level) const { indent(out, indent_level) << get_texture()->get_name(); if (_uses_alpha) { out << " (uses alpha)"; } if (_any_uvs) { // Compute the fraction of the image that is covered by the UV's // minmax rectangle. TexCoordd box = _max_uv - _min_uv; double area = box[0] * box[1]; out << " coverage " << area; } if (_wrap_u != EggTexture::WM_unspecified || _wrap_v != EggTexture::WM_unspecified) { if (_wrap_u != _wrap_v) { out << " (" << _wrap_u << ", " << _wrap_v << ")"; } else { out << " " << _wrap_u; } } if (_properties._format != EggTexture::F_unspecified) { out << " " << _properties._format; } switch (_properties._minfilter) { case EggTexture::FT_nearest_mipmap_nearest: case EggTexture::FT_linear_mipmap_nearest: case EggTexture::FT_nearest_mipmap_linear: case EggTexture::FT_linear_mipmap_linear: out << " mipmap"; break; default: break; } if(_properties._anisotropic_degree>1) { out << " aniso " << _properties._anisotropic_degree; } out << "\n"; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_uv_range // Access: Private // Description: Checks the geometry in the egg file to see what range // of UV's are requested for this particular texture // reference. // // If pal->_remap_uv is not RU_never, this will also // attempt to remap the UV's found so that the midpoint // lies in the unit square (0,0) - (1,1), in the hopes // of maximizing overlap of UV coordinates between // different polygons. However, the hypothetical // translations are not actually applied to the egg file // at this point (because we might decide not to place // the texture in a palette); they will actually be // applied when update_uv_range(), below, is called // later. //////////////////////////////////////////////////////////////////// void TextureReference:: get_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) { if (group->is_of_type(EggGroup::get_class_type())) { EggGroup *egg_group; DCAST_INTO_V(egg_group, group); if (egg_group->get_dart_type() != EggGroup::DT_none) { // If it's a character, we might change the kind of remapping we // do. remap = pal->_remap_char_uv; } } bool group_any_uvs = false; TexCoordd group_min_uv, group_max_uv; EggGroupNode::iterator ci; for (ci = group->begin(); ci != group->end(); ci++) { EggNode *child = (*ci); if (child->is_of_type(EggNurbsSurface::get_class_type())) { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, child); if (nurbs->has_texture() && nurbs->get_texture() == _egg_tex) { // Here's a NURBS surface that references the texture. Unlike // other kinds of geometries, NURBS don't store UV's; they're // implicit in the surface. NURBS UV's will always run in the // range (0,0) - (1,1). However, we do need to apply the // texture matrix. // We also don't count the NURBS surfaces in with the group's // UV's, because we can't adjust the UV's on a NURBS, so // counting them up would be misleading (the reason we count // up the group UV's is so we can consider adjusting them // later). Instead, we just accumulate the NURBS UV's // directly into our total. static const int num_nurbs_uvs = 4; static TexCoordd nurbs_uvs[num_nurbs_uvs] = { TexCoordd(0.0, 0.0), TexCoordd(0.0, 1.0), TexCoordd(1.0, 1.0), TexCoordd(1.0, 0.0) }; for (int i = 0; i < num_nurbs_uvs; i++) { TexCoordd uv = nurbs_uvs[i] * _tex_mat; collect_uv(_any_uvs, _min_uv, _max_uv, uv, uv); } } } else if (child->is_of_type(EggPrimitive::get_class_type())) { EggPrimitive *geom = DCAST(EggPrimitive, child); if (geom->has_texture() && geom->get_texture() == _egg_tex) { // Here's a piece of geometry that references this texture. // Walk through its vertices and get its UV's. TexCoordd geom_min_uv, geom_max_uv; if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) { if (remap == Palettizer::RU_poly) { LVector2d trans = translate_uv(geom_min_uv, geom_max_uv); geom_min_uv += trans; geom_max_uv += trans; } collect_uv(group_any_uvs, group_min_uv, group_max_uv, geom_min_uv, geom_max_uv); } } } else if (child->is_of_type(EggGroupNode::get_class_type())) { EggGroupNode *cg = DCAST(EggGroupNode, child); get_uv_range(cg, remap); } } if (group_any_uvs) { if (remap == Palettizer::RU_group) { LVector2d trans = translate_uv(group_min_uv, group_max_uv); group_min_uv += trans; group_max_uv += trans; } collect_uv(_any_uvs, _min_uv, _max_uv, group_min_uv, group_max_uv); } } //////////////////////////////////////////////////////////////////// // Function: TextureReference::update_uv_range // Access: Private // Description: Actually applies the UV translates that were assumed // in the previous call to get_uv_range(). //////////////////////////////////////////////////////////////////// void TextureReference:: update_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) { if (group->is_of_type(EggGroup::get_class_type())) { EggGroup *egg_group; DCAST_INTO_V(egg_group, group); if (egg_group->get_dart_type() != EggGroup::DT_none) { // If it's a character, we might change the kind of remapping we // do. remap = pal->_remap_char_uv; } } bool group_any_uvs = false; TexCoordd group_min_uv, group_max_uv; EggGroupNode::iterator ci; for (ci = group->begin(); ci != group->end(); ci++) { EggNode *child = (*ci); if (child->is_of_type(EggNurbsSurface::get_class_type())) { // We do nothing at this point for a Nurbs. Nothing we can do // about these things. } else if (child->is_of_type(EggPrimitive::get_class_type())) { if (remap != Palettizer::RU_never) { EggPrimitive *geom = DCAST(EggPrimitive, child); if (geom->has_texture() && geom->get_texture() == _egg_tex) { TexCoordd geom_min_uv, geom_max_uv; if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) { if (remap == Palettizer::RU_poly) { LVector2d trans = translate_uv(geom_min_uv, geom_max_uv); trans = trans * _inv_tex_mat; if (!trans.almost_equal(LVector2d::zero())) { translate_geom_uvs(geom, trans); } } else { collect_uv(group_any_uvs, group_min_uv, group_max_uv, geom_min_uv, geom_max_uv); } } } } } else if (child->is_of_type(EggGroupNode::get_class_type())) { EggGroupNode *cg = DCAST(EggGroupNode, child); update_uv_range(cg, remap); } } if (group_any_uvs && remap == Palettizer::RU_group) { LVector2d trans = translate_uv(group_min_uv, group_max_uv); trans = trans * _inv_tex_mat; if (!trans.almost_equal(LVector2d::zero())) { for (ci = group->begin(); ci != group->end(); ci++) { EggNode *child = (*ci); if (child->is_of_type(EggPrimitive::get_class_type())) { EggPrimitive *geom = DCAST(EggPrimitive, child); if (geom->has_texture() && geom->get_texture() == _egg_tex) { translate_geom_uvs(geom, trans); } } } } } } //////////////////////////////////////////////////////////////////// // Function: TextureReference::get_geom_uvs // Access: Private // Description: Determines the minimum and maximum UV range for a // particular primitive. Returns true if it has any // UV's, false otherwise. //////////////////////////////////////////////////////////////////// bool TextureReference:: get_geom_uvs(EggPrimitive *geom, TexCoordd &geom_min_uv, TexCoordd &geom_max_uv) { bool geom_any_uvs = false; EggPrimitive::iterator pi; for (pi = geom->begin(); pi != geom->end(); ++pi) { EggVertex *vtx = (*pi); if (vtx->has_uv()) { TexCoordd uv = vtx->get_uv() * _tex_mat; collect_uv(geom_any_uvs, geom_min_uv, geom_max_uv, uv, uv); } } return geom_any_uvs; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::translate_geom_uvs // Access: Private // Description: Applies the indicated translation to each UV in the // primitive. //////////////////////////////////////////////////////////////////// void TextureReference:: translate_geom_uvs(EggPrimitive *geom, const TexCoordd &trans) const { EggPrimitive::iterator pi; for (pi = geom->begin(); pi != geom->end(); ++pi) { EggVertex *vtx = (*pi); if (vtx->has_uv()) { EggVertex vtx_copy(*vtx); vtx_copy.set_uv(vtx_copy.get_uv() + trans); EggVertex *new_vtx = vtx->get_pool()->create_unique_vertex(vtx_copy); if (new_vtx->gref_size() != vtx->gref_size()) { new_vtx->copy_grefs_from(*vtx); } geom->replace(pi, new_vtx); } } } //////////////////////////////////////////////////////////////////// // Function: TextureReference::collect_uv // Access: Private, Static // Description: Updates any_uvs, min_uv, and max_uv with the // indicated min and max UV's already determined. //////////////////////////////////////////////////////////////////// void TextureReference:: collect_uv(bool &any_uvs, TexCoordd &min_uv, TexCoordd &max_uv, const TexCoordd &got_min_uv, const TexCoordd &got_max_uv) { if (any_uvs) { min_uv.set(min(min_uv[0], got_min_uv[0]), min(min_uv[1], got_min_uv[1])); max_uv.set(max(max_uv[0], got_max_uv[0]), max(max_uv[1], got_max_uv[1])); } else { // The first UV. min_uv = got_min_uv; max_uv = got_max_uv; any_uvs = true; } } //////////////////////////////////////////////////////////////////// // Function: TextureReference::translate_uv // Access: Private, Static // Description: Returns the needed adjustment to translate the given // bounding box so that its center lies in the unit // square (0,0) - (1,1). //////////////////////////////////////////////////////////////////// LVector2d TextureReference:: translate_uv(const TexCoordd &min_uv, const TexCoordd &max_uv) { TexCoordd center = (min_uv + max_uv) / 2; return LVector2d(-floor(center[0]), -floor(center[1])); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::register_with_read_factory // Access: Public, Static // Description: Registers the current object as something that can be // read from a Bam file. //////////////////////////////////////////////////////////////////// void TextureReference:: register_with_read_factory() { BamReader::get_factory()-> register_factory(get_class_type(), make_TextureReference); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::write_datagram // Access: Public, Virtual // Description: Fills the indicated datagram up with a binary // representation of the current object, in preparation // for writing to a Bam file. //////////////////////////////////////////////////////////////////// void TextureReference:: write_datagram(BamWriter *writer, Datagram &datagram) { TypedWritable::write_datagram(writer, datagram); writer->write_pointer(datagram, _egg_file); // We don't write _egg_tex or _egg_data; that's specific to the // session. datagram.add_string(_tref_name); _tex_mat.write_datagram(datagram); _inv_tex_mat.write_datagram(datagram); writer->write_pointer(datagram, _source_texture); writer->write_pointer(datagram, _placement); datagram.add_bool(_uses_alpha); datagram.add_bool(_any_uvs); datagram.add_float64(_min_uv[0]); datagram.add_float64(_min_uv[1]); datagram.add_float64(_max_uv[0]); datagram.add_float64(_max_uv[1]); datagram.add_int32((int)_wrap_u); datagram.add_int32((int)_wrap_v); _properties.write_datagram(writer, datagram); } //////////////////////////////////////////////////////////////////// // Function: TextureReference::complete_pointers // Access: Public, Virtual // Description: Called after the object is otherwise completely read // from a Bam file, this function's job is to store the // pointers that were retrieved from the Bam file for // each pointer object written. The return value is the // number of pointers processed from the list. //////////////////////////////////////////////////////////////////// int TextureReference:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = TypedWritable::complete_pointers(p_list, manager); if (p_list[pi] != (TypedWritable *)NULL) { DCAST_INTO_R(_egg_file, p_list[pi], pi); } pi++; if (p_list[pi] != (TypedWritable *)NULL) { DCAST_INTO_R(_source_texture, p_list[pi], pi); } pi++; if (p_list[pi] != (TypedWritable *)NULL) { DCAST_INTO_R(_placement, p_list[pi], pi); } pi++; pi += _properties.complete_pointers(p_list + pi, manager); return pi; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::make_TextureReference // Access: Protected // Description: This method is called by the BamReader when an object // of this type is encountered in a Bam file; it should // allocate and return a new object with all the data // read. //////////////////////////////////////////////////////////////////// TypedWritable* TextureReference:: make_TextureReference(const FactoryParams ¶ms) { TextureReference *me = new TextureReference; DatagramIterator scan; BamReader *manager; parse_params(params, scan, manager); me->fillin(scan, manager); return me; } //////////////////////////////////////////////////////////////////// // Function: TextureReference::fillin // Access: Protected // Description: Reads the binary data from the given datagram // iterator, which was written by a previous call to // write_datagram(). //////////////////////////////////////////////////////////////////// void TextureReference:: fillin(DatagramIterator &scan, BamReader *manager) { TypedWritable::fillin(scan, manager); manager->read_pointer(scan); // _egg_file if (Palettizer::_read_pi_version >= 11) { _tref_name = scan.get_string(); } _tex_mat.read_datagram(scan); _inv_tex_mat.read_datagram(scan); manager->read_pointer(scan); // _source_texture manager->read_pointer(scan); // _placement _uses_alpha = scan.get_bool(); _any_uvs = scan.get_bool(); _min_uv[0] = scan.get_float64(); _min_uv[1] = scan.get_float64(); _max_uv[0] = scan.get_float64(); _max_uv[1] = scan.get_float64(); _wrap_u = (EggTexture::WrapMode)scan.get_int32(); _wrap_v = (EggTexture::WrapMode)scan.get_int32(); _properties.fillin(scan, manager); }