text: #include "MDraw.h"
  
  #include <emmintrin.h>
  
  void DrawR(PixelBlock& w, int x, int y, Color c)
  {}
  
  static const byte n_o[] = {
  	0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
  	0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
  	0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
  	0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  	0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  	0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  	0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  	0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  	0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
  	0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
  	0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
  };
  
  void DrawO(PixelBlock& w, int x, int y, Color c)
  {
  	const byte *s = n_o;
  	dword *a = w.PointAdr(x, y);
  	int d = w.LineDelta();
  	dword ic = c;
  	for(int w = 0; w < 11; w++) {
  		for(int q = 0; q < 6; q++) {
  			if(*s)
  				a[q] = ic;
  			s++;
  		}
  		a += d;
  	}
  }
  
  String of_packed;
  
  void DrawOF(PixelBlock& w, int x, int y, Color c)
  {
  	dword *a = w.PointAdr(x, y);
  	int d = w.LineDelta();
  	dword ic = c;
  	const byte *s = of_packed;
  	dword *t = a;
  	for(;;) {
  		byte c = *s++;
  		if(c == 0)
  			break;
  		t += (c >> 3) & 15;
  		switch(c & 7) {
  		case 7:
  			t[7] = ic;
  		case 6:
  			t[6] = ic;
  		case 5:
  			t[5] = ic;
  		case 4:
  			t[4] = ic;
  		case 3:
  			t[3] = ic;
  		case 2:
  			t[2] = ic;
  		case 1:
  			t[1] = ic;
  		}
  		t += c & 7;
  		if(c & 0x80) {
  			a += d;
  			t = a;
  		}
  	}
  }
  
  void PackOF() {
  	StringBuffer pk;
  	for(int w = 0; w < 11; w++) {
  		int n = 0;
  		const byte *ln = n_o + w * 6;
  		bool wasnot = true;
  		for(int q = 0; q < 6; q++)
  			if(ln[q]) {
  				int m = 0;
  				while(q < 6 && ln[q]) {
  					m++;
  					q++;
  				}
  				while(n > 15) {
  					pk.Cat((15 << 3));
  					n -= 15;
  				}
  				if(m > 7) {
  					pk.Cat((n << 3) | 7);
  					m -= 7;
  					while(m > 7) {
  						pk.Cat(7);
  						m -= 7;
  					}
  					if(m)
  						pk.Cat(m);
  				}
  				else
  					pk.Cat((n << 3) | m);
  				n = 1;
  				wasnot = false;
  			}
  			else
  				n++;
  		if(wasnot)
  			pk.Cat(0x80);
  		else
  			*(pk.End() - 1) |= 0x80;
  	}
  	pk.Cat(0);
  	of_packed = pk;
  }
  
  int BlendColor1(int a, int c, int cc)
  {
  	return (byte)((((a + (a >> 7)) * (c - cc)) >> 8) + cc);
  }
  
  #define BLEND(i, d) \
  { \
  	const int alpha = d + (d >> 7); \
  	byte *m = (byte *)&a[i]; \
  	m[0] += (alpha * (tr - m[0]) >> 8); \
  	m[1] += (alpha * (tg - m[1]) >> 8); \
  	m[2] += (alpha * (tb - m[2]) >> 8); \
  }
  
  
  #define SET(i) a[i] = ic
  
  void DrawF(PixelBlock& w, int x, int y, Color c)
  {
  	dword *a = w.PointAdr(x, y);
  	int d = w.LineDelta();
  	byte tr = c.GetR();
  	byte tg = c.GetG();
  	byte tb = c.GetB();
  	dword ic = c;
  	BLEND(1, 0x80); SET(2); SET(3); BLEND(4, 0x80); a += d;
  	SET(1); BLEND(2, 0x10); BLEND(3, 0x10); SET(4); a += d;
  	BLEND(0, 0x80); BLEND(1, 0x80); BLEND(4, 0x80); BLEND(5, 0x80); a += d;
  	BLEND(0, 0xb0); BLEND(1, 0x70); BLEND(4, 0x70); BLEND(5, 0xb0); a += d;
  //	BLEND(0, 0xe0); BLEND(1, 0x30); BLEND(4, 0x30); BLEND(5, 0xe0); a += d;
  	SET(0); SET(5); a += d;
  	SET(0); SET(5); a += d;
  	SET(0); SET(5); a += d;
  //	BLEND(0, 0xe0); BLEND(1, 0x30); BLEND(4, 0x30); BLEND(5, 0xe0); a += d;
  	BLEND(0, 0xb0); BLEND(1, 0x70); BLEND(4, 0x70); BLEND(5, 0xb0); a += d;
  	BLEND(0, 0x80); BLEND(1, 0x80); BLEND(4, 0x80); BLEND(5, 0x80); a += d;
  	SET(1); BLEND(2, 0x10); BLEND(3, 0x10); SET(4); a += d;
  	BLEND(1, 0x80); SET(2); SET(3); BLEND(4, 0x80); a += d;
  }
  
  static const byte o[] = {
  	// 0     1     2     3     4     5
  	0x00, 0x80, 0xff, 0xff, 0x80, 0x00,
  	0x00, 0xff, 0x10, 0x10, 0xff, 0x00,
  	0x80, 0x80, 0x00, 0x00, 0xff, 0x80,
  	0xb0, 0x70, 0x00, 0x00, 0x70, 0xb0,
  	0xe0, 0x30, 0x00, 0x00, 0x30, 0xe0,
  	0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  	0xe0, 0x30, 0x00, 0x00, 0x30, 0xe0,
  	0xb0, 0x70, 0x00, 0x00, 0x70, 0xb0,
  	0x80, 0x80, 0x00, 0x00, 0xff, 0x80,
  	0x00, 0xff, 0x10, 0x10, 0xff, 0x00,
  	0x00, 0x80, 0xff, 0xff, 0x80, 0x00,
  };
  
  void DrawO1(PixelBlock& w, int x, int y, Color c)
  {
  	const byte *s = o;
  	dword *a = w.PointAdr(x, y);
  	int d = w.LineDelta();
  	byte tr = c.GetR();
  	byte tg = c.GetG();
  	byte tb = c.GetB();
  	for(int w = 0; w < 11; w++) {
  		for(int q = 0; q < 6; q++) {
  			int alpha = *s + (*s >> 7);
  			dword cc = a[q];
  			byte r = (byte)(cc >> 16);
  			byte g = (byte)(cc >> 8);
  			byte b = (byte)(cc);
  			r = (alpha * (tr - r) >> 8) + r;
  			g = (alpha * (tg - g) >> 8) + g;
  			b = (alpha * (tb - b) >> 8) + b;
  			a[q] = (byte(r) << 16) | (byte(g) << 8) | byte(b);
  			s++;
  		}
  		a += d;
  	}
  }
  
  void DrawO2(PixelBlock& w, int x, int y, Color c)
  {
  	const byte *s = o;
  	dword *a = w.PointAdr(x, y);
  	int d = w.LineDelta();
  	byte tr = c.GetR();
  	byte tg = c.GetG();
  	byte tb = c.GetB();
  	for(int w = 0; w < 11; w++) {
  		for(int q = 0; q < 6; q++) {
  			int alpha = *s + (*s >> 7);
  			s++;
  			byte *m = (byte *)&a[q];
  			m[0] += (alpha * (tr - m[0]) >> 8);
  			m[1] += (alpha * (tg - m[1]) >> 8);
  			m[2] += (alpha * (tb - m[2]) >> 8);
  		}
  		a += d;
  	}
  }
  
  String op;
  
  String PackOP(const byte *s, int cx, int cy)
  {
  	StringBuffer result;
  	for(int i = 0; i < cy; i++) {
  		int j = 0;
  		while(j < cx) {
  			if(*s == 0) {
  				int n = 0;
  				while(*s == 0 && j < cx) {
  					n++;
  					j++;
  					s++;
  				}
  				while(n >= 255) {
  					result.Cat(0);
  					result.Cat(254);
  					n -= 254;
  				}
  				result.Cat(0);
  				result.Cat(n);
  			}
  			else {
  				result.Cat(*s++);
  				j++;
  			}
  		}
  		result.Cat(0);
  		result.Cat(0);
  	}
  	result.Cat(0);
  	result.Cat(255);
  	return result;
  }
  
  void DrawOP(PixelBlock& w, int x, int y, Color c)
  {
  	const byte *s = op;
  	dword *a = w.PointAdr(x, y);
  	int d = w.LineDelta();
  	byte tr = c.GetR();
  	byte tg = c.GetG();
  	byte tb = c.GetB();
  	int q = 0;
  	for(;;) {
  		byte c = *s++;
  		if(c) {
  			byte *m = (byte *)&a[q];
  			int alpha = c + (c >> 7);
  			m[0] += alpha * (tr - m[0]) >> 8;
  			m[1] += alpha * (tg - m[1]) >> 8;
  			m[2] += alpha * (tb - m[2]) >> 8;
  			q++;
  		}
  		else {
  			c = *s++;
  			if(c)
  				q += c;
  			else {
  				if(s[0] == 0 && s[1] == 255)
  					return;
  				a += d;
  				q = 0;
  			}
  		}
  	}
  	a += d;
  }
  
  void DrawOPMMX(PixelBlock& w, int x, int y, Color color)
  {
  	const byte *s = op;
  	dword *a = w.PointAdr(x, y);
  	int d = w.LineDelta();
  	byte tr = color.GetR();
  	byte tg = color.GetG();
  	byte tb = color.GetB();
  	int q = 0;
  	__m64 zero = _mm_setzero_si64();
  	__m64 mc = _mm_unpacklo_pi8(_mm_cvtsi32_si64(color.GetRaw()), zero);
  	__m64 mask = _mm_set1_pi16(0xff);
  	for(;;) {
  		byte c = *s++;
  		if(c) {
  			__m64 alpha = _mm_cvtsi32_si64(c);
  			alpha = _mm_unpacklo_pi16(alpha, alpha);
  			alpha = _mm_unpacklo_pi32(alpha, alpha);
  			__m64 h = _mm_srli_pi16(alpha, 7);
  			alpha = _mm_adds_pi16(alpha, h);
  			__m64 m = _mm_cvtsi32_si64(a[q]);
  			m = _mm_unpacklo_pi8(m, zero);
  			h = _mm_sub_pi16(mc, m);
  			h = _mm_mullo_pi16(alpha, h);
  			h = _mm_srli_pi16(h, 8);
  			m = _mm_add_pi16(m, h);
  			m = _mm_and_si64(m, mask);
  			m = _mm_packs_pu16(m, m);
  			a[q++] = _mm_cvtsi64_si32(m);
  		}
  		else {
  			c = *s++;
  			if(c)
  				q += c;
  			else {
  				if(s[0] == 0 && s[1] == 255)
  					break;
  				a += d;
  				q = 0;
  			}
  		}
  	}
  	_m_empty();
  }
  
  #define N 300
  
  void DoTest(Draw& w, const char *name, void (*od)(PixelBlock&, int, int, Color))
  {
  	for(int section = 0; section < 2; section++) {
  		String ss = section ? "SECTION " : "SETDIB ";
  		{
  			TimeStop tm;
  			PixelBlock b(1024, 768, section);
  			for(int i = 0; i < N; i++) {
  				if(od) {
  					b.DrawRect(0, 0, 512, 768, White);
  					b.DrawRect(512, 0, 512, 768, Red);
  					for(int x = 0; x < 1024 / 8 - 1; x++)
  						for(int y = 0; y < 768 / 16 - 1; y++)
  							(*od)(b, 8 * x, 16 * y, x < 512 / 8 ? Black : White);
  				}
  				b.Put(w, 0, 0);
  				Draw::Flush();
  			}
  			RLOG(ss << name << ": " << tm.Elapsed() / N << " ms");
  		}
  		{
  			TimeStop tm;
  			PixelBlock b(1024, 768, section);
  			for(int i = 0; i < N; i++) {
  				if(od) {
  					for(int y = 0; y < 768 / 16 - 1; y++) {
  						b.DrawRect(0, 16 * y, 1024, 16, Color(y & 255, y & 255, y & 255));
  						for(int x = 0; x < 1024 / 8 - 1; x++)
  							(*od)(b, 8 * x, 16 * y, x < 512 / 8 ? Black : White);
  					}
  				}
  				b.Put(w, 0, 0);
  				Draw::Flush();
  			}
  			RLOG(ss << name << " cached: " << tm.Elapsed() / N << " ms");
  		}
  	}
  }
  
  void MDraw::Paint(Draw& w)
  {
  	Size sz = GetSize();
  /*
  	{
  		TimeStop tm;
  		for(int i = 0; i < 1000; i++)
  			w.DrawRect(0, 0, 1024, 768, Color(i, i, i));
  		Draw::Flush();
  		RLOG("Painting using GDI: " << tm);
  	}
  
  	{
  		TimeStop tm;
  		for(int i = 0; i < 1000; i++) {
  			PixelBlock b(1024, 768, true);
  			b.DrawRect(0, 0, sz.cx, sz.cy, Color(i, i, i));
  			b.Put(w, 0, 0);
  		}
  		Draw::Flush();
  		RLOG("Painting using Section: " << tm);
  	}
  */
  /*	{
  		FontInfo fi = w.GetFontInfo(Arial(15));
  		String text = String('0', 1024 / fi['0']);
  		TimeStop tm;
  		for(int i = 0; i < N; i++) {
  			w.DrawRect(0, 0, 1024, 768, White);
  			for(int y = 0; y < 768; y += fi.GetHeight())
  				w.DrawText(0, y, text, Arial(15), Color(i, i, i));
  			Draw::Flush();
  		}
  		RLOG("GDI: " << tm.Elapsed() / N << " ms");
  	}
  */
  	DoTest(w, "R - Just PUT", NULL);
  	DoTest(w, "R - Just rect", DrawR);
  	DoTest(w, "01 - no antialiasing", DrawO);
  	DoTest(w, "0F - no antialiasing packed", DrawOF);
  	DoTest(w, "01 - shifts", DrawO1);
  	DoTest(w, "02 - loads", DrawO2);
  	DoTest(w, "F - fast", DrawF);
  	DoTest(w, "0P - packed", DrawOP);
  	DoTest(w, "0P - packed MMX", DrawOPMMX);
  
  	w.DrawRect(0, 0, 100, 100, SBlue);
  }
  
  GUI_APP_MAIN
  {
  	PackOF();
  	DUMP(of_packed.GetLength());
  	op = PackOP(o, 6, 11);
  	LOGHEXDUMP(op, op.GetLength());
  	RDUMP(op.GetLength());
  	Ctrl::AutoBackPaintAreaSize = 0;
  	MDraw t;
  	t.SetRect(0, 0, 1024, 768);
  	t.Sizeable().Zoomable();
  	t.Run();
  }
  