This commit is contained in:
Russ Cox
2005-08-08 12:50:13 +00:00
parent 0189e66e88
commit 934846f35c
382 changed files with 62614 additions and 0 deletions

33
libmemdraw/Makefile Normal file
View File

@@ -0,0 +1,33 @@
LIB=libmemdraw.a
CC=gcc
CFLAGS=-I../include -I. -c -ggdb -D_THREAD_SAFE -pthread
O=o
OFILES=\
alloc.$O\
arc.$O\
cload.$O\
cmap.$O\
cread.$O\
defont.$O\
draw.$O\
ellipse.$O\
fillpoly.$O\
hwdraw.$O\
line.$O\
load.$O\
openmemsubfont.$O\
poly.$O\
read.$O\
string.$O\
subfont.$O\
unload.$O\
write.$O
$(LIB): $(OFILES)
ar r $(LIB) $(OFILES)
ranlib $(LIB)
%.$O: %.c
$(CC) $(CFLAGS) $*.c

200
libmemdraw/alloc.c Normal file
View File

@@ -0,0 +1,200 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#define poolalloc(a, b) malloc(b)
#define poolfree(a, b) free(b)
void
memimagemove(void *from, void *to)
{
Memdata *md;
md = *(Memdata**)to;
if(md->base != from){
print("compacted data not right: #%p\n", md->base);
abort();
}
md->base = to;
/* if allocmemimage changes this must change too */
md->bdata = (uchar*)&md->base[2];
}
Memimage*
allocmemimaged(Rectangle r, ulong chan, Memdata *md, void *X)
{
int d;
ulong l;
Memimage *i;
if(Dx(r) <= 0 || Dy(r) <= 0){
werrstr("bad rectangle %R", r);
return nil;
}
if((d = chantodepth(chan)) == 0) {
werrstr("bad channel descriptor %.8lux", chan);
return nil;
}
l = wordsperline(r, d);
i = mallocz(sizeof(Memimage), 1);
if(i == nil)
return nil;
i->X = X;
i->data = md;
i->zero = sizeof(ulong)*l*r.min.y;
if(r.min.x >= 0)
i->zero += (r.min.x*d)/8;
else
i->zero -= (-r.min.x*d+7)/8;
i->zero = -i->zero;
i->width = l;
i->r = r;
i->clipr = r;
i->flags = 0;
i->layer = nil;
i->cmap = memdefcmap;
if(memsetchan(i, chan) < 0){
free(i);
return nil;
}
return i;
}
Memimage*
_allocmemimage(Rectangle r, ulong chan)
{
int d;
ulong l, nw;
Memdata *md;
Memimage *i;
if((d = chantodepth(chan)) == 0) {
werrstr("bad channel descriptor %.8lux", chan);
return nil;
}
l = wordsperline(r, d);
nw = l*Dy(r);
md = malloc(sizeof(Memdata));
if(md == nil)
return nil;
md->ref = 1;
md->base = poolalloc(imagmem, (2+nw)*sizeof(ulong));
if(md->base == nil){
free(md);
return nil;
}
md->base[0] = (ulong)md;
md->base[1] = getcallerpc(&r);
/* if this changes, memimagemove must change too */
md->bdata = (uchar*)&md->base[2];
md->allocd = 1;
i = allocmemimaged(r, chan, md, nil);
if(i == nil){
poolfree(imagmem, md->base);
free(md);
return nil;
}
md->imref = i;
return i;
}
void
_freememimage(Memimage *i)
{
if(i == nil)
return;
if(i->data->ref-- == 1 && i->data->allocd){
if(i->data->base)
poolfree(imagmem, i->data->base);
free(i->data);
}
free(i);
}
/*
* Wordaddr is deprecated.
*/
ulong*
wordaddr(Memimage *i, Point p)
{
return (ulong*) ((ulong)byteaddr(i, p) & ~(sizeof(ulong)-1));
}
uchar*
byteaddr(Memimage *i, Point p)
{
uchar *a;
a = i->data->bdata+i->zero+sizeof(ulong)*p.y*i->width;
if(i->depth < 8){
/*
* We need to always round down,
* but C rounds toward zero.
*/
int np;
np = 8/i->depth;
if(p.x < 0)
return a+(p.x-np+1)/np;
else
return a+p.x/np;
}
else
return a+p.x*(i->depth/8);
}
int
memsetchan(Memimage *i, ulong chan)
{
int d;
int t, j, k;
ulong cc;
int bytes;
if((d = chantodepth(chan)) == 0) {
werrstr("bad channel descriptor");
return -1;
}
i->depth = d;
i->chan = chan;
i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes);
bytes = 1;
for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){
t=TYPE(cc);
if(t < 0 || t >= NChan){
werrstr("bad channel string");
return -1;
}
if(t == CGrey)
i->flags |= Fgrey;
if(t == CAlpha)
i->flags |= Falpha;
if(t == CMap && i->cmap == nil){
i->cmap = memdefcmap;
i->flags |= Fcmap;
}
i->shift[t] = j;
i->mask[t] = (1<<NBITS(cc))-1;
i->nbits[t] = NBITS(cc);
if(NBITS(cc) != 8)
bytes = 0;
}
i->nchan = k;
if(bytes)
i->flags |= Fbytes;
return 0;
}

9
libmemdraw/alpha.hoc Normal file
View File

@@ -0,0 +1,9 @@
func f(x) {
return x-x%1
}
func pixel(dr, dg, db, da, sr, sg, sb, sa, m) {
M = 255-f((sa*m)/255)
print f((sr*m+dr*M)/255), " ", f((sg*m+dg*M)/255), " ", f((sb*m+db*M)/255), " ", f((sa*m+da*M)/255), "\n"
return 0
}

117
libmemdraw/arc.c Normal file
View File

@@ -0,0 +1,117 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
/*
* elarc(dst,c,a,b,t,src,sp,alpha,phi)
* draws the part of an ellipse between rays at angles alpha and alpha+phi
* measured counterclockwise from the positive x axis. other
* arguments are as for ellipse(dst,c,a,b,t,src,sp)
*/
enum
{
R, T, L, B /* right, top, left, bottom */
};
static
Point corners[] = {
{1,1},
{-1,1},
{-1,-1},
{1,-1}
};
static
Point p00;
/*
* make a "wedge" mask covering the desired angle and contained in
* a surrounding square; draw a full ellipse; intersect that with the
* wedge to make a mask through which to copy src to dst.
*/
void
memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op)
{
int i, w, beta, tmp, c1, c2, m, m1;
Rectangle rect;
Point p, bnd[8];
Memimage *wedge, *figure, *mask;
if(a < 0)
a = -a;
if(b < 0)
b = -b;
w = t;
if(w < 0)
w = 0;
alpha = -alpha; /* compensate for upside-down coords */
phi = -phi;
beta = alpha + phi;
if(phi < 0){
tmp = alpha;
alpha = beta;
beta = tmp;
phi = -phi;
}
if(phi >= 360){
memellipse(dst, c, a, b, t, src, sp, op);
return;
}
while(alpha < 0)
alpha += 360;
while(beta < 0)
beta += 360;
c1 = alpha/90 & 3; /* number of nearest corner */
c2 = beta/90 & 3;
/*
* icossin returns point at radius ICOSSCALE.
* multiplying by m1 moves it outside the ellipse
*/
rect = Rect(-a-w, -b-w, a+w+1, b+w+1);
m = rect.max.x; /* inradius of bounding square */
if(m < rect.max.y)
m = rect.max.y;
m1 = (m+ICOSSCALE-1) >> 10;
m = m1 << 10; /* assure m1*cossin is inside */
i = 0;
bnd[i++] = Pt(0,0);
icossin(alpha, &p.x, &p.y);
bnd[i++] = mulpt(p, m1);
for(;;) {
bnd[i++] = mulpt(corners[c1], m);
if(c1==c2 && phi<180)
break;
c1 = (c1+1) & 3;
phi -= 90;
}
icossin(beta, &p.x, &p.y);
bnd[i++] = mulpt(p, m1);
figure = nil;
mask = nil;
wedge = allocmemimage(rect, GREY1);
if(wedge == nil)
goto Return;
memfillcolor(wedge, DTransparent);
memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S);
figure = allocmemimage(rect, GREY1);
if(figure == nil)
goto Return;
memfillcolor(figure, DTransparent);
memellipse(figure, p00, a, b, t, memopaque, p00, S);
mask = allocmemimage(rect, GREY1);
if(mask == nil)
goto Return;
memfillcolor(mask, DTransparent);
memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S);
c = subpt(c, dst->r.min);
memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op);
Return:
freememimage(wedge);
freememimage(figure);
freememimage(mask);
}

62
libmemdraw/arctest.c Normal file
View File

@@ -0,0 +1,62 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
extern int drawdebug;
void
main(int argc, char **argv)
{
char cc;
Memimage *x;
Point c = {208,871};
int a = 441;
int b = 441;
int thick = 0;
Point sp = {0,0};
int alpha = 51;
int phi = 3;
vlong t0, t1;
int i, n;
vlong del;
memimageinit();
x = allocmemimage(Rect(0,0,1000,1000), CMAP8);
n = atoi(argv[1]);
t0 = nsec();
t0 = nsec();
t0 = nsec();
t1 = nsec();
del = t1-t0;
t0 = nsec();
for(i=0; i<n; i++)
memarc(x, c, a, b, thick, memblack, sp, alpha, phi, SoverD);
t1 = nsec();
print("%lld %lld\n", t1-t0-del, del);
}
int drawdebug = 0;
void
rdb(void)
{
}
int
iprint(char *fmt, ...)
{
int n;
va_list va;
char buf[1024];
va_start(va, fmt);
n = doprint(buf, buf+sizeof buf, fmt, va) - buf;
va_end(va);
write(1,buf,n);
return 1;
}

68
libmemdraw/cload.c Normal file
View File

@@ -0,0 +1,68 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int
_cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
int y, bpl, c, cnt, offs;
uchar mem[NMEM], *memp, *omemp, *emem, *linep, *elinep, *u, *eu;
if(!rectinrect(r, i->r))
return -1;
bpl = bytesperline(r, i->depth);
u = data;
eu = data+ndata;
memp = mem;
emem = mem+NMEM;
y = r.min.y;
linep = byteaddr(i, Pt(r.min.x, y));
elinep = linep+bpl;
for(;;){
if(linep == elinep){
if(++y == r.max.y)
break;
linep = byteaddr(i, Pt(r.min.x, y));
elinep = linep+bpl;
}
if(u == eu){ /* buffer too small */
return -1;
}
c = *u++;
if(c >= 128){
for(cnt=c-128+1; cnt!=0 ;--cnt){
if(u == eu){ /* buffer too small */
return -1;
}
if(linep == elinep){ /* phase error */
return -1;
}
*linep++ = *u;
*memp++ = *u++;
if(memp == emem)
memp = mem;
}
}
else{
if(u == eu) /* short buffer */
return -1;
offs = *u++ + ((c&3)<<8)+1;
if(memp-mem < offs)
omemp = memp+(NMEM-offs);
else
omemp = memp-offs;
for(cnt=(c>>2)+NMATCH; cnt!=0; --cnt){
if(linep == elinep) /* phase error */
return -1;
*linep++ = *omemp;
*memp++ = *omemp++;
if(omemp == emem)
omemp = mem;
if(memp == emem)
memp = mem;
}
}
}
return u-data;
}

