mirror of
https://github.com/godotengine/godot.git
synced 2026-01-06 10:11:57 +03:00
Implement basic ASTC support
Implements basic ASTC support: * Only 4x4 and 8x8 block sizes. * Other block sizes are too complex to handle for Godot image compression handling. May be implemented sometime in the future. The need for ASTC is mostly for the following use cases: * Implement a high quality compression option for textures on mobile and M1 Apple hardware. * For this, the 4x4 is sufficient, since it uses the same size as BPTC. ASTC supports a lot of block sizes, but the benefit of supporting most of them is slim, while the implementation complexity in Godot is very high. Supporting only 4x4 (and 8x8) solves the real problem, which is lack of a BPTC alternative on hardware where it's missing. Note: This does not yet support encoding on import, an ASTC encoder will need to be added.
This commit is contained in:
@@ -173,6 +173,14 @@ int Image::get_format_pixel_size(Format p_format) {
|
||||
return 1;
|
||||
case FORMAT_DXT5_RA_AS_RG:
|
||||
return 1;
|
||||
case FORMAT_ASTC_4x4:
|
||||
return 1;
|
||||
case FORMAT_ASTC_4x4_HDR:
|
||||
return 1;
|
||||
case FORMAT_ASTC_8x8:
|
||||
return 1;
|
||||
case FORMAT_ASTC_8x8_HDR:
|
||||
return 1;
|
||||
case FORMAT_MAX: {
|
||||
}
|
||||
}
|
||||
@@ -213,7 +221,18 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
|
||||
r_h = 4;
|
||||
|
||||
} break;
|
||||
case FORMAT_ASTC_4x4:
|
||||
case FORMAT_ASTC_4x4_HDR: {
|
||||
r_w = 4;
|
||||
r_h = 4;
|
||||
|
||||
} break;
|
||||
case FORMAT_ASTC_8x8:
|
||||
case FORMAT_ASTC_8x8_HDR: {
|
||||
r_w = 8;
|
||||
r_h = 8;
|
||||
|
||||
} break;
|
||||
default: {
|
||||
r_w = 1;
|
||||
r_h = 1;
|
||||
@@ -222,7 +241,9 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
|
||||
}
|
||||
|
||||
int Image::get_format_pixel_rshift(Format p_format) {
|
||||
if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
|
||||
if (p_format == FORMAT_ASTC_8x8) {
|
||||
return 2;
|
||||
} else if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -260,6 +281,14 @@ int Image::get_format_block_size(Format p_format) {
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
case FORMAT_ASTC_4x4:
|
||||
case FORMAT_ASTC_4x4_HDR: {
|
||||
return 4;
|
||||
}
|
||||
case FORMAT_ASTC_8x8:
|
||||
case FORMAT_ASTC_8x8_HDR: {
|
||||
return 8;
|
||||
}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
@@ -2515,19 +2544,21 @@ Error Image::decompress() {
|
||||
_image_decompress_etc1(this);
|
||||
} else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RA_AS_RG && _image_decompress_etc2) {
|
||||
_image_decompress_etc2(this);
|
||||
} else if (format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR && _image_decompress_astc) {
|
||||
_image_decompress_astc(this);
|
||||
} else {
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality) {
|
||||
Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality, ASTCFormat p_astc_format) {
|
||||
ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode.");
|
||||
ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source.");
|
||||
return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality);
|
||||
return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality, p_astc_format);
|
||||
}
|
||||
|
||||
Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality) {
|
||||
Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality, ASTCFormat p_astc_format) {
|
||||
switch (p_mode) {
|
||||
case COMPRESS_S3TC: {
|
||||
ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
|
||||
@@ -2545,6 +2576,10 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels
|
||||
ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
|
||||
_image_compress_bptc_func(this, p_lossy_quality, p_channels);
|
||||
} break;
|
||||
case COMPRESS_ASTC: {
|
||||
ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
|
||||
_image_compress_astc_func(this, p_lossy_quality, p_astc_format);
|
||||
} break;
|
||||
case COMPRESS_MAX: {
|
||||
ERR_FAIL_V(ERR_INVALID_PARAMETER);
|
||||
} break;
|
||||
@@ -2895,10 +2930,12 @@ void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nu
|
||||
void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr;
|
||||
void (*Image::_image_compress_etc1_func)(Image *, float) = nullptr;
|
||||
void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = nullptr;
|
||||
void (*Image::_image_compress_astc_func)(Image *, float, Image::ASTCFormat) = nullptr;
|
||||
void (*Image::_image_decompress_bc)(Image *) = nullptr;
|
||||
void (*Image::_image_decompress_bptc)(Image *) = nullptr;
|
||||
void (*Image::_image_decompress_etc1)(Image *) = nullptr;
|
||||
void (*Image::_image_decompress_etc2)(Image *) = nullptr;
|
||||
void (*Image::_image_decompress_astc)(Image *) = nullptr;
|
||||
|
||||
Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr;
|
||||
Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr;
|
||||
@@ -3314,8 +3351,8 @@ void Image::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("detect_used_channels", "source"), &Image::detect_used_channels, DEFVAL(COMPRESS_SOURCE_GENERIC));
|
||||
ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7));
|
||||
ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality"), &Image::compress_from_channels, DEFVAL(0.7));
|
||||
ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality", "astc_format"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4));
|
||||
ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality", "astc_format"), &Image::compress_from_channels, DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4));
|
||||
ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress);
|
||||
ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed);
|
||||
|
||||
@@ -3399,6 +3436,10 @@ void Image::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8A1);
|
||||
BIND_ENUM_CONSTANT(FORMAT_ETC2_RA_AS_RG);
|
||||
BIND_ENUM_CONSTANT(FORMAT_DXT5_RA_AS_RG);
|
||||
BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4);
|
||||
BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4_HDR);
|
||||
BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8);
|
||||
BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8_HDR);
|
||||
BIND_ENUM_CONSTANT(FORMAT_MAX);
|
||||
|
||||
BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST);
|
||||
@@ -3426,6 +3467,9 @@ void Image::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_GENERIC);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL);
|
||||
|
||||
BIND_ENUM_CONSTANT(ASTC_FORMAT_4x4);
|
||||
BIND_ENUM_CONSTANT(ASTC_FORMAT_8x8);
|
||||
}
|
||||
|
||||
void Image::set_compress_bc_func(void (*p_compress_func)(Image *, float, UsedChannels)) {
|
||||
|
||||
Reference in New Issue
Block a user