1 /**
2 * Copyright (c) 2006-2019 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21 #include "ImageData.h"
22 #include "Image.h"
23 #include "filesystem/Filesystem.h"
24
25 #include <algorithm> // min/max
26
27 using love::thread::Lock;
28
29 namespace love
30 {
31 namespace image
32 {
33
34 love::Type ImageData::type("ImageData", &Data::type);
35
ImageData(Data * data)36 ImageData::ImageData(Data *data)
37 : ImageDataBase(PIXELFORMAT_UNKNOWN, 0, 0)
38 {
39 decode(data);
40 }
41
ImageData(int width,int height,PixelFormat format)42 ImageData::ImageData(int width, int height, PixelFormat format)
43 : ImageDataBase(format, width, height)
44 {
45 if (!validPixelFormat(format))
46 throw love::Exception("Unsupported pixel format for ImageData");
47
48 create(width, height, format);
49
50 // Set to black/transparency.
51 memset(data, 0, getSize());
52 }
53
ImageData(int width,int height,PixelFormat format,void * data,bool own)54 ImageData::ImageData(int width, int height, PixelFormat format, void *data, bool own)
55 : ImageDataBase(format, width, height)
56 {
57 if (!validPixelFormat(format))
58 throw love::Exception("Unsupported pixel format for ImageData");
59
60 if (own)
61 this->data = (unsigned char *) data;
62 else
63 create(width, height, format, data);
64 }
65
ImageData(const ImageData & c)66 ImageData::ImageData(const ImageData &c)
67 : ImageDataBase(c.format, c.width, c.height)
68 {
69 create(width, height, format, c.getData());
70 }
71
~ImageData()72 ImageData::~ImageData()
73 {
74 if (decodeHandler.get())
75 decodeHandler->freeRawPixels(data);
76 else
77 delete[] data;
78 }
79
clone() const80 love::image::ImageData *ImageData::clone() const
81 {
82 return new ImageData(*this);
83 }
84
create(int width,int height,PixelFormat format,void * data)85 void ImageData::create(int width, int height, PixelFormat format, void *data)
86 {
87 size_t datasize = width * height * getPixelFormatSize(format);
88
89 try
90 {
91 this->data = new unsigned char[datasize];
92 }
93 catch(std::bad_alloc &)
94 {
95 throw love::Exception("Out of memory");
96 }
97
98 if (data)
99 memcpy(this->data, data, datasize);
100
101 decodeHandler = nullptr;
102 this->format = format;
103
104 pixelSetFunction = getPixelSetFunction(format);
105 pixelGetFunction = getPixelGetFunction(format);
106 }
107
decode(Data * data)108 void ImageData::decode(Data *data)
109 {
110 FormatHandler *decoder = nullptr;
111 FormatHandler::DecodedImage decodedimage;
112
113 auto module = Module::getInstance<Image>(Module::M_IMAGE);
114
115 if (module == nullptr)
116 throw love::Exception("love.image must be loaded in order to decode an ImageData.");
117
118 for (FormatHandler *handler : module->getFormatHandlers())
119 {
120 if (handler->canDecode(data))
121 {
122 decoder = handler;
123 break;
124 }
125 }
126
127 if (decoder)
128 decodedimage = decoder->decode(data);
129
130 if (decodedimage.data == nullptr)
131 {
132 auto filedata = dynamic_cast<filesystem::FileData *>(data);
133
134 if (filedata != nullptr)
135 {
136 const std::string &name = filedata->getFilename();
137 throw love::Exception("Could not decode file '%s' to ImageData: unsupported file format", name.c_str());
138 }
139 else
140 throw love::Exception("Could not decode data to ImageData: unsupported encoded format");
141 }
142
143 if (decodedimage.size != decodedimage.width * decodedimage.height * getPixelFormatSize(decodedimage.format))
144 {
145 decoder->freeRawPixels(decodedimage.data);
146 throw love::Exception("Could not convert image!");
147 }
148
149 // Clean up any old data.
150 if (decodeHandler)
151 decodeHandler->freeRawPixels(this->data);
152 else
153 delete[] this->data;
154
155 this->width = decodedimage.width;
156 this->height = decodedimage.height;
157 this->data = decodedimage.data;
158 this->format = decodedimage.format;
159
160 decodeHandler = decoder;
161
162 pixelSetFunction = getPixelSetFunction(format);
163 pixelGetFunction = getPixelGetFunction(format);
164 }
165
encode(FormatHandler::EncodedFormat encodedFormat,const char * filename,bool writefile) const166 love::filesystem::FileData *ImageData::encode(FormatHandler::EncodedFormat encodedFormat, const char *filename, bool writefile) const
167 {
168 FormatHandler *encoder = nullptr;
169 FormatHandler::EncodedImage encodedimage;
170 FormatHandler::DecodedImage rawimage;
171
172 rawimage.width = width;
173 rawimage.height = height;
174 rawimage.size = getSize();
175 rawimage.data = data;
176 rawimage.format = format;
177
178 auto module = Module::getInstance<Image>(Module::M_IMAGE);
179
180 if (module == nullptr)
181 throw love::Exception("love.image must be loaded in order to encode an ImageData.");
182
183 for (FormatHandler *handler : module->getFormatHandlers())
184 {
185 if (handler->canEncode(format, encodedFormat))
186 {
187 encoder = handler;
188 break;
189 }
190 }
191
192 if (encoder != nullptr)
193 {
194 thread::Lock lock(mutex);
195 encodedimage = encoder->encode(rawimage, encodedFormat);
196 }
197
198 if (encoder == nullptr || encodedimage.data == nullptr)
199 {
200 const char *fname = "unknown";
201 love::getConstant(format, fname);
202 throw love::Exception("No suitable image encoder for %s format.", fname);
203 }
204
205 love::filesystem::FileData *filedata = nullptr;
206
207 try
208 {
209 filedata = new love::filesystem::FileData(encodedimage.size, filename);
210 }
211 catch (love::Exception &)
212 {
213 encoder->freeRawPixels(encodedimage.data);
214 throw;
215 }
216
217 memcpy(filedata->getData(), encodedimage.data, encodedimage.size);
218 encoder->freeRawPixels(encodedimage.data);
219
220 if (writefile)
221 {
222 auto fs = Module::getInstance<filesystem::Filesystem>(Module::M_FILESYSTEM);
223
224 if (fs == nullptr)
225 {
226 filedata->release();
227 throw love::Exception("love.filesystem must be loaded in order to write an encoded ImageData to a file.");
228 }
229
230 try
231 {
232 fs->write(filename, filedata->getData(), filedata->getSize());
233 }
234 catch (love::Exception &)
235 {
236 filedata->release();
237 throw;
238 }
239 }
240
241 return filedata;
242 }
243
getSize() const244 size_t ImageData::getSize() const
245 {
246 return size_t(getWidth() * getHeight()) * getPixelSize();
247 }
248
getData() const249 void *ImageData::getData() const
250 {
251 return data;
252 }
253
isSRGB() const254 bool ImageData::isSRGB() const
255 {
256 return false;
257 }
258
inside(int x,int y) const259 bool ImageData::inside(int x, int y) const
260 {
261 return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
262 }
263
clamp01(float x)264 static float clamp01(float x)
265 {
266 return std::min(std::max(x, 0.0f), 1.0f);
267 }
268
setPixelR8(const Colorf & c,ImageData::Pixel * p)269 static void setPixelR8(const Colorf &c, ImageData::Pixel *p)
270 {
271 p->rgba8[0] = (uint8) (clamp01(c.r) * 255.0f + 0.5f);
272 }
273
setPixelRG8(const Colorf & c,ImageData::Pixel * p)274 static void setPixelRG8(const Colorf &c, ImageData::Pixel *p)
275 {
276 p->rgba8[0] = (uint8) (clamp01(c.r) * 255.0f + 0.5f);
277 p->rgba8[1] = (uint8) (clamp01(c.g) * 255.0f + 0.5f);
278 }
279
setPixelRGBA8(const Colorf & c,ImageData::Pixel * p)280 static void setPixelRGBA8(const Colorf &c, ImageData::Pixel *p)
281 {
282 p->rgba8[0] = (uint8) (clamp01(c.r) * 255.0f + 0.5f);
283 p->rgba8[1] = (uint8) (clamp01(c.g) * 255.0f + 0.5f);
284 p->rgba8[2] = (uint8) (clamp01(c.b) * 255.0f + 0.5f);
285 p->rgba8[3] = (uint8) (clamp01(c.a) * 255.0f + 0.5f);
286 }
287
setPixelR16(const Colorf & c,ImageData::Pixel * p)288 static void setPixelR16(const Colorf &c, ImageData::Pixel *p)
289 {
290 p->rgba16[0] = (uint16) (clamp01(c.r) * 65535.0f + 0.5f);
291 }
292
setPixelRG16(const Colorf & c,ImageData::Pixel * p)293 static void setPixelRG16(const Colorf &c, ImageData::Pixel *p)
294 {
295 p->rgba16[0] = (uint16) (clamp01(c.r) * 65535.0f + 0.5f);
296 p->rgba16[1] = (uint16) (clamp01(c.g) * 65535.0f + 0.5f);
297 }
298
setPixelRGBA16(const Colorf & c,ImageData::Pixel * p)299 static void setPixelRGBA16(const Colorf &c, ImageData::Pixel *p)
300 {
301 p->rgba16[0] = (uint16) (clamp01(c.r) * 65535.0f + 0.5f);
302 p->rgba16[1] = (uint16) (clamp01(c.b) * 65535.0f + 0.5f);
303 p->rgba16[2] = (uint16) (clamp01(c.g) * 65535.0f + 0.5f);
304 p->rgba16[3] = (uint16) (clamp01(c.a) * 65535.0f + 0.5f);
305 }
306
setPixelR16F(const Colorf & c,ImageData::Pixel * p)307 static void setPixelR16F(const Colorf &c, ImageData::Pixel *p)
308 {
309 p->rgba16f[0] = float32to16(c.r);
310 }
311
setPixelRG16F(const Colorf & c,ImageData::Pixel * p)312 static void setPixelRG16F(const Colorf &c, ImageData::Pixel *p)
313 {
314 p->rgba16f[0] = float32to16(c.r);
315 p->rgba16f[1] = float32to16(c.g);
316 }
317
setPixelRGBA16F(const Colorf & c,ImageData::Pixel * p)318 static void setPixelRGBA16F(const Colorf &c, ImageData::Pixel *p)
319 {
320 p->rgba16f[0] = float32to16(c.r);
321 p->rgba16f[1] = float32to16(c.g);
322 p->rgba16f[2] = float32to16(c.b);
323 p->rgba16f[3] = float32to16(c.a);
324 }
325
setPixelR32F(const Colorf & c,ImageData::Pixel * p)326 static void setPixelR32F(const Colorf &c, ImageData::Pixel *p)
327 {
328 p->rgba32f[0] = c.r;
329 }
330
setPixelRG32F(const Colorf & c,ImageData::Pixel * p)331 static void setPixelRG32F(const Colorf &c, ImageData::Pixel *p)
332 {
333 p->rgba32f[0] = c.r;
334 p->rgba32f[1] = c.g;
335 }
336
setPixelRGBA32F(const Colorf & c,ImageData::Pixel * p)337 static void setPixelRGBA32F(const Colorf &c, ImageData::Pixel *p)
338 {
339 p->rgba32f[0] = c.r;
340 p->rgba32f[1] = c.g;
341 p->rgba32f[2] = c.b;
342 p->rgba32f[3] = c.a;
343 }
344
setPixelRGBA4(const Colorf & c,ImageData::Pixel * p)345 static void setPixelRGBA4(const Colorf &c, ImageData::Pixel *p)
346 {
347 // LSB->MSB: [a, b, g, r]
348 uint16 r = (uint16) (clamp01(c.r) * 0xF + 0.5);
349 uint16 g = (uint16) (clamp01(c.g) * 0xF + 0.5);
350 uint16 b = (uint16) (clamp01(c.b) * 0xF + 0.5);
351 uint16 a = (uint16) (clamp01(c.a) * 0xF + 0.5);
352 p->packed16 = (r << 12) | (g << 8) | (b << 4) | (a << 0);
353 }
354
setPixelRGB5A1(const Colorf & c,ImageData::Pixel * p)355 static void setPixelRGB5A1(const Colorf &c, ImageData::Pixel *p)
356 {
357 // LSB->MSB: [a, b, g, r]
358 uint16 r = (uint16) (clamp01(c.r) * 0x1F + 0.5);
359 uint16 g = (uint16) (clamp01(c.g) * 0x1F + 0.5);
360 uint16 b = (uint16) (clamp01(c.b) * 0x1F + 0.5);
361 uint16 a = (uint16) (clamp01(c.a) * 0x1 + 0.5);
362 p->packed16 = (r << 11) | (g << 6) | (b << 1) | (a << 0);
363 }
364
setPixelRGB565(const Colorf & c,ImageData::Pixel * p)365 static void setPixelRGB565(const Colorf &c, ImageData::Pixel *p)
366 {
367 // LSB->MSB: [b, g, r]
368 uint16 r = (uint16) (clamp01(c.r) * 0x1F + 0.5);
369 uint16 g = (uint16) (clamp01(c.g) * 0x3F + 0.5);
370 uint16 b = (uint16) (clamp01(c.b) * 0x1F + 0.5);
371 p->packed16 = (r << 11) | (g << 5) | (b << 0);
372 }
373
setPixelRGB10A2(const Colorf & c,ImageData::Pixel * p)374 static void setPixelRGB10A2(const Colorf &c, ImageData::Pixel *p)
375 {
376 // LSB->MSB: [r, g, b, a]
377 uint32 r = (uint32) (clamp01(c.r) * 0x3FF + 0.5);
378 uint32 g = (uint32) (clamp01(c.g) * 0x3FF + 0.5);
379 uint32 b = (uint32) (clamp01(c.b) * 0x3FF + 0.5);
380 uint32 a = (uint32) (clamp01(c.a) * 0x3 + 0.5);
381 p->packed32 = (r << 0) | (g << 10) | (b << 20) | (a << 30);
382 }
383
setPixelRG11B10F(const Colorf & c,ImageData::Pixel * p)384 static void setPixelRG11B10F(const Colorf &c, ImageData::Pixel *p)
385 {
386 // LSB->MSB: [r, g, b]
387 float11 r = float32to11(c.r);
388 float11 g = float32to11(c.g);
389 float10 b = float32to10(c.b);
390 p->packed32 = (r << 0) | (g << 11) | (b << 22);
391 }
392
getPixelR8(const ImageData::Pixel * p,Colorf & c)393 static void getPixelR8(const ImageData::Pixel *p, Colorf &c)
394 {
395 c.r = p->rgba8[0] / 255.0f;
396 c.g = 0.0f;
397 c.b = 0.0f;
398 c.a = 1.0f;
399 }
400
getPixelRG8(const ImageData::Pixel * p,Colorf & c)401 static void getPixelRG8(const ImageData::Pixel *p, Colorf &c)
402 {
403 c.r = p->rgba8[0] / 255.0f;
404 c.g = p->rgba8[1] / 255.0f;
405 c.b = 0.0f;
406 c.a = 1.0f;
407 }
408
getPixelRGBA8(const ImageData::Pixel * p,Colorf & c)409 static void getPixelRGBA8(const ImageData::Pixel *p, Colorf &c)
410 {
411 c.r = p->rgba8[0] / 255.0f;
412 c.g = p->rgba8[1] / 255.0f;
413 c.b = p->rgba8[2] / 255.0f;
414 c.a = p->rgba8[3] / 255.0f;
415 }
416
getPixelR16(const ImageData::Pixel * p,Colorf & c)417 static void getPixelR16(const ImageData::Pixel *p, Colorf &c)
418 {
419 c.r = p->rgba16[0] / 65535.0f;
420 c.g = 0.0f;
421 c.b = 0.0f;
422 c.a = 1.0f;
423 }
424
getPixelRG16(const ImageData::Pixel * p,Colorf & c)425 static void getPixelRG16(const ImageData::Pixel *p, Colorf &c)
426 {
427 c.r = p->rgba16[0] / 65535.0f;
428 c.g = p->rgba16[1] / 65535.0f;
429 c.b = 0.0f;
430 c.a = 1.0f;
431 }
432
getPixelRGBA16(const ImageData::Pixel * p,Colorf & c)433 static void getPixelRGBA16(const ImageData::Pixel *p, Colorf &c)
434 {
435 c.r = p->rgba16[0] / 65535.0f;
436 c.g = p->rgba16[1] / 65535.0f;
437 c.b = p->rgba16[2] / 65535.0f;
438 c.a = p->rgba16[3] / 65535.0f;
439 }
440
getPixelR16F(const ImageData::Pixel * p,Colorf & c)441 static void getPixelR16F(const ImageData::Pixel *p, Colorf &c)
442 {
443 c.r = float16to32(p->rgba16f[0]);
444 c.g = 0.0f;
445 c.b = 0.0f;
446 c.a = 1.0f;
447 }
448
getPixelRG16F(const ImageData::Pixel * p,Colorf & c)449 static void getPixelRG16F(const ImageData::Pixel *p, Colorf &c)
450 {
451 c.r = float16to32(p->rgba16f[0]);
452 c.g = float16to32(p->rgba16f[1]);
453 c.b = 0.0f;
454 c.a = 1.0f;
455 }
456
getPixelRGBA16F(const ImageData::Pixel * p,Colorf & c)457 static void getPixelRGBA16F(const ImageData::Pixel *p, Colorf &c)
458 {
459 c.r = float16to32(p->rgba16f[0]);
460 c.g = float16to32(p->rgba16f[1]);
461 c.b = float16to32(p->rgba16f[2]);
462 c.a = float16to32(p->rgba16f[3]);
463 }
464
getPixelR32F(const ImageData::Pixel * p,Colorf & c)465 static void getPixelR32F(const ImageData::Pixel *p, Colorf &c)
466 {
467 c.r = p->rgba32f[0];
468 c.g = 0.0f;
469 c.b = 0.0f;
470 c.a = 1.0f;
471 }
472
getPixelRG32F(const ImageData::Pixel * p,Colorf & c)473 static void getPixelRG32F(const ImageData::Pixel *p, Colorf &c)
474 {
475 c.r = p->rgba32f[0];
476 c.g = p->rgba32f[1];
477 c.b = 0.0f;
478 c.a = 1.0f;
479 }
480
getPixelRGBA32F(const ImageData::Pixel * p,Colorf & c)481 static void getPixelRGBA32F(const ImageData::Pixel *p, Colorf &c)
482 {
483 c.r = p->rgba32f[0];
484 c.g = p->rgba32f[1];
485 c.b = p->rgba32f[2];
486 c.a = p->rgba32f[3];
487 }
488
getPixelRGBA4(const ImageData::Pixel * p,Colorf & c)489 static void getPixelRGBA4(const ImageData::Pixel *p, Colorf &c)
490 {
491 // LSB->MSB: [a, b, g, r]
492 c.r = ((p->packed16 >> 12) & 0xF) / (float)0xF;
493 c.g = ((p->packed16 >> 8) & 0xF) / (float)0xF;
494 c.b = ((p->packed16 >> 4) & 0xF) / (float)0xF;
495 c.a = ((p->packed16 >> 0) & 0xF) / (float)0xF;
496 }
497
getPixelRGB5A1(const ImageData::Pixel * p,Colorf & c)498 static void getPixelRGB5A1(const ImageData::Pixel *p, Colorf &c)
499 {
500 // LSB->MSB: [a, b, g, r]
501 c.r = ((p->packed16 >> 11) & 0x1F) / (float)0x1F;
502 c.g = ((p->packed16 >> 6) & 0x1F) / (float)0x1F;
503 c.b = ((p->packed16 >> 1) & 0x1F) / (float)0x1F;
504 c.a = ((p->packed16 >> 0) & 0x1) / (float)0x1;
505 }
506
getPixelRGB565(const ImageData::Pixel * p,Colorf & c)507 static void getPixelRGB565(const ImageData::Pixel *p, Colorf &c)
508 {
509 // LSB->MSB: [b, g, r]
510 c.r = ((p->packed16 >> 11) & 0x1F) / (float)0x1F;
511 c.g = ((p->packed16 >> 5) & 0x3F) / (float)0x3F;
512 c.b = ((p->packed16 >> 0) & 0x1F) / (float)0x1F;
513 c.a = 1.0f;
514 }
515
getPixelRGB10A2(const ImageData::Pixel * p,Colorf & c)516 static void getPixelRGB10A2(const ImageData::Pixel *p, Colorf &c)
517 {
518 // LSB->MSB: [r, g, b, a]
519 c.r = ((p->packed32 >> 0) & 0x3FF) / (float)0x3FF;
520 c.g = ((p->packed32 >> 10) & 0x3FF) / (float)0x3FF;
521 c.b = ((p->packed32 >> 20) & 0x3FF) / (float)0x3FF;
522 c.a = ((p->packed32 >> 30) & 0x3) / (float)0x3;
523 }
524
getPixelRG11B10F(const ImageData::Pixel * p,Colorf & c)525 static void getPixelRG11B10F(const ImageData::Pixel *p, Colorf &c)
526 {
527 // LSB->MSB: [r, g, b]
528 c.r = float11to32((float11) ((p->packed32 >> 0) & 0x7FF));
529 c.g = float11to32((float11) ((p->packed32 >> 11) & 0x7FF));
530 c.b = float10to32((float10) ((p->packed32 >> 22) & 0x3FF));
531 c.a = 1.0f;
532 }
533
setPixel(int x,int y,const Colorf & c)534 void ImageData::setPixel(int x, int y, const Colorf &c)
535 {
536 if (!inside(x, y))
537 throw love::Exception("Attempt to set out-of-range pixel!");
538
539 size_t pixelsize = getPixelSize();
540 Pixel *p = (Pixel *) (data + ((y * width + x) * pixelsize));
541
542 if (pixelSetFunction == nullptr)
543 throw love::Exception("Unhandled pixel format %d in ImageData::setPixel", format);
544
545 Lock lock(mutex);
546
547 pixelSetFunction(c, p);
548 }
549
getPixel(int x,int y,Colorf & c) const550 void ImageData::getPixel(int x, int y, Colorf &c) const
551 {
552 if (!inside(x, y))
553 throw love::Exception("Attempt to get out-of-range pixel!");
554
555 size_t pixelsize = getPixelSize();
556 const Pixel *p = (const Pixel *) (data + ((y * width + x) * pixelsize));
557
558 if (pixelGetFunction == nullptr)
559 throw love::Exception("Unhandled pixel format %d in ImageData::setPixel", format);
560
561 Lock lock(mutex);
562
563 pixelGetFunction(p, c);
564 }
565
getPixel(int x,int y) const566 Colorf ImageData::getPixel(int x, int y) const
567 {
568 Colorf c;
569 getPixel(x, y, c);
570 return c;
571 }
572
573 union Row
574 {
575 uint8 *u8;
576 uint16 *u16;
577 float16 *f16;
578 float *f32;
579 };
580
pasteRGBA8toRGBA16(Row src,Row dst,int w)581 static void pasteRGBA8toRGBA16(Row src, Row dst, int w)
582 {
583 for (int i = 0; i < w * 4; i++)
584 dst.u16[i] = (uint16) src.u8[i] << 8u;
585 }
586
pasteRGBA8toRGBA16F(Row src,Row dst,int w)587 static void pasteRGBA8toRGBA16F(Row src, Row dst, int w)
588 {
589 for (int i = 0; i < w * 4; i++)
590 dst.f16[i] = float32to16(src.u8[i] / 255.0f);
591 }
592
pasteRGBA8toRGBA32F(Row src,Row dst,int w)593 static void pasteRGBA8toRGBA32F(Row src, Row dst, int w)
594 {
595 for (int i = 0; i < w * 4; i++)
596 dst.f32[i] = src.u8[i] / 255.0f;
597 }
598
pasteRGBA16toRGBA8(Row src,Row dst,int w)599 static void pasteRGBA16toRGBA8(Row src, Row dst, int w)
600 {
601 for (int i = 0; i < w * 4; i++)
602 dst.u8[i] = src.u16[i] >> 8u;
603 }
604
pasteRGBA16toRGBA16F(Row src,Row dst,int w)605 static void pasteRGBA16toRGBA16F(Row src, Row dst, int w)
606 {
607 for (int i = 0; i < w * 4; i++)
608 dst.f16[i] = float32to16(src.u16[i] / 65535.0f);
609 }
610
pasteRGBA16toRGBA32F(Row src,Row dst,int w)611 static void pasteRGBA16toRGBA32F(Row src, Row dst, int w)
612 {
613 for (int i = 0; i < w * 4; i++)
614 dst.f32[i] = src.u16[i] / 65535.0f;
615 }
616
pasteRGBA16FtoRGBA8(Row src,Row dst,int w)617 static void pasteRGBA16FtoRGBA8(Row src, Row dst, int w)
618 {
619 for (int i = 0; i < w * 4; i++)
620 dst.u8[i] = (uint8) (clamp01(float16to32(src.f16[i])) * 255.0f + 0.5f);
621 }
622
pasteRGBA16FtoRGBA16(Row src,Row dst,int w)623 static void pasteRGBA16FtoRGBA16(Row src, Row dst, int w)
624 {
625 for (int i = 0; i < w * 4; i++)
626 dst.u16[i] = (uint16) (clamp01(float16to32(src.f16[i])) * 65535.0f + 0.5f);
627 }
628
pasteRGBA16FtoRGBA32F(Row src,Row dst,int w)629 static void pasteRGBA16FtoRGBA32F(Row src, Row dst, int w)
630 {
631 for (int i = 0; i < w * 4; i++)
632 dst.f32[i] = float16to32(src.f16[i]);
633 }
634
pasteRGBA32FtoRGBA8(Row src,Row dst,int w)635 static void pasteRGBA32FtoRGBA8(Row src, Row dst, int w)
636 {
637 for (int i = 0; i < w * 4; i++)
638 dst.u8[i] = (uint8) (clamp01(src.f32[i]) * 255.0f + 0.5f);
639 }
640
pasteRGBA32FtoRGBA16(Row src,Row dst,int w)641 static void pasteRGBA32FtoRGBA16(Row src, Row dst, int w)
642 {
643 for (int i = 0; i < w * 4; i++)
644 dst.u16[i] = (uint16) (clamp01(src.f32[i]) * 65535.0f + 0.5f);
645 }
646
pasteRGBA32FtoRGBA16F(Row src,Row dst,int w)647 static void pasteRGBA32FtoRGBA16F(Row src, Row dst, int w)
648 {
649 for (int i = 0; i < w * 4; i++)
650 dst.f16[i] = float32to16(src.f32[i]);
651 }
652
paste(ImageData * src,int dx,int dy,int sx,int sy,int sw,int sh)653 void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, int sh)
654 {
655 PixelFormat dstformat = getFormat();
656 PixelFormat srcformat = src->getFormat();
657
658 int srcW = src->getWidth();
659 int srcH = src->getHeight();
660 int dstW = getWidth();
661 int dstH = getHeight();
662
663 size_t srcpixelsize = src->getPixelSize();
664 size_t dstpixelsize = getPixelSize();
665
666 // Check bounds; if the data ends up completely out of bounds, get out early.
667 if (sx >= srcW || sx + sw < 0 || sy >= srcH || sy + sh < 0
668 || dx >= dstW || dx + sw < 0 || dy >= dstH || dy + sh < 0)
669 return;
670
671 // Normalize values to the inside of both images.
672 if (dx < 0)
673 {
674 sw += dx;
675 sx -= dx;
676 dx = 0;
677 }
678 if (dy < 0)
679 {
680 sh += dy;
681 sy -= dy;
682 dy = 0;
683 }
684 if (sx < 0)
685 {
686 sw += sx;
687 dx -= sx;
688 sx = 0;
689 }
690 if (sy < 0)
691 {
692 sh += sy;
693 dy -= sy;
694 sy = 0;
695 }
696
697 if (dx + sw > dstW)
698 sw = dstW - dx;
699
700 if (dy + sh > dstH)
701 sh = dstH - dy;
702
703 if (sx + sw > srcW)
704 sw = srcW - sx;
705
706 if (sy + sh > srcH)
707 sh = srcH - sy;
708
709 Lock lock2(src->mutex);
710 Lock lock1(mutex);
711
712 uint8 *s = (uint8 *) src->getData();
713 uint8 *d = (uint8 *) getData();
714
715 auto getfunction = src->pixelGetFunction;
716 auto setfunction = pixelSetFunction;
717
718 // If the dimensions match up, copy the entire memory stream in one go
719 if (srcformat == dstformat && (sw == dstW && dstW == srcW && sh == dstH && dstH == srcH))
720 {
721 memcpy(d, s, srcpixelsize * sw * sh);
722 }
723 else if (sw > 0)
724 {
725 // Otherwise, copy each row individually.
726 for (int i = 0; i < sh; i++)
727 {
728 Row rowsrc = {s + (sx + (i + sy) * srcW) * srcpixelsize};
729 Row rowdst = {d + (dx + (i + dy) * dstW) * dstpixelsize};
730
731 if (srcformat == dstformat)
732 memcpy(rowdst.u8, rowsrc.u8, srcpixelsize * sw);
733
734 else if (srcformat == PIXELFORMAT_RGBA8 && dstformat == PIXELFORMAT_RGBA16)
735 pasteRGBA8toRGBA16(rowsrc, rowdst, sw);
736 else if (srcformat == PIXELFORMAT_RGBA8 && dstformat == PIXELFORMAT_RGBA16F)
737 pasteRGBA8toRGBA16F(rowsrc, rowdst, sw);
738 else if (srcformat == PIXELFORMAT_RGBA8 && dstformat == PIXELFORMAT_RGBA32F)
739 pasteRGBA8toRGBA32F(rowsrc, rowdst, sw);
740
741 else if (srcformat == PIXELFORMAT_RGBA16 && dstformat == PIXELFORMAT_RGBA8)
742 pasteRGBA16toRGBA8(rowsrc, rowdst, sw);
743 else if (srcformat == PIXELFORMAT_RGBA16 && dstformat == PIXELFORMAT_RGBA16F)
744 pasteRGBA16toRGBA16F(rowsrc, rowdst, sw);
745 else if (srcformat == PIXELFORMAT_RGBA16 && dstformat == PIXELFORMAT_RGBA32F)
746 pasteRGBA16toRGBA32F(rowsrc, rowdst, sw);
747
748 else if (srcformat == PIXELFORMAT_RGBA16F && dstformat == PIXELFORMAT_RGBA8)
749 pasteRGBA16FtoRGBA8(rowsrc, rowdst, sw);
750 else if (srcformat == PIXELFORMAT_RGBA16F && dstformat == PIXELFORMAT_RGBA16)
751 pasteRGBA16FtoRGBA16(rowsrc, rowdst, sw);
752 else if (srcformat == PIXELFORMAT_RGBA16F && dstformat == PIXELFORMAT_RGBA32F)
753 pasteRGBA16FtoRGBA32F(rowsrc, rowdst, sw);
754
755 else if (srcformat == PIXELFORMAT_RGBA32F && dstformat == PIXELFORMAT_RGBA8)
756 pasteRGBA32FtoRGBA8(rowsrc, rowdst, sw);
757 else if (srcformat == PIXELFORMAT_RGBA32F && dstformat == PIXELFORMAT_RGBA16)
758 pasteRGBA32FtoRGBA16(rowsrc, rowdst, sw);
759 else if (srcformat == PIXELFORMAT_RGBA32F && dstformat == PIXELFORMAT_RGBA16F)
760 pasteRGBA32FtoRGBA16F(rowsrc, rowdst, sw);
761
762 else
763 {
764 // Slow path: convert src -> Colorf -> dst.
765 Colorf c;
766 for (int x = 0; x < sw; x++)
767 {
768 auto srcp = (const Pixel *) (rowsrc.u8 + x * srcpixelsize);
769 auto dstp = (Pixel *) (rowdst.u8 + x * dstpixelsize);
770 getfunction(srcp, c);
771 setfunction(c, dstp);
772 }
773 }
774 }
775 }
776 }
777
getMutex() const778 love::thread::Mutex *ImageData::getMutex() const
779 {
780 return mutex;
781 }
782
getPixelSize() const783 size_t ImageData::getPixelSize() const
784 {
785 return getPixelFormatSize(format);
786 }
787
validPixelFormat(PixelFormat format)788 bool ImageData::validPixelFormat(PixelFormat format)
789 {
790 switch (format)
791 {
792 case PIXELFORMAT_R8:
793 case PIXELFORMAT_RG8:
794 case PIXELFORMAT_RGBA8:
795 case PIXELFORMAT_R16:
796 case PIXELFORMAT_RG16:
797 case PIXELFORMAT_RGBA16:
798 case PIXELFORMAT_R16F:
799 case PIXELFORMAT_RG16F:
800 case PIXELFORMAT_RGBA16F:
801 case PIXELFORMAT_R32F:
802 case PIXELFORMAT_RG32F:
803 case PIXELFORMAT_RGBA32F:
804 case PIXELFORMAT_RGBA4:
805 case PIXELFORMAT_RGB5A1:
806 case PIXELFORMAT_RGB565:
807 case PIXELFORMAT_RGB10A2:
808 case PIXELFORMAT_RG11B10F:
809 return true;
810 default:
811 return false;
812 }
813 }
814
canPaste(PixelFormat src,PixelFormat dst)815 bool ImageData::canPaste(PixelFormat src, PixelFormat dst)
816 {
817 if (src == dst)
818 return true;
819
820 if (!(src == PIXELFORMAT_RGBA8 || src == PIXELFORMAT_RGBA16
821 || src == PIXELFORMAT_RGBA16F || src == PIXELFORMAT_RGBA32F))
822 return false;
823
824 if (!(dst == PIXELFORMAT_RGBA8 || dst == PIXELFORMAT_RGBA16
825 || dst == PIXELFORMAT_RGBA16F || dst == PIXELFORMAT_RGBA32F))
826 return false;
827
828 return true;
829 }
830
getPixelSetFunction(PixelFormat format)831 ImageData::PixelSetFunction ImageData::getPixelSetFunction(PixelFormat format)
832 {
833 switch (format)
834 {
835 case PIXELFORMAT_R8: return setPixelR8;
836 case PIXELFORMAT_RG8: return setPixelRG8;
837 case PIXELFORMAT_RGBA8: return setPixelRGBA8;
838 case PIXELFORMAT_R16: return setPixelR16;
839 case PIXELFORMAT_RG16: return setPixelRG16;
840 case PIXELFORMAT_RGBA16: return setPixelRGBA16;
841 case PIXELFORMAT_R16F: return setPixelR16F;
842 case PIXELFORMAT_RG16F: return setPixelRG16F;
843 case PIXELFORMAT_RGBA16F: return setPixelRGBA16F;
844 case PIXELFORMAT_R32F: return setPixelR32F;
845 case PIXELFORMAT_RG32F: return setPixelRG32F;
846 case PIXELFORMAT_RGBA32F: return setPixelRGBA32F;
847 case PIXELFORMAT_RGBA4: return setPixelRGBA4;
848 case PIXELFORMAT_RGB5A1: return setPixelRGB5A1;
849 case PIXELFORMAT_RGB565: return setPixelRGB565;
850 case PIXELFORMAT_RGB10A2: return setPixelRGB10A2;
851 case PIXELFORMAT_RG11B10F: return setPixelRG11B10F;
852 default: return nullptr;
853 }
854 }
855
getPixelGetFunction(PixelFormat format)856 ImageData::PixelGetFunction ImageData::getPixelGetFunction(PixelFormat format)
857 {
858 switch (format)
859 {
860 case PIXELFORMAT_R8: return getPixelR8;
861 case PIXELFORMAT_RG8: return getPixelRG8;
862 case PIXELFORMAT_RGBA8: return getPixelRGBA8;
863 case PIXELFORMAT_R16: return getPixelR16;
864 case PIXELFORMAT_RG16: return getPixelRG16;
865 case PIXELFORMAT_RGBA16: return getPixelRGBA16;
866 case PIXELFORMAT_R16F: return getPixelR16F;
867 case PIXELFORMAT_RG16F: return getPixelRG16F;
868 case PIXELFORMAT_RGBA16F: return getPixelRGBA16F;
869 case PIXELFORMAT_R32F: return getPixelR32F;
870 case PIXELFORMAT_RG32F: return getPixelRG32F;
871 case PIXELFORMAT_RGBA32F: return getPixelRGBA32F;
872 case PIXELFORMAT_RGBA4: return getPixelRGBA4;
873 case PIXELFORMAT_RGB5A1: return getPixelRGB5A1;
874 case PIXELFORMAT_RGB565: return getPixelRGB565;
875 case PIXELFORMAT_RGB10A2: return getPixelRGB10A2;
876 case PIXELFORMAT_RG11B10F: return getPixelRG11B10F;
877 default: return nullptr;
878 }
879 }
880
getConstant(const char * in,FormatHandler::EncodedFormat & out)881 bool ImageData::getConstant(const char *in, FormatHandler::EncodedFormat &out)
882 {
883 return encodedFormats.find(in, out);
884 }
885
getConstant(FormatHandler::EncodedFormat in,const char * & out)886 bool ImageData::getConstant(FormatHandler::EncodedFormat in, const char *&out)
887 {
888 return encodedFormats.find(in, out);
889 }
890
getConstants(FormatHandler::EncodedFormat)891 std::vector<std::string> ImageData::getConstants(FormatHandler::EncodedFormat)
892 {
893 return encodedFormats.getNames();
894 }
895
896 StringMap<FormatHandler::EncodedFormat, FormatHandler::ENCODED_MAX_ENUM>::Entry ImageData::encodedFormatEntries[] =
897 {
898 {"tga", FormatHandler::ENCODED_TGA},
899 {"png", FormatHandler::ENCODED_PNG},
900 };
901
902 StringMap<FormatHandler::EncodedFormat, FormatHandler::ENCODED_MAX_ENUM> ImageData::encodedFormats(ImageData::encodedFormatEntries, sizeof(ImageData::encodedFormatEntries));
903
904 } // image
905 } // love
906