320
libmemdraw/cmap.c Normal file
View File

@@ -0,0 +1,320 @@
/*
* generated by mkcmap.c
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
static Memcmap def = {
/* cmap2rgb */ {
0x00,0x00,0x00,0x00,0x00,0x44,0x00,0x00,0x88,0x00,0x00,0xcc,0x00,0x44,0x00,0x00,
0x44,0x44,0x00,0x44,0x88,0x00,0x44,0xcc,0x00,0x88,0x00,0x00,0x88,0x44,0x00,0x88,
0x88,0x00,0x88,0xcc,0x00,0xcc,0x00,0x00,0xcc,0x44,0x00,0xcc,0x88,0x00,0xcc,0xcc,
0x00,0xdd,0xdd,0x11,0x11,0x11,0x00,0x00,0x55,0x00,0x00,0x99,0x00,0x00,0xdd,0x00,
0x55,0x00,0x00,0x55,0x55,0x00,0x4c,0x99,0x00,0x49,0xdd,0x00,0x99,0x00,0x00,0x99,
0x4c,0x00,0x99,0x99,0x00,0x93,0xdd,0x00,0xdd,0x00,0x00,0xdd,0x49,0x00,0xdd,0x93,
0x00,0xee,0x9e,0x00,0xee,0xee,0x22,0x22,0x22,0x00,0x00,0x66,0x00,0x00,0xaa,0x00,
0x00,0xee,0x00,0x66,0x00,0x00,0x66,0x66,0x00,0x55,0xaa,0x00,0x4f,0xee,0x00,0xaa,
0x00,0x00,0xaa,0x55,0x00,0xaa,0xaa,0x00,0x9e,0xee,0x00,0xee,0x00,0x00,0xee,0x4f,
0x00,0xff,0x55,0x00,0xff,0xaa,0x00,0xff,0xff,0x33,0x33,0x33,0x00,0x00,0x77,0x00,
0x00,0xbb,0x00,0x00,0xff,0x00,0x77,0x00,0x00,0x77,0x77,0x00,0x5d,0xbb,0x00,0x55,
0xff,0x00,0xbb,0x00,0x00,0xbb,0x5d,0x00,0xbb,0xbb,0x00,0xaa,0xff,0x00,0xff,0x00,
0x44,0x00,0x44,0x44,0x00,0x88,0x44,0x00,0xcc,0x44,0x44,0x00,0x44,0x44,0x44,0x44,
0x44,0x88,0x44,0x44,0xcc,0x44,0x88,0x00,0x44,0x88,0x44,0x44,0x88,0x88,0x44,0x88,
0xcc,0x44,0xcc,0x00,0x44,0xcc,0x44,0x44,0xcc,0x88,0x44,0xcc,0xcc,0x44,0x00,0x00,
0x55,0x00,0x00,0x55,0x00,0x55,0x4c,0x00,0x99,0x49,0x00,0xdd,0x55,0x55,0x00,0x55,
0x55,0x55,0x4c,0x4c,0x99,0x49,0x49,0xdd,0x4c,0x99,0x00,0x4c,0x99,0x4c,0x4c,0x99,
0x99,0x49,0x93,0xdd,0x49,0xdd,0x00,0x49,0xdd,0x49,0x49,0xdd,0x93,0x49,0xdd,0xdd,
0x4f,0xee,0xee,0x66,0x00,0x00,0x66,0x00,0x66,0x55,0x00,0xaa,0x4f,0x00,0xee,0x66,
0x66,0x00,0x66,0x66,0x66,0x55,0x55,0xaa,0x4f,0x4f,0xee,0x55,0xaa,0x00,0x55,0xaa,
0x55,0x55,0xaa,0xaa,0x4f,0x9e,0xee,0x4f,0xee,0x00,0x4f,0xee,0x4f,0x4f,0xee,0x9e,
0x55,0xff,0xaa,0x55,0xff,0xff,0x77,0x00,0x00,0x77,0x00,0x77,0x5d,0x00,0xbb,0x55,
0x00,0xff,0x77,0x77,0x00,0x77,0x77,0x77,0x5d,0x5d,0xbb,0x55,0x55,0xff,0x5d,0xbb,
0x00,0x5d,0xbb,0x5d,0x5d,0xbb,0xbb,0x55,0xaa,0xff,0x55,0xff,0x00,0x55,0xff,0x55,
0x88,0x00,0x88,0x88,0x00,0xcc,0x88,0x44,0x00,0x88,0x44,0x44,0x88,0x44,0x88,0x88,
0x44,0xcc,0x88,0x88,0x00,0x88,0x88,0x44,0x88,0x88,0x88,0x88,0x88,0xcc,0x88,0xcc,
0x00,0x88,0xcc,0x44,0x88,0xcc,0x88,0x88,0xcc,0xcc,0x88,0x00,0x00,0x88,0x00,0x44,
0x99,0x00,0x4c,0x99,0x00,0x99,0x93,0x00,0xdd,0x99,0x4c,0x00,0x99,0x4c,0x4c,0x99,
0x4c,0x99,0x93,0x49,0xdd,0x99,0x99,0x00,0x99,0x99,0x4c,0x99,0x99,0x99,0x93,0x93,
0xdd,0x93,0xdd,0x00,0x93,0xdd,0x49,0x93,0xdd,0x93,0x93,0xdd,0xdd,0x99,0x00,0x00,
0xaa,0x00,0x00,0xaa,0x00,0x55,0xaa,0x00,0xaa,0x9e,0x00,0xee,0xaa,0x55,0x00,0xaa,
0x55,0x55,0xaa,0x55,0xaa,0x9e,0x4f,0xee,0xaa,0xaa,0x00,0xaa,0xaa,0x55,0xaa,0xaa,
0xaa,0x9e,0x9e,0xee,0x9e,0xee,0x00,0x9e,0xee,0x4f,0x9e,0xee,0x9e,0x9e,0xee,0xee,
0xaa,0xff,0xff,0xbb,0x00,0x00,0xbb,0x00,0x5d,0xbb,0x00,0xbb,0xaa,0x00,0xff,0xbb,
0x5d,0x00,0xbb,0x5d,0x5d,0xbb,0x5d,0xbb,0xaa,0x55,0xff,0xbb,0xbb,0x00,0xbb,0xbb,
0x5d,0xbb,0xbb,0xbb,0xaa,0xaa,0xff,0xaa,0xff,0x00,0xaa,0xff,0x55,0xaa,0xff,0xaa,
0xcc,0x00,0xcc,0xcc,0x44,0x00,0xcc,0x44,0x44,0xcc,0x44,0x88,0xcc,0x44,0xcc,0xcc,
0x88,0x00,0xcc,0x88,0x44,0xcc,0x88,0x88,0xcc,0x88,0xcc,0xcc,0xcc,0x00,0xcc,0xcc,
0x44,0xcc,0xcc,0x88,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0xcc,0x00,0x44,0xcc,0x00,0x88,
0xdd,0x00,0x93,0xdd,0x00,0xdd,0xdd,0x49,0x00,0xdd,0x49,0x49,0xdd,0x49,0x93,0xdd,
0x49,0xdd,0xdd,0x93,0x00,0xdd,0x93,0x49,0xdd,0x93,0x93,0xdd,0x93,0xdd,0xdd,0xdd,
0x00,0xdd,0xdd,0x49,0xdd,0xdd,0x93,0xdd,0xdd,0xdd,0xdd,0x00,0x00,0xdd,0x00,0x49,
0xee,0x00,0x4f,0xee,0x00,0x9e,0xee,0x00,0xee,0xee,0x4f,0x00,0xee,0x4f,0x4f,0xee,
0x4f,0x9e,0xee,0x4f,0xee,0xee,0x9e,0x00,0xee,0x9e,0x4f,0xee,0x9e,0x9e,0xee,0x9e,
0xee,0xee,0xee,0x00,0xee,0xee,0x4f,0xee,0xee,0x9e,0xee,0xee,0xee,0xee,0x00,0x00,
0xff,0x00,0x00,0xff,0x00,0x55,0xff,0x00,0xaa,0xff,0x00,0xff,0xff,0x55,0x00,0xff,
0x55,0x55,0xff,0x55,0xaa,0xff,0x55,0xff,0xff,0xaa,0x00,0xff,0xaa,0x55,0xff,0xaa,
0xaa,0xff,0xaa,0xff,0xff,0xff,0x00,0xff,0xff,0x55,0xff,0xff,0xaa,0xff,0xff,0xff,
},
/* rgb2cmap */ {
0x00,0x00,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x04,0x04,0x22,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x11,0x22,0x22,0x22,0x33,0x33,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
0x04,0x22,0x22,0x33,0x33,0x33,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
0x04,0x04,0x33,0x33,0x33,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
0x15,0x15,0x33,0x33,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
0x4f,0x4f,0x22,0x40,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
0x4f,0x22,0x22,0x22,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
0x22,0x22,0x22,0x33,0x33,0x33,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
0x43,0x22,0x33,0x33,0x33,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x46,0x57,0x68,
0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68,
0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79,
0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x4a,0x5b,0x6c,
0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c,
0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x6c,0x7d,
0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x5f,
0x5c,0x5c,0x5c,0x4c,0x5d,0x5d,0x5d,0x4d,0x4d,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60,
0x5c,0x5c,0x5c,0x5d,0x5d,0x6e,0x6e,0x5e,0x5e,0x5e,0x6f,0x6f,0x5f,0x5f,0x60,0x60,
0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71,
0x4f,0x4f,0x40,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
0x4f,0x4f,0x22,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
0x43,0x22,0x33,0x33,0x33,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68,
0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79,
0x47,0x47,0x47,0x48,0x48,0x48,0x59,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c,
0x58,0x58,0x58,0x48,0x59,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x7d,0x7d,
0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x7d,
0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5d,0x4d,0x5e,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60,
0x6d,0x6d,0x6d,0x5d,0x6e,0x6e,0x6e,0x5e,0x5e,0x6f,0x6f,0x70,0x5f,0x5f,0x60,0x60,
0x7e,0x7e,0x7e,0x6e,0x6e,0x7f,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x70,0x60,0x60,0x71,
0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
0x50,0x50,0x33,0x33,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79,
0x47,0x47,0x47,0x48,0x48,0x48,0x66,0x49,0x49,0x49,0x78,0x78,0x4a,0x4a,0x5b,0x79,
0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
0x69,0x69,0x69,0x59,0x6a,0x6a,0x6a,0x7b,0x5a,0x6b,0x6b,0x6b,0x7c,0x6c,0x6c,0x7d,
0x7a,0x7a,0x7a,0x4c,0x4c,0x7b,0x7b,0x7b,0x4d,0x6b,0x6b,0x7c,0x7c,0x4e,0x7d,0x7d,
0x4b,0x4b,0x4b,0x4c,0x4c,0x7b,0x7b,0x4d,0x4d,0x5e,0x7c,0x7c,0x4e,0x5f,0x5f,0x7d,
0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x6e,0x4d,0x5e,0x5e,0x6f,0x4e,0x5f,0x5f,0x60,0x60,
0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x6e,0x5e,0x6f,0x6f,0x6f,0x70,0x5f,0x60,0x60,0x71,
0x7e,0x7e,0x7e,0x6e,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71,
0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79,
0x65,0x65,0x65,0x55,0x55,0x66,0x66,0x66,0x77,0x67,0x78,0x78,0x78,0x78,0x79,0x79,
0x65,0x65,0x65,0x48,0x48,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x5b,0x79,0x79,
0x76,0x76,0x76,0x48,0x59,0x59,0x77,0x77,0x77,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x77,0x5a,0x5a,0x6b,0x6b,0x5b,0x6c,0x6c,0x7d,
0x69,0x69,0x69,0x6a,0x6a,0x6a,0x7b,0x7b,0x5a,0x6b,0x6b,0x7c,0x7c,0x6c,0x7d,0x7d,
0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x6b,0x7c,0x7c,0x7c,0x7c,0x7d,0x7d,
0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x5e,0x7c,0x7c,0x7c,0x5f,0x5f,0x7d,
0x6d,0x6d,0x6d,0x5d,0x5d,0x6e,0x7b,0x5e,0x5e,0x6f,0x6f,0x7c,0x5f,0x5f,0x60,0x60,
0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71,
0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71,
0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
0x72,0x72,0x72,0x83,0x83,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x84,0x85,0x85,0x85,0x96,0x79,
0x82,0x82,0x82,0x83,0x83,0x83,0x66,0x84,0x84,0x84,0x67,0x85,0x85,0x85,0x96,0x79,
0x65,0x65,0x65,0x83,0x83,0x66,0x66,0x66,0x84,0x84,0x78,0x78,0x85,0x85,0x96,0x79,
0x65,0x65,0x65,0x83,0x66,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x96,0x79,0x79,
0x76,0x76,0x76,0x87,0x87,0x66,0x77,0x77,0x77,0x88,0x78,0x89,0x89,0x89,0x89,0x79,
0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a,
0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x6b,0x89,0x89,0x9a,0x9a,0x7d,
0x7a,0x7a,0x7a,0x87,0x6a,0x7b,0x7b,0x7b,0x88,0x6b,0x6b,0x7c,0x7c,0x9a,0x7d,0x7d,
0x8a,0x8a,0x8a,0x8b,0x8b,0x7b,0x7b,0x8c,0x8c,0x8c,0x7c,0x7c,0x8d,0x8d,0x7d,0x7d,
0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x7b,0x8c,0x8c,0x8c,0x7c,0x8d,0x8d,0x8d,0x9e,0x9e,
0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0x9e,
0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0x7f,0x8c,0x9d,0x9d,0x70,0x70,0x9e,0x9e,0x9e,0x71,
0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x9d,0x70,0x70,0x70,0x9e,0x9e,0x71,0x71,
0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
0x82,0x82,0x82,0x83,0x83,0x83,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x95,0x85,0x85,0x85,0x96,0xa7,
0x82,0x82,0x82,0x83,0x83,0x83,0x94,0x84,0x84,0x84,0x95,0x85,0x85,0x96,0x96,0xa7,
0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
0x76,0x76,0x76,0x83,0x94,0x94,0x77,0x77,0x77,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a,
0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xab,
0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab,
0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0xab,0xbc,
0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x9d,0x8d,0x8d,0x8d,0x9e,0x9e,
0x9b,0x9b,0x9b,0x8b,0x9c,0x9c,0x9c,0x8c,0x9d,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xaf,
0x9b,0x9b,0x9b,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0x9d,0xae,0xae,0x9e,0x9e,0xaf,0xaf,
0xac,0xac,0xac,0xad,0xad,0xad,0xad,0x9d,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xaf,
0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
0x9f,0x9f,0x9f,0x83,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0x96,0xa7,
0x93,0x93,0x93,0x83,0x94,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x77,0x95,0x95,0xa6,0xa6,0x96,0xa7,0xa7,0xb8,
0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xb8,
0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab,
0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc,
0x8a,0x8a,0x8a,0x8b,0x8b,0xa9,0xa9,0x8c,0x8c,0x8c,0xaa,0x8d,0x8d,0x8d,0xab,0xbc,
0x8a,0x8a,0x8a,0x8b,0x8b,0x9c,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xbc,
0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0xad,0x9d,0x9d,0x9d,0xae,0x8d,0x9e,0x9e,0xaf,0xaf,
0xac,0xac,0xac,0x9c,0xad,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0xaf,0xaf,0xaf,
0xbd,0xbd,0xbd,0xad,0xad,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xbf,0xaf,0xaf,0xb0,
0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
0xa4,0xa4,0xa4,0x94,0xa5,0xa5,0xa5,0xb6,0x95,0xa6,0xa6,0xa6,0xb7,0xa7,0xa7,0xb8,
0xa4,0xa4,0xa4,0xa5,0xa5,0xa5,0xb6,0xb6,0x95,0xa6,0xa6,0xb7,0xb7,0xa7,0xb8,0xb8,
0xb5,0xb5,0xb5,0x87,0x87,0xb6,0xb6,0xb6,0x88,0x99,0xa6,0xb7,0xb7,0x9a,0xb8,0xb8,
0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc,
0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xa9,0xa9,0x99,0xaa,0xaa,0xaa,0xbb,0xab,0xab,0xbc,
0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0x8c,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc,
0xb9,0xb9,0xb9,0x9c,0x9c,0xba,0xba,0xba,0x9d,0x9d,0xbb,0xbb,0xbb,0x9e,0x9e,0xbc,
0xac,0xac,0xac,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0x9e,0xaf,0xaf,
0xac,0xac,0xac,0xad,0xad,0xad,0xbe,0xbe,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xb0,
0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xae,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0,
0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
0xb1,0xb1,0xb1,0xc2,0xc2,0xb2,0xb2,0xc3,0xc3,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xa5,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xa7,0xb8,
0xc1,0xc1,0xc1,0xc2,0xc2,0xa5,0xb6,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xb8,0xb8,
0xb5,0xb5,0xb5,0xc2,0xa5,0xb6,0xb6,0xb6,0xc3,0xa6,0xa6,0xb7,0xb7,0xc4,0xb8,0xb8,
0xb5,0xb5,0xb5,0xa5,0xb6,0xb6,0xb6,0xb6,0xc3,0xa6,0xb7,0xb7,0xb7,0xb7,0xb8,0xb8,
0xc5,0xc5,0xc5,0xc6,0xc6,0xb6,0xb6,0xc7,0xc7,0xc7,0xb7,0xb7,0xc8,0xc8,0xb8,0xb8,
0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xaa,0xc8,0xc8,0xc8,0xab,0xbc,
0xa8,0xa8,0xa8,0xc6,0xc6,0xa9,0xa9,0xc7,0xc7,0xaa,0xaa,0xaa,0xc8,0xc8,0xab,0xbc,
0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0xaa,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc,
0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xba,0xcb,0xaa,0xbb,0xbb,0xbb,0xcc,0xbc,0xbc,
0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc,
0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xae,0xcc,0xcc,0xcc,0xaf,0xaf,
0xbd,0xbd,0xbd,0xad,0xbe,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xcc,0xaf,0xaf,0xb0,
0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xbf,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0,
0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb2,0xc3,0xc3,0xc3,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xd5,
0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb6,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xb8,
0xc1,0xc1,0xc1,0xc2,0xc2,0xb6,0xb6,0xc3,0xc3,0xd4,0xb7,0xb7,0xc4,0xd5,0xd5,0xb8,
0xb5,0xb5,0xb5,0xc2,0xb6,0xb6,0xb6,0xb6,0xc3,0xd4,0xb7,0xb7,0xb7,0xd5,0xd5,0xb8,
0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xb6,0xc7,0xc7,0xc7,0xb7,0xc8,0xc8,0xc8,0xd9,0xd9,
0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xd8,0xc8,0xc8,0xc8,0xd9,0xd9,
0xc5,0xc5,0xc5,0xc6,0xc6,0xd7,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xbc,
0xb9,0xb9,0xb9,0xd7,0xd7,0xba,0xba,0xba,0xd8,0xd8,0xbb,0xbb,0xbb,0xd9,0xd9,0xbc,
0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc,
0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xbb,0xcc,0xcc,0xcc,0xdd,0xdd,
0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd,
0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xb0,
0xbd,0xbd,0xbd,0xdb,0xbe,0xbe,0xbe,0xdc,0xdc,0xbf,0xbf,0xbf,0xdd,0xdd,0xb0,0xb0,
0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xc3,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
0xd2,0xd2,0xd2,0xc2,0xd3,0xd3,0xd3,0xc3,0xc3,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6,
0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xd3,0xc3,0xd4,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6,
0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xe4,0xc3,0xd4,0xd4,0xe5,0xc4,0xd5,0xd5,0xe6,0xe6,
0xe3,0xe3,0xe3,0xd3,0xd3,0xe4,0xb6,0xd4,0xd4,0xe5,0xe5,0xb7,0xd5,0xd5,0xe6,0xe6,
0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xd9,
0xd6,0xd6,0xd6,0xc6,0xd7,0xd7,0xd7,0xc7,0xd8,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xea,
0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xe8,0xd8,0xd8,0xd8,0xe9,0xc8,0xd9,0xd9,0xea,0xea,
0xe7,0xe7,0xe7,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xd9,0xea,0xea,
0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xe9,0xcc,0xcc,0xcc,0xea,0xea,
0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd,
0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee,
0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee,
0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
0xd2,0xd2,0xd2,0xd3,0xd3,0xe4,0xe4,0xd4,0xd4,0xd4,0xe5,0xe5,0xd5,0xd5,0xe6,0xe6,
0xe3,0xe3,0xe3,0xd3,0xe4,0xe4,0xe4,0xd4,0xd4,0xe5,0xe5,0xf6,0xd5,0xd5,0xe6,0xe6,
0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xe4,0xd4,0xe5,0xe5,0xe5,0xf6,0xd5,0xe6,0xe6,0xf7,
0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7,
0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xf5,0xc7,0xd8,0xd8,0xf6,0xc8,0xd9,0xd9,0xd9,0xf7,
0xd6,0xd6,0xd6,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xd8,0xe9,0xe9,0xd9,0xd9,0xea,0xea,
0xe7,0xe7,0xe7,0xd7,0xe8,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xea,0xea,0xea,
0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xf9,0xf9,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xfb,
0xf8,0xf8,0xf8,0xe8,0xf9,0xf9,0xf9,0xcb,0xe9,0xe9,0xfa,0xfa,0xcc,0xea,0xea,0xfb,
0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee,
0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee,
0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff,
0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7,
0xf4,0xf4,0xf4,0xe4,0xe4,0xf5,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xf6,0xe6,0xe6,0xf7,
0xf4,0xf4,0xf4,0xe4,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7,
0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7,
0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xd8,0xf6,0xf6,0xf6,0xd9,0xd9,0xf7,0xf7,
0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xe8,0xd8,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xea,
0xf8,0xf8,0xf8,0xe8,0xe8,0xf9,0xf9,0xf9,0xe9,0xe9,0xfa,0xfa,0xfa,0xea,0xea,0xfb,
0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xe9,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb,
0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb,
0xf8,0xf8,0xf8,0xdb,0xf9,0xf9,0xf9,0xdc,0xdc,0xfa,0xfa,0xfa,0xdd,0xdd,0xee,0xfb,
0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff,
0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xed,0xfe,0xfe,0xfe,0xfe,0xee,0xff,0xff,
}
};
Memcmap *memdefcmap = &def;
void _memmkcmap(void){}

