1 #include	<stdint.h>
2 #include	<stdlib.h>
3 #include	<string.h>
4 
5 #include	"base.h"
6 #include	"Exception.h"
7 #include	"Log.h"
8 #include	"MathBase.h"
9 #include	"Image.h"
10 
11 namespace	DisplayOutput
12 {
13 
14 /*
15 	CImage().
16 
17 */
CImage()18 CImage::CImage() :  m_Format( eImage_None ), m_Width(0), m_Height(0), m_nMipMaps(0), m_bRef( false )
19 {
20 }
21 
22 /*
23 	CImage().
24 
25 */
Copy(const CImage & _image,const uint32 _mipLevel)26 void	CImage::Copy( const CImage &_image, const uint32 _mipLevel )
27 {
28 	g_Log->Info( "CImage( const CImage & )..." );
29 
30 	if( _mipLevel == 0 )
31 	{
32 		m_Width = _image.m_Width;
33 		m_Height = _image.m_Width;
34 		m_nMipMaps = _image.m_nMipMaps;
35 		m_Format = _image.m_Format;
36 		m_bRef = _image.isReference();
37 
38 		if( !m_bRef )
39 		{
40 			uint32	size = getMipMappedSize( 0, m_nMipMaps );
41 			m_spData = new Base::CAlignedBuffer( size );
42 			if (m_spData->IsValid())
43 				memcpy( m_spData->GetBufferPtr(), _image.GetData( 0 ), size );
44 		}
45 	}
46 	else
47 	{
48 		m_Width = _image.GetWidth( _mipLevel );
49 		m_Height = _image.GetHeight( _mipLevel );
50 		m_nMipMaps = 1;//getNumberOfMipMapsFromDimesions();
51 		m_Format = _image.m_Format;
52 		m_bRef = false;
53 
54 		if( !m_bRef )
55 		{
56 			uint32	size = getMipMappedSize( 0, m_nMipMaps );
57 			m_spData = new Base::CAlignedBuffer( size );
58 			if ( m_spData->IsValid() )
59 				memcpy( m_spData->GetBufferPtr(), _image.GetData( _mipLevel ), size );
60 		}
61 	}
62 }
63 
64 /*
65 	CImage().
66 
67 */
Create(const uint32 _w,const uint32 _h,const eImageFormat _format,const bool _bMipmaps,const bool _bRef)68 void	CImage::Create( const uint32 _w, const uint32 _h, const eImageFormat _format, const bool _bMipmaps, const bool _bRef )
69 {
70 //	g_Log->Info( "Create( %d, %d, 0x%x )", _w, _h, _format );
71 
72 	m_Width = _w;
73 	m_Height = _h;
74 	m_nMipMaps = _bMipmaps ? getNumberOfMipMapsFromDimesions() : 1;
75 	m_Format = _format;
76 	m_bRef = _bRef ;
77 
78 	if( !m_bRef )
79 	{
80 		uint32	size = getMipMappedSize( 0, m_nMipMaps );
81 		m_spData  = new Base::CAlignedBuffer( size );
82 		memset( m_spData->GetBufferPtr(), 0, size );
83 	}
84 }
85 
86 /*
87 	~CImage().
88 
89 */
~CImage()90 CImage::~CImage()
91 {
92 //	g_Log->Info( "~CImage()..." );
93 }
94 
95 /*
96 	GetData().
97 
98 */
GetData(const uint32 _mipLevel) const99 uint8	*CImage::GetData( const uint32 _mipLevel ) const
100 {
101 	if( m_bRef && m_spData.IsNull() )
102 		return( NULL );
103 
104 	const Base::CAlignedBuffer *ab = m_spData.GetRepPtr()->getRealPointer();
105 
106 	if( _mipLevel == 0 )
107 		return( ab->GetBufferPtr() );
108 
109 	return( _mipLevel < m_nMipMaps) ? ab->GetBufferPtr() + getMipMappedSize( 0, _mipLevel ) : NULL;
110 }
111 
112 /*
113 	SetData().
114 
115 */
SetData(uint8 *)116 void	CImage::SetData( uint8* /*_pData*/ )
117 {
118 	//if( !m_bRef /*|| m_nMipMaps > 1*/ )
119 		//return;
120 
121 	//m_pData = _pData;
122 }
123 
124 
125 /*
126 	GetPitch().
127 
128 */
GetPitch(const uint32 _level) const129 uint32	CImage::GetPitch( const uint32 _level ) const
130 {
131 	return( GetWidth( _level ) * m_Format.getBPPixel() );
132 }
133 
134 
135 /*
136 */
getMipMappedSize(const uint32 _firstMipMapLevel,const uint32 _nMipMapLevels) const137 uint32 CImage::getMipMappedSize( const uint32 _firstMipMapLevel, const uint32 _nMipMapLevels ) const
138 {
139 	return( getMipMappedSize( _firstMipMapLevel, _nMipMapLevels, m_Format ) );
140 }
141 
142 /*int Image::getPixelCount(const int firstMipMapLevel, int nMipMapLevels) const {
143 	int w = getWidth (firstMipMapLevel);
144 	int h = getHeight(firstMipMapLevel);
145 	int d = getDepth (firstMipMapLevel);
146 	int size = 0;
147 	while (nMipMapLevels){
148 		size += w * h * d;
149 		w >>= 1;
150 		h >>= 1;
151 		d >>= 1;
152 		if (w + h + d == 0) break;
153 		if (w == 0) w = 1;
154 		if (h == 0) h = 1;
155 		if (d == 0) d = 1;
156 
157 		nMipMapLevels--;
158 	}
159 
160 	return (depth == 0)? 6 * size : size;
161 }*/
162 
163 /*
164 	getMipMappedSize().
165 
166 */
getMipMappedSize(const uint32 _firstMipMapLevel,const uint32 _nMipMapLevels,const CImageFormat & _format) const167 uint32 CImage::getMipMappedSize( const uint32 _firstMipMapLevel, const uint32 _nMipMapLevels, const CImageFormat &_format ) const
168 {
169 	uint32	w = GetWidth( _firstMipMapLevel ) << 1;
170 	uint32	h = GetHeight( _firstMipMapLevel ) << 1;
171 
172 	uint32	level = 0;
173 	uint32	size = 0;
174 
175 	while( level < _nMipMapLevels && (w != 1 || h != 1) )
176 	{
177 		if( w > 1 ) w >>= 1;
178 		if( h > 1 ) h >>= 1;
179 
180 		if( _format.isCompressed() )
181 			size += ((w + 3) >> 2) * ((h + 3) >> 2);
182 		else
183 			size += w * h;
184 
185 		level++;
186 	}
187 
188 	if( _format.isCompressed() )
189 		size *= _format.getBPBlock();
190 	else
191 		size *= _format.getBPPixel();
192 
193 	return( size );
194 }
195 
196 
197 /*
198 	getNumberOfMipMapsFromDimesions().
199 
200 */
getNumberOfMipMapsFromDimesions(void) const201 uint32 CImage::getNumberOfMipMapsFromDimesions( void ) const
202 {
203 	uint32 m = (m_Width > m_Height)? m_Width : m_Height;
204 	uint32 i = 0;
205 
206 	while( m > 0 )
207 	{
208 		m >>= 1;
209 		i++;
210 	}
211 
212 	return( i );
213 }
214 
215 /*
216 	Load().
217 
218 */
Load(const std::string & _fileName,const bool _calcMipmaps)219 bool	CImage::Load( const std::string &_fileName, const bool _calcMipmaps )
220 {
221 	std::string ext = "";
222 
223 	size_t offs = _fileName.find_last_of( '.', _fileName.size() );
224 	if( offs != _fileName.size() )
225 		ext = _fileName.substr( offs+1, _fileName.size()-1 );
226 
227 	if( ext == "" )
228 	{
229 		g_Log->Warning( "CImage::Load() No extension found for %s", _fileName.c_str() );
230 		return( false );
231 	}
232 
233 	bool	foundExt = false;
234 
235 	//	DDS?
236 	if( ext == "dds" )
237 	{
238 		foundExt = true;
239 		if( !LoadDDS( _fileName, _calcMipmaps ) )
240 			return( false );
241 	}
242 
243 	//	TGA?
244 	/*if( ext == "tga" )
245 	{
246 		foundExt = true;
247 		if( !LoadTGA( _fileName, _calcMipmaps ) )
248 			return( false );
249 	}*/
250 
251 	//	JPG?
252 	/*if( ext == "jpg" )
253 	{
254 		foundExt = true;
255 		if( !LoadJPG( _fileName, _calcMipmaps ) )
256 			return( false );
257 	}*/
258 
259 	//	PNG?
260 	if( ext == "png" )
261 	{
262 		foundExt = true;
263 		if( !LoadPNG( _fileName, _calcMipmaps ) )
264 			return( false );
265 	}
266 
267 	//	Unknown extension?
268 	if( foundExt == false )
269 	{
270 		g_Log->Warning( "CImage::Load() Unknown extension for %s", _fileName.c_str() );
271 		return( false );
272 	}
273 
274 	if( _calcMipmaps && !m_Format.isCompressed() )
275 	{
276 		if( !GenerateMipmaps() )
277 			return( false );
278 	}
279 
280 	if( m_nMipMaps == 0 )
281 		m_nMipMaps = 1;
282 
283 	//	Done!
284 	g_Log->Info( "CImage::Load( %s ): (%d x %d, %d MipMaps)", (const char *)_fileName.c_str(), m_Width, m_Height, m_nMipMaps );
285 	return( true );
286 }
287 
288 /*
289 	GenerateMipmaps().
290 
291 */
GenerateMipmaps(void)292 bool	CImage::GenerateMipmaps( void )
293 {
294 	//	Check if the image is power of two.
295 	uint32 w = Base::Math::ClosestPowerOfTwo( m_Width );
296 	uint32 h = Base::Math::ClosestPowerOfTwo( m_Height );
297 
298 	if( w != m_Width || h != m_Height)
299 	{
300 		//	TODO: resize?
301 		g_Log->Error( "CImage::GenerateMipmaps(): Image is not power of two!" );
302 		return( false );
303 	}
304 
305 	m_nMipMaps = getNumberOfMipMapsFromDimesions();
306 	return( createMipMaps() );
307 }
308 
309 /*
310 	Load().
311 
312 */
Save(const std::string & _fileName)313 bool	CImage::Save( const std::string &_fileName )
314 {
315 	std::string ext = "";
316 
317 	size_t offs = _fileName.find_last_of( '.', _fileName.size() );
318 	if( offs != _fileName.size() )
319 		ext = _fileName.substr( offs+1, _fileName.size()-1 );
320 
321 	if( ext == "" )
322 	{
323 		g_Log->Warning( "CImage::Save() No extension found for %s", _fileName.c_str() );
324 		return( false );
325 	}
326 
327 	//	DDS?
328 	if( ext == "dds" )
329 	{
330 		if( !SaveDDS( _fileName ) )
331 			return( false );
332 	}
333 
334 	g_Log->Info( "CImage::Save( %s ): Complete!", (const char *)_fileName.c_str(), m_Width, m_Height, m_nMipMaps );
335 	return( true );
336 }
337 
338 /*
339 	SaveDDS().
340 
341 */
342 
343 #define DDPF_ALPHAPIXELS 0x00000001
344 #define DDPF_FOURCC      0x00000004
345 #define DDPF_RGB         0x00000040
346 
347 #define DDSD_CAPS        0x00000001
348 #define DDSD_HEIGHT      0x00000002
349 #define DDSD_WIDTH       0x00000004
350 #define DDSD_PITCH       0x00000008
351 #define DDSD_PIXELFORMAT 0x00001000
352 #define DDSD_MIPMAPCOUNT 0x00020000
353 #define DDSD_LINEARSIZE  0x00080000
354 #define DDSD_DEPTH       0x00800000
355 #define DDSCAPS_COMPLEX  0x00000008
356 #define DDSCAPS_TEXTURE  0x00001000
357 #define DDSCAPS_MIPMAP   0x00400000
358 
359 //
360 #pragma pack (push, 1)
361 
362 struct DDSHeader {
363 	unsigned int ddsIdentifier;
364 	unsigned int size;
365 	unsigned int flags;
366 	unsigned int height;
367 	unsigned int width;
368 	unsigned int pitchOrLinearSize;
369 	unsigned int depth;
370 	unsigned int nMipMaps;
371 	unsigned int reserved[11];
372 	unsigned int size2;
373 	unsigned int flags2;
374 	unsigned int fourCC;
375 	unsigned int bpp;
376 
377 	unsigned int rBitMask;
378 	unsigned int gBitMask;
379 	unsigned int bBitMask;
380 	unsigned int aBitMask;
381 
382 	unsigned int caps1;
383 	unsigned int caps2;
384 	unsigned int reserved2[3];
385 };
386 #pragma pack (pop)
387 
SaveDDS(const std::string & _fileName)388 bool	CImage::SaveDDS( const std::string &_fileName )
389 {
390 	eImageFormat fmt = m_Format.getFormatEnum();
391 
392 	if( (fmt < eImage_I8 || fmt > eImage_RGBA8 ) && fmt != eImage_RGB565 && !m_Format.isCompressed() )
393 		return( false );
394 
395 	uint32 nChannels = m_Format.GetChannels();
396 
397 	uint32	fourCC[] = {	MCHAR4('D','X','T','1'),
398 							MCHAR4('D','X','T','3'),
399 							MCHAR4('D','X','T','5'),
400 							MCHAR4('A','T','I','2')	};
401 
402 	DDSHeader header = {
403 		MCHAR4('D','D','S',' '),
404 		124,
405 		DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | static_cast<unsigned int>(m_nMipMaps > 1? DDSD_MIPMAPCOUNT : 0),
406 		m_Height,
407 		m_Width,
408 		0,
409 		0,
410 		(m_nMipMaps > 1)? m_nMipMaps : 0,
411 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
412 		32,
413 		m_Format.isCompressed() ? DDPF_FOURCC : static_cast<unsigned int>((nChannels < 3)? 0x00020000 : DDPF_RGB) | static_cast<unsigned int>((nChannels & 1)? 0 : DDPF_ALPHAPIXELS),
414 		m_Format.isCompressed() ? fourCC[ fmt - eImage_DXT1 ] : 0,
415 		8 * nChannels,
416 		static_cast<unsigned int>((nChannels >= 3)? 0x00ff0000 : 0xFF),
417 		static_cast<unsigned int>((nChannels >= 3)? 0x0000ff00 : 0),
418 		static_cast<unsigned int>((nChannels >= 3)? 0x000000ff : 0),
419 		(nChannels >= 3)? 0xff000000 : (nChannels == 2)? 0xFF00 : 0,
420 		DDSCAPS_TEXTURE | static_cast<unsigned int>(m_nMipMaps > 1? DDSCAPS_MIPMAP | DDSCAPS_COMPLEX : 0),
421 		0,
422 		{ 0, 0, 0 },
423 	};
424 
425 	FILE	*pFile = fopen( _fileName.c_str(), "wb" );
426 	if( !pFile )
427 		return( false );
428 
429 	fwrite( &header, sizeof(header), 1, pFile );
430 
431 	uint32	size = getMipMappedSize( 0, m_nMipMaps );
432 
433 	bool	bAlpha = false;
434 
435 	if( bAlpha && (fmt == eImage_RGB8 || fmt == eImage_RGBA8) )
436 		flipChannels( m_spData->GetBufferPtr(), size / nChannels, nChannels );
437 
438 	fwrite( GetData( 0 ), size, 1, pFile );
439 
440 	//	Flip back... =)
441 	if( bAlpha && (fmt == eImage_RGB8 || fmt == eImage_RGBA8) )
442 		flipChannels( m_spData->GetBufferPtr(), size / nChannels, nChannels );
443 
444 	fclose( pFile );
445 
446 	return( true );
447 }
448 
449 /*
450 	buildMipMap8().
451 
452 */
buildMipMap8(uint8 * dest,uint8 * src,uint32 width,uint32 height,uint32 channels)453 void	buildMipMap8( uint8 *dest, uint8 *src, uint32 width, uint32 height, uint32 channels )
454 {
455 	uint32	xOff = (width  < 2)? 0 : channels;
456 	uint32	yOff = (height < 2)? 0 : width * channels;
457 
458 	for( uint32 y=0; y<height; y += 2 )
459 	{
460 		for( uint32 x=0; x<width; x += 2 )
461 		{
462 			for( uint32 i=0; i<channels; i++ )
463 			{
464 				*dest++ = ((src[0] +  src[xOff] + src[yOff] + src[yOff + xOff]) + 2) >> 2;
465 				src++;
466 			}
467 			src += xOff;
468 		}
469 		src += yOff;
470 	}
471 }
472 
473 /*
474 	buildMipMap32f().
475 
476 */
buildMipMap32f(fp4 * dest,fp4 * src,uint32 width,uint32 height,uint32 channels)477 void	buildMipMap32f( fp4 *dest, fp4 *src, uint32 width, uint32 height, uint32 channels )
478 {
479 	uint32	xOff = (width  < 2)? 0 : channels;
480 	uint32	yOff = (height < 2)? 0 : width * channels;
481 
482 	for( uint32 y=0; y<height; y += 2 )
483 	{
484 		for( uint32 x=0; x<width; x += 2 )
485 		{
486 			for( uint32 i=0; i<channels; i++ )
487 			{
488 				*dest++ = (src[0] + src[xOff] + src[yOff] + src[yOff + xOff]) * 0.25f;
489 				src++;
490 			}
491 
492 			src += xOff;
493 		}
494 
495 		src += yOff;
496 	}
497 }
498 
499 /*
500 	buildMipMapRGB565().
501 
502 */
buildMipMapRGB565(uint16 * dest,uint16 * src,uint32 width,uint32 height)503 void	buildMipMapRGB565( uint16 *dest, uint16 *src, uint32 width, uint32 height )
504 {
505 	uint32	x,y,diff;
506 	uint32	xOff = (width  < 2)? 0 : 1;
507 	uint32	yOff = (height < 2)? 0 : 1;
508 
509 	uint32	r,g,b;
510 
511 	diff = yOff * width;
512 
513 	for( y=0; y<height; y += 2 )
514 	{
515 		for( x=0; x<width; x += 2 )
516 		{
517 			r = (((src[0] >> 8) & 0xF8) + ((src[xOff] >> 8) & 0xF8) + ((src[diff] >> 8) & 0xF8) + ((src[diff + xOff] >> 8) & 0xF8));
518 			g = (((src[0] >> 3) & 0xFC) + ((src[xOff] >> 3) & 0xFC) + ((src[diff] >> 3) & 0xFC) + ((src[diff + xOff] >> 3) & 0xFC));
519 			b = (((src[0] << 3) & 0xF8) + ((src[xOff] << 3) & 0xF8) + ((src[diff] << 3) & 0xF8) + ((src[diff + xOff] << 3) & 0xF8));
520 
521 			*dest++ = (uint16)(((r << 6) & 0xF800) | ((g << 1) & 0x07E0) | ((b >> 5) & 0x1F));
522 			src += 2;
523 		}
524 
525 		src += width;
526 	}
527 }
528 
529 /*
530 	createMipMaps().
531 
532 */
createMipMaps(void)533 bool	CImage::createMipMaps( void )
534 {
535 	if( m_Format.isCompressed() )
536 		return( false );
537 
538 	if( m_bRef )
539 		return( false );
540 
541 	uint32	w = m_Width;
542 	uint32	h = m_Height;
543 
544 	union {
545 		uint8	*src;
546 		uint16	*src16;
547 		fp4		*src32f;
548 	};
549 
550 	union {
551 		uint8	*dest;
552 		uint16	*dest16;
553 		fp4		*dest32f;
554 	};
555 
556 	if( m_nMipMaps <= 1 )
557 	{
558 		m_spData->Reallocate( getMipMappedSize() );
559 		m_nMipMaps = getNumberOfMipMapsFromDimesions();
560 	}
561 
562 	dest = m_spData->GetBufferPtr();
563 
564 	uint32	nChannels = m_Format.GetChannels();
565 
566 	while( w > 1 || h > 1 )
567 	{
568 		src = dest;
569 
570 		if( m_Format.isPlain() )
571 		{
572 			if( m_Format.isFloat() )
573 			{
574 				dest32f += w * h * nChannels;
575 				buildMipMap32f(dest32f, src32f, w, h, nChannels);
576 			}
577 			else
578 			{
579 				dest += w * h * nChannels;
580 				buildMipMap8(dest, src, w, h, nChannels);
581 			}
582 		}
583 		else
584 		{
585 			dest16 += w * h;
586 			buildMipMapRGB565(dest16, src16, w, h);
587 		}
588 
589 		if( w > 1)	w >>= 1;
590 		if( h > 1)	h >>= 1;
591 	}
592 
593 	return( true );
594 }
595 
596 /*
597 */
getNumPixels(const uint32 _firstMipMapLevel,const uint32 _nMipMapLevels) const598 uint32 CImage::getNumPixels( const uint32 _firstMipMapLevel, const uint32 _nMipMapLevels ) const
599 {
600 	uint32	w = GetWidth( _firstMipMapLevel ) << 1;
601 	uint32	h = GetHeight( _firstMipMapLevel ) << 1;
602 	uint32	level = 0;
603 	uint32	size = 0;
604 
605 	while( level < _nMipMapLevels && (w != 1 || h != 1) )
606 	{
607 		if( w > 1 ) w >>= 1;
608 		if( h > 1 ) h >>= 1;
609 
610 		size += w * h;
611 		level++;
612 	}
613 
614 	return( size );
615 }
616 
617 /*
618 	Convert().
619 
620 */
Convert(const eImageFormat _newFormatType)621 bool	CImage::Convert( const eImageFormat _newFormatType )
622 {
623 	if( _newFormatType == m_Format.m_Format )
624 		return( false );
625 
626 	if( !m_Format.isPlain() )
627 		return( false );
628 
629 	if( m_bRef )
630 		return( false );
631 
632 	//
633 	CImageFormat newFormat = CImageFormat( _newFormatType );
634 	if( !newFormat.isPlain() )
635 		return( false );
636 
637 	uint8	*src = m_spData->GetBufferPtr();
638 	Base::spCAlignedBuffer newPixels = new Base::CAlignedBuffer( getMipMappedSize( 0, m_nMipMaps, newFormat ) );
639 	uint8	*dest = newPixels->GetBufferPtr();
640 
641 	uint32	nPixels = getNumPixels( 0, m_nMipMaps );
642 
643 	if( m_Format.is( eImage_RGB8 ) && newFormat.is( eImage_RGBA8 ) )
644 	{
645 		//	Fast path for RGB->RGBA8
646 		do
647 		{
648 			dest[0] = src[0];
649 			dest[1] = src[1];
650 			dest[2] = src[2];
651 			dest[3] = 255;
652 			dest += 4;
653 			src += 3;
654 		}	while ( --nPixels );
655 	}
656 	else
657 	{
658 		uint32	srcSize = m_Format.getBPPixel();
659 		uint32	nSrcChannels = m_Format.GetChannels();
660 
661 		uint32	destSize = newFormat.getBPPixel();
662 		uint32	nDestChannels = newFormat.GetChannels();
663 
664 		do
665 		{
666 			fp4	rgba[4];
667 
668             rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0.0f;
669 
670 			if( m_Format.isFloat() )
671 			{
672 				for( uint32 i=0; i<nSrcChannels; i++ )
673 					rgba[i] = ((fp4 *)src)[i];
674 			}
675 			else if( m_Format.m_Format >= eImage_I16 && m_Format.m_Format <= eImage_RGBA16 )
676 			{
677 				for( uint32 i=0; i<nSrcChannels; i++ )
678 					rgba[i] = ((uint16 *)src)[i] * (1.0f / 65535.0f);
679 			}
680 			else
681 			{
682 				for( uint32 i=0; i<nSrcChannels; i++ )
683 					rgba[i] = src[i] * (1.0f / 255.0f);
684 			}
685 
686 			if( nSrcChannels  < 4 )	rgba[3] = 1.0f;
687 			if( nSrcChannels == 1 )	rgba[2] = rgba[1] = rgba[0];
688 
689 			if( nDestChannels == 1 )
690 				rgba[0] = 0.30f * rgba[0] + 0.59f * rgba[1] + 0.11f * rgba[2];
691 
692 			if( newFormat.isFloat() )
693 			{
694 				for( uint32 i=0; i<nDestChannels; i++ )
695 					((fp4 *)dest)[i] = rgba[i];
696 			}
697 			else if( newFormat.m_Format >= eImage_I16 && newFormat.m_Format <= eImage_RGBA16 )
698 			{
699 				for( uint32 i=0; i<nDestChannels; i++ )
700 					((uint16 *)dest)[i] = (uint16)(65535 * Base::Math::Clamped( rgba[i], 0.0f, 1.1f ) + 0.5f );
701 			}
702 			/*else if( newFormat == FORMAT_RGB10A2)
703 			{
704 			*(uint *) dest =
705 			(uint(1023.0f * saturate(rgba[0]) + 0.5f) << 22) |
706 			(uint(1023.0f * saturate(rgba[1]) + 0.5f) << 12) |
707 			(uint(1023.0f * saturate(rgba[2]) + 0.5f) <<  2) |
708 			(uint(   3.0f * saturate(rgba[3]) + 0.5f));
709 			}*/
710 			else
711 			{
712 				for( uint32 i=0; i<nDestChannels; i++ )
713 					dest[i] = (uint8)( 255 * Base::Math::Clamped( rgba[i], 0.0f, 1.0f ) + 0.5f );
714 			}
715 
716 			src  += srcSize;
717 			dest += destSize;
718 
719 		} while( --nPixels );
720 	}
721 
722 	m_spData = newPixels;
723 	m_Format = newFormat;
724 
725 	return( true );
726 }
727 
icerp(int32 _a,int32 _b,int32 _c,int32 _d,int32 _x)728 static int32 icerp( int32 _a, int32 _b, int32 _c, int32 _d, int32 _x )
729 {
730 	int32 p = (_d - _c) - (_a - _b);
731 	int32 q = (_a - _b) - p;
732 	int32 r = _c - _a;
733 	return( (_x * (_x * (_x * p + (q << 7)) + (r << 14)) + (_b << 21)) >> 21 );
734 }
735 
736 
737 /*
738 	Scale().
739 
740 */
Scale(const uint32 _newWidth,const uint32 _newHeight,const eScaleFilters _eFilter)741 bool	CImage::Scale( const uint32 _newWidth, const uint32 _newHeight, const eScaleFilters _eFilter )
742 {
743 	if( !m_Format.isPlain() || m_Format.isFloat() )
744 	{
745 		if( m_Format.isCompressed() )
746 			g_Log->Warning( "CImage::Scale(): No deal, image is compressed." );
747 
748 		if( m_Format.isFloat() )
749 			g_Log->Warning( "CImage::Scale(): No deal, image is float." );
750 
751 		if( m_Format.isDepth() )
752 			g_Log->Warning( "CImage::Scale(): No deal, image is depth." );
753 
754 		return( false );
755 	}
756 
757     if ( _newHeight < 2 || _newWidth < 2 )
758     {
759         g_Log->Warning( "CImage::Scale(): No deal, new size too small." );
760         return ( false );
761     }
762 
763 	uint32 nChannels = m_Format.GetChannels();
764 
765 	Base::spCAlignedBuffer newPixels = new Base::CAlignedBuffer( _newWidth * _newHeight * nChannels );
766 
767 	uint8 *pData = GetData( 0 );
768 
769 	uint32	x,y,k,sampleX, sampleY, wX, wY;
770 	uint8	*src, *dest = newPixels->GetBufferPtr();
771 
772 	switch( _eFilter )
773 	{
774 		case	eImage_Nearest:
775 			for( y=0; y<_newHeight; y++ )
776 			{
777 				sampleY = (m_Height - 1) * y / (_newHeight - 1);
778 				for( x=0; x<_newWidth; x++ )
779 				{
780 					sampleX = (m_Width - 1) * x / (_newWidth - 1);
781 					for( k=0; k<nChannels; k++ )
782 					{
783 						*dest++ = pData[ (sampleY * m_Width + sampleX) * nChannels + k ];
784 					}
785 				}
786 			}
787 		break;
788 
789 		case	eImage_Bilinear:
790 			for( y=0; y<_newHeight; y++ )
791 			{
792 				sampleY = (((m_Height - 1) * y) << 8) / (_newHeight - 1);
793 
794 				if (y == _newHeight - 1)
795 					sampleY--;
796 
797 				wY = sampleY & 0xFF;
798 				sampleY >>= 8;
799 
800 				for( x=0; x<_newWidth; x++ )
801 				{
802 					sampleX = (((m_Width - 1) * x) << 8) / (_newWidth - 1);
803 					wX = sampleX & 0xFF;
804 					sampleX >>= 8;
805 
806 					src = pData + (sampleY * m_Width + sampleX) * nChannels;
807 
808 					for( k=0; k<nChannels; k++ )
809 					{
810 						*dest++ = ((	(256 - wX) * (256 - wY) * static_cast<uint32>(src[ 0 ]) +
811 									(256 - wX) * (      wY) * static_cast<uint32>(src[ m_Width * nChannels ]) +
812 									(      wX) * (256 - wY) * static_cast<uint32>(src[ nChannels ]) +
813 									(      wX) * (      wY) * static_cast<uint32>(src[ (m_Width + 1) * nChannels ]) ) >> 16) & 0xFF;
814                         src++;
815 					}
816 				}
817 			}
818 		break;
819 		case	eImage_Bicubic:
820 			int a,b,c,d;
821 			int res;
822 
823 			for( y=0; y<_newHeight; y++ )
824 			{
825 				sampleY = (((m_Height - 1) * y) << 7) / (_newHeight - 1);
826 				wY = sampleY & 0x7F;
827 				sampleY >>= 7;
828 
829 				for( x=0; x<_newWidth; x++ )
830 				{
831 					sampleX = (((m_Width - 1) * x) << 7) / (_newWidth - 1);
832 					wX = sampleX & 0x7F;
833 					sampleX >>= 7;
834 
835 					src = pData + ((sampleY - 1) * m_Width + (sampleX - 1)) * nChannels;
836 
837 					for( k=0; k<nChannels; k++ )
838 					{
839 						b = icerp( src[ m_Width * nChannels], src[( m_Width + 1) * nChannels], src[(    m_Width + 2) * nChannels], src[(    m_Width + 3) * nChannels], static_cast<int32>(wX)) & 0xFF;
840 						if( sampleY > 0 )
841 							a = icerp(src[0], src[nChannels], src[2 * nChannels], src[3 * nChannels], static_cast<int32>(wX)) & 0xFF;
842 						else
843 							a = b;
844 
845 						c = icerp(src[2 * m_Width * nChannels], src[(2 * m_Width + 1) * nChannels], src[(2 * m_Width + 2) * nChannels], src[(2 * m_Width + 3) * nChannels], static_cast<int32>(wX)) & 0xFF;
846 						if( sampleY < _newHeight - 1 )
847 							d = icerp(src[3 * m_Width * nChannels], src[(3 * m_Width + 1) * nChannels], src[(3 * m_Width + 2) * nChannels], src[(3 * m_Width + 3) * nChannels], static_cast<int32>(wX)) & 0xFF;
848 						else
849 							d = c;
850 
851 						res = icerp( a, b, c, d, static_cast<int32>(wY) ) & 0xFF;
852 						*dest++ = (res < 0)? 0 : (res > 255)? 255 : (res & 0xFF);
853 						src++;
854 					}
855 				}
856 			}
857 		break;
858 	}
859 
860 	m_spData = newPixels;
861 	m_Width  = _newWidth;
862 	m_Height = _newHeight;
863 	m_nMipMaps = 1;
864 
865 	return( true );
866 }
867 
868 /*
869 */
PutPixel(const int32 _x,const int32 _y,const fp4 _r,const fp4 _g,const fp4 _b,const fp4 _a)870 void	CImage::PutPixel( const int32 _x, const int32 _y, const fp4 _r, const fp4 _g, const fp4 _b, const fp4 _a )
871 {
872 	//	Complicated formats are no go.
873 	if( !m_Format.isPlain() )
874 		return;
875 
876 	if( _x < 0 || _x >= (int)m_Width )
877 		return;
878 
879 	if( _y < 0 || _y >= (int)m_Height )
880 		return;
881 
882 	fp4	rgba[4] = { _r, _g, _b, _a };
883 
884 	uint32	nDestChannels = m_Format.GetChannels();
885 	uint8	*pData = (GetData(0) + (static_cast<uint32>(_y) * GetPitch())) + (static_cast<uint32>(_x) * m_Format.getBPPixel() );
886 
887     if (pData == NULL)
888         return;
889 
890 	if( m_Format.isFloat() )
891 	{
892 		for( uint8 i=0; i<nDestChannels; i++ )
893 			((fp4 *)pData)[i] = rgba[i];
894 	}
895 	else if( m_Format.m_Format >= eImage_I16 && m_Format.m_Format <= eImage_RGBA16 )
896 	{
897 		for( uint8 i=0; i<nDestChannels; i++ )
898 			((uint16 *)pData)[i] = (uint16)(65535 * Base::Math::Clamped( rgba[i], 0.0f, 1.1f ) + 0.5f );
899 	}
900 	else
901 	{
902 		for( uint8 i=0; i<nDestChannels; i++ )
903 			pData[i] = (uint8)( 255 * Base::Math::Clamped( rgba[i], 0.0f, 1.0f ) + 0.5f );
904 	}
905 }
906 
907 /*
908 */
GetPixel(const int32 _x,const int32 _y,fp4 & _r,fp4 & _g,fp4 & _b,fp4 & _a)909 void	CImage::GetPixel( const int32 _x, const int32 _y, fp4 &_r, fp4 &_g, fp4 &_b, fp4 &_a )
910 {
911 	//	Complicated formats are no go.
912 	if( !m_Format.isPlain() )
913 		return;
914 
915 	if( _x < 0 || _x > (int)m_Width )
916 		return;
917 
918 	if( _y < 0 || _y > (int)m_Height )
919 		return;
920 
921 	uint32	nSrcChannels = m_Format.GetChannels();
922 	uint8	*pData = (GetData(0) + (static_cast<uint32>(_y) * GetPitch())) + (static_cast<uint32>(_x) * m_Format.getBPPixel() );
923 	fp4		rgba[4];
924 
925     _r = _g = _b = _a = 0;
926     rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0.0f;
927 
928     if (pData == NULL)
929         return;
930 
931 	if( m_Format.isFloat() )
932 	{
933 		for( uint32 i=0; i<nSrcChannels; i++ )
934 			rgba[i] = ((fp4 *)pData)[i];
935 	}
936 	else if( m_Format.m_Format >= eImage_I16 && m_Format.m_Format <= eImage_RGBA16 )
937 	{
938 		for( uint32 i=0; i<nSrcChannels; i++ )
939 			rgba[i] = ((uint16 *)pData)[i] * (1.0f / 65535.0f);
940 	}
941 	else
942 	{
943 		for( uint32 i=0; i<nSrcChannels; i++ )
944 			rgba[i] = pData[i] * (1.0f / 255.0f);
945 	}
946 
947 	if( nSrcChannels  < 4 )	rgba[3] = 1.0f;
948 	if( nSrcChannels == 1 )	rgba[2] = rgba[1] = rgba[0];
949 
950 	_r = rgba[0];
951 	_g = rgba[1];
952 	_b = rgba[2];
953 	_a = rgba[3];
954 }
955 
956 
957 
958 };
959 
960