1/**************************************************************************/
2/* image.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 "image.h"
32
33#include "core/error/error_list.h"
34#include "core/error/error_macros.h"
35#include "core/io/image_loader.h"
36#include "core/io/resource_loader.h"
37#include "core/math/math_funcs.h"
38#include "core/string/print_string.h"
39#include "core/templates/hash_map.h"
40#include "core/variant/dictionary.h"
41
42#include <stdio.h>
43#include <cmath>
44
45const char *Image::format_names[Image::FORMAT_MAX] = {
46 "Lum8", //luminance
47 "LumAlpha8", //luminance-alpha
48 "Red8",
49 "RedGreen",
50 "RGB8",
51 "RGBA8",
52 "RGBA4444",
53 "RGBA5551",
54 "RFloat", //float
55 "RGFloat",
56 "RGBFloat",
57 "RGBAFloat",
58 "RHalf", //half float
59 "RGHalf",
60 "RGBHalf",
61 "RGBAHalf",
62 "RGBE9995",
63 "DXT1 RGB8", //s3tc
64 "DXT3 RGBA8",
65 "DXT5 RGBA8",
66 "RGTC Red8",
67 "RGTC RedGreen8",
68 "BPTC_RGBA",
69 "BPTC_RGBF",
70 "BPTC_RGBFU",
71 "ETC", //etc1
72 "ETC2_R11", //etc2
73 "ETC2_R11S", //signed", NOT srgb.
74 "ETC2_RG11",
75 "ETC2_RG11S",
76 "ETC2_RGB8",
77 "ETC2_RGBA8",
78 "ETC2_RGB8A1",
79 "ETC2_RA_AS_RG",
80 "FORMAT_DXT5_RA_AS_RG",
81 "ASTC_4x4",
82 "ASTC_4x4_HDR",
83 "ASTC_8x8",
84 "ASTC_8x8_HDR",
85};
86
87SavePNGFunc Image::save_png_func = nullptr;
88SaveJPGFunc Image::save_jpg_func = nullptr;
89SaveEXRFunc Image::save_exr_func = nullptr;
90
91SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
92SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr;
93SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr;
94
95SaveWebPFunc Image::save_webp_func = nullptr;
96SaveWebPBufferFunc Image::save_webp_buffer_func = nullptr;
97
98void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel) {
99 uint32_t ofs = (p_y * width + p_x) * p_pixel_size;
100 memcpy(p_data + ofs, p_pixel, p_pixel_size);
101}
102
103void Image::_get_pixelb(int p_x, int p_y, uint32_t p_pixel_size, const uint8_t *p_data, uint8_t *p_pixel) {
104 uint32_t ofs = (p_y * width + p_x) * p_pixel_size;
105 memcpy(p_pixel, p_data + ofs, p_pixel_size);
106}
107
108int Image::get_format_pixel_size(Format p_format) {
109 switch (p_format) {
110 case FORMAT_L8:
111 return 1; //luminance
112 case FORMAT_LA8:
113 return 2; //luminance-alpha
114 case FORMAT_R8:
115 return 1;
116 case FORMAT_RG8:
117 return 2;
118 case FORMAT_RGB8:
119 return 3;
120 case FORMAT_RGBA8:
121 return 4;
122 case FORMAT_RGBA4444:
123 return 2;
124 case FORMAT_RGB565:
125 return 2;
126 case FORMAT_RF:
127 return 4; //float
128 case FORMAT_RGF:
129 return 8;
130 case FORMAT_RGBF:
131 return 12;
132 case FORMAT_RGBAF:
133 return 16;
134 case FORMAT_RH:
135 return 2; //half float
136 case FORMAT_RGH:
137 return 4;
138 case FORMAT_RGBH:
139 return 6;
140 case FORMAT_RGBAH:
141 return 8;
142 case FORMAT_RGBE9995:
143 return 4;
144 case FORMAT_DXT1:
145 return 1; //s3tc bc1
146 case FORMAT_DXT3:
147 return 1; //bc2
148 case FORMAT_DXT5:
149 return 1; //bc3
150 case FORMAT_RGTC_R:
151 return 1; //bc4
152 case FORMAT_RGTC_RG:
153 return 1; //bc5
154 case FORMAT_BPTC_RGBA:
155 return 1; //btpc bc6h
156 case FORMAT_BPTC_RGBF:
157 return 1; //float /
158 case FORMAT_BPTC_RGBFU:
159 return 1; //unsigned float
160 case FORMAT_ETC:
161 return 1; //etc1
162 case FORMAT_ETC2_R11:
163 return 1; //etc2
164 case FORMAT_ETC2_R11S:
165 return 1; //signed: return 1; NOT srgb.
166 case FORMAT_ETC2_RG11:
167 return 1;
168 case FORMAT_ETC2_RG11S:
169 return 1;
170 case FORMAT_ETC2_RGB8:
171 return 1;
172 case FORMAT_ETC2_RGBA8:
173 return 1;
174 case FORMAT_ETC2_RGB8A1:
175 return 1;
176 case FORMAT_ETC2_RA_AS_RG:
177 return 1;
178 case FORMAT_DXT5_RA_AS_RG:
179 return 1;
180 case FORMAT_ASTC_4x4:
181 return 1;
182 case FORMAT_ASTC_4x4_HDR:
183 return 1;
184 case FORMAT_ASTC_8x8:
185 return 1;
186 case FORMAT_ASTC_8x8_HDR:
187 return 1;
188 case FORMAT_MAX: {
189 }
190 }
191 return 0;
192}
193
194void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
195 switch (p_format) {
196 case FORMAT_DXT1: //s3tc bc1
197 case FORMAT_DXT3: //bc2
198 case FORMAT_DXT5: //bc3
199 case FORMAT_RGTC_R: //bc4
200 case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
201
202 r_w = 4;
203 r_h = 4;
204 } break;
205 case FORMAT_ETC: {
206 r_w = 4;
207 r_h = 4;
208 } break;
209 case FORMAT_BPTC_RGBA:
210 case FORMAT_BPTC_RGBF:
211 case FORMAT_BPTC_RGBFU: {
212 r_w = 4;
213 r_h = 4;
214 } break;
215 case FORMAT_ETC2_R11: //etc2
216 case FORMAT_ETC2_R11S: //signed: NOT srgb.
217 case FORMAT_ETC2_RG11:
218 case FORMAT_ETC2_RG11S:
219 case FORMAT_ETC2_RGB8:
220 case FORMAT_ETC2_RGBA8:
221 case FORMAT_ETC2_RGB8A1:
222 case FORMAT_ETC2_RA_AS_RG:
223 case FORMAT_DXT5_RA_AS_RG: {
224 r_w = 4;
225 r_h = 4;
226
227 } break;
228 case FORMAT_ASTC_4x4:
229 case FORMAT_ASTC_4x4_HDR: {
230 r_w = 4;
231 r_h = 4;
232
233 } break;
234 case FORMAT_ASTC_8x8:
235 case FORMAT_ASTC_8x8_HDR: {
236 r_w = 8;
237 r_h = 8;
238
239 } break;
240 default: {
241 r_w = 1;
242 r_h = 1;
243 } break;
244 }
245}
246
247int Image::get_format_pixel_rshift(Format p_format) {
248 if (p_format == FORMAT_ASTC_8x8) {
249 return 2;
250 } else if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
251 return 1;
252 } else {
253 return 0;
254 }
255}
256
257int Image::get_format_block_size(Format p_format) {
258 switch (p_format) {
259 case FORMAT_DXT1: //s3tc bc1
260 case FORMAT_DXT3: //bc2
261 case FORMAT_DXT5: //bc3
262 case FORMAT_RGTC_R: //bc4
263 case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
264
265 return 4;
266 }
267 case FORMAT_ETC: {
268 return 4;
269 }
270 case FORMAT_BPTC_RGBA:
271 case FORMAT_BPTC_RGBF:
272 case FORMAT_BPTC_RGBFU: {
273 return 4;
274 }
275 case FORMAT_ETC2_R11: //etc2
276 case FORMAT_ETC2_R11S: //signed: NOT srgb.
277 case FORMAT_ETC2_RG11:
278 case FORMAT_ETC2_RG11S:
279 case FORMAT_ETC2_RGB8:
280 case FORMAT_ETC2_RGBA8:
281 case FORMAT_ETC2_RGB8A1:
282 case FORMAT_ETC2_RA_AS_RG: //used to make basis universal happy
283 case FORMAT_DXT5_RA_AS_RG: //used to make basis universal happy
284
285 {
286 return 4;
287 }
288 case FORMAT_ASTC_4x4:
289 case FORMAT_ASTC_4x4_HDR: {
290 return 4;
291 }
292 case FORMAT_ASTC_8x8:
293 case FORMAT_ASTC_8x8_HDR: {
294 return 8;
295 }
296 default: {
297 }
298 }
299
300 return 1;
301}
302
303void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const {
304 int w = width;
305 int h = height;
306 int ofs = 0;
307
308 int pixel_size = get_format_pixel_size(format);
309 int pixel_rshift = get_format_pixel_rshift(format);
310 int block = get_format_block_size(format);
311 int minw, minh;
312 get_format_min_pixel_size(format, minw, minh);
313
314 for (int i = 0; i < p_mipmap; i++) {
315 int bw = w % block != 0 ? w + (block - w % block) : w;
316 int bh = h % block != 0 ? h + (block - h % block) : h;
317
318 int s = bw * bh;
319
320 s *= pixel_size;
321 s >>= pixel_rshift;
322 ofs += s;
323 w = MAX(minw, w >> 1);
324 h = MAX(minh, h >> 1);
325 }
326
327 r_offset = ofs;
328 r_width = w;
329 r_height = h;
330}
331
332int Image::get_mipmap_offset(int p_mipmap) const {
333 ERR_FAIL_INDEX_V(p_mipmap, get_mipmap_count() + 1, -1);
334
335 int ofs, w, h;
336 _get_mipmap_offset_and_size(p_mipmap, ofs, w, h);
337 return ofs;
338}
339
340int Image::get_mipmap_byte_size(int p_mipmap) const {
341 ERR_FAIL_INDEX_V(p_mipmap, get_mipmap_count() + 1, -1);
342
343 int ofs, w, h;
344 _get_mipmap_offset_and_size(p_mipmap, ofs, w, h);
345 int ofs2;
346 _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w, h);
347 return ofs2 - ofs;
348}
349
350void Image::get_mipmap_offset_and_size(int p_mipmap, int &r_ofs, int &r_size) const {
351 int ofs, w, h;
352 _get_mipmap_offset_and_size(p_mipmap, ofs, w, h);
353 int ofs2;
354 _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w, h);
355 r_ofs = ofs;
356 r_size = ofs2 - ofs;
357}
358
359void Image::get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int &r_size, int &w, int &h) const {
360 int ofs;
361 _get_mipmap_offset_and_size(p_mipmap, ofs, w, h);
362 int ofs2, w2, h2;
363 _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w2, h2);
364 r_ofs = ofs;
365 r_size = ofs2 - ofs;
366}
367
368Image::Image3DValidateError Image::validate_3d_image(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_images) {
369 int w = p_width;
370 int h = p_height;
371 int d = p_depth;
372
373 int arr_ofs = 0;
374
375 while (true) {
376 for (int i = 0; i < d; i++) {
377 int idx = i + arr_ofs;
378 if (idx >= p_images.size()) {
379 return VALIDATE_3D_ERR_MISSING_IMAGES;
380 }
381 if (p_images[idx].is_null() || p_images[idx]->is_empty()) {
382 return VALIDATE_3D_ERR_IMAGE_EMPTY;
383 }
384 if (p_images[idx]->get_format() != p_format) {
385 return VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH;
386 }
387 if (p_images[idx]->get_width() != w || p_images[idx]->get_height() != h) {
388 return VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH;
389 }
390 if (p_images[idx]->has_mipmaps()) {
391 return VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS;
392 }
393 }
394
395 arr_ofs += d;
396
397 if (!p_mipmaps) {
398 break;
399 }
400
401 if (w == 1 && h == 1 && d == 1) {
402 break;
403 }
404
405 w = MAX(1, w >> 1);
406 h = MAX(1, h >> 1);
407 d = MAX(1, d >> 1);
408 }
409
410 if (arr_ofs != p_images.size()) {
411 return VALIDATE_3D_ERR_EXTRA_IMAGES;
412 }
413
414 return VALIDATE_3D_OK;
415}
416
417String Image::get_3d_image_validation_error_text(Image3DValidateError p_error) {
418 switch (p_error) {
419 case VALIDATE_3D_OK: {
420 return "Ok";
421 } break;
422 case VALIDATE_3D_ERR_IMAGE_EMPTY: {
423 return "Empty Image found";
424 } break;
425 case VALIDATE_3D_ERR_MISSING_IMAGES: {
426 return "Missing Images";
427 } break;
428 case VALIDATE_3D_ERR_EXTRA_IMAGES: {
429 return "Too many Images";
430 } break;
431 case VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH: {
432 return "Image size mismatch";
433 } break;
434 case VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH: {
435 return "Image format mismatch";
436 } break;
437 case VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS: {
438 return "Image has included mipmaps";
439 } break;
440 }
441 return String();
442}
443
444int Image::get_width() const {
445 return width;
446}
447
448int Image::get_height() const {
449 return height;
450}
451
452Size2i Image::get_size() const {
453 return Size2i(width, height);
454}
455
456bool Image::has_mipmaps() const {
457 return mipmaps;
458}
459
460int Image::get_mipmap_count() const {
461 if (mipmaps) {
462 return get_image_required_mipmaps(width, height, format);
463 } else {
464 return 0;
465 }
466}
467
468//using template generates perfectly optimized code due to constant expression reduction and unused variable removal present in all compilers
469template <uint32_t read_bytes, bool read_alpha, uint32_t write_bytes, bool write_alpha, bool read_gray, bool write_gray>
470static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p_dst) {
471 constexpr uint32_t max_bytes = MAX(read_bytes, write_bytes);
472
473 for (int y = 0; y < p_height; y++) {
474 for (int x = 0; x < p_width; x++) {
475 const uint8_t *rofs = &p_src[((y * p_width) + x) * (read_bytes + (read_alpha ? 1 : 0))];
476 uint8_t *wofs = &p_dst[((y * p_width) + x) * (write_bytes + (write_alpha ? 1 : 0))];
477
478 uint8_t rgba[4] = { 0, 0, 0, 255 };
479
480 if constexpr (read_gray) {
481 rgba[0] = rofs[0];
482 rgba[1] = rofs[0];
483 rgba[2] = rofs[0];
484 } else {
485 for (uint32_t i = 0; i < max_bytes; i++) {
486 rgba[i] = (i < read_bytes) ? rofs[i] : 0;
487 }
488 }
489
490 if constexpr (read_alpha || write_alpha) {
491 rgba[3] = read_alpha ? rofs[read_bytes] : 255;
492 }
493
494 if constexpr (write_gray) {
495 // REC.709
496 const uint8_t luminance = (13938U * rgba[0] + 46869U * rgba[1] + 4729U * rgba[2] + 32768U) >> 16U;
497 wofs[0] = luminance;
498 } else {
499 for (uint32_t i = 0; i < write_bytes; i++) {
500 wofs[i] = rgba[i];
501 }
502 }
503
504 if constexpr (write_alpha) {
505 wofs[write_bytes] = rgba[3];
506 }
507 }
508 }
509}
510
511void Image::convert(Format p_new_format) {
512 if (data.size() == 0) {
513 return;
514 }
515
516 if (p_new_format == format) {
517 return;
518 }
519
520 // Includes the main image.
521 const int mipmap_count = get_mipmap_count() + 1;
522
523 if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) {
524 ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
525
526 } else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) {
527 //use put/set pixel which is slower but works with non byte formats
528 Image new_img(width, height, mipmaps, p_new_format);
529
530 for (int mip = 0; mip < mipmap_count; mip++) {
531 Ref<Image> src_mip = get_image_from_mipmap(mip);
532 Ref<Image> new_mip = new_img.get_image_from_mipmap(mip);
533
534 for (int y = 0; y < src_mip->height; y++) {
535 for (int x = 0; x < src_mip->width; x++) {
536 new_mip->set_pixel(x, y, src_mip->get_pixel(x, y));
537 }
538 }
539
540 int mip_offset = 0;
541 int mip_size = 0;
542 new_img.get_mipmap_offset_and_size(mip, mip_offset, mip_size);
543
544 memcpy(new_img.data.ptrw() + mip_offset, new_mip->data.ptr(), mip_size);
545 }
546
547 _copy_internals_from(new_img);
548
549 return;
550 }
551
552 Image new_img(width, height, mipmaps, p_new_format);
553
554 int conversion_type = format | p_new_format << 8;
555
556 for (int mip = 0; mip < mipmap_count; mip++) {
557 int mip_offset = 0;
558 int mip_size = 0;
559 int mip_width = 0;
560 int mip_height = 0;
561 get_mipmap_offset_size_and_dimensions(mip, mip_offset, mip_size, mip_width, mip_height);
562
563 const uint8_t *rptr = data.ptr() + mip_offset;
564 uint8_t *wptr = new_img.data.ptrw() + new_img.get_mipmap_offset(mip);
565
566 switch (conversion_type) {
567 case FORMAT_L8 | (FORMAT_LA8 << 8):
568 _convert<1, false, 1, true, true, true>(mip_width, mip_height, rptr, wptr);
569 break;
570 case FORMAT_L8 | (FORMAT_R8 << 8):
571 _convert<1, false, 1, false, true, false>(mip_width, mip_height, rptr, wptr);
572 break;
573 case FORMAT_L8 | (FORMAT_RG8 << 8):
574 _convert<1, false, 2, false, true, false>(mip_width, mip_height, rptr, wptr);
575 break;
576 case FORMAT_L8 | (FORMAT_RGB8 << 8):
577 _convert<1, false, 3, false, true, false>(mip_width, mip_height, rptr, wptr);
578 break;
579 case FORMAT_L8 | (FORMAT_RGBA8 << 8):
580 _convert<1, false, 3, true, true, false>(mip_width, mip_height, rptr, wptr);
581 break;
582 case FORMAT_LA8 | (FORMAT_L8 << 8):
583 _convert<1, true, 1, false, true, true>(mip_width, mip_height, rptr, wptr);
584 break;
585 case FORMAT_LA8 | (FORMAT_R8 << 8):
586 _convert<1, true, 1, false, true, false>(mip_width, mip_height, rptr, wptr);
587 break;
588 case FORMAT_LA8 | (FORMAT_RG8 << 8):
589 _convert<1, true, 2, false, true, false>(mip_width, mip_height, rptr, wptr);
590 break;
591 case FORMAT_LA8 | (FORMAT_RGB8 << 8):
592 _convert<1, true, 3, false, true, false>(mip_width, mip_height, rptr, wptr);
593 break;
594 case FORMAT_LA8 | (FORMAT_RGBA8 << 8):
595 _convert<1, true, 3, true, true, false>(mip_width, mip_height, rptr, wptr);
596 break;
597 case FORMAT_R8 | (FORMAT_L8 << 8):
598 _convert<1, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
599 break;
600 case FORMAT_R8 | (FORMAT_LA8 << 8):
601 _convert<1, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
602 break;
603 case FORMAT_R8 | (FORMAT_RG8 << 8):
604 _convert<1, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
605 break;
606 case FORMAT_R8 | (FORMAT_RGB8 << 8):
607 _convert<1, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
608 break;
609 case FORMAT_R8 | (FORMAT_RGBA8 << 8):
610 _convert<1, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
611 break;
612 case FORMAT_RG8 | (FORMAT_L8 << 8):
613 _convert<2, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
614 break;
615 case FORMAT_RG8 | (FORMAT_LA8 << 8):
616 _convert<2, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
617 break;
618 case FORMAT_RG8 | (FORMAT_R8 << 8):
619 _convert<2, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
620 break;
621 case FORMAT_RG8 | (FORMAT_RGB8 << 8):
622 _convert<2, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
623 break;
624 case FORMAT_RG8 | (FORMAT_RGBA8 << 8):
625 _convert<2, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
626 break;
627 case FORMAT_RGB8 | (FORMAT_L8 << 8):
628 _convert<3, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
629 break;
630 case FORMAT_RGB8 | (FORMAT_LA8 << 8):
631 _convert<3, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
632 break;
633 case FORMAT_RGB8 | (FORMAT_R8 << 8):
634 _convert<3, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
635 break;
636 case FORMAT_RGB8 | (FORMAT_RG8 << 8):
637 _convert<3, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
638 break;
639 case FORMAT_RGB8 | (FORMAT_RGBA8 << 8):
640 _convert<3, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
641 break;
642 case FORMAT_RGBA8 | (FORMAT_L8 << 8):
643 _convert<3, true, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
644 break;
645 case FORMAT_RGBA8 | (FORMAT_LA8 << 8):
646 _convert<3, true, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
647 break;
648 case FORMAT_RGBA8 | (FORMAT_R8 << 8):
649 _convert<3, true, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
650 break;
651 case FORMAT_RGBA8 | (FORMAT_RG8 << 8):
652 _convert<3, true, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
653 break;
654 case FORMAT_RGBA8 | (FORMAT_RGB8 << 8):
655 _convert<3, true, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
656 break;
657 }
658 }
659
660 _copy_internals_from(new_img);
661}
662
663Image::Format Image::get_format() const {
664 return format;
665}
666
667static double _bicubic_interp_kernel(double x) {
668 x = ABS(x);
669
670 double bc = 0;
671
672 if (x <= 1) {
673 bc = (1.5 * x - 2.5) * x * x + 1;
674 } else if (x < 2) {
675 bc = ((-0.5 * x + 2.5) * x - 4) * x + 2;
676 }
677
678 return bc;
679}
680
681template <int CC, class T>
682static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
683 // get source image size
684 int width = p_src_width;
685 int height = p_src_height;
686 double xfac = (double)width / p_dst_width;
687 double yfac = (double)height / p_dst_height;
688 // coordinates of source points and coefficients
689 double ox, oy, dx, dy;
690 int ox1, oy1, ox2, oy2;
691 // destination pixel values
692 // width and height decreased by 1
693 int ymax = height - 1;
694 int xmax = width - 1;
695 // temporary pointer
696
697 for (uint32_t y = 0; y < p_dst_height; y++) {
698 // Y coordinates
699 oy = (double)y * yfac - 0.5f;
700 oy1 = (int)oy;
701 dy = oy - (double)oy1;
702
703 for (uint32_t x = 0; x < p_dst_width; x++) {
704 // X coordinates
705 ox = (double)x * xfac - 0.5f;
706 ox1 = (int)ox;
707 dx = ox - (double)ox1;
708
709 // initial pixel value
710
711 T *__restrict dst = ((T *)p_dst) + (y * p_dst_width + x) * CC;
712
713 double color[CC];
714 for (int i = 0; i < CC; i++) {
715 color[i] = 0;
716 }
717
718 for (int n = -1; n < 3; n++) {
719 // get Y coefficient
720 [[maybe_unused]] double k1 = _bicubic_interp_kernel(dy - (double)n);
721
722 oy2 = oy1 + n;
723 if (oy2 < 0) {
724 oy2 = 0;
725 }
726 if (oy2 > ymax) {
727 oy2 = ymax;
728 }
729
730 for (int m = -1; m < 3; m++) {
731 // get X coefficient
732 [[maybe_unused]] double k2 = k1 * _bicubic_interp_kernel((double)m - dx);
733
734 ox2 = ox1 + m;
735 if (ox2 < 0) {
736 ox2 = 0;
737 }
738 if (ox2 > xmax) {
739 ox2 = xmax;
740 }
741
742 // get pixel of original image
743 const T *__restrict p = ((T *)p_src) + (oy2 * p_src_width + ox2) * CC;
744
745 for (int i = 0; i < CC; i++) {
746 if constexpr (sizeof(T) == 2) { //half float
747 color[i] = Math::half_to_float(p[i]);
748 } else {
749 color[i] += p[i] * k2;
750 }
751 }
752 }
753 }
754
755 for (int i = 0; i < CC; i++) {
756 if constexpr (sizeof(T) == 1) { //byte
757 dst[i] = CLAMP(Math::fast_ftoi(color[i]), 0, 255);
758 } else if constexpr (sizeof(T) == 2) { //half float
759 dst[i] = Math::make_half_float(color[i]);
760 } else {
761 dst[i] = color[i];
762 }
763 }
764 }
765 }
766}
767
768template <int CC, class T>
769static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
770 enum {
771 FRAC_BITS = 8,
772 FRAC_LEN = (1 << FRAC_BITS),
773 FRAC_HALF = (FRAC_LEN >> 1),
774 FRAC_MASK = FRAC_LEN - 1
775 };
776
777 for (uint32_t i = 0; i < p_dst_height; i++) {
778 // Add 0.5 in order to interpolate based on pixel center
779 uint32_t src_yofs_up_fp = (i + 0.5) * p_src_height * FRAC_LEN / p_dst_height;
780 // Calculate nearest src pixel center above current, and truncate to get y index
781 uint32_t src_yofs_up = src_yofs_up_fp >= FRAC_HALF ? (src_yofs_up_fp - FRAC_HALF) >> FRAC_BITS : 0;
782 uint32_t src_yofs_down = (src_yofs_up_fp + FRAC_HALF) >> FRAC_BITS;
783 if (src_yofs_down >= p_src_height) {
784 src_yofs_down = p_src_height - 1;
785 }
786 // Calculate distance to pixel center of src_yofs_up
787 uint32_t src_yofs_frac = src_yofs_up_fp & FRAC_MASK;
788 src_yofs_frac = src_yofs_frac >= FRAC_HALF ? src_yofs_frac - FRAC_HALF : src_yofs_frac + FRAC_HALF;
789
790 uint32_t y_ofs_up = src_yofs_up * p_src_width * CC;
791 uint32_t y_ofs_down = src_yofs_down * p_src_width * CC;
792
793 for (uint32_t j = 0; j < p_dst_width; j++) {
794 uint32_t src_xofs_left_fp = (j + 0.5) * p_src_width * FRAC_LEN / p_dst_width;
795 uint32_t src_xofs_left = src_xofs_left_fp >= FRAC_HALF ? (src_xofs_left_fp - FRAC_HALF) >> FRAC_BITS : 0;
796 uint32_t src_xofs_right = (src_xofs_left_fp + FRAC_HALF) >> FRAC_BITS;
797 if (src_xofs_right >= p_src_width) {
798 src_xofs_right = p_src_width - 1;
799 }
800 uint32_t src_xofs_frac = src_xofs_left_fp & FRAC_MASK;
801 src_xofs_frac = src_xofs_frac >= FRAC_HALF ? src_xofs_frac - FRAC_HALF : src_xofs_frac + FRAC_HALF;
802
803 src_xofs_left *= CC;
804 src_xofs_right *= CC;
805
806 for (uint32_t l = 0; l < CC; l++) {
807 if constexpr (sizeof(T) == 1) { //uint8
808 uint32_t p00 = p_src[y_ofs_up + src_xofs_left + l] << FRAC_BITS;
809 uint32_t p10 = p_src[y_ofs_up + src_xofs_right + l] << FRAC_BITS;
810 uint32_t p01 = p_src[y_ofs_down + src_xofs_left + l] << FRAC_BITS;
811 uint32_t p11 = p_src[y_ofs_down + src_xofs_right + l] << FRAC_BITS;
812
813 uint32_t interp_up = p00 + (((p10 - p00) * src_xofs_frac) >> FRAC_BITS);
814 uint32_t interp_down = p01 + (((p11 - p01) * src_xofs_frac) >> FRAC_BITS);
815 uint32_t interp = interp_up + (((interp_down - interp_up) * src_yofs_frac) >> FRAC_BITS);
816 interp >>= FRAC_BITS;
817 p_dst[i * p_dst_width * CC + j * CC + l] = uint8_t(interp);
818 } else if constexpr (sizeof(T) == 2) { //half float
819
820 float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS);
821 float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS);
822 const T *src = ((const T *)p_src);
823 T *dst = ((T *)p_dst);
824
825 float p00 = Math::half_to_float(src[y_ofs_up + src_xofs_left + l]);
826 float p10 = Math::half_to_float(src[y_ofs_up + src_xofs_right + l]);
827 float p01 = Math::half_to_float(src[y_ofs_down + src_xofs_left + l]);
828 float p11 = Math::half_to_float(src[y_ofs_down + src_xofs_right + l]);
829
830 float interp_up = p00 + (p10 - p00) * xofs_frac;
831 float interp_down = p01 + (p11 - p01) * xofs_frac;
832 float interp = interp_up + ((interp_down - interp_up) * yofs_frac);
833
834 dst[i * p_dst_width * CC + j * CC + l] = Math::make_half_float(interp);
835 } else if constexpr (sizeof(T) == 4) { //float
836
837 float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS);
838 float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS);
839 const T *src = ((const T *)p_src);
840 T *dst = ((T *)p_dst);
841
842 float p00 = src[y_ofs_up + src_xofs_left + l];
843 float p10 = src[y_ofs_up + src_xofs_right + l];
844 float p01 = src[y_ofs_down + src_xofs_left + l];
845 float p11 = src[y_ofs_down + src_xofs_right + l];
846
847 float interp_up = p00 + (p10 - p00) * xofs_frac;
848 float interp_down = p01 + (p11 - p01) * xofs_frac;
849 float interp = interp_up + ((interp_down - interp_up) * yofs_frac);
850
851 dst[i * p_dst_width * CC + j * CC + l] = interp;
852 }
853 }
854 }
855 }
856}
857
858template <int CC, class T>
859static void _scale_nearest(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
860 for (uint32_t i = 0; i < p_dst_height; i++) {
861 uint32_t src_yofs = i * p_src_height / p_dst_height;
862 uint32_t y_ofs = src_yofs * p_src_width * CC;
863
864 for (uint32_t j = 0; j < p_dst_width; j++) {
865 uint32_t src_xofs = j * p_src_width / p_dst_width;
866 src_xofs *= CC;
867
868 for (uint32_t l = 0; l < CC; l++) {
869 const T *src = ((const T *)p_src);
870 T *dst = ((T *)p_dst);
871
872 T p = src[y_ofs + src_xofs + l];
873 dst[i * p_dst_width * CC + j * CC + l] = p;
874 }
875 }
876 }
877}
878
879#define LANCZOS_TYPE 3
880
881static float _lanczos(float p_x) {
882 return Math::abs(p_x) >= LANCZOS_TYPE ? 0 : Math::sincn(p_x) * Math::sincn(p_x / LANCZOS_TYPE);
883}
884
885template <int CC, class T>
886static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
887 int32_t src_width = p_src_width;
888 int32_t src_height = p_src_height;
889 int32_t dst_height = p_dst_height;
890 int32_t dst_width = p_dst_width;
891
892 uint32_t buffer_size = src_height * dst_width * CC;
893 float *buffer = memnew_arr(float, buffer_size); // Store the first pass in a buffer
894
895 { // FIRST PASS (horizontal)
896
897 float x_scale = float(src_width) / float(dst_width);
898
899 float scale_factor = MAX(x_scale, 1); // A larger kernel is required only when downscaling
900 int32_t half_kernel = LANCZOS_TYPE * scale_factor;
901
902 float *kernel = memnew_arr(float, half_kernel * 2);
903
904 for (int32_t buffer_x = 0; buffer_x < dst_width; buffer_x++) {
905 // The corresponding point on the source image
906 float src_x = (buffer_x + 0.5f) * x_scale; // Offset by 0.5 so it uses the pixel's center
907 int32_t start_x = MAX(0, int32_t(src_x) - half_kernel + 1);
908 int32_t end_x = MIN(src_width - 1, int32_t(src_x) + half_kernel);
909
910 // Create the kernel used by all the pixels of the column
911 for (int32_t target_x = start_x; target_x <= end_x; target_x++) {
912 kernel[target_x - start_x] = _lanczos((target_x + 0.5f - src_x) / scale_factor);
913 }
914
915 for (int32_t buffer_y = 0; buffer_y < src_height; buffer_y++) {
916 float pixel[CC] = { 0 };
917 float weight = 0;
918
919 for (int32_t target_x = start_x; target_x <= end_x; target_x++) {
920 float lanczos_val = kernel[target_x - start_x];
921 weight += lanczos_val;
922
923 const T *__restrict src_data = ((const T *)p_src) + (buffer_y * src_width + target_x) * CC;
924
925 for (uint32_t i = 0; i < CC; i++) {
926 if constexpr (sizeof(T) == 2) { //half float
927 pixel[i] += Math::half_to_float(src_data[i]) * lanczos_val;
928 } else {
929 pixel[i] += src_data[i] * lanczos_val;
930 }
931 }
932 }
933
934 float *dst_data = ((float *)buffer) + (buffer_y * dst_width + buffer_x) * CC;
935
936 for (uint32_t i = 0; i < CC; i++) {
937 dst_data[i] = pixel[i] / weight; // Normalize the sum of all the samples
938 }
939 }
940 }
941
942 memdelete_arr(kernel);
943 } // End of first pass
944
945 { // SECOND PASS (vertical + result)
946
947 float y_scale = float(src_height) / float(dst_height);
948
949 float scale_factor = MAX(y_scale, 1);
950 int32_t half_kernel = LANCZOS_TYPE * scale_factor;
951
952 float *kernel = memnew_arr(float, half_kernel * 2);
953
954 for (int32_t dst_y = 0; dst_y < dst_height; dst_y++) {
955 float buffer_y = (dst_y + 0.5f) * y_scale;
956 int32_t start_y = MAX(0, int32_t(buffer_y) - half_kernel + 1);
957 int32_t end_y = MIN(src_height - 1, int32_t(buffer_y) + half_kernel);
958
959 for (int32_t target_y = start_y; target_y <= end_y; target_y++) {
960 kernel[target_y - start_y] = _lanczos((target_y + 0.5f - buffer_y) / scale_factor);
961 }
962
963 for (int32_t dst_x = 0; dst_x < dst_width; dst_x++) {
964 float pixel[CC] = { 0 };
965 float weight = 0;
966
967 for (int32_t target_y = start_y; target_y <= end_y; target_y++) {
968 float lanczos_val = kernel[target_y - start_y];
969 weight += lanczos_val;
970
971 float *buffer_data = ((float *)buffer) + (target_y * dst_width + dst_x) * CC;
972
973 for (uint32_t i = 0; i < CC; i++) {
974 pixel[i] += buffer_data[i] * lanczos_val;
975 }
976 }
977
978 T *dst_data = ((T *)p_dst) + (dst_y * dst_width + dst_x) * CC;
979
980 for (uint32_t i = 0; i < CC; i++) {
981 pixel[i] /= weight;
982
983 if constexpr (sizeof(T) == 1) { //byte
984 dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 255);
985 } else if constexpr (sizeof(T) == 2) { //half float
986 dst_data[i] = Math::make_half_float(pixel[i]);
987 } else { // float
988 dst_data[i] = pixel[i];
989 }
990 }
991 }
992 }
993
994 memdelete_arr(kernel);
995 } // End of second pass
996
997 memdelete_arr(buffer);
998}
999
1000static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, float p_alpha, uint32_t p_width, uint32_t p_height, uint32_t p_pixel_size) {
1001 uint16_t alpha = MIN((uint16_t)(p_alpha * 256.0f), 256);
1002
1003 for (uint32_t i = 0; i < p_width * p_height * p_pixel_size; i++) {
1004 p_dst[i] = (p_dst[i] * (256 - alpha) + p_src[i] * alpha) >> 8;
1005 }
1006}
1007
1008bool Image::is_size_po2() const {
1009 return uint32_t(width) == next_power_of_2(width) && uint32_t(height) == next_power_of_2(height);
1010}
1011
1012void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
1013 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
1014
1015 int w = next_power_of_2(width);
1016 int h = next_power_of_2(height);
1017 if (p_square) {
1018 w = h = MAX(w, h);
1019 }
1020
1021 if (w == width && h == height) {
1022 if (!p_square || w == h) {
1023 return; //nothing to do
1024 }
1025 }
1026
1027 resize(w, h, p_interpolation);
1028}
1029
1030void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
1031 ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use set_data() first.");
1032 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
1033
1034 bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
1035
1036 ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0.");
1037 ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
1038 ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + ".");
1039 ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + ".");
1040 ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS));
1041
1042 if (p_width == width && p_height == height) {
1043 return;
1044 }
1045
1046 Image dst(p_width, p_height, false, format);
1047
1048 // Setup mipmap-aware scaling
1049 Image dst2;
1050 int mip1 = 0;
1051 int mip2 = 0;
1052 float mip1_weight = 0;
1053 if (mipmap_aware) {
1054 float avg_scale = ((float)p_width / width + (float)p_height / height) * 0.5f;
1055 if (avg_scale >= 1.0f) {
1056 mipmap_aware = false;
1057 } else {
1058 float level = Math::log(1.0f / avg_scale) / Math::log(2.0f);
1059 mip1 = CLAMP((int)Math::floor(level), 0, get_mipmap_count());
1060 mip2 = CLAMP((int)Math::ceil(level), 0, get_mipmap_count());
1061 mip1_weight = 1.0f - (level - mip1);
1062 }
1063 }
1064 bool interpolate_mipmaps = mipmap_aware && mip1 != mip2;
1065 if (interpolate_mipmaps) {
1066 dst2.initialize_data(p_width, p_height, false, format);
1067 }
1068
1069 bool had_mipmaps = mipmaps;
1070 if (interpolate_mipmaps && !had_mipmaps) {
1071 generate_mipmaps();
1072 }
1073 // --
1074
1075 const uint8_t *r = data.ptr();
1076 const unsigned char *r_ptr = r;
1077
1078 uint8_t *w = dst.data.ptrw();
1079 unsigned char *w_ptr = w;
1080
1081 switch (p_interpolation) {
1082 case INTERPOLATE_NEAREST: {
1083 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
1084 switch (get_format_pixel_size(format)) {
1085 case 1:
1086 _scale_nearest<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1087 break;
1088 case 2:
1089 _scale_nearest<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1090 break;
1091 case 3:
1092 _scale_nearest<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1093 break;
1094 case 4:
1095 _scale_nearest<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1096 break;
1097 }
1098 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
1099 switch (get_format_pixel_size(format)) {
1100 case 4:
1101 _scale_nearest<1, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1102 break;
1103 case 8:
1104 _scale_nearest<2, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1105 break;
1106 case 12:
1107 _scale_nearest<3, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1108 break;
1109 case 16:
1110 _scale_nearest<4, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1111 break;
1112 }
1113
1114 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
1115 switch (get_format_pixel_size(format)) {
1116 case 2:
1117 _scale_nearest<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1118 break;
1119 case 4:
1120 _scale_nearest<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1121 break;
1122 case 6:
1123 _scale_nearest<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1124 break;
1125 case 8:
1126 _scale_nearest<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1127 break;
1128 }
1129 }
1130
1131 } break;
1132 case INTERPOLATE_BILINEAR:
1133 case INTERPOLATE_TRILINEAR: {
1134 for (int i = 0; i < 2; ++i) {
1135 int src_width;
1136 int src_height;
1137 const unsigned char *src_ptr;
1138
1139 if (!mipmap_aware) {
1140 if (i == 0) {
1141 // Standard behavior
1142 src_width = width;
1143 src_height = height;
1144 src_ptr = r_ptr;
1145 } else {
1146 // No need for a second iteration
1147 break;
1148 }
1149 } else {
1150 if (i == 0) {
1151 // Read from the first mipmap that will be interpolated
1152 // (if both levels are the same, we will not interpolate, but at least we'll sample from the right level)
1153 int offs;
1154 _get_mipmap_offset_and_size(mip1, offs, src_width, src_height);
1155 src_ptr = r_ptr + offs;
1156 } else if (!interpolate_mipmaps) {
1157 // No need generate a second image
1158 break;
1159 } else {
1160 // Switch to read from the second mipmap that will be interpolated
1161 int offs;
1162 _get_mipmap_offset_and_size(mip2, offs, src_width, src_height);
1163 src_ptr = r_ptr + offs;
1164 // Switch to write to the second destination image
1165 w = dst2.data.ptrw();
1166 w_ptr = w;
1167 }
1168 }
1169
1170 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
1171 switch (get_format_pixel_size(format)) {
1172 case 1:
1173 _scale_bilinear<1, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1174 break;
1175 case 2:
1176 _scale_bilinear<2, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1177 break;
1178 case 3:
1179 _scale_bilinear<3, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1180 break;
1181 case 4:
1182 _scale_bilinear<4, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1183 break;
1184 }
1185 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
1186 switch (get_format_pixel_size(format)) {
1187 case 4:
1188 _scale_bilinear<1, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1189 break;
1190 case 8:
1191 _scale_bilinear<2, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1192 break;
1193 case 12:
1194 _scale_bilinear<3, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1195 break;
1196 case 16:
1197 _scale_bilinear<4, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1198 break;
1199 }
1200 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
1201 switch (get_format_pixel_size(format)) {
1202 case 2:
1203 _scale_bilinear<1, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1204 break;
1205 case 4:
1206 _scale_bilinear<2, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1207 break;
1208 case 6:
1209 _scale_bilinear<3, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1210 break;
1211 case 8:
1212 _scale_bilinear<4, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height);
1213 break;
1214 }
1215 }
1216 }
1217
1218 if (interpolate_mipmaps) {
1219 // Switch to read again from the first scaled mipmap to overlay it over the second
1220 r = dst.data.ptr();
1221 _overlay(r, w, mip1_weight, p_width, p_height, get_format_pixel_size(format));
1222 }
1223
1224 } break;
1225 case INTERPOLATE_CUBIC: {
1226 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
1227 switch (get_format_pixel_size(format)) {
1228 case 1:
1229 _scale_cubic<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1230 break;
1231 case 2:
1232 _scale_cubic<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1233 break;
1234 case 3:
1235 _scale_cubic<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1236 break;
1237 case 4:
1238 _scale_cubic<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1239 break;
1240 }
1241 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
1242 switch (get_format_pixel_size(format)) {
1243 case 4:
1244 _scale_cubic<1, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1245 break;
1246 case 8:
1247 _scale_cubic<2, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1248 break;
1249 case 12:
1250 _scale_cubic<3, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1251 break;
1252 case 16:
1253 _scale_cubic<4, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1254 break;
1255 }
1256 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
1257 switch (get_format_pixel_size(format)) {
1258 case 2:
1259 _scale_cubic<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1260 break;
1261 case 4:
1262 _scale_cubic<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1263 break;
1264 case 6:
1265 _scale_cubic<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1266 break;
1267 case 8:
1268 _scale_cubic<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1269 break;
1270 }
1271 }
1272 } break;
1273 case INTERPOLATE_LANCZOS: {
1274 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
1275 switch (get_format_pixel_size(format)) {
1276 case 1:
1277 _scale_lanczos<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1278 break;
1279 case 2:
1280 _scale_lanczos<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1281 break;
1282 case 3:
1283 _scale_lanczos<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1284 break;
1285 case 4:
1286 _scale_lanczos<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1287 break;
1288 }
1289 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
1290 switch (get_format_pixel_size(format)) {
1291 case 4:
1292 _scale_lanczos<1, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1293 break;
1294 case 8:
1295 _scale_lanczos<2, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1296 break;
1297 case 12:
1298 _scale_lanczos<3, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1299 break;
1300 case 16:
1301 _scale_lanczos<4, float>(r_ptr, w_ptr, width, height, p_width, p_height);
1302 break;
1303 }
1304 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
1305 switch (get_format_pixel_size(format)) {
1306 case 2:
1307 _scale_lanczos<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1308 break;
1309 case 4:
1310 _scale_lanczos<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1311 break;
1312 case 6:
1313 _scale_lanczos<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1314 break;
1315 case 8:
1316 _scale_lanczos<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height);
1317 break;
1318 }
1319 }
1320 } break;
1321 }
1322
1323 if (interpolate_mipmaps) {
1324 dst._copy_internals_from(dst2);
1325 }
1326
1327 if (had_mipmaps) {
1328 dst.generate_mipmaps();
1329 }
1330
1331 _copy_internals_from(dst);
1332}
1333
1334void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) {
1335 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot crop in compressed or custom image formats.");
1336
1337 ERR_FAIL_COND_MSG(p_x < 0, "Start x position cannot be smaller than 0.");
1338 ERR_FAIL_COND_MSG(p_y < 0, "Start y position cannot be smaller than 0.");
1339 ERR_FAIL_COND_MSG(p_width <= 0, "Width of image must be greater than 0.");
1340 ERR_FAIL_COND_MSG(p_height <= 0, "Height of image must be greater than 0.");
1341 ERR_FAIL_COND_MSG(p_x + p_width > MAX_WIDTH, "End x position cannot be greater than " + itos(MAX_WIDTH) + ".");
1342 ERR_FAIL_COND_MSG(p_y + p_height > MAX_HEIGHT, "End y position cannot be greater than " + itos(MAX_HEIGHT) + ".");
1343
1344 /* to save memory, cropping should be done in-place, however, since this function
1345 will most likely either not be used much, or in critical areas, for now it won't, because
1346 it's a waste of time. */
1347
1348 if (p_width == width && p_height == height && p_x == 0 && p_y == 0) {
1349 return;
1350 }
1351
1352 uint8_t pdata[16]; //largest is 16
1353 uint32_t pixel_size = get_format_pixel_size(format);
1354
1355 Image dst(p_width, p_height, false, format);
1356
1357 {
1358 const uint8_t *r = data.ptr();
1359 uint8_t *w = dst.data.ptrw();
1360
1361 int m_h = p_y + p_height;
1362 int m_w = p_x + p_width;
1363 for (int y = p_y; y < m_h; y++) {
1364 for (int x = p_x; x < m_w; x++) {
1365 if ((x >= width || y >= height)) {
1366 for (uint32_t i = 0; i < pixel_size; i++) {
1367 pdata[i] = 0;
1368 }
1369 } else {
1370 _get_pixelb(x, y, pixel_size, r, pdata);
1371 }
1372
1373 dst._put_pixelb(x - p_x, y - p_y, pixel_size, w, pdata);
1374 }
1375 }
1376 }
1377
1378 if (has_mipmaps()) {
1379 dst.generate_mipmaps();
1380 }
1381 _copy_internals_from(dst);
1382}
1383
1384void Image::crop(int p_width, int p_height) {
1385 crop_from_point(0, 0, p_width, p_height);
1386}
1387
1388void Image::rotate_90(ClockDirection p_direction) {
1389 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats.");
1390 ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels.");
1391 ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels.");
1392
1393 bool used_mipmaps = has_mipmaps();
1394 if (used_mipmaps) {
1395 clear_mipmaps();
1396 }
1397
1398 // In-place 90 degrees rotation by following the permutation cycles.
1399 {
1400 // Explanation by example (clockwise):
1401 //
1402 // abc da
1403 // def -> eb
1404 // fc
1405 //
1406 // In memory:
1407 // 012345 012345
1408 // abcdef -> daebfc
1409 //
1410 // Permutation cycles:
1411 // (0 --a--> 1 --b--> 3 --d--> 0)
1412 // (2 --c--> 5 --f--> 4 --e--> 2)
1413 //
1414 // Applying cycles (backwards):
1415 // 0->s s=a (store)
1416 // 3->0 abcdef -> dbcdef
1417 // 1->3 dbcdef -> dbcbef
1418 // s->1 dbcbef -> dacbef
1419 //
1420 // 2->s s=c
1421 // 4->2 dacbef -> daebef
1422 // 5->4 daebef -> daebff
1423 // s->5 daebff -> daebfc
1424
1425 const int w = width;
1426 const int h = height;
1427 const int size = w * h;
1428
1429 uint8_t *data_ptr = data.ptrw();
1430 uint32_t pixel_size = get_format_pixel_size(format);
1431
1432 uint8_t single_pixel_buffer[16];
1433
1434#define PREV_INDEX_IN_CYCLE(index) (p_direction == CLOCKWISE) ? ((h - 1 - (index % h)) * w + (index / h)) : ((index % h) * w + (w - 1 - (index / h)))
1435
1436 if (w == h) { // Square case, 4-length cycles only (plus irrelevant thus skipped 1-length cycle in the middle for odd-sized squares).
1437 for (int y = 0; y < h / 2; y++) {
1438 for (int x = 0; x < (w + 1) / 2; x++) {
1439 int current = y * w + x;
1440 memcpy(single_pixel_buffer, data_ptr + current * pixel_size, pixel_size);
1441 for (int i = 0; i < 3; i++) {
1442 int prev = PREV_INDEX_IN_CYCLE(current);
1443 memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size);
1444 current = prev;
1445 }
1446 memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size);
1447 }
1448 }
1449 } else { // Rectangular case (w != h), kinda unpredictable cycles.
1450 int permuted_pixels_count = 0;
1451
1452 for (int i = 0; i < size; i++) {
1453 int prev = PREV_INDEX_IN_CYCLE(i);
1454 if (prev == i) {
1455 // 1-length cycle, pixel remains at the same index.
1456 permuted_pixels_count++;
1457 continue;
1458 }
1459
1460 // Check whether we already processed this cycle.
1461 // We iterate over it and if we'll find an index smaller than `i` then we already
1462 // processed this cycle because we always start at the smallest index in the cycle.
1463 // TODO: Improve this naive approach, can be done better.
1464 while (prev > i) {
1465 prev = PREV_INDEX_IN_CYCLE(prev);
1466 }
1467 if (prev < i) {
1468 continue;
1469 }
1470
1471 // Save the in-cycle pixel with the smallest index (`i`).
1472 memcpy(single_pixel_buffer, data_ptr + i * pixel_size, pixel_size);
1473
1474 // Overwrite pixels one by one by the preceding pixel in the cycle.
1475 int current = i;
1476 prev = PREV_INDEX_IN_CYCLE(current);
1477 while (prev != i) {
1478 memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size);
1479 permuted_pixels_count++;
1480
1481 current = prev;
1482 prev = PREV_INDEX_IN_CYCLE(current);
1483 };
1484
1485 // Overwrite the remaining pixel in the cycle by the saved pixel with the smallest index.
1486 memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size);
1487 permuted_pixels_count++;
1488
1489 if (permuted_pixels_count == size) {
1490 break;
1491 }
1492 }
1493
1494 width = h;
1495 height = w;
1496 }
1497
1498#undef PREV_INDEX_IN_CYCLE
1499 }
1500
1501 if (used_mipmaps) {
1502 generate_mipmaps();
1503 }
1504}
1505
1506void Image::rotate_180() {
1507 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats.");
1508 ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels.");
1509 ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels.");
1510
1511 bool used_mipmaps = has_mipmaps();
1512 if (used_mipmaps) {
1513 clear_mipmaps();
1514 }
1515
1516 {
1517 uint8_t *data_ptr = data.ptrw();
1518 uint32_t pixel_size = get_format_pixel_size(format);
1519
1520 uint8_t single_pixel_buffer[16];
1521
1522 uint8_t *from_begin_ptr = data_ptr;
1523 uint8_t *from_end_ptr = data_ptr + (width * height - 1) * pixel_size;
1524
1525 while (from_begin_ptr < from_end_ptr) {
1526 memcpy(single_pixel_buffer, from_begin_ptr, pixel_size);
1527 memcpy(from_begin_ptr, from_end_ptr, pixel_size);
1528 memcpy(from_end_ptr, single_pixel_buffer, pixel_size);
1529
1530 from_begin_ptr += pixel_size;
1531 from_end_ptr -= pixel_size;
1532 }
1533 }
1534
1535 if (used_mipmaps) {
1536 generate_mipmaps();
1537 }
1538}
1539
1540void Image::flip_y() {
1541 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats.");
1542
1543 bool used_mipmaps = has_mipmaps();
1544 if (used_mipmaps) {
1545 clear_mipmaps();
1546 }
1547
1548 {
1549 uint8_t *w = data.ptrw();
1550 uint8_t up[16];
1551 uint8_t down[16];
1552 uint32_t pixel_size = get_format_pixel_size(format);
1553
1554 for (int y = 0; y < height / 2; y++) {
1555 for (int x = 0; x < width; x++) {
1556 _get_pixelb(x, y, pixel_size, w, up);
1557 _get_pixelb(x, height - y - 1, pixel_size, w, down);
1558
1559 _put_pixelb(x, height - y - 1, pixel_size, w, up);
1560 _put_pixelb(x, y, pixel_size, w, down);
1561 }
1562 }
1563 }
1564
1565 if (used_mipmaps) {
1566 generate_mipmaps();
1567 }
1568}
1569
1570void Image::flip_x() {
1571 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_x in compressed or custom image formats.");
1572
1573 bool used_mipmaps = has_mipmaps();
1574 if (used_mipmaps) {
1575 clear_mipmaps();
1576 }
1577
1578 {
1579 uint8_t *w = data.ptrw();
1580 uint8_t up[16];
1581 uint8_t down[16];
1582 uint32_t pixel_size = get_format_pixel_size(format);
1583
1584 for (int y = 0; y < height; y++) {
1585 for (int x = 0; x < width / 2; x++) {
1586 _get_pixelb(x, y, pixel_size, w, up);
1587 _get_pixelb(width - x - 1, y, pixel_size, w, down);
1588
1589 _put_pixelb(width - x - 1, y, pixel_size, w, up);
1590 _put_pixelb(x, y, pixel_size, w, down);
1591 }
1592 }
1593 }
1594
1595 if (used_mipmaps) {
1596 generate_mipmaps();
1597 }
1598}
1599
1600/// Get mipmap size and offset.
1601int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) {
1602 // Data offset in mipmaps (including the original texture).
1603 int size = 0;
1604
1605 int w = p_width;
1606 int h = p_height;
1607
1608 // Current mipmap index in the loop below. p_mipmaps is the target mipmap index.
1609 // In this function, mipmap 0 represents the first mipmap instead of the original texture.
1610 int mm = 0;
1611
1612 int pixsize = get_format_pixel_size(p_format);
1613 int pixshift = get_format_pixel_rshift(p_format);
1614 int block = get_format_block_size(p_format);
1615
1616 // Technically, you can still compress up to 1 px no matter the format, so commenting this.
1617 //int minw, minh;
1618 //get_format_min_pixel_size(p_format, minw, minh);
1619 int minw = 1, minh = 1;
1620
1621 while (true) {
1622 int bw = w % block != 0 ? w + (block - w % block) : w;
1623 int bh = h % block != 0 ? h + (block - h % block) : h;
1624
1625 int s = bw * bh;
1626
1627 s *= pixsize;
1628 s >>= pixshift;
1629
1630 size += s;
1631
1632 if (p_mipmaps >= 0) {
1633 w = MAX(minw, w >> 1);
1634 h = MAX(minh, h >> 1);
1635 } else {
1636 if (w == minw && h == minh) {
1637 break;
1638 }
1639 w = MAX(minw, w >> 1);
1640 h = MAX(minh, h >> 1);
1641 }
1642
1643 // Set mipmap size.
1644 if (r_mm_width) {
1645 *r_mm_width = w;
1646 }
1647 if (r_mm_height) {
1648 *r_mm_height = h;
1649 }
1650
1651 // Reach target mipmap.
1652 if (p_mipmaps >= 0 && mm == p_mipmaps) {
1653 break;
1654 }
1655
1656 mm++;
1657 }
1658
1659 r_mipmaps = mm;
1660 return size;
1661}
1662
1663bool Image::_can_modify(Format p_format) const {
1664 return p_format <= FORMAT_RGBE9995;
1665}
1666
1667template <class Component, int CC, bool renormalize,
1668 void (*average_func)(Component &, const Component &, const Component &, const Component &, const Component &),
1669 void (*renormalize_func)(Component *)>
1670static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint32_t p_width, uint32_t p_height) {
1671 //fast power of 2 mipmap generation
1672 uint32_t dst_w = MAX(p_width >> 1, 1u);
1673 uint32_t dst_h = MAX(p_height >> 1, 1u);
1674
1675 int right_step = (p_width == 1) ? 0 : CC;
1676 int down_step = (p_height == 1) ? 0 : (p_width * CC);
1677
1678 for (uint32_t i = 0; i < dst_h; i++) {
1679 const Component *rup_ptr = &p_src[i * 2 * down_step];
1680 const Component *rdown_ptr = rup_ptr + down_step;
1681 Component *dst_ptr = &p_dst[i * dst_w * CC];
1682 uint32_t count = dst_w;
1683
1684 while (count) {
1685 count--;
1686 for (int j = 0; j < CC; j++) {
1687 average_func(dst_ptr[j], rup_ptr[j], rup_ptr[j + right_step], rdown_ptr[j], rdown_ptr[j + right_step]);
1688 }
1689
1690 if (renormalize) {
1691 renormalize_func(dst_ptr);
1692 }
1693
1694 dst_ptr += CC;
1695 rup_ptr += right_step * 2;
1696 rdown_ptr += right_step * 2;
1697 }
1698 }
1699}
1700
1701void Image::shrink_x2() {
1702 ERR_FAIL_COND(data.size() == 0);
1703
1704 if (mipmaps) {
1705 //just use the lower mipmap as base and copy all
1706 Vector<uint8_t> new_img;
1707
1708 int ofs = get_mipmap_offset(1);
1709
1710 int new_size = data.size() - ofs;
1711 new_img.resize(new_size);
1712 ERR_FAIL_COND(new_img.size() == 0);
1713
1714 {
1715 uint8_t *w = new_img.ptrw();
1716 const uint8_t *r = data.ptr();
1717
1718 memcpy(w, &r[ofs], new_size);
1719 }
1720
1721 width = MAX(width / 2, 1);
1722 height = MAX(height / 2, 1);
1723 data = new_img;
1724
1725 } else {
1726 Vector<uint8_t> new_img;
1727
1728 ERR_FAIL_COND(!_can_modify(format));
1729 int ps = get_format_pixel_size(format);
1730 new_img.resize((width / 2) * (height / 2) * ps);
1731 ERR_FAIL_COND(new_img.size() == 0);
1732 ERR_FAIL_COND(data.size() == 0);
1733
1734 {
1735 uint8_t *w = new_img.ptrw();
1736 const uint8_t *r = data.ptr();
1737
1738 switch (format) {
1739 case FORMAT_L8:
1740 case FORMAT_R8:
1741 _generate_po2_mipmap<uint8_t, 1, false, Image::average_4_uint8, Image::renormalize_uint8>(r, w, width, height);
1742 break;
1743 case FORMAT_LA8:
1744 _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(r, w, width, height);
1745 break;
1746 case FORMAT_RG8:
1747 _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(r, w, width, height);
1748 break;
1749 case FORMAT_RGB8:
1750 _generate_po2_mipmap<uint8_t, 3, false, Image::average_4_uint8, Image::renormalize_uint8>(r, w, width, height);
1751 break;
1752 case FORMAT_RGBA8:
1753 _generate_po2_mipmap<uint8_t, 4, false, Image::average_4_uint8, Image::renormalize_uint8>(r, w, width, height);
1754 break;
1755
1756 case FORMAT_RF:
1757 _generate_po2_mipmap<float, 1, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r), reinterpret_cast<float *>(w), width, height);
1758 break;
1759 case FORMAT_RGF:
1760 _generate_po2_mipmap<float, 2, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r), reinterpret_cast<float *>(w), width, height);
1761 break;
1762 case FORMAT_RGBF:
1763 _generate_po2_mipmap<float, 3, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r), reinterpret_cast<float *>(w), width, height);
1764 break;
1765 case FORMAT_RGBAF:
1766 _generate_po2_mipmap<float, 4, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r), reinterpret_cast<float *>(w), width, height);
1767 break;
1768
1769 case FORMAT_RH:
1770 _generate_po2_mipmap<uint16_t, 1, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r), reinterpret_cast<uint16_t *>(w), width, height);
1771 break;
1772 case FORMAT_RGH:
1773 _generate_po2_mipmap<uint16_t, 2, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r), reinterpret_cast<uint16_t *>(w), width, height);
1774 break;
1775 case FORMAT_RGBH:
1776 _generate_po2_mipmap<uint16_t, 3, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r), reinterpret_cast<uint16_t *>(w), width, height);
1777 break;
1778 case FORMAT_RGBAH:
1779 _generate_po2_mipmap<uint16_t, 4, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r), reinterpret_cast<uint16_t *>(w), width, height);
1780 break;
1781
1782 case FORMAT_RGBE9995:
1783 _generate_po2_mipmap<uint32_t, 1, false, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(r), reinterpret_cast<uint32_t *>(w), width, height);
1784 break;
1785 default: {
1786 }
1787 }
1788 }
1789
1790 width /= 2;
1791 height /= 2;
1792 data = new_img;
1793 }
1794}
1795
1796void Image::normalize() {
1797 bool used_mipmaps = has_mipmaps();
1798 if (used_mipmaps) {
1799 clear_mipmaps();
1800 }
1801
1802 for (int y = 0; y < height; y++) {
1803 for (int x = 0; x < width; x++) {
1804 Color c = get_pixel(x, y);
1805 Vector3 v(c.r * 2.0 - 1.0, c.g * 2.0 - 1.0, c.b * 2.0 - 1.0);
1806 v.normalize();
1807 c.r = v.x * 0.5 + 0.5;
1808 c.g = v.y * 0.5 + 0.5;
1809 c.b = v.z * 0.5 + 0.5;
1810 set_pixel(x, y, c);
1811 }
1812 }
1813
1814 if (used_mipmaps) {
1815 generate_mipmaps(true);
1816 }
1817}
1818
1819Error Image::generate_mipmaps(bool p_renormalize) {
1820 ERR_FAIL_COND_V_MSG(!_can_modify(format), ERR_UNAVAILABLE, "Cannot generate mipmaps in compressed or custom image formats.");
1821
1822 ERR_FAIL_COND_V_MSG(format == FORMAT_RGBA4444, ERR_UNAVAILABLE, "Cannot generate mipmaps from RGBA4444 format.");
1823
1824 ERR_FAIL_COND_V_MSG(width == 0 || height == 0, ERR_UNCONFIGURED, "Cannot generate mipmaps with width or height equal to 0.");
1825
1826 int mmcount;
1827
1828 int size = _get_dst_image_size(width, height, format, mmcount);
1829
1830 data.resize(size);
1831
1832 uint8_t *wp = data.ptrw();
1833
1834 int prev_ofs = 0;
1835 int prev_h = height;
1836 int prev_w = width;
1837
1838 for (int i = 1; i <= mmcount; i++) {
1839 int ofs, w, h;
1840 _get_mipmap_offset_and_size(i, ofs, w, h);
1841
1842 switch (format) {
1843 case FORMAT_L8:
1844 case FORMAT_R8:
1845 _generate_po2_mipmap<uint8_t, 1, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1846 break;
1847 case FORMAT_LA8:
1848 case FORMAT_RG8:
1849 _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1850 break;
1851 case FORMAT_RGB8:
1852 if (p_renormalize) {
1853 _generate_po2_mipmap<uint8_t, 3, true, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1854 } else {
1855 _generate_po2_mipmap<uint8_t, 3, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1856 }
1857
1858 break;
1859 case FORMAT_RGBA8:
1860 if (p_renormalize) {
1861 _generate_po2_mipmap<uint8_t, 4, true, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1862 } else {
1863 _generate_po2_mipmap<uint8_t, 4, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1864 }
1865 break;
1866 case FORMAT_RF:
1867 _generate_po2_mipmap<float, 1, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
1868 break;
1869 case FORMAT_RGF:
1870 _generate_po2_mipmap<float, 2, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
1871 break;
1872 case FORMAT_RGBF:
1873 if (p_renormalize) {
1874 _generate_po2_mipmap<float, 3, true, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
1875 } else {
1876 _generate_po2_mipmap<float, 3, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
1877 }
1878
1879 break;
1880 case FORMAT_RGBAF:
1881 if (p_renormalize) {
1882 _generate_po2_mipmap<float, 4, true, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
1883 } else {
1884 _generate_po2_mipmap<float, 4, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(&wp[prev_ofs]), reinterpret_cast<float *>(&wp[ofs]), prev_w, prev_h);
1885 }
1886
1887 break;
1888 case FORMAT_RH:
1889 _generate_po2_mipmap<uint16_t, 1, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
1890 break;
1891 case FORMAT_RGH:
1892 _generate_po2_mipmap<uint16_t, 2, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
1893 break;
1894 case FORMAT_RGBH:
1895 if (p_renormalize) {
1896 _generate_po2_mipmap<uint16_t, 3, true, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
1897 } else {
1898 _generate_po2_mipmap<uint16_t, 3, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
1899 }
1900
1901 break;
1902 case FORMAT_RGBAH:
1903 if (p_renormalize) {
1904 _generate_po2_mipmap<uint16_t, 4, true, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
1905 } else {
1906 _generate_po2_mipmap<uint16_t, 4, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(&wp[prev_ofs]), reinterpret_cast<uint16_t *>(&wp[ofs]), prev_w, prev_h);
1907 }
1908
1909 break;
1910 case FORMAT_RGBE9995:
1911 if (p_renormalize) {
1912 _generate_po2_mipmap<uint32_t, 1, true, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(&wp[prev_ofs]), reinterpret_cast<uint32_t *>(&wp[ofs]), prev_w, prev_h);
1913 } else {
1914 _generate_po2_mipmap<uint32_t, 1, false, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(&wp[prev_ofs]), reinterpret_cast<uint32_t *>(&wp[ofs]), prev_w, prev_h);
1915 }
1916
1917 break;
1918 default: {
1919 }
1920 }
1921
1922 prev_ofs = ofs;
1923 prev_w = w;
1924 prev_h = h;
1925 }
1926
1927 mipmaps = true;
1928
1929 return OK;
1930}
1931
1932Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, const Ref<Image> &p_normal_map) {
1933 Vector<double> normal_sat_vec; //summed area table
1934 double *normal_sat = nullptr; //summed area table for normal map
1935 int normal_w = 0, normal_h = 0;
1936
1937 ERR_FAIL_COND_V_MSG(p_normal_map.is_null() || p_normal_map->is_empty(), ERR_INVALID_PARAMETER, "Must provide a valid normal map for roughness mipmaps");
1938
1939 Ref<Image> nm = p_normal_map->duplicate();
1940 if (nm->is_compressed()) {
1941 nm->decompress();
1942 }
1943
1944 normal_w = nm->get_width();
1945 normal_h = nm->get_height();
1946
1947 normal_sat_vec.resize(normal_w * normal_h * 3);
1948
1949 normal_sat = normal_sat_vec.ptrw();
1950
1951 //create summed area table
1952
1953 for (int y = 0; y < normal_h; y++) {
1954 double line_sum[3] = { 0, 0, 0 };
1955 for (int x = 0; x < normal_w; x++) {
1956 double normal[3];
1957 Color color = nm->get_pixel(x, y);
1958 normal[0] = color.r * 2.0 - 1.0;
1959 normal[1] = color.g * 2.0 - 1.0;
1960 normal[2] = Math::sqrt(MAX(0.0, 1.0 - (normal[0] * normal[0] + normal[1] * normal[1]))); //reconstruct if missing
1961
1962 line_sum[0] += normal[0];
1963 line_sum[1] += normal[1];
1964 line_sum[2] += normal[2];
1965
1966 uint32_t ofs = (y * normal_w + x) * 3;
1967
1968 normal_sat[ofs + 0] = line_sum[0];
1969 normal_sat[ofs + 1] = line_sum[1];
1970 normal_sat[ofs + 2] = line_sum[2];
1971
1972 if (y > 0) {
1973 uint32_t prev_ofs = ((y - 1) * normal_w + x) * 3;
1974 normal_sat[ofs + 0] += normal_sat[prev_ofs + 0];
1975 normal_sat[ofs + 1] += normal_sat[prev_ofs + 1];
1976 normal_sat[ofs + 2] += normal_sat[prev_ofs + 2];
1977 }
1978 }
1979 }
1980
1981#if 0
1982 {
1983 Vector3 beg(normal_sat_vec[0], normal_sat_vec[1], normal_sat_vec[2]);
1984 Vector3 end(normal_sat_vec[normal_sat_vec.size() - 3], normal_sat_vec[normal_sat_vec.size() - 2], normal_sat_vec[normal_sat_vec.size() - 1]);
1985 Vector3 avg = (end - beg) / (normal_w * normal_h);
1986 print_line("average: " + avg);
1987 }
1988#endif
1989
1990 int mmcount;
1991
1992 _get_dst_image_size(width, height, format, mmcount);
1993
1994 uint8_t *base_ptr = data.ptrw();
1995
1996 for (int i = 1; i <= mmcount; i++) {
1997 int ofs, w, h;
1998 _get_mipmap_offset_and_size(i, ofs, w, h);
1999 uint8_t *ptr = &base_ptr[ofs];
2000
2001 for (int x = 0; x < w; x++) {
2002 for (int y = 0; y < h; y++) {
2003 int from_x = x * normal_w / w;
2004 int from_y = y * normal_h / h;
2005 int to_x = (x + 1) * normal_w / w;
2006 int to_y = (y + 1) * normal_h / h;
2007 to_x = MIN(to_x - 1, normal_w);
2008 to_y = MIN(to_y - 1, normal_h);
2009
2010 int size_x = (to_x - from_x) + 1;
2011 int size_y = (to_y - from_y) + 1;
2012
2013 //summed area table version (much faster)
2014
2015 double avg[3] = { 0, 0, 0 };
2016
2017 if (from_x > 0 && from_y > 0) {
2018 uint32_t tofs = ((from_y - 1) * normal_w + (from_x - 1)) * 3;
2019 avg[0] += normal_sat[tofs + 0];
2020 avg[1] += normal_sat[tofs + 1];
2021 avg[2] += normal_sat[tofs + 2];
2022 }
2023
2024 if (from_y > 0) {
2025 uint32_t tofs = ((from_y - 1) * normal_w + to_x) * 3;
2026 avg[0] -= normal_sat[tofs + 0];
2027 avg[1] -= normal_sat[tofs + 1];
2028 avg[2] -= normal_sat[tofs + 2];
2029 }
2030
2031 if (from_x > 0) {
2032 uint32_t tofs = (to_y * normal_w + (from_x - 1)) * 3;
2033 avg[0] -= normal_sat[tofs + 0];
2034 avg[1] -= normal_sat[tofs + 1];
2035 avg[2] -= normal_sat[tofs + 2];
2036 }
2037
2038 uint32_t tofs = (to_y * normal_w + to_x) * 3;
2039 avg[0] += normal_sat[tofs + 0];
2040 avg[1] += normal_sat[tofs + 1];
2041 avg[2] += normal_sat[tofs + 2];
2042
2043 double div = double(size_x * size_y);
2044 Vector3 vec(avg[0] / div, avg[1] / div, avg[2] / div);
2045
2046 float r = vec.length();
2047
2048 int pixel_ofs = y * w + x;
2049 Color c = _get_color_at_ofs(ptr, pixel_ofs);
2050
2051 float roughness = 0;
2052
2053 switch (p_roughness_channel) {
2054 case ROUGHNESS_CHANNEL_R: {
2055 roughness = c.r;
2056 } break;
2057 case ROUGHNESS_CHANNEL_G: {
2058 roughness = c.g;
2059 } break;
2060 case ROUGHNESS_CHANNEL_B: {
2061 roughness = c.b;
2062 } break;
2063 case ROUGHNESS_CHANNEL_L: {
2064 roughness = c.get_v();
2065 } break;
2066 case ROUGHNESS_CHANNEL_A: {
2067 roughness = c.a;
2068 } break;
2069 }
2070
2071 float variance = 0;
2072 if (r < 1.0f) {
2073 float r2 = r * r;
2074 float kappa = (3.0f * r - r * r2) / (1.0f - r2);
2075 variance = 0.25f / kappa;
2076 }
2077
2078 float threshold = 0.4;
2079 roughness = Math::sqrt(roughness * roughness + MIN(3.0f * variance, threshold * threshold));
2080
2081 switch (p_roughness_channel) {
2082 case ROUGHNESS_CHANNEL_R: {
2083 c.r = roughness;
2084 } break;
2085 case ROUGHNESS_CHANNEL_G: {
2086 c.g = roughness;
2087 } break;
2088 case ROUGHNESS_CHANNEL_B: {
2089 c.b = roughness;
2090 } break;
2091 case ROUGHNESS_CHANNEL_L: {
2092 c.r = roughness;
2093 c.g = roughness;
2094 c.b = roughness;
2095 } break;
2096 case ROUGHNESS_CHANNEL_A: {
2097 c.a = roughness;
2098 } break;
2099 }
2100
2101 _set_color_at_ofs(ptr, pixel_ofs, c);
2102 }
2103 }
2104#if 0
2105 {
2106 int size = get_mipmap_byte_size(i);
2107 print_line("size for mimpap " + itos(i) + ": " + itos(size));
2108 Vector<uint8_t> imgdata;
2109 imgdata.resize(size);
2110
2111
2112 uint8_t* wr = imgdata.ptrw();
2113 memcpy(wr.ptr(), ptr, size);
2114 wr = uint8_t*();
2115 Ref<Image> im = Image::create_from_data(w, h, false, format, imgdata);
2116 im->save_png("res://mipmap_" + itos(i) + ".png");
2117 }
2118#endif
2119 }
2120
2121 return OK;
2122}
2123
2124void Image::clear_mipmaps() {
2125 if (!mipmaps) {
2126 return;
2127 }
2128
2129 if (is_empty()) {
2130 return;
2131 }
2132
2133 int ofs, w, h;
2134 _get_mipmap_offset_and_size(1, ofs, w, h);
2135 data.resize(ofs);
2136
2137 mipmaps = false;
2138}
2139
2140bool Image::is_empty() const {
2141 return (data.size() == 0);
2142}
2143
2144Vector<uint8_t> Image::get_data() const {
2145 return data;
2146}
2147
2148Ref<Image> Image::create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
2149 Ref<Image> image;
2150 image.instantiate();
2151 image->initialize_data(p_width, p_height, p_use_mipmaps, p_format);
2152 return image;
2153}
2154
2155Ref<Image> Image::create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
2156 Ref<Image> image;
2157 image.instantiate();
2158 image->initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
2159 return image;
2160}
2161
2162void Image::set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
2163 initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
2164}
2165
2166void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
2167 ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
2168 ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
2169 ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
2170 "The Image width specified (" + itos(p_width) + " pixels) cannot be greater than " + itos(MAX_WIDTH) + "pixels.");
2171 ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT,
2172 "The Image height specified (" + itos(p_height) + " pixels) cannot be greater than " + itos(MAX_HEIGHT) + "pixels.");
2173 ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS,
2174 "Too many pixels for Image. Maximum is " + itos(MAX_WIDTH) + "x" + itos(MAX_HEIGHT) + " = " + itos(MAX_PIXELS) + "pixels.");
2175 ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum.");
2176
2177 int mm = 0;
2178 int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
2179 data.resize(size);
2180
2181 {
2182 uint8_t *w = data.ptrw();
2183 memset(w, 0, size);
2184 }
2185
2186 width = p_width;
2187 height = p_height;
2188 mipmaps = p_use_mipmaps;
2189 format = p_format;
2190}
2191
2192void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
2193 ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
2194 ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
2195 ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
2196 "The Image width specified (" + itos(p_width) + " pixels) cannot be greater than " + itos(MAX_WIDTH) + " pixels.");
2197 ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT,
2198 "The Image height specified (" + itos(p_height) + " pixels) cannot be greater than " + itos(MAX_HEIGHT) + " pixels.");
2199 ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS,
2200 "Too many pixels for Image. Maximum is " + itos(MAX_WIDTH) + "x" + itos(MAX_HEIGHT) + " = " + itos(MAX_PIXELS) + "pixels .");
2201 ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum.");
2202
2203 int mm;
2204 int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
2205
2206 if (unlikely(p_data.size() != size)) {
2207 String description_mipmaps = get_format_name(p_format) + " ";
2208 if (p_use_mipmaps) {
2209 const int num_mipmaps = get_image_required_mipmaps(p_width, p_height, p_format);
2210 if (num_mipmaps != 1) {
2211 description_mipmaps += vformat("with %d mipmaps", num_mipmaps);
2212 } else {
2213 description_mipmaps += "with 1 mipmap";
2214 }
2215 } else {
2216 description_mipmaps += "without mipmaps";
2217 }
2218 const String description = vformat("%dx%dx%d (%s)", p_width, p_height, get_format_pixel_size(p_format), description_mipmaps);
2219 ERR_FAIL_MSG(vformat("Expected Image data size of %s = %d bytes, got %d bytes instead.", description, size, p_data.size()));
2220 }
2221
2222 height = p_height;
2223 width = p_width;
2224 format = p_format;
2225 data = p_data;
2226
2227 mipmaps = p_use_mipmaps;
2228}
2229
2230void Image::initialize_data(const char **p_xpm) {
2231 int size_width = 0;
2232 int size_height = 0;
2233 int pixelchars = 0;
2234 mipmaps = false;
2235 bool has_alpha = false;
2236
2237 enum Status {
2238 READING_HEADER,
2239 READING_COLORS,
2240 READING_PIXELS,
2241 DONE
2242 };
2243
2244 Status status = READING_HEADER;
2245 int line = 0;
2246
2247 HashMap<String, Color> colormap;
2248 int colormap_size = 0;
2249 uint32_t pixel_size = 0;
2250 uint8_t *data_write = nullptr;
2251
2252 while (status != DONE) {
2253 const char *line_ptr = p_xpm[line];
2254
2255 switch (status) {
2256 case READING_HEADER: {
2257 String line_str = line_ptr;
2258 line_str.replace("\t", " ");
2259
2260 size_width = line_str.get_slicec(' ', 0).to_int();
2261 size_height = line_str.get_slicec(' ', 1).to_int();
2262 colormap_size = line_str.get_slicec(' ', 2).to_int();
2263 pixelchars = line_str.get_slicec(' ', 3).to_int();
2264 ERR_FAIL_COND(colormap_size > 32766);
2265 ERR_FAIL_COND(pixelchars > 5);
2266 ERR_FAIL_COND(size_width > 32767);
2267 ERR_FAIL_COND(size_height > 32767);
2268 status = READING_COLORS;
2269 } break;
2270 case READING_COLORS: {
2271 String colorstring;
2272 for (int i = 0; i < pixelchars; i++) {
2273 colorstring += *line_ptr;
2274 line_ptr++;
2275 }
2276 //skip spaces
2277 while (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == 0) {
2278 if (*line_ptr == 0) {
2279 break;
2280 }
2281 line_ptr++;
2282 }
2283 if (*line_ptr == 'c') {
2284 line_ptr++;
2285 while (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == 0) {
2286 if (*line_ptr == 0) {
2287 break;
2288 }
2289 line_ptr++;
2290 }
2291
2292 if (*line_ptr == '#') {
2293 line_ptr++;
2294 uint8_t col_r = 0;
2295 uint8_t col_g = 0;
2296 uint8_t col_b = 0;
2297 //uint8_t col_a=255;
2298
2299 for (int i = 0; i < 6; i++) {
2300 char v = line_ptr[i];
2301
2302 if (is_digit(v)) {
2303 v -= '0';
2304 } else if (v >= 'A' && v <= 'F') {
2305 v = (v - 'A') + 10;
2306 } else if (v >= 'a' && v <= 'f') {
2307 v = (v - 'a') + 10;
2308 } else {
2309 break;
2310 }
2311
2312 switch (i) {
2313 case 0:
2314 col_r = v << 4;
2315 break;
2316 case 1:
2317 col_r |= v;
2318 break;
2319 case 2:
2320 col_g = v << 4;
2321 break;
2322 case 3:
2323 col_g |= v;
2324 break;
2325 case 4:
2326 col_b = v << 4;
2327 break;
2328 case 5:
2329 col_b |= v;
2330 break;
2331 }
2332 }
2333
2334 // magenta mask
2335 if (col_r == 255 && col_g == 0 && col_b == 255) {
2336 colormap[colorstring] = Color(0, 0, 0, 0);
2337 has_alpha = true;
2338 } else {
2339 colormap[colorstring] = Color(col_r / 255.0, col_g / 255.0, col_b / 255.0, 1.0);
2340 }
2341 }
2342 }
2343 if (line == colormap_size) {
2344 status = READING_PIXELS;
2345 initialize_data(size_width, size_height, false, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
2346 data_write = data.ptrw();
2347 pixel_size = has_alpha ? 4 : 3;
2348 }
2349 } break;
2350 case READING_PIXELS: {
2351 int y = line - colormap_size - 1;
2352 for (int x = 0; x < size_width; x++) {
2353 char pixelstr[6] = { 0, 0, 0, 0, 0, 0 };
2354 for (int i = 0; i < pixelchars; i++) {
2355 pixelstr[i] = line_ptr[x * pixelchars + i];
2356 }
2357
2358 Color *colorptr = colormap.getptr(pixelstr);
2359 ERR_FAIL_NULL(colorptr);
2360 uint8_t pixel[4];
2361 for (uint32_t i = 0; i < pixel_size; i++) {
2362 pixel[i] = CLAMP((*colorptr)[i] * 255, 0, 255);
2363 }
2364 _put_pixelb(x, y, pixel_size, data_write, pixel);
2365 }
2366
2367 if (y == (size_height - 1)) {
2368 status = DONE;
2369 }
2370 } break;
2371 default: {
2372 }
2373 }
2374
2375 line++;
2376 }
2377}
2378#define DETECT_ALPHA_MAX_THRESHOLD 254
2379#define DETECT_ALPHA_MIN_THRESHOLD 2
2380
2381#define DETECT_ALPHA(m_value) \
2382 { \
2383 uint8_t value = m_value; \
2384 if (value < DETECT_ALPHA_MIN_THRESHOLD) \
2385 bit = true; \
2386 else if (value < DETECT_ALPHA_MAX_THRESHOLD) { \
2387 detected = true; \
2388 break; \
2389 } \
2390 }
2391
2392#define DETECT_NON_ALPHA(m_value) \
2393 { \
2394 uint8_t value = m_value; \
2395 if (value > 0) { \
2396 detected = true; \
2397 break; \
2398 } \
2399 }
2400
2401bool Image::is_invisible() const {
2402 if (format == FORMAT_L8 ||
2403 format == FORMAT_RGB8 || format == FORMAT_RG8) {
2404 return false;
2405 }
2406
2407 int len = data.size();
2408
2409 if (len == 0) {
2410 return true;
2411 }
2412
2413 int w, h;
2414 _get_mipmap_offset_and_size(1, len, w, h);
2415
2416 const uint8_t *r = data.ptr();
2417 const unsigned char *data_ptr = r;
2418
2419 bool detected = false;
2420
2421 switch (format) {
2422 case FORMAT_LA8: {
2423 for (int i = 0; i < (len >> 1); i++) {
2424 DETECT_NON_ALPHA(data_ptr[(i << 1) + 1]);
2425 }
2426
2427 } break;
2428 case FORMAT_RGBA8: {
2429 for (int i = 0; i < (len >> 2); i++) {
2430 DETECT_NON_ALPHA(data_ptr[(i << 2) + 3])
2431 }
2432
2433 } break;
2434
2435 case FORMAT_DXT3:
2436 case FORMAT_DXT5: {
2437 detected = true;
2438 } break;
2439 default: {
2440 }
2441 }
2442
2443 return !detected;
2444}
2445
2446Image::AlphaMode Image::detect_alpha() const {
2447 int len = data.size();
2448
2449 if (len == 0) {
2450 return ALPHA_NONE;
2451 }
2452
2453 int w, h;
2454 _get_mipmap_offset_and_size(1, len, w, h);
2455
2456 const uint8_t *r = data.ptr();
2457 const unsigned char *data_ptr = r;
2458
2459 bool bit = false;
2460 bool detected = false;
2461
2462 switch (format) {
2463 case FORMAT_LA8: {
2464 for (int i = 0; i < (len >> 1); i++) {
2465 DETECT_ALPHA(data_ptr[(i << 1) + 1]);
2466 }
2467
2468 } break;
2469 case FORMAT_RGBA8: {
2470 for (int i = 0; i < (len >> 2); i++) {
2471 DETECT_ALPHA(data_ptr[(i << 2) + 3])
2472 }
2473
2474 } break;
2475 case FORMAT_DXT3:
2476 case FORMAT_DXT5: {
2477 detected = true;
2478 } break;
2479 default: {
2480 }
2481 }
2482
2483 if (detected) {
2484 return ALPHA_BLEND;
2485 } else if (bit) {
2486 return ALPHA_BIT;
2487 } else {
2488 return ALPHA_NONE;
2489 }
2490}
2491
2492Error Image::load(const String &p_path) {
2493#ifdef DEBUG_ENABLED
2494 if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) {
2495 WARN_PRINT("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource.");
2496 }
2497#endif
2498 return ImageLoader::load_image(p_path, this);
2499}
2500
2501Ref<Image> Image::load_from_file(const String &p_path) {
2502#ifdef DEBUG_ENABLED
2503 if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) {
2504 WARN_PRINT("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource.");
2505 }
2506#endif
2507 Ref<Image> image;
2508 image.instantiate();
2509 Error err = ImageLoader::load_image(p_path, image);
2510 if (err != OK) {
2511 ERR_FAIL_V_MSG(Ref<Image>(), vformat("Failed to load image. Error %d", err));
2512 }
2513 return image;
2514}
2515
2516Error Image::save_png(const String &p_path) const {
2517 if (save_png_func == nullptr) {
2518 return ERR_UNAVAILABLE;
2519 }
2520
2521 return save_png_func(p_path, Ref<Image>((Image *)this));
2522}
2523
2524Error Image::save_jpg(const String &p_path, float p_quality) const {
2525 if (save_jpg_func == nullptr) {
2526 return ERR_UNAVAILABLE;
2527 }
2528
2529 return save_jpg_func(p_path, Ref<Image>((Image *)this), p_quality);
2530}
2531
2532Vector<uint8_t> Image::save_png_to_buffer() const {
2533 if (save_png_buffer_func == nullptr) {
2534 return Vector<uint8_t>();
2535 }
2536
2537 return save_png_buffer_func(Ref<Image>((Image *)this));
2538}
2539
2540Vector<uint8_t> Image::save_jpg_to_buffer(float p_quality) const {
2541 if (save_jpg_buffer_func == nullptr) {
2542 return Vector<uint8_t>();
2543 }
2544
2545 return save_jpg_buffer_func(Ref<Image>((Image *)this), p_quality);
2546}
2547
2548Error Image::save_exr(const String &p_path, bool p_grayscale) const {
2549 if (save_exr_func == nullptr) {
2550 return ERR_UNAVAILABLE;
2551 }
2552
2553 return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale);
2554}
2555
2556Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale) const {
2557 if (save_exr_buffer_func == nullptr) {
2558 return Vector<uint8_t>();
2559 }
2560 return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale);
2561}
2562
2563Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const {
2564 if (save_webp_func == nullptr) {
2565 return ERR_UNAVAILABLE;
2566 }
2567 ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), ERR_INVALID_PARAMETER, "The WebP lossy quality was set to " + rtos(p_quality) + ", which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive).");
2568
2569 return save_webp_func(p_path, Ref<Image>((Image *)this), p_lossy, p_quality);
2570}
2571
2572Vector<uint8_t> Image::save_webp_to_buffer(const bool p_lossy, const float p_quality) const {
2573 if (save_webp_buffer_func == nullptr) {
2574 return Vector<uint8_t>();
2575 }
2576 ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), Vector<uint8_t>(), "The WebP lossy quality was set to " + rtos(p_quality) + ", which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive).");
2577
2578 return save_webp_buffer_func(Ref<Image>((Image *)this), p_lossy, p_quality);
2579}
2580
2581int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) {
2582 int mm;
2583 return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps ? -1 : 0);
2584}
2585
2586int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format) {
2587 int mm;
2588 _get_dst_image_size(p_width, p_height, p_format, mm, -1);
2589 return mm;
2590}
2591
2592Size2i Image::get_image_mipmap_size(int p_width, int p_height, Format p_format, int p_mipmap) {
2593 int mm;
2594 Size2i ret;
2595 _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmap, &ret.x, &ret.y);
2596 return ret;
2597}
2598
2599int Image::get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap) {
2600 if (p_mipmap <= 0) {
2601 return 0;
2602 }
2603 int mm;
2604 return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmap - 1);
2605}
2606
2607int Image::get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h) {
2608 if (p_mipmap <= 0) {
2609 r_w = p_width;
2610 r_h = p_height;
2611 return 0;
2612 }
2613 int mm;
2614 return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmap - 1, &r_w, &r_h);
2615}
2616
2617bool Image::is_compressed() const {
2618 return format > FORMAT_RGBE9995;
2619}
2620
2621Error Image::decompress() {
2622 if (((format >= FORMAT_DXT1 && format <= FORMAT_RGTC_RG) || (format == FORMAT_DXT5_RA_AS_RG)) && _image_decompress_bc) {
2623 _image_decompress_bc(this);
2624 } else if (format >= FORMAT_BPTC_RGBA && format <= FORMAT_BPTC_RGBFU && _image_decompress_bptc) {
2625 _image_decompress_bptc(this);
2626 } else if (format == FORMAT_ETC && _image_decompress_etc1) {
2627 _image_decompress_etc1(this);
2628 } else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RA_AS_RG && _image_decompress_etc2) {
2629 _image_decompress_etc2(this);
2630 } else if (format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR && _image_decompress_astc) {
2631 _image_decompress_astc(this);
2632 } else {
2633 return ERR_UNAVAILABLE;
2634 }
2635 return OK;
2636}
2637
2638Error Image::compress(CompressMode p_mode, CompressSource p_source, ASTCFormat p_astc_format) {
2639 ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode.");
2640 ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source.");
2641 return compress_from_channels(p_mode, detect_used_channels(p_source), p_astc_format);
2642}
2643
2644Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format) {
2645 ERR_FAIL_COND_V(data.is_empty(), ERR_INVALID_DATA);
2646
2647 switch (p_mode) {
2648 case COMPRESS_S3TC: {
2649 ERR_FAIL_NULL_V(_image_compress_bc_func, ERR_UNAVAILABLE);
2650 _image_compress_bc_func(this, p_channels);
2651 } break;
2652 case COMPRESS_ETC: {
2653 ERR_FAIL_NULL_V(_image_compress_etc1_func, ERR_UNAVAILABLE);
2654 _image_compress_etc1_func(this);
2655 } break;
2656 case COMPRESS_ETC2: {
2657 ERR_FAIL_NULL_V(_image_compress_etc2_func, ERR_UNAVAILABLE);
2658 _image_compress_etc2_func(this, p_channels);
2659 } break;
2660 case COMPRESS_BPTC: {
2661 ERR_FAIL_NULL_V(_image_compress_bptc_func, ERR_UNAVAILABLE);
2662 _image_compress_bptc_func(this, p_channels);
2663 } break;
2664 case COMPRESS_ASTC: {
2665 ERR_FAIL_NULL_V(_image_compress_astc_func, ERR_UNAVAILABLE);
2666 _image_compress_astc_func(this, p_astc_format);
2667 } break;
2668 case COMPRESS_MAX: {
2669 ERR_FAIL_V(ERR_INVALID_PARAMETER);
2670 } break;
2671 }
2672
2673 return OK;
2674}
2675
2676Image::Image(const char **p_xpm) {
2677 width = 0;
2678 height = 0;
2679 mipmaps = false;
2680 format = FORMAT_L8;
2681
2682 initialize_data(p_xpm);
2683}
2684
2685Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
2686 width = 0;
2687 height = 0;
2688 mipmaps = p_use_mipmaps;
2689 format = FORMAT_L8;
2690
2691 initialize_data(p_width, p_height, p_use_mipmaps, p_format);
2692}
2693
2694Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
2695 width = 0;
2696 height = 0;
2697 mipmaps = p_mipmaps;
2698 format = FORMAT_L8;
2699
2700 initialize_data(p_width, p_height, p_mipmaps, p_format, p_data);
2701}
2702
2703Rect2i Image::get_used_rect() const {
2704 if (format != FORMAT_LA8 && format != FORMAT_RGBA8 && format != FORMAT_RGBAF && format != FORMAT_RGBAH && format != FORMAT_RGBA4444 && format != FORMAT_RGB565) {
2705 return Rect2i(0, 0, width, height);
2706 }
2707
2708 int len = data.size();
2709
2710 if (len == 0) {
2711 return Rect2i();
2712 }
2713
2714 int minx = 0xFFFFFF, miny = 0xFFFFFFF;
2715 int maxx = -1, maxy = -1;
2716 for (int j = 0; j < height; j++) {
2717 for (int i = 0; i < width; i++) {
2718 if (!(get_pixel(i, j).a > 0)) {
2719 continue;
2720 }
2721 if (i > maxx) {
2722 maxx = i;
2723 }
2724 if (j > maxy) {
2725 maxy = j;
2726 }
2727 if (i < minx) {
2728 minx = i;
2729 }
2730 if (j < miny) {
2731 miny = j;
2732 }
2733 }
2734 }
2735
2736 if (maxx == -1) {
2737 return Rect2i();
2738 } else {
2739 return Rect2i(minx, miny, maxx - minx + 1, maxy - miny + 1);
2740 }
2741}
2742
2743Ref<Image> Image::get_region(const Rect2i &p_region) const {
2744 Ref<Image> img = memnew(Image(p_region.size.x, p_region.size.y, mipmaps, format));
2745 img->blit_rect(Ref<Image>((Image *)this), p_region, Point2i(0, 0));
2746 return img;
2747}
2748
2749void Image::_get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest, Rect2i &r_clipped_src_rect, Rect2i &r_clipped_dest_rect) const {
2750 r_clipped_dest_rect.position = p_dest;
2751 r_clipped_src_rect = p_src_rect;
2752
2753 if (r_clipped_src_rect.position.x < 0) {
2754 r_clipped_dest_rect.position.x -= r_clipped_src_rect.position.x;
2755 r_clipped_src_rect.size.x += r_clipped_src_rect.position.x;
2756 r_clipped_src_rect.position.x = 0;
2757 }
2758 if (r_clipped_src_rect.position.y < 0) {
2759 r_clipped_dest_rect.position.y -= r_clipped_src_rect.position.y;
2760 r_clipped_src_rect.size.y += r_clipped_src_rect.position.y;
2761 r_clipped_src_rect.position.y = 0;
2762 }
2763
2764 if (r_clipped_dest_rect.position.x < 0) {
2765 r_clipped_src_rect.position.x -= r_clipped_dest_rect.position.x;
2766 r_clipped_src_rect.size.x += r_clipped_dest_rect.position.x;
2767 r_clipped_dest_rect.position.x = 0;
2768 }
2769 if (r_clipped_dest_rect.position.y < 0) {
2770 r_clipped_src_rect.position.y -= r_clipped_dest_rect.position.y;
2771 r_clipped_src_rect.size.y += r_clipped_dest_rect.position.y;
2772 r_clipped_dest_rect.position.y = 0;
2773 }
2774
2775 r_clipped_src_rect.size.x = MAX(0, MIN(r_clipped_src_rect.size.x, MIN(p_src->width - r_clipped_src_rect.position.x, width - r_clipped_dest_rect.position.x)));
2776 r_clipped_src_rect.size.y = MAX(0, MIN(r_clipped_src_rect.size.y, MIN(p_src->height - r_clipped_src_rect.position.y, height - r_clipped_dest_rect.position.y)));
2777
2778 r_clipped_dest_rect.size.x = r_clipped_src_rect.size.x;
2779 r_clipped_dest_rect.size.y = r_clipped_src_rect.size.y;
2780}
2781
2782void Image::blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest) {
2783 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2784 int dsize = data.size();
2785 int srcdsize = p_src->data.size();
2786 ERR_FAIL_COND(dsize == 0);
2787 ERR_FAIL_COND(srcdsize == 0);
2788 ERR_FAIL_COND(format != p_src->format);
2789 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot blit_rect in compressed or custom image formats.");
2790
2791 Rect2i src_rect;
2792 Rect2i dest_rect;
2793 _get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
2794 if (!src_rect.has_area() || !dest_rect.has_area()) {
2795 return;
2796 }
2797
2798 uint8_t *wp = data.ptrw();
2799 uint8_t *dst_data_ptr = wp;
2800
2801 const uint8_t *rp = p_src->data.ptr();
2802 const uint8_t *src_data_ptr = rp;
2803
2804 int pixel_size = get_format_pixel_size(format);
2805
2806 for (int i = 0; i < dest_rect.size.y; i++) {
2807 for (int j = 0; j < dest_rect.size.x; j++) {
2808 int src_x = src_rect.position.x + j;
2809 int src_y = src_rect.position.y + i;
2810
2811 int dst_x = dest_rect.position.x + j;
2812 int dst_y = dest_rect.position.y + i;
2813
2814 const uint8_t *src = &src_data_ptr[(src_y * p_src->width + src_x) * pixel_size];
2815 uint8_t *dst = &dst_data_ptr[(dst_y * width + dst_x) * pixel_size];
2816
2817 for (int k = 0; k < pixel_size; k++) {
2818 dst[k] = src[k];
2819 }
2820 }
2821 }
2822}
2823
2824void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest) {
2825 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2826 ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object.");
2827 int dsize = data.size();
2828 int srcdsize = p_src->data.size();
2829 int maskdsize = p_mask->data.size();
2830 ERR_FAIL_COND(dsize == 0);
2831 ERR_FAIL_COND(srcdsize == 0);
2832 ERR_FAIL_COND(maskdsize == 0);
2833 ERR_FAIL_COND_MSG(p_src->width != p_mask->width, "Source image width is different from mask width.");
2834 ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
2835 ERR_FAIL_COND(format != p_src->format);
2836
2837 Rect2i src_rect;
2838 Rect2i dest_rect;
2839 _get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
2840 if (!src_rect.has_area() || !dest_rect.has_area()) {
2841 return;
2842 }
2843
2844 uint8_t *wp = data.ptrw();
2845 uint8_t *dst_data_ptr = wp;
2846
2847 const uint8_t *rp = p_src->data.ptr();
2848 const uint8_t *src_data_ptr = rp;
2849
2850 int pixel_size = get_format_pixel_size(format);
2851
2852 Ref<Image> msk = p_mask;
2853
2854 for (int i = 0; i < dest_rect.size.y; i++) {
2855 for (int j = 0; j < dest_rect.size.x; j++) {
2856 int src_x = src_rect.position.x + j;
2857 int src_y = src_rect.position.y + i;
2858
2859 if (msk->get_pixel(src_x, src_y).a != 0) {
2860 int dst_x = dest_rect.position.x + j;
2861 int dst_y = dest_rect.position.y + i;
2862
2863 const uint8_t *src = &src_data_ptr[(src_y * p_src->width + src_x) * pixel_size];
2864 uint8_t *dst = &dst_data_ptr[(dst_y * width + dst_x) * pixel_size];
2865
2866 for (int k = 0; k < pixel_size; k++) {
2867 dst[k] = src[k];
2868 }
2869 }
2870 }
2871 }
2872}
2873
2874void Image::blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest) {
2875 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2876 int dsize = data.size();
2877 int srcdsize = p_src->data.size();
2878 ERR_FAIL_COND(dsize == 0);
2879 ERR_FAIL_COND(srcdsize == 0);
2880 ERR_FAIL_COND(format != p_src->format);
2881
2882 Rect2i src_rect;
2883 Rect2i dest_rect;
2884 _get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
2885 if (!src_rect.has_area() || !dest_rect.has_area()) {
2886 return;
2887 }
2888
2889 Ref<Image> img = p_src;
2890
2891 for (int i = 0; i < dest_rect.size.y; i++) {
2892 for (int j = 0; j < dest_rect.size.x; j++) {
2893 int src_x = src_rect.position.x + j;
2894 int src_y = src_rect.position.y + i;
2895
2896 int dst_x = dest_rect.position.x + j;
2897 int dst_y = dest_rect.position.y + i;
2898
2899 Color sc = img->get_pixel(src_x, src_y);
2900 if (sc.a != 0) {
2901 Color dc = get_pixel(dst_x, dst_y);
2902 dc = dc.blend(sc);
2903 set_pixel(dst_x, dst_y, dc);
2904 }
2905 }
2906 }
2907}
2908
2909void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest) {
2910 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2911 ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object.");
2912 int dsize = data.size();
2913 int srcdsize = p_src->data.size();
2914 int maskdsize = p_mask->data.size();
2915 ERR_FAIL_COND(dsize == 0);
2916 ERR_FAIL_COND(srcdsize == 0);
2917 ERR_FAIL_COND(maskdsize == 0);
2918 ERR_FAIL_COND_MSG(p_src->width != p_mask->width, "Source image width is different from mask width.");
2919 ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
2920 ERR_FAIL_COND(format != p_src->format);
2921
2922 Rect2i src_rect;
2923 Rect2i dest_rect;
2924 _get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
2925 if (!src_rect.has_area() || !dest_rect.has_area()) {
2926 return;
2927 }
2928
2929 Ref<Image> img = p_src;
2930 Ref<Image> msk = p_mask;
2931
2932 for (int i = 0; i < dest_rect.size.y; i++) {
2933 for (int j = 0; j < dest_rect.size.x; j++) {
2934 int src_x = src_rect.position.x + j;
2935 int src_y = src_rect.position.y + i;
2936
2937 // If the mask's pixel is transparent then we skip it
2938 //Color c = msk->get_pixel(src_x, src_y);
2939 //if (c.a == 0) continue;
2940 if (msk->get_pixel(src_x, src_y).a != 0) {
2941 int dst_x = dest_rect.position.x + j;
2942 int dst_y = dest_rect.position.y + i;
2943
2944 Color sc = img->get_pixel(src_x, src_y);
2945 if (sc.a != 0) {
2946 Color dc = get_pixel(dst_x, dst_y);
2947 dc = dc.blend(sc);
2948 set_pixel(dst_x, dst_y, dc);
2949 }
2950 }
2951 }
2952 }
2953}
2954
2955// Repeats `p_pixel` `p_count` times in consecutive memory.
2956// Results in the original pixel and `p_count - 1` subsequent copies of it.
2957void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_size, int p_count) {
2958 int offset = 1;
2959 for (int stride = 1; offset + stride <= p_count; stride *= 2) {
2960 memcpy(p_pixel + offset * p_pixel_size, p_pixel, stride * p_pixel_size);
2961 offset += stride;
2962 }
2963 if (offset < p_count) {
2964 memcpy(p_pixel + offset * p_pixel_size, p_pixel, (p_count - offset) * p_pixel_size);
2965 }
2966}
2967
2968void Image::fill(const Color &p_color) {
2969 if (data.size() == 0) {
2970 return;
2971 }
2972 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats.");
2973
2974 uint8_t *dst_data_ptr = data.ptrw();
2975
2976 int pixel_size = get_format_pixel_size(format);
2977
2978 // Put first pixel with the format-aware API.
2979 _set_color_at_ofs(dst_data_ptr, 0, p_color);
2980
2981 _repeat_pixel_over_subsequent_memory(dst_data_ptr, pixel_size, width * height);
2982}
2983
2984void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
2985 if (data.size() == 0) {
2986 return;
2987 }
2988 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
2989
2990 Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
2991 if (!r.has_area()) {
2992 return;
2993 }
2994
2995 uint8_t *dst_data_ptr = data.ptrw();
2996
2997 int pixel_size = get_format_pixel_size(format);
2998
2999 // Put first pixel with the format-aware API.
3000 uint8_t *rect_first_pixel_ptr = &dst_data_ptr[(r.position.y * width + r.position.x) * pixel_size];
3001 _set_color_at_ofs(rect_first_pixel_ptr, 0, p_color);
3002
3003 if (r.size.x == width) {
3004 // No need to fill rows separately.
3005 _repeat_pixel_over_subsequent_memory(rect_first_pixel_ptr, pixel_size, width * r.size.y);
3006 } else {
3007 _repeat_pixel_over_subsequent_memory(rect_first_pixel_ptr, pixel_size, r.size.x);
3008 for (int y = 1; y < r.size.y; y++) {
3009 memcpy(rect_first_pixel_ptr + y * width * pixel_size, rect_first_pixel_ptr, r.size.x * pixel_size);
3010 }
3011 }
3012}
3013
3014ImageMemLoadFunc Image::_png_mem_loader_func = nullptr;
3015ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
3016ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
3017ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
3018ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
3019ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
3020ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr;
3021
3022void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
3023void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
3024void (*Image::_image_compress_etc1_func)(Image *) = nullptr;
3025void (*Image::_image_compress_etc2_func)(Image *, Image::UsedChannels) = nullptr;
3026void (*Image::_image_compress_astc_func)(Image *, Image::ASTCFormat) = nullptr;
3027void (*Image::_image_decompress_bc)(Image *) = nullptr;
3028void (*Image::_image_decompress_bptc)(Image *) = nullptr;
3029void (*Image::_image_decompress_etc1)(Image *) = nullptr;
3030void (*Image::_image_decompress_etc2)(Image *) = nullptr;
3031void (*Image::_image_decompress_astc)(Image *) = nullptr;
3032
3033Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr;
3034Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr;
3035Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr;
3036Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr;
3037Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr;
3038Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr;
3039Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr;
3040Ref<Image> (*Image::basis_universal_unpacker_ptr)(const uint8_t *, int) = nullptr;
3041
3042void Image::_set_data(const Dictionary &p_data) {
3043 ERR_FAIL_COND(!p_data.has("width"));
3044 ERR_FAIL_COND(!p_data.has("height"));
3045 ERR_FAIL_COND(!p_data.has("format"));
3046 ERR_FAIL_COND(!p_data.has("mipmaps"));
3047 ERR_FAIL_COND(!p_data.has("data"));
3048
3049 int dwidth = p_data["width"];
3050 int dheight = p_data["height"];
3051 String dformat = p_data["format"];
3052 bool dmipmaps = p_data["mipmaps"];
3053 Vector<uint8_t> ddata = p_data["data"];
3054 Format ddformat = FORMAT_MAX;
3055 for (int i = 0; i < FORMAT_MAX; i++) {
3056 if (dformat == get_format_name(Format(i))) {
3057 ddformat = Format(i);
3058 break;
3059 }
3060 }
3061
3062 ERR_FAIL_COND(ddformat == FORMAT_MAX);
3063
3064 initialize_data(dwidth, dheight, dmipmaps, ddformat, ddata);
3065}
3066
3067Dictionary Image::_get_data() const {
3068 Dictionary d;
3069 d["width"] = width;
3070 d["height"] = height;
3071 d["format"] = get_format_name(format);
3072 d["mipmaps"] = mipmaps;
3073 d["data"] = data;
3074 return d;
3075}
3076
3077Color Image::get_pixelv(const Point2i &p_point) const {
3078 return get_pixel(p_point.x, p_point.y);
3079}
3080
3081Color Image::_get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const {
3082 switch (format) {
3083 case FORMAT_L8: {
3084 float l = ptr[ofs] / 255.0;
3085 return Color(l, l, l, 1);
3086 }
3087 case FORMAT_LA8: {
3088 float l = ptr[ofs * 2 + 0] / 255.0;
3089 float a = ptr[ofs * 2 + 1] / 255.0;
3090 return Color(l, l, l, a);
3091 }
3092 case FORMAT_R8: {
3093 float r = ptr[ofs] / 255.0;
3094 return Color(r, 0, 0, 1);
3095 }
3096 case FORMAT_RG8: {
3097 float r = ptr[ofs * 2 + 0] / 255.0;
3098 float g = ptr[ofs * 2 + 1] / 255.0;
3099 return Color(r, g, 0, 1);
3100 }
3101 case FORMAT_RGB8: {
3102 float r = ptr[ofs * 3 + 0] / 255.0;
3103 float g = ptr[ofs * 3 + 1] / 255.0;
3104 float b = ptr[ofs * 3 + 2] / 255.0;
3105 return Color(r, g, b, 1);
3106 }
3107 case FORMAT_RGBA8: {
3108 float r = ptr[ofs * 4 + 0] / 255.0;
3109 float g = ptr[ofs * 4 + 1] / 255.0;
3110 float b = ptr[ofs * 4 + 2] / 255.0;
3111 float a = ptr[ofs * 4 + 3] / 255.0;
3112 return Color(r, g, b, a);
3113 }
3114 case FORMAT_RGBA4444: {
3115 uint16_t u = ((uint16_t *)ptr)[ofs];
3116 float r = ((u >> 12) & 0xF) / 15.0;
3117 float g = ((u >> 8) & 0xF) / 15.0;
3118 float b = ((u >> 4) & 0xF) / 15.0;
3119 float a = (u & 0xF) / 15.0;
3120 return Color(r, g, b, a);
3121 }
3122 case FORMAT_RGB565: {
3123 uint16_t u = ((uint16_t *)ptr)[ofs];
3124 float r = (u & 0x1F) / 31.0;
3125 float g = ((u >> 5) & 0x3F) / 63.0;
3126 float b = ((u >> 11) & 0x1F) / 31.0;
3127 return Color(r, g, b, 1.0);
3128 }
3129 case FORMAT_RF: {
3130 float r = ((float *)ptr)[ofs];
3131 return Color(r, 0, 0, 1);
3132 }
3133 case FORMAT_RGF: {
3134 float r = ((float *)ptr)[ofs * 2 + 0];
3135 float g = ((float *)ptr)[ofs * 2 + 1];
3136 return Color(r, g, 0, 1);
3137 }
3138 case FORMAT_RGBF: {
3139 float r = ((float *)ptr)[ofs * 3 + 0];
3140 float g = ((float *)ptr)[ofs * 3 + 1];
3141 float b = ((float *)ptr)[ofs * 3 + 2];
3142 return Color(r, g, b, 1);
3143 }
3144 case FORMAT_RGBAF: {
3145 float r = ((float *)ptr)[ofs * 4 + 0];
3146 float g = ((float *)ptr)[ofs * 4 + 1];
3147 float b = ((float *)ptr)[ofs * 4 + 2];
3148 float a = ((float *)ptr)[ofs * 4 + 3];
3149 return Color(r, g, b, a);
3150 }
3151 case FORMAT_RH: {
3152 uint16_t r = ((uint16_t *)ptr)[ofs];
3153 return Color(Math::half_to_float(r), 0, 0, 1);
3154 }
3155 case FORMAT_RGH: {
3156 uint16_t r = ((uint16_t *)ptr)[ofs * 2 + 0];
3157 uint16_t g = ((uint16_t *)ptr)[ofs * 2 + 1];
3158 return Color(Math::half_to_float(r), Math::half_to_float(g), 0, 1);
3159 }
3160 case FORMAT_RGBH: {
3161 uint16_t r = ((uint16_t *)ptr)[ofs * 3 + 0];
3162 uint16_t g = ((uint16_t *)ptr)[ofs * 3 + 1];
3163 uint16_t b = ((uint16_t *)ptr)[ofs * 3 + 2];
3164 return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), 1);
3165 }
3166 case FORMAT_RGBAH: {
3167 uint16_t r = ((uint16_t *)ptr)[ofs * 4 + 0];
3168 uint16_t g = ((uint16_t *)ptr)[ofs * 4 + 1];
3169 uint16_t b = ((uint16_t *)ptr)[ofs * 4 + 2];
3170 uint16_t a = ((uint16_t *)ptr)[ofs * 4 + 3];
3171 return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), Math::half_to_float(a));
3172 }
3173 case FORMAT_RGBE9995: {
3174 return Color::from_rgbe9995(((uint32_t *)ptr)[ofs]);
3175 }
3176 default: {
3177 ERR_FAIL_V_MSG(Color(), "Can't get_pixel() on compressed image, sorry.");
3178 }
3179 }
3180}
3181
3182void Image::_set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color) {
3183 switch (format) {
3184 case FORMAT_L8: {
3185 ptr[ofs] = uint8_t(CLAMP(p_color.get_v() * 255.0, 0, 255));
3186 } break;
3187 case FORMAT_LA8: {
3188 ptr[ofs * 2 + 0] = uint8_t(CLAMP(p_color.get_v() * 255.0, 0, 255));
3189 ptr[ofs * 2 + 1] = uint8_t(CLAMP(p_color.a * 255.0, 0, 255));
3190 } break;
3191 case FORMAT_R8: {
3192 ptr[ofs] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
3193 } break;
3194 case FORMAT_RG8: {
3195 ptr[ofs * 2 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
3196 ptr[ofs * 2 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
3197 } break;
3198 case FORMAT_RGB8: {
3199 ptr[ofs * 3 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
3200 ptr[ofs * 3 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
3201 ptr[ofs * 3 + 2] = uint8_t(CLAMP(p_color.b * 255.0, 0, 255));
3202 } break;
3203 case FORMAT_RGBA8: {
3204 ptr[ofs * 4 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
3205 ptr[ofs * 4 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
3206 ptr[ofs * 4 + 2] = uint8_t(CLAMP(p_color.b * 255.0, 0, 255));
3207 ptr[ofs * 4 + 3] = uint8_t(CLAMP(p_color.a * 255.0, 0, 255));
3208
3209 } break;
3210 case FORMAT_RGBA4444: {
3211 uint16_t rgba = 0;
3212
3213 rgba = uint16_t(CLAMP(p_color.r * 15.0, 0, 15)) << 12;
3214 rgba |= uint16_t(CLAMP(p_color.g * 15.0, 0, 15)) << 8;
3215 rgba |= uint16_t(CLAMP(p_color.b * 15.0, 0, 15)) << 4;
3216 rgba |= uint16_t(CLAMP(p_color.a * 15.0, 0, 15));
3217
3218 ((uint16_t *)ptr)[ofs] = rgba;
3219
3220 } break;
3221 case FORMAT_RGB565: {
3222 uint16_t rgba = 0;
3223
3224 rgba = uint16_t(CLAMP(p_color.r * 31.0, 0, 31));
3225 rgba |= uint16_t(CLAMP(p_color.g * 63.0, 0, 33)) << 5;
3226 rgba |= uint16_t(CLAMP(p_color.b * 31.0, 0, 31)) << 11;
3227
3228 ((uint16_t *)ptr)[ofs] = rgba;
3229
3230 } break;
3231 case FORMAT_RF: {
3232 ((float *)ptr)[ofs] = p_color.r;
3233 } break;
3234 case FORMAT_RGF: {
3235 ((float *)ptr)[ofs * 2 + 0] = p_color.r;
3236 ((float *)ptr)[ofs * 2 + 1] = p_color.g;
3237 } break;
3238 case FORMAT_RGBF: {
3239 ((float *)ptr)[ofs * 3 + 0] = p_color.r;
3240 ((float *)ptr)[ofs * 3 + 1] = p_color.g;
3241 ((float *)ptr)[ofs * 3 + 2] = p_color.b;
3242 } break;
3243 case FORMAT_RGBAF: {
3244 ((float *)ptr)[ofs * 4 + 0] = p_color.r;
3245 ((float *)ptr)[ofs * 4 + 1] = p_color.g;
3246 ((float *)ptr)[ofs * 4 + 2] = p_color.b;
3247 ((float *)ptr)[ofs * 4 + 3] = p_color.a;
3248 } break;
3249 case FORMAT_RH: {
3250 ((uint16_t *)ptr)[ofs] = Math::make_half_float(p_color.r);
3251 } break;
3252 case FORMAT_RGH: {
3253 ((uint16_t *)ptr)[ofs * 2 + 0] = Math::make_half_float(p_color.r);
3254 ((uint16_t *)ptr)[ofs * 2 + 1] = Math::make_half_float(p_color.g);
3255 } break;
3256 case FORMAT_RGBH: {
3257 ((uint16_t *)ptr)[ofs * 3 + 0] = Math::make_half_float(p_color.r);
3258 ((uint16_t *)ptr)[ofs * 3 + 1] = Math::make_half_float(p_color.g);
3259 ((uint16_t *)ptr)[ofs * 3 + 2] = Math::make_half_float(p_color.b);
3260 } break;
3261 case FORMAT_RGBAH: {
3262 ((uint16_t *)ptr)[ofs * 4 + 0] = Math::make_half_float(p_color.r);
3263 ((uint16_t *)ptr)[ofs * 4 + 1] = Math::make_half_float(p_color.g);
3264 ((uint16_t *)ptr)[ofs * 4 + 2] = Math::make_half_float(p_color.b);
3265 ((uint16_t *)ptr)[ofs * 4 + 3] = Math::make_half_float(p_color.a);
3266 } break;
3267 case FORMAT_RGBE9995: {
3268 ((uint32_t *)ptr)[ofs] = p_color.to_rgbe9995();
3269
3270 } break;
3271 default: {
3272 ERR_FAIL_MSG("Can't set_pixel() on compressed image, sorry.");
3273 }
3274 }
3275}
3276
3277Color Image::get_pixel(int p_x, int p_y) const {
3278#ifdef DEBUG_ENABLED
3279 ERR_FAIL_INDEX_V(p_x, width, Color());
3280 ERR_FAIL_INDEX_V(p_y, height, Color());
3281#endif
3282
3283 uint32_t ofs = p_y * width + p_x;
3284 return _get_color_at_ofs(data.ptr(), ofs);
3285}
3286
3287void Image::set_pixelv(const Point2i &p_point, const Color &p_color) {
3288 set_pixel(p_point.x, p_point.y, p_color);
3289}
3290
3291void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
3292#ifdef DEBUG_ENABLED
3293 ERR_FAIL_INDEX(p_x, width);
3294 ERR_FAIL_INDEX(p_y, height);
3295#endif
3296
3297 uint32_t ofs = p_y * width + p_x;
3298 _set_color_at_ofs(data.ptrw(), ofs, p_color);
3299}
3300
3301void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) {
3302 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot adjust_bcs in compressed or custom image formats.");
3303
3304 uint8_t *w = data.ptrw();
3305 uint32_t pixel_size = get_format_pixel_size(format);
3306 uint32_t pixel_count = data.size() / pixel_size;
3307
3308 for (uint32_t i = 0; i < pixel_count; i++) {
3309 Color c = _get_color_at_ofs(w, i);
3310 Vector3 rgb(c.r, c.g, c.b);
3311
3312 rgb *= p_brightness;
3313 rgb = Vector3(0.5, 0.5, 0.5).lerp(rgb, p_contrast);
3314 float center = (rgb.x + rgb.y + rgb.z) / 3.0;
3315 rgb = Vector3(center, center, center).lerp(rgb, p_saturation);
3316 c.r = rgb.x;
3317 c.g = rgb.y;
3318 c.b = rgb.z;
3319 _set_color_at_ofs(w, i, c);
3320 }
3321}
3322
3323Image::UsedChannels Image::detect_used_channels(CompressSource p_source) const {
3324 ERR_FAIL_COND_V(data.size() == 0, USED_CHANNELS_RGBA);
3325 ERR_FAIL_COND_V(is_compressed(), USED_CHANNELS_RGBA);
3326 bool r = false, g = false, b = false, a = false, c = false;
3327
3328 const uint8_t *data_ptr = data.ptr();
3329
3330 uint32_t data_total = width * height;
3331
3332 for (uint32_t i = 0; i < data_total; i++) {
3333 Color col = _get_color_at_ofs(data_ptr, i);
3334
3335 if (col.r > 0.001) {
3336 r = true;
3337 }
3338 if (col.g > 0.001) {
3339 g = true;
3340 }
3341 if (col.b > 0.001) {
3342 b = true;
3343 }
3344 if (col.a < 0.999) {
3345 a = true;
3346 }
3347
3348 if (col.r != col.b || col.r != col.g || col.b != col.g) {
3349 c = true;
3350 }
3351 }
3352
3353 UsedChannels used_channels;
3354
3355 if (!c && !a) {
3356 used_channels = USED_CHANNELS_L;
3357 } else if (!c && a) {
3358 used_channels = USED_CHANNELS_LA;
3359 } else if (r && !g && !b && !a) {
3360 used_channels = USED_CHANNELS_R;
3361 } else if (r && g && !b && !a) {
3362 used_channels = USED_CHANNELS_RG;
3363 } else if (r && g && b && !a) {
3364 used_channels = USED_CHANNELS_RGB;
3365 } else {
3366 used_channels = USED_CHANNELS_RGBA;
3367 }
3368
3369 if (p_source == COMPRESS_SOURCE_SRGB && (used_channels == USED_CHANNELS_R || used_channels == USED_CHANNELS_RG)) {
3370 //R and RG do not support SRGB
3371 used_channels = USED_CHANNELS_RGB;
3372 }
3373
3374 if (p_source == COMPRESS_SOURCE_NORMAL) {
3375 //use RG channels only for normal
3376 used_channels = USED_CHANNELS_RG;
3377 }
3378
3379 return used_channels;
3380}
3381
3382void Image::optimize_channels() {
3383 switch (detect_used_channels()) {
3384 case USED_CHANNELS_L:
3385 convert(FORMAT_L8);
3386 break;
3387 case USED_CHANNELS_LA:
3388 convert(FORMAT_LA8);
3389 break;
3390 case USED_CHANNELS_R:
3391 convert(FORMAT_R8);
3392 break;
3393 case USED_CHANNELS_RG:
3394 convert(FORMAT_RG8);
3395 break;
3396 case USED_CHANNELS_RGB:
3397 convert(FORMAT_RGB8);
3398 break;
3399 case USED_CHANNELS_RGBA:
3400 convert(FORMAT_RGBA8);
3401 break;
3402 }
3403}
3404
3405void Image::_bind_methods() {
3406 ClassDB::bind_method(D_METHOD("get_width"), &Image::get_width);
3407 ClassDB::bind_method(D_METHOD("get_height"), &Image::get_height);
3408 ClassDB::bind_method(D_METHOD("get_size"), &Image::get_size);
3409 ClassDB::bind_method(D_METHOD("has_mipmaps"), &Image::has_mipmaps);
3410 ClassDB::bind_method(D_METHOD("get_format"), &Image::get_format);
3411 ClassDB::bind_method(D_METHOD("get_data"), &Image::get_data);
3412
3413 ClassDB::bind_method(D_METHOD("convert", "format"), &Image::convert);
3414
3415 ClassDB::bind_method(D_METHOD("get_mipmap_offset", "mipmap"), &Image::get_mipmap_offset);
3416
3417 ClassDB::bind_method(D_METHOD("resize_to_po2", "square", "interpolation"), &Image::resize_to_po2, DEFVAL(false), DEFVAL(INTERPOLATE_BILINEAR));
3418 ClassDB::bind_method(D_METHOD("resize", "width", "height", "interpolation"), &Image::resize, DEFVAL(INTERPOLATE_BILINEAR));
3419 ClassDB::bind_method(D_METHOD("shrink_x2"), &Image::shrink_x2);
3420
3421 ClassDB::bind_method(D_METHOD("crop", "width", "height"), &Image::crop);
3422 ClassDB::bind_method(D_METHOD("flip_x"), &Image::flip_x);
3423 ClassDB::bind_method(D_METHOD("flip_y"), &Image::flip_y);
3424 ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
3425 ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
3426
3427 ClassDB::bind_static_method("Image", D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
3428 ClassDB::bind_static_method("Image", D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
3429 ClassDB::bind_method(D_METHOD("set_data", "width", "height", "use_mipmaps", "format", "data"), &Image::set_data);
3430
3431 ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty);
3432
3433 ClassDB::bind_method(D_METHOD("load", "path"), &Image::load);
3434 ClassDB::bind_static_method("Image", D_METHOD("load_from_file", "path"), &Image::load_from_file);
3435 ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png);
3436 ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer);
3437 ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75));
3438 ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75));
3439 ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false));
3440 ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false));
3441 ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f));
3442 ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f));
3443
3444 ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha);
3445 ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible);
3446
3447 ClassDB::bind_method(D_METHOD("detect_used_channels", "source"), &Image::detect_used_channels, DEFVAL(COMPRESS_SOURCE_GENERIC));
3448 ClassDB::bind_method(D_METHOD("compress", "mode", "source", "astc_format"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(ASTC_FORMAT_4x4));
3449 ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "astc_format"), &Image::compress_from_channels, DEFVAL(ASTC_FORMAT_4x4));
3450 ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress);
3451 ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed);
3452
3453 ClassDB::bind_method(D_METHOD("rotate_90", "direction"), &Image::rotate_90);
3454 ClassDB::bind_method(D_METHOD("rotate_180"), &Image::rotate_180);
3455
3456 ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges);
3457 ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha);
3458 ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear);
3459 ClassDB::bind_method(D_METHOD("normal_map_to_xy"), &Image::normal_map_to_xy);
3460 ClassDB::bind_method(D_METHOD("rgbe_to_srgb"), &Image::rgbe_to_srgb);
3461 ClassDB::bind_method(D_METHOD("bump_map_to_normal_map", "bump_scale"), &Image::bump_map_to_normal_map, DEFVAL(1.0));
3462
3463 ClassDB::bind_method(D_METHOD("compute_image_metrics", "compared_image", "use_luma"), &Image::compute_image_metrics);
3464
3465 ClassDB::bind_method(D_METHOD("blit_rect", "src", "src_rect", "dst"), &Image::blit_rect);
3466 ClassDB::bind_method(D_METHOD("blit_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blit_rect_mask);
3467 ClassDB::bind_method(D_METHOD("blend_rect", "src", "src_rect", "dst"), &Image::blend_rect);
3468 ClassDB::bind_method(D_METHOD("blend_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blend_rect_mask);
3469 ClassDB::bind_method(D_METHOD("fill", "color"), &Image::fill);
3470 ClassDB::bind_method(D_METHOD("fill_rect", "rect", "color"), &Image::fill_rect);
3471
3472 ClassDB::bind_method(D_METHOD("get_used_rect"), &Image::get_used_rect);
3473 ClassDB::bind_method(D_METHOD("get_region", "region"), &Image::get_region);
3474
3475 ClassDB::bind_method(D_METHOD("copy_from", "src"), &Image::copy_internals_from);
3476
3477 ClassDB::bind_method(D_METHOD("_set_data", "data"), &Image::_set_data);
3478 ClassDB::bind_method(D_METHOD("_get_data"), &Image::_get_data);
3479
3480 ClassDB::bind_method(D_METHOD("get_pixelv", "point"), &Image::get_pixelv);
3481 ClassDB::bind_method(D_METHOD("get_pixel", "x", "y"), &Image::get_pixel);
3482 ClassDB::bind_method(D_METHOD("set_pixelv", "point", "color"), &Image::set_pixelv);
3483 ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel);
3484
3485 ClassDB::bind_method(D_METHOD("adjust_bcs", "brightness", "contrast", "saturation"), &Image::adjust_bcs);
3486
3487 ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer);
3488 ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
3489 ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
3490 ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
3491 ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
3492 ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer);
3493
3494 ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0));
3495 ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0));
3496
3497 ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
3498
3499 BIND_CONSTANT(MAX_WIDTH);
3500 BIND_CONSTANT(MAX_HEIGHT);
3501
3502 BIND_ENUM_CONSTANT(FORMAT_L8); //luminance
3503 BIND_ENUM_CONSTANT(FORMAT_LA8); //luminance-alpha
3504 BIND_ENUM_CONSTANT(FORMAT_R8);
3505 BIND_ENUM_CONSTANT(FORMAT_RG8);
3506 BIND_ENUM_CONSTANT(FORMAT_RGB8);
3507 BIND_ENUM_CONSTANT(FORMAT_RGBA8);
3508 BIND_ENUM_CONSTANT(FORMAT_RGBA4444);
3509 BIND_ENUM_CONSTANT(FORMAT_RGB565);
3510 BIND_ENUM_CONSTANT(FORMAT_RF); //float
3511 BIND_ENUM_CONSTANT(FORMAT_RGF);
3512 BIND_ENUM_CONSTANT(FORMAT_RGBF);
3513 BIND_ENUM_CONSTANT(FORMAT_RGBAF);
3514 BIND_ENUM_CONSTANT(FORMAT_RH); //half float
3515 BIND_ENUM_CONSTANT(FORMAT_RGH);
3516 BIND_ENUM_CONSTANT(FORMAT_RGBH);
3517 BIND_ENUM_CONSTANT(FORMAT_RGBAH);
3518 BIND_ENUM_CONSTANT(FORMAT_RGBE9995);
3519 BIND_ENUM_CONSTANT(FORMAT_DXT1); //s3tc bc1
3520 BIND_ENUM_CONSTANT(FORMAT_DXT3); //bc2
3521 BIND_ENUM_CONSTANT(FORMAT_DXT5); //bc3
3522 BIND_ENUM_CONSTANT(FORMAT_RGTC_R);
3523 BIND_ENUM_CONSTANT(FORMAT_RGTC_RG);
3524 BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBA); //btpc bc6h
3525 BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBF); //float /
3526 BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBFU); //unsigned float
3527 BIND_ENUM_CONSTANT(FORMAT_ETC); //etc1
3528 BIND_ENUM_CONSTANT(FORMAT_ETC2_R11); //etc2
3529 BIND_ENUM_CONSTANT(FORMAT_ETC2_R11S); //signed ); NOT srgb.
3530 BIND_ENUM_CONSTANT(FORMAT_ETC2_RG11);
3531 BIND_ENUM_CONSTANT(FORMAT_ETC2_RG11S);
3532 BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8);
3533 BIND_ENUM_CONSTANT(FORMAT_ETC2_RGBA8);
3534 BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8A1);
3535 BIND_ENUM_CONSTANT(FORMAT_ETC2_RA_AS_RG);
3536 BIND_ENUM_CONSTANT(FORMAT_DXT5_RA_AS_RG);
3537 BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4);
3538 BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4_HDR);
3539 BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8);
3540 BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8_HDR);
3541 BIND_ENUM_CONSTANT(FORMAT_MAX);
3542
3543 BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST);
3544 BIND_ENUM_CONSTANT(INTERPOLATE_BILINEAR);
3545 BIND_ENUM_CONSTANT(INTERPOLATE_CUBIC);
3546 BIND_ENUM_CONSTANT(INTERPOLATE_TRILINEAR);
3547 BIND_ENUM_CONSTANT(INTERPOLATE_LANCZOS);
3548
3549 BIND_ENUM_CONSTANT(ALPHA_NONE);
3550 BIND_ENUM_CONSTANT(ALPHA_BIT);
3551 BIND_ENUM_CONSTANT(ALPHA_BLEND);
3552
3553 BIND_ENUM_CONSTANT(COMPRESS_S3TC);
3554 BIND_ENUM_CONSTANT(COMPRESS_ETC);
3555 BIND_ENUM_CONSTANT(COMPRESS_ETC2);
3556 BIND_ENUM_CONSTANT(COMPRESS_BPTC);
3557 BIND_ENUM_CONSTANT(COMPRESS_ASTC);
3558 BIND_ENUM_CONSTANT(COMPRESS_MAX);
3559
3560 BIND_ENUM_CONSTANT(USED_CHANNELS_L);
3561 BIND_ENUM_CONSTANT(USED_CHANNELS_LA);
3562 BIND_ENUM_CONSTANT(USED_CHANNELS_R);
3563 BIND_ENUM_CONSTANT(USED_CHANNELS_RG);
3564 BIND_ENUM_CONSTANT(USED_CHANNELS_RGB);
3565 BIND_ENUM_CONSTANT(USED_CHANNELS_RGBA);
3566
3567 BIND_ENUM_CONSTANT(COMPRESS_SOURCE_GENERIC);
3568 BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB);
3569 BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL);
3570
3571 BIND_ENUM_CONSTANT(ASTC_FORMAT_4x4);
3572 BIND_ENUM_CONSTANT(ASTC_FORMAT_8x8);
3573}
3574
3575void Image::set_compress_bc_func(void (*p_compress_func)(Image *, UsedChannels)) {
3576 _image_compress_bc_func = p_compress_func;
3577}
3578
3579void Image::set_compress_bptc_func(void (*p_compress_func)(Image *, UsedChannels)) {
3580 _image_compress_bptc_func = p_compress_func;
3581}
3582
3583void Image::normal_map_to_xy() {
3584 convert(Image::FORMAT_RGBA8);
3585
3586 {
3587 int len = data.size() / 4;
3588 uint8_t *data_ptr = data.ptrw();
3589
3590 for (int i = 0; i < len; i++) {
3591 data_ptr[(i << 2) + 3] = data_ptr[(i << 2) + 0]; //x to w
3592 data_ptr[(i << 2) + 0] = data_ptr[(i << 2) + 1]; //y to xz
3593 data_ptr[(i << 2) + 2] = data_ptr[(i << 2) + 1];
3594 }
3595 }
3596
3597 convert(Image::FORMAT_LA8);
3598}
3599
3600Ref<Image> Image::rgbe_to_srgb() {
3601 if (data.size() == 0) {
3602 return Ref<Image>();
3603 }
3604
3605 ERR_FAIL_COND_V(format != FORMAT_RGBE9995, Ref<Image>());
3606
3607 Ref<Image> new_image = create_empty(width, height, false, Image::FORMAT_RGB8);
3608
3609 for (int row = 0; row < height; row++) {
3610 for (int col = 0; col < width; col++) {
3611 new_image->set_pixel(col, row, get_pixel(col, row).linear_to_srgb());
3612 }
3613 }
3614
3615 if (has_mipmaps()) {
3616 new_image->generate_mipmaps();
3617 }
3618
3619 return new_image;
3620}
3621
3622Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const {
3623 int ofs, size, w, h;
3624 get_mipmap_offset_size_and_dimensions(p_mipamp, ofs, size, w, h);
3625
3626 Vector<uint8_t> new_data;
3627 new_data.resize(size);
3628
3629 {
3630 uint8_t *wr = new_data.ptrw();
3631 const uint8_t *rd = data.ptr();
3632 memcpy(wr, rd + ofs, size);
3633 }
3634
3635 Ref<Image> image;
3636 image.instantiate();
3637 image->width = w;
3638 image->height = h;
3639 image->format = format;
3640 image->data = new_data;
3641
3642 image->mipmaps = false;
3643 return image;
3644}
3645
3646void Image::bump_map_to_normal_map(float bump_scale) {
3647 ERR_FAIL_COND(!_can_modify(format));
3648 clear_mipmaps();
3649 convert(Image::FORMAT_RF);
3650
3651 Vector<uint8_t> result_image; //rgba output
3652 result_image.resize(width * height * 4);
3653
3654 {
3655 const uint8_t *rp = data.ptr();
3656 uint8_t *wp = result_image.ptrw();
3657
3658 ERR_FAIL_NULL(rp);
3659
3660 unsigned char *write_ptr = wp;
3661 float *read_ptr = (float *)rp;
3662
3663 for (int ty = 0; ty < height; ty++) {
3664 int py = ty + 1;
3665 if (py >= height) {
3666 py -= height;
3667 }
3668
3669 for (int tx = 0; tx < width; tx++) {
3670 int px = tx + 1;
3671 if (px >= width) {
3672 px -= width;
3673 }
3674 float here = read_ptr[ty * width + tx];
3675 float to_right = read_ptr[ty * width + px];
3676 float above = read_ptr[py * width + tx];
3677 Vector3 up = Vector3(0, 1, (here - above) * bump_scale);
3678 Vector3 across = Vector3(1, 0, (to_right - here) * bump_scale);
3679
3680 Vector3 normal = across.cross(up);
3681 normal.normalize();
3682
3683 write_ptr[((ty * width + tx) << 2) + 0] = (127.5 + normal.x * 127.5);
3684 write_ptr[((ty * width + tx) << 2) + 1] = (127.5 + normal.y * 127.5);
3685 write_ptr[((ty * width + tx) << 2) + 2] = (127.5 + normal.z * 127.5);
3686 write_ptr[((ty * width + tx) << 2) + 3] = 255;
3687 }
3688 }
3689 }
3690 format = FORMAT_RGBA8;
3691 data = result_image;
3692}
3693
3694void Image::srgb_to_linear() {
3695 if (data.size() == 0) {
3696 return;
3697 }
3698
3699 static const uint8_t srgb2lin[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 88, 89, 90, 92, 93, 94, 95, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 116, 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, 155, 157, 159, 160, 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, 250, 252, 255 };
3700
3701 ERR_FAIL_COND(format != FORMAT_RGB8 && format != FORMAT_RGBA8);
3702
3703 if (format == FORMAT_RGBA8) {
3704 int len = data.size() / 4;
3705 uint8_t *data_ptr = data.ptrw();
3706
3707 for (int i = 0; i < len; i++) {
3708 data_ptr[(i << 2) + 0] = srgb2lin[data_ptr[(i << 2) + 0]];
3709 data_ptr[(i << 2) + 1] = srgb2lin[data_ptr[(i << 2) + 1]];
3710 data_ptr[(i << 2) + 2] = srgb2lin[data_ptr[(i << 2) + 2]];
3711 }
3712
3713 } else if (format == FORMAT_RGB8) {
3714 int len = data.size() / 3;
3715 uint8_t *data_ptr = data.ptrw();
3716
3717 for (int i = 0; i < len; i++) {
3718 data_ptr[(i * 3) + 0] = srgb2lin[data_ptr[(i * 3) + 0]];
3719 data_ptr[(i * 3) + 1] = srgb2lin[data_ptr[(i * 3) + 1]];
3720 data_ptr[(i * 3) + 2] = srgb2lin[data_ptr[(i * 3) + 2]];
3721 }
3722 }
3723}
3724
3725void Image::premultiply_alpha() {
3726 if (data.size() == 0) {
3727 return;
3728 }
3729
3730 if (format != FORMAT_RGBA8) {
3731 return; //not needed
3732 }
3733
3734 uint8_t *data_ptr = data.ptrw();
3735
3736 for (int i = 0; i < height; i++) {
3737 for (int j = 0; j < width; j++) {
3738 uint8_t *ptr = &data_ptr[(i * width + j) * 4];
3739
3740 ptr[0] = (uint16_t(ptr[0]) * uint16_t(ptr[3]) + 255U) >> 8;
3741 ptr[1] = (uint16_t(ptr[1]) * uint16_t(ptr[3]) + 255U) >> 8;
3742 ptr[2] = (uint16_t(ptr[2]) * uint16_t(ptr[3]) + 255U) >> 8;
3743 }
3744 }
3745}
3746
3747void Image::fix_alpha_edges() {
3748 if (data.size() == 0) {
3749 return;
3750 }
3751
3752 if (format != FORMAT_RGBA8) {
3753 return; //not needed
3754 }
3755
3756 Vector<uint8_t> dcopy = data;
3757 const uint8_t *srcptr = dcopy.ptr();
3758
3759 uint8_t *data_ptr = data.ptrw();
3760
3761 const int max_radius = 4;
3762 const int alpha_threshold = 20;
3763 const int max_dist = 0x7FFFFFFF;
3764
3765 for (int i = 0; i < height; i++) {
3766 for (int j = 0; j < width; j++) {
3767 const uint8_t *rptr = &srcptr[(i * width + j) * 4];
3768 uint8_t *wptr = &data_ptr[(i * width + j) * 4];
3769
3770 if (rptr[3] >= alpha_threshold) {
3771 continue;
3772 }
3773
3774 int closest_dist = max_dist;
3775 uint8_t closest_color[3];
3776
3777 int from_x = MAX(0, j - max_radius);
3778 int to_x = MIN(width - 1, j + max_radius);
3779 int from_y = MAX(0, i - max_radius);
3780 int to_y = MIN(height - 1, i + max_radius);
3781
3782 for (int k = from_y; k <= to_y; k++) {
3783 for (int l = from_x; l <= to_x; l++) {
3784 int dy = i - k;
3785 int dx = j - l;
3786 int dist = dy * dy + dx * dx;
3787 if (dist >= closest_dist) {
3788 continue;
3789 }
3790
3791 const uint8_t *rp2 = &srcptr[(k * width + l) << 2];
3792
3793 if (rp2[3] < alpha_threshold) {
3794 continue;
3795 }
3796
3797 closest_dist = dist;
3798 closest_color[0] = rp2[0];
3799 closest_color[1] = rp2[1];
3800 closest_color[2] = rp2[2];
3801 }
3802 }
3803
3804 if (closest_dist != max_dist) {
3805 wptr[0] = closest_color[0];
3806 wptr[1] = closest_color[1];
3807 wptr[2] = closest_color[2];
3808 }
3809 }
3810 }
3811}
3812
3813String Image::get_format_name(Format p_format) {
3814 ERR_FAIL_INDEX_V(p_format, FORMAT_MAX, String());
3815 return format_names[p_format];
3816}
3817
3818Error Image::load_png_from_buffer(const Vector<uint8_t> &p_array) {
3819 return _load_from_buffer(p_array, _png_mem_loader_func);
3820}
3821
3822Error Image::load_jpg_from_buffer(const Vector<uint8_t> &p_array) {
3823 return _load_from_buffer(p_array, _jpg_mem_loader_func);
3824}
3825
3826Error Image::load_webp_from_buffer(const Vector<uint8_t> &p_array) {
3827 return _load_from_buffer(p_array, _webp_mem_loader_func);
3828}
3829
3830Error Image::load_tga_from_buffer(const Vector<uint8_t> &p_array) {
3831 ERR_FAIL_NULL_V_MSG(
3832 _tga_mem_loader_func,
3833 ERR_UNAVAILABLE,
3834 "The TGA module isn't enabled. Recompile the Godot editor or export template binary with the `module_tga_enabled=yes` SCons option.");
3835 return _load_from_buffer(p_array, _tga_mem_loader_func);
3836}
3837
3838Error Image::load_bmp_from_buffer(const Vector<uint8_t> &p_array) {
3839 ERR_FAIL_NULL_V_MSG(
3840 _bmp_mem_loader_func,
3841 ERR_UNAVAILABLE,
3842 "The BMP module isn't enabled. Recompile the Godot editor or export template binary with the `module_bmp_enabled=yes` SCons option.");
3843 return _load_from_buffer(p_array, _bmp_mem_loader_func);
3844}
3845
3846Error Image::load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale) {
3847 ERR_FAIL_NULL_V_MSG(
3848 _svg_scalable_mem_loader_func,
3849 ERR_UNAVAILABLE,
3850 "The SVG module isn't enabled. Recompile the Godot editor or export template binary with the `module_svg_enabled=yes` SCons option.");
3851
3852 int buffer_size = p_array.size();
3853
3854 ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
3855
3856 Ref<Image> image = _svg_scalable_mem_loader_func(p_array.ptr(), buffer_size, scale);
3857 ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
3858
3859 copy_internals_from(image);
3860
3861 return OK;
3862}
3863
3864Error Image::load_svg_from_string(const String &p_svg_str, float scale) {
3865 return load_svg_from_buffer(p_svg_str.to_utf8_buffer(), scale);
3866}
3867
3868Error Image::load_ktx_from_buffer(const Vector<uint8_t> &p_array) {
3869 ERR_FAIL_NULL_V_MSG(
3870 _ktx_mem_loader_func,
3871 ERR_UNAVAILABLE,
3872 "The KTX module isn't enabled. Recompile the Godot editor or export template binary with the `module_ktx_enabled=yes` SCons option.");
3873 return _load_from_buffer(p_array, _ktx_mem_loader_func);
3874}
3875
3876void Image::convert_rg_to_ra_rgba8() {
3877 ERR_FAIL_COND(format != FORMAT_RGBA8);
3878 ERR_FAIL_COND(!data.size());
3879
3880 int s = data.size();
3881 uint8_t *w = data.ptrw();
3882 for (int i = 0; i < s; i += 4) {
3883 w[i + 3] = w[i + 1];
3884 w[i + 1] = 0;
3885 w[i + 2] = 0;
3886 }
3887}
3888
3889void Image::convert_ra_rgba8_to_rg() {
3890 ERR_FAIL_COND(format != FORMAT_RGBA8);
3891 ERR_FAIL_COND(!data.size());
3892
3893 int s = data.size();
3894 uint8_t *w = data.ptrw();
3895 for (int i = 0; i < s; i += 4) {
3896 w[i + 1] = w[i + 3];
3897 w[i + 2] = 0;
3898 w[i + 3] = 255;
3899 }
3900}
3901
3902void Image::convert_rgba8_to_bgra8() {
3903 ERR_FAIL_COND(format != FORMAT_RGBA8);
3904 ERR_FAIL_COND(!data.size());
3905
3906 int s = data.size();
3907 uint8_t *w = data.ptrw();
3908 for (int i = 0; i < s; i += 4) {
3909 uint8_t r = w[i];
3910 w[i] = w[i + 2]; // Swap R to B
3911 w[i + 2] = r; // Swap B to R
3912 }
3913}
3914
3915Error Image::_load_from_buffer(const Vector<uint8_t> &p_array, ImageMemLoadFunc p_loader) {
3916 int buffer_size = p_array.size();
3917
3918 ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
3919 ERR_FAIL_NULL_V(p_loader, ERR_INVALID_PARAMETER);
3920
3921 const uint8_t *r = p_array.ptr();
3922
3923 Ref<Image> image = p_loader(r, buffer_size);
3924 ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
3925
3926 copy_internals_from(image);
3927
3928 return OK;
3929}
3930
3931void Image::average_4_uint8(uint8_t &p_out, const uint8_t &p_a, const uint8_t &p_b, const uint8_t &p_c, const uint8_t &p_d) {
3932 p_out = static_cast<uint8_t>((p_a + p_b + p_c + p_d + 2) >> 2);
3933}
3934
3935void Image::average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d) {
3936 p_out = (p_a + p_b + p_c + p_d) * 0.25f;
3937}
3938
3939void Image::average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d) {
3940 p_out = Math::make_half_float((Math::half_to_float(p_a) + Math::half_to_float(p_b) + Math::half_to_float(p_c) + Math::half_to_float(p_d)) * 0.25f);
3941}
3942
3943void Image::average_4_rgbe9995(uint32_t &p_out, const uint32_t &p_a, const uint32_t &p_b, const uint32_t &p_c, const uint32_t &p_d) {
3944 p_out = ((Color::from_rgbe9995(p_a) + Color::from_rgbe9995(p_b) + Color::from_rgbe9995(p_c) + Color::from_rgbe9995(p_d)) * 0.25f).to_rgbe9995();
3945}
3946
3947void Image::renormalize_uint8(uint8_t *p_rgb) {
3948 Vector3 n(p_rgb[0] / 255.0, p_rgb[1] / 255.0, p_rgb[2] / 255.0);
3949 n *= 2.0;
3950 n -= Vector3(1, 1, 1);
3951 n.normalize();
3952 n += Vector3(1, 1, 1);
3953 n *= 0.5;
3954 n *= 255;
3955 p_rgb[0] = CLAMP(int(n.x), 0, 255);
3956 p_rgb[1] = CLAMP(int(n.y), 0, 255);
3957 p_rgb[2] = CLAMP(int(n.z), 0, 255);
3958}
3959
3960void Image::renormalize_float(float *p_rgb) {
3961 Vector3 n(p_rgb[0], p_rgb[1], p_rgb[2]);
3962 n.normalize();
3963 p_rgb[0] = n.x;
3964 p_rgb[1] = n.y;
3965 p_rgb[2] = n.z;
3966}
3967
3968void Image::renormalize_half(uint16_t *p_rgb) {
3969 Vector3 n(Math::half_to_float(p_rgb[0]), Math::half_to_float(p_rgb[1]), Math::half_to_float(p_rgb[2]));
3970 n.normalize();
3971 p_rgb[0] = Math::make_half_float(n.x);
3972 p_rgb[1] = Math::make_half_float(n.y);
3973 p_rgb[2] = Math::make_half_float(n.z);
3974}
3975
3976void Image::renormalize_rgbe9995(uint32_t *p_rgb) {
3977 // Never used
3978}
3979
3980Image::Image(const uint8_t *p_mem_png_jpg, int p_len) {
3981 width = 0;
3982 height = 0;
3983 mipmaps = false;
3984 format = FORMAT_L8;
3985
3986 if (_png_mem_loader_func) {
3987 copy_internals_from(_png_mem_loader_func(p_mem_png_jpg, p_len));
3988 }
3989
3990 if (is_empty() && _jpg_mem_loader_func) {
3991 copy_internals_from(_jpg_mem_loader_func(p_mem_png_jpg, p_len));
3992 }
3993
3994 if (is_empty() && _webp_mem_loader_func) {
3995 copy_internals_from(_webp_mem_loader_func(p_mem_png_jpg, p_len));
3996 }
3997}
3998
3999Ref<Resource> Image::duplicate(bool p_subresources) const {
4000 Ref<Image> copy;
4001 copy.instantiate();
4002 copy->_copy_internals_from(*this);
4003 return copy;
4004}
4005
4006void Image::set_as_black() {
4007 memset(data.ptrw(), 0, data.size());
4008}
4009
4010Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool p_luma_metric) {
4011 // https://github.com/richgel999/bc7enc_rdo/blob/master/LICENSE
4012 //
4013 // This is free and unencumbered software released into the public domain.
4014 // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
4015 // software, either in source code form or as a compiled binary, for any purpose,
4016 // commercial or non - commercial, and by any means.
4017 // In jurisdictions that recognize copyright laws, the author or authors of this
4018 // software dedicate any and all copyright interest in the software to the public
4019 // domain. We make this dedication for the benefit of the public at large and to
4020 // the detriment of our heirs and successors. We intend this dedication to be an
4021 // overt act of relinquishment in perpetuity of all present and future rights to
4022 // this software under copyright law.
4023 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4024 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4025 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
4026 // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
4027 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4028 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4029
4030 Dictionary result;
4031 result["max"] = INFINITY;
4032 result["mean"] = INFINITY;
4033 result["mean_squared"] = INFINITY;
4034 result["root_mean_squared"] = INFINITY;
4035 result["peak_snr"] = 0.0f;
4036
4037 ERR_FAIL_NULL_V(p_compared_image, result);
4038 Error err = OK;
4039 Ref<Image> compared_image = duplicate(true);
4040 if (compared_image->is_compressed()) {
4041 err = compared_image->decompress();
4042 }
4043 ERR_FAIL_COND_V(err != OK, result);
4044 Ref<Image> source_image = p_compared_image->duplicate(true);
4045 if (source_image->is_compressed()) {
4046 err = source_image->decompress();
4047 }
4048 ERR_FAIL_COND_V(err != OK, result);
4049
4050 ERR_FAIL_COND_V(err != OK, result);
4051
4052 ERR_FAIL_COND_V_MSG((compared_image->get_format() >= Image::FORMAT_RH) && (compared_image->get_format() <= Image::FORMAT_RGBE9995), result, "Metrics on HDR images are not supported.");
4053 ERR_FAIL_COND_V_MSG((source_image->get_format() >= Image::FORMAT_RH) && (source_image->get_format() <= Image::FORMAT_RGBE9995), result, "Metrics on HDR images are not supported.");
4054
4055 double image_metric_max, image_metric_mean, image_metric_mean_squared, image_metric_root_mean_squared, image_metric_peak_snr = 0.0;
4056 const bool average_component_error = true;
4057
4058 const uint32_t w = MIN(compared_image->get_width(), source_image->get_width());
4059 const uint32_t h = MIN(compared_image->get_height(), source_image->get_height());
4060
4061 // Histogram approach originally due to Charles Bloom.
4062 double hist[256];
4063 memset(hist, 0, sizeof(hist));
4064
4065 for (uint32_t y = 0; y < h; y++) {
4066 for (uint32_t x = 0; x < w; x++) {
4067 const Color color_a = compared_image->get_pixel(x, y);
4068
4069 const Color color_b = source_image->get_pixel(x, y);
4070
4071 if (!p_luma_metric) {
4072 ERR_FAIL_COND_V_MSG(color_a.r > 1.0f, Dictionary(), "Can't compare HDR colors.");
4073 ERR_FAIL_COND_V_MSG(color_b.r > 1.0f, Dictionary(), "Can't compare HDR colors.");
4074 hist[Math::abs(color_a.get_r8() - color_b.get_r8())]++;
4075 ERR_FAIL_COND_V_MSG(color_a.g > 1.0f, Dictionary(), "Can't compare HDR colors.");
4076 ERR_FAIL_COND_V_MSG(color_b.g > 1.0f, Dictionary(), "Can't compare HDR colors.");
4077 hist[Math::abs(color_a.get_g8() - color_b.get_g8())]++;
4078 ERR_FAIL_COND_V_MSG(color_a.b > 1.0f, Dictionary(), "Can't compare HDR colors.");
4079 ERR_FAIL_COND_V_MSG(color_b.b > 1.0f, Dictionary(), "Can't compare HDR colors.");
4080 hist[Math::abs(color_a.get_b8() - color_b.get_b8())]++;
4081 ERR_FAIL_COND_V_MSG(color_a.a > 1.0f, Dictionary(), "Can't compare HDR colors.");
4082 ERR_FAIL_COND_V_MSG(color_b.a > 1.0f, Dictionary(), "Can't compare HDR colors.");
4083 hist[Math::abs(color_a.get_a8() - color_b.get_a8())]++;
4084 } else {
4085 ERR_FAIL_COND_V_MSG(color_a.r > 1.0f, Dictionary(), "Can't compare HDR colors.");
4086 ERR_FAIL_COND_V_MSG(color_b.r > 1.0f, Dictionary(), "Can't compare HDR colors.");
4087 // REC709 weightings
4088 int luma_a = (13938U * color_a.get_r8() + 46869U * color_a.get_g8() + 4729U * color_a.get_b8() + 32768U) >> 16U;
4089 int luma_b = (13938U * color_b.get_r8() + 46869U * color_b.get_g8() + 4729U * color_b.get_b8() + 32768U) >> 16U;
4090 hist[Math::abs(luma_a - luma_b)]++;
4091 }
4092 }
4093 }
4094
4095 image_metric_max = 0;
4096 double sum = 0.0f, sum2 = 0.0f;
4097 for (uint32_t i = 0; i < 256; i++) {
4098 if (!hist[i]) {
4099 continue;
4100 }
4101
4102 image_metric_max = MAX(image_metric_max, i);
4103
4104 double x = i * hist[i];
4105
4106 sum += x;
4107 sum2 += i * x;
4108 }
4109
4110 // See http://richg42.blogspot.com/2016/09/how-to-compute-psnr-from-old-berkeley.html
4111 double total_values = w * h;
4112
4113 if (average_component_error) {
4114 total_values *= 4;
4115 }
4116
4117 image_metric_mean = CLAMP(sum / total_values, 0.0f, 255.0f);
4118 image_metric_mean_squared = CLAMP(sum2 / total_values, 0.0f, 255.0f * 255.0f);
4119
4120 image_metric_root_mean_squared = sqrt(image_metric_mean_squared);
4121
4122 if (!image_metric_root_mean_squared) {
4123 image_metric_peak_snr = 1e+10f;
4124 } else {
4125 image_metric_peak_snr = CLAMP(log10(255.0f / image_metric_root_mean_squared) * 20.0f, 0.0f, 500.0f);
4126 }
4127 result["max"] = image_metric_max;
4128 result["mean"] = image_metric_mean;
4129 result["mean_squared"] = image_metric_mean_squared;
4130 result["root_mean_squared"] = image_metric_root_mean_squared;
4131 result["peak_snr"] = image_metric_peak_snr;
4132 return result;
4133}
4134