Commits

Scott Lawrence committed c81c87f Merge

merge changes for storm-1187

  • Participants
  • Parent commits baaafe2, d38e4f4

Comments (0)

Files changed (44)

indra/cmake/Variables.cmake

   set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
   set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
   set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.2")
-  set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "DWARF with dSYM File")
+  set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym)
 
   # NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
   # -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'

indra/integration_tests/llimage_libtest/llimage_libtest.cpp

 " -o, --output <file1 .. file2> OR <type>\n"
 "        List of image files to create (assumes same order as for input files)\n"
 "        OR 3 letters file type extension to convert each input file into.\n"
+" -r, --region <x0, y0, x1, y1>\n"
+"        Crop region applied to the input files in pixels.\n"
+"        Only used for j2c images. Default is no region cropping.\n"
+" -d, --discard_level <n>\n"
+"        Discard level max used on input. 0 is highest resolution. Max discard level is 5.\n"
+"        This allows the input image to be clamped in resolution when loading.\n"
+"        Only valid for j2c images. Default is no discard.\n"
+" -p, --precincts <n>\n"
+"        Dimension of precincts in pixels. Precincts are assumed square and identical for\n"
+"        all levels. Note that this option also add PLT and tile markers to the codestream, \n"
+"        and uses RPCL order. Power of 2 must be used.\n"
+"        Only valid for output j2c images. Default is no precincts used.\n"
+" -b, --blocks <n>\n"
+"        Dimension of coding blocks in pixels. Blocks are assumed square. Power of 2 must\n"
+"        be used. Blocks must be smaller than precincts. Like precincts, this option adds\n"
+"        PLT, tile markers and uses RPCL.\n"
+"        Only valid for output j2c images. Default is 64.\n"
+" -rev, --reversible\n"
+"        Set the compression to be lossless (reversible in j2c parlance).\n"
+"        Only valid for output j2c images.\n"
 " -log, --logmetrics <metric>\n"
 "        Log performance data for <metric>. Results in <metric>.slp\n"
 "        Note: so far, only ImageCompressionTester has been tested.\n"
-" -r, --analyzeperformance\n"
+" -a, --analyzeperformance\n"
 "        Create a report comparing <metric>_baseline.slp with current <metric>.slp\n"
-"        Results in <metric>_report.csv"
+"        Results in <metric>_report.csv\n"
 " -s, --image-stats\n"
 "        Output stats for each input and output image.\n"
 "\n";
 // Create an empty formatted image instance of the correct type from the filename
 LLPointer<LLImageFormatted> create_image(const std::string &filename)
 {
-	std::string exten = gDirUtilp->getExtension(filename);
-	U32 codec = LLImageBase::getCodecFromExtension(exten);
-	
-	LLPointer<LLImageFormatted> image;
-	switch (codec)
-	{
-		case IMG_CODEC_BMP:
-			image = new LLImageBMP();
-			break;
-		case IMG_CODEC_TGA:
-			image = new LLImageTGA();
-			break;
-		case IMG_CODEC_JPEG:
-			image = new LLImageJPEG();
-			break;
-		case IMG_CODEC_J2C:
-			image = new LLImageJ2C();
-			break;
-		case IMG_CODEC_PNG:
-			image = new LLImagePNG();
-			break;
-		default:
-			return NULL;
-	}
-	
+	std::string exten = gDirUtilp->getExtension(filename);	
+	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromExtension(exten);
 	return image;
 }
 
 }
 
 // Load an image from file and return a raw (decompressed) instance of its data
-LLPointer<LLImageRaw> load_image(const std::string &src_filename, bool output_stats)
+LLPointer<LLImageRaw> load_image(const std::string &src_filename, int discard_level, int* region, bool output_stats)
 {
 	LLPointer<LLImageFormatted> image = create_image(src_filename);
-
+	
+	// This just loads the image file stream into a buffer. No decoding done.
 	if (!image->load(src_filename))
 	{
 		return NULL;
 	}
 	
 	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
+	
+	// Set the image restriction on load in the case of a j2c image
+	if ((image->getCodec() == IMG_CODEC_J2C) && ((discard_level != -1) || (region != NULL)))
+	{
+		// That method doesn't exist (and likely, doesn't make sense) for any other image file format
+		// hence the required cryptic cast.
+		((LLImageJ2C*)(image.get()))->initDecode(*raw_image, discard_level, region);
+	}
+	
 	if (!image->decode(raw_image, 0.0f))
 	{
 		return NULL;
 }
 
 // Save a raw image instance into a file
-bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, bool output_stats)
+bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, int blocks_size, int precincts_size, bool reversible, bool output_stats)
 {
 	LLPointer<LLImageFormatted> image = create_image(dest_filename);
 	
+	// Set the image codestream parameters on output in the case of a j2c image
+	if (image->getCodec() == IMG_CODEC_J2C)
+	{
+		// That method doesn't exist (and likely, doesn't make sense) for any other image file format
+		// hence the required cryptic cast.
+		if ((blocks_size != -1) || (precincts_size != -1))
+		{
+			((LLImageJ2C*)(image.get()))->initEncode(*raw_image, blocks_size, precincts_size);
+		}
+		((LLImageJ2C*)(image.get()))->setReversible(reversible);
+	}
+	
 	if (!image->encode(raw_image, 0.0f))
 	{
 		return false;
 	// List of input and output files
 	std::list<std::string> input_filenames;
 	std::list<std::string> output_filenames;
+	// Other optional parsed arguments
 	bool analyze_performance = false;
 	bool image_stats = false;
+	int* region = NULL;
+	int discard_level = -1;
+	int precincts_size = -1;
+	int blocks_size = -1;
+	bool reversible = false;
 
 	// Init whatever is necessary
 	ll_init_apr();
 				file_name = argv[arg+1];	// Next argument and loop over
 			}
 		}
+		else if ((!strcmp(argv[arg], "--region") || !strcmp(argv[arg], "-r")) && arg < argc-1)
+		{
+			std::string value_str = argv[arg+1];
+			int index = 0;
+			region = new int[4];
+			while (value_str[0] != '-')		// if arg starts with '-', it's the next option
+			{
+				int value = atoi(value_str.c_str());
+				region[index++] = value;
+				arg += 1;					// Definitely skip that arg now we know it's a number
+				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list
+					break;
+				if (index == 4)				// Break out of the loop if we captured 4 values already
+					break;
+				value_str = argv[arg+1];	// Next argument and loop over
+			}
+			if (index != 4)
+			{
+				std::cout << "--region arguments invalid" << std::endl;
+				delete [] region;
+				region = NULL;
+			}
+		}
+		else if (!strcmp(argv[arg], "--discard_level") || !strcmp(argv[arg], "-d"))
+		{
+			std::string value_str;
+			if ((arg + 1) < argc)
+			{
+				value_str = argv[arg+1];
+			}
+			if (((arg + 1) >= argc) || (value_str[0] == '-'))
+			{
+				std::cout << "No valid --discard_level argument given, discard_level ignored" << std::endl;
+			}
+			else
+			{
+				discard_level = atoi(value_str.c_str());
+				// Clamp to the values accepted by the viewer
+				discard_level = llclamp(discard_level,0,5);
+			}
+		}
+		else if (!strcmp(argv[arg], "--precincts") || !strcmp(argv[arg], "-p"))
+		{
+			std::string value_str;
+			if ((arg + 1) < argc)
+			{
+				value_str = argv[arg+1];
+			}
+			if (((arg + 1) >= argc) || (value_str[0] == '-'))
+			{
+				std::cout << "No valid --precincts argument given, precincts ignored" << std::endl;
+			}
+			else
+			{
+				precincts_size = atoi(value_str.c_str());
+				// *TODO: make sure precincts_size is a power of 2
+			}
+		}
+		else if (!strcmp(argv[arg], "--blocks") || !strcmp(argv[arg], "-b"))
+		{
+			std::string value_str;
+			if ((arg + 1) < argc)
+			{
+				value_str = argv[arg+1];
+			}
+			if (((arg + 1) >= argc) || (value_str[0] == '-'))
+			{
+				std::cout << "No valid --blocks argument given, blocks ignored" << std::endl;
+			}
+			else
+			{
+				blocks_size = atoi(value_str.c_str());
+				// *TODO: make sure blocks_size is a power of 2
+			}
+		}
+		else if (!strcmp(argv[arg], "--reversible") || !strcmp(argv[arg], "-rev"))
+		{
+			reversible = true;
+		}
 		else if (!strcmp(argv[arg], "--logmetrics") || !strcmp(argv[arg], "-log"))
 		{
 			// '--logmetrics' needs to be specified with a named test metric argument
 					break;
 			}
 		}
