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