1 /*************************************************************************/
2 /* image.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
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_macros.h"
34 #include "core/hash_map.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/os/copymem.h"
39 #include "core/print_string.h"
40
41 #include "thirdparty/misc/hq2x.h"
42
43 #include <stdio.h>
44
45 const 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 "PVRTC2", //pvrtc
72 "PVRTC2A",
73 "PVRTC4",
74 "PVRTC4A",
75 "ETC", //etc1
76 "ETC2_R11", //etc2
77 "ETC2_R11S", //signed", NOT srgb.
78 "ETC2_RG11",
79 "ETC2_RG11S",
80 "ETC2_RGB8",
81 "ETC2_RGBA8",
82 "ETC2_RGB8A1",
83
84 };
85
86 SavePNGFunc Image::save_png_func = NULL;
87 SaveEXRFunc Image::save_exr_func = NULL;
88
89 SavePNGBufferFunc Image::save_png_buffer_func = NULL;
90
_put_pixelb(int p_x,int p_y,uint32_t p_pixelsize,uint8_t * p_data,const uint8_t * p_pixel)91 void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel) {
92
93 uint32_t ofs = (p_y * width + p_x) * p_pixelsize;
94
95 for (uint32_t i = 0; i < p_pixelsize; i++) {
96 p_data[ofs + i] = p_pixel[i];
97 }
98 }
99
_get_pixelb(int p_x,int p_y,uint32_t p_pixelsize,const uint8_t * p_data,uint8_t * p_pixel)100 void Image::_get_pixelb(int p_x, int p_y, uint32_t p_pixelsize, const uint8_t *p_data, uint8_t *p_pixel) {
101
102 uint32_t ofs = (p_y * width + p_x) * p_pixelsize;
103
104 for (uint32_t i = 0; i < p_pixelsize; i++) {
105 p_pixel[i] = p_data[ofs + i];
106 }
107 }
108
get_format_pixel_size(Format p_format)109 int Image::get_format_pixel_size(Format p_format) {
110
111 switch (p_format) {
112 case FORMAT_L8:
113 return 1; //luminance
114 case FORMAT_LA8:
115 return 2; //luminance-alpha
116 case FORMAT_R8: return 1;
117 case FORMAT_RG8: return 2;
118 case FORMAT_RGB8: return 3;
119 case FORMAT_RGBA8: return 4;
120 case FORMAT_RGBA4444: return 2;
121 case FORMAT_RGBA5551: return 2;
122 case FORMAT_RF:
123 return 4; //float
124 case FORMAT_RGF: return 8;
125 case FORMAT_RGBF: return 12;
126 case FORMAT_RGBAF: return 16;
127 case FORMAT_RH:
128 return 2; //half float
129 case FORMAT_RGH: return 4;
130 case FORMAT_RGBH: return 6;
131 case FORMAT_RGBAH: return 8;
132 case FORMAT_RGBE9995: return 4;
133 case FORMAT_DXT1:
134 return 1; //s3tc bc1
135 case FORMAT_DXT3:
136 return 1; //bc2
137 case FORMAT_DXT5:
138 return 1; //bc3
139 case FORMAT_RGTC_R:
140 return 1; //bc4
141 case FORMAT_RGTC_RG:
142 return 1; //bc5
143 case FORMAT_BPTC_RGBA:
144 return 1; //btpc bc6h
145 case FORMAT_BPTC_RGBF:
146 return 1; //float /
147 case FORMAT_BPTC_RGBFU:
148 return 1; //unsigned float
149 case FORMAT_PVRTC2:
150 return 1; //pvrtc
151 case FORMAT_PVRTC2A: return 1;
152 case FORMAT_PVRTC4: return 1;
153 case FORMAT_PVRTC4A: return 1;
154 case FORMAT_ETC:
155 return 1; //etc1
156 case FORMAT_ETC2_R11:
157 return 1; //etc2
158 case FORMAT_ETC2_R11S:
159 return 1; //signed: return 1; NOT srgb.
160 case FORMAT_ETC2_RG11: return 1;
161 case FORMAT_ETC2_RG11S: return 1;
162 case FORMAT_ETC2_RGB8: return 1;
163 case FORMAT_ETC2_RGBA8: return 1;
164 case FORMAT_ETC2_RGB8A1: return 1;
165 case FORMAT_MAX: {
166 }
167 }
168 return 0;
169 }
170
get_format_min_pixel_size(Format p_format,int & r_w,int & r_h)171 void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
172
173 switch (p_format) {
174 case FORMAT_DXT1: //s3tc bc1
175 case FORMAT_DXT3: //bc2
176 case FORMAT_DXT5: //bc3
177 case FORMAT_RGTC_R: //bc4
178 case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
179
180 r_w = 4;
181 r_h = 4;
182 } break;
183 case FORMAT_PVRTC2:
184 case FORMAT_PVRTC2A: {
185
186 r_w = 16;
187 r_h = 8;
188 } break;
189 case FORMAT_PVRTC4A:
190 case FORMAT_PVRTC4: {
191
192 r_w = 8;
193 r_h = 8;
194 } break;
195 case FORMAT_ETC: {
196
197 r_w = 4;
198 r_h = 4;
199 } break;
200 case FORMAT_BPTC_RGBA:
201 case FORMAT_BPTC_RGBF:
202 case FORMAT_BPTC_RGBFU: {
203
204 r_w = 4;
205 r_h = 4;
206 } break;
207 case FORMAT_ETC2_R11: //etc2
208 case FORMAT_ETC2_R11S: //signed: NOT srgb.
209 case FORMAT_ETC2_RG11:
210 case FORMAT_ETC2_RG11S:
211 case FORMAT_ETC2_RGB8:
212 case FORMAT_ETC2_RGBA8:
213 case FORMAT_ETC2_RGB8A1: {
214
215 r_w = 4;
216 r_h = 4;
217
218 } break;
219
220 default: {
221 r_w = 1;
222 r_h = 1;
223 } break;
224 }
225 }
226
get_format_pixel_rshift(Format p_format)227 int Image::get_format_pixel_rshift(Format p_format) {
228
229 if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_PVRTC4 || p_format == FORMAT_PVRTC4A || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1)
230 return 1;
231 else if (p_format == FORMAT_PVRTC2 || p_format == FORMAT_PVRTC2A)
232 return 2;
233 else
234 return 0;
235 }
236
get_format_block_size(Format p_format)237 int Image::get_format_block_size(Format p_format) {
238
239 switch (p_format) {
240 case FORMAT_DXT1: //s3tc bc1
241 case FORMAT_DXT3: //bc2
242 case FORMAT_DXT5: //bc3
243 case FORMAT_RGTC_R: //bc4
244 case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
245
246 return 4;
247 }
248 case FORMAT_PVRTC2:
249 case FORMAT_PVRTC2A: {
250
251 return 4;
252 }
253 case FORMAT_PVRTC4A:
254 case FORMAT_PVRTC4: {
255
256 return 4;
257 }
258 case FORMAT_ETC: {
259
260 return 4;
261 }
262 case FORMAT_BPTC_RGBA:
263 case FORMAT_BPTC_RGBF:
264 case FORMAT_BPTC_RGBFU: {
265
266 return 4;
267 }
268 case FORMAT_ETC2_R11: //etc2
269 case FORMAT_ETC2_R11S: //signed: NOT srgb.
270 case FORMAT_ETC2_RG11:
271 case FORMAT_ETC2_RG11S:
272 case FORMAT_ETC2_RGB8:
273 case FORMAT_ETC2_RGBA8:
274 case FORMAT_ETC2_RGB8A1: {
275
276 return 4;
277 }
278 default: {
279 }
280 }
281
282 return 1;
283 }
284
_get_mipmap_offset_and_size(int p_mipmap,int & r_offset,int & r_width,int & r_height) const285 void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const {
286
287 int w = width;
288 int h = height;
289 int ofs = 0;
290
291 int pixel_size = get_format_pixel_size(format);
292 int pixel_rshift = get_format_pixel_rshift(format);
293 int block = get_format_block_size(format);
294 int minw, minh;
295 get_format_min_pixel_size(format, minw, minh);
296
297 for (int i = 0; i < p_mipmap; i++) {
298 int bw = w % block != 0 ? w + (block - w % block) : w;
299 int bh = h % block != 0 ? h + (block - h % block) : h;
300
301 int s = bw * bh;
302
303 s *= pixel_size;
304 s >>= pixel_rshift;
305 ofs += s;
306 w = MAX(minw, w >> 1);
307 h = MAX(minh, h >> 1);
308 }
309
310 r_offset = ofs;
311 r_width = w;
312 r_height = h;
313 }
314
get_mipmap_offset(int p_mipmap) const315 int Image::get_mipmap_offset(int p_mipmap) const {
316
317 ERR_FAIL_INDEX_V(p_mipmap, get_mipmap_count() + 1, -1);
318
319 int ofs, w, h;
320 _get_mipmap_offset_and_size(p_mipmap, ofs, w, h);
321 return ofs;
322 }
323
get_mipmap_offset_and_size(int p_mipmap,int & r_ofs,int & r_size) const324 void Image::get_mipmap_offset_and_size(int p_mipmap, int &r_ofs, int &r_size) const {
325
326 int ofs, w, h;
327 _get_mipmap_offset_and_size(p_mipmap, ofs, w, h);
328 int ofs2;
329 _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w, h);
330 r_ofs = ofs;
331 r_size = ofs2 - ofs;
332 }
333
get_mipmap_offset_size_and_dimensions(int p_mipmap,int & r_ofs,int & r_size,int & w,int & h) const334 void Image::get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int &r_size, int &w, int &h) const {
335
336 int ofs;
337 _get_mipmap_offset_and_size(p_mipmap, ofs, w, h);
338 int ofs2, w2, h2;
339 _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w2, h2);
340 r_ofs = ofs;
341 r_size = ofs2 - ofs;
342 }
343
get_width() const344 int Image::get_width() const {
345
346 return width;
347 }
348
get_height() const349 int Image::get_height() const {
350
351 return height;
352 }
353
get_size() const354 Vector2 Image::get_size() const {
355
356 return Vector2(width, height);
357 }
358
has_mipmaps() const359 bool Image::has_mipmaps() const {
360
361 return mipmaps;
362 }
363
get_mipmap_count() const364 int Image::get_mipmap_count() const {
365
366 if (mipmaps)
367 return get_image_required_mipmaps(width, height, format);
368 else
369 return 0;
370 }
371
372 //using template generates perfectly optimized code due to constant expression reduction and unused variable removal present in all compilers
373 template <uint32_t read_bytes, bool read_alpha, uint32_t write_bytes, bool write_alpha, bool read_gray, bool write_gray>
_convert(int p_width,int p_height,const uint8_t * p_src,uint8_t * p_dst)374 static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p_dst) {
375
376 uint32_t max_bytes = MAX(read_bytes, write_bytes);
377
378 for (int y = 0; y < p_height; y++) {
379 for (int x = 0; x < p_width; x++) {
380
381 const uint8_t *rofs = &p_src[((y * p_width) + x) * (read_bytes + (read_alpha ? 1 : 0))];
382 uint8_t *wofs = &p_dst[((y * p_width) + x) * (write_bytes + (write_alpha ? 1 : 0))];
383
384 uint8_t rgba[4];
385
386 if (read_gray) {
387 rgba[0] = rofs[0];
388 rgba[1] = rofs[0];
389 rgba[2] = rofs[0];
390 } else {
391
392 for (uint32_t i = 0; i < max_bytes; i++) {
393
394 rgba[i] = (i < read_bytes) ? rofs[i] : 0;
395 }
396 }
397
398 if (read_alpha || write_alpha) {
399 rgba[3] = read_alpha ? rofs[read_bytes] : 255;
400 }
401
402 if (write_gray) {
403 //TODO: not correct grayscale, should use fixed point version of actual weights
404 wofs[0] = uint8_t((uint16_t(rofs[0]) + uint16_t(rofs[1]) + uint16_t(rofs[2])) / 3);
405 } else {
406 for (uint32_t i = 0; i < write_bytes; i++) {
407
408 wofs[i] = rgba[i];
409 }
410 }
411
412 if (write_alpha) {
413 wofs[write_bytes] = rgba[3];
414 }
415 }
416 }
417 }
418
convert(Format p_new_format)419 void Image::convert(Format p_new_format) {
420
421 if (data.size() == 0)
422 return;
423
424 if (p_new_format == format)
425 return;
426
427 ERR_FAIL_COND_MSG(write_lock.ptr(), "Cannot convert image when it is locked.");
428
429 if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) {
430
431 ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
432
433 } else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) {
434
435 //use put/set pixel which is slower but works with non byte formats
436 Image new_img(width, height, 0, p_new_format);
437 lock();
438 new_img.lock();
439
440 for (int i = 0; i < width; i++) {
441 for (int j = 0; j < height; j++) {
442
443 new_img.set_pixel(i, j, get_pixel(i, j));
444 }
445 }
446
447 unlock();
448 new_img.unlock();
449
450 if (has_mipmaps()) {
451 new_img.generate_mipmaps();
452 }
453
454 _copy_internals_from(new_img);
455
456 return;
457 }
458
459 Image new_img(width, height, 0, p_new_format);
460
461 PoolVector<uint8_t>::Read r = data.read();
462 PoolVector<uint8_t>::Write w = new_img.data.write();
463
464 const uint8_t *rptr = r.ptr();
465 uint8_t *wptr = w.ptr();
466
467 int conversion_type = format | p_new_format << 8;
468
469 switch (conversion_type) {
470
471 case FORMAT_L8 | (FORMAT_LA8 << 8): _convert<1, false, 1, true, true, true>(width, height, rptr, wptr); break;
472 case FORMAT_L8 | (FORMAT_R8 << 8): _convert<1, false, 1, false, true, false>(width, height, rptr, wptr); break;
473 case FORMAT_L8 | (FORMAT_RG8 << 8): _convert<1, false, 2, false, true, false>(width, height, rptr, wptr); break;
474 case FORMAT_L8 | (FORMAT_RGB8 << 8): _convert<1, false, 3, false, true, false>(width, height, rptr, wptr); break;
475 case FORMAT_L8 | (FORMAT_RGBA8 << 8): _convert<1, false, 3, true, true, false>(width, height, rptr, wptr); break;
476 case FORMAT_LA8 | (FORMAT_L8 << 8): _convert<1, true, 1, false, true, true>(width, height, rptr, wptr); break;
477 case FORMAT_LA8 | (FORMAT_R8 << 8): _convert<1, true, 1, false, true, false>(width, height, rptr, wptr); break;
478 case FORMAT_LA8 | (FORMAT_RG8 << 8): _convert<1, true, 2, false, true, false>(width, height, rptr, wptr); break;
479 case FORMAT_LA8 | (FORMAT_RGB8 << 8): _convert<1, true, 3, false, true, false>(width, height, rptr, wptr); break;
480 case FORMAT_LA8 | (FORMAT_RGBA8 << 8): _convert<1, true, 3, true, true, false>(width, height, rptr, wptr); break;
481 case FORMAT_R8 | (FORMAT_L8 << 8): _convert<1, false, 1, false, false, true>(width, height, rptr, wptr); break;
482 case FORMAT_R8 | (FORMAT_LA8 << 8): _convert<1, false, 1, true, false, true>(width, height, rptr, wptr); break;
483 case FORMAT_R8 | (FORMAT_RG8 << 8): _convert<1, false, 2, false, false, false>(width, height, rptr, wptr); break;
484 case FORMAT_R8 | (FORMAT_RGB8 << 8): _convert<1, false, 3, false, false, false>(width, height, rptr, wptr); break;
485 case FORMAT_R8 | (FORMAT_RGBA8 << 8): _convert<1, false, 3, true, false, false>(width, height, rptr, wptr); break;
486 case FORMAT_RG8 | (FORMAT_L8 << 8): _convert<2, false, 1, false, false, true>(width, height, rptr, wptr); break;
487 case FORMAT_RG8 | (FORMAT_LA8 << 8): _convert<2, false, 1, true, false, true>(width, height, rptr, wptr); break;
488 case FORMAT_RG8 | (FORMAT_R8 << 8): _convert<2, false, 1, false, false, false>(width, height, rptr, wptr); break;
489 case FORMAT_RG8 | (FORMAT_RGB8 << 8): _convert<2, false, 3, false, false, false>(width, height, rptr, wptr); break;
490 case FORMAT_RG8 | (FORMAT_RGBA8 << 8): _convert<2, false, 3, true, false, false>(width, height, rptr, wptr); break;
491 case FORMAT_RGB8 | (FORMAT_L8 << 8): _convert<3, false, 1, false, false, true>(width, height, rptr, wptr); break;
492 case FORMAT_RGB8 | (FORMAT_LA8 << 8): _convert<3, false, 1, true, false, true>(width, height, rptr, wptr); break;
493 case FORMAT_RGB8 | (FORMAT_R8 << 8): _convert<3, false, 1, false, false, false>(width, height, rptr, wptr); break;
494 case FORMAT_RGB8 | (FORMAT_RG8 << 8): _convert<3, false, 2, false, false, false>(width, height, rptr, wptr); break;
495 case FORMAT_RGB8 | (FORMAT_RGBA8 << 8): _convert<3, false, 3, true, false, false>(width, height, rptr, wptr); break;
496 case FORMAT_RGBA8 | (FORMAT_L8 << 8): _convert<3, true, 1, false, false, true>(width, height, rptr, wptr); break;
497 case FORMAT_RGBA8 | (FORMAT_LA8 << 8): _convert<3, true, 1, true, false, true>(width, height, rptr, wptr); break;
498 case FORMAT_RGBA8 | (FORMAT_R8 << 8): _convert<3, true, 1, false, false, false>(width, height, rptr, wptr); break;
499 case FORMAT_RGBA8 | (FORMAT_RG8 << 8): _convert<3, true, 2, false, false, false>(width, height, rptr, wptr); break;
500 case FORMAT_RGBA8 | (FORMAT_RGB8 << 8): _convert<3, true, 3, false, false, false>(width, height, rptr, wptr); break;
501 }
502
503 r.release();
504 w.release();
505
506 bool gen_mipmaps = mipmaps;
507
508 _copy_internals_from(new_img);
509
510 if (gen_mipmaps)
511 generate_mipmaps();
512 }
513
get_format() const514 Image::Format Image::get_format() const {
515
516 return format;
517 }
518
_bicubic_interp_kernel(double x)519 static double _bicubic_interp_kernel(double x) {
520
521 x = ABS(x);
522
523 double bc = 0;
524
525 if (x <= 1)
526 bc = (1.5 * x - 2.5) * x * x + 1;
527 else if (x < 2)
528 bc = ((-0.5 * x + 2.5) * x - 4) * x + 2;
529
530 return bc;
531 }
532
533 template <int CC, class T>
_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)534 static 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) {
535
536 // get source image size
537 int width = p_src_width;
538 int height = p_src_height;
539 double xfac = (double)width / p_dst_width;
540 double yfac = (double)height / p_dst_height;
541 // coordinates of source points and coefficients
542 double ox, oy, dx, dy, k1, k2;
543 int ox1, oy1, ox2, oy2;
544 // destination pixel values
545 // width and height decreased by 1
546 int ymax = height - 1;
547 int xmax = width - 1;
548 // temporary pointer
549
550 for (uint32_t y = 0; y < p_dst_height; y++) {
551 // Y coordinates
552 oy = (double)y * yfac - 0.5f;
553 oy1 = (int)oy;
554 dy = oy - (double)oy1;
555
556 for (uint32_t x = 0; x < p_dst_width; x++) {
557 // X coordinates
558 ox = (double)x * xfac - 0.5f;
559 ox1 = (int)ox;
560 dx = ox - (double)ox1;
561
562 // initial pixel value
563
564 T *__restrict dst = ((T *)p_dst) + (y * p_dst_width + x) * CC;
565
566 double color[CC];
567 for (int i = 0; i < CC; i++) {
568 color[i] = 0;
569 }
570
571 for (int n = -1; n < 3; n++) {
572 // get Y coefficient
573 k1 = _bicubic_interp_kernel(dy - (double)n);
574
575 oy2 = oy1 + n;
576 if (oy2 < 0)
577 oy2 = 0;
578 if (oy2 > ymax)
579 oy2 = ymax;
580
581 for (int m = -1; m < 3; m++) {
582 // get X coefficient
583 k2 = k1 * _bicubic_interp_kernel((double)m - dx);
584
585 ox2 = ox1 + m;
586 if (ox2 < 0)
587 ox2 = 0;
588 if (ox2 > xmax)
589 ox2 = xmax;
590
591 // get pixel of original image
592 const T *__restrict p = ((T *)p_src) + (oy2 * p_src_width + ox2) * CC;
593
594 for (int i = 0; i < CC; i++) {
595 if (sizeof(T) == 2) { //half float
596 color[i] = Math::half_to_float(p[i]);
597 } else {
598 color[i] += p[i] * k2;
599 }
600 }
601 }
602 }
603
604 for (int i = 0; i < CC; i++) {
605 if (sizeof(T) == 1) { //byte
606 dst[i] = CLAMP(Math::fast_ftoi(color[i]), 0, 255);
607 } else if (sizeof(T) == 2) { //half float
608 dst[i] = Math::make_half_float(color[i]);
609 } else {
610 dst[i] = color[i];
611 }
612 }
613 }
614 }
615 }
616
617 template <int CC, class T>
_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)618 static 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) {
619
620 enum {
621 FRAC_BITS = 8,
622 FRAC_LEN = (1 << FRAC_BITS),
623 FRAC_HALF = (FRAC_LEN >> 1),
624 FRAC_MASK = FRAC_LEN - 1
625 };
626
627 for (uint32_t i = 0; i < p_dst_height; i++) {
628 // Add 0.5 in order to interpolate based on pixel center
629 uint32_t src_yofs_up_fp = (i + 0.5) * p_src_height * FRAC_LEN / p_dst_height;
630 // Calculate nearest src pixel center above current, and truncate to get y index
631 uint32_t src_yofs_up = src_yofs_up_fp >= FRAC_HALF ? (src_yofs_up_fp - FRAC_HALF) >> FRAC_BITS : 0;
632 uint32_t src_yofs_down = (src_yofs_up_fp + FRAC_HALF) >> FRAC_BITS;
633 if (src_yofs_down >= p_src_height) {
634 src_yofs_down = p_src_height - 1;
635 }
636 // Calculate distance to pixel center of src_yofs_up
637 uint32_t src_yofs_frac = src_yofs_up_fp & FRAC_MASK;
638 src_yofs_frac = src_yofs_frac >= FRAC_HALF ? src_yofs_frac - FRAC_HALF : src_yofs_frac + FRAC_HALF;
639
640 uint32_t y_ofs_up = src_yofs_up * p_src_width * CC;
641 uint32_t y_ofs_down = src_yofs_down * p_src_width * CC;
642
643 for (uint32_t j = 0; j < p_dst_width; j++) {
644 uint32_t src_xofs_left_fp = (j + 0.5) * p_src_width * FRAC_LEN / p_dst_width;
645 uint32_t src_xofs_left = src_xofs_left_fp >= FRAC_HALF ? (src_xofs_left_fp - FRAC_HALF) >> FRAC_BITS : 0;
646 uint32_t src_xofs_right = (src_xofs_left_fp + FRAC_HALF) >> FRAC_BITS;
647 if (src_xofs_right >= p_src_width) {
648 src_xofs_right = p_src_width - 1;
649 }
650 uint32_t src_xofs_frac = src_xofs_left_fp & FRAC_MASK;
651 src_xofs_frac = src_xofs_frac >= FRAC_HALF ? src_xofs_frac - FRAC_HALF : src_xofs_frac + FRAC_HALF;
652
653 src_xofs_left *= CC;
654 src_xofs_right *= CC;
655
656 for (uint32_t l = 0; l < CC; l++) {
657
658 if (sizeof(T) == 1) { //uint8
659 uint32_t p00 = p_src[y_ofs_up + src_xofs_left + l] << FRAC_BITS;
660 uint32_t p10 = p_src[y_ofs_up + src_xofs_right + l] << FRAC_BITS;
661 uint32_t p01 = p_src[y_ofs_down + src_xofs_left + l] << FRAC_BITS;
662 uint32_t p11 = p_src[y_ofs_down + src_xofs_right + l] << FRAC_BITS;
663
664 uint32_t interp_up = p00 + (((p10 - p00) * src_xofs_frac) >> FRAC_BITS);
665 uint32_t interp_down = p01 + (((p11 - p01) * src_xofs_frac) >> FRAC_BITS);
666 uint32_t interp = interp_up + (((interp_down - interp_up) * src_yofs_frac) >> FRAC_BITS);
667 interp >>= FRAC_BITS;
668 p_dst[i * p_dst_width * CC + j * CC + l] = interp;
669 } else if (sizeof(T) == 2) { //half float
670
671 float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS);
672 float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS);
673 const T *src = ((const T *)p_src);
674 T *dst = ((T *)p_dst);
675
676 float p00 = Math::half_to_float(src[y_ofs_up + src_xofs_left + l]);
677 float p10 = Math::half_to_float(src[y_ofs_up + src_xofs_right + l]);
678 float p01 = Math::half_to_float(src[y_ofs_down + src_xofs_left + l]);
679 float p11 = Math::half_to_float(src[y_ofs_down + src_xofs_right + l]);
680
681 float interp_up = p00 + (p10 - p00) * xofs_frac;
682 float interp_down = p01 + (p11 - p01) * xofs_frac;
683 float interp = interp_up + ((interp_down - interp_up) * yofs_frac);
684
685 dst[i * p_dst_width * CC + j * CC + l] = Math::make_half_float(interp);
686 } else if (sizeof(T) == 4) { //float
687
688 float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS);
689 float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS);
690 const T *src = ((const T *)p_src);
691 T *dst = ((T *)p_dst);
692
693 float p00 = src[y_ofs_up + src_xofs_left + l];
694 float p10 = src[y_ofs_up + src_xofs_right + l];
695 float p01 = src[y_ofs_down + src_xofs_left + l];
696 float p11 = src[y_ofs_down + src_xofs_right + l];
697
698 float interp_up = p00 + (p10 - p00) * xofs_frac;
699 float interp_down = p01 + (p11 - p01) * xofs_frac;
700 float interp = interp_up + ((interp_down - interp_up) * yofs_frac);
701
702 dst[i * p_dst_width * CC + j * CC + l] = interp;
703 }
704 }
705 }
706 }
707 }
708
709 template <int CC, class T>
_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)710 static 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) {
711
712 for (uint32_t i = 0; i < p_dst_height; i++) {
713
714 uint32_t src_yofs = i * p_src_height / p_dst_height;
715 uint32_t y_ofs = src_yofs * p_src_width * CC;
716
717 for (uint32_t j = 0; j < p_dst_width; j++) {
718
719 uint32_t src_xofs = j * p_src_width / p_dst_width;
720 src_xofs *= CC;
721
722 for (uint32_t l = 0; l < CC; l++) {
723
724 const T *src = ((const T *)p_src);
725 T *dst = ((T *)p_dst);
726
727 T p = src[y_ofs + src_xofs + l];
728 dst[i * p_dst_width * CC + j * CC + l] = p;
729 }
730 }
731 }
732 }
733
734 #define LANCZOS_TYPE 3
735
_lanczos(float p_x)736 static float _lanczos(float p_x) {
737 return Math::abs(p_x) >= LANCZOS_TYPE ? 0 : Math::sincn(p_x) * Math::sincn(p_x / LANCZOS_TYPE);
738 }
739
740 template <int CC, class T>
_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)741 static 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) {
742
743 int32_t src_width = p_src_width;
744 int32_t src_height = p_src_height;
745 int32_t dst_height = p_dst_height;
746 int32_t dst_width = p_dst_width;
747
748 uint32_t buffer_size = src_height * dst_width * CC;
749 float *buffer = memnew_arr(float, buffer_size); // Store the first pass in a buffer
750
751 { // FIRST PASS (horizontal)
752
753 float x_scale = float(src_width) / float(dst_width);
754
755 float scale_factor = MAX(x_scale, 1); // A larger kernel is required only when downscaling
756 int32_t half_kernel = LANCZOS_TYPE * scale_factor;
757
758 float *kernel = memnew_arr(float, half_kernel * 2);
759
760 for (int32_t buffer_x = 0; buffer_x < dst_width; buffer_x++) {
761
762 // The corresponding point on the source image
763 float src_x = (buffer_x + 0.5f) * x_scale; // Offset by 0.5 so it uses the pixel's center
764 int32_t start_x = MAX(0, int32_t(src_x) - half_kernel + 1);
765 int32_t end_x = MIN(src_width - 1, int32_t(src_x) + half_kernel);
766
767 // Create the kernel used by all the pixels of the column
768 for (int32_t target_x = start_x; target_x <= end_x; target_x++)
769 kernel[target_x - start_x] = _lanczos((target_x + 0.5f - src_x) / scale_factor);
770
771 for (int32_t buffer_y = 0; buffer_y < src_height; buffer_y++) {
772
773 float pixel[CC] = { 0 };
774 float weight = 0;
775
776 for (int32_t target_x = start_x; target_x <= end_x; target_x++) {
777
778 float lanczos_val = kernel[target_x - start_x];
779 weight += lanczos_val;
780
781 const T *__restrict src_data = ((const T *)p_src) + (buffer_y * src_width + target_x) * CC;
782
783 for (uint32_t i = 0; i < CC; i++) {
784 if (sizeof(T) == 2) //half float
785 pixel[i] += Math::half_to_float(src_data[i]) * lanczos_val;
786 else
787 pixel[i] += src_data[i] * lanczos_val;
788 }
789 }
790
791 float *dst_data = ((float *)buffer) + (buffer_y * dst_width + buffer_x) * CC;
792
793 for (uint32_t i = 0; i < CC; i++)
794 dst_data[i] = pixel[i] / weight; // Normalize the sum of all the samples
795 }
796 }
797
798 memdelete_arr(kernel);
799 } // End of first pass
800
801 { // SECOND PASS (vertical + result)
802
803 float y_scale = float(src_height) / float(dst_height);
804
805 float scale_factor = MAX(y_scale, 1);
806 int32_t half_kernel = LANCZOS_TYPE * scale_factor;
807
808 float *kernel = memnew_arr(float, half_kernel * 2);
809
810 for (int32_t dst_y = 0; dst_y < dst_height; dst_y++) {
811
812 float buffer_y = (dst_y + 0.5f) * y_scale;
813 int32_t start_y = MAX(0, int32_t(buffer_y) - half_kernel + 1);
814 int32_t end_y = MIN(src_height - 1, int32_t(buffer_y) + half_kernel);
815
816 for (int32_t target_y = start_y; target_y <= end_y; target_y++)
817 kernel[target_y - start_y] = _lanczos((target_y + 0.5f - buffer_y) / scale_factor);
818
819 for (int32_t dst_x = 0; dst_x < dst_width; dst_x++) {
820
821 float pixel[CC] = { 0 };
822 float weight = 0;
823
824 for (int32_t target_y = start_y; target_y <= end_y; target_y++) {
825
826 float lanczos_val = kernel[target_y - start_y];
827 weight += lanczos_val;
828
829 float *buffer_data = ((float *)buffer) + (target_y * dst_width + dst_x) * CC;
830
831 for (uint32_t i = 0; i < CC; i++)
832 pixel[i] += buffer_data[i] * lanczos_val;
833 }
834
835 T *dst_data = ((T *)p_dst) + (dst_y * dst_width + dst_x) * CC;
836
837 for (uint32_t i = 0; i < CC; i++) {
838 pixel[i] /= weight;
839
840 if (sizeof(T) == 1) //byte
841 dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 255);
842 else if (sizeof(T) == 2) //half float
843 dst_data[i] = Math::make_half_float(pixel[i]);
844 else // float
845 dst_data[i] = pixel[i];
846 }
847 }
848 }
849
850 memdelete_arr(kernel);
851 } // End of second pass
852
853 memdelete_arr(buffer);
854 }
855
_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)856 static 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) {
857
858 uint16_t alpha = MIN((uint16_t)(p_alpha * 256.0f), 256);
859
860 for (uint32_t i = 0; i < p_width * p_height * p_pixel_size; i++) {
861
862 p_dst[i] = (p_dst[i] * (256 - alpha) + p_src[i] * alpha) >> 8;
863 }
864 }
865
is_size_po2() const866 bool Image::is_size_po2() const {
867 return uint32_t(width) == next_power_of_2(width) && uint32_t(height) == next_power_of_2(height);
868 }
869
resize_to_po2(bool p_square)870 void Image::resize_to_po2(bool p_square) {
871
872 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
873
874 int w = next_power_of_2(width);
875 int h = next_power_of_2(height);
876 if (p_square) {
877 w = h = MAX(w, h);
878 }
879
880 if (w == width && h == height) {
881
882 if (!p_square || w == h)
883 return; //nothing to do
884 }
885
886 resize(w, h);
887 }
888
resize(int p_width,int p_height,Interpolation p_interpolation)889 void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
890
891 ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use create() or create_from_data() first.");
892 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
893 ERR_FAIL_COND_MSG(write_lock.ptr(), "Cannot resize image when it is locked.");
894
895 bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
896
897 ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0.");
898 ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
899 ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + ".");
900 ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + ".");
901
902 if (p_width == width && p_height == height)
903 return;
904
905 Image dst(p_width, p_height, 0, format);
906
907 // Setup mipmap-aware scaling
908 Image dst2;
909 int mip1 = 0;
910 int mip2 = 0;
911 float mip1_weight = 0;
912 if (mipmap_aware) {
913 float avg_scale = ((float)p_width / width + (float)p_height / height) * 0.5f;
914 if (avg_scale >= 1.0f) {
915 mipmap_aware = false;
916 } else {
917 float level = Math::log(1.0f / avg_scale) / Math::log(2.0f);
918 mip1 = CLAMP((int)Math::floor(level), 0, get_mipmap_count());
919 mip2 = CLAMP((int)Math::ceil(level), 0, get_mipmap_count());
920 mip1_weight = 1.0f - (level - mip1);
921 }
922 }
923 bool interpolate_mipmaps = mipmap_aware && mip1 != mip2;
924 if (interpolate_mipmaps) {
925 dst2.create(p_width, p_height, 0, format);
926 }
927
928 bool had_mipmaps = mipmaps;
929 if (interpolate_mipmaps && !had_mipmaps) {
930 generate_mipmaps();
931 }
932 // --
933
934 PoolVector<uint8_t>::Read r = data.read();
935 const unsigned char *r_ptr = r.ptr();
936
937 PoolVector<uint8_t>::Write w = dst.data.write();
938 unsigned char *w_ptr = w.ptr();
939
940 switch (p_interpolation) {
941
942 case INTERPOLATE_NEAREST: {
943
944 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
945 switch (get_format_pixel_size(format)) {
946 case 1: _scale_nearest<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
947 case 2: _scale_nearest<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
948 case 3: _scale_nearest<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
949 case 4: _scale_nearest<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
950 }
951 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
952 switch (get_format_pixel_size(format)) {
953 case 4: _scale_nearest<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
954 case 8: _scale_nearest<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
955 case 12: _scale_nearest<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
956 case 16: _scale_nearest<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
957 }
958
959 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
960 switch (get_format_pixel_size(format)) {
961 case 2: _scale_nearest<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
962 case 4: _scale_nearest<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
963 case 6: _scale_nearest<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
964 case 8: _scale_nearest<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
965 }
966 }
967
968 } break;
969 case INTERPOLATE_BILINEAR:
970 case INTERPOLATE_TRILINEAR: {
971
972 for (int i = 0; i < 2; ++i) {
973 int src_width;
974 int src_height;
975 const unsigned char *src_ptr;
976
977 if (!mipmap_aware) {
978 if (i == 0) {
979 // Standard behavior
980 src_width = width;
981 src_height = height;
982 src_ptr = r_ptr;
983 } else {
984 // No need for a second iteration
985 break;
986 }
987 } else {
988 if (i == 0) {
989 // Read from the first mipmap that will be interpolated
990 // (if both levels are the same, we will not interpolate, but at least we'll sample from the right level)
991 int offs;
992 _get_mipmap_offset_and_size(mip1, offs, src_width, src_height);
993 src_ptr = r_ptr + offs;
994 } else if (!interpolate_mipmaps) {
995 // No need generate a second image
996 break;
997 } else {
998 // Switch to read from the second mipmap that will be interpolated
999 int offs;
1000 _get_mipmap_offset_and_size(mip2, offs, src_width, src_height);
1001 src_ptr = r_ptr + offs;
1002 // Switch to write to the second destination image
1003 w = dst2.data.write();
1004 w_ptr = w.ptr();
1005 }
1006 }
1007
1008 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
1009 switch (get_format_pixel_size(format)) {
1010 case 1: _scale_bilinear<1, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1011 case 2: _scale_bilinear<2, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1012 case 3: _scale_bilinear<3, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1013 case 4: _scale_bilinear<4, uint8_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1014 }
1015 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
1016 switch (get_format_pixel_size(format)) {
1017 case 4: _scale_bilinear<1, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1018 case 8: _scale_bilinear<2, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1019 case 12: _scale_bilinear<3, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1020 case 16: _scale_bilinear<4, float>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1021 }
1022 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
1023 switch (get_format_pixel_size(format)) {
1024 case 2: _scale_bilinear<1, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1025 case 4: _scale_bilinear<2, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1026 case 6: _scale_bilinear<3, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1027 case 8: _scale_bilinear<4, uint16_t>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
1028 }
1029 }
1030 }
1031
1032 if (interpolate_mipmaps) {
1033 // Switch to read again from the first scaled mipmap to overlay it over the second
1034 r = dst.data.read();
1035 _overlay(r.ptr(), w.ptr(), mip1_weight, p_width, p_height, get_format_pixel_size(format));
1036 }
1037
1038 } break;
1039 case INTERPOLATE_CUBIC: {
1040
1041 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
1042 switch (get_format_pixel_size(format)) {
1043 case 1: _scale_cubic<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1044 case 2: _scale_cubic<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1045 case 3: _scale_cubic<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1046 case 4: _scale_cubic<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1047 }
1048 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
1049 switch (get_format_pixel_size(format)) {
1050 case 4: _scale_cubic<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1051 case 8: _scale_cubic<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1052 case 12: _scale_cubic<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1053 case 16: _scale_cubic<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1054 }
1055 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
1056 switch (get_format_pixel_size(format)) {
1057 case 2: _scale_cubic<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1058 case 4: _scale_cubic<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1059 case 6: _scale_cubic<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1060 case 8: _scale_cubic<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1061 }
1062 }
1063 } break;
1064 case INTERPOLATE_LANCZOS: {
1065
1066 if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
1067 switch (get_format_pixel_size(format)) {
1068 case 1: _scale_lanczos<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1069 case 2: _scale_lanczos<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1070 case 3: _scale_lanczos<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1071 case 4: _scale_lanczos<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1072 }
1073 } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
1074 switch (get_format_pixel_size(format)) {
1075 case 4: _scale_lanczos<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1076 case 8: _scale_lanczos<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1077 case 12: _scale_lanczos<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1078 case 16: _scale_lanczos<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1079 }
1080 } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
1081 switch (get_format_pixel_size(format)) {
1082 case 2: _scale_lanczos<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1083 case 4: _scale_lanczos<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1084 case 6: _scale_lanczos<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1085 case 8: _scale_lanczos<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
1086 }
1087 }
1088 } break;
1089 }
1090
1091 r.release();
1092 w.release();
1093
1094 if (interpolate_mipmaps) {
1095 dst._copy_internals_from(dst2);
1096 }
1097
1098 if (had_mipmaps)
1099 dst.generate_mipmaps();
1100
1101 _copy_internals_from(dst);
1102 }
1103
crop_from_point(int p_x,int p_y,int p_width,int p_height)1104 void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) {
1105
1106 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot crop in compressed or custom image formats.");
1107
1108 ERR_FAIL_COND_MSG(p_x < 0, "Start x position cannot be smaller than 0.");
1109 ERR_FAIL_COND_MSG(p_y < 0, "Start y position cannot be smaller than 0.");
1110 ERR_FAIL_COND_MSG(p_width <= 0, "Width of image must be greater than 0.");
1111 ERR_FAIL_COND_MSG(p_height <= 0, "Height of image must be greater than 0.");
1112 ERR_FAIL_COND_MSG(p_x + p_width > MAX_WIDTH, "End x position cannot be greater than " + itos(MAX_WIDTH) + ".");
1113 ERR_FAIL_COND_MSG(p_y + p_height > MAX_HEIGHT, "End y position cannot be greater than " + itos(MAX_HEIGHT) + ".");
1114
1115 /* to save memory, cropping should be done in-place, however, since this function
1116 will most likely either not be used much, or in critical areas, for now it won't, because
1117 it's a waste of time. */
1118
1119 if (p_width == width && p_height == height && p_x == 0 && p_y == 0)
1120 return;
1121
1122 uint8_t pdata[16]; //largest is 16
1123 uint32_t pixel_size = get_format_pixel_size(format);
1124
1125 Image dst(p_width, p_height, 0, format);
1126
1127 {
1128 PoolVector<uint8_t>::Read r = data.read();
1129 PoolVector<uint8_t>::Write w = dst.data.write();
1130
1131 int m_h = p_y + p_height;
1132 int m_w = p_x + p_width;
1133 for (int y = p_y; y < m_h; y++) {
1134
1135 for (int x = p_x; x < m_w; x++) {
1136
1137 if ((x >= width || y >= height)) {
1138 for (uint32_t i = 0; i < pixel_size; i++)
1139 pdata[i] = 0;
1140 } else {
1141 _get_pixelb(x, y, pixel_size, r.ptr(), pdata);
1142 }
1143
1144 dst._put_pixelb(x - p_x, y - p_y, pixel_size, w.ptr(), pdata);
1145 }
1146 }
1147 }
1148
1149 if (has_mipmaps())
1150 dst.generate_mipmaps();
1151 _copy_internals_from(dst);
1152 }
1153
crop(int p_width,int p_height)1154 void Image::crop(int p_width, int p_height) {
1155
1156 crop_from_point(0, 0, p_width, p_height);
1157 }
1158
flip_y()1159 void Image::flip_y() {
1160
1161 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats.");
1162
1163 bool used_mipmaps = has_mipmaps();
1164 if (used_mipmaps) {
1165 clear_mipmaps();
1166 }
1167
1168 {
1169 PoolVector<uint8_t>::Write w = data.write();
1170 uint8_t up[16];
1171 uint8_t down[16];
1172 uint32_t pixel_size = get_format_pixel_size(format);
1173
1174 for (int y = 0; y < height / 2; y++) {
1175
1176 for (int x = 0; x < width; x++) {
1177
1178 _get_pixelb(x, y, pixel_size, w.ptr(), up);
1179 _get_pixelb(x, height - y - 1, pixel_size, w.ptr(), down);
1180
1181 _put_pixelb(x, height - y - 1, pixel_size, w.ptr(), up);
1182 _put_pixelb(x, y, pixel_size, w.ptr(), down);
1183 }
1184 }
1185 }
1186
1187 if (used_mipmaps) {
1188 generate_mipmaps();
1189 }
1190 }
1191
flip_x()1192 void Image::flip_x() {
1193
1194 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_x in compressed or custom image formats.");
1195
1196 bool used_mipmaps = has_mipmaps();
1197 if (used_mipmaps) {
1198 clear_mipmaps();
1199 }
1200
1201 {
1202 PoolVector<uint8_t>::Write w = data.write();
1203 uint8_t up[16];
1204 uint8_t down[16];
1205 uint32_t pixel_size = get_format_pixel_size(format);
1206
1207 for (int y = 0; y < height; y++) {
1208
1209 for (int x = 0; x < width / 2; x++) {
1210
1211 _get_pixelb(x, y, pixel_size, w.ptr(), up);
1212 _get_pixelb(width - x - 1, y, pixel_size, w.ptr(), down);
1213
1214 _put_pixelb(width - x - 1, y, pixel_size, w.ptr(), up);
1215 _put_pixelb(x, y, pixel_size, w.ptr(), down);
1216 }
1217 }
1218 }
1219
1220 if (used_mipmaps) {
1221 generate_mipmaps();
1222 }
1223 }
1224
_get_dst_image_size(int p_width,int p_height,Format p_format,int & r_mipmaps,int p_mipmaps)1225 int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps) {
1226
1227 int size = 0;
1228 int w = p_width;
1229 int h = p_height;
1230 int mm = 0;
1231
1232 int pixsize = get_format_pixel_size(p_format);
1233 int pixshift = get_format_pixel_rshift(p_format);
1234 int block = get_format_block_size(p_format);
1235 //technically, you can still compress up to 1 px no matter the format, so commenting this
1236 //int minw, minh;
1237 //get_format_min_pixel_size(p_format, minw, minh);
1238 int minw = 1, minh = 1;
1239
1240 while (true) {
1241
1242 int bw = w % block != 0 ? w + (block - w % block) : w;
1243 int bh = h % block != 0 ? h + (block - h % block) : h;
1244
1245 int s = bw * bh;
1246
1247 s *= pixsize;
1248 s >>= pixshift;
1249
1250 size += s;
1251
1252 if (p_mipmaps >= 0 && mm == p_mipmaps)
1253 break;
1254
1255 if (p_mipmaps >= 0) {
1256
1257 w = MAX(minw, w >> 1);
1258 h = MAX(minh, h >> 1);
1259 } else {
1260 if (w == minw && h == minh)
1261 break;
1262 w = MAX(minw, w >> 1);
1263 h = MAX(minh, h >> 1);
1264 }
1265 mm++;
1266 };
1267
1268 r_mipmaps = mm;
1269 return size;
1270 }
1271
_can_modify(Format p_format) const1272 bool Image::_can_modify(Format p_format) const {
1273
1274 return p_format <= FORMAT_RGBE9995;
1275 }
1276
1277 template <class Component, int CC, bool renormalize,
1278 void (*average_func)(Component &, const Component &, const Component &, const Component &, const Component &),
1279 void (*renormalize_func)(Component *)>
_generate_po2_mipmap(const Component * p_src,Component * p_dst,uint32_t p_width,uint32_t p_height)1280 static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint32_t p_width, uint32_t p_height) {
1281
1282 //fast power of 2 mipmap generation
1283 uint32_t dst_w = MAX(p_width >> 1, 1);
1284 uint32_t dst_h = MAX(p_height >> 1, 1);
1285
1286 int right_step = (p_width == 1) ? 0 : CC;
1287 int down_step = (p_height == 1) ? 0 : (p_width * CC);
1288
1289 for (uint32_t i = 0; i < dst_h; i++) {
1290
1291 const Component *rup_ptr = &p_src[i * 2 * down_step];
1292 const Component *rdown_ptr = rup_ptr + down_step;
1293 Component *dst_ptr = &p_dst[i * dst_w * CC];
1294 uint32_t count = dst_w;
1295
1296 while (count) {
1297 count--;
1298 for (int j = 0; j < CC; j++) {
1299 average_func(dst_ptr[j], rup_ptr[j], rup_ptr[j + right_step], rdown_ptr[j], rdown_ptr[j + right_step]);
1300 }
1301
1302 if (renormalize) {
1303 renormalize_func(dst_ptr);
1304 }
1305
1306 dst_ptr += CC;
1307 rup_ptr += right_step * 2;
1308 rdown_ptr += right_step * 2;
1309 }
1310 }
1311 }
1312
expand_x2_hq2x()1313 void Image::expand_x2_hq2x() {
1314
1315 ERR_FAIL_COND(!_can_modify(format));
1316
1317 bool used_mipmaps = has_mipmaps();
1318 if (used_mipmaps) {
1319 clear_mipmaps();
1320 }
1321
1322 Format current = format;
1323
1324 if (current != FORMAT_RGBA8)
1325 convert(FORMAT_RGBA8);
1326
1327 PoolVector<uint8_t> dest;
1328 dest.resize(width * 2 * height * 2 * 4);
1329
1330 {
1331 PoolVector<uint8_t>::Read r = data.read();
1332 PoolVector<uint8_t>::Write w = dest.write();
1333
1334 ERR_FAIL_COND(!r.ptr());
1335
1336 hq2x_resize((const uint32_t *)r.ptr(), width, height, (uint32_t *)w.ptr());
1337 }
1338
1339 width *= 2;
1340 height *= 2;
1341 data = dest;
1342
1343 if (current != FORMAT_RGBA8)
1344 convert(current);
1345
1346 // FIXME: This is likely meant to use "used_mipmaps" as defined above, but if we do,
1347 // we end up with a regression: GH-22747
1348 if (mipmaps) {
1349 generate_mipmaps();
1350 }
1351 }
1352
shrink_x2()1353 void Image::shrink_x2() {
1354
1355 ERR_FAIL_COND(data.size() == 0);
1356
1357 if (mipmaps) {
1358
1359 //just use the lower mipmap as base and copy all
1360 PoolVector<uint8_t> new_img;
1361
1362 int ofs = get_mipmap_offset(1);
1363
1364 int new_size = data.size() - ofs;
1365 new_img.resize(new_size);
1366 ERR_FAIL_COND(new_img.size() == 0);
1367
1368 {
1369 PoolVector<uint8_t>::Write w = new_img.write();
1370 PoolVector<uint8_t>::Read r = data.read();
1371
1372 copymem(w.ptr(), &r[ofs], new_size);
1373 }
1374
1375 width = MAX(width / 2, 1);
1376 height = MAX(height / 2, 1);
1377 data = new_img;
1378
1379 } else {
1380
1381 PoolVector<uint8_t> new_img;
1382
1383 ERR_FAIL_COND(!_can_modify(format));
1384 int ps = get_format_pixel_size(format);
1385 new_img.resize((width / 2) * (height / 2) * ps);
1386 ERR_FAIL_COND(new_img.size() == 0);
1387 ERR_FAIL_COND(data.size() == 0);
1388
1389 {
1390 PoolVector<uint8_t>::Write w = new_img.write();
1391 PoolVector<uint8_t>::Read r = data.read();
1392
1393 switch (format) {
1394
1395 case FORMAT_L8:
1396 case FORMAT_R8: _generate_po2_mipmap<uint8_t, 1, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
1397 case FORMAT_LA8: _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
1398 case FORMAT_RG8: _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
1399 case FORMAT_RGB8: _generate_po2_mipmap<uint8_t, 3, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
1400 case FORMAT_RGBA8: _generate_po2_mipmap<uint8_t, 4, false, Image::average_4_uint8, Image::renormalize_uint8>(r.ptr(), w.ptr(), width, height); break;
1401
1402 case FORMAT_RF: _generate_po2_mipmap<float, 1, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
1403 case FORMAT_RGF: _generate_po2_mipmap<float, 2, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
1404 case FORMAT_RGBF: _generate_po2_mipmap<float, 3, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
1405 case FORMAT_RGBAF: _generate_po2_mipmap<float, 4, false, Image::average_4_float, Image::renormalize_float>(reinterpret_cast<const float *>(r.ptr()), reinterpret_cast<float *>(w.ptr()), width, height); break;
1406
1407 case FORMAT_RH: _generate_po2_mipmap<uint16_t, 1, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
1408 case FORMAT_RGH: _generate_po2_mipmap<uint16_t, 2, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
1409 case FORMAT_RGBH: _generate_po2_mipmap<uint16_t, 3, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
1410 case FORMAT_RGBAH: _generate_po2_mipmap<uint16_t, 4, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
1411
1412 case FORMAT_RGBE9995: _generate_po2_mipmap<uint32_t, 1, false, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(r.ptr()), reinterpret_cast<uint32_t *>(w.ptr()), width, height); break;
1413 default: {
1414 }
1415 }
1416 }
1417
1418 width /= 2;
1419 height /= 2;
1420 data = new_img;
1421 }
1422 }
1423
normalize()1424 void Image::normalize() {
1425
1426 bool used_mipmaps = has_mipmaps();
1427 if (used_mipmaps) {
1428 clear_mipmaps();
1429 }
1430
1431 lock();
1432
1433 for (int y = 0; y < height; y++) {
1434
1435 for (int x = 0; x < width; x++) {
1436
1437 Color c = get_pixel(x, y);
1438 Vector3 v(c.r * 2.0 - 1.0, c.g * 2.0 - 1.0, c.b * 2.0 - 1.0);
1439 v.normalize();
1440 c.r = v.x * 0.5 + 0.5;
1441 c.g = v.y * 0.5 + 0.5;
1442 c.b = v.z * 0.5 + 0.5;
1443 set_pixel(x, y, c);
1444 }
1445 }
1446
1447 unlock();
1448
1449 if (used_mipmaps) {
1450 generate_mipmaps(true);
1451 }
1452 }
1453
generate_mipmaps(bool p_renormalize)1454 Error Image::generate_mipmaps(bool p_renormalize) {
1455
1456 ERR_FAIL_COND_V_MSG(!_can_modify(format), ERR_UNAVAILABLE, "Cannot generate mipmaps in compressed or custom image formats.");
1457
1458 ERR_FAIL_COND_V_MSG(format == FORMAT_RGBA4444 || format == FORMAT_RGBA5551, ERR_UNAVAILABLE, "Cannot generate mipmaps in custom image formats.");
1459
1460 ERR_FAIL_COND_V_MSG(width == 0 || height == 0, ERR_UNCONFIGURED, "Cannot generate mipmaps with width or height equal to 0.");
1461
1462 int mmcount;
1463
1464 int size = _get_dst_image_size(width, height, format, mmcount);
1465
1466 data.resize(size);
1467
1468 PoolVector<uint8_t>::Write wp = data.write();
1469
1470 int prev_ofs = 0;
1471 int prev_h = height;
1472 int prev_w = width;
1473
1474 for (int i = 1; i <= mmcount; i++) {
1475
1476 int ofs, w, h;
1477 _get_mipmap_offset_and_size(i, ofs, w, h);
1478
1479 switch (format) {
1480
1481 case FORMAT_L8:
1482 case FORMAT_R8: _generate_po2_mipmap<uint8_t, 1, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
1483 case FORMAT_LA8:
1484 case FORMAT_RG8: _generate_po2_mipmap<uint8_t, 2, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
1485 case FORMAT_RGB8:
1486 if (p_renormalize)
1487 _generate_po2_mipmap<uint8_t, 3, true, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1488 else
1489 _generate_po2_mipmap<uint8_t, 3, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1490
1491 break;
1492 case FORMAT_RGBA8:
1493 if (p_renormalize)
1494 _generate_po2_mipmap<uint8_t, 4, true, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1495 else
1496 _generate_po2_mipmap<uint8_t, 4, false, Image::average_4_uint8, Image::renormalize_uint8>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
1497 break;
1498 case FORMAT_RF:
1499 _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);
1500 break;
1501 case FORMAT_RGF:
1502 _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);
1503 break;
1504 case FORMAT_RGBF:
1505 if (p_renormalize)
1506 _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);
1507 else
1508 _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);
1509
1510 break;
1511 case FORMAT_RGBAF:
1512 if (p_renormalize)
1513 _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);
1514 else
1515 _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);
1516
1517 break;
1518 case FORMAT_RH:
1519 _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);
1520 break;
1521 case FORMAT_RGH:
1522 _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);
1523 break;
1524 case FORMAT_RGBH:
1525 if (p_renormalize)
1526 _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);
1527 else
1528 _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);
1529
1530 break;
1531 case FORMAT_RGBAH:
1532 if (p_renormalize)
1533 _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);
1534 else
1535 _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);
1536
1537 break;
1538 case FORMAT_RGBE9995:
1539 if (p_renormalize)
1540 _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);
1541 else
1542 _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);
1543
1544 break;
1545 default: {
1546 }
1547 }
1548
1549 prev_ofs = ofs;
1550 prev_w = w;
1551 prev_h = h;
1552 }
1553
1554 mipmaps = true;
1555
1556 return OK;
1557 }
1558
clear_mipmaps()1559 void Image::clear_mipmaps() {
1560
1561 if (!mipmaps)
1562 return;
1563
1564 if (empty())
1565 return;
1566
1567 int ofs, w, h;
1568 _get_mipmap_offset_and_size(1, ofs, w, h);
1569 data.resize(ofs);
1570
1571 mipmaps = false;
1572 }
1573
empty() const1574 bool Image::empty() const {
1575
1576 return (data.size() == 0);
1577 }
1578
get_data() const1579 PoolVector<uint8_t> Image::get_data() const {
1580
1581 return data;
1582 }
1583
create(int p_width,int p_height,bool p_use_mipmaps,Format p_format)1584 void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
1585 ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0.");
1586 ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
1587 ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + ".");
1588 ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + ".");
1589 ERR_FAIL_COND_MSG(write_lock.ptr(), "Cannot create image when it is locked.");
1590
1591 int mm = 0;
1592 int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
1593 data.resize(size);
1594 {
1595 PoolVector<uint8_t>::Write w = data.write();
1596 zeromem(w.ptr(), size);
1597 }
1598
1599 width = p_width;
1600 height = p_height;
1601 mipmaps = p_use_mipmaps;
1602 format = p_format;
1603 }
1604
create(int p_width,int p_height,bool p_use_mipmaps,Format p_format,const PoolVector<uint8_t> & p_data)1605 void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const PoolVector<uint8_t> &p_data) {
1606 ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0.");
1607 ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
1608 ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + ".");
1609 ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + ".");
1610
1611 int mm;
1612 int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
1613
1614 ERR_FAIL_COND_MSG(p_data.size() != size, "Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes.");
1615
1616 height = p_height;
1617 width = p_width;
1618 format = p_format;
1619 data = p_data;
1620 mipmaps = p_use_mipmaps;
1621 }
1622
create(const char ** p_xpm)1623 void Image::create(const char **p_xpm) {
1624
1625 int size_width = 0;
1626 int size_height = 0;
1627 int pixelchars = 0;
1628 mipmaps = false;
1629 bool has_alpha = false;
1630
1631 enum Status {
1632 READING_HEADER,
1633 READING_COLORS,
1634 READING_PIXELS,
1635 DONE
1636 };
1637
1638 Status status = READING_HEADER;
1639 int line = 0;
1640
1641 HashMap<String, Color> colormap;
1642 int colormap_size = 0;
1643 uint32_t pixel_size = 0;
1644 PoolVector<uint8_t>::Write w;
1645
1646 while (status != DONE) {
1647
1648 const char *line_ptr = p_xpm[line];
1649
1650 switch (status) {
1651
1652 case READING_HEADER: {
1653
1654 String line_str = line_ptr;
1655 line_str.replace("\t", " ");
1656
1657 size_width = line_str.get_slicec(' ', 0).to_int();
1658 size_height = line_str.get_slicec(' ', 1).to_int();
1659 colormap_size = line_str.get_slicec(' ', 2).to_int();
1660 pixelchars = line_str.get_slicec(' ', 3).to_int();
1661 ERR_FAIL_COND(colormap_size > 32766);
1662 ERR_FAIL_COND(pixelchars > 5);
1663 ERR_FAIL_COND(size_width > 32767);
1664 ERR_FAIL_COND(size_height > 32767);
1665 status = READING_COLORS;
1666 } break;
1667 case READING_COLORS: {
1668
1669 String colorstring;
1670 for (int i = 0; i < pixelchars; i++) {
1671
1672 colorstring += *line_ptr;
1673 line_ptr++;
1674 }
1675 //skip spaces
1676 while (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == 0) {
1677 if (*line_ptr == 0)
1678 break;
1679 line_ptr++;
1680 }
1681 if (*line_ptr == 'c') {
1682
1683 line_ptr++;
1684 while (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == 0) {
1685 if (*line_ptr == 0)
1686 break;
1687 line_ptr++;
1688 }
1689
1690 if (*line_ptr == '#') {
1691 line_ptr++;
1692 uint8_t col_r = 0;
1693 uint8_t col_g = 0;
1694 uint8_t col_b = 0;
1695 //uint8_t col_a=255;
1696
1697 for (int i = 0; i < 6; i++) {
1698
1699 char v = line_ptr[i];
1700
1701 if (v >= '0' && v <= '9')
1702 v -= '0';
1703 else if (v >= 'A' && v <= 'F')
1704 v = (v - 'A') + 10;
1705 else if (v >= 'a' && v <= 'f')
1706 v = (v - 'a') + 10;
1707 else
1708 break;
1709
1710 switch (i) {
1711 case 0: col_r = v << 4; break;
1712 case 1: col_r |= v; break;
1713 case 2: col_g = v << 4; break;
1714 case 3: col_g |= v; break;
1715 case 4: col_b = v << 4; break;
1716 case 5: col_b |= v; break;
1717 };
1718 }
1719
1720 // magenta mask
1721 if (col_r == 255 && col_g == 0 && col_b == 255) {
1722
1723 colormap[colorstring] = Color(0, 0, 0, 0);
1724 has_alpha = true;
1725 } else {
1726
1727 colormap[colorstring] = Color(col_r / 255.0, col_g / 255.0, col_b / 255.0, 1.0);
1728 }
1729 }
1730 }
1731 if (line == colormap_size) {
1732
1733 status = READING_PIXELS;
1734 create(size_width, size_height, 0, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
1735 w = data.write();
1736 pixel_size = has_alpha ? 4 : 3;
1737 }
1738 } break;
1739 case READING_PIXELS: {
1740
1741 int y = line - colormap_size - 1;
1742 for (int x = 0; x < size_width; x++) {
1743
1744 char pixelstr[6] = { 0, 0, 0, 0, 0, 0 };
1745 for (int i = 0; i < pixelchars; i++)
1746 pixelstr[i] = line_ptr[x * pixelchars + i];
1747
1748 Color *colorptr = colormap.getptr(pixelstr);
1749 ERR_FAIL_COND(!colorptr);
1750 uint8_t pixel[4];
1751 for (uint32_t i = 0; i < pixel_size; i++) {
1752 pixel[i] = CLAMP((*colorptr)[i] * 255, 0, 255);
1753 }
1754 _put_pixelb(x, y, pixel_size, w.ptr(), pixel);
1755 }
1756
1757 if (y == (size_height - 1))
1758 status = DONE;
1759 } break;
1760 default: {
1761 }
1762 }
1763
1764 line++;
1765 }
1766 }
1767 #define DETECT_ALPHA_MAX_THRESHOLD 254
1768 #define DETECT_ALPHA_MIN_THRESHOLD 2
1769
1770 #define DETECT_ALPHA(m_value) \
1771 { \
1772 uint8_t value = m_value; \
1773 if (value < DETECT_ALPHA_MIN_THRESHOLD) \
1774 bit = true; \
1775 else if (value < DETECT_ALPHA_MAX_THRESHOLD) { \
1776 \
1777 detected = true; \
1778 break; \
1779 } \
1780 }
1781
1782 #define DETECT_NON_ALPHA(m_value) \
1783 { \
1784 uint8_t value = m_value; \
1785 if (value > 0) { \
1786 \
1787 detected = true; \
1788 break; \
1789 } \
1790 }
1791
is_invisible() const1792 bool Image::is_invisible() const {
1793
1794 if (format == FORMAT_L8 ||
1795 format == FORMAT_RGB8 || format == FORMAT_RG8)
1796 return false;
1797
1798 int len = data.size();
1799
1800 if (len == 0)
1801 return true;
1802
1803 int w, h;
1804 _get_mipmap_offset_and_size(1, len, w, h);
1805
1806 PoolVector<uint8_t>::Read r = data.read();
1807 const unsigned char *data_ptr = r.ptr();
1808
1809 bool detected = false;
1810
1811 switch (format) {
1812
1813 case FORMAT_LA8: {
1814
1815 for (int i = 0; i < (len >> 1); i++) {
1816 DETECT_NON_ALPHA(data_ptr[(i << 1) + 1]);
1817 }
1818
1819 } break;
1820 case FORMAT_RGBA8: {
1821
1822 for (int i = 0; i < (len >> 2); i++) {
1823 DETECT_NON_ALPHA(data_ptr[(i << 2) + 3])
1824 }
1825
1826 } break;
1827
1828 case FORMAT_PVRTC2A:
1829 case FORMAT_PVRTC4A:
1830 case FORMAT_DXT3:
1831 case FORMAT_DXT5: {
1832 detected = true;
1833 } break;
1834 default: {
1835 }
1836 }
1837
1838 return !detected;
1839 }
1840
detect_alpha() const1841 Image::AlphaMode Image::detect_alpha() const {
1842
1843 int len = data.size();
1844
1845 if (len == 0)
1846 return ALPHA_NONE;
1847
1848 int w, h;
1849 _get_mipmap_offset_and_size(1, len, w, h);
1850
1851 PoolVector<uint8_t>::Read r = data.read();
1852 const unsigned char *data_ptr = r.ptr();
1853
1854 bool bit = false;
1855 bool detected = false;
1856
1857 switch (format) {
1858
1859 case FORMAT_LA8: {
1860
1861 for (int i = 0; i < (len >> 1); i++) {
1862 DETECT_ALPHA(data_ptr[(i << 1) + 1]);
1863 }
1864
1865 } break;
1866 case FORMAT_RGBA8: {
1867
1868 for (int i = 0; i < (len >> 2); i++) {
1869 DETECT_ALPHA(data_ptr[(i << 2) + 3])
1870 }
1871
1872 } break;
1873 case FORMAT_PVRTC2A:
1874 case FORMAT_PVRTC4A:
1875 case FORMAT_DXT3:
1876 case FORMAT_DXT5: {
1877 detected = true;
1878 } break;
1879 default: {
1880 }
1881 }
1882
1883 if (detected)
1884 return ALPHA_BLEND;
1885 else if (bit)
1886 return ALPHA_BIT;
1887 else
1888 return ALPHA_NONE;
1889 }
1890
load(const String & p_path)1891 Error Image::load(const String &p_path) {
1892 #ifdef DEBUG_ENABLED
1893 if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) {
1894 WARN_PRINTS("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.");
1895 }
1896 #endif
1897 return ImageLoader::load_image(p_path, this);
1898 }
1899
save_png(const String & p_path) const1900 Error Image::save_png(const String &p_path) const {
1901
1902 if (save_png_func == NULL)
1903 return ERR_UNAVAILABLE;
1904
1905 return save_png_func(p_path, Ref<Image>((Image *)this));
1906 }
1907
save_png_to_buffer() const1908 PoolVector<uint8_t> Image::save_png_to_buffer() const {
1909 if (save_png_buffer_func == NULL) {
1910 return PoolVector<uint8_t>();
1911 }
1912
1913 return save_png_buffer_func(Ref<Image>((Image *)this));
1914 }
1915
save_exr(const String & p_path,bool p_grayscale) const1916 Error Image::save_exr(const String &p_path, bool p_grayscale) const {
1917
1918 if (save_exr_func == NULL)
1919 return ERR_UNAVAILABLE;
1920
1921 return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale);
1922 }
1923
get_image_data_size(int p_width,int p_height,Format p_format,bool p_mipmaps)1924 int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) {
1925
1926 int mm;
1927 return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps ? -1 : 0);
1928 }
1929
get_image_required_mipmaps(int p_width,int p_height,Format p_format)1930 int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format) {
1931
1932 int mm;
1933 _get_dst_image_size(p_width, p_height, p_format, mm, -1);
1934 return mm;
1935 }
1936
get_image_mipmap_offset(int p_width,int p_height,Format p_format,int p_mipmap)1937 int Image::get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap) {
1938
1939 if (p_mipmap <= 0) {
1940 return 0;
1941 }
1942 int mm;
1943 return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmap - 1);
1944 }
1945
is_compressed() const1946 bool Image::is_compressed() const {
1947 return format > FORMAT_RGBE9995;
1948 }
1949
decompress()1950 Error Image::decompress() {
1951
1952 if (format >= FORMAT_DXT1 && format <= FORMAT_RGTC_RG && _image_decompress_bc)
1953 _image_decompress_bc(this);
1954 else if (format >= FORMAT_BPTC_RGBA && format <= FORMAT_BPTC_RGBFU && _image_decompress_bptc)
1955 _image_decompress_bptc(this);
1956 else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc)
1957 _image_decompress_pvrtc(this);
1958 else if (format == FORMAT_ETC && _image_decompress_etc1)
1959 _image_decompress_etc1(this);
1960 else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc2)
1961 _image_decompress_etc2(this);
1962 else
1963 return ERR_UNAVAILABLE;
1964 return OK;
1965 }
1966
compress(CompressMode p_mode,CompressSource p_source,float p_lossy_quality)1967 Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality) {
1968
1969 switch (p_mode) {
1970
1971 case COMPRESS_S3TC: {
1972
1973 ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
1974 _image_compress_bc_func(this, p_lossy_quality, p_source);
1975 } break;
1976 case COMPRESS_PVRTC2: {
1977
1978 ERR_FAIL_COND_V(!_image_compress_pvrtc2_func, ERR_UNAVAILABLE);
1979 _image_compress_pvrtc2_func(this);
1980 } break;
1981 case COMPRESS_PVRTC4: {
1982
1983 ERR_FAIL_COND_V(!_image_compress_pvrtc4_func, ERR_UNAVAILABLE);
1984 _image_compress_pvrtc4_func(this);
1985 } break;
1986 case COMPRESS_ETC: {
1987
1988 ERR_FAIL_COND_V(!_image_compress_etc1_func, ERR_UNAVAILABLE);
1989 _image_compress_etc1_func(this, p_lossy_quality);
1990 } break;
1991 case COMPRESS_ETC2: {
1992
1993 ERR_FAIL_COND_V(!_image_compress_etc2_func, ERR_UNAVAILABLE);
1994 _image_compress_etc2_func(this, p_lossy_quality, p_source);
1995 } break;
1996 case COMPRESS_BPTC: {
1997
1998 ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
1999 _image_compress_bptc_func(this, p_lossy_quality, p_source);
2000 } break;
2001 }
2002
2003 return OK;
2004 }
2005
Image(const char ** p_xpm)2006 Image::Image(const char **p_xpm) {
2007
2008 width = 0;
2009 height = 0;
2010 mipmaps = false;
2011 format = FORMAT_L8;
2012
2013 create(p_xpm);
2014 }
2015
Image(int p_width,int p_height,bool p_use_mipmaps,Format p_format)2016 Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
2017
2018 width = 0;
2019 height = 0;
2020 mipmaps = p_use_mipmaps;
2021 format = FORMAT_L8;
2022
2023 create(p_width, p_height, p_use_mipmaps, p_format);
2024 }
2025
Image(int p_width,int p_height,bool p_mipmaps,Format p_format,const PoolVector<uint8_t> & p_data)2026 Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const PoolVector<uint8_t> &p_data) {
2027
2028 width = 0;
2029 height = 0;
2030 mipmaps = p_mipmaps;
2031 format = FORMAT_L8;
2032
2033 create(p_width, p_height, p_mipmaps, p_format, p_data);
2034 }
2035
get_used_rect() const2036 Rect2 Image::get_used_rect() const {
2037
2038 if (format != FORMAT_LA8 && format != FORMAT_RGBA8 && format != FORMAT_RGBAF && format != FORMAT_RGBAH && format != FORMAT_RGBA4444 && format != FORMAT_RGBA5551)
2039 return Rect2(Point2(), Size2(width, height));
2040
2041 int len = data.size();
2042
2043 if (len == 0)
2044 return Rect2();
2045
2046 const_cast<Image *>(this)->lock();
2047 int minx = 0xFFFFFF, miny = 0xFFFFFFF;
2048 int maxx = -1, maxy = -1;
2049 for (int j = 0; j < height; j++) {
2050 for (int i = 0; i < width; i++) {
2051
2052 if (!(get_pixel(i, j).a > 0))
2053 continue;
2054 if (i > maxx)
2055 maxx = i;
2056 if (j > maxy)
2057 maxy = j;
2058 if (i < minx)
2059 minx = i;
2060 if (j < miny)
2061 miny = j;
2062 }
2063 }
2064
2065 const_cast<Image *>(this)->unlock();
2066
2067 if (maxx == -1)
2068 return Rect2();
2069 else
2070 return Rect2(minx, miny, maxx - minx + 1, maxy - miny + 1);
2071 }
2072
get_rect(const Rect2 & p_area) const2073 Ref<Image> Image::get_rect(const Rect2 &p_area) const {
2074
2075 Ref<Image> img = memnew(Image(p_area.size.x, p_area.size.y, mipmaps, format));
2076 img->blit_rect(Ref<Image>((Image *)this), p_area, Point2(0, 0));
2077 return img;
2078 }
2079
blit_rect(const Ref<Image> & p_src,const Rect2 & p_src_rect,const Point2 & p_dest)2080 void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) {
2081
2082 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2083 int dsize = data.size();
2084 int srcdsize = p_src->data.size();
2085 ERR_FAIL_COND(dsize == 0);
2086 ERR_FAIL_COND(srcdsize == 0);
2087 ERR_FAIL_COND(format != p_src->format);
2088 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot blit_rect in compressed or custom image formats.");
2089
2090 Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
2091
2092 if (p_dest.x < 0)
2093 clipped_src_rect.position.x = ABS(p_dest.x);
2094 if (p_dest.y < 0)
2095 clipped_src_rect.position.y = ABS(p_dest.y);
2096
2097 if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0)
2098 return;
2099
2100 Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
2101 Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
2102
2103 PoolVector<uint8_t>::Write wp = data.write();
2104 uint8_t *dst_data_ptr = wp.ptr();
2105
2106 PoolVector<uint8_t>::Read rp = p_src->data.read();
2107 const uint8_t *src_data_ptr = rp.ptr();
2108
2109 int pixel_size = get_format_pixel_size(format);
2110
2111 for (int i = 0; i < dest_rect.size.y; i++) {
2112
2113 for (int j = 0; j < dest_rect.size.x; j++) {
2114
2115 int src_x = clipped_src_rect.position.x + j;
2116 int src_y = clipped_src_rect.position.y + i;
2117
2118 int dst_x = dest_rect.position.x + j;
2119 int dst_y = dest_rect.position.y + i;
2120
2121 const uint8_t *src = &src_data_ptr[(src_y * p_src->width + src_x) * pixel_size];
2122 uint8_t *dst = &dst_data_ptr[(dst_y * width + dst_x) * pixel_size];
2123
2124 for (int k = 0; k < pixel_size; k++) {
2125 dst[k] = src[k];
2126 }
2127 }
2128 }
2129 }
2130
blit_rect_mask(const Ref<Image> & p_src,const Ref<Image> & p_mask,const Rect2 & p_src_rect,const Point2 & p_dest)2131 void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) {
2132
2133 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2134 ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object.");
2135 int dsize = data.size();
2136 int srcdsize = p_src->data.size();
2137 int maskdsize = p_mask->data.size();
2138 ERR_FAIL_COND(dsize == 0);
2139 ERR_FAIL_COND(srcdsize == 0);
2140 ERR_FAIL_COND(maskdsize == 0);
2141 ERR_FAIL_COND_MSG(p_src->width != p_mask->width, "Source image width is different from mask width.");
2142 ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
2143 ERR_FAIL_COND(format != p_src->format);
2144
2145 Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
2146
2147 if (p_dest.x < 0)
2148 clipped_src_rect.position.x = ABS(p_dest.x);
2149 if (p_dest.y < 0)
2150 clipped_src_rect.position.y = ABS(p_dest.y);
2151
2152 if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0)
2153 return;
2154
2155 Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
2156 Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
2157
2158 PoolVector<uint8_t>::Write wp = data.write();
2159 uint8_t *dst_data_ptr = wp.ptr();
2160
2161 PoolVector<uint8_t>::Read rp = p_src->data.read();
2162 const uint8_t *src_data_ptr = rp.ptr();
2163
2164 int pixel_size = get_format_pixel_size(format);
2165
2166 Ref<Image> msk = p_mask;
2167 msk->lock();
2168
2169 for (int i = 0; i < dest_rect.size.y; i++) {
2170
2171 for (int j = 0; j < dest_rect.size.x; j++) {
2172
2173 int src_x = clipped_src_rect.position.x + j;
2174 int src_y = clipped_src_rect.position.y + i;
2175
2176 if (msk->get_pixel(src_x, src_y).a != 0) {
2177
2178 int dst_x = dest_rect.position.x + j;
2179 int dst_y = dest_rect.position.y + i;
2180
2181 const uint8_t *src = &src_data_ptr[(src_y * p_src->width + src_x) * pixel_size];
2182 uint8_t *dst = &dst_data_ptr[(dst_y * width + dst_x) * pixel_size];
2183
2184 for (int k = 0; k < pixel_size; k++) {
2185 dst[k] = src[k];
2186 }
2187 }
2188 }
2189 }
2190
2191 msk->unlock();
2192 }
2193
blend_rect(const Ref<Image> & p_src,const Rect2 & p_src_rect,const Point2 & p_dest)2194 void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) {
2195
2196 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2197 int dsize = data.size();
2198 int srcdsize = p_src->data.size();
2199 ERR_FAIL_COND(dsize == 0);
2200 ERR_FAIL_COND(srcdsize == 0);
2201 ERR_FAIL_COND(format != p_src->format);
2202
2203 Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
2204
2205 if (p_dest.x < 0)
2206 clipped_src_rect.position.x = ABS(p_dest.x);
2207 if (p_dest.y < 0)
2208 clipped_src_rect.position.y = ABS(p_dest.y);
2209
2210 if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0)
2211 return;
2212
2213 Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
2214 Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
2215
2216 lock();
2217 Ref<Image> img = p_src;
2218 img->lock();
2219
2220 for (int i = 0; i < dest_rect.size.y; i++) {
2221
2222 for (int j = 0; j < dest_rect.size.x; j++) {
2223
2224 int src_x = clipped_src_rect.position.x + j;
2225 int src_y = clipped_src_rect.position.y + i;
2226
2227 int dst_x = dest_rect.position.x + j;
2228 int dst_y = dest_rect.position.y + i;
2229
2230 Color sc = img->get_pixel(src_x, src_y);
2231 if (sc.a != 0) {
2232 Color dc = get_pixel(dst_x, dst_y);
2233 dc = dc.blend(sc);
2234 set_pixel(dst_x, dst_y, dc);
2235 }
2236 }
2237 }
2238
2239 img->unlock();
2240 unlock();
2241 }
2242
blend_rect_mask(const Ref<Image> & p_src,const Ref<Image> & p_mask,const Rect2 & p_src_rect,const Point2 & p_dest)2243 void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) {
2244
2245 ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
2246 ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object.");
2247 int dsize = data.size();
2248 int srcdsize = p_src->data.size();
2249 int maskdsize = p_mask->data.size();
2250 ERR_FAIL_COND(dsize == 0);
2251 ERR_FAIL_COND(srcdsize == 0);
2252 ERR_FAIL_COND(maskdsize == 0);
2253 ERR_FAIL_COND_MSG(p_src->width != p_mask->width, "Source image width is different from mask width.");
2254 ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
2255 ERR_FAIL_COND(format != p_src->format);
2256
2257 Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
2258
2259 if (p_dest.x < 0)
2260 clipped_src_rect.position.x = ABS(p_dest.x);
2261 if (p_dest.y < 0)
2262 clipped_src_rect.position.y = ABS(p_dest.y);
2263
2264 if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0)
2265 return;
2266
2267 Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
2268 Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
2269
2270 lock();
2271 Ref<Image> img = p_src;
2272 Ref<Image> msk = p_mask;
2273 img->lock();
2274 msk->lock();
2275
2276 for (int i = 0; i < dest_rect.size.y; i++) {
2277
2278 for (int j = 0; j < dest_rect.size.x; j++) {
2279
2280 int src_x = clipped_src_rect.position.x + j;
2281 int src_y = clipped_src_rect.position.y + i;
2282
2283 // If the mask's pixel is transparent then we skip it
2284 //Color c = msk->get_pixel(src_x, src_y);
2285 //if (c.a == 0) continue;
2286 if (msk->get_pixel(src_x, src_y).a != 0) {
2287
2288 int dst_x = dest_rect.position.x + j;
2289 int dst_y = dest_rect.position.y + i;
2290
2291 Color sc = img->get_pixel(src_x, src_y);
2292 if (sc.a != 0) {
2293 Color dc = get_pixel(dst_x, dst_y);
2294 dc = dc.blend(sc);
2295 set_pixel(dst_x, dst_y, dc);
2296 }
2297 }
2298 }
2299 }
2300
2301 msk->unlock();
2302 img->unlock();
2303 unlock();
2304 }
2305
fill(const Color & c)2306 void Image::fill(const Color &c) {
2307 ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats.");
2308
2309 lock();
2310
2311 PoolVector<uint8_t>::Write wp = data.write();
2312 uint8_t *dst_data_ptr = wp.ptr();
2313
2314 int pixel_size = get_format_pixel_size(format);
2315
2316 // put first pixel with the format-aware API
2317 set_pixel(0, 0, c);
2318
2319 for (int y = 0; y < height; y++) {
2320
2321 for (int x = 0; x < width; x++) {
2322
2323 uint8_t *dst = &dst_data_ptr[(y * width + x) * pixel_size];
2324
2325 for (int k = 0; k < pixel_size; k++) {
2326 dst[k] = dst_data_ptr[k];
2327 }
2328 }
2329 }
2330
2331 unlock();
2332 }
2333
2334 ImageMemLoadFunc Image::_png_mem_loader_func = NULL;
2335 ImageMemLoadFunc Image::_jpg_mem_loader_func = NULL;
2336 ImageMemLoadFunc Image::_webp_mem_loader_func = NULL;
2337 ImageMemLoadFunc Image::_tga_mem_loader_func = NULL;
2338
2339 void (*Image::_image_compress_bc_func)(Image *, float, Image::CompressSource) = NULL;
2340 void (*Image::_image_compress_bptc_func)(Image *, float, Image::CompressSource) = NULL;
2341 void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL;
2342 void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL;
2343 void (*Image::_image_compress_etc1_func)(Image *, float) = NULL;
2344 void (*Image::_image_compress_etc2_func)(Image *, float, Image::CompressSource) = NULL;
2345 void (*Image::_image_decompress_pvrtc)(Image *) = NULL;
2346 void (*Image::_image_decompress_bc)(Image *) = NULL;
2347 void (*Image::_image_decompress_bptc)(Image *) = NULL;
2348 void (*Image::_image_decompress_etc1)(Image *) = NULL;
2349 void (*Image::_image_decompress_etc2)(Image *) = NULL;
2350
2351 PoolVector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = NULL;
2352 Ref<Image> (*Image::lossy_unpacker)(const PoolVector<uint8_t> &) = NULL;
2353 PoolVector<uint8_t> (*Image::lossless_packer)(const Ref<Image> &) = NULL;
2354 Ref<Image> (*Image::lossless_unpacker)(const PoolVector<uint8_t> &) = NULL;
2355
_set_data(const Dictionary & p_data)2356 void Image::_set_data(const Dictionary &p_data) {
2357
2358 ERR_FAIL_COND(!p_data.has("width"));
2359 ERR_FAIL_COND(!p_data.has("height"));
2360 ERR_FAIL_COND(!p_data.has("format"));
2361 ERR_FAIL_COND(!p_data.has("mipmaps"));
2362 ERR_FAIL_COND(!p_data.has("data"));
2363
2364 int dwidth = p_data["width"];
2365 int dheight = p_data["height"];
2366 String dformat = p_data["format"];
2367 bool dmipmaps = p_data["mipmaps"];
2368 PoolVector<uint8_t> ddata = p_data["data"];
2369 Format ddformat = FORMAT_MAX;
2370 for (int i = 0; i < FORMAT_MAX; i++) {
2371 if (dformat == get_format_name(Format(i))) {
2372 ddformat = Format(i);
2373 break;
2374 }
2375 }
2376
2377 ERR_FAIL_COND(ddformat == FORMAT_MAX);
2378
2379 create(dwidth, dheight, dmipmaps, ddformat, ddata);
2380 }
2381
_get_data() const2382 Dictionary Image::_get_data() const {
2383
2384 Dictionary d;
2385 d["width"] = width;
2386 d["height"] = height;
2387 d["format"] = get_format_name(format);
2388 d["mipmaps"] = mipmaps;
2389 d["data"] = data;
2390 return d;
2391 }
2392
lock()2393 void Image::lock() {
2394
2395 ERR_FAIL_COND(data.size() == 0);
2396 write_lock = data.write();
2397 }
2398
unlock()2399 void Image::unlock() {
2400
2401 write_lock.release();
2402 }
2403
get_pixelv(const Point2 & p_src) const2404 Color Image::get_pixelv(const Point2 &p_src) const {
2405 return get_pixel(p_src.x, p_src.y);
2406 }
2407
get_pixel(int p_x,int p_y) const2408 Color Image::get_pixel(int p_x, int p_y) const {
2409
2410 uint8_t *ptr = write_lock.ptr();
2411 #ifdef DEBUG_ENABLED
2412 ERR_FAIL_COND_V_MSG(!ptr, Color(), "Image must be locked with 'lock()' before using get_pixel().");
2413
2414 ERR_FAIL_INDEX_V(p_x, width, Color());
2415 ERR_FAIL_INDEX_V(p_y, height, Color());
2416
2417 #endif
2418
2419 uint32_t ofs = p_y * width + p_x;
2420
2421 switch (format) {
2422 case FORMAT_L8: {
2423 float l = ptr[ofs] / 255.0;
2424 return Color(l, l, l, 1);
2425 }
2426 case FORMAT_LA8: {
2427 float l = ptr[ofs * 2 + 0] / 255.0;
2428 float a = ptr[ofs * 2 + 1] / 255.0;
2429 return Color(l, l, l, a);
2430 }
2431 case FORMAT_R8: {
2432
2433 float r = ptr[ofs] / 255.0;
2434 return Color(r, 0, 0, 1);
2435 }
2436 case FORMAT_RG8: {
2437
2438 float r = ptr[ofs * 2 + 0] / 255.0;
2439 float g = ptr[ofs * 2 + 1] / 255.0;
2440 return Color(r, g, 0, 1);
2441 }
2442 case FORMAT_RGB8: {
2443 float r = ptr[ofs * 3 + 0] / 255.0;
2444 float g = ptr[ofs * 3 + 1] / 255.0;
2445 float b = ptr[ofs * 3 + 2] / 255.0;
2446 return Color(r, g, b, 1);
2447 }
2448 case FORMAT_RGBA8: {
2449 float r = ptr[ofs * 4 + 0] / 255.0;
2450 float g = ptr[ofs * 4 + 1] / 255.0;
2451 float b = ptr[ofs * 4 + 2] / 255.0;
2452 float a = ptr[ofs * 4 + 3] / 255.0;
2453 return Color(r, g, b, a);
2454 }
2455 case FORMAT_RGBA4444: {
2456 uint16_t u = ((uint16_t *)ptr)[ofs];
2457 float r = ((u >> 12) & 0xF) / 15.0;
2458 float g = ((u >> 8) & 0xF) / 15.0;
2459 float b = ((u >> 4) & 0xF) / 15.0;
2460 float a = (u & 0xF) / 15.0;
2461 return Color(r, g, b, a);
2462 }
2463 case FORMAT_RGBA5551: {
2464
2465 uint16_t u = ((uint16_t *)ptr)[ofs];
2466 float r = ((u >> 11) & 0x1F) / 15.0;
2467 float g = ((u >> 6) & 0x1F) / 15.0;
2468 float b = ((u >> 1) & 0x1F) / 15.0;
2469 float a = (u & 0x1) / 1.0;
2470 return Color(r, g, b, a);
2471 }
2472 case FORMAT_RF: {
2473
2474 float r = ((float *)ptr)[ofs];
2475 return Color(r, 0, 0, 1);
2476 }
2477 case FORMAT_RGF: {
2478
2479 float r = ((float *)ptr)[ofs * 2 + 0];
2480 float g = ((float *)ptr)[ofs * 2 + 1];
2481 return Color(r, g, 0, 1);
2482 }
2483 case FORMAT_RGBF: {
2484
2485 float r = ((float *)ptr)[ofs * 3 + 0];
2486 float g = ((float *)ptr)[ofs * 3 + 1];
2487 float b = ((float *)ptr)[ofs * 3 + 2];
2488 return Color(r, g, b, 1);
2489 }
2490 case FORMAT_RGBAF: {
2491
2492 float r = ((float *)ptr)[ofs * 4 + 0];
2493 float g = ((float *)ptr)[ofs * 4 + 1];
2494 float b = ((float *)ptr)[ofs * 4 + 2];
2495 float a = ((float *)ptr)[ofs * 4 + 3];
2496 return Color(r, g, b, a);
2497 }
2498 case FORMAT_RH: {
2499
2500 uint16_t r = ((uint16_t *)ptr)[ofs];
2501 return Color(Math::half_to_float(r), 0, 0, 1);
2502 }
2503 case FORMAT_RGH: {
2504
2505 uint16_t r = ((uint16_t *)ptr)[ofs * 2 + 0];
2506 uint16_t g = ((uint16_t *)ptr)[ofs * 2 + 1];
2507 return Color(Math::half_to_float(r), Math::half_to_float(g), 0, 1);
2508 }
2509 case FORMAT_RGBH: {
2510
2511 uint16_t r = ((uint16_t *)ptr)[ofs * 3 + 0];
2512 uint16_t g = ((uint16_t *)ptr)[ofs * 3 + 1];
2513 uint16_t b = ((uint16_t *)ptr)[ofs * 3 + 2];
2514 return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), 1);
2515 }
2516 case FORMAT_RGBAH: {
2517
2518 uint16_t r = ((uint16_t *)ptr)[ofs * 4 + 0];
2519 uint16_t g = ((uint16_t *)ptr)[ofs * 4 + 1];
2520 uint16_t b = ((uint16_t *)ptr)[ofs * 4 + 2];
2521 uint16_t a = ((uint16_t *)ptr)[ofs * 4 + 3];
2522 return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), Math::half_to_float(a));
2523 }
2524 case FORMAT_RGBE9995: {
2525 return Color::from_rgbe9995(((uint32_t *)ptr)[ofs]);
2526 }
2527 default: {
2528 ERR_FAIL_V_MSG(Color(), "Can't get_pixel() on compressed image, sorry.");
2529 }
2530 }
2531 }
2532
set_pixelv(const Point2 & p_dst,const Color & p_color)2533 void Image::set_pixelv(const Point2 &p_dst, const Color &p_color) {
2534 set_pixel(p_dst.x, p_dst.y, p_color);
2535 }
2536
set_pixel(int p_x,int p_y,const Color & p_color)2537 void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
2538
2539 uint8_t *ptr = write_lock.ptr();
2540 #ifdef DEBUG_ENABLED
2541 ERR_FAIL_COND_MSG(!ptr, "Image must be locked with 'lock()' before using set_pixel().");
2542
2543 ERR_FAIL_INDEX(p_x, width);
2544 ERR_FAIL_INDEX(p_y, height);
2545
2546 #endif
2547
2548 uint32_t ofs = p_y * width + p_x;
2549
2550 switch (format) {
2551 case FORMAT_L8: {
2552 ptr[ofs] = uint8_t(CLAMP(p_color.get_v() * 255.0, 0, 255));
2553 } break;
2554 case FORMAT_LA8: {
2555 ptr[ofs * 2 + 0] = uint8_t(CLAMP(p_color.get_v() * 255.0, 0, 255));
2556 ptr[ofs * 2 + 1] = uint8_t(CLAMP(p_color.a * 255.0, 0, 255));
2557 } break;
2558 case FORMAT_R8: {
2559
2560 ptr[ofs] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
2561 } break;
2562 case FORMAT_RG8: {
2563
2564 ptr[ofs * 2 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
2565 ptr[ofs * 2 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
2566 } break;
2567 case FORMAT_RGB8: {
2568 ptr[ofs * 3 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
2569 ptr[ofs * 3 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
2570 ptr[ofs * 3 + 2] = uint8_t(CLAMP(p_color.b * 255.0, 0, 255));
2571 } break;
2572 case FORMAT_RGBA8: {
2573 ptr[ofs * 4 + 0] = uint8_t(CLAMP(p_color.r * 255.0, 0, 255));
2574 ptr[ofs * 4 + 1] = uint8_t(CLAMP(p_color.g * 255.0, 0, 255));
2575 ptr[ofs * 4 + 2] = uint8_t(CLAMP(p_color.b * 255.0, 0, 255));
2576 ptr[ofs * 4 + 3] = uint8_t(CLAMP(p_color.a * 255.0, 0, 255));
2577
2578 } break;
2579 case FORMAT_RGBA4444: {
2580
2581 uint16_t rgba = 0;
2582
2583 rgba = uint16_t(CLAMP(p_color.r * 15.0, 0, 15)) << 12;
2584 rgba |= uint16_t(CLAMP(p_color.g * 15.0, 0, 15)) << 8;
2585 rgba |= uint16_t(CLAMP(p_color.b * 15.0, 0, 15)) << 4;
2586 rgba |= uint16_t(CLAMP(p_color.a * 15.0, 0, 15));
2587
2588 ((uint16_t *)ptr)[ofs] = rgba;
2589
2590 } break;
2591 case FORMAT_RGBA5551: {
2592
2593 uint16_t rgba = 0;
2594
2595 rgba = uint16_t(CLAMP(p_color.r * 31.0, 0, 31)) << 11;
2596 rgba |= uint16_t(CLAMP(p_color.g * 31.0, 0, 31)) << 6;
2597 rgba |= uint16_t(CLAMP(p_color.b * 31.0, 0, 31)) << 1;
2598 rgba |= uint16_t(p_color.a > 0.5 ? 1 : 0);
2599
2600 ((uint16_t *)ptr)[ofs] = rgba;
2601
2602 } break;
2603 case FORMAT_RF: {
2604
2605 ((float *)ptr)[ofs] = p_color.r;
2606 } break;
2607 case FORMAT_RGF: {
2608
2609 ((float *)ptr)[ofs * 2 + 0] = p_color.r;
2610 ((float *)ptr)[ofs * 2 + 1] = p_color.g;
2611 } break;
2612 case FORMAT_RGBF: {
2613
2614 ((float *)ptr)[ofs * 3 + 0] = p_color.r;
2615 ((float *)ptr)[ofs * 3 + 1] = p_color.g;
2616 ((float *)ptr)[ofs * 3 + 2] = p_color.b;
2617 } break;
2618 case FORMAT_RGBAF: {
2619
2620 ((float *)ptr)[ofs * 4 + 0] = p_color.r;
2621 ((float *)ptr)[ofs * 4 + 1] = p_color.g;
2622 ((float *)ptr)[ofs * 4 + 2] = p_color.b;
2623 ((float *)ptr)[ofs * 4 + 3] = p_color.a;
2624 } break;
2625 case FORMAT_RH: {
2626
2627 ((uint16_t *)ptr)[ofs] = Math::make_half_float(p_color.r);
2628 } break;
2629 case FORMAT_RGH: {
2630
2631 ((uint16_t *)ptr)[ofs * 2 + 0] = Math::make_half_float(p_color.r);
2632 ((uint16_t *)ptr)[ofs * 2 + 1] = Math::make_half_float(p_color.g);
2633 } break;
2634 case FORMAT_RGBH: {
2635
2636 ((uint16_t *)ptr)[ofs * 3 + 0] = Math::make_half_float(p_color.r);
2637 ((uint16_t *)ptr)[ofs * 3 + 1] = Math::make_half_float(p_color.g);
2638 ((uint16_t *)ptr)[ofs * 3 + 2] = Math::make_half_float(p_color.b);
2639 } break;
2640 case FORMAT_RGBAH: {
2641
2642 ((uint16_t *)ptr)[ofs * 4 + 0] = Math::make_half_float(p_color.r);
2643 ((uint16_t *)ptr)[ofs * 4 + 1] = Math::make_half_float(p_color.g);
2644 ((uint16_t *)ptr)[ofs * 4 + 2] = Math::make_half_float(p_color.b);
2645 ((uint16_t *)ptr)[ofs * 4 + 3] = Math::make_half_float(p_color.a);
2646 } break;
2647 case FORMAT_RGBE9995: {
2648
2649 ((uint32_t *)ptr)[ofs] = p_color.to_rgbe9995();
2650
2651 } break;
2652 default: {
2653 ERR_FAIL_MSG("Can't set_pixel() on compressed image, sorry.");
2654 }
2655 }
2656 }
2657
get_detected_channels()2658 Image::DetectChannels Image::get_detected_channels() {
2659
2660 ERR_FAIL_COND_V(data.size() == 0, DETECTED_RGBA);
2661 ERR_FAIL_COND_V(is_compressed(), DETECTED_RGBA);
2662 bool r = false, g = false, b = false, a = false, c = false;
2663 lock();
2664 for (int i = 0; i < width; i++) {
2665 for (int j = 0; j < height; j++) {
2666
2667 Color col = get_pixel(i, j);
2668
2669 if (col.r > 0.001)
2670 r = true;
2671 if (col.g > 0.001)
2672 g = true;
2673 if (col.b > 0.001)
2674 b = true;
2675 if (col.a < 0.999)
2676 a = true;
2677
2678 if (col.r != col.b || col.r != col.g || col.b != col.g) {
2679 c = true;
2680 }
2681 }
2682 }
2683
2684 unlock();
2685
2686 if (!c && !a)
2687 return DETECTED_L;
2688 if (!c && a)
2689 return DETECTED_LA;
2690
2691 if (r && !g && !b && !a)
2692 return DETECTED_R;
2693
2694 if (r && g && !b && !a)
2695 return DETECTED_RG;
2696
2697 if (r && g && b && !a)
2698 return DETECTED_RGB;
2699
2700 return DETECTED_RGBA;
2701 }
2702
optimize_channels()2703 void Image::optimize_channels() {
2704 switch (get_detected_channels()) {
2705 case DETECTED_L: convert(FORMAT_L8); break;
2706 case DETECTED_LA: convert(FORMAT_LA8); break;
2707 case DETECTED_R: convert(FORMAT_R8); break;
2708 case DETECTED_RG: convert(FORMAT_RG8); break;
2709 case DETECTED_RGB: convert(FORMAT_RGB8); break;
2710 case DETECTED_RGBA: convert(FORMAT_RGBA8); break;
2711 }
2712 }
2713
_bind_methods()2714 void Image::_bind_methods() {
2715
2716 ClassDB::bind_method(D_METHOD("get_width"), &Image::get_width);
2717 ClassDB::bind_method(D_METHOD("get_height"), &Image::get_height);
2718 ClassDB::bind_method(D_METHOD("get_size"), &Image::get_size);
2719 ClassDB::bind_method(D_METHOD("has_mipmaps"), &Image::has_mipmaps);
2720 ClassDB::bind_method(D_METHOD("get_format"), &Image::get_format);
2721 ClassDB::bind_method(D_METHOD("get_data"), &Image::get_data);
2722
2723 ClassDB::bind_method(D_METHOD("convert", "format"), &Image::convert);
2724
2725 ClassDB::bind_method(D_METHOD("get_mipmap_offset", "mipmap"), &Image::get_mipmap_offset);
2726
2727 ClassDB::bind_method(D_METHOD("resize_to_po2", "square"), &Image::resize_to_po2, DEFVAL(false));
2728 ClassDB::bind_method(D_METHOD("resize", "width", "height", "interpolation"), &Image::resize, DEFVAL(INTERPOLATE_BILINEAR));
2729 ClassDB::bind_method(D_METHOD("shrink_x2"), &Image::shrink_x2);
2730 ClassDB::bind_method(D_METHOD("expand_x2_hq2x"), &Image::expand_x2_hq2x);
2731
2732 ClassDB::bind_method(D_METHOD("crop", "width", "height"), &Image::crop);
2733 ClassDB::bind_method(D_METHOD("flip_x"), &Image::flip_x);
2734 ClassDB::bind_method(D_METHOD("flip_y"), &Image::flip_y);
2735 ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
2736 ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
2737
2738 ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::_create_empty);
2739 ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::_create_from_data);
2740
2741 ClassDB::bind_method(D_METHOD("is_empty"), &Image::empty);
2742
2743 ClassDB::bind_method(D_METHOD("load", "path"), &Image::load);
2744 ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png);
2745 ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer);
2746 ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false));
2747
2748 ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha);
2749 ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible);
2750
2751 ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality"), &Image::compress);
2752 ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress);
2753 ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed);
2754
2755 ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges);
2756 ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha);
2757 ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear);
2758 ClassDB::bind_method(D_METHOD("normalmap_to_xy"), &Image::normalmap_to_xy);
2759 ClassDB::bind_method(D_METHOD("rgbe_to_srgb"), &Image::rgbe_to_srgb);
2760 ClassDB::bind_method(D_METHOD("bumpmap_to_normalmap", "bump_scale"), &Image::bumpmap_to_normalmap, DEFVAL(1.0));
2761
2762 ClassDB::bind_method(D_METHOD("blit_rect", "src", "src_rect", "dst"), &Image::blit_rect);
2763 ClassDB::bind_method(D_METHOD("blit_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blit_rect_mask);
2764 ClassDB::bind_method(D_METHOD("blend_rect", "src", "src_rect", "dst"), &Image::blend_rect);
2765 ClassDB::bind_method(D_METHOD("blend_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blend_rect_mask);
2766 ClassDB::bind_method(D_METHOD("fill", "color"), &Image::fill);
2767
2768 ClassDB::bind_method(D_METHOD("get_used_rect"), &Image::get_used_rect);
2769 ClassDB::bind_method(D_METHOD("get_rect", "rect"), &Image::get_rect);
2770
2771 ClassDB::bind_method(D_METHOD("copy_from", "src"), &Image::copy_internals_from);
2772
2773 ClassDB::bind_method(D_METHOD("_set_data", "data"), &Image::_set_data);
2774 ClassDB::bind_method(D_METHOD("_get_data"), &Image::_get_data);
2775
2776 ClassDB::bind_method(D_METHOD("lock"), &Image::lock);
2777 ClassDB::bind_method(D_METHOD("unlock"), &Image::unlock);
2778 ClassDB::bind_method(D_METHOD("get_pixelv", "src"), &Image::get_pixelv);
2779 ClassDB::bind_method(D_METHOD("get_pixel", "x", "y"), &Image::get_pixel);
2780 ClassDB::bind_method(D_METHOD("set_pixelv", "dst", "color"), &Image::set_pixelv);
2781 ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel);
2782
2783 ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer);
2784 ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
2785 ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
2786 ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
2787
2788 ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
2789
2790 BIND_CONSTANT(MAX_WIDTH);
2791 BIND_CONSTANT(MAX_HEIGHT);
2792
2793 BIND_ENUM_CONSTANT(FORMAT_L8); //luminance
2794 BIND_ENUM_CONSTANT(FORMAT_LA8); //luminance-alpha
2795 BIND_ENUM_CONSTANT(FORMAT_R8);
2796 BIND_ENUM_CONSTANT(FORMAT_RG8);
2797 BIND_ENUM_CONSTANT(FORMAT_RGB8);
2798 BIND_ENUM_CONSTANT(FORMAT_RGBA8);
2799 BIND_ENUM_CONSTANT(FORMAT_RGBA4444);
2800 BIND_ENUM_CONSTANT(FORMAT_RGBA5551);
2801 BIND_ENUM_CONSTANT(FORMAT_RF); //float
2802 BIND_ENUM_CONSTANT(FORMAT_RGF);
2803 BIND_ENUM_CONSTANT(FORMAT_RGBF);
2804 BIND_ENUM_CONSTANT(FORMAT_RGBAF);
2805 BIND_ENUM_CONSTANT(FORMAT_RH); //half float
2806 BIND_ENUM_CONSTANT(FORMAT_RGH);
2807 BIND_ENUM_CONSTANT(FORMAT_RGBH);
2808 BIND_ENUM_CONSTANT(FORMAT_RGBAH);
2809 BIND_ENUM_CONSTANT(FORMAT_RGBE9995);
2810 BIND_ENUM_CONSTANT(FORMAT_DXT1); //s3tc bc1
2811 BIND_ENUM_CONSTANT(FORMAT_DXT3); //bc2
2812 BIND_ENUM_CONSTANT(FORMAT_DXT5); //bc3
2813 BIND_ENUM_CONSTANT(FORMAT_RGTC_R);
2814 BIND_ENUM_CONSTANT(FORMAT_RGTC_RG);
2815 BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBA); //btpc bc6h
2816 BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBF); //float /
2817 BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBFU); //unsigned float
2818 BIND_ENUM_CONSTANT(FORMAT_PVRTC2); //pvrtc
2819 BIND_ENUM_CONSTANT(FORMAT_PVRTC2A);
2820 BIND_ENUM_CONSTANT(FORMAT_PVRTC4);
2821 BIND_ENUM_CONSTANT(FORMAT_PVRTC4A);
2822 BIND_ENUM_CONSTANT(FORMAT_ETC); //etc1
2823 BIND_ENUM_CONSTANT(FORMAT_ETC2_R11); //etc2
2824 BIND_ENUM_CONSTANT(FORMAT_ETC2_R11S); //signed ); NOT srgb.
2825 BIND_ENUM_CONSTANT(FORMAT_ETC2_RG11);
2826 BIND_ENUM_CONSTANT(FORMAT_ETC2_RG11S);
2827 BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8);
2828 BIND_ENUM_CONSTANT(FORMAT_ETC2_RGBA8);
2829 BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8A1);
2830 BIND_ENUM_CONSTANT(FORMAT_MAX);
2831
2832 BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST);
2833 BIND_ENUM_CONSTANT(INTERPOLATE_BILINEAR);
2834 BIND_ENUM_CONSTANT(INTERPOLATE_CUBIC);
2835 BIND_ENUM_CONSTANT(INTERPOLATE_TRILINEAR);
2836 BIND_ENUM_CONSTANT(INTERPOLATE_LANCZOS);
2837
2838 BIND_ENUM_CONSTANT(ALPHA_NONE);
2839 BIND_ENUM_CONSTANT(ALPHA_BIT);
2840 BIND_ENUM_CONSTANT(ALPHA_BLEND);
2841
2842 BIND_ENUM_CONSTANT(COMPRESS_S3TC);
2843 BIND_ENUM_CONSTANT(COMPRESS_PVRTC2);
2844 BIND_ENUM_CONSTANT(COMPRESS_PVRTC4);
2845 BIND_ENUM_CONSTANT(COMPRESS_ETC);
2846 BIND_ENUM_CONSTANT(COMPRESS_ETC2);
2847
2848 BIND_ENUM_CONSTANT(COMPRESS_SOURCE_GENERIC);
2849 BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB);
2850 BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL);
2851 }
2852
set_compress_bc_func(void (* p_compress_func)(Image *,float,CompressSource))2853 void Image::set_compress_bc_func(void (*p_compress_func)(Image *, float, CompressSource)) {
2854
2855 _image_compress_bc_func = p_compress_func;
2856 }
2857
set_compress_bptc_func(void (* p_compress_func)(Image *,float,CompressSource))2858 void Image::set_compress_bptc_func(void (*p_compress_func)(Image *, float, CompressSource)) {
2859
2860 _image_compress_bptc_func = p_compress_func;
2861 }
2862
normalmap_to_xy()2863 void Image::normalmap_to_xy() {
2864
2865 convert(Image::FORMAT_RGBA8);
2866
2867 {
2868 int len = data.size() / 4;
2869 PoolVector<uint8_t>::Write wp = data.write();
2870 unsigned char *data_ptr = wp.ptr();
2871
2872 for (int i = 0; i < len; i++) {
2873
2874 data_ptr[(i << 2) + 3] = data_ptr[(i << 2) + 0]; //x to w
2875 data_ptr[(i << 2) + 0] = data_ptr[(i << 2) + 1]; //y to xz
2876 data_ptr[(i << 2) + 2] = data_ptr[(i << 2) + 1];
2877 }
2878 }
2879
2880 convert(Image::FORMAT_LA8);
2881 }
2882
rgbe_to_srgb()2883 Ref<Image> Image::rgbe_to_srgb() {
2884
2885 if (data.size() == 0)
2886 return Ref<Image>();
2887
2888 ERR_FAIL_COND_V(format != FORMAT_RGBE9995, Ref<Image>());
2889
2890 Ref<Image> new_image;
2891 new_image.instance();
2892 new_image->create(width, height, 0, Image::FORMAT_RGB8);
2893
2894 lock();
2895
2896 new_image->lock();
2897
2898 for (int row = 0; row < height; row++) {
2899 for (int col = 0; col < width; col++) {
2900 new_image->set_pixel(col, row, get_pixel(col, row).to_srgb());
2901 }
2902 }
2903
2904 unlock();
2905 new_image->unlock();
2906
2907 if (has_mipmaps()) {
2908 new_image->generate_mipmaps();
2909 }
2910
2911 return new_image;
2912 }
2913
bumpmap_to_normalmap(float bump_scale)2914 void Image::bumpmap_to_normalmap(float bump_scale) {
2915 ERR_FAIL_COND(!_can_modify(format));
2916 convert(Image::FORMAT_RF);
2917
2918 PoolVector<uint8_t> result_image; //rgba output
2919 result_image.resize(width * height * 4);
2920
2921 {
2922 PoolVector<uint8_t>::Read rp = data.read();
2923 PoolVector<uint8_t>::Write wp = result_image.write();
2924
2925 ERR_FAIL_COND(!rp.ptr());
2926
2927 unsigned char *write_ptr = wp.ptr();
2928 float *read_ptr = (float *)rp.ptr();
2929
2930 for (int ty = 0; ty < height; ty++) {
2931 int py = ty + 1;
2932 if (py >= height) py -= height;
2933
2934 for (int tx = 0; tx < width; tx++) {
2935 int px = tx + 1;
2936 if (px >= width) px -= width;
2937 float here = read_ptr[ty * width + tx];
2938 float to_right = read_ptr[ty * width + px];
2939 float above = read_ptr[py * width + tx];
2940 Vector3 up = Vector3(0, 1, (here - above) * bump_scale);
2941 Vector3 across = Vector3(1, 0, (to_right - here) * bump_scale);
2942
2943 Vector3 normal = across.cross(up);
2944 normal.normalize();
2945
2946 write_ptr[((ty * width + tx) << 2) + 0] = (127.5 + normal.x * 127.5);
2947 write_ptr[((ty * width + tx) << 2) + 1] = (127.5 + normal.y * 127.5);
2948 write_ptr[((ty * width + tx) << 2) + 2] = (127.5 + normal.z * 127.5);
2949 write_ptr[((ty * width + tx) << 2) + 3] = 255;
2950 }
2951 }
2952 }
2953 format = FORMAT_RGBA8;
2954 data = result_image;
2955 }
2956
srgb_to_linear()2957 void Image::srgb_to_linear() {
2958
2959 if (data.size() == 0)
2960 return;
2961
2962 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 };
2963
2964 ERR_FAIL_COND(format != FORMAT_RGB8 && format != FORMAT_RGBA8);
2965
2966 if (format == FORMAT_RGBA8) {
2967
2968 int len = data.size() / 4;
2969 PoolVector<uint8_t>::Write wp = data.write();
2970 unsigned char *data_ptr = wp.ptr();
2971
2972 for (int i = 0; i < len; i++) {
2973
2974 data_ptr[(i << 2) + 0] = srgb2lin[data_ptr[(i << 2) + 0]];
2975 data_ptr[(i << 2) + 1] = srgb2lin[data_ptr[(i << 2) + 1]];
2976 data_ptr[(i << 2) + 2] = srgb2lin[data_ptr[(i << 2) + 2]];
2977 }
2978
2979 } else if (format == FORMAT_RGB8) {
2980
2981 int len = data.size() / 3;
2982 PoolVector<uint8_t>::Write wp = data.write();
2983 unsigned char *data_ptr = wp.ptr();
2984
2985 for (int i = 0; i < len; i++) {
2986
2987 data_ptr[(i * 3) + 0] = srgb2lin[data_ptr[(i * 3) + 0]];
2988 data_ptr[(i * 3) + 1] = srgb2lin[data_ptr[(i * 3) + 1]];
2989 data_ptr[(i * 3) + 2] = srgb2lin[data_ptr[(i * 3) + 2]];
2990 }
2991 }
2992 }
2993
premultiply_alpha()2994 void Image::premultiply_alpha() {
2995
2996 if (data.size() == 0)
2997 return;
2998
2999 if (format != FORMAT_RGBA8)
3000 return; //not needed
3001
3002 PoolVector<uint8_t>::Write wp = data.write();
3003 unsigned char *data_ptr = wp.ptr();
3004
3005 for (int i = 0; i < height; i++) {
3006 for (int j = 0; j < width; j++) {
3007
3008 uint8_t *ptr = &data_ptr[(i * width + j) * 4];
3009
3010 ptr[0] = (uint16_t(ptr[0]) * uint16_t(ptr[3])) >> 8;
3011 ptr[1] = (uint16_t(ptr[1]) * uint16_t(ptr[3])) >> 8;
3012 ptr[2] = (uint16_t(ptr[2]) * uint16_t(ptr[3])) >> 8;
3013 }
3014 }
3015 }
3016
fix_alpha_edges()3017 void Image::fix_alpha_edges() {
3018
3019 if (data.size() == 0)
3020 return;
3021
3022 if (format != FORMAT_RGBA8)
3023 return; //not needed
3024
3025 PoolVector<uint8_t> dcopy = data;
3026 PoolVector<uint8_t>::Read rp = dcopy.read();
3027 const uint8_t *srcptr = rp.ptr();
3028
3029 PoolVector<uint8_t>::Write wp = data.write();
3030 unsigned char *data_ptr = wp.ptr();
3031
3032 const int max_radius = 4;
3033 const int alpha_threshold = 20;
3034 const int max_dist = 0x7FFFFFFF;
3035
3036 for (int i = 0; i < height; i++) {
3037 for (int j = 0; j < width; j++) {
3038
3039 const uint8_t *rptr = &srcptr[(i * width + j) * 4];
3040 uint8_t *wptr = &data_ptr[(i * width + j) * 4];
3041
3042 if (rptr[3] >= alpha_threshold)
3043 continue;
3044
3045 int closest_dist = max_dist;
3046 uint8_t closest_color[3];
3047
3048 int from_x = MAX(0, j - max_radius);
3049 int to_x = MIN(width - 1, j + max_radius);
3050 int from_y = MAX(0, i - max_radius);
3051 int to_y = MIN(height - 1, i + max_radius);
3052
3053 for (int k = from_y; k <= to_y; k++) {
3054 for (int l = from_x; l <= to_x; l++) {
3055
3056 int dy = i - k;
3057 int dx = j - l;
3058 int dist = dy * dy + dx * dx;
3059 if (dist >= closest_dist)
3060 continue;
3061
3062 const uint8_t *rp2 = &srcptr[(k * width + l) << 2];
3063
3064 if (rp2[3] < alpha_threshold)
3065 continue;
3066
3067 closest_dist = dist;
3068 closest_color[0] = rp2[0];
3069 closest_color[1] = rp2[1];
3070 closest_color[2] = rp2[2];
3071 }
3072 }
3073
3074 if (closest_dist != max_dist) {
3075
3076 wptr[0] = closest_color[0];
3077 wptr[1] = closest_color[1];
3078 wptr[2] = closest_color[2];
3079 }
3080 }
3081 }
3082 }
3083
get_format_name(Format p_format)3084 String Image::get_format_name(Format p_format) {
3085
3086 ERR_FAIL_INDEX_V(p_format, FORMAT_MAX, String());
3087 return format_names[p_format];
3088 }
3089
load_png_from_buffer(const PoolVector<uint8_t> & p_array)3090 Error Image::load_png_from_buffer(const PoolVector<uint8_t> &p_array) {
3091 return _load_from_buffer(p_array, _png_mem_loader_func);
3092 }
3093
load_jpg_from_buffer(const PoolVector<uint8_t> & p_array)3094 Error Image::load_jpg_from_buffer(const PoolVector<uint8_t> &p_array) {
3095 return _load_from_buffer(p_array, _jpg_mem_loader_func);
3096 }
3097
load_webp_from_buffer(const PoolVector<uint8_t> & p_array)3098 Error Image::load_webp_from_buffer(const PoolVector<uint8_t> &p_array) {
3099 return _load_from_buffer(p_array, _webp_mem_loader_func);
3100 }
3101
load_tga_from_buffer(const PoolVector<uint8_t> & p_array)3102 Error Image::load_tga_from_buffer(const PoolVector<uint8_t> &p_array) {
3103 ERR_FAIL_NULL_V_MSG(_tga_mem_loader_func, ERR_UNAVAILABLE, "TGA module was not installed.");
3104 return _load_from_buffer(p_array, _tga_mem_loader_func);
3105 }
3106
_load_from_buffer(const PoolVector<uint8_t> & p_array,ImageMemLoadFunc p_loader)3107 Error Image::_load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader) {
3108 int buffer_size = p_array.size();
3109
3110 ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
3111 ERR_FAIL_COND_V(!p_loader, ERR_INVALID_PARAMETER);
3112
3113 PoolVector<uint8_t>::Read r = p_array.read();
3114
3115 Ref<Image> image = p_loader(r.ptr(), buffer_size);
3116 ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
3117
3118 copy_internals_from(image);
3119
3120 return OK;
3121 }
3122
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)3123 void 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) {
3124 p_out = static_cast<uint8_t>((p_a + p_b + p_c + p_d + 2) >> 2);
3125 }
3126
average_4_float(float & p_out,const float & p_a,const float & p_b,const float & p_c,const float & p_d)3127 void Image::average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d) {
3128 p_out = (p_a + p_b + p_c + p_d) * 0.25f;
3129 }
3130
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)3131 void 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) {
3132 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);
3133 }
3134
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)3135 void 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) {
3136 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();
3137 }
3138
renormalize_uint8(uint8_t * p_rgb)3139 void Image::renormalize_uint8(uint8_t *p_rgb) {
3140 Vector3 n(p_rgb[0] / 255.0, p_rgb[1] / 255.0, p_rgb[2] / 255.0);
3141 n *= 2.0;
3142 n -= Vector3(1, 1, 1);
3143 n.normalize();
3144 n += Vector3(1, 1, 1);
3145 n *= 0.5;
3146 n *= 255;
3147 p_rgb[0] = CLAMP(int(n.x), 0, 255);
3148 p_rgb[1] = CLAMP(int(n.y), 0, 255);
3149 p_rgb[2] = CLAMP(int(n.z), 0, 255);
3150 }
3151
renormalize_float(float * p_rgb)3152 void Image::renormalize_float(float *p_rgb) {
3153 Vector3 n(p_rgb[0], p_rgb[1], p_rgb[2]);
3154 n.normalize();
3155 p_rgb[0] = n.x;
3156 p_rgb[1] = n.y;
3157 p_rgb[2] = n.z;
3158 }
3159
renormalize_half(uint16_t * p_rgb)3160 void Image::renormalize_half(uint16_t *p_rgb) {
3161 Vector3 n(Math::half_to_float(p_rgb[0]), Math::half_to_float(p_rgb[1]), Math::half_to_float(p_rgb[2]));
3162 n.normalize();
3163 p_rgb[0] = Math::make_half_float(n.x);
3164 p_rgb[1] = Math::make_half_float(n.y);
3165 p_rgb[2] = Math::make_half_float(n.z);
3166 }
3167
renormalize_rgbe9995(uint32_t * p_rgb)3168 void Image::renormalize_rgbe9995(uint32_t *p_rgb) {
3169 // Never used
3170 }
3171
Image(const uint8_t * p_mem_png_jpg,int p_len)3172 Image::Image(const uint8_t *p_mem_png_jpg, int p_len) {
3173
3174 width = 0;
3175 height = 0;
3176 mipmaps = false;
3177 format = FORMAT_L8;
3178
3179 if (_png_mem_loader_func) {
3180 copy_internals_from(_png_mem_loader_func(p_mem_png_jpg, p_len));
3181 }
3182
3183 if (empty() && _jpg_mem_loader_func) {
3184 copy_internals_from(_jpg_mem_loader_func(p_mem_png_jpg, p_len));
3185 }
3186 }
3187
duplicate(bool p_subresources) const3188 Ref<Resource> Image::duplicate(bool p_subresources) const {
3189
3190 Ref<Image> copy;
3191 copy.instance();
3192 copy->_copy_internals_from(*this);
3193 return copy;
3194 }
3195
Image()3196 Image::Image() {
3197
3198 width = 0;
3199 height = 0;
3200 mipmaps = false;
3201 format = FORMAT_L8;
3202 }
3203
~Image()3204 Image::~Image() {
3205
3206 if (write_lock.ptr()) {
3207 unlock();
3208 }
3209 }
3210