2023-01-10 15:26:54 +01:00
/**************************************************************************/
/* resource_importer_texture.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2017-02-03 04:08:50 +01:00
# include "resource_importer_texture.h"
2017-03-05 15:47:28 +01:00
2018-09-11 18:13:45 +02:00
# include "core/io/config_file.h"
# include "core/io/image_loader.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_file_system.h"
2017-09-13 09:13:23 +02:00
# include "editor/editor_node.h"
2017-03-05 16:44:50 +01:00
# include "scene/resources/texture.h"
2017-09-13 09:13:23 +02:00
2017-03-05 16:44:50 +01:00
void ResourceImporterTexture : : _texture_reimport_srgb ( const Ref < StreamTexture > & p_tex ) {
2021-01-27 10:43:02 +01:00
singleton - > mutex . lock ( ) ;
2017-02-06 04:38:39 +01:00
StringName path = p_tex - > get_path ( ) ;
if ( ! singleton - > make_flags . has ( path ) ) {
2017-03-05 16:44:50 +01:00
singleton - > make_flags [ path ] = 0 ;
2017-02-06 04:38:39 +01:00
}
2017-03-05 16:44:50 +01:00
singleton - > make_flags [ path ] | = MAKE_SRGB_FLAG ;
2017-02-06 04:38:39 +01:00
2021-01-27 10:43:02 +01:00
singleton - > mutex . unlock ( ) ;
2017-02-06 04:38:39 +01:00
}
2017-03-05 16:44:50 +01:00
void ResourceImporterTexture : : _texture_reimport_3d ( const Ref < StreamTexture > & p_tex ) {
2021-01-27 10:43:02 +01:00
singleton - > mutex . lock ( ) ;
2017-02-06 04:38:39 +01:00
StringName path = p_tex - > get_path ( ) ;
if ( ! singleton - > make_flags . has ( path ) ) {
2017-03-05 16:44:50 +01:00
singleton - > make_flags [ path ] = 0 ;
2017-02-06 04:38:39 +01:00
}
2017-03-05 16:44:50 +01:00
singleton - > make_flags [ path ] | = MAKE_3D_FLAG ;
2017-02-06 04:38:39 +01:00
2021-01-27 10:43:02 +01:00
singleton - > mutex . unlock ( ) ;
2017-02-06 04:38:39 +01:00
}
2017-06-17 02:47:28 +02:00
void ResourceImporterTexture : : _texture_reimport_normal ( const Ref < StreamTexture > & p_tex ) {
2021-01-27 10:43:02 +01:00
singleton - > mutex . lock ( ) ;
2017-06-17 02:47:28 +02:00
StringName path = p_tex - > get_path ( ) ;
if ( ! singleton - > make_flags . has ( path ) ) {
singleton - > make_flags [ path ] = 0 ;
}
singleton - > make_flags [ path ] | = MAKE_NORMAL_FLAG ;
2021-01-27 10:43:02 +01:00
singleton - > mutex . unlock ( ) ;
2017-06-17 02:47:28 +02:00
}
2017-02-06 04:38:39 +01:00
void ResourceImporterTexture : : update_imports ( ) {
if ( EditorFileSystem : : get_singleton ( ) - > is_scanning ( ) | | EditorFileSystem : : get_singleton ( ) - > is_importing ( ) ) {
2019-05-19 12:34:40 +02:00
return ; // do nothing for now
2017-02-06 04:38:39 +01:00
}
2021-01-27 10:43:02 +01:00
mutex . lock ( ) ;
2017-02-06 04:38:39 +01:00
if ( make_flags . empty ( ) ) {
2021-01-27 10:43:02 +01:00
mutex . unlock ( ) ;
2017-02-06 04:38:39 +01:00
return ;
}
Vector < String > to_reimport ;
2017-03-05 16:44:50 +01:00
for ( Map < StringName , int > : : Element * E = make_flags . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-06 04:38:39 +01:00
Ref < ConfigFile > cf ;
cf . instance ( ) ;
2017-03-05 16:44:50 +01:00
String src_path = String ( E - > key ( ) ) + " .import " ;
2017-02-06 04:38:39 +01:00
Error err = cf - > load ( src_path ) ;
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( err ! = OK ) ;
2017-02-06 04:38:39 +01:00
2017-03-05 16:44:50 +01:00
bool changed = false ;
if ( E - > get ( ) & MAKE_SRGB_FLAG & & int ( cf - > get_value ( " params " , " flags/srgb " ) ) = = 2 ) {
cf - > set_value ( " params " , " flags/srgb " , 1 ) ;
changed = true ;
2017-02-06 04:38:39 +01:00
}
2017-06-17 02:47:28 +02:00
if ( E - > get ( ) & MAKE_NORMAL_FLAG & & int ( cf - > get_value ( " params " , " compress/normal_map " ) ) = = 0 ) {
2022-06-13 20:13:30 +02:00
print_line ( vformat ( TTR ( " %s: Texture detected as used as a normal map in 3D. Enabling red-green texture compression to reduce memory usage (blue channel is discarded). " ) , String ( E - > key ( ) ) ) ) ;
2017-06-17 02:47:28 +02:00
cf - > set_value ( " params " , " compress/normal_map " , 1 ) ;
changed = true ;
}
2017-03-05 16:44:50 +01:00
if ( E - > get ( ) & MAKE_3D_FLAG & & bool ( cf - > get_value ( " params " , " detect_3d " ) ) ) {
2022-06-13 20:13:30 +02:00
print_line ( vformat ( TTR ( " %s: Texture detected as used in 3D. Enabling filter, repeat, mipmap generation and VRAM texture compression. " ) , String ( E - > key ( ) ) ) ) ;
2017-03-05 16:44:50 +01:00
cf - > set_value ( " params " , " detect_3d " , false ) ;
cf - > set_value ( " params " , " compress/mode " , 2 ) ;
cf - > set_value ( " params " , " flags/repeat " , true ) ;
cf - > set_value ( " params " , " flags/filter " , true ) ;
cf - > set_value ( " params " , " flags/mipmaps " , true ) ;
changed = true ;
2017-02-06 04:38:39 +01:00
}
if ( changed ) {
cf - > save ( src_path ) ;
to_reimport . push_back ( E - > key ( ) ) ;
}
}
make_flags . clear ( ) ;
2021-01-27 10:43:02 +01:00
mutex . unlock ( ) ;
2017-02-06 04:38:39 +01:00
if ( to_reimport . size ( ) ) {
EditorFileSystem : : get_singleton ( ) - > reimport_files ( to_reimport ) ;
}
}
2017-02-01 13:45:45 +01:00
String ResourceImporterTexture : : get_importer_name ( ) const {
return " texture " ;
}
2017-03-05 16:44:50 +01:00
String ResourceImporterTexture : : get_visible_name ( ) const {
2017-02-01 13:45:45 +01:00
return " Texture " ;
}
2017-03-05 16:44:50 +01:00
void ResourceImporterTexture : : get_recognized_extensions ( List < String > * p_extensions ) const {
2017-02-01 13:45:45 +01:00
ImageLoader : : get_recognized_extensions ( p_extensions ) ;
}
String ResourceImporterTexture : : get_save_extension ( ) const {
return " stex " ;
}
2017-03-05 16:44:50 +01:00
String ResourceImporterTexture : : get_resource_type ( ) const {
2017-02-01 13:45:45 +01:00
return " StreamTexture " ;
}
2017-03-05 16:44:50 +01:00
bool ResourceImporterTexture : : get_option_visibility ( const String & p_option , const Map < StringName , Variant > & p_options ) const {
2017-04-26 17:49:08 +02:00
if ( p_option = = " compress/lossy_quality " ) {
int compress_mode = int ( p_options [ " compress/mode " ] ) ;
if ( compress_mode ! = COMPRESS_LOSSY & & compress_mode ! = COMPRESS_VIDEO_RAM ) {
return false ;
}
2018-08-27 18:47:13 +02:00
} else if ( p_option = = " compress/hdr_mode " ) {
2018-08-23 00:31:12 +02:00
int compress_mode = int ( p_options [ " compress/mode " ] ) ;
if ( compress_mode ! = COMPRESS_VIDEO_RAM ) {
return false ;
}
2022-03-27 00:21:07 +01:00
} else if ( p_option = = " compress/normal_map " ) {
int compress_mode = int ( p_options [ " compress/mode " ] ) ;
if ( compress_mode = = COMPRESS_LOSSLESS ) {
return false ;
}
2018-08-28 05:05:04 +02:00
} else if ( p_option = = " compress/bptc_ldr " ) {
int compress_mode = int ( p_options [ " compress/mode " ] ) ;
if ( compress_mode ! = COMPRESS_VIDEO_RAM ) {
return false ;
}
if ( ! ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_bptc " ) ) {
return false ;
}
2017-04-26 17:49:08 +02:00
}
2017-02-01 13:45:45 +01:00
return true ;
}
int ResourceImporterTexture : : get_preset_count ( ) const {
return 4 ;
}
String ResourceImporterTexture : : get_preset_name ( int p_idx ) const {
2017-03-05 16:44:50 +01:00
static const char * preset_names [ ] = {
2022-04-27 07:50:59 +02:00
TTRC ( " 2D, Detect 3D " ) ,
TTRC ( " 2D " ) ,
TTRC ( " 2D Pixel " ) ,
TTRC ( " 3D " ) ,
2017-02-01 13:45:45 +01:00
} ;
2022-04-27 07:50:59 +02:00
return TTRGET ( preset_names [ p_idx ] ) ;
2017-02-01 13:45:45 +01:00
}
2017-03-05 16:44:50 +01:00
void ResourceImporterTexture : : get_import_options ( List < ImportOption > * r_options , int p_preset ) const {
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 ) ) ;
2018-08-27 18:47:13 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " compress/hdr_mode " , PROPERTY_HINT_ENUM , " Enabled,Force RGBE " ) , 0 ) ) ;
2018-08-28 05:05:04 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " compress/bptc_ldr " , PROPERTY_HINT_ENUM , " Enabled,RGBA Only " ) , 0 ) ) ;
2017-06-17 02:47:28 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " compress/normal_map " , PROPERTY_HINT_ENUM , " Detect,Enable,Disabled " ) , 0 ) ) ;
2017-03-05 16:44:50 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " flags/repeat " , PROPERTY_HINT_ENUM , " Disabled,Enabled,Mirrored " ) , p_preset = = PRESET_3D ? 1 : 0 ) ) ;
2019-06-26 15:08:25 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " flags/filter " ) , p_preset ! = PRESET_2D_PIXEL ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " flags/mipmaps " ) , p_preset = = PRESET_3D ) ) ;
2017-03-05 16:44:50 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " flags/anisotropic " ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " flags/srgb " , PROPERTY_HINT_ENUM , " Disable,Enable,Detect " ) , 2 ) ) ;
2019-06-26 15:08:25 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " process/fix_alpha_border " ) , p_preset ! = PRESET_3D ) ) ;
2017-06-25 13:01:15 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " process/premult_alpha " ) , false ) ) ;
2017-05-30 03:11:33 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " process/HDR_as_SRGB " ) , false ) ) ;
2018-08-17 18:28:07 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " process/invert_color " ) , false ) ) ;
2021-05-13 20:04:02 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " process/normal_map_invert_y " ) , false ) ) ;
2017-03-05 16:44:50 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " stream " ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " size_limit " , PROPERTY_HINT_RANGE , " 0,4096,1 " ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " detect_3d " ) , p_preset = = PRESET_DETECT ) ) ;
2018-11-21 19:06:38 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : REAL , " svg/scale " , PROPERTY_HINT_RANGE , " 0.001,100,0.001 " ) , 1.0 ) ) ;
2017-02-01 13:45:45 +01:00
}
2019-02-25 02:34:12 +01:00
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 , bool p_detect_normal , bool p_force_normal , bool p_force_po2_for_compressed ) {
2017-03-05 16:44:50 +01:00
FileAccess * f = FileAccess : : open ( p_to_path , FileAccess : : WRITE ) ;
2021-06-17 01:13:36 +02:00
ERR_FAIL_NULL ( f ) ;
2017-02-01 13:45:45 +01:00
f - > store_8 ( ' G ' ) ;
f - > store_8 ( ' D ' ) ;
f - > store_8 ( ' S ' ) ;
f - > store_8 ( ' T ' ) ; //godot streamable texture
2019-02-25 02:34:12 +01:00
bool resize_to_po2 = false ;
if ( p_compress_mode = = COMPRESS_VIDEO_RAM & & p_force_po2_for_compressed & & ( p_mipmaps | | p_texture_flags & Texture : : FLAG_REPEAT ) ) {
resize_to_po2 = true ;
f - > store_16 ( next_power_of_2 ( p_image - > get_width ( ) ) ) ;
f - > store_16 ( p_image - > get_width ( ) ) ;
f - > store_16 ( next_power_of_2 ( p_image - > get_height ( ) ) ) ;
f - > store_16 ( p_image - > get_height ( ) ) ;
} else {
f - > store_16 ( p_image - > get_width ( ) ) ;
f - > store_16 ( 0 ) ;
f - > store_16 ( p_image - > get_height ( ) ) ;
f - > store_16 ( 0 ) ;
}
2017-02-01 13:45:45 +01:00
f - > store_32 ( p_texture_flags ) ;
2017-03-05 16:44:50 +01:00
uint32_t format = 0 ;
2017-02-01 13:45:45 +01:00
2021-05-05 12:44:11 +02:00
if ( p_streamable ) {
2017-03-05 16:44:50 +01:00
format | = StreamTexture : : FORMAT_BIT_STREAM ;
2021-05-05 12:44:11 +02:00
}
if ( p_mipmaps ) {
2017-03-05 16:44:50 +01:00
format | = StreamTexture : : FORMAT_BIT_HAS_MIPMAPS ; //mipmaps bit
2021-05-05 12:44:11 +02:00
}
if ( p_detect_3d ) {
2017-03-05 16:44:50 +01:00
format | = StreamTexture : : FORMAT_BIT_DETECT_3D ;
2021-05-05 12:44:11 +02:00
}
if ( p_detect_srgb ) {
2017-03-05 16:44:50 +01:00
format | = StreamTexture : : FORMAT_BIT_DETECT_SRGB ;
2021-05-05 12:44:11 +02:00
}
if ( p_detect_normal ) {
2017-06-17 02:47:28 +02:00
format | = StreamTexture : : FORMAT_BIT_DETECT_NORMAL ;
2021-05-05 12:44:11 +02:00
}
2017-02-01 13:45:45 +01:00
2017-05-27 02:49:49 +02:00
if ( ( p_compress_mode = = COMPRESS_LOSSLESS | | p_compress_mode = = COMPRESS_LOSSY ) & & p_image - > get_format ( ) > Image : : FORMAT_RGBA8 ) {
2017-08-01 01:58:14 +02:00
p_compress_mode = COMPRESS_UNCOMPRESSED ; //these can't go as lossy
2017-05-27 02:49:49 +02:00
}
2017-02-01 13:45:45 +01:00
switch ( p_compress_mode ) {
case COMPRESS_LOSSLESS : {
2021-08-13 22:17:55 +02:00
bool lossless_force_png = ProjectSettings : : get_singleton ( ) - > get ( " rendering/misc/lossless_compression/force_png " ) | |
! Image : : _webp_mem_loader_func ; // WebP module disabled.
2021-05-08 19:14:41 +02:00
bool use_webp = ! lossless_force_png & & p_image - > get_width ( ) < = 16383 & & p_image - > get_height ( ) < = 16383 ; // WebP has a size limit
2017-05-17 12:36:47 +02:00
Ref < Image > image = p_image - > duplicate ( ) ;
2017-02-01 13:45:45 +01:00
if ( p_mipmaps ) {
2017-05-17 12:36:47 +02:00
image - > generate_mipmaps ( ) ;
2017-02-01 13:45:45 +01:00
} else {
2017-05-17 12:36:47 +02:00
image - > clear_mipmaps ( ) ;
2017-02-01 13:45:45 +01:00
}
2017-05-17 12:36:47 +02:00
int mmc = image - > get_mipmap_count ( ) + 1 ;
2017-02-01 13:45:45 +01:00
2021-05-08 19:14:41 +02:00
if ( use_webp ) {
format | = StreamTexture : : FORMAT_BIT_WEBP ;
} else {
format | = StreamTexture : : FORMAT_BIT_PNG ;
}
2017-02-01 13:45:45 +01:00
f - > store_32 ( format ) ;
f - > store_32 ( mmc ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < mmc ; i + + ) {
if ( i > 0 ) {
2017-05-17 12:36:47 +02:00
image - > shrink_x2 ( ) ;
2017-02-01 13:45:45 +01:00
}
2021-05-08 19:14:41 +02:00
PoolVector < uint8_t > data ;
if ( use_webp ) {
data = Image : : webp_lossless_packer ( image ) ;
} else {
data = Image : : png_packer ( image ) ;
}
2017-02-01 13:45:45 +01:00
int data_len = data . size ( ) ;
f - > store_32 ( data_len ) ;
2017-03-05 16:44:50 +01:00
PoolVector < uint8_t > : : Read r = data . read ( ) ;
f - > store_buffer ( r . ptr ( ) , data_len ) ;
2017-02-01 13:45:45 +01:00
}
} break ;
case COMPRESS_LOSSY : {
2017-05-17 12:36:47 +02:00
Ref < Image > image = p_image - > duplicate ( ) ;
2017-02-01 13:45:45 +01:00
if ( p_mipmaps ) {
2017-05-17 12:36:47 +02:00
image - > generate_mipmaps ( ) ;
2017-02-01 13:45:45 +01:00
} else {
2017-05-17 12:36:47 +02:00
image - > clear_mipmaps ( ) ;
2017-02-01 13:45:45 +01:00
}
2017-05-17 12:36:47 +02:00
int mmc = image - > get_mipmap_count ( ) + 1 ;
2017-02-01 13:45:45 +01:00
2021-05-08 19:14:41 +02:00
format | = StreamTexture : : FORMAT_BIT_WEBP ;
2017-02-01 13:45:45 +01:00
f - > store_32 ( format ) ;
f - > store_32 ( mmc ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < mmc ; i + + ) {
if ( i > 0 ) {
2017-05-17 12:36:47 +02:00
image - > shrink_x2 ( ) ;
2017-02-01 13:45:45 +01:00
}
2021-05-08 19:14:41 +02:00
PoolVector < uint8_t > data = Image : : webp_lossy_packer ( image , p_lossy_quality ) ;
2017-02-01 13:45:45 +01:00
int data_len = data . size ( ) ;
f - > store_32 ( data_len ) ;
PoolVector < uint8_t > : : Read r = data . read ( ) ;
2017-03-05 16:44:50 +01:00
f - > store_buffer ( r . ptr ( ) , data_len ) ;
2017-02-01 13:45:45 +01:00
}
} break ;
case COMPRESS_VIDEO_RAM : {
2017-05-17 12:36:47 +02:00
Ref < Image > image = p_image - > duplicate ( ) ;
2019-02-25 02:34:12 +01:00
if ( resize_to_po2 ) {
image - > resize_to_po2 ( ) ;
}
2018-11-02 16:25:43 +01:00
if ( p_mipmaps ) {
image - > generate_mipmaps ( p_force_normal ) ;
}
2017-05-27 02:49:49 +02:00
if ( p_force_rgbe & & image - > get_format ( ) > = Image : : FORMAT_R8 & & image - > get_format ( ) < = Image : : FORMAT_RGBE9995 ) {
image - > convert ( Image : : FORMAT_RGBE9995 ) ;
} else {
2017-06-17 02:47:28 +02:00
Image : : CompressSource csource = Image : : COMPRESS_SOURCE_GENERIC ;
if ( p_force_normal ) {
csource = Image : : COMPRESS_SOURCE_NORMAL ;
} else if ( p_texture_flags & VS : : TEXTURE_FLAG_CONVERT_TO_LINEAR ) {
csource = Image : : COMPRESS_SOURCE_SRGB ;
}
image - > compress ( p_vram_compression , csource , p_lossy_quality ) ;
2017-05-27 02:49:49 +02:00
}
2017-02-01 13:45:45 +01:00
2017-05-17 12:36:47 +02:00
format | = image - > get_format ( ) ;
2017-02-01 13:45:45 +01:00
f - > store_32 ( format ) ;
2017-05-17 12:36:47 +02:00
PoolVector < uint8_t > data = image - > get_data ( ) ;
2017-02-01 13:45:45 +01:00
int dl = data . size ( ) ;
PoolVector < uint8_t > : : Read r = data . read ( ) ;
2017-03-05 16:44:50 +01:00
f - > store_buffer ( r . ptr ( ) , dl ) ;
2017-02-01 13:45:45 +01:00
} break ;
case COMPRESS_UNCOMPRESSED : {
2017-05-17 12:36:47 +02:00
Ref < Image > image = p_image - > duplicate ( ) ;
2017-02-01 13:45:45 +01:00
if ( p_mipmaps ) {
2017-05-17 12:36:47 +02:00
image - > generate_mipmaps ( ) ;
2017-02-01 13:45:45 +01:00
} else {
2017-05-17 12:36:47 +02:00
image - > clear_mipmaps ( ) ;
2017-02-01 13:45:45 +01:00
}
2017-05-17 12:36:47 +02:00
format | = image - > get_format ( ) ;
2017-02-01 13:45:45 +01:00
f - > store_32 ( format ) ;
2017-05-17 12:36:47 +02:00
PoolVector < uint8_t > data = image - > get_data ( ) ;
2017-02-01 13:45:45 +01:00
int dl = data . size ( ) ;
PoolVector < uint8_t > : : Read r = data . read ( ) ;
2017-03-05 16:44:50 +01:00
f - > store_buffer ( r . ptr ( ) , dl ) ;
2017-02-01 13:45:45 +01:00
} break ;
}
memdelete ( f ) ;
}
2019-02-26 22:43:37 +01:00
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 , Variant * r_metadata ) {
2017-02-01 13:45:45 +01:00
int compress_mode = p_options [ " compress/mode " ] ;
2017-03-05 16:44:50 +01:00
float lossy = p_options [ " compress/lossy_quality " ] ;
int repeat = p_options [ " flags/repeat " ] ;
bool filter = p_options [ " flags/filter " ] ;
bool mipmaps = p_options [ " flags/mipmaps " ] ;
bool anisotropic = p_options [ " flags/anisotropic " ] ;
int srgb = p_options [ " flags/srgb " ] ;
bool fix_alpha_border = p_options [ " process/fix_alpha_border " ] ;
bool premult_alpha = p_options [ " process/premult_alpha " ] ;
2018-08-17 18:28:07 +02:00
bool invert_color = p_options [ " process/invert_color " ] ;
2021-05-13 20:04:02 +02:00
bool normal_map_invert_y = p_options [ " process/normal_map_invert_y " ] ;
2017-02-01 13:45:45 +01:00
bool stream = p_options [ " stream " ] ;
int size_limit = p_options [ " size_limit " ] ;
2017-05-30 03:11:33 +02:00
bool hdr_as_srgb = p_options [ " process/HDR_as_SRGB " ] ;
2017-06-17 02:47:28 +02:00
int normal = p_options [ " compress/normal_map " ] ;
2017-08-31 18:52:07 +02:00
float scale = p_options [ " svg/scale " ] ;
2018-08-27 18:47:13 +02:00
bool force_rgbe = p_options [ " compress/hdr_mode " ] ;
2018-08-28 05:05:04 +02:00
int bptc_ldr = p_options [ " compress/bptc_ldr " ] ;
2017-02-01 13:45:45 +01:00
2017-05-17 12:36:47 +02:00
Ref < Image > image ;
image . instance ( ) ;
2021-05-04 16:00:45 +02:00
Error err = ImageLoader : : load_image ( p_source_file , image , nullptr , hdr_as_srgb , scale ) ;
2021-05-05 12:44:11 +02:00
if ( err ! = OK ) {
2017-02-01 13:45:45 +01:00
return err ;
2021-05-05 12:44:11 +02:00
}
2017-02-01 13:45:45 +01:00
2019-02-26 22:43:37 +01:00
Array formats_imported ;
2017-03-05 16:44:50 +01:00
int tex_flags = 0 ;
2021-05-05 12:44:11 +02:00
if ( repeat > 0 ) {
2017-03-05 16:44:50 +01:00
tex_flags | = Texture : : FLAG_REPEAT ;
2021-05-18 19:35:21 +02:00
const bool min_gles3 = GLOBAL_GET ( " rendering/quality/driver/driver_name " ) = = " GLES3 " & &
2021-10-28 13:23:24 +02:00
! GLOBAL_GET ( " rendering/quality/driver/fallback_to_gles2 " ) ;
2021-05-18 19:35:21 +02:00
if ( ! min_gles3 & & ! image - > is_size_po2 ( ) ) {
// The project can be run using GLES2. GLES2 does not guarantee that
// repeating textures with a non-power-of-two size will be displayed
// without artifacts (due to upscaling to the nearest power of 2).
if ( GLOBAL_GET ( " rendering/quality/driver/fallback_to_gles2 " ) ) {
WARN_PRINT ( vformat ( " %s: Imported a repeating texture with a size of %dx%d, but the project is configured to allow falling back to GLES2. \n Non-power-of-2 repeating textures may not display correctly on some platforms such as HTML5. This is because GLES2 does not mandate support for non-power-of-2 repeating textures. " ,
p_source_file , image - > get_width ( ) , image - > get_height ( ) ) ) ;
} else {
WARN_PRINT ( vformat ( " %s: Imported a repeating texture with a size of %dx%d, but the project is configured to use GLES2. \n Non-power-of-2 repeating textures may not display correctly on some platforms such as HTML5. This is because GLES2 does not mandate support for non-power-of-2 repeating textures. " ,
p_source_file , image - > get_width ( ) , image - > get_height ( ) ) ) ;
}
}
2021-05-05 12:44:11 +02:00
}
if ( repeat = = 2 ) {
2017-03-05 16:44:50 +01:00
tex_flags | = Texture : : FLAG_MIRRORED_REPEAT ;
2021-05-05 12:44:11 +02:00
}
if ( filter ) {
2017-03-05 16:44:50 +01:00
tex_flags | = Texture : : FLAG_FILTER ;
2021-05-05 12:44:11 +02:00
}
if ( mipmaps | | compress_mode = = COMPRESS_VIDEO_RAM ) {
2017-03-05 16:44:50 +01:00
tex_flags | = Texture : : FLAG_MIPMAPS ;
2021-05-05 12:44:11 +02:00
}
if ( anisotropic ) {
2017-03-05 16:44:50 +01:00
tex_flags | = Texture : : FLAG_ANISOTROPIC_FILTER ;
2021-05-05 12:44:11 +02:00
}
if ( srgb = = 1 ) {
2017-03-05 16:44:50 +01:00
tex_flags | = Texture : : FLAG_CONVERT_TO_LINEAR ;
2021-05-05 12:44:11 +02:00
}
2017-02-01 13:45:45 +01:00
2017-05-17 12:36:47 +02:00
if ( size_limit > 0 & & ( image - > get_width ( ) > size_limit | | image - > get_height ( ) > size_limit ) ) {
2017-02-01 13:45:45 +01:00
//limit size
2017-05-17 12:36:47 +02:00
if ( image - > get_width ( ) > = image - > get_height ( ) ) {
2017-02-01 13:45:45 +01:00
int new_width = size_limit ;
2017-05-17 12:36:47 +02:00
int new_height = image - > get_height ( ) * new_width / image - > get_width ( ) ;
2017-02-01 13:45:45 +01:00
2017-05-17 12:36:47 +02:00
image - > resize ( new_width , new_height , Image : : INTERPOLATE_CUBIC ) ;
2017-02-01 13:45:45 +01:00
} else {
int new_height = size_limit ;
2017-05-17 12:36:47 +02:00
int new_width = image - > get_width ( ) * new_height / image - > get_height ( ) ;
2017-02-01 13:45:45 +01:00
2017-05-17 12:36:47 +02:00
image - > resize ( new_width , new_height , Image : : INTERPOLATE_CUBIC ) ;
2017-02-01 13:45:45 +01:00
}
2018-07-03 15:55:50 +02:00
2018-11-25 21:05:35 +01:00
if ( normal = = 1 ) {
2018-07-03 15:55:50 +02:00
image - > normalize ( ) ;
}
2017-02-01 13:45:45 +01:00
}
if ( fix_alpha_border ) {
2017-05-17 12:36:47 +02:00
image - > fix_alpha_edges ( ) ;
2017-02-01 13:45:45 +01:00
}
if ( premult_alpha ) {
2017-05-17 12:36:47 +02:00
image - > premultiply_alpha ( ) ;
2017-02-01 13:45:45 +01:00
}
2018-08-17 18:28:07 +02:00
if ( invert_color ) {
int height = image - > get_height ( ) ;
int width = image - > get_width ( ) ;
image - > lock ( ) ;
2018-09-02 15:13:19 +02:00
for ( int i = 0 ; i < width ; i + + ) {
for ( int j = 0 ; j < height ; j + + ) {
2018-08-17 18:28:07 +02:00
image - > set_pixel ( i , j , image - > get_pixel ( i , j ) . inverted ( ) ) ;
}
}
image - > unlock ( ) ;
}
2021-05-13 20:04:02 +02:00
if ( normal_map_invert_y ) {
// Inverting the green channel can be used to flip a normal map's direction.
// There's no standard when it comes to normal map Y direction, so this is
// sometimes needed when using a normal map exported from another program.
// See <http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates>.
const int height = image - > get_height ( ) ;
const int width = image - > get_width ( ) ;
image - > lock ( ) ;
for ( int i = 0 ; i < width ; i + + ) {
for ( int j = 0 ; j < height ; j + + ) {
const Color color = image - > get_pixel ( i , j ) ;
image - > set_pixel ( i , j , Color ( color . r , 1 - color . g , color . b ) ) ;
}
}
image - > unlock ( ) ;
}
2017-02-06 04:38:39 +01:00
bool detect_3d = p_options [ " detect_3d " ] ;
2017-03-05 16:44:50 +01:00
bool detect_srgb = srgb = = 2 ;
2017-06-17 02:47:28 +02:00
bool detect_normal = normal = = 0 ;
bool force_normal = normal = = 1 ;
2017-02-01 13:45:45 +01:00
2017-03-05 16:44:50 +01:00
if ( compress_mode = = COMPRESS_VIDEO_RAM ) {
2017-07-19 22:00:46 +02:00
//must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
2017-02-01 13:45:45 +01:00
//Android, GLES 2.x
2017-09-06 01:17:26 +02:00
2017-09-13 09:13:23 +02:00
bool ok_on_pc = false ;
2018-08-28 05:05:04 +02:00
bool is_hdr = ( image - > get_format ( ) > = Image : : FORMAT_RF & & image - > get_format ( ) < = Image : : FORMAT_RGBE9995 ) ;
bool is_ldr = ( image - > get_format ( ) > = Image : : FORMAT_L8 & & image - > get_format ( ) < = Image : : FORMAT_RGBA5551 ) ;
bool can_bptc = ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_bptc " ) ;
bool can_s3tc = ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_s3tc " ) ;
2017-09-06 01:17:26 +02:00
2018-08-27 18:47:13 +02:00
if ( can_bptc ) {
Image : : DetectChannels channels = image - > get_detected_channels ( ) ;
2018-08-28 05:05:04 +02:00
if ( is_hdr ) {
if ( channels = = Image : : DETECTED_LA | | channels = = Image : : DETECTED_RGBA ) {
can_bptc = false ;
}
} else if ( is_ldr ) {
//handle "RGBA Only" setting
if ( bptc_ldr = = 1 & & channels ! = Image : : DETECTED_LA & & channels ! = Image : : DETECTED_RGBA ) {
can_bptc = false ;
}
2018-08-22 04:56:04 +02:00
}
2019-02-26 22:43:37 +01:00
formats_imported . push_back ( " bptc " ) ;
2018-08-22 04:56:04 +02:00
}
2018-08-28 05:05:04 +02:00
if ( ! can_bptc & & is_hdr & & ! force_rgbe ) {
//convert to ldr if this can't be stored hdr
image - > convert ( Image : : FORMAT_RGBA8 ) ;
}
2018-08-22 04:56:04 +02:00
2018-08-28 05:05:04 +02:00
if ( can_bptc | | can_s3tc ) {
2019-02-25 02:34:12 +01:00
_save_stex ( image , p_save_path + " .s3tc.stex " , compress_mode , lossy , can_bptc ? Image : : COMPRESS_BPTC : Image : : COMPRESS_S3TC , mipmaps , tex_flags , stream , detect_3d , detect_srgb , force_rgbe , detect_normal , force_normal , false ) ;
2017-06-17 02:47:28 +02:00
r_platform_variants - > push_back ( " s3tc " ) ;
2019-02-26 22:43:37 +01:00
formats_imported . push_back ( " s3tc " ) ;
2017-09-13 09:13:23 +02:00
ok_on_pc = true ;
2017-06-17 02:47:28 +02:00
}
2018-08-27 18:47:13 +02:00
if ( ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_etc2 " ) ) {
2019-03-07 16:15:10 +01:00
_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 , true ) ;
2017-06-17 02:47:28 +02:00
r_platform_variants - > push_back ( " etc2 " ) ;
2019-02-26 22:43:37 +01:00
formats_imported . push_back ( " etc2 " ) ;
2017-06-17 02:47:28 +02:00
}
2018-08-27 18:47:13 +02:00
if ( ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_etc " ) ) {
2019-02-25 02:34:12 +01:00
_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 , true ) ;
2017-07-19 22:00:46 +02:00
r_platform_variants - > push_back ( " etc " ) ;
2019-02-26 22:43:37 +01:00
formats_imported . push_back ( " etc " ) ;
2017-07-19 22:00:46 +02:00
}
2018-08-27 18:47:13 +02:00
if ( ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_pvrtc " ) ) {
2019-02-25 02:34:12 +01:00
_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 , true ) ;
2017-06-17 02:47:28 +02:00
r_platform_variants - > push_back ( " pvrtc " ) ;
2019-02-26 22:43:37 +01:00
formats_imported . push_back ( " pvrtc " ) ;
2017-06-17 02:47:28 +02:00
}
2017-02-01 13:45:45 +01:00
2017-09-06 01:17:26 +02:00
if ( ! ok_on_pc ) {
2022-03-07 14:50:02 +01:00
EditorNode : : add_io_error ( TTR ( " Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correctly on PC. " ) ) ;
2017-09-06 01:17:26 +02:00
}
2017-02-01 13:45:45 +01:00
} else {
//import normally
2019-02-25 02:34:12 +01:00
_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 , detect_normal , force_normal , false ) ;
2017-02-01 13:45:45 +01:00
}
2019-02-26 22:43:37 +01:00
if ( r_metadata ) {
Dictionary metadata ;
metadata [ " vram_texture " ] = compress_mode = = COMPRESS_VIDEO_RAM ;
if ( formats_imported . size ( ) ) {
metadata [ " imported_formats " ] = formats_imported ;
}
* r_metadata = metadata ;
}
2017-02-01 13:45:45 +01:00
return OK ;
}
2019-02-26 22:43:37 +01:00
const char * ResourceImporterTexture : : compression_formats [ ] = {
" bptc " ,
" s3tc " ,
" etc " ,
" etc2 " ,
" pvrtc " ,
2021-05-04 16:00:45 +02:00
nullptr
2019-02-26 22:43:37 +01:00
} ;
String ResourceImporterTexture : : get_import_settings_string ( ) const {
String s ;
int index = 0 ;
while ( compression_formats [ index ] ) {
String setting_path = " rendering/vram_compression/import_ " + String ( compression_formats [ index ] ) ;
bool test = ProjectSettings : : get_singleton ( ) - > get ( setting_path ) ;
if ( test ) {
s + = String ( compression_formats [ index ] ) ;
}
index + + ;
}
return s ;
}
bool ResourceImporterTexture : : are_import_settings_valid ( const String & p_path ) const {
//will become invalid if formats are missing to import
Dictionary metadata = ResourceFormatImporter : : get_singleton ( ) - > get_resource_metadata ( p_path ) ;
if ( ! metadata . has ( " vram_texture " ) ) {
return false ;
}
bool vram = metadata [ " vram_texture " ] ;
if ( ! vram ) {
return true ; //do not care about non vram
}
Vector < String > formats_imported ;
if ( metadata . has ( " imported_formats " ) ) {
formats_imported = metadata [ " imported_formats " ] ;
}
int index = 0 ;
bool valid = true ;
while ( compression_formats [ index ] ) {
String setting_path = " rendering/vram_compression/import_ " + String ( compression_formats [ index ] ) ;
bool test = ProjectSettings : : get_singleton ( ) - > get ( setting_path ) ;
if ( test ) {
if ( formats_imported . find ( compression_formats [ index ] ) = = - 1 ) {
valid = false ;
break ;
}
}
index + + ;
}
return valid ;
}
2021-05-04 16:00:45 +02:00
ResourceImporterTexture * ResourceImporterTexture : : singleton = nullptr ;
2017-02-06 04:38:39 +01:00
2017-03-05 16:44:50 +01:00
ResourceImporterTexture : : ResourceImporterTexture ( ) {
singleton = this ;
StreamTexture : : request_3d_callback = _texture_reimport_3d ;
StreamTexture : : request_srgb_callback = _texture_reimport_srgb ;
2017-06-17 02:47:28 +02:00
StreamTexture : : request_normal_callback = _texture_reimport_normal ;
2017-02-06 04:38:39 +01:00
}