From f169ddb221af704c6f6310b57aa47511fb6180d4 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 2 Aug 2005 22:35:12 +0000 Subject: [PATCH] regularize TexturePool interfaces for cube maps etc. --- panda/src/gobj/texture.cxx | 47 +---- panda/src/gobj/texture.h | 6 +- panda/src/gobj/texturePool.I | 44 +++++ panda/src/gobj/texturePool.cxx | 162 +++++++++++++++++- panda/src/gobj/texturePool.h | 15 +- .../particlesystem/spriteParticleRenderer.cxx | 9 +- panda/src/putil/Sources.pp | 6 +- panda/src/putil/hashFilename.I | 100 +++++++++++ panda/src/putil/hashFilename.cxx | 80 +++++++++ panda/src/putil/hashFilename.h | 60 +++++++ panda/src/putil/putil_composite1.cxx | 1 + 11 files changed, 476 insertions(+), 54 deletions(-) create mode 100644 panda/src/putil/hashFilename.I create mode 100755 panda/src/putil/hashFilename.cxx create mode 100644 panda/src/putil/hashFilename.h diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 798f387092..6a8b3e5da6 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -29,6 +29,7 @@ #include "preparedGraphicsObjects.h" #include "pnmImage.h" #include "virtualFileSystem.h" +#include "hashFilename.h" #include @@ -393,24 +394,13 @@ write(const Filename &name, int z) const { // corresponding number of digits. //////////////////////////////////////////////////////////////////// bool Texture:: -read_pages(const Filename &fullpath_template, int z_size) { - string fp = fullpath_template.get_fullpath(); - size_t hash = fp.rfind('#'); - if (hash == string::npos) { +read_pages(const HashFilename &fullpath_template, int z_size) { + if (!fullpath_template.has_hash()) { gobj_cat.error() << "Template " << fullpath_template << " contains no hash marks.\n"; return false; } - // Count the number of hash marks. - size_t num_hash = 1; - while (hash >= num_hash && fp[hash - num_hash] == '#') { - num_hash++; - } - - string prefix = fp.substr(0, hash - num_hash + 1); - string suffix = fp.substr(hash + 1); - clear_ram_image(); if (z_size == 0) { @@ -432,29 +422,23 @@ read_pages(const Filename &fullpath_template, int z_size) { if (z_size != 0) { set_z_size(z_size); for (int z = 0; z < z_size; z++) { - ostringstream strm; - strm << prefix << setw(num_hash) << setfill('0') << z << suffix; - if (!read(strm.str(), z)) { + if (!read(fullpath_template.get_filename_index(z), z)) { return false; } } } else { set_z_size(0); int z = 0; - ostringstream strm; - strm << prefix << setw(num_hash) << setfill('0') << z << suffix; - Filename file(strm.str()); VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + Filename file = fullpath_template.get_filename_index(z); while (vfs->exists(file)) { if (!read(file, z)) { return false; } ++z; - ostringstream strm; - strm << prefix << setw(num_hash) << setfill('0') << z << suffix; - file = Filename(strm.str()); + file = fullpath_template.get_filename_index(z); } } @@ -475,28 +459,15 @@ read_pages(const Filename &fullpath_template, int z_size) { // corresponding number of digits. //////////////////////////////////////////////////////////////////// bool Texture:: -write_pages(const Filename &fullpath_template) { - string fp = fullpath_template.get_fullpath(); - size_t hash = fp.rfind('#'); - if (hash == string::npos) { +write_pages(const HashFilename &fullpath_template) { + if (!fullpath_template.has_hash()) { gobj_cat.error() << "Template " << fullpath_template << " contains no hash marks.\n"; return false; } - // Count the number of hash marks. - size_t num_hash = 1; - while (hash >= num_hash && fp[hash - num_hash] == '#') { - num_hash++; - } - - string prefix = fp.substr(0, hash - num_hash + 1); - string suffix = fp.substr(hash + 1); - for (int z = 0; z < _z_size; z++) { - ostringstream strm; - strm << prefix << setw(num_hash) << setfill('0') << z << suffix; - if (!write(strm.str(), z)) { + if (!write(fullpath_template.get_filename_index(z), z)) { return false; } } diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index a3a2b39580..f9b59690ea 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -21,6 +21,7 @@ #include "pandabase.h" +#include "filename.h" #include "typedWritableReferenceCount.h" #include "namable.h" #include "graphicsStateGuardianBase.h" @@ -30,6 +31,7 @@ class PNMImage; class TextureContext; class FactoryParams; class PreparedGraphicsObjects; +class HashFilename; //////////////////////////////////////////////////////////////////// // Class : Texture @@ -159,8 +161,8 @@ PUBLISHED: int primary_file_num_channels = 0, int alpha_file_channel = 0); bool write(const Filename &fullpath, int z = 0) const; - bool read_pages(const Filename &fullpath_template, int z_size = 0); - bool write_pages(const Filename &fullpath_template); + bool read_pages(const HashFilename &fullpath_template, int z_size = 0); + bool write_pages(const HashFilename &fullpath_template); bool load(const PNMImage &pnmimage, int z = 0); bool store(PNMImage &pnmimage, int z = 0) const; diff --git a/panda/src/gobj/texturePool.I b/panda/src/gobj/texturePool.I index d59bfb8a43..7c61f09209 100644 --- a/panda/src/gobj/texturePool.I +++ b/panda/src/gobj/texturePool.I @@ -74,6 +74,50 @@ load_texture(const string &filename, const string &alpha_filename, alpha_file_channel); } +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::load_3d_texture +// Access: Published, Static +// Description: Loads a 3-D texture that is specified with a series +// of n pages, all numbered in sequence, and beginning +// with index 0. The filename should include a sequence +// of one or more hash characters ("#") which will be +// filled in with the index number of each level. +//////////////////////////////////////////////////////////////////// +INLINE Texture *TexturePool:: +load_3d_texture(const string &filename_template) { + return get_ptr()->ns_load_3d_texture(filename_template); +} + +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::load_cube_map +// Access: Published, Static +// Description: Loads a cube map texture that is specified with a +// series of 6 pages, numbered 0 through 5. The +// filename should include a sequence of one or more +// hash characters ("#") which will be filled in with +// the index number of each pagee. +//////////////////////////////////////////////////////////////////// +INLINE Texture *TexturePool:: +load_cube_map(const string &filename_template) { + return get_ptr()->ns_load_cube_map(filename_template); +} + +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::get_normalization_cube_map +// Access: Published, Static +// Description: Returns a standard Texture object that has been +// created with +// Texture::generate_normalization_cube_map(). This +// Texture may be shared by any application code +// requiring a normalization cube map. It will be at +// least as large as the specified size, though it may +// be larger. +//////////////////////////////////////////////////////////////////// +INLINE Texture *TexturePool:: +get_normalization_cube_map(int size) { + return get_ptr()->ns_get_normalization_cube_map(size); +} + //////////////////////////////////////////////////////////////////// // Function: TexturePool::add_texture // Access: Published, Static diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index 1678631cdc..81f8bf0693 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -93,11 +93,8 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) { << "Loading texture " << filename << "\n"; PT(Texture) tex = new Texture; if (!tex->read(filename, 0, primary_file_num_channels)) { - // This texture was not found. - gobj_cat.error() - << "Unable to read texture \"" << filename << "\"" - << " on texture_path " << texture_path - << " or model_path " << model_path <<"\n"; + // This texture was not found or could not be read. + report_texture_unreadable(filename); return NULL; } @@ -145,8 +142,8 @@ ns_load_texture(const Filename &orig_filename, PT(Texture) tex = new Texture; if (!tex->read(filename, alpha_filename, 0, primary_file_num_channels, alpha_file_channel)) { - // This texture was not found. - gobj_cat.error() << "Unable to read texture " << filename << "\n"; + // This texture was not found or could not be read. + report_texture_unreadable(filename); return NULL; } @@ -158,6 +155,114 @@ ns_load_texture(const Filename &orig_filename, return tex; } +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::ns_load_3d_texture +// Access: Private +// Description: The nonstatic implementation of load_3d_texture(). +//////////////////////////////////////////////////////////////////// +Texture *TexturePool:: +ns_load_3d_texture(const HashFilename &filename_template) { + // Look up filename 0 on the model path. + Filename filename = filename_template.get_filename_index(0); + if (!_fake_texture_image.empty()) { + filename = _fake_texture_image; + } + + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + vfs->resolve_filename(filename, get_texture_path()) || + vfs->resolve_filename(filename, get_model_path()); + + // Then, replace everything before the hash code with the directory + // we've found. + string hash = filename_template.get_hash_to_end(); + HashFilename hash_filename(filename.substr(0, filename.length() - hash.length()) + hash); + + Textures::const_iterator ti; + ti = _textures.find(hash_filename); + if (ti != _textures.end()) { + // This texture was previously loaded. + return (*ti).second; + } + + gobj_cat.info() + << "Loading 3-d texture " << hash_filename << "\n"; + PT(Texture) tex = new Texture; + tex->setup_3d_texture(); + if (!tex->read_pages(hash_filename)) { + // This texture was not found or could not be read. + report_texture_unreadable(filename); + } + + // Set the original filename, before we searched along the path. + tex->set_filename(filename_template); + + _textures[hash_filename] = tex; + return tex; +} + +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::ns_load_cube_map +// Access: Private +// Description: The nonstatic implementation of load_cube_map(). +//////////////////////////////////////////////////////////////////// +Texture *TexturePool:: +ns_load_cube_map(const HashFilename &filename_template) { + // Look up filename 0 on the model path. + Filename filename = filename_template.get_filename_index(0); + if (!_fake_texture_image.empty()) { + filename = _fake_texture_image; + } + + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + vfs->resolve_filename(filename, get_texture_path()) || + vfs->resolve_filename(filename, get_model_path()); + + // Then, replace everything before the hash code with the directory + // we've found. + string hash = filename_template.get_hash_to_end(); + HashFilename hash_filename(filename.substr(0, filename.length() - hash.length()) + hash); + + Textures::const_iterator ti; + ti = _textures.find(hash_filename); + if (ti != _textures.end()) { + // This texture was previously loaded. + return (*ti).second; + } + + gobj_cat.info() + << "Loading cube map texture " << hash_filename << "\n"; + PT(Texture) tex = new Texture; + tex->setup_cube_map(); + if (!tex->read_pages(hash_filename)) { + // This texture was not found or could not be read. + report_texture_unreadable(filename); + } + + // Set the original filename, before we searched along the path. + tex->set_filename(filename_template); + + _textures[hash_filename] = tex; + return tex; +} + +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::ns_get_normalization_cube_map +// Access: Private +// Description: The nonstatic implementation of get_normalization_cube_map(). +//////////////////////////////////////////////////////////////////// +Texture *TexturePool:: +ns_get_normalization_cube_map(int size) { + if (_normalization_cube_map == (Texture *)NULL) { + _normalization_cube_map = new Texture("normalization_cube_map"); + } + if (_normalization_cube_map->get_x_size() < size || + _normalization_cube_map->get_texture_type() != Texture::TT_cube_map) { + _normalization_cube_map->generate_normalization_cube_map(size); + } + + return _normalization_cube_map; +} + //////////////////////////////////////////////////////////////////// // Function: TexturePool::ns_add_texture // Access: Private @@ -197,6 +302,7 @@ ns_release_texture(Texture *tex) { void TexturePool:: ns_release_all_textures() { _textures.clear(); + _normalization_cube_map = NULL; } //////////////////////////////////////////////////////////////////// @@ -224,6 +330,16 @@ ns_garbage_collect() { } _textures.swap(new_set); + + if (_normalization_cube_map->get_ref_count() == 1) { + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Releasing normalization cube map\n"; + } + ++num_released; + _normalization_cube_map = NULL; + } + return num_released; } @@ -244,6 +360,38 @@ ns_list_contents(ostream &out) const { } } +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::report_texture_unreadable +// Access: Private +// Description: Prints a suitable error message when a texture could +// not be loaded. +//////////////////////////////////////////////////////////////////// +void TexturePool:: +report_texture_unreadable(const Filename &filename) const { + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + if (!vfs->exists(filename)) { + if (filename.is_local()) { + // The file doesn't exist, and it wasn't + // fully-qualified--therefore, it wasn't found along either + // search path. + gobj_cat.error() + << "Unable to find texture \"" << filename << "\"" + << " on texture_path " << texture_path + << " or model_path " << model_path <<"\n"; + } else { + // A fully-specified filename is not searched along the path, so + // don't mislead the user with the error message. + gobj_cat.error() + << "Texture \"" << filename << "\" does not exist.\n"; + } + + } else { + // The file exists, but it couldn't be read for some reason. + gobj_cat.error() + << "Texture \"" << filename << "\" exists but cannot be read.\n"; + } +} + //////////////////////////////////////////////////////////////////// // Function: TexturePool::get_ptr // Access: Private, Static diff --git a/panda/src/gobj/texturePool.h b/panda/src/gobj/texturePool.h index e5f8788181..f8285cb57f 100644 --- a/panda/src/gobj/texturePool.h +++ b/panda/src/gobj/texturePool.h @@ -23,6 +23,7 @@ #include "texture.h" #include "filename.h" #include "config_gobj.h" +#include "hashFilename.h" #include "pmap.h" @@ -47,6 +48,11 @@ PUBLISHED: const string &alpha_filename, int primary_file_num_channels = 0, int alpha_file_channel = 0); + INLINE static Texture *load_3d_texture(const string &filename_template); + INLINE static Texture *load_cube_map(const string &filename_template); + + INLINE static Texture *get_normalization_cube_map(int size); + INLINE static void add_texture(Texture *texture); INLINE static void release_texture(Texture *texture); INLINE static void release_all_textures(); @@ -60,7 +66,6 @@ PUBLISHED: INLINE static bool has_fake_texture_image(); INLINE static const string &get_fake_texture_image(); - // static void output(ostream &out); static void write(ostream &out); private: @@ -72,18 +77,26 @@ private: const Filename &orig_alpha_filename, int primary_file_num_channels, int alpha_file_channel); + Texture *ns_load_3d_texture(const HashFilename &filename_template); + Texture *ns_load_cube_map(const HashFilename &filename_template); + Texture *ns_get_normalization_cube_map(int size); + void ns_add_texture(Texture *texture); void ns_release_texture(Texture *texture); void ns_release_all_textures(); int ns_garbage_collect(); void ns_list_contents(ostream &out) const; + void report_texture_unreadable(const Filename &filename) const; + static TexturePool *get_ptr(); static TexturePool *_global_ptr; typedef phash_map Textures; Textures _textures; string _fake_texture_image; + + PT(Texture) _normalization_cube_map; }; #include "texturePool.I" diff --git a/panda/src/particlesystem/spriteParticleRenderer.cxx b/panda/src/particlesystem/spriteParticleRenderer.cxx index a43019a706..a0a12f9963 100644 --- a/panda/src/particlesystem/spriteParticleRenderer.cxx +++ b/panda/src/particlesystem/spriteParticleRenderer.cxx @@ -74,6 +74,7 @@ SpriteParticleRenderer(Texture *tex) : SpriteParticleRenderer:: SpriteParticleRenderer(const SpriteParticleRenderer& copy) : BaseParticleRenderer(copy), + _anims(copy._anims), _color(copy._color), _height(copy._height), _width(copy._width), @@ -95,7 +96,6 @@ SpriteParticleRenderer(const SpriteParticleRenderer& copy) : _blend_method(copy._blend_method), _color_interpolation_manager(copy._color_interpolation_manager), _pool_size(0), - _anims(copy._anims), _birth_list(copy._birth_list) { init_geoms(); } @@ -299,7 +299,6 @@ add_from_node(const NodePath &node_path, bool size_from_texels, bool resize) { GeomNode *gnode = NULL; const Geom *geom; const GeomPrimitive *primitive; - bool got_texcoord; for (int i = 0; i < np_col.get_num_paths(); ++i) { // Get the node from which we'll extract the geometry information. @@ -309,7 +308,7 @@ add_from_node(const NodePath &node_path, bool size_from_texels, bool resize) { nassertv(gnode->get_num_geoms() > 0); geom = gnode->get_geom(0); - got_texcoord = false; + bool got_texcoord = false; TexCoordf min_uv(0.0f, 0.0f); TexCoordf max_uv(0.0f, 0.0f); @@ -389,7 +388,7 @@ add_from_node(const NodePath &node_path, bool size_from_texels, bool resize) { float height = max(max_xyz[1] - min_xyz[1], max_xyz[2] - min_xyz[2]); - if (size_from_texels && got_texcoord) { + if (size_from_texels) { // If size_from_texels is true, we get the particle size from the // number of texels in the source image. float y_texels = _anims[0]->get_frame(0)->get_y_size() * fabs(_anims[0]->get_ur(0)[1] - _anims[0]->get_ll(0)[1]); @@ -601,7 +600,7 @@ render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) { for (i = 0; i < anim_count; ++i) { for (j = 0; j < _anim_size[i]; ++j) { // Set the particle per frame counts to 0. - memset(_ttl_count[i],NULL,_anim_size[i]*sizeof(int)); + memset(_ttl_count[i], 0, _anim_size[i]*sizeof(int)); _sprite_writer[i][j].vertex = GeomVertexWriter(_vdata[i][j], InternalName::get_vertex()); _sprite_writer[i][j].color = GeomVertexWriter(_vdata[i][j], InternalName::get_color()); diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index a634777a05..bff23aaacc 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -31,6 +31,7 @@ firstOfPairCompare.I firstOfPairCompare.h \ firstOfPairLess.I firstOfPairLess.h \ globalPointerRegistry.I globalPointerRegistry.h \ + hashFilename.I hashFilename.h \ indirectCompareNames.I indirectCompareNames.h \ indirectCompareSort.I indirectCompareSort.h \ indirectCompareTo.I indirectCompareTo.h \ @@ -70,7 +71,9 @@ datagramInputFile.cxx datagramOutputFile.cxx \ factoryBase.cxx \ factoryParam.cxx factoryParams.cxx \ - globalPointerRegistry.cxx ioPtaDatagramFloat.cxx \ + globalPointerRegistry.cxx \ + hashFilename.cxx \ + ioPtaDatagramFloat.cxx \ ioPtaDatagramInt.cxx ioPtaDatagramShort.cxx \ keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \ load_prc_file.cxx \ @@ -113,6 +116,7 @@ firstOfPairCompare.I firstOfPairCompare.h \ firstOfPairLess.I firstOfPairLess.h \ globalPointerRegistry.I globalPointerRegistry.h \ + hashFilename.I hashFilename.h \ indirectCompareNames.I indirectCompareNames.h \ indirectCompareSort.I indirectCompareSort.h \ indirectCompareTo.I indirectCompareTo.h \ diff --git a/panda/src/putil/hashFilename.I b/panda/src/putil/hashFilename.I new file mode 100644 index 0000000000..e84c5ea0cf --- /dev/null +++ b/panda/src/putil/hashFilename.I @@ -0,0 +1,100 @@ +// Filename: hashFilename.I +// Created by: drose (02Aug05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE HashFilename:: +HashFilename(const string &filename_pattern) : + Filename(filename_pattern) +{ + locate_hash(); +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE HashFilename:: +HashFilename(const HashFilename ©) : + Filename(copy), + _hash_start(copy._hash_start), + _hash_end(copy._hash_end) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HashFilename:: +operator = (const HashFilename ©) { + Filename::operator = (copy); + _hash_start = copy._hash_start; + _hash_end = copy._hash_end; +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HashFilename:: +operator = (const Filename ©) { + Filename::operator = (copy); + locate_hash(); +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE HashFilename:: +~HashFilename() { +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::has_hash +// Access: Published +// Description: Returns true if the filename pattern did include a +// sequence of hash marks, false otherwise. If this is +// true, then get_filename_index() will return a +// different filename each time. +//////////////////////////////////////////////////////////////////// +INLINE bool HashFilename:: +has_hash() const { + return (_hash_start != _hash_end); +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::get_hash_to_end +// Access: Published +// Description: Returns the part of the filename beginning at the +// hash sequence (if any), and continuing to the end of +// the filename. +//////////////////////////////////////////////////////////////////// +INLINE string HashFilename:: +get_hash_to_end() const { + return _filename.substr(_hash_start); +} diff --git a/panda/src/putil/hashFilename.cxx b/panda/src/putil/hashFilename.cxx new file mode 100755 index 0000000000..10c6cb5949 --- /dev/null +++ b/panda/src/putil/hashFilename.cxx @@ -0,0 +1,80 @@ +// Filename: hashFilename.cxx +// Created by: drose (02Aug05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "hashFilename.h" + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::get_filename_index +// Access: Published +// Description: Returns a Filename, derived from the HashFilename, +// with the sequence of hash marks (if any) replaced by +// the indicated index number. If the HashFilename does +// not contain a sequence of hash marks, this quietly +// returns the original filename. +//////////////////////////////////////////////////////////////////// +Filename HashFilename:: +get_filename_index(int index) const { + Filename file(*this); + + if (_hash_end != _hash_start) { + ostringstream strm; + strm << _filename.substr(0, _hash_start) + << setw(_hash_end - _hash_start) << setfill('0') << index + << _filename.substr(_hash_end); + file.set_fullpath(strm.str()); + } + + return file; +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::set_hash_to_end +// Access: Published +// Description: Replaces the part of the filename from the beginning +// of the has sequence to the end of the filename. +//////////////////////////////////////////////////////////////////// +void HashFilename:: +set_hash_to_end(const string &s) { + _filename.replace(_hash_start, string::npos, s); + + locate_basename(); + locate_extension(); + locate_hash(); +} + +//////////////////////////////////////////////////////////////////// +// Function: HashFilename::locate_hash +// Access: Private +// Description: Identifies the part of the filename that contains the +// sequence of hash marks, if any. +//////////////////////////////////////////////////////////////////// +void HashFilename:: +locate_hash() { + _hash_end = _filename.rfind('#'); + if (_hash_end == string::npos) { + _hash_end = string::npos; + _hash_start = string::npos; + + } else { + _hash_start = _hash_end; + ++_hash_end; + while (_hash_start > 0 && _filename[_hash_start - 1] == '#') { + --_hash_start; + } + } +} diff --git a/panda/src/putil/hashFilename.h b/panda/src/putil/hashFilename.h new file mode 100644 index 0000000000..ef86e6df77 --- /dev/null +++ b/panda/src/putil/hashFilename.h @@ -0,0 +1,60 @@ +// Filename: hashFilename.h +// Created by: drose (02Aug05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef HASHFILENAME_H +#define HASHFILENAME_H + +#include "pandabase.h" +#include "filename.h" + +//////////////////////////////////////////////////////////////////// +// Class : HashFilename +// Description : This is a specialization on Filename that is intended +// to be used to record a filename pattern for reading a +// numeric sequence of filenames in a directory; for +// instance, as used by TexturePool::load_cube_map(). +// +// The Filename may include a string of one or more hash +// marks ('#') in the basename or extension part. These +// will be filled in with digits when +// get_filename_index() is called. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA HashFilename : public Filename { +PUBLISHED: + INLINE HashFilename(const string &filename_pattern = string()); + INLINE HashFilename(const HashFilename ©); + INLINE void operator = (const HashFilename ©); + INLINE void operator = (const Filename ©); + INLINE ~HashFilename(); + + INLINE bool has_hash() const; + Filename get_filename_index(int index) const; + + INLINE string get_hash_to_end() const; + void set_hash_to_end(const string &s); + +private: + void locate_hash(); + + size_t _hash_start; + size_t _hash_end; +}; + +#include "hashFilename.I" + +#endif diff --git a/panda/src/putil/putil_composite1.cxx b/panda/src/putil/putil_composite1.cxx index efd5d1a79c..0a2beeb973 100644 --- a/panda/src/putil/putil_composite1.cxx +++ b/panda/src/putil/putil_composite1.cxx @@ -17,6 +17,7 @@ #include "factoryParam.cxx" #include "factoryParams.cxx" #include "globalPointerRegistry.cxx" +#include "hashFilename.cxx" #include "ioPtaDatagramFloat.cxx" #include "ioPtaDatagramInt.cxx" #include "ioPtaDatagramShort.cxx"