96
libmemdraw/cread.c Normal file
View File

@@ -0,0 +1,96 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
Memimage*
creadmemimage(int fd)
{
char hdr[5*12+1];
Rectangle r;
int m, nb, miny, maxy, new, ldepth, ncblock;
uchar *buf;
Memimage *i;
ulong chan;
if(readn(fd, hdr, 5*12) != 5*12){
werrstr("readmemimage: short header (2)");
return nil;
}
/*
* distinguish new channel descriptor from old ldepth.
* channel descriptors have letters as well as numbers,
* while ldepths are a single digit formatted as %-11d.
*/
new = 0;
for(m=0; m<10; m++){
if(hdr[m] != ' '){
new = 1;
break;
}
}
if(hdr[11] != ' '){
werrstr("creadimage: bad format");
return nil;
}
if(new){
hdr[11] = '\0';
if((chan = strtochan(hdr)) == 0){
werrstr("creadimage: bad channel string %s", hdr);
return nil;
}
}else{
ldepth = ((int)hdr[10])-'0';
if(ldepth<0 || ldepth>3){
werrstr("creadimage: bad ldepth %d", ldepth);
return nil;
}
chan = drawld2chan[ldepth];
}
r.min.x=atoi(hdr+1*12);
r.min.y=atoi(hdr+2*12);
r.max.x=atoi(hdr+3*12);
r.max.y=atoi(hdr+4*12);
if(r.min.x>r.max.x || r.min.y>r.max.y){
werrstr("creadimage: bad rectangle");
return nil;
}
i = allocmemimage(r, chan);
if(i == nil)
return nil;
ncblock = _compblocksize(r, i->depth);
buf = malloc(ncblock);
if(buf == nil)
goto Errout;
miny = r.min.y;
while(miny != r.max.y){
if(readn(fd, hdr, 2*12) != 2*12){
Shortread:
werrstr("readmemimage: short read");
Errout:
freememimage(i);
free(buf);
return nil;
}
maxy = atoi(hdr+0*12);
nb = atoi(hdr+1*12);
if(maxy<=miny || r.max.y<maxy){
werrstr("readimage: bad maxy %d", maxy);
goto Errout;
}
if(nb<=0 || ncblock<nb){
werrstr("readimage: bad count %d", nb);
goto Errout;
}
if(readn(fd, buf, nb)!=nb)
goto Shortread;
if(!new) /* old image: flip the data bits */
_twiddlecompressed(buf, nb);
cloadmemimage(i, Rect(r.min.x, miny, r.max.x, maxy), buf, nb);
miny = maxy;
}
free(buf);
return i;
}

