Browse Source

add support for txaFileFilter

David Rose 19 years ago
parent
commit
7834728560

+ 25 - 1
panda/src/egg2pg/eggLoader.cxx

@@ -855,7 +855,7 @@ load_textures() {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 bool EggLoader::
-load_texture(TextureDef &def, const EggTexture *egg_tex) {
+load_texture(TextureDef &def, EggTexture *egg_tex) {
   // Check to see if we should reduce the number of channels in
   // the texture.
   int wanted_channels = 0;
@@ -951,6 +951,30 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) {
     tex->set_alpha_filename(egg_tex->get_alpha_filename());
   }
 
+  // See if there is some egg data hanging on the texture.  In
+  // particular, the TxaFileFilter might have left that here for us.
+  TypedReferenceCount *aux = tex->get_aux_data("egg");
+  if (aux != (TypedReferenceCount *)NULL &&
+      aux->is_of_type(EggTexture::get_class_type())) {
+    EggTexture *aux_egg_tex = DCAST(EggTexture, aux);
+
+    if (aux_egg_tex->get_alpha_mode() != EggTexture::AM_unspecified) {
+      egg_tex->set_alpha_mode(aux_egg_tex->get_alpha_mode());
+    }
+    if (aux_egg_tex->get_format() != EggTexture::F_unspecified) {
+      egg_tex->set_format(aux_egg_tex->get_format());
+    }
+    if (aux_egg_tex->get_minfilter() != EggTexture::FT_unspecified) {
+      egg_tex->set_minfilter(aux_egg_tex->get_minfilter());
+    }
+    if (aux_egg_tex->get_magfilter() != EggTexture::FT_unspecified) {
+      egg_tex->set_magfilter(aux_egg_tex->get_magfilter());
+    }
+    if (aux_egg_tex->has_anisotropic_degree()) {
+      egg_tex->set_anisotropic_degree(aux_egg_tex->get_anisotropic_degree());
+    }
+  }
+
   apply_texture_attributes(tex, egg_tex);
 
   // Make a texture stage for the texture.

+ 1 - 1
panda/src/egg2pg/eggLoader.h

@@ -122,7 +122,7 @@ private:
                           const LMatrix4d &mat);
 
   void load_textures();
-  bool load_texture(TextureDef &def, const EggTexture *egg_tex);
+  bool load_texture(TextureDef &def, EggTexture *egg_tex);
   void apply_texture_attributes(Texture *tex, const EggTexture *egg_tex);
   Texture::CompressionMode convert_compression_mode(EggTexture::CompressionMode compression_mode) const;
   Texture::WrapMode convert_wrap_mode(EggTexture::WrapMode wrap_mode) const;

+ 43 - 12
panda/src/egg2pg/eggRenderState.cxx

@@ -60,6 +60,7 @@ fill_state(EggPrimitive *egg_prim) {
   EggRenderMode::DepthTestMode dtm = EggRenderMode::DTM_unspecified;
   EggRenderMode::VisibilityMode vm = EggRenderMode::VM_unspecified;
   bool implicit_alpha = false;
+  bool binary_alpha_only = true;  // true if all alpha sources are binary alpha.
   bool has_draw_order = false;
   int draw_order = 0;
   bool has_bin = false;
@@ -111,18 +112,26 @@ fill_state(EggPrimitive *egg_prim) {
         texture_attrib = texture_attrib->compose(def._texture);
       }
 
-      // If neither the primitive nor the texture specified an alpha
-      // mode, assume it should be alpha'ed if the texture has an
-      // alpha channel (unless the texture environment type is one
-      // that doesn't apply its alpha to the result).
-      if (egg_tex->affects_polygon_alpha() &&
-          am == EggRenderMode::AM_unspecified) {
+      if (egg_tex->affects_polygon_alpha()) {
         const TextureAttrib *tex_attrib = DCAST(TextureAttrib, def._texture);
         Texture *tex = tex_attrib->get_texture();
         nassertv(tex != (Texture *)NULL);
-        int num_components = tex->get_num_components();
-        if (egg_tex->has_alpha_channel(num_components)) {
-          implicit_alpha = true;
+
+        Texture::Format format = tex->get_format();
+        if (Texture::has_alpha(format) && !Texture::has_binary_alpha(format)) {
+          // This texture specifies a gradient alpha format.
+          binary_alpha_only = false;
+        }
+
+        if (am == EggRenderMode::AM_unspecified) {
+          // If neither the primitive nor the texture specified an
+          // alpha mode, assume it should be alpha'ed if the texture
+          // has an alpha channel (unless the texture environment type
+          // is one that doesn't apply its alpha to the result).
+          int num_components = tex->get_num_components();
+          if (egg_tex->has_alpha_channel(num_components)) {
+            implicit_alpha = true;
+          }
         }
       }
 
@@ -247,6 +256,7 @@ fill_state(EggPrimitive *egg_prim) {
     if (egg_prim->has_color()) {
       if (egg_prim->get_color()[3] != 1.0) {
         implicit_alpha = true;
+        binary_alpha_only = false;
       }
     }
     EggPrimitive::const_iterator vi;
@@ -256,6 +266,7 @@ fill_state(EggPrimitive *egg_prim) {
       if ((*vi)->has_color()) {
         if ((*vi)->get_color()[3] != 1.0) {
           implicit_alpha = true;
+          binary_alpha_only = false;
         }
       }
     }
@@ -265,10 +276,30 @@ fill_state(EggPrimitive *egg_prim) {
     }
   }
 
-  if (am == EggRenderMode::AM_on && 
-      egg_alpha_mode != EggRenderMode::AM_unspecified) {
+  switch (am) {
+  case EggRenderMode::AM_on:
     // Alpha type "on" means to get the default transparency type.
-    am = egg_alpha_mode;
+    if (binary_alpha_only) {
+      am = EggRenderMode::AM_binary;
+    } else if (egg_alpha_mode != EggRenderMode::AM_unspecified) {
+      am = egg_alpha_mode;
+    }
+    break;
+
+  case EggRenderMode::AM_blend:
+  case EggRenderMode::AM_ms:
+  case EggRenderMode::AM_ms_mask:
+  case EggRenderMode::AM_dual:
+    // Any of these modes gets implicitly downgraded to AM_binary, if
+    // all of the alpha sources only contribute a binary value to
+    // alpha.
+    if (binary_alpha_only) {
+      am = EggRenderMode::AM_binary;
+    }
+    break;
+
+  default:
+    break;
   }
 
   switch (am) {

+ 3 - 0
panda/src/gobj/Sources.pp

@@ -54,6 +54,7 @@
     texture.I texture.h \
     textureContext.I textureContext.h \
     texturePool.I texturePool.h \
+    texturePoolFilter.I texturePoolFilter.h \
     textureStage.I textureStage.h \
     transformBlend.I transformBlend.h \
     transformBlendTable.I transformBlendTable.h \
@@ -107,6 +108,7 @@
     shaderExpansion.cxx \
     sliderTable.cxx \
     texture.cxx textureContext.cxx texturePool.cxx \
+    texturePoolFilter.cxx \
     textureStage.cxx \
     transformBlend.cxx \
     transformBlendTable.cxx \
@@ -164,6 +166,7 @@
     texture.I texture.h \
     textureContext.I textureContext.h \
     texturePool.I texturePool.h \
+    texturePoolFilter.I texturePoolFilter.h \
     textureStage.I textureStage.h \
     transformBlend.I transformBlend.h \
     transformBlendTable.I transformBlendTable.h \

+ 20 - 18
panda/src/gobj/config_gobj.cxx

@@ -41,6 +41,7 @@
 #include "queryContext.h"
 #include "sliderTable.h"
 #include "texture.h"
+#include "texturePoolFilter.h"
 #include "textureStage.h"
 #include "textureContext.h"
 #include "shaderExpansion.h"
@@ -248,60 +249,62 @@ ConfigVariableDouble default_keystone
 ConfigureFn(config_gobj) {
   BufferContext::init_type();
   Geom::init_type();
+  GeomContext::init_type();
+  GeomLines::init_type();
+  GeomLinestrips::init_type();
   GeomMunger::init_type();
+  GeomPoints::init_type();
   GeomPrimitive::init_type();
   GeomTriangles::init_type();
-  GeomTristrips::init_type();
   GeomTrifans::init_type();
-  GeomLines::init_type();
-  GeomLinestrips::init_type();
-  GeomPoints::init_type();
+  GeomTristrips::init_type();
   GeomVertexArrayData::init_type();
   GeomVertexArrayFormat::init_type();
   GeomVertexData::init_type();
   GeomVertexFormat::init_type();
-  TextureContext::init_type();
-  GeomContext::init_type();
-  VertexBufferContext::init_type();
   IndexBufferContext::init_type();
+  InternalName::init_type();
+  Lens::init_type();
   Material::init_type();
+  MatrixLens::init_type();
   OcclusionQueryContext::init_type();
   OrthographicLens::init_type();
-  MatrixLens::init_type();
   PerspectiveLens::init_type();
-  Lens::init_type();
   QueryContext::init_type();
+  ShaderContext::init_type();
+  ShaderExpansion::init_type();
   SliderTable::init_type();
   Texture::init_type();
+  TextureContext::init_type();
+  TexturePoolFilter::init_type();
   TextureStage::init_type();
-  ShaderExpansion::init_type();
-  ShaderContext::init_type();
   TransformBlend::init_type();
   TransformBlendTable::init_type();
   TransformTable::init_type();
   UserVertexSlider::init_type();
   UserVertexTransform::init_type();
-  VertexTransform::init_type();
+  VertexBufferContext::init_type();
   VertexSlider::init_type();
+  VertexTransform::init_type();
   VideoTexture::init_type();
-  InternalName::init_type();
 
   //Registration of writeable object's creation
   //functions with BamReader's factory
   Geom::register_with_read_factory();
-  GeomTriangles::register_with_read_factory();
-  GeomTristrips::register_with_read_factory();
-  GeomTrifans::register_with_read_factory();
   GeomLines::register_with_read_factory();
   GeomLinestrips::register_with_read_factory();
   GeomPoints::register_with_read_factory();
+  GeomTriangles::register_with_read_factory();
+  GeomTrifans::register_with_read_factory();
+  GeomTristrips::register_with_read_factory();
   GeomVertexArrayData::register_with_read_factory();
   GeomVertexArrayFormat::register_with_read_factory();
   GeomVertexData::register_with_read_factory();
   GeomVertexFormat::register_with_read_factory();
+  InternalName::register_with_read_factory();
   Material::register_with_read_factory();
-  OrthographicLens::register_with_read_factory();
   MatrixLens::register_with_read_factory();
+  OrthographicLens::register_with_read_factory();
   PerspectiveLens::register_with_read_factory();
   SliderTable::register_with_read_factory();
   Texture::register_with_read_factory();
@@ -310,7 +313,6 @@ ConfigureFn(config_gobj) {
   TransformTable::register_with_read_factory();
   UserVertexSlider::register_with_read_factory();
   UserVertexTransform::register_with_read_factory();
-  InternalName::register_with_read_factory();
 }
 
 ostream &

+ 1 - 0
panda/src/gobj/gobj_composite2.cxx

@@ -15,6 +15,7 @@
 #include "texture.cxx"
 #include "textureContext.cxx"
 #include "texturePool.cxx"
+#include "texturePoolFilter.cxx"
 #include "textureStage.cxx"
 #include "shaderExpansion.cxx"
 #include "shaderContext.cxx"

+ 61 - 0
panda/src/gobj/texture.cxx

@@ -415,6 +415,50 @@ estimate_texture_memory() const {
   return bytes;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::set_aux_data
+//       Access: Published
+//  Description: Records an arbitrary object in the Texture,
+//               associated with a specified key.  The object may
+//               later be retrieved by calling get_aux_data() with the
+//               same key.
+//
+//               These data objects are not recorded to a bam or txo
+//               file.
+////////////////////////////////////////////////////////////////////
+void Texture::
+set_aux_data(const string &key, TypedReferenceCount *aux_data) {
+  _aux_data[key] = aux_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::clear_aux_data
+//       Access: Published
+//  Description: Removes a record previously recorded via
+//               set_aux_data().
+////////////////////////////////////////////////////////////////////
+void Texture::
+clear_aux_data(const string &key) {
+  _aux_data.erase(key);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_aux_data
+//       Access: Published
+//  Description: Returns a record previously recorded via
+//               set_aux_data().  Returns NULL if there was no record
+//               associated with the indicated key.
+////////////////////////////////////////////////////////////////////
+TypedReferenceCount *Texture::
+get_aux_data(const string &key) const {
+  AuxData::const_iterator di;
+  di = _aux_data.find(key);
+  if (di != _aux_data.end()) {
+    return (*di).second;
+  }
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::read_txo
 //       Access: Published
@@ -2357,6 +2401,23 @@ has_alpha(Format format) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::has_binary_alpha
+//       Access: Public, Static
+//  Description: Returns true if the indicated format includes a
+//               binary alpha only, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+has_binary_alpha(Format format) {
+  switch (format) {
+  case F_rgbm:
+    return true;
+
+  default:
+    return false;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::reconsider_z_size
 //       Access: Protected

+ 10 - 0
panda/src/gobj/texture.h

@@ -311,6 +311,10 @@ PUBLISHED:
 
   size_t estimate_texture_memory() const;
 
+  void set_aux_data(const string &key, TypedReferenceCount *aux_data);
+  void clear_aux_data(const string &key);
+  TypedReferenceCount *get_aux_data(const string &key) const;
+
 PUBLISHED:
   // These are published, but in general, you shouldn't be mucking
   // with these values; they are set automatically when a texture is
@@ -360,6 +364,7 @@ public:
 
   static bool is_specific(CompressionMode compression);
   static bool has_alpha(Format format);
+  static bool has_binary_alpha(Format format);
 
 protected:
   virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath,
@@ -516,6 +521,11 @@ protected:
 
   UpdateSeq _modified;
 
+private:
+  // The auxiliary data is not recorded to a bam file.
+  typedef pmap<string, PT(TypedReferenceCount) > AuxData;
+  AuxData _aux_data;
+
   // Datagram stuff
 public:
   static void register_with_read_factory();

+ 142 - 21
panda/src/gobj/texturePool.cxx

@@ -25,10 +25,11 @@
 #include "bamCache.h"
 #include "bamCacheRecord.h"
 #include "pnmFileTypeRegistry.h"
+#include "texturePoolFilter.h"
+#include "configVariableList.h"
+#include "load_dso.h"
 
-
-TexturePool *TexturePool::_global_ptr = (TexturePool *)NULL;
-
+TexturePool *TexturePool::_global_ptr;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePool::write
@@ -62,6 +63,19 @@ register_texture_type(MakeTextureFunc *func, const string &extensions) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::register_filter
+//       Access: Public
+//  Description: Records a TexturePoolFilter object that may operate
+//               on texture images as they are loaded from disk.
+////////////////////////////////////////////////////////////////////
+void TexturePool::
+register_filter(TexturePoolFilter *filter) {
+  gobj_cat.info()
+    << "Registering Texture filter " << *filter << "\n";
+  _filter_registry.push_back(filter);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePool::get_texture_type
 //       Access: Public
@@ -152,6 +166,11 @@ TexturePool *TexturePool::
 get_global_ptr() {
   if (_global_ptr == (TexturePool *)NULL) {
     _global_ptr = new TexturePool;
+
+    // We have to call this here, not in the constructor, so that the
+    // _global_ptr is safely assigned by the time the filters begin to
+    // load.
+    _global_ptr->load_filters();
   }
   return _global_ptr;
 }
@@ -229,20 +248,27 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
     return tex;
   }
 
+  // The texture was not found in the pool.
   PT(Texture) tex;
   PT(BamCacheRecord) record;
   bool store_record = false;
 
+  // Can one of our texture filters supply the texture?
+  tex = pre_load(orig_filename, Filename(), primary_file_num_channels, 0,
+                 read_mipmaps);
+
   BamCache *cache = BamCache::get_global_ptr();
-  if (cache->get_active() && !textures_header_only) {
-    // See if the texture can be found in the on-disk cache, if it is
-    // active.
-    record = cache->lookup(filename, "txo");
-    if (record != (BamCacheRecord *)NULL) {
-      if (record->has_data()) {
-        gobj_cat.info()
-          << "Texture " << filename << " found in disk cache.\n";
-        tex = DCAST(Texture, record->extract_data());
+  if (tex == (Texture *)NULL) {
+    // The texture was not supplied by a texture filter.  See if it
+    // can be found in the on-disk cache, if it is active.
+    if (cache->get_active() && !textures_header_only) {
+      record = cache->lookup(filename, "txo");
+      if (record != (BamCacheRecord *)NULL) {
+        if (record->has_data()) {
+          gobj_cat.info()
+            << "Texture " << filename << " found in disk cache.\n";
+          tex = DCAST(Texture, record->extract_data());
+        }
       }
     }
   }
@@ -276,6 +302,10 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
   }
 
   nassertr(!tex->get_fullpath().empty(), tex);
+
+  // Finally, apply any post-loading texture filters.
+  tex = post_load(tex);
+
   return tex;
 }
 
@@ -318,16 +348,24 @@ ns_load_texture(const Filename &orig_filename,
   PT(BamCacheRecord) record;
   bool store_record = false;
 
+  // Can one of our texture filters supply the texture?
+  tex = pre_load(orig_filename, alpha_filename, primary_file_num_channels, 
+                 alpha_file_channel, read_mipmaps);
+
   BamCache *cache = BamCache::get_global_ptr();
-  if (cache->get_active() && !textures_header_only) {
-    // See if the texture can be found in the on-disk cache, if it is
-    // active.
-    record = cache->lookup(filename, "txo");
-    if (record != (BamCacheRecord *)NULL) {
-      if (record->has_data()) {
-        gobj_cat.info()
-          << "Texture " << filename << " found in disk cache.\n";
-        tex = DCAST(Texture, record->extract_data());
+  if (tex == (Texture *)NULL) {
+    // The texture was not supplied by a texture filter.  See if it
+    // can be found in the on-disk cache, if it is active.
+    if (cache->get_active() && !textures_header_only) {
+      // See if the texture can be found in the on-disk cache, if it is
+      // active.
+      record = cache->lookup(filename, "txo");
+      if (record != (BamCacheRecord *)NULL) {
+        if (record->has_data()) {
+          gobj_cat.info()
+            << "Texture " << filename << " found in disk cache.\n";
+          tex = DCAST(Texture, record->extract_data());
+        }
       }
     }
   }
@@ -364,6 +402,10 @@ ns_load_texture(const Filename &orig_filename,
   }
 
   nassertr(!tex->get_fullpath().empty(), tex);
+
+  // Finally, apply any post-loading texture filters.
+  tex = post_load(tex);
+
   return tex;
 }
 
@@ -684,3 +726,82 @@ report_texture_unreadable(const Filename &filename) const {
     }
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::pre_load
+//       Access: Private
+//  Description: Invokes pre_load() on all registered filters until
+//               one returns non-NULL; returns NULL if there are no
+//               registered filters or if all registered filters
+//               returned NULL.
+////////////////////////////////////////////////////////////////////
+PT(Texture) TexturePool::
+pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
+         int primary_file_num_channels, int alpha_file_channel,
+         bool read_mipmaps) {
+  PT(Texture) tex;
+
+  FilterRegistry::iterator fi;
+  for (fi = _filter_registry.begin();
+       fi != _filter_registry.end();
+       ++fi) {
+    tex = (*fi)->pre_load(orig_filename, orig_alpha_filename,
+                          primary_file_num_channels, alpha_file_channel,
+                          read_mipmaps);
+    if (tex != (Texture *)NULL) {
+      return tex;
+    }
+  }
+
+  return tex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::post_load
+//       Access: Public, Virtual
+//  Description: Invokes post_load() on all registered filters.
+////////////////////////////////////////////////////////////////////
+PT(Texture) TexturePool::
+post_load(Texture *tex) {
+  PT(Texture) result = tex;
+
+  FilterRegistry::iterator fi;
+  for (fi = _filter_registry.begin();
+       fi != _filter_registry.end();
+       ++fi) {
+    result = (*fi)->post_load(result);
+  }
+
+  return result;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::load_filters
+//       Access: Private
+//  Description: Loads up all of the dll's named by the texture-filter
+//               Config.prc variable.
+////////////////////////////////////////////////////////////////////
+void TexturePool::
+load_filters() {
+  ConfigVariableList texture_filter
+    ("texture-filter",
+     PRC_DESC("Names one or more external libraries that should be loaded for the "
+              "purposes of performing texture filtering.  This variable may be repeated several "
+              "times.  As in load-display, the actual library filename is derived by "
+              "prefixing 'lib' to the specified name."));
+  
+  int num_aux = texture_filter.get_num_unique_values();
+  for (int i = 0; i < num_aux; i++) {
+    string name = texture_filter.get_unique_value(i);
+    
+    Filename dlname = Filename::dso_filename("lib" + name + ".so");
+    gobj_cat.info()
+      << "loading texture filter: " << dlname.to_os_specific() << endl;
+    void *tmp = load_dso(dlname);
+    if (tmp == (void *)NULL) {
+      gobj_cat.info()
+        << "Unable to load: " << load_dso_error() << endl;
+    }
+  }
+}

+ 17 - 1
panda/src/gobj/texturePool.h

@@ -26,6 +26,8 @@
 
 #include "pmap.h"
 
+class TexturePoolFilter;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : TexturePool
 // Description : This is the preferred interface for loading textures
@@ -68,12 +70,13 @@ PUBLISHED:
   INLINE static void clear_fake_texture_image();
   INLINE static bool has_fake_texture_image();
   INLINE static const string &get_fake_texture_image();
-  
+
   static void write(ostream &out);
 
 public:
   typedef PT(Texture) MakeTextureFunc();
   void register_texture_type(MakeTextureFunc *func, const string &extensions);
+  void register_filter(TexturePoolFilter *filter);
   
   MakeTextureFunc *get_texture_type(const string &extension) const;
   PT(Texture) make_texture(const string &extension) const;
@@ -107,6 +110,16 @@ private:
 
   void report_texture_unreadable(const Filename &filename) const;
 
+  // Methods to invoke a TexturePoolFilter.
+  PT(Texture) pre_load(const Filename &orig_filename, 
+                       const Filename &orig_alpha_filename,
+                       int primary_file_num_channels,
+                       int alpha_file_channel,
+                       bool read_mipmaps);
+  PT(Texture) post_load(Texture *tex);
+
+  void load_filters();
+
   static TexturePool *_global_ptr;
   typedef phash_map<string,  PT(Texture), string_hash> Textures;
   Textures _textures;
@@ -116,6 +129,9 @@ private:
 
   typedef pmap<string, MakeTextureFunc *> TypeRegistry;
   TypeRegistry _type_registry;
+
+  typedef pvector<TexturePoolFilter *> FilterRegistry;
+  FilterRegistry _filter_registry;
 };
 
 #include "texturePool.I"

+ 18 - 0
panda/src/gobj/texturePoolFilter.I

@@ -0,0 +1,18 @@
+// Filename: texturePoolFilter.I
+// Created by:  drose (27Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 72 - 0
panda/src/gobj/texturePoolFilter.cxx

@@ -0,0 +1,72 @@
+// Filename: texturePoolFilter.cxx
+// Created by:  drose (27Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "texturePoolFilter.h"
+
+TypeHandle TexturePoolFilter::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePoolFilter::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+TexturePoolFilter::
+~TexturePoolFilter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePoolFilter::pre_load
+//       Access: Public, Virtual
+//  Description: This method is called before each texture is loaded
+//               from disk, via the TexturePool, for the first time.
+//               If this method returns NULL, then a new Texture will
+//               be allocated and loaded from disk normally by the
+//               TexturePool; otherwise, if it returns non-NULL, then
+//               that returned pointer will be used as the Texture for
+//               this filename.
+////////////////////////////////////////////////////////////////////
+PT(Texture) TexturePoolFilter::
+pre_load(const Filename &, const Filename &, int, int, bool) {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePoolFilter::post_load
+//       Access: Public, Virtual
+//  Description: This method is called after each texture has been
+//               loaded from disk, via the TexturePool, for the first
+//               time.  By the time this method is called, the Texture
+//               has already been fully read from disk.  This method
+//               should return the Texture pointer that the
+//               TexturePool should actually return (usually it is the
+//               same as the pointer supplied).
+////////////////////////////////////////////////////////////////////
+PT(Texture) TexturePoolFilter::
+post_load(Texture *tex) {
+  return tex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePoolFilter::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void TexturePoolFilter::
+output(ostream &out) const {
+  out << get_type();
+}

+ 87 - 0
panda/src/gobj/texturePoolFilter.h

@@ -0,0 +1,87 @@
+// Filename: texturePoolFilter.h
+// Created by:  drose (27Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef TEXTUREPOOLFILTER_H
+#define TEXTUREPOOLFILTER_H
+
+#include "pandabase.h"
+#include "texture.h"
+#include "pointerTo.h"
+#include "typedObject.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : TexturePoolFilter
+// Description : This is an abstract base class, a placeholder for any
+//               number of different classes that may wish to
+//               implement an effect on every texture loaded from disk
+//               via the TexturePool.
+//
+//               In practice, as of the time of this writing, only the
+//               TxaFileFilter (in pandatool) actually implements
+//               this.  But other kinds of filters are possible.
+//
+//               This filter, once registered, will get a callback and
+//               a chance to modify each texture as it is loaded from
+//               disk the first time.  If more than one filter is
+//               registered, each will be called in sequence, in the
+//               order in which they were registered.  
+//
+//               The filter does not get called again if the texture
+//               is subsequently reloaded from disk.  It is suggested
+//               that filters for which this might be a problem should
+//               call tex->set_keep_ram_image(true).
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA TexturePoolFilter : public TypedObject {
+public:
+  virtual ~TexturePoolFilter();
+
+  virtual PT(Texture) pre_load(const Filename &orig_filename, 
+                               const Filename &orig_alpha_filename,
+                               int primary_file_num_channels,
+                               int alpha_file_channel,
+                               bool read_mipmaps);
+  virtual PT(Texture) post_load(Texture *tex);
+
+  virtual void output(ostream &out) const;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedObject::init_type();
+    register_type(_type_handle, "TexturePoolFilter",
+                  TypedObject::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const TexturePoolFilter &filter) {
+  filter.output(out);
+  return out;
+}
+
+#include "texturePoolFilter.I"
+
+#endif

+ 10 - 0
pandatool/src/egg-palettize/Sources.pp

@@ -15,3 +15,13 @@
 
 #end bin_target
 
+#begin lib_target
+  #define TARGET txafile
+  #define LOCAL_LIBS \
+    palettizer
+
+  #define SOURCES \
+    txaFileFilter.h txaFileFilter.I txaFileFilter.cxx
+
+#end lib_target
+

+ 18 - 0
pandatool/src/egg-palettize/txaFileFilter.I

@@ -0,0 +1,18 @@
+// Filename: txaFileFilter.I
+// Created by:  drose (27Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 162 - 0
pandatool/src/egg-palettize/txaFileFilter.cxx

@@ -0,0 +1,162 @@
+// Filename: txaFileFilter.cxx
+// Created by:  drose (27Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "txaFileFilter.h"
+#include "palettizer.h"
+#include "txaFile.h"
+#include "textureImage.h"
+#include "sourceTextureImage.h"
+#include "texturePool.h"
+#include "dconfig.h"
+#include "configVariableFilename.h"
+#include "virtualFileSystem.h"
+#include "config_util.h"
+
+NotifyCategoryDeclNoExport(txafile);
+NotifyCategoryDef(txafile, "");
+
+// A few lines to register this filter type with the TexturePool when
+// the shared library is loaded.
+Configure(config_txaFileFilter);
+ConfigureFn(config_txaFileFilter) {
+  TxaFileFilter::init_type();
+  TexturePool *pool = TexturePool::get_global_ptr();
+  pool->register_filter(new TxaFileFilter);
+}
+
+TypeHandle TxaFileFilter::_type_handle;
+TxaFile *TxaFileFilter::_txa_file;
+bool TxaFileFilter::_got_txa_file;
+
+////////////////////////////////////////////////////////////////////
+//     Function: TxaFileFilter::post_load
+//       Access: Public, Virtual
+//  Description: This method is called after each texture has been
+//               loaded from disk, via the TexturePool, for the first
+//               time.  By the time this method is called, the Texture
+//               has already been fully read from disk.  This method
+//               should return the Texture pointer that the
+//               TexturePool should actually return (usually it is the
+//               same as the pointer supplied).
+////////////////////////////////////////////////////////////////////
+PT(Texture) TxaFileFilter::
+post_load(Texture *tex) {
+  if (!_got_txa_file) {
+    read_txa_file();
+  }
+
+  TextureImage tex_image;
+  string name = tex->get_filename().get_basename_wo_extension();
+  tex_image.set_name(name);
+
+  SourceTextureImage *source = tex_image.get_source
+    (tex->get_fullpath(), tex->get_alpha_fullpath(), 0);
+  PNMImage pnm_image;
+  tex->store(pnm_image);
+  source->set_header(pnm_image);
+  tex_image.set_source_image(pnm_image);
+
+  tex_image.pre_txa_file();
+
+  bool matched = _txa_file->match_texture(&tex_image);
+  if (txafile_cat.is_debug()) {
+    if (!matched) {
+      txafile_cat.debug()
+        << "Not matched: " << name << "\n";
+    } else {
+      txafile_cat.debug()
+        << "Matched: " << name << "\n";
+    }
+  }
+
+  tex_image.post_txa_file();
+
+  PNMImage dest(tex_image.get_x_size(), 
+                tex_image.get_y_size(), 
+                tex_image.get_num_channels(),
+                pnm_image.get_maxval());
+  dest.quick_filter_from(pnm_image);
+
+  tex->load(dest);
+
+  // Create an EggTexture to pass back the requested alpha mode to
+  // the egg loader, if the texture is now being loaded from an egg
+  // file.
+  PT(EggTexture) egg_tex = new EggTexture(tex->get_name(), tex->get_fullpath());
+  const TextureProperties &props = tex_image.get_properties();
+
+  egg_tex->set_alpha_mode(tex_image.get_alpha_mode());
+  egg_tex->set_format(props._format);
+  egg_tex->set_minfilter(props._minfilter);
+  egg_tex->set_minfilter(props._magfilter);
+  egg_tex->set_anisotropic_degree(props._anisotropic_degree);
+
+  tex->set_aux_data("egg", egg_tex);
+
+  return tex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TxaFileFilter::read_txa_file
+//       Access: Private, Static
+//  Description: Reads the textures.txa file named by the variable
+//               txa-file.  Called only once, at startup.
+////////////////////////////////////////////////////////////////////
+void TxaFileFilter::
+read_txa_file() {
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
+  // We need to create a global Palettizer object to hold some of the
+  // global properties that may be specified in a txa file.
+  if (pal == (Palettizer *)NULL) {
+    pal = new Palettizer;
+  }
+
+  _txa_file = new TxaFile;
+  _got_txa_file = true;
+  
+  ConfigVariableFilename txa_file
+    ("txa-file", Filename("textures.txa"),
+     PRC_DESC("Specify the name of the txa file to load when the txafile texture filter"
+              "is in effect."));
+
+  Filename filename = txa_file;
+  vfs->resolve_filename(filename, texture_path);
+  vfs->resolve_filename(filename, model_path);
+
+  if (!vfs->exists(filename)) {
+    txafile_cat.warning()
+      << "Filename " << filename << " not found.\n";
+  } else {
+    filename.set_text();
+    istream *ifile = vfs->open_read_file(filename, true);
+    if (ifile == (istream *)NULL) {
+      txafile_cat.warning()
+        << "Filename " << filename << " cannot be read.\n";
+    } else {
+      if (!_txa_file->read(*ifile, filename)) {
+        txafile_cat.warning()
+          << "Syntax errors in " << filename << "\n";
+      } else {
+        txafile_cat.info()
+          << "Read " << filename << "\n";
+      }
+      vfs->close_read_file(ifile);
+    }
+  }
+}

+ 80 - 0
pandatool/src/egg-palettize/txaFileFilter.h

@@ -0,0 +1,80 @@
+// Filename: txaFileFilter.h
+// Created by:  drose (27Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef TXAFILEFILTER_H
+#define TXAFILEFILTER_H
+
+#include "pandatoolbase.h"
+#include "texturePoolFilter.h"
+
+class TxaFile;
+
+////////////////////////////////////////////////////////////////////
+//       Class : TxaFileFilter
+// Description : This is an abstract base class, a placeholder for any
+//               number of different classes that may wish to
+//               implement an effect on every texture loaded from disk
+//               via the TexturePool.
+//
+//               In practice, as of the time of this writing, only the
+//               TxaFileFilter (in pandatool) actually implements
+//               this.  But other kinds of filters are possible.
+//
+//               This filter, once registered, will get a callback and
+//               a chance to modify each texture as it is loaded from
+//               disk the first time.  If more than one filter is
+//               registered, each will be called in sequence, in the
+//               order in which they were registered.  
+//
+//               The filter does not get called again if the texture
+//               is subsequently reloaded from disk.  It is suggested
+//               that filters for which this might be a problem should
+//               call tex->set_keep_ram_image(true).
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA TxaFileFilter : public TexturePoolFilter {
+public:
+  virtual PT(Texture) post_load(Texture *tex);
+
+private:
+  static void read_txa_file();
+
+private:
+  static TxaFile *_txa_file;
+  static bool _got_txa_file;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TexturePoolFilter::init_type();
+    register_type(_type_handle, "TxaFileFilter",
+                  TexturePoolFilter::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "txaFileFilter.I"
+
+#endif