diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 260d1e1ced..efee35c04c 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -96,6 +96,7 @@ #include "uvScrollNode.h" #include "textureStagePool.h" #include "cmath.h" +#include "loaderOptions.h" #include #include @@ -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; } /** diff --git a/panda/src/egg2pg/eggLoader.h b/panda/src/egg2pg/eggLoader.h index ab11214e19..c6437a1674 100644 --- a/panda/src/egg2pg/eggLoader.h +++ b/panda/src/egg2pg/eggLoader.h @@ -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); diff --git a/panda/src/gobj/samplerState.h b/panda/src/gobj/samplerState.h index c161d48206..d15aa5758f 100644 --- a/panda/src/gobj/samplerState.h +++ b/panda/src/gobj/samplerState.h @@ -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; diff --git a/panda/src/gobj/texturePool.I b/panda/src/gobj/texturePool.I index 2cbb7da4b7..02e26ac58c 100644 --- a/panda/src/gobj/texturePool.I +++ b/panda/src/gobj/texturePool.I @@ -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; } diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index 755f937c67..5a636c7c18 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -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(). */ diff --git a/panda/src/gobj/texturePool.h b/panda/src/gobj/texturePool.h index aa4c8f83c1..94261fb323 100644 --- a/panda/src/gobj/texturePool.h +++ b/panda/src/gobj/texturePool.h @@ -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 Textures; Textures _textures; typedef pmap RelpathLookup; diff --git a/panda/src/putil/loaderOptions.I b/panda/src/putil/loaderOptions.I index 6e407e7840..4fc745a12a 100644 --- a/panda/src/putil/loaderOptions.I +++ b/panda/src/putil/loaderOptions.I @@ -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 diff --git a/panda/src/putil/loaderOptions.cxx b/panda/src/putil/loaderOptions.cxx index a52e407134..adaa6783dd 100644 --- a/panda/src/putil/loaderOptions.cxx +++ b/panda/src/putil/loaderOptions.cxx @@ -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) { diff --git a/panda/src/putil/loaderOptions.h b/panda/src/putil/loaderOptions.h index 826f5d072e..a8e39e0066 100644 --- a/panda/src/putil/loaderOptions.h +++ b/panda/src/putil/loaderOptions.h @@ -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; };