浏览代码

more work towards asynchronous texture loads: auto-caching compressed texture versions

David Rose 17 年之前
父节点
当前提交
617a769ef7
共有 38 个文件被更改,包括 1256 次插入611 次删除
  1. 1 1
      panda/src/dxgsg8/dxTextureContext8.cxx
  2. 1 1
      panda/src/dxgsg9/dxTextureContext9.cxx
  3. 1 1
      panda/src/egg/eggTexture.I
  4. 8 0
      panda/src/egg2pg/config_egg2pg.cxx
  5. 1 0
      panda/src/egg2pg/config_egg2pg.h
  6. 10 4
      panda/src/egg2pg/eggLoader.cxx
  7. 249 218
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  8. 1 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  9. 3 3
      panda/src/gobj/Sources.pp
  10. 0 19
      panda/src/gobj/config_gobj.cxx
  11. 0 2
      panda/src/gobj/config_gobj.h
  12. 89 137
      panda/src/gobj/texture.I
  13. 392 88
      panda/src/gobj/texture.cxx
  14. 30 10
      panda/src/gobj/texture.h
  15. 14 10
      panda/src/gobj/texturePool.I
  16. 158 79
      panda/src/gobj/texturePool.cxx
  17. 25 10
      panda/src/gobj/texturePool.h
  18. 2 1
      panda/src/gobj/texturePoolFilter.cxx
  19. 4 1
      panda/src/gobj/texturePoolFilter.h
  20. 1 0
      panda/src/gsgbase/graphicsStateGuardianBase.h
  21. 0 3
      panda/src/pgraph/Sources.pp
  22. 1 1
      panda/src/pgraph/loader.cxx
  23. 1 1
      panda/src/pgraph/loaderFileTypeBam.cxx
  24. 0 1
      panda/src/pgraph/pgraph_composite3.cxx
  25. 3 0
      panda/src/putil/Sources.pp
  26. 2 1
      panda/src/putil/bam.h
  27. 93 0
      panda/src/putil/bamCache.I
  28. 15 4
      panda/src/putil/bamCache.cxx
  29. 14 2
      panda/src/putil/bamCache.h
  30. 21 0
      panda/src/putil/bamReader.I
  31. 7 1
      panda/src/putil/bamReader.h
  32. 20 0
      panda/src/putil/config_util.cxx
  33. 3 4
      panda/src/putil/config_util.h
  34. 25 3
      panda/src/putil/loaderOptions.I
  35. 43 0
      panda/src/putil/loaderOptions.cxx
  36. 16 4
      panda/src/putil/loaderOptions.h
  37. 1 0
      panda/src/putil/putil_composite2.cxx
  38. 1 1
      panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

+ 1 - 1
panda/src/dxgsg8/dxTextureContext8.cxx

@@ -709,7 +709,7 @@ create_texture(DXScreenData &scrn) {
     goto error_exit;
     goto error_exit;
   }
   }
 
 
-  get_texture()->texture_uploaded();
+  get_texture()->texture_uploaded(scrn._dxgsg8);
   mark_loaded();
   mark_loaded();
   return true;
   return true;
 
 

+ 1 - 1
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -952,7 +952,7 @@ create_texture(DXScreenData &scrn) {
         }
         }
       }
       }
     }
     }
-    get_texture()->texture_uploaded();
+    get_texture()->texture_uploaded(scrn._dxgsg9);
   }
   }
   mark_loaded();
   mark_loaded();
   
   

+ 1 - 1
panda/src/egg/eggTexture.I

@@ -955,7 +955,7 @@ get_alpha_file_channel() const {
 //               mipmap level number; and the texture will be defined
 //               mipmap level number; and the texture will be defined
 //               with a series of images, one for each mipmap level.
 //               with a series of images, one for each mipmap level.
 //
 //
-//               If the filename is of a time that already requires a
+//               If the filename is of a type that already requires a
 //               hash mark, such as a cube map or a 3-d texture, then
 //               hash mark, such as a cube map or a 3-d texture, then
 //               the filename should now require two hash marks, and
 //               the filename should now require two hash marks, and
 //               the first one indicates the mipmap level number,
 //               the first one indicates the mipmap level number,

+ 8 - 0
panda/src/egg2pg/config_egg2pg.cxx

@@ -148,6 +148,14 @@ ConfigVariableBool egg_emulate_bface
           "it is false, a single polygon will be created with the two_sided "
           "it is false, a single polygon will be created with the two_sided "
           "flag set on it."));
           "flag set on it."));
 
 
+ConfigVariableBool egg_preload_simple_textures
+("egg-preload-simple-textures", true,
+ PRC_DESC("This specifies whether the egg loader will generate simple "
+          "texture images for each texture loaded.  This supercedes the "
+          "preload-simple-textures global default, for egg files.  In "
+          "fact, the egg loader will generate simple texture images if "
+          "either this or preload-simple-textures is true."));
+
 ConfigureFn(config_egg2pg) {
 ConfigureFn(config_egg2pg) {
   init_libegg2pg();
   init_libegg2pg();
 }
 }

+ 1 - 0
panda/src/egg2pg/config_egg2pg.h

@@ -50,6 +50,7 @@ extern EXPCL_PANDAEGG ConfigVariableEnum<EggRenderMode::AlphaMode> egg_alpha_mod
 extern EXPCL_PANDAEGG ConfigVariableInt egg_max_vertices;
 extern EXPCL_PANDAEGG ConfigVariableInt egg_max_vertices;
 extern EXPCL_PANDAEGG ConfigVariableInt egg_max_indices;
 extern EXPCL_PANDAEGG ConfigVariableInt egg_max_indices;
 extern EXPCL_PANDAEGG ConfigVariableBool egg_emulate_bface;
 extern EXPCL_PANDAEGG ConfigVariableBool egg_emulate_bface;
+extern EXPCL_PANDAEGG ConfigVariableBool egg_preload_simple_textures;
 
 
 extern EXPCL_PANDAEGG void init_libegg2pg();
 extern EXPCL_PANDAEGG void init_libegg2pg();
 
 

+ 10 - 4
panda/src/egg2pg/eggLoader.cxx

@@ -928,6 +928,12 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
     }
     }
   }
   }
 
 
+  // By convention, the egg loader will preload the simple texture images.
+  LoaderOptions options;
+  if (egg_preload_simple_textures) {
+    options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_preload_simple);
+  }
+
   PT(Texture) tex;
   PT(Texture) tex;
   switch (egg_tex->get_texture_type()) {
   switch (egg_tex->get_texture_type()) {
   case EggTexture::TT_unspecified:
   case EggTexture::TT_unspecified:
@@ -938,22 +944,22 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
                                       egg_tex->get_alpha_fullpath(),
                                       egg_tex->get_alpha_fullpath(),
                                       wanted_channels,
                                       wanted_channels,
                                       egg_tex->get_alpha_file_channel(),
                                       egg_tex->get_alpha_file_channel(),
-				      egg_tex->get_read_mipmaps());
+				      egg_tex->get_read_mipmaps(), options);
     } else {
     } else {
       tex = TexturePool::load_texture(egg_tex->get_fullpath(),
       tex = TexturePool::load_texture(egg_tex->get_fullpath(),
                                       wanted_channels,
                                       wanted_channels,
-				      egg_tex->get_read_mipmaps());
+				      egg_tex->get_read_mipmaps(), options);
     }
     }
     break;
     break;
 
 
   case EggTexture::TT_3d_texture:
   case EggTexture::TT_3d_texture:
     tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
     tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
-				       egg_tex->get_read_mipmaps());
+				       egg_tex->get_read_mipmaps(), options);
     break;
     break;
 
 
   case EggTexture::TT_cube_map:
   case EggTexture::TT_cube_map:
     tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
     tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
-				     egg_tex->get_read_mipmaps());
+				     egg_tex->get_read_mipmaps(), options);
     break;
     break;
   }
   }
 
 

+ 249 - 218
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -46,6 +46,8 @@
 #include "indirectLess.h"
 #include "indirectLess.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "load_prc_file.h"
 #include "load_prc_file.h"
+#include "bamCache.h"
+#include "bamCacheRecord.h"
 
 
 #ifdef HAVE_CG
 #ifdef HAVE_CG
 #include "Cg/cgGL.h"
 #include "Cg/cgGL.h"
@@ -2666,224 +2668,8 @@ extract_texture_data(Texture *tex) {
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   nassertr(tc != (TextureContext *)NULL, false);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-  GLenum target = get_texture_target(tex->get_texture_type());
-  GLP(BindTexture)(target, gtc->_index);
-
-  report_my_gl_errors();
-
-  GLint wrap_u, wrap_v, wrap_w;
-  GLint minfilter, magfilter;
-  GLfloat border_color[4];
-
-  GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_S, &wrap_u);
-  GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_T, &wrap_v);
-  wrap_w = GL_REPEAT;
-  if (_supports_3d_texture) {
-    GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_R, &wrap_w);
-  }
-  GLP(GetTexParameteriv)(target, GL_TEXTURE_MIN_FILTER, &minfilter);
-
-  // Mesa has a bug querying this property.
-  magfilter = GL_LINEAR;
-  //  GLP(GetTexParameteriv)(target, GL_TEXTURE_MAG_FILTER, &magfilter);
-
-  GLP(GetTexParameterfv)(target, GL_TEXTURE_BORDER_COLOR, border_color);
-
-  GLenum page_target = target;
-  if (target == GL_TEXTURE_CUBE_MAP) {
-    // We need a particular page to get the level parameter from.
-    page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
-  }
-
-  GLint width = 1, height = 1, depth = 1;
-  GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_WIDTH, &width);
-  GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_HEIGHT, &height);
-  if (_supports_3d_texture) {
-    GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_DEPTH, &depth);
-  }
-  report_my_gl_errors();
-
-  GLint internal_format;
-  GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
-
-  // Make sure we were able to query those parameters properly.
-  GLenum error_code = GLP(GetError)();
-  if (error_code != GL_NO_ERROR) {
-    GLCAT.error()
-      << "Unable to query texture parameters for " << tex->get_name()
-      << " : " << get_error_string(error_code) << "\n";
-
-    return false;
-  }
-
-  Texture::ComponentType type = Texture::T_unsigned_byte;
-  Texture::Format format = Texture::F_rgb;
-  Texture::CompressionMode compression = Texture::CM_off;
-
-  switch (internal_format) {
-  case GL_COLOR_INDEX:
-    format = Texture::F_color_index;
-    break;
-  case GL_DEPTH_COMPONENT:
-  case GL_DEPTH_STENCIL_EXT:
-    type = Texture::T_float;
-    format = Texture::F_depth_stencil;
-    break;
-  case GL_RGBA:
-    format = Texture::F_rgba;
-    break;
-  case GL_RGBA4:
-    format = Texture::F_rgba4;
-    break;
-  case GL_RGBA8:
-    format = Texture::F_rgba8;
-    break;
-  case GL_RGBA12:
-    type = Texture::T_unsigned_short;
-    format = Texture::F_rgba12;
-    break;
-
-  case GL_RGB:
-    format = Texture::F_rgb;
-    break;
-  case GL_RGB5:
-    format = Texture::F_rgb5;
-    break;
-  case GL_RGB5_A1:
-    format = Texture::F_rgba5;
-    break;
-  case GL_RGB8:
-    format = Texture::F_rgb8;
-    break;
-  case GL_RGB12:
-    format = Texture::F_rgb12;
-    break;
-  case GL_R3_G3_B2:
-    format = Texture::F_rgb332;
-
-  case GL_RED:
-    format = Texture::F_red;
-    break;
-  case GL_GREEN:
-    format = Texture::F_green;
-    break;
-  case GL_BLUE:
-    format = Texture::F_blue;
-    break;
-  case GL_ALPHA:
-    format = Texture::F_alpha;
-    break;
-  case GL_LUMINANCE:
-    format = Texture::F_luminance;
-    break;
-  case GL_LUMINANCE_ALPHA:
-    format = Texture::F_luminance_alpha;
-    break;
-
-  case GL_COMPRESSED_RGB:
-    format = Texture::F_rgb;
-    compression = Texture::CM_on;
-    break;
-  case GL_COMPRESSED_RGBA:
-    format = Texture::F_rgba;
-    compression = Texture::CM_on;
-    break;
-  case GL_COMPRESSED_ALPHA:
-    format = Texture::F_alpha;
-    compression = Texture::CM_on;
-    break;
-  case GL_COMPRESSED_LUMINANCE:
-    format = Texture::F_luminance;
-    compression = Texture::CM_on;
-    break;
-  case GL_COMPRESSED_LUMINANCE_ALPHA:
-    format = Texture::F_luminance_alpha;
-    compression = Texture::CM_on;
-    break;
-
-  case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-    format = Texture::F_rgb;
-    compression = Texture::CM_dxt1;
-    break;
-  case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-    format = Texture::F_rgbm;
-    compression = Texture::CM_dxt1;
-    break;
-  case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-    format = Texture::F_rgba;
-    compression = Texture::CM_dxt3;
-    break;
-  case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-    format = Texture::F_rgba;
-    compression = Texture::CM_dxt5;
-    break;
-  case GL_COMPRESSED_RGB_FXT1_3DFX:
-    format = Texture::F_rgb;
-    compression = Texture::CM_fxt1;
-    break;
-  case GL_COMPRESSED_RGBA_FXT1_3DFX:
-    format = Texture::F_rgba;
-    compression = Texture::CM_fxt1;
-    break;
-  }
-
-  /*
-  switch (target) {
-  case GL_TEXTURE_1D:
-    tex->setup_1d_texture(width, type, format);
-    break;
-    
-  case GL_TEXTURE_2D:
-    tex->setup_2d_texture(width, height, type, format);
-    break;
-    
-  case GL_TEXTURE_3D:
-    tex->setup_3d_texture(width, height, depth, type, format);
-    break;
-    
-  case GL_TEXTURE_CUBE_MAP:
-    tex->setup_cube_map(width, type, format);
-    break;
-  }
-  */
-
-  tex->set_wrap_u(get_panda_wrap_mode(wrap_u));
-  tex->set_wrap_v(get_panda_wrap_mode(wrap_v));
-  tex->set_wrap_w(get_panda_wrap_mode(wrap_w));
-  tex->set_border_color(Colorf(border_color[0], border_color[1],
-                               border_color[2], border_color[3]));
-
-  tex->set_minfilter(get_panda_filter_type(minfilter));
-  //  tex->set_magfilter(get_panda_filter_type(magfilter));
-
-  PTA_uchar image;
-  size_t page_size = 0;
-
-  if (!extract_texture_image(image, page_size, tex, target, page_target,
-                             type, compression, 0)) {
-    return false;
-  }
-
-  tex->set_ram_image(image, compression, page_size);
-
-  if (tex->uses_mipmaps()) {
-    // Also get the mipmap levels.
-    GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
-    GLint highest_level = num_expected_levels;
-    if (is_at_least_version(1, 2)) {
-      GLP(GetTexParameteriv)(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
-      highest_level = min(highest_level, num_expected_levels);
-    }
-    for (int n = 1; n <= highest_level; ++n) {
-      if (!extract_texture_image(image, page_size, tex, target, page_target,
-                                 type, compression, n)) {
-        return false;
-      }
-      tex->set_ram_mipmap_image(n, image, page_size);
-    }
-  }
 
 
-  return true;
+  return do_extract_texture_data(gtc);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -7159,7 +6945,22 @@ upload_texture(CLP(TextureContext) *gtc) {
     }
     }
 #endif
 #endif
 
 
