gobj: Fix TexturePool sharing texture objects when loaded with different properties

Fixes #1047
Closes #1105

Co-authored-by: rdb <git@rdb.name>
This commit is contained in:
Timothy Paustian 2023-02-07 12:23:30 +01:00 committed by rdb
parent 3f3c65917b
commit 4fa90bd754
9 changed files with 417 additions and 213 deletions

View File

@ -96,6 +96,7 @@
#include "uvScrollNode.h"
#include "textureStagePool.h"
#include "cmath.h"
#include "loaderOptions.h"
#include <ctype.h>
#include <algorithm>
@ -879,6 +880,7 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
// Check to see if we should reduce the number of channels in the texture.
int wanted_channels = 0;
bool wanted_alpha = false;
switch (egg_tex->get_format()) {
case EggTexture::F_red:
case EggTexture::F_green:
@ -932,6 +934,7 @@ 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);
}
@ -963,6 +966,15 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_allow_compression);
}
if (egg_force_srgb_textures) {
options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_force_srgb);
}
//The following code sets up all the options for the textures
//so that they can be differentiated later in texturePool
SamplerState sampler;
set_up_loader_options(egg_tex, options, sampler);
PT(Texture) tex;
switch (egg_tex->get_texture_type()) {
case EggTexture::TT_unspecified:
@ -976,22 +988,26 @@ 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(), options);
egg_tex->get_read_mipmaps(),
options, sampler);
} else {
tex = TexturePool::load_texture(egg_tex->get_fullpath(),
wanted_channels,
egg_tex->get_read_mipmaps(), options);
egg_tex->get_read_mipmaps(),
options, sampler);
}
break;
case EggTexture::TT_3d_texture:
tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
egg_tex->get_read_mipmaps(), options);
egg_tex->get_read_mipmaps(),
options, sampler);
break;
case EggTexture::TT_cube_map:
tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
egg_tex->get_read_mipmaps(), options);
egg_tex->get_read_mipmaps(),
options, sampler);
break;
}
@ -1030,8 +1046,7 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
egg_tex->set_anisotropic_degree(aux_egg_tex->get_anisotropic_degree());
}
}
apply_texture_attributes(tex, egg_tex);
check_texture_attributes(tex, sampler, egg_tex);
// Make a texture stage for the texture.
PT(TextureStage) stage = make_texture_stage(egg_tex);
@ -1042,18 +1057,26 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
return true;
}
/**
*
* Populate the loader options for the incoming texture. These are applied to
* the texture and also used to search for the texture. Textures are stored in
* texturePool in _textures a map object
*/
void EggLoader::
apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
if (egg_tex->get_compression_mode() != EggTexture::CM_default) {
tex->set_compression(convert_compression_mode(egg_tex->get_compression_mode()));
}
SamplerState sampler;
set_up_loader_options(EggTexture *egg_tex, LoaderOptions &options, SamplerState &sampler) {
//We store these options and Texture enums, so we need to convert them.
options.set_texture_format(convert_format(egg_tex->get_format(), egg_tex->get_env_type()));
options.set_texture_compression(convert_compression_mode(egg_tex->get_compression_mode()));
options.set_texture_quality(convert_quality_level(egg_tex->get_quality_level()));
set_up_sampler(sampler, egg_tex);
}
/**
* Set up the sampler object that will be stored in the texture pool. Samplers
* store the wrap mode, the min and mag filters, and anisotropic degree
*/
void EggLoader::
set_up_sampler(SamplerState &sampler, const EggTexture *egg_tex) {
EggTexture::WrapMode wrap_u = egg_tex->determine_wrap_u();
EggTexture::WrapMode wrap_v = egg_tex->determine_wrap_v();
EggTexture::WrapMode wrap_w = egg_tex->determine_wrap_w();
@ -1185,12 +1208,109 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
if (egg_tex->has_lod_bias()) {
sampler.set_lod_bias(egg_tex->get_lod_bias());
}
}
tex->set_default_sampler(sampler);
/**
* Now that the texture is fully loaded determine whether there are any
* inconsistencies in the texture vs the attributes.
*/
void EggLoader::
check_texture_attributes(Texture *tex, SamplerState sampler, const EggTexture *egg_tex) {
switch (tex->get_num_components()) {
case 1:
switch (egg_tex->get_format()) {
case EggTexture::F_unspecified:
case EggTexture::F_red:
case EggTexture::F_green:
case EggTexture::F_blue:
case EggTexture::F_alpha:
case EggTexture::F_luminance:
break;
default:
egg2pg_cat.warning()
<< "Inappropriate format " << egg_tex->get_format()
<< " for 1-component texture " << egg_tex->get_name() << "\n";
}
break;
case 2:
switch (egg_tex->get_format()) {
case EggTexture::F_unspecified:
case EggTexture::F_luminance_alpha:
case EggTexture::F_luminance_alphamask:
break;
default:
egg2pg_cat.error()
<< "Inappropriate format " << egg_tex->get_format()
<< " for 2-component texture " << egg_tex->get_name() << "\n";
}
break;
case 3:
// We'll quietly accept RGBA8 for a 3-component texture, since flt2egg
// generates these for 3-component as well as for 4-component textures.
switch (egg_tex->get_format()) {
case EggTexture::F_unspecified:
case EggTexture::F_rgb:
case EggTexture::F_rgb8:
case EggTexture::F_rgba8:
case EggTexture::F_rgb5:
case EggTexture::F_rgb332:
case EggTexture::F_srgb:
case EggTexture::F_srgb_alpha:
break;
case EggTexture::F_rgb12:
if (!egg_force_srgb_textures && tex->get_component_width() < 2) {
egg2pg_cat.error()
<< "Inappropriate format " << egg_tex->get_format()
<< " for 8-bit texture " << egg_tex->get_name() << "\n";
}
break;
default:
egg2pg_cat.error()
<< "Inappropriate format " << egg_tex->get_format()
<< " for 3-component texture " << egg_tex->get_name() << "\n";
}
break;
case 4:
switch (egg_tex->get_format()) {
case EggTexture::F_unspecified:
case EggTexture::F_rgba:
case EggTexture::F_rgbm:
case EggTexture::F_rgba8:
case EggTexture::F_rgba4:
case EggTexture::F_rgba5:
case EggTexture::F_srgb_alpha:
break;
case EggTexture::F_rgba12:
if (!egg_force_srgb_textures || tex->get_component_width() < 2) {
egg2pg_cat.warning()
<< "Inappropriate format " << egg_tex->get_format()
<< " for 8-bit texture " << egg_tex->get_name() << "\n";
}
break;
default:
egg2pg_cat.error()
<< "Inappropriate format " << egg_tex->get_format()
<< " for 4-component texture " << egg_tex->get_name() << "\n";
}
break;
default:
break;
}
}
/**
* Returns the Texture::Format enum corresponding to the EggTexture::Format.
* Returns 0 if the compression mode is unspecified.
*/
Texture::Format EggLoader::
convert_format(EggTexture::Format format, EggTexture::EnvType env) {
bool force_srgb = false;
if (egg_force_srgb_textures) {
switch (egg_tex->get_env_type()) {
switch (env) {
case EggTexture::ET_unspecified:
case EggTexture::ET_modulate:
case EggTexture::ET_decal:
@ -1201,186 +1321,103 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
case EggTexture::ET_modulate_glow:
case EggTexture::ET_modulate_gloss:
force_srgb = true;
if (egg2pg_cat.is_debug()) {
egg2pg_cat.debug()
<< "Enabling sRGB format on texture " << egg_tex->get_name() << "\n";
}
break;
default:
break;
}
}
if (tex->get_num_components() == 1) {
switch (egg_tex->get_format()) {
case EggTexture::F_red:
tex->set_format(Texture::F_red);
break;
case EggTexture::F_green:
tex->set_format(Texture::F_green);
break;
case EggTexture::F_blue:
tex->set_format(Texture::F_blue);
break;
case EggTexture::F_alpha:
tex->set_format(Texture::F_alpha);
break;
case EggTexture::F_luminance:
tex->set_format(force_srgb ? Texture::F_sluminance : Texture::F_luminance);
break;
switch (format) {
case EggTexture::F_unspecified:
// Gets handled in TexturePool
return (Texture::Format)0;
default:
egg2pg_cat.warning()
<< "Ignoring inappropriate format " << egg_tex->get_format()
<< " for 1-component texture " << egg_tex->get_name() << "\n";
case EggTexture::F_red:
return Texture::F_red;
case EggTexture::F_unspecified:
if (force_srgb) {
tex->set_format(Texture::F_sluminance);
}
break;
}
case EggTexture::F_green:
return Texture::F_green;
} else if (tex->get_num_components() == 2) {
switch (egg_tex->get_format()) {
case EggTexture::F_luminance_alpha:
tex->set_format(force_srgb ? Texture::F_sluminance_alpha : Texture::F_luminance_alpha);
break;
case EggTexture::F_blue:
return Texture::F_blue;
case EggTexture::F_luminance_alphamask:
tex->set_format(force_srgb ? Texture::F_sluminance_alpha : Texture::F_luminance_alphamask);
break;
case EggTexture::F_alpha:
return Texture::F_alpha;
default:
egg2pg_cat.warning()
<< "Ignoring inappropriate format " << egg_tex->get_format()
<< " for 2-component texture " << egg_tex->get_name() << "\n";
case EggTexture::F_luminance:
return (force_srgb ? Texture::F_sluminance : Texture::F_luminance);
case EggTexture::F_unspecified:
if (force_srgb) {
tex->set_format(Texture::F_sluminance_alpha);
}
break;
}
case EggTexture::F_rgba:
return (force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba);
} else if (tex->get_num_components() == 3) {
switch (egg_tex->get_format()) {
case EggTexture::F_rgb:
tex->set_format(force_srgb ? Texture::F_srgb : Texture::F_rgb);
break;
case EggTexture::F_rgb12:
if (force_srgb) {
tex->set_format(Texture::F_srgb);
} else if (tex->get_component_width() >= 2) {
// Only do this if the component width supports it.
tex->set_format(Texture::F_rgb12);
} else {
egg2pg_cat.warning()
<< "Ignoring inappropriate format " << egg_tex->get_format()
<< " for 8-bit texture " << egg_tex->get_name() << "\n";
}
break;
case EggTexture::F_rgb8:
case EggTexture::F_rgba8:
// We'll quietly accept RGBA8 for a 3-component texture, since flt2egg
// generates these for 3-component as well as for 4-component textures.
tex->set_format(force_srgb ? Texture::F_srgb : Texture::F_rgb8);
break;
case EggTexture::F_rgb5:
tex->set_format(force_srgb ? Texture::F_srgb : Texture::F_rgb5);
break;
case EggTexture::F_rgb332:
tex->set_format(force_srgb ? Texture::F_srgb : Texture::F_rgb332);
break;
case EggTexture::F_srgb:
case EggTexture::F_srgb_alpha:
tex->set_format(Texture::F_srgb);
break;
case EggTexture::F_rgbm:
return (force_srgb ? Texture::F_srgb_alpha : Texture::F_rgbm);
default:
egg2pg_cat.warning()
<< "Ignoring inappropriate format " << egg_tex->get_format()
<< " for 3-component texture " << egg_tex->get_name() << "\n";
case EggTexture::F_rgba12:
return (force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba12);
case EggTexture::F_unspecified:
if (force_srgb) {
tex->set_format(Texture::F_srgb);
}
break;
}
case EggTexture::F_rgba8:
return (force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba8);
} else if (tex->get_num_components() == 4) {
switch (egg_tex->get_format()) {
case EggTexture::F_rgba:
tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba);
break;
case EggTexture::F_rgbm:
tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgbm);
break;
case EggTexture::F_rgba12:
if (force_srgb) {
tex->set_format(Texture::F_srgb_alpha);
} else if (tex->get_component_width() >= 2) {
// Only do this if the component width supports it.
tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba12);
} else {
egg2pg_cat.warning()
<< "Ignoring inappropriate format " << egg_tex->get_format()
<< " for 8-bit texture " << egg_tex->get_name() << "\n";
}
break;
case EggTexture::F_rgba8:
tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba8);
break;
case EggTexture::F_rgba4:
tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba4);
break;
case EggTexture::F_rgba5:
tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba5);
break;
case EggTexture::F_srgb_alpha:
tex->set_format(Texture::F_srgb_alpha);
break;
case EggTexture::F_rgba4:
return (force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba4);
default:
egg2pg_cat.warning()
<< "Ignoring inappropriate format " << egg_tex->get_format()
<< " for 4-component texture " << egg_tex->get_name() << "\n";
case EggTexture::F_rgba5:
return (force_srgb ? Texture::F_srgb : Texture::F_rgba5);
case EggTexture::F_unspecified:
if (force_srgb) {
tex->set_format(Texture::F_srgb_alpha);
}
break;
}
case EggTexture::F_rgb:
return (force_srgb ? Texture::F_srgb : Texture::F_rgb);
case EggTexture::F_rgb12:
return (force_srgb ? Texture::F_srgb : Texture::F_rgb12);
case EggTexture::F_rgb8:
return (force_srgb ? Texture::F_srgb : Texture::F_rgb8);
case EggTexture::F_rgb5:
return (force_srgb ? Texture::F_srgb : Texture::F_rgb5);
case EggTexture::F_rgb332:
return (force_srgb ? Texture::F_srgb : Texture::F_rgb332);
case EggTexture::F_luminance_alpha:
return (force_srgb ? Texture::F_sluminance_alpha : Texture::F_luminance_alpha);
case EggTexture::F_luminance_alphamask:
return (force_srgb ? Texture::F_sluminance_alpha : Texture::F_luminance_alphamask);
case EggTexture::F_srgb:
return Texture::F_srgb;
case EggTexture::F_srgb_alpha:
return Texture::F_srgb_alpha;
}
if (force_srgb && tex->get_format() != Texture::F_alpha &&
!Texture::is_srgb(tex->get_format())) {
egg2pg_cat.warning()
<< "Unable to enable sRGB format on texture " << egg_tex->get_name()
<< " with specified format " << egg_tex->get_format() << "\n";
}
egg2pg_cat.warning()
<< "Unexpected format scalar: " << (int)format << "\n";
return (Texture::Format)0;
}
switch (egg_tex->get_quality_level()) {
/**
* Returns the Texture::QualityLevel enum corresponding to the
* EggTexture::QualityLevel. Returns QL_default if the quality level is
* unspecified.
*/
Texture::QualityLevel EggLoader::
convert_quality_level(EggTexture::QualityLevel quality) {
switch (quality) {
case EggTexture::QL_unspecified:
case EggTexture::QL_default:
tex->set_quality_level(Texture::QL_default);
break;
return Texture::QL_default;
case EggTexture::QL_fastest:
tex->set_quality_level(Texture::QL_fastest);
break;
case EggTexture::QL_normal:
tex->set_quality_level(Texture::QL_normal);
break;
return Texture::QL_fastest;
case EggTexture::QL_best:
tex->set_quality_level(Texture::QL_best);
break;
return Texture::QL_best;
case EggTexture::QL_normal:
return Texture::QL_normal;
}
return Texture::QL_default;
}
/**

View File

@ -118,7 +118,11 @@ private:
void load_textures();
bool load_texture(TextureDef &def, EggTexture *egg_tex);
void apply_texture_attributes(Texture *tex, const EggTexture *egg_tex);
void set_up_loader_options(EggTexture *egg_tex, LoaderOptions &options, SamplerState &sampler);
void set_up_sampler(SamplerState &sampler, const EggTexture *egg_tex);
void check_texture_attributes(Texture *tex, SamplerState sampler, const EggTexture *egg_tex);
Texture::Format convert_format(EggTexture::Format format, EggTexture::EnvType env);
Texture::QualityLevel convert_quality_level(EggTexture::QualityLevel mode);
Texture::CompressionMode convert_compression_mode(EggTexture::CompressionMode compression_mode) const;
SamplerState::WrapMode convert_wrap_mode(EggTexture::WrapMode wrap_mode) const;
PT(TextureStage) make_texture_stage(const EggTexture *egg_tex);

View File

@ -20,9 +20,8 @@
#include "luse.h"
#include "memoryBase.h"
#include "numeric_types.h"
#include "bamReader.h"
#include "config_gobj.h"
class BamReader;
class FactoryParams;
class GraphicsStateGuardianBase;
class PreparedGraphicsObjects;

View File

@ -68,9 +68,9 @@ get_texture(const Filename &filename, const Filename &alpha_filename,
*/
INLINE Texture *TexturePool::
load_texture(const Filename &filename, int primary_file_num_channels,
bool read_mipmaps, const LoaderOptions &options) {
bool read_mipmaps, const LoaderOptions &options, const SamplerState &sampler) {
return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels,
read_mipmaps, options);
read_mipmaps, options, sampler);
}
/**
@ -86,11 +86,11 @@ load_texture(const Filename &filename, int primary_file_num_channels,
INLINE Texture *TexturePool::
load_texture(const Filename &filename, const Filename &alpha_filename,
int primary_file_num_channels, int alpha_file_channel,
bool read_mipmaps, const LoaderOptions &options) {
bool read_mipmaps, const LoaderOptions &options, const SamplerState &sampler) {
return get_global_ptr()->ns_load_texture(filename, alpha_filename,
primary_file_num_channels,
alpha_file_channel,
read_mipmaps, options);
read_mipmaps, options, sampler);
}
/**
@ -105,9 +105,9 @@ load_texture(const Filename &filename, const Filename &alpha_filename,
*/
INLINE Texture *TexturePool::
load_3d_texture(const Filename &filename_pattern, bool read_mipmaps,
const LoaderOptions &options) {
const LoaderOptions &options, const SamplerState &sampler) {
return get_global_ptr()->ns_load_3d_texture(filename_pattern, read_mipmaps,
options);
options, sampler);
}
/**
@ -122,9 +122,9 @@ load_3d_texture(const Filename &filename_pattern, bool read_mipmaps,
*/
INLINE Texture *TexturePool::
load_2d_texture_array(const Filename &filename_pattern, bool read_mipmaps,
const LoaderOptions &options) {
const LoaderOptions &options, const SamplerState &sampler) {
return get_global_ptr()->ns_load_2d_texture_array(filename_pattern, read_mipmaps,
options);
options, sampler);
}
/**
@ -139,9 +139,9 @@ load_2d_texture_array(const Filename &filename_pattern, bool read_mipmaps,
*/
INLINE Texture *TexturePool::
load_cube_map(const Filename &filename_pattern, bool read_mipmaps,
const LoaderOptions &options) {
const LoaderOptions &options, const SamplerState &sampler) {
return get_global_ptr()->ns_load_cube_map(filename_pattern, read_mipmaps,
options);
options, sampler);
}
/**
@ -333,11 +333,31 @@ unregister_filter(TexturePoolFilter *tex_filter) {
return get_global_ptr()->ns_unregister_filter(tex_filter);
}
/**
*
*/
INLINE TexturePool::LookupKey::
LookupKey(Texture::TextureType texture_type,
int primary_file_num_channels, int alpha_file_channel,
const LoaderOptions &options, const SamplerState &sampler) :
_primary_file_num_channels(primary_file_num_channels),
_alpha_file_channel(alpha_file_channel),
_texture_type(texture_type),
_texture_format((Texture::Format)options.get_texture_format()),
_texture_compress((Texture::CompressionMode)options.get_texture_compression()),
_texture_quality((Texture::QualityLevel)options.get_texture_quality()),
_texture_sampler(sampler),
_force_srgb(options.get_texture_flags() & LoaderOptions::TF_force_srgb) {
}
/**
* Defines relative ordering between LookupKey instances.
*/
INLINE bool TexturePool::LookupKey::
operator < (const LookupKey &other) const {
if (_texture_type != other._texture_type) {
return _texture_type < other._texture_type;
}
if (_fullpath != other._fullpath) {
return _fullpath < other._fullpath;
}
@ -350,5 +370,17 @@ operator < (const LookupKey &other) const {
if (_alpha_file_channel != other._alpha_file_channel) {
return _alpha_file_channel < other._alpha_file_channel;
}
return _texture_type < other._texture_type;
if (_texture_format != other._texture_format) {
return _texture_format < other._texture_format;
}
if (_texture_compress != other._texture_compress) {
return _texture_compress < other._texture_compress;
}
if (_texture_quality != other._texture_quality) {
return _texture_quality < other._texture_quality;
}
if (_texture_sampler != other._texture_sampler) {
return _texture_sampler < other._texture_sampler;
}
return _force_srgb < other._force_srgb;
}

View File

@ -334,9 +334,9 @@ ns_get_texture(const Filename &orig_filename,
*/
Texture *TexturePool::
ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
bool read_mipmaps, const LoaderOptions &options) {
LookupKey key;
key._primary_file_num_channels = primary_file_num_channels;
bool read_mipmaps, const LoaderOptions &options, const SamplerState &sampler) {
LookupKey key(Texture::TT_2d_texture, primary_file_num_channels, 0, options, sampler);
{
MutexHolder holder(_lock);
resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
@ -484,7 +484,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
if (use_filters) {
tex = post_load(tex);
}
apply_texture_attributes(tex, options, sampler);
return tex;
}
@ -496,15 +496,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, const LoaderOptions &options) {
bool read_mipmaps, const LoaderOptions &options, const SamplerState &sampler) {
if (!_fake_texture_image.empty()) {
return ns_load_texture(_fake_texture_image, primary_file_num_channels,
read_mipmaps, options);
read_mipmaps, options, sampler);
}
LookupKey key;
key._primary_file_num_channels = primary_file_num_channels;
key._alpha_file_channel = alpha_file_channel;
LookupKey key(Texture::TT_2d_texture, primary_file_num_channels, alpha_file_channel, options, sampler);
{
MutexHolder holder(_lock);
resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
@ -619,7 +617,7 @@ ns_load_texture(const Filename &orig_filename,
if (use_filters) {
tex = post_load(tex);
}
apply_texture_attributes(tex, options, sampler);
return tex;
}
@ -628,12 +626,11 @@ ns_load_texture(const Filename &orig_filename,
*/
Texture *TexturePool::
ns_load_3d_texture(const Filename &filename_pattern,
bool read_mipmaps, const LoaderOptions &options) {
bool read_mipmaps, const LoaderOptions &options, const SamplerState &sampler) {
Filename orig_filename(filename_pattern);
orig_filename.set_pattern(true);
LookupKey key;
key._texture_type = Texture::TT_3d_texture;
LookupKey key(Texture::TT_3d_texture, 0, 0, options, sampler);
{
MutexHolder holder(_lock);
resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
@ -722,6 +719,7 @@ ns_load_3d_texture(const Filename &filename_pattern,
}
nassertr(!tex->get_fullpath().empty(), tex);
apply_texture_attributes(tex, options, sampler);
return tex;
}
@ -730,12 +728,11 @@ ns_load_3d_texture(const Filename &filename_pattern,
*/
Texture *TexturePool::
ns_load_2d_texture_array(const Filename &filename_pattern,
bool read_mipmaps, const LoaderOptions &options) {
bool read_mipmaps, const LoaderOptions &options, const SamplerState &sampler) {
Filename orig_filename(filename_pattern);
orig_filename.set_pattern(true);
LookupKey key;
key._texture_type = Texture::TT_2d_texture_array;
LookupKey key(Texture::TT_2d_texture_array, 0, 0, options, sampler);
{
MutexHolder holder(_lock);
resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
@ -824,6 +821,7 @@ ns_load_2d_texture_array(const Filename &filename_pattern,
}
nassertr(!tex->get_fullpath().empty(), tex);
apply_texture_attributes(tex, options, sampler);
return tex;
}
@ -832,12 +830,11 @@ ns_load_2d_texture_array(const Filename &filename_pattern,
*/
Texture *TexturePool::
ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps,
const LoaderOptions &options) {
const LoaderOptions &options, const SamplerState &sampler) {
Filename orig_filename(filename_pattern);
orig_filename.set_pattern(true);
LookupKey key;
key._texture_type = Texture::TT_cube_map;
LookupKey key(Texture::TT_cube_map, 0, 0, options, sampler);
{
MutexHolder holder(_lock);
resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
@ -926,6 +923,7 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps,
}
nassertr(!tex->get_fullpath().empty(), tex);
apply_texture_attributes(tex, options, sampler);
return tex;
}
@ -947,6 +945,49 @@ ns_get_normalization_cube_map(int size) {
return _normalization_cube_map;
}
/**
* The texture is loaded, apply any atributes that were sent in with the texture through LoaderOptions
* and Sampler State
*/
void TexturePool::
apply_texture_attributes(Texture *tex, const LoaderOptions &options, const SamplerState &sampler) {
int format = options.get_texture_format();
if (format != 0) {
tex->set_format((Texture::Format)format);
}
else if (options.get_texture_flags() & LoaderOptions::TF_force_srgb) {
int num_components = tex->get_num_components();
if (num_components == 1) {
if (!Texture::has_alpha(tex->get_format())) {
tex->set_format(Texture::F_sluminance);
}
}
else if (num_components == 2 && Texture::has_alpha(tex->get_format())) {
tex->set_format(Texture::F_sluminance_alpha);
}
else if (num_components == 3) {
tex->set_format(Texture::F_srgb);
}
else if (num_components == 4) {
tex->set_format(Texture::F_srgb_alpha);
}
else {
gobj_cat.warning()
<< "Unable to enable sRGB format on texture " << tex->get_name()
<< " with specified format " << tex->get_format() << "\n";
}
}
int compression = options.get_texture_compression();
if (compression != 0) {
tex->set_compression((Texture::CompressionMode)compression);
}
int quality = options.get_texture_quality();
if (quality != 0) {
tex->set_quality_level((Texture::QualityLevel)quality);
}
tex->set_default_sampler(sampler);
}
/**
* The nonstatic implementation of get_alpha_scale_map().
*/

View File

@ -49,22 +49,27 @@ PUBLISHED:
BLOCKING INLINE static Texture *load_texture(const Filename &filename,
int primary_file_num_channels = 0,
bool read_mipmaps = false,
const LoaderOptions &options = LoaderOptions());
const LoaderOptions &options = LoaderOptions(),
const SamplerState &sampler = SamplerState());
BLOCKING INLINE static Texture *load_texture(const Filename &filename,
const Filename &alpha_filename,
int primary_file_num_channels = 0,
int alpha_file_channel = 0,
bool read_mipmaps = false,
const LoaderOptions &options = LoaderOptions());
const LoaderOptions &options = LoaderOptions(),
const SamplerState &sampler = SamplerState());
BLOCKING INLINE static Texture *load_3d_texture(const Filename &filename_pattern,
bool read_mipmaps = false,
const LoaderOptions &options = LoaderOptions());
const LoaderOptions &options = LoaderOptions(),
const SamplerState &sampler = SamplerState());
BLOCKING INLINE static Texture *load_2d_texture_array(const Filename &filename_pattern,
bool read_mipmaps = false,
const LoaderOptions &options = LoaderOptions());
const LoaderOptions &options = LoaderOptions(),
const SamplerState &sampler = SamplerState());
BLOCKING INLINE static Texture *load_cube_map(const Filename &filename_pattern,
bool read_mipmaps = false,
const LoaderOptions &options = LoaderOptions());
const LoaderOptions &options = LoaderOptions(),
const SamplerState &sampler = SamplerState());
INLINE static Texture *get_normalization_cube_map(int size);
INLINE static Texture *get_alpha_scale_map();
@ -128,22 +133,31 @@ private:
Texture *ns_load_texture(const Filename &orig_filename,
int primary_file_num_channels,
bool read_mipmaps,
const LoaderOptions &options);
const LoaderOptions &options,
const SamplerState &sampler);
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,
const LoaderOptions &options);
const LoaderOptions &options,
const SamplerState &sampler);
Texture *ns_load_3d_texture(const Filename &filename_pattern,
bool read_mipmaps,
const LoaderOptions &options);
const LoaderOptions &options,
const SamplerState &sampler);
Texture *ns_load_2d_texture_array(const Filename &filename_pattern,
bool read_mipmaps,
const LoaderOptions &options);
const LoaderOptions &options,
const SamplerState &sampler);
Texture *ns_load_cube_map(const Filename &filename_pattern,
bool read_mipmaps,
const LoaderOptions &options);
const LoaderOptions &options,
const SamplerState &sampler);
void apply_texture_attributes(Texture *tex, const LoaderOptions &options,
const SamplerState &sampler);
Texture *ns_get_normalization_cube_map(int size);
Texture *ns_get_alpha_scale_map();
@ -187,14 +201,25 @@ private:
Mutex _filter_lock;
struct LookupKey {
LookupKey() = default;
INLINE LookupKey(Texture::TextureType texture_type,
int primary_file_num_channels, int alpha_file_channel,
const LoaderOptions &options, const SamplerState &sampler);
Filename _fullpath;
Filename _alpha_fullpath;
int _primary_file_num_channels = 0;
int _alpha_file_channel = 0;
Texture::Format _texture_format = (Texture::Format)0;
Texture::QualityLevel _texture_quality = Texture::QL_default;
Texture::CompressionMode _texture_compress = Texture::CM_default;
SamplerState _texture_sampler;
Texture::TextureType _texture_type = Texture::TT_2d_texture;
bool _force_srgb = false;
INLINE bool operator < (const LookupKey &other) const;
};
typedef pmap<LookupKey, PT(Texture)> Textures;
Textures _textures;
typedef pmap<Filename, Filename> RelpathLookup;