-		else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-r"))
+		else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
 		{
 			analyze_performance = true;
 		}
 	}
 	if (analyze_performance && !LLFastTimer::sMetricLog)
 	{
-		std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -r) -> exit" << std::endl;
+		std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -a) -> exit" << std::endl;
 		return 0;
 	}
 	
 	std::list<std::string>::iterator out_file = output_filenames.begin();
 	std::list<std::string>::iterator in_end = input_filenames.end();
 	std::list<std::string>::iterator out_end = output_filenames.end();
-	for (; in_file != in_end; ++in_file)
+	for (; in_file != in_end; ++in_file, ++out_file)
 	{
 		// Load file
-		LLPointer<LLImageRaw> raw_image = load_image(*in_file, image_stats);
+		LLPointer<LLImageRaw> raw_image = load_image(*in_file, discard_level, region, image_stats);
 		if (!raw_image)
 		{
 			std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
 		// Save file
 		if (out_file != out_end)
 		{
-			if (!save_image(*out_file, raw_image, image_stats))
+			if (!save_image(*out_file, raw_image, blocks_size, precincts_size, reversible, image_stats))
 			{
 				std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl;
 			}
 			{
 				std::cout << *in_file << " -> " << *out_file << std::endl;
 			}
-			++out_file;
 		}
 	}
 
+	// Output perf data if requested by user
+	if (analyze_performance)
+	{
+		std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
+		std::string current_name  = LLFastTimer::sLogName + ".slp"; 
+		std::string report_name   = LLFastTimer::sLogName + "_report.csv";
+		
+		std::cout << "Analyzing performance, check report in : " << report_name << std::endl;
+
+		LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline_name, current_name, report_name);
+	}
+	
 	// Stop the perf gathering system if needed
 	if (LLFastTimer::sMetricLog)
 	{
 		sAllDone = true;
 	}
 	
-	// Output perf data if requested by user
-	if (analyze_performance)
-	{
-		std::cout << "Analyzing performance" << std::endl;
-		
-		std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
-		std::string current_name  = LLFastTimer::sLogName + ".slp"; 
-		std::string report_name   = LLFastTimer::sLogName + "_report.csv";
-		
-		LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline_name, current_name, report_name);
-	}
-	
 	// Cleanup and exit
 	LLImage::cleanupClass();
 	if (fast_timer_log_thread)

indra/llimage/llimage.cpp

 		return false;
 	}
 	
-	LLPointer<LLImageFormatted> image;
-	switch(codec)
-	{
-	  //case IMG_CODEC_RGB:
-	  case IMG_CODEC_BMP:
-		image = new LLImageBMP();
-		break;
-	  case IMG_CODEC_TGA:
-		image = new LLImageTGA();
-		break;
-	  case IMG_CODEC_JPEG:
-		image = new LLImageJPEG();
-		break;
-	  case IMG_CODEC_J2C:
-		image = new LLImageJ2C();
-		break;
-	  case IMG_CODEC_DXT:
-		image = new LLImageDXT();
-		break;
-	  default:
-		return false;
-	}
+	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
 	llassert(image.notNull());
 
 	U8 *buffer = image->allocateData(length);

indra/llimage/llimagej2c.cpp

 	return res;
 }
 
+BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* region)
+{
+	return mImpl->initDecode(*this,raw_image,discard_level,region);
+}
+
+BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size)
+{
+	return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size);
+}
 
 BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
 {
 //static
 S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
 {
+	// Note: this only provides an *estimate* of the size in bytes of an image level
+	// *TODO: find a way to read the true size (when available) and convey the fact
+	// that the result is an estimate in the other cases
 	if (rate <= 0.f) rate = .125f;
 	while (discard_level > 0)
 	{

indra/llimage/llimagej2c.h

 	/*virtual*/ void resetLastError();
 	/*virtual*/ void setLastError(const std::string& message, const std::string& filename = std::string());
 	
+	BOOL initDecode(LLImageRaw &raw_image, int discard_level, int* region);
+	BOOL initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size);
 	
 	// Encode with comment text 
 	BOOL encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0);
 	virtual BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) = 0;
 	virtual BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
 							BOOL reversible=FALSE) = 0;
+	virtual BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL) = 0;
+	virtual BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1) = 0;
 
 	friend class LLImageJ2C;
 };

indra/llimagej2coj/llimagej2coj.cpp

 {
 }
 
+BOOL LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
+{
+	// No specific implementation for this method in the OpenJpeg case
+	return FALSE;
+}
+
+BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size)
+{
+	// No specific implementation for this method in the OpenJpeg case
+	return FALSE;
+}
 
 BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
 {

indra/llimagej2coj/llimagej2coj.h

 	/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
 	/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
 								BOOL reversible = FALSE);
+	/*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
+	/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1);
 };
 
 #endif

indra/llkdu/llimagej2ckdu.cpp

 
 class kdc_flow_control {
 	
-public: // Member functions
-    kdc_flow_control(kdu_image_in_base *img_in, kdu_codestream codestream);
-    ~kdc_flow_control();
-    bool advance_components();
-    void process_components();
+public:
+	kdc_flow_control(kdu_image_in_base *img_in, kdu_codestream codestream);
+	~kdc_flow_control();
+	bool advance_components();
+	void process_components();
 	
-private: // Data
-    
-    struct kdc_component_flow_control {
-    public: // Data
-        kdu_image_in_base *reader;
-        int vert_subsampling;
-        int ratio_counter;  /*  Initialized to 0, decremented by `count_delta';
+private:
+	
+	struct kdc_component_flow_control {
+	public:
+		kdu_image_in_base *reader;
+		int vert_subsampling;
+		int ratio_counter;  /*  Initialized to 0, decremented by `count_delta';
                                 when < 0, a new line must be processed, after
                                 which it is incremented by `vert_subsampling'.  */
