/*
								+----------------------------------+
								|                                  |
								|  ***   OpenGL 2.0 logo in   ***  |
								|                                  |
								|   Copyright © -tHE SWINe- 2009   |
								|                                  |
								|          OpenGL20Logo.h          |
								|                                  |
								+----------------------------------+
*/

#pragma once
#ifndef __OPENGL_LOGO_2_0_TGA_INCLUDED
#define __OPENGL_LOGO_2_0_TGA_INCLUDED

/**
 *	@file gl2/OpenGL20Logo.h
 *	@author -tHE SWINe-
 *	@date 2009
 *	@brief OpenGL 2.0 logo image
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

/**
 *	@brief OpenGL 2.0 logo image class
 */
class COpenGL20Logo {
public:
	/**
	 *	@brief gets image width
	 *
	 *	@return Returns image width, in pixels.
	 */
	static inline int n_Width()
	{
		return 150;
	}

	/**
	 *	@brief gets image height
	 *
	 *	@return Returns image height, in pixels.
	 */
	static inline int n_Height()
	{
		return 57;
	}

	/**
	 *	@brief gets image data
	 *
	 *	@return Returns image data, compressed and encoded in BASE64.
	 */
	static inline const char *p_s_Base64_Data()
	{
		static const char *p_s_data = "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";
		return p_s_data;
	}

