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