-    tex->texture_uploaded();
+    if (tex->get_post_load_store_cache()) {
+      tex->set_post_load_store_cache(false);
+      // OK, get the RAM image, and save it in a BamCache record.
+      if (do_extract_texture_data(gtc)) {
+        if (tex->has_ram_image()) {
+          BamCache *cache = BamCache::get_global_ptr();
+          PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
+          if (record != (BamCacheRecord *)NULL) {
+            record->set_data(tex, false);
+            cache->store(record);
+          }
+        }
+      }
+    }
+
+    tex->texture_uploaded(this);
     gtc->mark_loaded();
     gtc->mark_loaded();
 
 
     report_my_gl_errors();
     report_my_gl_errors();
@@ -7679,6 +7480,236 @@ check_nonresident_texture(BufferContextChain &chain) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::do_extract_texture_data
+//       Access: Protected
+//  Description: The internal implementation of
+//               extract_texture_data(), given an already-created
+//               TextureContext.
+////////////////////////////////////////////////////////////////////
+bool CLP(GraphicsStateGuardian)::
+do_extract_texture_data(CLP(TextureContext) *gtc) {
+  report_my_gl_errors();
+
+  Texture *tex = gtc->get_texture();
+  GLenum target = get_texture_target(tex->get_texture_type());
+  GLP(BindTexture)(target, gtc->_index);
+
+  GLint wrap_u, wrap_v, wrap_w;
+  GLint minfilter, magfilter;
+  GLfloat border_color[4];
+
+  GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_S, &wrap_u);
+  GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_T, &wrap_v);
+  wrap_w = GL_REPEAT;
+  if (_supports_3d_texture) {
+    GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_R, &wrap_w);
+  }
+  GLP(GetTexParameteriv)(target, GL_TEXTURE_MIN_FILTER, &minfilter);
+
+  // Mesa has a bug querying this property.
+  magfilter = GL_LINEAR;
+  //  GLP(GetTexParameteriv)(target, GL_TEXTURE_MAG_FILTER, &magfilter);
+
+  GLP(GetTexParameterfv)(target, GL_TEXTURE_BORDER_COLOR, border_color);
+
+  GLenum page_target = target;
+  if (target == GL_TEXTURE_CUBE_MAP) {
+    // We need a particular page to get the level parameter from.
+    page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+  }
+
+  GLint width = 1, height = 1, depth = 1;
+  GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_WIDTH, &width);
+  GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_HEIGHT, &height);
+  if (_supports_3d_texture) {
+    GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_DEPTH, &depth);
+  }
+  report_my_gl_errors();
+
+  GLint internal_format;
+  GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+
+  // Make sure we were able to query those parameters properly.
+  GLenum error_code = GLP(GetError)();
+  if (error_code != GL_NO_ERROR) {
+    GLCAT.error()
+      << "Unable to query texture parameters for " << tex->get_name()
+      << " : " << get_error_string(error_code) << "\n";
+
+    return false;
+  }
+
+  Texture::ComponentType type = Texture::T_unsigned_byte;
+  Texture::Format format = Texture::F_rgb;
+  Texture::CompressionMode compression = Texture::CM_off;
+
+  switch (internal_format) {
+  case GL_COLOR_INDEX:
+    format = Texture::F_color_index;
+    break;
+  case GL_DEPTH_COMPONENT:
+  case GL_DEPTH_STENCIL_EXT:
+    type = Texture::T_float;
+    format = Texture::F_depth_stencil;
+    break;
+  case GL_RGBA:
+    format = Texture::F_rgba;
+    break;
+  case GL_RGBA4:
+    format = Texture::F_rgba4;
+    break;
+  case GL_RGBA8:
+    format = Texture::F_rgba8;
+    break;
+  case GL_RGBA12:
+    type = Texture::T_unsigned_short;
+    format = Texture::F_rgba12;
+    break;
+
+  case GL_RGB:
+    format = Texture::F_rgb;
+    break;
+  case GL_RGB5:
+    format = Texture::F_rgb5;
+    break;
+  case GL_RGB5_A1:
+    format = Texture::F_rgba5;
+    break;
+  case GL_RGB8:
+    format = Texture::F_rgb8;
+    break;
+  case GL_RGB12:
+    format = Texture::F_rgb12;
+    break;
+  case GL_R3_G3_B2:
+    format = Texture::F_rgb332;
+
+  case GL_RED:
+    format = Texture::F_red;
+    break;
+  case GL_GREEN:
+    format = Texture::F_green;
+    break;
+  case GL_BLUE:
+    format = Texture::F_blue;
+    break;
+  case GL_ALPHA:
+    format = Texture::F_alpha;
+    break;
+  case GL_LUMINANCE:
+    format = Texture::F_luminance;
+    break;
+  case GL_LUMINANCE_ALPHA:
+    format = Texture::F_luminance_alpha;
+    break;
+
+  case GL_COMPRESSED_RGB:
+    format = Texture::F_rgb;
+    compression = Texture::CM_on;
+    break;
+  case GL_COMPRESSED_RGBA:
+    format = Texture::F_rgba;
+    compression = Texture::CM_on;
+    break;
+  case GL_COMPRESSED_ALPHA:
+    format = Texture::F_alpha;
+    compression = Texture::CM_on;
+    break;
+  case GL_COMPRESSED_LUMINANCE:
+    format = Texture::F_luminance;
+    compression = Texture::CM_on;
+    break;
+  case GL_COMPRESSED_LUMINANCE_ALPHA:
+    format = Texture::F_luminance_alpha;
+    compression = Texture::CM_on;
+    break;
+
+  case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    format = Texture::F_rgb;
+    compression = Texture::CM_dxt1;
+    break;
+  case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    format = Texture::F_rgbm;
+    compression = Texture::CM_dxt1;
+    break;
+  case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    format = Texture::F_rgba;
+    compression = Texture::CM_dxt3;
+    break;
+  case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    format = Texture::F_rgba;
+    compression = Texture::CM_dxt5;
+    break;
+  case GL_COMPRESSED_RGB_FXT1_3DFX:
+    format = Texture::F_rgb;
+    compression = Texture::CM_fxt1;
+    break;
+  case GL_COMPRESSED_RGBA_FXT1_3DFX:
+    format = Texture::F_rgba;
+    compression = Texture::CM_fxt1;
+    break;
+  }
+
+  /*
+  switch (target) {
+  case GL_TEXTURE_1D:
+    tex->setup_1d_texture(width, type, format);
+    break;
+    
+  case GL_TEXTURE_2D:
+    tex->setup_2d_texture(width, height, type, format);
+    break;
+    
+  case GL_TEXTURE_3D:
+    tex->setup_3d_texture(width, height, depth, type, format);
+    break;
+    
+  case GL_TEXTURE_CUBE_MAP:
+    tex->setup_cube_map(width, type, format);
+    break;
+  }
+  */
+
+  tex->set_wrap_u(get_panda_wrap_mode(wrap_u));
+  tex->set_wrap_v(get_panda_wrap_mode(wrap_v));
+  tex->set_wrap_w(get_panda_wrap_mode(wrap_w));
+  tex->set_border_color(Colorf(border_color[0], border_color[1],
+                               border_color[2], border_color[3]));
+
+  tex->set_minfilter(get_panda_filter_type(minfilter));
+  //  tex->set_magfilter(get_panda_filter_type(magfilter));
+
+  PTA_uchar image;
+  size_t page_size = 0;
+
+  if (!extract_texture_image(image, page_size, tex, target, page_target,
+                             type, compression, 0)) {
+    return false;
+  }
+
+  tex->set_ram_image(image, compression, page_size);
+
+  if (tex->uses_mipmaps()) {
+    // Also get the mipmap levels.
+    GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
+    GLint highest_level = num_expected_levels;
+    if (is_at_least_version(1, 2)) {
+      GLP(GetTexParameteriv)(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
+      highest_level = min(highest_level, num_expected_levels);
+    }
+    for (int n = 1; n <= highest_level; ++n) {
+      if (!extract_texture_image(image, page_size, tex, target, page_target,
+                                 type, compression, n)) {
+        return false;
+      }
+      tex->set_ram_mipmap_image(n, image, page_size);
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::extract_texture_image
 //     Function: GLGraphicsStateGuardian::extract_texture_image
 //       Access: Protected
 //       Access: Protected

+ 1 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -336,6 +336,7 @@ protected:
 
 
   size_t get_texture_memory_size(Texture *tex);
   size_t get_texture_memory_size(Texture *tex);
   void check_nonresident_texture(BufferContextChain &chain);
   void check_nonresident_texture(BufferContextChain &chain);
+  bool do_extract_texture_data(CLP(TextureContext) *gtc);
   bool extract_texture_image(PTA_uchar &image, size_t &page_size,
   bool extract_texture_image(PTA_uchar &image, size_t &page_size,
            Texture *tex, GLenum target, GLenum page_target,
            Texture *tex, GLenum target, GLenum page_target,
            Texture::ComponentType type,
            Texture::ComponentType type,

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

@@ -39,13 +39,13 @@
     geomVertexWriter.h geomVertexWriter.I \
     geomVertexWriter.h geomVertexWriter.I \
     indexBufferContext.I indexBufferContext.h \
     indexBufferContext.I indexBufferContext.h \
     internalName.I internalName.h \
     internalName.I internalName.h \
+    lens.h lens.I \
     material.I material.h materialPool.I materialPool.h  \
     material.I material.h materialPool.I materialPool.h  \
     matrixLens.I matrixLens.h \
     matrixLens.I matrixLens.h \
     occlusionQueryContext.I occlusionQueryContext.h \
     occlusionQueryContext.I occlusionQueryContext.h \
     orthographicLens.I orthographicLens.h perspectiveLens.I  \
     orthographicLens.I orthographicLens.h perspectiveLens.I  \
     perspectiveLens.h \
     perspectiveLens.h \
     preparedGraphicsObjects.I preparedGraphicsObjects.h \
     preparedGraphicsObjects.I preparedGraphicsObjects.h \
-    lens.h lens.I \
     queryContext.I queryContext.h \
     queryContext.I queryContext.h \
     savedContext.I savedContext.h \
     savedContext.I savedContext.h \
     shader.I shader.h \
     shader.I shader.h \
@@ -103,12 +103,12 @@
     indexBufferContext.cxx \
     indexBufferContext.cxx \
     material.cxx  \
     material.cxx  \
     internalName.cxx \
     internalName.cxx \
+    lens.cxx  \
     materialPool.cxx matrixLens.cxx \
     materialPool.cxx matrixLens.cxx \
     occlusionQueryContext.cxx \
     occlusionQueryContext.cxx \
     orthographicLens.cxx  \
     orthographicLens.cxx  \
     perspectiveLens.cxx \
     perspectiveLens.cxx \
     preparedGraphicsObjects.cxx \
     preparedGraphicsObjects.cxx \
-    lens.cxx  \
     queryContext.cxx \
     queryContext.cxx \
     savedContext.cxx \
     savedContext.cxx \
     shader.cxx \
     shader.cxx \
@@ -165,13 +165,13 @@
     geomVertexWriter.h geomVertexWriter.I \
     geomVertexWriter.h geomVertexWriter.I \
     indexBufferContext.I indexBufferContext.h \
     indexBufferContext.I indexBufferContext.h \
     internalName.I internalName.h \
     internalName.I internalName.h \
+    lens.h lens.I \
     material.I material.h \
     material.I material.h \
     materialPool.I materialPool.h matrixLens.I matrixLens.h \
     materialPool.I materialPool.h matrixLens.I matrixLens.h \
     occlusionQueryContext.I occlusionQueryContext.h \
     occlusionQueryContext.I occlusionQueryContext.h \
     orthographicLens.I orthographicLens.h perspectiveLens.I \
     orthographicLens.I orthographicLens.h perspectiveLens.I \
     perspectiveLens.h \
     perspectiveLens.h \
     preparedGraphicsObjects.I preparedGraphicsObjects.h \
     preparedGraphicsObjects.I preparedGraphicsObjects.h \
-    lens.h lens.I \
     queryContext.I queryContext.h \
     queryContext.I queryContext.h \
     savedContext.I savedContext.h \
     savedContext.I savedContext.h \
     shader.I shader.h \
     shader.I shader.h \

+ 0 - 19
panda/src/gobj/config_gobj.cxx

@@ -98,25 +98,6 @@ ConfigVariableBool keep_texture_ram
           "texture image from disk; but it will consume memory somewhat "
           "texture image from disk; but it will consume memory somewhat "
           "wastefully."));
           "wastefully."));
 
 
-ConfigVariableBool preload_textures
-("preload-textures", true,
- PRC_DESC("When this is true, texture images are loaded from disk as soon "
-          "as the Texture is created from the TexturePool.  When this is "
-          "false, the Texture is created immediately, but the image data "
-          "is not loaded from disk until the Texture is actually rendered "
-          "(or otherwise prepared) on the GSG.  This can help reduce "
-          "wasted memory from Textures that are created but never used "
-          "to render."));
-
-ConfigVariableBool preload_simple_textures
-("preload-simple-textures", false,
- PRC_DESC("When this is true, every texture image will have a simple "
-          "image generated for it at load time.  (Normally, textures "
-          "get a simple image at egg2bam time.)  This slows the initial "
-          "loading time of textures, but allows you to take advantage "
-          "of gsg::set_incomplete_render() to load textures on-the-fly "
-          "in a sub-thread."));
-
 ConfigVariableBool compressed_textures
 ConfigVariableBool compressed_textures
 ("compressed-textures", false,
 ("compressed-textures", false,
  PRC_DESC("Set this to true to compress textures as they are loaded into "
  PRC_DESC("Set this to true to compress textures as they are loaded into "

+ 0 - 2
panda/src/gobj/config_gobj.h

@@ -51,8 +51,6 @@ extern EXPCL_PANDA_GOBJ ConfigVariableList exclude_texture_scale;
 
 
 
 
 extern EXPCL_PANDA_GOBJ ConfigVariableBool keep_texture_ram;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool keep_texture_ram;
-extern EXPCL_PANDA_GOBJ ConfigVariableBool preload_textures;
-extern EXPCL_PANDA_GOBJ ConfigVariableBool preload_simple_textures;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool compressed_textures;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool compressed_textures;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_buffers;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_buffers;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_arrays;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_arrays;

+ 89 - 137
panda/src/gobj/texture.I

@@ -122,143 +122,6 @@ setup_cube_map(int size, ComponentType component_type,
   setup_texture(TT_cube_map, size, size, 6, component_type, format);
   setup_texture(TT_cube_map, size, size, 6, component_type, format);
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: Texture::read
-//       Access: Published
-//  Description: Reads the named filename into the texture.
-////////////////////////////////////////////////////////////////////
-INLINE bool Texture::
-read(const Filename &fullpath) {
-  ReMutexHolder holder(_lock);
-  clear();
-  return do_read(fullpath, Filename(), 0, 0, 0, 0, false, false, 
-                 !preload_textures && !preload_simple_textures, NULL);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Texture::read
-//       Access: Published
-//  Description: Combine a 3-component image with a grayscale image
-//               to get a 4-component image.
-//
-//               See the description of the full-parameter read()
-//               method for the meaning of the
-//               primary_file_num_channels and alpha_file_channel
-//               parameters.
-////////////////////////////////////////////////////////////////////
-INLINE bool Texture::
-read(const Filename &fullpath, const Filename &alpha_fullpath,
-     int primary_file_num_channels, int alpha_file_channel) {
-  ReMutexHolder holder(_lock);
-  clear();
-  return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
-		 alpha_file_channel, 0, 0, false, false, 
-                 !preload_textures && !preload_simple_textures, 
-                 NULL);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Texture::read
-//       Access: Published
-//  Description: Reads a single file into a single page or mipmap
-//               level, or automatically reads a series of files into
-//               a series of pages and/or mipmap levels.
-//
-//               See the description of the full-parameter read()
-//               method for the meaning of the various parameters.
-////////////////////////////////////////////////////////////////////
-INLINE bool Texture::
-read(const Filename &fullpath, int z, int n, 
-     bool read_pages, bool read_mipmaps) {
-  ReMutexHolder holder(_lock);
-  ++_properties_modified;
-  ++_image_modified;
-  return do_read(fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps,
-                 !preload_textures && !preload_simple_textures, NULL);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Texture::read
-//       Access: Published
-//  Description: Reads the texture from the indicated filename.  If
-//               primary_file_num_channels is not 0, it specifies the
-//               number of components to downgrade the image to if it
-//               is greater than this number.
-//
-//               If the filename has the extension .txo, this
-//               implicitly reads a texture object instead of a
-//               filename (which replaces all of the texture
-//               properties).  In this case, all the rest of the
-//               parameters are ignored, and the filename should not
-//               contain any hash marks; just the one named file will
-//               be read, since a single .txo file can contain all
-//               pages and mipmaps necessary to define a texture.
-//
-//               If alpha_fullpath is not empty, it specifies the name
-//               of a file from which to retrieve the alpha.  In this
-//               case, alpha_file_channel represents the numeric
-//               channel of this image file to use as the resulting
-//               texture's alpha channel; usually, this is 0 to
-//               indicate the grayscale combination of r, g, b; or it
-//               may be a one-based channel number, e.g. 1 for the red
-//               channel, 2 for the green channel, and so on.
-//
-//               If read pages is false, then z indicates the page
-//               number into which this image will be assigned.
-//               Normally this is 0 for the first (or only) page of
-//               the texture.  3-D textures have one page for each
-//               level of depth, and cube map textures always have six
-//               pages.
-//
-//               If read_pages is true, multiple images will be read
-//               at once, one for each page of a cube map or a 3-D
-//               texture.  In this case, the filename should contain a
-//               sequence of one or more hash marks ("#") which will
-//               be filled in with the z value of each page,
-//               zero-based.  In this case, the z parameter indicates
-//               the maximum z value that will be loaded, or 0 to load
-//               all filenames that exist.
-//
-//               If read_mipmaps is false, then n indicates the mipmap
-//               level to which this image will be assigned.  Normally
-//               this is 0 for the base texture image, but it is
-//               possible to load custom mipmap levels into the later
-//               images.  After the base texture image is loaded (thus
-//               defining the size of the texture), you can call
-//               get_expected_num_mipmap_levels() to determine the
-//               maximum sensible value for n.
-//
-//               If read_mipmaps is true, multiple images will be read
-//               as above, but this time the images represent the
-//               different mipmap levels of the texture image.  In
-//               this case, the n parameter indicates the maximum n
-//               value that will be loaded, or 0 to load all filenames
-//               that exist (up to the expected number of mipmap
-//               levels).
-//
-//               If both read_pages and read_mipmaps is true, then
-//               both sequences will be read; the filename should
-//               contain two sequences of hash marks, separated by
-//               some character such as a hyphen, underscore, or dot.
-//               The first hash mark sequence will be filled in with
-//               the mipmap level, while the second hash mark sequence
-//               will be the page index.
-//
-//               This method implicitly sets keep_ram_image to false.
-////////////////////////////////////////////////////////////////////
-INLINE bool Texture::
-read(const Filename &fullpath, const Filename &alpha_fullpath,
-     int primary_file_num_channels, int alpha_file_channel,
-     int z, int n, bool read_pages, bool read_mipmaps,
-     BamCacheRecord *record) {
-  ReMutexHolder holder(_lock);
-  ++_properties_modified;
-  ++_image_modified;
-  return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
-		 alpha_file_channel, z, n, read_pages, read_mipmaps,
-                 !preload_textures && !preload_simple_textures, record);
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::write
 //     Function: Texture::write
 //       Access: Published
 //       Access: Published
@@ -574,6 +437,45 @@ set_pad_size(int x, int y, int z) {
   _pad_z_size = z;
   _pad_z_size = z;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_orig_file_x_size
+//       Access: Published
+//  Description: Returns the X size of the original disk image that
+//               this Texture was loaded from (if it came from a disk
+//               file), before any automatic rescaling by Panda.
+////////////////////////////////////////////////////////////////////
+INLINE int Texture::
+get_orig_file_x_size() const {
+  return _orig_file_x_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_orig_file_y_size
+//       Access: Published
+//  Description: Returns the Y size of the original disk image that
+//               this Texture was loaded from (if it came from a disk
+//               file), before any automatic rescaling by Panda.
+////////////////////////////////////////////////////////////////////
+INLINE int Texture::
+get_orig_file_y_size() const {
+  return _orig_file_y_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_orig_file_z_size
+//       Access: Published
+//  Description: Returns the Z size of the original disk image that
+//               this Texture was loaded from (if it came from a disk
+//               file), before any automatic rescaling by Panda.
+////////////////////////////////////////////////////////////////////
+INLINE int Texture::
+get_orig_file_z_size() const {
+  // At the moment, we perform no automatic adjustment of Z size.  So
+  // we can just return the current value, since it would be the same
+  // thing.
+  return _z_size;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_num_components
 //     Function: Texture::get_num_components
 //       Access: Published
 //       Access: Published
@@ -737,6 +639,29 @@ get_compression() const {
   return _compression;
   return _compression;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::has_compression
+//       Access: Published
+//  Description: Returns true if the texture indicates it wants to be
+//               compressed, either with CM_on or higher, or
+//               CM_default and compressed-textures is true.
+//
+//               If true returned, this is not a guarantee that the
+//               texture is actually successfully compressed on the
+//               GSG.  It may be that the GSG does not support the
+//               requested compression mode, in which case the texture
+//               may actually be stored uncompressed in texture
+//               memory.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+has_compression() const {
+  if (_compression == CM_default) {
+    return compressed_textures;
+  } else {
+    return (_compression != CM_off);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_render_to_texture
 //     Function: Texture::get_render_to_texture
 //       Access: Published
 //       Access: Published
@@ -1408,7 +1333,34 @@ set_match_framebuffer_format(bool flag) {
   _match_framebuffer_format = flag;
   _match_framebuffer_format = flag;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_post_load_store_cache
+//       Access: Public
+//  Description: Returns the setting of the post_load_store_cache
+//               flag.  See set_post_load_store_cache().
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+get_post_load_store_cache() const {
+  return _post_load_store_cache;
+}
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::set_post_load_store_cache
+//       Access: Public
+//  Description: Sets the post_load_store_cache flag.  When this is
+//               set, the next time the texture is loaded on a GSG, it
+//               will automatically extract its RAM image from the GSG
+//               and save it to the global BamCache.
+//
+//               This is used to store compressed RAM images in the
+//               BamCache.  This flag should not be set explicitly; it
+//               is set automatically by the TexturePool when
+//               model-cache-compressed-textures is set true.
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::
+set_post_load_store_cache(bool flag) {
+  _post_load_store_cache = flag;
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::store_unscaled_byte
 //     Function: Texture::store_unscaled_byte

+ 392 - 88
panda/src/gobj/texture.cxx

@@ -78,6 +78,7 @@ Texture(const string &name) :
   _ram_image_compression = CM_off;
   _ram_image_compression = CM_off;
   _render_to_texture = false;
   _render_to_texture = false;
   _match_framebuffer_format = false;
   _match_framebuffer_format = false;
+  _post_load_store_cache = false;
   _quality_level = QL_default;
   _quality_level = QL_default;
 
 
   _texture_type = TT_2d_texture;
   _texture_type = TT_2d_texture;
@@ -91,6 +92,9 @@ Texture(const string &name) :
   _pad_y_size = 0;
   _pad_y_size = 0;
   _pad_z_size = 0;
   _pad_z_size = 0;
 
 
+  _orig_file_x_size = 0;
+  _orig_file_y_size = 0;
+
   _loaded_from_image = false;
   _loaded_from_image = false;
   _loaded_from_txo = false;
   _loaded_from_txo = false;
   _has_read_pages = false;
   _has_read_pages = false;
@@ -146,6 +150,8 @@ operator = (const Texture &copy) {
   _pad_x_size = copy._pad_x_size;
   _pad_x_size = copy._pad_x_size;
   _pad_y_size = copy._pad_y_size;
   _pad_y_size = copy._pad_y_size;
   _pad_z_size = copy._pad_z_size;
   _pad_z_size = copy._pad_z_size;
+  _orig_file_x_size = copy._orig_file_x_size;
+  _orig_file_y_size = copy._orig_file_y_size;
   _num_components = copy._num_components;
   _num_components = copy._num_components;
   _component_width = copy._component_width;
   _component_width = copy._component_width;
   _texture_type = copy._texture_type;
   _texture_type = copy._texture_type;
@@ -163,6 +169,7 @@ operator = (const Texture &copy) {
   _border_color = copy._border_color;
   _border_color = copy._border_color;
   _compression = copy._compression;
   _compression = copy._compression;
   _match_framebuffer_format = copy._match_framebuffer_format;
   _match_framebuffer_format = copy._match_framebuffer_format;
+  _post_load_store_cache = false;
   _quality_level = copy._quality_level;
   _quality_level = copy._quality_level;
   _ram_image_compression = copy._ram_image_compression;
   _ram_image_compression = copy._ram_image_compression;
   _ram_images = copy._ram_images;
   _ram_images = copy._ram_images;
@@ -251,6 +258,8 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
 
 
   clear_ram_image();
   clear_ram_image();
   set_pad_size();
   set_pad_size();
+  _orig_file_x_size = 0;
+  _orig_file_y_size = 0;
   _loaded_from_image = false;
   _loaded_from_image = false;
   _loaded_from_txo = false;
   _loaded_from_txo = false;
   _has_read_pages = false;
   _has_read_pages = false;
@@ -387,6 +396,150 @@ generate_alpha_scale_map() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Reads the named filename into the texture.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+read(const Filename &fullpath, const LoaderOptions &options) {
+  ReMutexHolder holder(_lock);
+  clear();
+  bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
+  return do_read(fullpath, Filename(), 0, 0, 0, 0, false, false, 
+                 header_only, NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Combine a 3-component image with a grayscale image
+//               to get a 4-component image.
+//
+//               See the description of the full-parameter read()
+//               method for the meaning of the
+//               primary_file_num_channels and alpha_file_channel
+//               parameters.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+read(const Filename &fullpath, const Filename &alpha_fullpath,
+     int primary_file_num_channels, int alpha_file_channel,
+     const LoaderOptions &options) {
+  ReMutexHolder holder(_lock);
+  clear();
+  bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
+  return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
+		 alpha_file_channel, 0, 0, false, false, 
+                 header_only, 
+                 NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Reads a single file into a single page or mipmap
+//               level, or automatically reads a series of files into
+//               a series of pages and/or mipmap levels.
+//
+//               See the description of the full-parameter read()
+//               method for the meaning of the various parameters.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+read(const Filename &fullpath, int z, int n, 
+     bool read_pages, bool read_mipmaps,
+     const LoaderOptions &options) {
+  ReMutexHolder holder(_lock);
+  ++_properties_modified;
+  ++_image_modified;
+  bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
+  return do_read(fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps,
+                 header_only, NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Reads the texture from the indicated filename.  If
+//               primary_file_num_channels is not 0, it specifies the
+//               number of components to downgrade the image to if it
+//               is greater than this number.
+//
+//               If the filename has the extension .txo, this
+//               implicitly reads a texture object instead of a
+//               filename (which replaces all of the texture
+//               properties).  In this case, all the rest of the
+//               parameters are ignored, and the filename should not
+//               contain any hash marks; just the one named file will
+//               be read, since a single .txo file can contain all
+//               pages and mipmaps necessary to define a texture.
+//
+//               If alpha_fullpath is not empty, it specifies the name
+//               of a file from which to retrieve the alpha.  In this
+//               case, alpha_file_channel represents the numeric
+//               channel of this image file to use as the resulting
+//               texture's alpha channel; usually, this is 0 to
+//               indicate the grayscale combination of r, g, b; or it
+//               may be a one-based channel number, e.g. 1 for the red
+//               channel, 2 for the green channel, and so on.
+//
+//               If read pages is false, then z indicates the page
+//               number into which this image will be assigned.
+//               Normally this is 0 for the first (or only) page of
+//               the texture.  3-D textures have one page for each
+//               level of depth, and cube map textures always have six
+//               pages.
+//
+//               If read_pages is true, multiple images will be read
+//               at once, one for each page of a cube map or a 3-D
+//               texture.  In this case, the filename should contain a
+//               sequence of one or more hash marks ("#") which will
+//               be filled in with the z value of each page,
+//               zero-based.  In this case, the z parameter indicates
+//               the maximum z value that will be loaded, or 0 to load
+//               all filenames that exist.
+//
+//               If read_mipmaps is false, then n indicates the mipmap
+//               level to which this image will be assigned.  Normally
+//               this is 0 for the base texture image, but it is
+//               possible to load custom mipmap levels into the later
+//               images.  After the base texture image is loaded (thus
+//               defining the size of the texture), you can call
+//               get_expected_num_mipmap_levels() to determine the
+//               maximum sensible value for n.
+//
+//               If read_mipmaps is true, multiple images will be read
+//               as above, but this time the images represent the
+//               different mipmap levels of the texture image.  In
+//               this case, the n parameter indicates the maximum n
+//               value that will be loaded, or 0 to load all filenames
+//               that exist (up to the expected number of mipmap
+//               levels).
+//
+//               If both read_pages and read_mipmaps is true, then
+//               both sequences will be read; the filename should
+//               contain two sequences of hash marks, separated by
+//               some character such as a hyphen, underscore, or dot.
+//               The first hash mark sequence will be filled in with
+//               the mipmap level, while the second hash mark sequence
+//               will be the page index.
+//
+//               This method implicitly sets keep_ram_image to false.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+read(const Filename &fullpath, const Filename &alpha_fullpath,
+     int primary_file_num_channels, int alpha_file_channel,
+     int z, int n, bool read_pages, bool read_mipmaps,
+     BamCacheRecord *record,
+     const LoaderOptions &options) {
+  ReMutexHolder holder(_lock);
+  ++_properties_modified;
+  ++_image_modified;
+  bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
+  return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
+		 alpha_file_channel, z, n, read_pages, read_mipmaps,
+                 header_only, record);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::estimate_texture_memory
 //     Function: Texture::estimate_texture_memory
 //       Access: Published
 //       Access: Published
@@ -688,7 +841,7 @@ load_related(const InternalName *suffix) const {
       // Use it to load the texture.
       // Use it to load the texture.
       res = TexturePool::load_texture(main, alph,
       res = TexturePool::load_texture(main, alph,
                                       _primary_file_num_channels,
                                       _primary_file_num_channels,
-                                      _alpha_file_channel);
+                                      _alpha_file_channel, false);
     } else {
     } else {
       // If the alpha variant of the filename doesn't exist, just go
       // If the alpha variant of the filename doesn't exist, just go
       // ahead and load the related texture without alpha.
       // ahead and load the related texture without alpha.
@@ -1309,7 +1462,9 @@ generate_ram_mipmap_images() {
 //               texture.  The simple image is only supported for
 //               texture.  The simple image is only supported for
 //               ordinary 2-d textures.
 //               ordinary 2-d textures.
 //
 //
-//               Also see generate_simple_ram_image().
+//               Also see generate_simple_ram_image(),
+//               modify_simple_ram_image(), and
+//               new_simple_ram_image().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Texture::
 void Texture::
 set_simple_ram_image(PTA_uchar image, int x_size, int y_size) {
 set_simple_ram_image(PTA_uchar image, int x_size, int y_size) {
@@ -1322,10 +1477,46 @@ set_simple_ram_image(PTA_uchar image, int x_size, int y_size) {
   _simple_y_size = y_size;
   _simple_y_size = y_size;
   _simple_ram_image._image = image;
   _simple_ram_image._image = image;
   _simple_ram_image._page_size = image.size();
   _simple_ram_image._page_size = image.size();
-  _simple_image_date_generated = 0;
+  _simple_image_date_generated = (PN_int32)time(NULL);
   ++_simple_image_modified;
   ++_simple_image_modified;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::modify_simple_ram_image
+//       Access: Published
+//  Description: Returns a modifiable pointer to the internal "simple"
+//               texture image.  See set_simple_ram_image().
+////////////////////////////////////////////////////////////////////
+PTA_uchar Texture::
+modify_simple_ram_image() {
+  ReMutexHolder holder(_lock);
+  _simple_image_date_generated = (PN_int32)time(NULL);
+  return _simple_ram_image._image;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::new_simple_ram_image
+//       Access: Published
+//  Description: Creates an empty array for the simple ram image of
+//               the indicated size, and returns a modifiable pointer
+//               to the new array.  See set_simple_ram_image().
+////////////////////////////////////////////////////////////////////
+PTA_uchar Texture::
+new_simple_ram_image(int x_size, int y_size) {
+  ReMutexHolder holder(_lock);
+  nassertr(get_texture_type() == TT_2d_texture, PTA_uchar());
+  size_t expected_page_size = (size_t)(x_size * y_size * 4);
+
+  _simple_x_size = x_size;
+  _simple_y_size = y_size;
+  _simple_ram_image._image = PTA_uchar::empty_array(expected_page_size);
+  _simple_ram_image._page_size = expected_page_size;
+  _simple_image_date_generated = (PN_int32)time(NULL);
+  ++_simple_image_modified;
+
+  return _simple_ram_image._image;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::generate_simple_ram_image
 //     Function: Texture::generate_simple_ram_image
 //       Access: Published
 //       Access: Published
@@ -1338,14 +1529,13 @@ void Texture::
 generate_simple_ram_image() {
 generate_simple_ram_image() {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
 
 
-  if (get_texture_type() != TT_2d_texture) {
-    clear_simple_ram_image();
+  if (get_texture_type() != TT_2d_texture ||
+      get_ram_image_compression() != CM_off) {
     return;
     return;
   }
   }
 
 
   PNMImage pnmimage;
   PNMImage pnmimage;
   if (!store(pnmimage)) {
   if (!store(pnmimage)) {
-    clear_simple_ram_image();
     return;
     return;
   }
   }
 
 
@@ -1854,11 +2044,13 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
 //               is false.
 //               is false.
 //
 //
 //               Normally, this is not called directly except by the
 //               Normally, this is not called directly except by the
-//               GraphicsStateGuardian.
+//               GraphicsStateGuardian.  It will be called in the draw
+//               thread.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Texture::
 void Texture::
-texture_uploaded() {
+texture_uploaded(GraphicsStateGuardianBase *gsg) {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
+
   if (!keep_texture_ram && !_keep_ram_image) {
   if (!keep_texture_ram && !_keep_ram_image) {
     // Once we have prepared the texture, we can generally safely
     // Once we have prepared the texture, we can generally safely
     // remove the pixels from main RAM.  The GSG is now responsible
     // remove the pixels from main RAM.  The GSG is now responsible
@@ -2197,6 +2389,11 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
     }
     }
     int x_size = image.get_x_size();
     int x_size = image.get_x_size();
     int y_size = image.get_y_size();
     int y_size = image.get_y_size();
+    if (z == 0 && n == 0) {
+      _orig_file_x_size = x_size;
+      _orig_file_y_size = y_size;
+    }
+
     if (textures_header_only) {
     if (textures_header_only) {
       // In this mode, we never intend to load the actual texture
       // In this mode, we never intend to load the actual texture
       // image anyway, so we don't even need to make the size right.
       // image anyway, so we don't even need to make the size right.
@@ -2224,6 +2421,8 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
     }
     }
 
 
     if (z == 0 && n == 0) {
     if (z == 0 && n == 0) {
+      _orig_file_x_size = image.get_x_size();
+      _orig_file_y_size = image.get_y_size();
       consider_rescale(image, fullpath.get_basename());
       consider_rescale(image, fullpath.get_basename());
     } else {
     } else {
       image.set_read_size(get_expected_mipmap_x_size(n),
       image.set_read_size(get_expected_mipmap_x_size(n),
@@ -2526,7 +2725,7 @@ do_load_one(const PNMImage &pnmimage, const string &name, int z, int n) {
     do_modify_ram_image();
     do_modify_ram_image();
     _loaded_from_image = true;
     _loaded_from_image = true;
   }
   }
-
+      
   do_modify_ram_mipmap_image(n);
   do_modify_ram_mipmap_image(n);
 
 
   // Ensure the PNMImage is an appropriate size.
   // Ensure the PNMImage is an appropriate size.
@@ -2609,25 +2808,45 @@ reconsider_dirty() {
 void Texture::
 void Texture::
 reload_ram_image() {
 reload_ram_image() {
   BamCache *cache = BamCache::get_global_ptr();
   BamCache *cache = BamCache::get_global_ptr();
+  PT(BamCacheRecord) record;
+
   if (cache->get_active() && !textures_header_only) {
   if (cache->get_active() && !textures_header_only) {
     // See if the texture can be found in the on-disk cache, if it is
     // See if the texture can be found in the on-disk cache, if it is
     // active.
     // active.
-    PT(BamCacheRecord) record = cache->lookup(get_fullpath(), "txo");
+
+    record = cache->lookup(get_fullpath(), "txo");
     if (record != (BamCacheRecord *)NULL && 
     if (record != (BamCacheRecord *)NULL && 
         record->has_data()) {
         record->has_data()) {
-      gobj_cat.info()
-        << "Texture " << get_name() << " reloaded from disk cache.\n";
-      PT(Texture) tex = DCAST(Texture, record->extract_data());
-      // We don't want to replace all the texture parameters--for
-      // instance, we don't want to change the filter type or the
-      // border color or anything--we just want to get the image and
-      // necessary associated parameters.
-      reconsider_image_properties(tex->get_x_size(), tex->get_y_size(),
-                                  tex->get_num_components(), 
-                                  tex->get_component_type(), 0);
-      set_compression(tex->get_compression());
-      _ram_images = tex->_ram_images;
-      return;
+      
+      // But don't use the cache record if the config parameters have
+      // changed, and we want a different-sized texture now.
+      int x_size = _orig_file_x_size;
+      int y_size = _orig_file_y_size;
+      Texture::adjust_size(x_size, y_size, _filename.get_basename());
+      if (get_x_size() == x_size && get_y_size() == y_size) {
+        PT(Texture) tex = DCAST(Texture, record->extract_data());
+       
+        // Also don't keep the cached version if it's compressed but
+        // we want uncompressed.
+        if (tex->get_ram_image_compression() == CM_off || !has_compression()) {
+          gobj_cat.info()
+            << "Texture " << get_name() << " reloaded from disk cache\n";
+          // We don't want to replace all the texture parameters--for
+          // instance, we don't want to change the filter type or the
+          // border color or anything--we just want to get the image and
+          // necessary associated parameters.
+          _loaded_from_image = false;
+          reconsider_image_properties(tex->get_x_size(), tex->get_y_size(),
+                                      tex->get_num_components(), 
+                                      tex->get_component_type(), 0);
+          set_compression(tex->get_compression());
+          _ram_image_compression = tex->_ram_image_compression;
+          _ram_images = tex->_ram_images;
+          _loaded_from_image = true;
+          
+          return;
+        }
+      }
     }
     }
   }
   }
 
 
@@ -2644,10 +2863,17 @@ reload_ram_image() {
   if (_has_read_mipmaps) {
   if (_has_read_mipmaps) {
     n = _num_mipmap_levels_read;
     n = _num_mipmap_levels_read;
   }
   }
+  _loaded_from_image = false;
 
 
   do_read(get_fullpath(), get_alpha_fullpath(),
   do_read(get_fullpath(), get_alpha_fullpath(),
           _primary_file_num_channels, _alpha_file_channel,
           _primary_file_num_channels, _alpha_file_channel,
           z, n, _has_read_pages, _has_read_mipmaps, false, NULL);
           z, n, _has_read_pages, _has_read_mipmaps, false, NULL);
+
+  if (has_ram_image() && record != (BamCacheRecord *)NULL) {
+    // Update the cache.
+    record->set_data(this, false);
+    cache->store(record);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -2791,6 +3017,91 @@ has_binary_alpha(Format format) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::adjust_size
+//       Access: Public, Static
+//  Description: Computes the proper size of the texture, based on the
+//               original size, the filename, and the resizing whims
+//               of the config file.
+//
+//               x_size and y_size should be loaded with the texture
+//               image's original size on disk.  On return, they will
+//               be loaded with the texture's in-memory target size.
+//               The return value is true if the size has been
+//               adjusted, or false if it is the same.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+adjust_size(int &x_size, int &y_size, const string &name) {
+  bool exclude = false;
+  int num_excludes = exclude_texture_scale.get_num_unique_values();
+  for (int i = 0; i < num_excludes && !exclude; ++i) {
+    GlobPattern pat(exclude_texture_scale.get_unique_value(i));
+    if (pat.matches(name)) {
+      exclude = true;
+    }
+  }
+
+  int new_x_size = x_size;
+  int new_y_size = y_size;
+
+  if (!exclude) {
+    new_x_size = (int)cfloor(new_x_size * texture_scale + 0.5);
+    new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5);
+  }
+
+  switch (get_textures_power_2()) {
+  case ATS_down:
+    new_x_size = down_to_power_2(new_x_size);
+    new_y_size = down_to_power_2(new_y_size);
+    break;
+
+  case ATS_up:
+    new_x_size = up_to_power_2(new_x_size);
+    new_y_size = up_to_power_2(new_y_size);
+    break;
+
+  case ATS_none:
+    break;
+  }
+
+  switch (textures_square.get_value()) {
+  case ATS_down:
+    new_x_size = new_y_size = min(new_x_size, new_y_size);
+    break;
+
+  case ATS_up:
+    new_x_size = new_y_size = max(new_x_size, new_y_size);
+    break;
+
+  case ATS_none:
+    break;
+  }
+
+  if (!exclude) {
+    int max_dimension = max_texture_dimension;
+    
+    if (max_dimension < 0) {
+      GraphicsStateGuardianBase *gsg = GraphicsStateGuardianBase::get_default_gsg();
+      if (gsg != (GraphicsStateGuardianBase *)NULL) {
+        max_dimension = gsg->get_max_texture_dimension();
+      }
+    }
+
+    if (max_dimension > 0) {
+      new_x_size = min(new_x_size, (int)max_dimension);
+      new_y_size = min(new_y_size, (int)max_dimension);
+    }
+  }
+
+  if (x_size != new_x_size || y_size != new_y_size) {
+    x_size = new_x_size;
+    y_size = new_y_size;
+    return true;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::reconsider_z_size
 //     Function: Texture::reconsider_z_size
 //       Access: Protected
 //       Access: Protected
@@ -3128,69 +3439,9 @@ set_size_padded(int x, int y, int z) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Texture::
 void Texture::
 consider_rescale(PNMImage &pnmimage, const string &name) {
 consider_rescale(PNMImage &pnmimage, const string &name) {
-  bool exclude = false;
-  int num_excludes = exclude_texture_scale.get_num_unique_values();
-  for (int i = 0; i < num_excludes && !exclude; ++i) {
-    GlobPattern pat(exclude_texture_scale.get_unique_value(i));
-    if (pat.matches(name)) {
-      exclude = true;
-    }
-  }
-
   int new_x_size = pnmimage.get_x_size();
   int new_x_size = pnmimage.get_x_size();
   int new_y_size = pnmimage.get_y_size();
   int new_y_size = pnmimage.get_y_size();
-
-  if (!exclude) {
-    new_x_size = (int)cfloor(new_x_size * texture_scale + 0.5);
-    new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5);
-  }
-
-  switch (get_textures_power_2()) {
-  case ATS_down:
-    new_x_size = down_to_power_2(new_x_size);
-    new_y_size = down_to_power_2(new_y_size);
-    break;
-
-  case ATS_up:
-    new_x_size = up_to_power_2(new_x_size);
-    new_y_size = up_to_power_2(new_y_size);
-    break;
-
-  case ATS_none:
-    break;
-  }
-
-  switch (textures_square.get_value()) {
-  case ATS_down:
-    new_x_size = new_y_size = min(new_x_size, new_y_size);
-    break;
-
-  case ATS_up:
-    new_x_size = new_y_size = max(new_x_size, new_y_size);
-    break;
-
-  case ATS_none:
-    break;
-  }
-
-  if (!exclude) {
-    int max_dimension = max_texture_dimension;
-    
-    if (max_dimension < 0) {
-      GraphicsStateGuardianBase *gsg = GraphicsStateGuardianBase::get_default_gsg();
-      if (gsg != (GraphicsStateGuardianBase *)NULL) {
-        max_dimension = gsg->get_max_texture_dimension();
-      }
-    }
-
-    if (max_dimension > 0) {
-      new_x_size = min(new_x_size, (int)max_dimension);
-      new_y_size = min(new_y_size, (int)max_dimension);
-    }
-  }
-
-  if (pnmimage.get_x_size() != new_x_size ||
-      pnmimage.get_y_size() != new_y_size) {
+  if (adjust_size(new_x_size, new_y_size, name)) {
     pnmimage.set_read_size(new_x_size, new_y_size);
     pnmimage.set_read_size(new_x_size, new_y_size);
   }
   }
 }
 }
@@ -3719,19 +3970,24 @@ make_from_bam(const FactoryParams &params) {
       case TT_1d_texture:
       case TT_1d_texture:
       case TT_2d_texture:
       case TT_2d_texture:
         if (alpha_filename.empty()) {
         if (alpha_filename.empty()) {
-          me = TexturePool::load_texture(filename, primary_file_num_channels);
+          me = TexturePool::load_texture(filename, primary_file_num_channels,
+                                         false, manager->get_loader_options());
         } else {
         } else {
           me = TexturePool::load_texture(filename, alpha_filename,
           me = TexturePool::load_texture(filename, alpha_filename,
-                                         primary_file_num_channels, alpha_file_channel);
+                                         primary_file_num_channels, 
+                                         alpha_file_channel,
+                                         false, manager->get_loader_options());
         }
         }
         break;
         break;
 
 
       case TT_3d_texture:
       case TT_3d_texture:
-        me = TexturePool::load_3d_texture(filename);
+        me = TexturePool::load_3d_texture(filename, false, 
+                                          manager->get_loader_options());
         break;
         break;
 
 
       case TT_cube_map:
       case TT_cube_map:
-        me = TexturePool::load_cube_map(filename);
+        me = TexturePool::load_cube_map(filename, false, 
+                                        manager->get_loader_options());
         break;
         break;
       }
       }
     }
     }
@@ -3795,6 +4051,39 @@ fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) {
     set_format(format);
     set_format(format);
   }
   }
 
 
+  _orig_file_x_size = 0;
+  _orig_file_y_size = 0;
+  bool has_simple_ram_image = false;
+  if (manager->get_file_minor_ver() >= 18) {
+    _orig_file_x_size = scan.get_uint32();
+    _orig_file_y_size = scan.get_uint32();
+    has_simple_ram_image = scan.get_bool();
+  }
+
+  if (has_simple_ram_image) {
+    int x_size = scan.get_uint32();
+    int y_size = scan.get_uint32();
+    PN_int32 date_generated = scan.get_int32();
+
+    size_t u_size = scan.get_uint32();
+    PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
+    for (size_t u_idx = 0; u_idx < u_size; ++u_idx) {
+      image[(int)u_idx] = scan.get_uint8();
+    }
+
+    // Only replace the simple ram image if it was generated more
+    // recently than the one we already have.
+    if (_simple_ram_image._image.empty() ||
+        date_generated > _simple_image_date_generated) {
+      _simple_x_size = x_size;
+      _simple_y_size = y_size;
+      _simple_image_date_generated = date_generated;
+      _simple_ram_image._image = image;
+      _simple_ram_image._page_size = u_size;
+      ++_simple_image_modified;
+    }
+  }  
+
   if (has_rawdata) {
   if (has_rawdata) {
     // In the rawdata case, we must always set the format.
     // In the rawdata case, we must always set the format.
     _format = format;
     _format = format;
@@ -3945,6 +4234,21 @@ write_datagram(BamWriter *manager, Datagram &me) {
   me.add_uint8(_format);
   me.add_uint8(_format);
   me.add_uint8(_num_components);
   me.add_uint8(_num_components);
 
 
+  me.add_uint32(_orig_file_x_size);
+  me.add_uint32(_orig_file_y_size);
+
+  bool has_simple_ram_image = !_simple_ram_image._image.empty();
+  me.add_bool(has_simple_ram_image);
+
+  // Write out the simple image too, so it will be available later.
+  if (has_simple_ram_image) {
+    me.add_uint32(_simple_x_size);
+    me.add_uint32(_simple_y_size);
+    me.add_int32(_simple_image_date_generated);
+    me.add_uint32(_simple_ram_image._image.size());
+    me.append_data(_simple_ram_image._image, _simple_ram_image._image.size());
+  }
+
   // If we are also including the texture's image data, then stuff it
   // If we are also including the texture's image data, then stuff it
   // in here.
   // in here.
   if (has_rawdata) {
   if (has_rawdata) {

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

@@ -28,6 +28,7 @@
 #include "pStatCollector.h"
 #include "pStatCollector.h"
 #include "reMutex.h"
 #include "reMutex.h"
 #include "reMutexHolder.h"
 #include "reMutexHolder.h"
+#include "loaderOptions.h"
 
 
 class PNMImage;
 class PNMImage;
 class TextureContext;
 class TextureContext;
@@ -211,15 +212,18 @@ PUBLISHED:
   void generate_normalization_cube_map(int size);
   void generate_normalization_cube_map(int size);
   void generate_alpha_scale_map();
   void generate_alpha_scale_map();
 
 
-  INLINE bool read(const Filename &fullpath);
-  INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath,
-                   int primary_file_num_channels, int alpha_file_channel);
-  INLINE bool read(const Filename &fullpath, int z, int n, 
-                   bool read_pages, bool read_mipmaps);
-  INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath,
-                   int primary_file_num_channels, int alpha_file_channel,
-                   int z, int n, bool read_pages, bool read_mipmaps,
-                   BamCacheRecord *record = NULL);
+  bool read(const Filename &fullpath, const LoaderOptions &options = LoaderOptions());
+  bool read(const Filename &fullpath, const Filename &alpha_fullpath,
+            int primary_file_num_channels, int alpha_file_channel,
+            const LoaderOptions &options = LoaderOptions());
+  bool read(const Filename &fullpath, int z, int n, 
+            bool read_pages, bool read_mipmaps,
+            const LoaderOptions &options = LoaderOptions());
+  bool read(const Filename &fullpath, const Filename &alpha_fullpath,
+            int primary_file_num_channels, int alpha_file_channel,
+            int z, int n, bool read_pages, bool read_mipmaps,
+            BamCacheRecord *record = NULL,
+            const LoaderOptions &options = LoaderOptions());
 
 
   INLINE bool write(const Filename &fullpath);
   INLINE bool write(const Filename &fullpath);
   INLINE bool write(const Filename &fullpath, int z, int n, 
   INLINE bool write(const Filename &fullpath, int z, int n, 
@@ -273,6 +277,7 @@ PUBLISHED:
   INLINE int get_anisotropic_degree() const;
   INLINE int get_anisotropic_degree() const;
   INLINE Colorf get_border_color() const;
   INLINE Colorf get_border_color() const;
   INLINE CompressionMode get_compression() const;
   INLINE CompressionMode get_compression() const;
+  INLINE bool has_compression() const;
   INLINE bool get_render_to_texture() const;
   INLINE bool get_render_to_texture() const;
   INLINE bool uses_mipmaps() const;
   INLINE bool uses_mipmaps() const;
 
 
@@ -321,6 +326,8 @@ PUBLISHED:
   INLINE size_t get_simple_ram_image_size() const;
   INLINE size_t get_simple_ram_image_size() const;
   INLINE CPTA_uchar get_simple_ram_image() const;
   INLINE CPTA_uchar get_simple_ram_image() const;
   void set_simple_ram_image(PTA_uchar image, int x_size, int y_size);
   void set_simple_ram_image(PTA_uchar image, int x_size, int y_size);
+  PTA_uchar modify_simple_ram_image();
+  PTA_uchar new_simple_ram_image(int x_size, int y_size);
   void generate_simple_ram_image();
   void generate_simple_ram_image();
   void clear_simple_ram_image();
   void clear_simple_ram_image();
 
 
@@ -369,6 +376,10 @@ PUBLISHED:
   
   
   INLINE void set_pad_size(int x=0, int y=0, int z=0);
   INLINE void set_pad_size(int x=0, int y=0, int z=0);
   void set_size_padded(int x=1, int y=1, int z=1);
   void set_size_padded(int x=1, int y=1, int z=1);
+
+  INLINE int get_orig_file_x_size() const;
+  INLINE int get_orig_file_y_size() const;
+  INLINE int get_orig_file_z_size() const;
   
   
   void set_format(Format format);
   void set_format(Format format);
   void set_component_type(ComponentType component_type);
   void set_component_type(ComponentType component_type);
@@ -383,11 +394,14 @@ PUBLISHED:
   INLINE bool get_match_framebuffer_format() const;
   INLINE bool get_match_framebuffer_format() const;
   INLINE void set_match_framebuffer_format(bool flag);
   INLINE void set_match_framebuffer_format(bool flag);
 
 
+  INLINE bool get_post_load_store_cache() const;
+  INLINE void set_post_load_store_cache(bool flag);
+
   TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
   TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                               GraphicsStateGuardianBase *gsg);
                               GraphicsStateGuardianBase *gsg);
 
 
 public:
 public:
-  void texture_uploaded();
+  void texture_uploaded(GraphicsStateGuardianBase *gsg);
   
   
   virtual bool has_cull_callback() const;
   virtual bool has_cull_callback() const;
   virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
   virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
@@ -405,6 +419,8 @@ public:
   static bool has_alpha(Format format);
   static bool has_alpha(Format format);
   static bool has_binary_alpha(Format format);
   static bool has_binary_alpha(Format format);
 
 
+  static bool adjust_size(int &x_size, int &y_size, const string &name);
+
 protected:
 protected:
   virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath,
   virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath,
                        int primary_file_num_channels, int alpha_file_channel,
                        int primary_file_num_channels, int alpha_file_channel,
@@ -541,11 +557,15 @@ protected:
   CompressionMode _compression;
   CompressionMode _compression;
   bool _render_to_texture;
   bool _render_to_texture;
   bool _match_framebuffer_format;
   bool _match_framebuffer_format;
+  bool _post_load_store_cache;
   QualityLevel _quality_level;
   QualityLevel _quality_level;
 
 
   int _pad_x_size;
   int _pad_x_size;
   int _pad_y_size;
   int _pad_y_size;
   int _pad_z_size;
   int _pad_z_size;
+
+  int _orig_file_x_size;
+  int _orig_file_y_size;
   
   
   // A Texture keeps a list (actually, a map) of all the
   // A Texture keeps a list (actually, a map) of all the
   // PreparedGraphicsObjects tables that it has been prepared into.
   // PreparedGraphicsObjects tables that it has been prepared into.

+ 14 - 10
panda/src/gobj/texturePool.I

@@ -55,9 +55,9 @@ verify_texture(const string &filename) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
 load_texture(const string &filename, int primary_file_num_channels,
 load_texture(const string &filename, int primary_file_num_channels,
-       bool read_mipmaps) {
+             bool read_mipmaps, const LoaderOptions &options) {
   return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels,
   return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels,
-             read_mipmaps);
+                                           read_mipmaps, options);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -78,11 +78,11 @@ load_texture(const string &filename, int primary_file_num_channels,
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
 load_texture(const string &filename, const string &alpha_filename,
 load_texture(const string &filename, const string &alpha_filename,
              int primary_file_num_channels, int alpha_file_channel,
              int primary_file_num_channels, int alpha_file_channel,
-       bool read_mipmaps) {
+             bool read_mipmaps, const LoaderOptions &options) {
   return get_global_ptr()->ns_load_texture(filename, alpha_filename, 
   return get_global_ptr()->ns_load_texture(filename, alpha_filename, 
-             primary_file_num_channels,
-             alpha_file_channel,
-             read_mipmaps);
+                                           primary_file_num_channels,
+                                           alpha_file_channel,
+                                           read_mipmaps, options);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -100,8 +100,10 @@ load_texture(const string &filename, const string &alpha_filename,
 //               second with the index number of each 3-d level.
 //               second with the index number of each 3-d level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
-load_3d_texture(const string &filename_pattern, bool read_mipmaps) {
-  return get_global_ptr()->ns_load_3d_texture(filename_pattern, read_mipmaps);
+load_3d_texture(const string &filename_pattern, bool read_mipmaps, 
+                const LoaderOptions &options) {
+  return get_global_ptr()->ns_load_3d_texture(filename_pattern, read_mipmaps, 
+                                              options);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -119,8 +121,10 @@ load_3d_texture(const string &filename_pattern, bool read_mipmaps) {
 //               second with the face number, 0 through 5.
 //               second with the face number, 0 through 5.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
-load_cube_map(const string &filename_pattern, bool read_mipmaps) {
-  return get_global_ptr()->ns_load_cube_map(filename_pattern, read_mipmaps);
+load_cube_map(const string &filename_pattern, bool read_mipmaps, 
+              const LoaderOptions &options) {
+  return get_global_ptr()->ns_load_cube_map(filename_pattern, read_mipmaps, 
+                                            options);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 158 - 79
panda/src/gobj/texturePool.cxx

@@ -235,7 +235,7 @@ ns_has_texture(const Filename &orig_filename) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Texture *TexturePool::
 Texture *TexturePool::
 ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
 ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
-                bool read_mipmaps) {
+                bool read_mipmaps, const LoaderOptions &options) {
   Filename filename(orig_filename);
   Filename filename(orig_filename);
 
 
   if (!_fake_texture_image.empty()) {
   if (!_fake_texture_image.empty()) {
@@ -265,31 +265,12 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
 
 
   // Can one of our texture filters supply the texture?
   // Can one of our texture filters supply the texture?
   tex = pre_load(orig_filename, Filename(), primary_file_num_channels, 0,
   tex = pre_load(orig_filename, Filename(), primary_file_num_channels, 0,
-                 read_mipmaps);
+                 read_mipmaps, options);
 
 
   BamCache *cache = BamCache::get_global_ptr();
   BamCache *cache = BamCache::get_global_ptr();
-  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());
-          if (preload_simple_textures && !tex->has_simple_ram_image()) {
-            tex->generate_simple_ram_image();
-          }
-          if (!preload_textures) {
-            // But drop the RAM until we need it.
-            tex->clear_ram_image();
-          }
-          tex->set_keep_ram_image(false);
-        }
-      }
-    }
-  }
+  bool compressed_cache_record = false;
+  try_load_cache(tex, cache, filename, record, compressed_cache_record,
+                 options);
 
 
   if (tex == (Texture *)NULL) {
   if (tex == (Texture *)NULL) {
     // The texture was neither in the pool, nor found in the on-disk
     // The texture was neither in the pool, nor found in the on-disk
@@ -298,19 +279,32 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
       << "Loading texture " << filename << "\n";
       << "Loading texture " << filename << "\n";
     tex = make_texture(filename.get_extension());
     tex = make_texture(filename.get_extension());
     if (!tex->read(filename, Filename(), primary_file_num_channels, 0,
     if (!tex->read(filename, Filename(), primary_file_num_channels, 0,
-                   0, 0, false, read_mipmaps, record)) {
+                   0, 0, false, read_mipmaps, record, options)) {
       // This texture was not found or could not be read.
       // This texture was not found or could not be read.
       report_texture_unreadable(filename);
       report_texture_unreadable(filename);
       return NULL;
       return NULL;
     }
     }
 
 
-    if (preload_simple_textures) {
+    if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
       tex->generate_simple_ram_image();
       tex->generate_simple_ram_image();
     }
     }
 
 
     store_record = (record != (BamCacheRecord *)NULL);
     store_record = (record != (BamCacheRecord *)NULL);
   }
   }
 
 
+  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
+    // We don't want to save the uncompressed version; we'll save the
+    // compressed version when it becomes available.
+    store_record = false;
+    if (!compressed_cache_record) {
+      tex->set_post_load_store_cache(true);
+    }
+
+  } else if (!cache->get_cache_textures()) {
+    // We don't want to save this texture.
+    store_record = false;
+  }
+
   // Set the original filename, before we searched along the path.
   // Set the original filename, before we searched along the path.
   nassertr(tex != (Texture *)NULL, NULL);
   nassertr(tex != (Texture *)NULL, NULL);
   tex->set_filename(orig_filename);
   tex->set_filename(orig_filename);
@@ -341,7 +335,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
     cache->store(record);
     cache->store(record);
   }
   }
 
 
-  if (!preload_textures) {
+  if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
     // And now drop the RAM until we need it.
     // And now drop the RAM until we need it.
     tex->clear_ram_image();
     tex->clear_ram_image();
   }
   }
@@ -364,13 +358,13 @@ ns_load_texture(const Filename &orig_filename,
                 const Filename &orig_alpha_filename,
                 const Filename &orig_alpha_filename,
                 int primary_file_num_channels,
                 int primary_file_num_channels,
                 int alpha_file_channel,
                 int alpha_file_channel,
-    bool read_mipmaps) {
+                bool read_mipmaps, const LoaderOptions &options) {
   Filename filename(orig_filename);
   Filename filename(orig_filename);
   Filename alpha_filename(orig_alpha_filename);
   Filename alpha_filename(orig_alpha_filename);
 
 
   if (!_fake_texture_image.empty()) {
   if (!_fake_texture_image.empty()) {
     return ns_load_texture(_fake_texture_image, primary_file_num_channels,
     return ns_load_texture(_fake_texture_image, primary_file_num_channels,
-         read_mipmaps);
+                           read_mipmaps, options);
   }
   }
 
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
@@ -399,25 +393,12 @@ ns_load_texture(const Filename &orig_filename,
 
 
   // Can one of our texture filters supply the texture?
   // Can one of our texture filters supply the texture?
   tex = pre_load(orig_filename, alpha_filename, primary_file_num_channels, 
   tex = pre_load(orig_filename, alpha_filename, primary_file_num_channels, 
-                 alpha_file_channel, read_mipmaps);
+                 alpha_file_channel, read_mipmaps, options);
 
 
   BamCache *cache = BamCache::get_global_ptr();
   BamCache *cache = BamCache::get_global_ptr();
-  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());
-        }
-      }
-    }
-  }
+  bool compressed_cache_record = false;
+  try_load_cache(tex, cache, filename, record, compressed_cache_record,
+                 options);
 
 
   if (tex == (Texture *)NULL) {
   if (tex == (Texture *)NULL) {
     // The texture was neither in the pool, nor found in the on-disk
     // The texture was neither in the pool, nor found in the on-disk
@@ -427,19 +408,33 @@ ns_load_texture(const Filename &orig_filename,
       << alpha_filename << endl;
       << alpha_filename << endl;
     tex = make_texture(filename.get_extension());
     tex = make_texture(filename.get_extension());
     if (!tex->read(filename, alpha_filename, primary_file_num_channels,
     if (!tex->read(filename, alpha_filename, primary_file_num_channels,
-                   alpha_file_channel, 0, 0, false, read_mipmaps)) {
+                   alpha_file_channel, 0, 0, false, read_mipmaps, NULL,
+                   options)) {
       // This texture was not found or could not be read.
       // This texture was not found or could not be read.
       report_texture_unreadable(filename);
       report_texture_unreadable(filename);
       return NULL;
       return NULL;
     }
     }
 
 
-    if (preload_simple_textures) {
+    if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
       tex->generate_simple_ram_image();
       tex->generate_simple_ram_image();
     }
     }
 
 
     store_record = (record != (BamCacheRecord *)NULL);
     store_record = (record != (BamCacheRecord *)NULL);
   }
   }
 
 
+  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
+    // We don't want to save the uncompressed version; we'll save the
+    // compressed version when it becomes available.
+    store_record = false;
+    if (!compressed_cache_record) {
+      tex->set_post_load_store_cache(true);
+    }
+
+  } else if (!cache->get_cache_textures()) {
+    // We don't want to save this texture.
+    store_record = false;
+  }
+
   // Set the original filenames, before we searched along the path.
   // Set the original filenames, before we searched along the path.
   nassertr(tex != (Texture *)NULL, NULL);
   nassertr(tex != (Texture *)NULL, NULL);
   tex->set_filename(orig_filename);
   tex->set_filename(orig_filename);
@@ -470,7 +465,7 @@ ns_load_texture(const Filename &orig_filename,
     cache->store(record);
     cache->store(record);
   }
   }
 
 
-  if (!preload_textures) {
+  if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
     // And now drop the RAM until we need it.
     // And now drop the RAM until we need it.
     tex->clear_ram_image();
     tex->clear_ram_image();
   }
   }
@@ -490,7 +485,7 @@ ns_load_texture(const Filename &orig_filename,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Texture *TexturePool::
 Texture *TexturePool::
 ns_load_3d_texture(const Filename &filename_pattern,
 ns_load_3d_texture(const Filename &filename_pattern,
-       bool read_mipmaps) {
+                   bool read_mipmaps, const LoaderOptions &options) {
   Filename filename(filename_pattern);
   Filename filename(filename_pattern);
   filename.set_pattern(true);
   filename.set_pattern(true);
 
 
@@ -514,18 +509,9 @@ ns_load_3d_texture(const Filename &filename_pattern,
   bool store_record = false;
   bool store_record = false;
 
 
   BamCache *cache = BamCache::get_global_ptr();
   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());
-      }
-    }
-  }
+  bool compressed_cache_record = false;
+  try_load_cache(tex, cache, filename, record, compressed_cache_record,
+                 options);
 
 
   if (tex == (Texture *)NULL || 
   if (tex == (Texture *)NULL || 
       tex->get_texture_type() != Texture::TT_3d_texture) {
       tex->get_texture_type() != Texture::TT_3d_texture) {
@@ -535,7 +521,7 @@ ns_load_3d_texture(const Filename &filename_pattern,
       << "Loading 3-d texture " << filename << "\n";
       << "Loading 3-d texture " << filename << "\n";
     tex = make_texture(filename.get_extension());
     tex = make_texture(filename.get_extension());
     tex->setup_3d_texture();
     tex->setup_3d_texture();
-    if (!tex->read(filename, 0, 0, true, read_mipmaps)) {
+    if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) {
       // This texture was not found or could not be read.
       // This texture was not found or could not be read.
       report_texture_unreadable(filename);
       report_texture_unreadable(filename);
       return NULL;
       return NULL;
@@ -543,6 +529,19 @@ ns_load_3d_texture(const Filename &filename_pattern,
     store_record = (record != (BamCacheRecord *)NULL);
     store_record = (record != (BamCacheRecord *)NULL);
   }
   }
 
 
+  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
+    // We don't want to save the uncompressed version; we'll save the
+    // compressed version when it becomes available.
+    store_record = false;
+    if (!compressed_cache_record) {
+      tex->set_post_load_store_cache(true);
+    }
+
+  } else if (!cache->get_cache_textures()) {
+    // We don't want to save this texture.
+    store_record = false;
+  }
+
   // Set the original filename, before we searched along the path.
   // Set the original filename, before we searched along the path.
   nassertr(tex != (Texture *)NULL, false);
   nassertr(tex != (Texture *)NULL, false);
   tex->set_filename(filename_pattern);
   tex->set_filename(filename_pattern);
@@ -579,7 +578,8 @@ ns_load_3d_texture(const Filename &filename_pattern,
 //  Description: The nonstatic implementation of load_cube_map().
 //  Description: The nonstatic implementation of load_cube_map().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Texture *TexturePool::
 Texture *TexturePool::
-ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
+ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps, 
+                 const LoaderOptions &options) {
   Filename filename(filename_pattern);
   Filename filename(filename_pattern);
   filename.set_pattern(true);
   filename.set_pattern(true);
 
 
@@ -603,18 +603,9 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
   bool store_record = false;
   bool store_record = false;
 
 
   BamCache *cache = BamCache::get_global_ptr();
   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());
-      }
-    }
-  }
+  bool compressed_cache_record = false;
+  try_load_cache(tex, cache, filename, record, compressed_cache_record,
+                 options);
 
 
   if (tex == (Texture *)NULL || 
   if (tex == (Texture *)NULL || 
       tex->get_texture_type() != Texture::TT_cube_map) {
       tex->get_texture_type() != Texture::TT_cube_map) {
@@ -624,13 +615,26 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
       << "Loading cube map texture " << filename << "\n";
       << "Loading cube map texture " << filename << "\n";
     tex = make_texture(filename.get_extension());
     tex = make_texture(filename.get_extension());
     tex->setup_cube_map();
     tex->setup_cube_map();
-    if (!tex->read(filename, 0, 0, true, read_mipmaps)) {
+    if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) {
       // This texture was not found or could not be read.
       // This texture was not found or could not be read.
       report_texture_unreadable(filename);
       report_texture_unreadable(filename);
       return NULL;
       return NULL;
     }
     }
     store_record = (record != (BamCacheRecord *)NULL);
     store_record = (record != (BamCacheRecord *)NULL);
   }
   }
+
+  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
+    // We don't want to save the uncompressed version; we'll save the
+    // compressed version when it becomes available.
+    store_record = false;
+    if (!compressed_cache_record) {
+      tex->set_post_load_store_cache(true);
+    }
+
+  } else if (!cache->get_cache_textures()) {
+    // We don't want to save this texture.
+    store_record = false;
+  }
     
     
   // Set the original filename, before we searched along the path.
   // Set the original filename, before we searched along the path.
   nassertr(tex != (Texture *)NULL, false);
   nassertr(tex != (Texture *)NULL, false);
@@ -840,6 +844,81 @@ ns_list_contents(ostream &out) const {
   out << "texture pool size - texture pool ram: " << total_size - total_ram_size << "\n";
   out << "texture pool size - texture pool ram: " << total_size - total_ram_size << "\n";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::try_load_cache
+//       Access: Private
+//  Description: Attempts to load the texture from the cache record.
+////////////////////////////////////////////////////////////////////
+void TexturePool::
+try_load_cache(PT(Texture) &tex, BamCache *cache, const Filename &filename,
+               PT(BamCacheRecord) &record, bool &compressed_cache_record,
+               const LoaderOptions &options) {
+  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_cache_textures() || cache->get_cache_compressed_textures()) && !textures_header_only) {
+      record = cache->lookup(filename, "txo");
+      if (record != (BamCacheRecord *)NULL) {
+        if (record->has_data()) {
+          tex = DCAST(Texture, record->extract_data());
+          compressed_cache_record = (tex->get_ram_image_compression() != Texture::CM_off);
+          int x_size = tex->get_orig_file_x_size();
+          int y_size = tex->get_orig_file_y_size();
+          Texture::adjust_size(x_size, y_size, filename.get_basename());
+
+          if (!cache->get_cache_textures() && !compressed_cache_record) {
+            // We're not supposed to be caching uncompressed textures.
+            if (gobj_cat.is_debug()) {
+              gobj_cat.debug()
+                << "Not caching uncompressed texture " << *tex << "\n";
+            }
+            tex = NULL;
+            record = NULL;
+
+          } else if (x_size != tex->get_x_size() ||
+                     y_size != tex->get_y_size()) {
+            // The cached texture no longer matches our expected size
+            // (the resizing config variables must have changed).
+            // We'll have to reload the texture from its original file
+            // so we can rebuild the cache.
+            if (gobj_cat.is_debug()) {
+              gobj_cat.debug()
+                << "Cached texture " << *tex << " has size "
+                << tex->get_x_size() << " x " << tex->get_y_size()
+                << " instead of " << x_size << " x " << y_size
+                << "; dropping cache.\n";
+            }
+            tex = NULL;
+
+          } else if (!tex->has_compression() && tex->get_ram_image_compression() != Texture::CM_off) {
+            // This texture shouldn't be compressed, but it is.  Go
+            // reload it.
+            if (gobj_cat.is_debug()) {
+              gobj_cat.debug()
+                << "Cached texture " << *tex
+                << " is compressed in cache; dropping cache.\n";
+            }
+            tex = NULL;
+
+          } else {
+            gobj_cat.info()
+              << "Texture " << filename << " found in disk cache.\n";
+            if ((options.get_texture_flags() & LoaderOptions::TF_preload_simple) &&
+                !tex->has_simple_ram_image()) {
+              tex->generate_simple_ram_image();
+            }
+            if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
+              // But drop the RAM until we need it.
+              tex->clear_ram_image();
+            }
+            tex->set_keep_ram_image(false);
+          }
+        }
+      }
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePool::report_texture_unreadable
 //     Function: TexturePool::report_texture_unreadable
 //       Access: Private
 //       Access: Private
@@ -892,7 +971,7 @@ report_texture_unreadable(const Filename &filename) const {
 PT(Texture) TexturePool::
 PT(Texture) TexturePool::
 pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
 pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
          int primary_file_num_channels, int alpha_file_channel,
          int primary_file_num_channels, int alpha_file_channel,
-         bool read_mipmaps) {
+         bool read_mipmaps, const LoaderOptions &options) {
   PT(Texture) tex;
   PT(Texture) tex;
 
 
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
@@ -903,7 +982,7 @@ pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
        ++fi) {
        ++fi) {
     tex = (*fi)->pre_load(orig_filename, orig_alpha_filename,
     tex = (*fi)->pre_load(orig_filename, orig_alpha_filename,
                           primary_file_num_channels, alpha_file_channel,
                           primary_file_num_channels, alpha_file_channel,
-                          read_mipmaps);
+                          read_mipmaps, options);
     if (tex != (Texture *)NULL) {
     if (tex != (Texture *)NULL) {
       return tex;
       return tex;
     }
     }

+ 25 - 10
panda/src/gobj/texturePool.h

@@ -19,10 +19,13 @@
 #include "texture.h"
 #include "texture.h"
 #include "filename.h"
 #include "filename.h"
 #include "config_gobj.h"
 #include "config_gobj.h"
+#include "loaderOptions.h"
 #include "pmutex.h"
 #include "pmutex.h"
 #include "pmap.h"
 #include "pmap.h"
 
 
 class TexturePoolFilter;
 class TexturePoolFilter;
+class BamCache;
+class BamCacheRecord;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : TexturePool
 //       Class : TexturePool
@@ -41,16 +44,20 @@ PUBLISHED:
   INLINE static bool verify_texture(const string &filename);
   INLINE static bool verify_texture(const string &filename);
   INLINE static Texture *load_texture(const string &filename, 
   INLINE static Texture *load_texture(const string &filename, 
                                       int primary_file_num_channels = 0,
                                       int primary_file_num_channels = 0,
-              bool read_mipmaps = false);
+                                      bool read_mipmaps = false,
+                                      const LoaderOptions &options = LoaderOptions());
   INLINE static Texture *load_texture(const string &filename,
   INLINE static Texture *load_texture(const string &filename,
                                       const string &alpha_filename, 
                                       const string &alpha_filename, 
                                       int primary_file_num_channels = 0,
                                       int primary_file_num_channels = 0,
                                       int alpha_file_channel = 0,
                                       int alpha_file_channel = 0,
-              bool read_mipmaps = false);
+                                      bool read_mipmaps = false,
+                                      const LoaderOptions &options = LoaderOptions());
   INLINE static Texture *load_3d_texture(const string &filename_pattern,
   INLINE static Texture *load_3d_texture(const string &filename_pattern,
-           bool read_mipmaps = false);
+                                         bool read_mipmaps = false,
+                                         const LoaderOptions &options = LoaderOptions());
   INLINE static Texture *load_cube_map(const string &filename_pattern,
   INLINE static Texture *load_cube_map(const string &filename_pattern,
-               bool read_mipmaps = false);
+                                       bool read_mipmaps = false,
+                                       const LoaderOptions &options = LoaderOptions());
 
 
   INLINE static Texture *get_normalization_cube_map(int size);
   INLINE static Texture *get_normalization_cube_map(int size);
   INLINE static Texture *get_alpha_scale_map();
   INLINE static Texture *get_alpha_scale_map();
@@ -87,17 +94,21 @@ private:
 
 
   bool ns_has_texture(const Filename &orig_filename);
   bool ns_has_texture(const Filename &orig_filename);
   Texture *ns_load_texture(const Filename &orig_filename, 
   Texture *ns_load_texture(const Filename &orig_filename, 
-         int primary_file_num_channels,
-         bool read_mipmaps);
+                           int primary_file_num_channels,
+                           bool read_mipmaps,
+                           const LoaderOptions &options);
   Texture *ns_load_texture(const Filename &orig_filename, 
   Texture *ns_load_texture(const Filename &orig_filename, 
                            const Filename &orig_alpha_filename, 
                            const Filename &orig_alpha_filename, 
                            int primary_file_num_channels,
                            int primary_file_num_channels,
                            int alpha_file_channel,
                            int alpha_file_channel,
-         bool read_mipmaps);
+                           bool read_mipmaps,
+                           const LoaderOptions &options);
   Texture *ns_load_3d_texture(const Filename &filename_pattern,
   Texture *ns_load_3d_texture(const Filename &filename_pattern,
-            bool read_mipmaps);
+                              bool read_mipmaps,
+                              const LoaderOptions &options);
   Texture *ns_load_cube_map(const Filename &filename_pattern,
   Texture *ns_load_cube_map(const Filename &filename_pattern,
-          bool read_mipmaps);
+                            bool read_mipmaps,
+                            const LoaderOptions &options);
   Texture *ns_get_normalization_cube_map(int size);
   Texture *ns_get_normalization_cube_map(int size);
   Texture *ns_get_alpha_scale_map();
   Texture *ns_get_alpha_scale_map();
 
 
@@ -107,6 +118,10 @@ private:
   int ns_garbage_collect();
   int ns_garbage_collect();
   void ns_list_contents(ostream &out) const;
   void ns_list_contents(ostream &out) const;
 
 
+  void try_load_cache(PT(Texture) &tex, BamCache *cache, 
+                      const Filename &filename, PT(BamCacheRecord) &record, 
+                      bool &compressed_cache_record,
+                      const LoaderOptions &options);
   void report_texture_unreadable(const Filename &filename) const;
   void report_texture_unreadable(const Filename &filename) const;
 
 
   // Methods to invoke a TexturePoolFilter.
   // Methods to invoke a TexturePoolFilter.
@@ -114,7 +129,7 @@ private:
                        const Filename &orig_alpha_filename,
                        const Filename &orig_alpha_filename,
                        int primary_file_num_channels,
                        int primary_file_num_channels,
                        int alpha_file_channel,
                        int alpha_file_channel,
-                       bool read_mipmaps);
+                       bool read_mipmaps, const LoaderOptions &options);
   PT(Texture) post_load(Texture *tex);
   PT(Texture) post_load(Texture *tex);
 
 
   void load_filters();
   void load_filters();

+ 2 - 1
panda/src/gobj/texturePoolFilter.cxx

@@ -37,7 +37,8 @@ TexturePoolFilter::
 //               this filename.
 //               this filename.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(Texture) TexturePoolFilter::
 PT(Texture) TexturePoolFilter::
-pre_load(const Filename &, const Filename &, int, int, bool) {
+pre_load(const Filename &, const Filename &, int, int, bool,
+         const LoaderOptions &) {
   return NULL;
   return NULL;
 }
 }
 
 

+ 4 - 1
panda/src/gobj/texturePoolFilter.h

@@ -20,6 +20,8 @@
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "typedObject.h"
 #include "typedObject.h"
 
 
+class LoaderOptions;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : TexturePoolFilter
 //       Class : TexturePoolFilter
 // Description : This is an abstract base class, a placeholder for any
 // Description : This is an abstract base class, a placeholder for any
@@ -50,7 +52,8 @@ public:
                                const Filename &orig_alpha_filename,
                                const Filename &orig_alpha_filename,
                                int primary_file_num_channels,
                                int primary_file_num_channels,
                                int alpha_file_channel,
                                int alpha_file_channel,
-                               bool read_mipmaps);
+                               bool read_mipmaps, 
+                               const LoaderOptions &options);
   virtual PT(Texture) post_load(Texture *tex);
   virtual PT(Texture) post_load(Texture *tex);
 
 
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;

+ 1 - 0
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -134,6 +134,7 @@ public:
 
 
   virtual TextureContext *prepare_texture(Texture *tex)=0;
   virtual TextureContext *prepare_texture(Texture *tex)=0;
   virtual void release_texture(TextureContext *tc)=0;
   virtual void release_texture(TextureContext *tc)=0;
+  virtual bool extract_texture_data(Texture *tex)=0;
 
 
   virtual GeomContext *prepare_geom(Geom *geom)=0;
   virtual GeomContext *prepare_geom(Geom *geom)=0;
   virtual void release_geom(GeomContext *gc)=0;
   virtual void release_geom(GeomContext *gc)=0;

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

@@ -69,7 +69,6 @@
     loaderFileType.h \
     loaderFileType.h \
     loaderFileTypeBam.h  \
     loaderFileTypeBam.h  \
     loaderFileTypeRegistry.h \
     loaderFileTypeRegistry.h \
-    loaderOptions.I loaderOptions.h \
     lodNode.I lodNode.h \
     lodNode.I lodNode.h \
     lodNodeType.h \
     lodNodeType.h \
     materialAttrib.I materialAttrib.h \
     materialAttrib.I materialAttrib.h \
@@ -184,7 +183,6 @@
     loaderFileType.cxx  \
     loaderFileType.cxx  \
     loaderFileTypeBam.cxx \
     loaderFileTypeBam.cxx \
     loaderFileTypeRegistry.cxx  \
     loaderFileTypeRegistry.cxx  \
-    loaderOptions.cxx \
     lodNode.cxx \
     lodNode.cxx \
     lodNodeType.cxx \
     lodNodeType.cxx \
     materialAttrib.cxx \
     materialAttrib.cxx \
@@ -295,7 +293,6 @@
     loaderFileType.h \
     loaderFileType.h \
     loaderFileTypeBam.h \
     loaderFileTypeBam.h \
     loaderFileTypeRegistry.h \
     loaderFileTypeRegistry.h \
-    loaderOptions.I loaderOptions.h \
     lodNode.I lodNode.h \
     lodNode.I lodNode.h \
     lodNodeType.h \
     lodNodeType.h \
     materialAttrib.I materialAttrib.h \
     materialAttrib.I materialAttrib.h \

+ 1 - 1
panda/src/pgraph/loader.cxx

@@ -257,7 +257,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
   bool report_errors = (options.get_flags() & LoaderOptions::LF_report_errors) != 0;
   bool report_errors = (options.get_flags() & LoaderOptions::LF_report_errors) != 0;
 
 
   PT(BamCacheRecord) record;
   PT(BamCacheRecord) record;
-  if (cache->get_active() && requested_type->get_allow_disk_cache(options)) {
+  if (cache->get_cache_models() && requested_type->get_allow_disk_cache(options)) {
     // See if the model can be found in the on-disk cache, if it is
     // See if the model can be found in the on-disk cache, if it is
     // active.
     // active.
     record = cache->lookup(pathname, "bam");
     record = cache->lookup(pathname, "bam");

+ 1 - 1
panda/src/pgraph/loaderFileTypeBam.cxx

@@ -80,7 +80,7 @@ load_file(const Filename &path, const LoaderOptions &options,
   if (!bam_file.open_read(path, report_errors)) {
   if (!bam_file.open_read(path, report_errors)) {
     return NULL;
     return NULL;
   }
   }
-
+  bam_file.get_reader()->set_loader_options(options);
   return bam_file.read_node(report_errors);
   return bam_file.read_node(report_errors);
 }
 }
 
 

+ 0 - 1
panda/src/pgraph/pgraph_composite3.cxx

@@ -9,7 +9,6 @@
 #include "loaderFileType.cxx"
 #include "loaderFileType.cxx"
 #include "loaderFileTypeBam.cxx"
 #include "loaderFileTypeBam.cxx"
 #include "loaderFileTypeRegistry.cxx"
 #include "loaderFileTypeRegistry.cxx"
-#include "loaderOptions.cxx"
 #include "lodNode.cxx"
 #include "lodNode.cxx"
 #include "lodNodeType.cxx"
 #include "lodNodeType.cxx"
 #include "materialAttrib.cxx"
 #include "materialAttrib.cxx"

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

@@ -48,6 +48,7 @@
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
     linkedListNode.I linkedListNode.h \
     linkedListNode.I linkedListNode.h \
     load_prc_file.h \
     load_prc_file.h \
+    loaderOptions.I loaderOptions.h \
     modifierButtons.I modifierButtons.h mouseButton.h \
     modifierButtons.I modifierButtons.h mouseButton.h \
     mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
     mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
     nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
     nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
@@ -96,6 +97,7 @@
     keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \
     keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \
     linkedListNode.cxx \
     linkedListNode.cxx \
     load_prc_file.cxx \
     load_prc_file.cxx \
+    loaderOptions.cxx \
     modifierButtons.cxx mouseButton.cxx mouseData.cxx \
     modifierButtons.cxx mouseButton.cxx mouseData.cxx \
     nameUniquifier.cxx \
     nameUniquifier.cxx \
     nodeCachedReferenceCount.cxx \
     nodeCachedReferenceCount.cxx \
@@ -153,6 +155,7 @@
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
     linkedListNode.I linkedListNode.h \
     linkedListNode.I linkedListNode.h \
     load_prc_file.h \
     load_prc_file.h \
+    loaderOptions.I loaderOptions.h \
     modifierButtons.I \
     modifierButtons.I \
     modifierButtons.h mouseButton.h mouseData.I mouseData.h \
     modifierButtons.h mouseButton.h mouseData.I mouseData.h \
     nameUniquifier.I nameUniquifier.h \
     nameUniquifier.I nameUniquifier.h \

+ 2 - 1
panda/src/putil/bam.h

@@ -32,7 +32,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
 
-static const unsigned short _bam_minor_ver = 17;
+static const unsigned short _bam_minor_ver = 18;
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
 // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
 // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
@@ -50,6 +50,7 @@ static const unsigned short _bam_minor_ver = 17;
 // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
 // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
 // Bumped to minor version 17 on 8/6/08 to add PartBundle::_anim_preload.
 // Bumped to minor version 17 on 8/6/08 to add PartBundle::_anim_preload.
+// Bumped to minor version 18 on 8/14/08 to add Texture::_simple_ram_image.
 
 
 
 
 #endif
 #endif

+ 93 - 0
panda/src/putil/bamCache.I

@@ -20,6 +20,10 @@
 //               that the cache should be consulted automatically on
 //               that the cache should be consulted automatically on
 //               loads, "not active" means that objects should be
 //               loads, "not active" means that objects should be
 //               loaded directly without consulting the cache.
 //               loaded directly without consulting the cache.
+//
+//               This represents the global flag.  Also see the
+//               individual cache_models, cache_textures,
+//               cache_compressed_textures flags.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void BamCache::
 INLINE void BamCache::
 set_active(bool active) {
 set_active(bool active) {
@@ -34,12 +38,101 @@ set_active(bool active) {
 //               should be consulted automatically on loads, "not
 //               should be consulted automatically on loads, "not
 //               active" means that objects should be loaded directly
 //               active" means that objects should be loaded directly
 //               without consulting the cache.
 //               without consulting the cache.
+//
+//               This represents the global flag.  Also see the
+//               individual cache_models, cache_textures,
+//               cache_compressed_textures flags.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool BamCache::
 INLINE bool BamCache::
 get_active() const {
 get_active() const {
   return _active;
   return _active;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: BamCache::set_cache_models
+//       Access: Published
+//  Description: Indicates whether model files (e.g. egg files and bam
+//               files) will be stored in the cache, as bam files.
+////////////////////////////////////////////////////////////////////
+INLINE void BamCache::
+set_cache_models(bool flag) {
+  _cache_models = flag;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamCache::get_cache_models
+//       Access: Published
+//  Description: Returns whether model files (e.g. egg files and bam
+//               files) will be stored in the cache, as bam files.
+//
+//               This also returns false if get_active() is false.
+////////////////////////////////////////////////////////////////////
+INLINE bool BamCache::
+get_cache_models() const {
+  return _cache_models && _active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamCache::set_cache_textures
+//       Access: Published
+//  Description: Indicates whether texture files will be stored in the
+//               cache, as uncompressed txo files.
+////////////////////////////////////////////////////////////////////
+INLINE void BamCache::
+set_cache_textures(bool flag) {
+  _cache_textures = flag;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamCache::get_cache_textures
+//       Access: Published
+//  Description: Returns whether texture files (e.g. egg files and bam
+//               files) will be stored in the cache, as txo files.
+//
+//               This also returns false if get_active() is false.
+////////////////////////////////////////////////////////////////////
+INLINE bool BamCache::
+get_cache_textures() const {
+  return _cache_textures && _active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamCache::set_cache_compressed_textures
+//       Access: Published
+//  Description: Indicates whether compressed texture files will be
+//               stored in the cache, as compressed txo files.  The
+//               compression data is extracted from the GSG after the
+//               texture has been loaded.
+//
+//               This may be set in conjunction with
+//               set_cache_textures(), or independently of it.  If
+//               set_cache_textures() is true and this is false, all
+//               textures will be cached in their uncompressed form.
+//               If set_cache_textures() is false and this is true,
+//               only compressed textures will be cached, and they
+//               will be cached in their compressed form.  If both are
+//               true, all textures will be cached, in their
+//               uncompressed or compressed form appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE void BamCache::
+set_cache_compressed_textures(bool flag) {
+  _cache_compressed_textures = flag;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamCache::get_cache_compressed_textures
+//       Access: Published
+//  Description: Returns whether compressed texture files will be
+//               stored in the cache, as compressed txo files.  See
+//               set_cache_compressed_textures().
+//
+//               This also returns false if get_active() is false.
+////////////////////////////////////////////////////////////////////
+INLINE bool BamCache::
+get_cache_compressed_textures() const {
+  return _cache_compressed_textures && _active;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: BamCache::get_root
 //     Function: BamCache::get_root
 //       Access: Published
 //       Access: Published

+ 15 - 4
panda/src/putil/bamCache.cxx

@@ -53,16 +53,31 @@ BamCache() :
      PRC_DESC("This is the amount of time, in seconds, between automatic "
      PRC_DESC("This is the amount of time, in seconds, between automatic "
               "flushes of the model-cache index."));
               "flushes of the model-cache index."));
 
 
+  ConfigVariableBool model_cache_models
+    ("model-cache-models", true,
+     PRC_DESC("If this is set to true, models will be cached in the "
+              "model cache, as bam files."));
+
   ConfigVariableBool model_cache_textures
   ConfigVariableBool model_cache_textures
     ("model-cache-textures", true,
     ("model-cache-textures", true,
      PRC_DESC("If this is set to true, textures will also be cached in the "
      PRC_DESC("If this is set to true, textures will also be cached in the "
               "model cache, as txo files."));
               "model cache, as txo files."));
 
 
+  ConfigVariableBool model_cache_compressed_textures
+    ("model-cache-compressed-textures", false,
+     PRC_DESC("If this is set to true, compressed textures will be cached "
+              "in the model cache, in their compressed form as downloaded "
+              "by the GSG.  This may be set in conjunction with "
+              "model-cache-textures, or it may be independent."));
+
   ConfigVariableInt model_cache_max_kbytes
   ConfigVariableInt model_cache_max_kbytes
     ("model-cache-max-kbytes", 1048576,
     ("model-cache-max-kbytes", 1048576,
      PRC_DESC("This is the maximum size of the model cache, in kilobytes."));
      PRC_DESC("This is the maximum size of the model cache, in kilobytes."));
 
 
+  _cache_models = model_cache_models;
   _cache_textures = model_cache_textures;
   _cache_textures = model_cache_textures;
+  _cache_compressed_textures = model_cache_compressed_textures;
+
   _flush_time = model_cache_flush;
   _flush_time = model_cache_flush;
   _max_kbytes = model_cache_max_kbytes;
   _max_kbytes = model_cache_max_kbytes;
 
 
@@ -143,10 +158,6 @@ set_root(const Filename &root) {
 PT(BamCacheRecord) BamCache::
 PT(BamCacheRecord) BamCache::
 lookup(const Filename &source_filename, const string &cache_extension) {
 lookup(const Filename &source_filename, const string &cache_extension) {
   consider_flush_index();
   consider_flush_index();
-
-  if ((cache_extension == "txo")&&(!_cache_textures)) {
-    return NULL;
-  }
   
   
   Filename source_pathname(source_filename);
   Filename source_pathname(source_filename);
   source_pathname.make_absolute();
   source_pathname.make_absolute();

+ 14 - 2
panda/src/putil/bamCache.h

@@ -48,6 +48,15 @@ PUBLISHED:
   INLINE void set_active(bool flag);
   INLINE void set_active(bool flag);
   INLINE bool get_active() const;
   INLINE bool get_active() const;
 
 
+  INLINE void set_cache_models(bool flag);
+  INLINE bool get_cache_models() const;
+
+  INLINE void set_cache_textures(bool flag);
+  INLINE bool get_cache_textures() const;
+
+  INLINE void set_cache_compressed_textures(bool flag);
+  INLINE bool get_cache_compressed_textures() const;
+
   void set_root(const Filename &root);
   void set_root(const Filename &root);
   INLINE const Filename &get_root() const;
   INLINE const Filename &get_root() const;
 
 
@@ -92,17 +101,20 @@ private:
   PT(BamCacheRecord) read_record(const Filename &source_pathname,
   PT(BamCacheRecord) read_record(const Filename &source_pathname,
                                  const Filename &cache_filename,
                                  const Filename &cache_filename,
                                  int pass);
                                  int pass);
-  static PT(BamCacheRecord) do_read_record(Filename &cache_pathname, bool read_data);
+  static PT(BamCacheRecord) do_read_record(Filename &cache_pathname, 
+                                           bool read_data);
 
 
   static string hash_filename(const string &filename);
   static string hash_filename(const string &filename);
   static void make_global();
   static void make_global();
 
 
   bool _active;
   bool _active;
+  bool _cache_models;
+  bool _cache_textures;
+  bool _cache_compressed_textures;
   bool _read_only;
   bool _read_only;
   Filename _root;
   Filename _root;
   int _flush_time;
   int _flush_time;
   int _max_kbytes;
   int _max_kbytes;
-  bool _cache_textures;
   static BamCache *_global_ptr;
   static BamCache *_global_ptr;
 
 
   BamCacheIndex *_index;
   BamCacheIndex *_index;

+ 21 - 0
panda/src/putil/bamReader.I

@@ -26,6 +26,27 @@ get_filename() const {
   return _filename;
   return _filename;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: BamReader::get_loader_options
+//       Access: Public
+//  Description: Returns the LoaderOptions passed to the loader when
+//               the model was requested, if any.
+////////////////////////////////////////////////////////////////////
+INLINE const LoaderOptions &BamReader::
+get_loader_options() const {
+  return _loader_options;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamReader::set_loader_options
+//       Access: Public
+//  Description: Specifies the LoaderOptions for this BamReader.
+////////////////////////////////////////////////////////////////////
+INLINE void BamReader::
+set_loader_options(const LoaderOptions &options) {
+  _loader_options = options;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::is_eof
 //     Function: BamReader::is_eof
 //       Access: Public
 //       Access: Public

+ 7 - 1
panda/src/putil/bamReader.h

@@ -23,6 +23,7 @@
 #include "datagramIterator.h"
 #include "datagramIterator.h"
 #include "bamReaderParam.h"
 #include "bamReaderParam.h"
 #include "bamEndian.h"
 #include "bamEndian.h"
+#include "loaderOptions.h"
 #include "factory.h"
 #include "factory.h"
 #include "vector_int.h"
 #include "vector_int.h"
 #include "pset.h"
 #include "pset.h"
@@ -99,6 +100,9 @@ public:
   AuxData *get_aux_data(TypedWritable *obj, const string &name) const;
   AuxData *get_aux_data(TypedWritable *obj, const string &name) const;
 
 
   INLINE const Filename &get_filename() const;
   INLINE const Filename &get_filename() const;
+
+  INLINE const LoaderOptions &get_loader_options() const;
+  INLINE void set_loader_options(const LoaderOptions &options);
   
   
   TypedWritable *read_object();
   TypedWritable *read_object();
   INLINE bool is_eof() const;
   INLINE bool is_eof() const;
@@ -185,9 +189,11 @@ private:
   typedef phash_map<int, TypeHandle, int_hash> IndexMap;
   typedef phash_map<int, TypeHandle, int_hash> IndexMap;
   IndexMap _index_map;
   IndexMap _index_map;
 
 
-  // This is the filename of the BAM, or null string if not in a file.
+  // This is the filename of the BAM, or empty string if not in a file.
   Filename _filename;
   Filename _filename;
 
 
+  LoaderOptions _loader_options;
+
   // This maps the object ID numbers encountered within the Bam file
   // This maps the object ID numbers encountered within the Bam file
   // to the actual pointers of the corresponding generated objects.
   // to the actual pointers of the corresponding generated objects.
   class CreatedObj {
   class CreatedObj {

+ 20 - 0
panda/src/putil/config_util.cxx

@@ -126,6 +126,26 @@ ConfigVariableDouble sleep_precision
           "timeout of 1.0 seconds, we can expect to actually sleep for "
           "timeout of 1.0 seconds, we can expect to actually sleep for "
           "somewhere between 1.0 and 1.0 + sleep-precision seconds."));
           "somewhere between 1.0 and 1.0 + sleep-precision seconds."));
 
 
+ConfigVariableBool preload_textures
+("preload-textures", true,
+ PRC_DESC("When this is true, texture images are loaded from disk as soon "
+          "as the Texture is created from the TexturePool.  When this is "
+          "false, the Texture is created immediately, but the image data "
+          "is not loaded from disk until the Texture is actually rendered "
+          "(or otherwise prepared) on the GSG.  This can help reduce "
+          "wasted memory from Textures that are created but never used "
+          "to render."));
+
+ConfigVariableBool preload_simple_textures
+("preload-simple-textures", false,
+ PRC_DESC("When this is true, every texture image will have a simple "
+          "image generated for it at load time.  (Normally, textures "
+          "get a simple image at egg2bam time.)  This slows the initial "
+          "loading time of textures, but allows you to take advantage "
+          "of gsg::set_incomplete_render() to load textures on-the-fly "
+          "in a sub-thread.  It's not generally necessary if you are "
+          "loading bam files that were generated via egg2bam."));
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libputil
 //     Function: init_libputil
 //  Description: Initializes the library.  This must be called at
 //  Description: Initializes the library.  This must be called at

+ 3 - 4
panda/src/putil/config_util.h

@@ -53,11 +53,10 @@ EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_sound_path();
 EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_plugin_path();
 EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_plugin_path();
 END_PUBLISH
 END_PUBLISH
 
 
-extern ConfigVariableDouble clock_frame_rate;
-extern ConfigVariableDouble clock_degrade_factor;
-extern ConfigVariableDouble max_dt;
 extern ConfigVariableDouble sleep_precision;
 extern ConfigVariableDouble sleep_precision;
-extern ConfigVariableDouble average_frame_rate_interval;
+
+extern EXPCL_PANDA_PUTIL ConfigVariableBool preload_textures;
+extern EXPCL_PANDA_PUTIL ConfigVariableBool preload_simple_textures;
 
 
 extern EXPCL_PANDA_PUTIL void init_libputil();
 extern EXPCL_PANDA_PUTIL void init_libputil();
 
 

+ 25 - 3
panda/src/pgraph/loaderOptions.I → panda/src/putil/loaderOptions.I

@@ -19,8 +19,8 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE LoaderOptions::
 INLINE LoaderOptions::
-LoaderOptions(int flags) : 
-  _flags(flags)
+LoaderOptions(int flags, int texture_flags) : 
+  _flags(flags), _texture_flags(texture_flags)
 {
 {
 }
 }
 
 
@@ -31,7 +31,8 @@ LoaderOptions(int flags) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE LoaderOptions::
 INLINE LoaderOptions::
 LoaderOptions(const LoaderOptions &copy) :
 LoaderOptions(const LoaderOptions &copy) :
-  _flags(copy._flags)
+  _flags(copy._flags),
+  _texture_flags(copy._texture_flags)
 {
 {
 }
 }
 
 
@@ -43,6 +44,7 @@ LoaderOptions(const LoaderOptions &copy) :
 INLINE void LoaderOptions::
 INLINE void LoaderOptions::
 operator = (const LoaderOptions &copy) {
 operator = (const LoaderOptions &copy) {
   _flags = copy._flags;
   _flags = copy._flags;
+  _texture_flags = copy._texture_flags;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -64,3 +66,23 @@ INLINE int LoaderOptions::
 get_flags() const {
 get_flags() const {
   return _flags;
   return _flags;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderOptions::set_texture_flags
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void LoaderOptions::
+set_texture_flags(int texture_flags) {
+  _texture_flags = texture_flags;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderOptions::get_texture_flags
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE int LoaderOptions::
+get_texture_flags() const {
+  return _texture_flags;
+}

+ 43 - 0
panda/src/pgraph/loaderOptions.cxx → panda/src/putil/loaderOptions.cxx

@@ -13,8 +13,26 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "loaderOptions.h"
 #include "loaderOptions.h"
+#include "config_util.h"
 #include "indent.h"
 #include "indent.h"
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderOptions::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+LoaderOptions::
+LoaderOptions(int flags) : 
+  _flags(flags), _texture_flags(0)  
+{
+  if (preload_textures) {
+    _texture_flags |= TF_preload;
+  }
+  if (preload_simple_textures) {
+    _texture_flags |= TF_preload_simple;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LoaderOptions::output
 //     Function: LoaderOptions::output
 //       Access: Published
 //       Access: Published
@@ -23,6 +41,7 @@
 void LoaderOptions::
 void LoaderOptions::
 output(ostream &out) const {
 output(ostream &out) const {
   out << "LoaderOptions(";
   out << "LoaderOptions(";
+
   string sep = "";
   string sep = "";
   write_flag(out, sep, "LF_search", LF_search);
   write_flag(out, sep, "LF_search", LF_search);
   write_flag(out, sep, "LF_report_errors", LF_report_errors);
   write_flag(out, sep, "LF_report_errors", LF_report_errors);
@@ -41,6 +60,16 @@ output(ostream &out) const {
   if (sep.empty()) {
   if (sep.empty()) {
     out << "0";
     out << "0";
   }
   }
+
+  out << ", ";
+
+  sep = "";
+  write_texture_flag(out, sep, "TF_preload", TF_preload);
+  write_texture_flag(out, sep, "TF_preload_simple", TF_preload_simple);
+  if (sep.empty()) {
+    out << "0";
+  }
+
   out << ")";
   out << ")";
 }
 }
 
 
@@ -57,3 +86,17 @@ write_flag(ostream &out, string &sep,
     sep = " | ";
     sep = " | ";
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: LoaderOptions::write_texture_flag
+//       Access: Private
+//  Description: Used to implement output().
+////////////////////////////////////////////////////////////////////
+void LoaderOptions::
+write_texture_flag(ostream &out, string &sep, 
+                   const string &flag_name, int flag) const {
+  if ((_texture_flags & flag) == flag) {
+    out << sep << flag_name;
+    sep = " | ";
+  }
+}

+ 16 - 4
panda/src/pgraph/loaderOptions.h → panda/src/putil/loaderOptions.h

@@ -22,10 +22,9 @@
 // Description : Specifies parameters that may be passed to the
 // Description : Specifies parameters that may be passed to the
 //               loader.
 //               loader.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_PGRAPH LoaderOptions {
+class EXPCL_PANDA_PUTIL LoaderOptions {
 PUBLISHED:
 PUBLISHED:
-  // At the moment, we only have this one set of flags.  Maybe one day
-  // there will be more options.
+  // Flags for loading model files.
   enum LoaderFlags {
   enum LoaderFlags {
     LF_search            = 0x0001,
     LF_search            = 0x0001,
     LF_report_errors     = 0x0002,
     LF_report_errors     = 0x0002,
@@ -39,19 +38,32 @@ PUBLISHED:
     LF_allow_instance    = 0x0080,  // returned pointer might be shared
     LF_allow_instance    = 0x0080,  // returned pointer might be shared
   };
   };
 
 
-  INLINE LoaderOptions(int flags = LF_search | LF_report_errors);
+  // Flags for loading texture files.
+  enum TextureFlags {
+    TF_preload           = 0x0004,  // Texture will have RAM image
+    TF_preload_simple    = 0x0008,  // Texture will have simple RAM image
+  };
+
+  LoaderOptions(int flags = LF_search | LF_report_errors);
+  INLINE LoaderOptions(int flags, int texture_flags);
   INLINE LoaderOptions(const LoaderOptions &copy);
   INLINE LoaderOptions(const LoaderOptions &copy);
   INLINE void operator = (const LoaderOptions &copy);
   INLINE void operator = (const LoaderOptions &copy);
 
 
   INLINE void set_flags(int flags);
   INLINE void set_flags(int flags);
   INLINE int get_flags() const;
   INLINE int get_flags() const;
 
 
+  INLINE void set_texture_flags(int flags);
+  INLINE int get_texture_flags() const;
+
   void output(ostream &out) const;
   void output(ostream &out) const;
 
 
 private:
 private:
   void write_flag(ostream &out, string &sep, 
   void write_flag(ostream &out, string &sep, 
                   const string &flag_name, int flag) const;
                   const string &flag_name, int flag) const;
+  void write_texture_flag(ostream &out, string &sep, 
+                          const string &flag_name, int flag) const;
   int _flags;
   int _flags;
+  int _texture_flags;
 };
 };
 
 
 INLINE ostream &operator << (ostream &out, const LoaderOptions &opts) {
 INLINE ostream &operator << (ostream &out, const LoaderOptions &opts) {

+ 1 - 0
panda/src/putil/putil_composite2.cxx

@@ -3,6 +3,7 @@
 #include "lineStreamBuf.cxx"
 #include "lineStreamBuf.cxx"
 #include "linkedListNode.cxx"
 #include "linkedListNode.cxx"
 #include "load_prc_file.cxx"
 #include "load_prc_file.cxx"
+#include "loaderOptions.cxx"
 #include "modifierButtons.cxx"
 #include "modifierButtons.cxx"
 #include "mouseButton.cxx"
 #include "mouseButton.cxx"
 #include "mouseData.cxx"
 #include "mouseData.cxx"

+ 1 - 1
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -2114,7 +2114,7 @@ upload_texture(TinyTextureContext *gtc) {
 
 
   gtc->update_data_size_bytes(bytecount);
   gtc->update_data_size_bytes(bytecount);
   
   
-  tex->texture_uploaded();
+  tex->texture_uploaded(this);
   gtc->mark_loaded();
   gtc->mark_loaded();
 
 
   return true;
   return true;