Support .ktx textures, ETC1/ETC2/EAC compression

This commit is contained in:
rdb 2016-07-15 11:47:49 +02:00
parent a4554a7dfe
commit 400bc2cc26
9 changed files with 1293 additions and 34 deletions

View File

@ -602,16 +602,10 @@ load_model(const NodePath &parent, Filename filename) {
if (model_type == (LoaderFileType *)NULL) {
// The extension isn't a known model file type; is it a known image file
// extension?
if (extension == "txo" || downcase(extension) == "dds") {
// A texture object. Not exactly an image, but certainly a texture.
TexturePool *texture_pool = TexturePool::get_global_ptr();
if (texture_pool->get_texture_type(extension) != NULL) {
// It is a known image file extension.
is_image = true;
} else {
TexturePool *texture_pool = TexturePool::get_global_ptr();
if (texture_pool->get_texture_type(extension) != NULL) {
// It is a known image file extension.
is_image = true;
}
}
}
}

View File

@ -231,6 +231,16 @@ typedef char GLchar;
#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
#define GL_COMPRESSED_R11_EAC 0x9270
#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
#define GL_COMPRESSED_RG11_EAC 0x9272
#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
#define GL_COMPRESSED_RGB8_ETC2 0x9274
#define GL_COMPRESSED_SRGB8_ETC2 0x9275
#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
#undef SUPPORT_IMMEDIATE_MODE
#define APIENTRY

View File

@ -132,6 +132,17 @@
#define GL_DEBUG_SEVERITY_LOW 0x9148
#define GL_DEBUG_OUTPUT 0x92E0
#define GL_COMPRESSED_R11_EAC 0x9270
#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
#define GL_COMPRESSED_RG11_EAC 0x9272
#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
#define GL_COMPRESSED_RGB8_ETC2 0x9274
#define GL_COMPRESSED_SRGB8_ETC2 0x9275
#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
#undef SUPPORT_IMMEDIATE_MODE
#define APIENTRY
#define APIENTRYP *

View File

@ -1053,6 +1053,24 @@ reset() {
break;
#endif
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
_compressed_texture_formats.set_bit(Texture::CM_eac);
break;
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
_compressed_texture_formats.set_bit(Texture::CM_etc1);
_compressed_texture_formats.set_bit(Texture::CM_etc2);
break;
#ifdef OPENGLES
case GL_ETC1_RGB8_OES:
_compressed_texture_formats.set_bit(Texture::CM_etc1);
break;
#endif
default:
break;
}
@ -8066,6 +8084,12 @@ get_texture_target(Texture::TextureType texture_type) const {
return GL_TEXTURE_1D;
#endif
case Texture::TT_1d_texture_array:
// There are no 1D array textures in OpenGL ES. Fall back to 2D textures.
#ifndef OPENGLES
return GL_TEXTURE_1D_ARRAY;
#endif
case Texture::TT_2d_texture:
return GL_TEXTURE_2D;
@ -8282,6 +8306,11 @@ get_component_type(Texture::ComponentType component_type) {
return GL_HALF_FLOAT;
#endif
#ifndef OPENGLES_1
case Texture::T_unsigned_int:
return GL_UNSIGNED_INT;
#endif
default:
GLCAT.error() << "Invalid Texture::Type value!\n";
return GL_UNSIGNED_BYTE;
@ -8444,9 +8473,9 @@ get_external_image_format(Texture *tex) const {
case Texture::CM_rgtc:
#ifndef OPENGLES
if (tex->get_format() == Texture::F_luminance) {
if (format == Texture::F_luminance) {
return GL_COMPRESSED_LUMINANCE_LATC1_EXT;
} else if (tex->get_format() == Texture::F_luminance_alpha) {
} else if (format == Texture::F_luminance_alpha) {
return GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
} else if (tex->get_num_components() == 1) {
return GL_COMPRESSED_RED_RGTC1;
@ -8456,6 +8485,41 @@ get_external_image_format(Texture *tex) const {
#endif
break;
case Texture::CM_etc1:
#ifdef OPENGLES
return GL_ETC1_RGB8_OES;
#endif
// Fall through - ETC2 is backward compatible
case Texture::CM_etc2:
if (format == Texture::F_rgbm) {
return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
} else if (format == Texture::F_srgb_alpha) {
return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
} else if (format == Texture::F_srgb) {
return GL_COMPRESSED_SRGB8_ETC2;
} else if (Texture::has_alpha(format)) {
return GL_COMPRESSED_RGBA8_ETC2_EAC;
} else {
return GL_COMPRESSED_RGB8_ETC2;
}
break;
case Texture::CM_eac:
if (Texture::is_unsigned(tex->get_component_type())) {
if (tex->get_num_components() == 1) {
return GL_COMPRESSED_R11_EAC;
} else {
return GL_COMPRESSED_RG11_EAC;
}
} else {
if (tex->get_num_components() == 1) {
return GL_COMPRESSED_SIGNED_R11_EAC;
} else {
return GL_COMPRESSED_SIGNED_RG11_EAC;
}
}
break;
case Texture::CM_default:
case Texture::CM_off:
case Texture::CM_dxt2:
@ -8565,7 +8629,7 @@ get_external_image_format(Texture *tex) const {
}
GLCAT.error()
<< "Invalid Texture::Format value in get_external_image_format(): "
<< tex->get_format() << "\n";
<< format << "\n";
return GL_RGB;
}
@ -8615,10 +8679,14 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
break;
case Texture::F_rgbm:
case Texture::F_rgba5:
case Texture::F_rgb10_a2:
if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
}
if (get_supports_compressed_texture_format(Texture::CM_etc2) && !is_3d) {
return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
}
#ifndef OPENGLES
if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
return GL_COMPRESSED_RGBA_FXT1_3DFX;
@ -8633,6 +8701,9 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
}
#endif
if (get_supports_compressed_texture_format(Texture::CM_etc2) && !is_3d) {
return GL_COMPRESSED_RGBA8_ETC2_EAC;
}
#ifndef OPENGLES
if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
return GL_COMPRESSED_RGBA_FXT1_3DFX;
@ -8651,6 +8722,9 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
#endif
if (get_supports_compressed_texture_format(Texture::CM_etc2) && !is_3d) {
return GL_COMPRESSED_RGBA8_ETC2_EAC;
}
#ifndef OPENGLES
if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
return GL_COMPRESSED_RGBA_FXT1_3DFX;
@ -8661,7 +8735,6 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
case Texture::F_rgb:
case Texture::F_rgb5:
case Texture::F_rgba5:
case Texture::F_rgb8:
case Texture::F_rgb12:
case Texture::F_rgb332:
@ -8670,7 +8743,14 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
}
#ifndef OPENGLES
if (get_supports_compressed_texture_format(Texture::CM_etc2) && !is_3d) {
return GL_COMPRESSED_RGB8_ETC2;
}
#ifdef OPENGLES
if (get_supports_compressed_texture_format(Texture::CM_etc1) && !is_3d) {
return GL_ETC1_RGB8_OES;
}
#else
if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
return GL_COMPRESSED_RGB_FXT1_3DFX;
}
@ -8702,6 +8782,13 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
return GL_COMPRESSED_RED_RGTC1;
}
#endif
if (get_supports_compressed_texture_format(Texture::CM_eac) && !is_3d) {
if (Texture::is_unsigned(tex->get_component_type())) {
return GL_COMPRESSED_R11_EAC;
} else {
return GL_COMPRESSED_SIGNED_R11_EAC;
}
}
if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
}
@ -8721,6 +8808,13 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
return GL_COMPRESSED_RG_RGTC2;
}
#endif
if (get_supports_compressed_texture_format(Texture::CM_eac) && !is_3d) {
if (Texture::is_unsigned(tex->get_component_type())) {
return GL_COMPRESSED_RG11_EAC;
} else {
return GL_COMPRESSED_SIGNED_RG11_EAC;
}
}
if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
}
@ -8764,12 +8858,18 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
}
if (get_supports_compressed_texture_format(Texture::CM_etc2) && !is_3d) {
return GL_COMPRESSED_SRGB8_ETC2;
}
return GL_COMPRESSED_SRGB;
case Texture::F_srgb_alpha:
if (get_supports_compressed_texture_format(Texture::CM_dxt5) && !is_3d) {
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
}
if (get_supports_compressed_texture_format(Texture::CM_etc2) && !is_3d) {
return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
}
return GL_COMPRESSED_SRGB_ALPHA;
case Texture::F_sluminance:
@ -8855,9 +8955,9 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
case Texture::CM_rgtc:
#ifndef OPENGLES
if (tex->get_format() == Texture::F_luminance) {
if (format == Texture::F_luminance) {
return GL_COMPRESSED_LUMINANCE_LATC1_EXT;
} else if (tex->get_format() == Texture::F_luminance_alpha) {
} else if (format == Texture::F_luminance_alpha) {
return GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
} else if (tex->get_num_components() == 1) {
return GL_COMPRESSED_RED_RGTC1;
@ -8867,6 +8967,41 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
#endif
break;
case Texture::CM_etc1:
#ifdef OPENGLES
return GL_ETC1_RGB8_OES;
#endif
// Fall through - ETC2 is backward compatible
case Texture::CM_etc2:
if (format == Texture::F_rgbm) {
return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
} else if (format == Texture::F_srgb_alpha) {
return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
} else if (format == Texture::F_srgb) {
return GL_COMPRESSED_SRGB8_ETC2;
} else if (Texture::has_alpha(format)) {
return GL_COMPRESSED_RGBA8_ETC2_EAC;
} else {
return GL_COMPRESSED_RGB8_ETC2;
}
break;
case Texture::CM_eac:
if (Texture::is_unsigned(tex->get_component_type())) {
if (tex->get_num_components() == 1) {
return GL_COMPRESSED_R11_EAC;
} else {
return GL_COMPRESSED_RG11_EAC;
}
} else {
if (tex->get_num_components() == 1) {
return GL_COMPRESSED_SIGNED_R11_EAC;
} else {
return GL_COMPRESSED_SIGNED_RG11_EAC;
}
}
break;
case Texture::CM_default:
case Texture::CM_off:
case Texture::CM_dxt2:
@ -9197,7 +9332,7 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
default:
GLCAT.error()
<< "Invalid image format in get_internal_image_format(): "
<< (int)tex->get_format() << "\n";
<< (int)format << "\n";
return force_sized ? GL_RGB8 : GL_RGB;
}
}
@ -11661,6 +11796,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
break;
case Texture::TT_2d_texture:
case Texture::TT_cube_map:
case Texture::TT_1d_texture_array:
_glTexStorage2D(target, num_levels, internal_format, width, height);
break;
case Texture::TT_3d_texture:
@ -12119,6 +12255,14 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
// fill it in with the correct clear color, which we can then
// upload.
ptimage = tex->make_ram_mipmap_image(n);
} else if (image_compression != Texture::CM_off) {
// We can't upload a NULL compressed texture.
if (_supports_texture_max_level) {
// Tell the GL we have no more mipmaps for it to use.
glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias);
}
break;
}
}
image_ptr = ptimage;