-        int initial_lines;
-        int remaining_lines;
-        kdu_line_buf *line;
-    };
-    
-    kdu_codestream codestream;
-    kdu_dims valid_tile_indices;
-    kdu_coords tile_idx;
-    kdu_tile tile;
-    int num_components;
-    kdc_component_flow_control *components;
-    int count_delta; // Holds the minimum of the `vert_subsampling' fields
-    kdu_multi_analysis engine;
-    kdu_long max_buffer_memory;
+		int initial_lines;
+		int remaining_lines;
+		kdu_line_buf *line;
+	};
+	
+	kdu_codestream codestream;
+	kdu_dims valid_tile_indices;
+	kdu_coords tile_idx;
+	kdu_tile tile;
+	int num_components;
+	kdc_component_flow_control *components;
+	int count_delta; // Holds the minimum of the `vert_subsampling' fields
+	kdu_multi_analysis engine;
+	kdu_long max_buffer_memory;
 };
 
 //
 
 const char* engineInfoLLImageJ2CKDU()
 {
-	return "KDU v6.4.1";
+	std::string version = llformat("KDU %s", KDU_CORE_VERSION);
+	return version.c_str();
 }
 
 LLImageJ2CKDU* createLLImageJ2CKDU()
 class LLKDUDecodeState
 {
 public:
+	LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
+	~LLKDUDecodeState();
+	BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
 
+private:
 	S32 mNumComponents;
 	BOOL mUseYCC;
 	kdu_dims mDims;
 	kdu_tile_comp mComps[4];
 	kdu_line_buf mLines[4];
 	kdu_pull_ifc mEngines[4];
-	bool mReversible[4]; // Some components may be reversible and others not.
-	int mBitDepths[4]; // Original bit-depth may be quite different from 8.
-
+	bool mReversible[4]; // Some components may be reversible and others not
+	int mBitDepths[4];   // Original bit-depth may be quite different from 8
+	
 	kdu_tile mTile;
 	kdu_byte *mBuf;
 	S32 mRowGap;
-
-	LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
-	~LLKDUDecodeState();
-	BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
-
-public:
-	int *AssignLayerBytes(siz_params *siz, int &num_specs);
-
-	void setupCodeStream(BOOL keep_codestream, LLImageJ2CKDU::ECodeStreamMode mode);
-	BOOL initDecode(LLImageRaw &raw_image, F32 decode_time, LLImageJ2CKDU::ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
 };
 
 void ll_kdu_error( void )
 public:
 	/*virtual*/ void put_text(const char *s);
 	/*virtual*/ void put_text(const kdu_uint16 *s);
-	/*virtual*/ void flush(bool end_of_message=false);
+	/*virtual*/ void flush(bool end_of_message = false);
 	static LLKDUMessageError sDefaultMessage;
 };
 
 
 void LLKDUMessageError::flush(bool end_of_message)
 {
-	if( end_of_message ) 
+	if (end_of_message) 
 	{
 		throw "KDU throwing an exception";
 	}
 mTPosp(NULL),
 mTileIndicesp(NULL),
 mRawImagep(NULL),
-mDecodeState(NULL)
+mDecodeState(NULL),
+mBlocksSize(-1),
+mPrecinctsSize(-1)
 {
 }
 
 void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode)
 {
 	S32 data_size = base.getDataSize();
-	S32 max_bytes = base.getMaxBytes() ? base.getMaxBytes() : data_size;
+	S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
 
 	//
 	//  Initialization
 	// Set the maximum number of bytes to use from the codestream
 	mCodeStreamp->set_max_bytes(max_bytes);
 
-	//    If you want to flip or rotate the image for some reason, change
+	//	If you want to flip or rotate the image for some reason, change
 	// the resolution, or identify a restricted region of interest, this is
 	// the place to do it.  You may use "kdu_codestream::change_appearance"
 	// and "kdu_codestream::apply_input_restrictions" for this purpose.
-	//    If you wish to truncate the code-stream prior to decompression, you
+	//	If you wish to truncate the code-stream prior to decompression, you
 	// may use "kdu_codestream::set_max_bytes".
-	//    If you wish to retain all compressed data so that the material
+	//	If you wish to retain all compressed data so that the material
 	// can be decompressed multiple times, possibly with different appearance
 	// parameters, you should call "kdu_codestream::set_persistent" here.
-	//    There are a variety of other features which must be enabled at
+	//	There are a variety of other features which must be enabled at
 	// this point if you want to take advantage of them.  See the
 	// descriptions appearing with the "kdu_codestream" interface functions
 	// in "kdu_compressed.h" for an itemized account of these capabilities.
 
-	switch( mode )
+	switch (mode)
 	{
 	case MODE_FAST:
 		mCodeStreamp->set_fast();
 	mTileIndicesp = NULL;
 }
 
-BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count )
+BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
+{
+	return initDecode(base,raw_image,0.0f,MODE_FAST,0,4,discard_level,region);
+}
+
+BOOL LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size)
+{
+	mBlocksSize = blocks_size;
+	mPrecinctsSize = precincts_size;
+	return TRUE;
+}
+
+BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
 {
 	base.resetLastError();
 
 
 		mRawImagep = &raw_image;
 		mCodeStreamp->change_appearance(false, true, false);
-		mCodeStreamp->apply_input_restrictions(first_channel,max_channel_count,base.getRawDiscardLevel(),0,NULL);
 
+		// Apply loading discard level and cropping if required
+		kdu_dims* region_kdu = NULL;
+		if (region != NULL)
+		{
+			region_kdu = new kdu_dims;
+			region_kdu->pos.x  = region[0];
+			region_kdu->pos.y  = region[1];
+			region_kdu->size.x = region[2] - region[0];
+			region_kdu->size.y = region[3] - region[1];
+		}
+		int discard = (discard_level != -1 ? discard_level : base.getRawDiscardLevel());
+		
+		// Apply loading restrictions
+		mCodeStreamp->apply_input_restrictions( first_channel, max_channel_count, discard, 0, region_kdu);
+		
+		// Clean-up
+		if (region_kdu)
+		{
+			delete region_kdu;
+			region_kdu = NULL;
+		}
+
+		// Resize raw_image according to the image to be decoded
 		kdu_dims dims; mCodeStreamp->get_dims(0,dims);
 		S32 channels = base.getComponents() - first_channel;
-		if( channels > max_channel_count )
-		{
-			channels = max_channel_count;
-		}
+		channels = llmin(channels,max_channel_count);
 		raw_image.resize(dims.size.x, dims.size.y, channels);
+		//	llinfos << "Resizing raw_image to " << dims.size.x << ":" << dims.size.y << llendl;
 
-		//	llinfos << "Resizing to " << dims.size.x << ":" << dims.size.y << llendl;
 		if (!mTileIndicesp)
 		{
 			mTileIndicesp = new kdu_dims;
 					// canvas coordinate system.  Comparing the two tells
 					// us where the current tile is in the buffer.
 					S32 channels = base.getComponents() - first_channel;
-					if( channels > max_channel_count )
+					if (channels > max_channel_count)
 					{
 						channels = max_channel_count;
 					}
 					return FALSE;
 				}
 			}
-			catch( const char* msg )
+			catch (const char* msg)
 			{
 				base.setLastError(ll_safe_string(msg));
 				base.decodeFailed();
 				cleanupCodeStream();
 				return TRUE; // done
 			}
