var drawmsg = { A: {fmt: ["i4:id", "i4:imageid", "i4:fillid", "i1:public"], handler: drawallocscreen, size: 13}, b: {fmt: ["i4:id", "i4:screenid", "i1:refresh", "b4:chan", "i1:repl", "b16:r", "b16:clipr", "b4:color"], handler: drawallocate, size: 50}, c: {fmt: ["i4:dstid", "i1:repl", "b16:clipr"], handler: drawclip, size:21}, d: {fmt: ["i4:dstid", "i4:srcid", "i4:maskid", "b16:dstr", "b8:srcp", "b8:maskp"], handler: drawdraw, size: 44}, D: {fmt: ["i1:debug"], handler: drawdebug, size: 1}, E: {fmt: ["i4:dstid", "i4:srcid", "b8:c", "i4:a", "i4:b", "i4:thick", "b8:sp", "i4:alpha", "i4:phi"], handler: drawfillellipse, size: 44}, f: {fmt: ["i4:id"], handler: drawfree, size: 4}, L: {fmt: ["i4:dstid", "b8:p0", "b8:p1", "i4:end0", "i4:end1", "i4:thick", "i4:srcid", "b8:sp"], handler: drawline, size: 44}, n: {fmt: ["i4:id", "S1:n"], handler: drawname, size: 5}, v: {fmt: [], handler: drawflush, size: 0}, y: {fmt: ["i4:id", "b16:r", "R:buf"], handler: drawload, size: 20}, }; var disp = {id: 0, r: [0, 0, 640, 480], chan: "r8g8b8a8", repl: 0, refresh: 0}; disp.clipr = disp.r; var pub = {"noborder.screen.0": disp}; var screens = {}; var conns = []; var mouse = [0, 0, 0, 0]; var canv; var starttime = new Date().getTime(); var onmouse = []; var drawdebugon = 0; function punpack(b) { var a; a = unpack(b, ["i4:x", "i4:y"]); return [a.x, a.y]; } function runpack(b) { var a; a = unpack(b, ["j4:minx", "j4:miny", "j4:maxx", "j4:maxy"]); return [a.minx, a.miny, a.maxx, a.maxy]; } function newconn() { var i; for(x in conns) if(conns[x].used != true){ conns[x].used = true; conns[x].img = disp; conns[x].imgs = {0: disp}; return conns[x]; } i = conns.length; conns.push({id: i, img: disp, used: true, imgs: {0: disp}}); mkdir("/dev/draw/" + i); lookupfile("/dev/draw/" + i, true).id = i; mkfile("/dev/draw/" + i + "/ctl", undefined, drawctlread, undefined); mkfile("/dev/draw/" + i + "/data", undefined, invalidop, drawdatawrite); mkfile("/dev/draw/" + i + "/colormap", undefined, undefined, undefined); mkfile("/dev/draw/" + i + "/refresh", undefined, invalidop, undefined); return conns[i]; } function drawnewopen(f) { if(canv == undefined){ canv = document.getElementById('draw').getContext('2d'); if(canv == undefined) return "no canvas"; disp.canvas = canv.canvas; disp.ctx = canv; } f.f = lookupfile("/dev/draw/" + newconn().id + "/ctl", true); return ""; } function drawctlread(f, p) { var id, c, i; id = f.f.parent.id; c = conns[id]; i = c.img; a = [id, i.id, i.chan, i.repl].concat(i.r).concat(i.clipr); for(x in a){ a[x] = String(a[x]).substring(0, 11); if(a[x].length < 11) a[x] = Array(12 - a[x].length).join(' ') + a[x]; } readstr(p, a.join(' ')+' '); } function drawdatawrite(f, p) { var t, s, m, i; i = 0; while(i < p.data.length){ t = p.data[i]; if(drawmsg[t] == undefined){ writeterminal("unknown message " + t + "\n"); return error9p(p.tag, "unknown message " + t); } i++; m = unpack(p.data.substring(i), drawmsg[t].fmt); if(drawdebugon){ print(t + " " + JSON.stringify(m) + "\n"); } s = drawmsg[t].handler(conns[f.f.parent.id], m); if(s != "" && s != undefined){ writeterminal(s + "\n"); return error9p(p.tag, s); } i += drawmsg[t].size; switch(t){ case 'n': i += m.n.length; break; case 'y': i += m.buf.length; break; default: break; } } respond(p, -1); } function drawallocate(c, p) { var i, j, n; if(c.imgs[p.id] != undefined) return "id " + p.id + " already in use"; i = allocimg(runpack(p.r), [p.color.charCodeAt(3), p.color.charCodeAt(2), p.color.charCodeAt(1), p.color.charCodeAt(0)], p.repl); i.id = p.id; i.refresh = p.refresh; i.clipr = runpack(p.clipr); i.chan = p.chan; if(p.screenid != 0){ i.screen = screens[p.screenid]; if(i.screen == undefined) return "screenid " + p.screenid + " not in use"; i.screen.win.push(i); } c.imgs[p.id] = i; } function drawallocscreen(c, p) { if(screens[p.id] != undefined) return "id " + p.id + " already in use"; if(c.imgs[p.imageid] == undefined) return "id " + p.imageid + " not in use"; if(c.imgs[p.fillid] == undefined) return "id " + p.fillid + " not in use"; screens[p.id] = {image: c.imgs[p.imageid], fill: c.imgs[p.fillid], public: p.public, win: []}; } function drawfree(c, p) { c.imgs[p.id] = undefined; } function drawclip(c, p) { if(c.imgs[p.dstid] == undefined) return "id " + p.dstid + " not in use"; c.imgs[p.dstid].clipr = runpack(p.clipr); c.imgs[p.dstid].repl = p.repl; } function ellipse(c, p, fill) { var dst, src, center, color; dst = c.imgs[p.dstid]; if(dst == undefined) return "id " + p.dstid + " not in use"; src = c.imgs[p.srcid]; if(src == undefined) return "id " + p.srcid + " not in use"; center = punpack(p.c); color = src.ctx.getImageData(0, 0, 1, 1).data; dst.ctx.beginPath(); dst.ctx.ellipse(center[0], center[1], p.a, p.b, 0, 0, 2 * Math.PI); if(fill){ dst.ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')'; dst.ctx.fill(); } dst.ctx.strokeStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')'; dst.ctx.stroke(); dstflush(dst); } function drawfillellipse(c, p) { ellipse(c, p, 1); } function drawline(c, p) { var dst, src, p0, p1, color; dst = c.imgs[p.dstid]; if(dst == undefined) return "id " + p.dstid + " not in use"; src = c.imgs[p.srcid]; if(src == undefined) return "id " + p.srcid + " not in use"; p0 = punpack(p.p0); p1 = punpack(p.p1); color = src.ctx.getImageData(0, 0, 1, 1).data; dst.ctx.beginPath(); dst.ctx.moveTo(p0[0], p0[1]); dst.ctx.lineTo(p1[0], p1[1]); dst.ctx.lineWidth = 1 + 2 * p.thick; dst.ctx.strokeStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')'; dst.ctx.stroke(); dstflush(dst); } function drawload(c, p) { var im, d, i, j, k, l, r; im = c.imgs[p.id]; if(im == undefined) return "id + " + p.id + " not in use"; r = runpack(p.r); d = im.ctx.getImageData(0, 0, im.canvas.width, im.canvas.height); k = 0; for(i = r[1]; i < r[3]; i++) for(j = r[0]; j < r[2]; j++) for(l = 0; l < 3; l++) d.data[4 * (d.data.width * i + j) + l] = p.buf[k++]; im.ctx.putImageData(d, 0, 0); } function drawname(c, p) { if(c.imgs[p.id] != undefined) return "id " + p.id + " already in use"; if(pub[p.n] == undefined) return "no such image " + p.n; c.imgs[p.id] = pub[p.n]; } function drawdebug(c, p) { drawdebugon = p.debug; } function drawflush(c, p) { dstflush(disp); } function dstflush(dst) { var s; s = dst.screen; if(s != undefined){ memdraw(s.image, s.image.r, s.fill, [0, 0], undefined, undefined, 11); for(x in s.win) memdraw(s.image, s.image.r, s.win[x], [0, 0], undefined, undefined, 11); dstflush(s.image); } } function drawdraw(c, p) { var dst, src; dst = c.imgs[p.dstid]; if(dst == undefined) return "id " + p.dstid + " not in use"; src = c.imgs[p.srcid]; if(src == undefined) return "id " + p.srcid + " not in use"; mask = c.imgs[p.maskid]; memdraw(dst, runpack(p.dstr), src, punpack(p.srcp), mask, punpack(p.maskp), 11); dstflush(dst); } mkfile("/dev/winname", undefined, function(f, p) { readstr(p, "noborder.screen.0"); }, undefined); mkfile("/dev/cursor", undefined, function(){}, function(f, p) {respond(p, -1);}); mkdir("/dev/draw"); mkfile("/dev/draw/new", drawnewopen, drawctlread, invalidop); function mousechange(k, e) { var c, n; c = document.getElementById('draw'); mouse = [e.clientX - c.offsetLeft, e.clientY - c.offsetLeft, mouse[2], new Date().getTime() - starttime]; switch(k){ case 1: mouse[2] |= (1<