#include #include #include #include #include #include #include #include #include typedef Point Triangle[3]; Memimage *fb; Memimage *red, *green, *blue; Channel *drawc; void resized(void); void* emalloc(ulong n) { void *p; p = malloc(n); if(p == nil) sysfatal("malloc: %r"); setmalloctag(p, getcallerpc(&n)); return p; } void* erealloc(void *p, ulong n) { void *np; np = realloc(p, n); if(np == nil){ if(n == 0) return nil; sysfatal("realloc: %r"); } if(p == nil) setmalloctag(np, getcallerpc(&p)); else setrealloctag(np, getcallerpc(&p)); return np; } Image* eallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong col) { Image *i; i = allocimage(d, r, chan, repl, col); if(i == nil) sysfatal("allocimage: %r"); return i; } Memimage* eallocmemimage(Rectangle r, ulong chan) { Memimage *i; i = allocmemimage(r, chan); if(i == nil) sysfatal("allocmemimage: %r"); memfillcolor(i, DTransparent); return i; } Memimage* rgb(ulong c) { Memimage *i; i = eallocmemimage(Rect(0,0,1,1), screen->chan); i->flags |= Frepl; i->clipr = Rect(-1e6, -1e6, 1e6, 1e6); memfillcolor(i, c); return i; } void pixel(Memimage *dst, Point p, Memimage *src) { Rectangle r; r.min = addpt(dst->r.min, p); r.max = addpt(r.min, Pt(1,1)); memimagedraw(dst, r, src, ZP, nil, ZP, SoverD); } void swap(int *a, int *b) { int t; t = *a; *a = *b; *b = t; } void bresenham(Memimage *dst, Point p0, Point p1, Memimage *src) { int steep = 0, Δe, e, Δy; Point p, dp; /* transpose the points */ if(abs(p0.x-p1.x) < abs(p0.y-p1.y)){ steep = 1; swap(&p0.x, &p0.y); swap(&p1.x, &p1.y); } /* make them left-to-right */ if(p0.x > p1.x){ swap(&p0.x, &p1.x); swap(&p0.y, &p1.y); } dp = subpt(p1, p0); Δe = 2*abs(dp.y); e = 0; Δy = p1.y > p0.y? 1: -1; for(p = p0; p.x <= p1.x; p.x++){ if(steep) swap(&p.x, &p.y); pixel(dst, p, src); if(steep) swap(&p.x, &p.y); e += Δe; if(e > dp.x){ p.y += Δy; e -= 2*dp.x; } } } int ycoordsort(void *a, void *b) { return ((Point*)a)->y - ((Point*)b)->y; } void triangle(Memimage *dst, Point p0, Point p1, Point p2, Memimage *src) { Triangle t; t[0] = p0; t[1] = p1; t[2] = p2; qsort(t, nelem(t), sizeof(Point), ycoordsort); bresenham(dst, t[0], t[1], src); bresenham(dst, t[1], t[2], src); bresenham(dst, t[2], t[0], green); } void filltriangle(Memimage *dst, Point p0, Point p1, Point p2, Memimage *src) { int y; double m₀₂, m₀₁, m₁₂; Point dp₀₂, dp₀₁, dp₁₂; Triangle t; t[0] = p0; t[1] = p1; t[2] = p2; qsort(t, nelem(t), sizeof(Point), ycoordsort); dp₀₂ = subpt(t[2], t[0]); m₀₂ = (double)dp₀₂.x/dp₀₂.y; dp₀₁ = subpt(t[1], t[0]); m₀₁ = (double)dp₀₁.x/dp₀₁.y; dp₁₂ = subpt(t[2], t[1]); m₁₂ = (double)dp₁₂.x/dp₁₂.y; fprint(2, "%P %P %P\n", t[0], t[1], t[2]); fprint(2, "m₀₂ %g m₀₁ %g m₁₂ %g\n", m₀₂, m₀₁, m₁₂); for(y = t[0].y; y <= t[1].y; y++) bresenham(dst, Pt(t[0].x + (y-t[0].y)*m₀₂,y), Pt(t[0].x + (y-t[0].y)*m₀₁,y), src); for(; y <= t[2].y; y++) bresenham(dst, Pt(t[0].x + (y-t[0].y)*m₀₂,y), Pt(t[1].x + (y-t[1].y)*m₁₂,y), src); bresenham(dst, t[0], t[1], src); bresenham(dst, t[1], t[2], src); bresenham(dst, t[2], t[0], green); } void redraw(void) { lockdisplay(display); draw(screen, screen->r, display->black, nil, ZP); loadimage(screen, screen->r, byteaddr(fb, fb->r.min), bytesperline(fb->r, fb->depth)*Dy(fb->r)); flushimage(display, 1); unlockdisplay(display); } void rmb(Mousectl *, Keyboardctl *) { } void lmb(Mousectl *, Keyboardctl *) { } void mouse(Mousectl *mc, Keyboardctl *kc) { if((mc->buttons&1) != 0) lmb(mc, kc); if((mc->buttons&4) != 0) rmb(mc, kc); } void key(Rune r) { switch(r){ case Kdel: case 'q': threadexitsall(nil); } } void usage(void) { fprint(2, "usage: %s\n", argv0); exits("usage"); } void threadmain(int argc, char *argv[]) { Mousectl *mc; Keyboardctl *kc; Rune r; GEOMfmtinstall(); ARGBEGIN{ default: usage(); }ARGEND; if(argc > 0) usage(); if(newwindow(nil) < 0) sysfatal("newwindow: %r"); if(initdraw(nil, nil, nil) < 0) sysfatal("initdraw: %r"); if(memimageinit() != 0) sysfatal("memimageinit: %r"); if((mc = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); if((kc = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); fb = eallocmemimage(screen->r, screen->chan); red = rgb(DRed); green = rgb(DGreen); blue = rgb(DBlue); bresenham(fb, Pt(40,40), Pt(300,300), red); bresenham(fb, Pt(80,80), Pt(100,200), red); bresenham(fb, Pt(80,80), Pt(200,100), red); filltriangle(fb, Pt(30,10), Pt(45, 45), Pt(5, 100), red); triangle(fb, Pt(300,120), Pt(350,200), Pt(50, 210), red); triangle(fb, Pt(300,130), Pt(350,80), Pt(50, 220), red); drawc = chancreate(sizeof(void*), 1); display->locking = 1; unlockdisplay(display); nbsend(drawc, nil); for(;;){ enum { MOUSE, RESIZE, KEYBOARD, DRAW }; Alt a[] = { {mc->c, &mc->Mouse, CHANRCV}, {mc->resizec, nil, CHANRCV}, {kc->c, &r, CHANRCV}, {drawc, nil, CHANRCV}, {nil, nil, CHANEND} }; switch(alt(a)){ case MOUSE: mouse(mc, kc); break; case RESIZE: resized(); break; case KEYBOARD: key(r); break; case DRAW: redraw(); break; } } } void resized(void) { lockdisplay(display); if(getwindow(display, Refnone) < 0) sysfatal("couldn't resize"); unlockdisplay(display); nbsend(drawc, nil); }