1/**
2 * Copyright (c) 2006-2023 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// LOVE
22#include "Image.h"
23#include "common/config.h"
24
25#include "magpie/PNGHandler.h"
26#include "magpie/STBHandler.h"
27#include "magpie/EXRHandler.h"
28
29#include "magpie/ddsHandler.h"
30#include "magpie/PVRHandler.h"
31#include "magpie/KTXHandler.h"
32#include "magpie/PKMHandler.h"
33#include "magpie/ASTCHandler.h"
34
35namespace love
36{
37namespace image
38{
39
40love::Type Image::type("image", &Module::type);
41
42Image::Image()
43{
44 using namespace magpie;
45
46 float16Init(); // Makes sure half-float conversions can be used.
47
48 formatHandlers = {
49 new PNGHandler,
50 new STBHandler,
51 new EXRHandler,
52 new DDSHandler,
53 new PVRHandler,
54 new KTXHandler,
55 new PKMHandler,
56 new ASTCHandler,
57 };
58}
59
60Image::~Image()
61{
62 // ImageData objects reference the FormatHandlers in our list, so we should
63 // release them instead of deleting them completely here.
64 for (FormatHandler *handler : formatHandlers)
65 handler->release();
66}
67
68const char *Image::getName() const
69{
70 return "love.image.magpie";
71}
72
73love::image::ImageData *Image::newImageData(Data *data)
74{
75 return new ImageData(data);
76}
77
78love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format)
79{
80 return new ImageData(width, height, format);
81}
82
83love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format, void *data, bool own)
84{
85 return new ImageData(width, height, format, data, own);
86}
87
88love::image::CompressedImageData *Image::newCompressedData(Data *data)
89{
90 return new CompressedImageData(formatHandlers, data);
91}
92
93bool Image::isCompressed(Data *data)
94{
95 for (FormatHandler *handler : formatHandlers)
96 {
97 if (handler->canParseCompressed(data))
98 return true;
99 }
100
101 return false;
102}
103
104const std::list<FormatHandler *> &Image::getFormatHandlers() const
105{
106 return formatHandlers;
107}
108
109ImageData *Image::newPastedImageData(ImageData *src, int sx, int sy, int w, int h)
110{
111 ImageData *res = newImageData(w, h, src->getFormat());
112 try
113 {
114 res->paste(src, 0, 0, sx, sy, w, h);
115 }
116 catch (love::Exception &)
117 {
118 res->release();
119 throw;
120 }
121 return res;
122}
123
124std::vector<StrongRef<ImageData>> Image::newCubeFaces(love::image::ImageData *src)
125{
126 // The faces array is always ordered +x, -x, +y, -y, +z, -z.
127 std::vector<StrongRef<ImageData>> faces;
128
129 int totalW = src->getWidth();
130 int totalH = src->getHeight();
131
132 if (totalW % 3 == 0 && totalH % 4 == 0 && totalW / 3 == totalH / 4)
133 {
134 // +y
135 // +z +x -z
136 // -y
137 // -x
138
139 int w = totalW / 3;
140 int h = totalH / 4;
141
142 faces.emplace_back(newPastedImageData(src, 1*w, 1*h, w, h), Acquire::NORETAIN);
143 faces.emplace_back(newPastedImageData(src, 1*w, 3*h, w, h), Acquire::NORETAIN);
144 faces.emplace_back(newPastedImageData(src, 1*w, 0*h, w, h), Acquire::NORETAIN);
145 faces.emplace_back(newPastedImageData(src, 1*w, 2*h, w, h), Acquire::NORETAIN);
146 faces.emplace_back(newPastedImageData(src, 0*w, 1*h, w, h), Acquire::NORETAIN);
147 faces.emplace_back(newPastedImageData(src, 2*w, 1*h, w, h), Acquire::NORETAIN);
148 }
149 else if (totalW % 4 == 0 && totalH % 3 == 0 && totalW / 4 == totalH / 3)
150 {
151 // +y
152 // -x +z +x -z
153 // -y
154
155 int w = totalW / 4;
156 int h = totalH / 3;
157
158 faces.emplace_back(newPastedImageData(src, 2*w, 1*h, w, h), Acquire::NORETAIN);
159 faces.emplace_back(newPastedImageData(src, 0*w, 1*h, w, h), Acquire::NORETAIN);
160 faces.emplace_back(newPastedImageData(src, 1*w, 0*h, w, h), Acquire::NORETAIN);
161 faces.emplace_back(newPastedImageData(src, 1*w, 2*h, w, h), Acquire::NORETAIN);
162 faces.emplace_back(newPastedImageData(src, 1*w, 1*h, w, h), Acquire::NORETAIN);
163 faces.emplace_back(newPastedImageData(src, 3*w, 1*h, w, h), Acquire::NORETAIN);
164 }
165 else if (totalH % 6 == 0 && totalW == totalH / 6)
166 {
167 // +x
168 // -x
169 // +y
170 // -y
171 // +z
172 // -z
173
174 int w = totalW;
175 int h = totalH / 6;
176
177 for (int i = 0; i < 6; i++)
178 faces.emplace_back(newPastedImageData(src, 0, i * h, w, h), Acquire::NORETAIN);
179 }
180 else if (totalW % 6 == 0 && totalW / 6 == totalH)
181 {
182 // +x -x +y -y +z -z
183
184 int w = totalW / 6;
185 int h = totalH;
186
187 for (int i = 0; i < 6; i++)
188 faces.emplace_back(newPastedImageData(src, i * w, 0, w, h), Acquire::NORETAIN);
189 }
190 else
191 throw love::Exception("Unknown cubemap image dimensions!");
192
193 return faces;
194}
195
196std::vector<StrongRef<ImageData>> Image::newVolumeLayers(ImageData *src)
197{
198 std::vector<StrongRef<ImageData>> layers;
199
200 int totalW = src->getWidth();
201 int totalH = src->getHeight();
202
203 if (totalW % totalH == 0)
204 {
205 for (int i = 0; i < totalW / totalH; i++)
206 layers.emplace_back(newPastedImageData(src, i * totalH, 0, totalH, totalH), Acquire::NORETAIN);
207 }
208 else if (totalH % totalW == 0)
209 {
210 for (int i = 0; i < totalH / totalW; i++)
211 layers.emplace_back(newPastedImageData(src, 0, i * totalW, totalW, totalW), Acquire::NORETAIN);
212 }
213 else
214 throw love::Exception("Cannot extract volume layers from source ImageData.");
215
216 return layers;
217}
218
219} // image
220} // love
221