BPTC support

This commit is contained in:
elasota 2018-08-21 22:56:04 -04:00
parent 0e6551d8e2
commit 35f6ba5c5d
34 changed files with 10491 additions and 70 deletions

View file

@ -135,6 +135,12 @@ Comment: CA certificates
Copyright: Mozilla Contributors Copyright: Mozilla Contributors
License: MPL-2.0 License: MPL-2.0
Files: ./thirdparty/cvtt/
Comment: Convection Texture Tools Stand-Alone Kernels
Copyright: 2018, Eric Lasota
2018, Microsoft Corp.
License: MIT
Files: ./thirdparty/enet/ Files: ./thirdparty/enet/
Comment: ENet Comment: ENet
Copyright: 2002-2016, Lee Salzman Copyright: 2002-2016, Lee Salzman

View file

@ -253,6 +253,21 @@ Color Color::hex64(uint64_t p_hex) {
return Color(r, g, b, a); return Color(r, g, b, a);
} }
Color Color::from_rgbe9995(uint32_t p_rgbe) {
float r = p_rgbe & 0x1ff;
float g = (p_rgbe >> 9) & 0x1ff;
float b = (p_rgbe >> 18) & 0x1ff;
float e = (p_rgbe >> 27);
float m = Math::pow(2, e - 15.0 - 9.0);
float rd = r * m;
float gd = g * m;
float bd = b * m;
return Color(rd, gd, bd, 1.0f);
}
static float _parse_col(const String &p_str, int p_ofs) { static float _parse_col(const String &p_str, int p_ofs) {
int ig = 0; int ig = 0;

View file

@ -195,6 +195,7 @@ struct Color {
static Color named(const String &p_name); static Color named(const String &p_name);
String to_html(bool p_alpha = true) const; String to_html(bool p_alpha = true) const;
Color from_hsv(float p_h, float p_s, float p_v, float p_a); Color from_hsv(float p_h, float p_s, float p_v, float p_a);
static Color from_rgbe9995(uint32_t p_color);
_FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys
operator String() const; operator String() const;

View file

@ -1029,8 +1029,10 @@ bool Image::_can_modify(Format p_format) const {
return p_format <= FORMAT_RGBE9995; return p_format <= FORMAT_RGBE9995;
} }
template <int CC, bool renormalize> template <class Component, int CC, bool renormalize,
static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_width, uint32_t p_height) { void (*average_func)(Component &, const Component &, const Component &, const Component &, const Component &),
void (*renormalize_func)(Component *)>
static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint32_t p_width, uint32_t p_height) {
//fast power of 2 mipmap generation //fast power of 2 mipmap generation
uint32_t dst_w = p_width >> 1; uint32_t dst_w = p_width >> 1;
@ -1038,34 +1040,19 @@ static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t
for (uint32_t i = 0; i < dst_h; i++) { for (uint32_t i = 0; i < dst_h; i++) {
const uint8_t *rup_ptr = &p_src[i * 2 * p_width * CC]; const Component *rup_ptr = &p_src[i * 2 * p_width * CC];
const uint8_t *rdown_ptr = rup_ptr + p_width * CC; const Component *rdown_ptr = rup_ptr + p_width * CC;
uint8_t *dst_ptr = &p_dst[i * dst_w * CC]; Component *dst_ptr = &p_dst[i * dst_w * CC];
uint32_t count = dst_w; uint32_t count = dst_w;
while (count--) { while (count--) {
for (int j = 0; j < CC; j++) { for (int j = 0; j < CC; j++) {
average_func(dst_ptr[j], rup_ptr[j], rup_ptr[j + CC], rdown_ptr[j], rdown_ptr[j + CC]);
uint16_t val = 0;
val += rup_ptr[j];
val += rup_ptr[j + CC];
val += rdown_ptr[j];
val += rdown_ptr[j + CC];
dst_ptr[j] = val >> 2;
} }
if (renormalize) { if (renormalize) {
Vector3 n(dst_ptr[0] / 255.0, dst_ptr[1] / 255.0, dst_ptr[2] / 255.0); renormalize_func(dst_ptr);
n *= 2.0;
n -= Vector3(1, 1, 1);
n.normalize();
n += Vector3(1, 1, 1);
n *= 0.5;
n *= 255;
dst_ptr[0] = CLAMP(int(n.x), 0, 255);
dst_ptr[1] = CLAMP(int(n.y), 0, 255);
dst_ptr[2] = CLAMP(int(n.z), 0, 255);
} }
dst_ptr += CC; dst_ptr += CC;
@ -1150,11 +1137,23 @@ void Image::shrink_x2() {
switch (format) { switch (format) {
case FORMAT_L8: case FORMAT_L8:
case FORMAT_R8: _generate_po2_mipmap<1, false>(r.ptr(), w.ptr(), width, height); break; case FORMAT_R8: _generate_po2_mipmap<uint8_t, 1, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
case FORMAT_LA8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break; case FORMAT_LA8: _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
case FORMAT_RG8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break; case FORMAT_RG8: _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
case FORMAT_RGB8: _generate_po2_mipmap<3, false>(r.ptr(), w.ptr(), width, height); break; case FORMAT_RGB8: _generate_po2_mipmap<uint8_t, 3, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
case FORMAT_RGBA8: _generate_po2_mipmap<4, false>(r.ptr(), w.ptr(), width, height); break; case FORMAT_RGBA8: _generate_po2_mipmap<uint8_t, 4, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
case FORMAT_RF: _generate_po2_mipmap<float, 1, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
case FORMAT_RGF: _generate_po2_mipmap<float, 2, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
case FORMAT_RGBF: _generate_po2_mipmap<float, 3, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
case FORMAT_RGBAF: _generate_po2_mipmap<float, 4, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
case FORMAT_RH: _generate_po2_mipmap<uint16_t, 1, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
case FORMAT_RGH: _generate_po2_mipmap<uint16_t, 2, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
case FORMAT_RGBH: _generate_po2_mipmap<uint16_t, 3, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
case FORMAT_RGBAH: _generate_po2_mipmap<uint16_t, 4, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
case FORMAT_RGBE9995: _generate_po2_mipmap<uint32_t, 1, false, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(r.ptr()), reinterpret_cast<uint32_t *>(w.ptr()), width, height); break;
default: {} default: {}
} }
} }
@ -1224,21 +1223,68 @@ Error Image::generate_mipmaps(bool p_renormalize) {
switch (format) { switch (format) {
case FORMAT_L8: case FORMAT_L8:
case FORMAT_R8: _generate_po2_mipmap<1, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; case FORMAT_R8: _generate_po2_mipmap<uint8_t, 1, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
case FORMAT_LA8: case FORMAT_LA8:
case FORMAT_RG8: _generate_po2_mipmap<2, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; case FORMAT_RG8: _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
case FORMAT_RGB8: case FORMAT_RGB8:
if (p_renormalize) if (p_renormalize)
_generate_po2_mipmap<3, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); _generate_po2_mipmap<uint8_t, 3, true, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
else else
_generate_po2_mipmap<3, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); _generate_po2_mipmap<uint8_t, 3, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
break; break;
case FORMAT_RGBA8: case FORMAT_RGBA8:
if (p_renormalize) if (p_renormalize)
_generate_po2_mipmap<4, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); _generate_po2_mipmap<uint8_t, 4, true, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
else else
_generate_po2_mipmap<4, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); _generate_po2_mipmap<uint8_t, 4, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
break;
case FORMAT_RF:
_generate_po2_mipmap<float, 1, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RGF:
_generate_po2_mipmap<float, 2, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RGBF:
if (p_renormalize)
_generate_po2_mipmap<float, 3, true, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
else
_generate_po2_mipmap<float, 3, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RGBAF:
if (p_renormalize)
_generate_po2_mipmap<float, 4, true, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
else
_generate_po2_mipmap<float, 4, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RH:
_generate_po2_mipmap<uint16_t, 1, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RGH:
_generate_po2_mipmap<uint16_t, 2, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RGBH:
if (p_renormalize)
_generate_po2_mipmap<uint16_t, 3, true, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
else
_generate_po2_mipmap<uint16_t, 3, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RGBAH:
if (p_renormalize)
_generate_po2_mipmap<uint16_t, 4, true, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
else
_generate_po2_mipmap<uint16_t, 4, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
break;
case FORMAT_RGBE9995:
if (p_renormalize)
_generate_po2_mipmap<uint32_t, 1, true, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(&wp[prev_ofs]), reinterpret_cast<uint32_t *>(&wp[ofs]), prev_w, prev_h);
else
_generate_po2_mipmap<uint32_t, 1, false, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(&wp[prev_ofs]), reinterpret_cast<uint32_t *>(&wp[ofs]), prev_w, prev_h);
break; break;
default: {} default: {}
} }
@ -1617,8 +1663,10 @@ bool Image::is_compressed() const {
Error Image::decompress() { Error Image::decompress() {
if (format >= FORMAT_DXT1 && format <= FORMAT_BPTC_RGBFU && _image_decompress_bc) if (format >= FORMAT_DXT1 && format <= FORMAT_RGTC_RG && _image_decompress_bc)
_image_decompress_bc(this); _image_decompress_bc(this);
else if (format >= FORMAT_BPTC_RGBA && format <= FORMAT_BPTC_RGBFU && _image_decompress_bptc)
_image_decompress_bptc(this);
else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc) else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc)
_image_decompress_pvrtc(this); _image_decompress_pvrtc(this);
else if (format == FORMAT_ETC && _image_decompress_etc1) else if (format == FORMAT_ETC && _image_decompress_etc1)
@ -1659,6 +1707,11 @@ Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_loss
ERR_FAIL_COND_V(!_image_compress_etc2_func, ERR_UNAVAILABLE); ERR_FAIL_COND_V(!_image_compress_etc2_func, ERR_UNAVAILABLE);
_image_compress_etc2_func(this, p_lossy_quality, p_source); _image_compress_etc2_func(this, p_lossy_quality, p_source);
} break; } break;
case COMPRESS_BPTC: {
ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
_image_compress_bptc_func(this, p_lossy_quality, p_source);
} break;
} }
return OK; return OK;
@ -1996,12 +2049,14 @@ ImageMemLoadFunc Image::_jpg_mem_loader_func = NULL;
ImageMemLoadFunc Image::_webp_mem_loader_func = NULL; ImageMemLoadFunc Image::_webp_mem_loader_func = NULL;
void (*Image::_image_compress_bc_func)(Image *, Image::CompressSource) = NULL; void (*Image::_image_compress_bc_func)(Image *, Image::CompressSource) = NULL;
void (*Image::_image_compress_bptc_func)(Image *, float, Image::CompressSource) = NULL;
void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL; void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL;
void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL; void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL;
void (*Image::_image_compress_etc1_func)(Image *, float) = NULL; void (*Image::_image_compress_etc1_func)(Image *, float) = NULL;
void (*Image::_image_compress_etc2_func)(Image *, float, Image::CompressSource) = NULL; void (*Image::_image_compress_etc2_func)(Image *, float, Image::CompressSource) = NULL;
void (*Image::_image_decompress_pvrtc)(Image *) = NULL; void (*Image::_image_decompress_pvrtc)(Image *) = NULL;
void (*Image::_image_decompress_bc)(Image *) = NULL; void (*Image::_image_decompress_bc)(Image *) = NULL;
void (*Image::_image_decompress_bptc)(Image *) = NULL;
void (*Image::_image_decompress_etc1)(Image *) = NULL; void (*Image::_image_decompress_etc1)(Image *) = NULL;
void (*Image::_image_decompress_etc2)(Image *) = NULL; void (*Image::_image_decompress_etc2)(Image *) = NULL;
@ -2185,18 +2240,7 @@ Color Image::get_pixel(int p_x, int p_y) const {
return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), Math::half_to_float(a)); return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), Math::half_to_float(a));
} break; } break;
case FORMAT_RGBE9995: { case FORMAT_RGBE9995: {
uint32_t rgbe = ((uint32_t *)ptr)[ofs]; return Color::from_rgbe9995(((uint32_t *)ptr)[ofs]);
float r = rgbe & 0x1ff;
float g = (rgbe >> 9) & 0x1ff;
float b = (rgbe >> 18) & 0x1ff;
float e = (rgbe >> 27);
float m = Math::pow(2, e - 15.0 - 9.0);
;
float rd = r * m;
float gd = g * m;
float bd = b * m;
return Color(rd, gd, bd, 1.0);
} break; } break;
default: { default: {
@ -2530,6 +2574,11 @@ void Image::set_compress_bc_func(void (*p_compress_func)(Image *, CompressSource
_image_compress_bc_func = p_compress_func; _image_compress_bc_func = p_compress_func;
} }
void Image::set_compress_bptc_func(void (*p_compress_func)(Image *, float, CompressSource)) {
_image_compress_bptc_func = p_compress_func;
}
void Image::normalmap_to_xy() { void Image::normalmap_to_xy() {
convert(Image::FORMAT_RGBA8); convert(Image::FORMAT_RGBA8);
@ -2783,6 +2832,55 @@ Error Image::_load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadF
return OK; return OK;
} }
void Image::average_4_uint8(uint8_t &p_out, const uint8_t &p_a, const uint8_t &p_b, const uint8_t &p_c, const uint8_t &p_d) {
p_out = static_cast<uint8_t>((p_a + p_b + p_c + p_d + 2) >> 2);
}
void Image::average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d) {
p_out = (p_a + p_b + p_c + p_d) * 0.25f;
}
void Image::average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d) {
p_out = Math::make_half_float((Math::half_to_float(p_a) + Math::half_to_float(p_b) + Math::half_to_float(p_c) + Math::half_to_float(p_d)) * 0.25f);
}
void Image::average_4_rgbe9995(uint32_t &p_out, const uint32_t &p_a, const uint32_t &p_b, const uint32_t &p_c, const uint32_t &p_d) {
p_out = ((Color::from_rgbe9995(p_a) + Color::from_rgbe9995(p_b) + Color::from_rgbe9995(p_c) + Color::from_rgbe9995(p_d)) * 0.25f).to_rgbe9995();
}
void Image::renormalize_uint8(uint8_t *p_rgb) {
Vector3 n(p_rgb[0] / 255.0, p_rgb[1] / 255.0, p_rgb[2] / 255.0);
n *= 2.0;
n -= Vector3(1, 1, 1);
n.normalize();
n += Vector3(1, 1, 1);
n *= 0.5;
n *= 255;
p_rgb[0] = CLAMP(int(n.x), 0, 255);
p_rgb[1] = CLAMP(int(n.y), 0, 255);
p_rgb[2] = CLAMP(int(n.z), 0, 255);
}
void Image::renormalize_float(float *p_rgb) {
Vector3 n(p_rgb[0], p_rgb[1], p_rgb[2]);
n.normalize();
p_rgb[0] = n.x;
p_rgb[1] = n.y;
p_rgb[2] = n.z;
}
void Image::renormalize_half(uint16_t *p_rgb) {
Vector3 n(Math::half_to_float(p_rgb[0]), Math::half_to_float(p_rgb[1]), Math::half_to_float(p_rgb[2]));
n.normalize();
p_rgb[0] = Math::make_half_float(n.x);
p_rgb[1] = Math::make_half_float(n.y);
p_rgb[2] = Math::make_half_float(n.z);
}
void Image::renormalize_rgbe9995(uint32_t *p_rgb) {
// Never used
}
Image::Image(const uint8_t *p_mem_png_jpg, int p_len) { Image::Image(const uint8_t *p_mem_png_jpg, int p_len) {
width = 0; width = 0;

View file

@ -127,6 +127,7 @@ public:
static ImageMemLoadFunc _webp_mem_loader_func; static ImageMemLoadFunc _webp_mem_loader_func;
static void (*_image_compress_bc_func)(Image *, CompressSource p_source); static void (*_image_compress_bc_func)(Image *, CompressSource p_source);
static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, CompressSource p_source);
static void (*_image_compress_pvrtc2_func)(Image *); static void (*_image_compress_pvrtc2_func)(Image *);
static void (*_image_compress_pvrtc4_func)(Image *); static void (*_image_compress_pvrtc4_func)(Image *);
static void (*_image_compress_etc1_func)(Image *, float); static void (*_image_compress_etc1_func)(Image *, float);
@ -134,6 +135,7 @@ public:
static void (*_image_decompress_pvrtc)(Image *); static void (*_image_decompress_pvrtc)(Image *);
static void (*_image_decompress_bc)(Image *); static void (*_image_decompress_bc)(Image *);
static void (*_image_decompress_bptc)(Image *);
static void (*_image_decompress_etc1)(Image *); static void (*_image_decompress_etc1)(Image *);
static void (*_image_decompress_etc2)(Image *); static void (*_image_decompress_etc2)(Image *);
@ -182,6 +184,15 @@ private:
Error _load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader); Error _load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader);
static void average_4_uint8(uint8_t &p_out, const uint8_t &p_a, const uint8_t &p_b, const uint8_t &p_c, const uint8_t &p_d);
static void average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d);
static void average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d);
static void average_4_rgbe9995(uint32_t &p_out, const uint32_t &p_a, const uint32_t &p_b, const uint32_t &p_c, const uint32_t &p_d);
static void renormalize_uint8(uint8_t *p_rgb);
static void renormalize_float(float *p_rgb);
static void renormalize_half(uint16_t *p_rgb);
static void renormalize_rgbe9995(uint32_t *p_rgb);
public: public:
int get_width() const; ///< Get image width int get_width() const; ///< Get image width
int get_height() const; ///< Get image height int get_height() const; ///< Get image height
@ -282,6 +293,7 @@ public:
COMPRESS_PVRTC4, COMPRESS_PVRTC4,
COMPRESS_ETC, COMPRESS_ETC,
COMPRESS_ETC2, COMPRESS_ETC2,
COMPRESS_BPTC
}; };
Error compress(CompressMode p_mode = COMPRESS_S3TC, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7); Error compress(CompressMode p_mode = COMPRESS_S3TC, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7);
@ -305,6 +317,7 @@ public:
Ref<Image> get_rect(const Rect2 &p_area) const; Ref<Image> get_rect(const Rect2 &p_area) const;
static void set_compress_bc_func(void (*p_compress_func)(Image *, CompressSource)); static void set_compress_bc_func(void (*p_compress_func)(Image *, CompressSource));
static void set_compress_bptc_func(void (*p_compress_func)(Image *, float, CompressSource));
static String get_format_name(Format p_format); static String get_format_name(Format p_format);
Error load_png_from_buffer(const PoolVector<uint8_t> &p_array); Error load_png_from_buffer(const PoolVector<uint8_t> &p_array);

