-Added EXR supprot for HDR (no BC6 compression yet though)
-Improvements to texture importer -Proper detection of S3TC compression modes, and added all modes to Image -Fixes to non-power of 2 compressed textures, which should all be supported by GLES3
This commit is contained in:
parent
41918f328a
commit
f89641907f
18 changed files with 13368 additions and 118 deletions
512
core/image.cpp
512
core/image.cpp
|
@ -45,7 +45,6 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
|
||||||
"RedGreen",
|
"RedGreen",
|
||||||
"RGB8",
|
"RGB8",
|
||||||
"RGBA8",
|
"RGBA8",
|
||||||
"RGB565", //16 bit
|
|
||||||
"RGBA4444",
|
"RGBA4444",
|
||||||
"RGBA5551",
|
"RGBA5551",
|
||||||
"RFloat", //float
|
"RFloat", //float
|
||||||
|
@ -56,11 +55,14 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
|
||||||
"RGHalf",
|
"RGHalf",
|
||||||
"RGBHalf",
|
"RGBHalf",
|
||||||
"RGBAHalf",
|
"RGBAHalf",
|
||||||
"DXT1", //s3tc
|
"RGBE9995",
|
||||||
"DXT3",
|
"DXT1 RGB8", //s3tc
|
||||||
"DXT5",
|
"DXT3 RGBA8",
|
||||||
"ATI1",
|
"DXT5 RGBA8",
|
||||||
"ATI2",
|
"LATC Lum8",
|
||||||
|
"LATC LumAlpha8",
|
||||||
|
"RGTC Red8",
|
||||||
|
"RGTC RedGreen8",
|
||||||
"BPTC_RGBA",
|
"BPTC_RGBA",
|
||||||
"BPTC_RGBF",
|
"BPTC_RGBF",
|
||||||
"BPTC_RGBFU",
|
"BPTC_RGBFU",
|
||||||
|
@ -110,8 +112,6 @@ int Image::get_format_pixel_size(Format p_format) {
|
||||||
case FORMAT_RG8: return 2;
|
case FORMAT_RG8: return 2;
|
||||||
case FORMAT_RGB8: return 3;
|
case FORMAT_RGB8: return 3;
|
||||||
case FORMAT_RGBA8: return 4;
|
case FORMAT_RGBA8: return 4;
|
||||||
case FORMAT_RGB565:
|
|
||||||
return 2; //16 bit
|
|
||||||
case FORMAT_RGBA4444: return 2;
|
case FORMAT_RGBA4444: return 2;
|
||||||
case FORMAT_RGBA5551: return 2;
|
case FORMAT_RGBA5551: return 2;
|
||||||
case FORMAT_RF:
|
case FORMAT_RF:
|
||||||
|
@ -122,17 +122,20 @@ int Image::get_format_pixel_size(Format p_format) {
|
||||||
case FORMAT_RH:
|
case FORMAT_RH:
|
||||||
return 2; //half float
|
return 2; //half float
|
||||||
case FORMAT_RGH: return 4;
|
case FORMAT_RGH: return 4;
|
||||||
case FORMAT_RGBH: return 8;
|
case FORMAT_RGBH: return 6;
|
||||||
case FORMAT_RGBAH: return 12;
|
case FORMAT_RGBAH: return 8;
|
||||||
|
case FORMAT_RGBE9995: return 4;
|
||||||
case FORMAT_DXT1:
|
case FORMAT_DXT1:
|
||||||
return 1; //s3tc bc1
|
return 1; //s3tc bc1
|
||||||
case FORMAT_DXT3:
|
case FORMAT_DXT3:
|
||||||
return 1; //bc2
|
return 1; //bc2
|
||||||
case FORMAT_DXT5:
|
case FORMAT_DXT5:
|
||||||
return 1; //bc3
|
return 1; //bc3
|
||||||
case FORMAT_ATI1:
|
case FORMAT_LATC_L:
|
||||||
|
case FORMAT_RGTC_R:
|
||||||
return 1; //bc4
|
return 1; //bc4
|
||||||
case FORMAT_ATI2:
|
case FORMAT_LATC_LA:
|
||||||
|
case FORMAT_RGTC_RG:
|
||||||
return 1; //bc5
|
return 1; //bc5
|
||||||
case FORMAT_BPTC_RGBA:
|
case FORMAT_BPTC_RGBA:
|
||||||
return 1; //btpc bc6h
|
return 1; //btpc bc6h
|
||||||
|
@ -168,8 +171,10 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
|
||||||
case FORMAT_DXT1: //s3tc bc1
|
case FORMAT_DXT1: //s3tc bc1
|
||||||
case FORMAT_DXT3: //bc2
|
case FORMAT_DXT3: //bc2
|
||||||
case FORMAT_DXT5: //bc3
|
case FORMAT_DXT5: //bc3
|
||||||
case FORMAT_ATI1: //bc4
|
case FORMAT_LATC_L: //bc4
|
||||||
case FORMAT_ATI2: { //bc5 case case FORMAT_DXT1:
|
case FORMAT_LATC_LA: //bc4
|
||||||
|
case FORMAT_RGTC_R: //bc4
|
||||||
|
case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
|
||||||
|
|
||||||
r_w = 4;
|
r_w = 4;
|
||||||
r_h = 4;
|
r_h = 4;
|
||||||
|
@ -220,7 +225,7 @@ 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) {
|
int Image::get_format_pixel_rshift(Format p_format) {
|
||||||
|
|
||||||
if (p_format == FORMAT_DXT1 || p_format == FORMAT_ATI1 || p_format == FORMAT_PVRTC4 || p_format == FORMAT_PVRTC4A || 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_DXT1 || p_format == FORMAT_LATC_L || p_format == FORMAT_RGTC_R || p_format == FORMAT_PVRTC4 || p_format == FORMAT_PVRTC4A || 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;
|
return 1;
|
||||||
else if (p_format == FORMAT_PVRTC2 || p_format == FORMAT_PVRTC2A)
|
else if (p_format == FORMAT_PVRTC2 || p_format == FORMAT_PVRTC2A)
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -228,6 +233,56 @@ int Image::get_format_pixel_rshift(Format p_format) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Image::get_format_block_size(Format p_format) {
|
||||||
|
|
||||||
|
switch (p_format) {
|
||||||
|
case FORMAT_DXT1: //s3tc bc1
|
||||||
|
case FORMAT_DXT3: //bc2
|
||||||
|
case FORMAT_DXT5: //bc3
|
||||||
|
case FORMAT_LATC_L: //bc4
|
||||||
|
case FORMAT_LATC_LA: //bc4
|
||||||
|
case FORMAT_RGTC_R: //bc4
|
||||||
|
case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
} break;
|
||||||
|
case FORMAT_PVRTC2:
|
||||||
|
case FORMAT_PVRTC2A: {
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
} break;
|
||||||
|
case FORMAT_PVRTC4A:
|
||||||
|
case FORMAT_PVRTC4: {
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
} break;
|
||||||
|
case FORMAT_ETC: {
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
} break;
|
||||||
|
case FORMAT_BPTC_RGBA:
|
||||||
|
case FORMAT_BPTC_RGBF:
|
||||||
|
case FORMAT_BPTC_RGBFU: {
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
} break;
|
||||||
|
case FORMAT_ETC2_R11: //etc2
|
||||||
|
case FORMAT_ETC2_R11S: //signed: NOT srgb.
|
||||||
|
case FORMAT_ETC2_RG11:
|
||||||
|
case FORMAT_ETC2_RG11S:
|
||||||
|
case FORMAT_ETC2_RGB8:
|
||||||
|
case FORMAT_ETC2_RGBA8:
|
||||||
|
case FORMAT_ETC2_RGB8A1: {
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const {
|
void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const {
|
||||||
|
|
||||||
int w = width;
|
int w = width;
|
||||||
|
@ -236,11 +291,16 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_widt
|
||||||
|
|
||||||
int pixel_size = get_format_pixel_size(format);
|
int pixel_size = get_format_pixel_size(format);
|
||||||
int pixel_rshift = get_format_pixel_rshift(format);
|
int pixel_rshift = get_format_pixel_rshift(format);
|
||||||
|
int block = get_format_block_size(format);
|
||||||
int minw, minh;
|
int minw, minh;
|
||||||
get_format_min_pixel_size(format, minw, minh);
|
get_format_min_pixel_size(format, minw, minh);
|
||||||
|
|
||||||
for (int i = 0; i < p_mipmap; i++) {
|
for (int i = 0; i < p_mipmap; i++) {
|
||||||
int s = w * h;
|
int bw = w % block != 0 ? w + (block - w % block) : w;
|
||||||
|
int bh = h % block != 0 ? h + (block - h % block) : h;
|
||||||
|
|
||||||
|
int s = bw * bh;
|
||||||
|
|
||||||
s *= pixel_size;
|
s *= pixel_size;
|
||||||
s >>= pixel_rshift;
|
s >>= pixel_rshift;
|
||||||
ofs += s;
|
ofs += s;
|
||||||
|
@ -356,10 +416,35 @@ void Image::convert(Format p_new_format) {
|
||||||
if (p_new_format == format)
|
if (p_new_format == format)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (format >= FORMAT_RGB565 || p_new_format >= FORMAT_RGB565) {
|
if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) {
|
||||||
|
|
||||||
ERR_EXPLAIN("Cannot convert to <-> from non byte formats.");
|
ERR_EXPLAIN("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
|
|
||||||
|
} else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) {
|
||||||
|
|
||||||
|
//use put/set pixel which is slower but works with non byte formats
|
||||||
|
Image new_img(width, height, 0, p_new_format);
|
||||||
|
lock();
|
||||||
|
new_img.lock();
|
||||||
|
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
for (int j = 0; j < height; j++) {
|
||||||
|
|
||||||
|
new_img.put_pixel(i, j, get_pixel(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
new_img.unlock();
|
||||||
|
|
||||||
|
if (has_mipmaps()) {
|
||||||
|
new_img.generate_mipmaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
_copy_internals_from(new_img);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image new_img(width, height, 0, p_new_format);
|
Image new_img(width, height, 0, p_new_format);
|
||||||
|
@ -801,12 +886,17 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &
|
||||||
|
|
||||||
int pixsize = get_format_pixel_size(p_format);
|
int pixsize = get_format_pixel_size(p_format);
|
||||||
int pixshift = get_format_pixel_rshift(p_format);
|
int pixshift = get_format_pixel_rshift(p_format);
|
||||||
|
int block = get_format_block_size(p_format);
|
||||||
int minw, minh;
|
int minw, minh;
|
||||||
get_format_min_pixel_size(p_format, minw, minh);
|
get_format_min_pixel_size(p_format, minw, minh);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
int s = w * h;
|
int bw = w % block != 0 ? w + (block - w % block) : w;
|
||||||
|
int bh = h % block != 0 ? h + (block - h % block) : h;
|
||||||
|
|
||||||
|
int s = bw * bh;
|
||||||
|
|
||||||
s *= pixsize;
|
s *= pixsize;
|
||||||
s >>= pixshift;
|
s >>= pixshift;
|
||||||
|
|
||||||
|
@ -834,7 +924,7 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &
|
||||||
|
|
||||||
bool Image::_can_modify(Format p_format) const {
|
bool Image::_can_modify(Format p_format) const {
|
||||||
|
|
||||||
return p_format < FORMAT_RGB565;
|
return p_format <= FORMAT_RGBE9995;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int CC>
|
template <int CC>
|
||||||
|
@ -1392,12 +1482,12 @@ int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::is_compressed() const {
|
bool Image::is_compressed() const {
|
||||||
return format >= FORMAT_RGB565;
|
return format > FORMAT_RGBE9995;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Image::decompress() {
|
Error Image::decompress() {
|
||||||
|
|
||||||
if (format >= FORMAT_DXT1 && format <= FORMAT_ATI2 && _image_decompress_bc)
|
if (format >= FORMAT_DXT1 && format <= FORMAT_BPTC_RGBFU && _image_decompress_bc)
|
||||||
_image_decompress_bc(this);
|
_image_decompress_bc(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);
|
||||||
|
@ -1414,11 +1504,6 @@ Error Image::compress(CompressMode p_mode) {
|
||||||
|
|
||||||
switch (p_mode) {
|
switch (p_mode) {
|
||||||
|
|
||||||
case COMPRESS_16BIT: {
|
|
||||||
|
|
||||||
//ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
|
|
||||||
//_image_compress_bc_func(this);
|
|
||||||
} break;
|
|
||||||
case COMPRESS_S3TC: {
|
case COMPRESS_S3TC: {
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
|
ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
|
||||||
|
@ -1624,6 +1709,361 @@ Dictionary Image::_get_data() const {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Image::lock() {
|
||||||
|
|
||||||
|
ERR_FAIL_COND(data.size() == 0);
|
||||||
|
write_lock = data.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::unlock() {
|
||||||
|
|
||||||
|
write_lock = PoolVector<uint8_t>::Write();
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Image::get_pixel(int p_x, int p_y) {
|
||||||
|
|
||||||
|
uint8_t *ptr = write_lock.ptr();
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (!ptr) {
|
||||||
|
ERR_EXPLAIN("Image must be locked with 'lock()' before using get_pixel()");
|
||||||
|
ERR_FAIL_COND_V(!ptr, Color());
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_INDEX_V(p_x, width, Color());
|
||||||
|
ERR_FAIL_INDEX_V(p_y, height, Color());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t ofs = p_y * width + p_x;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case FORMAT_L8: {
|
||||||
|
float l = ptr[ofs] / 255.0;
|
||||||
|
return Color(l, l, l, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_LA8: {
|
||||||
|
float l = ptr[ofs * 2 + 0] / 255.0;
|
||||||
|
float a = ptr[ofs * 2 + 1] / 255.0;
|
||||||
|
return Color(l, l, l, a);
|
||||||
|
} break;
|
||||||
|
case FORMAT_R8: {
|
||||||
|
|
||||||
|
float r = ptr[ofs] / 255.0;
|
||||||
|
return Color(r, 0, 0, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RG8: {
|
||||||
|
|
||||||
|
float r = ptr[ofs * 2 + 0] / 255.0;
|
||||||
|
float g = ptr[ofs * 2 + 1] / 255.0;
|
||||||
|
return Color(r, g, 0, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGB8: {
|
||||||
|
float r = ptr[ofs * 3 + 0] / 255.0;
|
||||||
|
float g = ptr[ofs * 3 + 1] / 255.0;
|
||||||
|
float b = ptr[ofs * 3 + 2] / 255.0;
|
||||||
|
return Color(r, g, b, 1);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBA8: {
|
||||||
|
float r = ptr[ofs * 4 + 0] / 255.0;
|
||||||
|
float g = ptr[ofs * 4 + 1] / 255.0;
|
||||||
|
float b = ptr[ofs * 4 + 2] / 255.0;
|
||||||
|
float a = ptr[ofs * 4 + 3] / 255.0;
|
||||||
|
return Color(r, g, b, a);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBA4444: {
|
||||||
|
uint16_t u = ((uint16_t *)ptr)[ofs];
|
||||||
|
float r = (u & 0xF) / 15.0;
|
||||||
|
float g = ((u >> 4) & 0xF) / 15.0;
|
||||||
|
float b = ((u >> 8) & 0xF) / 15.0;
|
||||||
|
float a = ((u >> 12) & 0xF) / 15.0;
|
||||||
|
return Color(r, g, b, a);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBA5551: {
|
||||||
|
|
||||||
|
uint16_t u = ((uint16_t *)ptr)[ofs];
|
||||||
|
float r = (u & 0x1F) / 15.0;
|
||||||
|
float g = ((u >> 5) & 0x1F) / 15.0;
|
||||||
|
float b = ((u >> 10) & 0x1F) / 15.0;
|
||||||
|
float a = ((u >> 15) & 0x1) / 1.0;
|
||||||
|
return Color(r, g, b, a);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RF: {
|
||||||
|
|
||||||
|
float r = ((float *)ptr)[ofs];
|
||||||
|
return Color(r, 0, 0, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGF: {
|
||||||
|
|
||||||
|
float r = ((float *)ptr)[ofs * 2 + 0];
|
||||||
|
float g = ((float *)ptr)[ofs * 2 + 1];
|
||||||
|
return Color(r, g, 0, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBF: {
|
||||||
|
|
||||||
|
float r = ((float *)ptr)[ofs * 3 + 0];
|
||||||
|
float g = ((float *)ptr)[ofs * 3 + 1];
|
||||||
|
float b = ((float *)ptr)[ofs * 3 + 2];
|
||||||
|
return Color(r, g, b, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBAF: {
|
||||||
|
|
||||||
|
float r = ((float *)ptr)[ofs * 4 + 0];
|
||||||
|
float g = ((float *)ptr)[ofs * 4 + 1];
|
||||||
|
float b = ((float *)ptr)[ofs * 4 + 2];
|
||||||
|
float a = ((float *)ptr)[ofs * 4 + 3];
|
||||||
|
return Color(r, g, b, a);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RH: {
|
||||||
|
|
||||||
|
uint16_t r = ((uint16_t *)ptr)[ofs];
|
||||||
|
return Color(Math::half_to_float(r), 0, 0, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGH: {
|
||||||
|
|
||||||
|
uint16_t r = ((uint16_t *)ptr)[ofs * 2 + 0];
|
||||||
|
uint16_t g = ((uint16_t *)ptr)[ofs * 2 + 1];
|
||||||
|
return Color(Math::half_to_float(r), Math::half_to_float(g), 0, 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBH: {
|
||||||
|
|
||||||
|
uint16_t r = ((uint16_t *)ptr)[ofs * 3 + 0];
|
||||||
|
uint16_t g = ((uint16_t *)ptr)[ofs * 3 + 1];
|
||||||
|
uint16_t b = ((uint16_t *)ptr)[ofs * 3 + 2];
|
||||||
|
return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), 1);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBAH: {
|
||||||
|
|
||||||
|
uint16_t r = ((uint16_t *)ptr)[ofs * 4 + 0];
|
||||||
|
uint16_t g = ((uint16_t *)ptr)[ofs * 4 + 1];
|
||||||
|
uint16_t b = ((uint16_t *)ptr)[ofs * 4 + 2];
|
||||||
|
uint16_t a = ((uint16_t *)ptr)[ofs * 4 + 3];
|
||||||
|
return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), Math::half_to_float(a));
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBE9995: {
|
||||||
|
uint32_t rgbe = ((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;
|
||||||
|
default: {
|
||||||
|
ERR_EXPLAIN("Can't get_pixel() on compressed image, sorry.");
|
||||||
|
ERR_FAIL_V(Color());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::put_pixel(int p_x, int p_y, const Color &p_color) {
|
||||||
|
|
||||||
|
uint8_t *ptr = write_lock.ptr();
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (!ptr) {
|
||||||
|
ERR_EXPLAIN("Image must be locked with 'lock()' before using put_pixel()");
|
||||||
|
ERR_FAIL_COND(!ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_INDEX(p_x, width);
|
||||||
|
ERR_FAIL_INDEX(p_y, height);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t ofs = p_y * width + p_x;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case FORMAT_L8: {
|
||||||
|
ptr[ofs] = uint8_t(CLAMP(p_color.gray() * 255.0, 0, 255));
|
||||||
|
} break;
|
||||||
|
case FORMAT_LA8: {
|
||||||
|
ptr[ofs * 2 + 0] = uint8_t(CLAMP(p_color.gray() * 255.0, 0, 255));
|
||||||
|
ptr[ofs * 2 + 1] = uint8_t(CLAMP(p_color.a * 255.0, 0, 255));
|
||||||
|
} break;
|
||||||
|
case FORMAT_R8: {
|
||||||
|
|
||||||
|
ptr[ofs] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
|
||||||
|
} break;
|
||||||
|
case FORMAT_RG8: {
|
||||||
|
|
||||||
|
ptr[ofs * 2 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
|
||||||
|
ptr[ofs * 2 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGB8: {
|
||||||
|
ptr[ofs * 3 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
|
||||||
|
ptr[ofs * 3 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
|
||||||
|
ptr[ofs * 3 + 2] = uint8_t(CLAMP(p_color.b * 255.0, 0, 255));
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBA8: {
|
||||||
|
ptr[ofs * 4 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
|
||||||
|
ptr[ofs * 4 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
|
||||||
|
ptr[ofs * 4 + 2] = uint8_t(CLAMP(p_color.b * 255.0, 0, 255));
|
||||||
|
ptr[ofs * 4 + 3] = uint8_t(CLAMP(p_color.a * 255.0, 0, 255));
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBA4444: {
|
||||||
|
|
||||||
|
uint16_t rgba = 0;
|
||||||
|
|
||||||
|
rgba = uint16_t(CLAMP(p_color.r * 15.0, 0, 15));
|
||||||
|
rgba |= uint16_t(CLAMP(p_color.g * 15.0, 0, 15)) << 4;
|
||||||
|
rgba |= uint16_t(CLAMP(p_color.b * 15.0, 0, 15)) << 8;
|
||||||
|
rgba |= uint16_t(CLAMP(p_color.a * 15.0, 0, 15)) << 12;
|
||||||
|
|
||||||
|
((uint16_t *)ptr)[ofs] = rgba;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBA5551: {
|
||||||
|
|
||||||
|
uint16_t rgba = 0;
|
||||||
|
|
||||||
|
rgba = uint16_t(CLAMP(p_color.r * 31.0, 0, 31));
|
||||||
|
rgba |= uint16_t(CLAMP(p_color.g * 31.0, 0, 31)) << 5;
|
||||||
|
rgba |= uint16_t(CLAMP(p_color.b * 31.0, 0, 31)) << 10;
|
||||||
|
rgba |= uint16_t(p_color.a > 0.5 ? 1 : 0) << 15;
|
||||||
|
|
||||||
|
((uint16_t *)ptr)[ofs] = rgba;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case FORMAT_RF: {
|
||||||
|
|
||||||
|
((float *)ptr)[ofs] = p_color.r;
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGF: {
|
||||||
|
|
||||||
|
((float *)ptr)[ofs * 2 + 0] = p_color.r;
|
||||||
|
((float *)ptr)[ofs * 2 + 1] = p_color.g;
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBF: {
|
||||||
|
|
||||||
|
((float *)ptr)[ofs * 3 + 0] = p_color.r;
|
||||||
|
((float *)ptr)[ofs * 3 + 1] = p_color.g;
|
||||||
|
((float *)ptr)[ofs * 3 + 2] = p_color.b;
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBAF: {
|
||||||
|
|
||||||
|
((float *)ptr)[ofs * 4 + 0] = p_color.r;
|
||||||
|
((float *)ptr)[ofs * 4 + 1] = p_color.g;
|
||||||
|
((float *)ptr)[ofs * 4 + 2] = p_color.b;
|
||||||
|
((float *)ptr)[ofs * 4 + 3] = p_color.a;
|
||||||
|
} break;
|
||||||
|
case FORMAT_RH: {
|
||||||
|
|
||||||
|
((uint16_t *)ptr)[ofs] = Math::make_half_float(p_color.r);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGH: {
|
||||||
|
|
||||||
|
((uint16_t *)ptr)[ofs * 2 + 0] = Math::make_half_float(p_color.r);
|
||||||
|
((uint16_t *)ptr)[ofs * 2 + 1] = Math::make_half_float(p_color.g);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBH: {
|
||||||
|
|
||||||
|
((uint16_t *)ptr)[ofs * 3 + 0] = Math::make_half_float(p_color.r);
|
||||||
|
((uint16_t *)ptr)[ofs * 3 + 1] = Math::make_half_float(p_color.g);
|
||||||
|
((uint16_t *)ptr)[ofs * 3 + 2] = Math::make_half_float(p_color.b);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBAH: {
|
||||||
|
|
||||||
|
((uint16_t *)ptr)[ofs * 4 + 0] = Math::make_half_float(p_color.r);
|
||||||
|
((uint16_t *)ptr)[ofs * 4 + 1] = Math::make_half_float(p_color.g);
|
||||||
|
((uint16_t *)ptr)[ofs * 4 + 2] = Math::make_half_float(p_color.b);
|
||||||
|
((uint16_t *)ptr)[ofs * 4 + 3] = Math::make_half_float(p_color.a);
|
||||||
|
} break;
|
||||||
|
case FORMAT_RGBE9995: {
|
||||||
|
|
||||||
|
const float pow2to9 = 512.0f;
|
||||||
|
const float B = 7.0f;
|
||||||
|
//const float Emax = 31.0f;
|
||||||
|
const float N = 9.0f;
|
||||||
|
|
||||||
|
float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f);
|
||||||
|
|
||||||
|
float cRed = MAX(0.0f, MIN(sharedexp, p_color.r));
|
||||||
|
float cGreen = MAX(0.0f, MIN(sharedexp, p_color.g));
|
||||||
|
float cBlue = MAX(0.0f, MIN(sharedexp, p_color.b));
|
||||||
|
|
||||||
|
float cMax = MAX(cRed, MAX(cGreen, cBlue));
|
||||||
|
|
||||||
|
// expp = MAX(-B - 1, log2(maxc)) + 1 + B
|
||||||
|
float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math::log(2.0))) + 1.0f + B;
|
||||||
|
|
||||||
|
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
|
||||||
|
|
||||||
|
float exps = expp + 1.0f;
|
||||||
|
|
||||||
|
if (0.0 <= sMax && sMax < pow2to9) {
|
||||||
|
exps = expp;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sRed = (cRed / pow(2.0f, exps - B - N)) + 0.5f;
|
||||||
|
float sGreen = (cGreen / pow(2.0f, exps - B - N)) + 0.5f;
|
||||||
|
float sBlue = (cBlue / pow(2.0f, exps - B - N)) + 0.5f;
|
||||||
|
|
||||||
|
((uint32_t *)ptr)[ofs] = ((uint32_t)(sRed)&0x1FF) | (((uint32_t)(sGreen)&0x1FF) << 9) | (((uint32_t)(sBlue)&0x1FF) << 18) | (((uint32_t)(exps)&0x1F) << 27);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
ERR_EXPLAIN("Can't put_pixel() on compressed image, sorry.");
|
||||||
|
ERR_FAIL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::DetectChannels Image::get_detected_channels() {
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(data.size() == 0, DETECTED_RGBA);
|
||||||
|
ERR_FAIL_COND_V(is_compressed(), DETECTED_RGBA);
|
||||||
|
bool r = false, g = false, b = false, a = false, c = false;
|
||||||
|
lock();
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
for (int j = 0; j < height; j++) {
|
||||||
|
|
||||||
|
Color col = get_pixel(i, j);
|
||||||
|
|
||||||
|
if (col.r > 0.001)
|
||||||
|
r = true;
|
||||||
|
if (col.g > 0.001)
|
||||||
|
g = true;
|
||||||
|
if (col.b > 0.001)
|
||||||
|
b = true;
|
||||||
|
if (col.a < 0.999)
|
||||||
|
a = true;
|
||||||
|
|
||||||
|
if (col.r != col.b || col.r != col.g || col.b != col.g) {
|
||||||
|
c = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
if (!c && !a)
|
||||||
|
return DETECTED_L;
|
||||||
|
if (!c && a)
|
||||||
|
return DETECTED_LA;
|
||||||
|
|
||||||
|
if (r && !g && !b && !a)
|
||||||
|
return DETECTED_R;
|
||||||
|
|
||||||
|
if (r && g && !b && !a)
|
||||||
|
return DETECTED_RG;
|
||||||
|
|
||||||
|
if (r && g && b && !a)
|
||||||
|
return DETECTED_RGB;
|
||||||
|
|
||||||
|
return DETECTED_RGBA;
|
||||||
|
}
|
||||||
|
|
||||||
void Image::_bind_methods() {
|
void Image::_bind_methods() {
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_width"), &Image::get_width);
|
ClassDB::bind_method(D_METHOD("get_width"), &Image::get_width);
|
||||||
|
@ -1677,6 +2117,11 @@ void Image::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Image::_set_data);
|
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Image::_set_data);
|
||||||
ClassDB::bind_method(D_METHOD("_get_data"), &Image::_get_data);
|
ClassDB::bind_method(D_METHOD("_get_data"), &Image::_get_data);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("lock"), &Image::lock);
|
||||||
|
ClassDB::bind_method(D_METHOD("unlock"), &Image::unlock);
|
||||||
|
ClassDB::bind_method(D_METHOD("put_pixel", "x", "y", "color"), &Image::put_pixel);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_pixel", "x", "y"), &Image::get_pixel);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
|
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
|
||||||
|
|
||||||
BIND_CONSTANT(FORMAT_L8); //luminance
|
BIND_CONSTANT(FORMAT_L8); //luminance
|
||||||
|
@ -1685,7 +2130,6 @@ void Image::_bind_methods() {
|
||||||
BIND_CONSTANT(FORMAT_RG8);
|
BIND_CONSTANT(FORMAT_RG8);
|
||||||
BIND_CONSTANT(FORMAT_RGB8);
|
BIND_CONSTANT(FORMAT_RGB8);
|
||||||
BIND_CONSTANT(FORMAT_RGBA8);
|
BIND_CONSTANT(FORMAT_RGBA8);
|
||||||
BIND_CONSTANT(FORMAT_RGB565); //16 bit
|
|
||||||
BIND_CONSTANT(FORMAT_RGBA4444);
|
BIND_CONSTANT(FORMAT_RGBA4444);
|
||||||
BIND_CONSTANT(FORMAT_RGBA5551);
|
BIND_CONSTANT(FORMAT_RGBA5551);
|
||||||
BIND_CONSTANT(FORMAT_RF); //float
|
BIND_CONSTANT(FORMAT_RF); //float
|
||||||
|
@ -1696,11 +2140,14 @@ void Image::_bind_methods() {
|
||||||
BIND_CONSTANT(FORMAT_RGH);
|
BIND_CONSTANT(FORMAT_RGH);
|
||||||
BIND_CONSTANT(FORMAT_RGBH);
|
BIND_CONSTANT(FORMAT_RGBH);
|
||||||
BIND_CONSTANT(FORMAT_RGBAH);
|
BIND_CONSTANT(FORMAT_RGBAH);
|
||||||
|
BIND_CONSTANT(FORMAT_RGBE9995);
|
||||||
BIND_CONSTANT(FORMAT_DXT1); //s3tc bc1
|
BIND_CONSTANT(FORMAT_DXT1); //s3tc bc1
|
||||||
BIND_CONSTANT(FORMAT_DXT3); //bc2
|
BIND_CONSTANT(FORMAT_DXT3); //bc2
|
||||||
BIND_CONSTANT(FORMAT_DXT5); //bc3
|
BIND_CONSTANT(FORMAT_DXT5); //bc3
|
||||||
BIND_CONSTANT(FORMAT_ATI1); //bc4
|
BIND_CONSTANT(FORMAT_LATC_L);
|
||||||
BIND_CONSTANT(FORMAT_ATI2); //bc5
|
BIND_CONSTANT(FORMAT_LATC_LA);
|
||||||
|
BIND_CONSTANT(FORMAT_RGTC_R);
|
||||||
|
BIND_CONSTANT(FORMAT_RGTC_RG);
|
||||||
BIND_CONSTANT(FORMAT_BPTC_RGBA); //btpc bc6h
|
BIND_CONSTANT(FORMAT_BPTC_RGBA); //btpc bc6h
|
||||||
BIND_CONSTANT(FORMAT_BPTC_RGBF); //float /
|
BIND_CONSTANT(FORMAT_BPTC_RGBF); //float /
|
||||||
BIND_CONSTANT(FORMAT_BPTC_RGBFU); //unsigned float
|
BIND_CONSTANT(FORMAT_BPTC_RGBFU); //unsigned float
|
||||||
|
@ -1726,7 +2173,6 @@ void Image::_bind_methods() {
|
||||||
BIND_CONSTANT(ALPHA_BIT);
|
BIND_CONSTANT(ALPHA_BIT);
|
||||||
BIND_CONSTANT(ALPHA_BLEND);
|
BIND_CONSTANT(ALPHA_BLEND);
|
||||||
|
|
||||||
BIND_CONSTANT(COMPRESS_16BIT);
|
|
||||||
BIND_CONSTANT(COMPRESS_S3TC);
|
BIND_CONSTANT(COMPRESS_S3TC);
|
||||||
BIND_CONSTANT(COMPRESS_PVRTC2);
|
BIND_CONSTANT(COMPRESS_PVRTC2);
|
||||||
BIND_CONSTANT(COMPRESS_PVRTC4);
|
BIND_CONSTANT(COMPRESS_PVRTC4);
|
||||||
|
@ -1924,4 +2370,8 @@ Image::Image() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::~Image() {
|
Image::~Image() {
|
||||||
|
|
||||||
|
if (write_lock.ptr()) {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
40
core/image.h
40
core/image.h
|
@ -66,7 +66,6 @@ public:
|
||||||
FORMAT_RG8,
|
FORMAT_RG8,
|
||||||
FORMAT_RGB8,
|
FORMAT_RGB8,
|
||||||
FORMAT_RGBA8,
|
FORMAT_RGBA8,
|
||||||
FORMAT_RGB565, //16 bit
|
|
||||||
FORMAT_RGBA4444,
|
FORMAT_RGBA4444,
|
||||||
FORMAT_RGBA5551,
|
FORMAT_RGBA5551,
|
||||||
FORMAT_RF, //float
|
FORMAT_RF, //float
|
||||||
|
@ -77,14 +76,17 @@ public:
|
||||||
FORMAT_RGH,
|
FORMAT_RGH,
|
||||||
FORMAT_RGBH,
|
FORMAT_RGBH,
|
||||||
FORMAT_RGBAH,
|
FORMAT_RGBAH,
|
||||||
|
FORMAT_RGBE9995,
|
||||||
FORMAT_DXT1, //s3tc bc1
|
FORMAT_DXT1, //s3tc bc1
|
||||||
FORMAT_DXT3, //bc2
|
FORMAT_DXT3, //bc2
|
||||||
FORMAT_DXT5, //bc3
|
FORMAT_DXT5, //bc3
|
||||||
FORMAT_ATI1, //bc4
|
FORMAT_LATC_L,
|
||||||
FORMAT_ATI2, //bc5
|
FORMAT_LATC_LA,
|
||||||
FORMAT_BPTC_RGBA, //btpc bc6h
|
FORMAT_RGTC_R,
|
||||||
FORMAT_BPTC_RGBF, //float /
|
FORMAT_RGTC_RG,
|
||||||
FORMAT_BPTC_RGBFU, //unsigned float
|
FORMAT_BPTC_RGBA, //btpc bc7
|
||||||
|
FORMAT_BPTC_RGBF, //float bc6h
|
||||||
|
FORMAT_BPTC_RGBFU, //unsigned float bc6hu
|
||||||
FORMAT_PVRTC2, //pvrtc
|
FORMAT_PVRTC2, //pvrtc
|
||||||
FORMAT_PVRTC2A,
|
FORMAT_PVRTC2A,
|
||||||
FORMAT_PVRTC4,
|
FORMAT_PVRTC4,
|
||||||
|
@ -125,13 +127,13 @@ public:
|
||||||
static void (*_image_decompress_etc)(Image *);
|
static void (*_image_decompress_etc)(Image *);
|
||||||
static void (*_image_decompress_etc2)(Image *);
|
static void (*_image_decompress_etc2)(Image *);
|
||||||
|
|
||||||
Error _decompress_bc();
|
|
||||||
|
|
||||||
static PoolVector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality);
|
static PoolVector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality);
|
||||||
static Ref<Image> (*lossy_unpacker)(const PoolVector<uint8_t> &p_buffer);
|
static Ref<Image> (*lossy_unpacker)(const PoolVector<uint8_t> &p_buffer);
|
||||||
static PoolVector<uint8_t> (*lossless_packer)(const Ref<Image> &p_image);
|
static PoolVector<uint8_t> (*lossless_packer)(const Ref<Image> &p_image);
|
||||||
static Ref<Image> (*lossless_unpacker)(const PoolVector<uint8_t> &p_buffer);
|
static Ref<Image> (*lossless_unpacker)(const PoolVector<uint8_t> &p_buffer);
|
||||||
|
|
||||||
|
PoolVector<uint8_t>::Write write_lock;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
@ -253,18 +255,18 @@ public:
|
||||||
|
|
||||||
static int get_format_pixel_size(Format p_format);
|
static int get_format_pixel_size(Format p_format);
|
||||||
static int get_format_pixel_rshift(Format p_format);
|
static int get_format_pixel_rshift(Format p_format);
|
||||||
|
static int get_format_block_size(Format p_format);
|
||||||
static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h);
|
static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h);
|
||||||
|
|
||||||
static int get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps = 0);
|
static int get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps = 0);
|
||||||
static int get_image_required_mipmaps(int p_width, int p_height, Format p_format);
|
static int get_image_required_mipmaps(int p_width, int p_height, Format p_format);
|
||||||
|
|
||||||
enum CompressMode {
|
enum CompressMode {
|
||||||
COMPRESS_16BIT,
|
|
||||||
COMPRESS_S3TC,
|
COMPRESS_S3TC,
|
||||||
COMPRESS_PVRTC2,
|
COMPRESS_PVRTC2,
|
||||||
COMPRESS_PVRTC4,
|
COMPRESS_PVRTC4,
|
||||||
COMPRESS_ETC,
|
COMPRESS_ETC,
|
||||||
COMPRESS_ETC2
|
COMPRESS_ETC2,
|
||||||
};
|
};
|
||||||
|
|
||||||
Error compress(CompressMode p_mode = COMPRESS_S3TC);
|
Error compress(CompressMode p_mode = COMPRESS_S3TC);
|
||||||
|
@ -289,6 +291,24 @@ public:
|
||||||
|
|
||||||
virtual Ref<Resource> duplicate(bool p_subresources = false) const;
|
virtual Ref<Resource> duplicate(bool p_subresources = false) const;
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
//this is used for compression
|
||||||
|
enum DetectChannels {
|
||||||
|
DETECTED_L,
|
||||||
|
DETECTED_LA,
|
||||||
|
DETECTED_R,
|
||||||
|
DETECTED_RG,
|
||||||
|
DETECTED_RGB,
|
||||||
|
DETECTED_RGBA,
|
||||||
|
};
|
||||||
|
|
||||||
|
DetectChannels get_detected_channels();
|
||||||
|
|
||||||
|
Color get_pixel(int p_x, int p_y);
|
||||||
|
void put_pixel(int p_x, int p_y, const Color &p_color);
|
||||||
|
|
||||||
void copy_internals_from(const Ref<Image> &p_image) {
|
void copy_internals_from(const Ref<Image> &p_image) {
|
||||||
ERR_FAIL_COND(p_image.is_null());
|
ERR_FAIL_COND(p_image.is_null());
|
||||||
format = p_image->format;
|
format = p_image->format;
|
||||||
|
|
|
@ -278,6 +278,10 @@ public:
|
||||||
return u.f32;
|
return u.f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _ALWAYS_INLINE_ float half_to_float(const uint16_t h) {
|
||||||
|
return halfptr_to_float(&h);
|
||||||
|
}
|
||||||
|
|
||||||
static _ALWAYS_INLINE_ uint16_t make_half_float(float f) {
|
static _ALWAYS_INLINE_ uint16_t make_half_float(float f) {
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
|
|
@ -163,18 +163,6 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
|
||||||
r_gl_type = GL_UNSIGNED_BYTE;
|
r_gl_type = GL_UNSIGNED_BYTE;
|
||||||
srgb = true;
|
srgb = true;
|
||||||
|
|
||||||
} break;
|
|
||||||
case Image::FORMAT_RGB565: {
|
|
||||||
#ifndef GLES_OVER_GL
|
|
||||||
r_gl_internal_format = GL_RGB565;
|
|
||||||
#else
|
|
||||||
//#warning TODO: Convert tod 555 if 565 is not supported (GLES3.3-)
|
|
||||||
r_gl_internal_format = GL_RGB5;
|
|
||||||
#endif
|
|
||||||
//r_gl_internal_format=GL_RGB565;
|
|
||||||
r_gl_format = GL_RGB;
|
|
||||||
r_gl_type = GL_UNSIGNED_SHORT_5_6_5;
|
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Image::FORMAT_RGBA4444: {
|
case Image::FORMAT_RGBA4444: {
|
||||||
|
|
||||||
|
@ -240,6 +228,12 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
|
||||||
r_gl_format = GL_RGBA;
|
r_gl_format = GL_RGBA;
|
||||||
r_gl_type = GL_HALF_FLOAT;
|
r_gl_type = GL_HALF_FLOAT;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Image::FORMAT_RGBE9995: {
|
||||||
|
r_gl_internal_format = GL_RGB9_E5;
|
||||||
|
r_gl_format = GL_RGB;
|
||||||
|
r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Image::FORMAT_DXT1: {
|
case Image::FORMAT_DXT1: {
|
||||||
|
|
||||||
|
@ -289,7 +283,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Image::FORMAT_ATI1: {
|
case Image::FORMAT_LATC_L: {
|
||||||
|
|
||||||
if (config.latc_supported) {
|
if (config.latc_supported) {
|
||||||
|
|
||||||
|
@ -305,7 +299,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Image::FORMAT_ATI2: {
|
case Image::FORMAT_LATC_LA: {
|
||||||
|
|
||||||
if (config.latc_supported) {
|
if (config.latc_supported) {
|
||||||
|
|
||||||
|
@ -318,6 +312,36 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
|
||||||
need_decompress = true;
|
need_decompress = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Image::FORMAT_RGTC_R: {
|
||||||
|
|
||||||
|
if (config.rgtc_supported) {
|
||||||
|
|
||||||
|
r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT;
|
||||||
|
r_gl_format = GL_RGBA;
|
||||||
|
r_gl_type = GL_UNSIGNED_BYTE;
|
||||||
|
r_compressed = true;
|
||||||
|
srgb = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
need_decompress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Image::FORMAT_RGTC_RG: {
|
||||||
|
|
||||||
|
if (config.rgtc_supported) {
|
||||||
|
|
||||||
|
r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT;
|
||||||
|
r_gl_format = GL_RGBA;
|
||||||
|
r_gl_type = GL_UNSIGNED_BYTE;
|
||||||
|
r_compressed = true;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
need_decompress = true;
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Image::FORMAT_BPTC_RGBA: {
|
case Image::FORMAT_BPTC_RGBA: {
|
||||||
|
|
||||||
|
@ -662,7 +686,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
|
||||||
if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) {
|
if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) {
|
||||||
|
|
||||||
img->shrink_x2();
|
img->shrink_x2();
|
||||||
} else if (img->get_format() <= Image::FORMAT_RGB565) {
|
} else if (img->get_format() <= Image::FORMAT_RGBA8) {
|
||||||
|
|
||||||
img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR);
|
img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR);
|
||||||
}
|
}
|
||||||
|
@ -768,6 +792,9 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
|
||||||
int h = img->get_height();
|
int h = img->get_height();
|
||||||
|
|
||||||
int tsize = 0;
|
int tsize = 0;
|
||||||
|
|
||||||
|
int block = Image::get_format_block_size(img->get_format());
|
||||||
|
|
||||||
for (int i = 0; i < mipmaps; i++) {
|
for (int i = 0; i < mipmaps; i++) {
|
||||||
|
|
||||||
int size, ofs;
|
int size, ofs;
|
||||||
|
@ -777,7 +804,16 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
|
||||||
|
|
||||||
if (texture->compressed) {
|
if (texture->compressed) {
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||||
glCompressedTexImage2D(blit_target, i, internal_format, w, h, 0, size, &read[ofs]);
|
|
||||||
|
//this is not needed, as compressed takes the regular size, even if blocks extend it
|
||||||
|
//int bw = (w % block != 0) ? w + (block - w % block) : w;
|
||||||
|
//int bh = (h % block != 0) ? h + (block - h % block) : h;
|
||||||
|
|
||||||
|
int bw = w;
|
||||||
|
int bh = h;
|
||||||
|
|
||||||
|
glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
|
||||||
|
print_line("format: " + Image::get_format_name(texture->format) + " size: " + Vector2(bw, bh) + " block: " + itos(block));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
@ -6358,6 +6394,7 @@ void RasterizerStorageGLES3::initialize() {
|
||||||
config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc");
|
config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc");
|
||||||
config.etc_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture");
|
config.etc_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture");
|
||||||
config.latc_supported = config.extensions.has("GL_EXT_texture_compression_latc");
|
config.latc_supported = config.extensions.has("GL_EXT_texture_compression_latc");
|
||||||
|
config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc");
|
||||||
config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc");
|
config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc");
|
||||||
#ifdef GLES_OVER_GL
|
#ifdef GLES_OVER_GL
|
||||||
config.hdr_supported = true;
|
config.hdr_supported = true;
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
|
|
||||||
bool s3tc_supported;
|
bool s3tc_supported;
|
||||||
bool latc_supported;
|
bool latc_supported;
|
||||||
|
bool rgtc_supported;
|
||||||
bool bptc_supported;
|
bool bptc_supported;
|
||||||
bool etc_supported;
|
bool etc_supported;
|
||||||
bool etc2_supported;
|
bool etc2_supported;
|
||||||
|
|
|
@ -169,6 +169,7 @@ 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::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));
|
||||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_3D ? true : false));
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_3D ? true : false));
|
||||||
|
@ -181,7 +182,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
|
||||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "detect_3d"), p_preset == PRESET_DETECT));
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "detect_3d"), p_preset == PRESET_DETECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb) {
|
void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe) {
|
||||||
|
|
||||||
FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
|
FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
|
||||||
f->store_8('G');
|
f->store_8('G');
|
||||||
|
@ -204,6 +205,10 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
|
||||||
if (p_detect_srgb)
|
if (p_detect_srgb)
|
||||||
format |= StreamTexture::FORMAT_BIT_DETECT_SRGB;
|
format |= StreamTexture::FORMAT_BIT_DETECT_SRGB;
|
||||||
|
|
||||||
|
if ((p_compress_mode == COMPRESS_LOSSLESS || p_compress_mode == COMPRESS_LOSSY) && p_image->get_format() > Image::FORMAT_RGBA8) {
|
||||||
|
p_compress_mode == COMPRESS_UNCOMPRESSED; //these can't go as lossy
|
||||||
|
}
|
||||||
|
|
||||||
switch (p_compress_mode) {
|
switch (p_compress_mode) {
|
||||||
case COMPRESS_LOSSLESS: {
|
case COMPRESS_LOSSLESS: {
|
||||||
|
|
||||||
|
@ -267,7 +272,12 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
|
||||||
|
|
||||||
Ref<Image> image = p_image->duplicate();
|
Ref<Image> image = p_image->duplicate();
|
||||||
image->generate_mipmaps();
|
image->generate_mipmaps();
|
||||||
image->compress(p_vram_compression);
|
|
||||||
|
if (p_force_rgbe && image->get_format() >= Image::FORMAT_R8 && image->get_format() <= Image::FORMAT_RGBE9995) {
|
||||||
|
image->convert(Image::FORMAT_RGBE9995);
|
||||||
|
} else {
|
||||||
|
image->compress(p_vram_compression);
|
||||||
|
}
|
||||||
|
|
||||||
format |= image->get_format();
|
format |= image->get_format();
|
||||||
|
|
||||||
|
@ -316,6 +326,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||||
bool premult_alpha = p_options["process/premult_alpha"];
|
bool premult_alpha = p_options["process/premult_alpha"];
|
||||||
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;
|
||||||
|
|
||||||
Ref<Image> image;
|
Ref<Image> image;
|
||||||
image.instance();
|
image.instance();
|
||||||
|
@ -367,16 +378,16 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||||
if (compress_mode == COMPRESS_VIDEO_RAM) {
|
if (compress_mode == COMPRESS_VIDEO_RAM) {
|
||||||
//must import in all formats
|
//must import in all formats
|
||||||
//Android, GLES 2.x
|
//Android, GLES 2.x
|
||||||
_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb);
|
_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
||||||
r_platform_variants->push_back("etc");
|
r_platform_variants->push_back("etc");
|
||||||
//_save_stex(image,p_save_path+".etc2.stex",compress_mode,lossy,Image::COMPRESS_ETC2,mipmaps,tex_flags,stream);
|
//_save_stex(image,p_save_path+".etc2.stex",compress_mode,lossy,Image::COMPRESS_ETC2,mipmaps,tex_flags,stream);
|
||||||
//r_platform_variants->push_back("etc2");
|
//r_platform_variants->push_back("etc2");
|
||||||
_save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb);
|
_save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
||||||
r_platform_variants->push_back("s3tc");
|
r_platform_variants->push_back("s3tc");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//import normally
|
//import normally
|
||||||
_save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_16BIT /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb);
|
_save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|
|
@ -80,7 +80,7 @@ public:
|
||||||
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
|
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
|
||||||
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
|
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
|
||||||
|
|
||||||
void _save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb);
|
void _save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe);
|
||||||
|
|
||||||
virtual Error 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 = NULL);
|
virtual Error 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 = NULL);
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,8 @@ void TextureEditor::_notification(int p_what) {
|
||||||
String format;
|
String format;
|
||||||
if (texture->cast_to<ImageTexture>()) {
|
if (texture->cast_to<ImageTexture>()) {
|
||||||
format = Image::get_format_name(texture->cast_to<ImageTexture>()->get_format());
|
format = Image::get_format_name(texture->cast_to<ImageTexture>()->get_format());
|
||||||
|
} else if (texture->cast_to<StreamTexture>()) {
|
||||||
|
format = Image::get_format_name(texture->cast_to<StreamTexture>()->get_format());
|
||||||
} else {
|
} else {
|
||||||
format = texture->get_class();
|
format = texture->get_class();
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,8 +76,8 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
|
||||||
{ "DXT1", true, false, 4, 8, Image::FORMAT_DXT1 },
|
{ "DXT1", true, false, 4, 8, Image::FORMAT_DXT1 },
|
||||||
{ "DXT3", true, false, 4, 16, Image::FORMAT_DXT3 },
|
{ "DXT3", true, false, 4, 16, Image::FORMAT_DXT3 },
|
||||||
{ "DXT5", true, false, 4, 16, Image::FORMAT_DXT5 },
|
{ "DXT5", true, false, 4, 16, Image::FORMAT_DXT5 },
|
||||||
{ "ATI1", true, false, 4, 8, Image::FORMAT_ATI1 },
|
{ "ATI1", true, false, 4, 8, Image::FORMAT_LATC_L },
|
||||||
{ "ATI2", true, false, 4, 16, Image::FORMAT_ATI2 },
|
{ "ATI2", true, false, 4, 16, Image::FORMAT_LATC_LA },
|
||||||
{ "BGRA8", false, false, 1, 4, Image::FORMAT_RGBA8 },
|
{ "BGRA8", false, false, 1, 4, Image::FORMAT_RGBA8 },
|
||||||
{ "BGR8", false, false, 1, 3, Image::FORMAT_RGB8 },
|
{ "BGR8", false, false, 1, 3, Image::FORMAT_RGB8 },
|
||||||
{ "RGBA8", false, false, 1, 4, Image::FORMAT_RGBA8 },
|
{ "RGBA8", false, false, 1, 4, Image::FORMAT_RGBA8 },
|
||||||
|
|
|
@ -59,9 +59,9 @@ void image_decompress_squish(Image *p_image) {
|
||||||
squish_flags = squish::kDxt3;
|
squish_flags = squish::kDxt3;
|
||||||
} else if (p_image->get_format() == Image::FORMAT_DXT5) {
|
} else if (p_image->get_format() == Image::FORMAT_DXT5) {
|
||||||
squish_flags = squish::kDxt5;
|
squish_flags = squish::kDxt5;
|
||||||
} else if (p_image->get_format() == Image::FORMAT_ATI1) {
|
} else if (p_image->get_format() == Image::FORMAT_LATC_L || p_image->get_format() == Image::FORMAT_RGTC_R) {
|
||||||
squish_flags = squish::kBc4;
|
squish_flags = squish::kBc4;
|
||||||
} else if (p_image->get_format() == Image::FORMAT_ATI2) {
|
} else if (p_image->get_format() == Image::FORMAT_LATC_LA || p_image->get_format() == Image::FORMAT_RGTC_RG) {
|
||||||
squish_flags = squish::kBc5;
|
squish_flags = squish::kBc5;
|
||||||
} else {
|
} else {
|
||||||
ERR_FAIL_COND(true);
|
ERR_FAIL_COND(true);
|
||||||
|
@ -81,61 +81,82 @@ void image_decompress_squish(Image *p_image) {
|
||||||
|
|
||||||
void image_compress_squish(Image *p_image) {
|
void image_compress_squish(Image *p_image) {
|
||||||
|
|
||||||
int w = p_image->get_width();
|
|
||||||
int h = p_image->get_height();
|
|
||||||
|
|
||||||
if (!p_image->has_mipmaps()) {
|
|
||||||
ERR_FAIL_COND(!w || w % 4 != 0);
|
|
||||||
ERR_FAIL_COND(!h || h % 4 != 0);
|
|
||||||
} else {
|
|
||||||
ERR_FAIL_COND(!w || w != nearest_power_of_2(w));
|
|
||||||
ERR_FAIL_COND(!h || h != nearest_power_of_2(h));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (p_image->get_format() >= Image::FORMAT_DXT1)
|
if (p_image->get_format() >= Image::FORMAT_DXT1)
|
||||||
return; //do not compress, already compressed
|
return; //do not compress, already compressed
|
||||||
|
|
||||||
int shift = 0;
|
int w = p_image->get_width();
|
||||||
int squish_comp = squish::kColourRangeFit; // TODO: use lossy quality setting to determine the quality
|
int h = p_image->get_height();
|
||||||
Image::Format target_format;
|
|
||||||
|
|
||||||
if (p_image->get_format() == Image::FORMAT_LA8) {
|
if (p_image->get_format() <= Image::FORMAT_RGBA8) {
|
||||||
//compressed normalmap
|
|
||||||
target_format = Image::FORMAT_DXT5;
|
|
||||||
squish_comp |= squish::kDxt5;
|
|
||||||
} else if (p_image->detect_alpha() != Image::ALPHA_NONE) {
|
|
||||||
|
|
||||||
target_format = Image::FORMAT_DXT3;
|
int squish_comp = squish::kColourRangeFit;
|
||||||
squish_comp |= squish::kDxt3;
|
Image::Format target_format;
|
||||||
} else {
|
|
||||||
target_format = Image::FORMAT_DXT1;
|
Image::DetectChannels dc = p_image->get_detected_channels();
|
||||||
shift = 1;
|
|
||||||
squish_comp |= squish::kDxt1;
|
p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
|
||||||
|
|
||||||
|
switch (dc) {
|
||||||
|
case Image::DETECTED_L: {
|
||||||
|
|
||||||
|
target_format = Image::FORMAT_LATC_L;
|
||||||
|
squish_comp |= squish::kBc4;
|
||||||
|
} break;
|
||||||
|
case Image::DETECTED_LA: {
|
||||||
|
|
||||||
|
target_format = Image::FORMAT_LATC_LA;
|
||||||
|
squish_comp |= squish::kBc5;
|
||||||
|
} break;
|
||||||
|
case Image::DETECTED_R: {
|
||||||
|
|
||||||
|
target_format = Image::FORMAT_RGTC_R;
|
||||||
|
squish_comp |= squish::kBc4;
|
||||||
|
} break;
|
||||||
|
case Image::DETECTED_RG: {
|
||||||
|
|
||||||
|
target_format = Image::FORMAT_RGTC_RG;
|
||||||
|
squish_comp |= squish::kBc5;
|
||||||
|
} break;
|
||||||
|
case Image::DETECTED_RGB: {
|
||||||
|
|
||||||
|
target_format = Image::FORMAT_DXT1;
|
||||||
|
squish_comp |= squish::kDxt1;
|
||||||
|
} break;
|
||||||
|
case Image::DETECTED_RGBA: {
|
||||||
|
|
||||||
|
//TODO, should convert both, then measure which one does a better job
|
||||||
|
target_format = Image::FORMAT_DXT5;
|
||||||
|
squish_comp |= squish::kDxt5;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolVector<uint8_t> data;
|
||||||
|
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
|
||||||
|
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>::Read rb = p_image->get_data().read();
|
||||||
|
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);
|
||||||
|
squish::CompressImage(&rb[src_ofs], bw, bh, &wb[dst_ofs], squish_comp);
|
||||||
|
dst_ofs += (MAX(4, w) * MAX(4, h)) >> 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
p_image->convert(Image::FORMAT_RGBA8); //always expects rgba
|
|
||||||
|
|
||||||
PoolVector<uint8_t> data;
|
|
||||||
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
|
|
||||||
int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
|
|
||||||
data.resize(target_size);
|
|
||||||
|
|
||||||
PoolVector<uint8_t>::Read rb = p_image->get_data().read();
|
|
||||||
PoolVector<uint8_t>::Write wb = data.write();
|
|
||||||
|
|
||||||
int dst_ofs = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i <= mm_count; i++) {
|
|
||||||
|
|
||||||
int src_ofs = p_image->get_mipmap_offset(i);
|
|
||||||
squish::CompressImage(&rb[src_ofs], w, h, &wb[dst_ofs], squish_comp);
|
|
||||||
dst_ofs += (MAX(4, w) * MAX(4, h)) >> 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);
|
|
||||||
}
|
}
|
||||||
|
|
20
modules/tinyexr/SCsub
Normal file
20
modules/tinyexr/SCsub
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import('env')
|
||||||
|
Import('env_modules')
|
||||||
|
|
||||||
|
env_tinyexr = env_modules.Clone()
|
||||||
|
|
||||||
|
# Thirdparty source files
|
||||||
|
# Not unbundled for now as they are not commonly available as shared library
|
||||||
|
thirdparty_dir = "#thirdparty/tinyexr/"
|
||||||
|
thirdparty_sources = [
|
||||||
|
"tinyexr.cc",
|
||||||
|
]
|
||||||
|
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||||
|
|
||||||
|
env_tinyexr.add_source_files(env.modules_sources, thirdparty_sources)
|
||||||
|
env_tinyexr.Append(CPPPATH=[thirdparty_dir])
|
||||||
|
|
||||||
|
# Godot's own source files
|
||||||
|
env_tinyexr.add_source_files(env.modules_sources, "*.cpp")
|
7
modules/tinyexr/config.py
Normal file
7
modules/tinyexr/config.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
def can_build(platform):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def configure(env):
|
||||||
|
pass
|
160
modules/tinyexr/image_loader_tinyexr.cpp
Normal file
160
modules/tinyexr/image_loader_tinyexr.cpp
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* image_loader_jpegd.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* http://www.godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2017 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_loader_tinyexr.h"
|
||||||
|
|
||||||
|
#include "os/os.h"
|
||||||
|
#include "print_string.h"
|
||||||
|
|
||||||
|
#include "thirdparty/tinyexr/tinyexr.h"
|
||||||
|
|
||||||
|
Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f) {
|
||||||
|
|
||||||
|
PoolVector<uint8_t> src_image;
|
||||||
|
int src_image_len = f->get_len();
|
||||||
|
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
|
||||||
|
src_image.resize(src_image_len);
|
||||||
|
|
||||||
|
PoolVector<uint8_t>::Write w = src_image.write();
|
||||||
|
|
||||||
|
f->get_buffer(&w[0], src_image_len);
|
||||||
|
|
||||||
|
f->close();
|
||||||
|
|
||||||
|
EXRVersion exr_version;
|
||||||
|
EXRImage exr_image;
|
||||||
|
EXRHeader exr_header;
|
||||||
|
const char *err = NULL;
|
||||||
|
|
||||||
|
InitEXRHeader(&exr_header);
|
||||||
|
|
||||||
|
int ret = ParseEXRVersionFromMemory(&exr_version, w.ptr(), src_image_len);
|
||||||
|
if (ret != TINYEXR_SUCCESS) {
|
||||||
|
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, w.ptr(), src_image_len, &err);
|
||||||
|
if (ret != TINYEXR_SUCCESS) {
|
||||||
|
if (err) {
|
||||||
|
ERR_PRINTS(String(err));
|
||||||
|
}
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitEXRImage(&exr_image);
|
||||||
|
ret = LoadEXRImageFromMemory(&exr_image, &exr_header, w.ptr(), src_image_len, &err);
|
||||||
|
if (ret != TINYEXR_SUCCESS) {
|
||||||
|
if (err) {
|
||||||
|
ERR_PRINTS(String(err));
|
||||||
|
}
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RGBA
|
||||||
|
int idxR = -1;
|
||||||
|
int idxG = -1;
|
||||||
|
int idxB = -1;
|
||||||
|
int idxA = -1;
|
||||||
|
for (int c = 0; c < exr_header.num_channels; c++) {
|
||||||
|
if (strcmp(exr_header.channels[c].name, "R") == 0) {
|
||||||
|
idxR = c;
|
||||||
|
} else if (strcmp(exr_header.channels[c].name, "G") == 0) {
|
||||||
|
idxG = c;
|
||||||
|
} else if (strcmp(exr_header.channels[c].name, "B") == 0) {
|
||||||
|
idxB = c;
|
||||||
|
} else if (strcmp(exr_header.channels[c].name, "A") == 0) {
|
||||||
|
idxA = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idxR == -1) {
|
||||||
|
ERR_PRINT("R channel not found");
|
||||||
|
// @todo { free exr_image }
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idxG == -1) {
|
||||||
|
ERR_PRINT("G channel not found\n")
|
||||||
|
// @todo { free exr_image }
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idxB == -1) {
|
||||||
|
ERR_PRINT("B channel not found\n")
|
||||||
|
// @todo { free exr_image }
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolVector<uint8_t> imgdata;
|
||||||
|
Image::Format format;
|
||||||
|
|
||||||
|
if (idxA > 0) {
|
||||||
|
|
||||||
|
imgdata.resize(exr_image.width * exr_image.height * 8); //RGBA16
|
||||||
|
format = Image::FORMAT_RGBAH;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
imgdata.resize(exr_image.width * exr_image.height * 6); //RGB16
|
||||||
|
format = Image::FORMAT_RGBH;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
PoolVector<uint8_t>::Write wd = imgdata.write();
|
||||||
|
uint16_t *iw = (uint16_t *)wd.ptr();
|
||||||
|
|
||||||
|
// Assume `out_rgba` have enough memory allocated.
|
||||||
|
for (int i = 0; i < exr_image.width * exr_image.height; i++) {
|
||||||
|
|
||||||
|
*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxR][i]);
|
||||||
|
*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxG][i]);
|
||||||
|
*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxB][i]);
|
||||||
|
|
||||||
|
if (idxA > 0) {
|
||||||
|
*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxA][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_line("EXR w: " + itos(exr_image.width) + " h:" + itos(exr_image.height) + " format " + Image::get_format_name(format));
|
||||||
|
p_image->create(exr_image.width, exr_image.height, false, format, imgdata);
|
||||||
|
|
||||||
|
w = PoolVector<uint8_t>::Write();
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageLoaderTinyEXR::get_recognized_extensions(List<String> *p_extensions) const {
|
||||||
|
|
||||||
|
p_extensions->push_back("exr");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageLoaderTinyEXR::ImageLoaderTinyEXR() {
|
||||||
|
}
|
46
modules/tinyexr/image_loader_tinyexr.h
Normal file
46
modules/tinyexr/image_loader_tinyexr.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* image_loader_jpegd.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* http://www.godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2017 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_LOADER_TINYEXR_H
|
||||||
|
#define IMAGE_LOADER_TINYEXR_H
|
||||||
|
|
||||||
|
#include "io/image_loader.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
@author Juan Linietsky <reduzio@gmail.com>
|
||||||
|
*/
|
||||||
|
class ImageLoaderTinyEXR : public ImageFormatLoader {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual Error load_image(Ref<Image> p_image, FileAccess *f);
|
||||||
|
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||||
|
ImageLoaderTinyEXR();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
45
modules/tinyexr/register_types.cpp
Normal file
45
modules/tinyexr/register_types.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* register_types.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* http://www.godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2017 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"
|
||||||
|
|
||||||
|
#include "image_loader_tinyexr.h"
|
||||||
|
|
||||||
|
static ImageLoaderTinyEXR *image_loader_tinyexr = NULL;
|
||||||
|
|
||||||
|
void register_tinyexr_types() {
|
||||||
|
|
||||||
|
image_loader_tinyexr = memnew(ImageLoaderTinyEXR);
|
||||||
|
ImageLoader::add_image_format_loader(image_loader_tinyexr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister_tinyexr_types() {
|
||||||
|
|
||||||
|
memdelete(image_loader_tinyexr);
|
||||||
|
}
|
31
modules/tinyexr/register_types.h
Normal file
31
modules/tinyexr/register_types.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* register_types.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* http://www.godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2017 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. */
|
||||||
|
/*************************************************************************/
|
||||||
|
void register_tinyexr_types();
|
||||||
|
void unregister_tinyexr_types();
|
2
thirdparty/tinyexr/tinyexr.cc
vendored
Normal file
2
thirdparty/tinyexr/tinyexr.cc
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#define TINYEXR_IMPLEMENTATION
|
||||||
|
#include "tinyexr.h"
|
12393
thirdparty/tinyexr/tinyexr.h
vendored
Normal file
12393
thirdparty/tinyexr/tinyexr.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue