30
30
31
31
#include " image.h"
32
32
33
+ #include " core/config/project_settings.h"
33
34
#include " core/error/error_list.h"
34
35
#include " core/error/error_macros.h"
35
36
#include " core/io/image_loader.h"
@@ -501,6 +502,38 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
501
502
}
502
503
}
503
504
505
+ template <typename T, uint32_t read_channels, uint32_t write_channels, T def_zero, T def_one>
506
+ static void _convert_fast (int p_width, int p_height, const T *p_src, T *p_dst) {
507
+ uint32_t dst_count = 0 ;
508
+ uint32_t src_count = 0 ;
509
+
510
+ const int resolution = p_width * p_height;
511
+
512
+ for (int i = 0 ; i < resolution; i++) {
513
+ memcpy (p_dst + dst_count, p_src + src_count, MIN (read_channels, write_channels) * sizeof (T));
514
+
515
+ if constexpr (write_channels > read_channels) {
516
+ const T def_value[4 ] = { def_zero, def_zero, def_zero, def_one };
517
+ memcpy (p_dst + dst_count + read_channels, &def_value[read_channels], (write_channels - read_channels) * sizeof (T));
518
+ }
519
+
520
+ dst_count += write_channels;
521
+ src_count += read_channels;
522
+ }
523
+ }
524
+
525
+ static bool _are_formats_compatible (Image::Format p_format0, Image::Format p_format1) {
526
+ if (p_format0 <= Image::FORMAT_RGBA8 && p_format1 <= Image::FORMAT_RGBA8) {
527
+ return true ;
528
+ } else if (p_format0 <= Image::FORMAT_RGBAH && p_format0 >= Image::FORMAT_RH && p_format1 <= Image::FORMAT_RGBAH && p_format1 >= Image::FORMAT_RH) {
529
+ return true ;
530
+ } else if (p_format0 <= Image::FORMAT_RGBAF && p_format0 >= Image::FORMAT_RF && p_format1 <= Image::FORMAT_RGBAF && p_format1 >= Image::FORMAT_RF) {
531
+ return true ;
532
+ }
533
+
534
+ return false ;
535
+ }
536
+
504
537
void Image::convert (Format p_new_format) {
505
538
ERR_FAIL_INDEX_MSG (p_new_format, FORMAT_MAX, " The Image format specified (" + itos (p_new_format) + " ) is out of range. See Image's Format enum." );
506
539
if (data.size () == 0 ) {
@@ -517,7 +550,7 @@ void Image::convert(Format p_new_format) {
517
550
if (Image::is_format_compressed (format) || Image::is_format_compressed (p_new_format)) {
518
551
ERR_FAIL_MSG (" Cannot convert to <-> from compressed formats. Use compress() and decompress() instead." );
519
552
520
- } else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8 ) {
553
+ } else if (! _are_formats_compatible ( format, p_new_format) ) {
521
554
// use put/set pixel which is slower but works with non byte formats
522
555
Image new_img (width, height, mipmaps, p_new_format);
523
556
@@ -648,6 +681,78 @@ void Image::convert(Format p_new_format) {
648
681
case FORMAT_RGBA8 | (FORMAT_RGB8 << 8 ):
649
682
_convert<3 , true , 3 , false , false , false >(mip_width, mip_height, rptr, wptr);
650
683
break ;
684
+ case FORMAT_RH | (FORMAT_RGH << 8 ):
685
+ _convert_fast<uint16_t , 1 , 2 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
686
+ break ;
687
+ case FORMAT_RH | (FORMAT_RGBH << 8 ):
688
+ _convert_fast<uint16_t , 1 , 3 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
689
+ break ;
690
+ case FORMAT_RH | (FORMAT_RGBAH << 8 ):
691
+ _convert_fast<uint16_t , 1 , 4 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
692
+ break ;
693
+ case FORMAT_RGH | (FORMAT_RH << 8 ):
694
+ _convert_fast<uint16_t , 2 , 1 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
695
+ break ;
696
+ case FORMAT_RGH | (FORMAT_RGBH << 8 ):
697
+ _convert_fast<uint16_t , 2 , 3 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
698
+ break ;
699
+ case FORMAT_RGH | (FORMAT_RGBAH << 8 ):
700
+ _convert_fast<uint16_t , 2 , 4 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
701
+ break ;
702
+ case FORMAT_RGBH | (FORMAT_RH << 8 ):
703
+ _convert_fast<uint16_t , 3 , 1 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
704
+ break ;
705
+ case FORMAT_RGBH | (FORMAT_RGH << 8 ):
706
+ _convert_fast<uint16_t , 3 , 2 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
707
+ break ;
708
+ case FORMAT_RGBH | (FORMAT_RGBAH << 8 ):
709
+ _convert_fast<uint16_t , 3 , 4 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
710
+ break ;
711
+ case FORMAT_RGBAH | (FORMAT_RH << 8 ):
712
+ _convert_fast<uint16_t , 4 , 1 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
713
+ break ;
714
+ case FORMAT_RGBAH | (FORMAT_RGH << 8 ):
715
+ _convert_fast<uint16_t , 4 , 2 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
716
+ break ;
717
+ case FORMAT_RGBAH | (FORMAT_RGBH << 8 ):
718
+ _convert_fast<uint16_t , 4 , 3 , 0x0000 , 0x3C00 >(mip_width, mip_height, (const uint16_t *)rptr, (uint16_t *)wptr);
719
+ break ;
720
+ case FORMAT_RF | (FORMAT_RGF << 8 ):
721
+ _convert_fast<uint32_t , 1 , 2 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
722
+ break ;
723
+ case FORMAT_RF | (FORMAT_RGBF << 8 ):
724
+ _convert_fast<uint32_t , 1 , 3 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
725
+ break ;
726
+ case FORMAT_RF | (FORMAT_RGBAF << 8 ):
727
+ _convert_fast<uint32_t , 1 , 4 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
728
+ break ;
729
+ case FORMAT_RGF | (FORMAT_RF << 8 ):
730
+ _convert_fast<uint32_t , 2 , 1 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
731
+ break ;
732
+ case FORMAT_RGF | (FORMAT_RGBF << 8 ):
733
+ _convert_fast<uint32_t , 2 , 3 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
734
+ break ;
735
+ case FORMAT_RGF | (FORMAT_RGBAF << 8 ):
736
+ _convert_fast<uint32_t , 2 , 4 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
737
+ break ;
738
+ case FORMAT_RGBF | (FORMAT_RF << 8 ):
739
+ _convert_fast<uint32_t , 3 , 1 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
740
+ break ;
741
+ case FORMAT_RGBF | (FORMAT_RGF << 8 ):
742
+ _convert_fast<uint32_t , 3 , 2 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
743
+ break ;
744
+ case FORMAT_RGBF | (FORMAT_RGBAF << 8 ):
745
+ _convert_fast<uint32_t , 3 , 4 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
746
+ break ;
747
+ case FORMAT_RGBAF | (FORMAT_RF << 8 ):
748
+ _convert_fast<uint32_t , 4 , 1 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
749
+ break ;
750
+ case FORMAT_RGBAF | (FORMAT_RGF << 8 ):
751
+ _convert_fast<uint32_t , 4 , 2 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
752
+ break ;
753
+ case FORMAT_RGBAF | (FORMAT_RGBF << 8 ):
754
+ _convert_fast<uint32_t , 4 , 3 , 0x00000000 , 0x3F800000 >(mip_width, mip_height, (const uint32_t *)rptr, (uint32_t *)wptr);
755
+ break ;
651
756
}
652
757
}
653
758
@@ -2630,6 +2735,27 @@ Error Image::compress(CompressMode p_mode, CompressSource p_source, ASTCFormat p
2630
2735
Error Image::compress_from_channels (CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format) {
2631
2736
ERR_FAIL_COND_V (data.is_empty (), ERR_INVALID_DATA);
2632
2737
2738
+ // RenderingDevice only.
2739
+ if (GLOBAL_GET (" rendering/textures/vram_compression/compress_with_gpu" )) {
2740
+ switch (p_mode) {
2741
+ case COMPRESS_BPTC: {
2742
+ // BC7 is unsupported currently.
2743
+ if ((format >= FORMAT_RF && format <= FORMAT_RGBE9995) && _image_compress_bptc_rd_func) {
2744
+ Error result = _image_compress_bptc_rd_func (this , p_channels);
2745
+
2746
+ // If the image was compressed successfully, we return here. If not, we fall back to the default compression scheme.
2747
+ if (result == OK) {
2748
+ return OK;
2749
+ }
2750
+ }
2751
+
2752
+ } break ;
2753
+
2754
+ default : {
2755
+ }
2756
+ }
2757
+ }
2758
+
2633
2759
switch (p_mode) {
2634
2760
case COMPRESS_S3TC: {
2635
2761
ERR_FAIL_NULL_V (_image_compress_bc_func, ERR_UNAVAILABLE);
@@ -3011,6 +3137,7 @@ void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr
3011
3137
void (*Image::_image_compress_etc1_func)(Image *) = nullptr ;
3012
3138
void (*Image::_image_compress_etc2_func)(Image *, Image::UsedChannels) = nullptr ;
3013
3139
void (*Image::_image_compress_astc_func)(Image *, Image::ASTCFormat) = nullptr ;
3140
+ Error (*Image::_image_compress_bptc_rd_func)(Image *, Image::UsedChannels) = nullptr;
3014
3141
void (*Image::_image_decompress_bc)(Image *) = nullptr ;
3015
3142
void (*Image::_image_decompress_bptc)(Image *) = nullptr ;
3016
3143
void (*Image::_image_decompress_etc1)(Image *) = nullptr ;
@@ -3696,6 +3823,33 @@ void Image::bump_map_to_normal_map(float bump_scale) {
3696
3823
data = result_image;
3697
3824
}
3698
3825
3826
+ bool Image::detect_signed (bool p_include_mips) const {
3827
+ ERR_FAIL_COND_V (is_compressed (), false );
3828
+
3829
+ if (format >= Image::FORMAT_RH && format <= Image::FORMAT_RGBAH) {
3830
+ const uint16_t *img_data = reinterpret_cast <const uint16_t *>(data.ptr ());
3831
+ const uint64_t img_size = p_include_mips ? (data.size () / 2 ) : (width * height * get_format_pixel_size (format) / 2 );
3832
+
3833
+ for (uint64_t i = 0 ; i < img_size; i++) {
3834
+ if ((img_data[i] & 0x8000 ) != 0 && (img_data[i] & 0x7fff ) != 0 ) {
3835
+ return true ;
3836
+ }
3837
+ }
3838
+
3839
+ } else if (format >= Image::FORMAT_RF && format <= Image::FORMAT_RGBAF) {
3840
+ const uint32_t *img_data = reinterpret_cast <const uint32_t *>(data.ptr ());
3841
+ const uint64_t img_size = p_include_mips ? (data.size () / 4 ) : (width * height * get_format_pixel_size (format) / 4 );
3842
+
3843
+ for (uint64_t i = 0 ; i < img_size; i++) {
3844
+ if ((img_data[i] & 0x80000000 ) != 0 && (img_data[i] & 0x7fffffff ) != 0 ) {
3845
+ return true ;
3846
+ }
3847
+ }
3848
+ }
3849
+
3850
+ return false ;
3851
+ }
3852
+
3699
3853
void Image::srgb_to_linear () {
3700
3854
if (data.size () == 0 ) {
3701
3855
return ;
0 commit comments