|  | #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+sizeof(Memdata*)+sizeof(ulong); | 
|  | } | 
|  |  | 
|  | Memimage* | 
|  | allocmemimaged(Rectangle r, u32int chan, Memdata *md, void *X) | 
|  | { | 
|  | int d; | 
|  | u32int 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(u32int)*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, u32int chan) | 
|  | { | 
|  | int d; | 
|  | u32int l, nw; | 
|  | uchar *p; | 
|  | 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, sizeof(Memdata*)+(1+nw)*sizeof(ulong)); | 
|  | if(md->base == nil){ | 
|  | free(md); | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | p = (uchar*)md->base; | 
|  | *(Memdata**)p = md; | 
|  | p += sizeof(Memdata*); | 
|  |  | 
|  | *(ulong*)p = getcallerpc(&r); | 
|  | p += sizeof(ulong); | 
|  |  | 
|  | /* if this changes, memimagemove must change too */ | 
|  | md->bdata = p; | 
|  | 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. | 
|  | */ | 
|  | u32int* | 
|  | wordaddr(Memimage *i, Point p) | 
|  | { | 
|  | return (u32int*) ((ulong)byteaddr(i, p) & ~(sizeof(u32int)-1)); | 
|  | } | 
|  |  | 
|  | uchar* | 
|  | byteaddr(Memimage *i, Point p) | 
|  | { | 
|  | uchar *a; | 
|  |  | 
|  | /* careful to sign-extend negative p.y for 64-bits */ | 
|  | a = i->data->bdata+i->zero+(int)(sizeof(u32int)*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, u32int chan) | 
|  | { | 
|  | int d; | 
|  | int t, j, k; | 
|  | u32int 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; | 
|  | } |