-			catch( ... )
+			catch (...)
 			{
 				base.setLastError( "Unknown J2C error" );
 				base.decodeFailed();
 
 BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible)
 {
-	// Collect simple arguments.
-	bool transpose, vflip, hflip;
-	bool allow_rate_prediction, mem, quiet, no_weights;
-	int cpu_iterations;
-	std::ostream *record_stream;
-
-	transpose = false;
-	record_stream = NULL;
-	allow_rate_prediction = true;
-	no_weights = false;
-	cpu_iterations = -1;
-	mem = false;
-	quiet = false;
-	vflip = true;
-	hflip = false;
+	// Declare and set simple arguments
+	bool transpose = false;
+	bool vflip = true;
+	bool hflip = false;
 
 	try
 	{
-		// Set up input image files.
+		// Set up input image files
 		siz_params siz;
 		
-		// Should set rate someplace here.
+		// Should set rate someplace here
 		LLKDUMemIn mem_in(raw_image.getData(),
 			raw_image.getDataSize(),
 			raw_image.getWidth(),
 		siz.set(Sprecision,0,0,8);  // Image samples have original bit-depth of 8
 		siz.set(Ssigned,0,0,false); // Image samples are originally unsigned
 
-		kdu_params *siz_ref = &siz; siz_ref->finalize();
-		siz_params transformed_siz; // Use this one to construct code-strea
+		kdu_params *siz_ref = &siz; 
+		siz_ref->finalize();
+		siz_params transformed_siz; // Use this one to construct code-stream
 		transformed_siz.copy_from(&siz,-1,-1,-1,0,transpose,false,false);
 
-		// Construct the `kdu_codestream' object and parse all remaining arguments.
-
+		// Construct the `kdu_codestream' object and parse all remaining arguments
 		U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
-		if (max_output_size < 1000)
-		{
-			max_output_size = 1000;
-		}
+		max_output_size = (max_output_size < 1000 ? 1000 : max_output_size);
 		U8 *output_buffer = new U8[max_output_size];
-
-		U32 output_size = max_output_size; // gets modified
-		LLKDUMemTarget output(output_buffer, output_size, base.getWidth()*base.getHeight()*base.getComponents());
-		if (output_size > max_output_size)
-		{
-			llerrs << llformat("LLImageJ2C::encode output_size(%d) > max_output_size(%d)",
-				output_size,max_output_size) << llendl;
-		}
+		U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size
+		LLKDUMemTarget output(output_buffer, output_size, max_output_size);
 
 		kdu_codestream codestream;
 		codestream.create(&transformed_siz,&output);
 		kdu_long layer_bytes[64];
 		U32 max_bytes = 0;
 
-		if ((num_components >= 3) && !no_weights)
+		if (num_components >= 3)
 		{
+			// Note that we always use YCC and not YUV
+			// *TODO: Verify this doesn't screws up reversible textures (like sculpties) as YCC is not reversible but YUV is...
 			set_default_colour_weights(codestream.access_siz());
 		}
 
 		if (reversible)
 		{
-			// If we're doing reversible, assume we're not using quality layers.
-			// Yes, I know this is incorrect!
 			codestream.access_siz()->parse_string("Creversible=yes");
+			// *TODO: we should use yuv in reversible mode and one level since those images are small. 
+			// Don't turn this on now though as both create problems on decoding for the moment
+			//codestream.access_siz()->parse_string("Clevels=1");
+			//codestream.access_siz()->parse_string("Cycc=no");
+			// If we're doing reversible (i.e. lossless compression), assumes we're not using quality layers.
+			// *TODO: this is incorrect and unecessary. Try using the regular layer setting.
 			codestream.access_siz()->parse_string("Clayers=1");
 			num_layer_specs = 1;
 			layer_bytes[0] = 0;
 			// Rate is the argument passed into the LLImageJ2C which
 			// specifies the target compression rate.  The default is 8:1.
 			// Possibly if max_bytes < 500, we should just use the default setting?
+			// *TODO: mRate is actually always 8:1 in the viewer. Test different values. Also force to reversible for small (< 500 bytes) textures.
 			if (base.mRate != 0.f)
 			{
 				max_bytes = (U32)(base.mRate*base.getWidth()*base.getHeight()*base.getComponents());
 				codestream.access_siz()->parse_string(layer_string.c_str());
 			}
 		}
+		
+		// Set up data ordering, markers, etc... if precincts or blocks specified
+		if ((mBlocksSize != -1) || (mPrecinctsSize != -1))
+		{
+			if (mPrecinctsSize != -1)
+			{
+				std::string precincts_string = llformat("Cprecincts={%d,%d}",mPrecinctsSize,mPrecinctsSize);
+				codestream.access_siz()->parse_string(precincts_string.c_str());
+			}
+			if (mBlocksSize != -1)
+			{
+				std::string blocks_string = llformat("Cblk={%d,%d}",mBlocksSize,mBlocksSize);
+				codestream.access_siz()->parse_string(blocks_string.c_str());
+			}
+			std::string ordering_string = llformat("Corder=RPCL");
+			codestream.access_siz()->parse_string(ordering_string.c_str());
+			std::string PLT_string = llformat("ORGgen_plt=yes");
+			codestream.access_siz()->parse_string(PLT_string.c_str());
+			std::string Parts_string = llformat("ORGtparts=R");
+			codestream.access_siz()->parse_string(Parts_string.c_str());
+		}
+		
 		codestream.access_siz()->finalize_all();
-		if (cpu_iterations >= 0)
-		{
-			codestream.collect_timing_stats(cpu_iterations);
-		}
 		codestream.change_appearance(transpose,vflip,hflip);
 
 		// Now we are ready for sample data processing.
-        kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream);
-        bool done = false;
-        while (!done)
-        { 
-            // Process line by line
-            done = true;
-            if (tile->advance_components())
-            {
-                done = false;
-                tile->process_components();
-            }
-        }
+		kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream);
+		bool done = false;
+		while (!done)
+		{ 
+			// Process line by line
+			if (tile->advance_components())
+			{
+				tile->process_components();
+			}
+			else
+			{
+				done = true;
+			}
+		}
 
 		// Produce the compressed output
-        codestream.flush(layer_bytes,num_layer_specs);
+		codestream.flush(layer_bytes,num_layer_specs);
 
 		// Cleanup
-        delete tile;
-
+		delete tile;
 		codestream.destroy();
-		if (record_stream != NULL)
-		{
-			delete record_stream;
-		}
 
 		// Now that we're done encoding, create the new data buffer for the compressed
 		// image and stick it there.
-
 		base.copyData(output_buffer, output_size);
 		base.updateData(); // set width, height
 		delete[] output_buffer;
 BOOL LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
 {
 	// *FIX: kdu calls our callback function if there's an error, and
-	// then bombs.  To regain control, we throw an exception, and
+	// then bombs. To regain control, we throw an exception, and
 	// catch it here.
 	try
 	{
 		setupCodeStream(base, FALSE, MODE_FAST);
 		return TRUE;
 	}
-	catch( const char* msg )
+	catch (const char* msg)
 	{
 		base.setLastError(ll_safe_string(msg));
 		return FALSE;
 	}
-	catch( ... )
+	catch (...)
 	{
 		base.setLastError( "Unknown J2C error" );
 		return FALSE;
 	assert(cod != NULL);
 
 	bool can_use_ycc = true;
-	bool rev0=false;
-	int depth0=0, sub_x0=1, sub_y0=1;
-	for (int c=0; c < 3; c++)
+	bool rev0 = false;
+	int depth0 = 0, sub_x0 = 1, sub_y0 = 1;
+	for (int c = 0; c < 3; c++)
 	{
-		int depth=0; siz->get(Sprecision,c,0,depth);
-		int sub_y=1; siz->get(Ssampling,c,0,sub_y);
-		int sub_x=1; siz->get(Ssampling,c,1,sub_x);
+		int depth = 0; siz->get(Sprecision,c,0,depth);
+		int sub_y = 1; siz->get(Ssampling,c,0,sub_y);
+		int sub_x = 1; siz->get(Ssampling,c,1,sub_x);
 		kdu_params *coc = cod->access_relation(-1,c);
-		bool rev=false; coc->get(Creversible,0,0,rev);
+		bool rev = false; coc->get(Creversible,0,0,rev);
 		if (c == 0)
-		{ rev0=rev; depth0=depth; sub_x0=sub_x; sub_y0=sub_y; }
-		else if ((rev != rev0) || (depth != depth0) ||
-			(sub_x != sub_x0) || (sub_y != sub_y0))
+		{
+			rev0 = rev; depth0 = depth; sub_x0 = sub_x; sub_y0 = sub_y;
+		}
+		else if ((rev != rev0) || (depth != depth0) || 
+				 (sub_x != sub_x0) || (sub_y != sub_y0))
+		{
 			can_use_ycc = false;
+		}
 	}
 	if (!can_use_ycc)
+	{
 		return;
+	}
 
 	bool use_ycc;
 	if (!cod->get(Cycc,0,0,use_ycc))
+	{
 		cod->set(Cycc,0,0,use_ycc=true);
+	}
 	if (!use_ycc)
+	{
 		return;
+	}
 	float weight;
-	if (cod->get(Clev_weights,0,0,weight) ||
-		cod->get(Cband_weights,0,0,weight))
-		return; // Weights already specified explicitly.
+	if (cod->get(Clev_weights,0,0,weight) || cod->get(Cband_weights,0,0,weight))
+	{
+		// Weights already specified explicitly -> nothing to do
+		return; 
+	}
 
-	/* These example weights are adapted from numbers generated by Marcus Nadenau
-	at EPFL, for a viewing distance of 15 cm and a display resolution of
-	300 DPI. */
+	// These example weights are adapted from numbers generated by Marcus Nadenau
+	// at EPFL, for a viewing distance of 15 cm and a display resolution of
+	// 300 DPI.
 
 	cod->parse_string("Cband_weights:C0="
 		"{0.0901},{0.2758},{0.2758},"
 				val += 128;
 				if (val & ((-1)<<8))
 				{
-					val = (val<0)?0:255;
+					val = (val < 0 ? 0 : 255);
 				}
 				*dest = (kdu_byte) val;
 			}
 				val += 128;
 				if (val & ((-1)<<8))
 				{
-					val = (val<0)?0:255;
+					val = (val < 0 ? 0 : 255);
 				}
 				*dest = (kdu_byte) val;
 			}
 					val += 128;
 					if (val & ((-1)<<8))
 					{
-						val = (val<0)?0:255;
+						val = (val < 0 ? 0 : 255);
 					}
 					*dest = (kdu_byte) val;
 				}
 					val += 128;
 					if (val & ((-1)<<8))
 					{
-						val = (val<0)?0:(256-(1<<upshift));
+						val = (val < 0 ? 0 : 256 - (1<<upshift));
 					}
 					*dest = (kdu_byte) val;
 				}
 					val += 128;
 					if (val & ((-1)<<8))
 					{
-						val = (val<0)?0:255;
+						val = (val < 0 ? 0 : 255);
 					}
 					*dest = (kdu_byte) val;
 				}
 					val += 128;
 					if (val & ((-1)<<8))
 					{
-						val = (val<0)?0:(256-(1<<upshift));
+						val = (val < 0 ? 0 : 256 - (1<<upshift));
 					}
 					*dest = (kdu_byte) val;
 				}
 
 	mNumComponents = tile.get_num_components();
 