View File

@ -18,6 +18,9 @@ constexpr LoaderOptions::
LoaderOptions(int flags, int texture_flags) :
_flags(flags),
_texture_flags(texture_flags),
_texture_format(0),
_texture_compress(0),
_texture_quality(0),
_texture_num_views(0),
_auto_texture_scale(ATS_unspecified)
{
@ -55,6 +58,55 @@ get_texture_flags() const {
return _texture_flags;
}
/**
* Set the texture format
*/
INLINE void LoaderOptions::
set_texture_format(int format) {
_texture_format = format;
}
/**
* Get the texture format
*/
INLINE int LoaderOptions::
get_texture_format() const {
return _texture_format;
}
/**
* Set the texture compression
*/
INLINE void LoaderOptions::
set_texture_compression(int compress) {
_texture_compress = compress;
}
/**
* Get the texture compression
*/
INLINE int LoaderOptions::
get_texture_compression() const {
return _texture_compress;
}
/**
* Set the texture quality
*/
INLINE void LoaderOptions::
set_texture_quality(int quality) {
_texture_quality = quality;
}
/**
* Get the texture quality
*/
INLINE int LoaderOptions::
get_texture_quality() const {
return _texture_quality;
}
/**
* Specifies the expected number of views to load for the texture. This is
* ignored unless TF_multiview is included in texture_flags. This must be

View File

@ -24,6 +24,9 @@ LoaderOptions::
LoaderOptions(int flags) :
_flags(flags),
_texture_flags(0),
_texture_format(0),
_texture_compress(0),
_texture_quality(0),
_texture_num_views(0),
_auto_texture_scale(ATS_unspecified)
{

View File

@ -47,6 +47,7 @@ PUBLISHED:
TF_float = 0x0100, // Load as a floating-point (depth) texture
TF_allow_compression = 0x0200, // Consider compressing RAM image
TF_no_filters = 0x0400, // disallow using texture pool filters
TF_force_srgb = 0x0800, // Force the texture to have an sRGB format
};
explicit LoaderOptions(int flags = LF_search | LF_report_errors);
@ -58,6 +59,13 @@ PUBLISHED:
INLINE void set_texture_flags(int flags);
INLINE int get_texture_flags() const;
INLINE void set_texture_format(int format);
INLINE int get_texture_format() const;
INLINE void set_texture_compression(int compress);
INLINE int get_texture_compression() const;
INLINE void set_texture_quality(int quality);
INLINE int get_texture_quality() const;
INLINE void set_texture_num_views(int num_views);
INLINE int get_texture_num_views() const;
MAKE_PROPERTY(texture_flags, get_texture_flags, set_texture_flags);
@ -78,6 +86,9 @@ private:
const std::string &flag_name, int flag) const;
int _flags;
int _texture_flags;
int _texture_format;
int _texture_compress;
int _texture_quality;
int _texture_num_views;
AutoTextureScale _auto_texture_scale;
};