68
libmemdraw/defont.c Normal file
View File

@@ -0,0 +1,68 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
Memsubfont*
getmemdefont(void)
{
char *hdr, *p;
int n;
Fontchar *fc;
Memsubfont *f;
int ld;
Rectangle r;
Memdata *md;
Memimage *i;
/*
* make sure data is word-aligned. this is true with Plan 9 compilers
* but not in general. the byte order is right because the data is
* declared as char*, not ulong*.
*/
p = (char*)defontdata;
n = (ulong)p & 3;
if(n != 0){
memmove(p+(4-n), p, sizeofdefont-n);
p += 4-n;
}
ld = atoi(p+0*12);
r.min.x = atoi(p+1*12);
r.min.y = atoi(p+2*12);
r.max.x = atoi(p+3*12);
r.max.y = atoi(p+4*12);
md = mallocz(sizeof(Memdata), 1);
if(md == nil)
return nil;
p += 5*12;
md->base = nil; /* so freememimage doesn't free p */
md->bdata = (uchar*)p; /* ick */
md->ref = 1;
md->allocd = 1; /* so freememimage does free md */
i = allocmemimaged(r, drawld2chan[ld], md, nil);
if(i == nil){
free(md);
return nil;
}
hdr = p+Dy(r)*i->width*sizeof(ulong);
n = atoi(hdr);
p = hdr+3*12;
fc = malloc(sizeof(Fontchar)*(n+1));
if(fc == 0){
freememimage(i);
return 0;
}
_unpackinfo(fc, (uchar*)p, n);
f = allocmemsubfont("*default*", n, atoi(hdr+12), atoi(hdr+24), fc, i);
if(f == 0){
freememimage(i);
free(fc);
return 0;
}
return f;
}

2499
libmemdraw/draw.c Normal file

File diff suppressed because it is too large Load Diff

1004
libmemdraw/drawtest.c Normal file

File diff suppressed because it is too large Load Diff

248
libmemdraw/ellipse.c Normal file
View File

@@ -0,0 +1,248 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
/*
* ellipse(dst, c, a, b, t, src, sp)
* draws an ellipse centered at c with semiaxes a,b>=0
* and semithickness t>=0, or filled if t<0. point sp
* in src maps to c in dst
*
* very thick skinny ellipses are brushed with circles (slow)
* others are approximated by filling between 2 ellipses
* criterion for very thick when b<a: t/b > 0.5*x/(1-x)
* where x = b/a
*/
typedef struct Param Param;
typedef struct State State;
static void bellipse(int, State*, Param*);
static void erect(int, int, int, int, Param*);
static void eline(int, int, int, int, Param*);
struct Param {
Memimage *dst;
Memimage *src;
Point c;
int t;
Point sp;
Memimage *disc;
int op;
};
/*
* denote residual error by e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2
* e(x,y) = 0 on ellipse, e(x,y) < 0 inside, e(x,y) > 0 outside
*/
struct State {
int a;
int x;
vlong a2; /* a^2 */
vlong b2; /* b^2 */
vlong b2x; /* b^2 * x */
vlong a2y; /* a^2 * y */
vlong c1;
vlong c2; /* test criteria */
vlong ee; /* ee = e(x+1/2,y-1/2) - (a^2+b^2)/4 */
vlong dxe;
vlong dye;
vlong d2xe;
vlong d2ye;
};
static
State*
newstate(State *s, int a, int b)
{
s->x = 0;
s->a = a;
s->a2 = (vlong)(a*a);
s->b2 = (vlong)(b*b);
s->b2x = (vlong)0;
s->a2y = s->a2*(vlong)b;
s->c1 = -((s->a2>>2) + (vlong)(a&1) + s->b2);
s->c2 = -((s->b2>>2) + (vlong)(b&1));
s->ee = -s->a2y;
s->dxe = (vlong)0;
s->dye = s->ee<<1;
s->d2xe = s->b2<<1;
s->d2ye = s->a2<<1;
return s;
}
/*
* return x coord of rightmost pixel on next scan line
*/
static
int
step(State *s)
{
while(s->x < s->a) {
if(s->ee+s->b2x <= s->c1 || /* e(x+1,y-1/2) <= 0 */
s->ee+s->a2y <= s->c2) { /* e(x+1/2,y) <= 0 (rare) */
s->dxe += s->d2xe;
s->ee += s->dxe;
s->b2x += s->b2;
s->x++;
continue;
}
s->dye += s->d2ye;
s->ee += s->dye;
s->a2y -= s->a2;
if(s->ee-s->a2y <= s->c2) { /* e(x+1/2,y-1) <= 0 */
s->dxe += s->d2xe;
s->ee += s->dxe;
s->b2x += s->b2;
return s->x++;
}
break;
}
return s->x;
}
void
memellipse(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int op)
{
State in, out;
int y, inb, inx, outx, u;
Param p;
if(a < 0)
a = -a;
if(b < 0)
b = -b;
p.dst = dst;
p.src = src;
p.c = c;
p.t = t;
p.sp = subpt(sp, c);
p.disc = nil;
p.op = op;
u = (t<<1)*(a-b);
if(b<a && u>b*b || a<b && -u>a*a) {
/* if(b<a&&(t<<1)>b*b/a || a<b&&(t<<1)>a*a/b) # very thick */
bellipse(b, newstate(&in, a, b), &p);
return;
}
if(t < 0) {
inb = -1;
newstate(&out, a, y = b);
} else {
inb = b - t;
newstate(&out, a+t, y = b+t);
}
if(t > 0)
newstate(&in, a-t, inb);
inx = 0;
for( ; y>=0; y--) {
outx = step(&out);
if(y > inb) {
erect(-outx, y, outx, y, &p);
if(y != 0)
erect(-outx, -y, outx, -y, &p);
continue;
}
if(t > 0) {
inx = step(&in);
if(y == inb)
inx = 0;
} else if(inx > outx)
inx = outx;
erect(inx, y, outx, y, &p);
if(y != 0)
erect(inx, -y, outx, -y, &p);
erect(-outx, y, -inx, y, &p);
if(y != 0)
erect(-outx, -y, -inx, -y, &p);
inx = outx + 1;
}
}
static Point p00 = {0, 0};
/*
* a brushed ellipse
*/
static
void
bellipse(int y, State *s, Param *p)
{
int t, ox, oy, x, nx;
t = p->t;
p->disc = allocmemimage(Rect(-t,-t,t+1,t+1), GREY1);
if(p->disc == nil)
return;
memfillcolor(p->disc, DTransparent);
memellipse(p->disc, p00, t, t, -1, memopaque, p00, p->op);
oy = y;
ox = 0;
nx = x = step(s);
do {
while(nx==x && y-->0)
nx = step(s);
y++;
eline(-x,-oy,-ox, -y, p);
eline(ox,-oy, x, -y, p);
eline(-x, y,-ox, oy, p);
eline(ox, y, x, oy, p);
ox = x+1;
x = nx;
y--;
oy = y;
} while(oy > 0);
}
/*
* a rectangle with closed (not half-open) coordinates expressed
* relative to the center of the ellipse
*/
static
void
erect(int x0, int y0, int x1, int y1, Param *p)
{
Rectangle r;
/* print("R %d,%d %d,%d\n", x0, y0, x1, y1); /**/
r = Rect(p->c.x+x0, p->c.y+y0, p->c.x+x1+1, p->c.y+y1+1);
memdraw(p->dst, r, p->src, addpt(p->sp, r.min), memopaque, p00, p->op);
}
/*
* a brushed point similarly specified
*/
static
void
epoint(int x, int y, Param *p)
{
Point p0;
Rectangle r;
/* print("P%d %d,%d\n", p->t, x, y); /**/
p0 = Pt(p->c.x+x, p->c.y+y);
r = Rpt(addpt(p0, p->disc->r.min), addpt(p0, p->disc->r.max));
memdraw(p->dst, r, p->src, addpt(p->sp, r.min), p->disc, p->disc->r.min, p->op);
}
/*
* a brushed horizontal or vertical line similarly specified
*/
static
void
eline(int x0, int y0, int x1, int y1, Param *p)
{
/* print("L%d %d,%d %d,%d\n", p->t, x0, y0, x1, y1); /**/
if(x1 > x0+1)
erect(x0+1, y0-p->t, x1-1, y1+p->t, p);
else if(y1 > y0+1)
erect(x0-p->t, y0+1, x1+p->t, y1-1, p);
epoint(x0, y0, p);
if(x1-x0 || y1-y0)
epoint(x1, y1, p);
}