-	llassert(mNumComponents<=4);
+	llassert(mNumComponents <= 4);
 	mUseYCC = tile.get_ycc();
 
-	for (c=0; c<4; ++c)
+	for (c = 0; c < 4; ++c)
 	{
 		mReversible[c] = false;
 		mBitDepths[c] = 0;
 	}
 
 	// Open tile-components and create processing engines and resources
-	for (c=0; c < mNumComponents; c++)
+	for (c = 0; c < mNumComponents; c++)
 	{
 		mComps[c] = mTile.access_component(c);
 		mReversible[c] = mComps[c].get_reversible();
 		}
 	}
 	mAllocator.finalize(); // Actually creates buffering resources
-	for (c=0; c < mNumComponents; c++)
+	for (c = 0; c < mNumComponents; c++)
 	{
 		mLines[c].create(); // Grabs resources from the allocator.
 	}
 
 LLKDUDecodeState::~LLKDUDecodeState()
 {
-	S32 c;
 	// Cleanup
-	for (c=0; c < mNumComponents; c++)
+	for (S32 c = 0; c < mNumComponents; c++)
 	{
 		mEngines[c].destroy(); // engines are interfaces; no default destructors
 	}
-
 	mTile.close();
 }
 
 	LLTimer decode_timer;
 	while (mDims.size.y--)
 	{
-		for (c=0; c < mNumComponents; c++)
+		for (c = 0; c < mNumComponents; c++)
 		{
 			mEngines[c].pull(mLines[c],true);
 		}
 		{
 			kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
 		}
-		for (c=0; c < mNumComponents; c++)
+		for (c = 0; c < mNumComponents; c++)
 		{
 			transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
 		}
 
 kdc_flow_control::kdc_flow_control (kdu_image_in_base *img_in, kdu_codestream codestream)
 {
-    int n;
-    
-    this->codestream = codestream;
-    codestream.get_valid_tiles(valid_tile_indices);
-    tile_idx = valid_tile_indices.pos;
-    tile = codestream.open_tile(tile_idx,NULL);
-    
-    // Set up the individual components
-    num_components = codestream.get_num_components(true);
-    components = new kdc_component_flow_control[num_components];
-    count_delta = 0;
-    kdc_component_flow_control *comp = components;
-    for (n = 0; n < num_components; n++, comp++)
-    {
-        comp->line = NULL;
-        comp->reader = img_in;
-        kdu_coords subsampling;  
-        codestream.get_subsampling(n,subsampling,true);
-        kdu_dims dims;  
-        codestream.get_tile_dims(tile_idx,n,dims,true);
-        comp->vert_subsampling = subsampling.y;
-        if ((n == 0) || (comp->vert_subsampling < count_delta))
-        {
-            count_delta = comp->vert_subsampling;
-        }
-        comp->ratio_counter = 0;
-        comp->remaining_lines = comp->initial_lines = dims.size.y;
-    }
-    assert(num_components >= 0);
-    
-    tile.set_components_of_interest(num_components);
-    max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
+	int n;
+	
+	this->codestream = codestream;
+	codestream.get_valid_tiles(valid_tile_indices);
+	tile_idx = valid_tile_indices.pos;
+	tile = codestream.open_tile(tile_idx,NULL);
+	
+	// Set up the individual components
+	num_components = codestream.get_num_components(true);
+	components = new kdc_component_flow_control[num_components];
+	count_delta = 0;
+	kdc_component_flow_control *comp = components;
+	for (n = 0; n < num_components; n++, comp++)
+	{
+		comp->line = NULL;
+		comp->reader = img_in;
+		kdu_coords subsampling;  
+		codestream.get_subsampling(n,subsampling,true);
+		kdu_dims dims;  
+		codestream.get_tile_dims(tile_idx,n,dims,true);
+		comp->vert_subsampling = subsampling.y;
+		if ((n == 0) || (comp->vert_subsampling < count_delta))
+		{
+			count_delta = comp->vert_subsampling;
+		}
+		comp->ratio_counter = 0;
+		comp->remaining_lines = comp->initial_lines = dims.size.y;
+	}
+	assert(num_components >= 0);
+	
+	tile.set_components_of_interest(num_components);
+	max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
 }
 
 kdc_flow_control::~kdc_flow_control()
 {
-    if (components != NULL)
-        delete[] components;
-    if (engine.exists())
-        engine.destroy();
+	if (components != NULL)
+	{
+		delete[] components;
+	}
+	if (engine.exists())
+	{
+		engine.destroy();
+	}
 }
 
 bool kdc_flow_control::advance_components()
 {
-    bool found_line = false;
-    while (!found_line)
-    {
-        bool all_done = true;
-        kdc_component_flow_control *comp = components;
-        for (int n = 0; n < num_components; n++, comp++)
-        {
-            assert(comp->ratio_counter >= 0);
-            if (comp->remaining_lines > 0)
-            {
-                all_done = false;
-                comp->ratio_counter -= count_delta;
-                if (comp->ratio_counter < 0)
-                {
-                    found_line = true;
-                    comp->line = engine.exchange_line(n,NULL,NULL);
-                    assert(comp->line != NULL);
+	bool found_line = false;
+	while (!found_line)
+	{
+		bool all_done = true;
+		kdc_component_flow_control *comp = components;
+		for (int n = 0; n < num_components; n++, comp++)
+		{
+			assert(comp->ratio_counter >= 0);
+			if (comp->remaining_lines > 0)
+			{
+				all_done = false;
+				comp->ratio_counter -= count_delta;
+				if (comp->ratio_counter < 0)
+				{
+					found_line = true;
+					comp->line = engine.exchange_line(n,NULL,NULL);
+					assert(comp->line != NULL);
 					if (comp->line->get_width())
 					{
 						comp->reader->get(n,*(comp->line),0);
 					}
-                }
-            }
-        }
-        if (all_done)
-        {
-            return false;
-        }
-    }
-    return true;
+				}
+			}
+		}
+		if (all_done)
+		{
+			return false;
+		}
+	}
+	return true;
 }
 
 void kdc_flow_control::process_components()
 {
-    kdc_component_flow_control *comp = components;
-    for (int n = 0; n < num_components; n++, comp++)
-    {
-        if (comp->ratio_counter < 0)
-        {
-            comp->ratio_counter += comp->vert_subsampling;
-            assert(comp->ratio_counter >= 0);
-            assert(comp->remaining_lines > 0);
-            comp->remaining_lines--;
-            assert(comp->line != NULL);
-            engine.exchange_line(n,comp->line,NULL);
-            comp->line = NULL;
-        }
-    }
+	kdc_component_flow_control *comp = components;
+	for (int n = 0; n < num_components; n++, comp++)
+	{
+		if (comp->ratio_counter < 0)
+		{
+			comp->ratio_counter += comp->vert_subsampling;
+			assert(comp->ratio_counter >= 0);
+			assert(comp->remaining_lines > 0);
+			comp->remaining_lines--;
+			assert(comp->line != NULL);
+			engine.exchange_line(n,comp->line,NULL);
+			comp->line = NULL;
+		}
+	}
 }

indra/llkdu/llimagej2ckdu.h

 	/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
 	/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
 								BOOL reversible=FALSE);
