#ifndef _TRIPLE_WAVELET_H_
#define _TRIPLE_WAVELET_H_

#define COMPRESS_PERCENT 95.0f		// Specify how much wavelet coefficients are discarded[0, 100].

#define WAVELET_CONS 2.5198420997897464f
#define PARENT_CONS  0.62996052494743660f
//#define PARENT_CONS  4.0f / ( WAVELET_CONS * WAVELET_CONS )

#define CUBEWIDTH 64
#define BLOCKSIZE ( ( CUBEWIDTH * CUBEWIDTH - 1 ) / 3 )

#define USE_LIMIT 1e-6f

//#define COMPRESS_PSUM

namespace wavelet {

	static unsigned int leveltable[ 9 ][ 3 ] = { { 1, 0, 1 }, { 4, 1, 2 }, { 16, 5, 4 }, { 64, 21, 8 }, { 256, 85, 16 }, { 1024, 341, 32 }, { 4096, 1365, 64 }, { 16384, 5461, 128 }, { 65536, 21845, 256 } };
	
	class BRDF {
		public:
			unsigned char* coeff;
			float coeff_min;
			float coeff_max;
			float coeff_table[ 256 ];

			unsigned int*   usedcoeff_offset;
			unsigned short* usedcoeff_num;
			unsigned short* usedcoeff_table;
			unsigned int    usedcoeff;

		#ifdef COMPRESS_PSUM
			unsigned char* psum;
			float psum_min;
			float psum_max;
			float psum_table[ 256 ];
		#else
			float* psum;
		#endif

			unsigned int normal_samples;
			unsigned int reflection_samples;

		#ifdef COMPRESS_PSUM
			BRDF() : coeff( 0 ), coeff_min( 0.0f ), coeff_max( 0.0f ), psum( 0 ), psum_min( 0.0f ), psum_max( 0.0f ), normal_samples( 0 ), reflection_samples( 0 ) {}
		#else
			BRDF() : coeff( 0 ), coeff_min( 0.0f ), coeff_max( 0.0f ), usedcoeff_offset( 0 ), usedcoeff_num( 0 ), usedcoeff_table( 0 ), psum( 0 ), normal_samples( 0 ), reflection_samples( 0 ), coeff_num( CUBEWIDTH * CUBEWIDTH ), psum_num( BLOCKSIZE ) {}
		#endif		
			BRDF( const char* filename )
			{
				input_brdfWaveletCoeff( filename );
			}
			
			~BRDF()
			{
				if ( coeff != 0 ) delete [] coeff;
				if ( psum  != 0 ) delete [] psum;
				if ( usedcoeff_offset != 0 ) delete [] usedcoeff_offset;
				if ( usedcoeff_num != 0 ) delete [] usedcoeff_num;
				if ( usedcoeff_table != 0 ) delete [] usedcoeff_table;
			}

			const unsigned int getMapOffset( const float normal[ 3 ], const float reflection[ 3 ] )
			{
				return 2 * reflection_dir_table[ (int)( reflection[ 0 ] * 99.9999f ) / 2 + 50 ][ (int)( reflection[ 1 ] * 99.9999f ) / 2 + 50 ][ reflection[ 3 ] > 0.0f ? 0 : 1 ];
			}

			inline float getCoeff( const unsigned int mapoffset, const unsigned int level, const unsigned int type, const unsigned int i, const unsigned int j )
			{
				return coeff_table[ coeff[ mapoffset * coeff_num + type * BLOCKSIZE + leveltable[ level ][ 1 ] + ( leveltable[ level ][ 2 ] * j + i ) + 1 ] ];
			}

			inline float getParentSum( const unsigned int mapoffset, const unsigned int level, const unsigned int i, const unsigned int j )
			{
				return psum[ mapoffset * psum_num + leveltable[ level ][ 1 ] + ( leveltable[ level ][ 2 ] * j + i ) ];
			}

			bool input_brdfWaveletCoeff( const char* filename );
			bool output_brdfWaveletCoeff( const char* filename );
			void setTable( void );

		private:
			unsigned int coeff_num;
			unsigned int psum_num;

