1 | /**************************************************************************/ |
2 | /* resource_importer_layered_texture.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "resource_importer_layered_texture.h" |
32 | |
33 | #include "core/config/project_settings.h" |
34 | #include "core/error/error_macros.h" |
35 | #include "core/io/config_file.h" |
36 | #include "core/io/image_loader.h" |
37 | #include "core/object/ref_counted.h" |
38 | #include "editor/editor_file_system.h" |
39 | #include "editor/editor_node.h" |
40 | #include "editor/import/resource_importer_texture.h" |
41 | #include "editor/import/resource_importer_texture_settings.h" |
42 | #include "scene/resources/compressed_texture.h" |
43 | #include "scene/resources/texture.h" |
44 | |
45 | String ResourceImporterLayeredTexture::get_importer_name() const { |
46 | switch (mode) { |
47 | case MODE_CUBEMAP: { |
48 | return "cubemap_texture" ; |
49 | } break; |
50 | case MODE_2D_ARRAY: { |
51 | return "2d_array_texture" ; |
52 | } break; |
53 | case MODE_CUBEMAP_ARRAY: { |
54 | return "cubemap_array_texture" ; |
55 | } break; |
56 | case MODE_3D: { |
57 | return "3d_texture" ; |
58 | } break; |
59 | } |
60 | |
61 | ERR_FAIL_V("" ); |
62 | } |
63 | |
64 | String ResourceImporterLayeredTexture::get_visible_name() const { |
65 | switch (mode) { |
66 | case MODE_CUBEMAP: { |
67 | return "Cubemap" ; |
68 | } break; |
69 | case MODE_2D_ARRAY: { |
70 | return "Texture2DArray" ; |
71 | } break; |
72 | case MODE_CUBEMAP_ARRAY: { |
73 | return "CubemapArray" ; |
74 | } break; |
75 | case MODE_3D: { |
76 | return "Texture3D" ; |
77 | } break; |
78 | } |
79 | |
80 | ERR_FAIL_V("" ); |
81 | } |
82 | |
83 | void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_extensions) const { |
84 | ImageLoader::get_recognized_extensions(p_extensions); |
85 | } |
86 | |
87 | String ResourceImporterLayeredTexture::get_save_extension() const { |
88 | switch (mode) { |
89 | case MODE_CUBEMAP: { |
90 | return "ccube" ; |
91 | } break; |
92 | case MODE_2D_ARRAY: { |
93 | return "ctexarray" ; |
94 | } break; |
95 | case MODE_CUBEMAP_ARRAY: { |
96 | return "ccubearray" ; |
97 | } break; |
98 | case MODE_3D: { |
99 | return "ctex3d" ; |
100 | } break; |
101 | } |
102 | |
103 | ERR_FAIL_V(String()); |
104 | } |
105 | |
106 | String ResourceImporterLayeredTexture::get_resource_type() const { |
107 | switch (mode) { |
108 | case MODE_CUBEMAP: { |
109 | return "CompressedCubemap" ; |
110 | } break; |
111 | case MODE_2D_ARRAY: { |
112 | return "CompressedTexture2DArray" ; |
113 | } break; |
114 | case MODE_CUBEMAP_ARRAY: { |
115 | return "CompressedCubemapArray" ; |
116 | } break; |
117 | case MODE_3D: { |
118 | return "CompressedTexture3D" ; |
119 | } break; |
120 | } |
121 | ERR_FAIL_V(String()); |
122 | } |
123 | |
124 | bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { |
125 | if (p_option == "compress/lossy_quality" && p_options.has("compress/mode" )) { |
126 | return int(p_options["compress/mode" ]) == COMPRESS_LOSSY; |
127 | } |
128 | if ((p_option == "compress/high_quality" || p_option == "compress/hdr_compression" ) && p_options.has("compress/mode" )) { |
129 | return int(p_options["compress/mode" ]) == COMPRESS_VRAM_COMPRESSED; |
130 | } |
131 | return true; |
132 | } |
133 | |
134 | int ResourceImporterLayeredTexture::get_preset_count() const { |
135 | return 0; |
136 | } |
137 | |
138 | String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const { |
139 | return "" ; |
140 | } |
141 | |
142 | void ResourceImporterLayeredTexture::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { |
143 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode" , PROPERTY_HINT_ENUM, "Lossless,Lossy,VRAM Compressed,VRAM Uncompressed,Basis Universal" , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1)); |
144 | r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality" ), false)); |
145 | r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality" , PROPERTY_HINT_RANGE, "0,1,0.01" ), 0.7)); |
146 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression" , PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always" ), 1)); |
147 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack" , PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized,Normal Map (RG Channels)" ), 0)); |
148 | r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate" ), true)); |
149 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit" , PROPERTY_HINT_RANGE, "-1,256" ), -1)); |
150 | |
151 | if (mode == MODE_2D_ARRAY || mode == MODE_3D) { |
152 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/horizontal" , PROPERTY_HINT_RANGE, "1,256,1" ), 8)); |
153 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/vertical" , PROPERTY_HINT_RANGE, "1,256,1" ), 8)); |
154 | } |
155 | if (mode == MODE_CUBEMAP || mode == MODE_CUBEMAP_ARRAY) { |
156 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/arrangement" , PROPERTY_HINT_ENUM, "1x6,2x3,3x2,6x1" ), 1)); |
157 | if (mode == MODE_CUBEMAP_ARRAY) { |
158 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/layout" , PROPERTY_HINT_ENUM, "Horizontal,Vertical" ), 1)); |
159 | r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount" , PROPERTY_HINT_RANGE, "1,1024,1,or_greater" ), 1)); |
160 | } |
161 | } |
162 | } |
163 | |
164 | void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2) { |
165 | Vector<Ref<Image>> mipmap_images; //for 3D |
166 | |
167 | if (mode == MODE_3D) { |
168 | //3D saves in its own way |
169 | |
170 | for (int i = 0; i < p_images.size(); i++) { |
171 | if (p_images.write[i]->has_mipmaps()) { |
172 | p_images.write[i]->clear_mipmaps(); |
173 | } |
174 | |
175 | if (p_force_po2) { |
176 | p_images.write[i]->resize_to_po2(); |
177 | } |
178 | } |
179 | |
180 | if (p_mipmaps) { |
181 | Vector<Ref<Image>> parent_images = p_images; |
182 | //create 3D mipmaps, this is horrible, though not used very often |
183 | int w = p_images[0]->get_width(); |
184 | int h = p_images[0]->get_height(); |
185 | int d = p_images.size(); |
186 | |
187 | while (w > 1 || h > 1 || d > 1) { |
188 | Vector<Ref<Image>> mipmaps; |
189 | int mm_w = MAX(1, w >> 1); |
190 | int mm_h = MAX(1, h >> 1); |
191 | int mm_d = MAX(1, d >> 1); |
192 | |
193 | for (int i = 0; i < mm_d; i++) { |
194 | Ref<Image> mm = Image::create_empty(mm_w, mm_h, false, p_images[0]->get_format()); |
195 | Vector3 pos; |
196 | pos.z = float(i) * float(d) / float(mm_d) + 0.5; |
197 | for (int x = 0; x < mm_w; x++) { |
198 | for (int y = 0; y < mm_h; y++) { |
199 | pos.x = float(x) * float(w) / float(mm_w) + 0.5; |
200 | pos.y = float(y) * float(h) / float(mm_h) + 0.5; |
201 | |
202 | Vector3i posi = Vector3i(pos); |
203 | Vector3 fract = pos - Vector3(posi); |
204 | Vector3i posi_n = posi; |
205 | if (posi_n.x < w - 1) { |
206 | posi_n.x++; |
207 | } |
208 | if (posi_n.y < h - 1) { |
209 | posi_n.y++; |
210 | } |
211 | if (posi_n.z < d - 1) { |
212 | posi_n.z++; |
213 | } |
214 | |
215 | Color c000 = parent_images[posi.z]->get_pixel(posi.x, posi.y); |
216 | Color c100 = parent_images[posi.z]->get_pixel(posi_n.x, posi.y); |
217 | Color c010 = parent_images[posi.z]->get_pixel(posi.x, posi_n.y); |
218 | Color c110 = parent_images[posi.z]->get_pixel(posi_n.x, posi_n.y); |
219 | Color c001 = parent_images[posi_n.z]->get_pixel(posi.x, posi.y); |
220 | Color c101 = parent_images[posi_n.z]->get_pixel(posi_n.x, posi.y); |
221 | Color c011 = parent_images[posi_n.z]->get_pixel(posi.x, posi_n.y); |
222 | Color c111 = parent_images[posi_n.z]->get_pixel(posi_n.x, posi_n.y); |
223 | |
224 | Color cx00 = c000.lerp(c100, fract.x); |
225 | Color cx01 = c001.lerp(c101, fract.x); |
226 | Color cx10 = c010.lerp(c110, fract.x); |
227 | Color cx11 = c011.lerp(c111, fract.x); |
228 | |
229 | Color cy0 = cx00.lerp(cx10, fract.y); |
230 | Color cy1 = cx01.lerp(cx11, fract.y); |
231 | |
232 | Color cz = cy0.lerp(cy1, fract.z); |
233 | |
234 | mm->set_pixel(x, y, cz); |
235 | } |
236 | } |
237 | |
238 | mipmaps.push_back(mm); |
239 | } |
240 | |
241 | w = mm_w; |
242 | h = mm_h; |
243 | d = mm_d; |
244 | |
245 | mipmap_images.append_array(mipmaps); |
246 | parent_images = mipmaps; |
247 | } |
248 | } |
249 | } else { |
250 | for (int i = 0; i < p_images.size(); i++) { |
251 | if (p_force_po2) { |
252 | p_images.write[i]->resize_to_po2(); |
253 | } |
254 | |
255 | if (p_mipmaps) { |
256 | p_images.write[i]->generate_mipmaps(p_csource == Image::COMPRESS_SOURCE_NORMAL); |
257 | } else { |
258 | p_images.write[i]->clear_mipmaps(); |
259 | } |
260 | } |
261 | } |
262 | |
263 | Ref<FileAccess> f = FileAccess::open(p_to_path, FileAccess::WRITE); |
264 | f->store_8('G'); |
265 | f->store_8('S'); |
266 | f->store_8('T'); |
267 | f->store_8('L'); |
268 | |
269 | f->store_32(CompressedTextureLayered::FORMAT_VERSION); |
270 | f->store_32(p_images.size()); // For 2d layers or 3d depth. |
271 | f->store_32(mode); |
272 | f->store_32(0); |
273 | |
274 | f->store_32(0); |
275 | f->store_32(mipmap_images.size()); // Adjust the amount of mipmaps. |
276 | f->store_32(0); |
277 | f->store_32(0); |
278 | |
279 | for (int i = 0; i < p_images.size(); i++) { |
280 | ResourceImporterTexture::save_to_ctex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy); |
281 | } |
282 | |
283 | for (int i = 0; i < mipmap_images.size(); i++) { |
284 | ResourceImporterTexture::save_to_ctex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy); |
285 | } |
286 | } |
287 | |
288 | Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { |
289 | int compress_mode = p_options["compress/mode" ]; |
290 | float lossy = p_options["compress/lossy_quality" ]; |
291 | bool high_quality = p_options["compress/high_quality" ]; |
292 | int hdr_compression = p_options["compress/hdr_compression" ]; |
293 | bool mipmaps = p_options["mipmaps/generate" ]; |
294 | |
295 | int channel_pack = p_options["compress/channel_pack" ]; |
296 | int hslices = (p_options.has("slices/horizontal" )) ? int(p_options["slices/horizontal" ]) : 0; |
297 | int vslices = (p_options.has("slices/vertical" )) ? int(p_options["slices/vertical" ]) : 0; |
298 | int arrangement = (p_options.has("slices/arrangement" )) ? int(p_options["slices/arrangement" ]) : 0; |
299 | int layout = (p_options.has("slices/layout" )) ? int(p_options["slices/layout" ]) : 0; |
300 | int amount = (p_options.has("slices/amount" )) ? int(p_options["slices/amount" ]) : 0; |
301 | |
302 | if (mode == MODE_CUBEMAP || mode == MODE_CUBEMAP_ARRAY) { |
303 | switch (arrangement) { |
304 | case CUBEMAP_FORMAT_1X6: { |
305 | hslices = 1; |
306 | vslices = 6; |
307 | } break; |
308 | case CUBEMAP_FORMAT_2X3: { |
309 | hslices = 2; |
310 | vslices = 3; |
311 | } break; |
312 | case CUBEMAP_FORMAT_3X2: { |
313 | hslices = 3; |
314 | vslices = 2; |
315 | } break; |
316 | case CUBEMAP_FORMAT_6X1: { |
317 | hslices = 6; |
318 | vslices = 1; |
319 | } break; |
320 | } |
321 | |
322 | if (mode == MODE_CUBEMAP_ARRAY) { |
323 | if (layout == 0) { |
324 | hslices *= amount; |
325 | } else { |
326 | vslices *= amount; |
327 | } |
328 | } |
329 | } |
330 | |
331 | Ref<Image> image; |
332 | image.instantiate(); |
333 | Error err = ImageLoader::load_image(p_source_file, image); |
334 | if (err != OK) { |
335 | return err; |
336 | } |
337 | |
338 | if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) { |
339 | //basis universal does not support float formats, fall back |
340 | compress_mode = COMPRESS_VRAM_COMPRESSED; |
341 | } |
342 | |
343 | if (compress_mode == COMPRESS_VRAM_COMPRESSED) { |
344 | mipmaps = true; |
345 | |
346 | //if using video ram, optimize |
347 | if (channel_pack == 0) { |
348 | //remove alpha if not needed, so compression is more efficient |
349 | if (image->get_format() == Image::FORMAT_RGBA8 && !image->detect_alpha()) { |
350 | image->convert(Image::FORMAT_RGB8); |
351 | } |
352 | } else if (image->get_format() < Image::FORMAT_RGBA8) { |
353 | image->optimize_channels(); |
354 | } |
355 | } |
356 | |
357 | Image::CompressSource csource = Image::COMPRESS_SOURCE_GENERIC; |
358 | if (channel_pack == 0) { |
359 | csource = Image::COMPRESS_SOURCE_SRGB; |
360 | } else if (channel_pack == 2) { |
361 | // force normal |
362 | csource = Image::COMPRESS_SOURCE_NORMAL; |
363 | } |
364 | |
365 | Image::UsedChannels used_channels = image->detect_used_channels(csource); |
366 | |
367 | Vector<Ref<Image>> slices; |
368 | |
369 | int slice_w = image->get_width() / hslices; |
370 | int slice_h = image->get_height() / vslices; |
371 | |
372 | for (int i = 0; i < vslices; i++) { |
373 | for (int j = 0; j < hslices; j++) { |
374 | int x = slice_w * j; |
375 | int y = slice_h * i; |
376 | Ref<Image> slice = image->get_region(Rect2i(x, y, slice_w, slice_h)); |
377 | ERR_CONTINUE(slice.is_null() || slice->is_empty()); |
378 | if (slice->get_width() != slice_w || slice->get_height() != slice_h) { |
379 | slice->resize(slice_w, slice_h); |
380 | } |
381 | slices.push_back(slice); |
382 | } |
383 | } |
384 | Array formats_imported; |
385 | Ref<LayeredTextureImport> texture_import; |
386 | texture_import.instantiate(); |
387 | texture_import->csource = &csource; |
388 | texture_import->save_path = p_save_path; |
389 | texture_import->options = p_options; |
390 | texture_import->platform_variants = r_platform_variants; |
391 | texture_import->image = image; |
392 | texture_import->formats_imported = formats_imported; |
393 | texture_import->slices = &slices; |
394 | texture_import->compress_mode = compress_mode; |
395 | texture_import->lossy = lossy; |
396 | texture_import->hdr_compression = hdr_compression; |
397 | texture_import->mipmaps = mipmaps; |
398 | texture_import->used_channels = used_channels; |
399 | texture_import->high_quality = high_quality; |
400 | |
401 | _check_compress_ctex(p_source_file, texture_import); |
402 | if (r_metadata) { |
403 | Dictionary meta; |
404 | meta["vram_texture" ] = compress_mode == COMPRESS_VRAM_COMPRESSED; |
405 | if (formats_imported.size()) { |
406 | meta["imported_formats" ] = formats_imported; |
407 | } |
408 | *r_metadata = meta; |
409 | } |
410 | |
411 | return OK; |
412 | } |
413 | |
414 | const char *ResourceImporterLayeredTexture::compression_formats[] = { |
415 | "s3tc_bptc" , |
416 | "etc2_astc" , |
417 | nullptr |
418 | }; |
419 | |
420 | String ResourceImporterLayeredTexture::get_import_settings_string() const { |
421 | String s; |
422 | |
423 | int index = 0; |
424 | while (compression_formats[index]) { |
425 | String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]); |
426 | bool test = GLOBAL_GET(setting_path); |
427 | if (test) { |
428 | s += String(compression_formats[index]); |
429 | } |
430 | index++; |
431 | } |
432 | |
433 | return s; |
434 | } |
435 | |
436 | bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_path) const { |
437 | //will become invalid if formats are missing to import |
438 | Dictionary meta = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path); |
439 | |
440 | if (!meta.has("vram_texture" )) { |
441 | return false; |
442 | } |
443 | |
444 | bool vram = meta["vram_texture" ]; |
445 | if (!vram) { |
446 | return true; //do not care about non vram |
447 | } |
448 | |
449 | Vector<String> formats_imported; |
450 | if (meta.has("imported_formats" )) { |
451 | formats_imported = meta["imported_formats" ]; |
452 | } |
453 | |
454 | int index = 0; |
455 | bool valid = true; |
456 | while (compression_formats[index]) { |
457 | String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]); |
458 | if (ProjectSettings::get_singleton()->has_setting(setting_path)) { |
459 | bool test = GLOBAL_GET(setting_path); |
460 | if (test) { |
461 | if (!formats_imported.has(compression_formats[index])) { |
462 | valid = false; |
463 | break; |
464 | } |
465 | } |
466 | } else { |
467 | WARN_PRINT("Setting for imported format not found: " + setting_path); |
468 | } |
469 | index++; |
470 | } |
471 | |
472 | return valid; |
473 | } |
474 | |
475 | ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = nullptr; |
476 | |
477 | ResourceImporterLayeredTexture::ResourceImporterLayeredTexture(bool p_singleton) { |
478 | // This should only be set through the EditorNode. |
479 | if (p_singleton) { |
480 | singleton = this; |
481 | } |
482 | |
483 | mode = MODE_CUBEMAP; |
484 | } |
485 | |
486 | ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() { |
487 | if (singleton == this) { |
488 | singleton = nullptr; |
489 | } |
490 | } |
491 | |
492 | void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source_file, Ref<LayeredTextureImport> r_texture_import) { |
493 | String extension = get_save_extension(); |
494 | ERR_FAIL_NULL(r_texture_import->csource); |
495 | if (r_texture_import->compress_mode != COMPRESS_VRAM_COMPRESSED) { |
496 | // Import normally. |
497 | _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false); |
498 | return; |
499 | } |
500 | // Must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). |
501 | // Android, GLES 2.x |
502 | |
503 | const bool can_s3tc_bptc = ResourceImporterTextureSettings::should_import_s3tc_bptc(); |
504 | const bool can_etc2_astc = ResourceImporterTextureSettings::should_import_etc2_astc(); |
505 | |
506 | // Add list of formats imported |
507 | if (can_s3tc_bptc) { |
508 | r_texture_import->formats_imported.push_back("s3tc_bptc" ); |
509 | } |
510 | if (can_etc2_astc) { |
511 | r_texture_import->formats_imported.push_back("etc2_astc" ); |
512 | } |
513 | |
514 | bool can_compress_hdr = r_texture_import->hdr_compression > 0; |
515 | ERR_FAIL_NULL(r_texture_import->image); |
516 | bool is_hdr = (r_texture_import->image->get_format() >= Image::FORMAT_RF && r_texture_import->image->get_format() <= Image::FORMAT_RGBE9995); |
517 | ERR_FAIL_NULL(r_texture_import->slices); |
518 | // Can compress hdr, but hdr with alpha is not compressible. |
519 | bool use_uncompressed = false; |
520 | |
521 | if (is_hdr) { |
522 | if (r_texture_import->used_channels == Image::USED_CHANNELS_LA || r_texture_import->used_channels == Image::USED_CHANNELS_RGBA) { |
523 | if (r_texture_import->hdr_compression == 2) { |
524 | // The user selected to compress hdr anyway, so force an alpha-less format. |
525 | if (r_texture_import->image->get_format() == Image::FORMAT_RGBAF) { |
526 | for (int i = 0; i < r_texture_import->slices->size(); i++) { |
527 | r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBF); |
528 | } |
529 | |
530 | } else if (r_texture_import->image->get_format() == Image::FORMAT_RGBAH) { |
531 | for (int i = 0; i < r_texture_import->slices->size(); i++) { |
532 | r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBH); |
533 | } |
534 | } |
535 | } else { |
536 | can_compress_hdr = false; |
537 | } |
538 | } |
539 | |
540 | if (!can_compress_hdr) { |
541 | //default to rgbe |
542 | if (r_texture_import->image->get_format() != Image::FORMAT_RGBE9995) { |
543 | for (int i = 0; i < r_texture_import->slices->size(); i++) { |
544 | r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBE9995); |
545 | } |
546 | } |
547 | use_uncompressed = true; |
548 | } |
549 | } |
550 | |
551 | if (use_uncompressed) { |
552 | _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, COMPRESS_VRAM_UNCOMPRESSED, r_texture_import->lossy, Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false); |
553 | } else { |
554 | if (can_s3tc_bptc) { |
555 | Image::CompressMode image_compress_mode; |
556 | String image_compress_format; |
557 | if (r_texture_import->high_quality || is_hdr) { |
558 | image_compress_mode = Image::COMPRESS_BPTC; |
559 | image_compress_format = "bptc" ; |
560 | } else { |
561 | image_compress_mode = Image::COMPRESS_S3TC; |
562 | image_compress_format = "s3tc" ; |
563 | } |
564 | _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true); |
565 | r_texture_import->platform_variants->push_back(image_compress_format); |
566 | } |
567 | |
568 | if (can_etc2_astc) { |
569 | Image::CompressMode image_compress_mode; |
570 | String image_compress_format; |
571 | if (r_texture_import->high_quality || is_hdr) { |
572 | image_compress_mode = Image::COMPRESS_ASTC; |
573 | image_compress_format = "astc" ; |
574 | } else { |
575 | image_compress_mode = Image::COMPRESS_ETC2; |
576 | image_compress_format = "etc2" ; |
577 | } |
578 | _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true); |
579 | r_texture_import->platform_variants->push_back(image_compress_format); |
580 | } |
581 | } |
582 | } |
583 | |