class @Rect { U32 x0; U32 y0; U32 x1; U32 y1; }; class @Point { U32 x; U32 y; } class @draw_A { U32 id; U32 imageid; U32 fillid; U8 public; }; class @draw_P { U32 dstid; U16 n; U32 wind; @Point ignore; U32 srcid; @Point sp; // U16 sp[4]; // dp[2*2*(n+1)]; }; class @draw_b { U32 id; U32 screenid; U8 refresh; U32 chan; U8 repl; @Rect r; @Rect clipr; U32 color; }; class @draw_d { U32 dstid; U32 srcid; U32 maskid; @Rect dstr; @Point srcp; @Point maskp; }; class @draw_y { U32 id; @Rect r; }; I64 @image_cbgr24_to_4_bit(CBGR24* ptr, Bool dither_probability) { I64 res, k; if (dither_probability) { k = RandU32; if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= 3 * SqrI64(k.u8[0])) res = 8; else res = 0; if (ptr->r >= k.u8[1]) res |= RED; if (ptr->g >= k.u8[2]) res |= GREEN; if (ptr->b >= k.u8[3]) res |= BLUE; } else { if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= SqrI64(0x80)) { res = 8; if (ptr->r >= 0x80) res |= RED; if (ptr->g >= 0x80) res |= GREEN; if (ptr->b >= 0x80) res |= BLUE; } else { res = 0; if (ptr->r >= 0x40) res |= RED; if (ptr->g >= 0x40) res |= GREEN; if (ptr->b >= 0x40) res |= BLUE; } } return res; } I64 @nt_draw_A(@nt* nt, @draw_A* d, JsonObject* dobj) { // FIXME: Implement this. @nt_tx_dbg(nt, "id: %d, imageid: %d, fillid: %d, public: %d", d->id, d->imageid, d->fillid, d->public); // PressAKey; return sizeof(@draw_A); } I64 @nt_draw_b(@nt* nt, @draw_b* d, JsonObject* dobj) { // Allocate an image with a given id on the screen named by screenid. // b id[4] screenid[4] refresh[1] chan[4] repl[1] r[4 * 4] clipr[4 * 4] color[4] @nt_tx_dbg(nt, "id: %d, screenid: %d, refresh: %d, chan: %d, repl: %d", d->id, d->screenid, d->refresh, d->chan, d->repl); @nt_tx_dbg(nt, "rect: x0: %d, y0: %d, x1: %d, y1: %d", d->r.x0, d->r.y0, d->r.x1, d->r.y1); @nt_tx_dbg(nt, "clip rect: x0: %d, y0: %d, x1: %d, y1: %d", d->clipr.x0, d->clipr.y0, d->clipr.x1, d->clipr.y1); @nt_tx_dbg(nt, "color: %08x", d->color); U8 intbuf[16]; StrPrint(intbuf, "%d", d->id); if (dobj->o("imgs")->@(intbuf)) { @nt_tx_dbg(nt, "error: image id already exists"); PressAKey; } CDC* dc = NULL; if (!d->repl) { dc = DCNew(d->r.x1 - d->r.x0, d->r.y1 - d->r.y0); } JsonObject* iobj = Json.CreateObject(nt->main_task); JsonObject* tmpr = NULL; iobj->set("id", d->id, JSON_NUMBER); iobj->set("screenid", d->screenid, JSON_NUMBER); iobj->set("refresh", d->refresh, JSON_NUMBER); iobj->set("chan", d->chan, JSON_NUMBER); iobj->set("repl", d->repl, JSON_NUMBER); iobj->set("dc", dc, JSON_NUMBER); iobj->set("r", Json.CreateObject(nt->main_task), JSON_OBJECT); iobj->set("clipr", Json.CreateObject(nt->main_task), JSON_OBJECT); tmpr = iobj->o("r"); tmpr->set("x0", d->r.x0, JSON_NUMBER); tmpr->set("y0", d->r.x1, JSON_NUMBER); tmpr->set("x1", d->r.y0, JSON_NUMBER); tmpr->set("y1", d->r.y1, JSON_NUMBER); tmpr = iobj->o("clipr"); tmpr->set("x0", d->clipr.x0, JSON_NUMBER); tmpr->set("y0", d->clipr.x1, JSON_NUMBER); tmpr->set("x1", d->clipr.y0, JSON_NUMBER); tmpr->set("y1", d->clipr.y1, JSON_NUMBER); if (dc) { CBGR24 bgr; bgr.b = d->color.u8[0]; bgr.g = d->color.u8[1]; bgr.r = d->color.u8[2]; DCFill(dc, @image_cbgr24_to_4_bit(&bgr, 0)); } StrPrint(intbuf, "%d", d->id); dobj->o("imgs")->set(intbuf, iobj, JSON_OBJECT); return sizeof(@draw_b); } U0 @nt_draw_y_mono_1bit(CDC* dc, @draw_y* d) { U8* _c = d; I64 x = 0; I64 y = 0; I64 sx = 0; _c += sizeof(@draw_y); for (y = 0; y < d->r.y1; y++) { for (x = 0; x < d->r.x1; x++) { dc->color = @t((reverse_bits(*_c) >> sx) & 1, 15, 0); GrPlot(dc, x, y); sx++; if (sx > 7) { sx = 0; _c++; } } if (sx) { sx = 0; _c++; } } } I64 @nt_draw_y(@nt* nt, @draw_y* d, JsonObject* dobj) { // y id[4] r[4*4] buf[x*1] // Replace the rectangle r of pixels in image id with the pixel data in buf. @nt_tx_dbg(nt, "id: %d", d->id); @nt_tx_dbg(nt, "rect: x0: %d, y0: %d, x1: %d, y1: %d", d->r.x0, d->r.y0, d->r.x1, d->r.y1); U32 int_w; U8 intbuf[16]; StrPrint(intbuf, "%d", d->id); JsonObject* iobj = dobj->o("imgs")->@(intbuf); if (!iobj) { @nt_tx_dbg(nt, "imageid %d does not exist\n", d->id); PressAKey; } CDC* dc = iobj->@("dc"); if (!dc) { @nt_tx_dbg(nt, "no device context for imageid %d\n", d->id); PressAKey; } switch (iobj->@("chan")) { case 0x31: @nt_draw_y_mono_1bit(dc, d); int_w = d->r.x1; while (int_w % 8) { int_w++; } return sizeof(@draw_y) + ((int_w * d->r.y1) / 8); default: @nt_tx_dbg(nt, "unsupported chan value: 0x%04x", iobj->@("chan")); PressAKey; break; } } // drawcoord(uchar *p, uchar *maxp, int oldx, int *newx) U8* @nt_drawcoord(@nt* nt, U8* p, U8* maxp, U32 oldx, U32* newx) { U32 b, x; if (p >= maxp) { @nt_tx_dbg(nt, "error: Eshortdraw1: p = 0x%08x, maxp = 0x%08x", p, maxp); PressAKey; } b = *p++; x = b & 0x7F; if (b & 0x80) { if (p + 1 >= maxp) { @nt_tx_dbg(nt, "error: Eshortdraw2: p = 0x%08x", p); PressAKey; } x |= *p++ << 7; x |= *p++ << 15; if (x & (1 << 22)) x |= ~0 << 23; } else { if (b & 0x40) x |= ~0 << 7; x += oldx; } *newx = x; return p; } I64 @nt_draw_P(@nt* nt, @draw_P* d, JsonObject* dobj) { // P dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] dp[2*2*(n+1)] // Draw a polygon as the p message, but fill it rather than outlining it. @nt_tx_dbg(nt, "dstid: %d, n: %d, srcid: %d", d->dstid, d->n, d->srcid); // FIXME: Implement this. JsonObject* iobj; U8 idbuf[16]; I64 dx, dy; CDC* dst = NULL; CDC* src = NULL; StrPrint(idbuf, "%d", d->dstid); iobj = dobj->o("imgs")->o(idbuf); if (iobj) { dst = iobj->@("dc"); } // StrPrint(idbuf, "%d", d->srcid); // iobj = dobj->o("imgs")->o(idbuf); // if (iobj) { // src = iobj->@("dc"); // } if (dst) { dx = 0 + d->sp.x; dy = 0 + d->sp.y; // dy = d->sp.y; // dst->color = BLUE; //@nt_tx_dbg(nt, "plot dst pixel: dx: %d, dy: %d", dx, dy); // GrPlot(dst, dx, dy); } I64 i; //, j; I64 dp_length = 0; U8* dp_ptr = d; U8* maxp = 0x80000000000000; dp_ptr += 4 + 2 + 4 + 4 + 4 + 4 + 2 * 4; // d += sizeof(@draw_P); I64 b = 0; // m = 1+4+2+4 +4+4 +4 +2*4 // U32 ox = 0; // U32 oy = 0; // p.x = d->sp.x; // p.y = d->sp.y; U64 __p = d; __p += sizeof(@draw_P); @Point p; p.x = (__p)(U32*)[0]; p.y = (__p)(U32*)[1]; U32 ox = p.x; U32 oy = p.y; for (i = 0; i < d->n + 1; i++) { dp_ptr = @nt_drawcoord(nt, dp_ptr, maxp, ox, &p.x); dp_ptr = @nt_drawcoord(nt, dp_ptr, maxp, oy, &p.y); if (dst) { dst->color = BLACK; @nt_tx_dbg(nt, "plot line: x0: %d, y0: %d, x1: %d, y1: %d", ox, oy, p.x, p.y); if (!(ox > dst->width || oy > dst->height || p.x > dst->width || p.y > dst->height)) { GrLine(dst, ox, oy, p.x, p.y); } // GrPlot(dst, dx + p.x, dy + p.y); } ox = p.x; oy = p.y; // for (j = 0; j < 2; j++) { // b = dp_ptr[dp_length++]; // if (b & 0x80) { // dp_length += 2; // } // } } // Sleep(5000); // PressAKey; return sizeof(@draw_P) + dp_length - d(U8*); } I64 @nt_draw_d(@nt* nt, @draw_d* d, JsonObject* dobj) { // m = 1+4+4+4+4*4+2*4+2*4; // d dstid[4] srcid[4] maskid[4] dstr[4*4] srcp[2*4] maskp[2*4] // Use the draw operator to combine the rectangle dstr of image dstid with a rectangle of image srcid ... // res = 4 + 4 + 4 + sizeof(@Rect) + sizeof(@Point) + sizeof(@Point); I64 res = 4 + 4 + 4 + sizeof(@Rect) + sizeof(@Point) + sizeof(@Point); @nt_tx_dbg(nt, "dstid: %d, srcid: %d, maskid: %d, dstr: (%d,%d, %d,%d), srcp: (%d,%d) maskp: (%d,%d)", d->dstid, d->srcid, d->maskid, d->dstr.x0, d->dstr.y0, d->dstr.x1, d->dstr.y1, d->srcp.x, d->srcp.y, d->maskp.x, d->maskp.y); JsonObject* iobj; U8 idbuf[16]; I64 dx, dy; CDC* dst; CDC* src; StrPrint(idbuf, "%d", d->dstid); iobj = dobj->o("imgs")->o(idbuf); if (!iobj) { return res; } dst = iobj->@("dc"); if (!dst) { return res; } StrPrint(idbuf, "%d", d->srcid); iobj = dobj->o("imgs")->o(idbuf); if (!iobj) { return res; } src = iobj->@("dc"); if (!src) { return res; } dx = U32_MAX - d->srcp.x; dy = U32_MAX - d->srcp.y; GrBlot(dst, dx, dy, src); return res; // if (dobj->o("imgs")->o(idbuf)) { // @nt_tx_dbg(nt, "image id %d exists for srcid", d->srcid); // src = dobj->o("imgs")->o(idbuf)->@("dc"); // // if (src) { // @nt_tx_dbg(nt, "src dc: width: %d, height: %d", src->width, src->height); // if (d->dstr.x1 == 640 && d->dstr.y1 == 480 && src->width != 640) { // dx = U32_MAX - d->srcp.x; // dy = U32_MAX - d->srcp.y; // GrBlot(gr.dc, dx, dy, src); // } // } // } // // return 4 + 4 + 4 + sizeof(@Rect) + sizeof(@Point) + sizeof(@Point); } I64 @nt_draw_cmd(@nt* nt, U8* data, JsonObject* dobj, U8* data_ptr, I64 i) { I64 cmd = data_ptr[i++]; I64 res = 0; // size[4] Twrite tag[2] fid[4] offset[8] count[4] @nt_tx_dbg(nt, "draw cmd: %c, offset: 0x%04x", cmd, i - 1 + (4 + 1 + 2 + 4 + 8 + 4)); JsonKey* k; JsonObject* o; CDC* dc; switch (cmd) { case 0: @nt_tx_dbg(nt, "ERROR: draw cmd is NULL, i: 0x%04x", i - 1 + (4 + 1 + 2 + 4 + 8 + 4)); PressAKey; break; case 'A': res = @nt_draw_A(nt, data_ptr + i, dobj); break; case 'p': case 'P': res = @nt_draw_P(nt, data_ptr + i, dobj); break; case 'b': res = @nt_draw_b(nt, data_ptr + i, dobj); break; case 'v': k = dobj->o("imgs")->keys; while (k) { o = k->value; if (o && o->@("dc")) { dc = o->@("dc"); if (dc->width == 640 && dc->height == 480) { GrBlot(nt->screen, 0, 0, dc); } } k = k->next; } // FIXME: update display buffer break; case 'y': res = @nt_draw_y(nt, data_ptr + i, dobj); break; case 'c': // c dstid[4] repl[1] clipr[4*4] // Change the replicate bit and clipping rectangle of the image dstid. res = 4 + 1 + sizeof(@Rect); break; case 'd': res = @nt_draw_d(nt, data_ptr + i, dobj); break; default: // Sleep(5000); @nt_tx_dbg(nt, "ERROR: unimplemented draw cmd: %c, offset: 0x%04x", cmd, i - 1 + (4 + 1 + 2 + 4 + 8 + 4)); // Sleep(5000); PressAKey; break; } return ++res; } U0 @nt_draw(@nt* nt, U8* data, @9p_qid * qid) { SET_MSGS // size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] U8 dobjbuf[32]; StrCpy(dobjbuf, StrFind("/dev/draw/", qid->path) + 10); StrFind("/data", dobjbuf)[0] = NULL; JsonObject* dobj = nt->drawobjs->@(dobjbuf); U64 draw_ptr = data + (4 + 1 + 2 + 4 + 8 + 4); U32 length = *(data + (4 + 1 + 2 + 4 + 8))(U32*); I64 i = 0; while (i < length) { i += @nt_draw_cmd(nt, data, dobj, draw_ptr, i); } }