PageRenderTime 119ms CodeModel.GetById 18ms app.highlight 75ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llimage/llimage.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1758 lines | 1347 code | 235 blank | 176 comment | 260 complexity | 86f37f85c8005a11967191de9d7e77ec MD5 | raw file
   1/** 
   2 * @file llimage.cpp
   3 * @brief Base class for images.
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28
  29#include "llimage.h"
  30
  31#include "llmath.h"
  32#include "v4coloru.h"
  33#include "llmemtype.h"
  34
  35#include "llimagebmp.h"
  36#include "llimagetga.h"
  37#include "llimagej2c.h"
  38#include "llimagejpeg.h"
  39#include "llimagepng.h"
  40#include "llimagedxt.h"
  41#include "llimageworker.h"
  42#include "llmemory.h"
  43
  44//---------------------------------------------------------------------------
  45// LLImage
  46//---------------------------------------------------------------------------
  47
  48//static
  49std::string LLImage::sLastErrorMessage;
  50LLMutex* LLImage::sMutex = NULL;
  51LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ;
  52
  53//static
  54void LLImage::initClass()
  55{
  56	sMutex = new LLMutex(NULL);
  57
  58	LLImageBase::createPrivatePool() ;
  59}
  60
  61//static
  62void LLImage::cleanupClass()
  63{
  64	delete sMutex;
  65	sMutex = NULL;
  66
  67	LLImageBase::destroyPrivatePool() ;
  68}
  69
  70//static
  71const std::string& LLImage::getLastError()
  72{
  73	static const std::string noerr("No Error");
  74	return sLastErrorMessage.empty() ? noerr : sLastErrorMessage;
  75}
  76
  77//static
  78void LLImage::setLastError(const std::string& message)
  79{
  80	LLMutexLock m(sMutex);
  81	sLastErrorMessage = message;
  82}
  83
  84//---------------------------------------------------------------------------
  85// LLImageBase
  86//---------------------------------------------------------------------------
  87
  88LLImageBase::LLImageBase()
  89	: mData(NULL),
  90	  mDataSize(0),
  91	  mWidth(0),
  92	  mHeight(0),
  93	  mComponents(0),
  94	  mBadBufferAllocation(false),
  95	  mAllowOverSize(false),
  96	  mMemType(LLMemType::MTYPE_IMAGEBASE)
  97{
  98}
  99
 100// virtual
 101LLImageBase::~LLImageBase()
 102{
 103	deleteData(); // virtual
 104}
 105
 106//static 
 107void LLImageBase::createPrivatePool() 
 108{
 109	if(!sPrivatePoolp)
 110	{
 111		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC_THREADED) ;
 112	}
 113}
 114	
 115//static 
 116void LLImageBase::destroyPrivatePool() 
 117{
 118	if(sPrivatePoolp)
 119	{
 120		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
 121		sPrivatePoolp = NULL ;
 122	}
 123}
 124
 125// virtual
 126void LLImageBase::dump()
 127{
 128	llinfos << "LLImageBase mComponents " << mComponents
 129		<< " mData " << mData
 130		<< " mDataSize " << mDataSize
 131		<< " mWidth " << mWidth
 132		<< " mHeight " << mHeight
 133		<< llendl;
 134}
 135
 136// virtual
 137void LLImageBase::sanityCheck()
 138{
 139	if (mWidth > MAX_IMAGE_SIZE
 140		|| mHeight > MAX_IMAGE_SIZE
 141		|| mDataSize > (S32)MAX_IMAGE_DATA_SIZE
 142		|| mComponents > (S8)MAX_IMAGE_COMPONENTS
 143		)
 144	{
 145		llerrs << "Failed LLImageBase::sanityCheck "
 146			   << "width " << mWidth
 147			   << "height " << mHeight
 148			   << "datasize " << mDataSize
 149			   << "components " << mComponents
 150			   << "data " << mData
 151			   << llendl;
 152	}
 153}
 154
 155// virtual
 156void LLImageBase::deleteData()
 157{
 158	FREE_MEM(sPrivatePoolp, mData) ;
 159	mData = NULL;
 160	mDataSize = 0;
 161}
 162
 163// virtual
 164U8* LLImageBase::allocateData(S32 size)
 165{
 166	LLMemType mt1(mMemType);
 167	
 168	if (size < 0)
 169	{
 170		size = mWidth * mHeight * mComponents;
 171		if (size <= 0)
 172		{
 173			llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << llendl;
 174		}
 175	}
 176	
 177	//make this function thread-safe.
 178	static const U32 MAX_BUFFER_SIZE = 4096 * 4096 * 16 ; //256 MB
 179	if (size < 1 || size > MAX_BUFFER_SIZE) 
 180	{
 181		llinfos << "width: " << mWidth << " height: " << mHeight << " components: " << mComponents << llendl ;
 182		if(mAllowOverSize)
 183		{
 184			llinfos << "Oversize: " << size << llendl ;
 185		}
 186		else
 187		{
 188			llerrs << "LLImageBase::allocateData: bad size: " << size << llendl;
 189		}
 190	}
 191	if (!mData || size != mDataSize)
 192	{
 193		deleteData(); // virtual
 194		mBadBufferAllocation = false ;
 195		mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 196		if (!mData)
 197		{
 198			llwarns << "Failed to allocate image data size [" << size << "]" << llendl;
 199			size = 0 ;
 200			mWidth = mHeight = 0 ;
 201			mBadBufferAllocation = true ;
 202		}
 203		mDataSize = size;
 204	}
 205
 206	return mData;
 207}
 208
 209// virtual
 210U8* LLImageBase::reallocateData(S32 size)
 211{
 212	LLMemType mt1(mMemType);
 213	U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 214	if (!new_datap)
 215	{
 216		llwarns << "Out of memory in LLImageBase::reallocateData" << llendl;
 217		return 0;
 218	}
 219	if (mData)
 220	{
 221		S32 bytes = llmin(mDataSize, size);
 222		memcpy(new_datap, mData, bytes);	/* Flawfinder: ignore */
 223		FREE_MEM(sPrivatePoolp, mData) ;
 224	}
 225	mData = new_datap;
 226	mDataSize = size;
 227	return mData;
 228}
 229
 230const U8* LLImageBase::getData() const	
 231{ 
 232	if(mBadBufferAllocation)
 233	{
 234		llerrs << "Bad memory allocation for the image buffer!" << llendl ;
 235	}
 236
 237	return mData; 
 238} // read only
 239
 240U8* LLImageBase::getData()				
 241{ 
 242	if(mBadBufferAllocation)
 243	{
 244		llerrs << "Bad memory allocation for the image buffer!" << llendl ;
 245	}
 246
 247	return mData; 
 248}
 249
 250bool LLImageBase::isBufferInvalid()
 251{
 252	return mBadBufferAllocation || mData == NULL ;
 253}
 254
 255void LLImageBase::setSize(S32 width, S32 height, S32 ncomponents)
 256{
 257	mWidth = width;
 258	mHeight = height;
 259	mComponents = ncomponents;
 260}
 261
 262U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 size)
 263{
 264	setSize(width, height, ncomponents);
 265	return allocateData(size); // virtual
 266}
 267
 268//---------------------------------------------------------------------------
 269// LLImageRaw
 270//---------------------------------------------------------------------------
 271
 272S32 LLImageRaw::sGlobalRawMemory = 0;
 273S32 LLImageRaw::sRawImageCount = 0;
 274
 275LLImageRaw::LLImageRaw()
 276	: LLImageBase()
 277{
 278	mMemType = LLMemType::MTYPE_IMAGERAW;
 279	++sRawImageCount;
 280}
 281
 282LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components)
 283	: LLImageBase()
 284{
 285	mMemType = LLMemType::MTYPE_IMAGERAW;
 286	//llassert( S32(width) * S32(height) * S32(components) <= MAX_IMAGE_DATA_SIZE );
 287	allocateDataSize(width, height, components);
 288	++sRawImageCount;
 289}
 290
 291LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
 292	: LLImageBase()
 293{
 294	mMemType = LLMemType::MTYPE_IMAGERAW;
 295	if(allocateDataSize(width, height, components))
 296	{
 297		memcpy(getData(), data, width*height*components);
 298	}
 299	++sRawImageCount;
 300}
 301
 302//LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
 303//	: LLImageBase()
 304//{
 305//	createFromFile(filename, j2c_lowest_mip_only);
 306//}
 307
 308LLImageRaw::~LLImageRaw()
 309{
 310	// NOTE: ~LLimageBase() call to deleteData() calls LLImageBase::deleteData()
 311	//        NOT LLImageRaw::deleteData()
 312	deleteData();
 313	--sRawImageCount;
 314}
 315
 316// virtual
 317U8* LLImageRaw::allocateData(S32 size)
 318{
 319	U8* res = LLImageBase::allocateData(size);
 320	sGlobalRawMemory += getDataSize();
 321	return res;
 322}
 323
 324// virtual
 325U8* LLImageRaw::reallocateData(S32 size)
 326{
 327	sGlobalRawMemory -= getDataSize();
 328	U8* res = LLImageBase::reallocateData(size);
 329	sGlobalRawMemory += getDataSize();
 330	return res;
 331}
 332
 333// virtual
 334void LLImageRaw::deleteData()
 335{
 336	sGlobalRawMemory -= getDataSize();
 337	LLImageBase::deleteData();
 338}
 339
 340void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) 
 341{ 
 342	if(data == getData())
 343	{
 344		return ;
 345	}
 346
 347	deleteData();
 348
 349	LLImageBase::setSize(width, height, components) ;
 350	LLImageBase::setDataAndSize(data, width * height * components) ;
 351	
 352	sGlobalRawMemory += getDataSize();
 353}
 354
 355BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
 356{
 357	if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components))
 358	{
 359		return TRUE;
 360	}
 361	// Reallocate the data buffer.
 362	deleteData();
 363
 364	allocateDataSize(width,height,components);
 365
 366	return TRUE;
 367}
 368
 369#if 0
 370U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
 371{
 372	LLMemType mt1(mMemType);
 373	U8 *data = new U8[width*height*getComponents()];
 374
 375	// Should do some simple bounds checking
 376	if (!data)
 377	{
 378		llerrs << "Out of memory in LLImageRaw::getSubImage" << llendl;
 379		return NULL;
 380	}
 381
 382	U32 i;
 383	for (i = y_pos; i < y_pos+height; i++)
 384	{
 385		memcpy(data + i*width*getComponents(),		/* Flawfinder: ignore */
 386				getData() + ((y_pos + i)*getWidth() + x_pos)*getComponents(), getComponents()*width);
 387	}
 388	return data;
 389}
 390#endif
 391
 392BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
 393							 const U8 *data, U32 stride, BOOL reverse_y)
 394{
 395	if (!getData())
 396	{
 397		return FALSE;
 398	}
 399	if (!data)
 400	{
 401		return FALSE;
 402	}
 403
 404	// Should do some simple bounds checking
 405
 406	U32 i;
 407	for (i = 0; i < height; i++)
 408	{
 409		const U32 row = reverse_y ? height - 1 - i : i;
 410		const U32 from_offset = row * ((stride == 0) ? width*getComponents() : stride);
 411		const U32 to_offset = (y_pos + i)*getWidth() + x_pos;
 412		memcpy(getData() + to_offset*getComponents(),		/* Flawfinder: ignore */
 413				data + from_offset, getComponents()*width);
 414	}
 415
 416	return TRUE;
 417}
 418
 419void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a)
 420{
 421	llassert( getComponents() <= 4 );
 422	// This is fairly bogus, but it'll do for now.
 423	U8 *pos = getData();
 424	U32 x, y;
 425	for (x = 0; x < getWidth(); x++)
 426	{
 427		for (y = 0; y < getHeight(); y++)
 428		{
 429			*pos = r;
 430			pos++;
 431			if (getComponents() == 1)
 432			{
 433				continue;
 434			}
 435			*pos = g;
 436			pos++;
 437			if (getComponents() == 2)
 438			{
 439				continue;
 440			}
 441			*pos = b;
 442			pos++;
 443			if (getComponents() == 3)
 444			{
 445				continue;
 446			}
 447			*pos = a;
 448			pos++;
 449		}
 450	}
 451}
 452
 453// Reverses the order of the rows in the image
 454void LLImageRaw::verticalFlip()
 455{
 456	LLMemType mt1(mMemType);
 457	S32 row_bytes = getWidth() * getComponents();
 458	llassert(row_bytes > 0);
 459	std::vector<U8> line_buffer(row_bytes);
 460	S32 mid_row = getHeight() / 2;
 461	for( S32 row = 0; row < mid_row; row++ )
 462	{
 463		U8* row_a_data = getData() + row * row_bytes;
 464		U8* row_b_data = getData() + (getHeight() - 1 - row) * row_bytes;
 465		memcpy( &line_buffer[0], row_a_data,  row_bytes );
 466		memcpy( row_a_data,  row_b_data,  row_bytes );
 467		memcpy( row_b_data,  &line_buffer[0], row_bytes );
 468	}
 469}
 470
 471
 472void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
 473{
 474	// Find new sizes
 475	S32 new_width = MIN_IMAGE_SIZE;
 476	S32 new_height = MIN_IMAGE_SIZE;
 477
 478	while( (new_width < getWidth()) && (new_width < max_dim) )
 479	{
 480		new_width <<= 1;
 481	}
 482
 483	while( (new_height < getHeight()) && (new_height < max_dim) )
 484	{
 485		new_height <<= 1;
 486	}
 487
 488	scale( new_width, new_height, scale_image );
 489}
 490
 491void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
 492{
 493	// Find new sizes
 494	S32 new_width = max_dim;
 495	S32 new_height = max_dim;
 496
 497	while( (new_width > getWidth()) && (new_width > MIN_IMAGE_SIZE) )
 498	{
 499		new_width >>= 1;
 500	}
 501
 502	while( (new_height > getHeight()) && (new_height > MIN_IMAGE_SIZE) )
 503	{
 504		new_height >>= 1;
 505	}
 506
 507	scale( new_width, new_height, scale_image );
 508}
 509
 510void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
 511{
 512	// Strong bias towards rounding down (to save bandwidth)
 513	// No bias would mean THRESHOLD == 1.5f;
 514	const F32 THRESHOLD = 1.75f; 
 515
 516	// Find new sizes
 517	S32 larger_w = max_dim;	// 2^n >= mWidth
 518	S32 smaller_w = max_dim;	// 2^(n-1) <= mWidth
 519	while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) )
 520	{
 521		larger_w = smaller_w;
 522		smaller_w >>= 1;
 523	}
 524	S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
 525
 526
 527	S32 larger_h = max_dim;	// 2^m >= mHeight
 528	S32 smaller_h = max_dim;	// 2^(m-1) <= mHeight
 529	while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) )
 530	{
 531		larger_h = smaller_h;
 532		smaller_h >>= 1;
 533	}
 534	S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
 535
 536
 537	scale( new_width, new_height );
 538}
 539
 540
 541
 542
 543// Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f).  Thanks, Jim Blinn!
 544inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b )
 545{
 546	U32 i = a * b + 128;
 547	return U8((i + (i>>8)) >> 8);
 548}
 549
 550
 551void LLImageRaw::composite( LLImageRaw* src )
 552{
 553	LLImageRaw* dst = this;  // Just for clarity.
 554
 555	llassert(3 == src->getComponents());
 556	llassert(3 == dst->getComponents());
 557
 558	if( 3 == dst->getComponents() )
 559	{
 560		if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
 561		{
 562			// No scaling needed
 563			if( 3 == src->getComponents() )
 564			{
 565				copyUnscaled( src );  // alpha is one so just copy the data.
 566			}
 567			else
 568			{
 569				compositeUnscaled4onto3( src );
 570			}
 571		}
 572		else
 573		{
 574			if( 3 == src->getComponents() )
 575			{
 576				copyScaled( src );  // alpha is one so just copy the data.
 577			}
 578			else
 579			{
 580				compositeScaled4onto3( src );
 581			}
 582		}
 583	}
 584}
 585
 586// Src and dst can be any size.  Src has 4 components.  Dst has 3 components.
 587void LLImageRaw::compositeScaled4onto3(LLImageRaw* src)
 588{
 589	LLMemType mt1(mMemType);
 590	llinfos << "compositeScaled4onto3" << llendl;
 591
 592	LLImageRaw* dst = this;  // Just for clarity.
 593
 594	llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) );
 595
 596	S32 temp_data_size = src->getWidth() * dst->getHeight() * src->getComponents();
 597	llassert_always(temp_data_size > 0);
 598	std::vector<U8> temp_buffer(temp_data_size);
 599
 600	// Vertical: scale but no composite
 601	for( S32 col = 0; col < src->getWidth(); col++ )
 602	{
 603		copyLineScaled( src->getData() + (src->getComponents() * col), &temp_buffer[0] + (src->getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
 604	}
 605
 606	// Horizontal: scale and composite
 607	for( S32 row = 0; row < dst->getHeight(); row++ )
 608	{
 609		compositeRowScaled4onto3( &temp_buffer[0] + (src->getComponents() * src->getWidth() * row), dst->getData() + (dst->getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth() );
 610	}
 611}
 612
 613
 614// Src and dst are same size.  Src has 4 components.  Dst has 3 components.
 615void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src )
 616{
 617	/*
 618	//test fastFractionalMult()
 619	{
 620		U8 i = 255;
 621		U8 j = 255;
 622		do
 623		{
 624			do
 625			{
 626				llassert( fastFractionalMult(i, j) == (U8)(255*(i/255.f)*(j/255.f) + 0.5f) );
 627			} while( j-- );
 628		} while( i-- );
 629	}
 630	*/
 631
 632	LLImageRaw* dst = this;  // Just for clarity.
 633
 634	llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
 635	llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
 636
 637
 638	U8* src_data = src->getData();
 639	U8* dst_data = dst->getData();
 640	S32 pixels = getWidth() * getHeight();
 641	while( pixels-- )
 642	{
 643		U8 alpha = src_data[3];
 644		if( alpha )
 645		{
 646			if( 255 == alpha )
 647			{
 648				dst_data[0] = src_data[0];
 649				dst_data[1] = src_data[1];
 650				dst_data[2] = src_data[2];
 651			}
 652			else
 653			{
 654
 655				U8 transparency = 255 - alpha;
 656				dst_data[0] = fastFractionalMult( dst_data[0], transparency ) + fastFractionalMult( src_data[0], alpha );
 657				dst_data[1] = fastFractionalMult( dst_data[1], transparency ) + fastFractionalMult( src_data[1], alpha );
 658				dst_data[2] = fastFractionalMult( dst_data[2], transparency ) + fastFractionalMult( src_data[2], alpha );
 659			}
 660		}
 661
 662		src_data += 4;
 663		dst_data += 3;
 664	}
 665}
 666
 667// Fill the buffer with a constant color
 668void LLImageRaw::fill( const LLColor4U& color )
 669{
 670	S32 pixels = getWidth() * getHeight();
 671	if( 4 == getComponents() )
 672	{
 673		U32* data = (U32*) getData();
 674		for( S32 i = 0; i < pixels; i++ )
 675		{
 676			data[i] = color.mAll;
 677		}
 678	}
 679	else
 680	if( 3 == getComponents() )
 681	{
 682		U8* data = getData();
 683		for( S32 i = 0; i < pixels; i++ )
 684		{
 685			data[0] = color.mV[0];
 686			data[1] = color.mV[1];
 687			data[2] = color.mV[2];
 688			data += 3;
 689		}
 690	}
 691}
 692
 693
 694
 695
 696// Src and dst can be any size.  Src and dst can each have 3 or 4 components.
 697void LLImageRaw::copy(LLImageRaw* src)
 698{
 699	if (!src)
 700	{
 701		llwarns << "LLImageRaw::copy called with a null src pointer" << llendl;
 702		return;
 703	}
 704
 705	LLImageRaw* dst = this;  // Just for clarity.
 706
 707	if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
 708	{
 709		// No scaling needed
 710		if( src->getComponents() == dst->getComponents() )
 711		{
 712			copyUnscaled( src );
 713		}
 714		else
 715		if( 3 == src->getComponents() )
 716		{
 717			copyUnscaled3onto4( src );
 718		}
 719		else
 720		{
 721			// 4 == src->getComponents()
 722			copyUnscaled4onto3( src );
 723		}
 724	}
 725	else
 726	{
 727		// Scaling needed
 728		// No scaling needed
 729		if( src->getComponents() == dst->getComponents() )
 730		{
 731			copyScaled( src );
 732		}
 733		else
 734		if( 3 == src->getComponents() )
 735		{
 736			copyScaled3onto4( src );
 737		}
 738		else
 739		{
 740			// 4 == src->getComponents()
 741			copyScaled4onto3( src );
 742		}
 743	}
 744}
 745
 746// Src and dst are same size.  Src and dst have same number of components.
 747void LLImageRaw::copyUnscaled(LLImageRaw* src)
 748{
 749	LLImageRaw* dst = this;  // Just for clarity.
 750
 751	llassert( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) );
 752	llassert( src->getComponents() == dst->getComponents() );
 753	llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
 754
 755	memcpy( dst->getData(), src->getData(), getWidth() * getHeight() * getComponents() );	/* Flawfinder: ignore */
 756}
 757
 758
 759// Src and dst can be any size.  Src has 3 components.  Dst has 4 components.
 760void LLImageRaw::copyScaled3onto4(LLImageRaw* src)
 761{
 762	llassert( (3 == src->getComponents()) && (4 == getComponents()) );
 763
 764	// Slow, but simple.  Optimize later if needed.
 765	LLImageRaw temp( src->getWidth(), src->getHeight(), 4);
 766	temp.copyUnscaled3onto4( src );
 767	copyScaled( &temp );
 768}
 769
 770
 771// Src and dst can be any size.  Src has 4 components.  Dst has 3 components.
 772void LLImageRaw::copyScaled4onto3(LLImageRaw* src)
 773{
 774	llassert( (4 == src->getComponents()) && (3 == getComponents()) );
 775
 776	// Slow, but simple.  Optimize later if needed.
 777	LLImageRaw temp( src->getWidth(), src->getHeight(), 3);
 778	temp.copyUnscaled4onto3( src );
 779	copyScaled( &temp );
 780}
 781
 782
 783// Src and dst are same size.  Src has 4 components.  Dst has 3 components.
 784void LLImageRaw::copyUnscaled4onto3( LLImageRaw* src )
 785{
 786	LLImageRaw* dst = this;  // Just for clarity.
 787
 788	llassert( (3 == dst->getComponents()) && (4 == src->getComponents()) );
 789	llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
 790
 791	S32 pixels = getWidth() * getHeight();
 792	U8* src_data = src->getData();
 793	U8* dst_data = dst->getData();
 794	for( S32 i=0; i<pixels; i++ )
 795	{
 796		dst_data[0] = src_data[0];
 797		dst_data[1] = src_data[1];
 798		dst_data[2] = src_data[2];
 799		src_data += 4;
 800		dst_data += 3;
 801	}
 802}
 803
 804
 805// Src and dst are same size.  Src has 3 components.  Dst has 4 components.
 806void LLImageRaw::copyUnscaled3onto4( LLImageRaw* src )
 807{
 808	LLImageRaw* dst = this;  // Just for clarity.
 809	llassert( 3 == src->getComponents() );
 810	llassert( 4 == dst->getComponents() );
 811	llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
 812
 813	S32 pixels = getWidth() * getHeight();
 814	U8* src_data = src->getData();
 815	U8* dst_data = dst->getData();
 816	for( S32 i=0; i<pixels; i++ )
 817	{
 818		dst_data[0] = src_data[0];
 819		dst_data[1] = src_data[1];
 820		dst_data[2] = src_data[2];
 821		dst_data[3] = 255;
 822		src_data += 3;
 823		dst_data += 4;
 824	}
 825}
 826
 827
 828// Src and dst can be any size.  Src and dst have same number of components.
 829void LLImageRaw::copyScaled( LLImageRaw* src )
 830{
 831	LLMemType mt1(mMemType);
 832	LLImageRaw* dst = this;  // Just for clarity.
 833
 834	llassert_always( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) );
 835	llassert_always( src->getComponents() == dst->getComponents() );
 836
 837	if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
 838	{
 839		memcpy( dst->getData(), src->getData(), getWidth() * getHeight() * getComponents() );	/* Flawfinder: ignore */
 840		return;
 841	}
 842
 843	S32 temp_data_size = src->getWidth() * dst->getHeight() * getComponents();
 844	llassert_always(temp_data_size > 0);
 845	std::vector<U8> temp_buffer(temp_data_size);
 846
 847	// Vertical
 848	for( S32 col = 0; col < src->getWidth(); col++ )
 849	{
 850		copyLineScaled( src->getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
 851	}
 852
 853	// Horizontal
 854	for( S32 row = 0; row < dst->getHeight(); row++ )
 855	{
 856		copyLineScaled( &temp_buffer[0] + (getComponents() * src->getWidth() * row), dst->getData() + (getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth(), 1, 1 );
 857	}
 858}
 859
 860#if 0
 861//scale down image by not blending a pixel with its neighbors.
 862BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
 863{
 864	LLMemType mt1(mMemType);
 865
 866	S8 c = getComponents() ;
 867	llassert((1 == c) || (3 == c) || (4 == c) );
 868
 869	S32 old_width = getWidth();
 870	S32 old_height = getHeight();
 871	
 872	S32 new_data_size = old_width * new_height * c ;
 873	llassert_always(new_data_size > 0);
 874
 875	F32 ratio_x = (F32)old_width / new_width ;
 876	F32 ratio_y = (F32)old_height / new_height ;
 877	if( ratio_x < 1.0f || ratio_y < 1.0f )
 878	{
 879		return TRUE;  // Nothing to do.
 880	}
 881	ratio_x -= 1.0f ;
 882	ratio_y -= 1.0f ;
 883
 884	U8* new_data = allocateMemory(new_data_size) ;
 885	llassert_always(new_data != NULL) ;
 886
 887	U8* old_data = getData() ;
 888	S32 i, j, k, s, t;
 889	for(i = 0, s = 0, t = 0 ; i < new_height ; i++)
 890	{
 891		for(j = 0 ; j < new_width ; j++)
 892		{
 893			for(k = 0 ; k < c ; k++)
 894			{
 895				new_data[s++] = old_data[t++] ;
 896			}
 897			t += (S32)(ratio_x * c + 0.1f) ;
 898		}
 899		t += (S32)(ratio_y * old_width * c + 0.1f) ;
 900	}
 901
 902	setDataAndSize(new_data, new_width, new_height, c) ;
 903	
 904	return TRUE ;
 905}
 906#endif
 907
 908BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
 909{
 910	LLMemType mt1(mMemType);
 911	llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) );
 912
 913	S32 old_width = getWidth();
 914	S32 old_height = getHeight();
 915	
 916	if( (old_width == new_width) && (old_height == new_height) )
 917	{
 918		return TRUE;  // Nothing to do.
 919	}
 920
 921	// Reallocate the data buffer.
 922
 923	if (scale_image_data)
 924	{
 925		S32 temp_data_size = old_width * new_height * getComponents();
 926		llassert_always(temp_data_size > 0);
 927		std::vector<U8> temp_buffer(temp_data_size);
 928
 929		// Vertical
 930		for( S32 col = 0; col < old_width; col++ )
 931		{
 932			copyLineScaled( getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), old_height, new_height, old_width, old_width );
 933		}
 934
 935		deleteData();
 936
 937		U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
 938
 939		// Horizontal
 940		for( S32 row = 0; row < new_height; row++ )
 941		{
 942			copyLineScaled( &temp_buffer[0] + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
 943		}
 944	}
 945	else
 946	{
 947		// copy	out	existing image data
 948		S32	temp_data_size = old_width * old_height	* getComponents();
 949		std::vector<U8> temp_buffer(temp_data_size);
 950		memcpy(&temp_buffer[0],	getData(), temp_data_size);
 951
 952		// allocate	new	image data,	will delete	old	data
 953		U8*	new_buffer = allocateDataSize(new_width, new_height, getComponents());
 954
 955		for( S32 row = 0; row <	new_height;	row++ )
 956		{
 957			if (row	< old_height)
 958			{
 959				memcpy(new_buffer +	(new_width * row * getComponents()), &temp_buffer[0] + (old_width *	row	* getComponents()),	getComponents()	* llmin(old_width, new_width));
 960				if (old_width <	new_width)
 961				{
 962					// pad out rest	of row with	black
 963					memset(new_buffer +	(getComponents() * ((new_width * row) +	old_width)), 0,	getComponents()	* (new_width - old_width));
 964				}
 965			}
 966			else
 967			{
 968				// pad remaining rows with black
 969				memset(new_buffer +	(new_width * row * getComponents()), 0,	new_width *	getComponents());
 970			}
 971		}
 972	}
 973
 974	return TRUE ;
 975}
 976
 977void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step )
 978{
 979	const S32 components = getComponents();
 980	llassert( components >= 1 && components <= 4 );
 981
 982	const F32 ratio = F32(in_pixel_len) / out_pixel_len; // ratio of old to new
 983	const F32 norm_factor = 1.f / ratio;
 984
 985	S32 goff = components >= 2 ? 1 : 0;
 986	S32 boff = components >= 3 ? 2 : 0;
 987	for( S32 x = 0; x < out_pixel_len; x++ )
 988	{
 989		// Sample input pixels in range from sample0 to sample1.
 990		// Avoid floating point accumulation error... don't just add ratio each time.  JC
 991		const F32 sample0 = x * ratio;
 992		const F32 sample1 = (x+1) * ratio;
 993		const S32 index0 = llfloor(sample0);			// left integer (floor)
 994		const S32 index1 = llfloor(sample1);			// right integer (floor)
 995		const F32 fract0 = 1.f - (sample0 - F32(index0));	// spill over on left
 996		const F32 fract1 = sample1 - F32(index1);			// spill-over on right
 997
 998		if( index0 == index1 )
 999		{
1000			// Interval is embedded in one input pixel
1001			S32 t0 = x * out_pixel_step * components;
1002			S32 t1 = index0 * in_pixel_step * components;
1003			U8* outp = out + t0;
1004			U8* inp = in + t1;
1005			for (S32 i = 0; i < components; ++i)
1006			{
1007				*outp = *inp;
1008				++outp;
1009				++inp;
1010			}
1011		}
1012		else
1013		{
1014			// Left straddle
1015			S32 t1 = index0 * in_pixel_step * components;
1016			F32 r = in[t1 + 0] * fract0;
1017			F32 g = in[t1 + goff] * fract0;
1018			F32 b = in[t1 + boff] * fract0;
1019			F32 a = 0;
1020			if( components == 4)
1021			{
1022				a = in[t1 + 3] * fract0;
1023			}
1024		
1025			// Central interval
1026			if (components < 4)
1027			{
1028				for( S32 u = index0 + 1; u < index1; u++ )
1029				{
1030					S32 t2 = u * in_pixel_step * components;
1031					r += in[t2 + 0];
1032					g += in[t2 + goff];
1033					b += in[t2 + boff];
1034				}
1035			}
1036			else
1037			{
1038				for( S32 u = index0 + 1; u < index1; u++ )
1039				{
1040					S32 t2 = u * in_pixel_step * components;
1041					r += in[t2 + 0];
1042					g += in[t2 + 1];
1043					b += in[t2 + 2];
1044					a += in[t2 + 3];
1045				}
1046			}
1047
1048			// right straddle
1049			// Watch out for reading off of end of input array.
1050			if( fract1 && index1 < in_pixel_len )
1051			{
1052				S32 t3 = index1 * in_pixel_step * components;
1053				if (components < 4)
1054				{
1055					U8 in0 = in[t3 + 0];
1056					U8 in1 = in[t3 + goff];
1057					U8 in2 = in[t3 + boff];
1058					r += in0 * fract1;
1059					g += in1 * fract1;
1060					b += in2 * fract1;
1061				}
1062				else
1063				{
1064					U8 in0 = in[t3 + 0];
1065					U8 in1 = in[t3 + 1];
1066					U8 in2 = in[t3 + 2];
1067					U8 in3 = in[t3 + 3];
1068					r += in0 * fract1;
1069					g += in1 * fract1;
1070					b += in2 * fract1;
1071					a += in3 * fract1;
1072				}
1073			}
1074
1075			r *= norm_factor;
1076			g *= norm_factor;
1077			b *= norm_factor;
1078			a *= norm_factor;  // skip conditional
1079
1080			S32 t4 = x * out_pixel_step * components;
1081			out[t4 + 0] = U8(llround(r));
1082			if (components >= 2)
1083				out[t4 + 1] = U8(llround(g));
1084			if (components >= 3)
1085				out[t4 + 2] = U8(llround(b));
1086			if( components == 4)
1087				out[t4 + 3] = U8(llround(a));
1088		}
1089	}
1090}
1091
1092void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len )
1093{
1094	llassert( getComponents() == 3 );
1095
1096	const S32 IN_COMPONENTS = 4;
1097	const S32 OUT_COMPONENTS = 3;
1098
1099	const F32 ratio = F32(in_pixel_len) / out_pixel_len; // ratio of old to new
1100	const F32 norm_factor = 1.f / ratio;
1101
1102	for( S32 x = 0; x < out_pixel_len; x++ )
1103	{
1104		// Sample input pixels in range from sample0 to sample1.
1105		// Avoid floating point accumulation error... don't just add ratio each time.  JC
1106		const F32 sample0 = x * ratio;
1107		const F32 sample1 = (x+1) * ratio;
1108		const S32 index0 = S32(sample0);			// left integer (floor)
1109		const S32 index1 = S32(sample1);			// right integer (floor)
1110		const F32 fract0 = 1.f - (sample0 - F32(index0));	// spill over on left
1111		const F32 fract1 = sample1 - F32(index1);			// spill-over on right
1112
1113		U8 in_scaled_r;
1114		U8 in_scaled_g;
1115		U8 in_scaled_b;
1116		U8 in_scaled_a;
1117
1118		if( index0 == index1 )
1119		{
1120			// Interval is embedded in one input pixel
1121			S32 t1 = index0 * IN_COMPONENTS;
1122			in_scaled_r = in[t1 + 0];
1123			in_scaled_g = in[t1 + 0];
1124			in_scaled_b = in[t1 + 0];
1125			in_scaled_a = in[t1 + 0];
1126		}
1127		else
1128		{
1129			// Left straddle
1130			S32 t1 = index0 * IN_COMPONENTS;
1131			F32 r = in[t1 + 0] * fract0;
1132			F32 g = in[t1 + 1] * fract0;
1133			F32 b = in[t1 + 2] * fract0;
1134			F32 a = in[t1 + 3] * fract0;
1135		
1136			// Central interval
1137			for( S32 u = index0 + 1; u < index1; u++ )
1138			{
1139				S32 t2 = u * IN_COMPONENTS;
1140				r += in[t2 + 0];
1141				g += in[t2 + 1];
1142				b += in[t2 + 2];
1143				a += in[t2 + 3];
1144			}
1145
1146			// right straddle
1147			// Watch out for reading off of end of input array.
1148			if( fract1 && index1 < in_pixel_len )
1149			{
1150				S32 t3 = index1 * IN_COMPONENTS;
1151				r += in[t3 + 0] * fract1;
1152				g += in[t3 + 1] * fract1;
1153				b += in[t3 + 2] * fract1;
1154				a += in[t3 + 3] * fract1;
1155			}
1156
1157			r *= norm_factor;
1158			g *= norm_factor;
1159			b *= norm_factor;
1160			a *= norm_factor;
1161
1162			in_scaled_r = U8(llround(r));
1163			in_scaled_g = U8(llround(g));
1164			in_scaled_b = U8(llround(b));
1165			in_scaled_a = U8(llround(a));
1166		}
1167
1168		if( in_scaled_a )
1169		{
1170			if( 255 == in_scaled_a )
1171			{
1172				out[0] = in_scaled_r;
1173				out[1] = in_scaled_g;
1174				out[2] = in_scaled_b;
1175			}
1176			else
1177			{
1178				U8 transparency = 255 - in_scaled_a;
1179				out[0] = fastFractionalMult( out[0], transparency ) + fastFractionalMult( in_scaled_r, in_scaled_a );
1180				out[1] = fastFractionalMult( out[1], transparency ) + fastFractionalMult( in_scaled_g, in_scaled_a );
1181				out[2] = fastFractionalMult( out[2], transparency ) + fastFractionalMult( in_scaled_b, in_scaled_a );
1182			}
1183		}
1184		out += OUT_COMPONENTS;
1185	}
1186}
1187
1188
1189//----------------------------------------------------------------------------
1190
1191static struct
1192{
1193	const char* exten;
1194	EImageCodec codec;
1195}
1196file_extensions[] =
1197{
1198	{ "bmp", IMG_CODEC_BMP },
1199	{ "tga", IMG_CODEC_TGA },
1200	{ "j2c", IMG_CODEC_J2C },
1201	{ "jp2", IMG_CODEC_J2C },
1202	{ "texture", IMG_CODEC_J2C },
1203	{ "jpg", IMG_CODEC_JPEG },
1204	{ "jpeg", IMG_CODEC_JPEG },
1205	{ "mip", IMG_CODEC_DXT },
1206	{ "dxt", IMG_CODEC_DXT },
1207	{ "png", IMG_CODEC_PNG }
1208};
1209#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
1210#if 0
1211static std::string find_file(std::string &name, S8 *codec)
1212{
1213	std::string tname;
1214	for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
1215	{
1216		tname = name + "." + std::string(file_extensions[i].exten);
1217		llifstream ifs(tname, llifstream::binary);
1218		if (ifs.is_open())
1219		{
1220			ifs.close();
1221			if (codec)
1222				*codec = file_extensions[i].codec;
1223			return std::string(file_extensions[i].exten);
1224		}
1225	}
1226	return std::string("");
1227}
1228#endif
1229EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
1230{
1231	for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
1232	{
1233		if (exten == file_extensions[i].exten)
1234			return file_extensions[i].codec;
1235	}
1236	return IMG_CODEC_INVALID;
1237}
1238#if 0
1239bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
1240{
1241	std::string name = filename;
1242	size_t dotidx = name.rfind('.');
1243	S8 codec = IMG_CODEC_INVALID;
1244	std::string exten;
1245	
1246	deleteData(); // delete any existing data
1247
1248	if (dotidx != std::string::npos)
1249	{
1250		exten = name.substr(dotidx+1);
1251		LLStringUtil::toLower(exten);
1252		codec = getCodecFromExtension(exten);
1253	}
1254	else
1255	{
1256		exten = find_file(name, &codec);
1257		name = name + "." + exten;
1258	}
1259	if (codec == IMG_CODEC_INVALID)
1260	{
1261		return false; // format not recognized
1262	}
1263
1264	llifstream ifs(name, llifstream::binary);
1265	if (!ifs.is_open())
1266	{
1267		// SJB: changed from llinfos to lldebugs to reduce spam
1268		lldebugs << "Unable to open image file: " << name << llendl;
1269		return false;
1270	}
1271	
1272	ifs.seekg (0, std::ios::end);
1273	int length = ifs.tellg();
1274	if (j2c_lowest_mip_only && length > 2048)
1275	{
1276		length = 2048;
1277	}
1278	ifs.seekg (0, std::ios::beg);
1279
1280	if (!length)
1281	{
1282		llinfos << "Zero length file file: " << name << llendl;
1283		return false;
1284	}
1285	
1286	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
1287	llassert(image.notNull());
1288
1289	U8 *buffer = image->allocateData(length);
1290	ifs.read ((char*)buffer, length);
1291	ifs.close();
1292	
1293	BOOL success;
1294
1295	success = image->updateData();
1296	if (success)
1297	{
1298		if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C)
1299		{
1300			S32 width = image->getWidth();
1301			S32 height = image->getHeight();
1302			S32 discard_level = 0;
1303			while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL)
1304			{
1305				width >>= 1;
1306				height >>= 1;
1307				discard_level++;
1308			}
1309			((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level);
1310		}
1311		success = image->decode(this, 100000.0f);
1312	}
1313
1314	image = NULL; // deletes image
1315	if (!success)
1316	{
1317		deleteData();
1318		llwarns << "Unable to decode image" << name << llendl;
1319		return false;
1320	}
1321
1322	return true;
1323}
1324#endif
1325//---------------------------------------------------------------------------
1326// LLImageFormatted
1327//---------------------------------------------------------------------------
1328
1329//static
1330S32 LLImageFormatted::sGlobalFormattedMemory = 0;
1331
1332LLImageFormatted::LLImageFormatted(S8 codec)
1333	: LLImageBase(),
1334	  mCodec(codec),
1335	  mDecoding(0),
1336	  mDecoded(0),
1337	  mDiscardLevel(-1)
1338{
1339	mMemType = LLMemType::MTYPE_IMAGEFORMATTED;
1340}
1341
1342// virtual
1343LLImageFormatted::~LLImageFormatted()
1344{
1345	// NOTE: ~LLimageBase() call to deleteData() calls LLImageBase::deleteData()
1346	//        NOT LLImageFormatted::deleteData()
1347	deleteData();
1348}
1349
1350//----------------------------------------------------------------------------
1351
1352//virtual
1353void LLImageFormatted::resetLastError()
1354{
1355	LLImage::setLastError("");
1356}
1357
1358//virtual
1359void LLImageFormatted::setLastError(const std::string& message, const std::string& filename)
1360{
1361	std::string error = message;
1362	if (!filename.empty())
1363		error += std::string(" FILE: ") + filename;
1364	LLImage::setLastError(error);
1365}
1366
1367//----------------------------------------------------------------------------
1368
1369// static
1370LLImageFormatted* LLImageFormatted::createFromType(S8 codec)
1371{
1372	LLImageFormatted* image;
1373	switch(codec)
1374	{
1375	  case IMG_CODEC_BMP:
1376		image = new LLImageBMP();
1377		break;
1378	  case IMG_CODEC_TGA:
1379		image = new LLImageTGA();
1380		break;
1381	  case IMG_CODEC_JPEG:
1382		image = new LLImageJPEG();
1383		break;
1384	  case IMG_CODEC_PNG:
1385		image = new LLImagePNG();
1386		break;
1387	  case IMG_CODEC_J2C:
1388		image = new LLImageJ2C();
1389		break;
1390	  case IMG_CODEC_DXT:
1391		image = new LLImageDXT();
1392		break;
1393	  default:
1394		image = NULL;
1395		break;
1396	}
1397	return image;
1398}
1399
1400// static
1401LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring)
1402{
1403	std::string exten;
1404	size_t dotidx = instring.rfind('.');
1405	if (dotidx != std::string::npos)
1406	{
1407		exten = instring.substr(dotidx+1);
1408	}
1409	else
1410	{
1411		exten = instring;
1412	}
1413	S8 codec = getCodecFromExtension(exten);
1414	return createFromType(codec);
1415}
1416//----------------------------------------------------------------------------
1417
1418// virtual
1419void LLImageFormatted::dump()
1420{
1421	LLImageBase::dump();
1422
1423	llinfos << "LLImageFormatted"
1424			<< " mDecoding " << mDecoding
1425			<< " mCodec " << S32(mCodec)
1426			<< " mDecoded " << mDecoded
1427			<< llendl;
1428}
1429
1430//----------------------------------------------------------------------------
1431
1432S32 LLImageFormatted::calcDataSize(S32 discard_level)
1433{
1434	if (discard_level < 0)
1435	{
1436		discard_level = mDiscardLevel;
1437	}
1438	S32 w = getWidth() >> discard_level;
1439	S32 h = getHeight() >> discard_level;
1440	w = llmax(w, 1);
1441	h = llmax(h, 1);
1442	return w * h * getComponents();
1443}
1444
1445S32 LLImageFormatted::calcDiscardLevelBytes(S32 bytes)
1446{
1447	llassert(bytes >= 0);
1448	S32 discard_level = 0;
1449	while (1)
1450	{
1451		S32 bytes_needed = calcDataSize(discard_level); // virtual
1452		if (bytes_needed <= bytes)
1453		{
1454			break;
1455		}
1456		discard_level++;
1457		if (discard_level > MAX_IMAGE_MIP)
1458		{
1459			return -1;
1460		}
1461	}
1462	return discard_level;
1463}
1464
1465
1466//----------------------------------------------------------------------------
1467
1468// Subclasses that can handle more than 4 channels should override this function.
1469BOOL LLImageFormatted::decodeChannels(LLImageRaw* raw_image,F32  decode_time, S32 first_channel, S32 max_channel)
1470{
1471	llassert( (first_channel == 0) && (max_channel == 4) );
1472	return decode( raw_image, decode_time );  // Loads first 4 channels by default.
1473} 
1474
1475//----------------------------------------------------------------------------
1476
1477// virtual
1478U8* LLImageFormatted::allocateData(S32 size)
1479{
1480	U8* res = LLImageBase::allocateData(size); // calls deleteData()
1481	sGlobalFormattedMemory += getDataSize();
1482	return res;
1483}
1484
1485// virtual
1486U8* LLImageFormatted::reallocateData(S32 size)
1487{
1488	sGlobalFormattedMemory -= getDataSize();
1489	U8* res = LLImageBase::reallocateData(size);
1490	sGlobalFormattedMemory += getDataSize();
1491	return res;
1492}
1493
1494// virtual
1495void LLImageFormatted::deleteData()
1496{
1497	sGlobalFormattedMemory -= getDataSize();
1498	LLImageBase::deleteData();
1499}
1500
1501//----------------------------------------------------------------------------
1502
1503// virtual
1504void LLImageFormatted::sanityCheck()
1505{
1506	LLImageBase::sanityCheck();
1507
1508	if (mCodec >= IMG_CODEC_EOF)
1509	{
1510		llerrs << "Failed LLImageFormatted::sanityCheck "
1511			   << "decoding " << S32(mDecoding)
1512			   << "decoded " << S32(mDecoded)
1513			   << "codec " << S32(mCodec)
1514			   << llendl;
1515	}
1516}
1517
1518//----------------------------------------------------------------------------
1519
1520BOOL LLImageFormatted::copyData(U8 *data, S32 size)
1521{
1522	if ( data && ((data != getData()) || (size != getDataSize())) )
1523	{
1524		deleteData();
1525		allocateData(size);
1526		memcpy(getData(), data, size);	/* Flawfinder: ignore */
1527	}
1528	return TRUE;
1529}
1530
1531// LLImageFormatted becomes the owner of data
1532void LLImageFormatted::setData(U8 *data, S32 size)
1533{
1534	if (data && data != getData())
1535	{
1536		deleteData();
1537		setDataAndSize(data, size); // Access private LLImageBase members
1538
1539		sGlobalFormattedMemory += getDataSize();
1540	}
1541}
1542
1543void LLImageFormatted::appendData(U8 *data, S32 size)
1544{
1545	if (data)
1546	{
1547		if (!getData())
1548		{
1549			setData(data, size);
1550		}
1551		else 
1552		{
1553			S32 cursize = getDataSize();
1554			S32 newsize = cursize + size;
1555			reallocateData(newsize);
1556			memcpy(getData() + cursize, data, size);
1557			FREE_MEM(LLImageBase::getPrivatePool(), data);
1558		}
1559	}
1560}
1561
1562//----------------------------------------------------------------------------
1563
1564BOOL LLImageFormatted::load(const std::string &filename)
1565{
1566	resetLastError();
1567
1568	S32 file_size = 0;
1569	LLAPRFile infile ;
1570	infile.open(filename, LL_APR_RB, NULL, &file_size);
1571	apr_file_t* apr_file = infile.getFileHandle();
1572	if (!apr_file)
1573	{
1574		setLastError("Unable to open file for reading", filename);
1575		return FALSE;
1576	}
1577	if (file_size == 0)
1578	{
1579		setLastError("File is empty",filename);
1580		return FALSE;
1581	}
1582
1583	BOOL res;
1584	U8 *data = allocateData(file_size);
1585	apr_size_t bytes_read = file_size;
1586	apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
1587	if (s != APR_SUCCESS || (S32) bytes_read != file_size)
1588	{
1589		deleteData();
1590		setLastError("Unable to read entire file",filename);
1591		res = FALSE;
1592	}
1593	else
1594	{
1595		res = updateData();
1596	}
1597	
1598	return res;
1599}
1600
1601BOOL LLImageFormatted::save(const std::string &filename)
1602{
1603	resetLastError();
1604
1605	LLAPRFile outfile ;
1606	outfile.open(filename, LL_APR_WB);
1607	if (!outfile.getFileHandle())
1608	{
1609		setLastError("Unable to open file for writing", filename);
1610		return FALSE;
1611	}
1612	
1613	outfile.write(getData(), 	getDataSize());
1614	outfile.close() ;
1615	return TRUE;
1616}
1617
1618// BOOL LLImageFormatted::save(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
1619// Depricated to remove VFS dependency.
1620// Use:
1621// LLVFile::writeFile(image->getData(), image->getDataSize(), vfs, uuid, type);
1622
1623//----------------------------------------------------------------------------
1624
1625S8 LLImageFormatted::getCodec() const
1626{
1627	return mCodec;
1628}
1629
1630//============================================================================
1631
1632static void avg4_colors4(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst)
1633{
1634	dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2);
1635	dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2);
1636	dst[2] = (U8)(((U32)(a[2]) + b[2] + c[2] + d[2])>>2);
1637	dst[3] = (U8)(((U32)(a[3]) + b[3] + c[3] + d[3])>>2);
1638}
1639
1640static void avg4_colors3(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst)
1641{
1642	dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2);
1643	dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2);
1644	dst[2] = (U8)(((U32)(a[2]) + b[2] + c[2] + d[2])>>2);
1645}
1646
1647static void avg4_colors2(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst)
1648{
1649	dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2);
1650	dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2);
1651}
1652
1653//static
1654void LLImageBase::generateMip(const U8* indata, U8* mipdata, S32 width, S32 height, S32 nchannels)
1655{
1656	llassert(width > 0 && height > 0);
1657	U8* data = mipdata;
1658	S32 in_width = width*2;
1659	for (S32 h=0; h<height; h++)
1660	{
1661		for (S32 w=0; w<width; w++)
1662		{
1663			switch(nchannels)
1664			{
1665			  case 4:
1666				avg4_colors4(indata, indata+4, indata+4*in_width, indata+4*in_width+4, data);
1667				break;
1668			  case 3:
1669				avg4_colors3(indata, indata+3, indata+3*in_width, indata+3*in_width+3, data);
1670				break;
1671			  case 2:
1672				avg4_colors2(indata, indata+2, indata+2*in_width, indata+2*in_width+2, data);
1673				break;
1674			  case 1:
1675				*(U8*)data = (U8)(((U32)(indata[0]) + indata[1] + indata[in_width] + indata[in_width+1])>>2);
1676				break;
1677			  default:
1678				llerrs << "generateMmip called with bad num channels" << llendl;
1679			}
1680			indata += nchannels*2;
1681			data += nchannels;
1682		}
1683		indata += nchannels*in_width; // skip odd lines
1684	}
1685}
1686
1687
1688//============================================================================
1689
1690//static
1691F32 LLImageBase::calc_download_priority(F32 virtual_size, F32 visible_pixels, S32 bytes_sent)
1692{
1693	F32 w_priority;
1694
1695	F32 bytes_weight = 1.f;
1696	if (!bytes_sent)
1697	{
1698		bytes_weight = 20.f;
1699	}
1700	else if (bytes_sent < 1000)
1701	{
1702		bytes_weight = 1.f;
1703	}
1704	else if (bytes_sent < 2000)
1705	{
1706		bytes_weight = 1.f/1.5f;
1707	}
1708	else if (bytes_sent < 4000)
1709	{
1710		bytes_weight = 1.f/3.f;
1711	}
1712	else if (bytes_sent < 8000)
1713	{
1714		bytes_weight = 1.f/6.f;
1715	}
1716	else if (bytes_sent < 16000)
1717	{
1718		bytes_weight = 1.f/12.f;
1719	}
1720	else if (bytes_sent < 32000)
1721	{
1722		bytes_weight = 1.f/20.f;
1723	}
1724	else if (bytes_sent < 64000)
1725	{
1726		bytes_weight = 1.f/32.f;
1727	}
1728	else
1729	{
1730		bytes_weight = 1.f/64.f;
1731	}
1732	bytes_weight *= bytes_weight;
1733
1734
1735	//llinfos << "VS: " << virtual_size << llendl;
1736	F32 virtual_size_factor = virtual_size / (10.f*10.f);
1737
1738	// The goal is for weighted priority to be <= 0 when we've reached a point where
1739	// we've sent enough data.
1740	//llinfos << "BytesSent: " << bytes_sent << llendl;
1741	//llinfos << "BytesWeight: " << bytes_weight << llendl;
1742	//llinfos << "PreLog: " << bytes_weight * virtual_size_factor << llendl;
1743	w_priority = (F32)log10(bytes_weight * virtual_size_factor);
1744
1745	//llinfos << "PreScale: " << w_priority << llendl;
1746
1747	// We don't want to affect how MANY bytes we send based on the visible pixels, but the order
1748	// in which they're sent.  We post-multiply so we don't change the zero point.
1749	if (w_priority > 0.f)
1750	{
1751		F32 pixel_weight = (F32)log10(visible_pixels + 1)*3.0f;
1752		w_priority *= pixel_weight;
1753	}
1754
1755	return w_priority;
1756}
1757
1758//============================================================================