iv.vfs: don't turn "w+" mode to "r+" mode, lol
[iv.d.git] / sdpyutil.d
blobfddb7ec9ad0ed9ac0e5e76424e7d6b633b8bb577
1 /* Written by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module iv.sdpyutil /*is aliced*/;
19 import arsd.color;
20 import arsd.simpledisplay;
21 import iv.alice;
23 //version = krc_debug;
26 // ////////////////////////////////////////////////////////////////////////// //
27 public bool sdpyHasXShm () {
28 static if (UsingSimpledisplayX11) {
29 __gshared int xshmAvailable = -1;
30 if (xshmAvailable < 0) {
31 int i1, i2, i3;
32 xshmAvailable = (XQueryExtension(XDisplayConnection.get(), "MIT-SHM", &i1, &i2, &i3) != 0 ? 1 : 0);
34 return (xshmAvailable > 0);
35 } else {
36 return false;
41 // ////////////////////////////////////////////////////////////////////////// //
42 /// get desktop number for the given window; -1: unknown
43 public int getWindowDesktop (SimpleWindow sw) {
44 static if (UsingSimpledisplayX11) {
45 import core.stdc.config;
46 if (sw is null || sw.closed) return -1;
47 auto dpy = sw.impl.display;
48 auto xwin = sw.impl.window;
49 auto atomWTF = GetAtom!("_NET_WM_DESKTOP", true)(dpy);
50 Atom aType;
51 int format;
52 c_ulong itemCount;
53 c_ulong bytesAfter;
54 void* propRes;
55 int desktop = -1;
56 auto status = XGetWindowProperty(dpy, xwin, atomWTF, 0, 1, /*False*/0, AnyPropertyType, &aType, &format, &itemCount, &bytesAfter, &propRes);
57 if (status >= Success) {
58 if (propRes !is null) {
59 if (itemCount > 0 && format == 32) desktop = *cast(int*)propRes;
60 XFree(propRes);
63 return desktop;
64 } else {
65 return -1;
70 // ////////////////////////////////////////////////////////////////////////// //
71 /// switch to desktop with the given window
72 public void switchToWindowDesktop(bool doflush=true) (SimpleWindow sw) {
73 static if (UsingSimpledisplayX11) {
74 if (sw is null || sw.closed) return;
75 auto desktop = sw.getWindowDesktop();
76 if (desktop < 0) return;
77 auto dpy = sw.impl.display;
78 XEvent e;
79 e.xclient.type = EventType.ClientMessage;
80 e.xclient.serial = 0;
81 e.xclient.send_event = 1/*True*/;
82 e.xclient.message_type = GetAtom!("_NET_CURRENT_DESKTOP", true)(dpy);
83 e.xclient.window = RootWindow(dpy, DefaultScreen(dpy));
84 e.xclient.format = 32;
85 e.xclient.data.l[0] = desktop;
86 XSendEvent(dpy, RootWindow(dpy, DefaultScreen(dpy)), false, EventMask.SubstructureRedirectMask|EventMask.SubstructureNotifyMask, &e);
87 static if (doflush) flushGui();
92 // ////////////////////////////////////////////////////////////////////////// //
93 /// switch to the given window
94 public void switchToWindow(string src="normal") (SimpleWindow sw) if (src == "normal" || src == "pager") {
95 static if (UsingSimpledisplayX11) {
96 if (sw is null || sw.closed) return;
97 switchToWindowDesktop!false(sw);
98 auto dpy = sw.impl.display;
99 auto xwin = sw.impl.window;
100 XEvent e;
101 e.xclient.type = EventType.ClientMessage;
102 e.xclient.serial = 0;
103 e.xclient.send_event = 1/*True*/;
104 e.xclient.message_type = GetAtom!("_NET_ACTIVE_WINDOW", true)(dpy);
105 e.xclient.window = xwin;
106 e.xclient.format = 32;
107 static if (src == "pager") {
108 e.xclient.data.l[0] = 2; // pretend to be a pager
109 } else {
110 e.xclient.data.l[0] = 1; // application request
112 XSendEvent(dpy, RootWindow(dpy, DefaultScreen(dpy)), false, EventMask.SubstructureRedirectMask|EventMask.SubstructureNotifyMask, &e);
113 flushGui();
118 // ////////////////////////////////////////////////////////////////////////// //
119 /// Get global window coordinates and size. This can be used to show various notifications.
120 void getWindowRect (SimpleWindow sw, out int x, out int y, out int width, out int height) {
121 static if (UsingSimpledisplayX11) {
122 if (sw is null || sw.closed) { width = 1; height = 1; return; } // 1: just in case
123 Window dummyw;
124 //XWindowAttributes xwa;
125 //XGetWindowAttributes(dpy, nativeHandle, &xwa);
126 //XTranslateCoordinates(dpy, nativeHandle, RootWindow(dpy, DefaultScreen(dpy)), xwa.x, xwa.y, &x, &y, &dummyw);
127 XTranslateCoordinates(sw.impl.display, sw.impl.window, RootWindow(sw.impl.display, DefaultScreen(sw.impl.display)), x, y, &x, &y, &dummyw);
128 width = sw.width;
129 height = sw.height;
130 } else {
131 assert(0, "iv.sdpyutil: getWindowRect() -- not for windoze yet");
136 // ////////////////////////////////////////////////////////////////////////// //
137 public void getWorkAreaRect (out int x, out int y, out int width, out int height) {
138 static if (UsingSimpledisplayX11) {
139 import core.stdc.config;
140 width = 800;
141 height = 600;
142 auto dpy = XDisplayConnection.get;
143 if (dpy is null) return;
144 auto root = RootWindow(dpy, DefaultScreen(dpy));
145 auto atomWTF = GetAtom!("_NET_WORKAREA", true)(dpy);
146 Atom aType;
147 int format;
148 c_ulong itemCount;
149 c_ulong bytesAfter;
150 int* propRes;
151 auto status = XGetWindowProperty(dpy, root, atomWTF, 0, 4, /*False*/0, AnyPropertyType, &aType, &format, &itemCount, &bytesAfter, cast(void**)&propRes);
152 if (status >= Success) {
153 if (propRes !is null) {
154 x = propRes[0];
155 y = propRes[1];
156 width = propRes[2];
157 height = propRes[3];
158 XFree(propRes);
161 } else {
162 width = 800;
163 height = 600;
168 // ////////////////////////////////////////////////////////////////////////// //
169 enum _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0;
170 enum _NET_WM_MOVERESIZE_SIZE_TOP = 1;
171 enum _NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2;
172 enum _NET_WM_MOVERESIZE_SIZE_RIGHT = 3;
173 enum _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4;
174 enum _NET_WM_MOVERESIZE_SIZE_BOTTOM = 5;
175 enum _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
176 enum _NET_WM_MOVERESIZE_SIZE_LEFT = 7;
177 enum _NET_WM_MOVERESIZE_MOVE = 8; /* movement only */
178 enum _NET_WM_MOVERESIZE_SIZE_KEYBOARD = 9; /* size via keyboard */
179 enum _NET_WM_MOVERESIZE_MOVE_KEYBOARD = 10; /* move via keyboard */
180 enum _NET_WM_MOVERESIZE_CANCEL = 11; /* cancel operation */
183 public void wmInitiateMoving (SimpleWindow sw, int localx, int localy) {
184 static if (UsingSimpledisplayX11) {
185 if (sw is null || sw.closed || sw.hidden) return;
186 Window dummyw;
187 auto dpy = sw.impl.display;
188 auto xwin = sw.impl.window;
189 auto root = RootWindow(dpy, DefaultScreen(dpy));
190 // convert local to global
191 //{ import core.stdc.stdio; printf("local: %d,%d\n", localx, localy); }
192 XTranslateCoordinates(dpy, xwin, root, localx, localy, &localx, &localy, &dummyw);
193 //{ import core.stdc.stdio; printf("global: %d,%d\n", localx, localy); }
194 // send event
195 XEvent e;
196 e.xclient.type = EventType.ClientMessage;
197 e.xclient.serial = 0;
198 e.xclient.send_event = 1/*True*/;
199 e.xclient.message_type = GetAtom!("_NET_WM_MOVERESIZE", true)(dpy);
200 e.xclient.window = xwin;
201 e.xclient.format = 32;
202 e.xclient.data.l[0] = localx; // root_x
203 e.xclient.data.l[1] = localy; // root_y
204 e.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
205 e.xclient.data.l[3] = 0; // left button
206 e.xclient.data.l[4] = 1; // application request
207 XSendEvent(dpy, root, false, EventMask.SubstructureRedirectMask|EventMask.SubstructureNotifyMask, &e);
208 flushGui();
213 public void wmCancelMoving (SimpleWindow sw, int localx, int localy) {
214 static if (UsingSimpledisplayX11) {
215 if (sw is null || sw.closed || sw.hidden) return;
216 Window dummyw;
217 auto dpy = sw.impl.display;
218 auto xwin = sw.impl.window;
219 auto root = RootWindow(dpy, DefaultScreen(dpy));
220 // convert local to global
221 XTranslateCoordinates(dpy, xwin, root, localx, localy, &localx, &localy, &dummyw);
222 // send event
223 XEvent e;
224 e.xclient.type = EventType.ClientMessage;
225 e.xclient.serial = 0;
226 e.xclient.send_event = 1/*True*/;
227 e.xclient.message_type = GetAtom!("_NET_WM_MOVERESIZE", true)(dpy);
228 e.xclient.window = xwin;
229 e.xclient.format = 32;
230 e.xclient.data.l[0] = localx; // root_x
231 e.xclient.data.l[1] = localy; // root_y
232 e.xclient.data.l[2] = _NET_WM_MOVERESIZE_CANCEL;
233 e.xclient.data.l[3] = 0; // left button
234 e.xclient.data.l[4] = 1; // application request
235 XSendEvent(dpy, root, false, EventMask.SubstructureRedirectMask|EventMask.SubstructureNotifyMask, &e);
236 flushGui();
241 // ////////////////////////////////////////////////////////////////////////// //
242 public struct XRefCounted(T) if (is(T == struct)) {
243 private:
244 usize intrp__;
246 private:
247 static void doIncRef (usize ox) nothrow @trusted @nogc {
248 pragma(inline, true);
249 if (ox) {
250 *cast(uint*)(ox-uint.sizeof) += 1;
251 version(krc_debug) { import core.stdc.stdio : printf; printf("doIncRef for 0x%08x (%u)\n", cast(uint)ox, *cast(uint*)(ox-uint.sizeof)); }
255 static void doDecRef() (ref usize ox) {
256 if (ox) {
257 version(krc_debug) { import core.stdc.stdio : printf; printf("doDecRef for 0x%08x (%u)\n", cast(uint)ox, *cast(uint*)(ox-uint.sizeof)); }
258 if ((*cast(uint*)(ox-uint.sizeof) -= 1) == 0) {
259 // kill and free
260 scope(exit) {
261 import core.stdc.stdlib : free;
262 import core.memory : GC;
264 version(krc_debug) { import core.stdc.stdio : printf; printf("CG CLEANUP FOR WRAPPER 0x%08x\n", cast(uint)ox); }
265 version(krc_debug) import core.stdc.stdio : printf;
266 void* mem = cast(void*)ox;
267 version(krc_debug) { import core.stdc.stdio : printf; printf("DESTROYING WRAPPER 0x%08x\n", cast(uint)mem); }
268 enum instSize = T.sizeof;
269 auto pbm = __traits(getPointerBitmap, T);
270 version(krc_debug) printf("[%.*s]: size=%u (%u) (%u)\n", cast(uint)T.stringof.length, T.stringof.ptr, cast(uint)pbm[0], cast(uint)instSize, cast(uint)(pbm[0]/usize.sizeof));
271 immutable(ubyte)* p = cast(immutable(ubyte)*)(pbm.ptr+1);
272 usize bitnum = 0;
273 immutable end = pbm[0]/usize.sizeof;
274 while (bitnum < end) {
275 if (p[bitnum/8]&(1U<<(bitnum%8))) {
276 usize len = 1;
277 while (bitnum+len < end && (p[(bitnum+len)/8]&(1U<<((bitnum+len)%8))) != 0) ++len;
278 version(krc_debug) printf(" #%u (%u)\n", cast(uint)(bitnum*usize.sizeof), cast(uint)len);
279 GC.removeRange((cast(usize*)mem)+bitnum);
280 bitnum += len;
281 } else {
282 ++bitnum;
286 free(cast(void*)(ox-uint.sizeof));
287 ox = 0;
289 (*cast(T*)ox).destroy;
294 public:
295 this(A...) (auto ref A args) {
296 intrp__ = newOx!T(args);
299 this() (auto ref typeof(this) src) nothrow @trusted @nogc {
300 intrp__ = src.intrp__;
301 doIncRef(intrp__);
304 ~this () { doDecRef(intrp__); }
306 this (this) nothrow @trusted @nogc { doIncRef(intrp__); }
308 void opAssign() (typeof(this) src) {
309 if (!intrp__ && !src.intrp__) return;
310 version(krc_debug) { import core.stdc.stdio : printf; printf("***OPASSIGN(0x%08x -> 0x%08x)\n", cast(void*)src.intrp__, cast(void*)intrp__); }
311 if (intrp__) {
312 // assigning to non-empty
313 if (src.intrp__) {
314 // both streams are active
315 if (intrp__ == src.intrp__) return; // nothing to do
316 auto oldo = intrp__;
317 auto newo = src.intrp__;
318 // first increase rc for new object
319 doIncRef(newo);
320 // replace object for this
321 intrp__ = newo;
322 // release old object
323 doDecRef(oldo);
324 } else {
325 // just close this one
326 scope(exit) intrp__ = 0;
327 doDecRef(intrp__);
329 } else if (src.intrp__) {
330 // this is empty, but other is not; easy deal
331 intrp__ = src.intrp__;
332 doIncRef(intrp__);
336 usize toHash () const pure nothrow @safe @nogc { pragma(inline, true); return intrp__; } // yeah, so simple
337 bool opEquals() (auto ref typeof(this) s) const { pragma(inline, true); return (intrp__ == s.intrp__); }
339 @property bool hasObject () const pure nothrow @trusted @nogc { pragma(inline, true); return (intrp__ != 0); }
341 @property inout(T)* intr_ () inout pure nothrow @trusted @nogc { pragma(inline, true); return cast(typeof(return))intrp__; }
343 // hack!
344 static if (__traits(compiles, ((){T s; bool v = s.valid;}))) {
345 @property bool valid () const nothrow @trusted @nogc { pragma(inline, true); return (intrp__ ? intr_.valid : false); }
348 alias intr_ this;
350 static private:
351 usize newOx (CT, A...) (auto ref A args) if (is(CT == struct)) {
352 import core.exception : onOutOfMemoryErrorNoGC;
353 import core.memory : GC;
354 import core.stdc.stdlib : malloc, free;
355 import core.stdc.string : memset;
356 import std.conv : emplace;
357 enum instSize = CT.sizeof;
358 // let's hope that malloc() aligns returned memory right
359 auto memx = malloc(instSize+uint.sizeof);
360 if (memx is null) onOutOfMemoryErrorNoGC(); // oops
361 scope(failure) free(memx);
362 memset(memx, 0, instSize+uint.sizeof);
363 *cast(uint*)memx = 1;
364 auto mem = memx+uint.sizeof;
365 emplace!CT(mem[0..instSize], args);
367 version(krc_debug) import core.stdc.stdio : printf;
368 auto pbm = __traits(getPointerBitmap, CT);
369 version(krc_debug) printf("[%.*s]: size=%u (%u) (%u)\n", cast(uint)CT.stringof.length, CT.stringof.ptr, cast(uint)pbm[0], cast(uint)instSize, cast(uint)(pbm[0]/usize.sizeof));
370 immutable(ubyte)* p = cast(immutable(ubyte)*)(pbm.ptr+1);
371 usize bitnum = 0;
372 immutable end = pbm[0]/usize.sizeof;
373 while (bitnum < end) {
374 if (p[bitnum/8]&(1U<<(bitnum%8))) {
375 usize len = 1;
376 while (bitnum+len < end && (p[(bitnum+len)/8]&(1U<<((bitnum+len)%8))) != 0) ++len;
377 version(krc_debug) printf(" #%u (%u)\n", cast(uint)(bitnum*usize.sizeof), cast(uint)len);
378 GC.addRange((cast(usize*)mem)+bitnum, usize.sizeof*len);
379 bitnum += len;
380 } else {
381 ++bitnum;
384 version(krc_debug) { import core.stdc.stdio : printf; printf("CREATED WRAPPER 0x%08x\n", mem); }
385 return cast(usize)mem;
390 static if (UsingSimpledisplayX11) {
391 // ////////////////////////////////////////////////////////////////////////// //
392 // for X11 we will keep all XShm-allocated images in this list, so we can free 'em on connection closing.
393 // we'll use glibc malloc()/free(), 'cause `unregisterImage()` can be called from object dtor.
394 private struct XShmSeg {
395 private:
396 __gshared usize headp = 0, tailp = 0;
398 static @property XShmSeg* head () nothrow @trusted @nogc { pragma(inline, true); return cast(XShmSeg*)headp; }
399 static @property void head (XShmSeg* v) nothrow @trusted @nogc { pragma(inline, true); headp = cast(usize)v; }
401 static @property XShmSeg* tail () nothrow @trusted @nogc { pragma(inline, true); return cast(XShmSeg*)tailp; }
402 static @property void tail (XShmSeg* v) nothrow @trusted @nogc { pragma(inline, true); tailp = cast(usize)v; }
404 private:
405 usize segp; // XShmSegmentInfo*; hide it from GC
406 usize prevp; // next link; hide it from GC
407 usize nextp; // next link; hide it from GC
409 private:
410 @property bool valid () const pure nothrow @trusted @nogc { pragma(inline, true); return (segp != 0); }
412 @property XShmSeg* next () pure nothrow @trusted @nogc { pragma(inline, true); return cast(XShmSeg*)nextp; }
413 @property void next (XShmSeg* v) pure nothrow @trusted @nogc { pragma(inline, true); nextp = cast(usize)v; }
415 @property XShmSeg* prev () pure nothrow @trusted @nogc { pragma(inline, true); return cast(XShmSeg*)prevp; }
416 @property void prev (XShmSeg* v) pure nothrow @trusted @nogc { pragma(inline, true); prevp = cast(usize)v; }
418 @property XShmSegmentInfo* seg () pure nothrow @trusted @nogc { pragma(inline, true); return cast(XShmSegmentInfo*)segp; }
419 @property void seg (XShmSegmentInfo* v) pure nothrow @trusted @nogc { pragma(inline, true); segp = cast(usize)v; }
421 static:
422 XShmSeg* alloc () nothrow @trusted @nogc {
423 import core.stdc.stdlib : malloc, free;
424 XShmSeg* res = cast(XShmSeg*)malloc(XShmSeg.sizeof);
425 if (res !is null) {
426 res.seg = cast(XShmSegmentInfo*)malloc(XShmSegmentInfo.sizeof);
427 if (res.seg is null) { free(res); return null; }
428 res.prev = tail;
429 res.next = null;
430 if (tail !is null) tail.next = res; else { assert(head is null); head = res; }
431 tail = res;
433 return res;
436 void free (XShmSeg* seg, bool unregister) {
437 if (seg !is null) {
438 //{ import core.stdc.stdio; printf("00: freeing...\n"); }
439 import core.stdc.stdlib : free;
440 if (seg.prev !is null) seg.prev.next = seg.next; else { assert(head is seg); head = head.next; if (head !is null) head.prev = null; }
441 if (seg.next !is null) seg.next.prev = seg.prev; else { assert(tail is seg); tail = tail.prev; if (tail !is null) tail.next = null; }
442 if (seg.seg) {
443 if (unregister) {
444 //{ import core.stdc.stdio; printf("00: freeing-unreg...\n"); }
445 shmdt(seg.seg.shmaddr);
446 shmctl(seg.seg.shmid, IPC_RMID, null);
448 free(seg.seg);
450 free(seg);
454 void freeList () {
455 import core.stdc.stdlib : free;
456 while (head !is null) {
457 //{ import core.stdc.stdio; printf("01: freeing...\n"); }
458 if (head.seg) {
459 //{ import core.stdc.stdio; printf("01: freeing-unreg...\n"); }
460 shmdt(head.seg.shmaddr);
461 shmctl(head.seg.shmid, IPC_RMID, null);
462 free(head.seg);
464 auto p = head;
465 head = head.next;
466 free(p);
468 tail = null;
471 shared static ~this () { freeList(); }
476 // ////////////////////////////////////////////////////////////////////////// //
477 public alias XImageTC = XRefCounted!XlibImageTC;
479 public struct XlibImageTC {
480 static if (UsingSimpledisplayX11) {
481 private bool thisIsXShm;
482 private union {
483 XImage handle;
484 XImage* handleshm;
486 private XShmSeg* shminfo;
488 @disable this (this);
490 this (MemoryImage img, bool xshm=false) {
491 if (img is null || img.width < 1 || img.height < 1) throw new Exception("can't create xlib image from empty MemoryImage");
492 create(img.width, img.height, img, xshm);
495 this (int wdt, int hgt, bool xshm=false) {
496 if (wdt < 1 || hgt < 1) throw new Exception("invalid xlib image");
497 create(wdt, hgt, null, xshm);
500 this (int wdt, int hgt, MemoryImage aimg, bool xshm=false) {
501 if (wdt < 1 || hgt < 1) throw new Exception("invalid xlib image");
502 create(wdt, hgt, aimg, xshm);
505 ~this () { dispose(); }
507 @property bool valid () const pure nothrow @trusted @nogc { pragma(inline, true); return (thisIsXShm ? handleshm !is null : handle.data !is null); }
508 @property bool xshm () const pure nothrow @trusted @nogc { pragma(inline, true); return thisIsXShm; }
510 @property int width () const pure nothrow @trusted @nogc { pragma(inline, true); return (thisIsXShm ? handleshm.width : handle.width); }
511 @property int height () const pure nothrow @trusted @nogc { pragma(inline, true); return (thisIsXShm ? handleshm.height : handle.height); }
513 inout(uint)* data () inout nothrow @trusted @nogc { pragma(inline, true); return cast(typeof(return))(thisIsXShm ? handleshm.data : handle.data); }
515 void setup (MemoryImage aimg, bool xshm=false) {
516 dispose();
517 if (aimg is null || aimg.width < 1 || aimg.height < 1) throw new Exception("can't create xlib image from empty MemoryImage");
518 create(aimg.width, aimg.height, aimg, xshm);
521 void setup (int wdt, int hgt, MemoryImage aimg=null, bool xshm=false) {
522 dispose();
523 if (wdt < 1 || hgt < 1) throw new Exception("invalid xlib image");
524 create(wdt, hgt, aimg, xshm);
527 TrueColorImage getAsTC () {
528 if (!valid) return null;
529 auto tc = new TrueColorImage(width, height);
530 scope(failure) delete tc;
531 auto sc = cast(const(uint)*)data;
532 auto dc = tc.imageData.colors.ptr;
533 foreach (immutable dy; 0..height) {
534 foreach (immutable dx; 0..width) {
535 *dc++ = img2c(*sc++);
538 return tc;
541 private void create (int width, int height, MemoryImage ximg, bool xshm) {
542 import core.stdc.stdlib : malloc, free;
543 if (xshm && !sdpyHasXShm) xshm = false;
544 thisIsXShm = xshm;
545 if (xshm) {
546 auto dpy = XDisplayConnection.get();
547 if (dpy is null) throw new Exception("can't create XShmImage");
549 shminfo = XShmSeg.alloc();
550 if (shminfo is null) throw new Exception("can't create XShmImage");
551 bool registered = false;
552 scope(failure) { XShmSeg.free(shminfo, registered); shminfo = null; }
554 handleshm = XShmCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 24, ImageFormat.ZPixmap, null, shminfo.seg, width, height);
555 if (handleshm is null) throw new Exception("can't create XShmImage");
556 assert(handleshm.bytes_per_line == 4*width);
558 shminfo.seg.shmid = shmget(IPC_PRIVATE, handleshm.bytes_per_line*height, IPC_CREAT|511 /* 0777 */);
559 assert(shminfo.seg.shmid >= 0);
560 registered = true;
561 handleshm.data = shminfo.seg.shmaddr = cast(ubyte*)shmat(shminfo.seg.shmid, null, 0);
562 assert(handleshm.data != cast(ubyte*)-1);
564 auto rawData = cast(uint*)handleshm.data;
565 if (ximg is null || ximg.width < width || ximg.height < height) rawData[0..width*height] = 0;
566 if (ximg !is null && ximg.width > 0 && ximg.height > 0) {
567 foreach (immutable int y; 0..height) {
568 foreach (immutable int x; 0..width) {
569 rawData[y*width+x] = c2img(ximg.getPixel(x, y));
574 shminfo.seg.readOnly = 0;
575 XShmAttach(dpy, shminfo.seg);
576 } else {
577 auto rawData = cast(uint*)malloc(width*height*4);
578 scope(failure) free(rawData);
579 if (ximg is null || ximg.width < width || ximg.height < height) rawData[0..width*height] = 0;
580 if (ximg !is null && ximg.width > 0 && ximg.height > 0) {
581 foreach (immutable int y; 0..height) {
582 foreach (immutable int x; 0..width) {
583 rawData[y*width+x] = c2img(ximg.getPixel(x, y));
587 //handle = XCreateImage(dpy, DefaultVisual(dpy, screen), 24/*bpp*/, ImageFormat.ZPixmap, 0/*offset*/, cast(ubyte*)rawData, width, height, 8/*FIXME*/, 4*width); // padding, bytes per line
588 handle.width = width;
589 handle.height = height;
590 handle.xoffset = 0;
591 handle.format = ImageFormat.ZPixmap;
592 handle.data = rawData;
593 handle.byte_order = 0;
594 handle.bitmap_unit = 32;
595 handle.bitmap_bit_order = 0;
596 handle.bitmap_pad = 8;
597 handle.depth = 24;
598 handle.bytes_per_line = 0;
599 handle.bits_per_pixel = 32; // THIS MATTERS!
600 handle.red_mask = 0x00ff0000;
601 handle.green_mask = 0x0000ff00;
602 handle.blue_mask = 0x000000ff;
603 XInitImage(&handle);
607 void dispose () {
608 if (thisIsXShm) {
609 if (auto dpy = XDisplayConnection.get()) XShmDetach(dpy, shminfo.seg);
610 XDestroyImage(handleshm);
611 //shmdt(shminfo.seg.shmaddr);
612 //shmctl(shminfo.seg.shmid, IPC_RMID, null);
613 XShmSeg.free(shminfo, true);
614 shminfo = null;
615 handleshm = null;
616 } else {
617 if (handle.data !is null) {
618 import core.stdc.stdlib : free;
619 if (handle.data !is null) free(handle.data);
620 handle = XImage.init;
625 void putPixel (int x, int y, Color c) nothrow @trusted @nogc {
626 pragma(inline, true);
627 if (valid && x >= 0 && y >= 0 && x < width && y < height) {
628 data[y*width+x] = c2img(c);
632 Color getPixel (int x, int y, Color c) nothrow @trusted @nogc {
633 pragma(inline, true);
634 return (valid && x >= 0 && y >= 0 && x < width && y < height ? img2c(data[y*width+x]) : Color.transparent);
637 uint* row (int y) nothrow @trusted @nogc {
638 pragma(inline, true);
639 return (valid && y >= 0 && y < height ? data+y*width : null);
642 // blit to window buffer
643 void blitAt (SimpleWindow w, int destx, int desty) { blitRect(w, destx, desty, 0, 0, width, height); }
645 // blit to window buffer
646 void blitRect (SimpleWindow w, int destx, int desty, int sx0, int sy0, int swdt, int shgt) {
647 if (w is null || !valid || w.closed) return;
648 if (thisIsXShm) {
649 XShmPutImage(w.impl.display, cast(Drawable)w.impl.buffer, w.impl.gc, handleshm, sx0, sy0, destx, desty, swdt, shgt, 0);
650 } else {
651 XPutImage(w.impl.display, cast(Drawable)w.impl.buffer, w.impl.gc, &handle, sx0, sy0, destx, desty, swdt, shgt);
655 // blit to window
656 void blitAtWin (SimpleWindow w, int destx, int desty) { blitRectWin(w, destx, desty, 0, 0, width, height); }
658 // blit to window
659 void blitRectWin (SimpleWindow w, int destx, int desty, int sx0, int sy0, int swdt, int shgt) {
660 if (w is null || !valid || w.closed) return;
661 if (thisIsXShm) {
662 XShmPutImage(w.impl.display, cast(Drawable)w.impl.window, w.impl.gc, handleshm, sx0, sy0, destx, desty, swdt, shgt, 0);
663 } else {
664 XPutImage(w.impl.display, cast(Drawable)w.impl.window, w.impl.gc, &handle, sx0, sy0, destx, desty, swdt, shgt);
669 static:
670 public ubyte icR (uint c) pure nothrow @safe @nogc { pragma(inline, true); return ((c>>16)&0xff); }
671 public ubyte icG (uint c) pure nothrow @safe @nogc { pragma(inline, true); return ((c>>8)&0xff); }
672 public ubyte icB (uint c) pure nothrow @safe @nogc { pragma(inline, true); return (c&0xff); }
673 public ubyte icA (uint c) pure nothrow @safe @nogc { pragma(inline, true); return ((c>>24)&0xff); }
675 public uint icRGB (int r, int g, int b) pure nothrow @safe @nogc {
676 pragma(inline, true);
677 return (Color.clampToByte(r)<<16)|(Color.clampToByte(g)<<8)|Color.clampToByte(b);
680 public uint icRGBA (int r, int g, int b, int a) pure nothrow @safe @nogc {
681 pragma(inline, true);
682 return (Color.clampToByte(a)<<24)|(Color.clampToByte(r)<<16)|(Color.clampToByte(g)<<8)|Color.clampToByte(b);
685 public uint c2img (in Color c) pure nothrow @safe @nogc {
686 pragma(inline, true);
687 return
688 ((c.asUint&0xff)<<16)|
689 (c.asUint&0x00ff00U)|
690 ((c.asUint>>16)&0xff);
693 public uint c2imgA (in Color c) pure nothrow @safe @nogc {
694 pragma(inline, true);
695 return
696 ((c.asUint&0xff)<<16)|
697 (c.asUint&0xff_00ff00U)|
698 ((c.asUint>>16)&0xff);
701 public uint c2img (uint c) pure nothrow @safe @nogc {
702 pragma(inline, true);
703 return
704 ((c&0xff)<<16)|
705 (c&0x00ff00)|
706 ((c>>16)&0xff);
709 public uint c2imgA (uint c) pure nothrow @safe @nogc {
710 pragma(inline, true);
711 return
712 ((c&0xff)<<16)|
713 (c&0xff_00ff00)|
714 ((c>>16)&0xff);
717 public Color img2c (uint clr) pure nothrow @safe @nogc {
718 pragma(inline, true);
719 return Color((clr>>16)&0xff, (clr>>8)&0xff, clr&0xff);
722 public Color img2cA (uint clr) pure nothrow @safe @nogc {
723 pragma(inline, true);
724 return Color((clr>>16)&0xff, (clr>>8)&0xff, clr&0xff, (clr>>24)&0xff);
729 // ////////////////////////////////////////////////////////////////////////// //
730 static if (UsingSimpledisplayX11) {
732 public alias XPixmap = XRefCounted!XlibPixmap;
734 public struct XlibPixmap {
735 Pixmap xpm;
736 private int mWidth, mHeight;
738 this (SimpleWindow w) {}
740 this (SimpleWindow w, int wdt, int hgt) { setup(w, wdt, hgt); }
741 this (SimpleWindow w, ref XlibImageTC xtc) { setup(w, xtc); }
742 this (SimpleWindow w, XImageTC xtc) { if (!xtc.hasObject) throw new Exception("can't create pixmap from empty object"); setup(w, *xtc.intr_); }
744 this (SimpleWindow w, ref XlibPixmap xpm) { setup(w, xpm); }
745 this (SimpleWindow w, XPixmap xpm) { if (!xpm.hasObject) throw new Exception("can't create pixmap from empty object"); setup(w, *xpm.intr_); }
747 @disable this (this);
749 ~this () { dispose(); }
751 @property bool valid () const pure nothrow @trusted @nogc { pragma(inline, true); return (xpm != 0); }
753 @property int width () const pure nothrow @trusted @nogc { pragma(inline, true); return mWidth; }
754 @property int height () const pure nothrow @trusted @nogc { pragma(inline, true); return mHeight; }
756 void copyFromWinBuf (SimpleWindow w) {
757 if (w is null || w.closed) throw new Exception("can't copy pixmap without window");
758 if (!valid || mWidth != w.width || mHeight != w.height) {
759 dispose();
760 xpm = XCreatePixmap(w.impl.display, cast(Drawable)w.impl.window, w.width, w.height, 24);
761 mWidth = w.width;
762 mHeight = w.height;
764 XCopyArea(w.impl.display, cast(Drawable)w.impl.buffer, cast(Drawable)xpm, w.impl.gc, 0, 0, mWidth, mHeight, 0, 0);
767 void copyFrom (SimpleWindow w, ref XlibPixmap axpm) {
768 if (!valid) return;
769 if (!axpm.valid) return;
770 if (w is null || w.closed) throw new Exception("can't copy pixmap without window");
771 XCopyArea(w.impl.display, cast(Drawable)axpm.xpm, cast(Drawable)xpm, w.impl.gc, 0, 0, axpm.width, axpm.height, 0, 0);
774 void copyFrom (SimpleWindow w, XPixmap axpm) {
775 if (!axpm.hasObject) return;
776 copyFrom(w, *axpm.intr_);
779 void setup (SimpleWindow w, int wdt, int hgt) {
780 dispose();
781 if (w is null || w.closed) throw new Exception("can't create pixmap without window");
782 if (wdt < 1) wdt = 1;
783 if (hgt < 1) hgt = 1;
784 if (wdt > 16384) wdt = 16384;
785 if (hgt > 16384) hgt = 16384;
786 xpm = XCreatePixmap(w.impl.display, cast(Drawable)w.impl.window, wdt, hgt, 24);
787 mWidth = wdt;
788 mHeight = hgt;
791 void setup (SimpleWindow w, XPixmap xpm) {
792 if (!xpm.hasObject) throw new Exception("can't create pixmap from empty xlib image");
793 setup(w, *xpm.intr_);
796 void setup (SimpleWindow w, ref XlibPixmap axpm) {
797 if (!axpm.valid) throw new Exception("can't create pixmap from empty xlib pixmap");
798 dispose();
799 if (w is null || w.closed) throw new Exception("can't create pixmap without window");
800 int wdt = axpm.width;
801 int hgt = axpm.height;
802 if (wdt < 1) wdt = 1;
803 if (hgt < 1) hgt = 1;
804 if (wdt > 16384) wdt = 16384;
805 if (hgt > 16384) hgt = 16384;
806 xpm = XCreatePixmap(w.impl.display, cast(Drawable)w.impl.window, wdt, hgt, 24);
807 XCopyArea(w.impl.display, cast(Drawable)axpm.xpm, cast(Drawable)xpm, w.impl.gc, 0, 0, wdt, hgt, 0, 0);
808 mWidth = wdt;
809 mHeight = hgt;
812 void setup (SimpleWindow w, XImageTC xtc) {
813 if (!xtc.hasObject) throw new Exception("can't create pixmap from empty xlib image");
814 setup(w, *xtc.intr_);
817 void setup (SimpleWindow w, ref XlibImageTC xtc) {
818 if (!xtc.valid) throw new Exception("can't create pixmap from empty xlib image");
819 dispose();
820 if (w is null || w.closed) throw new Exception("can't create pixmap without window");
821 int wdt = xtc.width;
822 int hgt = xtc.height;
823 if (wdt < 1) wdt = 1;
824 if (hgt < 1) hgt = 1;
825 if (wdt > 16384) wdt = 16384;
826 if (hgt > 16384) hgt = 16384;
827 xpm = XCreatePixmap(w.impl.display, cast(Drawable)w.impl.window, wdt, hgt, 24);
828 // source x, source y
829 if (xtc.thisIsXShm) {
830 XShmPutImage(w.impl.display, cast(Drawable)xpm, w.impl.gc, xtc.handleshm, 0, 0, 0, 0, wdt, hgt, 0);
831 } else {
832 XPutImage(w.impl.display, cast(Drawable)xpm, w.impl.gc, &xtc.handle, 0, 0, 0, 0, wdt, hgt);
834 mWidth = wdt;
835 mHeight = hgt;
838 void dispose () {
839 if (xpm) {
840 XFreePixmap(XDisplayConnection.get(), xpm);
841 xpm = 0;
843 mWidth = mHeight = 0;
846 // blit to window buffer
847 void blitAt (SimpleWindow w, int x, int y) {
848 blitRect(w, x, y, 0, 0, width, height);
851 // blit to window buffer
852 void blitRect (SimpleWindow w, int destx, int desty, int sx0, int sy0, int swdt, int shgt) {
853 if (w is null || !xpm || w.closed) return;
854 XCopyArea(w.impl.display, cast(Drawable)xpm, cast(Drawable)w.impl.buffer, w.impl.gc, sx0, sy0, swdt, shgt, destx, desty);
857 // blit to window buffer
858 void blitAtWin (SimpleWindow w, int x, int y) {
859 blitRectWin(w, x, y, 0, 0, width, height);
862 // blit to window buffer
863 void blitRectWin (SimpleWindow w, int destx, int desty, int sx0, int sy0, int swdt, int shgt) {
864 if (w is null || !xpm || w.closed) return;
865 XCopyArea(w.impl.display, cast(Drawable)xpm, cast(Drawable)w.impl.window, w.impl.gc, sx0, sy0, swdt, shgt, destx, desty);
869 // ////////////////////////////////////////////////////////////////////////// //
873 void sdpyNormalizeArrowKeys(bool domods=true) (ref KeyEvent event) {
874 static if (domods) {
875 switch (event.key) {
876 case Key.Ctrl_r: event.key = Key.Ctrl; return;
877 case Key.Shift_r: event.key = Key.Shift; return;
878 case Key.Alt_r: event.key = Key.Alt; return;
879 case Key.Windows_r: event.key = Key.Windows; return;
880 default:
883 if ((event.modifierState&ModifierState.numLock) == 0) {
884 switch (event.key) {
885 case Key.PadEnter: event.key = Key.Enter; return;
886 case Key.Pad1: event.key = Key.End; return;
887 case Key.Pad2: event.key = Key.Down; return;
888 case Key.Pad3: event.key = Key.PageDown; return;
889 case Key.Pad4: event.key = Key.Left; return;
890 //case Key.Pad5: event.key = Key.; return;
891 case Key.Pad6: event.key = Key.Right; return;
892 case Key.Pad7: event.key = Key.Home; return;
893 case Key.Pad8: event.key = Key.Up; return;
894 case Key.Pad9: event.key = Key.PageUp; return;
895 case Key.Pad0: event.key = Key.Insert; return;
896 default:
903 // ////////////////////////////////////////////////////////////////////////// //
904 // this mixin can be used to alphablend two `uint` colors
905 // `colu32name` is variable that holds color to blend,
906 // `destu32name` is variable that holds "current" color (from surface, for example)
907 // alpha value of `destu32name` doesn't matter
908 // alpha value of `colu32name` means: 255 for replace color, 0 for keep `destu32name` (was reversed)
909 private enum ColorBlendMixinStr(string colu32name, string destu32name) = "{
910 immutable uint a_tmp_ = (256-(255-(("~colu32name~")>>24)))&(-(1-(((255-(("~colu32name~")>>24))+1)>>8))); // to not loose bits, but 255 should become 0
911 immutable uint dc_tmp_ = ("~destu32name~")&0xffffff;
912 immutable uint srb_tmp_ = (("~colu32name~")&0xff00ff);
913 immutable uint sg_tmp_ = (("~colu32name~")&0x00ff00);
914 immutable uint drb_tmp_ = (dc_tmp_&0xff00ff);
915 immutable uint dg_tmp_ = (dc_tmp_&0x00ff00);
916 immutable uint orb_tmp_ = (drb_tmp_+(((srb_tmp_-drb_tmp_)*a_tmp_+0x800080)>>8))&0xff00ff;
917 immutable uint og_tmp_ = (dg_tmp_+(((sg_tmp_-dg_tmp_)*a_tmp_+0x008000)>>8))&0x00ff00;
918 ("~destu32name~") = (orb_tmp_|og_tmp_)|0xff000000; /*&0xffffff;*/
922 Color blend (Color dst, Color src) nothrow @trusted @nogc {
923 pragma(inline, true);
924 mixin(ColorBlendMixinStr!("src.asUint", "dst.asUint"));
925 return dst;
929 // the only two requirements: alpha is in high bits, and "0 alpha" means "transparent"
930 uint blendU32 (uint dst, uint src) nothrow @trusted @nogc {
931 pragma(inline, true);
932 mixin(ColorBlendMixinStr!("src", "dst"));
933 return dst;
937 Color blend (Color dst, Color src) pure nothrow @trusted @nogc { pragma(inline, true); return dst.alphaBlend(src); }
938 uint blendU32 (uint dst, uint src) pure nothrow @trusted @nogc { pragma(inline, true); mixin(Color.ColorBlendMixinStr!("src", "dst")); return dst; }
941 // ////////////////////////////////////////////////////////////////////////// //
942 import iv.gxx.geom;
944 // some "fastgfx" backend
945 class SdpyDrawBase {
946 protected:
947 static T abs(T) (T n) pure nothrow @safe @nogc { pragma(inline, true); return (n < 0 ? -n : n); }
949 version(Windows) {
950 private static int lrintf (float f) nothrow @trusted @nogc { pragma(inline, true); return cast(int)(f+0.5f); }
951 private static int lrintd (double f) nothrow @trusted @nogc { pragma(inline, true); return cast(int)(f+0.5); }
952 } else {
953 private import core.stdc.math : lrintf, lrintd = lrint;
955 private import core.stdc.math : sqrtf, sqrtd = sqrt;
956 private import core.stdc.math : floorf, floord = floor;
957 private import core.stdc.math : cosf, sinf;
959 public:
960 GxSize dim;
961 GxRect clip;
963 protected: // low-level methods; will always be called with valid coords
964 // must be overriden
965 abstract Color getpix (int x, int y);
966 abstract void putpix (int x, int y, Color c);
968 // optionals
969 void hline (int x, int y, int len, Color c) {
970 while (len-- > 0) putpix(x++, y, c);
973 void vline (int x, int y, int len, Color c) {
974 while (len-- > 0) putpix(x, y++, c);
977 void fillrc (int x, int y, int w, int h, Color c) {
978 while (h-- > 0) hline(x, y++, w, c);
981 public:
982 this (int awdt, int ahgt) {
983 if (awdt < 0) awdt = 0;
984 if (ahgt < 0) ahgt = 0;
985 dim = GxSize(awdt, ahgt);
986 clip = GxRect(dim);
989 final @property int width () const pure nothrow @safe @nogc { pragma(inline, true); return dim.width; }
990 final @property int height () const pure nothrow @safe @nogc { pragma(inline, true); return dim.height; }
992 void cls (Color clr=Color.white) { fillrc(0, 0, dim.width, dim.height, clr); }
994 // can return null, yeah
995 TrueColorImage getBuffer () { return null; }
997 final:
998 Color getPixel (int x, int y) {
999 pragma(inline, true);
1000 return (x >= 0 && y >= 0 && x < dim.width && y < dim.height && clip.inside(x, y) ? getpix(x, y) : Color.transparent);
1003 void putPixel (int x, int y, Color c) {
1004 pragma(inline, true);
1005 if (x >= 0 && y >= 0 && x < dim.width && y < dim.height && clip.inside(x, y)) putpix(x, y, c);
1008 void drawHLine (int x, int y, int len, Color c) {
1009 pragma(inline, true);
1010 if (GxRect(dim).clipHStripe(x, y, len) && clip.clipHStripe(x, y, len)) hline(x, y, len, c);
1013 void drawVLine (int x, int y, int len, Color c) {
1014 pragma(inline, true);
1015 if (GxRect(dim).clipVStripe(x, y, len) && clip.clipVStripe(x, y, len)) vline(x, y, len, c);
1018 void fillRect (int x, int y, int w, int h, Color c) {
1019 pragma(inline, true);
1020 if (GxRect(dim).clipHVStripes(x, y, w, h) && clip.clipHVStripes(x, y, w, h)) fillrc(x, y, w, h, c);
1023 void drawRect(bool filled) (int x, int y, int w, int h, Color c) {
1024 pragma(inline, true);
1025 static if (filled) {
1026 if (GxRect(dim).clipHVStripes(x, y, w, h) && clip.clipHVStripes(x, y, w, h)) fillrc(x, y, w, h, c);
1027 } else {
1028 hline(x, y, w, c);
1029 if (h > 1) hline(x, y+h-1, w, c);
1030 if (h > 2 && w > 2) {
1031 vline(x+1, y, w-2, c);
1032 vline(x+1, y+h-1, w-2, c);
1037 void drawEllipse(bool filled=false) (int x0, int y0, int x1, int y1, Color col) {
1038 int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; // values of diameter
1039 long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; // error increment
1040 long err = dx+dy+b1*a*a; // error of 1.step
1041 int prev_y0 = -1, prev_y1 = -1;
1042 if (x0 > x1) { x0 = x1; x1 += a; } // if called with swapped points...
1043 if (y0 > y1) y0 = y1; // ...exchange them
1044 y0 += (b+1)/2; y1 = y0-b1; // starting pixel
1045 a *= 8*a; b1 = 8*b*b;
1046 do {
1047 long e2;
1048 if (y0 != prev_y0) {
1049 static if (filled) {
1050 drawHLine(x0, y0, x1-x0+1, col);
1051 } else {
1052 putPixel(x0, y0, col);
1053 if (x1 != x0) putPixel(x1, y0, col);
1055 prev_y0 = y0;
1057 if (y1 != y0 && y1 != prev_y1) {
1058 static if (filled) {
1059 drawHLine(x0, y1, x1-x0+1, col);
1060 } else {
1061 putPixel(x0, y1, col);
1062 if (x1 != x0) putPixel(x1, y1, col);
1064 prev_y1 = y1;
1066 e2 = 2*err;
1067 if (e2 >= dx) { ++x0; --x1; err += dx += b1; } // x step
1068 if (e2 <= dy) { ++y0; --y1; err += dy += a; } // y step
1069 } while (x0 <= x1);
1070 while (y0-y1 < b) {
1071 // too early stop of flat ellipses a=1
1072 putPixel(x0-1, ++y0, col); // complete tip of ellipse
1073 putPixel(x0-1, --y1, col);
1077 void drawCircle(bool filled=false) (int cx, int cy, int radius, Color col) {
1078 if (radius < 1) return;
1079 int error = -radius, x = radius, y = 0;
1080 if (radius == 1) { putPixel(cx, cy, col); return; }
1081 while (x >= y) {
1082 int last_y = y;
1083 error += y;
1084 ++y;
1085 error += y;
1086 static if (filled) {
1087 drawHLine(cx-x, cy+last_y, 2*x+1, col);
1088 } else {
1089 putPixel(cx-x, cy+last_y, col);
1090 if (x != 0) putPixel(cx+x, cy+last_y, col);
1092 if (x != 0 && last_y != 0) {
1093 static if (filled) {
1094 drawHLine(cx-x, cy-last_y, 2*x+1, col);
1095 } else {
1096 putPixel(cx-x, cy-last_y, col);
1097 putPixel(cx+x, cy-last_y, col);
1100 if (error >= 0) {
1101 if (x != last_y) {
1102 static if (filled) {
1103 drawHLine(cx-last_y, cy+x, 2*last_y+1, col);
1104 if (last_y != 0 && x != 0) drawHLine(cx-last_y, cy-x, 2*last_y+1, col);
1105 } else {
1106 putPixel(cx-last_y, cy+x, col);
1107 if (last_y != 0 && x != 0) {
1108 putPixel(cx+last_y, cy+x, col);
1109 putPixel(cx-last_y, cy-x, col);
1110 putPixel(cx+last_y, cy-x, col);
1114 error -= x;
1115 --x;
1116 error -= x;
1121 void drawLineEx(bool lastPoint=true) (int x0, int y0, int x1, int y1, scope void delegate (int x, int y) putPixel) {
1122 enum swap(string a, string b) = "{int tmp_="~a~";"~a~"="~b~";"~b~"=tmp_;}";
1124 if (x0 == x1 && y0 == y1) {
1125 static if (lastPoint) putPixel(x0, y0);
1126 return;
1129 // clip rectange
1130 int wx0 = clip.x0, wy0 = clip.y0, wx1 = clip.x1, wy1 = clip.y1;
1131 if (wx0 < 0) wx0 = 0; else if (wx0 >= dim.width) wx0 = dim.width-1;
1132 if (wx1 < 0) wx1 = 0; else if (wx1 >= dim.width) wx1 = dim.width-1;
1133 if (wy0 < 0) wy0 = 0; else if (wy0 >= dim.height) wy0 = dim.height-1;
1134 if (wy1 < 0) wy1 = 0; else if (wy1 >= dim.height) wy1 = dim.height-1;
1135 if (wx0 > wx1 || wy0 > wy1) return;
1136 // other vars
1137 int stx, sty; // "steps" for x and y axes
1138 int dsx, dsy; // "lengthes" for x and y axes
1139 int dx2, dy2; // "double lengthes" for x and y axes
1140 int xd, yd; // current coord
1141 int e; // "error" (as in bresenham algo)
1142 int rem;
1143 int term;
1144 int* d0, d1;
1145 // horizontal setup
1146 if (x0 < x1) {
1147 // from left to right
1148 if (x0 > wx1 || x1 < wx0) return; // out of screen
1149 stx = 1; // going right
1150 } else {
1151 // from right to left
1152 if (x1 > wx1 || x0 < wx0) return; // out of screen
1153 stx = -1; // going left
1154 x0 = -x0;
1155 x1 = -x1;
1156 wx0 = -wx0;
1157 wx1 = -wx1;
1158 mixin(swap!("wx0", "wx1"));
1160 // vertical setup
1161 if (y0 < y1) {
1162 // from top to bottom
1163 if (y0 > wy1 || y1 < wy0) return; // out of screen
1164 sty = 1; // going down
1165 } else {
1166 // from bottom to top
1167 if (y1 > wy1 || y0 < wy0) return; // out of screen
1168 sty = -1; // going up
1169 y0 = -y0;
1170 y1 = -y1;
1171 wy0 = -wy0;
1172 wy1 = -wy1;
1173 mixin(swap!("wy0", "wy1"));
1175 dsx = x1-x0;
1176 dsy = y1-y0;
1177 if (dsx < dsy) {
1178 d0 = &yd;
1179 d1 = &xd;
1180 mixin(swap!("x0", "y0"));
1181 mixin(swap!("x1", "y1"));
1182 mixin(swap!("dsx", "dsy"));
1183 mixin(swap!("wx0", "wy0"));
1184 mixin(swap!("wx1", "wy1"));
1185 mixin(swap!("stx", "sty"));
1186 } else {
1187 d0 = &xd;
1188 d1 = &yd;
1190 dx2 = 2*dsx;
1191 dy2 = 2*dsy;
1192 xd = x0;
1193 yd = y0;
1194 e = 2*dsy-dsx;
1195 term = x1;
1196 bool xfixed = false;
1197 if (y0 < wy0) {
1198 // clip at top
1199 int temp = dx2*(wy0-y0)-dsx;
1200 xd += temp/dy2;
1201 rem = temp%dy2;
1202 if (xd > wx1) return; // x is moved out of clipping rect, nothing to do
1203 if (xd+1 >= wx0) {
1204 yd = wy0;
1205 e -= rem+dsx;
1206 if (rem > 0) { ++xd; e += dy2; }
1207 xfixed = true;
1210 if (!xfixed && x0 < wx0) {
1211 // clip at left
1212 int temp = dy2*(wx0-x0);
1213 yd += temp/dx2;
1214 rem = temp%dx2;
1215 if (yd > wy1 || yd == wy1 && rem >= dsx) return;
1216 xd = wx0;
1217 e += rem;
1218 if (rem >= dsx) { ++yd; e -= dx2; }
1220 if (y1 > wy1) {
1221 // clip at bottom
1222 int temp = dx2*(wy1-y0)+dsx;
1223 term = x0+temp/dy2;
1224 rem = temp%dy2;
1225 if (rem == 0) --term;
1227 if (term > wx1) term = wx1; // clip at right
1228 static if (lastPoint) {
1229 // draw last point
1230 ++term;
1231 } else {
1232 if (term == xd) return; // this is the only point, get out of here
1234 if (sty == -1) yd = -yd;
1235 if (stx == -1) { xd = -xd; term = -term; }
1236 dx2 -= dy2;
1237 // draw it; `putPixel()` can omit checks
1238 while (xd != term) {
1239 putPixel(*d0, *d1);
1240 // done drawing, move coords
1241 if (e >= 0) {
1242 yd += sty;
1243 e -= dx2;
1244 } else {
1245 e += dy2;
1247 xd += stx;
1251 void drawLine(bool lastPoint=true) (int x0, int y0, int x1, int y1, Color c) { drawLineEx!lastPoint(x0, y0, x1, y1, (x, y) => putPixel(x, y, c)); }
1253 // ////////////////////////////////////////////////////////////////////// //
1254 // plot a limited quadratic Bezier segment
1255 final void drawQuadBezierSeg (int x0, int y0, int x1, int y1, int x2, int y2, Color fc) {
1256 int sx = x2-x1, sy = y2-y1;
1257 long xx = x0-x1, yy = y0-y1; // relative values for checks
1258 assert(xx*sx <= 0 && yy*sy <= 0); // sign of gradient must not change
1259 double cur = xx*sy-yy*sx; // curvature
1260 // begin with longer part
1261 if (sx*cast(long)sx+sy*cast(long)sy > xx*xx+yy*yy) { x2 = x0; x0 = sx+x1; y2 = y0; y0 = sy+y1; cur = -cur; } // swap P0 P2
1262 // no straight line
1263 if (cur != 0) {
1264 xx += sx; xx *= (sx = (x0 < x2 ? 1 : -1)); // x step direction
1265 yy += sy; yy *= (sy = (y0 < y2 ? 1 : -1)); // y step direction
1266 // differences 2nd degree
1267 long xy = 2*xx*yy;
1268 xx *= xx;
1269 yy *= yy;
1270 // negated curvature?
1271 if (cur*sx*sy < 0) { xx = -xx; yy = -yy; xy = -xy; cur = -cur; }
1272 double dx = 4.0*sy*cur*(x1-x0)+xx-xy; // differences 1st degree
1273 double dy = 4.0*sx*cur*(y0-y1)+yy-xy;
1274 xx += xx;
1275 yy += yy;
1276 double err = dx+dy+xy; // error 1st step
1277 do {
1278 putPixel(x0, y0, fc); // plot curve
1279 if (x0 == x2 && y0 == y2) return; // last pixel -> curve finished
1280 y1 = 2*err < dx; // save value for test of y step
1281 if (2*err > dy) { x0 += sx; dx -= xy; err += dy += yy; } // x step
1282 if (y1) { y0 += sy; dy -= xy; err += dx += xx; } // y step
1283 } while (dy < 0 && dx > 0); // gradient negates -> algorithm fails
1285 drawLine(x0, y0, x2, y2, fc); // plot remaining part to end
1288 // plot any quadratic Bezier curve
1289 final void drawQuadBezier (int x0, int y0, int x1, int y1, int x2, int y2, Color fc) {
1290 int x = x0-x1, y = y0-y1;
1291 double t = x0-2*x1+x2;
1292 // horizontal cut at P4?
1293 if (cast(long)x*(x2-x1) > 0) {
1294 // vertical cut at P6 too?
1295 if (cast(long)y*(y2-y1) > 0) {
1296 // which first?
1297 if (abs((y0-2*y1+y2)/t*x) > abs(y)) { x0 = x2; x2 = x+x1; y0 = y2; y2 = y+y1; } // swap points
1298 // now horizontal cut at P4 comes first
1300 t = (x0-x1)/t;
1301 double r = (1-t)*((1-t)*y0+2.0*t*y1)+t*t*y2; // By(t=P4)
1302 t = (x0*x2-x1*x1)*t/(x0-x1); // gradient dP4/dx=0
1303 x = lrintd(t); y = lrintd(r);
1304 r = (y1-y0)*(t-x0)/(x1-x0)+y0; // intersect P3 | P0 P1
1305 drawQuadBezierSeg(x0, y0, x, lrintd(r), x, y, fc);
1306 r = (y1-y2)*(t-x2)/(x1-x2)+y2; // intersect P4 | P1 P2
1307 x0 = x1 = x; y0 = y; y1 = lrintd(r); // P0 = P4, P1 = P8
1309 // vertical cut at P6?
1310 if (cast(long)(y0-y1)*(y2-y1) > 0) {
1311 t = y0-2*y1+y2; t = (y0-y1)/t;
1312 double r = (1-t)*((1-t)*x0+2.0*t*x1)+t*t*x2; // Bx(t=P6)
1313 t = (y0*y2-y1*y1)*t/(y0-y1); // gradient dP6/dy=0
1314 x = lrintd(r); y = lrintd(t);
1315 r = (x1-x0)*(t-y0)/(y1-y0)+x0; // intersect P6 | P0 P1
1316 drawQuadBezierSeg(x0, y0, lrintd(r), y, x, y, fc);
1317 r = (x1-x2)*(t-y2)/(y1-y2)+x2; // intersect P7 | P1 P2
1318 x0 = x; x1 = lrintd(r); y0 = y1 = y; // P0 = P6, P1 = P7
1320 drawQuadBezierSeg(x0, y0, x1, y1, x2, y2, fc); // remaining part
1323 // plot a limited rational Bezier segment, squared weight
1324 final void drawQuadRationalBezierSeg (int x0, int y0, int x1, int y1, int x2, int y2, float w, Color fc) {
1325 int sx = x2-x1, sy = y2-y1; // relative values for checks
1326 double dx = x0-x2, dy = y0-y2, xx = x0-x1, yy = y0-y1;
1327 double xy = xx*sy+yy*sx, cur = xx*sy-yy*sx; // curvature
1328 assert(xx*sx <= 0.0 && yy*sy <= 0.0); // sign of gradient must not change
1329 if (cur != 0.0 && w > 0.0) { // no straight line
1330 // begin with longer part
1331 if (sx*cast(long)sx+sy*cast(long)sy > xx*xx+yy*yy) { x2 = x0; x0 -= cast(int)dx; y2 = y0; y0 -= cast(int)dy; cur = -cur; } // swap P0 P2
1332 xx = 2.0*(4.0*w*sx*xx+dx*dx); // differences 2nd degree
1333 yy = 2.0*(4.0*w*sy*yy+dy*dy);
1334 sx = (x0 < x2 ? 1 : -1); // x step direction
1335 sy = (y0 < y2 ? 1 : -1); // y step direction
1336 xy = -2.0*sx*sy*(2.0*w*xy+dx*dy);
1337 // negated curvature?
1338 if (cur*sx*sy < 0.0) { xx = -xx; yy = -yy; xy = -xy; cur = -cur; }
1339 dx = 4.0*w*(x1-x0)*sy*cur+xx/2.0+xy; // differences 1st degree
1340 dy = 4.0*w*(y0-y1)*sx*cur+yy/2.0+xy;
1341 if (w < 0.5 && dy > dx) {
1342 // flat ellipse, algorithm fails
1343 cur = (w+1.0)/2.0; w = sqrtf(w); xy = 1.0/(w+1.0);
1344 sx = lrintd((x0+2.0*w*x1+x2)*xy/2.0); // subdivide curve in half
1345 sy = lrintd((y0+2.0*w*y1+y2)*xy/2.0);
1346 dx = floord((w*x1+x0)*xy+0.5); dy = floord((y1*w+y0)*xy+0.5);
1347 drawQuadRationalBezierSeg(x0, y0, cast(int)dx, cast(int)dy, sx, sy, cur, fc);/* plot separately */
1348 dx = floord((w*x1+x2)*xy+0.5); dy = floord((y1*w+y2)*xy+0.5);
1349 drawQuadRationalBezierSeg(sx, sy, cast(int)dx, cast(int)dy, x2, y2, cur, fc);
1350 return;
1352 double err = dx+dy-xy; // error 1.step
1353 do {
1354 putPixel(x0, y0, fc); // plot curve
1355 if (x0 == x2 && y0 == y2) return; // last pixel -> curve finished
1356 x1 = 2*err > dy; y1 = 2*(err+yy) < -dy;/* save value for test of x step */
1357 if (2*err < dx || y1) { y0 += sy; dy += xy; err += dx += xx; }/* y step */
1358 if (2*err > dx || x1) { x0 += sx; dx += xy; err += dy += yy; }/* x step */
1359 } while (dy <= xy && dx >= xy); // gradient negates -> algorithm fails
1361 drawLine(x0, y0, x2, y2, fc); // plot remaining needle to end
1364 // rectangle enclosing the ellipse, integer rotation angle
1365 final void drawRotatedEllipseRect (int x0, int y0, int x1, int y1, long zd, Color fc) {
1366 int xd = x1-x0, yd = y1-y0;
1367 float w = xd*cast(long)yd;
1368 if (zd == 0) return drawEllipse(x0, y0, x1, y1, fc); // looks nicer
1369 if (w != 0.0) w = (w-zd)/(w+w); // squared weight of P1
1370 assert(w <= 1.0 && w >= 0.0); // limit angle to |zd|<=xd*yd
1371 // snap xe,ye to int
1372 xd = lrintf(xd*w);
1373 yd = lrintf(yd*w);
1374 drawQuadRationalBezierSeg(x0, y0+yd, x0, y0, x0+xd, y0, 1.0-w, fc);
1375 drawQuadRationalBezierSeg(x0, y0+yd, x0, y1, x1-xd, y1, w, fc);
1376 drawQuadRationalBezierSeg(x1, y1-yd, x1, y1, x1-xd, y1, 1.0-w, fc);
1377 drawQuadRationalBezierSeg(x1, y1-yd, x1, y0, x0+xd, y0, w, fc);
1380 // plot ellipse rotated by angle (radian)
1381 final void drawRotatedEllipse (int x, int y, int a, int b, float angle, Color fc) {
1382 float xd = cast(long)a*a, yd = cast(long)b*b;
1383 float s = sinf(angle), zd = (xd-yd)*s; // ellipse rotation
1384 xd = sqrtf(xd-zd*s), yd = sqrtf(yd+zd*s); // surrounding rectangle
1385 a = lrintf(xd);
1386 b = lrintf(yd);
1387 zd = zd*a*b/(xd*yd); // scale to integer
1388 drawRotatedEllipseRect(x-a, y-b, x+a, y+b, cast(long)(4*zd*cosf(angle)), fc);
1391 // plot limited cubic Bezier segment
1392 final void drawCubicBezierSeg (int x0, int y0, float x1, float y1, float x2, float y2, int x3, int y3, Color fc) {
1393 immutable double EP = 0.01;
1394 int leg = 1;
1395 int sx = (x0 < x3 ? 1 : -1), sy = (y0 < y3 ? 1 : -1); // step direction
1396 float xc = -abs(x0+x1-x2-x3), xa = xc-4*sx*(x1-x2), xb = sx*(x0-x1-x2+x3);
1397 float yc = -abs(y0+y1-y2-y3), ya = yc-4*sy*(y1-y2), yb = sy*(y0-y1-y2+y3);
1398 // check for curve restrains
1399 // slope P0-P1 == P2-P3 and (P0-P3 == P1-P2 or no slope change)
1400 assert((x1-x0)*(x2-x3) < EP && ((x3-x0)*(x1-x2) < EP || xb*xb < xa*xc+EP));
1401 assert((y1-y0)*(y2-y3) < EP && ((y3-y0)*(y1-y2) < EP || yb*yb < ya*yc+EP));
1402 // quadratic Bezier
1403 if (xa == 0 && ya == 0) {
1404 // new midpoint
1405 sx = cast(int)floorf((3*x1-x0+1)/2);
1406 sy = cast(int)floorf((3*y1-y0+1)/2);
1407 return drawQuadBezierSeg(x0, y0, sx, sy, x3, y3, fc);
1409 x1 = (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+1; // line lengths
1410 x2 = (x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)+1;
1411 // loop over both ends
1412 do {
1413 double ab = xa*yb-xb*ya;
1414 double ac = xa*yc-xc*ya;
1415 double bc = xb*yc-xc*yb;
1416 double ex = ab*(ab+ac-3*bc)+ac*ac; // P0 part of self-intersection loop?
1417 immutable int f = cast(int)(ex > 0 ? 1 : sqrtf(1+1024/x1)); // calculate resolution
1418 ab *= f; ac *= f; bc *= f; ex *= f*f; // increase resolution
1419 // init differences of 1st degree
1420 double xy = 9*(ab+ac+bc)/8;
1421 double cb = 8*(xa-ya);
1422 double dx = 27*(8*ab*(yb*yb-ya*yc)+ex*(ya+2*yb+yc))/64-ya*ya*(xy-ya);
1423 double dy = 27*(8*ab*(xb*xb-xa*xc)-ex*(xa+2*xb+xc))/64-xa*xa*(xy+xa);
1424 // init differences of 2nd degree
1425 double xx = 3*(3*ab*(3*yb*yb-ya*ya-2*ya*yc)-ya*(3*ac*(ya+yb)+ya*cb))/4;
1426 double yy = 3*(3*ab*(3*xb*xb-xa*xa-2*xa*xc)-xa*(3*ac*(xa+xb)+xa*cb))/4;
1427 xy = xa*ya*(6*ab+6*ac-3*bc+cb); ac = ya*ya; cb = xa*xa;
1428 xy = 3*(xy+9*f*(cb*yb*yc-xb*xc*ac)-18*xb*yb*ab)/8;
1429 // negate values if inside self-intersection loop
1430 if (ex < 0) { dx = -dx; dy = -dy; xx = -xx; yy = -yy; xy = -xy; ac = -ac; cb = -cb; }
1431 // init differences of 3rd degree
1432 ab = 6*ya*ac;
1433 ac = -6*xa*ac;
1434 bc = 6*ya*cb;
1435 cb = -6*xa*cb;
1436 // error of 1st step
1437 dx += xy;
1438 ex = dx+dy;
1439 dy += xy;
1440 const(double)* pxy = &xy;
1441 zzloop: for (int fx = f, fy = f; x0 != x3 && y0 != y3; ) {
1442 putPixel(x0, y0, fc); // plot curve
1443 // move sub-steps of one pixel
1444 do {
1445 if (dx > *pxy || dy < *pxy) break zzloop; // confusing values
1446 y1 = 2*ex-dy; // save value for test of y step
1447 if (2*ex >= dx) { fx--; ex += dx += xx; dy += xy += ac; yy += bc; xx += ab; } // x sub-step
1448 if (y1 <= 0) { fy--; ex += dy += yy; dx += xy += bc; xx += ac; yy += cb; } // y sub-step
1449 } while (fx > 0 && fy > 0); // pixel complete?
1450 if (2*fx <= f) { x0 += sx; fx += f; } // x step
1451 if (2*fy <= f) { y0 += sy; fy += f; } // y step
1452 if (pxy == &xy && dx < 0 && dy > 0) pxy = &EP; // pixel ahead valid
1454 // swap legs
1455 xx = x0; x0 = x3; x3 = cast(int)xx; sx = -sx; xb = -xb;
1456 yy = y0; y0 = y3; y3 = cast(int)yy; sy = -sy; yb = -yb; x1 = x2;
1457 } while (leg--); // try other end
1458 drawLine(x0, y0, x3, y3, fc); // remaining part in case of cusp or crunode
1461 // plot any cubic Bezier curve
1462 final void drawCubicBezier (int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, Color fc) {
1463 int n = 0, i = 0;
1464 long xc = x0+x1-x2-x3, xa = xc-4*(x1-x2);
1465 long xb = x0-x1-x2+x3, xd = xb+4*(x1+x2);
1466 long yc = y0+y1-y2-y3, ya = yc-4*(y1-y2);
1467 long yb = y0-y1-y2+y3, yd = yb+4*(y1+y2);
1468 float fx0 = x0, fy0 = y0;
1469 double t1 = xb*xb-xa*xc;
1470 double[5] t = void;
1471 // sub-divide curve at gradient sign changes
1472 if (xa == 0) { // horizontal
1473 if (abs(xc) < 2*abs(xb)) t.ptr[n++] = xc/(2.0*xb); // one change
1474 } else if (t1 > 0.0) { // two changes
1475 immutable double t2 = sqrtd(t1);
1476 t1 = (xb-t2)/xa; if (abs(t1) < 1.0) t.ptr[n++] = t1;
1477 t1 = (xb+t2)/xa; if (abs(t1) < 1.0) t.ptr[n++] = t1;
1479 t1 = yb*yb-ya*yc;
1480 if (ya == 0) { // vertical
1481 if (abs(yc) < 2*abs(yb)) t.ptr[n++] = yc/(2.0*yb); // one change
1482 } else if (t1 > 0.0) { // two changes
1483 immutable double t2 = sqrtd(t1);
1484 t1 = (yb-t2)/ya; if (abs(t1) < 1.0) t.ptr[n++] = t1;
1485 t1 = (yb+t2)/ya; if (abs(t1) < 1.0) t.ptr[n++] = t1;
1487 // bubble sort of 4 points
1488 for (i = 1; i < n; i++) if ((t1 = t.ptr[i-1]) > t.ptr[i]) { t.ptr[i-1] = t.ptr[i]; t.ptr[i] = t1; i = 0; }
1489 t1 = -1.0; t.ptr[n] = 1.0; // begin / end point
1490 for (i = 0; i <= n; i++) { // plot each segment separately
1491 immutable double t2 = t.ptr[i]; // sub-divide at t[i-1], t[i]
1492 float fx1 = (t1*(t1*xb-2*xc)-t2*(t1*(t1*xa-2*xb)+xc)+xd)/8-fx0;
1493 float fy1 = (t1*(t1*yb-2*yc)-t2*(t1*(t1*ya-2*yb)+yc)+yd)/8-fy0;
1494 float fx2 = (t2*(t2*xb-2*xc)-t1*(t2*(t2*xa-2*xb)+xc)+xd)/8-fx0;
1495 float fy2 = (t2*(t2*yb-2*yc)-t1*(t2*(t2*ya-2*yb)+yc)+yd)/8-fy0;
1496 immutable float fx3 = (t2*(t2*(3*xb-t2*xa)-3*xc)+xd)/8;
1497 immutable float fy3 = (t2*(t2*(3*yb-t2*ya)-3*yc)+yd)/8;
1498 fx0 -= fx3;
1499 fy0 -= fy3;
1500 // scale bounds to int
1501 x3 = lrintf(fx3);
1502 y3 = lrintf(fy3);
1503 if (fx0 != 0.0f) { fx1 *= fx0 = (x0-x3)/fx0; fx2 *= fx0; }
1504 if (fy0 != 0.0f) { fy1 *= fy0 = (y0-y3)/fy0; fy2 *= fy0; }
1505 if (x0 != x3 || y0 != y3) drawCubicBezierSeg(x0, y0, x0+fx1, y0+fy1, x0+fx2, y0+fy2, x3, y3, fc); // segment t1 - t2
1506 x0 = x3; y0 = y3; fx0 = fx3; fy0 = fy3; t1 = t2;
1510 // ////////////////////////////////////////////////////////////////////////// //
1511 enum BaphometDims = 512; // [0..511]
1512 final void renderBaphomet (Color fc, float ofsx=0, float ofsy=0, float scalex=1, float scaley=1) {
1513 auto path = cast(const(ubyte)[])baphometPath;
1514 immutable plen = path.length;
1515 uint ppos = 0;
1517 enum Command {
1518 Bounds, // always first, has 4 args (x0, y0, x1, y1)
1519 StrokeMode,
1520 FillMode,
1521 StrokeFillMode,
1522 NormalStroke,
1523 ThinStroke,
1524 MoveTo,
1525 LineTo,
1526 CubicTo, // cubic bezier
1527 EndPath,
1530 Command getCommand () nothrow @trusted @nogc {
1531 if (ppos >= plen) assert(0, "invalid path");
1532 return cast(Command)(path.ptr[ppos++]);
1535 float getFloat () nothrow @trusted @nogc {
1536 if (ppos >= plen || plen-ppos < float.sizeof) assert(0, "invalid path");
1537 version(LittleEndian) {
1538 float res = *cast(const(float)*)(&path.ptr[ppos]);
1539 ppos += cast(uint)float.sizeof;
1540 return res;
1541 } else {
1542 static assert(float.sizeof == 4);
1543 uint xp = path.ptr[ppos]|(path.ptr[ppos+1]<<8)|(path.ptr[ppos+2]<<16)|(path.ptr[ppos+3]<<24);
1544 ppos += cast(uint)float.sizeof;
1545 return *cast(const(float)*)(&xp);
1549 int scaleX (float v) nothrow @trusted @nogc { pragma(inline, true); return lrintf(ofsx+v*scalex); }
1550 int scaleY (float v) nothrow @trusted @nogc { pragma(inline, true); return lrintf(ofsy+v*scaley); }
1552 int cx = 0, cy = 0;
1553 while (ppos < plen) {
1554 auto cmd = getCommand();
1555 final switch (cmd) {
1556 case Command.Bounds: ppos += 4*cast(uint)float.sizeof; break;
1557 case Command.StrokeMode: case Command.FillMode: case Command.StrokeFillMode: break;
1558 case Command.NormalStroke: case Command.ThinStroke: break;
1559 case Command.MoveTo:
1560 cx = scaleX(getFloat());
1561 cy = scaleY(getFloat());
1562 break;
1563 case Command.LineTo:
1564 immutable int ex = scaleX(getFloat());
1565 immutable int ey = scaleY(getFloat());
1566 drawLine(cx, cy, ex, ey, fc);
1567 cx = ex;
1568 cy = ey;
1569 break;
1570 case Command.CubicTo: // cubic bezier
1571 immutable int x1 = scaleX(getFloat());
1572 immutable int y1 = scaleY(getFloat());
1573 immutable int x2 = scaleX(getFloat());
1574 immutable int y2 = scaleY(getFloat());
1575 immutable int ex = scaleX(getFloat());
1576 immutable int ey = scaleY(getFloat());
1577 drawCubicBezier(cx, cy, x1, y1, x2, y2, ex, ey, fc);
1578 cx = ex;
1579 cy = ey;
1580 break;
1581 case Command.EndPath: // don't close this path
1582 break;
1587 // ////////////////////////////////////////////////////////////////////////// //
1588 enum CharWidth = 10, CharHeight = 10;
1590 void drawChar (int x, int y, char ch, Color c, Color bg=Color.transparent) {
1591 foreach (immutable dy; 0..10) {
1592 ushort w = confont10.ptr[ch*10+dy];
1593 foreach (immutable dx; 0..10) {
1594 if (w&0x8000) {
1595 if (c.a != 0) putPixel(x+dx, y+dy, c);
1596 } else {
1597 if (bg.a != 0) putPixel(x+dx, y+dy, bg);
1599 w <<= 1;
1604 void drawText (int x, int y, const(char)[] text, Color c, Color bg=Color.transparent) {
1605 foreach (char ch; text) {
1606 drawChar(x, y, ch, c, bg);
1607 x += CharWidth;
1611 void drawTextShadow (int x, int y, const(char)[] text, Color c, Color shadc) {
1612 drawText(x+1, y+1, text, shadc);
1613 drawText(x, y, text, c);
1616 // ////////////////////////////////////////////////////////////////////////// //
1617 static public __gshared immutable ushort[256*10] confont10 = [
1618 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x4080,0x5280,0x4080,0x5e80,0x4c80,0x2100,0x1e00,
1619 0x0000,0x0000,0x3f00,0x7f80,0x6d80,0x7f80,0x6180,0x7380,0x3f00,0x1e00,0x0000,0x0000,0x3b80,0x7fc0,0x7fc0,0x7fc0,0x3f80,0x1f00,0x0e00,
1620 0x0400,0x0000,0x0400,0x0e00,0x1f00,0x3f80,0x7fc0,0x3f80,0x1f00,0x0e00,0x0400,0x0000,0x0000,0x0e00,0x1f00,0x0e00,0x3f80,0x7fc0,0x3580,
1621 0x0400,0x0e00,0x0000,0x0400,0x0e00,0x1f00,0x3f80,0x7fc0,0x7fc0,0x3580,0x0400,0x0e00,0x0000,0x0000,0x0000,0x0000,0x0c00,0x1e00,0x1e00,
1622 0x0c00,0x0000,0x0000,0x0000,0xffc0,0xffc0,0xffc0,0xf3c0,0xe1c0,0xe1c0,0xf3c0,0xffc0,0xffc0,0xffc0,0x0000,0x0000,0x1e00,0x3300,0x2100,
1623 0x2100,0x3300,0x1e00,0x0000,0x0000,0xffc0,0xffc0,0xe1c0,0xccc0,0xdec0,0xdec0,0xccc0,0xe1c0,0xffc0,0xffc0,0x0000,0x0780,0x0380,0x0780,
1624 0x3e80,0x6600,0x6600,0x6600,0x3c00,0x0000,0x0000,0x1e00,0x3300,0x3300,0x3300,0x1e00,0x0c00,0x3f00,0x0c00,0x0000,0x0400,0x0600,0x0700,
1625 0x0500,0x0500,0x0400,0x1c00,0x3c00,0x1800,0x0000,0x0000,0x1f80,0x1f80,0x1080,0x1080,0x1180,0x3380,0x7100,0x2000,0x0000,0x0000,0x0c00,
1626 0x6d80,0x1e00,0x7380,0x7380,0x1e00,0x6d80,0x0c00,0x0000,0x1000,0x1800,0x1c00,0x1e00,0x1f00,0x1e00,0x1c00,0x1800,0x1000,0x0000,0x0100,
1627 0x0300,0x0700,0x0f00,0x1f00,0x0f00,0x0700,0x0300,0x0100,0x0000,0x0000,0x0c00,0x1e00,0x3f00,0x0c00,0x0c00,0x3f00,0x1e00,0x0c00,0x0000,
1628 0x0000,0x3300,0x3300,0x3300,0x3300,0x3300,0x0000,0x3300,0x0000,0x0000,0x0000,0x3f80,0x6d80,0x6d80,0x3d80,0x0d80,0x0d80,0x0d80,0x0000,
1629 0x0000,0x0000,0x1f00,0x3000,0x1f00,0x3180,0x1f00,0x0180,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7f80,0x7f80,0x7f80,
1630 0x0000,0x0000,0x0000,0x0c00,0x1e00,0x3f00,0x0c00,0x0c00,0x3f00,0x1e00,0x0c00,0xffc0,0x0000,0x0c00,0x1e00,0x3f00,0x0c00,0x0c00,0x0c00,
1631 0x0c00,0x0c00,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x3f00,0x1e00,0x0c00,0x0000,0x0000,0x0000,0x0600,0x0300,0x7f80,0x0300,
1632 0x0600,0x0000,0x0000,0x0000,0x0000,0x0000,0x1800,0x3000,0x7f80,0x3000,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6000,
1633 0x6000,0x6000,0x7f80,0x0000,0x0000,0x0000,0x0000,0x1100,0x3180,0x7fc0,0x3180,0x1100,0x0000,0x0000,0x0000,0x0000,0x0000,0x0400,0x0e00,
1634 0x1f00,0x3f80,0x7fc0,0x0000,0x0000,0x0000,0x0000,0x0000,0x7fc0,0x3f80,0x1f00,0x0e00,0x0400,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
1635 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x1e00,0x1e00,0x0c00,0x0c00,0x0000,0x0c00,0x0000,0x0000,0x0000,0x1b00,
1636 0x1b00,0x1b00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1b00,0x1b00,0x7fc0,0x1b00,0x7fc0,0x1b00,0x1b00,0x0000,0x0000,0x0400,
1637 0x1f00,0x3580,0x3400,0x1f00,0x0580,0x3580,0x1f00,0x0400,0x0000,0x0000,0x3180,0x3300,0x0600,0x0c00,0x1980,0x3180,0x0000,0x0000,0x0000,
1638 0x0000,0x1c00,0x3300,0x3300,0x1f80,0x3300,0x3300,0x1d80,0x0000,0x0000,0x0000,0x0e00,0x0c00,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,
1639 0x0000,0x0000,0x0600,0x0c00,0x1800,0x1800,0x1800,0x0c00,0x0600,0x0000,0x0000,0x0000,0x1800,0x0c00,0x0600,0x0600,0x0600,0x0c00,0x1800,
1640 0x0000,0x0000,0x0000,0x0000,0x3300,0x1e00,0x7f80,0x1e00,0x3300,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x3f00,0x0c00,0x0c00,
1641 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0000,
1642 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0180,0x0300,0x0600,0x0c00,
1643 0x1800,0x3000,0x6000,0x0000,0x0000,0x0000,0x1f00,0x3380,0x3780,0x3f80,0x3d80,0x3980,0x1f00,0x0000,0x0000,0x0000,0x0c00,0x1c00,0x0c00,
1644 0x0c00,0x0c00,0x0c00,0x3f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x0180,0x0f00,0x1800,0x3180,0x3f80,0x0000,0x0000,0x0000,0x1f00,0x3180,
1645 0x0180,0x0700,0x0180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x0700,0x0f00,0x1b00,0x3300,0x3f80,0x0300,0x0780,0x0000,0x0000,0x0000,0x3f80,
1646 0x3000,0x3000,0x3f00,0x0180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x0f00,0x1800,0x3000,0x3f00,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,
1647 0x3f80,0x3180,0x0180,0x0300,0x0600,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x1f00,0x3180,0x3180,0x1f00,0x0000,0x0000,
1648 0x0000,0x1f00,0x3180,0x3180,0x1f80,0x0180,0x0300,0x1e00,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0c00,0x0c00,0x0000,
1649 0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0c00,0x0c00,0x1800,0x0000,0x0000,0x0300,0x0600,0x0c00,0x1800,0x0c00,0x0600,0x0300,
1650 0x0000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x1800,0x0c00,0x0600,0x0300,0x0600,0x0c00,
1651 0x1800,0x0000,0x0000,0x0000,0x1e00,0x3300,0x0300,0x0300,0x0600,0x0c00,0x0000,0x0c00,0x0000,0x0000,0x3f00,0x6180,0x6780,0x6d80,0x6780,
1652 0x6000,0x3f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3f80,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,
1653 0x3180,0x3180,0x3f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3000,0x3000,0x3180,0x1f00,0x0000,0x0000,0x0000,0x3e00,0x3300,0x3180,
1654 0x3180,0x3180,0x3300,0x3e00,0x0000,0x0000,0x0000,0x3f80,0x3000,0x3000,0x3f00,0x3000,0x3000,0x3f80,0x0000,0x0000,0x0000,0x3f80,0x3000,
1655 0x3000,0x3f00,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3380,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x3180,
1656 0x3180,0x3180,0x3f80,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x1e00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0000,
1657 0x0700,0x0300,0x0300,0x0300,0x3300,0x3300,0x1e00,0x0000,0x0000,0x0000,0x3180,0x3180,0x3300,0x3e00,0x3300,0x3180,0x3180,0x0000,0x0000,
1658 0x0000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3f80,0x0000,0x0000,0x0000,0x6180,0x7380,0x7f80,0x6d80,0x6180,0x6180,0x6180,0x0000,
1659 0x0000,0x0000,0x3180,0x3980,0x3d80,0x3780,0x3380,0x3180,0x3180,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x3180,0x3180,0x1f00,
1660 0x0000,0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x3180,0x3380,
1661 0x1f00,0x0380,0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,0x3300,0x3180,0x3180,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x1f00,0x0180,
1662 0x3180,0x1f00,0x0000,0x0000,0x0000,0x7f80,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,0x3180,
1663 0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,0x3180,0x1b00,0x0e00,0x0400,0x0000,0x0000,0x0000,0x6180,0x6180,0x6180,
1664 0x6d80,0x7f80,0x7380,0x6180,0x0000,0x0000,0x0000,0x6180,0x3300,0x1e00,0x0c00,0x1e00,0x3300,0x6180,0x0000,0x0000,0x0000,0x6180,0x6180,
1665 0x3300,0x1e00,0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x3f80,0x0300,0x0600,0x0c00,0x1800,0x3000,0x3f80,0x0000,0x0000,0x0000,0x1e00,
1666 0x1800,0x1800,0x1800,0x1800,0x1800,0x1e00,0x0000,0x0000,0x0000,0x6000,0x3000,0x1800,0x0c00,0x0600,0x0300,0x0000,0x0000,0x0000,0x0000,
1667 0x1e00,0x0600,0x0600,0x0600,0x0600,0x0600,0x1e00,0x0000,0x0000,0x0000,0x0400,0x0e00,0x1b00,0x3180,0x0000,0x0000,0x0000,0x0000,0x0000,
1668 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffc0,0x0000,0x0000,0x1c00,0x0c00,0x0600,0x0000,0x0000,0x0000,0x0000,0x0000,
1669 0x0000,0x0000,0x0000,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0000,0x3000,0x3000,0x3f00,0x3180,0x3180,0x3180,0x3f00,
1670 0x0000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3180,0x1f00,0x0000,0x0000,0x0000,0x0180,0x0180,0x1f80,0x3180,0x3180,0x3180,
1671 0x1f80,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,0x0000,0x0000,0x0000,0x0f00,0x1800,0x1800,0x3e00,0x1800,
1672 0x1800,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3180,0x3180,0x3180,0x1f80,0x0180,0x1f00,0x0000,0x3000,0x3000,0x3f00,0x3180,
1673 0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x0c00,0x0000,0x1c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0000,0x0600,0x0000,0x0e00,
1674 0x0600,0x0600,0x0600,0x0600,0x0600,0x1c00,0x0000,0x3000,0x3000,0x3180,0x3300,0x3e00,0x3300,0x3180,0x0000,0x0000,0x0000,0x1c00,0x0c00,
1675 0x0c00,0x0c00,0x0c00,0x0c00,0x0700,0x0000,0x0000,0x0000,0x0000,0x0000,0x3300,0x7f80,0x6d80,0x6d80,0x6180,0x0000,0x0000,0x0000,0x0000,
1676 0x0000,0x3f00,0x3180,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,
1677 0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3180,0x3180,0x1f80,0x0180,0x01c0,0x0000,
1678 0x0000,0x0000,0x0000,0x3f00,0x3180,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3000,0x1f00,0x0180,0x3f00,0x0000,
1679 0x0000,0x0000,0x1800,0x1800,0x3e00,0x1800,0x1800,0x1800,0x0f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,
1680 0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x3180,0x1b00,0x0e00,0x0400,0x0000,0x0000,0x0000,0x0000,0x0000,0x6180,0x6d80,0x6d80,0x7f80,
1681 0x3300,0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x1b00,0x0e00,0x1b00,0x3180,0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,
1682 0x1f80,0x0180,0x1f00,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0600,0x0c00,0x1800,0x3f00,0x0000,0x0000,0x0000,0x0e00,0x1800,0x1800,0x3000,
1683 0x1800,0x1800,0x0e00,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x1c00,0x0600,0x0600,
1684 0x0300,0x0600,0x0600,0x1c00,0x0000,0x0000,0x0000,0x0000,0x0000,0x3800,0x6d80,0x0700,0x0000,0x0000,0x0000,0x0000,0x0000,0x0400,0x0e00,
1685 0x1b00,0x3180,0x3180,0x3180,0x3f80,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3000,0x3000,0x3180,0x1f00,0x0c00,0x1800,0x0000,0x1b00,
1686 0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x0600,0x0c00,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,0x0000,0x0000,0x0e00,
1687 0x1b00,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,
1688 0x0c00,0x0600,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0e00,0x1b00,0x0e00,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,
1689 0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3180,0x1f00,0x0c00,0x1800,0x0e00,0x1b00,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,
1690 0x0000,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,0x0000,0x0000,0x0c00,0x0600,0x0000,0x1f00,0x3180,0x3f80,0x3000,
1691 0x1f00,0x0000,0x0000,0x0000,0x3600,0x0000,0x1c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x1c00,0x3600,0x0000,0x1c00,0x0c00,0x0c00,
1692 0x0c00,0x1e00,0x0000,0x0000,0x1800,0x0c00,0x0000,0x1c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x3180,
1693 0x3f80,0x3180,0x3180,0x0000,0x0000,0x0e00,0x1b00,0x0e00,0x1f00,0x3180,0x3f80,0x3180,0x3180,0x0000,0x0000,0x0600,0x0c00,0x0000,0x3f80,
1694 0x3000,0x3f00,0x3000,0x3f80,0x0000,0x0000,0x0000,0x0000,0x0000,0x3b80,0x0ec0,0x3fc0,0x6e00,0x3b80,0x0000,0x0000,0x0000,0x1f80,0x3600,
1695 0x6600,0x7f80,0x6600,0x6600,0x6780,0x0000,0x0000,0x0e00,0x1b00,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x1b00,
1696 0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0c00,0x0600,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0e00,
1697 0x1b00,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x0c00,0x0600,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,
1698 0x0000,0x1b00,0x0000,0x3180,0x3180,0x3180,0x1f80,0x0180,0x1f00,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,
1699 0x0000,0x0000,0x1b00,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x0000,0x0000,0x0400,0x1f00,0x3580,0x3400,0x3580,0x1f00,
1700 0x0400,0x0000,0x0000,0x0f00,0x1980,0x1800,0x3e00,0x1800,0x1800,0x3000,0x3f80,0x0000,0x0000,0x6180,0x6180,0x3300,0x1e00,0x3f00,0x0c00,
1701 0x3f00,0x0c00,0x0000,0x0000,0x7f00,0x6180,0x6d80,0x6d80,0x7f00,0x6c00,0x6c00,0x6700,0x0000,0x0000,0x0700,0x0c00,0x0c00,0x1e00,0x0c00,
1702 0x0c00,0x0c00,0x3800,0x0000,0x0600,0x0c00,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0c00,0x1800,0x0000,0x1c00,0x0c00,
1703 0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0600,0x0c00,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0600,0x0c00,0x0000,0x3180,
1704 0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x1d80,0x3700,0x0000,0x3f00,0x3180,0x3180,0x3180,0x3180,0x0000,0x0000,0x1d80,0x3700,0x0000,
1705 0x3980,0x3d80,0x3780,0x3380,0x3180,0x0000,0x0000,0x0000,0x1e00,0x0300,0x1f00,0x3300,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x1e00,
1706 0x3300,0x3300,0x3300,0x1e00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0000,0x0c00,0x1800,0x3000,0x3000,0x3300,0x1e00,0x0000,0x0000,
1707 0x0000,0x0000,0x0000,0x3f80,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f80,0x0180,0x0180,0x0180,0x0000,0x0000,
1708 0x0000,0x2080,0x2100,0x2200,0x2400,0x0b00,0x1180,0x2300,0x4380,0x0000,0x0000,0x2080,0x2100,0x2200,0x2400,0x0a80,0x1280,0x2380,0x4080,
1709 0x0000,0x0000,0x0c00,0x0000,0x0c00,0x0c00,0x1e00,0x1e00,0x0c00,0x0000,0x0000,0x0000,0x0000,0x1980,0x3300,0x6600,0x3300,0x1980,0x0000,
1710 0x0000,0x0000,0x0000,0x0000,0x6600,0x3300,0x1980,0x3300,0x6600,0x0000,0x0000,0x0000,0x2200,0x8880,0x2200,0x8880,0x2200,0x8880,0x2200,
1711 0x8880,0x2200,0x8880,0x5540,0xaa80,0x5540,0xaa80,0x5540,0xaa80,0x5540,0xaa80,0x5540,0xaa80,0xbb80,0xeec0,0xbb80,0xeec0,0xbb80,0xeec0,
1712 0xbb80,0xeec0,0xbb80,0xeec0,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0xfc00,
1713 0xfc00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0xfc00,0xfc00,0x0c00,0x0c00,0xfc00,0xfc00,0x0c00,0x0c00,0x3300,0x3300,0x3300,0x3300,
1714 0xf300,0xf300,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,0x0000,0x0000,0xff00,0xff00,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,0xfc00,
1715 0xfc00,0x0c00,0x0c00,0xfc00,0xfc00,0x0c00,0x0c00,0x3300,0x3300,0xf300,0xf300,0x0300,0x0300,0xf300,0xf300,0x3300,0x3300,0x3300,0x3300,
1716 0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,0xff00,0xff00,0x0300,0x0300,0xf300,0xf300,0x3300,0x3300,0x3300,
1717 0x3300,0xf300,0xf300,0x0300,0x0300,0xff00,0xff00,0x0000,0x0000,0x3300,0x3300,0x3300,0x3300,0xff00,0xff00,0x0000,0x0000,0x0000,0x0000,
1718 0x1800,0x1800,0xf800,0xf800,0x1800,0x1800,0xf800,0xf800,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xfc00,0xfc00,0x0c00,0x0c00,0x0c00,
1719 0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0xffc0,0xffc0,0x0000,0x0000,
1720 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffc0,0xffc0,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,
1721 0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0xffc0,0xffc0,
1722 0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x3300,0x3300,0x3300,0x3300,0x33c0,
1723 0x33c0,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x33c0,0x33c0,0x3000,0x3000,0x3fc0,0x3fc0,0x0000,0x0000,0x0000,0x0000,0x3fc0,0x3fc0,
1724 0x3000,0x3000,0x33c0,0x33c0,0x3300,0x3300,0x3300,0x3300,0xf3c0,0xf3c0,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,0xffc0,
1725 0xffc0,0x0000,0x0000,0xf3c0,0xf3c0,0x3300,0x3300,0x3300,0x3300,0x33c0,0x33c0,0x3000,0x3000,0x33c0,0x33c0,0x3300,0x3300,0x0000,0x0000,
1726 0xffc0,0xffc0,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x3300,0x3300,0xf3c0,0xf3c0,0x0000,0x0000,0xf3c0,0xf3c0,0x3300,0x3300,0x0c00,
1727 0x0c00,0xffc0,0xffc0,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x3300,0x3300,0x3300,0x3300,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,
1728 0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0xffc0,0xffc0,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0xffc0,0xffc0,0x3300,0x3300,0x3300,
1729 0x3300,0x3300,0x3300,0x3300,0x3300,0x3fc0,0x3fc0,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0fc0,0x0fc0,
1730 0x0000,0x0000,0x0000,0x0000,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0x3fc0,0x3fc0,0x3300,
1731 0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0xf3c0,0xf3c0,0x3300,0x3300,0x3300,0x3300,0x0c00,0x0c00,0xffc0,0xffc0,0x0000,0x0000,
1732 0xffc0,0xffc0,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0xfc00,0xfc00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0fc0,
1733 0x0fc0,0x0c00,0x0c00,0x0c00,0x0c00,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,
1734 0x0000,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0x07c0,0x07c0,0x07c0,
1735 0x07c0,0x07c0,0x07c0,0x07c0,0x07c0,0x07c0,0x07c0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
1736 0x0000,0x1d80,0x3700,0x3200,0x3700,0x1d80,0x0000,0x0000,0x0000,0x1e00,0x3300,0x3300,0x3600,0x3300,0x3180,0x3700,0x3000,0x0000,0x0000,
1737 0x3f80,0x3180,0x3000,0x3000,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x7f80,0x3300,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,
1738 0x0000,0x3f80,0x1800,0x0c00,0x0600,0x0c00,0x1800,0x3f80,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3600,0x3300,0x3300,0x1e00,0x0000,
1739 0x0000,0x0000,0x0000,0x0000,0x6300,0x6300,0x6700,0x7d80,0x6000,0x6000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0c00,0x0c00,0x0c00,0x0600,
1740 0x0000,0x0000,0x0000,0x1e00,0x0c00,0x3f00,0x6d80,0x6d80,0x3f00,0x0c00,0x1e00,0x0000,0x0000,0x1e00,0x3300,0x3300,0x3f00,0x3300,0x3300,
1741 0x1e00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x3180,0x1b00,0x3b80,0x0000,0x0000,0x0000,0x1f00,0x0c00,0x0600,0x1f00,0x3180,
1742 0x3180,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x3b80,0x66c0,0x64c0,0x6cc0,0x3b80,0x0000,0x0000,0x0000,0x0000,0x0180,0x3f00,0x6780,
1743 0x6d80,0x7980,0x3f00,0x6000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3000,0x1e00,0x3000,0x1f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,
1744 0x3180,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0000,0x3f00,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,
1745 0x3f00,0x0c00,0x0c00,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0600,0x0c00,0x1800,0x0c00,0x0600,0x0000,0x3f00,0x0000,0x0000,0x0000,0x1800,
1746 0x0c00,0x0600,0x0c00,0x1800,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0700,0x0d80,0x0d80,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,
1747 0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x6c00,0x6c00,0x3800,0x0000,0x0000,0x0000,0x0c00,0x0000,0x3f00,0x0000,0x0c00,0x0000,0x0000,0x0000,
1748 0x0000,0x3800,0x6d80,0x0700,0x0000,0x3800,0x6d80,0x0700,0x0000,0x0000,0x0000,0x0e00,0x1b00,0x1b00,0x0e00,0x0000,0x0000,0x0000,0x0000,
1749 0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0000,0x0000,0x0000,
1750 0x0000,0x0000,0x0000,0x07c0,0x0600,0x0600,0x6600,0x3600,0x1e00,0x0e00,0x0600,0x0200,0x0000,0x3e00,0x3300,0x3300,0x3300,0x3300,0x0000,
1751 0x0000,0x0000,0x0000,0x0000,0x1e00,0x0300,0x0e00,0x1800,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1e00,0x1e00,0x1e00,
1752 0x1e00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
1755 private static immutable ubyte[7641] baphometPath = [
1756 0x01,0x04,0x06,0x30,0x89,0x7f,0x43,0x00,0x80,0xff,0x43,0x08,0xa0,0x1d,0xc6,0x43,0x00,0x80,0xff,0x43,
1757 0x00,0x80,0xff,0x43,0xa2,0x1d,0xc6,0x43,0x00,0x80,0xff,0x43,0x30,0x89,0x7f,0x43,0x08,0x00,0x80,0xff,
1758 0x43,0x7a,0x89,0xe5,0x42,0xa0,0x1d,0xc6,0x43,0x00,0x00,0x00,0x00,0x30,0x89,0x7f,0x43,0x00,0x00,0x00,
1759 0x00,0x08,0x7a,0x89,0xe5,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7a,0x89,0xe5,0x42,0x00,0x00,
1760 0x00,0x00,0x30,0x89,0x7f,0x43,0x08,0x00,0x00,0x00,0x00,0xa2,0x1d,0xc6,0x43,0x7a,0x89,0xe5,0x42,0x00,
1761 0x80,0xff,0x43,0x30,0x89,0x7f,0x43,0x00,0x80,0xff,0x43,0x09,0x06,0x30,0x89,0x7f,0x43,0x72,0x87,0xdd,
1762 0x43,0x08,0x16,0x68,0xb3,0x43,0x72,0x87,0xdd,0x43,0x71,0x87,0xdd,0x43,0x17,0x68,0xb3,0x43,0x71,0x87,
1763 0xdd,0x43,0x30,0x89,0x7f,0x43,0x08,0x71,0x87,0xdd,0x43,0xd2,0x2f,0x18,0x43,0x16,0x68,0xb3,0x43,0x35,
1764 0xe2,0x87,0x42,0x30,0x89,0x7f,0x43,0x35,0xe2,0x87,0x42,0x08,0xd1,0x2f,0x18,0x43,0x35,0xe2,0x87,0x42,
1765 0x35,0xe2,0x87,0x42,0xd2,0x2f,0x18,0x43,0x35,0xe2,0x87,0x42,0x30,0x89,0x7f,0x43,0x08,0x35,0xe2,0x87,
1766 0x42,0x17,0x68,0xb3,0x43,0xd1,0x2f,0x18,0x43,0x72,0x87,0xdd,0x43,0x30,0x89,0x7f,0x43,0x72,0x87,0xdd,
1767 0x43,0x09,0x06,0x79,0xcb,0x11,0x43,0x62,0xbf,0xd7,0x42,0x07,0xa4,0x3f,0x7f,0x43,0x0b,0x86,0xdc,0x43,
1768 0x07,0x6c,0xb9,0xb2,0x43,0xe8,0xd1,0xca,0x42,0x07,0x6e,0x4d,0xa0,0x42,0xa9,0x10,0x9c,0x43,0x07,0xb7,
1769 0x40,0xd7,0x43,0xa9,0x10,0x9c,0x43,0x07,0x79,0xcb,0x11,0x43,0x62,0xbf,0xd7,0x42,0x09,0x06,0x98,0x42,
1770 0x74,0x43,0xb1,0x8d,0x68,0x43,0x08,0xd7,0x24,0x79,0x43,0xba,0x83,0x6e,0x43,0xa9,0x16,0x7c,0x43,0x56,
1771 0xa1,0x76,0x43,0x74,0x2a,0x7d,0x43,0x44,0x73,0x80,0x43,0x08,0x55,0xd1,0x7e,0x43,0xe3,0xea,0x76,0x43,
1772 0xbc,0x18,0x81,0x43,0x7f,0xa8,0x6e,0x43,0x8f,0x0a,0x84,0x43,0x02,0xfc,0x68,0x43,0x09,0x06,0x92,0x29,
1773 0x8d,0x43,0x73,0xc3,0x67,0x43,0x08,0xa4,0xd9,0x8e,0x43,0xf2,0xa6,0x7a,0x43,0x8f,0x22,0x88,0x43,0x75,
1774 0x2a,0x7d,0x43,0x42,0x7f,0x82,0x43,0x08,0xc8,0x88,0x43,0x09,0x06,0xc1,0x79,0x74,0x43,0x50,0x64,0x89,
1775 0x43,0x08,0x68,0x2d,0x72,0x43,0xee,0x21,0x81,0x43,0xcd,0x97,0x55,0x43,0xe6,0xf1,0x7b,0x43,0x91,0xec,
1776 0x5d,0x43,0xa8,0xc7,0x6a,0x43,0x09,0x06,0xfa,0xa5,0x52,0x43,0x60,0x97,0x7c,0x43,0x08,0x19,0xff,0x50,
1777 0x43,0xe9,0x6e,0x8a,0x43,0xb0,0xbd,0x70,0x43,0x4c,0x51,0x82,0x43,0x04,0xeb,0x69,0x43,0x66,0x0f,0x8e,
1778 0x43,0x09,0x06,0x17,0xbf,0x71,0x43,0x2c,0x58,0x94,0x43,0x08,0x1c,0x96,0x6e,0x43,0x61,0x68,0x99,0x43,
1779 0x2d,0x3a,0x6e,0x43,0xc8,0x81,0x9e,0x43,0xb7,0x9b,0x72,0x43,0x61,0xa4,0xa3,0x43,0x09,0x06,0x30,0xdb,
1780 0x82,0x43,0xdb,0xe9,0x93,0x43,0x08,0x11,0x82,0x84,0x43,0x61,0x68,0x99,0x43,0xe8,0x4a,0x84,0x43,0x8e,
1781 0xa6,0x9e,0x43,0x42,0x7f,0x82,0x43,0x61,0xa4,0xa3,0x43,0x09,0x06,0xc4,0x02,0x85,0x43,0xd1,0x0b,0x92,
1782 0x43,0x08,0xd6,0xb2,0x86,0x43,0x34,0x1e,0x92,0x43,0x4f,0x58,0x87,0x43,0xa4,0xf1,0x92,0x43,0x03,0xd9,
1783 0x87,0x43,0x7b,0xc6,0x94,0x43,0x09,0x06,0x87,0x3e,0x64,0x43,0x31,0x3b,0x93,0x43,0x08,0x3b,0xbf,0x64,
1784 0x43,0x6f,0xf9,0x91,0x43,0x96,0x0b,0x67,0x43,0xc5,0x4a,0x91,0x43,0xcf,0xfe,0x6a,0x43,0x31,0x2f,0x91,
1785 0x43,0x09,0x06,0x16,0x74,0xb5,0x43,0x08,0xec,0x8e,0x43,0x08,0x1b,0x4b,0xb2,0x43,0xee,0x5d,0x8b,0x43,
1786 0x48,0x4d,0xad,0x43,0x12,0xa6,0x8a,0x43,0xf3,0xd7,0xa7,0x43,0x74,0xb8,0x8a,0x43,0x08,0x8c,0xb2,0xa0,
1787 0x43,0xcd,0xf8,0x8a,0x43,0x68,0x46,0x9b,0x43,0x79,0x8f,0x87,0x43,0x49,0xc9,0x96,0x43,0xe9,0x3e,0x82,
1788 0x43,0x08,0x60,0x5c,0x97,0x43,0xa1,0xde,0x8b,0x43,0x4e,0xa0,0x93,0x43,0x31,0x3b,0x93,0x43,0x9f,0xea,
1789 0x8d,0x43,0x27,0x8d,0x99,0x43,0x08,0x07,0xe0,0x8c,0x43,0x06,0x34,0x9b,0x43,0x38,0xe9,0x8c,0x43,0x46,
1790 0x0a,0x9e,0x43,0x3d,0xcc,0x8b,0x43,0xb2,0x06,0xa2,0x43,0x08,0xf1,0x40,0x8a,0x43,0xb0,0x12,0xa4,0x43,
1791 0x39,0xd1,0x88,0x43,0x76,0x43,0xa6,0x43,0xfa,0x06,0x88,0x43,0xa4,0x75,0xa9,0x43,0x08,0x19,0x6c,0x88,
1792 0x43,0x9f,0x9e,0xac,0x43,0x66,0xeb,0x87,0x43,0x44,0x76,0xb0,0x43,0x6b,0xce,0x86,0x43,0x3b,0xbc,0xb4,
1793 0x43,0x08,0xa9,0x8c,0x85,0x43,0x06,0xd0,0xb5,0x43,0xfa,0xee,0x83,0x43,0x74,0xa3,0xb6,0x43,0x3d,0x90,
1794 0x81,0x43,0x31,0xf6,0xb6,0x43,0x08,0x9d,0x61,0x7d,0x43,0xee,0x48,0xb7,0x43,0x3b,0x1f,0x75,0x43,0xcf,
1795 0xe3,0xb6,0x43,0xee,0x6f,0x6d,0x43,0x68,0xe2,0xb5,0x43,0x08,0xd4,0xed,0x6b,0x43,0x87,0x2f,0xb2,0x43,
1796 0x0e,0xc9,0x6b,0x43,0xa7,0x7c,0xae,0x43,0x98,0xfa,0x67,0x43,0xab,0x53,0xab,0x43,0x08,0x25,0x2c,0x64,
1797 0x43,0x33,0xa2,0xa8,0x43,0x40,0x96,0x61,0x43,0xc3,0xc2,0xa5,0x43,0x64,0xde,0x60,0x43,0xfa,0xa2,0xa2,
1798 0x43,0x08,0xb0,0x5d,0x60,0x43,0x06,0x4c,0x9f,0x43,0x9a,0xca,0x5f,0x43,0x38,0x3d,0x9b,0x43,0x3b,0x8f,
1799 0x5c,0x43,0x85,0xb0,0x98,0x43,0x08,0x42,0x36,0x51,0x43,0x3d,0xf0,0x91,0x43,0xcd,0x4f,0x49,0x43,0xdb,
1800 0xb9,0x8b,0x43,0xe0,0xdb,0x44,0x43,0x42,0x8b,0x84,0x43,0x08,0x7e,0xc9,0x44,0x43,0x8a,0x57,0x8d,0x43,
1801 0xbc,0x6c,0x0f,0x43,0x23,0x62,0x8e,0x43,0xf5,0x17,0x07,0x43,0xc5,0x3e,0x8f,0x43,0x09,0x06,0xe0,0xea,
1802 0x76,0x43,0xab,0xef,0xc5,0x43,0x08,0x12,0x00,0x79,0x43,0xab,0xcb,0xbf,0x43,0x79,0xb9,0x6d,0x43,0x7e,
1803 0x8d,0xba,0x43,0xee,0x6f,0x6d,0x43,0x98,0xeb,0xb5,0x43,0x08,0xe0,0x02,0x7b,0x43,0x5f,0x1c,0xb8,0x43,
1804 0x85,0x2c,0x82,0x43,0xe9,0x65,0xb8,0x43,0xd6,0xb2,0x86,0x43,0xc6,0x05,0xb5,0x43,0x08,0x03,0xcd,0x85,
1805 0x43,0x5a,0x39,0xb9,0x43,0xe4,0x4f,0x81,0x43,0xdb,0xd4,0xbf,0x43,0xdf,0x6c,0x82,0x43,0xbc,0x93,0xc5,
1806 0x43,0x09,0x06,0xf0,0xd0,0x22,0x43,0x5d,0x19,0x08,0x43,0x08,0xbc,0xab,0x49,0x43,0x4a,0x35,0x29,0x43,
1807 0xcb,0xf7,0x65,0x43,0xce,0x37,0x45,0x43,0x0e,0x99,0x63,0x43,0x67,0xc6,0x5c,0x43,0x09,0x06,0x05,0x94,
1808 0xab,0x43,0xc2,0x13,0x04,0x43,0x08,0x9f,0x26,0x98,0x43,0x11,0x42,0x25,0x43,0x97,0x00,0x8a,0x43,0x32,
1809 0x32,0x41,0x43,0xf5,0x2f,0x8b,0x43,0xc7,0xc0,0x58,0x43,0x09,0x06,0x8f,0x85,0x48,0x43,0xe0,0xa8,0x8c,
1810 0x43,0x08,0x55,0xaa,0x48,0x43,0xe0,0xa8,0x8c,0x43,0x6b,0x3d,0x49,0x43,0xc1,0x43,0x8c,0x43,0x31,0x62,
1811 0x49,0x43,0xc1,0x43,0x8c,0x43,0x08,0x2f,0xe3,0x2f,0x43,0xad,0xe7,0x98,0x43,0xff,0x0d,0x0d,0x43,0xad,
1812 0xf3,0x9a,0x43,0xf0,0xaf,0xcc,0x42,0x74,0x00,0x97,0x43,0x08,0xbb,0xa2,0xf7,0x42,0x93,0x4d,0x93,0x43,
1813 0x5e,0x19,0x08,0x43,0x5a,0x2a,0x87,0x43,0x23,0x6e,0x10,0x43,0x42,0x97,0x86,0x43,0x08,0xca,0xe8,0x33,
1814 0x43,0x1b,0x3c,0x80,0x43,0x80,0xe8,0x4d,0x43,0xda,0xf4,0x70,0x43,0xae,0x0e,0x4f,0x43,0x2b,0x1b,0x65,
1815 0x43,0x08,0x66,0x96,0x54,0x43,0xa3,0xe1,0x3b,0x43,0x4e,0xc4,0x19,0x43,0xa0,0x1a,0x16,0x43,0x10,0xe2,
1816 0x14,0x43,0x26,0x14,0xe0,0x42,0x08,0x5c,0x91,0x1c,0x43,0xcb,0x27,0xee,0x42,0xa9,0x40,0x24,0x43,0x71,
1817 0x3b,0xfc,0x42,0xf3,0xef,0x2b,0x43,0x8b,0x27,0x05,0x43,0x08,0xe2,0x4b,0x2c,0x43,0x48,0x86,0x07,0x43,
1818 0x79,0x62,0x2f,0x43,0x05,0xe5,0x09,0x43,0x55,0x32,0x34,0x43,0xa0,0xd2,0x09,0x43,0x08,0x74,0xa3,0x36,
1819 0x43,0x3a,0xd1,0x08,0x43,0x7e,0x81,0x38,0x43,0x09,0xd4,0x0a,0x43,0x0d,0xba,0x39,0x43,0xa0,0xea,0x0d,
1820 0x43,0x08,0x6f,0xe4,0x3d,0x43,0x43,0xc7,0x0e,0x43,0xd6,0xe5,0x3e,0x43,0xc4,0x4a,0x11,0x43,0x55,0x7a,
1821 0x40,0x43,0x59,0x72,0x13,0x43,0x08,0x55,0x92,0x44,0x43,0xbf,0x73,0x14,0x43,0x23,0x95,0x46,0x43,0xa5,
1822 0x09,0x17,0x43,0xe0,0xf3,0x48,0x43,0xfe,0x55,0x19,0x43,0x08,0xcd,0x4f,0x49,0x43,0xaa,0x10,0x1c,0x43,
1823 0x61,0x77,0x4b,0x43,0xfe,0x6d,0x1d,0x43,0x80,0xe8,0x4d,0x43,0x2b,0x94,0x1e,0x43,0x08,0x58,0xc9,0x51,
1824 0x43,0x41,0x27,0x1f,0x43,0x9b,0x82,0x53,0x43,0x35,0x72,0x20,0x43,0x53,0xf2,0x54,0x43,0x88,0xcf,0x21,
1825 0x43,0x08,0x7b,0x29,0x55,0x43,0xe8,0x0a,0x25,0x43,0xb2,0x2d,0x58,0x43,0xef,0xe8,0x26,0x43,0x9b,0xb2,
1826 0x5b,0x43,0xd0,0x8f,0x28,0x43,0x08,0x5f,0xef,0x5f,0x43,0xeb,0x11,0x2a,0x43,0xfd,0xdc,0x5f,0x43,0x6e,
1827 0x95,0x2c,0x43,0x3b,0xa7,0x60,0x43,0x2b,0xf4,0x2e,0x43,0x08,0x06,0xbb,0x61,0x43,0xfd,0xe5,0x31,0x43,
1828 0xe7,0x61,0x63,0x43,0xef,0x30,0x33,0x43,0x53,0x52,0x65,0x43,0xa3,0xb1,0x33,0x43,0x08,0x12,0xa0,0x68,
1829 0x43,0x7f,0x69,0x34,0x43,0x40,0xc6,0x69,0x43,0x64,0xff,0x36,0x43,0x7e,0x90,0x6a,0x43,0x71,0xcc,0x39,
1830 0x43,0x08,0xbc,0x5a,0x6b,0x43,0x51,0x73,0x3b,0x43,0xc1,0x49,0x6c,0x43,0xa5,0xd0,0x3c,0x43,0xe0,0xba,
1831 0x6e,0x43,0xb8,0x74,0x3c,0x43,0x08,0x6b,0x1c,0x73,0x43,0x13,0xc1,0x3e,0x43,0x40,0xf6,0x71,0x43,0xce,
1832 0x1f,0x41,0x43,0x55,0x89,0x72,0x43,0x8d,0x7e,0x43,0x43,0x08,0x68,0x2d,0x72,0x43,0x89,0xae,0x4b,0x43,
1833 0xc1,0x79,0x74,0x43,0xcb,0x78,0x4c,0x43,0x55,0xa1,0x76,0x43,0x5b,0xb1,0x4d,0x43,0x08,0xa2,0x38,0x7a,
1834 0x43,0xd1,0x56,0x4e,0x43,0x85,0xb6,0x78,0x43,0xb1,0x15,0x54,0x43,0x83,0xc7,0x77,0x43,0x89,0x0e,0x5c,
1835 0x43,0x08,0xcf,0x46,0x77,0x43,0x0f,0x81,0x5f,0x43,0x1a,0xde,0x7a,0x43,0xce,0xc7,0x5d,0x43,0x42,0x73,
1836 0x80,0x43,0x99,0xc3,0x5a,0x43,0x08,0x85,0x2c,0x82,0x43,0xf6,0xe6,0x59,0x43,0x81,0x3d,0x81,0x43,0x16,
1837 0x10,0x50,0x43,0xd6,0x8e,0x80,0x43,0x5b,0x99,0x49,0x43,0x08,0xc4,0xea,0x80,0x43,0x22,0x95,0x46,0x43,
1838 0xfa,0xe2,0x81,0x43,0xda,0xec,0x43,0x43,0x78,0x77,0x83,0x43,0xe4,0xb2,0x41,0x43,0x08,0x8a,0x27,0x85,
1839 0x43,0x86,0x77,0x3e,0x43,0x0c,0x9f,0x85,0x43,0x07,0xf4,0x3b,0x43,0x8f,0x16,0x86,0x43,0xe6,0x82,0x39,
1840 0x43,0x08,0x85,0x44,0x86,0x43,0x37,0xd9,0x35,0x43,0x1e,0x4f,0x87,0x43,0xe1,0x7b,0x34,0x43,0xdf,0x90,
1841 0x88,0x43,0xb6,0x55,0x33,0x43,0x08,0xae,0x93,0x8a,0x43,0xfd,0xe5,0x31,0x43,0xfa,0x12,0x8a,0x43,0xbf,
1842 0x03,0x2d,0x43,0x19,0x78,0x8a,0x43,0x45,0x5e,0x2c,0x43,0x08,0x03,0xf1,0x8b,0x43,0xac,0x47,0x29,0x43,
1843 0x2f,0x17,0x8d,0x43,0x45,0x46,0x28,0x43,0xc8,0x21,0x8e,0x43,0x30,0xb3,0x27,0x43,0x08,0xa9,0xc8,0x8f,
1844 0x43,0xef,0xe8,0x26,0x43,0xbf,0x5b,0x90,0x43,0x5b,0xc1,0x24,0x43,0x10,0xca,0x90,0x43,0xa0,0x62,0x22,
1845 0x43,0x08,0x26,0x5d,0x91,0x43,0xbb,0xcc,0x1f,0x43,0xf0,0x70,0x92,0x43,0x78,0x13,0x1e,0x43,0x77,0xd7,
1846 0x93,0x43,0x73,0x24,0x1d,0x43,0x08,0x65,0x3f,0x96,0x43,0xce,0x58,0x1b,0x43,0xbe,0x7f,0x96,0x43,0xbf,
1847 0x8b,0x18,0x43,0x60,0x5c,0x97,0x43,0xb6,0xad,0x16,0x43,0x08,0xba,0xa8,0x99,0x43,0x78,0xcb,0x11,0x43,
1848 0x49,0xe1,0x9a,0x43,0x78,0xcb,0x11,0x43,0x01,0x51,0x9c,0x43,0x73,0xdc,0x10,0x43,0x08,0x72,0x24,0x9d,
1849 0x43,0xd2,0xff,0x0f,0x43,0x1c,0xd3,0x9d,0x43,0x07,0xec,0x0e,0x43,0xeb,0xc9,0x9d,0x43,0xe8,0x7a,0x0c,
1850 0x43,0x08,0x60,0x80,0x9d,0x43,0xd7,0xbe,0x08,0x43,0x4d,0xe8,0x9f,0x43,0x86,0x50,0x08,0x43,0x25,0xbd,
1851 0xa1,0x43,0x5b,0x2a,0x07,0x43,0x08,0x99,0x7f,0xa3,0x43,0xc9,0xf1,0x05,0x43,0x48,0x1d,0xa5,0x43,0x86,
1852 0x38,0x04,0x43,0x6c,0x71,0xa6,0x43,0x18,0x59,0x01,0x43,0x08,0x32,0x96,0xa6,0x43,0x6e,0x64,0xff,0x42,
1853 0x48,0x29,0xa7,0x43,0xed,0xcf,0xfd,0x42,0x5f,0xbc,0xa7,0x43,0x71,0x3b,0xfc,0x42,0x08,0xf3,0xe3,0xa9,
1854 0x43,0xf7,0x7d,0xf7,0x42,0xd8,0x6d,0xaa,0x43,0x45,0xe5,0xf2,0x42,0x48,0x41,0xab,0x43,0xcb,0x27,0xee,
1855 0x42,0x08,0x24,0xf9,0xab,0x43,0x52,0x6a,0xe9,0x42,0xee,0x0c,0xad,0x43,0x4c,0x8c,0xe7,0x42,0x1b,0x33,
1856 0xae,0x43,0xcc,0xf7,0xe5,0x42,0x08,0xaa,0x6b,0xaf,0x43,0xe8,0x61,0xe3,0x42,0x90,0xf5,0xaf,0x43,0xc9,
1857 0xf0,0xe0,0x42,0xe0,0x63,0xb0,0x43,0xe5,0x5a,0xde,0x42,0x08,0xaa,0x83,0xb3,0x43,0x29,0x2d,0x09,0x43,
1858 0x6a,0xfe,0x8e,0x43,0xb8,0x74,0x3c,0x43,0xd5,0x06,0x95,0x43,0xe6,0x79,0x67,0x43,0x08,0x2f,0x53,0x97,
1859 0x43,0xe9,0xb0,0x74,0x43,0xa8,0x28,0xa0,0x43,0x43,0xfd,0x76,0x43,0x83,0x28,0xad,0x43,0x17,0x59,0x81,
1860 0x43,0x08,0x3d,0xe7,0xbf,0x43,0x4b,0x8d,0x8c,0x43,0xae,0x96,0xba,0x43,0x66,0x27,0x92,0x43,0x15,0xe0,
1861 0xc7,0x43,0x6f,0x11,0x96,0x43,0x08,0x7e,0x5d,0xb2,0x43,0xdb,0x01,0x98,0x43,0x9e,0x56,0xa0,0x43,0x80,
1862 0xc1,0x97,0x43,0x69,0x2e,0x97,0x43,0x31,0x17,0x8d,0x43,0x09,0x06,0xab,0xa7,0x39,0x43,0x67,0x0f,0x0e,
1863 0x43,0x08,0xdb,0xbc,0x3b,0x43,0xe8,0x92,0x10,0x43,0xb5,0x85,0x3b,0x43,0x97,0x3c,0x14,0x43,0xab,0xa7,
1864 0x39,0x43,0x0c,0x0b,0x18,0x43,0x09,0x06,0xca,0x30,0x40,0x43,0x30,0x3b,0x13,0x43,0x08,0x17,0xc8,0x43,
1865 0x43,0xa5,0x09,0x17,0x43,0x7e,0xc9,0x44,0x43,0x1a,0xd8,0x1a,0x43,0x9d,0x22,0x43,0x43,0x8d,0xa6,0x1e,
1866 0x43,0x09,0x06,0xc8,0x78,0x4c,0x43,0xed,0xc9,0x1d,0x43,0x08,0x0b,0x32,0x4e,0x43,0x22,0xce,0x20,0x43,
1867 0x23,0xc5,0x4e,0x43,0x58,0xd2,0x23,0x43,0x0b,0x32,0x4e,0x43,0x2b,0xc4,0x26,0x43,0x09,0x06,0xec,0x08,
1868 0x58,0x43,0xc7,0xb1,0x26,0x43,0x08,0x02,0x9c,0x58,0x43,0xef,0x00,0x2b,0x43,0xd9,0x64,0x58,0x43,0x02,
1869 0xbd,0x2e,0x43,0x10,0x51,0x57,0x43,0x37,0xc1,0x31,0x43,0x09,0x06,0xcb,0xdf,0x61,0x43,0x4a,0x65,0x31,
1870 0x43,0x08,0xbe,0x2a,0x63,0x43,0xbd,0x33,0x35,0x43,0x32,0xe1,0x62,0x43,0x56,0x4a,0x38,0x43,0xde,0x83,
1871 0x61,0x43,0x3c,0xe0,0x3a,0x43,0x09,0x06,0x1c,0x7e,0x6a,0x43,0x5b,0x39,0x39,0x43,0x08,0x31,0x11,0x6b,
1872 0x43,0x0c,0xd2,0x3d,0x43,0x1c,0x7e,0x6a,0x43,0x13,0xd9,0x42,0x43,0xd9,0xc4,0x68,0x43,0xcb,0x60,0x48,
1873 0x43,0x09,0x06,0xe5,0xc1,0x73,0x43,0x16,0xf8,0x4b,0x43,0x08,0xa6,0xf7,0x72,0x43,0xb1,0xfd,0x4f,0x43,
1874 0x3b,0x07,0x71,0x43,0x4a,0x14,0x53,0x43,0xa2,0xf0,0x6d,0x43,0x7c,0x29,0x55,0x43,0x09,0x06,0x00,0x8d,
1875 0xa6,0x43,0xef,0x21,0x01,0x43,0x08,0x52,0xfb,0xa6,0x43,0xce,0xc8,0x02,0x43,0xe6,0x16,0xa7,0x43,0x51,
1876 0x4c,0x05,0x43,0x3b,0x68,0xa6,0x43,0x4c,0x75,0x08,0x43,0x09,0x06,0xde,0x20,0xa1,0x43,0x86,0x50,0x08,
1877 0x43,0x08,0xd4,0x4e,0xa1,0x43,0xd3,0xe7,0x0b,0x43,0xb5,0xe9,0xa0,0x43,0x59,0x5a,0x0f,0x43,0xba,0xcc,
1878 0x9f,0x43,0x54,0x83,0x12,0x43,0x09,0x06,0x77,0xfb,0x99,0x43,0x6c,0x16,0x13,0x43,0x08,0xde,0xfc,0x9a,
1879 0x43,0x4a,0xbd,0x14,0x43,0x06,0x34,0x9b,0x43,0xfe,0x55,0x19,0x43,0x13,0xe9,0x99,0x43,0x41,0x27,0x1f,
1880 0x43,0x09,0x06,0x46,0xce,0x93,0x43,0x26,0xa5,0x1d,0x43,0x08,0xe7,0xaa,0x94,0x43,0xbb,0xcc,0x1f,0x43,
1881 0x18,0xb4,0x94,0x43,0xa8,0x40,0x24,0x43,0xe2,0xbb,0x93,0x43,0x21,0xfe,0x28,0x43,0x09,0x06,0xb1,0x8e,
1882 0x8d,0x43,0xa8,0x58,0x28,0x43,0x08,0x19,0x90,0x8e,0x43,0x54,0x13,0x2b,0x43,0xa4,0xd9,0x8e,0x43,0x84,
1883 0x40,0x31,0x43,0x46,0xaa,0x8d,0x43,0x29,0x24,0x37,0x43,0x09,0x06,0xd6,0xbe,0x88,0x43,0xef,0x30,0x33,
1884 0x43,0x08,0x0c,0xb7,0x89,0x43,0x0e,0xa2,0x35,0x43,0xc0,0x37,0x8a,0x43,0x7a,0xaa,0x3b,0x43,0xbb,0x48,
1885 0x89,0x43,0xbb,0x7b,0x41,0x43,0x09,0x06,0x3a,0xad,0x82,0x43,0xc4,0x59,0x43,0x43,0x08,0xd2,0xb7,0x83,
1886 0x43,0x2b,0x5b,0x44,0x43,0x35,0xd6,0x85,0x43,0x48,0xf5,0x49,0x43,0x42,0x97,0x86,0x43,0xc4,0xa1,0x4f,
1887 0x43,0x09,0x06,0x9c,0xb3,0x80,0x43,0x48,0x55,0x5a,0x43,0x08,0xff,0xc5,0x80,0x43,0x09,0x73,0x55,0x43,
1888 0x93,0xe1,0x80,0x43,0x0f,0x39,0x53,0x43,0xf1,0xbe,0x7e,0x43,0x18,0xe7,0x4c,0x43,0x09,0x06,0xe0,0x02,
1889 0x7b,0x43,0x92,0xec,0x5d,0x43,0x08,0x09,0x3a,0x7b,0x43,0xf0,0xf7,0x58,0x43,0x09,0x3a,0x7b,0x43,0xe6,
1890 0x31,0x5b,0x43,0xe0,0x02,0x7b,0x43,0xa8,0x4f,0x56,0x43,0x09,0x06,0x39,0x4f,0x7d,0x43,0x3e,0x8f,0x5c,
1891 0x43,0x08,0xe9,0xe0,0x7c,0x43,0x03,0x9c,0x58,0x43,0x1e,0x2b,0x81,0x43,0x7f,0x30,0x5a,0x43,0xff,0x73,
1892 0x7d,0x43,0xf6,0xb6,0x51,0x43,0x09,0x06,0x5c,0xb8,0x52,0x43,0x28,0x21,0x87,0x43,0x08,0xae,0x3e,0x57,
1893 0x43,0x12,0x9a,0x88,0x43,0x23,0xf5,0x56,0x43,0x04,0xf1,0x8b,0x43,0x25,0xfc,0x5b,0x43,0x85,0x74,0x8e,
1894 0x43,0x08,0x2f,0xf2,0x61,0x43,0x8e,0x52,0x90,0x43,0xd9,0xdc,0x6c,0x43,0x85,0x74,0x8e,0x43,0xc6,0x20,
1895 0x69,0x43,0x3d,0xd8,0x8d,0x43,0x08,0x6d,0x8c,0x5a,0x43,0xf5,0x3b,0x8d,0x43,0x3d,0x77,0x58,0x43,0xa1,
1896 0xc6,0x87,0x43,0xf8,0xed,0x5e,0x43,0x5e,0x0d,0x86,0x43,0x09,0x06,0xde,0xcc,0x92,0x43,0xf7,0x17,0x87,
1897 0x43,0x08,0xb6,0x89,0x90,0x43,0xae,0x87,0x88,0x43,0x4a,0xa5,0x90,0x43,0xa1,0xde,0x8b,0x43,0xf9,0x2a,
1898 0x8e,0x43,0x23,0x62,0x8e,0x43,0x08,0xf5,0x2f,0x8b,0x43,0x5c,0x49,0x90,0x43,0x35,0xd6,0x85,0x43,0x8e,
1899 0x46,0x8e,0x43,0x3d,0xb4,0x87,0x43,0x47,0xaa,0x8d,0x43,0x08,0x6a,0xfe,0x8e,0x43,0xff,0x0d,0x8d,0x43,
1900 0xbb,0x6c,0x8f,0x43,0xf7,0x17,0x87,0x43,0x5c,0x31,0x8c,0x43,0xb2,0x5e,0x85,0x43,0x09,0x06,0x60,0x38,
1901 0x91,0x43,0x69,0x5d,0x7a,0x43,0x08,0x34,0x1e,0x92,0x43,0x1e,0x5b,0x89,0x43,0x04,0x63,0x7e,0x43,0x5e,
1902 0x01,0x84,0x43,0x59,0x2a,0x87,0x43,0x0d,0xcf,0x8d,0x43,0x09,0x03,0x04,0x06,0x5a,0x18,0x63,0x43,0x82,
1903 0x79,0x8b,0x43,0x08,0x25,0x2c,0x64,0x43,0x82,0x79,0x8b,0x43,0x2a,0x1b,0x65,0x43,0x9d,0xef,0x8a,0x43,
1904 0x2a,0x1b,0x65,0x43,0xc1,0x37,0x8a,0x43,0x08,0x2a,0x1b,0x65,0x43,0x17,0x89,0x89,0x43,0x25,0x2c,0x64,
1905 0x43,0x31,0xff,0x88,0x43,0x5a,0x18,0x63,0x43,0x31,0xff,0x88,0x43,0x08,0xf3,0x16,0x62,0x43,0x31,0xff,
1906 0x88,0x43,0xee,0x27,0x61,0x43,0x17,0x89,0x89,0x43,0xee,0x27,0x61,0x43,0xc1,0x37,0x8a,0x43,0x08,0xee,
1907 0x27,0x61,0x43,0x9d,0xef,0x8a,0x43,0xf3,0x16,0x62,0x43,0x82,0x79,0x8b,0x43,0x5a,0x18,0x63,0x43,0x82,
1908 0x79,0x8b,0x43,0x09,0x06,0x4f,0x64,0x89,0x43,0x82,0x79,0x8b,0x43,0x08,0x34,0xee,0x89,0x43,0x82,0x79,
1909 0x8b,0x43,0x85,0x5c,0x8a,0x43,0x9d,0xef,0x8a,0x43,0x85,0x5c,0x8a,0x43,0xc1,0x37,0x8a,0x43,0x08,0x85,
1910 0x5c,0x8a,0x43,0x17,0x89,0x89,0x43,0x34,0xee,0x89,0x43,0x31,0xff,0x88,0x43,0x4f,0x64,0x89,0x43,0x31,
1911 0xff,0x88,0x43,0x08,0x9c,0xe3,0x88,0x43,0x31,0xff,0x88,0x43,0x19,0x6c,0x88,0x43,0x17,0x89,0x89,0x43,
1912 0x19,0x6c,0x88,0x43,0xc1,0x37,0x8a,0x43,0x08,0x19,0x6c,0x88,0x43,0x9d,0xef,0x8a,0x43,0x9c,0xe3,0x88,
1913 0x43,0x82,0x79,0x8b,0x43,0x4f,0x64,0x89,0x43,0x82,0x79,0x8b,0x43,0x09,0x02,0x04,0x06,0x19,0x60,0x86,
1914 0x43,0xec,0xed,0xa3,0x43,0x08,0x35,0xd6,0x85,0x43,0x76,0x43,0xa6,0x43,0x93,0xe1,0x80,0x43,0x57,0x02,
1915 0xac,0x43,0x61,0xd8,0x80,0x43,0x87,0x17,0xae,0x43,0x08,0xa5,0x85,0x80,0x43,0xc3,0xfe,0xaf,0x43,0xce,
1916 0xbc,0x80,0x43,0x83,0x40,0xb1,0x43,0xa5,0x91,0x82,0x43,0x79,0x6e,0xb1,0x43,0x08,0x23,0x26,0x84,0x43,
1917 0x40,0x93,0xb1,0x43,0x30,0xe7,0x84,0x43,0xbe,0x1b,0xb1,0x43,0x11,0x82,0x84,0x43,0xab,0x6b,0xaf,0x43,
1918 0x08,0xb7,0x41,0x84,0x43,0x3b,0x98,0xae,0x43,0xb7,0x41,0x84,0x43,0xc3,0xf2,0xad,0x43,0xa1,0xae,0x83,
1919 0x43,0x83,0x28,0xad,0x43,0x08,0xb2,0x52,0x83,0x43,0x80,0x39,0xac,0x43,0x81,0x49,0x83,0x43,0xf0,0x00,
1920 0xab,0x43,0xe4,0x67,0x85,0x43,0x76,0x4f,0xa8,0x43,0x08,0x9c,0xd7,0x86,0x43,0xd1,0x83,0xa6,0x43,0xec,
1921 0x45,0x87,0x43,0x01,0x75,0xa2,0x43,0x19,0x60,0x86,0x43,0xec,0xed,0xa3,0x43,0x09,0x06,0xd9,0xdc,0x6c,
1922 0x43,0x14,0x25,0xa4,0x43,0x08,0xa2,0xf0,0x6d,0x43,0x9f,0x7a,0xa6,0x43,0x47,0xec,0x77,0x43,0x80,0x39,
1923 0xac,0x43,0xa9,0xfe,0x77,0x43,0xb0,0x4e,0xae,0x43,0x08,0x23,0xa4,0x78,0x43,0xea,0x35,0xb0,0x43,0xd2,
1924 0x35,0x78,0x43,0xab,0x77,0xb1,0x43,0xc1,0x79,0x74,0x43,0xa2,0xa5,0xb1,0x43,0x08,0xc6,0x50,0x71,0x43,
1925 0x68,0xca,0xb1,0x43,0xab,0xce,0x6f,0x43,0xe7,0x52,0xb1,0x43,0xea,0x98,0x70,0x43,0xd4,0xa2,0xaf,0x43,
1926 0x08,0x9d,0x19,0x71,0x43,0x96,0xd8,0xae,0x43,0x9d,0x19,0x71,0x43,0xec,0x29,0xae,0x43,0xca,0x3f,0x72,
1927 0x43,0xab,0x5f,0xad,0x43,0x08,0xa6,0xf7,0x72,0x43,0xa7,0x70,0xac,0x43,0x09,0x0a,0x73,0x43,0x17,0x38,
1928 0xab,0x43,0x44,0xcd,0x6e,0x43,0x9f,0x86,0xa8,0x43,0x08,0xd4,0xed,0x6b,0x43,0xf8,0xba,0xa6,0x43,0x31,
1929 0x11,0x6b,0x43,0x2a,0xac,0xa2,0x43,0xd9,0xdc,0x6c,0x43,0x14,0x25,0xa4,0x43,0x09,0x01,0x05,0x06,0x66,
1930 0x5d,0x7a,0x43,0x74,0xeb,0xc2,0x43,0x08,0x09,0x22,0x77,0x43,0x50,0xbb,0xc7,0x43,0xe9,0xe0,0x7c,0x43,
1931 0xf5,0x86,0xc9,0x43,0x8f,0x94,0x7a,0x43,0xc5,0x95,0xcd,0x43,0x09,0x06,0x08,0x98,0x80,0x43,0x6b,0x19,
1932 0xc3,0x43,0x08,0xb7,0x35,0x82,0x43,0x79,0xf2,0xc7,0x43,0xf1,0xbe,0x7e,0x43,0x1e,0xbe,0xc9,0x43,0x73,
1933 0x7c,0x80,0x43,0xec,0xcc,0xcd,0x43,0x09,0x06,0x28,0xab,0x7d,0x43,0xae,0xde,0xc6,0x43,0x08,0x1e,0xcd,
1934 0x7b,0x43,0x8a,0xa2,0xc9,0x43,0x30,0x89,0x7f,0x43,0x5c,0x94,0xcc,0x43,0x28,0xab,0x7d,0x43,0x42,0x2a,
1935 0xcf,0x43,0x09,0x01,0x05,0x06,0x24,0x14,0xe0,0x42,0xf5,0x77,0x97,0x43,0x08,0xf7,0x1d,0xe7,0x42,0x74,
1936 0x00,0x97,0x43,0x4d,0x93,0xec,0x42,0xdb,0xf5,0x95,0x43,0x29,0x4b,0xed,0x42,0xcd,0x34,0x95,0x43,0x09,
1937 0x06,0x29,0x7b,0xf5,0x42,0x6f,0x1d,0x98,0x43,0x08,0xe4,0xf1,0xfb,0x42,0x61,0x5c,0x97,0x43,0xdb,0x7d,
1938 0x01,0x43,0xb2,0xbe,0x95,0x43,0x55,0x23,0x02,0x43,0xe7,0xaa,0x94,0x43,0x09,0x06,0x98,0xdc,0x03,0x43,
1939 0xbe,0x8b,0x98,0x43,0x08,0x66,0xdf,0x05,0x43,0x47,0xe6,0x97,0x43,0xae,0x87,0x08,0x43,0x98,0x48,0x96,
1940 0x43,0x61,0x08,0x09,0x43,0xd6,0x06,0x95,0x43,0x09,0x06,0x31,0x0b,0x0b,0x43,0x8e,0x82,0x98,0x43,0x08,
1941 0xdb,0xc5,0x0d,0x43,0x80,0xc1,0x97,0x43,0xd6,0xee,0x10,0x43,0xa9,0xec,0x95,0x43,0x79,0xcb,0x11,0x43,
1942 0x55,0x8f,0x94,0x43,0x09,0x06,0xd1,0x2f,0x18,0x43,0xdb,0x01,0x98,0x43,0x08,0xad,0xe7,0x18,0x43,0x38,
1943 0x25,0x97,0x43,0x8a,0x9f,0x19,0x43,0x80,0xb5,0x95,0x43,0xd6,0x1e,0x19,0x43,0xe0,0xd8,0x94,0x43,0x09,
1944 0x06,0x9a,0x5b,0x1d,0x43,0x58,0x8a,0x97,0x43,0x08,0x01,0x5d,0x1e,0x43,0xf1,0x88,0x96,0x43,0x2f,0x83,
1945 0x1f,0x43,0x19,0xb4,0x94,0x43,0x19,0xf0,0x1e,0x43,0x6f,0x05,0x94,0x43,0x09,0x06,0x0b,0x53,0x24,0x43,
1946 0xae,0xdb,0x96,0x43,0x08,0x25,0xd5,0x25,0x43,0x50,0xac,0x95,0x43,0x53,0xfb,0x26,0x43,0x8a,0x7b,0x93,
1947 0x43,0x76,0x43,0x26,0x43,0xb7,0x95,0x92,0x43,0x09,0x06,0x76,0x5b,0x2a,0x43,0x47,0xda,0x95,0x43,0x08,
1948 0xf3,0xef,0x2b,0x43,0x10,0xe2,0x94,0x43,0x6d,0x95,0x2c,0x43,0xae,0xc3,0x92,0x43,0x68,0xa6,0x2b,0x43,
1949 0x47,0xc2,0x91,0x43,0x09,0x06,0x36,0xc1,0x31,0x43,0x2c,0x58,0x94,0x43,0x08,0x8c,0x1e,0x33,0x43,0x31,
1950 0x3b,0x93,0x43,0x79,0x7a,0x33,0x43,0xff,0x25,0x91,0x43,0xd9,0x9d,0x32,0x43,0xc1,0x5b,0x90,0x43,0x09,
1951 0x06,0x25,0x35,0x36,0x43,0x31,0x3b,0x93,0x43,0x08,0x3f,0xb7,0x37,0x43,0xc1,0x67,0x92,0x43,0xe0,0x93,
1952 0x38,0x43,0xae,0xb7,0x90,0x43,0x7e,0x81,0x38,0x43,0x0d,0xdb,0x8f,0x43,0x09,0x06,0xb5,0x85,0x3b,0x43,
1953 0xe4,0xaf,0x91,0x43,0x08,0xcf,0x07,0x3d,0x43,0x9d,0x13,0x91,0x43,0xbc,0x63,0x3d,0x43,0x47,0xb6,0x8f,
1954 0x43,0xe5,0x9a,0x3d,0x43,0x74,0xd0,0x8e,0x43,0x09,0x06,0xae,0xc6,0x42,0x43,0xa4,0xd9,0x8e,0x43,0x08,
1955 0xca,0x48,0x44,0x43,0xfa,0x2a,0x8e,0x43,0xa2,0x11,0x44,0x43,0x9d,0xfb,0x8c,0x43,0x55,0x92,0x44,0x43,
1956 0x0d,0xc3,0x8b,0x43,0x09,0x06,0x39,0x10,0xc3,0x43,0x34,0x36,0x96,0x43,0x08,0x92,0x44,0xc1,0x43,0xe4,
1957 0xc7,0x95,0x43,0x6f,0xf0,0xbf,0x43,0x4b,0xbd,0x94,0x43,0x47,0xb9,0xbf,0x43,0x0b,0xf3,0x93,0x43,0x09,
1958 0x06,0x8f,0x49,0xbe,0x43,0xb7,0xad,0x96,0x43,0x08,0x11,0xb5,0xbc,0x43,0x77,0xe3,0x95,0x43,0x9c,0xf2,
1959 0xba,0x43,0xfa,0x4e,0x94,0x43,0xae,0x96,0xba,0x43,0x31,0x3b,0x93,0x43,0x09,0x06,0xdb,0xb0,0xb9,0x43,
1960 0x10,0xee,0x96,0x43,0x08,0x42,0xa6,0xb8,0x43,0xc8,0x51,0x96,0x43,0x50,0x5b,0xb7,0x43,0x19,0xb4,0x94,
1961 0x43,0xf7,0x1a,0xb7,0x43,0x58,0x72,0x93,0x43,0x09,0x06,0xf2,0x2b,0xb6,0x43,0x10,0xee,0x96,0x43,0x08,
1962 0x9d,0xce,0xb4,0x43,0x04,0x2d,0x96,0x43,0xed,0x30,0xb3,0x43,0x2c,0x58,0x94,0x43,0xce,0xcb,0xb2,0x43,
1963 0xd6,0xfa,0x92,0x43,0x09,0x06,0x5a,0x09,0xb1,0x43,0x19,0xc0,0x96,0x43,0x08,0x6c,0xad,0xb0,0x43,0x77,
1964 0xe3,0x95,0x43,0x7e,0x51,0xb0,0x43,0xc0,0x73,0x94,0x43,0xd8,0x91,0xb0,0x43,0x1e,0x97,0x93,0x43,0x09,
1965 0x06,0x48,0x4d,0xad,0x43,0xbe,0x7f,0x96,0x43,0x08,0x95,0xcc,0xac,0x43,0x58,0x7e,0x95,0x43,0x4d,0x30,
1966 0xac,0x43,0x80,0xa9,0x93,0x43,0xd8,0x79,0xac,0x43,0xd6,0xfa,0x92,0x43,0x09,0x06,0x90,0xd1,0xa9,0x43,
1967 0x14,0xd1,0x95,0x43,0x08,0x83,0x10,0xa9,0x43,0xb7,0xa1,0x94,0x43,0x3b,0x74,0xa8,0x43,0xf1,0x70,0x92,
1968 0x43,0x29,0xd0,0xa8,0x43,0x1e,0x8b,0x91,0x43,0x09,0x06,0x5a,0xcd,0xa6,0x43,0x8a,0x87,0x95,0x43,0x08,
1969 0x1c,0x03,0xa6,0x43,0x23,0x86,0x94,0x43,0x5f,0xb0,0xa5,0x43,0xc1,0x67,0x92,0x43,0xe1,0x27,0xa6,0x43,
1970 0x8a,0x6f,0x91,0x43,0x09,0x06,0xd4,0x5a,0xa3,0x43,0x2c,0x58,0x94,0x43,0x08,0x29,0xac,0xa2,0x43,0x31,
1971 0x3b,0x93,0x43,0x32,0x7e,0xa2,0x43,0xff,0x25,0x91,0x43,0x83,0xec,0xa2,0x43,0x8e,0x52,0x90,0x43,0x09,
1972 0x06,0xf8,0x96,0xa0,0x43,0x1e,0x97,0x93,0x43,0x08,0xeb,0xd5,0x9f,0x43,0x7b,0xba,0x92,0x43,0x99,0x67,
1973 0x9f,0x43,0x9d,0x13,0x91,0x43,0x99,0x67,0x9f,0x43,0xfa,0x36,0x90,0x43,0x09,0x06,0xeb,0xc9,0x9d,0x43,
1974 0xc8,0x39,0x92,0x43,0x08,0xde,0x08,0x9d,0x43,0xb2,0xa6,0x91,0x43,0xe6,0xda,0x9c,0x43,0x2c,0x40,0x90,
1975 0x43,0x52,0xbf,0x9c,0x43,0x5a,0x5a,0x8f,0x43,0x09,0x06,0x37,0x3d,0x9b,0x43,0x85,0x80,0x90,0x43,0x08,
1976 0x2a,0x7c,0x9a,0x43,0xdb,0xd1,0x8f,0x43,0xf0,0xa0,0x9a,0x43,0x7d,0xa2,0x8e,0x43,0x65,0x57,0x9a,0x43,
1977 0xee,0x69,0x8d,0x43,0x09,0x02,0x04,0x06,0x2a,0xf4,0x2e,0x42,0x04,0x21,0x94,0x43,0x08,0x0d,0x8a,0x31,
1978 0x42,0x9f,0x0e,0x94,0x43,0xf3,0x1f,0x34,0x42,0x3d,0xfc,0x93,0x43,0x63,0xff,0x36,0x42,0xa9,0xe0,0x93,
1979 0x43,0x08,0xb5,0x34,0x5d,0x42,0x0b,0xf3,0x93,0x43,0x6d,0xa4,0x5e,0x42,0x03,0x39,0x98,0x43,0xe7,0x31,
1980 0x5b,0x42,0x93,0x89,0x9d,0x43,0x08,0x02,0x9c,0x58,0x42,0xd4,0x5a,0xa3,0x43,0x38,0x70,0x53,0x42,0x14,
1981 0x49,0xaa,0x43,0xf8,0xed,0x5e,0x42,0x83,0x28,0xad,0x43,0x08,0xea,0x68,0x68,0x42,0x20,0x22,0xaf,0x43,
1982 0x12,0xb8,0x6c,0x42,0xb5,0x49,0xb1,0x43,0x2a,0x4b,0x6d,0x42,0x0d,0x96,0xb3,0x43,0x07,0x2a,0x4b,0x6d,
1983 0x42,0xc6,0x05,0xb5,0x43,0x08,0x87,0x6e,0x6c,0x42,0x68,0xee,0xb7,0x43,0x1c,0x66,0x66,0x42,0x31,0x0e,
1984 0xbb,0x43,0x57,0x11,0x5e,0x42,0x8f,0x49,0xbe,0x43,0x08,0x66,0x96,0x54,0x42,0xb9,0x5c,0xb8,0x43,0x2c,
1985 0x2b,0x3c,0x42,0x68,0xd6,0xb3,0x43,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x07,0x2a,0xf4,0x2e,0x42,
1986 0x61,0xa4,0xa3,0x43,0x08,0x55,0x1a,0x30,0x42,0xf0,0xd0,0xa2,0x43,0xf8,0xf6,0x30,0x42,0xb2,0x06,0xa2,
1987 0x43,0x98,0xd3,0x31,0x42,0xd6,0x4e,0xa1,0x43,0x08,0x1c,0x6f,0x38,0x42,0x2a,0x94,0x9e,0x43,0xc1,0x22,
1988 0x36,0x42,0xf5,0x9b,0x9d,0x43,0x2a,0xf4,0x2e,0x42,0x6a,0x52,0x9d,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x57,
1989 0xa2,0x9b,0x43,0x08,0xab,0x8f,0x35,0x42,0x8a,0xab,0x9b,0x43,0xe9,0x71,0x3a,0x42,0xb2,0xe2,0x9b,0x43,
1990 0xb7,0x74,0x3c,0x42,0x34,0x5a,0x9c,0x43,0x08,0x23,0x7d,0x42,0x42,0x0b,0x2f,0x9e,0x43,0xe5,0x9a,0x3d,
1991 0x42,0x38,0x6d,0xa3,0x43,0x36,0xd9,0x35,0x42,0xf3,0xd7,0xa7,0x43,0x08,0x12,0x61,0x2e,0x42,0xb0,0x42,
1992 0xac,0x43,0x63,0xff,0x36,0x42,0xdd,0x74,0xaf,0x43,0x1e,0xa6,0x45,0x42,0x44,0x82,0xb2,0x43,0x08,0x74,
1993 0x1b,0x4b,0x42,0x79,0x7a,0xb3,0x43,0x10,0x21,0x4f,0x42,0x2a,0x18,0xb5,0x43,0xdb,0x4c,0x54,0x42,0x91,
1994 0x19,0xb6,0x43,0x08,0xee,0x3f,0x65,0x42,0x5f,0x28,0xba,0x43,0xa7,0xaf,0x66,0x42,0xb9,0x50,0xb6,0x43,
1995 0x14,0x58,0x5c,0x42,0xca,0xdc,0xb1,0x43,0x08,0x2c,0x8b,0x4c,0x42,0x4e,0x30,0xac,0x43,0x19,0xcf,0x48,
1996 0x42,0x2a,0xd0,0xa8,0x43,0xbc,0xab,0x49,0x42,0xa9,0x4c,0xa6,0x43,0x08,0x61,0x5f,0x47,0x42,0xfa,0xa2,
1997 0xa2,0x43,0xa7,0xaf,0x66,0x42,0x85,0x98,0x94,0x43,0x2a,0xf4,0x2e,0x42,0xc3,0x62,0x95,0x43,0x07,0x2a,
1998 0xf4,0x2e,0x42,0x04,0x21,0x94,0x43,0x09,0x06,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,0x08,0xdc,0xe3,
1999 0xf1,0x41,0xe9,0x9e,0x92,0x43,0xd2,0xe7,0x0b,0x42,0xd6,0x06,0x95,0x43,0x2a,0xf4,0x2e,0x42,0x04,0x21,
2000 0x94,0x43,0x07,0x2a,0xf4,0x2e,0x42,0xc3,0x62,0x95,0x43,0x08,0x87,0x17,0x2e,0x42,0xc3,0x62,0x95,0x43,
2001 0xe7,0x3a,0x2d,0x42,0xf5,0x6b,0x95,0x43,0x44,0x5e,0x2c,0x42,0xf5,0x6b,0x95,0x43,0x08,0xd1,0x47,0x1c,
2002 0x42,0x19,0xc0,0x96,0x43,0x66,0xdf,0x05,0x42,0x38,0x19,0x95,0x43,0x12,0x6a,0x00,0x42,0xb2,0xbe,0x95,
2003 0x43,0x08,0xbb,0x6b,0xea,0x41,0xd6,0x12,0x97,0x43,0x2d,0x82,0xfa,0x41,0x61,0x74,0x9b,0x43,0x7e,0x72,
2004 0x06,0x42,0x8a,0xab,0x9b,0x43,0x08,0xc8,0x39,0x12,0x42,0x4e,0xd0,0x9b,0x43,0x53,0xe3,0x22,0x42,0xc3,
2005 0x86,0x9b,0x43,0x2a,0xf4,0x2e,0x42,0x57,0xa2,0x9b,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x6a,0x52,0x9d,0x43,
2006 0x08,0x01,0xa5,0x2a,0x42,0xa4,0x2d,0x9d,0x43,0x96,0x9c,0x24,0x42,0x06,0x40,0x9d,0x43,0x8a,0xb7,0x1d,
2007 0x42,0x9a,0x5b,0x9d,0x43,0x08,0x6b,0x16,0x13,0x42,0xcd,0x64,0x9d,0x43,0x42,0xc7,0x0e,0x42,0x9a,0x5b,
2008 0x9d,0x43,0x23,0x26,0x04,0x42,0xcd,0x64,0x9d,0x43,0x08,0xe6,0x91,0xeb,0x41,0x38,0x49,0x9d,0x43,0x73,
2009 0x7b,0xdb,0x41,0xf5,0x83,0x99,0x43,0x7f,0x60,0xe2,0x41,0x0b,0x0b,0x98,0x43,0x08,0x7f,0x60,0xe2,0x41,
2010 0xec,0x99,0x95,0x43,0xe3,0x5a,0xde,0x41,0xbe,0x7f,0x96,0x43,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,
2011 0x07,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,0x09,0x06,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x08,
2012 0xd4,0x7e,0x29,0x42,0xab,0x6b,0xaf,0x43,0x4e,0x0c,0x26,0x42,0x44,0x6a,0xae,0x43,0x38,0x79,0x25,0x42,
2013 0xd4,0x96,0xad,0x43,0x08,0x25,0xbd,0x21,0x42,0xe2,0x4b,0xac,0x43,0x49,0x35,0x29,0x42,0x9a,0x97,0xa7,
2014 0x43,0x2a,0xf4,0x2e,0x42,0x61,0xa4,0xa3,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x09,0x06,
2015 0x1d,0xe5,0x7f,0x43,0x87,0x4a,0xe6,0x43,0x08,0x86,0x20,0x80,0x43,0x57,0x41,0xe6,0x43,0x7d,0x4e,0x80,
2016 0x43,0x25,0x38,0xe6,0x43,0xa5,0x85,0x80,0x43,0xf3,0x2e,0xe6,0x43,0x08,0x35,0xca,0x83,0x43,0xd4,0xc9,
2017 0xe5,0x43,0x9c,0xd7,0x86,0x43,0x44,0x91,0xe4,0x43,0xd5,0xca,0x8a,0x43,0x91,0x1c,0xe6,0x43,0x08,0x53,
2018 0x5f,0x8c,0x43,0xf8,0x1d,0xe7,0x43,0x2f,0x17,0x8d,0x43,0x4e,0x7b,0xe8,0x43,0x92,0x29,0x8d,0x43,0x2f,
2019 0x22,0xea,0x43,0x07,0x92,0x29,0x8d,0x43,0x44,0xb5,0xea,0x43,0x08,0xfe,0x0d,0x8d,0x43,0x2a,0x4b,0xed,
2020 0x43,0xe3,0x8b,0x8b,0x43,0x55,0x7d,0xf0,0x43,0xec,0x51,0x89,0x43,0x72,0x0b,0xf4,0x43,0x08,0xcd,0xd4,
2021 0x84,0x43,0x9d,0x55,0xfb,0x43,0xc9,0xe5,0x83,0x43,0x74,0x1e,0xfb,0x43,0x73,0x94,0x84,0x43,0x5a,0x90,
2022 0xf7,0x43,0x08,0xe8,0x62,0x88,0x43,0xfd,0x30,0xee,0x43,0x39,0xc5,0x86,0x43,0xdd,0xbf,0xeb,0x43,0x35,
2023 0xbe,0x81,0x43,0x40,0xde,0xed,0x43,0x08,0x4f,0x34,0x81,0x43,0x36,0x0c,0xee,0x43,0x08,0x98,0x80,0x43,
2024 0xfd,0x30,0xee,0x43,0x1d,0xe5,0x7f,0x43,0x91,0x4c,0xee,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x91,0x40,0xec,
2025 0x43,0x08,0x35,0xbe,0x81,0x43,0x06,0xf7,0xeb,0x43,0x15,0x65,0x83,0x43,0x49,0xa4,0xeb,0x43,0x1e,0x43,
2026 0x85,0x43,0xbe,0x5a,0xeb,0x43,0x08,0xae,0x93,0x8a,0x43,0xfd,0x18,0xea,0x43,0x42,0x97,0x86,0x43,0x5f,
2027 0x67,0xf4,0x43,0xa9,0x98,0x87,0x43,0xd4,0x1d,0xf4,0x43,0x08,0x5c,0x25,0x8a,0x43,0xcf,0x16,0xef,0x43,
2028 0x46,0xaa,0x8d,0x43,0x5a,0x3c,0xe9,0x43,0x19,0x6c,0x88,0x43,0x53,0x5e,0xe7,0x43,0x08,0xc4,0x02,0x85,
2029 0x43,0x96,0x0b,0xe7,0x43,0x85,0x2c,0x82,0x43,0x83,0x67,0xe7,0x43,0x1d,0xe5,0x7f,0x43,0x72,0xc3,0xe7,
2030 0x43,0x07,0x1d,0xe5,0x7f,0x43,0x87,0x4a,0xe6,0x43,0x09,0x06,0xfd,0x24,0x6c,0x43,0xd9,0x94,0xe0,0x43,
2031 0x08,0xfa,0x6c,0x78,0x43,0xd1,0xc2,0xe0,0x43,0x25,0x5c,0x6c,0x43,0x25,0x44,0xe8,0x43,0x1d,0xe5,0x7f,
2032 0x43,0x87,0x4a,0xe6,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x72,0xc3,0xe7,0x43,0x08,0xa6,0x27,0x7b,0x43,0x91,
2033 0x28,0xe8,0x43,0xbc,0xa2,0x77,0x43,0xb0,0x8d,0xe8,0x43,0xc6,0x68,0x75,0x43,0x57,0x4d,0xe8,0x43,0x08,
2034 0xe0,0xd2,0x72,0x43,0xab,0x9e,0xe7,0x43,0x50,0x9a,0x71,0x43,0x2a,0x27,0xe7,0x43,0xea,0x98,0x70,0x43,
2035 0x57,0x35,0xe4,0x43,0x08,0x94,0x3b,0x6f,0x43,0x14,0x7c,0xe2,0x43,0xff,0x13,0x6d,0x43,0x06,0xbb,0xe1,
2036 0x43,0xcf,0xfe,0x6a,0x43,0x06,0xbb,0xe1,0x43,0x08,0x44,0x9d,0x66,0x43,0x77,0x8e,0xe2,0x43,0x3b,0xef,
2037 0x6c,0x43,0x91,0x10,0xe4,0x43,0xfd,0x24,0x6c,0x43,0xb0,0x81,0xe6,0x43,0x08,0x96,0x23,0x6b,0x43,0xee,
2038 0x57,0xe9,0x43,0xca,0x0f,0x6a,0x43,0x5f,0x37,0xec,0x43,0x55,0x71,0x6e,0x43,0x9f,0x01,0xed,0x43,0x08,
2039 0xdb,0xfb,0x75,0x43,0x3b,0xef,0xec,0x43,0x09,0x3a,0x7b,0x43,0xb0,0xa5,0xec,0x43,0x1d,0xe5,0x7f,0x43,
2040 0x91,0x40,0xec,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x91,0x4c,0xee,0x43,0x08,0xa9,0x16,0x7c,0x43,0xb0,0xb1,
2041 0xee,0x43,0x47,0xec,0x77,0x43,0xd9,0xe8,0xee,0x43,0x1e,0x9d,0x73,0x43,0xcf,0x16,0xef,0x43,0x08,0x0e,
2042 0xc9,0x6b,0x43,0xee,0x7b,0xef,0x43,0x7e,0x90,0x6a,0x43,0xfd,0x30,0xee,0x43,0x01,0xfc,0x68,0x43,0x4e,
2043 0x93,0xec,0x43,0x08,0x31,0xf9,0x66,0x43,0x4e,0x87,0xea,0x43,0x31,0x11,0x6b,0x43,0xd4,0xd5,0xe7,0x43,
2044 0xd9,0xc4,0x68,0x43,0xd4,0xc9,0xe5,0x43,0x08,0xe5,0x79,0x67,0x43,0x77,0x9a,0xe4,0x43,0x44,0x9d,0x66,
2045 0x43,0xab,0x86,0xe3,0x43,0x7e,0x78,0x66,0x43,0x0b,0xaa,0xe2,0x43,0x07,0x7e,0x78,0x66,0x43,0x57,0x29,
2046 0xe2,0x43,0x08,0xa7,0xaf,0x66,0x43,0xbe,0x1e,0xe1,0x43,0x87,0x56,0x68,0x43,0x77,0x82,0xe0,0x43,0xfd,
2047 0x24,0x6c,0x43,0xd9,0x94,0xe0,0x43,0x09,0x06,0xc4,0x41,0xbf,0x43,0x85,0xc0,0x72,0x42,0x08,0x73,0xdf,
2048 0xc0,0x43,0xf4,0x76,0x72,0x42,0x97,0x33,0xc2,0x43,0x85,0xc0,0x72,0x42,0xb2,0xb5,0xc3,0x43,0x64,0x56,
2049 0x75,0x42,0x08,0x03,0x24,0xc4,0x43,0x5e,0x7f,0x78,0x42,0xfa,0x51,0xc4,0x43,0x01,0x85,0x7c,0x42,0x5c,
2050 0x64,0xc4,0x43,0xa0,0xb3,0x80,0x42,0x07,0x5c,0x64,0xc4,0x43,0x10,0x93,0x83,0x42,0x08,0xc8,0x48,0xc4,
2051 0x43,0x1c,0x78,0x8a,0x42,0x27,0x6c,0xc3,0x43,0xaf,0xcf,0x94,0x42,0x23,0x7d,0xc2,0x43,0x99,0x9c,0xa4,
2052 0x42,0x08,0x3d,0xe7,0xbf,0x43,0xfb,0xfd,0xb5,0x42,0xb3,0x9d,0xbf,0x43,0x88,0x17,0xae,0x42,0xc4,0x41,
2053 0xbf,0x43,0x69,0x76,0xa3,0x42,0x07,0xc4,0x41,0xbf,0x43,0xac,0xc8,0x8f,0x42,0x08,0x4f,0x8b,0xbf,0x43,
2054 0xed,0x81,0x91,0x42,0xe4,0xa6,0xbf,0x43,0x5d,0x61,0x94,0x42,0xfa,0x39,0xc0,0x43,0x3b,0x49,0x9d,0x42,
2055 0x08,0x2b,0x43,0xc0,0x43,0x28,0xed,0xa9,0x42,0x61,0x3b,0xc1,0x43,0x00,0x9e,0xa5,0x42,0xe4,0xb2,0xc1,
2056 0x43,0x5d,0x91,0x9c,0x42,0x08,0x78,0xce,0xc1,0x43,0xfd,0x36,0x90,0x42,0x22,0x89,0xc4,0x43,0x81,0x72,
2057 0x86,0x42,0xae,0xc6,0xc2,0x43,0xa0,0xb3,0x80,0x42,0x08,0x54,0x86,0xc2,0x43,0x58,0xd1,0x7e,0x42,0x30,
2058 0x32,0xc1,0x43,0xce,0x5e,0x7b,0x42,0xc4,0x41,0xbf,0x43,0xe8,0xf1,0x7b,0x42,0x07,0xc4,0x41,0xbf,0x43,
2059 0x85,0xc0,0x72,0x42,0x09,0x06,0xf6,0x32,0xbb,0x43,0x40,0xa7,0x60,0x42,0x08,0x35,0xfd,0xbb,0x43,0xa4,
2060 0xa1,0x5c,0x42,0x5e,0x34,0xbc,0x43,0x9d,0x2a,0x70,0x42,0x5e,0x40,0xbe,0x43,0x0e,0x0a,0x73,0x42,0x08,
2061 0x4c,0x9c,0xbe,0x43,0x0e,0x0a,0x73,0x42,0x08,0xef,0xbe,0x43,0x0e,0x0a,0x73,0x42,0xc4,0x41,0xbf,0x43,
2062 0x85,0xc0,0x72,0x42,0x07,0xc4,0x41,0xbf,0x43,0xe8,0xf1,0x7b,0x42,0x08,0xcd,0x13,0xbf,0x43,0xe8,0xf1,
2063 0x7b,0x42,0xd6,0xe5,0xbe,0x43,0x71,0x3b,0x7c,0x42,0xdf,0xb7,0xbe,0x43,0x71,0x3b,0x7c,0x42,0x08,0x08,
2064 0xe3,0xbc,0x43,0xa4,0x61,0x7d,0x42,0x28,0x3c,0xbb,0x43,0x91,0x45,0x69,0x42,0x28,0x3c,0xbb,0x43,0x58,
2065 0x71,0x6e,0x42,0x08,0xce,0xfb,0xba,0x43,0xd5,0x35,0x78,0x42,0x59,0x45,0xbb,0x43,0x58,0x23,0x82,0x42,
2066 0xa1,0xe1,0xbb,0x43,0xd7,0xbe,0x88,0x42,0x08,0xc9,0x18,0xbc,0x43,0xaf,0x9f,0x8c,0x42,0x1e,0x76,0xbd,
2067 0x43,0x51,0x7c,0x8d,0x42,0xd6,0xe5,0xbe,0x43,0xf4,0x58,0x8e,0x42,0x08,0x9c,0x0a,0xbf,0x43,0x45,0xc7,
2068 0x8e,0x42,0x30,0x26,0xbf,0x43,0x96,0x35,0x8f,0x42,0xc4,0x41,0xbf,0x43,0xac,0xc8,0x8f,0x42,0x07,0xc4,
2069 0x41,0xbf,0x43,0x69,0x76,0xa3,0x42,0x08,0x08,0xef,0xbe,0x43,0xb1,0xd6,0x99,0x42,0xe8,0x89,0xbe,0x43,
2070 0xde,0xc5,0x8d,0x42,0xc0,0x46,0xbc,0x43,0xc2,0x5b,0x90,0x42,0x08,0x9c,0xf2,0xba,0x43,0x86,0x80,0x90,
2071 0x42,0xf2,0x43,0xba,0x43,0xe8,0x73,0x87,0x42,0x8f,0x31,0xba,0x43,0xb6,0xf4,0x7d,0x42,0x07,0x8f,0x31,
2072 0xba,0x43,0x21,0xc6,0x76,0x42,0x08,0xc0,0x3a,0xba,0x43,0x5f,0x48,0x6b,0x42,0xae,0x96,0xba,0x43,0xe3,
2073 0x83,0x61,0x42,0xf6,0x32,0xbb,0x43,0x40,0xa7,0x60,0x42,0x09,0x06,0xea,0x74,0xea,0x43,0x61,0x44,0x93,
2074 0x43,0x08,0x24,0x5c,0xec,0x43,0x31,0x3b,0x93,0x43,0xfb,0x30,0xee,0x43,0x93,0x4d,0x93,0x43,0x0d,0xe1,
2075 0xef,0x43,0x80,0xa9,0x93,0x43,0x08,0x8f,0x58,0xf0,0x43,0xd1,0x17,0x94,0x43,0xb7,0x8f,0xf0,0x43,0x10,
2076 0xe2,0x94,0x43,0xea,0x98,0xf0,0x43,0xa9,0xec,0x95,0x43,0x07,0xea,0x98,0xf0,0x43,0x38,0x25,0x97,0x43,
2077 0x08,0x23,0x74,0xf0,0x43,0x9f,0x32,0x9a,0x43,0x5a,0x60,0xef,0x43,0x53,0xcb,0x9e,0x43,0x2d,0x3a,0xee,
2078 0x43,0xfd,0x91,0xa3,0x43,0x08,0xa2,0xf0,0xed,0x43,0xdd,0x38,0xa5,0x43,0x17,0xa7,0xed,0x43,0xbe,0xdf,
2079 0xa6,0x43,0x5a,0x54,0xed,0x43,0x9f,0x86,0xa8,0x43,0x08,0xfc,0x24,0xec,0x43,0xca,0xc4,0xad,0x43,0x48,
2080 0xa4,0xeb,0x43,0x40,0x6f,0xab,0x43,0x28,0x3f,0xeb,0x43,0x1c,0x0f,0xa8,0x43,0x08,0x1f,0x6d,0xeb,0x43,
2081 0x72,0x48,0xa3,0x43,0x67,0x09,0xec,0x43,0xd1,0x53,0x9e,0x43,0xea,0x74,0xea,0x43,0x1e,0xc7,0x9b,0x43,
2082 0x07,0xea,0x74,0xea,0x43,0x8a,0x9f,0x99,0x43,0x08,0x7e,0x90,0xea,0x43,0x8a,0x9f,0x99,0x43,0x12,0xac,
2083 0xea,0x43,0xbc,0xa8,0x99,0x43,0xa7,0xc7,0xea,0x43,0xbc,0xa8,0x99,0x43,0x08,0x51,0x76,0xeb,0x43,0x9f,
2084 0x32,0x9a,0x43,0x5e,0x37,0xec,0x43,0x49,0xed,0x9c,0x43,0xb0,0xa5,0xec,0x43,0x2a,0xa0,0xa0,0x43,0x08,
2085 0x09,0xe6,0xec,0x43,0xd1,0x77,0xa4,0x43,0x28,0x4b,0xed,0x43,0x61,0xa4,0xa3,0x43,0xab,0xc2,0xed,0x43,
2086 0x8e,0xb2,0xa0,0x43,0x08,0x70,0xe7,0xed,0x43,0xde,0x08,0x9d,0x43,0x87,0x86,0xf0,0x43,0x2f,0x53,0x97,
2087 0x43,0x87,0x7a,0xee,0x43,0xec,0x99,0x95,0x43,0x08,0xca,0x27,0xee,0x43,0xff,0x3d,0x95,0x43,0x74,0xca,
2088 0xec,0x43,0x55,0x8f,0x94,0x43,0xea,0x74,0xea,0x43,0xe7,0xaa,0x94,0x43,0x07,0xea,0x74,0xea,0x43,0x61,
2089 0x44,0x93,0x43,0x09,0x06,0x05,0xd3,0xe5,0x43,0x19,0x9c,0x90,0x43,0x08,0x09,0xc2,0xe6,0x43,0xd1,0xff,
2090 0x8f,0x43,0x4d,0x6f,0xe6,0x43,0x74,0xe8,0x92,0x43,0x3b,0xd7,0xe8,0x43,0xc3,0x56,0x93,0x43,0x08,0x1f,
2091 0x61,0xe9,0x43,0x93,0x4d,0x93,0x43,0x05,0xeb,0xe9,0x43,0x93,0x4d,0x93,0x43,0xea,0x74,0xea,0x43,0x61,
2092 0x44,0x93,0x43,0x07,0xea,0x74,0xea,0x43,0xe7,0xaa,0x94,0x43,0x08,0x24,0x50,0xea,0x43,0xe7,0xaa,0x94,
2093 0x43,0x2d,0x22,0xea,0x43,0xe7,0xaa,0x94,0x43,0x36,0xf4,0xe9,0x43,0xe7,0xaa,0x94,0x43,0x08,0xa2,0xcc,
2094 0xe7,0x43,0xe0,0xd8,0x94,0x43,0xd4,0xc9,0xe5,0x43,0x19,0xa8,0x92,0x43,0xd4,0xc9,0xe5,0x43,0x27,0x69,
2095 0x93,0x43,0x08,0x17,0x77,0xe5,0x43,0xe0,0xd8,0x94,0x43,0x67,0xe5,0xe5,0x43,0x47,0xda,0x95,0x43,0x43,
2096 0x9d,0xe6,0x43,0xe2,0xd3,0x97,0x43,0x08,0x9d,0xdd,0xe6,0x43,0xad,0xe7,0x98,0x43,0x09,0xce,0xe8,0x43,
2097 0xff,0x55,0x99,0x43,0xea,0x74,0xea,0x43,0x8a,0x9f,0x99,0x43,0x07,0xea,0x74,0xea,0x43,0x1e,0xc7,0x9b,
2098 0x43,0x08,0x71,0xcf,0xe9,0x43,0x53,0xb3,0x9a,0x43,0xa7,0xbb,0xe8,0x43,0xdb,0x0d,0x9a,0x43,0xc6,0x14,
2099 0xe7,0x43,0xdb,0x0d,0x9a,0x43,0x08,0x48,0x80,0xe5,0x43,0xdb,0x0d,0x9a,0x43,0x0a,0xb6,0xe4,0x43,0xc3,
2100 0x6e,0x97,0x43,0x76,0x9a,0xe4,0x43,0x74,0xf4,0x94,0x43,0x07,0x76,0x9a,0xe4,0x43,0x79,0xd7,0x93,0x43,
2101 0x08,0xd8,0xac,0xe4,0x43,0x66,0x27,0x92,0x43,0x29,0x1b,0xe5,0x43,0xe0,0xc0,0x90,0x43,0x05,0xd3,0xe5,
2102 0x43,0x19,0x9c,0x90,0x43,0x09,0x06,0x1b,0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x08,0x71,0x0b,0xf4,0x42,
2103 0x00,0x0e,0x8d,0x42,0x8c,0x0f,0x01,0x43,0x3e,0xc0,0x89,0x42,0xf3,0x28,0x06,0x43,0x48,0x9e,0x8b,0x42,
2104 0x08,0x15,0x89,0x09,0x43,0x00,0x0e,0x8d,0x42,0xe0,0x9c,0x0a,0x43,0xc1,0x8b,0x98,0x42,0xa6,0xc1,0x0a,
2105 0x43,0x02,0xa5,0xaa,0x42,0x07,0xa6,0xc1,0x0a,0x43,0xf9,0xf6,0xb0,0x42,0x08,0xa6,0xc1,0x0a,0x43,0x47,
2106 0x8e,0xb4,0x42,0x42,0xaf,0x0a,0x43,0x1f,0x6f,0xb8,0x42,0xe0,0x9c,0x0a,0x43,0xba,0x74,0xbc,0x42,0x08,
2107 0xa1,0xd2,0x09,0x43,0x40,0x47,0xd0,0x42,0x0d,0xab,0x07,0x43,0x91,0xb5,0xd0,0x42,0x3b,0xb9,0x04,0x43,
2108 0xec,0x71,0xba,0x42,0x08,0xe5,0x5b,0x03,0x43,0xe3,0x33,0xa8,0x42,0x63,0xd8,0x00,0x43,0xce,0x70,0x9f,
2109 0x42,0x1b,0x66,0xe6,0x42,0xae,0x2f,0xa5,0x42,0x07,0x1b,0x66,0xe6,0x42,0xa2,0x4a,0x9e,0x42,0x08,0xed,
2110 0x6f,0xed,0x42,0x73,0x24,0x9d,0x42,0xd8,0x0c,0xf5,0x42,0x99,0x6c,0x9c,0x42,0x27,0xab,0xfd,0x42,0xea,
2111 0xda,0x9c,0x42,0x08,0x36,0xca,0x03,0x43,0x2b,0x94,0x9e,0x42,0x68,0xc7,0x01,0x43,0x8f,0xbe,0xa2,0x42,
2112 0xfa,0x06,0x08,0x43,0x73,0xb4,0xb5,0x42,0x08,0x8e,0x2e,0x0a,0x43,0x1f,0x6f,0xb8,0x42,0x9d,0xe3,0x08,
2113 0x43,0xd7,0x1e,0x99,0x42,0x28,0x15,0x05,0x43,0x32,0x3b,0x93,0x42,0x08,0x63,0xf0,0x04,0x43,0x70,0xed,
2114 0x8f,0x42,0x71,0x0b,0xf4,0x42,0x32,0x3b,0x93,0x42,0x1b,0x66,0xe6,0x42,0x73,0xf4,0x94,0x42,0x07,0x1b,
2115 0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x09,0x06,0x5e,0x28,0xba,0x42,0x35,0xe2,0x87,0x42,0x08,0x8e,0x55,
2116 0xc0,0x42,0xb8,0x4d,0x86,0x42,0x60,0xbf,0xd7,0x42,0x3e,0xf0,0x91,0x42,0x63,0xf6,0xe4,0x42,0x70,0xed,
2117 0x8f,0x42,0x08,0x7a,0x89,0xe5,0x42,0xac,0xc8,0x8f,0x42,0xcc,0xf7,0xe5,0x42,0xac,0xc8,0x8f,0x42,0x1b,
2118 0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x07,0x1b,0x66,0xe6,0x42,0x73,0xf4,0x94,0x42,0x08,0x63,0xf6,0xe4,
2119 0x42,0x3b,0x19,0x95,0x42,0xe6,0x61,0xe3,0x42,0x00,0x3e,0x95,0x42,0xf4,0x16,0xe2,0x42,0xc4,0x62,0x95,
2120 0x42,0x08,0x6e,0x74,0xd6,0x42,0x15,0xd1,0x95,0x42,0x97,0x63,0xca,0x42,0xaf,0xcf,0x94,0x42,0xfb,0x2d,
2121 0xbe,0x42,0x86,0x80,0x90,0x42,0x08,0x97,0x03,0xba,0x42,0xce,0x10,0x8f,0x42,0x5e,0x28,0xba,0x42,0x3e,
2122 0xf0,0x91,0x42,0xf2,0x4f,0xbc,0x42,0x45,0xf7,0x96,0x42,0x08,0x27,0x54,0xbf,0x42,0x73,0x24,0x9d,0x42,
2123 0xa5,0xe8,0xc0,0x42,0x86,0xe0,0xa0,0x42,0xe4,0xca,0xc5,0x42,0xed,0x11,0xaa,0x42,0x08,0x54,0xaa,0xc8,
2124 0x42,0x86,0x40,0xb1,0x42,0x59,0x81,0xc5,0x42,0xa1,0x11,0xc4,0x42,0x3e,0xe7,0xbf,0x42,0xfb,0x8d,0xce,
2125 0x42,0x08,0xb4,0x6d,0xb7,0x42,0x30,0xc2,0xd9,0x42,0x46,0xf5,0xc9,0x42,0xdf,0x53,0xd9,0x42,0x38,0x40,
2126 0xcb,0x42,0x62,0x8f,0xcf,0x42,0x08,0x7d,0xf9,0xcc,0x42,0xec,0xa1,0xc2,0x42,0x07,0x43,0xcd,0x42,0x6c,
2127 0xdd,0xb8,0x42,0x2b,0x8b,0xcc,0x42,0x92,0xf5,0xaf,0x42,0x08,0xf9,0x8d,0xce,0x42,0x41,0x57,0xa7,0x42,
2128 0x5b,0xb8,0xd2,0x42,0xae,0x2f,0xa5,0x42,0x18,0x2f,0xd9,0x42,0x13,0x2a,0xa1,0x42,0x08,0x41,0x7e,0xdd,
2129 0x42,0xe3,0x03,0xa0,0x42,0x2e,0xf2,0xe1,0x42,0x7c,0x02,0x9f,0x42,0x1b,0x66,0xe6,0x42,0xa2,0x4a,0x9e,
2130 0x42,0x07,0x1b,0x66,0xe6,0x42,0xae,0x2f,0xa5,0x42,0x08,0x4d,0x63,0xe4,0x42,0x00,0x9e,0xa5,0x42,0xf4,
2131 0x16,0xe2,0x42,0x15,0x31,0xa6,0x42,0x99,0xca,0xdf,0x42,0x2b,0xc4,0xa6,0x42,0x08,0xc0,0x82,0xc6,0x42,
2132 0xc4,0xc2,0xa5,0x42,0x57,0xe1,0xd5,0x42,0x91,0xb5,0xd0,0x42,0x54,0xda,0xd0,0x42,0x97,0x93,0xd2,0x42,
2133 0x08,0x9c,0x3a,0xc7,0x42,0x17,0x58,0xdc,0x42,0x9c,0x0a,0xbf,0x42,0x6e,0xa4,0xde,0x42,0x90,0x25,0xb8,
2134 0x42,0xdf,0x53,0xd9,0x42,0x08,0x59,0x21,0xb5,0x42,0xf2,0xdf,0xd4,0x42,0x51,0x43,0xb3,0x42,0x91,0xb5,
2135 0xd0,0x42,0xc5,0x29,0xbb,0x42,0x0e,0x1a,0xca,0x42,0x08,0x65,0x36,0xc4,0x42,0xd0,0x07,0xbd,0x42,0x3e,
2136 0xe7,0xbf,0x42,0x37,0x09,0xbe,0x42,0x0c,0xea,0xc1,0x42,0xcd,0xd0,0xaf,0x42,0x08,0x2b,0x5b,0xc4,0x42,
2137 0x18,0x08,0xa3,0x42,0x67,0xa6,0xab,0x42,0x99,0x3c,0x94,0x42,0x5e,0x28,0xba,0x42,0x35,0xe2,0x87,0x42,
2138 0x09,];
2142 // ////////////////////////////////////////////////////////////////////////// //
2143 final class SdpyDrawSdpyImage : SdpyDrawBase {
2144 private:
2145 Image vbuf;
2147 protected:
2148 // must be overriden
2149 override Color getpix (int x, int y) {
2150 static if (UsingSimpledisplayX11) {
2151 pragma(inline, true);
2152 const(uint)* dp = (cast(const(uint)*)vbuf.getDataPointer)+y*vbuf.width+x;
2153 return XlibImageTC.img2c(*dp);
2154 } else {
2155 return vbuf.getPixel(x, y);
2159 override void putpix (int x, int y, Color col) {
2160 static if (UsingSimpledisplayX11) {
2161 uint* dp = (cast(uint*)vbuf.getDataPointer)+y*vbuf.width+x;
2162 if (col.a == 255) *dp = XlibImageTC.c2img(col)|0xff_000000; else *dp = blendU32(*dp, XlibImageTC.c2img(col)|(col.a<<24));
2163 } else {
2164 vbuf.setPixel(x, y, col);
2168 // optionals
2169 override void hline (int x, int y, int len, Color col) {
2170 static if (UsingSimpledisplayX11) {
2171 uint* dp = (cast(uint*)vbuf.getDataPointer)+y*vbuf.width+x;
2172 uint uc = XlibImageTC.c2img(col);
2173 if (col.a == 255) {
2174 uc |= 0xff_000000;
2175 foreach (immutable _; 0..len) *dp++ = uc;
2176 } else {
2177 uc |= col.a<<24;
2178 foreach (immutable _; 0..len) { *dp = blendU32(*dp, uc); ++dp; }
2180 } else {
2181 while (len-- > 0) vbuf.setPixel(x++, y, col);
2185 public:
2186 this (Image img) {
2187 vbuf = img;
2188 super(img.width, img.height);
2191 override TrueColorImage getBuffer () {
2192 auto img = new TrueColorImage(vbuf.width, vbuf.height);
2193 static if (UsingSimpledisplayX11) {
2194 const(uint)* sp = cast(const(uint)*)vbuf.getDataPointer;
2195 auto dp = img.imageData.colors.ptr;
2196 foreach (immutable y; 0..vbuf.height) {
2197 foreach (immutable x; 0..vbuf.width) {
2198 *dp++ = XlibImageTC.img2c(*sp++);
2201 } else {
2202 foreach (immutable y; 0..vbuf.height) {
2203 foreach (immutable x; 0..vbuf.width) {
2204 img.setPixel(x, y, vbuf.getPixel(x, y));
2208 return img;
2211 final @property Image imagebuf () pure nothrow @safe @nogc { pragma(inline, true); return vbuf; }
2215 // ////////////////////////////////////////////////////////////////////////// //
2216 // some "fastgfx" backend
2218 class SdpyAADrawBase(RendT) if (is(RT : Renderer!ST, ST)) {
2219 protected:
2220 static T abs(T) (T n) pure nothrow @safe @nogc { pragma(inline, true); return (n < 0 ? -n : n); }
2222 version(Windows) {
2223 private static int lrintf (float f) nothrow @trusted @nogc { pragma(inline, true); return cast(int)(f+0.5f); }
2224 private static int lrintd (double f) nothrow @trusted @nogc { pragma(inline, true); return cast(int)(f+0.5); }
2225 } else {
2226 private import core.stdc.math : lrintf, lrintd = lrint;
2228 private import core.stdc.math : sqrtf, sqrtd = sqrt;
2229 private import core.stdc.math : floorf, floord = floor;
2230 private import core.stdc.math : cosf, sinf;
2232 public:
2233 GxSize dim;
2234 GxRect clip;
2235 RendT rend;
2237 protected nothrow @trusted @nogc: // low-level methods; will always be called with valid coords
2238 // must be overriden
2239 // optionals
2240 final void hline (int x, int y, int len, Color c) {
2241 while (len-- > 0) rend.putPixel(x++, y, c);
2244 final void vline (int x, int y, int len, Color c) {
2245 while (len-- > 0) rend.putPixel(x, y++, c);
2248 final void fillrc (int x, int y, int w, int h, Color c) {
2249 while (h-- > 0) hline(x, y++, w, c);
2252 protected:
2253 Rasterizer rast;
2254 float tessTol = 0.25f;
2255 float angleTol = 0.0f; // 0.0f -- angle tolerance for McSeem Bezier rasterizer
2256 float cuspLimit = 0; // 0 -- cusp limit for McSeem Bezier rasterizer (0: real cusps)
2258 public nothrow @trusted @nogc:
2259 this (int awdt, int ahgt) {
2260 if (awdt < 0) awdt = 0;
2261 if (ahgt < 0) ahgt = 0;
2262 dim = GxSize(awdt, ahgt);
2263 clip = GxRect(dim);
2264 rend.reset();
2265 rend.moveTo(0, 0);
2268 final @property int width () const pure nothrow @safe @nogc { pragma(inline, true); return dim.width; }
2269 final @property int height () const pure nothrow @safe @nogc { pragma(inline, true); return dim.height; }
2271 void cls (Color clr=Color.white) { rend.clear(clr); beginPath(); }
2273 // can return null, yeah
2274 TrueColorImage getBuffer () { return null; }
2276 final:
2277 Color getPixel (int x, int y) {
2278 pragma(inline, true);
2279 return (x >= 0 && y >= 0 && x < dim.width && y < dim.height && clip.inside(x, y) ? rend.getPixel(x, y) : Color.transparent);
2282 void putPixel (int x, int y, Color c) {
2283 pragma(inline, true);
2284 if (x >= 0 && y >= 0 && x < dim.width && y < dim.height && clip.inside(x, y)) rend.putPixel(x, y, c);
2287 // ////////////////////////////////////////////////////////////////////////// //
2288 // based on the ideas and code of Maxim Shemanarev. Rest in Peace, bro!
2289 // see http://www.antigrain.com/research/adaptive_bezier/index.html
2290 private void nvg__tesselateBezierMcSeem (in float x1, in float y1, in float x2, in float y2, in float x3, in float y3, in float x4, in float y4, in int level/*, in int type*/) {
2291 enum CollinearEPS = 0.00000001f; // 0.00001f;
2292 enum AngleTolEPS = 0.01f;
2294 static float distSquared (in float x1, in float y1, in float x2, in float y2) pure nothrow @safe @nogc {
2295 pragma(inline, true);
2296 immutable float dx = x2-x1;
2297 immutable float dy = y2-y1;
2298 return dx*dx+dy*dy;
2301 if (level == 0) {
2302 rast.lineTo(x1, y1/*, 0*/);
2303 nvg__tesselateBezierMcSeem(ctx, x1, y1, x2, y2, x3, y3, x4, y4, 1/*, type*/);
2304 rast.lineTo(x4, y4/*, type*/);
2305 return;
2308 if (level >= 32) return; // recurse limit; practically, it should be never reached, but...
2310 // calculate all the mid-points of the line segments
2311 immutable float x12 = (x1+x2)*0.5f;
2312 immutable float y12 = (y1+y2)*0.5f;
2313 immutable float x23 = (x2+x3)*0.5f;
2314 immutable float y23 = (y2+y3)*0.5f;
2315 immutable float x34 = (x3+x4)*0.5f;
2316 immutable float y34 = (y3+y4)*0.5f;
2317 immutable float x123 = (x12+x23)*0.5f;
2318 immutable float y123 = (y12+y23)*0.5f;
2319 immutable float x234 = (x23+x34)*0.5f;
2320 immutable float y234 = (y23+y34)*0.5f;
2321 immutable float x1234 = (x123+x234)*0.5f;
2322 immutable float y1234 = (y123+y234)*0.5f;
2324 // try to approximate the full cubic curve by a single straight line
2325 immutable float dx = x4-x1;
2326 immutable float dy = y4-y1;
2328 float d2 = nvg__absf(((x2-x4)*dy-(y2-y4)*dx));
2329 float d3 = nvg__absf(((x3-x4)*dy-(y3-y4)*dx));
2331 final switch ((cast(int)(d2 > CollinearEPS)<<1)+cast(int)(d3 > CollinearEPS)) {
2332 case 0:
2333 // all collinear or p1 == p4
2334 float k = dx*dx+dy*dy;
2335 if (k == 0) {
2336 d2 = distSquared(x1, y1, x2, y2);
2337 d3 = distSquared(x4, y4, x3, y3);
2338 } else {
2339 k = 1.0f/k;
2340 float da1 = x2-x1;
2341 float da2 = y2-y1;
2342 d2 = k*(da1*dx+da2*dy);
2343 da1 = x3-x1;
2344 da2 = y3-y1;
2345 d3 = k*(da1*dx+da2*dy);
2346 if (d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1) {
2347 // Simple collinear case, 1---2---3---4
2348 // We can leave just two endpoints
2349 return;
2351 if (d2 <= 0) d2 = distSquared(x2, y2, x1, y1);
2352 else if (d2 >= 1) d2 = distSquared(x2, y2, x4, y4);
2353 else d2 = distSquared(x2, y2, x1+d2*dx, y1+d2*dy);
2355 if (d3 <= 0) d3 = distSquared(x3, y3, x1, y1);
2356 else if (d3 >= 1) d3 = distSquared(x3, y3, x4, y4);
2357 else d3 = distSquared(x3, y3, x1+d3*dx, y1+d3*dy);
2359 if (d2 > d3) {
2360 if (d2 < ctx.tessTol) {
2361 rast.lineTo(x2, y2/*, type*/);
2362 return;
2364 } if (d3 < ctx.tessTol) {
2365 rast.lineTo(x3, y3/*, type*/);
2366 return;
2368 break;
2369 case 1:
2370 // p1,p2,p4 are collinear, p3 is significant
2371 if (d3*d3 <= ctx.tessTol*(dx*dx+dy*dy)) {
2372 if (ctx.angleTol < AngleTolEPS) {
2373 rast.lineTo(x23, y23/*, type*/);
2374 return;
2375 } else {
2376 // angle condition
2377 float da1 = nvg__absf(nvg__atan2f(y4-y3, x4-x3)-nvg__atan2f(y3-y2, x3-x2));
2378 if (da1 >= NVG_PI) da1 = 2*NVG_PI-da1;
2379 if (da1 < ctx.angleTol) {
2380 rast.lineTo(x2, y2/*, type*/);
2381 rast.lineTo(x3, y3/*, type*/);
2382 return;
2384 if (ctx.cuspLimit != 0.0) {
2385 if (da1 > ctx.cuspLimit) {
2386 rast.lineTo(x3, y3/*, type*/);
2387 return;
2392 break;
2393 case 2:
2394 // p1,p3,p4 are collinear, p2 is significant
2395 if (d2*d2 <= ctx.tessTol*(dx*dx+dy*dy)) {
2396 if (ctx.angleTol < AngleTolEPS) {
2397 rast.lineTo(x23, y23/*, type*/);
2398 return;
2399 } else {
2400 // angle condition
2401 float da1 = nvg__absf(nvg__atan2f(y3-y2, x3-x2)-nvg__atan2f(y2-y1, x2-x1));
2402 if (da1 >= NVG_PI) da1 = 2*NVG_PI-da1;
2403 if (da1 < ctx.angleTol) {
2404 rast.lineTo(x2, y2/*, type*/);
2405 rast.lineTo(x3, y3/*, type*/);
2406 return;
2408 if (ctx.cuspLimit != 0.0) {
2409 if (da1 > ctx.cuspLimit) {
2410 rast.lineTo(x2, y2/*, type*/);
2411 return;
2416 break;
2417 case 3:
2418 // regular case
2419 if ((d2+d3)*(d2+d3) <= ctx.tessTol*(dx*dx+dy*dy)) {
2420 // if the curvature doesn't exceed the distance tolerance value, we tend to finish subdivisions
2421 if (ctx.angleTol < AngleTolEPS) {
2422 rast.lineTo(x23, y23/*, type*/);
2423 return;
2424 } else {
2425 // angle and cusp condition
2426 immutable float k = nvg__atan2f(y3-y2, x3-x2);
2427 float da1 = nvg__absf(k-nvg__atan2f(y2-y1, x2-x1));
2428 float da2 = nvg__absf(nvg__atan2f(y4-y3, x4-x3)-k);
2429 if (da1 >= NVG_PI) da1 = 2*NVG_PI-da1;
2430 if (da2 >= NVG_PI) da2 = 2*NVG_PI-da2;
2431 if (da1+da2 < ctx.angleTol) {
2432 // finally we can stop the recursion
2433 rast.lineTo(x23, y23/*, type*/);
2434 return;
2436 if (ctx.cuspLimit != 0.0) {
2437 if (da1 > ctx.cuspLimit) {
2438 rast.lineTo(x2, y2/*, type*/);
2439 return;
2441 if (da2 > ctx.cuspLimit) {
2442 rast.lineTo(x3, y3/*, type*/);
2443 return;
2448 break;
2451 // continue subdivision
2452 nvg__tesselateBezierMcSeem(x1, y1, x12, y12, x123, y123, x1234, y1234, level+1/*, 0*/);
2453 nvg__tesselateBezierMcSeem(x1234, y1234, x234, y234, x34, y34, x4, y4, level+1/*, type*/);
2456 @property float curX () const pure { pragma(inline, true); return rast.curX; }
2457 @property float curY () const pure { pragma(inline, true); return rast.curY; }
2459 void beginPath () { pragma(inline, true); rast.reset(); rast.moveTo(0, 0); }
2461 void moveTo (in float x, in float y) { pragma(inline, true); rast.moveTo(x, y); }
2462 void lineTo (in float x, in float y) { pragma(inline, true); rast.lineTo(x, y); }
2464 void bezierTo (in float x2, in float y2, in float x3, in float y3, in float x4, in float y4) {
2465 pragma(inline, true);
2466 nvg__tesselateBezierMcSeem(curX, curY, x2, y2, x3, y3, x4, y4);
2469 void quadTo (in float cx, in float cy, in float x, in float y) {
2470 immutable float x0 = curX;
2471 immutable float y0 = curY;
2472 bezierTo(
2473 x0+2.0f/3.0f*(cx-x0), y0+2.0f/3.0f*(cy-y0),
2474 x+2.0f/3.0f*(cx-x), y+2.0f/3.0f*(cy-y),
2475 x, y,
2479 void fill (in Color c) {
2480 pragma(inline, true);
2481 rast.render(rend, c);
2484 // ////////////////////////////////////////////////////////////////////////// //
2485 enum BaphometDims = 512; // [0..511]
2486 final void renderBaphomet (in Color fc, float ofsx=0, float ofsy=0, float scalex=1, float scaley=1) {
2487 auto path = cast(const(ubyte)[])baphometPath;
2488 immutable plen = path.length;
2489 uint ppos = 0;
2491 void drawLine (float x1, float y1, float x2, float y2, float width=0.2) {
2492 import std.math : sqrt;
2493 float dx = x2-x1;
2494 float dy = y2-y1;
2495 immutable float d = sqrtf(dx*dx+dy*dy);
2497 dx = width*(y2-y1)/d;
2498 dy = width*(x2-x1)/d;
2500 rast.moveTo(x1-dx, y1+dy);
2501 rast.lineTo(x2-dx, y2+dy);
2502 rast.lineTo(x2+dx, y2-dy);
2503 rast.lineTo(x1+dx, y1-dy);
2506 enum Command {
2507 Bounds, // always first, has 4 args (x0, y0, x1, y1)
2508 StrokeMode,
2509 FillMode,
2510 StrokeFillMode,
2511 NormalStroke,
2512 ThinStroke,
2513 MoveTo,
2514 LineTo,
2515 CubicTo, // cubic bezier
2516 EndPath,
2519 Command getCommand () nothrow @trusted @nogc {
2520 if (ppos >= plen) assert(0, "invalid path");
2521 return cast(Command)(path.ptr[ppos++]);
2524 float getFloat () nothrow @trusted @nogc {
2525 if (ppos >= plen || plen-ppos < float.sizeof) assert(0, "invalid path");
2526 version(LittleEndian) {
2527 float res = *cast(const(float)*)(&path.ptr[ppos]);
2528 ppos += cast(uint)float.sizeof;
2529 return res;
2530 } else {
2531 static assert(float.sizeof == 4);
2532 uint xp = path.ptr[ppos]|(path.ptr[ppos+1]<<8)|(path.ptr[ppos+2]<<16)|(path.ptr[ppos+3]<<24);
2533 ppos += cast(uint)float.sizeof;
2534 return *cast(const(float)*)(&xp);
2538 int scaleX (float v) nothrow @trusted @nogc { pragma(inline, true); return lrintf(ofsx+v*scalex); }
2539 int scaleY (float v) nothrow @trusted @nogc { pragma(inline, true); return lrintf(ofsy+v*scaley); }
2541 int cx = 0, cy = 0;
2542 bool doStroke = false, doFill = false;
2543 while (ppos < plen) {
2544 auto cmd = getCommand();
2545 final switch (cmd) {
2546 case Command.Bounds: ppos += 4*cast(uint)float.sizeof; break;
2547 case Command.StrokeMode: doStroke = true; doFill = false; break;
2548 case Command.FillMode: doStroke = false; doFill = true;
2549 case Command.StrokeFillMode: break;
2550 case Command.NormalStroke: case Command.ThinStroke: break;
2551 case Command.MoveTo:
2552 cx = scaleX(getFloat());
2553 cy = scaleY(getFloat());
2554 rast.moveTo(cx, cy);
2555 break;
2556 case Command.LineTo:
2557 immutable int ex = scaleX(getFloat());
2558 immutable int ey = scaleY(getFloat());
2559 if (doFill) rast.lineTo(ex, ey); else if (doStroke) drawLine(cx, cy, ex, ey, fc);
2560 cx = ex;
2561 cy = ey;
2562 break;
2563 case Command.CubicTo: // cubic bezier
2564 immutable int x1 = scaleX(getFloat());
2565 immutable int y1 = scaleY(getFloat());
2566 immutable int x2 = scaleX(getFloat());
2567 immutable int y2 = scaleY(getFloat());
2568 immutable int ex = scaleX(getFloat());
2569 immutable int ey = scaleY(getFloat());
2570 if (doFill) drawCubicBezier(cx, cy, x1, y1, x2, y2, ex, ey, fc);
2571 cx = ex;
2572 cy = ey;
2573 break;
2574 case Command.EndPath: // don't close this path
2575 break;
2582 // ////////////////////////////////////////////////////////////////////////// //
2583 private:
2584 /* *****************************************************************************
2585 Anti-Grain Geometry - Version 2.1 Lite
2586 Copyright (C) 2002-2003 Maxim Shemanarev (McSeem)
2588 Permission to copy, use, modify, sell and distribute this software
2589 is granted provided this copyright notice appears in all copies.
2590 This software is provided "as is" without express or implied
2591 warranty, and with no claim as to its suitability for any purpose.
2593 The author gratefully acknowleges the support of David Turner,
2594 Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
2595 libray - in producing this work. See http://www.freetype.org for details.
2597 Initially the rendering algorithm was designed by David Turner and the
2598 other authors of the FreeType library - see the above notice. I nearly
2599 created a similar renderer, but still I was far from David's work.
2600 I completely redesigned the original code and adapted it for Anti-Grain
2601 ideas. Two functions - renderLine and renderScanLine are the core of
2602 the algorithm - they calculate the exact coverage of each pixel cell
2603 of the polygon. I left these functions almost as is, because there's
2604 no way to improve the perfection - hats off to David and his group!
2606 All other code is very different from the original.
2607 ***************************************************************************** */
2608 struct RenderingBuffer {
2609 private:
2610 ubyte* mBuf; // Pointer to renrdering buffer
2611 ubyte** mRows; // Pointers to each row of the buffer
2612 uint mWidth; // Width in pixels
2613 uint mHeight; // Height in pixels
2614 int mStride; // Number of bytes per row. Can be < 0
2615 uint mMaxHeight; // Maximal current height
2617 public nothrow @trusted @nogc:
2618 @disable this (this); // no copies
2620 this (ubyte* buf, uint width, uint height, int stride) {
2621 attach(buf, width, height, stride);
2624 ~this () {
2625 import core.stdc.stdlib : free;
2626 free(mRows);
2629 void attach (ubyte* buf, uint width, uint height, int stride) {
2630 import core.stdc.stdlib : realloc;
2631 if (width < 1 || height < 1 || width > short.max || height > short.max) assert(0, "invalid rendering buffer dimensions");
2632 mBuf = buf;
2633 mWidth = width;
2634 mHeight = height;
2635 mStride = stride;
2636 if (height > mMaxHeight || mRows is null) {
2637 mRows = cast(ubyte**)realloc(mRows, (ubyte*).sizeof*height);
2638 if (mRows is null) assert(0, "out of memory");
2641 ubyte* rowPtr = mBuf;
2642 if (stride < 0) rowPtr = mBuf-cast(int)(height-1)*stride;
2644 ubyte** rows = mRows;
2645 while (height--) {
2646 *rows++ = rowPtr;
2647 rowPtr += stride;
2651 @property inout(ubyte)* buf () inout pure { pragma(inline, true); return mBuf; }
2652 uint width () const pure { pragma(inline, true); return mWidth; }
2653 uint height () const pure { pragma(inline, true); return mHeight; }
2654 int stride () const pure { pragma(inline, true); return mStride; }
2656 bool inbox (int x, int y) const pure { pragma(inline, true); return (x >= 0 && y >= 0 && x < cast(int)mWidth && y < cast(int)mHeight); }
2658 uint absStride() const pure { pragma(inline, true); return (mStride < 0 ? cast(uint)(-mStride) : cast(uint)mStride); }
2660 inout(ubyte)* row (uint y) inout pure { pragma(inline, true); return (y < mHeight ? mRows[y] : null); }
2662 inout(ubyte)[] opSlice () inout pure { pragma(inline, true); return mBuf[0..mHeight*absStride]; }
2666 struct ScanLine {
2667 private:
2668 int mMinX;
2669 uint mMaxLen;
2670 int mDX;
2671 int mDY;
2672 int mLastX = 0x7fff;
2673 int mLastY = 0x7fff;
2674 ubyte* mCovers;
2675 ubyte** mStartPtrs;
2676 ushort* mCounts;
2677 uint mNumSpans;
2678 ubyte** mCurStartPtr;
2679 ushort* mCurCount;
2681 public:
2682 enum { AAShift = 8 }
2684 static struct Iterator {
2685 private:
2686 const(ubyte)* mCovers;
2687 const(ushort)* mCurCount;
2688 const(ubyte*)* mCurStartPtr;
2690 public nothrow @trusted @nogc:
2691 @disable this (this); // no copies
2693 this (in ref ScanLine sl) {
2694 mCovers = sl.mCovers;
2695 mCurCount = sl.mCounts;
2696 mCurStartPtr = sl.mStartPtrs;
2699 int next () {
2700 ++mCurCount;
2701 ++mCurStartPtr;
2702 return cast(int)(*mCurStartPtr-mCovers);
2705 @property int numPix () const pure { pragma(inline, true); return cast(int)(*mCurCount); }
2706 @property const(ubyte)* covers () const pure { pragma(inline, true); return *mCurStartPtr; }
2709 public nothrow @trusted @nogc:
2710 @disable this (this); // no copies
2712 ~this () {
2713 import core.stdc.stdlib : free;
2714 free(mCounts);
2715 free(mStartPtrs);
2716 free(mCovers);
2719 auto iterator () const { pragma(inline, true); return Iterator(this); }
2721 void reset (int minX, int maxX, int dx=0, int dy=0) {
2722 uint maxLen = maxX-minX+2;
2723 if (maxLen > mMaxLen) {
2724 import core.stdc.stdlib : realloc;
2725 mCovers = cast(ubyte*)realloc(mCovers, maxLen);
2726 if (mCovers is null) assert(0, "out of memory");
2727 mStartPtrs = cast(ubyte**)realloc(mStartPtrs, (ubyte*).sizeof*maxLen);
2728 if (mStartPtrs is null) assert(0, "out of memory");
2729 mCounts = cast(ushort*)realloc(mCounts, ushort.sizeof*maxLen);
2730 if (mCounts is null) assert(0, "out of memory");
2731 mMaxLen = maxLen;
2733 mDX = dx;
2734 mDY = dy;
2735 mLastX = 0x7fff;
2736 mLastY = 0x7fff;
2737 mMinX = minX;
2738 mCurCount = mCounts;
2739 mCurStartPtr = mStartPtrs;
2740 mNumSpans = 0;
2743 void resetSpans () {
2744 pragma(inline, true);
2745 mLastX = 0x7fff;
2746 mLastY = 0x7fff;
2747 mCurCount = mCounts;
2748 mCurStartPtr = mStartPtrs;
2749 mNumSpans = 0;
2752 void addSpan (int x, int y, uint num, uint cover) {
2753 import core.stdc.string : memset;
2754 x -= mMinX;
2755 memset(mCovers+x, cover, num);
2756 if (x == mLastX+1) {
2757 (*mCurCount) += cast(ushort)num;
2758 } else {
2759 *++mCurCount = cast(ushort)num;
2760 *++mCurStartPtr = mCovers+x;
2761 ++mNumSpans;
2763 mLastX = x+num-1;
2764 mLastY = y;
2767 void addCell (int x, int y, uint cover) {
2768 x -= mMinX;
2769 mCovers[x] = cast(ubyte)cover;
2770 if (x == mLastX+1) {
2771 ++(*mCurCount);
2772 } else {
2773 *++mCurCount = 1;
2774 *++mCurStartPtr = mCovers+x;
2775 ++mNumSpans;
2777 mLastX = x;
2778 mLastY = y;
2781 @property bool isReady (int y) const pure { pragma(inline, true); return (mNumSpans && (y^mLastY)); }
2782 @property int baseX () const pure { pragma(inline, true); return mMinX+mDX; }
2783 @property int y () const pure { pragma(inline, true); return mLastY+mDY; }
2784 @property uint numSpans () const pure { pragma(inline, true); return mNumSpans; }
2788 public template isGoodSpan(T) {
2789 static if (is(T == struct)) {
2790 enum isGoodSpan = is(typeof((){
2791 T span;
2792 span.render(cast(ubyte*)0x29a, cast(int)0x29a, cast(uint)0x29a, cast(const(ubyte)*)0x29a, Color.red);
2793 span.hline(cast(ubyte*)0x29a, cast(int)0x29a, cast(uint)0x29a, Color.red);
2794 Color c = span.get(cast(const(ubyte)*)0x29a, cast(int)0x29a);
2795 // we should be able to copy it
2796 T spanNew = span;
2797 }));
2798 } else {
2799 enum isGoodSpan = false;
2803 public struct Renderer(Span) if (isGoodSpan!Span) {
2804 private:
2805 RenderingBuffer mRBuf;
2806 Span mSpan;
2808 public nothrow @trusted @nogc:
2809 this (ubyte* abuf, uint awidth, uint aheight, int astride) { mRBuf.attach(abuf, awidth, aheight, astride); }
2811 void attach (ubyte* abuf, uint awidth, uint aheight, int astride) { mRBuf.attach(abuf, awidth, aheight, astride); }
2813 void clear (in Color c) {
2814 foreach (immutable uint y; 0..mRBuf.height) {
2815 mSpan.hline(mRBuf.row(y), 0, mRBuf.width, c);
2819 void setPixel (int x, int y, in Color c) {
2820 if (mRBuf.inbox(x, y)) {
2821 mSpan.hline(mRBuf.row(y), x, 1, c);
2825 Color getPixel (int x, int y) const pure { pragma(inline, true); return (mRBuf.inbox(x, y) ? mSpan.get(mRBuf.row(y), x) : Color.transparent); }
2827 @property int width () const pure { pragma(inline, true); return mRBuf.width; }
2828 @property int height () const pure { pragma(inline, true); return mRBuf.height; }
2830 void render (in ref ScanLine sl, in Color c) {
2831 if (sl.y < 0 || sl.y >= cast(int)mRBuf.height) return;
2832 uint numSpans = sl.numSpans;
2833 int baseX = sl.baseX;
2834 ubyte* row = mRBuf.row(sl.y);
2835 auto span = sl.iterator;
2836 do {
2837 int x = span.next+baseX;
2838 const(ubyte)* covers = span.covers;
2839 int numPix = span.numPix;
2840 if (x < 0) {
2841 numPix += x;
2842 if (numPix <= 0) continue;
2843 covers -= x;
2844 x = 0;
2846 if (x+numPix >= cast(int)mRBuf.width) {
2847 numPix = mRBuf.width-x;
2848 if (numPix <= 0) continue;
2850 mSpan.render(row, x, numPix, covers, c);
2851 } while (--numSpans);
2854 inout(ubyte)[] opSlice () inout pure { pragma(inline, true); return mRBuf[]; }
2858 /* *****************************************************************************
2859 These constants determine the subpixel accuracy, to be more precise,
2860 the number of bits of the fractional part of the coordinates.
2861 The possible coordinate capacity in bits can be calculated by formula:
2862 sizeof(int) * 8 - PolyBaseShift * 2, i.e, for 32-bit integers and
2863 8-bits fractional part the capacity is 16 bits or [-32768...32767].
2864 ***************************************************************************** */
2865 enum : uint {
2866 PolyBaseShift = 8U,
2867 PolyBaseSize = cast(uint)(1<<PolyBaseShift),
2868 PolyBaseMask = cast(uint)(PolyBaseSize-1),
2872 int polyCoord (in double c) pure nothrow @safe @nogc { pragma(inline, true); return cast(int)(c*PolyBaseSize); }
2875 // A pixel cell
2876 struct Cell {
2877 public:
2878 short x, y;
2879 int packedCoord;
2880 int cover;
2881 int area;
2883 public nothrow @trusted @nogc:
2884 this (int cx, int cy, int c, int a) {
2885 pragma(inline, true);
2886 x = cast(short)cx;
2887 y = cast(short)cy;
2888 packedCoord = (cy<<16)+cx;
2889 cover = c;
2890 area = a;
2893 void setCover (int c, int a) {
2894 pragma(inline, true);
2895 cover = c;
2896 area = a;
2899 void addCover (int c, int a) {
2900 pragma(inline, true);
2901 cover += c;
2902 area += a;
2905 void setCoord (int cx, int cy) {
2906 pragma(inline, true);
2907 x = cast(short)cx;
2908 y = cast(short)cy;
2909 packedCoord = (cy<<16)+cx;
2912 void set (int cx, int cy, int c, int a) {
2913 pragma(inline, true);
2914 x = cast(short)cx;
2915 y = cast(short)cy;
2916 packedCoord = (cy<<16)+cx;
2917 cover = c;
2918 area = a;
2923 // An internal class that implements the main rasterization algorithm. Used in the rasterizer. Should not be used direcly.
2924 struct Outline {
2925 private:
2926 enum : uint {
2927 CellBlockShift = 12U,
2928 CellBlockSize = cast(uint)(1<<CellBlockShift),
2929 CellBlockMask = cast(uint)(CellBlockSize-1),
2930 CellBlockPool = 256U,
2931 CellBlockLimit = 1024U,
2934 enum QSortThreshold = 9;
2936 enum : uint {
2937 NotClosed = 1U,
2938 SortRequired = 2U,
2941 private:
2942 uint mNumBlocks;
2943 uint mMaxBlocks;
2944 uint mCurBlock;
2945 uint mNumCells;
2946 Cell** mCells;
2947 Cell* mCurCellPtr;
2948 Cell** mSortedCells;
2949 uint mSortedSize;
2950 Cell mCurCell = Cell(0x7fff, 0x7fff, 0, 0);
2951 int mCurX;
2952 int mCurY;
2953 int mCloseX;
2954 int mCloseY;
2955 int mMinX = 0x7fffffff;
2956 int mMinY = 0x7fffffff;
2957 int mMaxX = -0x7fffffff;
2958 int mMaxY = -0x7fffffff;
2959 uint mFlags = SortRequired;
2961 public nothrow @trusted @nogc:
2962 @disable this (this); // no copies
2964 ~this () {
2965 import core.stdc.stdlib : free;
2966 free(mSortedCells);
2967 if (mNumBlocks) {
2968 Cell** ptr = mCells+mNumBlocks-1;
2969 while (mNumBlocks--) {
2970 free(*ptr);
2971 --ptr;
2973 free(mCells);
2977 void reset () {
2978 mNumCells = 0;
2979 mCurBlock = 0;
2980 mCurCell.set(0x7fff, 0x7fff, 0, 0);
2981 mFlags |= SortRequired;
2982 mFlags &= ~NotClosed;
2983 mMinX = 0x7fffffff;
2984 mMinY = 0x7fffffff;
2985 mMaxX = -0x7fffffff;
2986 mMaxY = -0x7fffffff;
2989 void moveTo (int x, int y) {
2990 if ((mFlags&SortRequired) == 0) reset();
2991 if (mFlags&NotClosed) lineTo(mCloseX, mCloseY);
2992 setCurCell(x>>PolyBaseShift, y>>PolyBaseShift);
2993 mCloseX = mCurX = x;
2994 mCloseY = mCurY = y;
2997 void lineTo (int x, int y) {
2998 if ((mFlags&SortRequired) && ((mCurX^x)|(mCurY^y))) {
2999 int c = mCurX>>PolyBaseShift;
3000 if (c < mMinX) mMinX = c;
3001 ++c;
3002 if (c > mMaxX) mMaxX = c;
3004 c = x>>PolyBaseShift;
3005 if (c < mMinX) mMinX = c;
3006 ++c;
3007 if (c > mMaxX) mMaxX = c;
3009 renderLine(mCurX, mCurY, x, y);
3010 mCurX = x;
3011 mCurY = y;
3012 mFlags |= NotClosed;
3016 @property double curX () const pure { pragma(inline, true); return cast(double)mCurX/cast(double)PolyBaseSize; }
3017 @property double curY () const pure { pragma(inline, true); return cast(double)mCurY/cast(double)PolyBaseSize; }
3019 @property int minX () const pure { pragma(inline, true); return mMinX; }
3020 @property int minY () const pure { pragma(inline, true); return mMinY; }
3021 @property int maxX () const pure { pragma(inline, true); return mMaxX; }
3022 @property int maxY () const pure { pragma(inline, true); return mMaxY; }
3024 @property uint numCells () const pure { pragma(inline, true); return mNumCells; }
3026 const(Cell)** cells () {
3027 if (mFlags&NotClosed) {
3028 lineTo(mCloseX, mCloseY);
3029 mFlags &= ~NotClosed;
3031 // perform sort only the first time
3032 if (mFlags&SortRequired) {
3033 addCurCell();
3034 if (mNumCells == 0) return null;
3035 sortCells();
3036 mFlags &= ~SortRequired;
3038 return cast(const(Cell)**)mSortedCells;
3041 private:
3042 void allocateBlock () {
3043 import core.stdc.stdlib : realloc;
3044 if (mCurBlock >= mNumBlocks) {
3045 import core.stdc.string : memset;
3046 if (mNumBlocks >= mMaxBlocks) {
3047 Cell** newCells = cast(Cell**)realloc(mCells, (mMaxBlocks+CellBlockPool)*(Cell*).sizeof);
3048 if (newCells is null) assert(0, "out of memory");
3049 mCells = newCells;
3050 mMaxBlocks += CellBlockPool;
3052 auto cc = cast(Cell*)realloc(null, Cell.sizeof*CellBlockSize);
3053 if (cc is null) assert(0, "out of memory");
3054 memset(cc, 0, Cell.sizeof*CellBlockSize);
3055 foreach (ref c; cc[0..CellBlockSize]) c = Cell.init;
3056 mCells[mNumBlocks++] = cc;
3058 mCurCellPtr = mCells[mCurBlock++];
3061 void addCurCell () {
3062 if (mCurCell.area|mCurCell.cover) {
3063 if ((mNumCells&CellBlockMask) == 0) {
3064 if (mNumBlocks >= CellBlockLimit) return;
3065 allocateBlock();
3067 *mCurCellPtr++ = mCurCell;
3068 ++mNumCells;
3072 void setCurCell (int x, int y) {
3073 if (mCurCell.packedCoord != (y<<16)+x) {
3074 addCurCell();
3075 mCurCell.set(x, y, 0, 0);
3079 void renderScanLine (int ey, int x1, int y1, int x2, int y2) {
3080 int ex1 = x1>>PolyBaseShift;
3081 int ex2 = x2>>PolyBaseShift;
3082 int fx1 = x1&PolyBaseMask;
3083 int fx2 = x2&PolyBaseMask;
3085 int delta, p, first, dx;
3086 int incr, lift, mod, rem;
3088 // trivial case; happens often
3089 if (y1 == y2) {
3090 setCurCell(ex2, ey);
3091 return;
3094 // everything is located in a single cell: that is easy!
3095 if (ex1 == ex2) {
3096 delta = y2-y1;
3097 mCurCell.addCover(delta, (fx1+fx2)*delta);
3098 return;
3101 // ok, we'll have to render a run of adjacent cells on the same scanline...
3102 p = (PolyBaseSize-fx1)*(y2-y1);
3103 first = PolyBaseSize;
3104 incr = 1;
3106 dx = x2-x1;
3108 if (dx < 0) {
3109 p = fx1*(y2-y1);
3110 first = 0;
3111 incr = -1;
3112 dx = -dx;
3115 delta = p/dx;
3116 mod = p%dx;
3118 if (mod < 0) {
3119 --delta;
3120 mod += dx;
3123 mCurCell.addCover(delta, (fx1+first)*delta);
3125 ex1 += incr;
3126 setCurCell(ex1, ey);
3127 y1 += delta;
3129 if (ex1 != ex2) {
3130 p = PolyBaseSize*(y2-y1+delta);
3131 lift = p/dx;
3132 rem = p%dx;
3134 if (rem < 0) {
3135 --lift;
3136 rem += dx;
3139 mod -= dx;
3141 while (ex1 != ex2) {
3142 delta = lift;
3143 mod += rem;
3144 if (mod >= 0) {
3145 mod -= dx;
3146 ++delta;
3148 mCurCell.addCover(delta, PolyBaseSize*delta);
3149 y1 += delta;
3150 ex1 += incr;
3151 setCurCell(ex1, ey);
3155 delta = y2-y1;
3156 mCurCell.addCover(delta, (fx2+PolyBaseSize-first)*delta);
3159 void renderLine (int x1, int y1, int x2, int y2) {
3160 int ey1 = y1>>PolyBaseShift;
3161 int ey2 = y2>>PolyBaseShift;
3162 int fy1 = y1&PolyBaseMask;
3163 int fy2 = y2&PolyBaseMask;
3165 int dx, dy, xFrom, xTo;
3166 int p, rem, mod, lift, delta, first, incr;
3168 if (ey1 < mMinY) mMinY = ey1;
3169 if (ey1+1 > mMaxY) mMaxY = ey1+1;
3170 if (ey2 < mMinY) mMinY = ey2;
3171 if (ey2+1 > mMaxY) mMaxY = ey2+1;
3173 dx = x2-x1;
3174 dy = y2-y1;
3176 // everything is on a single scanline
3177 if (ey1 == ey2) {
3178 renderScanLine(ey1, x1, fy1, x2, fy2);
3179 return;
3182 // vertical line: we have to calculate start and end cells,
3183 // and then the common values of the area and coverage for
3184 // all cells of the line. we know exactly there's only one
3185 // cell, so, we don't have to call renderScanLine().
3186 incr = 1;
3187 if (dx == 0) {
3188 int ex = x1>>PolyBaseShift;
3189 int twoFx = (x1-(ex<<PolyBaseShift))<<1;
3190 int area;
3192 first = PolyBaseSize;
3193 if (dy < 0) {
3194 first = 0;
3195 incr = -1;
3198 xFrom = x1;
3200 //renderScanLine(ey1, xFrom, fy1, xFrom, first);
3201 delta = first-fy1;
3202 mCurCell.addCover(delta, twoFx*delta);
3204 ey1 += incr;
3205 setCurCell(ex, ey1);
3207 delta = first+first-PolyBaseSize;
3208 area = twoFx*delta;
3209 while (ey1 != ey2) {
3210 //renderScanLine(ey1, xFrom, PolyBaseSize - first, xFrom, first);
3211 mCurCell.setCover(delta, area);
3212 ey1 += incr;
3213 setCurCell(ex, ey1);
3215 //renderScanLine(ey1, xFrom, PolyBaseSize - first, xFrom, fy2);
3216 delta = fy2-PolyBaseSize+first;
3217 mCurCell.addCover(delta, twoFx*delta);
3218 return;
3221 // ok, we have to render several scanlines
3222 p = (PolyBaseSize-fy1)*dx;
3223 first = PolyBaseSize;
3225 if (dy < 0) {
3226 p = fy1*dx;
3227 first = 0;
3228 incr = -1;
3229 dy = -dy;
3232 delta = p/dy;
3233 mod = p%dy;
3235 if (mod < 0) {
3236 --delta;
3237 mod += dy;
3240 xFrom = x1+delta;
3241 renderScanLine(ey1, x1, fy1, xFrom, first);
3243 ey1 += incr;
3244 setCurCell(xFrom>>PolyBaseShift, ey1);
3246 if (ey1 != ey2) {
3247 p = PolyBaseSize*dx;
3248 lift = p/dy;
3249 rem = p%dy;
3251 if (rem < 0) {
3252 --lift;
3253 rem += dy;
3255 mod -= dy;
3257 while (ey1 != ey2) {
3258 delta = lift;
3259 mod += rem;
3260 if (mod >= 0) {
3261 mod -= dy;
3262 ++delta;
3265 xTo = xFrom+delta;
3266 renderScanLine(ey1, xFrom, PolyBaseSize-first, xTo, first);
3267 xFrom = xTo;
3269 ey1 += incr;
3270 setCurCell(xFrom>>PolyBaseShift, ey1);
3274 renderScanLine(ey1, xFrom, PolyBaseSize-first, x2, fy2);
3277 static void qsortCells (Cell** start, uint num) {
3278 static void swapCells (Cell** a, Cell** b) nothrow @trusted @nogc {
3279 pragma(inline, true);
3280 auto temp = *a;
3281 *a = *b;
3282 *b = temp;
3285 static bool lessThan (Cell** a, Cell** b) nothrow @trusted @nogc { pragma(inline, true); return ((**a).packedCoord < (**b).packedCoord); }
3287 Cell**[80] stack = void;
3288 Cell*** top;
3289 Cell** limit;
3290 Cell** base;
3292 limit = start+num;
3293 base = start;
3294 top = stack.ptr;
3296 for (;;) {
3297 int len = cast(int)(limit-base);
3299 Cell** i;
3300 Cell** j;
3301 Cell** pivot;
3303 if (len > QSortThreshold) {
3304 // we use base + len/2 as the pivot
3305 pivot = base+len/2;
3306 swapCells(base, pivot);
3308 i = base+1;
3309 j = limit-1;
3311 // now ensure that *i <= *base <= *j
3312 if (lessThan(j, i)) swapCells(i, j);
3313 if (lessThan(base, i)) swapCells(base, i);
3314 if (lessThan(j, base)) swapCells(base, j);
3316 for (;;) {
3317 do { ++i; } while (lessThan(i, base));
3318 do { --j; } while (lessThan(base, j));
3319 if (i > j) break;
3320 swapCells(i, j);
3323 swapCells(base, j);
3325 // now, push the largest sub-array
3326 if (j-base > limit-i) {
3327 top[0] = base;
3328 top[1] = j;
3329 base = i;
3330 } else {
3331 top[0] = i;
3332 top[1] = limit;
3333 limit = j;
3335 top += 2;
3336 } else {
3337 // the sub-array is small, perform insertion sort
3338 j = base;
3339 i = j+1;
3340 for (; i < limit; j = i, ++i) {
3341 for (; lessThan(j+1, j); --j) {
3342 swapCells(j+1, j);
3343 if (j == base) break;
3346 if (top > stack.ptr) {
3347 top -= 2;
3348 base = top[0];
3349 limit = top[1];
3350 } else {
3351 break;
3357 void sortCells () {
3358 if (mNumCells == 0) return;
3360 if (mNumCells > mSortedSize) {
3361 import core.stdc.stdlib: realloc;
3362 mSortedSize = mNumCells;
3363 mSortedCells = cast(Cell**)realloc(mSortedCells, (mNumCells+1)*(Cell*).sizeof);
3366 Cell** sortedPtr = mSortedCells;
3367 Cell** blockPtr = mCells;
3368 Cell* cellPtr;
3370 uint nb = mNumCells>>CellBlockShift;
3371 uint i;
3373 while (nb--) {
3374 cellPtr = *blockPtr++;
3375 i = CellBlockSize;
3376 while (i--) *sortedPtr++ = cellPtr++;
3379 cellPtr = *blockPtr++;
3380 i = mNumCells&CellBlockMask;
3381 while (i--) *sortedPtr++ = cellPtr++;
3382 mSortedCells[mNumCells] = null;
3383 qsortCells(mSortedCells, mNumCells);
3388 /* *****************************************************************************
3389 Polygon rasterizer that is used to render filled polygons with
3390 high-quality Anti-Aliasing. Internally, by default, the class uses
3391 integer coordinates in format 24.8, i.e. 24 bits for integer part
3392 and 8 bits for fractional - see PolyBaseShift. This class can be
3393 used in the following way:
3395 1. fillRule = FillRule.EvenOdd; // optional
3397 2. gamma() - optional.
3399 3. reset()
3401 4. moveTo(x, y) / lineTo(x, y) - make the polygon. One can create
3402 more than one contour, but each contour must consist of at least 3
3403 vertices, i.e. moveTo(x1, y1); lineTo(x2, y2); lineTo(x3, y3);
3404 is the absolute minimum of vertices that define a triangle.
3405 The algorithm does not check either the number of vertices nor
3406 coincidence of their coordinates, but in the worst case it just
3407 won't draw anything.
3408 The orger of the vertices (clockwise or counterclockwise)
3409 is important when using the non-zero filling rule (FillNonZero).
3410 In this case the vertex order of all the contours must be the same
3411 if you want your intersecting polygons to be without "holes".
3412 You actually can use different vertices order. If the contours do not
3413 intersect each other the order is not important anyway. If they do,
3414 contours with the same vertex order will be rendered without "holes"
3415 while the intersecting contours with different orders will have "holes".
3417 fillRule() and gamma() can be called anytime before "sweeping".
3418 ***************************************************************************** */
3419 public struct Rasterizer {
3420 public:
3421 enum : uint {
3422 AAShift = ScanLine.AAShift,
3423 AANum = 1<<AAShift,
3424 AAMask = AANum-1,
3425 AA2Num = AANum*2,
3426 AA2Mask = AA2Num-1,
3429 enum FillRule {
3430 NonZero,
3431 EvenOdd,
3434 private:
3435 Outline mOutline;
3436 ScanLine mScanline;
3437 FillRule mFillingRule = FillRule.NonZero;
3438 ubyte[256] mGamma = DefaultGamma[];
3440 public nothrow @trusted @nogc:
3441 void reset () { mOutline.reset(); }
3443 @property FillRule fillRule () const pure { pragma(inline, true); return mFillingRule; }
3444 @property void fillRule (FillRule v) { pragma(inline, true); mFillingRule = v; }
3446 void gamma (in double g) {
3447 foreach (immutable uint i; 0..256) {
3448 import std.math : pow;
3449 mGamma.ptr[i] = cast(ubyte)(pow(cast(double)i/255.0, g)*255.0);
3453 void gamma (const(ubyte)[] g) {
3454 if (g.length != 256) assert(0, "invalid gamma array");
3455 mGamma[] = g[0..256];
3458 void moveTo (int x, int y) { mOutline.moveTo(x, y); }
3459 void lineTo (int x, int y) { mOutline.lineTo(x, y); }
3461 void moveTo (in double x, in double y) { mOutline.moveTo(polyCoord(x), polyCoord(y)); }
3462 void lineTo (in double x, in double y) { mOutline.lineTo(polyCoord(x), polyCoord(y)); }
3464 @property double curX () const pure { pragma(inline, true); return mOutline.curX; }
3465 @property double curY () const pure { pragma(inline, true); return mOutline.curY; }
3467 @property int minX () const pure { pragma(inline, true); return mOutline.minX; }
3468 @property int minY () const pure { pragma(inline, true); return mOutline.minY; }
3469 @property int maxX () const pure { pragma(inline, true); return mOutline.maxX; }
3470 @property int maxY () const pure { pragma(inline, true); return mOutline.maxY; }
3472 uint calculateAlpha (int area) const pure {
3473 int cover = area>>(PolyBaseShift*2+1-AAShift);
3474 if (cover < 0) cover = -cover;
3475 if (mFillingRule == FillRule.EvenOdd) {
3476 cover &= AA2Mask;
3477 if (cover > AANum) cover = AA2Num-cover;
3479 if (cover > AAMask) cover = AAMask;
3480 return cover;
3483 void render(RT) (ref RT r, in Color c, int dx=0, int dy=0) if (is(RT : Renderer!ST, ST)) {
3484 const(Cell)** cells = mOutline.cells();
3485 if (mOutline.numCells() == 0) return;
3487 int x, y;
3488 int cover;
3489 int alpha;
3490 int area;
3492 mScanline.reset(mOutline.minX(), mOutline.maxX(), dx, dy);
3494 cover = 0;
3495 const(Cell)* curCell = *cells++;
3496 for (;;) {
3497 const(Cell)* startCell = curCell;
3499 int coord = curCell.packedCoord;
3500 x = curCell.x;
3501 y = curCell.y;
3503 area = startCell.area;
3504 cover += startCell.cover;
3506 // accumulate all start cells
3507 while ((curCell = *cells++) !is null) {
3508 if (curCell.packedCoord != coord) break;
3509 area += curCell.area;
3510 cover += curCell.cover;
3513 if (area) {
3514 alpha = calculateAlpha((cover<<(PolyBaseShift+1))-area);
3515 if (alpha) {
3516 if (mScanline.isReady(y)) {
3517 r.render(mScanline, c);
3518 mScanline.resetSpans();
3520 mScanline.addCell(x, y, mGamma[alpha]);
3522 ++x;
3525 if (!curCell) break;
3527 if (curCell.x > x) {
3528 alpha = calculateAlpha(cover<<(PolyBaseShift+1));
3529 if (alpha) {
3530 if (mScanline.isReady(y)) {
3531 r.render(mScanline, c);
3532 mScanline.resetSpans();
3534 mScanline.addSpan(x, y, curCell.x-x, mGamma[alpha]);
3539 if (mScanline.numSpans) r.render(mScanline, c);
3542 bool hitTest (int tx, int ty) {
3543 const(Cell)** cells = mOutline.cells();
3544 if (mOutline.numCells == 0) return false;
3546 int x, y;
3547 int cover;
3548 int alpha;
3549 int area;
3551 cover = 0;
3552 const(Cell)* curCell = *cells++;
3553 for (;;) {
3554 const(Cell)* startCell = curCell;
3556 int coord = curCell.packedCoord;
3557 x = curCell.x;
3558 y = curCell.y;
3560 if (y > ty) return false;
3562 area = startCell.area;
3563 cover += startCell.cover;
3565 while ((curCell = *cells++) !is null) {
3566 if (curCell.packedCoord != coord) break;
3567 area += curCell.area;
3568 cover += curCell.cover;
3571 if (area) {
3572 alpha = calculateAlpha((cover<<(PolyBaseShift+1))-area);
3573 if (alpha) {
3574 if (tx == x && ty == y) return true;
3576 ++x;
3579 if (!curCell) break;
3581 if (curCell.x > x) {
3582 alpha = calculateAlpha(cover<<(PolyBaseShift+1));
3583 if (alpha) {
3584 if (ty == y && tx >= x && tx <= curCell.x) return true;
3588 return false;
3591 private:
3592 static immutable ubyte[256] DefaultGamma = [
3593 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8,
3594 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 16, 16, 17, 18, 18,
3595 19, 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28,
3596 29, 29, 30, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37, 38,
3597 39, 39, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49,
3598 49, 50, 51, 51, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60,
3599 60, 61, 62, 62, 63, 64, 65, 65, 66, 67, 68, 68, 69, 70, 71, 71,
3600 72, 73, 74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 82, 83, 83, 84,
3601 85, 86, 87, 88, 89, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
3602 100,101,101,102,103,104,105,106,107,108,109,110,111,112,114,115,
3603 116,117,118,119,120,121,122,123,124,126,127,128,129,130,131,132,
3604 134,135,136,137,139,140,141,142,144,145,146,147,149,150,151,153,
3605 154,155,157,158,159,161,162,164,165,166,168,169,171,172,174,175,
3606 177,178,180,181,183,184,186,188,189,191,192,194,195,197,199,200,
3607 202,204,205,207,209,210,212,214,215,217,219,220,222,224,225,227,
3608 229,230,232,234,236,237,239,241,242,244,246,248,249,251,253,255
3613 // ////////////////////////////////////////////////////////////////////////// //
3614 // X11 image: "bgra"; TrueColorImage: "rgba"
3615 public struct SimpleSpan(string mode)
3616 if (mode == "bgra" || mode == "rgba" || mode == "x11" || mode == "X11" || mode == "arsd" || mode == "bgr" || mode == "rgb")
3618 static if (mode == "bgra" || mode == "x11" || mode == "X11") {
3619 enum IsBGRA = true;
3620 enum Is32Bit = true;
3621 } else static if (mode == "rgba" || mode == "arsd") {
3622 enum IsBGRA = false;
3623 enum Is32Bit = true;
3624 } else static if (mode == "bgr") {
3625 enum IsBGRA = true;
3626 enum Is32Bit = false;
3627 } else static if (mode == "rgb") {
3628 enum IsBGRA = false;
3629 enum Is32Bit = false;
3630 } else {
3631 static assert(0, "invalid mode");
3634 static void render (ubyte* ptr, int x, uint count, const(ubyte)* covers, in Color c) {
3635 static if (Is32Bit) {
3636 ubyte* p = ptr+(x<<2);
3637 } else {
3638 ubyte* p = ptr+x+x+x;
3640 do {
3641 int alpha = (*covers++)*c.a;
3642 static if (IsBGRA) {
3643 int b = p[0];
3644 int g = p[1];
3645 int r = p[2];
3646 static if (Is32Bit) int a = p[3];
3647 *p++ = cast(ubyte)((((c.b-b)*alpha)+(b<<16))>>16);
3648 *p++ = cast(ubyte)((((c.g-g)*alpha)+(g<<16))>>16);
3649 *p++ = cast(ubyte)((((c.r-r)*alpha)+(r<<16))>>16);
3650 static if (Is32Bit) *p++ = cast(ubyte)((((c.a-a)*alpha)+(a<<16))>>16);
3651 } else {
3652 int r = p[0];
3653 int g = p[1];
3654 int b = p[2];
3655 static if (Is32Bit) int a = p[3];
3656 *p++ = cast(ubyte)((((c.r-r)*alpha)+(r<<16))>>16);
3657 *p++ = cast(ubyte)((((c.g-g)*alpha)+(g<<16))>>16);
3658 *p++ = cast(ubyte)((((c.b-b)*alpha)+(b<<16))>>16);
3659 static if (Is32Bit) *p++ = cast(ubyte)((((c.a-a)*alpha)+(a<<16))>>16);
3661 } while (--count);
3664 static void hline (ubyte* ptr, int x, uint count, in Color c) {
3665 static if (!IsBGRA && Is32Bit) {
3666 // fastest case
3667 uint* p = cast(uint*)(ptr+(x<<2));
3668 p[0..count] = c.asUint;
3669 } else {
3670 static if (Is32Bit) {
3671 ubyte* p = ptr+(x<<2);
3672 } else {
3673 ubyte* p = ptr+x+x+x;
3675 do {
3676 static if (IsBGRA) {
3677 *p++ = c.b;
3678 *p++ = c.g;
3679 *p++ = c.r;
3680 } else {
3681 *p++ = c.r;
3682 *p++ = c.g;
3683 *p++ = c.b;
3685 static if (Is32Bit) *p++ = c.a;
3686 } while (--count);
3690 static Color get (const(ubyte)* ptr, int x) {
3691 static if (Is32Bit) {
3692 const(ubyte)* p = ptr+(x<<2);
3693 } else {
3694 const(ubyte)* p = ptr+x+x+x;
3696 static if (IsBGRA) {
3697 static if (Is32Bit) {
3698 return Color(p[2], p[1], p[0], p[3]);
3699 } else {
3700 return Color(p[2], p[1], p[0], 255);
3702 } else {
3703 static if (Is32Bit) {
3704 return Color(p[0], p[1], p[2], p[3]);
3705 } else {
3706 return Color(p[0], p[1], p[2]);
3714 // ////////////////////////////////////////////////////////////////////////// //
3716 version(linux) final class SdpyDrawVBuf : SdpyDrawBase {
3717 private:
3718 XImageTC vbuf;
3720 protected:
3721 // must be overriden
3722 override Color getpix (int x, int y) {
3723 pragma(inline, true);
3724 return XlibImageTC.img2c(vbuf.data[y*vbuf.width+x]);
3727 override void putpix (int x, int y, Color col) {
3728 uint* dp = vbuf.data+y*vbuf.width+x;
3729 if (col.a == 255) *dp = XlibImageTC.c2img(col)|0xff_000000; else *dp = blendU32(*dp, XlibImageTC.c2img(col)|(col.a<<24));
3732 // optionals
3733 override void hline (int x, int y, int len, Color col) {
3734 uint* dp = vbuf.data+y*vbuf.width+x;
3735 uint uc = XlibImageTC.c2img(col);
3736 if (col.a == 255) {
3737 uc |= 0xff_000000;
3738 foreach (immutable _; 0..len) *dp++ = uc;
3739 } else {
3740 uc |= col.a<<24;
3741 foreach (immutable _; 0..len) { *dp = blendU32(*dp, uc); ++dp; }
3745 public:
3746 this (XImageTC img) {
3747 vbuf = img;
3748 super(img.width, img.height);
3751 override TrueColorImage getBuffer () {
3752 auto img = new TrueColorImage(vbuf.width, vbuf.height);
3753 const(uint)* sp = cast(const(uint)*)vbuf.data;
3754 auto dp = img.imageData.colors.ptr;
3755 foreach (immutable y; 0..vbuf.height) {
3756 foreach (immutable x; 0..vbuf.width) {
3757 *dp++ = XlibImageTC.img2c(*sp++);
3760 return img;
3763 final @property XImageTC imagebuf () pure nothrow @safe @nogc { pragma(inline, true); return vbuf; }
3765 final void cls (Color clr) {
3766 import core.stdc.string : memset;
3767 if (!vbuf.valid) return;
3768 if (clr.r == 0 && clr.g == 0 && clr.b == 0) {
3769 memset(vbuf.data, 0, vbuf.width*vbuf.height*uint.sizeof);
3770 } else {
3771 drawRect!true(0, 0, vbuf.width, vbuf.height);
3775 void blitFrom (DFImage src, int x0, int y0, int subalpha=-1, int cx0=0, int cy0=0, int cx1=int.max, int cy1=int.max) {
3776 if (src is null || !src.valid || !vbuf.valid) return;
3777 if (cx1 >= vbuf.width) cx1 = vbuf.width-1;
3778 if (cy1 >= vbuf.height) cy1 = vbuf.height-1;
3779 if (cx0 < 0) cx0 = 0;
3780 if (cy0 < 0) cy0 = 0;
3781 if (cx1 < cx0 || cy1 < cy0 || cx1 < 0 || cy1 < 0 || cx0 >= vbuf.width || cy0 >= vbuf.height) return; // nothing to do here
3783 void doBlit(bool doSrcAlpha, bool doSubAlpha) (int x, int y, int xofs, int yofs, int wdt, int hgt, int subalpha=0) {
3784 auto sc = cast(const(uint)*)src.data.ptr;
3785 auto dc = vbuf.data;
3786 sc += yofs*src.width+xofs;
3787 dc += y*vbuf.width+x;
3788 foreach (immutable dy; 0..hgt) {
3789 static if (!doSubAlpha && !doSrcAlpha) {
3790 // fastest path
3791 import core.stdc.string : memcpy;
3792 memcpy(dc, sc, wdt*uint.sizeof);
3793 } else {
3794 auto scl = sc;
3795 auto dcl = dc;
3796 foreach (immutable dx; 0..wdt) {
3797 static if (doSubAlpha) {
3798 static assert(!doSrcAlpha);
3799 *dcl = XlibImageTC.icRGB(
3800 XlibImageTC.icR(*dcl)+XlibImageTC.icR(*scl)*(255-subalpha)/255,
3801 XlibImageTC.icG(*dcl)+XlibImageTC.icG(*scl)*(255-subalpha)/255,
3802 XlibImageTC.icB(*dcl)+XlibImageTC.icB(*scl)*(255-subalpha)/255,
3804 } else {
3805 static assert(doSrcAlpha);
3806 if (XlibImageTC.icA(*scl) == 255) {
3807 *dcl = *scl;
3808 } else if (XlibImageTC.icA(*scl)) {
3809 *dcl = (*dcl).blendU32(*scl);
3812 ++scl;
3813 ++dcl;
3816 sc += src.width;
3817 dc += vbuf.width;
3821 int swdt = src.width, shgt = src.height, xofs = 0, yofs = 0, x = x0, y = y0;
3822 if (!GxRect(cx0, cy0, cx1-cx0+1, cy1-cy0+1).clipHVStripes(x, y, swdt, shgt, &xofs, &yofs)) return; // nothing to do here
3823 if (!src.hasAlpha && subalpha < 0) {
3824 doBlit!(false, false)(x, y, xofs, yofs, swdt, shgt);
3825 } else if (subalpha >= 0) {
3826 doBlit!(false, true)(x, y, xofs, yofs, swdt, shgt, subalpha);
3827 } else if (src.hasAlpha) {
3828 doBlit!(true, false)(x, y, xofs, yofs, swdt, shgt);
3829 } else {
3830 assert(0, "wtf?!");
3834 void blendRect (int x0, int y0, int w, int h, Color clr) {
3835 if (clr.a == 0 || !vbuf.valid) return;
3836 if (!GxRect(0, 0, vbuf.width, vbuf.height).clipHVStripes(x0, y0, w, h)) return; // nothing to do here
3837 auto dc = vbuf.data;
3838 dc += y0*vbuf.width+x0;
3839 if (clr.a == 255) {
3840 uint c = XlibImageTC.c2img(clr);
3841 foreach (immutable dy; 0..h) {
3842 auto dcl = dc;
3843 foreach (immutable dx; 0..w) *dcl++ = c;
3844 dc += vbuf.width;
3846 } else {
3847 uint c = XlibImageTC.icRGBA(clr.r, clr.g, clr.b, clr.a);
3848 foreach (immutable dy; 0..h) {
3849 auto dcl = dc;
3850 foreach (immutable dx; 0..w) {
3851 *dcl = (*dcl).blendU32(c);
3852 ++dcl;
3854 dc += vbuf.width;