Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/egg-palettize/textureReference.cxx

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

Generated on Fri May 2 03:18:31 2003 for Panda-Tool by doxygen1.3