View file

@ -78,7 +78,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
if (assign != String()) { if (assign != String()) {
if (!path_found && assign.begins_with("path.") && r_path_and_type.path == String()) { if (!path_found && assign.begins_with("path.") && r_path_and_type.path == String()) {
String feature = assign.get_slicec('.', 1); String feature = assign.get_slicec('.', 1);
if (OS::get_singleton()->has_feature(feature)) { if (feature == "fallback" || OS::get_singleton()->has_feature(feature)) {
r_path_and_type.path = value; r_path_and_type.path = value;
path_found = true; //first match must have priority path_found = true; //first match must have priority
} }

View file

@ -61,11 +61,12 @@ void RasterizerStorageGLES2::bind_quad_array() const {
glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
} }
Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) { Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const {
r_gl_format = 0; r_gl_format = 0;
Ref<Image> image = p_image; Ref<Image> image = p_image;
r_compressed = false; r_compressed = false;
r_real_format = p_format;
bool need_decompress = false; bool need_decompress = false;
@ -317,6 +318,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
r_gl_format = GL_RGBA; r_gl_format = GL_RGBA;
r_gl_internal_format = GL_RGBA; r_gl_internal_format = GL_RGBA;
r_gl_type = GL_UNSIGNED_BYTE; r_gl_type = GL_UNSIGNED_BYTE;
r_real_format = Image::FORMAT_RGBA8;
return image; return image;
} }
@ -384,7 +386,8 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
} break; } break;
} }
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type, compressed); Image::Format real_format;
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed);
texture->alloc_width = texture->width; texture->alloc_width = texture->width;
texture->alloc_height = texture->height; texture->alloc_height = texture->height;
@ -426,7 +429,8 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
texture->images.write[p_layer] = p_image; texture->images.write[p_layer] = p_image;
} }
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed); Image::Format real_format;
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed);
if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
@ -570,11 +574,19 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) { if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) {
return texture->images[p_layer]; return texture->images[p_layer];
} }
#ifdef GLES_OVER_GL #ifdef GLES_OVER_GL
Image::Format real_format;
GLenum gl_format;
GLenum gl_internal_format;
GLenum gl_type;
bool compressed;
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed);
PoolVector<uint8_t> data; PoolVector<uint8_t> data;
int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, texture->mipmaps > 1 ? -1 : 0); int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1 ? -1 : 0);
data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
PoolVector<uint8_t>::Write wb = data.write(); PoolVector<uint8_t>::Write wb = data.write();
@ -591,7 +603,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
int ofs = 0; int ofs = 0;
if (i > 0) { if (i > 0) {
ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, i - 1); ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1);
} }
if (texture->compressed) { if (texture->compressed) {
@ -607,7 +619,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
data.resize(data_size); data.resize(data_size);
Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, texture->format, data)); Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, real_format, data));
return Ref<Image>(img); return Ref<Image>(img);
#else #else