523
libmemdraw/fillpoly.c Normal file
View File

@@ -0,0 +1,523 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
typedef struct Seg Seg;
struct Seg
{
Point p0;
Point p1;
long num;
long den;
long dz;
long dzrem;
long z;
long zerr;
long d;
};
static void zsort(Seg **seg, Seg **ep);
static int ycompare(void*, void*);
static int xcompare(void*, void*);
static int zcompare(void*, void*);
static void xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int, int, int);
static void yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int);
static void
fillcolor(Memimage *dst, int left, int right, int y, Memimage *src, Point p)
{
int srcval;
USED(src);
srcval = p.x;
p.x = left;
p.y = y;
memset(byteaddr(dst, p), srcval, right-left);
}
static void
fillline(Memimage *dst, int left, int right, int y, Memimage *src, Point p, int op)
{
Rectangle r;
r.min.x = left;
r.min.y = y;
r.max.x = right;
r.max.y = y+1;
p.x += left;
p.y += y;
memdraw(dst, r, src, p, memopaque, p, op);
}
static void
fillpoint(Memimage *dst, int x, int y, Memimage *src, Point p, int op)
{
Rectangle r;
r.min.x = x;
r.min.y = y;
r.max.x = x+1;
r.max.y = y+1;
p.x += x;
p.y += y;
memdraw(dst, r, src, p, memopaque, p, op);
}
void
memfillpoly(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int op)
{
_memfillpolysc(dst, vert, nvert, w, src, sp, 0, 0, 0, op);
}
void
_memfillpolysc(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
{
Seg **seg, *segtab;
Point p0;
int i;
if(nvert == 0)
return;
seg = malloc((nvert+2)*sizeof(Seg*));
if(seg == nil)
return;
segtab = malloc((nvert+1)*sizeof(Seg));
if(segtab == nil) {
free(seg);
return;
}
sp.x = (sp.x - vert[0].x) >> fixshift;
sp.y = (sp.y - vert[0].y) >> fixshift;
p0 = vert[nvert-1];
if(!fixshift) {
p0.x <<= 1;
p0.y <<= 1;
}
for(i = 0; i < nvert; i++) {
segtab[i].p0 = p0;
p0 = vert[i];
if(!fixshift) {
p0.x <<= 1;
p0.y <<= 1;
}
segtab[i].p1 = p0;
segtab[i].d = 1;
}
if(!fixshift)
fixshift = 1;
xscan(dst, seg, segtab, nvert, w, src, sp, detail, fixshift, clipped, op);
if(detail)
yscan(dst, seg, segtab, nvert, w, src, sp, fixshift, op);
free(seg);
free(segtab);
}
static long
mod(long x, long y)
{
long z;
z = x%y;
if((long)(((ulong)z)^((ulong)y)) > 0 || z == 0)
return z;
return z + y;
}
static long
sdiv(long x, long y)
{
if((long)(((ulong)x)^((ulong)y)) >= 0 || x == 0)
return x/y;
return (x+((y>>30)|1))/y-1;
}
static long
smuldivmod(long x, long y, long z, long *mod)
{
vlong vx;
if(x == 0 || y == 0){
*mod = 0;
return 0;
}
vx = x;
vx *= y;
*mod = vx % z;
if(*mod < 0)
*mod += z; /* z is always >0 */
if((vx < 0) == (z < 0))
return vx/z;
return -((-vx)/z);
}
static void
xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
{
long y, maxy, x, x2, xerr, xden, onehalf;
Seg **ep, **next, **p, **q, *s;
long n, i, iy, cnt, ix, ix2, minx, maxx;
Point pt;
void (*fill)(Memimage*, int, int, int, Memimage*, Point, int);
fill = fillline;
/*
* This can only work on 8-bit destinations, since fillcolor is
* just using memset on sp.x.
*
* I'd rather not even enable it then, since then if the general
* code is too slow, someone will come up with a better improvement
* than this sleazy hack. -rsc
*
if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) {
fill = fillcolor;
sp.x = membyteval(src);
}
*
*/
USED(clipped);
for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
*p = s;
if(s->p0.y == s->p1.y)
continue;
if(s->p0.y > s->p1.y) {
pt = s->p0;
s->p0 = s->p1;
s->p1 = pt;
s->d = -s->d;
}
s->num = s->p1.x - s->p0.x;
s->den = s->p1.y - s->p0.y;
s->dz = sdiv(s->num, s->den) << fixshift;
s->dzrem = mod(s->num, s->den) << fixshift;
s->dz += sdiv(s->dzrem, s->den);
s->dzrem = mod(s->dzrem, s->den);
p++;
}
n = p-seg;
if(n == 0)
return;
*p = 0;
qsort(seg, p-seg , sizeof(Seg*), ycompare);
onehalf = 0;
if(fixshift)
onehalf = 1 << (fixshift-1);
minx = dst->clipr.min.x;
maxx = dst->clipr.max.x;
y = seg[0]->p0.y;
if(y < (dst->clipr.min.y << fixshift))
y = dst->clipr.min.y << fixshift;
iy = (y + onehalf) >> fixshift;
y = (iy << fixshift) + onehalf;
maxy = dst->clipr.max.y << fixshift;
ep = next = seg;
while(y<maxy) {
for(q = p = seg; p < ep; p++) {
s = *p;
if(s->p1.y < y)
continue;
s->z += s->dz;
s->zerr += s->dzrem;
if(s->zerr >= s->den) {
s->z++;
s->zerr -= s->den;
if(s->zerr < 0 || s->zerr >= s->den)
print("bad ratzerr1: %ld den %ld dzrem %ld\n", s->zerr, s->den, s->dzrem);
}
*q++ = s;
}
for(p = next; *p; p++) {
s = *p;
if(s->p0.y >= y)
break;
if(s->p1.y < y)
continue;
s->z = s->p0.x;
s->z += smuldivmod(y - s->p0.y, s->num, s->den, &s->zerr);
if(s->zerr < 0 || s->zerr >= s->den)
print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
*q++ = s;
}
ep = q;
next = p;
if(ep == seg) {
if(*next == 0)
break;
iy = (next[0]->p0.y + onehalf) >> fixshift;
y = (iy << fixshift) + onehalf;
continue;
}
zsort(seg, ep);
for(p = seg; p < ep; p++) {
cnt = 0;
x = p[0]->z;
xerr = p[0]->zerr;
xden = p[0]->den;
ix = (x + onehalf) >> fixshift;
if(ix >= maxx)
break;
if(ix < minx)
ix = minx;
cnt += p[0]->d;
p++;
for(;;) {
if(p == ep) {
print("xscan: fill to infinity");
return;
}
cnt += p[0]->d;
if((cnt&wind) == 0)
break;
p++;
}
x2 = p[0]->z;
ix2 = (x2 + onehalf) >> fixshift;
if(ix2 <= minx)
continue;
if(ix2 > maxx)
ix2 = maxx;
if(ix == ix2 && detail) {
if(xerr*p[0]->den + p[0]->zerr*xden > p[0]->den*xden)
x++;
ix = (x + x2) >> (fixshift+1);
ix2 = ix+1;
}
(*fill)(dst, ix, ix2, iy, src, sp, op);
}
y += (1<<fixshift);
iy++;
}
}
static void
yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int fixshift, int op)
{
long x, maxx, y, y2, yerr, yden, onehalf;
Seg **ep, **next, **p, **q, *s;
int n, i, ix, cnt, iy, iy2, miny, maxy;
Point pt;
for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
*p = s;
if(s->p0.x == s->p1.x)
continue;
if(s->p0.x > s->p1.x) {
pt = s->p0;
s->p0 = s->p1;
s->p1 = pt;
s->d = -s->d;
}
s->num = s->p1.y - s->p0.y;
s->den = s->p1.x - s->p0.x;
s->dz = sdiv(s->num, s->den) << fixshift;
s->dzrem = mod(s->num, s->den) << fixshift;
s->dz += sdiv(s->dzrem, s->den);
s->dzrem = mod(s->dzrem, s->den);
p++;
}
n = p-seg;
if(n == 0)
return;
*p = 0;
qsort(seg, n , sizeof(Seg*), xcompare);
onehalf = 0;
if(fixshift)
onehalf = 1 << (fixshift-1);
miny = dst->clipr.min.y;
maxy = dst->clipr.max.y;
x = seg[0]->p0.x;
if(x < (dst->clipr.min.x << fixshift))
x = dst->clipr.min.x << fixshift;
ix = (x + onehalf) >> fixshift;
x = (ix << fixshift) + onehalf;
maxx = dst->clipr.max.x << fixshift;
ep = next = seg;
while(x<maxx) {
for(q = p = seg; p < ep; p++) {
s = *p;
if(s->p1.x < x)
continue;
s->z += s->dz;
s->zerr += s->dzrem;
if(s->zerr >= s->den) {
s->z++;
s->zerr -= s->den;
if(s->zerr < 0 || s->zerr >= s->den)
print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
}
*q++ = s;
}
for(p = next; *p; p++) {
s = *p;
if(s->p0.x >= x)
break;
if(s->p1.x < x)
continue;
s->z = s->p0.y;
s->z += smuldivmod(x - s->p0.x, s->num, s->den, &s->zerr);
if(s->zerr < 0 || s->zerr >= s->den)
print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
*q++ = s;
}
ep = q;
next = p;
if(ep == seg) {
if(*next == 0)
break;
ix = (next[0]->p0.x + onehalf) >> fixshift;
x = (ix << fixshift) + onehalf;
continue;
}
zsort(seg, ep);
for(p = seg; p < ep; p++) {
cnt = 0;
y = p[0]->z;
yerr = p[0]->zerr;
yden = p[0]->den;
iy = (y + onehalf) >> fixshift;
if(iy >= maxy)
break;
if(iy < miny)
iy = miny;
cnt += p[0]->d;
p++;
for(;;) {
if(p == ep) {
print("yscan: fill to infinity");
return;
}
cnt += p[0]->d;
if((cnt&wind) == 0)
break;
p++;
}
y2 = p[0]->z;
iy2 = (y2 + onehalf) >> fixshift;
if(iy2 <= miny)
continue;
if(iy2 > maxy)
iy2 = maxy;
if(iy == iy2) {
if(yerr*p[0]->den + p[0]->zerr*yden > p[0]->den*yden)
y++;
iy = (y + y2) >> (fixshift+1);
fillpoint(dst, ix, iy, src, sp, op);
}
}
x += (1<<fixshift);
ix++;
}
}
static void
zsort(Seg **seg, Seg **ep)
{
int done;
Seg **q, **p, *s;
if(ep-seg < 20) {
/* bubble sort by z - they should be almost sorted already */
q = ep;
do {
done = 1;
q--;
for(p = seg; p < q; p++) {
if(p[0]->z > p[1]->z) {
s = p[0];
p[0] = p[1];
p[1] = s;
done = 0;
}
}
} while(!done);
} else {
q = ep-1;
for(p = seg; p < q; p++) {
if(p[0]->z > p[1]->z) {
qsort(seg, ep-seg, sizeof(Seg*), zcompare);
break;
}
}
}
}
static int
ycompare(void *a, void *b)
{
Seg **s0, **s1;
long y0, y1;
s0 = a;
s1 = b;
y0 = (*s0)->p0.y;
y1 = (*s1)->p0.y;
if(y0 < y1)
return -1;
if(y0 == y1)
return 0;
return 1;
}
static int
xcompare(void *a, void *b)
{
Seg **s0, **s1;
long x0, x1;
s0 = a;
s1 = b;
x0 = (*s0)->p0.x;
x1 = (*s1)->p0.x;
if(x0 < x1)
return -1;
if(x0 == x1)
return 0;
return 1;
}
static int
zcompare(void *a, void *b)
{
Seg **s0, **s1;
long z0, z1;
s0 = a;
s1 = b;
z0 = (*s0)->z;
z1 = (*s1)->z;
if(z0 < z1)
return -1;
if(z0 == z1)
return 0;
return 1;
}