+	/*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
+	/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1);
 
 private:
+	BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL);
 	void setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode);
 	void cleanupCodeStream();
-	BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
 
 	// Encode variable
 	LLKDUMemSource *mInputp;
 	kdu_codestream *mCodeStreamp;
 	kdu_coords *mTPosp; // tile position
 	kdu_dims *mTileIndicesp;
+	int mBlocksSize;
+	int mPrecinctsSize;
 
 	// Temporary variables for in-progress decodes...
 	LLImageRaw *mRawImagep;

indra/llkdu/llkdumem.cpp

 	num_components = in_num_components;
 	alignment_bytes = 0;
 
-	for (n=0; n<3; ++n)
+	for (n = 0; n < 3; ++n)
 	{
 		precision[n] = 0;
 	}
 
-	for (n=0; n < num_components; ++n)
+	for (n = 0; n < num_components; ++n)
 	{
 		siz->set(Sdims,n,0,rows);
 		siz->set(Sdims,n,1,cols);
 	}
 	image_line_buf *tmp;
 	while ((tmp=incomplete_lines) != NULL)
-    {
+	{
 		incomplete_lines = tmp->next;
 		delete tmp; 
 	}
 	while ((tmp=free_lines) != NULL)
-    {
+	{
 		free_lines = tmp->next;
 		delete tmp;
 	}
 	assert((idx >= 0) && (idx < num_components));
 	x_tnum = x_tnum*num_components+idx;
 	image_line_buf *scan, *prev=NULL;
-	for (scan=incomplete_lines; scan != NULL; prev=scan, scan=scan->next)
-    {
+	for (scan = incomplete_lines; scan != NULL; prev = scan, scan = scan->next)
+	{
 		assert(scan->next_x_tnum >= x_tnum);
 		if (scan->next_x_tnum == x_tnum)
 		{
 			break;
 		}
-    }
+	}
 	if (scan == NULL)
-    { // Need to read a new image line.
+	{ // Need to read a new image line.
 		assert(x_tnum == 0); // Must consume in very specific order.
 		if (num_unread_rows == 0)
 		{
 		num_unread_rows--;
 		scan->accessed_samples = 0;
 		scan->next_x_tnum = 0;
-    }
+	}
 
 	assert((cols-scan->accessed_samples) >= line.get_width());
 
 		}
 	}
 	else
-    {
+	{
 		kdu_sample16 *dp = line.get_buf16();
 		if (line.is_absolute())
 		{ // 16-bit absolute integers
 				dp->ival = (((kdu_int16)(*sp)) - 128) << (KDU_FIX_POINT-8);
 			}
 		}
-    }
+	}
 
 	scan->next_x_tnum++;
 	if (idx == (num_components-1))

indra/llkdu/llkdumem.h

 
 class LLKDUMemSource: public kdu_compressed_source
 {
-public: // Member functions
+public:
 	LLKDUMemSource(U8 *input_buffer, U32 size)
 	{
 		mData = input_buffer;
 		mCurPos = 0;
 	}
 
-    ~LLKDUMemSource()
+	~LLKDUMemSource()
 	{
 	}
 
-    int read(kdu_byte *buf, int num_bytes)
+	int read(kdu_byte *buf, int num_bytes)
 	{
 		U32 num_out;
 		num_out = num_bytes;
 		mCurPos = 0;
 	}
 
-private: // Data
+private:
 	U8 *mData;
 	U32 mSize;
 	U32 mCurPos;
 
 class LLKDUMemTarget: public kdu_compressed_target
 {
-public: // Member functions
+public:
 	LLKDUMemTarget(U8 *output_buffer, U32 &output_size, const U32 buffer_size)
 	{
 		mData = output_buffer;
 		mOutputSize = &output_size;
 	}
 
-    ~LLKDUMemTarget()
-    {
+	~LLKDUMemTarget()
+	{
 	}
 
-    bool write(const kdu_byte *buf, int num_bytes)
+	bool write(const kdu_byte *buf, int num_bytes)
 	{
 		U32 num_out;
 		num_out = num_bytes;
 		return true;
 	}
 	
-private: // Data
+private:
 	U8 *mData;
 	U32 mSize;
 	U32 mCurPos;
 
 class LLKDUMemIn : public kdu_image_in_base
 {
-public: // Member functions
-    LLKDUMemIn(const U8 *data,
+public:
+	LLKDUMemIn(const U8 *data,
 				const U32 size,
 				const U16 rows,
 				const U16 cols,
 				U8 in_num_components,
 				siz_params *siz);
-    ~LLKDUMemIn();
+	~LLKDUMemIn();
 
-    bool get(int comp_idx, kdu_line_buf &line, int x_tnum);
+	bool get(int comp_idx, kdu_line_buf &line, int x_tnum);
 
-private: // Data
+private:
 	const U8 *mData;
-    int first_comp_idx;
-    int num_components;
-    int rows, cols;
-    int alignment_bytes; // Number of 0's at end of each line.
-    int precision[3];
-    image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
-    image_line_buf *free_lines;
-    int num_unread_rows;
+	int first_comp_idx;
+	int num_components;
+	int rows, cols;
+	int alignment_bytes; // Number of 0's at end of each line.
+	int precision[3];
+	image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
+	image_line_buf *free_lines;
+	int num_unread_rows;
 
 	U32 mCurPos;
 	U32 mDataSize;

indra/llui/llloadingindicator.cpp

 //static LLDefaultChildRegistry::Register<LLLoadingIndicator> r("loading_indicator");
 
 ///////////////////////////////////////////////////////////////////////////////
-// LLLoadingIndicator::Data class
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Pre-loaded images shared by all instances of the widget
- */
-class LLLoadingIndicator::Data: public LLSingleton<LLLoadingIndicator::Data>
-{
-public:
-	/*virtual*/ void		initSingleton(); // from LLSingleton
-
-	LLPointer<LLUIImage>	getNextImage(S8& idx) const;
-	U8						getImagesCount() const	{ return NIMAGES; }
-private:
-
-	static const U8			NIMAGES = 12;
-	LLPointer<LLUIImage>	mImages[NIMAGES];
-};
-
-// virtual
-// Called right after the instance gets constructed.
-void LLLoadingIndicator::Data::initSingleton()
-{
-	// Load images.
-	for (U8 i = 0; i < NIMAGES; ++i)
-	{
-		std::string img_name = llformat("Progress_%d", i+1);
-		mImages[i] = LLUI::getUIImage(img_name, 0);
-		llassert(mImages[i]);
-	}
-}
-
-LLPointer<LLUIImage> LLLoadingIndicator::Data::getNextImage(S8& idx) const
-{
-	// Calculate next index, performing array bounds checking.
-	idx = (idx >= NIMAGES || idx < 0) ? 0 : (idx + 1) % NIMAGES; 
-	return mImages[idx];
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // LLLoadingIndicator class
 ///////////////////////////////////////////////////////////////////////////////
 
 LLLoadingIndicator::LLLoadingIndicator(const Params& p)
-:	LLUICtrl(p)
-	, mRotationsPerSec(p.rotations_per_sec > 0 ? p.rotations_per_sec : 1.0f)
-	, mCurImageIdx(-1)
+:	LLUICtrl(p), 
+	mImagesPerSec(p.images_per_sec > 0 ? p.images_per_sec : 1.0f), 
+	mCurImageIdx(0)
 {
-	// Select initial image.
-	mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+}
+
+void LLLoadingIndicator::initFromParams(const Params& p)
+{
+	for (LLInitParam::ParamIterator<LLUIImage*>::const_iterator it = p.images().image.begin(), end_it = p.images().image.end();
+		it != end_it;
+		++it)
+	{
+		mImages.push_back(it->getValue());
+	}
 
 	// Start timer for switching images.
 	start();
 	if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired())
 	{
 		// Switch to the next image.
-		mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+		if (!mImages.empty())
+		{
+			mCurImageIdx = (mCurImageIdx + 1) % mImages.size();
+		}
 
 		// Restart timer.
 		start();
 	}
 
+	LLUIImagePtr cur_image = mImages.empty() ? LLUIImagePtr(NULL) : mImages[mCurImageIdx];
+
 	// Draw current image.
-	if( mCurImagep.notNull() )
+	if( cur_image.notNull() )
 	{
-		mCurImagep->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
+		cur_image->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
 	}
 
 	LLUICtrl::draw();
 void LLLoadingIndicator::start()
 {
 	mImageSwitchTimer.start();
-	F32 period = 1.0f / (Data::instance().getImagesCount() * mRotationsPerSec);
+	F32 period = 1.0f / (mImages.size() * mImagesPerSec);
 	mImageSwitchTimer.setTimerExpirySec(period);
 }

indra/llui/llloadingindicator.h

 /**
  * Perpetual loading indicator (a la MacOSX or YouTube)
  * 
- * Number of rotations per second can be overriden
- * with the "roations_per_sec" parameter.
+ * Number of rotations per second can be overridden
+ * with the "images_per_sec" parameter.
  * 
  * Can start/stop spinning.
  * 
 {
 	LOG_CLASS(LLLoadingIndicator);
 public:
+
+	struct Images : public LLInitParam::Block<Images>
+	{
+		Multiple<LLUIImage*>	image;
+
+		Images()
+		:	image("image")
+		{}
+	};
+
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
-		Optional<F32>	rotations_per_sec;
+		Optional<F32>			images_per_sec;
+		Batch<Images>			images;
+
 		Params()
-		:	rotations_per_sec("rotations_per_sec", 1.0f)
+		:	images_per_sec("images_per_sec", 1.0f),
+			images("images")
 		{}
 	};
 
 
 private:
 	LLLoadingIndicator(const Params&);
+	void initFromParams(const Params&);
+
 	friend class LLUICtrlFactory;
 
-	class Data;
+	F32						mImagesPerSec;
+	S8						mCurImageIdx;
+	LLFrameTimer			mImageSwitchTimer;
 
-	F32						mRotationsPerSec;
-	S8						mCurImageIdx;
-	LLPointer<LLUIImage>	mCurImagep;
-	LLFrameTimer			mImageSwitchTimer;
+	std::vector<LLUIImagePtr> mImages;
 };
 
 #endif // LL_LLLOADINGINDICATOR_H

indra/llui/llui.cpp

 {
 	if(sImageProvider)
 	{
-		sImageProvider->cleanUp();
-	}
+	sImageProvider->cleanUp();
+}
 }
 
 void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup,  const clear_popups_t& clear_popups)
 
 namespace LLInitParam
 {
-	TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
-	:	super_t(descriptor, name, value, func, min_count, max_count),
+	ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
+	:	super_t(color),
 		red("red"),
 		green("green"),
 		blue("blue"),
 		alpha("alpha"),
 		control("")
 	{
-		setBlockFromValue();
+		updateBlockFromValue();
 	}
 
-	void TypedParam<LLUIColor>::setValueFromBlock() const
+	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
 	{
 		if (control.isProvided())
 		{
-			mData.mValue = LLUIColorTable::instance().getColor(control);
+			updateValue(LLUIColorTable::instance().getColor(control));
 		}
 		else
 		{
-			mData.mValue = LLColor4(red, green, blue, alpha);
+			updateValue(LLColor4(red, green, blue, alpha));
 		}
 	}
 	
-	void TypedParam<LLUIColor>::setBlockFromValue()
+	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue()
 	{
-		LLColor4 color = mData.mValue.get();
+		LLColor4 color = getValue();
 		red.set(color.mV[VRED], false);
 		green.set(color.mV[VGREEN], false);
 		blue.set(color.mV[VBLUE], false);
 		control.set("", false);
 	}
 
-	void TypeValues<LLUIColor>::declareValues()
-	{
-		declare("white", LLColor4::white);
-		declare("black", LLColor4::black);
-		declare("red", LLColor4::red);
-		declare("green", LLColor4::green);
-		declare("blue", LLColor4::blue);
-	}
-
 	bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
 	{
 		return !(a->getFontDesc() < b->getFontDesc())
 			&& !(b->getFontDesc() < a->getFontDesc());
 	}
 
-	TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
-	:	super_t(descriptor, _name, value, func, min_count, max_count),
+	ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
+	:	super_t(fontp),
 		name("name"),
 		size("size"),
 		style("style")
 	{
-		setBlockFromValue();
+		if (!fontp)
+		{
+			updateValue(LLFontGL::getFontDefault());
+		}
 		addSynonym(name, "");
-		setBlockFromValue();
+		updateBlockFromValue();
 	}
 
-	void TypedParam<const LLFontGL*>::setValueFromBlock() const
+	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
 	{
 		const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
 		if (res_fontp)
 		{
-			mData.mValue = res_fontp;
+			updateValue(res_fontp);
 			return;
 		}
 
 		const LLFontGL* fontp = LLFontGL::getFont(desc);
 		if (fontp)
 		{
-			mData.mValue = fontp;
-		}		
+			updateValue(fontp);
+		}
+		else
+		{
+			updateValue(LLFontGL::getFontDefault());
+		}
 	}
 	
-	void TypedParam<const LLFontGL*>::setBlockFromValue()
+	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue()
 	{
-		if (mData.mValue)
+		if (getValue())
 		{
-			name.set(LLFontGL::nameFromFont(mData.mValue), false);
-			size.set(LLFontGL::sizeFromFont(mData.mValue), false);
-			style.set(LLFontGL::getStringFromStyle(mData.mValue->getFontDesc().getStyle()), false);
+			name.set(LLFontGL::nameFromFont(getValue()), false);
+			size.set(LLFontGL::sizeFromFont(getValue()), false);
+			style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), false);
 		}
 	}
 
-	TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
-	:	super_t(descriptor, name, value, func, min_count, max_count),
+	ParamValue<LLRect, TypeValues<LLRect> >::ParamValue(const LLRect& rect)
+	:	super_t(rect),
 		left("left"),
 		top("top"),
 		right("right"),
 		width("width"),
 		height("height")
 	{
-		setBlockFromValue();
+		updateBlockFromValue();
 	}
 
-	void TypedParam<LLRect>::setValueFromBlock() const
+	void ParamValue<LLRect, TypeValues<LLRect> >::updateValueFromBlock()
 	{
 		LLRect rect;
 
 			rect.mBottom = bottom;
 			rect.mTop = top;
 		}
-		mData.mValue = rect;
+		updateValue(rect);
 	}
 	
-	void TypedParam<LLRect>::setBlockFromValue()
+	void ParamValue<LLRect, TypeValues<LLRect> >::updateBlockFromValue()
 	{
 		// because of the ambiguity in specifying a rect by position and/or dimensions
 		// we clear the "provided" flag so that values from xui/etc have priority
 		// over those calculated from the rect object
 
-		left.set(mData.mValue.mLeft, false);
-		right.set(mData.mValue.mRight, false);
-		bottom.set(mData.mValue.mBottom, false);
-		top.set(mData.mValue.mTop, false);
-		width.set(mData.mValue.getWidth(), false);
-		height.set(mData.mValue.getHeight(), false);
+		LLRect& value = getValue();
+		left.set(value.mLeft, false);
+		right.set(value.mRight, false);
+		bottom.set(value.mBottom, false);
+		top.set(value.mTop, false);
+		width.set(value.getWidth(), false);
+		height.set(value.getHeight(), false);
 	}
 
-	TypedParam<LLCoordGL>::TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
-	:	super_t(descriptor, name, value, func, min_count, max_count),
+	ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::ParamValue(const LLCoordGL& coord)
+	:	super_t(coord),
 		x("x"),
 		y("y")
 	{
-		setBlockFromValue();
+		updateBlockFromValue();
 	}
 
-	void TypedParam<LLCoordGL>::setValueFromBlock() const
+	void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateValueFromBlock()
 	{
-		mData.mValue.set(x, y);
+		updateValue(LLCoordGL(x, y));
 	}
 	
-	void TypedParam<LLCoordGL>::setBlockFromValue()
+	void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateBlockFromValue()
 	{
-		x.set(mData.mValue.mX, false);
-		y.set(mData.mValue.mY, false);
+		x.set(getValue().mX, false);
+		y.set(getValue().mY, false);
 	}
 
 

indra/llui/llui.h

 namespace LLInitParam
 {
 	template<>
-	class TypedParam<LLRect> 
-	:	public BlockValue<LLRect>
+	class ParamValue<LLRect, TypeValues<LLRect> > 
+	:	public CustomParamValue<LLRect>
 	{
-        typedef BlockValue<LLRect> super_t;
+        typedef CustomParamValue<LLRect> super_t;
 	public:
 		Optional<S32>	left,
 						top,
 						width,
 						height;
 
-		TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
+		ParamValue(const LLRect& value);
 
-		void setValueFromBlock() const;
-		void setBlockFromValue();
+		void updateValueFromBlock();
+		void updateBlockFromValue();
 	};
 
 	template<>
-	struct TypeValues<LLUIColor> : public TypeValuesHelper<LLUIColor>
+	class ParamValue<LLUIColor, TypeValues<LLUIColor> > 
+	:	public CustomParamValue<LLUIColor>
 	{
-		static void declareValues();
+        typedef CustomParamValue<LLUIColor> super_t;
+
+	public:
+		Optional<F32>			red,
+								green,
+								blue,
+								alpha;
+		Optional<std::string>	control;
+
+		ParamValue(const LLUIColor& color);
+		void updateValueFromBlock();
+		void updateBlockFromValue();
 	};
 
 	template<>
-	class TypedParam<LLUIColor> 
-	:	public BlockValue<LLUIColor>
+	class ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> > 
+	:	public CustomParamValue<const LLFontGL* >
 	{
-        typedef BlockValue<LLUIColor> super_t;
-	public:
-		Optional<F32>	red,
-						green,
-						blue,
-						alpha;
-		Optional<std::string> control;
-
-		TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
-		void setValueFromBlock() const;
-		void setBlockFromValue();
-	};
-
-	// provide a better default for Optional<const LLFontGL*> than NULL
-	template <>
-	struct DefaultInitializer<const LLFontGL*>
-	{
-		// return reference to a single default instance of T
-		// built-in types will be initialized to zero, default constructor otherwise
-		static const LLFontGL* get() 
-		{ 
-			static const LLFontGL* sDefaultFont = LLFontGL::getFontDefault();  
-			return sDefaultFont;
-		} 
-	};
-
-
-	template<>
-	class TypedParam<const LLFontGL*> 
-	:	public BlockValue<const LLFontGL*>
-	{
-        typedef BlockValue<const LLFontGL*> super_t;
+        typedef CustomParamValue<const LLFontGL*> super_t;
 	public:
 		Optional<std::string>	name,
 								size,
 								style;
 
-		TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
-		void setValueFromBlock() const;
-		void setBlockFromValue();
+		ParamValue(const LLFontGL* value);
+		void updateValueFromBlock();
+		void updateBlockFromValue();
 	};
 
 	template<>
 
 
 	template<>
-	class TypedParam<LLCoordGL>
-	:	public BlockValue<LLCoordGL>
+	class ParamValue<LLCoordGL, TypeValues<LLCoordGL> >
+	:	public CustomParamValue<LLCoordGL>
 	{
-		typedef BlockValue<LLCoordGL> super_t;
+		typedef CustomParamValue<LLCoordGL> super_t;
 	public:
 		Optional<S32>	x,
 						y;
 
-		TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
-		void setValueFromBlock() const;
-		void setBlockFromValue();
+		ParamValue(const LLCoordGL& val);
+		void updateValueFromBlock();
+		void updateBlockFromValue();
 	};
 }
 

indra/llui/lluiimage.cpp

 
 namespace LLInitParam
 {
-	void TypedParam<LLUIImage*>::setValueFromBlock() const
+