#include "Draw.h"

NAMESPACE_UPP

static int sMaskPos16(dword mask)
{
	if(mask > 0xffff)
		return 0;
	int pos = 0;
	while(((mask << pos) & 0x18000) != 0x8000)
		pos++;
	return pos;
}

void RasterFormat::Set16le(dword _rmask, dword _gmask, dword _bmask)
{
	rpos = sMaskPos16(rmask = _rmask);
	gpos = sMaskPos16(gmask = _gmask);
	bpos = sMaskPos16(bmask = _bmask);
	type = RASTER_16;
}

void RasterFormat::Set16be(dword _rmask, dword _gmask, dword _bmask)
{
	Set16le(_rmask, _gmask, _bmask);
	type = RASTER_16|RASTER_MSBFIRST;
}

void RasterFormat::Set24le(dword rmask, dword gmask, dword bmask)
{
	rpos = GetChMaskPos32(rmask);
	gpos = GetChMaskPos32(gmask);
	bpos = GetChMaskPos32(bmask);
	apos = 0;
	type = RASTER_24;
}

void RasterFormat::Set32le(dword rmask, dword gmask, dword bmask, dword amask)
{
	Set24le(rmask, gmask, bmask);
	if(amask) {
		apos = GetChMaskPos32(amask);
		type = RASTER_32ALPHA;
	}
	else
		type = RASTER_32;
}

void RasterFormat::Set24be(dword rmask, dword gmask, dword bmask)
{
	rpos = 2 - GetChMaskPos32(rmask);
	gpos = 2 - GetChMaskPos32(gmask);
	bpos = 2 - GetChMaskPos32(bmask);
	apos = 0;
	type = RASTER_24;
}

void RasterFormat::Set32be(dword rmask, dword gmask, dword bmask, dword amask)
{
	rpos = 3 - GetChMaskPos32(rmask);
	gpos = 3 - GetChMaskPos32(gmask);
	bpos = 3 - GetChMaskPos32(bmask);
	if(amask) {
		apos = 3 - GetChMaskPos32(amask);
		type = RASTER_32ALPHA;
	}
	else
		type = RASTER_32;
}

void RasterFormat::SetRGBA()
{
	type = RASTER_32ALPHA;
	bpos = 0;
	gpos = 1;
	rpos = 2;
	apos = 3;
}

int RasterFormat::IsRGBA() const
{
	return (type & 31) == RASTER_32ALPHA && bpos == 0 && gpos == 1 && rpos == 2 && apos == 3;
}

static byte bits[16] = { 1, 2, 4, 8, 16, 16, 24, 32, 32 };

int RasterFormat::GetByteCount(int cx) const
{
	int b = bits[type & 15];
	return (cx * b + 7) >> 3;
}

int RasterFormat::GetBpp() const
{
	return bits[type & 15];
}

bool RasterFormat::HasAlpha() const
{
	return (type & 15) == RASTER_32ALPHA;
}

int RasterFormat::GetColorCount() const
{
	static int colors[16] = { 2, 4, 16, 256, 256, 65536, 256 * 256 * 256, 256 * 256 * 256, 256 * 256 * 256 };
	return colors[type & 15];
}

int RasterFormat::GetPaletteCount() const
{
	static int colors[16] = { 2, 4, 16, 256 };
	return (type & 15) < 4 ? colors[type & 15] : 0;
}

void RasterFormat::TailBits(RGBA *t, const byte *src, int cx, byte andm, byte shift, const RGBA *palette)
{
	if(cx) {
		byte c = *src;
		while(cx > 0) {
			*t++ = palette[c & andm]; c >>= shift;
			cx--;
		}
	}
}

void RasterFormat::TailBitsMSB1st(RGBA *t, const byte *src, int cx, byte shift1, byte andm, byte shift, const RGBA *palette)
{
	if(cx) {
		byte c = *src;
		while(cx > 0) {
			*t++ = palette[(c >> shift1) & andm]; c <<= shift;
			cx--;
		}
	}
}

