]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CImageLoaderRGB.cpp
1f0b141e1591db9dafd265191c594a4eded50557
[irrlicht.git] / source / Irrlicht / CImageLoaderRGB.cpp
1 //! Copyright (C) 2009-2012 Gary Conway\r
2 //! This file is part of the "Irrlicht Engine".\r
3 //! For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 /*\r
6         Author: Gary Conway (Viper) - co-author of the ZIP file format, Feb 1989,\r
7                                                  see the story at http://www.idcnet.us/ziphistory.html\r
8         Website:        http://idcnet.us\r
9         Email:          codeslinger@vipergc.com\r
10         Created:        March 1, 2009\r
11         Version:        1.0\r
12         Updated:\r
13 \r
14         This module will load SGI .rgb files (along with the other extensions). The module complies\r
15         with version 1.0 of the SGI Image File Format by Paul Haeberli of Silicon Graphics Computer Systems\r
16         The module handles BW, RGB and RGBA images.\r
17 \r
18         RGB images are stored with either 8 bits per COLOR VALUE, one each for red,green,blue (24bpp)\r
19         or 16 bits per COLOR VALUE, again one each for red,green,blue  (48 bpp), not including the alpha channel\r
20 \r
21 \r
22         OPTIONS NOT SUPPORTED\r
23 \r
24         1.      16 bit COLOR VALUES (48bpp modes)\r
25         2.      COLORMAP = DITHERED mode\r
26 \r
27 \r
28 \r
29 For non- run length encoded files, this is the structure\r
30 \r
31         The Header\r
32         The Image Data\r
33 \r
34 If the image is run length encoded, this is the structure:\r
35         The Header\r
36         The Offset Tables\r
37         The Image Data\r
38 \r
39 The Header consists of the following:\r
40 \r
41         Size  | Type   | Name      | Description\r
42 \r
43       2 bytes | short  | MAGIC     | IRIS image file magic number\r
44       1 byte  | char   | STORAGE   | Storage format\r
45       1 byte  | char   | BPC       | Number of bytes per pixel channel\r
46       2 bytes | ushort | DIMENSION | Number of dimensions\r
47       2 bytes | ushort | XSIZE     | X size in pixels\r
48       2 bytes | ushort | YSIZE     | Y size in pixels\r
49       2 bytes | ushort | ZSIZE     | Number of channels\r
50       4 bytes | long   | PIXMIN    | Minimum pixel value\r
51       4 bytes | long   | PIXMAX    | Maximum pixel value\r
52       4 bytes | char   | DUMMY     | Ignored\r
53      80 bytes | char   | IMAGENAME | Image name\r
54       4 bytes | long   | COLORMAP  | Colormap ID\r
55     404 bytes | char   | DUMMY     | Ignored\r
56 \r
57 Here is a description of each field in the image file Header:\r
58 \r
59 MAGIC - This is the decimal value 474 saved as a short. This identifies the file as an SGI image file.\r
60 \r
61 STORAGE -       specifies whether the image is stored using run length encoding (RLE) or not (VERBATIM).\r
62                         If RLE is used, the value of this byte will be 1. Otherwise the value of this byte will\r
63                         be 0. The only allowed values for this field are 0 or 1.\r
64 \r
65 BPC -           describes the precision that is used to store each channel of an image. This is the number of\r
66                         bytes per pixel component. The majority of SGI image files use 1 byte per pixel component,\r
67                         giving 256 levels. Some SGI image files use 2 bytes per component. The only allowed values\r
68                         for this field are 1 or 2.\r
69 \r
70 DIMENSION - described the number of dimensions in the data stored in the image file.\r
71                         The only allowed values are 1, 2, or 3. If this value is 1, the image file\r
72                         consists of only 1 channel and only 1 scanline (row). The length of this\r
73                         scanline is given by the value of XSIZE below. If this value is 2, the file\r
74                         consists of a single channel with a number of scanlines. The width and height\r
75                         of the image are given by the values of XSIZE and YSIZE below.\r
76                         If this value is 3, the file consists of a number of channels.\r
77                         The width and height of the image are given by the values of XSIZE and YSIZE below.\r
78                         The number of channels is given by the value of ZSIZE below.\r
79 \r
80 XSIZE -         The width of the image in pixels\r
81 \r
82 YSIZE -         The height of the image in pixels\r
83 \r
84 ZSIZE -         The number of channels in the image. B/W (greyscale) images are stored as 2 dimensional\r
85                         images with a ZSIZE of 1. RGB color images are stored as 3 dimensional images with a\r
86                         ZSIZE of 3. An RGB image with an ALPHA channel is stored as a 3 dimensional image with\r
87                         a ZSIZE of 4. There are no inherent limitations in the SGI image file format that would\r
88                         preclude the creation of image files with more than 4 channels.\r
89 \r
90 PINMIN -        The minimum pixel value in the image. The value of 0 may be used if no pixel has a value\r
91                         that is smaller than 0.\r
92 \r
93 PINMAX -        The maximum pixel value in the image. The value of 255 may be used if no pixel has a\r
94                         value that is greater than 255. This is the value that is considered to be full\r
95                         brightness in the image.\r
96 \r
97 DUMMY -         This 4 bytes of data should be set to 0.\r
98 \r
99 IMAGENAME - An null terminated ascii string of up to 79 characters terminated by a null may be\r
100                         included here. This is not commonly used.\r
101 \r
102 COLORMAP -      This controls how the pixel values in the file should be interpreted. It can have one\r
103                         of these four values:\r
104 \r
105 0: NORMAL - The data in the channels represent B/W values for images with 1 channel, RGB values\r
106                         for images with 3 channels, and RGBA values for images with 4 channels. Almost all\r
107                         the SGI image files are of this type.\r
108 \r
109 1: DITHERED - The image will have only 1 channel of data. For each pixel, RGB data is packed\r
110                         into one 8 bit value. 3 bits are used for red and green, while blue uses 2 bits.\r
111                         Red data is found in bits[2..0], green data in bits[5..3], and blue data in\r
112                         bits[7..6]. This format is obsolete.\r
113 \r
114 2: SCREEN - The image will have only 1 channel of data. This format was used to store\r
115                         color-indexed pixels. To convert the pixel values into RGB values a colormap\r
116                         must be used. The appropriate color map varies from image to image. This format is obsolete.\r
117 \r
118 3: COLORMAP - The image is used to store a color map from an SGI machine. In this case the\r
119                         image is not displayable in the conventional sense.\r
120 \r
121 DUMMY -         This 404 bytes of data should be set to 0. This makes the Header exactly 512 bytes.\r
122 */\r
123 \r
124 #include "CImageLoaderRGB.h"\r
125 \r
126 #ifdef _IRR_COMPILE_WITH_RGB_LOADER_\r
127 \r
128 #include "IReadFile.h"\r
129 #include "SColor.h"\r
130 #include "CColorConverter.h"\r
131 #include "CImage.h"\r
132 #include "os.h"\r
133 #include "irrString.h"\r
134 \r
135 \r
136 namespace irr\r
137 {\r
138 namespace video\r
139 {\r
140 \r
141 //! constructor\r
142 CImageLoaderRGB::CImageLoaderRGB()\r
143 {\r
144         #ifdef _DEBUG\r
145         setDebugName("CImageLoaderRGB");\r
146         #endif\r
147 }\r
148 \r
149 \r
150 //! returns true if the file maybe is able to be loaded by this class\r
151 //! based on the file extensions listed here\r
152 bool CImageLoaderRGB::isALoadableFileExtension(const io::path& filename) const\r
153 {\r
154         return core::hasFileExtension( filename, "rgb", "rgba", "sgi" ) ||\r
155                core::hasFileExtension( filename, "int", "inta", "bw" );\r
156 }\r
157 \r
158 \r
159 //! returns true if the file maybe is able to be loaded by this class\r
160 bool CImageLoaderRGB::isALoadableFileFormat(io::IReadFile* file) const\r
161 {\r
162         rgbStruct rgb;\r
163         return checkFormat(file, rgb);\r
164 }\r
165 \r
166 \r
167 /** The main entry point, read and format the image file.\r
168 \return Pointer to the image data on success\r
169                                 null pointer on fail */\r
170 IImage* CImageLoaderRGB::loadImage(io::IReadFile* file) const\r
171 {\r
172         IImage* image = 0;\r
173         s32* paletteData = 0;\r
174 \r
175         rgbStruct rgb;   // construct our structure for holding data\r
176 \r
177         // read Header information\r
178         if (checkFormat(file, rgb))\r
179         {\r
180                 // 16 bits per COLOR VALUE, not supported, this is 48bpp mode\r
181                 if (rgb.Header.BPC != 1)\r
182                 {\r
183                         os::Printer::log("Only one byte per pixel RGB files are supported", file->getFileName(), ELL_ERROR);\r
184                 }\r
185                 else if (rgb.Header.Colormap != 0)\r
186                 {\r
187                         os::Printer::log("Dithered, Screen and Colormap RGB files are not supported", file->getFileName(), ELL_ERROR);\r
188                 }\r
189                 else if (rgb.Header.Storage == 1 && !readOffsetTables(file, rgb))\r
190                 {\r
191                         os::Printer::log("Failed to read RLE table in RGB file", file->getFileName(), ELL_ERROR);\r
192                 }\r
193                 else if (!rgb.allocateTemps())\r
194                 {\r
195                         os::Printer::log("Out of memory in RGB file loader", file->getFileName(), ELL_ERROR);\r
196                 }\r
197                 else\r
198                 {\r
199                         // read and process the file to rgbData\r
200                         processFile(file, rgb);\r
201 \r
202 /*\r
203                   ZSIZE         Description\r
204                         1               BW (grayscale) image\r
205                         3               RGB image\r
206                         4               RGBa image with one alpha channel\r
207 \r
208                         When the Alpha channel is present, I am not sure with RGB files if\r
209                         it's a precomputed RGB color or it needs to be completely calculated. My guess\r
210                         would be that it's not precomputed for two reasons.\r
211 \r
212                         1. the loss of precision when calculating the fraction, then storing the result as an int\r
213                         2. the loss of the original color data when the image might be composited with another. Yes\r
214                                 the original color data could be computed, however, not without another loss in precision\r
215 \r
216                         Also, I don't know where to find the background color\r
217                         Pixmin and Pixmax are apparently the min and max alpha blend values (0-100%)\r
218 \r
219                         Complete Alpha blending computation\r
220                         The actual resulting merged color is computed this way:\r
221                         (image color â—Š alpha) + (background color â—Š (100% - alpha)).\r
222 \r
223                         Using precomputed blending\r
224                         (image color) + (background color â—Š (100% - alpha)).\r
225 \r
226                         Alternatively, the RGB files could use another blending technique entirely\r
227 */\r
228 \r
229                         switch (rgb.Header.Zsize)\r
230                         {\r
231                         case 1:\r
232                                 // BW (grayscale) image\r
233                                 paletteData = new s32[256];\r
234                                 for (int n=0; n<256; n++)\r
235                                         paletteData[n] = n;\r
236 \r
237                                 image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(rgb.Header.Xsize, rgb.Header.Ysize));\r
238                                 if (image)\r
239                                         CColorConverter::convert8BitTo16Bit(rgb.rgbData, (s16*)image->getData(), rgb.Header.Xsize, rgb.Header.Ysize, paletteData, 0, true);\r
240                                 break;\r
241                         case 3:\r
242                                 // RGB image\r
243                                 // one byte per COLOR VALUE, eg, 24bpp\r
244                                 image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(rgb.Header.Xsize, rgb.Header.Ysize));\r
245                                 if (image)\r
246                                         CColorConverter::convert24BitTo24Bit(rgb.rgbData, (u8*)image->getData(), rgb.Header.Xsize, rgb.Header.Ysize, 0, true, false);\r
247                                 break;\r
248                         case 4:\r
249                                 // RGBa image with one alpha channel (32bpp)\r
250                                 // image is stored in rgbData as RGBA\r
251 \r
252                                 converttoARGB(reinterpret_cast<u32*>(rgb.rgbData),      rgb.Header.Ysize * rgb.Header.Xsize);\r
253 \r
254                                 image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(rgb.Header.Xsize, rgb.Header.Ysize));\r
255                                 if (image)\r
256                                         CColorConverter::convert32BitTo32Bit((s32*)rgb.rgbData, (s32*)image->getData(), rgb.Header.Xsize, rgb.Header.Ysize, 0, true);\r
257 \r
258                                 break;\r
259                         default:\r
260                                 // Format unknown\r
261                                 os::Printer::log("Unsupported pixel format in RGB file", file->getFileName(), ELL_ERROR);\r
262                         }\r
263                 }\r
264         }\r
265 \r
266         // and tidy up allocated memory\r
267         delete [] paletteData;\r
268 \r
269         return image;\r
270 }\r
271 \r
272 // returns true on success\r
273 bool CImageLoaderRGB::readHeader(io::IReadFile* file, rgbStruct& rgb) const\r
274 {\r
275         if ( file->read(&rgb.Header, sizeof(rgb.Header)) < s32(sizeof(rgb.Header)) )\r
276                 return false;\r
277 \r
278         // test for INTEL or BIG ENDIAN processor\r
279         // if INTEL, then swap the byte order on 16 bit INT's to make them BIG ENDIAN\r
280         // because that is the native format for the .rgb file\r
281 #ifndef __BIG_ENDIAN__\r
282         rgb.Header.Magic     = os::Byteswap::byteswap(rgb.Header.Magic);\r
283         rgb.Header.Storage   = os::Byteswap::byteswap(rgb.Header.Storage);\r
284         rgb.Header.Dimension = os::Byteswap::byteswap(rgb.Header.Dimension);\r
285         rgb.Header.Xsize     = os::Byteswap::byteswap(rgb.Header.Xsize);\r
286         rgb.Header.Ysize     = os::Byteswap::byteswap(rgb.Header.Ysize);\r
287         rgb.Header.Zsize     = os::Byteswap::byteswap(rgb.Header.Zsize);\r
288         rgb.Header.Pixmin    = os::Byteswap::byteswap(rgb.Header.Pixmin);\r
289         rgb.Header.Pixmax    = os::Byteswap::byteswap(rgb.Header.Pixmax);\r
290         rgb.Header.Colormap  = os::Byteswap::byteswap(rgb.Header.Colormap);\r
291 #endif\r
292 \r
293         // calculate the size of the buffer needed: XSIZE * YSIZE * ZSIZE * BPC\r
294         rgb.ImageSize = (rgb.Header.Xsize)*(rgb.Header.Ysize)*(rgb.Header.Zsize)*(rgb.Header.BPC);\r
295 \r
296         return true;\r
297 }\r
298 \r
299 \r
300 bool CImageLoaderRGB::checkFormat(io::IReadFile* file, rgbStruct& rgb) const\r
301 {\r
302         if (!readHeader(file, rgb))\r
303                 return false;\r
304 \r
305         return (rgb.Header.Magic == 0x1DA);\r
306 }\r
307 \r
308 /*\r
309 If the image is stored using run length encoding, offset tables follow the Header that\r
310 describe what the file offsets are to the RLE for each scanline. This information only\r
311 applies if the value for STORAGE above is 1.\r
312 \r
313          Size  | Type   | Name      | Description\r
314 \r
315   tablen longs | long   | STARTTAB  | Start table\r
316   tablen longs | long   | LENGTHTAB | Length table\r
317 \r
318 One entry in each table is needed for each scanline of RLE data. The total number of scanlines in the image (tablen) is determined by the product of the YSIZE and ZSIZE. There are two tables of longs that are written. Each consists of tablen longs of data. The first table has the file offsets to the RLE data for each scanline in the image. In a file with more than 1 channel (ZSIZE > 1) this table first has all the offsets for the scanlines in the first channel, followed be offsets for the scanlines in the second channel, etc. The second table has the RLE data length for each scanline in the image. In a file with more than 1 channel (ZSIZE > 1) this table first has all the RLE data lengths for the scanlines in the first channel, followed be RLE data lengths for the scanlines in the second channel, etc.\r
319 \r
320 To find the the file offset, and the number of bytes in the RLE data for a particular scanline, these\r
321 two arrays may be read in and indexed as follows:\r
322 \r
323 To read in the tables:\r
324 \r
325     unsigned long *starttab, *lengthtab;\r
326 \r
327     tablen = YSIZE*ZSIZE*sizeof(long);\r
328     starttab = (unsigned long *)mymalloc(tablen);\r
329     lengthtab = (unsigned long *)mymalloc(tablen);\r
330     fseek(rgb->inf,512,SEEK_SET);\r
331     readlongtab(rgb->inf,starttab);\r
332     readlongtab(rgb->inf,lengthtab);\r
333 \r
334 To find the file offset and RLE data length for a scanline:\r
335 \r
336 rowno is an integer in the range 0 to YSIZE-1 channo is an integer in the range 0 to ZSIZE-1\r
337 \r
338     rleoffset = starttab[rowno+channo*YSIZE]\r
339     rlelength = lengthtab[rowno+channo*YSIZE]\r
340 \r
341 It is possible for two identical rows (scanlines) to share compressed data. A completely\r
342 white image could be written as a single compressed row and having all table entries point\r
343 to that row. Another little hack that should work is if you are writing out a RGB RLE file,\r
344 and a particular scanline is achromatic (greyscale), you could just make the r, g and b rows\r
345 point to the same data!!\r
346 \r
347   RETURNS:      on success true, else returns false\r
348 */\r
349 \r
350 bool CImageLoaderRGB::readOffsetTables(io::IReadFile* file, rgbStruct& rgb) const\r
351 {\r
352         rgb.TableLen = rgb.Header.Ysize * rgb.Header.Zsize ; // calc size of tables\r
353 \r
354         // return error if unable to allocate tables\r
355         rgb.StartTable = new u32[rgb.TableLen];\r
356         if (!rgb.StartTable)\r
357                 return false;\r
358         rgb.LengthTable = new u32[rgb.TableLen];\r
359         if (!rgb.LengthTable)\r
360                 return false;\r
361 \r
362         file->seek(512);\r
363         file->read(rgb.StartTable, rgb.TableLen* sizeof(u32));\r
364         file->read(rgb.LengthTable, rgb.TableLen* sizeof(u32));\r
365 \r
366         // if we are on an INTEL platform, swap the bytes\r
367 #ifndef __BIG_ENDIAN__\r
368         const u32 length = rgb.TableLen;\r
369         for (u32 i=0; i<length; ++i)\r
370         {\r
371                 rgb.StartTable[i] = os::Byteswap::byteswap(rgb.StartTable[i]);\r
372                 rgb.LengthTable[i] = os::Byteswap::byteswap(rgb.LengthTable[i]);\r
373         }\r
374 #endif\r
375 \r
376         return true;\r
377 }\r
378 \r
379 \r
380 /*\r
381         The Header has already been read into rgb structure\r
382         The Tables have been read if necessary\r
383         Now process the actual data\r
384 */\r
385 void CImageLoaderRGB::processFile(io::IReadFile* file, rgbStruct& rgb) const\r
386 {\r
387         u16 *tempShort;\r
388 \r
389         // calculate the size of the buffer needed: XSIZE * YSIZE * ZSIZE * BPC\r
390         rgb.rgbData = new u8 [(rgb.Header.Xsize)*(rgb.Header.Ysize)*(rgb.Header.Zsize)*(rgb.Header.BPC)];\r
391         u8 *ptr = rgb.rgbData;\r
392 \r
393         // cycle through all scanlines\r
394 \r
395 #ifdef _IRR_RGB_FILE_INVERTED_IMAGE_\r
396         // preserve the image as stored, eg, inverted\r
397         for (u16 i = 0; i < rgb.Header.Ysize; ++i)\r
398 #else\r
399         // invert the image to make it upright\r
400         for (s32 i = (s32)(rgb.Header.Ysize)-1; i>=0; --i)\r
401 #endif\r
402         {\r
403                 // check the number of channels and read a row of data\r
404                 if (rgb.Header.Zsize >= 1)\r
405                         readRGBrow( rgb.tmpR, i, 0, file, rgb);\r
406                 if (rgb.Header.Zsize >= 2)\r
407                         readRGBrow( rgb.tmpG, i, 1, file, rgb);\r
408                 if (rgb.Header.Zsize >= 3)\r
409                         readRGBrow( rgb.tmpB, i, 2, file, rgb);\r
410                 if (rgb.Header.Zsize >= 4)\r
411                         readRGBrow( rgb.tmpA, i, 3, file, rgb);\r
412 \r
413                 // cycle thru all values for this row\r
414                 for (u16 j = 0; j < rgb.Header.Xsize; ++j)\r
415                 {\r
416                         if(rgb.Header.BPC == 1)\r
417                         {\r
418                                 // ONE byte per color\r
419                                 if (rgb.Header.Zsize >= 1)\r
420                                         *ptr++ = rgb.tmpR[j];\r
421                                 if (rgb.Header.Zsize >= 2)\r
422                                         *ptr++ = rgb.tmpG[j];\r
423                                 if (rgb.Header.Zsize >= 3)\r
424                                         *ptr++ = rgb.tmpB[j];\r
425                                 if (rgb.Header.Zsize >= 4)\r
426                                         *ptr++ = rgb.tmpA[j];\r
427                         }\r
428                         else\r
429                         {\r
430                                 // TWO bytes per color\r
431                                 if( rgb.Header.Zsize >= 1 )\r
432                                 {\r
433                                         // two bytes of color data\r
434                                         tempShort  = (u16 *) (ptr);\r
435                                         *tempShort = *(  (u16 *) (rgb.tmpR) + j);\r
436                                         tempShort++;\r
437                                         ptr = ( u8 *)(tempShort);\r
438                                 }\r
439                                 if( rgb.Header.Zsize >= 2 )\r
440                                 {\r
441                                         tempShort  = ( u16 *) (ptr);\r
442                                         *tempShort = *( ( u16 *) (rgb.tmpG) + j);\r
443                                         tempShort++;\r
444                                         ptr = ( u8 *) (tempShort);\r
445                                 }\r
446                                 if( rgb.Header.Zsize >= 3 )\r
447                                 {\r
448                                         tempShort  = ( u16 *) (ptr);\r
449                                         *tempShort = *( ( u16 *) (rgb.tmpB) + j);\r
450                                         tempShort++;\r
451                                         ptr = ( u8 *)(tempShort);\r
452                                 }\r
453                                 if( rgb.Header.Zsize >= 4 )\r
454                                 {\r
455                                         tempShort  = ( u16 *) (ptr);\r
456                                         *tempShort = *( ( u16 *) (rgb.tmpA) + j);\r
457                                         tempShort++;\r
458                                         ptr = ( u8 *)(tempShort);\r
459                                 }\r
460                         } // end if(rgb.Header.BPC == 1)\r
461         } // end for\r
462         } // end for\r
463 }\r
464 \r
465 \r
466 /*\r
467         This information only applies if the value for STORAGE is 1. If the image is\r
468         stored using run length encoding, the image data follows the offset/length tables.\r
469         The RLE data is not in any particular order. The offset tables are used to\r
470         locate the rle data for any scanline.\r
471 \r
472         The RLE data must be read in from the file and expanded into pixel data in the following manner:\r
473 \r
474         If BPC is 1, then there is one byte per pixel. In this case the RLE data should be\r
475         read into an array of chars. To expand data, the low order seven bits of the first\r
476         byte: bits[6..0] are used to form a count. If the high order bit of the first byte\r
477         is 1: bit[7], then the count is used to specify how many bytes to copy from the RLE\r
478         data buffer to the destination. Otherwise, if the high order bit of the first byte\r
479         is 0: bit[7], then the count is used to specify how many times to repeat the value\r
480         of the following byte, in the destination. This process continues until a count\r
481         of 0 is found. This should decompress exactly XSIZE pixels.\r
482 \r
483 \r
484         One entry in each table is needed for each scanline of RLE data. The total number of\r
485         scanlines in the image (tablen) is determined by the product of the YSIZE and ZSIZE.\r
486         There are two tables of longs that are written. Each consists of tablen longs of data.\r
487         The first table has the file offsets to the RLE data for each scanline in the image. In\r
488         a file with more than 1 channel (ZSIZE > 1) this table first has all the offsets for the\r
489         scanlines in the first channel, followed be offsets for the scanlines in the second\r
490         channel, etc. The second table has the RLE data length for each scanline in the image.\r
491         In a file with more than 1 channel (ZSIZE > 1) this table first has all the RLE data\r
492         lengths for the scanlines in the first channel, followed be RLE data lengths for the\r
493         scanlines in the second channel, etc.\r
494 \r
495         Return a row of data, expanding RLE compression if necessary\r
496 */\r
497 void CImageLoaderRGB::readRGBrow(u8 *buf, int y, int z, io::IReadFile* file, rgbStruct& rgb) const\r
498 {\r
499         if (rgb.Header.Storage != 1)\r
500         {\r
501                 // stored VERBATIM\r
502 \r
503                 file->seek(512+(y*rgb.Header.Xsize * rgb.Header.BPC)+(z* rgb.Header.Xsize * rgb.Header.Ysize * rgb.Header.BPC));\r
504                 file->read(buf, rgb.Header.Xsize * rgb.Header.BPC);\r
505 \r
506 #ifndef __BIG_ENDIAN__\r
507                 if (rgb.Header.BPC != 1)\r
508                 {\r
509                         u16* tmpbuf = reinterpret_cast<u16*>(buf);\r
510                         for (u16 i=0; i<rgb.Header.Xsize; ++i)\r
511                                 tmpbuf[i] = os::Byteswap::byteswap(tmpbuf[i]);\r
512                 }\r
513 #endif\r
514                 return;\r
515         }\r
516 \r
517         // the file is stored as Run Length Encoding (RLE)\r
518         // each sequence is stored as 0x80  NumRepeats ByteToRepeat\r
519 \r
520         // get the file offset from StartTable and SEEK\r
521         // then read the data\r
522 \r
523         file->seek((long) rgb.StartTable[y+z * rgb.Header.Ysize]);\r
524         file->read(rgb.tmp, rgb.LengthTable[y+z * rgb.Header.Ysize]);\r
525 \r
526         // rgb.tmp has the data\r
527 \r
528         u16 pixel;\r
529         u16 *tempShort;\r
530         u8* iPtr = rgb.tmp;\r
531         u8* oPtr = buf;\r
532         while (true)\r
533         {\r
534                 // if BPC = 1, then one byte per pixel\r
535                 if (rgb.Header.BPC == 1)\r
536                 {\r
537                         pixel = *iPtr++;\r
538                 }\r
539                 else\r
540                 {\r
541                         // BPC = 2, so two bytes per pixel\r
542                         tempShort = (u16 *)  iPtr;\r
543                         pixel = *tempShort;\r
544                         tempShort++;\r
545                         iPtr = (u8 *) tempShort;\r
546                 }\r
547 \r
548 #ifndef __BIG_ENDIAN__\r
549                 if (rgb.Header.BPC != 1)\r
550                         pixel = os::Byteswap::byteswap(pixel);\r
551 #endif\r
552 \r
553                 s32 count = (s32)(pixel & 0x7F);\r
554 \r
555                 // limit the count value to the remaining row size\r
556                 if (oPtr + count*rgb.Header.BPC > buf + rgb.Header.Xsize * rgb.Header.BPC)\r
557                 {\r
558                         count = ( (buf + rgb.Header.Xsize * rgb.Header.BPC) - oPtr ) / rgb.Header.BPC;\r
559                 }\r
560 \r
561                 if (count<=0)\r
562                         break;\r
563                 else if (pixel & 0x80)\r
564                 {\r
565                         // repeat the byte pointed to by iPtr, count times\r
566                         while (count--)\r
567                         {\r
568                                 if(rgb.Header.BPC == 1)\r
569                                 {\r
570                                         *oPtr++ = *iPtr++;\r
571                                 }\r
572                                 else\r
573                                 {\r
574                                         // write pixel from iPtr to oPtr, move both two bytes ahead\r
575                                         tempShort = (u16 *) (iPtr);\r
576                                         pixel = *tempShort;\r
577                                         tempShort++;\r
578                                         iPtr = (u8 *) (tempShort);\r
579 #ifndef __BIG_ENDIAN__\r
580                                         pixel = os::Byteswap::byteswap(pixel);\r
581 #endif\r
582                                         tempShort = (u16 *) (oPtr);\r
583                                         *tempShort = pixel;\r
584                                         tempShort++;\r
585                                         oPtr = (u8 *) (tempShort);\r
586                                 }\r
587                         }\r
588                 }\r
589                 else\r
590                 {\r
591                         if (rgb.Header.BPC == 1)\r
592                         {\r
593                                 pixel = *iPtr++;\r
594                         }\r
595                         else\r
596                         {\r
597                                 tempShort = (u16 *) (iPtr);\r
598                                 pixel = *tempShort;\r
599                                 tempShort++;\r
600                                 iPtr = (u8 *) (tempShort);\r
601                         }\r
602 \r
603 #ifndef __BIG_ENDIAN__\r
604                         if (rgb.Header.BPC != 1)\r
605                                 pixel = os::Byteswap::byteswap(pixel);\r
606 #endif\r
607 \r
608                         while (count--)\r
609                         {\r
610                                 if(rgb.Header.BPC == 1)\r
611                                 {\r
612                                         *oPtr++ = (u8) pixel;\r
613                                 }\r
614                                 else\r
615                                 {\r
616                                         tempShort  = (u16 *) (oPtr);\r
617                                         *tempShort = pixel;\r
618                                         tempShort++;\r
619                                         oPtr = (u8 *) (tempShort);\r
620                                 }\r
621                         }\r
622                 } // else if (pixel & 0x80)\r
623         } // while (true)\r
624 }\r
625 \r
626 \r
627 // we have 1 byte per COLOR VALUE, eg 24bpp and 1 alpha channel\r
628 // color values are stored as RGBA, convert to ARGB\r
629 // todo: replace with CColorConverter method\r
630 void CImageLoaderRGB::converttoARGB(u32* in, const u32 size) const\r
631 {\r
632         for (u32 x=0; x < size; ++x)\r
633         {\r
634                 *in=(*in>>8)|(*in<<24);\r
635                 ++in;\r
636         }\r
637 }\r
638 \r
639 \r
640 //! creates a loader which is able to load SGI RGB images\r
641 IImageLoader* createImageLoaderRGB()\r
642 {\r
643         return new CImageLoaderRGB;\r
644 }\r
645 \r
646 \r
647 } // end namespace video\r
648 } // end namespace irr\r
649 \r
650 #endif\r
651 \r