View file

@ -325,7 +325,7 @@ public:
mutable RID_Owner<Texture> texture_owner; mutable RID_Owner<Texture> texture_owner;
Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed); Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const;
virtual RID texture_create(); virtual RID texture_create();
virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);

View file

@ -118,10 +118,11 @@ void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat,
GLuint RasterizerStorageGLES3::system_fbo = 0; GLuint RasterizerStorageGLES3::system_fbo = 0;
Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb) { Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb) const {
r_compressed = false; r_compressed = false;
r_gl_format = 0; r_gl_format = 0;
r_real_format = p_format;
Ref<Image> image = p_image; Ref<Image> image = p_image;
srgb = false; srgb = false;
@ -565,6 +566,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8_ALPHA8 : GL_RGBA8; r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
r_gl_type = GL_UNSIGNED_BYTE; r_gl_type = GL_UNSIGNED_BYTE;
r_compressed = false; r_compressed = false;
r_real_format = Image::FORMAT_RGBA8;
srgb = true; srgb = true;
return image; return image;
@ -638,7 +640,8 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
} break; } break;
} }
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type, compressed, srgb); Image::Format real_format;
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, srgb);
texture->alloc_width = texture->width; texture->alloc_width = texture->width;
texture->alloc_height = texture->height; texture->alloc_height = texture->height;
@ -710,7 +713,8 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
texture->images.write[p_layer] = p_image; texture->images.write[p_layer] = p_image;
} }
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed, srgb); Image::Format real_format;
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb);
if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
@ -941,7 +945,8 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I
p_sub_img = p_image->get_rect(Rect2(src_x, src_y, src_w, src_h)); p_sub_img = p_image->get_rect(Rect2(src_x, src_y, src_w, src_h));
} }
Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, format, internal_format, type, compressed, srgb); Image::Format real_format;
Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb);
GLenum blit_target; GLenum blit_target;
@ -1014,9 +1019,17 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
#ifdef GLES_OVER_GL #ifdef GLES_OVER_GL
Image::Format real_format;
GLenum gl_format;
GLenum gl_internal_format;
GLenum gl_type;
bool compressed;
bool srgb;
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, srgb);
PoolVector<uint8_t> data; PoolVector<uint8_t> data;
int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, texture->mipmaps > 1 ? -1 : 0); int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1 ? -1 : 0);
data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
PoolVector<uint8_t>::Write wb = data.write(); PoolVector<uint8_t>::Write wb = data.write();
@ -1033,7 +1046,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
int ofs = 0; int ofs = 0;
if (i > 0) { if (i > 0) {
ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, i - 1); ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1);
} }
if (texture->compressed) { if (texture->compressed) {
@ -1069,7 +1082,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
(a | a << 2 | a << 4 | a << 6) << 24; (a | a << 2 | a << 4 | a << 6) << 24;
} }
} else { } else {
img_format = texture->format; img_format = real_format;
} }
wb = PoolVector<uint8_t>::Write(); wb = PoolVector<uint8_t>::Write();
@ -7368,6 +7381,9 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const { bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const {
if (p_feature == "bptc")
return config.bptc_supported;
if (p_feature == "s3tc") if (p_feature == "s3tc")
return config.s3tc_supported; return config.s3tc_supported;

View file

@ -340,7 +340,7 @@ public:
mutable RID_Owner<Texture> texture_owner; mutable RID_Owner<Texture> texture_owner;
Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb); Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb) const;
virtual RID texture_create(); virtual RID texture_create();
virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);