void RasterFormat::Read(RGBA *t, const byte *s, int cx, const RGBA *palette) const
{
	switch(type) {
	case RASTER_1:
		{
			const byte *e = s + (cx >> 3);
			while(s < e) {
				byte c = *s++;
				t[0] = palette[(c >> 0) & 1];
				t[1] = palette[(c >> 1) & 1];
				t[2] = palette[(c >> 2) & 1];
				t[3] = palette[(c >> 3) & 1];
				t[4] = palette[(c >> 4) & 1];
				t[5] = palette[(c >> 5) & 1];
				t[6] = palette[(c >> 6) & 1];
				t[7] = palette[(c >> 7) & 1];
				t += 8;
			}
			TailBits(t, s, cx & 7, 1, 1, palette);
		}
		break;
	case RASTER_1|RASTER_MSBFIRST:
		{
			const byte *e = s + (cx >> 3);
			while(s < e) {
				byte c = *s++;
				t[7] = palette[(c >> 0) & 1];
				t[6] = palette[(c >> 1) & 1];
				t[5] = palette[(c >> 2) & 1];
				t[4] = palette[(c >> 3) & 1];
				t[3] = palette[(c >> 4) & 1];
				t[2] = palette[(c >> 5) & 1];
				t[1] = palette[(c >> 6) & 1];
				t[0] = palette[(c >> 7) & 1];
				t += 8;
			}
			TailBitsMSB1st(t, s, cx & 7, 7, 1, 1, palette);
		}
		break;
	case RASTER_2:
		{
			const byte *e = s + (cx >> 2);
			while(s < e) {
				byte c = *s++;
				t[0] = palette[(c >> 0) & 3];
				t[1] = palette[(c >> 2) & 3];
				t[2] = palette[(c >> 4) & 3];
				t[3] = palette[(c >> 6) & 3];
				t += 4;
			}
			TailBits(t, s, cx & 3, 3, 2, palette);
		}
		break;
	case RASTER_2|RASTER_MSBFIRST:
		{
			const byte *e = s + (cx >> 2);
			while(s < e) {
				byte c = *s++;
				t[3] = palette[(c >> 0) & 3];
				t[2] = palette[(c >> 2) & 3];
				t[1] = palette[(c >> 4) & 3];
				t[0] = palette[(c >> 6) & 3];
				t += 4;
			}
			TailBitsMSB1st(t, s, cx & 3, 6, 3, 2, palette);
		}
		break;
	case RASTER_4:
		{
			const byte *e = s + (cx >> 1);
			while(s < e) {
				byte c = *s++;
				t[0] = palette[(c >> 0) & 15];
				t[1] = palette[(c >> 4) & 15];
				t += 2;
			}
			TailBits(t, s, cx & 1, 15, 4, palette);
		}
		break;
	case RASTER_4|RASTER_MSBFIRST:
		{
			const byte *e = s + (cx >> 1);
			while(s < e) {
				byte c = *s++;
				t[1] = palette[(c >> 0) & 15];
				t[0] = palette[(c >> 4) & 15];
				t += 2;
			}
			TailBitsMSB1st(t, s, cx & 1, 4, 15, 4, palette);
		}
		break;
	case RASTER_8:
	case RASTER_8|RASTER_MSBFIRST:
		{
			RGBA *e = t + cx;
			while(t < e)
				*t++ = palette[*s++];
		}
		break;
	case RASTER_8ALPHA:
	case RASTER_8ALPHA|RASTER_MSBFIRST:
		{
			RGBA *e = t + cx;
			while(t < e) {
				RGBA pal = palette[*s];
				pal.a = s[1];
				*t++ = pal;
				s += 2;
			}
			break;
		}
	case RASTER_16:
		{
			RGBA *e = t + cx;
			while(t < e) {
				word w = Peek16le(s);
				t->a = 255;
				t->r = byte((w & rmask) << rpos >> 8);
				t->g = byte((w & gmask) << gpos >> 8);
				t->b = byte((w & bmask) << bpos >> 8);
				s += 2;
				t++;
			}
		}
		break;
	case RASTER_16|RASTER_MSBFIRST:
		{
			RGBA *e = t + cx;
			while(t < e) {
				word w = Peek16be(s);
				t->a = 255;
				t->r = byte((w & rmask) << rpos >> 8);
				t->g = byte((w & gmask) << gpos >> 8);
				t->b = byte((w & bmask) << bpos >> 8);
				s += 2;
				t++;
			}
		}
		break;
	case RASTER_24:
	case RASTER_24|RASTER_MSBFIRST:
		{
			RGBA *e = t + cx;
			while(t < e) {
				t->a = 255;
				t->r = s[rpos];
				t->g = s[gpos];
				t->b = s[bpos];
				s += 3;
				t++;
			}
		}
		break;
	case RASTER_32:
	case RASTER_32|RASTER_MSBFIRST:
		if(bpos == 0 && gpos == 1 && rpos == 2) {
			RGBA *e = t + cx;
			while(t < e) {
				*t = *(RGBA *)s;
				t->a = 255;
				s += 4;
				t++;
			}
		}
		else
		{
			RGBA *e = t + cx;
			while(t < e) {
				t->a = 255;
				t->r = s[rpos];
				t->g = s[gpos];
				t->b = s[bpos];
				s += 4;
				t++;
			}
		}
		break;
	case RASTER_32ALPHA:
	case RASTER_32ALPHA|RASTER_MSBFIRST:
		if(bpos == 0 && gpos == 1 && rpos == 2 && apos == 3)
			memcpy(t, s, cx * sizeof(RGBA));
		else
		{
			RGBA *e = t + cx;
			while(t < e) {
				t->a = s[apos];
				t->r = s[rpos];
				t->g = s[gpos];
				t->b = s[bpos];
				s += 4;
				t++;
			}
		}
		break;
	}
}

END_UPP_NAMESPACE
