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

This commit is contained in:
David Rose 2008-08-14 23:50:17 +00:00
parent c7177a828f
commit 617a769ef7
38 changed files with 1256 additions and 611 deletions

View File

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

View File

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

View File

@ -955,7 +955,7 @@ get_alpha_file_channel() const {
// mipmap level number; and the texture will be defined
// 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
// the filename should now require two hash marks, and
// the first one indicates the mipmap level number,

View File

@ -148,6 +148,14 @@ ConfigVariableBool egg_emulate_bface
"it is false, a single polygon will be created with the two_sided "
"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) {
init_libegg2pg();
}

View File

@ -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_indices;
extern EXPCL_PANDAEGG ConfigVariableBool egg_emulate_bface;
extern EXPCL_PANDAEGG ConfigVariableBool egg_preload_simple_textures;
extern EXPCL_PANDAEGG void init_libegg2pg();

View File

@ -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;
switch (egg_tex->get_texture_type()) {
case EggTexture::TT_unspecified:
@ -938,22 +944,22 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
egg_tex->get_alpha_fullpath(),
wanted_channels,
egg_tex->get_alpha_file_channel(),
egg_tex->get_read_mipmaps());
egg_tex->get_read_mipmaps(), options);
} else {
tex = TexturePool::load_texture(egg_tex->get_fullpath(),
wanted_channels,
egg_tex->get_read_mipmaps());
egg_tex->get_read_mipmaps(), options);
}
break;
case EggTexture::TT_3d_texture:
tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
egg_tex->get_read_mipmaps());
egg_tex->get_read_mipmaps(), options);
break;
case EggTexture::TT_cube_map:
tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
egg_tex->get_read_mipmaps());
egg_tex->get_read_mipmaps(), options);
break;
}

View File