View File

@ -1296,12 +1296,15 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
case GL_SAMPLER_2D_ARRAY_SHADOW:
#ifndef OPENGLES
case GL_INT_SAMPLER_1D:
case GL_INT_SAMPLER_1D_ARRAY:
case GL_INT_SAMPLER_BUFFER:
case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_1D:
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
case GL_SAMPLER_1D:
case GL_SAMPLER_1D_ARRAY:
case GL_SAMPLER_1D_SHADOW:
case GL_SAMPLER_BUFFER:
case GL_SAMPLER_CUBE_MAP_ARRAY:
@ -1597,6 +1600,12 @@ get_sampler_texture_type(int &out, GLenum param_type) {
case GL_SAMPLER_1D:
out = Texture::TT_1d_texture;
return true;
case GL_INT_SAMPLER_1D_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
case GL_SAMPLER_1D_ARRAY:
out = Texture::TT_1d_texture_array;
return true;
#endif
case GL_INT_SAMPLER_2D:

View File

@ -2318,8 +2318,8 @@ get_unsigned_short(const unsigned char *&p) {
}
/**
* Returns true if the indicated filename ends in .txo or .txo.pz, false
* otherwise.
* Returns true if the indicated filename ends in .txo or .txo.pz or .txo.gz,
* false otherwise.
*/
INLINE bool Texture::
is_txo_filename(const Filename &fullpath) {
@ -2333,8 +2333,8 @@ is_txo_filename(const Filename &fullpath) {
}
/**
* Returns true if the indicated filename ends in .dds or .dds.pz, false
* otherwise.
* Returns true if the indicated filename ends in .dds or .dds.pz or .dds.gz,
* false otherwise.
*/
INLINE bool Texture::
is_dds_filename(const Filename &fullpath) {
@ -2347,6 +2347,21 @@ is_dds_filename(const Filename &fullpath) {
return (downcase(extension) == "dds");
}
/**
* Returns true if the indicated filename ends in .ktx or .ktx.pz or .ktx.gz,
* false otherwise.
*/
INLINE bool Texture::
is_ktx_filename(const Filename &fullpath) {
string extension = fullpath.get_extension();
#ifdef HAVE_ZLIB
if (extension == "pz" || extension == "gz") {
extension = Filename(fullpath.get_basename_wo_extension()).get_extension();
}
#endif // HAVE_ZLIB
return (downcase(extension) == "ktx");
}
/**
*
*/

File diff suppressed because it is too large Load Diff

View File

@ -79,6 +79,7 @@ PUBLISHED:
TT_cube_map,
TT_buffer_texture,
TT_cube_map_array,
TT_1d_texture_array,
};
enum ComponentType {
@ -90,6 +91,7 @@ PUBLISHED:
T_byte,
T_short,
T_half_float,
T_unsigned_int,
};
enum Format {
@ -206,6 +208,9 @@ PUBLISHED:
CM_pvr1_2bpp,
CM_pvr1_4bpp,
CM_rgtc, // BC4/BC5: 1 or 2 channels, individually compressed.
CM_etc1,
CM_etc2,
CM_eac, // EAC: 1 or 2 channels.
};
enum QualityLevel {
@ -284,6 +289,7 @@ PUBLISHED:
BLOCKING static PT(Texture) make_from_txo(istream &in, const string &filename = "");
BLOCKING bool write_txo(ostream &out, const string &filename = "") const;
BLOCKING bool read_dds(istream &in, const string &filename = "", bool header_only = false);
BLOCKING bool read_ktx(istream &in, const string &filename = "", bool header_only = false);
BLOCKING INLINE bool load(const PNMImage &pnmimage, const LoaderOptions &options = LoaderOptions());
BLOCKING INLINE bool load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options = LoaderOptions());
@ -657,6 +663,8 @@ protected:
bool do_read_txo(CData *cdata, istream &in, const string &filename);
bool do_read_dds_file(CData *cdata, const Filename &fullpath, bool header_only);
bool do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only);
bool do_read_ktx_file(CData *cdata, const Filename &fullpath, bool header_only);
bool do_read_ktx(CData *cdata, istream &in, const string &filename, bool header_only);
bool do_write(CData *cdata, const Filename &fullpath, int z, int n,
bool write_pages, bool write_mipmaps);
@ -840,6 +848,7 @@ private:
INLINE static bool is_txo_filename(const Filename &fullpath);
INLINE static bool is_dds_filename(const Filename &fullpath);
INLINE static bool is_ktx_filename(const Filename &fullpath);
void do_filter_2d_mipmap_pages(const CData *cdata,
RamImage &to, const RamImage &from,

View File

@ -90,7 +90,7 @@ get_texture_type(const string &extension) const {
// Check the PNM type registry.
PNMFileTypeRegistry *pnm_reg = PNMFileTypeRegistry::get_global_ptr();
PNMFileType *type = pnm_reg->get_type_from_extension(c);
if (type != (PNMFileType *)NULL) {
if (type != (PNMFileType *)NULL || c == "txo" || c == "dds" || c == "ktx") {
// This is a known image type; create an ordinary Texture.
((TexturePool *)this)->_type_registry[c] = Texture::make_texture;
return Texture::make_texture;
@ -109,6 +109,11 @@ void TexturePool::
write_texture_types(ostream &out, int indent_level) const {
MutexHolder holder(_lock);
// These are supported out of the box.
indent(out, indent_level) << "Texture Object .txo\n";
indent(out, indent_level) << "DirectDraw Surface .dds\n";
indent(out, indent_level) << "Khronos Texture .ktx\n";
PNMFileTypeRegistry *pnm_reg = PNMFileTypeRegistry::get_global_ptr();
pnm_reg->write(out, indent_level);