diff options
author | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
commit | 7028cbe09c688437910a25623098762bf0fa592d (patch) | |
tree | 10b5af58277d9880380c2251f109325542c4e6eb /src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp | |
parent | Move lemon to the src/others directory. (diff) | |
download | SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.zip SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.gz SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.bz2 SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.xz |
Move Irrlicht to src/others.
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp')
-rw-r--r-- | src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp new file mode 100644 index 0000000..3eb5c3b --- /dev/null +++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp | |||
@@ -0,0 +1,375 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "CImageLoaderPSD.h" | ||
6 | |||
7 | #ifdef _IRR_COMPILE_WITH_PSD_LOADER_ | ||
8 | |||
9 | #include "IReadFile.h" | ||
10 | #include "os.h" | ||
11 | #include "CImage.h" | ||
12 | #include "irrString.h" | ||
13 | |||
14 | |||
15 | namespace irr | ||
16 | { | ||
17 | namespace video | ||
18 | { | ||
19 | |||
20 | |||
21 | //! constructor | ||
22 | CImageLoaderPSD::CImageLoaderPSD() | ||
23 | { | ||
24 | #ifdef _DEBUG | ||
25 | setDebugName("CImageLoaderPSD"); | ||
26 | #endif | ||
27 | } | ||
28 | |||
29 | |||
30 | //! returns true if the file maybe is able to be loaded by this class | ||
31 | //! based on the file extension (e.g. ".tga") | ||
32 | bool CImageLoaderPSD::isALoadableFileExtension(const io::path& filename) const | ||
33 | { | ||
34 | return core::hasFileExtension ( filename, "psd" ); | ||
35 | } | ||
36 | |||
37 | |||
38 | |||
39 | //! returns true if the file maybe is able to be loaded by this class | ||
40 | bool CImageLoaderPSD::isALoadableFileFormat(io::IReadFile* file) const | ||
41 | { | ||
42 | if (!file) | ||
43 | return false; | ||
44 | |||
45 | u8 type[3]; | ||
46 | file->read(&type, sizeof(u8)*3); | ||
47 | return (type[2]==2); // we currently only handle tgas of type 2. | ||
48 | } | ||
49 | |||
50 | |||
51 | |||
52 | //! creates a surface from the file | ||
53 | IImage* CImageLoaderPSD::loadImage(io::IReadFile* file) const | ||
54 | { | ||
55 | u32* imageData = 0; | ||
56 | |||
57 | PsdHeader header; | ||
58 | file->read(&header, sizeof(PsdHeader)); | ||
59 | |||
60 | #ifndef __BIG_ENDIAN__ | ||
61 | header.version = os::Byteswap::byteswap(header.version); | ||
62 | header.channels = os::Byteswap::byteswap(header.channels); | ||
63 | header.height = os::Byteswap::byteswap(header.height); | ||
64 | header.width = os::Byteswap::byteswap(header.width); | ||
65 | header.depth = os::Byteswap::byteswap(header.depth); | ||
66 | header.mode = os::Byteswap::byteswap(header.mode); | ||
67 | #endif | ||
68 | |||
69 | if (header.signature[0] != '8' || | ||
70 | header.signature[1] != 'B' || | ||
71 | header.signature[2] != 'P' || | ||
72 | header.signature[3] != 'S') | ||
73 | return 0; | ||
74 | |||
75 | if (header.version != 1) | ||
76 | { | ||
77 | os::Printer::log("Unsupported PSD file version", file->getFileName(), ELL_ERROR); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | if (header.mode != 3 || header.depth != 8) | ||
82 | { | ||
83 | os::Printer::log("Unsupported PSD color mode or depth.\n", file->getFileName(), ELL_ERROR); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | // skip color mode data | ||
88 | |||
89 | u32 l; | ||
90 | file->read(&l, sizeof(u32)); | ||
91 | #ifndef __BIG_ENDIAN__ | ||
92 | l = os::Byteswap::byteswap(l); | ||
93 | #endif | ||
94 | if (!file->seek(l, true)) | ||
95 | { | ||
96 | os::Printer::log("Error seeking file pos to image resources.\n", file->getFileName(), ELL_ERROR); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | // skip image resources | ||
101 | |||
102 | file->read(&l, sizeof(u32)); | ||
103 | #ifndef __BIG_ENDIAN__ | ||
104 | l = os::Byteswap::byteswap(l); | ||
105 | #endif | ||
106 | if (!file->seek(l, true)) | ||
107 | { | ||
108 | os::Printer::log("Error seeking file pos to layer and mask.\n", file->getFileName(), ELL_ERROR); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | // skip layer & mask | ||
113 | |||
114 | file->read(&l, sizeof(u32)); | ||
115 | #ifndef __BIG_ENDIAN__ | ||
116 | l = os::Byteswap::byteswap(l); | ||
117 | #endif | ||
118 | if (!file->seek(l, true)) | ||
119 | { | ||
120 | os::Printer::log("Error seeking file pos to image data section.\n", file->getFileName(), ELL_ERROR); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | // read image data | ||
125 | |||
126 | u16 compressionType; | ||
127 | file->read(&compressionType, sizeof(u16)); | ||
128 | #ifndef __BIG_ENDIAN__ | ||
129 | compressionType = os::Byteswap::byteswap(compressionType); | ||
130 | #endif | ||
131 | |||
132 | if (compressionType != 1 && compressionType != 0) | ||
133 | { | ||
134 | os::Printer::log("Unsupported psd compression mode.\n", file->getFileName(), ELL_ERROR); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | // create image data block | ||
139 | |||
140 | imageData = new u32[header.width * header.height]; | ||
141 | |||
142 | bool res = false; | ||
143 | |||
144 | if (compressionType == 0) | ||
145 | res = readRawImageData(file, header, imageData); // RAW image data | ||
146 | else | ||
147 | res = readRLEImageData(file, header, imageData); // RLE compressed data | ||
148 | |||
149 | video::IImage* image = 0; | ||
150 | |||
151 | if (res) | ||
152 | { | ||
153 | // create surface | ||
154 | image = new CImage(ECF_A8R8G8B8, | ||
155 | core::dimension2d<u32>(header.width, header.height), imageData); | ||
156 | } | ||
157 | |||
158 | if (!image) | ||
159 | delete [] imageData; | ||
160 | imageData = 0; | ||
161 | |||
162 | return image; | ||
163 | } | ||
164 | |||
165 | |||
166 | bool CImageLoaderPSD::readRawImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const | ||
167 | { | ||
168 | u8* tmpData = new u8[header.width * header.height]; | ||
169 | |||
170 | for (s32 channel=0; channel<header.channels && channel < 3; ++channel) | ||
171 | { | ||
172 | if (!file->read(tmpData, sizeof(c8) * header.width * header.height)) | ||
173 | { | ||
174 | os::Printer::log("Error reading color channel\n", file->getFileName(), ELL_ERROR); | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | s16 shift = getShiftFromChannel((c8)channel, header); | ||
179 | if (shift != -1) | ||
180 | { | ||
181 | u32 mask = 0xff << shift; | ||
182 | |||
183 | for (u32 x=0; x<header.width; ++x) | ||
184 | { | ||
185 | for (u32 y=0; y<header.height; ++y) | ||
186 | { | ||
187 | s32 index = x + y*header.width; | ||
188 | imageData[index] = ~(~imageData[index] | mask); | ||
189 | imageData[index] |= tmpData[index] << shift; | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | |||
194 | } | ||
195 | |||
196 | delete [] tmpData; | ||
197 | return true; | ||
198 | } | ||
199 | |||
200 | |||
201 | bool CImageLoaderPSD::readRLEImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const | ||
202 | { | ||
203 | /* If the compression code is 1, the image data | ||
204 | starts with the byte counts for all the scan lines in the channel | ||
205 | (LayerBottom LayerTop), with each count stored as a two | ||
206 | byte value. The RLE compressed data follows, with each scan line | ||
207 | compressed separately. The RLE compression is the same compres-sion | ||
208 | algorithm used by the Macintosh ROM routine PackBits, and | ||
209 | the TIFF standard. | ||
210 | If the Layer's Size, and therefore the data, is odd, a pad byte will | ||
211 | be inserted at the end of the row. | ||
212 | */ | ||
213 | |||
214 | /* | ||
215 | A pseudo code fragment to unpack might look like this: | ||
216 | |||
217 | Loop until you get the number of unpacked bytes you are expecting: | ||
218 | Read the next source byte into n. | ||
219 | If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. | ||
220 | Else if n is between -127 and -1 inclusive, copy the next byte -n+1 | ||
221 | times. | ||
222 | Else if n is -128, noop. | ||
223 | Endloop | ||
224 | |||
225 | In the inverse routine, it is best to encode a 2-byte repeat run as a replicate run | ||
226 | except when preceded and followed by a literal run. In that case, it is best to merge | ||
227 | the three runs into one literal run. Always encode 3-byte repeats as replicate runs. | ||
228 | That is the essence of the algorithm. Here are some additional rules: | ||
229 | - Pack each row separately. Do not compress across row boundaries. | ||
230 | - The number of uncompressed bytes per row is defined to be (ImageWidth + 7) | ||
231 | / 8. If the uncompressed bitmap is required to have an even number of bytes per | ||
232 | row, decompress into word-aligned buffers. | ||
233 | - If a run is larger than 128 bytes, encode the remainder of the run as one or more | ||
234 | additional replicate runs. | ||
235 | When PackBits data is decompressed, the result should be interpreted as per com-pression | ||
236 | type 1 (no compression). | ||
237 | */ | ||
238 | |||
239 | u8* tmpData = new u8[header.width * header.height]; | ||
240 | u16 *rleCount= new u16 [header.height * header.channels]; | ||
241 | |||
242 | s32 size=0; | ||
243 | |||
244 | for (u32 y=0; y<header.height * header.channels; ++y) | ||
245 | { | ||
246 | if (!file->read(&rleCount[y], sizeof(u16))) | ||
247 | { | ||
248 | delete [] tmpData; | ||
249 | delete [] rleCount; | ||
250 | os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR); | ||
251 | return false; | ||
252 | } | ||
253 | |||
254 | #ifndef __BIG_ENDIAN__ | ||
255 | rleCount[y] = os::Byteswap::byteswap(rleCount[y]); | ||
256 | #endif | ||
257 | size += rleCount[y]; | ||
258 | } | ||
259 | |||
260 | s8 *buf = new s8[size]; | ||
261 | if (!file->read(buf, size)) | ||
262 | { | ||
263 | delete [] rleCount; | ||
264 | delete [] buf; | ||
265 | delete [] tmpData; | ||
266 | os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR); | ||
267 | return false; | ||
268 | } | ||
269 | |||
270 | u16 *rcount=rleCount; | ||
271 | |||
272 | s8 rh; | ||
273 | u16 bytesRead; | ||
274 | u8 *dest; | ||
275 | s8 *pBuf = buf; | ||
276 | |||
277 | // decompress packbit rle | ||
278 | |||
279 | for (s32 channel=0; channel<header.channels; channel++) | ||
280 | { | ||
281 | for (u32 y=0; y<header.height; ++y, ++rcount) | ||
282 | { | ||
283 | bytesRead=0; | ||
284 | dest = &tmpData[y*header.width]; | ||
285 | |||
286 | while (bytesRead < *rcount) | ||
287 | { | ||
288 | rh = *pBuf++; | ||
289 | ++bytesRead; | ||
290 | |||
291 | if (rh >= 0) | ||
292 | { | ||
293 | ++rh; | ||
294 | |||
295 | while (rh--) | ||
296 | { | ||
297 | *dest = *pBuf++; | ||
298 | ++bytesRead; | ||
299 | ++dest; | ||
300 | } | ||
301 | } | ||
302 | else | ||
303 | if (rh > -128) | ||
304 | { | ||
305 | rh = -rh +1; | ||
306 | |||
307 | while (rh--) | ||
308 | { | ||
309 | *dest = *pBuf; | ||
310 | ++dest; | ||
311 | } | ||
312 | |||
313 | ++pBuf; | ||
314 | ++bytesRead; | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | |||
319 | s16 shift = getShiftFromChannel((c8)channel, header); | ||
320 | |||
321 | if (shift != -1) | ||
322 | { | ||
323 | u32 mask = 0xff << shift; | ||
324 | |||
325 | for (u32 x=0; x<header.width; ++x) | ||
326 | for (u32 y=0; y<header.height; ++y) | ||
327 | { | ||
328 | s32 index = x + y*header.width; | ||
329 | imageData[index] = ~(~imageData[index] | mask); | ||
330 | imageData[index] |= tmpData[index] << shift; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | |||
335 | delete [] rleCount; | ||
336 | delete [] buf; | ||
337 | delete [] tmpData; | ||
338 | |||
339 | return true; | ||
340 | } | ||
341 | |||
342 | |||
343 | s16 CImageLoaderPSD::getShiftFromChannel(c8 channelNr, const PsdHeader& header) const | ||
344 | { | ||
345 | switch(channelNr) | ||
346 | { | ||
347 | case 0: | ||
348 | return 16; // red | ||
349 | case 1: | ||
350 | return 8; // green | ||
351 | case 2: | ||
352 | return 0; // blue | ||
353 | case 3: | ||
354 | return header.channels == 4 ? 24 : -1; // ? | ||
355 | case 4: | ||
356 | return 24; // alpha | ||
357 | default: | ||
358 | return -1; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | |||
363 | |||
364 | //! creates a loader which is able to load tgas | ||
365 | IImageLoader* createImageLoaderPSD() | ||
366 | { | ||
367 | return new CImageLoaderPSD(); | ||
368 | } | ||
369 | |||
370 | |||
371 | } // end namespace video | ||
372 | } // end namespace irr | ||
373 | |||
374 | #endif | ||
375 | |||