View file

@ -661,6 +661,21 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
List<String> remaps; List<String> remaps;
config->get_section_keys("remap", &remaps); config->get_section_keys("remap", &remaps);
Set<String> remap_features;
for (List<String>::Element *F = remaps.front(); F; F = F->next()) {
String remap = F->get();
String feature = remap.get_slice(".", 1);
if (feature == "fallback" || features.has(feature)) {
remap_features.insert(feature);
}
}
if (remap_features.size() > 1) {
this->resolve_platform_feature_priorities(p_preset, remap_features);
}
for (List<String>::Element *F = remaps.front(); F; F = F->next()) { for (List<String>::Element *F = remaps.front(); F; F = F->next()) {
String remap = F->get(); String remap = F->get();
@ -670,7 +685,8 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
p_func(p_udata, remapped_path, array, idx, total); p_func(p_udata, remapped_path, array, idx, total);
} else if (remap.begins_with("path.")) { } else if (remap.begins_with("path.")) {
String feature = remap.get_slice(".", 1); String feature = remap.get_slice(".", 1);
if (features.has(feature)) {
if (remap_features.has(feature)) {
String remapped_path = config->get_value("remap", remap); String remapped_path = config->get_value("remap", remap);
Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path);
p_func(p_udata, remapped_path, array, idx, total); p_func(p_udata, remapped_path, array, idx, total);
@ -1249,9 +1265,11 @@ void EditorExportPlatformPC::get_preset_features(const Ref<EditorExportPreset> &
void EditorExportPlatformPC::get_export_options(List<ExportOption> *r_options) { void EditorExportPlatformPC::get_export_options(List<ExportOption> *r_options) {
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/bptc"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/no_bptc_fallbacks"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "binary_format/64_bits"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "binary_format/64_bits"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE), ""));
@ -1434,6 +1452,16 @@ void EditorExportPlatformPC::get_platform_features(List<String> *r_features) {
} }
} }
void EditorExportPlatformPC::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
if (p_features.has("bptc")) {
if (p_preset->has("texture_format/no_bptc_fallbacks")) {
p_features.erase("s3tc");
p_features.erase("fallback");
}
}
}
int EditorExportPlatformPC::get_chmod_flags() const { int EditorExportPlatformPC::get_chmod_flags() const {
return chmod_flags; return chmod_flags;

View file

@ -246,6 +246,7 @@ public:
virtual Error export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); virtual Error export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual void get_platform_features(List<String> *r_features) = 0; virtual void get_platform_features(List<String> *r_features) = 0;
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) = 0;
EditorExportPlatform(); EditorExportPlatform();
}; };
@ -403,6 +404,7 @@ public:
void add_platform_feature(const String &p_feature); void add_platform_feature(const String &p_feature);
virtual void get_platform_features(List<String> *r_features); virtual void get_platform_features(List<String> *r_features);
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features);
int get_chmod_flags() const; int get_chmod_flags() const;
void set_chmod_flags(int p_flags); void set_chmod_flags(int p_flags);