			unsigned short int normal_dir_table[ 50 ][ 50 ][ 2 ];
			unsigned short int reflection_dir_table[ 100 ][ 100 ][ 2 ];
	};

	// uncompressed, unquantized wavelet coefficient structre.
	struct waveletdata 
	{
		float coef[ 2 ][ CUBEWIDTH * CUBEWIDTH ];	/* dual paraboloid */
		float psum[ 2 ][ BLOCKSIZE ];
	};

	struct prequantizedwaveletcoeff 
	{
		float val;						// unquantized wavelet coefficient float value.
		unsigned char index;			// the position index in a block[0, 255].
	};

	// quantized wavelet coefficient structure.
	struct quantizedwaveletcoeff 
	{
		unsigned char val;				// quantized wavelet coefficient[0, 255].
		unsigned char index;			// the position index in a block[0, 255].
	};

	/*
	* Illustration of quantized wavelet coefficient memory management(here for example 64x64x6 cubemap). 
	*
	*
	* 1. First, split 64x64x64 wavelet coefficient row into blocks of 256 samples. 
	*
	* 0     256   512          64x64x6
	* +------+-----+- ... -+------+
	* |      |     |       |      |    The number of blocks = 64x64x6 / 256 = 96 blocks.
	* +------+-----+- ... -+------+
	*
	*
	* 2. Create 96 pointer array(wcoefflist).
	*    Then we assign null if all elements in a block has zero.
	*    Else substitute pointer address of wavelet coefficient arrays.
	*    
	*
	* wcoefflist
	*
	*  +----+
	*  |null|      wcoeffarray
	*  +----+      +-----+-----+
	*  | --------> |  w1 |  w2 |
	*  +----+      +-----+-----+
	*  |null|
	*  +----+
	*  |null|
	*  +----+      +-----+-----+-----+
	*  | --------> |  w3 |  w4 | w5  |
	*  +----+      +-----+-----+-----+
	*    .
	*    .
	*    .
	*   \|
	*
	*   N = 64x64x64 / 256 = 96 cells
	*
	*
	* 3. When we are doing space matrix manipulation,
	*    we can restore the original position of a coefficient as follows
	*
	*    w1's original position in the row = 1(cell index) * 256 + w1.index
	*    w3's original position in the row = 4(cell index) * 256 + w3.index
	*/

	void compress_index( const float* data, const unsigned int size, unsigned int* compressed_size, unsigned short* compressed_index, float* cliped_values );
	void compress_value( const float* data, const unsigned int size, float* max, float* min, unsigned char** compressed_value );

	// sign
	static float quad_signs[ 3 ][ 4 ] = { {  1.0f, -1.0f,  1.0f, -1.0f },	
								          { -1.0f, -1.0f,  1.0f,  1.0f },
								          { -1.0f,  1.0f,  1.0f, -1.0f } };

	// return sign
	inline float sign_of_quadrant( const unsigned int type, const unsigned int qx, const unsigned int qy )
	{
		return quad_signs[ type ][ qy * 2 + qx ];
	}

	inline float getCoeff( const float* data, const unsigned int level, const unsigned int type, const unsigned int i, const unsigned int j )
	{
		return data[ type * BLOCKSIZE + leveltable[ level ][ 1 ] + ( leveltable[ level ][ 2 ] * j + i ) + 1 ];
	}

	void compute_Phong( const unsigned int reflection_sample, const unsigned int multiplier, BRDF& brdf );
	void compute_Lambert( const unsigned int normal_sample, BRDF& brdf );

	void decompose( const unsigned int size, float data[] );

	float parent_sum( const float* data, const unsigned int level, const unsigned int i, const unsigned int j );
	void calcParentSumTable( const unsigned int size, const float data[], float* sumTable );

	void throw_away_percent( const unsigned int size, float data[], float percentage );
	void throw_away_val( const unsigned int size, float data[], float threshold ); 
}

#endif<h1>Software error:</h1>
<pre>Permission denied at plugin/attach/AttachHandler.pm line 172.
</pre>
<p>
For help, please send mail to the webmaster (<a href="mailto:webmaster@sourceforge.net">webmaster@sourceforge.net</a>), giving this error message 
and the time and date of the error.

</p>