iv.nanovega: fixed idiotic vanilla warning
[iv.d.git] / glkgi.d
blob535a9d79c2f10da87ce9b108078c211ad825cf96
1 /* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 /// DO NOT USE YET!
18 module iv.glkgi /*is aliced*/;
20 import iv.alice;
21 import core.atomic;
22 import std.concurrency;
24 public import arsd.simpledisplay;
25 //public import arsd.color;
26 //public import arsd.image;
28 import iv.bclamp;
29 public import iv.cmdcongl;
30 import iv.glbinds;
32 //version=glkgi_rgba; // default, has priority
33 //version=glkgi_bgra;
35 version(BigEndian) static assert(0, "sorry, big-endian platforms aren't supported yet");
37 version(glkgi_rgba) {
38 public enum KGIRGBA = true;
39 } else version(glkgi_bgra) {
40 public enum KGIRGBA = false;
41 } else {
42 public enum KGIRGBA = true;
46 // ////////////////////////////////////////////////////////////////////////// //
47 public enum kgiMaxCurW = 64;
48 public enum kgiMaxCurH = 64;
51 // ////////////////////////////////////////////////////////////////////////// //
52 // 0:b; 1:g; 2:r; 3: nothing
53 private __gshared int vbufW = 800, vbufH = 600;
54 __gshared uint* vbuf; // see KGIRGBA
55 __gshared uint* vbufsaved; // saved before updating texture
56 private __gshared uint* vcurbuf;
57 private __gshared bool blit2x = false;
58 //private enum BlitType { normal, bw, green, red }
59 //private __gshared BlitType blitType = BlitType.normal;
60 private __gshared bool scanlines = false;
61 private __gshared SimpleWindow vbwin;
62 private __gshared uint vbTexId = 0;
63 private __gshared uint vbCurTexId = 0;
64 private __gshared uint sdrScanlineId = 0;
65 private __gshared int shaderVersionOk = -1; // <0: not checked; 0: fail; >0: ok
66 private __gshared string kgiTitle = "KGI Graphics";
67 private __gshared uint vupcounter = 0;
68 private __gshared uint vupcounterlast = 0;
69 private shared bool updateTexture = true;
70 private shared bool updateCurTexture = true;
71 private __gshared uint fps = 35; // average FPS
72 private __gshared bool showShaderWarnings = false;
74 private __gshared bool oldogl = false;
76 private __gshared int mcurX = 0, mcurY = 0;
77 private __gshared int mhotX = 0, mhotY = 0;
78 private __gshared int mcurHidden = 1;
80 private shared bool vWantMotionEvents = false;
81 private shared bool vWantCharEvents = false;
84 public @property bool kgiMotionEvents () nothrow @trusted @nogc { pragma(inline, true); return atomicLoad(vWantMotionEvents); } ///
85 public @property bool kgiCharEvents () nothrow @trusted @nogc { pragma(inline, true); return atomicLoad(vWantCharEvents); } ///
87 public @property void kgiMotionEvents (bool v) nothrow @trusted @nogc { pragma(inline, true); atomicStore(vWantMotionEvents, v); } ///
88 public @property void kgiCharEvents (bool v) nothrow @trusted @nogc { pragma(inline, true); atomicStore(vWantCharEvents, v); } ///
90 public @property int kgiWidth () nothrow @trusted @nogc { pragma(inline, true); return vbufW; }
91 public @property int kgiHeight () nothrow @trusted @nogc { pragma(inline, true); return vbufH; }
94 //FIXME! turn this to proper setter
95 public __gshared bool delegate () onKGICloseRequest;
98 shared static this () {
99 conRegVar!blit2x("v_scale2x", "video window scale");
100 conRegVar!scanlines("v_scanlines", "emulate old CRT scanline effect");
101 conRegVar!vbufW(64, 4096, "v_width", "video window width");
102 conRegVar!vbufH(64, 4096, "v_height", "video window height");
103 conRegVar!fps(1, 60, "v_fps", "video update rate");
104 conRegVar!kgiTitle("v_title", "video window title");
105 conRegVar!showShaderWarnings("v_shader_warnings", "show warnings from shader compilation");
106 conRegVar!oldogl("v_legacygl", "set to true to use legacy OpenGL");
110 private void setUpdateTextureFlag () {
111 pragma(inline, true);
112 if (vbuf !is null) {
113 atomicFence();
114 auto c = vupcounter;
115 if (vupcounterlast != c) {
116 vupcounterlast = c;
117 vbufsaved[0..vbufW*vbufH] = vbuf[0..vbufW*vbufH];
119 atomicStore(updateTexture, true);
125 public void kgiHideCursor () {
126 bool csc;
128 consoleLock();
129 scope(exit) consoleUnlock();
130 ++mcurHidden;
131 csc = (vbwin !is null && (mcurHidden == -1 || mcurHidden == 1));
133 if (csc) vbwin.showCursor();
138 public void kgiShowCursor () {
139 bool csc;
141 consoleLock();
142 scope(exit) consoleUnlock();
143 --mcurHidden;
144 csc = (vbwin !is null && mcurHidden == 0);
146 if (csc) vbwin.hideCursor();
151 public void kgiSetCursor (int wdt, int hgt, const(VColor)[] img, int hotx=0, int hoty=0) nothrow @trusted @nogc {
152 consoleLock();
153 scope(exit) consoleUnlock();
154 mhotX = hotx;
155 mhotY = hoty;
156 if (vcurbuf is null) return;
157 vcurbuf[0..kgiMaxCurW*kgiMaxCurH] = 0;
158 if (wdt < 1 || hgt < 1) return;
159 foreach (immutable dy; 0..64) {
160 if (dy >= hgt) break;
161 foreach (immutable dx; 0..64) {
162 if (dx >= wdt) break;
163 uint sp = dy*wdt+dx;
164 if (sp >= img.length) break;
165 vcurbuf[dy*kgiMaxCurW+dx] = img.ptr[sp];
168 atomicStore(updateCurTexture, true);
172 private void unpackDefaultCursor () nothrow @trusted @nogc {
173 mhotX = 2;
174 mhotY = 0;
175 if (vcurbuf is null) return;
176 vcurbuf[0..kgiMaxCurW*kgiMaxCurH] = 0;
177 foreach (immutable dy; 0..defaultCurHeight) {
178 foreach (immutable dx; 0..defaultCurWidth) {
179 uint sp = dy*defaultCurWidth+dx;
180 vcurbuf[dy*kgiMaxCurW+dx] = defaultCurPal.ptr[defaultCurImg.ptr[sp]];
187 public void kgiSetDefaultCursor () nothrow @trusted @nogc {
188 consoleLock();
189 scope(exit) consoleUnlock();
190 unpackDefaultCursor();
191 atomicStore(updateCurTexture, true);
195 public void kgiSetBlankCursor () nothrow @trusted @nogc {
196 consoleLock();
197 scope(exit) consoleUnlock();
198 mhotX = mhotY = 0;
199 if (vcurbuf is null) return;
200 vcurbuf[0..kgiMaxCurW*kgiMaxCurH] = 0;
201 atomicStore(updateCurTexture, true);
205 // ////////////////////////////////////////////////////////////////////////// //
207 public struct KGIEvent {
208 enum Type { None, Key, Mouse, Char, Close }
209 Type type = Type.None;
210 union {
211 KeyEvent k;
212 MouseEvent m;
213 dchar ch;
215 static createClose () pure nothrow @trusted @nogc {
216 KGIEvent ev = void;
217 ev.type = KGIEvent.Type.Close;
218 return ev;
220 @property const pure nothrow @trusted @nogc:
221 bool isMouse () { pragma(inline, true); return (type == Type.Mouse); }
222 bool isKey () { pragma(inline, true); return (type == Type.Key); }
223 bool isChar () { pragma(inline, true); return (type == Type.Char); }
224 bool isNone () { pragma(inline, true); return (type == Type.None); }
225 bool isClose () { pragma(inline, true); return (type == Type.Close); }
229 private __gshared KGIEvent[] evbuf;
230 private __gshared uint evbufused;
234 public bool kgiHasEvent () {
235 consoleLock();
236 scope(exit) consoleUnlock();
237 version(LDC) {} else atomicFence();
238 if (vupcounter) setUpdateTextureFlag(); // just in case
239 return (evbufused > 0 || vbwin is null); // no vbwin --> always has Quit
244 public KGIEvent kgiPeekEvent () {
245 consoleLock();
246 scope(exit) consoleUnlock();
247 version(LDC) {} else atomicFence();
248 if (!atomicLoad(kgiThreadStarted)) return KGIEvent.createClose();
249 if (vupcounter) setUpdateTextureFlag(); // just in case
250 if (evbufused > 0) return evbuf[0];
251 if (vbwin is null) return KGIEvent(KGIEvent.Type.Close);
252 return KGIEvent();
257 public KGIEvent kgiGetEvent () {
258 import core.thread;
259 import core.time;
260 version(LDC) {} else atomicFence();
261 if (vupcounter) setUpdateTextureFlag(); // just in case
262 for (;;) {
264 consoleLock();
265 scope(exit) consoleUnlock();
266 if (!atomicLoad(kgiThreadStarted)) return KGIEvent.createClose();
267 if (evbufused > 0) {
268 auto ev = evbuf[0];
269 if (evbufused > 1) {
270 import core.stdc.string : memmove;
271 memmove(evbuf.ptr, evbuf.ptr+1, KGIEvent.sizeof*(evbufused-1));
273 --evbufused;
274 evbuf[evbufused].type = KGIEvent.Type.None;
275 return ev;
276 } else if (vbwin is null) {
277 return KGIEvent(KGIEvent.Type.Close);
280 Thread.sleep(10.msecs); //FIXME
285 private void pushEventIntr (ref KGIEvent ev) {
286 if (evbufused >= evbuf.length) evbuf.length += 256;
287 evbuf[evbufused++] = ev;
292 public void kgiPushEvent (KeyEvent e) {
293 KGIEvent ev = void;
294 ev.type = KGIEvent.Type.Key;
295 ev.k = e;
296 consoleLock();
297 scope(exit) consoleUnlock();
298 pushEventIntr(ev);
302 public void kgiPushEvent (MouseEvent e) {
303 KGIEvent ev = void;
304 ev.type = KGIEvent.Type.Mouse;
305 ev.m = e;
306 consoleLock();
307 scope(exit) consoleUnlock();
308 pushEventIntr(ev);
312 public void kgiPushEvent (dchar ch) {
313 KGIEvent ev = void;
314 ev.type = KGIEvent.Type.Char;
315 ev.ch = ch;
316 consoleLock();
317 scope(exit) consoleUnlock();
318 pushEventIntr(ev);
322 public void kgiPushCloseEvent(bool clearQueue=true) () {
323 KGIEvent ev = void;
324 ev.type = KGIEvent.Type.Close;
325 consoleLock();
326 scope(exit) consoleUnlock();
327 static if (clearQueue) evbufused = 0;
328 pushEventIntr(ev);
332 /// remove all keypresses from input queue
333 public void kgiKeyFlush () {
334 uint sidx = 0, didx = 0;
335 consoleLock();
336 scope(exit) consoleUnlock();
337 if (!atomicLoad(kgiThreadStarted)) return;
338 while (sidx < evbufused) {
339 if (!evbuf[sidx].isKey) {
340 if (sidx != didx) evbuf[didx] = evbuf[sidx];
341 ++didx;
343 ++sidx;
345 evbufused = didx;
349 /// wait for keypress (and eat it)
350 public KGIEvent kgiWaitKey () {
351 for (;;) {
352 auto ev = kgiGetEvent();
353 if (ev.isClose) {
354 consoleLock();
355 scope(exit) consoleUnlock();
356 evbufused = 1;
357 evbuf[0] = ev;
358 return ev;
360 if (!ev.isKey) continue;
361 if (!ev.k.pressed) continue;
362 return ev;
367 /// flush drawing buffer (copy it to actual screen)
368 public void kgiFlush () {
369 setUpdateTextureFlag();
370 while (atomicLoad(updateTexture)) {
371 import core.thread;
372 import core.time;
373 if (!atomicLoad(kgiThreadStarted)) return;
374 Thread.sleep(1.msecs);
379 // ////////////////////////////////////////////////////////////////////////// //
381 public void kgiDeinit () {
382 concmd("quit");
386 private void kgiThread (Tid starterTid) {
387 try {
388 vbwin = new SimpleWindow(vbufW*(blit2x ? 2 : 1), vbufH*(blit2x ? 2 : 1), kgiTitle, OpenGlOptions.yes, Resizability.fixedSize);
389 if (mcurHidden == 0) vbwin.hideCursor();
391 static if (is(typeof(openGLContextFallbackActivated))) {
392 if (openGLContextFallbackActivated) oldogl = true;
395 vbwin.redrawOpenGlScene = delegate () {
396 glgfxBlit();
397 glconDraw();
400 version(Windows) {
401 // eat shit
402 } else {
403 vbwin.closeQuery = delegate () {
404 if (onKGICloseRequest !is null) try { if (!onKGICloseRequest()) return; } catch (Throwable e) {}
405 concmd("quit");
409 vbwin.visibleForTheFirstTime = delegate () {
410 vbwin.setAsCurrentOpenGlContext();
413 import core.stdc.stdio;
414 printf("GL version: %s\n", glGetString(GL_VERSION));
415 GLint l, h;
416 glGetIntegerv(GL_MAJOR_VERSION, &h);
417 glGetIntegerv(GL_MINOR_VERSION, &l);
418 printf("version: %d.%d\n", h, l);
419 printf("shader version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
420 GLint svcount;
421 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &svcount);
422 if (svcount > 0) {
423 printf("%d shader versions supported:\n", svcount);
424 foreach (GLuint n; 0..svcount) printf(" %d: %s\n", n, glGetStringi(GL_SHADING_LANGUAGE_VERSION, n));
427 GLint ecount;
428 glGetIntegerv(GL_NUM_EXTENSIONS, &ecount);
429 if (ecount > 0) {
430 printf("%d extensions supported:\n", ecount);
431 foreach (GLuint n; 0..ecount) printf(" %d: %s\n", n, glGetStringi(GL_EXTENSIONS, n));
436 glgfxInitTexture();
437 glconInit(vbufW, vbufH, (blit2x ? 2 : 1));
438 glgfxUpdateTexture();
439 vbwin.redrawOpenGlSceneNow();
441 send(starterTid, 42);
444 bool receiveMessages () {
445 bool res = false;
446 for (;;) {
447 import core.time : Duration;
448 auto got = receiveTimeout(
449 Duration.zero, // don't wait
450 (OwnerTerminated e) {
451 //conwriteln("OWNER IS TERMINATED!");
452 res = true;
454 (Variant v) {
455 conwriteln("WARNING: unknown thread message received and ignored: ", v.toString);
458 if (!got) break; // no more messages
460 return res;
463 bool processConsoleCommands () {
464 consoleLock();
465 scope(exit) consoleUnlock();
466 auto ccwasempty = conQueueEmpty();
467 conProcessQueue();
468 return (!ccwasempty && conQueueEmpty());
471 bool lastConVisible = isConsoleVisible;
473 //FIXME: FPS time calculations are totally broken
474 import core.time;
475 uint rfps = (fps < 0 ? 1 : fps > 120 ? 120 : fps);
476 uint msfull = 1000/fps;
477 auto lastFrameTime = MonoTime.currTime;
478 auto lastCursorTime = MonoTime.currTime;
480 version(Windows) {
481 // windoze eats shit! if we won't awake event loop here, it will fuck itself.
482 import core.sys.windows.winuser;
483 PostMessage(null, WM_USER, 0, 0);
486 vbwin.eventLoop(8,
487 delegate () {
488 //version(Windows) { {import core.stdc.stdio : printf; printf("xxx\n"); } }
489 if (vbwin.closed) return;
490 if (isQuitRequested) { kgiPushCloseEvent(); vbwin.close(); return; }
491 if (receiveMessages()) { kgiPushCloseEvent(); vbwin.close(); return; }
492 auto conexeced = processConsoleCommands();
493 bool convis = isConsoleVisible;
494 if (lastConVisible != convis || conexeced) {
495 lastConVisible = isConsoleVisible;
496 setUpdateTextureFlag();
497 consoleLock();
498 scope(exit) consoleUnlock();
499 if (evbufused == 0) {
500 KGIEvent kev;
501 pushEventIntr(kev);
504 bool newFrame = false;
505 auto ctt = MonoTime.currTime;
506 if (lastConVisible != convis || conexeced) {
507 newFrame = true;
508 } else if (convis) {
509 // visible console should be updated at least 35 times per second
510 newFrame = ((ctt-lastFrameTime).total!"msecs" >= 28);
511 } else {
512 // fps
513 if ((ctt-lastFrameTime).total!"msecs" >= msfull) newFrame = true;
515 //if (newFrame) atomicStore(updateTexture, true);
516 if (newFrame || atomicLoad(updateTexture)) {
517 lastFrameTime = ctt;
518 lastCursorTime = ctt;
519 glgfxUpdateTexture();
520 //version(Windows) { {import core.stdc.stdio : printf; printf("000\n"); } }
521 vbwin.redrawOpenGlSceneNow();
522 } else if (mcurHidden == 0) {
523 // ~60 FPS for mouse cursor
524 if ((ctt-lastCursorTime).total!"msecs" >= 16) {
525 lastCursorTime = ctt;
526 glgfxUpdateCurTexture();
527 //version(Windows) { {import core.stdc.stdio : printf; printf("001\n"); } }
528 vbwin.redrawOpenGlSceneNow();
532 delegate (KeyEvent event) {
533 if (vbwin.closed) return;
534 if (isQuitRequested) { kgiPushCloseEvent(); vbwin.close(); return; }
535 if (glconKeyEvent(event)) return;
536 //if (event.pressed && event.key == Key.Escape) { concmd("quit"); return; }
537 kgiPushEvent(event);
539 delegate (MouseEvent event) {
540 if (vbwin.closed) return;
541 mcurX = event.x/(blit2x ? 2 : 1);
542 mcurY = event.y/(blit2x ? 2 : 1);
543 if (event.type == MouseEventType.motion && !kgiMotionEvents) return;
544 if (blit2x) { event.x /= 2; event.y /= 2; }
545 kgiPushEvent(event);
547 delegate (dchar ch) {
548 if (vbwin.closed) return;
549 if (glconCharEvent(ch)) return;
550 if (ch == '`') concmd("r_console tan");
551 if (!kgiCharEvents) return;
552 kgiPushEvent(ch);
555 } catch (Throwable e) {
556 // here, we are dead and fucked (the exact order doesn't matter)
557 import core.stdc.stdlib : abort;
558 import core.stdc.stdio : fprintf, stderr;
559 import core.memory : GC;
560 import core.thread;
561 GC.disable(); // yeah
562 thread_suspendAll(); // stop right here, you criminal scum!
563 auto s = e.toString();
564 fprintf(stderr, "\n=== FATAL ===\n%.*s\n", cast(uint)s.length, s.ptr);
565 abort(); // die, you bitch!
567 flushGui();
568 vbwin = null;
571 import core.stdc.stdlib : exit;
572 exit(0);
575 kgiPushCloseEvent();
576 atomicStore(kgiThreadStarted, false);
580 // ////////////////////////////////////////////////////////////////////////// //
581 private __gshared Tid kgiTid;
582 private shared bool kgiThreadStarted = false;
585 private void startKGIThread () {
586 //if (!cas(&kgiThreadStarted, false, true)) assert(0, "render thread already started!");
587 kgiTid = spawn(&kgiThread, thisTid);
588 setMaxMailboxSize(kgiTid, 1024, OnCrowding.throwException); //FIXME
589 // wait for "i'm ready" signal
590 receive(
591 (int ok) {
592 if (ok != 42) assert(0, "wtf?!");
595 //conwriteln("rendering thread started");
600 public bool kgiInitEx (int awdt, int ahgt, string title, bool a2x, uint afps) {
601 import core.stdc.stdlib : malloc;
602 import arsd.simpledisplay;
604 if (awdt < 1 || ahgt < 1 || awdt > 4096 || ahgt > 4096) {
605 return false;
606 //assert(0, "invalid dimensions");
609 if (!cas(&kgiThreadStarted, false, true)) return false;
611 if (vbwin !is null) assert(0, "double initialization");
613 if (afps < 1) afps = 1; else if (afps > 60) afps = 60;
615 conSealVar("v_scale2x");
616 conSealVar("v_width");
617 conSealVar("v_height");
618 conSealVar("v_title");
619 conSealVar("v_fps");
621 vbuf = cast(typeof(vbuf))malloc(vbuf[0].sizeof*awdt*ahgt);
622 if (vbuf is null) assert(0, "KGI: out of memory");
623 vbuf[0..awdt*ahgt] = 0;
625 vbufsaved = cast(typeof(vbuf))malloc(vbufsaved[0].sizeof*awdt*ahgt);
626 if (vbufsaved is null) assert(0, "KGI: out of memory");
627 vbufsaved[0..awdt*ahgt] = vbuf[0..awdt*ahgt];
629 vcurbuf = cast(typeof(vcurbuf))malloc(vcurbuf[0].sizeof*kgiMaxCurW*kgiMaxCurH);
630 if (vbuf is null) assert(0, "KGI: out of memory");
631 vcurbuf[0..kgiMaxCurW*kgiMaxCurH] = 0;
632 unpackDefaultCursor();
634 vbufW = awdt;
635 vbufH = ahgt;
636 blit2x = a2x;
637 fps = afps;
638 kgiTitle = title;
640 if (!oldogl) {
641 setOpenGLContextVersion(3, 2); // up to GLSL 150
642 //openGLContextCompatible = false;
643 static if (is(typeof(openGLContextAllowFallback))) {
644 openGLContextAllowFallback = true;
648 startKGIThread();
650 return true;
654 public bool kgiInit () { return kgiInitEx(vbufW, vbufH, kgiTitle, blit2x, fps); }
655 public bool kgiInit (int awdt, int ahgt) { return kgiInitEx(awdt, ahgt, kgiTitle, blit2x, fps); }
656 public bool kgiInit (int awdt, int ahgt, string title) { return kgiInitEx(awdt, ahgt, title, blit2x, fps); }
657 public bool kgiInit (int awdt, int ahgt, string title, bool a2x) { return kgiInitEx(awdt, ahgt, title, a2x, fps); }
658 public bool kgiInit (int awdt, int ahgt, string title, bool a2x, uint afps) { return kgiInitEx(awdt, ahgt, title, a2x, afps); }
661 // ////////////////////////////////////////////////////////////////////////// //
662 private uint glgfxCompileShader (const(char)[] src) nothrow @trusted {
663 import iv.glbinds;
665 if (shaderVersionOk < 0) {
666 // check if we have sufficient shader version here
667 shaderVersionOk = 0;
668 bool found = false;
669 GLint svcount;
670 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &svcount);
671 if (svcount > 0) {
672 foreach (GLuint n; 0..svcount) {
673 import core.stdc.string : strncmp;
674 auto v = glGetStringi(GL_SHADING_LANGUAGE_VERSION, n);
675 if (v is null) continue;
676 //if (strncmp(v, "130", 3) != 0) continue;
677 if (strncmp(cast(char*)v, "150".ptr, 3) != 0) continue;
678 if (v[3] > ' ') continue;
679 found = true;
680 break;
683 if (!found) return 0; //assert(0, "can't find OpenGL GLSL 150");
686 auto adr = glGetProcAddress("glTexParameterf");
687 if (adr is null) return 0;
690 shaderVersionOk = 1;
692 if (shaderVersionOk == 0) return 0;
693 return compileShaders(src);
697 private void glgfxInitTexture () nothrow @trusted {
698 import iv.glbinds;
700 //if (vbTexId) { glDeleteTextures(1, &vbTexId); vbTexId = 0; }
702 enum wrapOpt = GL_REPEAT;
703 enum filterOpt = GL_NEAREST; //GL_LINEAR;
704 enum ttype = GL_UNSIGNED_BYTE;
706 glGenTextures(1, &vbTexId);
707 if (vbTexId == 0) assert(0, "can't create kgi texture");
709 glGenTextures(1, &vbCurTexId);
710 if (vbTexId == 0) assert(0, "can't create kgicursor texture");
712 GLint gltextbinding;
713 glGetIntegerv(GL_TEXTURE_BINDING_2D, &gltextbinding);
714 scope(exit) glBindTexture(GL_TEXTURE_2D, gltextbinding);
716 glBindTexture(GL_TEXTURE_2D, vbTexId);
717 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapOpt);
718 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapOpt);
719 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterOpt);
720 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterOpt);
721 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
722 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
724 GLfloat[4] bclr = 0.0;
725 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
727 static if (KGIRGBA) enum TexType = GL_RGBA; else enum TexType = GL_BGRA;
728 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vbufW, vbufH, 0, TexType, GL_UNSIGNED_BYTE, vbufsaved);
731 glBindTexture(GL_TEXTURE_2D, vbCurTexId);
732 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapOpt);
733 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapOpt);
734 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterOpt);
735 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterOpt);
736 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
737 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
739 //GLfloat[4] bclr = 0.0;
740 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
742 //static if (KGIRGBA) enum TexType = GL_RGBA; else enum TexType = GL_BGRA;
743 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kgiMaxCurW, kgiMaxCurH, 0, TexType, GL_UNSIGNED_BYTE, vcurbuf);
747 private void glgfxUpdateTexture () nothrow @trusted {
748 import iv.glbinds;
750 consoleLock();
751 scope(exit) consoleUnlock();
753 version(LDC) {} else atomicFence();
754 vupcounter = 0;
756 static if (KGIRGBA) enum TexType = GL_RGBA; else enum TexType = GL_BGRA;
757 if (!oldogl) {
758 glTextureSubImage2D(vbTexId, 0, 0/*x*/, 0/*y*/, vbufW, vbufH, TexType, GL_UNSIGNED_BYTE, vbufsaved);
759 } else {
760 glBindTexture(GL_TEXTURE_2D, vbTexId);
761 glTexSubImage2D(GL_TEXTURE_2D, 0, 0/*x*/, 0/*y*/, vbufW, vbufH, TexType, GL_UNSIGNED_BYTE, vbufsaved);
762 glBindTexture(GL_TEXTURE_2D, 0);
764 atomicStore(updateTexture, false);
765 vupcounterlast = vupcounterlast.max;
767 if (atomicLoad(updateCurTexture)) {
768 if (!oldogl) {
769 glTextureSubImage2D(vbCurTexId, 0, 0/*x*/, 0/*y*/, kgiMaxCurW, kgiMaxCurH, TexType, GL_UNSIGNED_BYTE, vcurbuf);
770 } else {
771 glBindTexture(GL_TEXTURE_2D, vbCurTexId);
772 glTexSubImage2D(GL_TEXTURE_2D, 0, 0/*x*/, 0/*y*/, kgiMaxCurW, kgiMaxCurH, TexType, GL_UNSIGNED_BYTE, vcurbuf);
773 glBindTexture(GL_TEXTURE_2D, 0);
775 atomicStore(updateCurTexture, false);
780 private void glgfxUpdateCurTexture () nothrow @trusted {
781 import iv.glbinds;
783 if (atomicLoad(updateCurTexture)) {
784 consoleLock();
785 scope(exit) consoleUnlock();
787 static if (KGIRGBA) enum TexType = GL_RGBA; else enum TexType = GL_BGRA;
788 if (!oldogl) {
789 glTextureSubImage2D(vbCurTexId, 0, 0/*x*/, 0/*y*/, kgiMaxCurW, kgiMaxCurH, TexType, GL_UNSIGNED_BYTE, vcurbuf);
790 } else {
791 glBindTexture(GL_TEXTURE_2D, vbCurTexId);
792 glTexSubImage2D(GL_TEXTURE_2D, 0, 0/*x*/, 0/*y*/, kgiMaxCurW, kgiMaxCurH, TexType, GL_UNSIGNED_BYTE, vcurbuf);
793 glBindTexture(GL_TEXTURE_2D, 0);
796 atomicStore(updateCurTexture, false);
801 private void glgfxBlit () nothrow @trusted {
802 import iv.glbinds;
804 consoleLock();
805 scope(exit) consoleUnlock();
807 //if (vbwin is null || vbwin.closed || vbTexId == 0) return;
810 GLint glmatmode;
811 GLint gltextbinding;
812 GLint oldprg;
813 GLint oldfbr, oldfbw;
814 GLint[4] glviewport;
815 glGetIntegerv(GL_MATRIX_MODE, &glmatmode);
816 glGetIntegerv(GL_TEXTURE_BINDING_2D, &gltextbinding);
817 glGetIntegerv(GL_VIEWPORT, glviewport.ptr);
818 glGetIntegerv(GL_CURRENT_PROGRAM, &oldprg);
819 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldfbr);
820 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfbw);
821 glMatrixMode(GL_PROJECTION); glPushMatrix();
822 glMatrixMode(GL_MODELVIEW); glPushMatrix();
823 glMatrixMode(GL_TEXTURE); glPushMatrix();
824 glMatrixMode(GL_COLOR); glPushMatrix();
825 glPushAttrib(/*GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_CURRENT_BIT*/GL_ALL_ATTRIB_BITS); // let's play safe
826 // restore on exit
827 scope(exit) {
828 glPopAttrib(/*GL_ENABLE_BIT*/);
829 glMatrixMode(GL_PROJECTION); glPopMatrix();
830 glMatrixMode(GL_MODELVIEW); glPopMatrix();
831 glMatrixMode(GL_TEXTURE); glPopMatrix();
832 glMatrixMode(GL_COLOR); glPopMatrix();
833 glMatrixMode(glmatmode);
834 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, oldfbr);
835 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, oldfbw);
836 glBindTexture(GL_TEXTURE_2D, gltextbinding);
837 glUseProgram(oldprg);
838 glViewport(glviewport.ptr[0], glviewport.ptr[1], glviewport.ptr[2], glviewport.ptr[3]);
842 enum x = 0;
843 enum y = 0;
844 immutable w = vbufW;
845 immutable h = vbufH;
847 if (!oldogl) {
848 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
849 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
851 if (scanlines && shaderVersionOk < 0) sdrScanlineId = glgfxCompileShader(sdrScanlineSrc);
852 glUseProgram(scanlines ? sdrScanlineId : 0);
855 glMatrixMode(GL_PROJECTION); // for ortho camera
856 glLoadIdentity();
857 // left, right, bottom, top, near, far
858 glViewport(0, 0, w*(blit2x ? 2 : 1), h*(blit2x ? 2 : 1));
859 glOrtho(0, w, h, 0, -1, 1); // top-to-bottom
860 glMatrixMode(GL_MODELVIEW);
861 glLoadIdentity();
863 glEnable(GL_TEXTURE_2D);
864 glDisable(GL_LIGHTING);
865 glDisable(GL_DITHER);
866 //glDisable(GL_BLEND);
867 glDisable(GL_DEPTH_TEST);
868 //glEnable(GL_BLEND);
869 //glBlendFunc(GL_SRC_ALPHA, GL_ONE);
870 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
871 glDisable(GL_BLEND);
872 glDisable(GL_STENCIL_TEST);
874 glColor4f(1, 1, 1, 1);
875 glBindTexture(GL_TEXTURE_2D, vbTexId);
876 //scope(exit) glBindTexture(GL_TEXTURE_2D, 0);
877 glBegin(GL_QUADS);
878 glTexCoord2f(0.0f, 0.0f); glVertex2i(x, y); // top-left
879 glTexCoord2f(1.0f, 0.0f); glVertex2i(w, y); // top-right
880 glTexCoord2f(1.0f, 1.0f); glVertex2i(w, h); // bottom-right
881 glTexCoord2f(0.0f, 1.0f); glVertex2i(x, h); // bottom-left
882 glEnd();
884 if (mcurHidden == 0) {
885 glEnable(GL_BLEND);
886 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
887 glBindTexture(GL_TEXTURE_2D, vbCurTexId);
889 int cx0 = mcurX-mhotX;
890 int cy0 = mcurY-mhotY;
892 glBegin(GL_QUADS);
893 glTexCoord2f(0.0f, 0.0f); glVertex2i(cx0, cy0); // top-left
894 glTexCoord2f(1.0f, 0.0f); glVertex2i(cx0+kgiMaxCurW, cy0); // top-right
895 glTexCoord2f(1.0f, 1.0f); glVertex2i(cx0+kgiMaxCurW, cy0+kgiMaxCurH); // bottom-right
896 glTexCoord2f(0.0f, 1.0f); glVertex2i(cx0, cy0+kgiMaxCurH); // bottom-left
897 glEnd();
899 glDisable(GL_BLEND);
904 // ////////////////////////////////////////////////////////////////////////// //
905 alias VColor = uint;
907 /// vlRGBA struct to ease color components extraction/replacing
908 align(1) struct vlRGBA {
909 align(1):
910 static if (KGIRGBA) {
911 ubyte b, g, r, a;
912 } else {
913 ubyte r, g, b, a;
916 static assert(vlRGBA.sizeof == VColor.sizeof);
919 static if (KGIRGBA) {
920 enum : VColor {
921 vlAShift = 24,
922 vlRShift = 0,
923 vlGShift = 8,
924 vlBShift = 16,
926 } else {
927 enum : VColor {
928 vlAShift = 24,
929 vlRShift = 16,
930 vlGShift = 8,
931 vlBShift = 0,
934 static assert(vlAShift == 24, "invalid A position in color"); // alas
937 enum : VColor {
938 vlAMask = 0xffu<<vlAShift,
939 vlRMask = 0xffu<<vlRShift,
940 vlGMask = 0xffu<<vlGShift,
941 vlBMask = 0xffu<<vlBShift,
942 vlColorMask = vlRMask|vlGMask|vlBMask,
946 enum VColor Transparent = vlAMask; /// completely transparent pixel color
949 bool isTransparent(T : VColor) (T col) pure nothrow @safe @nogc {
950 pragma(inline, true);
951 return ((col&vlAMask) == vlAMask);
954 bool isOpaque(T : VColor) (T col) pure nothrow @safe @nogc {
955 pragma(inline, true);
956 return ((col&vlAMask) == 0);
959 // a=0: opaque
960 VColor rgbcol(TR, TG, TB, TA=ubyte) (TR r, TG g, TB b, TA a=0) pure nothrow @safe @nogc
961 if (__traits(isIntegral, TR) && __traits(isIntegral, TG) && __traits(isIntegral, TB) && __traits(isIntegral, TA)) {
962 pragma(inline, true);
963 return
964 (clampToByte(a)<<vlAShift)|
965 (clampToByte(r)<<vlRShift)|
966 (clampToByte(g)<<vlGShift)|
967 (clampToByte(b)<<vlBShift);
970 alias rgbacol = rgbcol;
973 // generate some templates (rgbRed, rgbSetRed, etc.)
974 private enum genRGBGetSet(string cname) =
975 "ubyte rgb"~cname~"() (VColor clr) pure nothrow @safe @nogc {\n"~
976 " pragma(inline, true);\n"~
977 " return ((clr>>vl"~cname[0]~"Shift)&0xff);\n"~
978 "}\n"~
979 "VColor rgbSet"~cname~"(T) (VColor clr, T v) pure nothrow @safe @nogc if (__traits(isIntegral, T)) {\n"~
980 " pragma(inline, true);\n"~
981 " return (clr&~vl"~cname[0]~"Mask)|(clampToByte(v)<<vl"~cname[0]~"Shift);\n"~
982 "}\n";
984 mixin(genRGBGetSet!"Alpha");
985 mixin(genRGBGetSet!"Red");
986 mixin(genRGBGetSet!"Green");
987 mixin(genRGBGetSet!"Blue");
990 // ////////////////////////////////////////////////////////////////////////// //
991 nothrow @trusted @nogc {
993 private void putPixelIntrNoCheck (in int xx, in int yy, in VColor col) {
994 pragma(inline, true);
995 uint* da = vbuf+yy*vbufW+xx;
996 if (col&vlAMask) {
997 immutable uint a = 256-(col>>24); // to not loose bits
998 immutable uint dc = (*da)&0xffffff;
999 immutable uint srb = (col&0xff00ff);
1000 immutable uint sg = (col&0x00ff00);
1001 immutable uint drb = (dc&0xff00ff);
1002 immutable uint dg = (dc&0x00ff00);
1003 immutable uint orb = (drb+(((srb-drb)*a+0x800080)>>8))&0xff00ff;
1004 immutable uint og = (dg+(((sg-dg)*a+0x008000)>>8))&0x00ff00;
1005 *da = orb|og;
1006 } else {
1007 *da = col;
1011 private void putPixelIntr (int xx, int yy, VColor col) {
1012 pragma(inline, true);
1013 if ((col&vlAMask) != vlAMask && xx >= 0 && yy >= 0 && xx < vbufW && yy < vbufH) {
1014 uint* da = vbuf+yy*vbufW+xx;
1015 if (col&vlAMask) {
1016 immutable uint a = 256-(col>>24); // to not loose bits
1017 immutable uint dc = (*da)&0xffffff;
1018 immutable uint srb = (col&0xff00ff);
1019 immutable uint sg = (col&0x00ff00);
1020 immutable uint drb = (dc&0xff00ff);
1021 immutable uint dg = (dc&0x00ff00);
1022 immutable uint orb = (drb+(((srb-drb)*a+0x800080)>>8))&0xff00ff;
1023 immutable uint og = (dg+(((sg-dg)*a+0x008000)>>8))&0x00ff00;
1024 *da = orb|og;
1025 } else {
1026 *da = col;
1031 void putPixel (int xx, int yy, VColor col) {
1032 pragma(inline, true);
1033 if ((col&vlAMask) != vlAMask && xx >= 0 && yy >= 0 && xx < vbufW && yy < vbufH) {
1034 uint* da = vbuf+yy*vbufW+xx;
1035 if (col&vlAMask) {
1036 immutable uint a = 256-(col>>24); // to not loose bits
1037 immutable uint dc = (*da)&0xffffff;
1038 immutable uint srb = (col&0xff00ff);
1039 immutable uint sg = (col&0x00ff00);
1040 immutable uint drb = (dc&0xff00ff);
1041 immutable uint dg = (dc&0x00ff00);
1042 immutable uint orb = (drb+(((srb-drb)*a+0x800080)>>8))&0xff00ff;
1043 immutable uint og = (dg+(((sg-dg)*a+0x008000)>>8))&0x00ff00;
1044 *da = orb|og;
1045 } else {
1046 *da = col;
1048 version(LDC) {} else atomicFence();
1049 ++vupcounter;
1053 private void setPixelIntr (int xx, int yy, VColor col) {
1054 pragma(inline, true);
1055 if (xx >= 0 && yy >= 0 && xx < vbufW && yy < vbufH) {
1056 uint* da = vbuf+yy*vbufW+xx;
1057 *da = col;
1061 void setPixel (int xx, int yy, VColor col) {
1062 pragma(inline, true);
1063 if (xx >= 0 && yy >= 0 && xx < vbufW && yy < vbufH) {
1064 uint* da = vbuf+yy*vbufW+xx;
1065 *da = col;
1066 version(LDC) {} else atomicFence();
1067 ++vupcounter;
1072 VColor getPixel (int xx, int yy) {
1073 pragma(inline, true);
1074 return (xx >= 0 && yy >= 0 && xx < vbufW && yy < vbufH ? vbuf[yy*vbufW+xx]&vlColorMask : Transparent);
1078 // ////////////////////////////////////////////////////////////////////////// //
1079 void cls (VColor col) {
1080 vbuf[0..vbufW*vbufH] = col;
1081 version(LDC) {} else atomicFence();
1082 ++vupcounter;
1086 // ////////////////////////////////////////////////////////////////////////// //
1087 void drawRect (int x, int y, int w, int h, immutable VColor col) {
1088 if (w < 1 || h < 1) return;
1089 if (x <= -w || y <= -h || x >= vbufW || y >= vbufH || isTransparent(col)) return;
1090 if (x < 0) { w += x; x = 0; }
1091 if (y < 0) { h += y; h = 0; }
1092 if (x+w >= vbufW) w = vbufW-x;
1093 if (y+h >= vbufH) h = vbufH-y;
1094 assert(x >= 0 && y >= 0 && x < vbufW && y < vbufH && w > 0 && h > 0 && x+w <= vbufW && y+h <= vbufH);
1095 if (isOpaque(col)) {
1096 uint d = y*vbufW+x;
1097 vbuf[d..d+w] = col;
1098 d += vbufW;
1099 foreach (immutable yy; y+1..y+h-1) {
1100 vbuf[d] = col;
1101 vbuf[d+w-1] = col;
1102 d += vbufW;
1104 if (h > 1) vbuf[d..d+w] = col;
1105 } else {
1106 foreach (immutable yy; y..y+h) {
1107 putPixelIntr(x, yy, col);
1108 putPixelIntr(x+w-1, yy, col);
1110 foreach (immutable xx; x+1..x+w-1) {
1111 putPixelIntr(xx, y, col);
1112 if (h > 1) putPixelIntr(xx, y+h-1, col);
1115 version(LDC) {} else atomicFence();
1116 ++vupcounter;
1119 void fillRect (int x, int y, int w, int h, immutable VColor col) {
1120 if (w < 1 || h < 1) return;
1121 if (x <= -w || y <= -h || x >= vbufW || y >= vbufH || isTransparent(col)) return;
1122 if (x < 0) { w += x; x = 0; }
1123 if (y < 0) { h += y; h = 0; }
1124 if (x+w >= vbufW) w = vbufW-x;
1125 if (y+h >= vbufH) h = vbufH-y;
1126 assert(x >= 0 && y >= 0 && x < vbufW && y < vbufH && w > 0 && h > 0 && x+w <= vbufW && y+h <= vbufH);
1127 if (isOpaque(col)) {
1128 uint d = y*vbufW+x;
1129 foreach (immutable yy; y..y+h) {
1130 vbuf[d..d+w] = col;
1131 d += vbufW;
1133 } else {
1134 foreach (immutable yy; y..y+h) {
1135 foreach (immutable xx; x..x+w) {
1136 putPixelIntr(xx, yy, col);
1140 version(LDC) {} else atomicFence();
1141 ++vupcounter;
1144 void hline (int x, int y, int len, immutable VColor col) { drawRect(x, y, len, 1, col); }
1145 void vline (int x, int y, int len, immutable VColor col) { drawRect(x, y, 1, len, col); }
1148 // ////////////////////////////////////////////////////////////////////////// //
1149 void drawLine(bool lastPoint=true) (int x0, int y0, int x1, int y1, immutable VColor col) {
1150 enum swap(string a, string b) = "{int tmp_="~a~";"~a~"="~b~";"~b~"=tmp_;}";
1152 if ((col&vlAMask) == vlAMask) return;
1154 if (x0 == x1 && y0 == y1) {
1155 static if (lastPoint) putPixel(x0, y0, col);
1156 return;
1159 // clip rectange
1160 int wx0 = 0, wy0 = 0, wx1 = vbufW-1, wy1 = vbufH-1;
1161 // other vars
1162 int stx, sty; // "steps" for x and y axes
1163 int dsx, dsy; // "lengthes" for x and y axes
1164 int dx2, dy2; // "double lengthes" for x and y axes
1165 int xd, yd; // current coord
1166 int e; // "error" (as in bresenham algo)
1167 int rem;
1168 int term;
1169 int *d0, d1;
1170 // horizontal setup
1171 if (x0 < x1) {
1172 // from left to right
1173 if (x0 > wx1 || x1 < wx0) return; // out of screen
1174 stx = 1; // going right
1175 } else {
1176 // from right to left
1177 if (x1 > wx1 || x0 < wx0) return; // out of screen
1178 stx = -1; // going left
1179 x0 = -x0;
1180 x1 = -x1;
1181 wx0 = -wx0;
1182 wx1 = -wx1;
1183 mixin(swap!("wx0", "wx1"));
1185 // vertical setup
1186 if (y0 < y1) {
1187 // from top to bottom
1188 if (y0 > wy1 || y1 < wy0) return; // out of screen
1189 sty = 1; // going down
1190 } else {
1191 // from bottom to top
1192 if (y1 > wy1 || y0 < wy0) return; // out of screen
1193 sty = -1; // going up
1194 y0 = -y0;
1195 y1 = -y1;
1196 wy0 = -wy0;
1197 wy1 = -wy1;
1198 mixin(swap!("wy0", "wy1"));
1200 dsx = x1-x0;
1201 dsy = y1-y0;
1202 if (dsx < dsy) {
1203 d0 = &yd;
1204 d1 = &xd;
1205 mixin(swap!("x0", "y0"));
1206 mixin(swap!("x1", "y1"));
1207 mixin(swap!("dsx", "dsy"));
1208 mixin(swap!("wx0", "wy0"));
1209 mixin(swap!("wx1", "wy1"));
1210 mixin(swap!("stx", "sty"));
1211 } else {
1212 d0 = &xd;
1213 d1 = &yd;
1215 dx2 = 2*dsx;
1216 dy2 = 2*dsy;
1217 xd = x0;
1218 yd = y0;
1219 e = 2*dsy-dsx;
1220 term = x1;
1221 bool xfixed = false;
1222 if (y0 < wy0) {
1223 // clip at top
1224 int temp = dx2*(wy0-y0)-dsx;
1225 xd += temp/dy2;
1226 rem = temp%dy2;
1227 if (xd > wx1) return; // x is moved out of clipping rect, nothing to do
1228 if (xd+1 >= wx0) {
1229 yd = wy0;
1230 e -= rem+dsx;
1231 if (rem > 0) { ++xd; e += dy2; }
1232 xfixed = true;
1235 if (!xfixed && x0 < wx0) {
1236 // clip at left
1237 int temp = dy2*(wx0-x0);
1238 yd += temp/dx2;
1239 rem = temp%dx2;
1240 if (yd > wy1 || yd == wy1 && rem >= dsx) return;
1241 xd = wx0;
1242 e += rem;
1243 if (rem >= dsx) { ++yd; e -= dx2; }
1245 if (y1 > wy1) {
1246 // clip at bottom
1247 int temp = dx2*(wy1-y0)+dsx;
1248 term = x0+temp/dy2;
1249 rem = temp%dy2;
1250 if (rem == 0) --term;
1252 if (term > wx1) term = wx1; // clip at right
1253 static if (lastPoint) {
1254 // draw last point
1255 ++term;
1256 } else {
1257 if (term == xd) return; // this is the only point, get out of here
1259 if (sty == -1) yd = -yd;
1260 if (stx == -1) { xd = -xd; term = -term; }
1261 dx2 -= dy2;
1262 // draw it; `putPixel()` can omit checks
1263 while (xd != term) {
1264 putPixelIntrNoCheck(*d0, *d1, col);
1265 // done drawing, move coords
1266 if (e >= 0) {
1267 yd += sty;
1268 e -= dx2;
1269 } else {
1270 e += dy2;
1272 xd += stx;
1274 version(LDC) {} else atomicFence();
1275 ++vupcounter;
1279 // ////////////////////////////////////////////////////////////////////////// //
1280 private void plot4points() (int cx, int cy, int x, int y, VColor clr) @trusted {
1281 putPixelIntr(cx+x, cy+y, clr);
1282 if (x != 0) putPixelIntr(cx-x, cy+y, clr);
1283 if (y != 0) putPixelIntr(cx+x, cy-y, clr);
1284 putPixelIntr(cx-x, cy-y, clr);
1288 void drawCircle (int cx, int cy, int radius, VColor clr) @trusted {
1289 if (radius > 0 && !isTransparent(clr)) {
1290 int error = -radius, x = radius, y = 0;
1291 if (radius == 1) { putPixelIntr(cx, cy, clr); return; }
1292 while (x > y) {
1293 plot4points(cx, cy, x, y, clr);
1294 plot4points(cx, cy, y, x, clr);
1295 error += y*2+1;
1296 ++y;
1297 if (error >= 0) { --x; error -= x*2; }
1299 plot4points(cx, cy, x, y, clr);
1300 version(LDC) {} else atomicFence();
1301 ++vupcounter;
1305 void fillCircle (int cx, int cy, int radius, VColor clr) @trusted {
1306 if (radius > 0 && !isTransparent(clr)) {
1307 int error = -radius, x = radius, y = 0;
1308 if (radius == 1) { putPixelIntr(cx, cy, clr); return; }
1309 while (x >= y) {
1310 int last_y = y;
1311 error += y;
1312 ++y;
1313 error += y;
1314 hline(cx-x, cy+last_y, 2*x+1, clr);
1315 if (x != 0 && last_y != 0) hline(cx-x, cy-last_y, 2*x+1, clr);
1316 if (error >= 0) {
1317 if (x != last_y) {
1318 hline(cx-last_y, cy+x, 2*last_y+1, clr);
1319 if (last_y != 0 && x != 0) hline(cx-last_y, cy-x, 2*last_y+1, clr);
1321 error -= x;
1322 --x;
1323 error -= x;
1326 version(LDC) {} else atomicFence();
1327 ++vupcounter;
1332 void drawEllipse (int x0, int y0, int w, int h, VColor clr) @trusted {
1333 import std.math : abs;
1334 if (w == 0 && h == 0) return;
1335 if (w == 1) { vline(x0, y0, h, clr); return; }
1336 if (h == 1) { hline(x0, y0, w, clr); return; }
1337 int x1 = x0+w-1;
1338 int y1 = y0+h-1;
1339 int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; // values of diameter
1340 long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; // error increment
1341 long err = dx+dy+b1*a*a; // error of 1.step
1342 if (x0 > x1) { x0 = x1; x1 += a; } // if called with swapped points...
1343 if (y0 > y1) y0 = y1; // ...exchange them
1344 y0 += (b+1)/2; y1 = y0-b1; // starting pixel
1345 a *= 8*a; b1 = 8*b*b;
1346 do {
1347 long e2;
1348 putPixelIntr(x1, y0, clr); // I. Quadrant
1349 putPixelIntr(x0, y0, clr); // II. Quadrant
1350 putPixelIntr(x0, y1, clr); // III. Quadrant
1351 putPixelIntr(x1, y1, clr); // IV. Quadrant
1352 e2 = 2*err;
1353 if (e2 >= dx) { ++x0; --x1; err += dx += b1; } // x step
1354 if (e2 <= dy) { ++y0; --y1; err += dy += a; } // y step
1355 } while (x0 <= x1);
1356 while (y0-y1 < b) {
1357 // too early stop of flat ellipses a=1
1358 putPixelIntr(x0-1, ++y0, clr); // complete tip of ellipse
1359 putPixelIntr(x0-1, --y1, clr);
1361 version(LDC) {} else atomicFence();
1362 ++vupcounter;
1365 void fillEllipse (int x0, int y0, int w, int h, VColor clr) @trusted {
1366 import std.math : abs;
1367 if (w == 0 && h == 0) return;
1368 if (w == 1) { vline(x0, y0, h, clr); return; }
1369 if (h == 1) { hline(x0, y0, w, clr); return; }
1370 int x1 = x0+w-1;
1371 int y1 = y0+h-1;
1372 int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; // values of diameter
1373 long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; // error increment
1374 long err = dx+dy+b1*a*a; // error of 1.step
1375 int prev_y0 = -1, prev_y1 = -1;
1376 if (x0 > x1) { x0 = x1; x1 += a; } // if called with swapped points...
1377 if (y0 > y1) y0 = y1; // ...exchange them
1378 y0 += (b+1)/2; y1 = y0-b1; // starting pixel
1379 a *= 8*a; b1 = 8*b*b;
1380 do {
1381 long e2;
1382 if (y0 != prev_y0) { hline(x0, y0, x1-x0+1, clr); prev_y0 = y0; }
1383 if (y1 != y0 && y1 != prev_y1) { hline(x0, y1, x1-x0+1, clr); prev_y1 = y1; }
1384 e2 = 2*err;
1385 if (e2 >= dx) { ++x0; --x1; err += dx += b1; } // x step
1386 if (e2 <= dy) { ++y0; --y1; err += dy += a; } // y step
1387 } while (x0 <= x1);
1388 while (y0-y1 < b) {
1389 // too early stop of flat ellipses a=1
1390 putPixelIntr(x0-1, ++y0, clr); // complete tip of ellipse
1391 putPixelIntr(x0-1, --y1, clr);
1393 version(LDC) {} else atomicFence();
1394 ++vupcounter;
1398 // //////////////////////////////////////////////////////////////////////// //
1399 int charWidth(string type="msx") () {
1400 static if (type == "msx") return 6;
1401 else static if (type == "dos") return 8;
1402 else static if (type == "d10") return 10;
1403 else static assert(0, "invalid font type");
1406 int charHeight(string type="msx") () {
1407 static if (type == "msx") return 8;
1408 else static if (type == "dos") return 8;
1409 else static if (type == "d10") return 10;
1410 else static assert(0, "invalid font type");
1413 void drawCharWdt(string type="msx") (int x, int y, int wdt, int shift, char ch, VColor fgcol, VColor bgcol=Transparent) @trusted {
1414 static if (type == "msx") { alias fontb8 = kgiFont6; enum fwdt = 8; enum fhgt = 8; enum fmask = 0x80; }
1415 else static if (type == "dos") { alias fontb8 = kgiFont8; enum fwdt = 8; enum fhgt = 8; enum fmask = 0x80; }
1416 else static if (type == "d10") { alias fontb8 = kgiFont10; enum fwdt = 10; enum fhgt = 10; enum fmask = 0x8000; }
1417 else static assert(0, "invalid font type");
1418 usize pos = ch*fhgt;
1419 if (wdt < 1 || shift >= fwdt) return;
1420 if (fgcol == Transparent && bgcol == Transparent) return;
1421 if (wdt > fwdt) wdt = fwdt;
1422 if (shift < 0) shift = 0;
1423 foreach (immutable int dy; 0..fhgt) {
1424 ushort b = cast(ushort)(fontb8.ptr[pos++]<<shift);
1425 foreach (immutable int dx; 0..wdt) {
1426 VColor c = (b&fmask ? fgcol : bgcol);
1427 putPixelIntr(x+dx, y+dy, c);
1428 b <<= 1;
1431 version(LDC) {} else atomicFence();
1432 ++vupcounter;
1435 // outline types
1436 enum : ubyte {
1437 OutLeft = 0x01,
1438 OutRight = 0x02,
1439 OutUp = 0x04,
1440 OutDown = 0x08,
1441 OutLU = 0x10, // left-up
1442 OutRU = 0x20, // right-up
1443 OutLD = 0x40, // left-down
1444 OutRD = 0x80, // right-down
1445 OutAll = 0xff,
1448 void drawCharWdtOut(string type="msx") (int x, int y, int wdt, int shift, char ch, VColor fgcol, VColor outcol=Transparent, ubyte ot=0) @trusted {
1449 static if (type == "msx") { alias fontb8 = kgiFont6; enum fwdt = 8; enum fhgt = 8; enum fmask = 0x80; }
1450 else static if (type == "dos") { alias fontb8 = kgiFont8; enum fwdt = 8; enum fhgt = 8; enum fmask = 0x80; }
1451 else static if (type == "d10") { alias fontb8 = kgiFont10; enum fwdt = 10; enum fhgt = 10; enum fmask = 0x8000; }
1452 else static assert(0, "invalid font type");
1453 if (fgcol == Transparent && outcol == Transparent) return;
1454 if (ot == 0 || outcol == Transparent) {
1455 // no outline? simple draw
1456 drawCharWdt(x, y, wdt, shift, ch, fgcol, Transparent);
1457 return;
1459 usize pos = ch*fhgt;
1460 if (wdt < 1 || shift >= fwdt) return;
1461 if (wdt > 8) wdt = fwdt;
1462 if (shift < 0) shift = 0;
1463 ubyte[fhgt+2][fwdt+2] bmp = 0; // char bitmap; 0: empty; 1: char; 2: outline
1464 foreach (immutable dy; 1..fhgt+1) {
1465 ushort b = cast(ushort)(fontb8.ptr[pos++]<<shift);
1466 foreach (immutable dx; 1..wdt+1) {
1467 if (b&fmask) {
1468 // put pixel
1469 bmp[dy][dx] = 1;
1470 // put outlines
1471 if ((ot&OutUp) && bmp[dy-1][dx] == 0) bmp[dy-1][dx] = 2;
1472 if ((ot&OutDown) && bmp[dy+1][dx] == 0) bmp[dy+1][dx] = 2;
1473 if ((ot&OutLeft) && bmp[dy][dx-1] == 0) bmp[dy][dx-1] = 2;
1474 if ((ot&OutRight) && bmp[dy][dx+1] == 0) bmp[dy][dx+1] = 2;
1475 if ((ot&OutLU) && bmp[dy-1][dx-1] == 0) bmp[dy-1][dx-1] = 2;
1476 if ((ot&OutRU) && bmp[dy-1][dx+1] == 0) bmp[dy-1][dx+1] = 2;
1477 if ((ot&OutLD) && bmp[dy+1][dx-1] == 0) bmp[dy+1][dx-1] = 2;
1478 if ((ot&OutRD) && bmp[dy+1][dx+1] == 0) bmp[dy+1][dx+1] = 2;
1480 b <<= 1;
1483 // now draw it
1484 --x;
1485 --y;
1486 foreach (immutable int dy; 0..fhgt+2) {
1487 foreach (immutable int dx; 0..fwdt+2) {
1488 if (auto t = bmp[dy][dx]) putPixelIntr(x+dx, y+dy, (t == 1 ? fgcol : outcol));
1491 version(LDC) {} else atomicFence();
1492 ++vupcounter;
1495 void drawChar(string type="msx") (int x, int y, char ch, VColor fgcol, VColor bgcol=Transparent) @trusted {
1496 drawCharWdt!type(x, y, charWidth!type, 0, ch, fgcol, bgcol);
1499 void drawCharOut(string type="msx") (int x, int y, char ch, VColor fgcol, VColor outcol=Transparent, ubyte ot=OutAll) @trusted {
1500 drawCharWdtOut!type(x, y, charWidth!type, 0, ch, fgcol, outcol, ot);
1503 void drawStr(string type="msx") (int x, int y, const(char)[] str, VColor fgcol, VColor bgcol=Transparent) @trusted {
1504 foreach (immutable char ch; str) {
1505 drawChar!type(x, y, ch, fgcol, bgcol);
1506 x += charWidth!type;
1510 void drawStrOut(string type="msx") (int x, int y, const(char)[] str, VColor fgcol, VColor outcol=Transparent, ubyte ot=OutAll) @trusted {
1511 foreach (immutable char ch; str) {
1512 drawCharOut!type(x, y, ch, fgcol, outcol, ot);
1513 x += charWidth!type;
1517 int strWidth(string type="msx") (const(char)[] str) {
1518 return cast(int)str.length*charWidth!type;
1521 int charWidthProp(string type="msx") (char ch) @trusted pure {
1522 static if (type == "msx") { alias fontw8 = kgiFont6PropWidth; }
1523 else static if (type == "dos") { alias fontw8 = kgiFont8PropWidth; }
1524 else static assert(0, "invalid font type");
1525 return (fontw8.ptr[ch]&0x0f);
1528 int strWidthProp(string type="msx") (const(char)[] str) @trusted pure {
1529 static if (type == "msx") { alias fontw8 = kgiFont6PropWidth; }
1530 else static if (type == "dos") { alias fontw8 = kgiFont8PropWidth; }
1531 else static assert(0, "invalid font type");
1532 int wdt = 0;
1533 foreach (immutable char ch; str) wdt += (fontw8[ch]&0x0f)+1;
1534 if (wdt > 0) --wdt; // don't count last empty pixel
1535 return wdt;
1538 int drawCharProp(string type="msx") (int x, int y, char ch, VColor fgcol, VColor bgcol=Transparent) @trusted {
1539 static if (type == "msx") { alias fontw8 = kgiFont6PropWidth; }
1540 else static if (type == "dos") { alias fontw8 = kgiFont8PropWidth; }
1541 else static assert(0, "invalid font type");
1542 immutable int wdt = (fontw8[ch]&0x0f);
1543 drawCharWdt!type(x, y, wdt, fontw8[ch]>>4, ch, fgcol, bgcol);
1544 return wdt;
1547 int drawCharPropOut(string type="msx") (int x, int y, char ch, VColor fgcol, VColor outcol=Transparent, ubyte ot=OutAll) @trusted {
1548 static if (type == "msx") { alias fontw8 = kgiFont6PropWidth; }
1549 else static if (type == "dos") { alias fontw8 = kgiFont8PropWidth; }
1550 else static assert(0, "invalid font type");
1551 immutable int wdt = (fontw8[ch]&0x0f);
1552 drawCharWdtOut!type(x, y, wdt, fontw8[ch]>>4, ch, fgcol, outcol, ot);
1553 return wdt;
1556 int drawStrProp(string type="msx") (int x, int y, const(char)[] str, VColor fgcol, VColor bgcol=Transparent) @trusted {
1557 bool vline = false;
1558 int sx = x;
1559 foreach (immutable char ch; str) {
1560 if (vline) {
1561 if (!isTransparent(bgcol)) {
1562 foreach (int dy; 0..8) putPixelIntr(x, y+dy, bgcol);
1563 // no need to advance vupcounter, 'cause `drawCharProp` will do it
1564 //version(LDC) {} else atomicFence();
1565 //++vupcounter;
1567 ++x;
1569 vline = true;
1570 x += drawCharProp!type(x, y, ch, fgcol, bgcol);
1572 return x-sx;
1575 int drawStrPropOut(string type="msx") (int x, int y, const(char)[] str, VColor fgcol, VColor outcol=Transparent, ubyte ot=OutAll) @trusted {
1576 int sx = x;
1577 foreach (immutable char ch; str) {
1578 x += drawCharPropOut!type(x, y, ch, fgcol, outcol, ot)+1;
1580 if (x > sx) --x; // don't count last empty pixel
1581 return x-sx;
1585 // ////////////////////////////////////////////////////////////////////////// //
1586 /** floodfill area; based on Tarry's maze algorithm.
1588 * fill area with color/pattern. trades memory for speed: doesn't recurse, doesn't allocate.
1589 * will use "transparency" byte as temporary, and will leave it dirty.
1591 * NOTES:
1592 * neither `isBorder` nor `patColor` will be called with out-of-range coordinates.
1594 void floodFillEx (int x, int y, scope bool delegate (int x, int y) nothrow @nogc isBorder, scope VColor delegate (int x, int y) nothrow @nogc patColor) nothrow @trusted @nogc {
1595 enum : ubyte {
1596 DirMask = 0x03,
1597 Seed = 0x10,
1598 Scanned = 0x80,
1601 static ubyte getmark (int x, int y) nothrow @trusted @nogc {
1602 pragma(inline, true);
1603 return cast(ubyte)(x >= 0 && y >= 0 && x < vbufW && y < vbufH ? vbuf[y*vbufW+x]>>vlAShift : Scanned);
1606 static void setmark (int x, int y, ubyte mark) nothrow @trusted @nogc {
1607 pragma(inline, true);
1608 if (x >= 0 && y >= 0 && x < vbufW && y < vbufH) vbuf[y*vbufW+x] = (vbuf[y*vbufW+x]&vlColorMask)|(mark<<vlAShift);
1611 if (x < 0 || y < 0 || x >= vbufW || y >= vbufH) return; // nothing to do
1612 if (isBorder(x, y)) return; // nothing to do
1614 //setPixel(x, y, getPixel(x, y)); // set update flag
1616 // one can mark bounding rectangle with Scanned
1617 // reset flags
1618 auto p = vbuf;
1619 foreach (immutable dy; 0..vbufH) {
1620 foreach (immutable dx; 0..vbufW) {
1621 *p &= vlColorMask; // "not visited" mark
1622 ++p;
1626 //setmark(x, y, Scanned|Fill|Seed);
1627 VColor pc = patColor(x, y);
1628 if (isOpaque(pc)) {
1629 vbuf[y*vbufW+x] = (pc&vlColorMask)|((Scanned|Seed)<<vlAShift);
1630 } else {
1631 // do alpha
1632 putPixelIntrNoCheck(x, y, pc);
1633 setmark(x, y, Scanned|Seed);
1636 ubyte dir = 0; // direction: right, left, up, down
1637 for (;;) {
1638 x += (dir == 0 ? 1 : dir == 1 ? -1 : 0);
1639 y += (dir == 3 ? 1 : dir == 2 ? -1 : 0);
1640 auto mk = getmark(x, y);
1641 if (mk == 0) {
1642 // not yet visited, check for border
1643 if (isBorder(x, y)) {
1644 mk = Scanned;
1645 setmark(x, y, Scanned);
1648 if ((mk&Scanned) == 0) {
1649 // not scanned
1650 //setmark(x, y, Scanned|Fill|dir);
1651 pc = patColor(x, y);
1652 if (isOpaque(pc)) {
1653 vbuf[y*vbufW+x] = (pc&vlColorMask)|((Scanned|dir)<<vlAShift);
1654 } else {
1655 // do alpha
1656 putPixelIntrNoCheck(x, y, pc);
1657 setmark(x, y, Scanned|dir);
1659 if (dir != 1) dir = 0; // make exit direction
1660 } else {
1661 // already scanned
1662 for (;;) {
1663 x -= (dir == 0 ? 1 : dir == 1 ? -1 : 0);
1664 y -= (dir == 3 ? 1 : dir == 2 ? -1 : 0);
1665 mk = getmark(x, y);
1666 if (mk&Seed) {
1667 // done, fill pixels (you can set Fill flag and check all pixels here)
1668 if ((mk&DirMask) == 3) {
1669 // set update flag
1670 version(LDC) {} else atomicFence();
1671 ++vupcounter;
1672 return;
1674 // remember new dir
1675 ++mk;
1676 setmark(x, y, mk);
1677 dir = mk&DirMask;
1678 break; // next pixel
1680 ++dir;
1681 if ((mk&DirMask) == (dir^1)) ++dir; // skip entry-direction
1682 if (dir <= 3) break; // next pixel
1683 dir = mk&DirMask;
1688 } // @nogc
1691 // ////////////////////////////////////////////////////////////////////////// //
1692 // fonts
1693 static public immutable ubyte[256*8] kgiFont6 = [
1694 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c,0x3c,0x7e,0xdb,0xff,0xff,0xdb,0x66,0x3c,0x6c,0xfe,
1695 0xfe,0xfe,0x7c,0x38,0x10,0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x10,0x38,0x54,0xfe,0x54,0x10,0x38,0x00,0x10,0x38,0x7c,0xfe,
1696 0xfe,0x10,0x38,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0xff,0xff,0xff,0xe7,0xe7,0xff,0xff,0xff,0x38,0x44,0x82,0x82,0x82,0x44,
1697 0x38,0x00,0xc7,0xbb,0x7d,0x7d,0x7d,0xbb,0xc7,0xff,0x0f,0x03,0x05,0x79,0x88,0x88,0x88,0x70,0x38,0x44,0x44,0x44,0x38,0x10,0x7c,0x10,
1698 0x30,0x28,0x24,0x24,0x28,0x20,0xe0,0xc0,0x3c,0x24,0x3c,0x24,0x24,0xe4,0xdc,0x18,0x10,0x54,0x38,0xee,0x38,0x54,0x10,0x00,0x10,0x10,
1699 0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xf0,
1700 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1f,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xff,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
1701 0x10,0x10,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0xf0,0x10,0x10,0x10,0x10,
1702 0x10,0x10,0x10,0x1f,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0xf0,0x00,0x00,0x00,0x00,0x81,0x42,0x24,0x18,0x18,0x24,0x42,0x81,0x01,0x02,
1703 0x04,0x08,0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00,0x10,0x10,0xff,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1704 0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x00,0x00,0x20,0x00,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x50,0x50,0xf8,0x50,0xf8,0x50,
1705 0x50,0x00,0x20,0x78,0xa0,0x70,0x28,0xf0,0x20,0x00,0xc0,0xc8,0x10,0x20,0x40,0x98,0x18,0x00,0x40,0xa0,0x40,0xa8,0x90,0x98,0x60,0x00,
1706 0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00,0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00,0x88,0x50,
1707 0x20,0xf8,0x20,0x50,0x88,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x40,0x00,0x00,0x00,0x78,
1708 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x70,0x88,0x98,0xa8,0xc8,0x88,
1709 0x70,0x00,0x20,0x60,0xa0,0x20,0x20,0x20,0xf8,0x00,0x70,0x88,0x08,0x10,0x60,0x80,0xf8,0x00,0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00,
1710 0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,0xf8,0x80,0xe0,0x10,0x08,0x10,0xe0,0x00,0x30,0x40,0x80,0xf0,0x88,0x88,0x70,0x00,0xf8,0x88,
1711 0x10,0x20,0x20,0x20,0x20,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x70,0x88,0x88,0x78,0x08,0x10,0x60,0x00,0x00,0x00,0x20,0x00,
1712 0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x20,0x40,0x18,0x30,0x60,0xc0,0x60,0x30,0x18,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,
1713 0x00,0x00,0xc0,0x60,0x30,0x18,0x30,0x60,0xc0,0x00,0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00,0x70,0x88,0x08,0x68,0xa8,0xa8,0x70,0x00,
1714 0x20,0x50,0x88,0x88,0xf8,0x88,0x88,0x00,0xf0,0x48,0x48,0x70,0x48,0x48,0xf0,0x00,0x30,0x48,0x80,0x80,0x80,0x48,0x30,0x00,0xe0,0x50,
1715 0x48,0x48,0x48,0x50,0xe0,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x80,0xb8,
1716 0x88,0x88,0x70,0x00,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x38,0x10,0x10,0x10,0x90,0x90,
1717 0x60,0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x88,0xd8,0xa8,0xa8,0x88,0x88,0x88,0x00,
1718 0x88,0xc8,0xc8,0xa8,0x98,0x98,0x88,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,
1719 0x88,0x88,0xa8,0x90,0x68,0x00,0xf0,0x88,0x88,0xf0,0xa0,0x90,0x88,0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,0xf8,0x20,0x20,0x20,
1720 0x20,0x20,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x88,0x88,0x88,0x88,0x50,0x50,0x20,0x00,0x88,0x88,0x88,0xa8,0xa8,0xd8,
1721 0x88,0x00,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x88,0x88,0x88,0x70,0x20,0x20,0x20,0x00,0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,
1722 0x70,0x40,0x40,0x40,0x40,0x40,0x70,0x00,0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x70,0x00,0x20,0x50,
1723 0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x08,
1724 0x78,0x88,0x78,0x00,0x80,0x80,0xb0,0xc8,0x88,0xc8,0xb0,0x00,0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00,0x08,0x08,0x68,0x98,0x88,0x98,
1725 0x68,0x00,0x00,0x00,0x70,0x88,0xf8,0x80,0x70,0x00,0x10,0x28,0x20,0xf8,0x20,0x20,0x20,0x00,0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x70,
1726 0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x90,0x60,0x40,0x40,
1727 0x48,0x50,0x60,0x50,0x48,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x00,0xd0,0xa8,0xa8,0xa8,0xa8,0x00,0x00,0x00,0xb0,0xc8,
1728 0x88,0x88,0x88,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00,0x00,0xb0,0xc8,0xc8,0xb0,0x80,0x80,0x00,0x00,0x68,0x98,0x98,0x68,
1729 0x08,0x08,0x00,0x00,0xb0,0xc8,0x80,0x80,0x80,0x00,0x00,0x00,0x78,0x80,0xf0,0x08,0xf0,0x00,0x40,0x40,0xf0,0x40,0x40,0x48,0x30,0x00,
1730 0x00,0x00,0x90,0x90,0x90,0x90,0x68,0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,0x00,0x00,0x88,0xa8,0xa8,0xa8,0x50,0x00,0x00,0x00,
1731 0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00,0x88,0x88,0x98,0x68,0x08,0x70,0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00,0x18,0x20,0x20,0x40,
1732 0x20,0x20,0x18,0x00,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00,0xc0,0x20,0x20,0x10,0x20,0x20,0xc0,0x00,0x40,0xa8,0x10,0x00,0x00,0x00,
1733 0x00,0x00,0x00,0x00,0x20,0x50,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xf0,0xf0,0xf0,0xf0,0x0f,0x0f,0x0f,0x0f,
1734 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x00,0x00,0x00,0xff,0xff,
1735 0xff,0xff,0xff,0xff,0x00,0x00,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xfc,0xfc,0xfc,0xfc,
1736 0xfc,0xfc,0xfc,0xfc,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x11,0x22,0x44,0x88,0x11,0x22,
1737 0x44,0x88,0x88,0x44,0x22,0x11,0x88,0x44,0x22,0x11,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x7c,0xfe,
1738 0x80,0xc0,0xe0,0xf0,0xe0,0xc0,0x80,0x00,0x01,0x03,0x07,0x0f,0x07,0x03,0x01,0x00,0xff,0x7e,0x3c,0x18,0x18,0x3c,0x7e,0xff,0x81,0xc3,
1739 0xe7,0xff,0xff,0xe7,0xc3,0x81,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
1740 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xf0,0xf0,0xf0,0x33,0x33,0xcc,0xcc,0x33,0x33,0xcc,0xcc,0x00,0x20,0x20,0x50,0x50,0x88,
1741 0xf8,0x00,0x20,0x20,0x70,0x20,0x70,0x20,0x20,0x00,0x00,0x00,0x00,0x50,0x88,0xa8,0x50,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1742 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xff,0xff,
1743 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x90,0x90,0x90,0x68,0x00,0x30,0x48,0x48,0x70,0x48,0x48,0x70,0xc0,0xf8,0x88,0x80,0x80,
1744 0x80,0x80,0x80,0x00,0x00,0x50,0x70,0x88,0xf8,0x80,0x70,0x00,0x00,0x00,0x78,0x80,0xf0,0x80,0x78,0x00,0x00,0x00,0x78,0x90,0x90,0x90,
1745 0x60,0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x50,0x00,0x70,0x20,0x20,0x20,0x70,0x00,0xf8,0x20,0x70,0xa8,0xa8,0x70,0x20,0xf8,
1746 0x20,0x50,0x88,0xf8,0x88,0x50,0x20,0x00,0x70,0x88,0x88,0x88,0x50,0x50,0xd8,0x00,0x30,0x40,0x40,0x20,0x50,0x50,0x50,0x20,0x00,0x00,
1747 0x00,0x50,0xa8,0xa8,0x50,0x00,0x08,0x70,0xa8,0xa8,0xa8,0x70,0x80,0x00,0x38,0x40,0x80,0xf8,0x80,0x40,0x38,0x00,0x70,0x88,0x88,0x88,
1748 0x88,0x88,0x88,0x00,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0xf8,0x00,0xc0,0x30,0x08,0x30,0xc0,0x00,
1749 0xf8,0x00,0x50,0xf8,0x80,0xf0,0x80,0x80,0xf8,0x00,0x78,0x80,0x80,0xf0,0x80,0x80,0x78,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0xa0,0x40,
1750 0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x50,0x70,0x20,0x20,0x20,0x20,0x70,0x00,0x00,0x18,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x30,
1751 0x78,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x3e,0x20,0x20,0x20,0xa0,0x60,0x20,0x00,0xa0,0x50,0x50,0x50,
1752 0x00,0x00,0x00,0x00,0x40,0xa0,0x20,0x40,0xe0,0x00,0x00,0x00,0x00,0x38,0x38,0x38,0x38,0x38,0x38,0x00,0x3c,0x42,0x99,0xa1,0xa1,0x99,
1753 0x42,0x3c,0x00,0x00,0x90,0xa8,0xe8,0xa8,0x90,0x00,0x00,0x00,0x60,0x10,0x70,0x90,0x68,0x00,0x00,0x00,0xf0,0x80,0xf0,0x88,0xf0,0x00,
1754 0x00,0x00,0x90,0x90,0x90,0xf8,0x08,0x00,0x00,0x00,0x30,0x50,0x50,0x70,0x88,0x00,0x00,0x00,0x70,0x88,0xf8,0x80,0x70,0x00,0x00,0x20,
1755 0x70,0xa8,0xa8,0x70,0x20,0x00,0x00,0x00,0x78,0x48,0x40,0x40,0x40,0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00,0x88,0x98,
1756 0xa8,0xc8,0x88,0x00,0x00,0x50,0x20,0x00,0x98,0xa8,0xc8,0x00,0x00,0x00,0x90,0xa0,0xc0,0xa0,0x90,0x00,0x00,0x00,0x38,0x28,0x28,0x48,
1757 0x88,0x00,0x00,0x00,0x88,0xd8,0xa8,0x88,0x88,0x00,0x00,0x00,0x88,0x88,0xf8,0x88,0x88,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,
1758 0x00,0x00,0x78,0x48,0x48,0x48,0x48,0x00,0x00,0x00,0x78,0x88,0x78,0x28,0x48,0x00,0x00,0x00,0xf0,0x88,0xf0,0x80,0x80,0x00,0x00,0x00,
1759 0x78,0x80,0x80,0x80,0x78,0x00,0x00,0x00,0xf8,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x88,0x50,0x20,0x40,0x80,0x00,0x00,0x00,0xa8,0x70,
1760 0x20,0x70,0xa8,0x00,0x00,0x00,0xf0,0x48,0x70,0x48,0xf0,0x00,0x00,0x00,0x40,0x40,0x70,0x48,0x70,0x00,0x00,0x00,0x88,0x88,0xc8,0xa8,
1761 0xc8,0x00,0x00,0x00,0xf0,0x08,0x70,0x08,0xf0,0x00,0x00,0x00,0xa8,0xa8,0xa8,0xa8,0xf8,0x00,0x00,0x00,0x70,0x88,0x38,0x88,0x70,0x00,
1762 0x00,0x00,0xa8,0xa8,0xa8,0xf8,0x08,0x00,0x00,0x00,0x48,0x48,0x78,0x08,0x08,0x00,0x00,0x00,0xc0,0x40,0x70,0x48,0x70,0x00,0x90,0xa8,
1763 0xa8,0xe8,0xa8,0xa8,0x90,0x00,0x20,0x50,0x88,0x88,0xf8,0x88,0x88,0x00,0xf8,0x88,0x80,0xf0,0x88,0x88,0xf0,0x00,0x90,0x90,0x90,0x90,
1764 0x90,0xf8,0x08,0x00,0x38,0x28,0x28,0x48,0x48,0xf8,0x88,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x20,0x70,0xa8,0xa8,0xa8,0x70,
1765 0x20,0x00,0xf8,0x88,0x88,0x80,0x80,0x80,0x80,0x00,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x88,0x88,0x98,0xa8,0xc8,0x88,0x88,0x00,
1766 0x50,0x20,0x88,0x98,0xa8,0xc8,0x88,0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00,0x18,0x28,0x48,0x48,0x48,0x48,0x88,0x00,0x88,0xd8,
1767 0xa8,0xa8,0x88,0x88,0x88,0x00,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0xf8,0x88,0x88,0x88,
1768 0x88,0x88,0x88,0x00,0x78,0x88,0x88,0x78,0x28,0x48,0x88,0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x80,0x80,0x80,0x88,
1769 0x70,0x00,0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x88,0x88,0x88,0x50,0x20,0x40,0x80,0x00,0xa8,0xa8,0x70,0x20,0x70,0xa8,0xa8,0x00,
1770 0xf0,0x48,0x48,0x70,0x48,0x48,0xf0,0x00,0x80,0x80,0x80,0xf0,0x88,0x88,0xf0,0x00,0x88,0x88,0x88,0xc8,0xa8,0xa8,0xc8,0x00,0xf0,0x08,
1771 0x08,0x30,0x08,0x08,0xf0,0x00,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xf8,0x00,0x70,0x88,0x08,0x78,0x08,0x88,0x70,0x00,0xa8,0xa8,0xa8,0xa8,
1772 0xa8,0xf8,0x08,0x00,0x88,0x88,0x88,0x88,0x78,0x08,0x08,0x00,0xc0,0x40,0x40,0x70,0x48,0x48,0x70,0x00,
1775 static public immutable ubyte[256*8] kgiFont8 = [
1776 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e,0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e,0x6c,0xfe,
1777 0xfe,0xfe,0x7c,0x38,0x10,0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x38,0x7c,0x38,0xfe,0xfe,0xd6,0x10,0x38,0x10,0x10,0x38,0x7c,
1778 0xfe,0x7c,0x10,0x38,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0x00,0x3c,0x66,0x42,0x42,0x66,
1779 0x3c,0x00,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0x0f,0x07,0x0f,0x7d,0xcc,0xcc,0xcc,0x78,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,
1780 0x3f,0x33,0x3f,0x30,0x30,0x70,0xf0,0xe0,0x7f,0x63,0x7f,0x63,0x63,0x67,0xe6,0xc0,0x99,0x5a,0x3c,0xe7,0xe7,0x3c,0x5a,0x99,0x80,0xe0,
1781 0xf8,0xfe,0xf8,0xe0,0x80,0x00,0x02,0x0e,0x3e,0xfe,0x3e,0x0e,0x02,0x00,0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18,0x66,0x66,0x66,0x66,
1782 0x66,0x00,0x66,0x00,0x7f,0xdb,0xdb,0x7b,0x1b,0x1b,0x1b,0x00,0x7e,0xc3,0x78,0xcc,0xcc,0x78,0x8c,0xf8,0x00,0x00,0x00,0x00,0x7e,0x7e,
1783 0x7e,0x00,0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,
1784 0x00,0x18,0x0c,0xfe,0x0c,0x18,0x00,0x00,0x00,0x30,0x60,0xfe,0x60,0x30,0x00,0x00,0x00,0x00,0xc0,0xc0,0xc0,0xfe,0x00,0x00,0x00,0x24,
1785 0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1786 0x00,0x00,0x00,0x00,0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0xfe,0x6c,
1787 0x6c,0x00,0x30,0x7c,0xc0,0x78,0x0c,0xf8,0x30,0x00,0x00,0xc6,0xcc,0x18,0x30,0x66,0xc6,0x00,0x38,0x6c,0x38,0x76,0xdc,0xcc,0x76,0x00,
1788 0x60,0x60,0xc0,0x00,0x00,0x00,0x00,0x00,0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x00,0x60,0x30,0x18,0x18,0x18,0x30,0x60,0x00,0x00,0x66,
1789 0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x30,0x30,0xfc,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x30,0x60,0x00,0x00,0x00,0xfc,
1790 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x06,0x0c,0x18,0x30,0x60,0xc0,0x80,0x00,0x78,0xcc,0xdc,0xfc,0xec,0xcc,
1791 0x78,0x00,0x30,0xf0,0x30,0x30,0x30,0x30,0xfc,0x00,0x78,0xcc,0x0c,0x38,0x60,0xcc,0xfc,0x00,0x78,0xcc,0x0c,0x38,0x0c,0xcc,0x78,0x00,
1792 0x1c,0x3c,0x6c,0xcc,0xfe,0x0c,0x0c,0x00,0xfc,0xc0,0xf8,0x0c,0x0c,0xcc,0x78,0x00,0x38,0x60,0xc0,0xf8,0xcc,0xcc,0x78,0x00,0xfc,0xcc,
1793 0x0c,0x18,0x30,0x60,0x60,0x00,0x78,0xcc,0xcc,0x78,0xcc,0xcc,0x78,0x00,0x78,0xcc,0xcc,0x7c,0x0c,0x18,0x70,0x00,0x00,0x00,0x30,0x30,
1794 0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x00,0x70,0x30,0x60,0x18,0x30,0x60,0xc0,0x60,0x30,0x18,0x00,0x00,0x00,0xfc,0x00,0xfc,0x00,
1795 0x00,0x00,0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0x00,0x78,0xcc,0x0c,0x18,0x30,0x00,0x30,0x00,0x7c,0xc6,0xde,0xde,0xde,0xc0,0x78,0x00,
1796 0x30,0x78,0xcc,0xcc,0xfc,0xcc,0xcc,0x00,0xfc,0x66,0x66,0x7c,0x66,0x66,0xfc,0x00,0x3c,0x66,0xc0,0xc0,0xc0,0x66,0x3c,0x00,0xfc,0x6c,
1797 0x66,0x66,0x66,0x6c,0xfc,0x00,0xfe,0x62,0x68,0x78,0x68,0x62,0xfe,0x00,0xfe,0x62,0x68,0x78,0x68,0x60,0xf0,0x00,0x3c,0x66,0xc0,0xc0,
1798 0xce,0x66,0x3e,0x00,0xcc,0xcc,0xcc,0xfc,0xcc,0xcc,0xcc,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x1e,0x0c,0x0c,0x0c,0xcc,0xcc,
1799 0x78,0x00,0xe6,0x66,0x6c,0x78,0x6c,0x66,0xe6,0x00,0xf0,0x60,0x60,0x60,0x62,0x66,0xfe,0x00,0xc6,0xee,0xfe,0xd6,0xc6,0xc6,0xc6,0x00,
1800 0xc6,0xe6,0xf6,0xde,0xce,0xc6,0xc6,0x00,0x38,0x6c,0xc6,0xc6,0xc6,0x6c,0x38,0x00,0xfc,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00,0x78,0xcc,
1801 0xcc,0xcc,0xdc,0x78,0x1c,0x00,0xfc,0x66,0x66,0x7c,0x78,0x6c,0xe6,0x00,0x78,0xcc,0xe0,0x38,0x1c,0xcc,0x78,0x00,0xfc,0xb4,0x30,0x30,
1802 0x30,0x30,0x78,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xfc,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x30,0x00,0xc6,0xc6,0xc6,0xd6,0xfe,0xee,
1803 0xc6,0x00,0xc6,0xc6,0x6c,0x38,0x6c,0xc6,0xc6,0x00,0xcc,0xcc,0xcc,0x78,0x30,0x30,0x78,0x00,0xfe,0xcc,0x98,0x30,0x62,0xc6,0xfe,0x00,
1804 0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00,0xc0,0x60,0x30,0x18,0x0c,0x06,0x02,0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x78,0x00,0x10,0x38,
1805 0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x0c,
1806 0x7c,0xcc,0x76,0x00,0xe0,0x60,0x7c,0x66,0x66,0x66,0xbc,0x00,0x00,0x00,0x78,0xcc,0xc0,0xcc,0x78,0x00,0x1c,0x0c,0x0c,0x7c,0xcc,0xcc,
1807 0x76,0x00,0x00,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,0x38,0x6c,0x60,0xf0,0x60,0x60,0xf0,0x00,0x00,0x00,0x76,0xcc,0xcc,0x7c,0x0c,0xf8,
1808 0xe0,0x60,0x6c,0x76,0x66,0x66,0xe6,0x00,0x30,0x00,0x70,0x30,0x30,0x30,0x78,0x00,0x18,0x00,0x78,0x18,0x18,0x18,0xd8,0x70,0xe0,0x60,
1809 0x66,0x6c,0x78,0x6c,0xe6,0x00,0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0xec,0xfe,0xd6,0xc6,0xc6,0x00,0x00,0x00,0xf8,0xcc,
1810 0xcc,0xcc,0xcc,0x00,0x00,0x00,0x78,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0xdc,0x66,0x66,0x7c,0x60,0xf0,0x00,0x00,0x76,0xcc,0xcc,0x7c,
1811 0x0c,0x1e,0x00,0x00,0xd8,0x6c,0x6c,0x60,0xf0,0x00,0x00,0x00,0x7c,0xc0,0x78,0x0c,0xf8,0x00,0x10,0x30,0x7c,0x30,0x30,0x34,0x18,0x00,
1812 0x00,0x00,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0xcc,0xcc,0xcc,0x78,0x30,0x00,0x00,0x00,0xc6,0xc6,0xd6,0xfe,0x6c,0x00,0x00,0x00,
1813 0xc6,0x6c,0x38,0x6c,0xc6,0x00,0x00,0x00,0xcc,0xcc,0xcc,0x7c,0x0c,0xf8,0x00,0x00,0xfc,0x98,0x30,0x64,0xfc,0x00,0x1c,0x30,0x30,0xe0,
1814 0x30,0x30,0x1c,0x00,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0xe0,0x30,0x30,0x1c,0x30,0x30,0xe0,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,
1815 0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x78,0xcc,0xc0,0xcc,0x78,0x18,0x0c,0x78,0x00,0xcc,0x00,0xcc,0xcc,0xcc,0x7e,0x00,
1816 0x1c,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,0x7e,0xc3,0x3c,0x06,0x3e,0x66,0x3f,0x00,0xcc,0x00,0x78,0x0c,0x7c,0xcc,0x7e,0x00,0xe0,0x00,
1817 0x78,0x0c,0x7c,0xcc,0x7e,0x00,0x30,0x30,0x78,0x0c,0x7c,0xcc,0x7e,0x00,0x00,0x00,0x7c,0xc0,0xc0,0x7c,0x06,0x3c,0x7e,0xc3,0x3c,0x66,
1818 0x7e,0x60,0x3c,0x00,0xcc,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,0xe0,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,0xcc,0x00,0x70,0x30,0x30,0x30,
1819 0x78,0x00,0x7c,0xc6,0x38,0x18,0x18,0x18,0x3c,0x00,0xe0,0x00,0x70,0x30,0x30,0x30,0x78,0x00,0xcc,0x30,0x78,0xcc,0xcc,0xfc,0xcc,0x00,
1820 0x30,0x30,0x00,0x78,0xcc,0xfc,0xcc,0x00,0x1c,0x00,0xfc,0x60,0x78,0x60,0xfc,0x00,0x00,0x00,0x7f,0x0c,0x7f,0xcc,0x7f,0x00,0x3e,0x6c,
1821 0xcc,0xfe,0xcc,0xcc,0xce,0x00,0x78,0xcc,0x00,0x78,0xcc,0xcc,0x78,0x00,0x00,0xcc,0x00,0x78,0xcc,0xcc,0x78,0x00,0x00,0xe0,0x00,0x78,
1822 0xcc,0xcc,0x78,0x00,0x78,0xcc,0x00,0xcc,0xcc,0xcc,0x7e,0x00,0x00,0xe0,0x00,0xcc,0xcc,0xcc,0x7e,0x00,0x00,0xcc,0x00,0xcc,0xcc,0xfc,
1823 0x0c,0xf8,0xc6,0x38,0x7c,0xc6,0xc6,0x7c,0x38,0x00,0xcc,0x00,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x18,0x18,0x7e,0xc0,0xc0,0x7e,0x18,0x18,
1824 0x38,0x6c,0x64,0xf0,0x60,0xe6,0xfc,0x00,0xcc,0xcc,0x78,0xfc,0x30,0xfc,0x30,0x00,0xf0,0xd8,0xd8,0xf4,0xcc,0xde,0xcc,0x0e,0x0e,0x1b,
1825 0x18,0x7e,0x18,0x18,0xd8,0x70,0x1c,0x00,0x78,0x0c,0x7c,0xcc,0x7e,0x00,0x38,0x00,0x70,0x30,0x30,0x30,0x78,0x00,0x00,0x1c,0x00,0x78,
1826 0xcc,0xcc,0x78,0x00,0x00,0x1c,0x00,0xcc,0xcc,0xcc,0x7e,0x00,0x00,0xf8,0x00,0xf8,0xcc,0xcc,0xcc,0x00,0xfc,0x00,0xcc,0xec,0xfc,0xdc,
1827 0xcc,0x00,0x3c,0x6c,0x6c,0x3e,0x00,0x7e,0x00,0x00,0x3c,0x66,0x66,0x3c,0x00,0x7e,0x00,0x00,0x30,0x00,0x30,0x60,0xc0,0xcc,0x78,0x00,
1828 0x00,0x00,0x00,0xfc,0xc0,0xc0,0x00,0x00,0x00,0x00,0x00,0xfc,0x0c,0x0c,0x00,0x00,0xc6,0xcc,0xd8,0x3e,0x63,0xce,0x98,0x1f,0xc6,0xcc,
1829 0xd8,0xf3,0x67,0xcf,0x9f,0x03,0x00,0x18,0x00,0x18,0x18,0x3c,0x3c,0x18,0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00,0x00,0xcc,0x66,0x33,
1830 0x66,0xcc,0x00,0x00,0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0xdc,0x76,0xdc,0x76,0xdc,0x76,
1831 0xdc,0x76,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,
1832 0x36,0x36,0x36,0x36,0xf6,0x36,0x36,0x36,0x00,0x00,0x00,0x00,0xfe,0x36,0x36,0x36,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x36,0x36,
1833 0xf6,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x00,0x00,0xfe,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0xf6,0x06,
1834 0xfe,0x00,0x00,0x00,0x36,0x36,0x36,0x36,0xfe,0x00,0x00,0x00,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,
1835 0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,
1836 0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,
1837 0x1f,0x18,0x1f,0x18,0x18,0x18,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3f,0x00,0x00,0x00,0x00,0x00,0x3f,0x30,
1838 0x37,0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,
1839 0x36,0x36,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x36,0x36,0xf7,0x00,0xf7,0x36,0x36,0x36,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,
1840 0x36,0x36,0x36,0x36,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x36,0x36,0x36,0x36,0x36,
1841 0x36,0x36,0x3f,0x00,0x00,0x00,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
1842 0x3f,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xf7,0x36,0x36,0x36,0x18,0x18,0xff,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x00,
1843 0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
1844 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,
1845 0x76,0xdc,0xc8,0xdc,0x76,0x00,0x00,0x78,0xcc,0xf8,0xcc,0xf8,0xc0,0xc0,0x00,0xfe,0xc6,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0xfe,0x6c,0x6c,
1846 0x6c,0x6c,0x6c,0x00,0xfe,0x66,0x30,0x18,0x30,0x66,0xfe,0x00,0x00,0x00,0x7e,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x66,0x66,0x66,0x66,0x7c,
1847 0x60,0xc0,0x00,0x76,0xdc,0x18,0x18,0x18,0x18,0x00,0xfc,0x30,0x78,0xcc,0xcc,0x78,0x30,0xfc,0x38,0x6c,0xc6,0xfe,0xc6,0x6c,0x38,0x00,
1848 0x38,0x6c,0xc6,0xc6,0x6c,0x6c,0xee,0x00,0x1c,0x30,0x18,0x7c,0xcc,0xcc,0x78,0x00,0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00,0x06,0x0c,
1849 0x7e,0xdb,0xdb,0x7e,0x60,0xc0,0x3c,0x60,0xc0,0xfc,0xc0,0x60,0x3c,0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0xfc,0x00,0xfc,
1850 0x00,0xfc,0x00,0x00,0x30,0x30,0xfc,0x30,0x30,0x00,0xfc,0x00,0x60,0x30,0x18,0x30,0x60,0x00,0xfc,0x00,0x18,0x30,0x60,0x30,0x18,0x00,
1851 0xfc,0x00,0x0e,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0x70,0x30,0x30,0x00,0xfc,0x00,0x30,0x30,0x00,
1852 0x00,0x72,0x9c,0x00,0x72,0x9c,0x00,0x00,0x38,0x6c,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
1853 0x00,0x00,0x18,0x00,0x00,0x00,0x0f,0x0c,0x0c,0x0c,0xec,0x6c,0x3c,0x1c,0x78,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x78,0x0c,0x38,0x60,
1854 0x7c,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1857 static public immutable ushort[256*10] kgiFont10 = [
1858 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x4080,0x5280,0x4080,0x5e80,0x4c80,0x2100,0x1e00,
1859 0x0000,0x0000,0x3f00,0x7f80,0x6d80,0x7f80,0x6180,0x7380,0x3f00,0x1e00,0x0000,0x0000,0x3b80,0x7fc0,0x7fc0,0x7fc0,0x3f80,0x1f00,0x0e00,
1860 0x0400,0x0000,0x0400,0x0e00,0x1f00,0x3f80,0x7fc0,0x3f80,0x1f00,0x0e00,0x0400,0x0000,0x0000,0x0e00,0x1f00,0x0e00,0x3f80,0x7fc0,0x3580,
1861 0x0400,0x0e00,0x0000,0x0400,0x0e00,0x1f00,0x3f80,0x7fc0,0x7fc0,0x3580,0x0400,0x0e00,0x0000,0x0000,0x0000,0x0000,0x0c00,0x1e00,0x1e00,
1862 0x0c00,0x0000,0x0000,0x0000,0xffc0,0xffc0,0xffc0,0xf3c0,0xe1c0,0xe1c0,0xf3c0,0xffc0,0xffc0,0xffc0,0x0000,0x0000,0x1e00,0x3300,0x2100,
1863 0x2100,0x3300,0x1e00,0x0000,0x0000,0xffc0,0xffc0,0xe1c0,0xccc0,0xdec0,0xdec0,0xccc0,0xe1c0,0xffc0,0xffc0,0x0000,0x0780,0x0380,0x0780,
1864 0x3e80,0x6600,0x6600,0x6600,0x3c00,0x0000,0x0000,0x1e00,0x3300,0x3300,0x3300,0x1e00,0x0c00,0x3f00,0x0c00,0x0000,0x0400,0x0600,0x0700,
1865 0x0500,0x0500,0x0400,0x1c00,0x3c00,0x1800,0x0000,0x0000,0x1f80,0x1f80,0x1080,0x1080,0x1180,0x3380,0x7100,0x2000,0x0000,0x0000,0x0c00,
1866 0x6d80,0x1e00,0x7380,0x7380,0x1e00,0x6d80,0x0c00,0x0000,0x1000,0x1800,0x1c00,0x1e00,0x1f00,0x1e00,0x1c00,0x1800,0x1000,0x0000,0x0100,
1867 0x0300,0x0700,0x0f00,0x1f00,0x0f00,0x0700,0x0300,0x0100,0x0000,0x0000,0x0c00,0x1e00,0x3f00,0x0c00,0x0c00,0x3f00,0x1e00,0x0c00,0x0000,
1868 0x0000,0x3300,0x3300,0x3300,0x3300,0x3300,0x0000,0x3300,0x0000,0x0000,0x0000,0x3f80,0x6d80,0x6d80,0x3d80,0x0d80,0x0d80,0x0d80,0x0000,
1869 0x0000,0x0000,0x1f00,0x3000,0x1f00,0x3180,0x1f00,0x0180,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7f80,0x7f80,0x7f80,
1870 0x0000,0x0000,0x0000,0x0c00,0x1e00,0x3f00,0x0c00,0x0c00,0x3f00,0x1e00,0x0c00,0xffc0,0x0000,0x0c00,0x1e00,0x3f00,0x0c00,0x0c00,0x0c00,
1871 0x0c00,0x0c00,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x3f00,0x1e00,0x0c00,0x0000,0x0000,0x0000,0x0600,0x0300,0x7f80,0x0300,
1872 0x0600,0x0000,0x0000,0x0000,0x0000,0x0000,0x1800,0x3000,0x7f80,0x3000,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6000,
1873 0x6000,0x6000,0x7f80,0x0000,0x0000,0x0000,0x0000,0x1100,0x3180,0x7fc0,0x3180,0x1100,0x0000,0x0000,0x0000,0x0000,0x0000,0x0400,0x0e00,
1874 0x1f00,0x3f80,0x7fc0,0x0000,0x0000,0x0000,0x0000,0x0000,0x7fc0,0x3f80,0x1f00,0x0e00,0x0400,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
1875 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x1e00,0x1e00,0x0c00,0x0c00,0x0000,0x0c00,0x0000,0x0000,0x0000,0x1b00,
1876 0x1b00,0x1b00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1b00,0x1b00,0x7fc0,0x1b00,0x7fc0,0x1b00,0x1b00,0x0000,0x0000,0x0400,
1877 0x1f00,0x3580,0x3400,0x1f00,0x0580,0x3580,0x1f00,0x0400,0x0000,0x0000,0x3180,0x3300,0x0600,0x0c00,0x1980,0x3180,0x0000,0x0000,0x0000,
1878 0x0000,0x1c00,0x3300,0x3300,0x1f80,0x3300,0x3300,0x1d80,0x0000,0x0000,0x0000,0x0e00,0x0c00,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,
1879 0x0000,0x0000,0x0600,0x0c00,0x1800,0x1800,0x1800,0x0c00,0x0600,0x0000,0x0000,0x0000,0x1800,0x0c00,0x0600,0x0600,0x0600,0x0c00,0x1800,
1880 0x0000,0x0000,0x0000,0x0000,0x3300,0x1e00,0x7f80,0x1e00,0x3300,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x3f00,0x0c00,0x0c00,
1881 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0000,
1882 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0180,0x0300,0x0600,0x0c00,
1883 0x1800,0x3000,0x6000,0x0000,0x0000,0x0000,0x1f00,0x3380,0x3780,0x3f80,0x3d80,0x3980,0x1f00,0x0000,0x0000,0x0000,0x0c00,0x1c00,0x0c00,
1884 0x0c00,0x0c00,0x0c00,0x3f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x0180,0x0f00,0x1800,0x3180,0x3f80,0x0000,0x0000,0x0000,0x1f00,0x3180,
1885 0x0180,0x0700,0x0180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x0700,0x0f00,0x1b00,0x3300,0x3f80,0x0300,0x0780,0x0000,0x0000,0x0000,0x3f80,
1886 0x3000,0x3000,0x3f00,0x0180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x0f00,0x1800,0x3000,0x3f00,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,
1887 0x3f80,0x3180,0x0180,0x0300,0x0600,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x1f00,0x3180,0x3180,0x1f00,0x0000,0x0000,
1888 0x0000,0x1f00,0x3180,0x3180,0x1f80,0x0180,0x0300,0x1e00,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0c00,0x0c00,0x0000,
1889 0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0c00,0x0c00,0x1800,0x0000,0x0000,0x0300,0x0600,0x0c00,0x1800,0x0c00,0x0600,0x0300,
1890 0x0000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x1800,0x0c00,0x0600,0x0300,0x0600,0x0c00,
1891 0x1800,0x0000,0x0000,0x0000,0x1e00,0x3300,0x0300,0x0300,0x0600,0x0c00,0x0000,0x0c00,0x0000,0x0000,0x3f00,0x6180,0x6780,0x6d80,0x6780,
1892 0x6000,0x3f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3f80,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,
1893 0x3180,0x3180,0x3f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3000,0x3000,0x3180,0x1f00,0x0000,0x0000,0x0000,0x3e00,0x3300,0x3180,
1894 0x3180,0x3180,0x3300,0x3e00,0x0000,0x0000,0x0000,0x3f80,0x3000,0x3000,0x3f00,0x3000,0x3000,0x3f80,0x0000,0x0000,0x0000,0x3f80,0x3000,
1895 0x3000,0x3f00,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3380,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x3180,
1896 0x3180,0x3180,0x3f80,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x1e00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0000,
1897 0x0700,0x0300,0x0300,0x0300,0x3300,0x3300,0x1e00,0x0000,0x0000,0x0000,0x3180,0x3180,0x3300,0x3e00,0x3300,0x3180,0x3180,0x0000,0x0000,
1898 0x0000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3f80,0x0000,0x0000,0x0000,0x6180,0x7380,0x7f80,0x6d80,0x6180,0x6180,0x6180,0x0000,
1899 0x0000,0x0000,0x3180,0x3980,0x3d80,0x3780,0x3380,0x3180,0x3180,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x3180,0x3180,0x1f00,
1900 0x0000,0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x3180,0x3380,
1901 0x1f00,0x0380,0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,0x3300,0x3180,0x3180,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x1f00,0x0180,
1902 0x3180,0x1f00,0x0000,0x0000,0x0000,0x7f80,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,0x3180,
1903 0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,0x3180,0x1b00,0x0e00,0x0400,0x0000,0x0000,0x0000,0x6180,0x6180,0x6180,
1904 0x6d80,0x7f80,0x7380,0x6180,0x0000,0x0000,0x0000,0x6180,0x3300,0x1e00,0x0c00,0x1e00,0x3300,0x6180,0x0000,0x0000,0x0000,0x6180,0x6180,
1905 0x3300,0x1e00,0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x3f80,0x0300,0x0600,0x0c00,0x1800,0x3000,0x3f80,0x0000,0x0000,0x0000,0x1e00,
1906 0x1800,0x1800,0x1800,0x1800,0x1800,0x1e00,0x0000,0x0000,0x0000,0x6000,0x3000,0x1800,0x0c00,0x0600,0x0300,0x0000,0x0000,0x0000,0x0000,
1907 0x1e00,0x0600,0x0600,0x0600,0x0600,0x0600,0x1e00,0x0000,0x0000,0x0000,0x0400,0x0e00,0x1b00,0x3180,0x0000,0x0000,0x0000,0x0000,0x0000,
1908 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffc0,0x0000,0x0000,0x1c00,0x0c00,0x0600,0x0000,0x0000,0x0000,0x0000,0x0000,
1909 0x0000,0x0000,0x0000,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0000,0x3000,0x3000,0x3f00,0x3180,0x3180,0x3180,0x3f00,
1910 0x0000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3180,0x1f00,0x0000,0x0000,0x0000,0x0180,0x0180,0x1f80,0x3180,0x3180,0x3180,
1911 0x1f80,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,0x0000,0x0000,0x0000,0x0f00,0x1800,0x1800,0x3e00,0x1800,
1912 0x1800,0x1800,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3180,0x3180,0x3180,0x1f80,0x0180,0x1f00,0x0000,0x3000,0x3000,0x3f00,0x3180,
1913 0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x0c00,0x0000,0x1c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0000,0x0600,0x0000,0x0e00,
1914 0x0600,0x0600,0x0600,0x0600,0x0600,0x1c00,0x0000,0x3000,0x3000,0x3180,0x3300,0x3e00,0x3300,0x3180,0x0000,0x0000,0x0000,0x1c00,0x0c00,
1915 0x0c00,0x0c00,0x0c00,0x0c00,0x0700,0x0000,0x0000,0x0000,0x0000,0x0000,0x3300,0x7f80,0x6d80,0x6d80,0x6180,0x0000,0x0000,0x0000,0x0000,
1916 0x0000,0x3f00,0x3180,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,
1917 0x0000,0x0000,0x3f00,0x3180,0x3180,0x3f00,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3180,0x3180,0x1f80,0x0180,0x01c0,0x0000,
1918 0x0000,0x0000,0x0000,0x3f00,0x3180,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3000,0x1f00,0x0180,0x3f00,0x0000,
1919 0x0000,0x0000,0x1800,0x1800,0x3e00,0x1800,0x1800,0x1800,0x0f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,
1920 0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x3180,0x1b00,0x0e00,0x0400,0x0000,0x0000,0x0000,0x0000,0x0000,0x6180,0x6d80,0x6d80,0x7f80,
1921 0x3300,0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x1b00,0x0e00,0x1b00,0x3180,0x0000,0x0000,0x0000,0x0000,0x0000,0x3180,0x3180,0x3180,
1922 0x1f80,0x0180,0x1f00,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0600,0x0c00,0x1800,0x3f00,0x0000,0x0000,0x0000,0x0e00,0x1800,0x1800,0x3000,
1923 0x1800,0x1800,0x0e00,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x1c00,0x0600,0x0600,
1924 0x0300,0x0600,0x0600,0x1c00,0x0000,0x0000,0x0000,0x0000,0x0000,0x3800,0x6d80,0x0700,0x0000,0x0000,0x0000,0x0000,0x0000,0x0400,0x0e00,
1925 0x1b00,0x3180,0x3180,0x3180,0x3f80,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3000,0x3000,0x3180,0x1f00,0x0c00,0x1800,0x0000,0x1b00,
1926 0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x0600,0x0c00,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,0x0000,0x0000,0x0e00,
1927 0x1b00,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,
1928 0x0c00,0x0600,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0e00,0x1b00,0x0e00,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,
1929 0x0000,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3000,0x3180,0x1f00,0x0c00,0x1800,0x0e00,0x1b00,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,
1930 0x0000,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x3180,0x3f80,0x3000,0x1f00,0x0000,0x0000,0x0c00,0x0600,0x0000,0x1f00,0x3180,0x3f80,0x3000,
1931 0x1f00,0x0000,0x0000,0x0000,0x3600,0x0000,0x1c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x1c00,0x3600,0x0000,0x1c00,0x0c00,0x0c00,
1932 0x0c00,0x1e00,0x0000,0x0000,0x1800,0x0c00,0x0000,0x1c00,0x0c00,0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x3180,
1933 0x3f80,0x3180,0x3180,0x0000,0x0000,0x0e00,0x1b00,0x0e00,0x1f00,0x3180,0x3f80,0x3180,0x3180,0x0000,0x0000,0x0600,0x0c00,0x0000,0x3f80,
1934 0x3000,0x3f00,0x3000,0x3f80,0x0000,0x0000,0x0000,0x0000,0x0000,0x3b80,0x0ec0,0x3fc0,0x6e00,0x3b80,0x0000,0x0000,0x0000,0x1f80,0x3600,
1935 0x6600,0x7f80,0x6600,0x6600,0x6780,0x0000,0x0000,0x0e00,0x1b00,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0000,0x1b00,
1936 0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0c00,0x0600,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0e00,
1937 0x1b00,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x0c00,0x0600,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,
1938 0x0000,0x1b00,0x0000,0x3180,0x3180,0x3180,0x1f80,0x0180,0x1f00,0x0000,0x0000,0x1b00,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,
1939 0x0000,0x0000,0x1b00,0x0000,0x3180,0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x0000,0x0000,0x0400,0x1f00,0x3580,0x3400,0x3580,0x1f00,
1940 0x0400,0x0000,0x0000,0x0f00,0x1980,0x1800,0x3e00,0x1800,0x1800,0x3000,0x3f80,0x0000,0x0000,0x6180,0x6180,0x3300,0x1e00,0x3f00,0x0c00,
1941 0x3f00,0x0c00,0x0000,0x0000,0x7f00,0x6180,0x6d80,0x6d80,0x7f00,0x6c00,0x6c00,0x6700,0x0000,0x0000,0x0700,0x0c00,0x0c00,0x1e00,0x0c00,
1942 0x0c00,0x0c00,0x3800,0x0000,0x0600,0x0c00,0x0000,0x1f00,0x0180,0x1f80,0x3180,0x1f80,0x0000,0x0000,0x0c00,0x1800,0x0000,0x1c00,0x0c00,
1943 0x0c00,0x0c00,0x1e00,0x0000,0x0000,0x0600,0x0c00,0x0000,0x1f00,0x3180,0x3180,0x3180,0x1f00,0x0000,0x0000,0x0600,0x0c00,0x0000,0x3180,
1944 0x3180,0x3180,0x3180,0x1f80,0x0000,0x0000,0x1d80,0x3700,0x0000,0x3f00,0x3180,0x3180,0x3180,0x3180,0x0000,0x0000,0x1d80,0x3700,0x0000,
1945 0x3980,0x3d80,0x3780,0x3380,0x3180,0x0000,0x0000,0x0000,0x1e00,0x0300,0x1f00,0x3300,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x1e00,
1946 0x3300,0x3300,0x3300,0x1e00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0000,0x0c00,0x1800,0x3000,0x3000,0x3300,0x1e00,0x0000,0x0000,
1947 0x0000,0x0000,0x0000,0x3f80,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f80,0x0180,0x0180,0x0180,0x0000,0x0000,
1948 0x0000,0x2080,0x2100,0x2200,0x2400,0x0b00,0x1180,0x2300,0x4380,0x0000,0x0000,0x2080,0x2100,0x2200,0x2400,0x0a80,0x1280,0x2380,0x4080,
1949 0x0000,0x0000,0x0c00,0x0000,0x0c00,0x0c00,0x1e00,0x1e00,0x0c00,0x0000,0x0000,0x0000,0x0000,0x1980,0x3300,0x6600,0x3300,0x1980,0x0000,
1950 0x0000,0x0000,0x0000,0x0000,0x6600,0x3300,0x1980,0x3300,0x6600,0x0000,0x0000,0x0000,0x2200,0x8880,0x2200,0x8880,0x2200,0x8880,0x2200,
1951 0x8880,0x2200,0x8880,0x5540,0xaa80,0x5540,0xaa80,0x5540,0xaa80,0x5540,0xaa80,0x5540,0xaa80,0xbb80,0xeec0,0xbb80,0xeec0,0xbb80,0xeec0,
1952 0xbb80,0xeec0,0xbb80,0xeec0,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0xfc00,
1953 0xfc00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0xfc00,0xfc00,0x0c00,0x0c00,0xfc00,0xfc00,0x0c00,0x0c00,0x3300,0x3300,0x3300,0x3300,
1954 0xf300,0xf300,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,0x0000,0x0000,0xff00,0xff00,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,0xfc00,
1955 0xfc00,0x0c00,0x0c00,0xfc00,0xfc00,0x0c00,0x0c00,0x3300,0x3300,0xf300,0xf300,0x0300,0x0300,0xf300,0xf300,0x3300,0x3300,0x3300,0x3300,
1956 0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,0xff00,0xff00,0x0300,0x0300,0xf300,0xf300,0x3300,0x3300,0x3300,
1957 0x3300,0xf300,0xf300,0x0300,0x0300,0xff00,0xff00,0x0000,0x0000,0x3300,0x3300,0x3300,0x3300,0xff00,0xff00,0x0000,0x0000,0x0000,0x0000,
1958 0x1800,0x1800,0xf800,0xf800,0x1800,0x1800,0xf800,0xf800,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xfc00,0xfc00,0x0c00,0x0c00,0x0c00,
1959 0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0xffc0,0xffc0,0x0000,0x0000,
1960 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffc0,0xffc0,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,
1961 0x0c00,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0c00,0x0c00,0xffc0,0xffc0,
1962 0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x3300,0x3300,0x3300,0x3300,0x33c0,
1963 0x33c0,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x33c0,0x33c0,0x3000,0x3000,0x3fc0,0x3fc0,0x0000,0x0000,0x0000,0x0000,0x3fc0,0x3fc0,
1964 0x3000,0x3000,0x33c0,0x33c0,0x3300,0x3300,0x3300,0x3300,0xf3c0,0xf3c0,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,0xffc0,
1965 0xffc0,0x0000,0x0000,0xf3c0,0xf3c0,0x3300,0x3300,0x3300,0x3300,0x33c0,0x33c0,0x3000,0x3000,0x33c0,0x33c0,0x3300,0x3300,0x0000,0x0000,
1966 0xffc0,0xffc0,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x3300,0x3300,0xf3c0,0xf3c0,0x0000,0x0000,0xf3c0,0xf3c0,0x3300,0x3300,0x0c00,
1967 0x0c00,0xffc0,0xffc0,0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0x3300,0x3300,0x3300,0x3300,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,
1968 0x0000,0x0000,0xffc0,0xffc0,0x0000,0x0000,0xffc0,0xffc0,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0xffc0,0xffc0,0x3300,0x3300,0x3300,
1969 0x3300,0x3300,0x3300,0x3300,0x3300,0x3fc0,0x3fc0,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0fc0,0x0fc0,
1970 0x0000,0x0000,0x0000,0x0000,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0x3fc0,0x3fc0,0x3300,
1971 0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0x3300,0xf3c0,0xf3c0,0x3300,0x3300,0x3300,0x3300,0x0c00,0x0c00,0xffc0,0xffc0,0x0000,0x0000,
1972 0xffc0,0xffc0,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0xfc00,0xfc00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0fc0,
1973 0x0fc0,0x0c00,0x0c00,0x0c00,0x0c00,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,
1974 0x0000,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0x07c0,0x07c0,0x07c0,
1975 0x07c0,0x07c0,0x07c0,0x07c0,0x07c0,0x07c0,0x07c0,0xffc0,0xffc0,0xffc0,0xffc0,0xffc0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
1976 0x0000,0x1d80,0x3700,0x3200,0x3700,0x1d80,0x0000,0x0000,0x0000,0x1e00,0x3300,0x3300,0x3600,0x3300,0x3180,0x3700,0x3000,0x0000,0x0000,
1977 0x3f80,0x3180,0x3000,0x3000,0x3000,0x3000,0x3000,0x0000,0x0000,0x0000,0x0000,0x7f80,0x3300,0x3300,0x3300,0x3300,0x3300,0x0000,0x0000,
1978 0x0000,0x3f80,0x1800,0x0c00,0x0600,0x0c00,0x1800,0x3f80,0x0000,0x0000,0x0000,0x0000,0x0000,0x1f80,0x3600,0x3300,0x3300,0x1e00,0x0000,
1979 0x0000,0x0000,0x0000,0x0000,0x6300,0x6300,0x6700,0x7d80,0x6000,0x6000,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0c00,0x0c00,0x0c00,0x0600,
1980 0x0000,0x0000,0x0000,0x1e00,0x0c00,0x3f00,0x6d80,0x6d80,0x3f00,0x0c00,0x1e00,0x0000,0x0000,0x1e00,0x3300,0x3300,0x3f00,0x3300,0x3300,
1981 0x1e00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,0x3180,0x3180,0x1b00,0x3b80,0x0000,0x0000,0x0000,0x1f00,0x0c00,0x0600,0x1f00,0x3180,
1982 0x3180,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x3b80,0x66c0,0x64c0,0x6cc0,0x3b80,0x0000,0x0000,0x0000,0x0000,0x0180,0x3f00,0x6780,
1983 0x6d80,0x7980,0x3f00,0x6000,0x0000,0x0000,0x0000,0x0000,0x1f00,0x3000,0x1e00,0x3000,0x1f00,0x0000,0x0000,0x0000,0x1f00,0x3180,0x3180,
1984 0x3180,0x3180,0x3180,0x3180,0x0000,0x0000,0x0000,0x0000,0x3f00,0x0000,0x3f00,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,
1985 0x3f00,0x0c00,0x0c00,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0600,0x0c00,0x1800,0x0c00,0x0600,0x0000,0x3f00,0x0000,0x0000,0x0000,0x1800,
1986 0x0c00,0x0600,0x0c00,0x1800,0x0000,0x3f00,0x0000,0x0000,0x0000,0x0700,0x0d80,0x0d80,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,
1987 0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x6c00,0x6c00,0x3800,0x0000,0x0000,0x0000,0x0c00,0x0000,0x3f00,0x0000,0x0c00,0x0000,0x0000,0x0000,
1988 0x0000,0x3800,0x6d80,0x0700,0x0000,0x3800,0x6d80,0x0700,0x0000,0x0000,0x0000,0x0e00,0x1b00,0x1b00,0x0e00,0x0000,0x0000,0x0000,0x0000,
1989 0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0c00,0x0000,0x0000,0x0000,
1990 0x0000,0x0000,0x0000,0x07c0,0x0600,0x0600,0x6600,0x3600,0x1e00,0x0e00,0x0600,0x0200,0x0000,0x3e00,0x3300,0x3300,0x3300,0x3300,0x0000,
1991 0x0000,0x0000,0x0000,0x0000,0x1e00,0x0300,0x0e00,0x1800,0x1f00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1e00,0x1e00,0x1e00,
1992 0x1e00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
1995 // bits 0..3: width
1996 // bits 4..7: lshift
1997 public immutable ubyte[256] kgiFont6PropWidth = () {
1998 ubyte[256] res;
1999 foreach (immutable cnum; 0..256) {
2000 import core.bitop : bsf, bsr;
2001 immutable doshift =
2002 (cnum >= 32 && cnum <= 127) ||
2003 (cnum >= 143 && cnum <= 144) ||
2004 (cnum >= 166 && cnum <= 167) ||
2005 (cnum >= 192 && cnum <= 255);
2006 int shift = 0;
2007 if (doshift) {
2008 shift = 8;
2009 foreach (immutable dy; 0..8) {
2010 immutable b = kgiFont6[cnum*8+dy];
2011 if (b) {
2012 immutable mn = 7-bsr(b);
2013 if (mn < shift) shift = mn;
2017 ubyte wdt = 0;
2018 foreach (immutable dy; 0..8) {
2019 immutable b = (kgiFont6[cnum*8+dy]<<shift);
2020 immutable cwdt = (b ? 8-bsf(b) : 0);
2021 if (cwdt > wdt) wdt = cast(ubyte)cwdt;
2023 switch (cnum) {
2024 case 0: wdt = 8; break; // 8px space
2025 case 32: wdt = 5; break; // 5px space
2026 case 17: .. case 27: wdt = 8; break; // single frames
2027 case 48: .. case 57: wdt = 5; break; // digits are monospaced
2028 case 127: .. case 142: wdt = 8; break; // filled frames
2029 case 145: .. case 151: wdt = 8; break; // filled frames
2030 case 155: .. case 159: wdt = 8; break; // filled frames
2031 default:
2033 res[cnum] = (wdt&0x0f)|((shift<<4)&0xf0);
2035 return res;
2036 }();
2038 // bits 0..3: width
2039 // bits 4..7: lshift
2040 public immutable ubyte[256] kgiFont8PropWidth = () {
2041 ubyte[256] res;
2042 foreach (immutable cnum; 0..256) {
2043 import core.bitop : bsf, bsr;
2044 immutable doshift =
2045 (cnum >= 32 && cnum <= 127) ||
2046 (cnum >= 143 && cnum <= 144) ||
2047 (cnum >= 166 && cnum <= 167) ||
2048 (cnum >= 192 && cnum <= 255);
2049 int shift = 0;
2050 if (doshift) {
2051 shift = 8;
2052 foreach (immutable dy; 0..8) {
2053 immutable b = kgiFont8[cnum*8+dy];
2054 if (b) {
2055 immutable mn = 7-bsr(b);
2056 if (mn < shift) shift = mn;
2060 ubyte wdt = 0;
2061 foreach (immutable dy; 0..8) {
2062 immutable b = (kgiFont8[cnum*8+dy]<<shift);
2063 immutable cwdt = (b ? 8-bsf(b) : 0);
2064 if (cwdt > wdt) wdt = cast(ubyte)cwdt;
2066 switch (cnum) {
2067 case 0: wdt = 8; break; // 8px space
2068 case 32: wdt = 5; break; // 5px space
2069 case 48: .. case 57: wdt = 5; break; // digits are monospaced
2070 case 176: .. case 223: wdt = 8; break; // pseudographics (frames, etc)
2071 default:
2073 res[cnum] = (wdt&0x0f)|((shift<<4)&0xf0);
2075 return res;
2076 }();
2079 // ////////////////////////////////////////////////////////////////////////// //
2080 private:
2082 const(char)[] sdrGetPart(string typepfx) (const(char)[] s) nothrow @trusted @nogc {
2083 // skips prefix "---"
2084 static usize findMark(string at) (const(char)[] s, uint idx=0) nothrow @trusted @nogc {
2085 while (idx < s.length) {
2086 if (idx == 0 || s.ptr[idx-1] == '\n') {
2087 while (idx < s.length && (s.ptr[idx] == ' ' || s.ptr[idx] == '\t')) ++idx;
2088 if (s.length-idx >= 3 && s.ptr[idx] == '-' && s.ptr[idx+1] == '-' && s.ptr[idx+2] == '-') {
2089 static if (at == "start") {
2090 while (idx > 0 && s.ptr[idx-1] != '\n') --idx;
2091 } else static if (at == "end") {
2092 idx += 3;
2093 while (idx < s.length && s.ptr[idx] == '-') ++idx;
2094 while (idx < s.length && (s.ptr[idx] == ' ' || s.ptr[idx] == '\t')) ++idx;
2095 } else {
2096 static assert(0, "wtf?!");
2098 return idx;
2101 ++idx;
2103 return idx;
2106 usize idx = findMark!"end"(s);
2107 while (idx < s.length) {
2108 if (s.length-idx >= typepfx.length && s[idx..idx+typepfx.length] == typepfx) {
2109 while (idx < s.length && s.ptr[idx] != '\n') ++idx;
2110 while (idx < s.length && s.ptr[idx] <= ' ') ++idx;
2111 if (idx >= s.length) return null;
2112 auto eidx = findMark!"start"(s, idx);
2113 if (eidx > s.length) eidx = s.length;
2114 while (eidx > idx && s.ptr[eidx-1] <= ' ') --eidx;
2115 return (eidx > idx ? s[idx..eidx] : null);
2116 } else {
2117 while (idx < s.length && s.ptr[idx] != '\n') ++idx;
2118 idx = findMark!"end"(s, idx);
2121 return null;
2125 // find var id: glGetUniformLocation(prg, bufasciiz.ptr)
2126 // set var: glUniformXXX()
2128 // returns 0 or programid
2129 uint compileShaders (const(char)[] src) nothrow @trusted {
2130 import iv.glbinds;
2132 GLuint prg = 0;
2133 GLuint fsid = 0, vsid = 0;
2135 auto fragsrc = sdrGetPart!"frag"(src);
2136 auto vertsrc = sdrGetPart!"vert"(src);
2138 if (fragsrc.length == 0 && vertsrc.length == 0) return 0;
2140 if (fragsrc.length) {
2141 fsid = createShader!GL_FRAGMENT_SHADER(fragsrc);
2142 if (fsid == 0) return 0;
2145 if (vertsrc.length) {
2146 vsid = createShader!GL_VERTEX_SHADER(vertsrc);
2147 if (vsid == 0) {
2148 if (fsid != 0) glDeleteShader(fsid);
2149 return 0;
2153 prg = glCreateProgram();
2154 if (prg == 0) {
2155 if (fsid != 0) glDeleteShader(fsid);
2156 if (vsid != 0) glDeleteShader(vsid);
2157 conwriteln("GLKGI ERROR: can't create shader program.");
2158 return 0;
2161 if (fsid) glAttachShader(prg, fsid);
2162 if (vsid) glAttachShader(prg, vsid);
2163 glLinkProgram(prg);
2165 GLint lres = 0;
2166 glGetProgramiv(prg, GL_LINK_STATUS, &lres);
2167 if (lres != GL_TRUE) {
2168 glDeleteProgram(prg);
2169 if (fsid != 0) glDeleteShader(fsid);
2170 if (vsid != 0) glDeleteShader(vsid);
2171 conwriteln("GLKGI ERROR: can't link shader program.");
2172 return 0;
2175 return prg;
2179 // returns 0 or shaderid
2180 uint createShader(uint type) (const(char)[] src) nothrow @trusted {
2181 import iv.glbinds;
2183 auto shaderId = glCreateShader(type);
2184 if (!shaderId) {
2185 conwriteln("GLKGI ERROR: can't create shader.");
2186 return 0;
2188 auto sptr = src.ptr;
2189 GLint slen = cast(int)src.length;
2190 glShaderSource(shaderId, 1, &sptr, &slen);
2191 glCompileShader(shaderId);
2192 GLint success = 0;
2193 glGetShaderiv(shaderId, GL_COMPILE_STATUS, &success);
2194 if (!success || showShaderWarnings) {
2195 import core.stdc.stdlib : malloc, free;
2196 GLint logSize = 0;
2197 glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &logSize);
2198 if (logSize > 0) {
2199 auto logStrZ = cast(GLchar*)malloc(logSize);
2200 if (logStrZ !is null) {
2201 //import core.stdc.stdio : printf;
2202 scope(exit) free(logStrZ);
2203 glGetShaderInfoLog(shaderId, logSize, null, logStrZ);
2204 if (logSize > 0 && logStrZ[logSize-1] == 0) --logSize;
2205 //printf("shader '%.*s' compilation messages:\n%s\n", cast(uint)ashaderName.length, ashaderName.ptr, logStrZ);
2206 conwriteln("GLKGI: shader compilation messages:\n", logStrZ[0..logSize]);
2210 if (!success) {
2211 glDeleteShader(shaderId);
2212 conwriteln("GLKGI ERROR: can't compile shader.");
2213 return 0;
2215 return shaderId;
2219 // ////////////////////////////////////////////////////////////////////////// //
2220 // shaders
2221 static string sdrScanlineSrc = q{
2222 ---frag---
2223 #version 120
2225 uniform sampler2D tex;
2227 void main () {
2228 vec4 color = texture2D(tex, gl_TexCoord[0].xy);
2229 if (mod(floor(gl_FragCoord.y), 2) == 1) { color.x *= 0.75; color.y *= 0.75; color.z *= 0.75; }
2230 gl_FragColor = color;
2233 ---vert---
2234 #version 120
2236 void main () {
2237 gl_TexCoord[0] = gl_MultiTexCoord0;
2238 //gl_Position = gl_ProjectionMatrix*gl_ModelViewMatrix*gl_Vertex;
2239 gl_Position = gl_ProjectionMatrix*gl_Vertex;
2244 // ////////////////////////////////////////////////////////////////////////// //
2245 // default cursor (hi, Death Track!)
2246 private enum defaultCurWidth = 17;
2247 private enum defaultCurHeight = 23;
2248 private static immutable ubyte[defaultCurWidth*defaultCurHeight] defaultCurImg = [
2249 0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2250 0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
2251 1,0,3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,
2252 1,1,3,3,2,2,0,0,0,0,0,0,0,0,0,0,0,
2253 1,1,3,3,4,2,2,0,0,0,0,0,0,0,0,0,0,
2254 1,1,3,3,4,4,2,2,0,0,0,0,0,0,0,0,0,
2255 1,1,3,3,4,4,4,2,2,0,0,0,0,0,0,0,0,
2256 1,1,3,3,4,4,4,4,2,2,0,0,0,0,0,0,0,
2257 1,1,3,3,4,4,4,5,6,2,2,0,0,0,0,0,0,
2258 1,1,3,3,4,4,5,6,7,5,2,2,0,0,0,0,0,
2259 1,1,3,3,4,5,6,7,5,4,5,2,2,0,0,0,0,
2260 1,1,3,3,5,6,7,5,4,5,6,7,2,2,0,0,0,
2261 1,1,3,3,6,7,5,4,5,6,7,7,7,2,2,0,0,
2262 1,1,3,3,7,5,4,5,6,7,7,7,7,7,2,2,0,
2263 1,1,3,3,5,4,5,6,8,8,8,8,8,8,8,8,2,
2264 1,1,3,3,4,5,6,3,8,8,8,8,8,8,8,8,8,
2265 1,1,3,3,5,6,3,3,1,1,1,1,1,1,1,0,0,
2266 1,1,3,3,6,3,3,1,1,1,1,1,1,1,1,0,0,
2267 1,1,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,
2268 1,1,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,
2269 1,1,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
2270 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2271 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2273 private static immutable VColor[9] defaultCurPal = [
2274 rgbacol( 0, 0, 0, 0),
2275 rgbacol( 0, 0, 0,127),
2276 rgbacol( 85,255,255,255),
2277 rgbacol( 85, 85,255,255),
2278 rgbacol(255, 85, 85,255),
2279 rgbacol(170, 0,170,255),
2280 rgbacol( 85, 85, 85,255),
2281 rgbacol( 0, 0, 0,255),
2282 rgbacol( 0, 0,170,255),