1 module x11gfx
is aliced
;
3 import arsd
.simpledisplay
;
7 // ////////////////////////////////////////////////////////////////////////// //
8 // 0:b; 1:g; 2:r; 3: nothing
9 __gshared
int vbufW
= 256, vbufH
= 192;
10 __gshared
uint[] vbuf
;
11 __gshared
bool blit2x
= true;
12 enum BlitType
{ Normal
, BlackWhite
, Green
}
13 __gshared
int blitType
= BlitType
.Normal
;
16 // ////////////////////////////////////////////////////////////////////////// //
17 final class X11Image
{
22 assert(w
> 0 && w
<= 4096);
23 assert(h
> 0 && h
<= 4096);
30 VColor
getPixel (int x
, int y
) const {
31 return (x
>= 0 && y
>= 0 && x
< width
&& y
< height ? data
[y
*width
+x
] : Transparent
);
34 void setPixel (int x
, int y
, VColor c
) {
35 if (x
>= 0 && y
>= 0 && x
< width
&& y
< height
) data
[y
*width
+x
] = c
;
38 void blitFast (int x
, int y
) const {
39 if (width
< 1 || height
< 1) return;
40 if (x
<= -width || y
<= -height
) return;
41 if (x
>= vbufW || y
>= vbufH
) return;
42 auto src
= cast(const(VColor
)*)data
.ptr
;
43 if (x
>= 0 && y
>= 0 && x
+width
< vbufW
&& y
+height
< vbufH
) {
44 auto d
= cast(uint*)vbuf
.ptr
;
46 foreach (int dy
; 0..height
) {
47 d
[0..width
] = src
[0..width
];
52 foreach (int dy
; 0..height
) {
53 foreach (int dx
; 0..width
) {
54 .setPixel(x
+dx
, y
+dy
, *src
++);
60 void blit (int x
, int y
) const {
61 if (width
< 1 || height
< 1) return;
62 if (x
<= -width || y
<= -height
) return;
63 if (x
>= vbufW || y
>= vbufH
) return;
64 auto src
= cast(const(VColor
)*)data
.ptr
;
65 foreach (int dy
; 0..height
) {
66 foreach (int dx
; 0..width
) {
67 putPixel(x
+dx
, y
+dy
, *src
++);
72 void blit2x (int x
, int y
) const {
73 if (width
< 1 || height
< 1) return;
74 if (x
<= -width || y
<= -height
) return;
75 if (x
>= vbufW || y
>= vbufH
) return;
76 auto src
= cast(const(VColor
)*)data
.ptr
;
77 foreach (immutable int dy
; 0..height
) {
78 foreach (immutable int dx
; 0..width
) {
79 putPixel(x
+dx
*2+0, y
+dy
*2+0, *src
);
80 putPixel(x
+dx
*2+1, y
+dy
*2+0, *src
);
81 putPixel(x
+dx
*2+0, y
+dy
*2+1, *src
);
82 putPixel(x
+dx
*2+1, y
+dy
*2+1, *src
);
88 private void blit2xImpl(string op
) (int x
, int y
) nothrow @trusted @nogc {
89 if (width
< 1 || height
< 1) return;
90 if (x
<= -width || y
<= -height
) return;
91 if (x
>= vbufW || y
>= vbufH
) return;
92 auto s
= cast(const(ubyte)*)data
.ptr
;
93 //auto d = cast(uint*)vscr2x;
94 foreach (immutable int dy
; 0..height
) {
95 foreach (immutable int dx
; 0..width
) {
96 static if (op
.length
) mixin(op
);
97 immutable uint c1
= ((((c0
&0x00ff00ff)*6)>>3)&0x00ff00ff)|
(((c0
&0x0000ff00)*6)>>3)&0x0000ff00;
98 putPixel(x
+dx
*2+0, y
+dy
*2+0, c0
);
99 putPixel(x
+dx
*2+1, y
+dy
*2+0, c0
);
100 putPixel(x
+dx
*2+0, y
+dy
*2+1, c1
);
101 putPixel(x
+dx
*2+1, y
+dy
*2+1, c1
);
107 alias blit2xTV
= blit2xImpl
!"immutable uint c0 = (cast(immutable(uint)*)s)[0];";
108 alias blit2xTVBW
= blit2xImpl
!"immutable ubyte i = cast(ubyte)((s[0]*28+s[1]*151+s[2]*77)/256); immutable uint c0 = (i<<16)|(i<<8)|i;";
109 alias blit2xTVGreen
= blit2xImpl
!"immutable ubyte i = cast(ubyte)((s[0]*28+s[1]*151+s[2]*77)/256); immutable uint c0 = i<<8;";
114 vbuf
.length
= vbufW
*vbufH
;
120 void blit2xImpl(string op
, bool scanlines
=true) (Image img
) {
121 static if (UsingSimpledisplayX11
) {
122 auto s
= cast(const(ubyte)*)vbuf
.ptr
;
123 immutable iw
= img
.width
;
124 auto dd = cast(uint*)img
.getDataPointer
;
125 foreach (immutable int dy
; 0..vbufH
) {
126 if (dy
*2+1 >= img
.height
) return;
127 auto d
= dd+iw
*(dy
*2);
128 foreach (immutable int dx
; 0..vbufW
) {
130 static if (op
.length
) mixin(op
);
131 static if (scanlines
) {
132 immutable uint c1
= ((((c0
&0x00ff00ff)*6)>>3)&0x00ff00ff)|
(((c0
&0x0000ff00)*6)>>3)&0x0000ff00;
137 d
[iw
+0] = d
[iw
+1] = c1
;
145 immutable bpp
= img
.bytesPerPixel();
146 immutable rofs
= img
.redByteOffset
;
147 immutable gofs
= img
.greenByteOffset
;
148 immutable bofs
= img
.blueByteOffset
;
149 immutable nlo
= img
.adjustmentForNextLine
;
150 auto s
= cast(const(ubyte)*)vbuf
.ptr
;
151 immutable iw
= img
.width
;
152 auto dd = cast(ubyte*)img
.getDataPointer
;
153 foreach (immutable int dy
; 0..vbufH
) {
154 if (dy
*2+1 >= img
.height
) return;
155 auto d
= dd+img
.offsetForPixel(0, dy
*2);
156 foreach (immutable int dx
; 0..vbufW
) {
158 static if (op
.length
) mixin(op
);
159 static if (scanlines
) {
160 immutable uint c1
= ((((c0
&0x00ff00ff)*6)>>3)&0x00ff00ff)|
(((c0
&0x0000ff00)*6)>>3)&0x0000ff00;
164 d
[bofs
] = d
[bofs
+bpp
] = c0
&0xff;
165 d
[gofs
] = d
[gofs
+bpp
] = (c0
>>8)&0xff;
166 d
[rofs
] = d
[rofs
+bpp
] = (c0
>>16)&0xff;
167 d
[bofs
+nlo
] = d
[bofs
+nlo
+bpp
] = c0
&0xff;
168 d
[gofs
+nlo
] = d
[gofs
+nlo
+bpp
] = (c0
>>8)&0xff;
169 d
[rofs
+nlo
] = d
[rofs
+nlo
+bpp
] = (c0
>>16)&0xff;
178 alias blit2xTV
= blit2xImpl
!"immutable uint c0 = (cast(immutable(uint)*)s)[0];";
179 alias blit2xTVBW
= blit2xImpl
!"immutable ubyte i = cast(ubyte)((s[0]*28+s[1]*151+s[2]*77)/256); immutable uint c0 = (i<<16)|(i<<8)|i;";
180 alias blit2xTVGreen
= blit2xImpl
!"immutable ubyte i = cast(ubyte)((s[0]*28+s[1]*151+s[2]*77)/256); immutable uint c0 = i<<8;";
184 void realizeVBuf (Image img
) {
187 auto dp = cast(uint*)img.getDataPointer;
188 import core.stdc.string : memcpy;
189 memcpy(dp, sp, vbufW*vbufH*4);
192 if (img
.width
< vbufW
*2 || img
.height
< vbufH
*2) return;
194 case BlitType
.BlackWhite
: blit2xTVBW(img
); break;
195 case BlitType
.Green
: blit2xTVGreen(img
); break;
196 default: blit2xTV(img
); break;
199 if (img
.width
< vbufW || img
.height
< vbufH
) return;
200 static if (UsingSimpledisplayX11
) {
201 auto dp
= cast(uint*)img
.getDataPointer
;
202 dp
[0..vbufW
*vbufH
] = vbuf
.ptr
[0..vbufW
*vbufH
];
205 auto sp
= cast(ubyte*)vbuf
.ptr
;
206 auto dp
= cast(ubyte*)img
.getDataPointer
;
207 immutable bpp
= img
.bytesPerPixel();
208 immutable rofs
= img
.redByteOffset
;
209 immutable gofs
= img
.greenByteOffset
;
210 immutable bofs
= img
.blueByteOffset
;
211 foreach (immutable y
; 0..vbufH
) {
212 auto d
= dp
+img
.offsetForTopLeftPixel
;
213 foreach (immutable x
; 0..vbufW
) {
226 // ////////////////////////////////////////////////////////////////////////// //
227 ubyte clampToByte(T
) (T n
) @safe pure nothrow @nogc
228 if (__traits(isIntegral
, T
) && (T
.sizeof
== 2 || T
.sizeof
== 4))
230 static if (__VERSION__
> 2067) pragma(inline
, true);
231 n
&= -cast(int)(n
>= 0);
232 return cast(ubyte)(n|
((255-cast(int)n
)>>31));
235 ubyte clampToByte(T
) (T n
) @safe pure nothrow @nogc
236 if (__traits(isIntegral
, T
) && T
.sizeof
== 1)
238 static if (__VERSION__
> 2067) pragma(inline
, true);
243 // ////////////////////////////////////////////////////////////////////////// //
246 /// vlRGBA struct to ease color components extraction/replacing
247 align(1) struct vlRGBA
{
251 static assert(vlRGBA
.sizeof
== VColor
.sizeof
);
255 vlAMask
= 0xff000000u
,
256 vlRMask
= 0x00ff0000u
,
257 vlGMask
= 0x0000ff00u
,
258 vlBMask
= 0x000000ffu
269 enum VColor Transparent
= vlAMask
; /// completely transparent pixel color
272 bool isTransparent(T
: VColor
) (T col
) @safe pure nothrow @nogc {
273 static if (__VERSION__
> 2067) pragma(inline
, true);
274 return ((col
&vlAMask
) == vlAMask
);
277 bool isOpaque(T
: VColor
) (T col
) @safe pure nothrow @nogc {
278 static if (__VERSION__
> 2067) pragma(inline
, true);
279 return ((col
&vlAMask
) == 0);
283 VColor
rgbcol(TR
, TG
, TB
, TA
=ubyte) (TR r
, TG g
, TB b
, TA a
=0) @safe pure nothrow @nogc
284 if (__traits(isIntegral
, TR
) && __traits(isIntegral
, TG
) && __traits(isIntegral
, TB
) && __traits(isIntegral
, TA
)) {
285 static if (__VERSION__
> 2067) pragma(inline
, true);
287 (clampToByte(a
)<<vlAShift
)|
288 (clampToByte(r
)<<vlRShift
)|
289 (clampToByte(g
)<<vlGShift
)|
290 (clampToByte(b
)<<vlBShift
);
293 alias rgbacol
= rgbcol
;
296 // generate some templates
297 private enum genRGBGetSet(string cname
) =
298 "ubyte rgb"~cname
~"() (VColor clr) @safe pure nothrow @nogc {\n"~
299 " static if (__VERSION__ > 2067) pragma(inline, true);\n"~
300 " return ((clr>>vl"~cname
[0]~"Shift)&0xff);\n"~
302 "VColor rgbSet"~cname
~"(T) (VColor clr, T v) @safe pure nothrow @nogc if (__traits(isIntegral, T)) {\n"~
303 " static if (__VERSION__ > 2067) pragma(inline, true);\n"~
304 " return (clr&~vl"~cname
[0]~"Mask)|(clampToByte(v)<<vl"~cname
[0]~"Shift);\n"~
307 mixin(genRGBGetSet
!"Alpha");
308 mixin(genRGBGetSet
!"Red");
309 mixin(genRGBGetSet
!"Green");
310 mixin(genRGBGetSet
!"Blue");
313 void putPixel(TX
, TY
) (TX x
, TY y
, VColor col
) @trusted
314 if (__traits(isIntegral
, TX
) && __traits(isIntegral
, TY
))
316 static if (__VERSION__
> 2067) pragma(inline
, true);
317 immutable long xx
= cast(long)x
;
318 immutable long yy
= cast(long)y
;
319 if ((col
&vlAMask
) != vlAMask
&& xx
>= 0 && yy
>= 0 && xx
< vbufW
&& yy
< vbufH
) {
320 uint* da = vbuf
.ptr
+yy
*vbufW
+xx
;
322 immutable uint a
= 256-(col
>>24); // to not loose bits
323 immutable uint dc
= (*da)&0xffffff;
324 immutable uint srb
= (col
&0xff00ff);
325 immutable uint sg
= (col
&0x00ff00);
326 immutable uint drb
= (dc
&0xff00ff);
327 immutable uint dg
= (dc
&0x00ff00);
328 immutable uint orb
= (drb
+(((srb
-drb
)*a
+0x800080)>>8))&0xff00ff;
329 immutable uint og
= (dg
+(((sg
-dg
)*a
+0x008000)>>8))&0x00ff00;
337 void setPixel(TX
, TY
) (TX x
, TY y
, VColor col
) @trusted
338 if (__traits(isIntegral
, TX
) && __traits(isIntegral
, TY
))
340 static if (__VERSION__
> 2067) pragma(inline
, true);
341 immutable long xx
= cast(long)x
;
342 immutable long yy
= cast(long)y
;
343 if (xx
>= 0 && yy
>= 0 && xx
< vbufW
&& yy
< vbufH
) {
344 uint* da = vbuf
.ptr
+yy
*vbufW
+xx
;
350 void drawLine(bool lastPoint
=true) (int x0
, int y0
, int x1
, int y1
, immutable VColor col
) {
351 enum swap(string a
, string b
) = "{int tmp_="~a
~";"~a
~"="~b
~";"~b
~"=tmp_;}";
353 if ((col
&vlAMask
) == vlAMask
) return;
355 if (x0
== x1
&& y0
== y1
) {
356 static if (lastPoint
) putPixel(x0
, y0
, col
);
361 int wx0
= 0, wy0
= 0, wx1
= vbufW
-1, wy1
= vbufH
-1;
363 int stx
, sty
; // "steps" for x and y axes
364 int dsx
, dsy
; // "lengthes" for x and y axes
365 int dx2
, dy2
; // "double lengthes" for x and y axes
366 int xd
, yd
; // current coord
367 int e
; // "error" (as in bresenham algo)
373 // from left to right
374 if (x0
> wx1 || x1
< wx0
) return; // out of screen
375 stx
= 1; // going right
377 // from right to left
378 if (x1
> wx1 || x0
< wx0
) return; // out of screen
379 stx
= -1; // going left
384 mixin(swap
!("wx0", "wx1"));
388 // from top to bottom
389 if (y0
> wy1 || y1
< wy0
) return; // out of screen
390 sty
= 1; // going down
392 // from bottom to top
393 if (y1
> wy1 || y0
< wy0
) return; // out of screen
394 sty
= -1; // going up
399 mixin(swap
!("wy0", "wy1"));
406 mixin(swap
!("x0", "y0"));
407 mixin(swap
!("x1", "y1"));
408 mixin(swap
!("dsx", "dsy"));
409 mixin(swap
!("wx0", "wy0"));
410 mixin(swap
!("wx1", "wy1"));
411 mixin(swap
!("stx", "sty"));
425 int temp
= dx2
*(wy0
-y0
)-dsx
;
428 if (xd
> wx1
) return; // x is moved out of clipping rect, nothing to do
432 if (rem
> 0) { ++xd
; e
+= dy2
; }
436 if (!xfixed
&& x0
< wx0
) {
438 int temp
= dy2
*(wx0
-x0
);
441 if (yd
> wy1 || yd
== wy1
&& rem
>= dsx
) return;
444 if (rem
>= dsx
) { ++yd
; e
-= dx2
; }
448 int temp
= dx2
*(wy1
-y0
)+dsx
;
451 if (rem
== 0) --term
;
453 if (term
> wx1
) term
= wx1
; // clip at right
454 static if (lastPoint
) {
458 if (term
== xd
) return; // this is the only point, get out of here
460 if (sty
== -1) yd
= -yd
;
461 if (stx
== -1) { xd
= -xd
; term
= -term
; }
463 // draw it; `putPixel()` can omit checks
465 // inlined `putPixel(*d0, *d1, col)`
466 // this can be made even faster by precalculating `da` and making
467 // separate code branches for mixing and non-mixing drawing, but...
469 uint* da = vbuf
.ptr
+(*d1
)*vbufW
+(*d0
);
471 immutable uint a
= 256-(col
>>24); // to not loose bits
472 immutable uint dc
= (*da)&0xffffff;
473 immutable uint srb
= (col
&0xff00ff);
474 immutable uint sg
= (col
&0x00ff00);
475 immutable uint drb
= (dc
&0xff00ff);
476 immutable uint dg
= (dc
&0x00ff00);
477 immutable uint orb
= (drb
+(((srb
-drb
)*a
+0x800080)>>8))&0xff00ff;
478 immutable uint og
= (dg
+(((sg
-dg
)*a
+0x008000)>>8))&0x00ff00;
483 // done drawing, move coords
495 // //////////////////////////////////////////////////////////////////////// //
497 * Draw character onto virtual screen in KOI8 encoding.
505 * col = foreground color
506 * bkcol = background color
511 void drawCharWdt (int x
, int y
, int wdt
, int shift
, char ch
, VColor col
, VColor bkcol
=Transparent
) @trusted {
513 if (wdt
< 1 || shift
>= 8) return;
514 if (col
== Transparent
&& bkcol
== Transparent
) return;
515 if (wdt
> 8) wdt
= 8;
516 if (shift
< 0) shift
= 0;
517 foreach (immutable int dy
; 0..8) {
518 ubyte b
= cast(ubyte)(vlFont6
[pos
++]<<shift
);
519 foreach (immutable int dx
; 0..wdt
) {
520 VColor c
= (b
&0x80 ? col
: bkcol
);
521 if (!isTransparent(c
)) putPixel(x
+dx
, y
+dy
, c
);
533 OutLU
= 0x10, // left-up
534 OutRU
= 0x20, // right-up
535 OutLD
= 0x40, // left-down
536 OutRD
= 0x80, // right-down
541 * Draw outlined character onto virtual screen in KOI8 encoding.
549 * col = foreground color
550 * outcol = outline color
551 * ot = outline type, OutXXX, ored
556 void drawCharWdtOut (int x
, int y
, int wdt
, int shift
, char ch
, VColor col
, VColor outcol
=Transparent
, ubyte ot
=0) @trusted {
557 if (col
== Transparent
&& outcol
== Transparent
) return;
558 if (ot
== 0 || outcol
== Transparent
) {
559 // no outline? simple draw
560 drawCharWdt(x
, y
, wdt
, shift
, ch
, col
, Transparent
);
564 if (wdt
< 1 || shift
>= 8) return;
565 if (wdt
> 8) wdt
= 8;
566 if (shift
< 0) shift
= 0;
567 ubyte[8+2][8+2] bmp
= 0; // char bitmap; 0: empty; 1: char; 2: outline
568 foreach (immutable dy
; 1..9) {
569 ubyte b
= cast(ubyte)(vlFont6
[pos
++]<<shift
);
570 foreach (immutable dx
; 1..wdt
+1) {
575 if ((ot
&OutUp
) && bmp
[dy
-1][dx
] == 0) bmp
[dy
-1][dx
] = 2;
576 if ((ot
&OutDown
) && bmp
[dy
+1][dx
] == 0) bmp
[dy
+1][dx
] = 2;
577 if ((ot
&OutLeft
) && bmp
[dy
][dx
-1] == 0) bmp
[dy
][dx
-1] = 2;
578 if ((ot
&OutRight
) && bmp
[dy
][dx
+1] == 0) bmp
[dy
][dx
+1] = 2;
579 if ((ot
&OutLU
) && bmp
[dy
-1][dx
-1] == 0) bmp
[dy
-1][dx
-1] = 2;
580 if ((ot
&OutRU
) && bmp
[dy
-1][dx
+1] == 0) bmp
[dy
-1][dx
+1] = 2;
581 if ((ot
&OutLD
) && bmp
[dy
+1][dx
-1] == 0) bmp
[dy
+1][dx
-1] = 2;
582 if ((ot
&OutRD
) && bmp
[dy
+1][dx
+1] == 0) bmp
[dy
+1][dx
+1] = 2;
590 foreach (immutable int dy
; 0..10) {
591 foreach (immutable int dx
; 0..10) {
592 if (auto t
= bmp
[dy
][dx
]) putPixel(x
+dx
, y
+dy
, (t
== 1 ? col
: outcol
));
598 * Draw 6x8 character onto virtual screen in KOI8 encoding.
604 * col = foreground color
605 * bkcol = background color
610 void drawChar (int x
, int y
, char ch
, VColor col
, VColor bkcol
=Transparent
) @trusted {
611 drawCharWdt(x
, y
, 6, 0, ch
, col
, bkcol
);
614 void drawCharOut (int x
, int y
, char ch
, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
615 drawCharWdtOut(x
, y
, 6, 0, ch
, col
, outcol
, ot
);
618 void drawStr (int x
, int y
, string
str, VColor col
, VColor bkcol
=Transparent
) @trusted {
619 foreach (immutable char ch
; str) {
620 drawChar(x
, y
, ch
, col
, bkcol
);
625 void drawStrOut (int x
, int y
, string
str, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
626 foreach (immutable char ch
; str) {
627 drawCharOut(x
, y
, ch
, col
, outcol
, ot
);
632 static int charWidthProp (char ch
) @trusted pure { return (vlFontPropWidth
[ch
]&0x0f); }
634 int strWidthProp (string
str) @trusted pure {
636 foreach (immutable char ch
; str) wdt
+= (vlFontPropWidth
[ch
]&0x0f)+1;
637 if (wdt
> 0) --wdt
; // don't count last empty pixel
641 int drawCharProp (int x
, int y
, char ch
, VColor col
, VColor bkcol
=Transparent
) @trusted {
642 immutable int wdt
= (vlFontPropWidth
[ch
]&0x0f);
643 drawCharWdt(x
, y
, wdt
, vlFontPropWidth
[ch
]>>4, ch
, col
, bkcol
);
647 int drawCharPropOut (int x
, int y
, char ch
, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
648 immutable int wdt
= (vlFontPropWidth
[ch
]&0x0f);
649 drawCharWdtOut(x
, y
, wdt
, vlFontPropWidth
[ch
]>>4, ch
, col
, outcol
, ot
);
653 int drawStrProp (int x
, int y
, string
str, VColor col
, VColor bkcol
=Transparent
) @trusted {
656 foreach (immutable char ch
; str) {
658 if (!isTransparent(bkcol
)) foreach (int dy
; 0..8) putPixel(x
, y
+dy
, bkcol
);
662 x
+= drawCharProp(x
, y
, ch
, col
, bkcol
);
667 int drawStrPropOut (int x
, int y
, string
str, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
669 foreach (immutable char ch
; str) {
670 x
+= drawCharPropOut(x
, y
, ch
, col
, outcol
, ot
)+1;
672 if (x
> sx
) --x
; // don't count last empty pixel
676 // ////////////////////////////////////////////////////////////////////////// //
677 void clear (VColor col
) @trusted {
678 vbuf
.ptr
[0..vbufW
*vbufH
] = col
;
682 // ////////////////////////////////////////////////////////////////////////// //
683 public immutable ubyte[256*8] vlFont6
= [
2992 // bits 4..7: lshift
2993 public immutable ubyte[256] vlFontPropWidth
= () {
2995 foreach (immutable cnum
; 0..256) {
2996 import core
.bitop
: bsf, bsr;
2998 (cnum
>= 32 && cnum
<= 127) ||
2999 (cnum
>= 143 && cnum
<= 144) ||
3000 (cnum
>= 166 && cnum
<= 167) ||
3001 (cnum
>= 192 && cnum
<= 255);
3005 foreach (immutable dy
; 0..8) {
3006 immutable b
= vlFont6
[cnum
*8+dy
];
3008 immutable mn
= 7-bsr(b
);
3009 if (mn
< shift
) shift
= mn
;
3014 foreach (immutable dy
; 0..8) {
3015 immutable b
= (vlFont6
[cnum
*8+dy
]<<shift
);
3016 immutable cwdt
= (b ?
8-bsf(b
) : 0);
3017 if (cwdt
> wdt
) wdt
= cast(ubyte)cwdt
;
3020 case 0: wdt
= 8; break; // 8px space
3021 case 32: wdt
= 5; break; // 5px space
3022 case 17: .. case 27: wdt
= 8; break; // single frames
3023 case 48: .. case 57: wdt
= 5; break; // digits are monospaced
3024 case 127: .. case 142: wdt
= 8; break; // filled frames
3025 case 145: .. case 151: wdt
= 8; break; // filled frames
3026 case 155: .. case 159: wdt
= 8; break; // filled frames
3029 res
[cnum
] = (wdt
&0x0f)|
((shift
<<4)&0xf0);