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