ultimatepp/uppdev/Polygon2/main.cpp
cxl 64d02d802e Syncing uppdev
git-svn-id: svn://ultimatepp.org/upp/trunk@710 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-12-18 10:12:07 +00:00

332 lines
6.7 KiB
C++

#include <CtrlLib/CtrlLib.h>
using namespace Upp;
#define LDUMP(x)
#define LLOG(x);
#define LTIMING(x) RTIMING(x)
class AABuffer {
struct RGBAi {
dword r;
dword g;
dword b;
dword a;
void Write(RGBA& t) {
t.r = byte(r >> 4);
t.g = byte(g >> 4);
t.b = byte(b >> 4);
t.a = byte(a >> 4);
}
void Put(const RGBA& s) {
r += s.r;
g += s.g;
b += s.b;
a += s.a;
}
RGBAi() { r = g = b = a = 0; }
};
#define COMPLEX *(RGBA *)(
struct P16 {
RGBA simple;
RGBA *complex;
bool IsComplex() const { return simple.b == 255 && simple.a == 0; }
};
Buffer< Buffer<P16> > line;
int cx, gx, cy;
void Free();
static bool MakeComplexIf(P16 *p, RGBA color)
{
if(!p->IsComplex()) {
if(p->simple == color)
return false;
RGBA h = p->simple;
p->complex = new RGBA[16];
p->complex[0] = h; p->complex[1] = h; p->complex[2] = h; p->complex[3] = h;
p->complex[4] = h; p->complex[5] = h; p->complex[6] = h; p->complex[7] = h;
p->complex[8] = h; p->complex[9] = h; p->complex[10] = h; p->complex[11] = h;
p->complex[12] = h; p->complex[13] = h; p->complex[14] = h; p->complex[15] = h;
p->simple.b = 255;
p->simple.a = 0;
}
return true;
}
public:
void Fill(int x, int y, int n, RGBA color);
void Create(int cx, int cy);
Image Downsample();
~AABuffer();
};
void AABuffer::Fill(int x, int y, int n, RGBA color)
{
if(n <= 0)
return;
P16 *p = line[y];
int j = x >> 4;
int a = x & 15;
if(a || n < 16) {
int c = min(n, 16 - a);
if(MakeComplexIf(p, color))
UPP::Fill(p->complex + a, color, c);
n -= c;
p++;
}
while(n > 16) {
if(p->IsComplex())
delete[] p->complex;
p->simple = color;
n -= 16;
p++;
}
if(n && MakeComplexIf(p, color))
UPP::Fill(p->complex, color, n);
}
void AABuffer::Create(int _cx, int _cy)
{
cx = _cx << 2;
cy = _cy << 2;
gx = (cx + 15) >> 4;
line.Alloc(cy);
for(int i = 0; i < cy; i++) {
line[i].Alloc(gx);
memset(line[i], 0, cx * sizeof(P16));
}
}
Image AABuffer::Downsample()
{
LTIMING("Downscale");
Size tsz = Size(cx >> 2, cy >> 2);
ImageBuffer tb(tsz);
RGBA *t = tb;
for(int y = 0; y < tsz.cy; y++) {
P16 *p[4];
p[0] = line[4 * y + 0];
p[1] = line[4 * y + 1];
p[2] = line[4 * y + 2];
p[3] = line[4 * y + 3];
int x = 0;
for(int i = 0; i < gx; i++) {
RGBA c = p[1]->simple;
if(c == p[2]->simple && c == p[3]->simple && c == p[4]->simple) {
if(x + 4 < tsz.cx) {
t[0] = c;
t[1] = c;
t[2] = c;
t[3] = c;
t += 4;
}
else
while(x < tsz.cx)
*t++ = c;
}
else {
RGBAi m[4];
for(int j = 0; j < 4; j++) {
if(*p[j].IsSimple()) {
for(int k = 0; k < 4; k++)
m[k].Put4(*p[j]->simple);
}
else {
for(int k = 0; k < 4; k++) {
m[0].Put(p[j].complex[0]);
m[0].Put(p[j].complex[1]);
m[0].Put(p[j].complex[2]);
m[0].Put(p[j].complex[3]);
}
}
}
}
p[0]++;
p[1]++;
p[2]++;
p[3]++;
}
return tb;
}
struct PolygonRenderer {
Buffer< Vector<int> > ln;
int y0, ymax, lnc;
void AddPoint(int x, int y)
{
LDUMP(Point(x, y));
if(y >= y0 && y <= ymax) {
Vector<int>& v = ln[y - y0];
int i;
for(i = 0; i < v.GetCount(); i++)
if(x < v[i])
break;
v.Insert(i, x);
}
}
void RenderPolygon(ImageBuffer& b, const Vector<Point>& p, RGBA color)
{
LTIMING("RenderPolygon");
if(p.GetCount() < 2)
return;
ymax = y0 = p[0].y;
for(int i = 0; i < p.GetCount(); i++) {
int y = p[i].y;
y0 = min(y0, y);
ymax = max(ymax, y);
}
y0 = minmax(y0, 0, b.GetHeight() - 1);
ymax = minmax(ymax, 0, b.GetHeight() - 1);
int lines = ymax - y0 + 1;
ln.Alloc(lines);
for(int i = 0; i < p.GetCount(); i++) {
Point p1 = p[i];
Point p2 = p[i > 0 ? i - 1 : p.GetCount() - 1];
LLOG(p1 << " - " << p2);
if(p1.y > p2.y)
Swap(p1, p2);
int delta = ((p2.x - p1.x) << 16) / (p2.y - p1.y + 1);
int x = p1.x << 16;
AddPoint(p1.x, p1.y);
for(int y = p1.y; y < p2.y; y++) {
x += delta;
AddPoint(x >> 16, y);
}
AddPoint(p2.x, p2.y);
}
RGBA *t = b[y0];
int cx = b.GetWidth();
for(int i = 0; i < lines; i++) {
LDUMP(y0 + i);
Vector<int>& v = ln[i];
int j = 0;
while(j < v.GetCount() - 1) {
LLOG(v[j] << ' ' << v[j + 1]);
if(v[j] < cx && v[j + 1] >= 0) {
int x1 = max(v[j], 0);
int x2 = min(v[j + 1], cx - 1);
Fill(t + x1, color, x2 - x1 + 1);
}
j += 2;
}
t += cx;
}
}
};
void RenderPolygon(ImageBuffer& b, const Vector<Point>& p, RGBA color)
{
PolygonRenderer r;
r.RenderPolygon(b, p, color);
}
struct RGBAi {
dword r;
dword g;
dword b;
dword a;
void Get(RGBA& t) {
t.r = r >> 4;
t.g = g >> 4;
t.b = b >> 4;
t.a = a >> 4;
}
void Put(const RGBA& s) {
r += s.r;
g += s.g;
b += s.b;
a += s.a;
}
RGBAi() { r = g = b = a = 0; }
};
Image Downscale(const ImageBuffer& b)
{
LTIMING("Downscale");
Size tsz = b.GetSize() / 4;
ImageBuffer tb(tsz);
int cx = b.GetWidth();
const RGBA *bs = ~b;
RGBA *t = tb;
for(int y = 0; y < tsz.cy; y++) {
const RGBA *q = bs;
for(int x = 0; x < tsz.cx; x++) {
RGBAi m;
const RGBA *s = q;
m.Put(s[0]); m.Put(s[1]); m.Put(s[2]); m.Put(s[3]);
s += cx;
m.Put(s[0]); m.Put(s[1]); m.Put(s[2]); m.Put(s[3]);
s += cx;
m.Put(s[0]); m.Put(s[1]); m.Put(s[2]); m.Put(s[3]);
s += cx;
m.Put(s[0]); m.Put(s[1]); m.Put(s[2]); m.Put(s[3]);
q += 4;
m.Get(*t++);
}
bs += 4 * cx;
}
return tb;
}
struct App : TopWindow {
Vector<Point> p;
virtual void LeftDown(Point, dword) {
Size sz = GetSize() * 4;
int n = Random(10) + 3;
p.SetCount(n);
for(int i = 0; i < n; i++)
p[i] = Point(Random(sz.cx), Random(sz.cy));
// p[i] = Point(Random(sz.cx + 30) - 15, Random(sz.cy + 30) - 15);
Refresh();
}
void Plot(ImageBuffer& b, int x, int y) {
if(Rect(b.GetSize()).Contains(Point(x, y)))
b[y][x] = Yellow();
}
virtual void Paint(Draw& w) {
ImageBuffer b(GetSize() * 4);
Fill(b, LtGray(), b.GetLength());
Image m;
for(int i = 0; i < 10; i++) {
RenderPolygon(b, p, Red());
for(int i = 0; i < p.GetCount(); i++) {
Point q = p[i];
Plot(b, q.x, q.y);
Plot(b, q.x - 1, q.y);
Plot(b, q.x + 1, q.y);
Plot(b, q.x, q.y + 1);
Plot(b, q.x, q.y - 1);
}
m = Downscale(b);
}
w.DrawImage(0, 0, m);
}
App() {
p << Point(20, 20) << Point(200, 20) << Point(230, 150) << Point(120, 200);
}
};
GUI_APP_MAIN
{
App().Run();
}