Panda3D
|
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 ¶ms) { 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 }