View file

@ -163,6 +163,7 @@ void ResourceImporterLayeredTexture::_save_tex(const Vector<Ref<Image> > &p_imag
Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {
int compress_mode = p_options["compress/mode"]; int compress_mode = p_options["compress/mode"];
int no_bptc_if_rgb = p_options["compress/no_bptc_if_rgb"];
int repeat = p_options["flags/repeat"]; int repeat = p_options["flags/repeat"];
bool filter = p_options["flags/filter"]; bool filter = p_options["flags/filter"];
bool mipmaps = p_options["flags/mipmaps"]; bool mipmaps = p_options["flags/mipmaps"];
@ -226,6 +227,26 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
//Android, GLES 2.x //Android, GLES 2.x
bool ok_on_pc = false; bool ok_on_pc = false;
bool encode_bptc = false;
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc")) {
encode_bptc = true;
if (no_bptc_if_rgb) {
Image::DetectChannels channels = image->get_detected_channels();
if (channels != Image::DETECTED_LA && channels != Image::DETECTED_RGBA) {
encode_bptc = false;
}
}
}
if (encode_bptc) {
_save_tex(slices, p_save_path + ".bptc." + extension, compress_mode, Image::COMPRESS_BPTC, mipmaps, tex_flags);
r_platform_variants->push_back("bptc");
ok_on_pc = true;
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) { if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) {

View file

@ -188,7 +188,8 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 2 : 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 2 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_mode", PROPERTY_HINT_ENUM, "Compress,Force RGBE"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/no_bptc_if_rgb"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_mode", PROPERTY_HINT_ENUM, "LDR Fallback,Force RGBE,RGBE Fallback"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/normal_map", PROPERTY_HINT_ENUM, "Detect,Enable,Disabled"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/normal_map", PROPERTY_HINT_ENUM, "Detect,Enable,Disabled"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), p_preset == PRESET_3D ? 1 : 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), p_preset == PRESET_3D ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), p_preset == PRESET_2D_PIXEL ? false : true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), p_preset == PRESET_2D_PIXEL ? false : true));
@ -347,6 +348,7 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {
int compress_mode = p_options["compress/mode"]; int compress_mode = p_options["compress/mode"];
int no_bptc_if_rgb = p_options["compress/no_bptc_if_rgb"];
float lossy = p_options["compress/lossy_quality"]; float lossy = p_options["compress/lossy_quality"];
int repeat = p_options["flags/repeat"]; int repeat = p_options["flags/repeat"];
bool filter = p_options["flags/filter"]; bool filter = p_options["flags/filter"];
@ -359,6 +361,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
bool stream = p_options["stream"]; bool stream = p_options["stream"];
int size_limit = p_options["size_limit"]; int size_limit = p_options["size_limit"];
bool force_rgbe = int(p_options["compress/hdr_mode"]) == 1; bool force_rgbe = int(p_options["compress/hdr_mode"]) == 1;
bool rgbe_fallback = int(p_options["compress/hdr_mode"]) == 2;
bool hdr_as_srgb = p_options["process/HDR_as_SRGB"]; bool hdr_as_srgb = p_options["process/HDR_as_SRGB"];
int normal = p_options["compress/normal_map"]; int normal = p_options["compress/normal_map"];
float scale = p_options["svg/scale"]; float scale = p_options["svg/scale"];
@ -434,31 +437,59 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
//Android, GLES 2.x //Android, GLES 2.x
bool ok_on_pc = false; bool ok_on_pc = false;
bool encode_bptc = false;
bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995);
bool no_ldr_compression = (is_hdr && rgbe_fallback);
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) { if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc")) {
encode_bptc = true;
if (no_bptc_if_rgb && !is_hdr) {
Image::DetectChannels channels = image->get_detected_channels();
if (channels != Image::DETECTED_LA && channels != Image::DETECTED_RGBA) {
encode_bptc = false;
}
}
}
if (encode_bptc) {
_save_stex(image, p_save_path + ".bptc.stex", compress_mode, lossy, Image::COMPRESS_BPTC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
r_platform_variants->push_back("bptc");
ok_on_pc = true;
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc") && !no_ldr_compression) {
_save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
r_platform_variants->push_back("s3tc"); r_platform_variants->push_back("s3tc");
ok_on_pc = true; ok_on_pc = true;
} }
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) { if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2") && !no_ldr_compression) {
_save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
r_platform_variants->push_back("etc2"); r_platform_variants->push_back("etc2");
} }
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) { if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc") && !no_ldr_compression) {
_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
r_platform_variants->push_back("etc"); r_platform_variants->push_back("etc");
} }
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc") && !no_ldr_compression) {
_save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
r_platform_variants->push_back("pvrtc"); r_platform_variants->push_back("pvrtc");
} }
if (is_hdr && rgbe_fallback) {
_save_stex(image, p_save_path + ".fallback.stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb, true, detect_normal, force_normal);
r_platform_variants->push_back("fallback");
ok_on_pc = true;
}
if (!ok_on_pc) { if (!ok_on_pc) {
EditorNode::add_io_error("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correcly on PC."); EditorNode::add_io_error("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correcly on PC.");
} }

View file

@ -1007,6 +1007,7 @@ void ProjectSettingsEditor::_copy_to_platform_about_to_show() {
Set<String> presets; Set<String> presets;
presets.insert("bptc");
presets.insert("s3tc"); presets.insert("s3tc");
presets.insert("etc"); presets.insert("etc");
presets.insert("etc2"); presets.insert("etc2");

21
modules/cvtt/SCsub Normal file
View file

@ -0,0 +1,21 @@
#!/usr/bin/env python
Import('env')
Import('env_modules')
env_cvtt = env_modules.Clone()
# Thirdparty source files
if env['builtin_squish']:
thirdparty_dir = "#thirdparty/cvtt/"
thirdparty_sources = [
"ConvectionKernels.cpp"
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_cvtt.add_source_files(env.modules_sources, thirdparty_sources)
env_cvtt.Append(CPPPATH=[thirdparty_dir])
# Godot source files
env_cvtt.add_source_files(env.modules_sources, "*.cpp")

5
modules/cvtt/config.py Normal file
View file

@ -0,0 +1,5 @@
def can_build(env, platform):
return env['tools']
def configure(env):
pass

View file

@ -0,0 +1,300 @@
/*************************************************************************/
/* image_compress_cvtt.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "image_compress_cvtt.h"
#include "print_string.h"
#include <ConvectionKernels.h>
void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressSource p_source) {
if (p_image->get_format() >= Image::FORMAT_BPTC_RGBA)
return; //do not compress, already compressed
int w = p_image->get_width();
int h = p_image->get_height();
bool is_ldr = (p_image->get_format() <= Image::FORMAT_RGBA8);
bool is_hdr = (p_image->get_format() == Image::FORMAT_RGBH);
if (!is_ldr && !is_hdr) {
return; // Not a usable source format
}
cvtt::Options options;
uint32_t flags = cvtt::Flags::Fastest;
if (p_lossy_quality > 0.85)
flags = cvtt::Flags::Ultra;
else if (p_lossy_quality > 0.75)
flags = cvtt::Flags::Better;
else if (p_lossy_quality > 0.55)
flags = cvtt::Flags::Default;
else if (p_lossy_quality > 0.35)
flags = cvtt::Flags::Fast;
else if (p_lossy_quality > 0.15)
flags = cvtt::Flags::Faster;
flags |= cvtt::Flags::BC7_RespectPunchThrough;
if (p_source == Image::COMPRESS_SOURCE_NORMAL) {
flags |= cvtt::Flags::Uniform;
}
Image::Format target_format = Image::FORMAT_BPTC_RGBA;
bool is_signed = false;
if (is_hdr) {
PoolVector<uint8_t>::Read rb = p_image->get_data().read();
const uint16_t *source_data = reinterpret_cast<const uint16_t *>(&rb[0]);
int pixel_element_count = w * h * 3;
for (int i = 0; i < pixel_element_count; i++) {
if ((source_data[i] & 0x8000) != 0 && (source_data[i] & 0x7fff) != 0) {
is_signed = true;
break;
}
}
target_format = is_signed ? Image::FORMAT_BPTC_RGBF : Image::FORMAT_BPTC_RGBFU;
} else {
p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
}
PoolVector<uint8_t>::Read rb = p_image->get_data().read();
PoolVector<uint8_t> data;
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
data.resize(target_size);
int shift = Image::get_format_pixel_rshift(target_format);
PoolVector<uint8_t>::Write wb = data.write();
int dst_ofs = 0;
for (int i = 0; i <= mm_count; i++) {
int bw = w % 4 != 0 ? w + (4 - w % 4) : w;
int bh = h % 4 != 0 ? h + (4 - h % 4) : h;
int src_ofs = p_image->get_mipmap_offset(i);
const uint8_t *in_bytes = &rb[src_ofs];
uint8_t *out_bytes = &wb[dst_ofs];
cvtt::PixelBlockU8 input_blocks_ldr[cvtt::NumParallelBlocks];
cvtt::PixelBlockF16 input_blocks_hdr[cvtt::NumParallelBlocks];
int bytes_per_pixel = is_hdr ? 6 : 4;
for (int y_start = 0; y_start < h; y_start += 4) {
int y_end = y_start + 4;
for (int x_start = 0; x_start < w; x_start += 4 * cvtt::NumParallelBlocks) {
int x_end = x_start + 4 * cvtt::NumParallelBlocks;
for (int y = y_start; y < y_end; y++) {
int first_input_element = (y - y_start) * 4;
const uint8_t *row_start;
if (y >= h) {
row_start = in_bytes + (h - 1) * (w * bytes_per_pixel);
} else {
row_start = in_bytes + y * (w * bytes_per_pixel);
}
for (int x = x_start; x < x_end; x++) {
const uint8_t *pixel_start;
if (x >= w) {
pixel_start = row_start + (w - 1) * bytes_per_pixel;
} else {
pixel_start = row_start + x * bytes_per_pixel;
}
int block_index = (x - x_start) / 4;
int block_element = (x - x_start) % 4 + first_input_element;
if (is_hdr) {
memcpy(input_blocks_hdr[block_index].m_pixels[block_element], pixel_start, bytes_per_pixel);
input_blocks_hdr[block_index].m_pixels[block_element][3] = 0x3c00; // 1.0 (unused)
} else {
memcpy(input_blocks_ldr[block_index].m_pixels[block_element], pixel_start, bytes_per_pixel);
}
}
}
uint8_t output_blocks[16 * cvtt::NumParallelBlocks];
if (is_hdr) {
if (is_signed) {
cvtt::Kernels::EncodeBC6HS(output_blocks, input_blocks_hdr, options);
} else {
cvtt::Kernels::EncodeBC6HU(output_blocks, input_blocks_hdr, options);
}
} else {
cvtt::Kernels::EncodeBC7(output_blocks, input_blocks_ldr, options);
}
int num_real_blocks = ((w - x_start) + 3) / 4;
if (num_real_blocks > cvtt::NumParallelBlocks) {
num_real_blocks = cvtt::NumParallelBlocks;
}
memcpy(out_bytes, output_blocks, 16 * num_real_blocks);
out_bytes += 16 * num_real_blocks;
}
}
dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift;
w >>= 1;
h >>= 1;
}
rb = PoolVector<uint8_t>::Read();
wb = PoolVector<uint8_t>::Write();
p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}
void image_decompress_cvtt(Image *p_image) {
Image::Format target_format;
bool is_signed = false;
bool is_hdr = false;
Image::Format input_format = p_image->get_format();
switch (input_format) {
case Image::FORMAT_BPTC_RGBA:
target_format = Image::FORMAT_RGBA8;
break;
case Image::FORMAT_BPTC_RGBF:
case Image::FORMAT_BPTC_RGBFU:
target_format = Image::FORMAT_RGBH;
is_signed = (input_format == Image::FORMAT_BPTC_RGBF);
is_hdr = true;
break;
default:
return; // Invalid input format
};
int w = p_image->get_width();
int h = p_image->get_height();
PoolVector<uint8_t>::Read rb = p_image->get_data().read();
PoolVector<uint8_t> data;
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->get_mipmap_count();
data.resize(target_size);
int shift = Image::get_format_pixel_rshift(target_format);
PoolVector<uint8_t>::Write wb = data.write();
int bytes_per_pixel = is_hdr ? 6 : 4;
int dst_ofs = 0;
for (int i = 0; i <= mm_count; i++) {
int src_ofs = p_image->get_mipmap_offset(i);
const uint8_t *in_bytes = &rb[src_ofs];
uint8_t *out_bytes = &wb[dst_ofs];
cvtt::PixelBlockU8 output_blocks_ldr[cvtt::NumParallelBlocks];
cvtt::PixelBlockF16 output_blocks_hdr[cvtt::NumParallelBlocks];
for (int y_start = 0; y_start < h; y_start += 4) {
int y_end = y_start + 4;
for (int x_start = 0; x_start < w; x_start += 4 * cvtt::NumParallelBlocks) {
int x_end = x_start + 4 * cvtt::NumParallelBlocks;
uint8_t input_blocks[16 * cvtt::NumParallelBlocks];
memset(input_blocks, 0, sizeof(input_blocks));
int num_real_blocks = ((w - x_start) + 3) / 4;
if (num_real_blocks > cvtt::NumParallelBlocks) {
num_real_blocks = cvtt::NumParallelBlocks;
}
memcpy(input_blocks, in_bytes, 16 * num_real_blocks);
in_bytes += 16 * num_real_blocks;
if (is_hdr) {
if (is_signed) {
cvtt::Kernels::DecodeBC6HS(output_blocks_hdr, input_blocks);
} else {
cvtt::Kernels::DecodeBC6HU(output_blocks_hdr, input_blocks);
}
} else {
cvtt::Kernels::DecodeBC7(output_blocks_ldr, input_blocks);
}
for (int y = y_start; y < y_end; y++) {
int first_input_element = (y - y_start) * 4;
uint8_t *row_start;
if (y >= h) {
row_start = out_bytes + (h - 1) * (w * bytes_per_pixel);
} else {
row_start = out_bytes + y * (w * bytes_per_pixel);
}
for (int x = x_start; x < x_end; x++) {
uint8_t *pixel_start;
if (x >= w) {
pixel_start = row_start + (w - 1) * bytes_per_pixel;
} else {
pixel_start = row_start + x * bytes_per_pixel;
}
int block_index = (x - x_start) / 4;
int block_element = (x - x_start) % 4 + first_input_element;
if (is_hdr) {
memcpy(pixel_start, output_blocks_hdr[block_index].m_pixels[block_element], bytes_per_pixel);
} else {
memcpy(pixel_start, output_blocks_ldr[block_index].m_pixels[block_element], bytes_per_pixel);
}
}
}
}
}
dst_ofs += w * h * bytes_per_pixel;
w >>= 1;
h >>= 1;
}
rb = PoolVector<uint8_t>::Read();
wb = PoolVector<uint8_t>::Write();
p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}

View file

@ -0,0 +1,39 @@
/*************************************************************************/
/* image_compress_cvtt.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef IMAGE_COMPRESS_CVTT_H
#define IMAGE_COMPRESS_CVTT_H
#include "image.h"
void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressSource p_source);
void image_decompress_cvtt(Image *p_image);
#endif // IMAGE_COMPRESS_CVTT_H

View file

@ -0,0 +1,45 @@
/*************************************************************************/
/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
#ifdef TOOLS_ENABLED
#include "image_compress_cvtt.h"
void register_cvtt_types() {
Image::set_compress_bptc_func(image_compress_cvtt);
Image::_image_decompress_bptc = image_decompress_cvtt;
}
void unregister_cvtt_types() {}
#endif

View file

@ -0,0 +1,34 @@
/*************************************************************************/
/* register_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef TOOLS_ENABLED
void register_cvtt_types();
void unregister_cvtt_types();
#endif

View file

@ -1860,6 +1860,9 @@ public:
r_features->push_back("Android"); r_features->push_back("Android");
} }
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
}
EditorExportAndroid() { EditorExportAndroid() {
Ref<Image> img = memnew(Image(_android_logo)); Ref<Image> img = memnew(Image(_android_logo));

View file

@ -119,6 +119,9 @@ public:
r_features->push_back("iOS"); r_features->push_back("iOS");
} }
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
}
EditorExportPlatformIOS(); EditorExportPlatformIOS();
~EditorExportPlatformIOS(); ~EditorExportPlatformIOS();
}; };

View file

@ -74,6 +74,9 @@ public:
r_features->push_back(get_os_name()); r_features->push_back(get_os_name());
} }
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
}
EditorExportPlatformJavaScript(); EditorExportPlatformJavaScript();
}; };

View file

@ -86,6 +86,9 @@ public:
r_features->push_back("OSX"); r_features->push_back("OSX");
} }
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
}
EditorExportPlatformOSX(); EditorExportPlatformOSX();
~EditorExportPlatformOSX(); ~EditorExportPlatformOSX();
}; };

View file

@ -1454,6 +1454,9 @@ public:
r_features->push_back("UWP"); r_features->push_back("UWP");
} }
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
}
EditorExportUWP() { EditorExportUWP() {
Ref<Image> img = memnew(Image(_uwp_logo)); Ref<Image> img = memnew(Image(_uwp_logo));
logo.instance(); logo.instance();

View file

@ -2805,7 +2805,7 @@ int OS_Windows::get_power_percent_left() {
bool OS_Windows::_check_internal_feature_support(const String &p_feature) { bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc"; return p_feature == "pc" || p_feature == "s3tc" || p_feature == "bptc";
} }
void OS_Windows::disable_crash_handler() { void OS_Windows::disable_crash_handler() {

View file

@ -2344,7 +2344,7 @@ Error OS_X11::shell_open(String p_uri) {
bool OS_X11::_check_internal_feature_support(const String &p_feature) { bool OS_X11::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc"; return p_feature == "pc" || p_feature == "s3tc" || p_feature == "bptc";
} }
String OS_X11::get_config_path() const { String OS_X11::get_config_path() const {

View file

@ -2361,6 +2361,7 @@ VisualServer::VisualServer() {
//ERR_FAIL_COND(singleton); //ERR_FAIL_COND(singleton);
singleton = this; singleton = this;
GLOBAL_DEF("rendering/vram_compression/import_bptc", false);
GLOBAL_DEF("rendering/vram_compression/import_s3tc", true); GLOBAL_DEF("rendering/vram_compression/import_s3tc", true);
GLOBAL_DEF("rendering/vram_compression/import_etc", false); GLOBAL_DEF("rendering/vram_compression/import_etc", false);
GLOBAL_DEF("rendering/vram_compression/import_etc2", true); GLOBAL_DEF("rendering/vram_compression/import_etc2", true);

11
thirdparty/README.md vendored
View file

@ -40,6 +40,17 @@ File extracted from a recent Fedora install:
as it's generated on the user's system.) as it's generated on the user's system.)
## cvtt
- Upstream: https://github.com/elasota/cvtt
- Version: 1.0.0-beta4
- License: MIT
Files extracted from upstream source:
- all .cpp, .h, and .txt files in ConvectionKernels/
## enet ## enet
- Upstream: http://enet.bespin.org - Upstream: http://enet.bespin.org

7576
thirdparty/cvtt/ConvectionKernels.cpp vendored Normal file

File diff suppressed because it is too large Load diff

145
thirdparty/cvtt/ConvectionKernels.h vendored Normal file
View file

@ -0,0 +1,145 @@
/*
Convection Texture Tools
Copyright (c) 2018 Eric Lasota
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#ifndef __CVTT_CONVECTION_KERNELS__
#define __CVTT_CONVECTION_KERNELS__
#include <stdint.h>
namespace cvtt
{
namespace Flags
{
// Enable partitioned modes in BC7 encoding (slower, better quality)
const uint32_t BC7_EnablePartitioning = 0x001;
// Enable 3-partition modes in BC7 encoding (slower, better quality, requires BC7_EnablePartitioning)
const uint32_t BC7_Enable3Subsets = 0x002;
// Enable dual-plane modes in BC7 encoding (slower, better quality)
const uint32_t BC7_EnableDualPlane = 0x004;
// Use fast indexing in BC7 encoding (about 2x faster, slightly worse quality)
const uint32_t BC7_FastIndexing = 0x008;
// Try precomputed single-color lookups where applicable (slightly slower, small quality increase on specific blocks)
const uint32_t BC7_TrySingleColor = 0x010;
// Don't allow non-zero or non-max alpha values in blocks that only contain one or the other
const uint32_t BC7_RespectPunchThrough = 0x020;
// Use fast indexing in HDR formats (faster, worse quality)
const uint32_t BC6H_FastIndexing = 0x040;
// Exhaustive search RGB orderings when encoding BC1-BC3 (much slower, better quality)
const uint32_t S3TC_Exhaustive = 0x080;
// Penalize distant endpoints, improving quality on inaccurate GPU decoders
const uint32_t S3TC_Paranoid = 0x100;
// Uniform color channel importance
const uint32_t Uniform = 0x200;
// Misc useful default flag combinations
const uint32_t Fastest = (BC6H_FastIndexing | S3TC_Paranoid);
const uint32_t Faster = (BC7_EnableDualPlane | BC6H_FastIndexing | S3TC_Paranoid);
const uint32_t Fast = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_FastIndexing | S3TC_Paranoid);
const uint32_t Default = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_Enable3Subsets | BC7_FastIndexing | S3TC_Paranoid);
const uint32_t Better = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_Enable3Subsets | S3TC_Paranoid | S3TC_Exhaustive);
const uint32_t Ultra = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_Enable3Subsets | BC7_TrySingleColor | S3TC_Paranoid | S3TC_Exhaustive);
}
const unsigned int NumParallelBlocks = 8;
struct Options
{
uint32_t flags; // Bitmask of cvtt::Flags values
float threshold; // Alpha test threshold for BC1
float redWeight; // Red channel importance
float greenWeight; // Green channel importance
float blueWeight; // Blue channel importance
float alphaWeight; // Alpha channel importance
int refineRoundsBC7; // Number of refine rounds for BC7
int refineRoundsBC6H; // Number of refine rounds for BC6H (max 3)
int refineRoundsIIC; // Number of refine rounds for independent interpolated channels (BC3 alpha, BC4, BC5)
int refineRoundsS3TC; // Number of refine rounds for S3TC RGB
int seedPoints; // Number of seed points (min 1, max 4)
Options()
: flags(Flags::Default)
, threshold(0.5f)
, redWeight(0.2125f / 0.7154f)
, greenWeight(1.0f)
, blueWeight(0.0721f / 0.7154f)
, alphaWeight(1.0f)
, refineRoundsBC7(2)
, refineRoundsBC6H(3)
, refineRoundsIIC(8)
, refineRoundsS3TC(2)
, seedPoints(4)
{
}
};
// RGBA input block for unsigned 8-bit formats
struct PixelBlockU8
{
uint8_t m_pixels[16][4];
};
// RGBA input block for signed 8-bit formats
struct PixelBlockS8
{
int8_t m_pixels[16][4];
};
// RGBA input block for half-precision float formats (bit-cast to int16_t)
struct PixelBlockF16
{
int16_t m_pixels[16][4];
};
namespace Kernels
{
// NOTE: All functions accept and output NumParallelBlocks blocks at once
void EncodeBC1(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
void EncodeBC2(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
void EncodeBC3(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
void EncodeBC4U(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
void EncodeBC4S(uint8_t *pBC, const PixelBlockS8 *pBlocks, const Options &options);
void EncodeBC5U(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
void EncodeBC5S(uint8_t *pBC, const PixelBlockS8 *pBlocks, const Options &options);
void EncodeBC6HU(uint8_t *pBC, const PixelBlockF16 *pBlocks, const Options &options);
void EncodeBC6HS(uint8_t *pBC, const PixelBlockF16 *pBlocks, const Options &options);
void EncodeBC7(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
void DecodeBC6HU(PixelBlockF16 *pBlocks, const uint8_t *pBC);
void DecodeBC6HS(PixelBlockF16 *pBlocks, const uint8_t *pBC);
void DecodeBC7(PixelBlockU8 *pBlocks, const uint8_t *pBC);
}
}
#endif

File diff suppressed because it is too large Load diff

45
thirdparty/cvtt/LICENSE.txt vendored Normal file
View file

@ -0,0 +1,45 @@
Convection Texture Tools Stand-Alone Kernels
Copyright (c) 2018 Eric Lasota
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************
Based on DirectX Texture Library
Copyright (c) 2018 Microsoft Corp
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.