12
libmemdraw/hwdraw.c Normal file
View File

@@ -0,0 +1,12 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int
hwdraw(Memdrawparam *p)
{
USED(p);
return 0; /* could not satisfy request */
}

12
libmemdraw/iprint.c Normal file
View File

@@ -0,0 +1,12 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int
iprint(char *fmt,...)
{
USED(fmt);
return -1;
}

485
libmemdraw/line.c Normal file
View File

@@ -0,0 +1,485 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
enum
{
Arrow1 = 8,
Arrow2 = 10,
Arrow3 = 3,
};
static
int
lmin(int a, int b)
{
if(a < b)
return a;
return b;
}
static
int
lmax(int a, int b)
{
if(a > b)
return a;
return b;
}
#ifdef NOTUSED
/*
* Rather than line clip, we run the Bresenham loop over the full line,
* and clip on each pixel. This is more expensive but means that
* lines look the same regardless of how the windowing has tiled them.
* For speed, we check for clipping outside the loop and make the
* test easy when possible.
*/
static
void
horline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
{
int x, y, dy, deltay, deltax, maxx;
int dd, easy, e, bpp, m, m0;
uchar *d;
deltax = p1.x - p0.x;
deltay = p1.y - p0.y;
dd = dst->width*sizeof(ulong);
dy = 1;
if(deltay < 0){
dd = -dd;
deltay = -deltay;
dy = -1;
}
maxx = lmin(p1.x, clipr.max.x-1);
bpp = dst->depth;
m0 = 0xFF^(0xFF>>bpp);
m = m0 >> (p0.x&(7/dst->depth))*bpp;
easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
e = 2*deltay - deltax;
y = p0.y;
d = byteaddr(dst, p0);
deltay *= 2;
deltax = deltay - 2*deltax;
for(x=p0.x; x<=maxx; x++){
if(easy || (clipr.min.x<=x && clipr.min.y<=y && y<clipr.max.y))
*d ^= (*d^srcval) & m;
if(e > 0){
y += dy;
d += dd;
e += deltax;
}else
e += deltay;
d++;
m >>= bpp;
if(m == 0)
m = m0;
}
}
static
void
verline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
{
int x, y, deltay, deltax, maxy;
int easy, e, bpp, m, m0, dd;
uchar *d;
deltax = p1.x - p0.x;
deltay = p1.y - p0.y;
dd = 1;
if(deltax < 0){
dd = -1;
deltax = -deltax;
}
maxy = lmin(p1.y, clipr.max.y-1);
bpp = dst->depth;
m0 = 0xFF^(0xFF>>bpp);
m = m0 >> (p0.x&(7/dst->depth))*bpp;
easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
e = 2*deltax - deltay;
x = p0.x;
d = byteaddr(dst, p0);
deltax *= 2;
deltay = deltax - 2*deltay;
for(y=p0.y; y<=maxy; y++){
if(easy || (clipr.min.y<=y && clipr.min.x<=x && x<clipr.max.x))
*d ^= (*d^srcval) & m;
if(e > 0){
x += dd;
d += dd;
e += deltay;
}else
e += deltax;
d += dst->width*sizeof(ulong);
m >>= bpp;
if(m == 0)
m = m0;
}
}
static
void
horliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
{
int x, y, sx, sy, deltay, deltax, minx, maxx;
int bpp, m, m0;
uchar *d, *s;
deltax = p1.x - p0.x;
deltay = p1.y - p0.y;
sx = drawreplxy(src->r.min.x, src->r.max.x, p0.x+dsrc.x);
minx = lmax(p0.x, clipr.min.x);
maxx = lmin(p1.x, clipr.max.x-1);
bpp = dst->depth;
m0 = 0xFF^(0xFF>>bpp);
m = m0 >> (minx&(7/dst->depth))*bpp;
for(x=minx; x<=maxx; x++){
y = p0.y + (deltay*(x-p0.x)+deltax/2)/deltax;
if(clipr.min.y<=y && y<clipr.max.y){
d = byteaddr(dst, Pt(x, y));
sy = drawreplxy(src->r.min.y, src->r.max.y, y+dsrc.y);
s = byteaddr(src, Pt(sx, sy));
*d ^= (*d^*s) & m;
}
if(++sx >= src->r.max.x)
sx = src->r.min.x;
m >>= bpp;
if(m == 0)
m = m0;
}
}
static
void
verliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
{
int x, y, sx, sy, deltay, deltax, miny, maxy;
int bpp, m, m0;
uchar *d, *s;
deltax = p1.x - p0.x;
deltay = p1.y - p0.y;
sy = drawreplxy(src->r.min.y, src->r.max.y, p0.y+dsrc.y);
miny = lmax(p0.y, clipr.min.y);
maxy = lmin(p1.y, clipr.max.y-1);
bpp = dst->depth;
m0 = 0xFF^(0xFF>>bpp);
for(y=miny; y<=maxy; y++){
if(deltay == 0) /* degenerate line */
x = p0.x;
else
x = p0.x + (deltax*(y-p0.y)+deltay/2)/deltay;
if(clipr.min.x<=x && x<clipr.max.x){
m = m0 >> (x&(7/dst->depth))*bpp;
d = byteaddr(dst, Pt(x, y));
sx = drawreplxy(src->r.min.x, src->r.max.x, x+dsrc.x);
s = byteaddr(src, Pt(sx, sy));
*d ^= (*d^*s) & m;
}
if(++sy >= src->r.max.y)
sy = src->r.min.y;
}
}
static
void
horline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
{
int x, y, deltay, deltax, minx, maxx;
int bpp, m, m0;
uchar *d, *s;
deltax = p1.x - p0.x;
deltay = p1.y - p0.y;
minx = lmax(p0.x, clipr.min.x);
maxx = lmin(p1.x, clipr.max.x-1);
bpp = dst->depth;
m0 = 0xFF^(0xFF>>bpp);
m = m0 >> (minx&(7/dst->depth))*bpp;
for(x=minx; x<=maxx; x++){
y = p0.y + (deltay*(x-p0.x)+deltay/2)/deltax;
if(clipr.min.y<=y && y<clipr.max.y){
d = byteaddr(dst, Pt(x, y));
s = byteaddr(src, addpt(dsrc, Pt(x, y)));
*d ^= (*d^*s) & m;
}
m >>= bpp;
if(m == 0)
m = m0;
}
}
static
void
verline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
{
int x, y, deltay, deltax, miny, maxy;
int bpp, m, m0;
uchar *d, *s;
deltax = p1.x - p0.x;
deltay = p1.y - p0.y;
miny = lmax(p0.y, clipr.min.y);
maxy = lmin(p1.y, clipr.max.y-1);
bpp = dst->depth;
m0 = 0xFF^(0xFF>>bpp);
for(y=miny; y<=maxy; y++){
if(deltay == 0) /* degenerate line */
x = p0.x;
else
x = p0.x + deltax*(y-p0.y)/deltay;
if(clipr.min.x<=x && x<clipr.max.x){
m = m0 >> (x&(7/dst->depth))*bpp;
d = byteaddr(dst, Pt(x, y));
s = byteaddr(src, addpt(dsrc, Pt(x, y)));
*d ^= (*d^*s) & m;
}
}
}
#endif /* NOTUSED */
static Memimage*
membrush(int radius)
{
static Memimage *brush;
static int brushradius;
if(brush==nil || brushradius!=radius){
freememimage(brush);
brush = allocmemimage(Rect(0, 0, 2*radius+1, 2*radius+1), memopaque->chan);
if(brush != nil){
memfillcolor(brush, DTransparent); /* zeros */
memellipse(brush, Pt(radius, radius), radius, radius, -1, memopaque, Pt(radius, radius), S);
}
brushradius = radius;
}
return brush;
}
static
void
discend(Point p, int radius, Memimage *dst, Memimage *src, Point dsrc, int op)
{
Memimage *disc;
Rectangle r;
disc = membrush(radius);
if(disc != nil){
r.min.x = p.x - radius;
r.min.y = p.y - radius;
r.max.x = p.x + radius+1;
r.max.y = p.y + radius+1;
memdraw(dst, r, src, addpt(r.min, dsrc), disc, Pt(0,0), op);
}
}
static
void
arrowend(Point tip, Point *pp, int end, int sin, int cos, int radius)
{
int x1, x2, x3;
/* before rotation */
if(end == Endarrow){
x1 = Arrow1;
x2 = Arrow2;
x3 = Arrow3;
}else{
x1 = (end>>5) & 0x1FF; /* distance along line from end of line to tip */
x2 = (end>>14) & 0x1FF; /* distance along line from barb to tip */
x3 = (end>>23) & 0x1FF; /* distance perpendicular from edge of line to barb */
}
/* comments follow track of right-facing arrowhead */
pp->x = tip.x+((2*radius+1)*sin/2-x1*cos); /* upper side of shaft */
pp->y = tip.y-((2*radius+1)*cos/2+x1*sin);
pp++;
pp->x = tip.x+((2*radius+2*x3+1)*sin/2-x2*cos); /* upper barb */
pp->y = tip.y-((2*radius+2*x3+1)*cos/2+x2*sin);
pp++;
pp->x = tip.x;
pp->y = tip.y;
pp++;
pp->x = tip.x+(-(2*radius+2*x3+1)*sin/2-x2*cos); /* lower barb */
pp->y = tip.y-(-(2*radius+2*x3+1)*cos/2+x2*sin);
pp++;
pp->x = tip.x+(-(2*radius+1)*sin/2-x1*cos); /* lower side of shaft */
pp->y = tip.y+((2*radius+1)*cos/2-x1*sin);
}
void
_memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
{
/*
* BUG: We should really really pick off purely horizontal and purely
* vertical lines and handle them separately with calls to memimagedraw
* on rectangles.
*/
int hor;
int sin, cos, dx, dy, t;
Rectangle oclipr, r;
Point q, pts[10], *pp, d;
if(radius < 0)
return;
if(rectclip(&clipr, dst->r) == 0)
return;
if(rectclip(&clipr, dst->clipr) == 0)
return;
d = subpt(sp, p0);
if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
return;
if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
return;
/* this means that only verline() handles degenerate lines (p0==p1) */
hor = (abs(p1.x-p0.x) > abs(p1.y-p0.y));
/*
* Clipping is a little peculiar. We can't use Sutherland-Cohen
* clipping because lines are wide. But this is probably just fine:
* we do all math with the original p0 and p1, but clip when deciding
* what pixels to draw. This means the layer code can call this routine,
* using clipr to define the region being written, and get the same set
* of pixels regardless of the dicing.
*/
if((hor && p0.x>p1.x) || (!hor && p0.y>p1.y)){
q = p0;
p0 = p1;
p1 = q;
t = end0;
end0 = end1;
end1 = t;
}
if((p0.x == p1.x || p0.y == p1.y) && (end0&0x1F) == Endsquare && (end1&0x1F) == Endsquare){
r.min = p0;
r.max = p1;
if(p0.x == p1.x){
r.min.x -= radius;
r.max.x += radius+1;
}
else{
r.min.y -= radius;
r.max.y += radius+1;
}
oclipr = dst->clipr;
dst->clipr = clipr;
memimagedraw(dst, r, src, sp, memopaque, sp, op);
dst->clipr = oclipr;
return;
}
/* Hard: */
/* draw thick line using polygon fill */
icossin2(p1.x-p0.x, p1.y-p0.y, &cos, &sin);
dx = (sin*(2*radius+1))/2;
dy = (cos*(2*radius+1))/2;
pp = pts;
oclipr = dst->clipr;
dst->clipr = clipr;
q.x = ICOSSCALE*p0.x+ICOSSCALE/2-cos/2;
q.y = ICOSSCALE*p0.y+ICOSSCALE/2-sin/2;
switch(end0 & 0x1F){
case Enddisc:
discend(p0, radius, dst, src, d, op);
/* fall through */
case Endsquare:
default:
pp->x = q.x-dx;
pp->y = q.y+dy;
pp++;
pp->x = q.x+dx;
pp->y = q.y-dy;
pp++;
break;
case Endarrow:
arrowend(q, pp, end0, -sin, -cos, radius);
_memfillpolysc(dst, pts, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
pp[1] = pp[4];
pp += 2;
}
q.x = ICOSSCALE*p1.x+ICOSSCALE/2+cos/2;
q.y = ICOSSCALE*p1.y+ICOSSCALE/2+sin/2;
switch(end1 & 0x1F){
case Enddisc:
discend(p1, radius, dst, src, d, op);
/* fall through */
case Endsquare:
default:
pp->x = q.x+dx;
pp->y = q.y-dy;
pp++;
pp->x = q.x-dx;
pp->y = q.y+dy;
pp++;
break;
case Endarrow:
arrowend(q, pp, end1, sin, cos, radius);
_memfillpolysc(dst, pp, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
pp[1] = pp[4];
pp += 2;
}
_memfillpolysc(dst, pts, pp-pts, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 0, 10, 1, op);
dst->clipr = oclipr;
return;
}
void
memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
{
_memimageline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
}
/*
* Simple-minded conservative code to compute bounding box of line.
* Result is probably a little larger than it needs to be.
*/
static
void
addbbox(Rectangle *r, Point p)
{
if(r->min.x > p.x)
r->min.x = p.x;
if(r->min.y > p.y)
r->min.y = p.y;
if(r->max.x < p.x+1)
r->max.x = p.x+1;
if(r->max.y < p.y+1)
r->max.y = p.y+1;
}
int
memlineendsize(int end)
{
int x3;
if((end&0x3F) != Endarrow)
return 0;
if(end == Endarrow)
x3 = Arrow3;
else
x3 = (end>>23) & 0x1FF;
return x3;
}
Rectangle
memlinebbox(Point p0, Point p1, int end0, int end1, int radius)
{
Rectangle r, r1;
int extra;
r.min.x = 10000000;
r.min.y = 10000000;
r.max.x = -10000000;
r.max.y = -10000000;
extra = lmax(memlineendsize(end0), memlineendsize(end1));
r1 = insetrect(canonrect(Rpt(p0, p1)), -(radius+extra));
addbbox(&r, r1.min);
addbbox(&r, r1.max);
return r;
}

72
libmemdraw/load.c Normal file
View File

@@ -0,0 +1,72 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int
_loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
int y, l, lpart, rpart, mx, m, mr;
uchar *q;
if(!rectinrect(r, i->r))
return -1;
l = bytesperline(r, i->depth);
if(ndata < l*Dy(r))
return -1;
ndata = l*Dy(r);
q = byteaddr(i, r.min);
mx = 7/i->depth;
lpart = (r.min.x & mx) * i->depth;
rpart = (r.max.x & mx) * i->depth;
m = 0xFF >> lpart;
/* may need to do bit insertion on edges */
if(l == 1){ /* all in one byte */
if(rpart)
m ^= 0xFF >> rpart;
for(y=r.min.y; y<r.max.y; y++){
*q ^= (*data^*q) & m;
q += i->width*sizeof(ulong);
data++;
}
return ndata;
}
if(lpart==0 && rpart==0){ /* easy case */
for(y=r.min.y; y<r.max.y; y++){
memmove(q, data, l);
q += i->width*sizeof(ulong);
data += l;
}
return ndata;
}
mr = 0xFF ^ (0xFF >> rpart);
if(lpart!=0 && rpart==0){
for(y=r.min.y; y<r.max.y; y++){
*q ^= (*data^*q) & m;
if(l > 1)
memmove(q+1, data+1, l-1);
q += i->width*sizeof(ulong);
data += l;
}
return ndata;
}
if(lpart==0 && rpart!=0){
for(y=r.min.y; y<r.max.y; y++){
if(l > 1)
memmove(q, data, l-1);
q[l-1] ^= (data[l-1]^q[l-1]) & mr;
q += i->width*sizeof(ulong);
data += l;
}
return ndata;
}
for(y=r.min.y; y<r.max.y; y++){
*q ^= (*data^*q) & m;
if(l > 2)
memmove(q+1, data+1, l-2);
q[l-1] ^= (data[l-1]^q[l-1]) & mr;
q += i->width*sizeof(ulong);
data += l;
}
return ndata;
}

79
libmemdraw/mkcmap.c Normal file
View File

@@ -0,0 +1,79 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
/*
struct Memcmap
{
uchar cmap2rgb[3*256];
uchar rgb2cmap[16*16*16];
};
*/
static Memcmap*
mkcmap(void)
{
static Memcmap def;
int i, rgb, r, g, b;
for(i=0; i<256; i++){
rgb = cmap2rgb(i);
r = (rgb>>16)&0xff;
g = (rgb>>8)&0xff;
b = rgb&0xff;
def.cmap2rgb[3*i] = r;
def.cmap2rgb[3*i+1] = g;
def.cmap2rgb[3*i+2] = b;
}
for(r=0; r<16; r++)
for(g=0; g<16; g++)
for(b=0; b<16; b++)
def.rgb2cmap[r*16*16+g*16+b] = rgb2cmap(r*0x11, g*0x11, b*0x11);
return &def;
}
void
main(int argc, char **argv)
{
Memcmap *c;
int i, j, inferno;
inferno = 0;
ARGBEGIN{
case 'i':
inferno = 1;
}ARGEND
memimageinit();
c = mkcmap();
if(!inferno)
print("#include <u.h>\n#include <libc.h>\n");
else
print("#include \"lib9.h\"\n");
print("#include <draw.h>\n");
print("#include <memdraw.h>\n\n");
print("static Memcmap def = {\n");
print("/* cmap2rgb */ {\n");
for(i=0; i<sizeof(c->cmap2rgb); ){
print("\t");
for(j=0; j<16; j++, i++)
print("0x%2.2ux,", c->cmap2rgb[i]);
print("\n");
}
print("},\n");
print("/* rgb2cmap */ {\n");
for(i=0; i<sizeof(c->rgb2cmap);){
print("\t");
for(j=0; j<16; j++, i++)
print("0x%2.2ux,", c->rgb2cmap[i]);
print("\n");
}
print("}\n");
print("};\n");
print("Memcmap *memdefcmap = &def;\n");
print("void _memmkcmap(void){}\n");
exits(0);
}

27
libmemdraw/mkfile Normal file
View File

@@ -0,0 +1,27 @@
<$DSRC/mkfile-$CONF
TARG=libmemdraw.$L
OFILES=\
alloc.$O\
arc.$O\
cload.$O\
cmap.$O\
cread.$O\
defont.$O\
draw.$O\
ellipse.$O\
fillpoly.$O\
hwdraw.$O\
line.$O\
load.$O\
openmemsubfont.$O\
poly.$O\
read.$O\
string.$O\
subfont.$O\
unload.$O\
write.$O
HFILE=\
<$DSRC/mklib-$CONF

View File

@@ -0,0 +1,53 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
Memsubfont*
openmemsubfont(char *name)
{
Memsubfont *sf;
Memimage *i;
Fontchar *fc;
int fd, n;
char hdr[3*12+4+1];
uchar *p;
fd = open(name, OREAD);
if(fd < 0)
return nil;
p = nil;
i = readmemimage(fd);
if(i == nil)
goto Err;
if(read(fd, hdr, 3*12) != 3*12){
werrstr("openmemsubfont: header read error: %r");
goto Err;
}
n = atoi(hdr);
p = malloc(6*(n+1));
if(p == nil)
goto Err;
if(read(fd, p, 6*(n+1)) != 6*(n+1)){
werrstr("openmemsubfont: fontchar read error: %r");
goto Err;
}
fc = malloc(sizeof(Fontchar)*(n+1));
if(fc == nil)
goto Err;
_unpackinfo(fc, p, n);
sf = allocmemsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i);
if(sf == nil){
free(fc);
goto Err;
}
free(p);
return sf;
Err:
close(fd);
if (i != nil)
freememimage(i);
if (p != nil)
free(p);
return nil;
}

