Panda3D

textureReference.cxx

00001 // Filename: textureReference.cxx
00002 // Created by:  drose (29Nov00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "textureReference.h"
00016 #include "textureImage.h"
00017 #include "paletteImage.h"
00018 #include "sourceTextureImage.h"
00019 #include "destTextureImage.h"
00020 #include "texturePlacement.h"
00021 #include "palettizer.h"
00022 #include "eggFile.h"
00023 
00024 #include "indent.h"
00025 #include "eggTexture.h"
00026 #include "eggData.h"
00027 #include "eggGroupNode.h"
00028 #include "eggGroup.h"
00029 #include "eggNurbsSurface.h"
00030 #include "eggVertexPool.h"
00031 #include "datagram.h"
00032 #include "datagramIterator.h"
00033 #include "bamReader.h"
00034 #include "bamWriter.h"
00035 #include "string_utils.h"
00036 
00037 #include <math.h>
00038 
00039 TypeHandle TextureReference::_type_handle;
00040 
00041 ////////////////////////////////////////////////////////////////////
00042 //     Function: TextureReference::Constructor
00043 //       Access: Public
00044 //  Description:
00045 ////////////////////////////////////////////////////////////////////
00046 TextureReference::
00047 TextureReference() {
00048   _egg_file = (EggFile *)NULL;
00049   _egg_tex = (EggTexture *)NULL;
00050   _tex_mat = LMatrix3d::ident_mat();
00051   _inv_tex_mat = LMatrix3d::ident_mat();
00052   _source_texture = (SourceTextureImage *)NULL;
00053   _placement = (TexturePlacement *)NULL;
00054   _uses_alpha = false;
00055   _any_uvs = false;
00056   _min_uv.set(0.0, 0.0);
00057   _max_uv.set(0.0, 0.0);
00058   _wrap_u = EggTexture::WM_unspecified;
00059   _wrap_v = EggTexture::WM_unspecified;
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: TextureReference::Destructor
00064 //       Access: Public
00065 //  Description:
00066 ////////////////////////////////////////////////////////////////////
00067 TextureReference::
00068 ~TextureReference() {
00069   clear_placement();
00070 }
00071 
00072 ////////////////////////////////////////////////////////////////////
00073 //     Function: TextureReference::from_egg
00074 //       Access: Public
00075 //  Description: Sets up the TextureReference using information
00076 //               extracted from an egg file.
00077 ////////////////////////////////////////////////////////////////////
00078 void TextureReference::
00079 from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex) {
00080   _egg_file = egg_file;
00081   _egg_tex = egg_tex;
00082   _egg_data = data;
00083   _tref_name = egg_tex->get_name();
00084 
00085   if (_egg_tex->has_transform2d()) {
00086     _tex_mat = _egg_tex->get_transform2d();
00087     if (!_inv_tex_mat.invert_from(_tex_mat)) {
00088       _inv_tex_mat = LMatrix3d::ident_mat();
00089     }
00090   } else {
00091     _tex_mat = LMatrix3d::ident_mat();
00092     _inv_tex_mat = LMatrix3d::ident_mat();
00093   }
00094 
00095   Filename filename = _egg_tex->get_filename();
00096   Filename alpha_filename;
00097   if (_egg_tex->has_alpha_filename()) {
00098     alpha_filename = _egg_tex->get_alpha_filename();
00099   }
00100   int alpha_file_channel = _egg_tex->get_alpha_file_channel();
00101 
00102   _properties._format = _egg_tex->get_format();
00103   _properties._minfilter = _egg_tex->get_minfilter();
00104   _properties._magfilter = _egg_tex->get_magfilter();
00105   _properties._quality_level = _egg_tex->get_quality_level();
00106   _properties._anisotropic_degree = _egg_tex->get_anisotropic_degree();
00107 
00108   string name = filename.get_basename_wo_extension();
00109   TextureImage *texture = pal->get_texture(name);
00110   if (texture->get_name() != name) {
00111     nout << "Texture name conflict: \"" << name
00112          << "\" conflicts with existing texture named \"" 
00113          << texture->get_name() << "\".\n";
00114 
00115     // Make this a hard error; refuse to do anything else until the
00116     // user fixes it.  Case conflicts can be very bad, especially if
00117     // CVS is involved on a Windows machine.
00118     exit(1);
00119   }
00120   _source_texture = texture->get_source(filename, alpha_filename, 
00121                                         alpha_file_channel);
00122   _source_texture->update_properties(_properties);
00123 
00124   _uses_alpha = false;
00125   EggRenderMode::AlphaMode alpha_mode = _egg_tex->get_alpha_mode();
00126   if (alpha_mode == EggRenderMode::AM_unspecified) {
00127     if (_source_texture->get_size()) {
00128       _uses_alpha =
00129         _egg_tex->has_alpha_channel(_source_texture->get_num_channels());
00130     }
00131 
00132   } else if (alpha_mode == EggRenderMode::AM_off) {
00133     _uses_alpha = false;
00134 
00135   } else {
00136     _uses_alpha = true;
00137   }
00138 
00139   get_uv_range(_egg_data, pal->_remap_uv);
00140 
00141   _wrap_u = _egg_tex->determine_wrap_u();
00142   _wrap_v = _egg_tex->determine_wrap_v();
00143 }
00144 
00145 ////////////////////////////////////////////////////////////////////
00146 //     Function: TextureReference::from_egg_quick
00147 //       Access: Public
00148 //  Description: Sets up the pointers within the TextureReference
00149 //               to the same egg file pointers indicated by the other
00150 //               TextureReference object, without changing any of the
00151 //               other internal data stored here regarding the egg
00152 //               structures.  This is intended for use when we have
00153 //               already shown that the two TextureReferences describe
00154 //               equivalent data.
00155 ////////////////////////////////////////////////////////////////////
00156 void TextureReference::
00157 from_egg_quick(const TextureReference &other) {
00158   nassertv(_tref_name == other._tref_name);
00159   _egg_file = other._egg_file;
00160   _egg_tex = other._egg_tex;
00161   _egg_data = other._egg_data;
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: TextureReference::release_egg_data
00166 //       Access: Public
00167 //  Description: Called to indicate that the EggData previously passed
00168 //               to from_egg() is about to be deallocated, and all of
00169 //               its pointers should be cleared.
00170 ////////////////////////////////////////////////////////////////////
00171 void TextureReference::
00172 release_egg_data() {
00173   _egg_tex = NULL;
00174   _egg_data = NULL;
00175 }
00176 
00177 ////////////////////////////////////////////////////////////////////
00178 //     Function: TextureReference::rebind_egg_data
00179 //       Access: Public
00180 //  Description: After an EggData has previously been released via
00181 //               release_egg_data(), this can be called to indicate
00182 //               that the egg file has been reloaded and we should
00183 //               assign the indicated pointers.
00184 ////////////////////////////////////////////////////////////////////
00185 void TextureReference::
00186 rebind_egg_data(EggData *data, EggTexture *egg_tex) {
00187   nassertv(_tref_name == egg_tex->get_name());
00188   _egg_data = data;
00189   _egg_tex = egg_tex;
00190 }
00191 
00192 ////////////////////////////////////////////////////////////////////
00193 //     Function: TextureReference::get_egg_file
00194 //       Access: Public
00195 //  Description: Returns the EggFile that references this texture.
00196 ////////////////////////////////////////////////////////////////////
00197 EggFile *TextureReference::
00198 get_egg_file() const {
00199   return _egg_file;
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: TextureReference::get_source
00204 //       Access: Public
00205 //  Description: Returns the SourceTextureImage that this object
00206 //               refers to.
00207 ////////////////////////////////////////////////////////////////////
00208 SourceTextureImage *TextureReference::
00209 get_source() const {
00210   return _source_texture;
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: TextureReference::get_texture
00215 //       Access: Public
00216 //  Description: Returns the TextureImage that this object refers to.
00217 ////////////////////////////////////////////////////////////////////
00218 TextureImage *TextureReference::
00219 get_texture() const {
00220   nassertr(_source_texture != (SourceTextureImage *)NULL, (TextureImage *)NULL);
00221   return _source_texture->get_texture();
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: TextureReference::get_tref_name
00226 //       Access: Public
00227 //  Description: Returns the name of the EggTexture entry that
00228 //               references this texture.
00229 ////////////////////////////////////////////////////////////////////
00230 const string &TextureReference::
00231 get_tref_name() const {
00232   return _tref_name;
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: TextureReference::operator <
00237 //       Access: Public
00238 //  Description: Defines an ordering of TextureReference pointers in
00239 //               alphabetical order by their tref name.
00240 ////////////////////////////////////////////////////////////////////
00241 bool TextureReference::
00242 operator < (const TextureReference &other) const {
00243   return _tref_name < other._tref_name;
00244 }
00245 
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: TextureReference::has_uvs
00248 //       Access: Public
00249 //  Description: Returns true if this TextureReference actually uses
00250 //               the texture on geometry, with UV's and everything, or
00251 //               false otherwise.  Strictly speaking, this should
00252 //               always return true.
00253 ////////////////////////////////////////////////////////////////////
00254 bool TextureReference::
00255 has_uvs() const {
00256   return _any_uvs;
00257 }
00258 
00259 ////////////////////////////////////////////////////////////////////
00260 //     Function: TextureReference::get_min_uv
00261 //       Access: Public
00262 //  Description: Returns the minimum UV coordinate in use for the
00263 //               texture by this reference.
00264 ////////////////////////////////////////////////////////////////////
00265 const LTexCoordd &TextureReference::
00266 get_min_uv() const {
00267   nassertr(_any_uvs, _min_uv);
00268   return _min_uv;
00269 }
00270 
00271 ////////////////////////////////////////////////////////////////////
00272 //     Function: TextureReference::get_max_uv
00273 //       Access: Public
00274 //  Description: Returns the maximum UV coordinate in use for the
00275 //               texture by this reference.
00276 ////////////////////////////////////////////////////////////////////
00277 const LTexCoordd &TextureReference::
00278 get_max_uv() const {
00279   nassertr(_any_uvs, _max_uv);
00280   return _max_uv;
00281 }
00282 
00283 ////////////////////////////////////////////////////////////////////
00284 //     Function: TextureReference::get_wrap_u
00285 //       Access: Public
00286 //  Description: Returns the specification for the wrapping in the U
00287 //               direction.
00288 ////////////////////////////////////////////////////////////////////
00289 EggTexture::WrapMode TextureReference::
00290 get_wrap_u() const {
00291   return _wrap_u;
00292 }
00293 
00294 ////////////////////////////////////////////////////////////////////
00295 //     Function: TextureReference::get_wrap_v
00296 //       Access: Public
00297 //  Description: Returns the specification for the wrapping in the V
00298 //               direction.
00299 ////////////////////////////////////////////////////////////////////
00300 EggTexture::WrapMode TextureReference::
00301 get_wrap_v() const {
00302   return _wrap_v;
00303 }
00304 
00305 ////////////////////////////////////////////////////////////////////
00306 //     Function: TextureReference::is_equivalent
00307 //       Access: Public
00308 //  Description: Returns true if all essential properties of this
00309 //               TextureReference are the same as that of the other,
00310 //               or false if any of them differ.  This is useful when
00311 //               reading a new egg file and comparing its references
00312 //               to its previously-defined references.
00313 ////////////////////////////////////////////////////////////////////
00314 bool TextureReference::
00315 is_equivalent(const TextureReference &other) const {
00316   if (_source_texture != other._source_texture) {
00317     return false;
00318   }
00319   if (!_properties.egg_properties_match(other._properties)) {
00320     return false;
00321   }
00322   if (_uses_alpha != other._uses_alpha) {
00323     return false;
00324   }
00325   if (_any_uvs != other._any_uvs) {
00326     return false;
00327   }
00328   if (_wrap_u != other._wrap_u ||
00329       _wrap_v != other._wrap_v) {
00330     return false;
00331   }
00332   if (_any_uvs) {
00333     if (!_min_uv.almost_equal(other._min_uv, 0.00001)) {
00334       return false;
00335     }
00336     if (!_max_uv.almost_equal(other._max_uv, 0.00001)) {
00337       return false;
00338     }
00339   }
00340   if (!_tex_mat.almost_equal(other._tex_mat, 0.00001)) {
00341     return false;
00342   }
00343 
00344   return true;
00345 }
00346 
00347 ////////////////////////////////////////////////////////////////////
00348 //     Function: TextureReference::set_placement
00349 //       Access: Public
00350 //  Description: Sets the particular TexturePlacement that is
00351 //               appropriate for this egg file.  This is called by
00352 //               EggFile::choose_placements().
00353 ////////////////////////////////////////////////////////////////////
00354 void TextureReference::
00355 set_placement(TexturePlacement *placement) {
00356   if (_placement != placement) {
00357     if (_placement != (TexturePlacement *)NULL) {
00358       // Remove our reference from the old placement object.
00359       _placement->remove_egg(this);
00360     }
00361     _placement = placement;
00362     if (_placement != (TexturePlacement *)NULL) {
00363       // Add our reference to the new placement object.
00364       _placement->add_egg(this);
00365     }
00366   }
00367 }
00368 
00369 ////////////////////////////////////////////////////////////////////
00370 //     Function: TextureReference::clear_placement
00371 //       Access: Public
00372 //  Description: Removes any reference to a TexturePlacement.
00373 ////////////////////////////////////////////////////////////////////
00374 void TextureReference::
00375 clear_placement() {
00376   set_placement((TexturePlacement *)NULL);
00377 }
00378 
00379 ////////////////////////////////////////////////////////////////////
00380 //     Function: TextureReference::get_placement
00381 //       Access: Public
00382 //  Description: Returns the particular TexturePlacement that is
00383 //               appropriate for this egg file.  This will not be
00384 //               filled in until EggFile::choose_placements() has been
00385 //               called.
00386 ////////////////////////////////////////////////////////////////////
00387 TexturePlacement *TextureReference::
00388 get_placement() const {
00389   return _placement;
00390 }
00391 
00392 ////////////////////////////////////////////////////////////////////
00393 //     Function: TextureReference::mark_egg_stale
00394 //       Access: Public
00395 //  Description: Marks the egg file that shares this reference as
00396 //               stale.
00397 ////////////////////////////////////////////////////////////////////
00398 void TextureReference::
00399 mark_egg_stale() {
00400   if (_egg_file != (EggFile *)NULL) {
00401     _egg_file->mark_stale();
00402   }
00403 }
00404 
00405 ////////////////////////////////////////////////////////////////////
00406 //     Function: TextureReference::update_egg
00407 //       Access: Public
00408 //  Description: Updates the egg file with all the relevant
00409 //               information to reference the texture in its new home,
00410 //               wherever that might be.
00411 ////////////////////////////////////////////////////////////////////
00412 void TextureReference::
00413 update_egg() {
00414   if (_egg_tex == (EggTexture *)NULL) {
00415     // Not much we can do if we don't have an actual egg file to
00416     // reference.
00417     return;
00418   }
00419 
00420   if (_placement == (TexturePlacement *)NULL) {
00421     // Nor if we don't have an actual placement yet.  This is possible
00422     // if the egg was assigned to the "null" group, and the texture
00423     // hasn't been re-assigned yet.
00424     return;
00425   }
00426 
00427   TextureImage *texture = get_texture();
00428   if (texture != (TextureImage *)NULL) {
00429     // Make sure the alpha mode is set according to what the texture
00430     // image wants.
00431     if (texture->has_num_channels() && 
00432         !_egg_tex->has_alpha_channel(texture->get_num_channels())) {
00433       // The egg file doesn't want to use the alpha on the texture;
00434       // leave it unspecified so the egg loader can figure out whether
00435       // to enable alpha or not based on the object color.
00436       _egg_tex->set_alpha_mode(EggRenderMode::AM_unspecified);
00437 
00438     } else {
00439       // The egg file does want alpha, so get the alpha mode from the
00440       // texture.
00441       EggRenderMode::AlphaMode am = texture->get_alpha_mode();
00442       if (am != EggRenderMode::AM_unspecified) {
00443         _egg_tex->set_alpha_mode(am);
00444       }
00445     }
00446 
00447     // Also make sure the wrap mode is set properly.
00448     if (texture->get_txa_wrap_u() != EggTexture::WM_unspecified) {
00449       _egg_tex->set_wrap_u(texture->get_txa_wrap_u());
00450     }
00451     if (texture->get_txa_wrap_v() != EggTexture::WM_unspecified) {
00452       _egg_tex->set_wrap_v(texture->get_txa_wrap_v());
00453     }
00454   }
00455 
00456   // We check for an OmitReason of OR_none, rather than asking
00457   // is_placed(), because in this case we don't want to consider an
00458   // OR_solitary texture as having been placed.
00459   if (_placement->get_omit_reason() == OR_unknown) {
00460     // The texture doesn't even exist.  We can't update the egg to
00461     // point to any meaningful path; just leave it pointing to the
00462     // source texture's basename.  Maybe it will be found along the
00463     // texture path later.
00464     Filename orig_filename = _egg_tex->get_filename();
00465     texture->update_egg_tex(_egg_tex);
00466     _egg_tex->set_filename(orig_filename.get_basename());
00467     return;
00468   }
00469   if (_placement->get_omit_reason() != OR_none) {
00470     // The texture exists but is not on a palette.  This is the easy
00471     // case; we simply have to update the texture reference to the new
00472     // texture location.
00473     DestTextureImage *dest = _placement->get_dest();
00474     nassertv(dest != (DestTextureImage *)NULL);
00475     dest->update_egg_tex(_egg_tex);
00476     return;
00477   }
00478 
00479   // The texture *does* appear on a palette.  This means we need to
00480   // not only update the texture reference, but also adjust the UV's.
00481   // In most cases, we can do this by simply applying a texture matrix
00482   // to the reference.
00483   PaletteImage *image = _placement->get_image();
00484   nassertv(image != (PaletteImage *)NULL);
00485 
00486   image->update_egg_tex(_egg_tex);
00487 
00488   // Palette images never wrap, so the wrap mode doesn't matter.  We
00489   // let this default to unspecified, which means the images will
00490   // wrap by default, which is the fastest mode for tinydisplay anyway.
00491   _egg_tex->set_wrap_mode(EggTexture::WM_unspecified);
00492   _egg_tex->set_wrap_u(EggTexture::WM_unspecified);
00493   _egg_tex->set_wrap_v(EggTexture::WM_unspecified);
00494 
00495   LMatrix3d new_tex_mat;
00496   _placement->compute_tex_matrix(new_tex_mat);
00497 
00498   // Compose the new texture matrix with whatever matrix was already
00499   // there, if any.
00500   _egg_tex->set_transform2d(_tex_mat * new_tex_mat);
00501 
00502   // Finally, go back and actually adjust the UV's to match what we
00503   // claimed they could be.
00504   if (_egg_tex->get_tex_gen() == EggTexture::TG_unspecified) {
00505     update_uv_range(_egg_data, pal->_remap_uv);
00506   }
00507 }
00508 
00509 ////////////////////////////////////////////////////////////////////
00510 //     Function: TextureReference::apply_properties_to_source
00511 //       Access: Public
00512 //  Description: Applies the texture properties as read from the egg
00513 //               file to the source image's properties.  This updates
00514 //               the source image with the now-known properties
00515 //               indicated with in the tref block of the egg file.
00516 ////////////////////////////////////////////////////////////////////
00517 void TextureReference::
00518 apply_properties_to_source() {
00519   nassertv(_source_texture != (SourceTextureImage *)NULL);
00520   _source_texture->update_properties(_properties);
00521 }
00522 
00523 ////////////////////////////////////////////////////////////////////
00524 //     Function: TextureReference::output
00525 //       Access: Public
00526 //  Description:
00527 ////////////////////////////////////////////////////////////////////
00528 void TextureReference::
00529 output(ostream &out) const {
00530   out << *_source_texture;
00531 }
00532 
00533 ////////////////////////////////////////////////////////////////////
00534 //     Function: TextureReference::write
00535 //       Access: Public
00536 //  Description:
00537 ////////////////////////////////////////////////////////////////////
00538 void TextureReference::
00539 write(ostream &out, int indent_level) const {
00540   indent(out, indent_level)
00541     << get_texture()->get_name();
00542 
00543   if (_uses_alpha) {
00544     out << " (uses alpha)";
00545   }
00546 
00547   if (_any_uvs) {
00548     // Compute the fraction of the image that is covered by the UV's
00549     // minmax rectangle.
00550     LTexCoordd box = _max_uv - _min_uv;
00551     double area = box[0] * box[1];
00552 
00553     out << " coverage " << area;
00554   }
00555 
00556   if (_wrap_u != EggTexture::WM_unspecified ||
00557       _wrap_v != EggTexture::WM_unspecified) {
00558     if (_wrap_u != _wrap_v) {
00559       out << " (" << _wrap_u << ", " << _wrap_v << ")";
00560     } else {
00561       out << " " << _wrap_u;
00562     }
00563   }
00564 
00565   if (_properties._format != EggTexture::F_unspecified) {
00566     out << " " << _properties._format;
00567   }
00568 
00569   switch (_properties._minfilter) {
00570       case EggTexture::FT_nearest_mipmap_nearest:
00571       case EggTexture::FT_linear_mipmap_nearest:
00572       case EggTexture::FT_nearest_mipmap_linear:
00573       case EggTexture::FT_linear_mipmap_linear:
00574         out << " mipmap";
00575         break;
00576 
00577       default:
00578         break;
00579   }
00580 
00581   if(_properties._anisotropic_degree>1) {
00582         out << " aniso " << _properties._anisotropic_degree;
00583   }
00584 
00585   out << "\n";
00586 }
00587 
00588 
00589 ////////////////////////////////////////////////////////////////////
00590 //     Function: TextureReference::get_uv_range
00591 //       Access: Private
00592 //  Description: Checks the geometry in the egg file to see what range
00593 //               of UV's are requested for this particular texture
00594 //               reference.
00595 //
00596 //               If pal->_remap_uv is not RU_never, this will also
00597 //               attempt to remap the UV's found so that the midpoint
00598 //               lies in the unit square (0,0) - (1,1), in the hopes
00599 //               of maximizing overlap of UV coordinates between
00600 //               different polygons.  However, the hypothetical
00601 //               translations are not actually applied to the egg file
00602 //               at this point (because we might decide not to place
00603 //               the texture in a palette); they will actually be
00604 //               applied when update_uv_range(), below, is called
00605 //               later.
00606 //
00607 //               The return value is true if the search should
00608 //               continue, or false if it should abort prematurely.
00609 ////////////////////////////////////////////////////////////////////
00610 bool TextureReference::
00611 get_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) {
00612   if (group->is_of_type(EggGroup::get_class_type())) {
00613     EggGroup *egg_group;
00614     DCAST_INTO_R(egg_group, group, false);
00615 
00616     if (egg_group->get_dart_type() != EggGroup::DT_none) {
00617       // If it's a character, we might change the kind of remapping we
00618       // do.
00619       remap = pal->_remap_char_uv;
00620     }
00621   }
00622 
00623   bool group_any_uvs = false;
00624   LTexCoordd group_min_uv, group_max_uv;
00625 
00626   EggGroupNode::iterator ci;
00627   for (ci = group->begin(); ci != group->end(); ci++) {
00628     EggNode *child = (*ci);
00629     if (child->is_of_type(EggNurbsSurface::get_class_type())) {
00630       EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, child);
00631       if (nurbs->has_texture(_egg_tex)) {
00632         // Here's a NURBS surface that references the texture.  Unlike
00633         // other kinds of geometries, NURBS don't store UV's; they're
00634         // implicit in the surface.  NURBS UV's will always run in the
00635         // range (0, 0) - (1, 1).  However, we do need to apply the
00636         // texture matrix.
00637 
00638         // We also don't count the NURBS surfaces in with the group's
00639         // UV's, because we can't adjust the UV's on a NURBS, so
00640         // counting them up would be misleading (the reason we count
00641         // up the group UV's is so we can consider adjusting them
00642         // later).  Instead, we just accumulate the NURBS UV's
00643         // directly into our total.
00644         collect_nominal_uv_range();
00645       }
00646 
00647     } else if (child->is_of_type(EggPrimitive::get_class_type())) {
00648       EggPrimitive *geom = DCAST(EggPrimitive, child);
00649       if (geom->has_texture(_egg_tex)) {
00650         // Here's a piece of geometry that references this texture.
00651         // Walk through its vertices and get its UV's.
00652 
00653         if (_egg_tex->get_tex_gen() != EggTexture::TG_unspecified) {
00654           // If the texture has a TexGen mode, we don't check the UV
00655           // range on the model, since that doesn't matter.  Instead,
00656           // we assume the texture is used in the range (0, 0) - (1,
00657           // 1), which will be true for a sphere map, although the
00658           // effective range is a little less clear for the
00659           // TG_world_position and similar modes.
00660           collect_nominal_uv_range();
00661 
00662           // In fact, now we can return, having found at least one
00663           // model that references the texture; there's no need to
00664           // search further.
00665           return false;
00666           
00667         } else {
00668           LTexCoordd geom_min_uv, geom_max_uv;
00669           
00670           if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) {
00671             if (remap == Palettizer::RU_poly) {
00672               LVector2d trans = translate_uv(geom_min_uv, geom_max_uv);
00673               geom_min_uv += trans;
00674               geom_max_uv += trans;
00675             }
00676             collect_uv(group_any_uvs, group_min_uv, group_max_uv,
00677                        geom_min_uv, geom_max_uv);
00678           }
00679         }
00680       }
00681         
00682     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00683       EggGroupNode *cg = DCAST(EggGroupNode, child);
00684       if (!get_uv_range(cg, remap)) {
00685         return false;
00686       }
00687     }
00688   }
00689 
00690   if (group_any_uvs) {
00691     if (remap == Palettizer::RU_group) {
00692       LVector2d trans = translate_uv(group_min_uv, group_max_uv);
00693       group_min_uv += trans;
00694       group_max_uv += trans;
00695     }
00696     collect_uv(_any_uvs, _min_uv, _max_uv, group_min_uv, group_max_uv);
00697   }
00698 
00699   return true;
00700 }
00701 
00702 ////////////////////////////////////////////////////////////////////
00703 //     Function: TextureReference::update_uv_range
00704 //       Access: Private
00705 //  Description: Actually applies the UV translates that were assumed
00706 //               in the previous call to get_uv_range().
00707 ////////////////////////////////////////////////////////////////////
00708 void TextureReference::
00709 update_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) {
00710   if (group->is_of_type(EggGroup::get_class_type())) {
00711     EggGroup *egg_group;
00712     DCAST_INTO_V(egg_group, group);
00713 
00714     if (egg_group->get_dart_type() != EggGroup::DT_none) {
00715       // If it's a character, we might change the kind of remapping we
00716       // do.
00717       remap = pal->_remap_char_uv;
00718     }
00719   }
00720 
00721   bool group_any_uvs = false;
00722   LTexCoordd group_min_uv, group_max_uv;
00723 
00724   EggGroupNode::iterator ci;
00725   for (ci = group->begin(); ci != group->end(); ci++) {
00726     EggNode *child = (*ci);
00727     if (child->is_of_type(EggNurbsSurface::get_class_type())) {
00728       // We do nothing at this point for a Nurbs.  Nothing we can do
00729       // about these things.
00730 
00731     } else if (child->is_of_type(EggPrimitive::get_class_type())) {
00732       if (remap != Palettizer::RU_never) {
00733         EggPrimitive *geom = DCAST(EggPrimitive, child);
00734         if (geom->has_texture(_egg_tex)) {
00735           LTexCoordd geom_min_uv, geom_max_uv;
00736 
00737           if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) {
00738             if (remap == Palettizer::RU_poly) {
00739               LVector2d trans = translate_uv(geom_min_uv, geom_max_uv);
00740               trans = trans * _inv_tex_mat;
00741               if (!trans.almost_equal(LVector2d::zero())) {
00742                 translate_geom_uvs(geom, trans);
00743               }
00744             } else {
00745               collect_uv(group_any_uvs, group_min_uv, group_max_uv,
00746                          geom_min_uv, geom_max_uv);
00747             }
00748           }
00749         }
00750       }
00751 
00752     } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00753       EggGroupNode *cg = DCAST(EggGroupNode, child);
00754       update_uv_range(cg, remap);
00755     }
00756   }
00757 
00758   if (group_any_uvs && remap == Palettizer::RU_group) {
00759     LVector2d trans = translate_uv(group_min_uv, group_max_uv);
00760     trans = trans * _inv_tex_mat;
00761     if (!trans.almost_equal(LVector2d::zero())) {
00762       for (ci = group->begin(); ci != group->end(); ci++) {
00763         EggNode *child = (*ci);
00764         if (child->is_of_type(EggPrimitive::get_class_type())) {
00765           EggPrimitive *geom = DCAST(EggPrimitive, child);
00766           if (geom->has_texture(_egg_tex)) {
00767             translate_geom_uvs(geom, trans);
00768           }
00769         }
00770       }
00771     }
00772   }
00773 }
00774 
00775 ////////////////////////////////////////////////////////////////////
00776 //     Function: TextureReference::get_geom_uvs
00777 //       Access: Private
00778 //  Description: Determines the minimum and maximum UV range for a
00779 //               particular primitive.  Returns true if it has any
00780 //               UV's, false otherwise.
00781 ////////////////////////////////////////////////////////////////////
00782 bool TextureReference::
00783 get_geom_uvs(EggPrimitive *geom,
00784              LTexCoordd &geom_min_uv, LTexCoordd &geom_max_uv) {
00785   string uv_name = _egg_tex->get_uv_name();
00786   bool geom_any_uvs = false;
00787 
00788   EggPrimitive::iterator pi;
00789   for (pi = geom->begin(); pi != geom->end(); ++pi) {
00790     EggVertex *vtx = (*pi);
00791     if (vtx->has_uv(uv_name)) {
00792       LTexCoordd uv = vtx->get_uv(uv_name) * _tex_mat;
00793       collect_uv(geom_any_uvs, geom_min_uv, geom_max_uv, uv, uv);
00794     }
00795   }
00796 
00797   return geom_any_uvs;
00798 }
00799 
00800 ////////////////////////////////////////////////////////////////////
00801 //     Function: TextureReference::translate_geom_uvs
00802 //       Access: Private
00803 //  Description: Applies the indicated translation to each UV in the
00804 //               primitive.
00805 ////////////////////////////////////////////////////////////////////
00806 void TextureReference::
00807 translate_geom_uvs(EggPrimitive *geom, const LTexCoordd &trans) const {
00808   string uv_name = _egg_tex->get_uv_name();
00809 
00810   EggPrimitive::iterator pi;
00811   for (pi = geom->begin(); pi != geom->end(); ++pi) {
00812     EggVertex *vtx = (*pi);
00813     if (vtx->has_uv(uv_name)) {
00814       EggVertex vtx_copy(*vtx);
00815       vtx_copy.set_uv(uv_name, vtx_copy.get_uv(uv_name) + trans);
00816       EggVertex *new_vtx = vtx->get_pool()->create_unique_vertex(vtx_copy);
00817 
00818       if (new_vtx->gref_size() != vtx->gref_size()) {
00819         new_vtx->copy_grefs_from(*vtx);
00820       }
00821 
00822       geom->replace(pi, new_vtx);
00823     }
00824   }
00825 }
00826 
00827 ////////////////////////////////////////////////////////////////////
00828 //     Function: TextureReference::collect_nominal_uv_range
00829 //       Access: Private
00830 //  Description: Updates _any_uvs, _min_uv, and _max_uv with the range
00831 //               (0, 0) - (1, 1), adjusted by the texture matrix.
00832 ////////////////////////////////////////////////////////////////////
00833 void TextureReference::
00834 collect_nominal_uv_range() {
00835   static const int num_nurbs_uvs = 4;
00836   static LTexCoordd nurbs_uvs[num_nurbs_uvs] = {
00837     LTexCoordd(0.0, 0.0),
00838     LTexCoordd(0.0, 1.0),
00839     LTexCoordd(1.0, 1.0),
00840     LTexCoordd(1.0, 0.0)
00841   };
00842   
00843   for (int i = 0; i < num_nurbs_uvs; i++) {
00844     LTexCoordd uv = nurbs_uvs[i] * _tex_mat;
00845     collect_uv(_any_uvs, _min_uv, _max_uv, uv, uv);
00846   }
00847 }
00848 
00849 ////////////////////////////////////////////////////////////////////
00850 //     Function: TextureReference::collect_uv
00851 //       Access: Private, Static
00852 //  Description: Updates any_uvs, min_uv, and max_uv with the
00853 //               indicated min and max UV's already determined.
00854 ////////////////////////////////////////////////////////////////////
00855 void TextureReference::
00856 collect_uv(bool &any_uvs, LTexCoordd &min_uv, LTexCoordd &max_uv,
00857            const LTexCoordd &got_min_uv, const LTexCoordd &got_max_uv) {
00858   if (any_uvs) {
00859     min_uv.set(min(min_uv[0], got_min_uv[0]),
00860                min(min_uv[1], got_min_uv[1]));
00861     max_uv.set(max(max_uv[0], got_max_uv[0]),
00862                max(max_uv[1], got_max_uv[1]));
00863   } else {
00864     // The first UV.
00865     min_uv = got_min_uv;
00866     max_uv = got_max_uv;
00867     any_uvs = true;
00868   }
00869 }
00870 
00871 ////////////////////////////////////////////////////////////////////
00872 //     Function: TextureReference::translate_uv
00873 //       Access: Private, Static
00874 //  Description: Returns the needed adjustment to translate the given
00875 //               bounding box so that its center lies in the unit
00876 //               square (0,0) - (1,1).
00877 ////////////////////////////////////////////////////////////////////
00878 LVector2d TextureReference::
00879 translate_uv(const LTexCoordd &min_uv, const LTexCoordd &max_uv) {
00880   LTexCoordd center = (min_uv + max_uv) / 2;
00881   return LVector2d(-floor(center[0]), -floor(center[1]));
00882 }
00883 
00884 ////////////////////////////////////////////////////////////////////
00885 //     Function: TextureReference::register_with_read_factory
00886 //       Access: Public, Static
00887 //  Description: Registers the current object as something that can be
00888 //               read from a Bam file.
00889 ////////////////////////////////////////////////////////////////////
00890 void TextureReference::
00891 register_with_read_factory() {
00892   BamReader::get_factory()->
00893     register_factory(get_class_type(), make_TextureReference);
00894 }
00895 
00896 ////////////////////////////////////////////////////////////////////
00897 //     Function: TextureReference::write_datagram
00898 //       Access: Public, Virtual
00899 //  Description: Fills the indicated datagram up with a binary
00900 //               representation of the current object, in preparation
00901 //               for writing to a Bam file.
00902 ////////////////////////////////////////////////////////////////////
00903 void TextureReference::
00904 write_datagram(BamWriter *writer, Datagram &datagram) {
00905   TypedWritable::write_datagram(writer, datagram);
00906   writer->write_pointer(datagram, _egg_file);
00907 
00908   // We don't write _egg_tex or _egg_data; that's specific to the
00909   // session.
00910 
00911   datagram.add_string(_tref_name);
00912 
00913   _tex_mat.write_datagram(datagram);
00914   _inv_tex_mat.write_datagram(datagram);
00915 
00916   writer->write_pointer(datagram, _source_texture);
00917   writer->write_pointer(datagram, _placement);
00918 
00919   datagram.add_bool(_uses_alpha);
00920   datagram.add_bool(_any_uvs);
00921   datagram.add_float64(_min_uv[0]);
00922   datagram.add_float64(_min_uv[1]);
00923   datagram.add_float64(_max_uv[0]);
00924   datagram.add_float64(_max_uv[1]);
00925   datagram.add_int32((int)_wrap_u);
00926   datagram.add_int32((int)_wrap_v);
00927   _properties.write_datagram(writer, datagram);
00928 }
00929 
00930 ////////////////////////////////////////////////////////////////////
00931 //     Function: TextureReference::complete_pointers
00932 //       Access: Public, Virtual
00933 //  Description: Called after the object is otherwise completely read
00934 //               from a Bam file, this function's job is to store the
00935 //               pointers that were retrieved from the Bam file for
00936 //               each pointer object written.  The return value is the
00937 //               number of pointers processed from the list.
00938 ////////////////////////////////////////////////////////////////////
00939 int TextureReference::
00940 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00941   int pi = TypedWritable::complete_pointers(p_list, manager);
00942 
00943   if (p_list[pi] != (TypedWritable *)NULL) {
00944     DCAST_INTO_R(_egg_file, p_list[pi], pi);
00945   }
00946   pi++;
00947 
00948   if (p_list[pi] != (TypedWritable *)NULL) {
00949     DCAST_INTO_R(_source_texture, p_list[pi], pi);
00950   }
00951   pi++;
00952 
00953   if (p_list[pi] != (TypedWritable *)NULL) {
00954     DCAST_INTO_R(_placement, p_list[pi], pi);
00955   }
00956   pi++;
00957 
00958   pi += _properties.complete_pointers(p_list + pi, manager);
00959 
00960   return pi;
00961 }
00962 
00963 ////////////////////////////////////////////////////////////////////
00964 //     Function: TextureReference::make_TextureReference
00965 //       Access: Protected
00966 //  Description: This method is called by the BamReader when an object
00967 //               of this type is encountered in a Bam file; it should
00968 //               allocate and return a new object with all the data
00969 //               read.
00970 ////////////////////////////////////////////////////////////////////
00971 TypedWritable* TextureReference::
00972 make_TextureReference(const FactoryParams &params) {
00973   TextureReference *me = new TextureReference;
00974   DatagramIterator scan;
00975   BamReader *manager;
00976 
00977   parse_params(params, scan, manager);
00978   me->fillin(scan, manager);
00979   return me;
00980 }
00981 
00982 ////////////////////////////////////////////////////////////////////
00983 //     Function: TextureReference::fillin
00984 //       Access: Protected
00985 //  Description: Reads the binary data from the given datagram
00986 //               iterator, which was written by a previous call to
00987 //               write_datagram().
00988 ////////////////////////////////////////////////////////////////////
00989 void TextureReference::
00990 fillin(DatagramIterator &scan, BamReader *manager) {
00991   TypedWritable::fillin(scan, manager);
00992   manager->read_pointer(scan);  // _egg_file
00993 
00994   if (Palettizer::_read_pi_version >= 11) {
00995     _tref_name = scan.get_string();
00996   }
00997 
00998   _tex_mat.read_datagram(scan);
00999   _inv_tex_mat.read_datagram(scan);
01000 
01001   manager->read_pointer(scan);  // _source_texture
01002   manager->read_pointer(scan);  // _placement
01003 
01004   _uses_alpha = scan.get_bool();
01005   _any_uvs = scan.get_bool();
01006   _min_uv[0] = scan.get_float64();
01007   _min_uv[1] = scan.get_float64();
01008   _max_uv[0] = scan.get_float64();
01009   _max_uv[1] = scan.get_float64();
01010   _wrap_u = (EggTexture::WrapMode)scan.get_int32();
01011   _wrap_v = (EggTexture::WrapMode)scan.get_int32();
01012   _properties.fillin(scan, manager);
01013 }
 All Classes Functions Variables Enumerations