#include "MDraw.h" #include 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(); }