210 lines
3.9 KiB
C
210 lines
3.9 KiB
C
|
#include <u.h>
|
||
|
#include <libc.h>
|
||
|
#include <draw.h>
|
||
|
#include <memdraw.h>
|
||
|
#include "xmem.h"
|
||
|
|
||
|
/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
|
||
|
#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
|
||
|
|
||
|
Memimage*
|
||
|
xallocmemimage(Rectangle r, ulong chan, int pmid)
|
||
|
{
|
||
|
Memimage *m;
|
||
|
Xmem *xm;
|
||
|
XImage *xi;
|
||
|
int offset;
|
||
|
int d;
|
||
|
|
||
|
m = _allocmemimage(r, chan);
|
||
|
if(chan != GREY1 && chan != xscreenchan)
|
||
|
return m;
|
||
|
|
||
|
d = m->depth;
|
||
|
xm = mallocz(sizeof(Xmem), 1);
|
||
|
if(pmid != PMundef)
|
||
|
xm->pmid = pmid;
|
||
|
else
|
||
|
xm->pmid = XCreatePixmap(xdisplay, xscreenid, Dx(r), Dy(r), (d==32) ? 24 : d);
|
||
|
|
||
|
if(m->depth == 24)
|
||
|
offset = r.min.x&(4-1);
|
||
|
else
|
||
|
offset = r.min.x&(31/m->depth);
|
||
|
r.min.x -= offset;
|
||
|
|
||
|
assert(wordsperline(r, m->depth) <= m->width);
|
||
|
|
||
|
xi = XCreateImage(xdisplay, xvis, m->depth==32?24:m->depth, ZPixmap, 0,
|
||
|
(char*)m->data->bdata, Dx(r), Dy(r), 32, m->width*sizeof(ulong));
|
||
|
|
||
|
if(xi == nil){
|
||
|
_freememimage(m);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
xm->xi = xi;
|
||
|
xm->pc = getcallerpc(&r);
|
||
|
xm->r = r;
|
||
|
|
||
|
/*
|
||
|
* Set the parameters of the XImage so its memory looks exactly like a
|
||
|
* Memimage, so we can call _memimagedraw on the same data. All frame
|
||
|
* buffers we've seen, and Plan 9's graphics code, require big-endian
|
||
|
* bits within bytes, but little endian byte order within pixels.
|
||
|
*/
|
||
|
xi->bitmap_unit = m->depth < 8 || m->depth == 24 ? 8 : m->depth;
|
||
|
xi->byte_order = LSBFirst;
|
||
|
xi->bitmap_bit_order = MSBFirst;
|
||
|
xi->bitmap_pad = 32;
|
||
|
xm->r = Rect(0,0,0,0);
|
||
|
XInitImage(xi);
|
||
|
XFlush(xdisplay);
|
||
|
|
||
|
m->X = xm;
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
Memimage*
|
||
|
allocmemimage(Rectangle r, ulong chan)
|
||
|
{
|
||
|
return xallocmemimage(r, chan, PMundef);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
freememimage(Memimage *m)
|
||
|
{
|
||
|
Xmem *xm;
|
||
|
|
||
|
if(m == nil)
|
||
|
return;
|
||
|
|
||
|
if(m->data->ref == 1){
|
||
|
if((xm = m->X) != nil){
|
||
|
if(xm->xi){
|
||
|
xm->xi->data = nil;
|
||
|
XFree(xm->xi);
|
||
|
}
|
||
|
XFreePixmap(xdisplay, xm->pmid);
|
||
|
free(xm);
|
||
|
m->X = nil;
|
||
|
}
|
||
|
}
|
||
|
_freememimage(m);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
memfillcolor(Memimage *m, ulong val)
|
||
|
{
|
||
|
_memfillcolor(m, val);
|
||
|
if(m->X){
|
||
|
if((val & 0xFF) == 0xFF)
|
||
|
xfillcolor(m, m->r, _rgbatoimg(m, val));
|
||
|
else
|
||
|
putXdata(m, m->r);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
addrect(Rectangle *rp, Rectangle r)
|
||
|
{
|
||
|
if(rp->min.x >= rp->max.x)
|
||
|
*rp = r;
|
||
|
else
|
||
|
combinerect(rp, r);
|
||
|
}
|
||
|
|
||
|
XImage*
|
||
|
getXdata(Memimage *m, Rectangle r)
|
||
|
{
|
||
|
uchar *p;
|
||
|
int x, y;
|
||
|
Xmem *xm;
|
||
|
Point xdelta, delta;
|
||
|
Point tp;
|
||
|
|
||
|
xm = m->X;
|
||
|
if(xm == nil)
|
||
|
return;
|
||
|
|
||
|
assert(xm != nil && xm->xi != nil);
|
||
|
|
||
|
if(xm->dirty == 0)
|
||
|
return xm->xi;
|
||
|
|
||
|
r = xm->dirtyr;
|
||
|
if(Dx(r)==0 || Dy(r)==0)
|
||
|
return xm->xi;
|
||
|
|
||
|
delta = subpt(r.min, m->r.min);
|
||
|
tp = xm->r.min; /* avoid unaligned access on digital unix */
|
||
|
xdelta = subpt(r.min, tp);
|
||
|
|
||
|
XGetSubImage(xdisplay, xm->pmid, delta.x, delta.y, Dx(r), Dy(r),
|
||
|
AllPlanes, ZPixmap, xm->xi, xdelta.x, xdelta.y);
|
||
|
|
||
|
if(xtblbit && m->chan == CMAP8)
|
||
|
for(y=r.min.y; y<r.max.y; y++)
|
||
|
for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
|
||
|
*p = x11toplan9[*p];
|
||
|
|
||
|
xm->dirty = 0;
|
||
|
xm->dirtyr = Rect(0,0,0,0);
|
||
|
return xm->xi;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
putXdata(Memimage *m, Rectangle r)
|
||
|
{
|
||
|
Xmem *xm;
|
||
|
XImage *xi;
|
||
|
GC g;
|
||
|
int offset;
|
||
|
Point xdelta, delta;
|
||
|
Point tp;
|
||
|
int x, y;
|
||
|
uchar *p;
|
||
|
|
||
|
xm = m->X;
|
||
|
if(xm == nil)
|
||
|
return;
|
||
|
|
||
|
assert(xm != nil);
|
||
|
assert(xm->xi != nil);
|
||
|
|
||
|
xi = xm->xi;
|
||
|
|
||
|
g = (m->chan == GREY1) ? xgccopy0 : xgccopy;
|
||
|
if(m->depth == 24)
|
||
|
offset = r.min.x % 4;
|
||
|
else
|
||
|
offset = m->r.min.x & (31/m->depth);
|
||
|
|
||
|
delta = subpt(r.min, m->r.min);
|
||
|
tp = xm->r.min; /* avoid unaligned access on digital unix */
|
||
|
xdelta = subpt(r.min, tp);
|
||
|
|
||
|
if(xtblbit && m->chan == CMAP8)
|
||
|
for(y=r.min.y; y<r.max.y; y++)
|
||
|
for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
|
||
|
*p = plan9tox11[*p];
|
||
|
|
||
|
XPutImage(xdisplay, xm->pmid, g, xi, xdelta.x, xdelta.y, delta.x, delta.y, Dx(r), Dy(r));
|
||
|
|
||
|
if(xtblbit && m->chan == CMAP8)
|
||
|
for(y=r.min.y; y<r.max.y; y++)
|
||
|
for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
|
||
|
*p = x11toplan9[*p];
|
||
|
}
|
||
|
|
||
|
void
|
||
|
dirtyXdata(Memimage *m, Rectangle r)
|
||
|
{
|
||
|
Xmem *xm;
|
||
|
|
||
|
if((xm = m->X) != nil){
|
||
|
xm->dirty = 1;
|
||
|
addrect(&xm->dirtyr, r);
|
||
|
}
|
||
|
}
|