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