24
libmemdraw/poly.c Normal file
View File

@@ -0,0 +1,24 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
void
mempoly(Memimage *dst, Point *vert, int nvert, int end0, int end1, int radius, Memimage *src, Point sp, int op)
{
int i, e0, e1;
Point d;
if(nvert < 2)
return;
d = subpt(sp, vert[0]);
for(i=1; i<nvert; i++){
e0 = e1 = Enddisc;
if(i == 1)
e0 = end0;
if(i == nvert-1)
e1 = end1;
memline(dst, vert[i-1], vert[i], e0, e1, radius, src, addpt(d, vert[i-1]), op);
}
}

111
libmemdraw/read.c Normal file
View File

@@ -0,0 +1,111 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
Memimage*
readmemimage(int fd)
{
char hdr[5*12+1];
int dy;
ulong chan;
uint l, n;
int m, j;
int new, miny, maxy;
Rectangle r;
uchar *tmp;
int ldepth, chunk;
Memimage *i;
if(readn(fd, hdr, 11) != 11){
werrstr("readimage: short header");
return nil;
}
if(memcmp(hdr, "compressed\n", 11) == 0)
return creadmemimage(fd);
if(readn(fd, hdr+11, 5*12-11) != 5*12-11){
werrstr("readimage: short header (2)");
return nil;
}
/*
* distinguish new channel descriptor from old ldepth.
* channel descriptors have letters as well as numbers,
* while ldepths are a single digit formatted as %-11d.
*/
new = 0;
for(m=0; m<10; m++){
if(hdr[m] != ' '){
new = 1;
break;
}
}
if(hdr[11] != ' '){
werrstr("readimage: bad format");
return nil;
}
if(new){
hdr[11] = '\0';
if((chan = strtochan(hdr)) == 0){
werrstr("readimage: bad channel string %s", hdr);
return nil;
}
}else{
ldepth = ((int)hdr[10])-'0';
if(ldepth<0 || ldepth>3){
werrstr("readimage: bad ldepth %d", ldepth);
return nil;
}
chan = drawld2chan[ldepth];
}
r.min.x = atoi(hdr+1*12);
r.min.y = atoi(hdr+2*12);
r.max.x = atoi(hdr+3*12);
r.max.y = atoi(hdr+4*12);
if(r.min.x>r.max.x || r.min.y>r.max.y){
werrstr("readimage: bad rectangle");
return nil;
}
miny = r.min.y;
maxy = r.max.y;
l = bytesperline(r, chantodepth(chan));
i = allocmemimage(r, chan);
if(i == nil)
return nil;
chunk = 32*1024;
if(chunk < l)
chunk = l;
tmp = malloc(chunk);
if(tmp == nil)
goto Err;
while(maxy > miny){
dy = maxy - miny;
if(dy*l > chunk)
dy = chunk/l;
if(dy <= 0){
werrstr("readmemimage: image too wide for buffer");
goto Err;
}
n = dy*l;
m = readn(fd, tmp, n);
if(m != n){
werrstr("readmemimage: read count %d not %d: %r", m, n);
Err:
freememimage(i);
free(tmp);
return nil;
}
if(!new) /* an old image: must flip all the bits */
for(j=0; j<chunk; j++)
tmp[j] ^= 0xFF;
if(loadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
goto Err;
miny += dy;
}
free(tmp);
return i;
}

68
libmemdraw/string.c Normal file
View File

@@ -0,0 +1,68 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
Point
memimagestring(Memimage *b, Point p, Memimage *color, Point cp, Memsubfont *f, char *cs)
{
int w, width;
uchar *s;
Rune c;
Fontchar *i;
s = (uchar*)cs;
for(; c=*s; p.x+=width, cp.x+=width){
width = 0;
if(c < Runeself)
s++;
else{
w = chartorune(&c, (char*)s);
if(w == 0){
s++;
continue;
}
s += w;
}
if(c >= f->n)
continue;
// i = f->info+c;
i = &(f->info[c]);
width = i->width;
memdraw(b, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom),
color, cp, f->bits, Pt(i->x, i->top), SoverD);
}
return p;
}
Point
memsubfontwidth(Memsubfont *f, char *cs)
{
Rune c;
Point p;
uchar *s;
Fontchar *i;
int w, width;
p = Pt(0, f->height);
s = (uchar*)cs;
for(; c=*s; p.x+=width){
width = 0;
if(c < Runeself)
s++;
else{
w = chartorune(&c, (char*)s);
if(w == 0){
s++;
continue;
}
s += w;
}
if(c >= f->n)
continue;
i = f->info+c;
width = i->width;
}
return p;
}