	/**
	 *	@brief decompresses image raster
	 *
	 *	@return Returns pointer to image raster (caller is responsible for freeing it up),
	 *		or 0 on failure.
	 */
	static inline uint32_t *p_Decompress()
	{
		return p_Decode_RLE_Huff_Base64(p_s_Base64_Data(), 150, 57, 4678, 0, 1, 4, false);
	}

private:
	static void UnPredict_ImagePlane(uint8_t *p_buffer, int n_width, int n_height, int n_pred_type)
	{
		int n_first_row = (n_pred_type == 1)? 0 : 1;
		int n_first_col = (n_pred_type == 0)? 0 : 1;
		p_buffer += n_first_row * n_width;
		for(int y = n_first_row; y < n_height; ++ y) {
			if(n_first_col)
				++ p_buffer;
			for(int x = n_first_col; x < n_width; ++ x, ++ p_buffer) {
				if(n_pred_type == 0)
					*p_buffer += p_buffer[-n_width];
				else if(n_pred_type == 1)
					*p_buffer += p_buffer[-1];
				else if(n_pred_type == 2) {
					*p_buffer += (int(p_buffer[-1]) + int(p_buffer[-n_width]) +
						int(p_buffer[-n_width - 1])) / 3;
				} else {
					int a = p_buffer[-1], b = p_buffer[-n_width], c = p_buffer[-n_width - 1];
					int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c);
					*p_buffer += (pa <= pb && pa <= pc)? a : ((pb <= pc)? b : c);
				}
			}
		}
	}

	static uint32_t *p_Decode_RLE_Huff_Base64(const char *p_s_base64,
		int n_image_width, int n_image_height, int n_afterhuff_size,
		int n_predictor_y, int n_predictor_uv, int n_subsample, bool b_gray)
	{
		int n_base64_length = strlen(p_s_base64);
		int n_base64_out_size = (n_base64_length / 4) * 3 +
			max(int(n_base64_length % 4) - 1, 0);

		int n_image_size = n_image_width * n_image_height;
		int n_chroma_w = (n_image_width + n_subsample - 1) / n_subsample;
		int n_chroma_h = (n_image_height + n_subsample - 1)/ n_subsample;
		int n_chroma_plane_size = n_chroma_w * n_chroma_h;
		int n_chroma_size = n_chroma_plane_size * 2;
		int n_image_data_size = n_image_width * n_image_height + ((b_gray)? 0 : n_chroma_size);

		int n_prehuff_size = max(n_base64_out_size, n_image_data_size);
		int n_temp_buffer_size = n_prehuff_size + n_afterhuff_size;
		uint8_t *p_temp_buffer;
		if(!(p_temp_buffer = new(std::nothrow) uint8_t[n_temp_buffer_size]))
			return 0;;
		uint32_t *p_raster;
		if(!(p_raster = new(std::nothrow) uint32_t[n_image_width * n_image_height])) {
			delete[] p_temp_buffer;
			return 0;
		}

		{
			int p_ic_tab[256];
			for(int i = 0; i < 256; ++ i) {
				p_ic_tab[i] = (isupper(i))? i - 'A' : (islower(i))? i - 'a' + 26 :
					(isdigit(i))? i - '0' + 52 : (i == '+')? 62 : (i == '/')? 63 : -1;
			}
			const uint8_t *p_src = (const uint8_t*)p_s_base64;
			uint8_t *p_dst = p_temp_buffer;
			for(const uint8_t *p_end = p_src + n_base64_length - 3; p_src < p_end; p_src += 4) {
				uint8_t p_tmp[] = {p_ic_tab[p_src[1]], p_ic_tab[p_src[2]], };
				*p_dst ++ = (p_ic_tab[p_src[0]] << 2) | (p_tmp[0] >> 4);
				*p_dst ++ = (p_tmp[0] << 4) | (p_tmp[1] >> 2);
				*p_dst ++ = (p_tmp[1] << 6) | p_ic_tab[p_src[3]];
			}
			if(n_base64_length % 4 == 3) {
				uint8_t n_tmp = p_ic_tab[p_src[1]];
				*p_dst ++ = (p_ic_tab[p_src[0]] << 2) | (n_tmp >> 4);
				*p_dst ++ = n_tmp | (p_ic_tab[p_src[2]] >> 2);
			} else if(n_base64_length % 4 == 2) {
				*p_dst ++ = (p_ic_tab[p_src[0]] << 2) | (p_ic_tab[p_src[1]] >> 4);
			}
		}
		{
			const uint8_t *p_huff_src = p_temp_buffer, *p_huff_end = p_huff_src + n_base64_out_size;
			_ASSERTE(p_huff_src + 16 * sizeof(int) <= p_huff_end);
			const int *p_code_num = (const int*)p_huff_src; p_huff_src += 16 * sizeof(int);
			int p_min_code[16], p_max_code[16], p_table_off[16], n_code_num = 0;
			for(int i = 0, n_cw = 0; i < 16; ++ i, n_cw <<= 1) {
				p_min_code[i] = n_cw;
				p_max_code[i] = (n_cw += p_code_num[i]);
				p_table_off[i] = n_code_num - p_min_code[i];
				n_code_num += p_code_num[i];
			}
			_ASSERTE(p_huff_src + n_code_num <= p_huff_end);
			const uint8_t *p_symbol = p_huff_src; p_huff_src += n_code_num;
			uint8_t *p_huff_dest = p_temp_buffer + n_prehuff_size;
			for(int n_byte = 0, n_bit_num = 0, n_counter = n_afterhuff_size; n_counter --;) {
				for(int i = 0, n_code = 0;; ++ i) {
					_ASSERTE(i < 16);
					if(!(n_bit_num-- )) {
						_ASSERTE(p_huff_src < p_huff_end);
						n_byte = *p_huff_src ++;
						n_bit_num = 7;
					}
					n_code = (n_code << 1) | (n_byte >> 7);
					n_byte = (n_byte << 1) & 0xff;
					if(n_code >= p_min_code[i] && n_code < p_max_code[i]) {
						*p_huff_dest ++ = p_symbol[n_code + p_table_off[i]];
						break;
					}
				}
			}
		}
		{
			uint8_t *p_rle_dest = p_temp_buffer;
			const uint8_t *p_rle_src = p_temp_buffer + n_prehuff_size,
				*p_src_end = p_rle_src + n_afterhuff_size;
			for(; p_rle_src != p_src_end;) {
				uint8_t n_code = *p_rle_src ++;
				bool b_compressed = n_code & 1;
				int n_run_length = (n_code >> 1) + 1;
				_ASSERTE(p_rle_src + ((b_compressed)? 1 : n_run_length) <= p_src_end);
				while(n_run_length --)
					*p_rle_dest ++ = (b_compressed)? *p_rle_src : *p_rle_src ++;
				if(b_compressed)
					++ p_rle_src;
			}
		}
		{
			uint8_t *p_y = p_temp_buffer;
			uint8_t *p_u = p_y + n_image_size;
			uint8_t *p_v = p_u + n_chroma_plane_size;
			UnPredict_ImagePlane(p_y, n_image_width, n_image_height, n_predictor_y);
			UnPredict_ImagePlane(p_u, n_chroma_w, n_chroma_h, n_predictor_uv);
			UnPredict_ImagePlane(p_v, n_chroma_w, n_chroma_h, n_predictor_uv);
			for(int y = 0, h = n_image_height; y < h; ++ y) {
				for(int x = 0, w = n_image_width; x < w; ++ x) {
					int n_cr_idx = x / n_subsample + y / n_subsample * n_chroma_w;
					int Y = *p_y ++, u = p_u[n_cr_idx] - 128, v = p_v[n_cr_idx] - 128;
					uint8_t r = uint8_t(max(0, min(255, Y + 1.402f * v)));
					uint8_t g = uint8_t(max(0, min(255, Y - 0.34414f * u - 0.71414f * v)));
					uint8_t b = uint8_t(max(0, min(255, Y + 1.772f * u)));
					p_raster[x + y * w] = 0xff000000 | (r << 16) | (g << 8) | b;
				}
			}
		}

		delete[] p_temp_buffer;
		
		return p_raster;
	}
};

#endif // !__OPENGL_LOGO_2_0_TGA_INCLUDED