@ -46,6 +46,8 @@
#include "indirectLess.h"
#include "pStatTimer.h"
#include "load_prc_file.h"
#include "bamCache.h"
#include "bamCacheRecord.h"
#ifdef HAVE_CG
#include "Cg/cgGL.h"
@ -2666,224 +2668,8 @@ extract_texture_data(Texture *tex) {
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
nassertr(tc != (TextureContext *)NULL, false);
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
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();
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
// Access: Protected

View File

@ -336,6 +336,7 @@ protected:
size_t get_texture_memory_size(Texture *tex);
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,
Texture *tex, GLenum target, GLenum page_target,
Texture::ComponentType type,

View File

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

View File

@ -98,25 +98,6 @@ ConfigVariableBool keep_texture_ram
"texture image from disk; but it will consume memory somewhat "
"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
("compressed-textures", false,
PRC_DESC("Set this to true to compress textures as they are loaded into "

View File

@ -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 preload_textures;
extern EXPCL_PANDA_GOBJ ConfigVariableBool preload_simple_textures;
extern EXPCL_PANDA_GOBJ ConfigVariableBool compressed_textures;
extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_buffers;
extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_arrays;

View File

@ -122,143 +122,6 @@ setup_cube_map(int size, ComponentType component_type,
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
// Access: Published
@ -574,6 +437,45 @@ set_pad_size(int x, int y, int 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
// Access: Published
@ -737,6 +639,29 @@ get_compression() const {
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
// Access: Published
@ -1408,7 +1333,34 @@ set_match_framebuffer_format(bool 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

View File

@ -78,6 +78,7 @@ Texture(const string &name) :
_ram_image_compression = CM_off;
_render_to_texture = false;
_match_framebuffer_format = false;
_post_load_store_cache = false;
_quality_level = QL_default;
_texture_type = TT_2d_texture;
@ -91,6 +92,9 @@ Texture(const string &name) :
_pad_y_size = 0;
_pad_z_size = 0;
_orig_file_x_size = 0;
_orig_file_y_size = 0;
_loaded_from_image = false;
_loaded_from_txo = false;
_has_read_pages = false;
@ -146,6 +150,8 @@ operator = (const Texture &copy) {
_pad_x_size = copy._pad_x_size;
_pad_y_size = copy._pad_y_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;
_component_width = copy._component_width;
_texture_type = copy._texture_type;
@ -163,6 +169,7 @@ operator = (const Texture &copy) {
_border_color = copy._border_color;
_compression = copy._compression;
_match_framebuffer_format = copy._match_framebuffer_format;
_post_load_store_cache = false;
_quality_level = copy._quality_level;
_ram_image_compression = copy._ram_image_compression;
_ram_images = copy._ram_images;
@ -251,6 +258,8 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
clear_ram_image();
set_pad_size();
_orig_file_x_size = 0;
_orig_file_y_size = 0;
_loaded_from_image = false;
_loaded_from_txo = 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
// Access: Published
@ -688,7 +841,7 @@ load_related(const InternalName *suffix) const {
// Use it to load the texture.
res = TexturePool::load_texture(main, alph,
_primary_file_num_channels,
_alpha_file_channel);
_alpha_file_channel, false);
} else {
// If the alpha variant of the filename doesn't exist, just go
// ahead and load the related texture without alpha.
@ -1309,7 +1462,9 @@ generate_ram_mipmap_images() {
// texture. The simple image is only supported for
// 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::
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_ram_image._image = image;
_simple_ram_image._page_size = image.size();
_simple_image_date_generated = 0;
_simple_image_date_generated = (PN_int32)time(NULL);
++_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
// Access: Published
@ -1338,14 +1529,13 @@ void Texture::
generate_simple_ram_image() {
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;
}
PNMImage pnmimage;
if (!store(pnmimage)) {
clear_simple_ram_image();
return;
}
@ -1854,11 +2044,13 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
// is false.
//
// Normally, this is not called directly except by the
// GraphicsStateGuardian.
// GraphicsStateGuardian. It will be called in the draw
// thread.
////////////////////////////////////////////////////////////////////
void Texture::
texture_uploaded() {
texture_uploaded(GraphicsStateGuardianBase *gsg) {
ReMutexHolder holder(_lock);
if (!keep_texture_ram && !_keep_ram_image) {
// Once we have prepared the texture, we can generally safely
// 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 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) {
// In this mode, we never intend to load the actual texture
// 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) {
_orig_file_x_size = image.get_x_size();
_orig_file_y_size = image.get_y_size();
consider_rescale(image, fullpath.get_basename());
} else {
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();
_loaded_from_image = true;
}
do_modify_ram_mipmap_image(n);
// Ensure the PNMImage is an appropriate size.
@ -2609,25 +2808,45 @@ reconsider_dirty() {
void Texture::
reload_ram_image() {
BamCache *cache = BamCache::get_global_ptr();
PT(BamCacheRecord) record;
if (cache->get_active() && !textures_header_only) {
// See if the texture can be found in the on-disk cache, if it is
// active.
PT(BamCacheRecord) record = cache->lookup(get_fullpath(), "txo");
record = cache->lookup(get_fullpath(), "txo");
if (record != (BamCacheRecord *)NULL &&
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) {
n = _num_mipmap_levels_read;
}
_loaded_from_image = false;
do_read(get_fullpath(), get_alpha_fullpath(),
_primary_file_num_channels, _alpha_file_channel,
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
// Access: Protected
@ -3128,69 +3439,9 @@ set_size_padded(int x, int y, int z) {
////////////////////////////////////////////////////////////////////
void Texture::
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_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);
}
}
@ -3719,19 +3970,24 @@ make_from_bam(const FactoryParams &params) {
case TT_1d_texture:
case TT_2d_texture:
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 {
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;
case TT_3d_texture:
me = TexturePool::load_3d_texture(filename);
me = TexturePool::load_3d_texture(filename, false,
manager->get_loader_options());
break;
case TT_cube_map:
me = TexturePool::load_cube_map(filename);
me = TexturePool::load_cube_map(filename, false,
manager->get_loader_options());
break;
}
}
@ -3795,6 +4051,39 @@ fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) {
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) {
// In the rawdata case, we must always set the format.
_format = format;
@ -3945,6 +4234,21 @@ write_datagram(BamWriter *manager, Datagram &me) {
me.add_uint8(_format);
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
// in here.
if (has_rawdata) {

View File

@ -28,6 +28,7 @@
#include "pStatCollector.h"
#include "reMutex.h"
#include "reMutexHolder.h"
#include "loaderOptions.h"
class PNMImage;
class TextureContext;
@ -211,15 +212,18 @@ PUBLISHED:
void generate_normalization_cube_map(int size);
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, int z, int n,
@ -273,6 +277,7 @@ PUBLISHED:
INLINE int get_anisotropic_degree() const;
INLINE Colorf get_border_color() const;
INLINE CompressionMode get_compression() const;
INLINE bool has_compression() const;
INLINE bool get_render_to_texture() const;
INLINE bool uses_mipmaps() const;
@ -321,6 +326,8 @@ PUBLISHED:
INLINE size_t get_simple_ram_image_size() const;
INLINE CPTA_uchar get_simple_ram_image() const;
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 clear_simple_ram_image();
@ -369,6 +376,10 @@ PUBLISHED:
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);
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_component_type(ComponentType component_type);
@ -383,11 +394,14 @@ PUBLISHED:
INLINE bool get_match_framebuffer_format() const;
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,
GraphicsStateGuardianBase *gsg);
public:
void texture_uploaded();
void texture_uploaded(GraphicsStateGuardianBase *gsg);
virtual bool has_cull_callback() 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_binary_alpha(Format format);
static bool adjust_size(int &x_size, int &y_size, const string &name);
protected:
virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath,
int primary_file_num_channels, int alpha_file_channel,
@ -541,11 +557,15 @@ protected:
CompressionMode _compression;
bool _render_to_texture;
bool _match_framebuffer_format;
bool _post_load_store_cache;
QualityLevel _quality_level;
int _pad_x_size;
int _pad_y_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
// PreparedGraphicsObjects tables that it has been prepared into.

View File

@ -55,9 +55,9 @@ verify_texture(const string &filename) {
////////////////////////////////////////////////////////////////////
INLINE Texture *TexturePool::
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,
read_mipmaps);
read_mipmaps, options);
}
////////////////////////////////////////////////////////////////////
@ -78,11 +78,11 @@ load_texture(const string &filename, int primary_file_num_channels,
INLINE Texture *TexturePool::
load_texture(const string &filename, const string &alpha_filename,
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,
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.
////////////////////////////////////////////////////////////////////
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.
////////////////////////////////////////////////////////////////////
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);
}
////////////////////////////////////////////////////////////////////

View File

@ -235,7 +235,7 @@ ns_has_texture(const Filename &orig_filename) {
////////////////////////////////////////////////////////////////////
Texture *TexturePool::
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);
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?
tex = pre_load(orig_filename, Filename(), primary_file_num_channels, 0,
read_mipmaps);
read_mipmaps, options);
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) {
// 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";
tex = make_texture(filename.get_extension());
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.
report_texture_unreadable(filename);
return NULL;
}
if (preload_simple_textures) {
if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
tex->generate_simple_ram_image();
}
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.
nassertr(tex != (Texture *)NULL, NULL);
tex->set_filename(orig_filename);
@ -341,7 +335,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
cache->store(record);
}
if (!preload_textures) {
if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
// And now drop the RAM until we need it.
tex->clear_ram_image();
}
@ -364,13 +358,13 @@ ns_load_texture(const Filename &orig_filename,
const Filename &orig_alpha_filename,
int primary_file_num_channels,
int alpha_file_channel,
bool read_mipmaps) {
bool read_mipmaps, const LoaderOptions &options) {
Filename filename(orig_filename);
Filename alpha_filename(orig_alpha_filename);
if (!_fake_texture_image.empty()) {
return ns_load_texture(_fake_texture_image, primary_file_num_channels,
read_mipmaps);
read_mipmaps, options);
}
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?
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();
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) {
// 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;
tex = make_texture(filename.get_extension());
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.
report_texture_unreadable(filename);
return NULL;
}
if (preload_simple_textures) {
if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
tex->generate_simple_ram_image();
}
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.
nassertr(tex != (Texture *)NULL, NULL);
tex->set_filename(orig_filename);
@ -470,7 +465,7 @@ ns_load_texture(const Filename &orig_filename,
cache->store(record);
}
if (!preload_textures) {
if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
// And now drop the RAM until we need it.
tex->clear_ram_image();
}
@ -490,7 +485,7 @@ ns_load_texture(const Filename &orig_filename,
////////////////////////////////////////////////////////////////////
Texture *TexturePool::
ns_load_3d_texture(const Filename &filename_pattern,
bool read_mipmaps) {
bool read_mipmaps, const LoaderOptions &options) {
Filename filename(filename_pattern);
filename.set_pattern(true);
@ -514,18 +509,9 @@ ns_load_3d_texture(const Filename &filename_pattern,
bool store_record = false;
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 ||
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";
tex = make_texture(filename.get_extension());
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.
report_texture_unreadable(filename);
return NULL;
@ -543,6 +529,19 @@ ns_load_3d_texture(const Filename &filename_pattern,
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.
nassertr(tex != (Texture *)NULL, false);
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().
////////////////////////////////////////////////////////////////////
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.set_pattern(true);
@ -603,18 +603,9 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
bool store_record = false;
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 ||
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";
tex = make_texture(filename.get_extension());
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.
report_texture_unreadable(filename);
return 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.
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";
}
////////////////////////////////////////////////////////////////////
// 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
// Access: Private
@ -892,7 +971,7 @@ report_texture_unreadable(const Filename &filename) const {
PT(Texture) TexturePool::
pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
int primary_file_num_channels, int alpha_file_channel,
bool read_mipmaps) {
bool read_mipmaps, const LoaderOptions &options) {
PT(Texture) tex;
MutexHolder holder(_lock);
@ -903,7 +982,7 @@ pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
++fi) {
tex = (*fi)->pre_load(orig_filename, orig_alpha_filename,
primary_file_num_channels, alpha_file_channel,
read_mipmaps);
read_mipmaps, options);
if (tex != (Texture *)NULL) {
return tex;
}

View File

@ -19,10 +19,13 @@
#include "texture.h"
#include "filename.h"
#include "config_gobj.h"
#include "loaderOptions.h"
#include "pmutex.h"
#include "pmap.h"
class TexturePoolFilter;
class BamCache;
class BamCacheRecord;
////////////////////////////////////////////////////////////////////
// Class : TexturePool
@ -41,16 +44,20 @@ PUBLISHED:
INLINE static bool verify_texture(const string &filename);
INLINE static Texture *load_texture(const string &filename,
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,
const string &alpha_filename,
int primary_file_num_channels = 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,
bool read_mipmaps = false);
bool read_mipmaps = false,
const LoaderOptions &options = LoaderOptions());
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_alpha_scale_map();
@ -87,17 +94,21 @@ private:
bool ns_has_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,
const Filename &orig_alpha_filename,
int primary_file_num_channels,
int alpha_file_channel,
bool read_mipmaps);
bool read_mipmaps,
const LoaderOptions &options);
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,
bool read_mipmaps);
bool read_mipmaps,
const LoaderOptions &options);
Texture *ns_get_normalization_cube_map(int size);
Texture *ns_get_alpha_scale_map();
@ -107,6 +118,10 @@ private:
int ns_garbage_collect();
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;
// Methods to invoke a TexturePoolFilter.
@ -114,7 +129,7 @@ private:
const Filename &orig_alpha_filename,
int primary_file_num_channels,
int alpha_file_channel,
bool read_mipmaps);
bool read_mipmaps, const LoaderOptions &options);
PT(Texture) post_load(Texture *tex);
void load_filters();

View File

@ -37,7 +37,8 @@ TexturePoolFilter::
// this filename.
////////////////////////////////////////////////////////////////////
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;
}

View File

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

View File

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

View File

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

View File

@ -257,7 +257,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
bool report_errors = (options.get_flags() & LoaderOptions::LF_report_errors) != 0;
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
// active.
record = cache->lookup(pathname, "bam");

View File

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

View File

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

View File

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

View File

@ -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 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 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.
@ -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 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 18 on 8/14/08 to add Texture::_simple_ram_image.
#endif

View File

@ -20,6 +20,10 @@
// that the cache should be consulted automatically on
// loads, "not active" means that objects should be
// 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::
set_active(bool active) {
@ -34,12 +38,101 @@ set_active(bool active) {
// should be consulted automatically on loads, "not
// active" means that objects should be loaded directly
// without consulting the cache.
//
// This represents the global flag. Also see the
// individual cache_models, cache_textures,
// cache_compressed_textures flags.
////////////////////////////////////////////////////////////////////
INLINE bool BamCache::
get_active() const {
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
// Access: Published

View File

@ -53,16 +53,31 @@ BamCache() :
PRC_DESC("This is the amount of time, in seconds, between automatic "
"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
("model-cache-textures", true,
PRC_DESC("If this is set to true, textures will also be cached in the "
"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
("model-cache-max-kbytes", 1048576,
PRC_DESC("This is the maximum size of the model cache, in kilobytes."));
_cache_models = model_cache_models;
_cache_textures = model_cache_textures;
_cache_compressed_textures = model_cache_compressed_textures;
_flush_time = model_cache_flush;
_max_kbytes = model_cache_max_kbytes;
@ -143,10 +158,6 @@ set_root(const Filename &root) {
PT(BamCacheRecord) BamCache::
lookup(const Filename &source_filename, const string &cache_extension) {
consider_flush_index();
if ((cache_extension == "txo")&&(!_cache_textures)) {
return NULL;
}
Filename source_pathname(source_filename);
source_pathname.make_absolute();

View File

@ -48,6 +48,15 @@ PUBLISHED:
INLINE void set_active(bool flag);
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);
INLINE const Filename &get_root() const;
@ -92,17 +101,20 @@ private:
PT(BamCacheRecord) read_record(const Filename &source_pathname,
const Filename &cache_filename,
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 void make_global();
bool _active;
bool _cache_models;
bool _cache_textures;
bool _cache_compressed_textures;
bool _read_only;
Filename _root;
int _flush_time;
int _max_kbytes;
bool _cache_textures;
static BamCache *_global_ptr;
BamCacheIndex *_index;

View File

@ -26,6 +26,27 @@ get_filename() const {
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
// Access: Public

View File

@ -23,6 +23,7 @@
#include "datagramIterator.h"
#include "bamReaderParam.h"
#include "bamEndian.h"
#include "loaderOptions.h"
#include "factory.h"
#include "vector_int.h"
#include "pset.h"
@ -99,6 +100,9 @@ public:
AuxData *get_aux_data(TypedWritable *obj, const string &name) 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();
INLINE bool is_eof() const;
@ -185,9 +189,11 @@ private:
typedef phash_map<int, TypeHandle, int_hash> IndexMap;
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;
LoaderOptions _loader_options;
// This maps the object ID numbers encountered within the Bam file
// to the actual pointers of the corresponding generated objects.
class CreatedObj {

View File

@ -126,6 +126,26 @@ ConfigVariableDouble sleep_precision
"timeout of 1.0 seconds, we can expect to actually sleep for "
"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
// Description: Initializes the library. This must be called at

View File

@ -53,11 +53,10 @@ EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_sound_path();
EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_plugin_path();
END_PUBLISH
extern ConfigVariableDouble clock_frame_rate;
extern ConfigVariableDouble clock_degrade_factor;
extern ConfigVariableDouble max_dt;
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();

View File

@ -19,8 +19,8 @@
// Description:
////////////////////////////////////////////////////////////////////
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::
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::
operator = (const LoaderOptions &copy) {
_flags = copy._flags;
_texture_flags = copy._texture_flags;
}
////////////////////////////////////////////////////////////////////
@ -64,3 +66,23 @@ INLINE int LoaderOptions::
get_flags() const {
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;
}

View File

@ -13,8 +13,26 @@
////////////////////////////////////////////////////////////////////
#include "loaderOptions.h"
#include "config_util.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
// Access: Published
@ -23,6 +41,7 @@
void LoaderOptions::
output(ostream &out) const {
out << "LoaderOptions(";
string sep = "";
write_flag(out, sep, "LF_search", LF_search);
write_flag(out, sep, "LF_report_errors", LF_report_errors);
@ -41,6 +60,16 @@ output(ostream &out) const {
if (sep.empty()) {
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 << ")";
}
@ -57,3 +86,17 @@ write_flag(ostream &out, string &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 = " | ";
}
}

View File

@ -22,10 +22,9 @@
// Description : Specifies parameters that may be passed to the
// loader.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH LoaderOptions {
class EXPCL_PANDA_PUTIL LoaderOptions {
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 {
LF_search = 0x0001,
LF_report_errors = 0x0002,
@ -39,19 +38,32 @@ PUBLISHED:
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 void operator = (const LoaderOptions &copy);
INLINE void set_flags(int flags);
INLINE int get_flags() const;
INLINE void set_texture_flags(int flags);
INLINE int get_texture_flags() const;
void output(ostream &out) const;
private:
void write_flag(ostream &out, string &sep,
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 _texture_flags;
};
INLINE ostream &operator << (ostream &out, const LoaderOptions &opts) {

View File

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

View File

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