34
libmemdraw/subfont.c Normal file
View File

@@ -0,0 +1,34 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
Memsubfont*
allocmemsubfont(char *name, int n, int height, int ascent, Fontchar *info, Memimage *i)
{
Memsubfont *f;
f = malloc(sizeof(Memsubfont));
if(f == 0)
return 0;
f->n = n;
f->height = height;
f->ascent = ascent;
f->info = info;
f->bits = i;
if(name)
f->name = strdup(name);
else
f->name = 0;
return f;
}
void
freememsubfont(Memsubfont *f)
{
if(f == 0)
return;
free(f->info); /* note: f->info must have been malloc'ed! */
freememimage(f->bits);
free(f);
}

19
libmemdraw/times Normal file
View File

@@ -0,0 +1,19 @@
draw1: 6M for draw 0,0,100,100 no repl
draw3: 4M for draw 0,0,100,100 no repl
just read src, dst - 250k
mask reading - 650k
write dst - 100k
alpha calculation - 3000k
olddraw: 10M for draw 0, 0, 1000, 1000 no repl all ldepth 3
44M for draw 0, 0, 1000, 1000 src, mask ldepth 2 dst ldepth 3
draw4: 160M for draw 0, 0, 1000, 1000 no repl all r8g8b8
null loop: 10k
src, dst reading: 13-15M each
mask reading: 30M
alpha calculation loop: 90M
null alpha loop: 2M
minimal loop control +20M
alpha calculation with divides +190M
alpha calculation wtih shifts +70M
writeback: 11M

25
libmemdraw/unload.c Normal file
View File

@@ -0,0 +1,25 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int
unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
int y, l;
uchar *q;
if(!rectinrect(r, i->r))
return -1;
l = bytesperline(r, i->depth);
if(ndata < l*Dy(r))
return -1;
ndata = l*Dy(r);
q = byteaddr(i, r.min);
for(y=r.min.y; y<r.max.y; y++){
memmove(data, q, l);
q += i->width*sizeof(ulong);
data += l;
}
return ndata;
}

183
libmemdraw/write.c Normal file
View File

@@ -0,0 +1,183 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#define CHUNK 8000
#define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
#define NHASH (1<<(HSHIFT*NMATCH))
#define HMASK (NHASH-1)
#define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK)
typedef struct Hlist Hlist;
struct Hlist{
uchar *s;
Hlist *next, *prev;
};
int
writememimage(int fd, Memimage *i)
{
uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */
uchar *loutp; /* start of encoded line */
Hlist *hash; /* heads of hash chains of past strings */
Hlist *chain, *hp; /* hash chain members, pointer */
Hlist *cp; /* next Hlist to fall out of window */
int h; /* hash value */
uchar *line, *eline; /* input line, end pointer */
uchar *data, *edata; /* input buffer, end pointer */
ulong n; /* length of input buffer */
ulong nb; /* # of bytes returned by unloadimage */
int bpl; /* input line length */
int offs, runlen; /* offset, length of consumed data */
uchar dumpbuf[NDUMP]; /* dump accumulator */
int ndump; /* length of dump accumulator */
int miny, dy; /* y values while unloading input */
int ncblock; /* size of compressed blocks */
Rectangle r;
uchar *p, *q, *s, *es, *t;
char hdr[11+5*12+1];
char cbuf[20];
r = i->r;
bpl = bytesperline(r, i->depth);
n = Dy(r)*bpl;
data = malloc(n);
ncblock = _compblocksize(r, i->depth);
outbuf = malloc(ncblock);
hash = malloc(NHASH*sizeof(Hlist));
chain = malloc(NMEM*sizeof(Hlist));
if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
ErrOut:
free(data);
free(outbuf);
free(hash);
free(chain);
return -1;
}
for(miny = r.min.y; miny != r.max.y; miny += dy){
dy = r.max.y-miny;
if(dy*bpl > CHUNK)
dy = CHUNK/bpl;
nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
data+(miny-r.min.y)*bpl, dy*bpl);
if(nb != dy*bpl)
goto ErrOut;
}
sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
if(write(fd, hdr, 11+5*12) != 11+5*12)
goto ErrOut;
edata = data+n;
eout = outbuf+ncblock;
line = data;
r.max.y = r.min.y;
while(line != edata){
memset(hash, 0, NHASH*sizeof(Hlist));
memset(chain, 0, NMEM*sizeof(Hlist));
cp = chain;
h = 0;
outp = outbuf;
for(n = 0; n != NMATCH; n++)
h = hupdate(h, line[n]);
loutp = outbuf;
while(line != edata){
ndump = 0;
eline = line+bpl;
for(p = line; p != eline; ){
if(eline-p < NRUN)
es = eline;
else
es = p+NRUN;
q = 0;
runlen = 0;
for(hp = hash[h].next; hp; hp = hp->next){
s = p + runlen;
if(s >= es)
continue;
t = hp->s + runlen;
for(; s >= p; s--)
if(*s != *t--)
goto matchloop;
t += runlen+2;
s += runlen+2;
for(; s < es; s++)
if(*s != *t++)
break;
n = s-p;
if(n > runlen){
runlen = n;
q = hp->s;
if(n == NRUN)
break;
}
matchloop: ;
}
if(runlen < NMATCH){
if(ndump == NDUMP){
if(eout-outp < ndump+1)
goto Bfull;
*outp++ = ndump-1+128;
memmove(outp, dumpbuf, ndump);
outp += ndump;
ndump = 0;
}
dumpbuf[ndump++] = *p;
runlen = 1;
}
else{
if(ndump != 0){
if(eout-outp < ndump+1)
goto Bfull;
*outp++ = ndump-1+128;
memmove(outp, dumpbuf, ndump);
outp += ndump;
ndump = 0;
}
offs = p-q-1;
if(eout-outp < 2)
goto Bfull;
*outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
*outp++ = offs&255;
}
for(q = p+runlen; p != q; p++){
if(cp->prev)
cp->prev->next = 0;
cp->next = hash[h].next;
cp->prev = &hash[h];
if(cp->next)
cp->next->prev = cp;
cp->prev->next = cp;
cp->s = p;
if(++cp == &chain[NMEM])
cp = chain;
if(edata-p > NMATCH)
h = hupdate(h, p[NMATCH]);
}
}
if(ndump != 0){
if(eout-outp < ndump+1)
goto Bfull;
*outp++ = ndump-1+128;
memmove(outp, dumpbuf, ndump);
outp += ndump;
}
line = eline;
loutp = outp;
r.max.y++;
}
Bfull:
if(loutp == outbuf)
goto ErrOut;
n = loutp-outbuf;
sprint(hdr, "%11d %11ld ", r.max.y, n);
write(fd, hdr, 2*12);
write(fd, outbuf, n);
r.min.y = r.max.y;
}
free(data);
free(outbuf);
free(hash);
free(chain);
return 0;
}