1 module x11gfx
is aliced
;
3 import arsd
.simpledisplay
;
7 // ////////////////////////////////////////////////////////////////////////// //
13 assert(w
> 0 && w
<= 4096);
14 assert(h
> 0 && h
<= 4096);
21 VColor
getPixel (int x
, int y
) const {
22 return (x
>= 0 && y
>= 0 && x
< width
&& y
< height ? data
[y
*width
+x
] : Transparent
);
25 void setPixel (int x
, int y
, VColor c
) {
26 if (x
>= 0 && y
>= 0 && x
< width
&& y
< height
) data
[y
*width
+x
] = c
;
29 void blit (int x
, int y
) const {
30 if (width
< 1 || height
< 1) return;
31 if (x
<= -width || y
<= -height
) return;
32 if (x
>= vbufW || y
>= vbufH
) return;
33 auto src
= cast(const(VColor
)*)data
.ptr
;
34 foreach (int dy
; 0..height
) {
35 foreach (int dx
; 0..width
) {
36 putPixel(x
+dx
, y
+dy
, *src
++);
41 void blit2x (int x
, int y
) const {
42 if (width
< 1 || height
< 1) return;
43 if (x
<= -width || y
<= -height
) return;
44 if (x
>= vbufW || y
>= vbufH
) return;
45 auto src
= cast(const(VColor
)*)data
.ptr
;
46 foreach (immutable int dy
; 0..height
) {
47 foreach (immutable int dx
; 0..width
) {
48 putPixel(x
+dx
*2+0, y
+dy
*2+0, *src
);
49 putPixel(x
+dx
*2+1, y
+dy
*2+0, *src
);
50 putPixel(x
+dx
*2+0, y
+dy
*2+1, *src
);
51 putPixel(x
+dx
*2+1, y
+dy
*2+1, *src
);
57 private void blit2xImpl(string op
) (int x
, int y
) nothrow @trusted @nogc {
58 if (width
< 1 || height
< 1) return;
59 if (x
<= -width || y
<= -height
) return;
60 if (x
>= vbufW || y
>= vbufH
) return;
61 auto s
= cast(const(ubyte)*)data
.ptr
;
62 //auto d = cast(uint*)vscr2x;
63 foreach (immutable int dy
; 0..height
) {
64 foreach (immutable int dx
; 0..width
) {
65 static if (op
.length
) mixin(op
);
66 immutable uint c1
= ((((c0
&0x00ff00ff)*6)>>3)&0x00ff00ff)|
(((c0
&0x0000ff00)*6)>>3)&0x0000ff00;
67 putPixel(x
+dx
*2+0, y
+dy
*2+0, c0
);
68 putPixel(x
+dx
*2+1, y
+dy
*2+0, c0
);
69 putPixel(x
+dx
*2+0, y
+dy
*2+1, c1
);
70 putPixel(x
+dx
*2+1, y
+dy
*2+1, c1
);
76 alias blit2xTV
= blit2xImpl
!"immutable uint c0 = (cast(immutable(uint)*)s)[0];";
77 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;";
78 alias blit2xTVGreen
= blit2xImpl
!"immutable ubyte i = cast(ubyte)((s[0]*28+s[1]*151+s[2]*77)/256); immutable uint c0 = i<<8;";
82 // ////////////////////////////////////////////////////////////////////////// //
83 // 0:b; 1:g; 2:r; 3: nothing
84 __gshared
int vbufW
= 256*2, vbufH
= 192*2;
85 __gshared
uint[] vbuf
;
88 vbuf
.length
= vbufW
*vbufH
;
93 void realizeVBuf (Image img
) {
96 auto dp = cast(uint*)img.getDataPointer;
97 import core.stdc.string : memcpy;
98 memcpy(dp, sp, vbufW*vbufH*4);
100 auto dp
= cast(uint*)img
.getDataPointer
;
101 dp
[0..vbufW
*vbufH
] = vbuf
.ptr
[0..vbufW
*vbufH
];
105 // ////////////////////////////////////////////////////////////////////////// //
106 ubyte clampToByte(T
) (T n
) @safe pure nothrow @nogc
107 if (__traits(isIntegral
, T
) && (T
.sizeof
== 2 || T
.sizeof
== 4))
109 static if (__VERSION__
> 2067) pragma(inline
, true);
110 n
&= -cast(int)(n
>= 0);
111 return cast(ubyte)(n|
((255-cast(int)n
)>>31));
114 ubyte clampToByte(T
) (T n
) @safe pure nothrow @nogc
115 if (__traits(isIntegral
, T
) && T
.sizeof
== 1)
117 static if (__VERSION__
> 2067) pragma(inline
, true);
122 // ////////////////////////////////////////////////////////////////////////// //
125 /// vlRGBA struct to ease color components extraction/replacing
126 align(1) struct vlRGBA
{
130 static assert(vlRGBA
.sizeof
== VColor
.sizeof
);
134 vlAMask
= 0xff000000u
,
135 vlRMask
= 0x00ff0000u
,
136 vlGMask
= 0x0000ff00u
,
137 vlBMask
= 0x000000ffu
148 enum VColor Transparent
= vlAMask
; /// completely transparent pixel color
151 bool isTransparent(T
: VColor
) (T col
) @safe pure nothrow @nogc {
152 static if (__VERSION__
> 2067) pragma(inline
, true);
153 return ((col
&vlAMask
) == vlAMask
);
156 bool isOpaque(T
: VColor
) (T col
) @safe pure nothrow @nogc {
157 static if (__VERSION__
> 2067) pragma(inline
, true);
158 return ((col
&vlAMask
) == 0);
162 VColor
rgbcol(TR
, TG
, TB
, TA
=ubyte) (TR r
, TG g
, TB b
, TA a
=0) @safe pure nothrow @nogc
163 if (__traits(isIntegral
, TR
) && __traits(isIntegral
, TG
) && __traits(isIntegral
, TB
) && __traits(isIntegral
, TA
)) {
164 static if (__VERSION__
> 2067) pragma(inline
, true);
166 (clampToByte(a
)<<vlAShift
)|
167 (clampToByte(r
)<<vlRShift
)|
168 (clampToByte(g
)<<vlGShift
)|
169 (clampToByte(b
)<<vlBShift
);
172 alias rgbacol
= rgbcol
;
175 // generate some templates
176 private enum genRGBGetSet(string cname
) =
177 "ubyte rgb"~cname
~"() (VColor clr) @safe pure nothrow @nogc {\n"~
178 " static if (__VERSION__ > 2067) pragma(inline, true);\n"~
179 " return ((clr>>vl"~cname
[0]~"Shift)&0xff);\n"~
181 "VColor rgbSet"~cname
~"(T) (VColor clr, T v) @safe pure nothrow @nogc if (__traits(isIntegral, T)) {\n"~
182 " static if (__VERSION__ > 2067) pragma(inline, true);\n"~
183 " return (clr&~vl"~cname
[0]~"Mask)|(clampToByte(v)<<vl"~cname
[0]~"Shift);\n"~
186 mixin(genRGBGetSet
!"Alpha");
187 mixin(genRGBGetSet
!"Red");
188 mixin(genRGBGetSet
!"Green");
189 mixin(genRGBGetSet
!"Blue");
192 void putPixel(TX
, TY
) (TX x
, TY y
, VColor col
) @trusted
193 if (__traits(isIntegral
, TX
) && __traits(isIntegral
, TY
))
195 static if (__VERSION__
> 2067) pragma(inline
, true);
196 immutable long xx
= cast(long)x
;
197 immutable long yy
= cast(long)y
;
198 if ((col
&vlAMask
) != vlAMask
&& xx
>= 0 && yy
>= 0 && xx
< vbufW
&& yy
< vbufH
) {
199 uint* da = vbuf
.ptr
+yy
*vbufW
+xx
;
201 immutable uint a
= 256-(col
>>24); // to not loose bits
202 immutable uint dc
= (*da)&0xffffff;
203 immutable uint srb
= (col
&0xff00ff);
204 immutable uint sg
= (col
&0x00ff00);
205 immutable uint drb
= (dc
&0xff00ff);
206 immutable uint dg
= (dc
&0x00ff00);
207 immutable uint orb
= (drb
+(((srb
-drb
)*a
+0x800080)>>8))&0xff00ff;
208 immutable uint og
= (dg
+(((sg
-dg
)*a
+0x008000)>>8))&0x00ff00;
216 void setPixel(TX
, TY
) (TX x
, TY y
, VColor col
) @trusted
217 if (__traits(isIntegral
, TX
) && __traits(isIntegral
, TY
))
219 static if (__VERSION__
> 2067) pragma(inline
, true);
220 immutable long xx
= cast(long)x
+mXOfs
;
221 immutable long yy
= cast(long)y
+mYOfs
;
222 if (xx
>= mClipX0
&& yy
>= mClipY0
&& xx
<= mClipX1
&& yy
<= mClipY1
) {
223 uint* da = vbuf
.ptr
+yy
*vbufW
+xx
;
229 void drawLine(bool lastPoint
=true) (int x0
, int y0
, int x1
, int y1
, immutable VColor col
) {
230 enum swap(string a
, string b
) = "{int tmp_="~a
~";"~a
~"="~b
~";"~b
~"=tmp_;}";
232 if ((col
&vlAMask
) == vlAMask
) return;
234 if (x0
== x1
&& y0
== y1
) {
235 static if (lastPoint
) putPixel(x0
, y0
, col
);
240 int wx0
= 0, wy0
= 0, wx1
= vbufW
-1, wy1
= vbufH
-1;
242 int stx
, sty
; // "steps" for x and y axes
243 int dsx
, dsy
; // "lengthes" for x and y axes
244 int dx2
, dy2
; // "double lengthes" for x and y axes
245 int xd
, yd
; // current coord
246 int e
; // "error" (as in bresenham algo)
252 // from left to right
253 if (x0
> wx1 || x1
< wx0
) return; // out of screen
254 stx
= 1; // going right
256 // from right to left
257 if (x1
> wx1 || x0
< wx0
) return; // out of screen
258 stx
= -1; // going left
263 mixin(swap
!("wx0", "wx1"));
267 // from top to bottom
268 if (y0
> wy1 || y1
< wy0
) return; // out of screen
269 sty
= 1; // going down
271 // from bottom to top
272 if (y1
> wy1 || y0
< wy0
) return; // out of screen
273 sty
= -1; // going up
278 mixin(swap
!("wy0", "wy1"));
285 mixin(swap
!("x0", "y0"));
286 mixin(swap
!("x1", "y1"));
287 mixin(swap
!("dsx", "dsy"));
288 mixin(swap
!("wx0", "wy0"));
289 mixin(swap
!("wx1", "wy1"));
290 mixin(swap
!("stx", "sty"));
304 int temp
= dx2
*(wy0
-y0
)-dsx
;
307 if (xd
> wx1
) return; // x is moved out of clipping rect, nothing to do
311 if (rem
> 0) { ++xd
; e
+= dy2
; }
315 if (!xfixed
&& x0
< wx0
) {
317 int temp
= dy2
*(wx0
-x0
);
320 if (yd
> wy1 || yd
== wy1
&& rem
>= dsx
) return;
323 if (rem
>= dsx
) { ++yd
; e
-= dx2
; }
327 int temp
= dx2
*(wy1
-y0
)+dsx
;
330 if (rem
== 0) --term
;
332 if (term
> wx1
) term
= wx1
; // clip at right
333 static if (lastPoint
) {
337 if (term
== xd
) return; // this is the only point, get out of here
339 if (sty
== -1) yd
= -yd
;
340 if (stx
== -1) { xd
= -xd
; term
= -term
; }
342 // draw it; `putPixel()` can omit checks
344 // inlined `putPixel(*d0, *d1, col)`
345 // this can be made even faster by precalculating `da` and making
346 // separate code branches for mixing and non-mixing drawing, but...
348 uint* da = vbuf
.ptr
+(*d1
)*vbufW
+(*d0
);
350 immutable uint a
= 256-(col
>>24); // to not loose bits
351 immutable uint dc
= (*da)&0xffffff;
352 immutable uint srb
= (col
&0xff00ff);
353 immutable uint sg
= (col
&0x00ff00);
354 immutable uint drb
= (dc
&0xff00ff);
355 immutable uint dg
= (dc
&0x00ff00);
356 immutable uint orb
= (drb
+(((srb
-drb
)*a
+0x800080)>>8))&0xff00ff;
357 immutable uint og
= (dg
+(((sg
-dg
)*a
+0x008000)>>8))&0x00ff00;
362 // done drawing, move coords
374 // //////////////////////////////////////////////////////////////////////// //
376 * Draw character onto virtual screen in KOI8 encoding.
384 * col = foreground color
385 * bkcol = background color
390 void drawCharWdt (int x
, int y
, int wdt
, int shift
, char ch
, VColor col
, VColor bkcol
=Transparent
) @trusted {
392 if (wdt
< 1 || shift
>= 8) return;
393 if (col
== Transparent
&& bkcol
== Transparent
) return;
394 if (wdt
> 8) wdt
= 8;
395 if (shift
< 0) shift
= 0;
396 foreach (immutable int dy
; 0..8) {
397 ubyte b
= cast(ubyte)(vlFont6
[pos
++]<<shift
);
398 foreach (immutable int dx
; 0..wdt
) {
399 VColor c
= (b
&0x80 ? col
: bkcol
);
400 if (!isTransparent(c
)) putPixel(x
+dx
, y
+dy
, c
);
412 OutLU
= 0x10, // left-up
413 OutRU
= 0x20, // right-up
414 OutLD
= 0x40, // left-down
415 OutRD
= 0x80, // right-down
420 * Draw outlined character onto virtual screen in KOI8 encoding.
428 * col = foreground color
429 * outcol = outline color
430 * ot = outline type, OutXXX, ored
435 void drawCharWdtOut (int x
, int y
, int wdt
, int shift
, char ch
, VColor col
, VColor outcol
=Transparent
, ubyte ot
=0) @trusted {
436 if (col
== Transparent
&& outcol
== Transparent
) return;
437 if (ot
== 0 || outcol
== Transparent
) {
438 // no outline? simple draw
439 drawCharWdt(x
, y
, wdt
, shift
, ch
, col
, Transparent
);
443 if (wdt
< 1 || shift
>= 8) return;
444 if (wdt
> 8) wdt
= 8;
445 if (shift
< 0) shift
= 0;
446 ubyte[8+2][8+2] bmp
= 0; // char bitmap; 0: empty; 1: char; 2: outline
447 foreach (immutable dy
; 1..9) {
448 ubyte b
= cast(ubyte)(vlFont6
[pos
++]<<shift
);
449 foreach (immutable dx
; 1..wdt
+1) {
454 if ((ot
&OutUp
) && bmp
[dy
-1][dx
] == 0) bmp
[dy
-1][dx
] = 2;
455 if ((ot
&OutDown
) && bmp
[dy
+1][dx
] == 0) bmp
[dy
+1][dx
] = 2;
456 if ((ot
&OutLeft
) && bmp
[dy
][dx
-1] == 0) bmp
[dy
][dx
-1] = 2;
457 if ((ot
&OutRight
) && bmp
[dy
][dx
+1] == 0) bmp
[dy
][dx
+1] = 2;
458 if ((ot
&OutLU
) && bmp
[dy
-1][dx
-1] == 0) bmp
[dy
-1][dx
-1] = 2;
459 if ((ot
&OutRU
) && bmp
[dy
-1][dx
+1] == 0) bmp
[dy
-1][dx
+1] = 2;
460 if ((ot
&OutLD
) && bmp
[dy
+1][dx
-1] == 0) bmp
[dy
+1][dx
-1] = 2;
461 if ((ot
&OutRD
) && bmp
[dy
+1][dx
+1] == 0) bmp
[dy
+1][dx
+1] = 2;
469 foreach (immutable int dy
; 0..10) {
470 foreach (immutable int dx
; 0..10) {
471 if (auto t
= bmp
[dy
][dx
]) putPixel(x
+dx
, y
+dy
, (t
== 1 ? col
: outcol
));
477 * Draw 6x8 character onto virtual screen in KOI8 encoding.
483 * col = foreground color
484 * bkcol = background color
489 void drawChar (int x
, int y
, char ch
, VColor col
, VColor bkcol
=Transparent
) @trusted {
490 drawCharWdt(x
, y
, 6, 0, ch
, col
, bkcol
);
493 void drawCharOut (int x
, int y
, char ch
, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
494 drawCharWdtOut(x
, y
, 6, 0, ch
, col
, outcol
, ot
);
497 void drawStr (int x
, int y
, string
str, VColor col
, VColor bkcol
=Transparent
) @trusted {
498 foreach (immutable char ch
; str) {
499 drawChar(x
, y
, ch
, col
, bkcol
);
504 void drawStrOut (int x
, int y
, string
str, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
505 foreach (immutable char ch
; str) {
506 drawCharOut(x
, y
, ch
, col
, outcol
, ot
);
511 static int charWidthProp (char ch
) @trusted pure { return (vlFontPropWidth
[ch
]&0x0f); }
513 int strWidthProp (string
str) @trusted pure {
515 foreach (immutable char ch
; str) wdt
+= (vlFontPropWidth
[ch
]&0x0f)+1;
516 if (wdt
> 0) --wdt
; // don't count last empty pixel
520 int drawCharProp (int x
, int y
, char ch
, VColor col
, VColor bkcol
=Transparent
) @trusted {
521 immutable int wdt
= (vlFontPropWidth
[ch
]&0x0f);
522 drawCharWdt(x
, y
, wdt
, vlFontPropWidth
[ch
]>>4, ch
, col
, bkcol
);
526 int drawCharPropOut (int x
, int y
, char ch
, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
527 immutable int wdt
= (vlFontPropWidth
[ch
]&0x0f);
528 drawCharWdtOut(x
, y
, wdt
, vlFontPropWidth
[ch
]>>4, ch
, col
, outcol
, ot
);
532 int drawStrProp (int x
, int y
, string
str, VColor col
, VColor bkcol
=Transparent
) @trusted {
535 foreach (immutable char ch
; str) {
537 if (!isTransparent(bkcol
)) foreach (int dy
; 0..8) putPixel(x
, y
+dy
, bkcol
);
541 x
+= drawCharProp(x
, y
, ch
, col
, bkcol
);
546 int drawStrPropOut (int x
, int y
, string
str, VColor col
, VColor outcol
=Transparent
, ubyte ot
=OutAll
) @trusted {
548 foreach (immutable char ch
; str) {
549 x
+= drawCharPropOut(x
, y
, ch
, col
, outcol
, ot
)+1;
551 if (x
> sx
) --x
; // don't count last empty pixel
555 // ////////////////////////////////////////////////////////////////////////// //
556 void clear (VColor col
) @trusted {
557 vbuf
.ptr
[0..vbufW
*vbufH
] = col
;
561 // ////////////////////////////////////////////////////////////////////////// //
562 public immutable ubyte[256*8] vlFont6
= [
2871 // bits 4..7: lshift
2872 public immutable ubyte[256] vlFontPropWidth
= () {
2874 foreach (immutable cnum
; 0..256) {
2875 import core
.bitop
: bsf, bsr;
2877 (cnum
>= 32 && cnum
<= 127) ||
2878 (cnum
>= 143 && cnum
<= 144) ||
2879 (cnum
>= 166 && cnum
<= 167) ||
2880 (cnum
>= 192 && cnum
<= 255);
2884 foreach (immutable dy
; 0..8) {
2885 immutable b
= vlFont6
[cnum
*8+dy
];
2887 immutable mn
= 7-bsr(b
);
2888 if (mn
< shift
) shift
= mn
;
2893 foreach (immutable dy
; 0..8) {
2894 immutable b
= (vlFont6
[cnum
*8+dy
]<<shift
);
2895 immutable cwdt
= (b ?
8-bsf(b
) : 0);
2896 if (cwdt
> wdt
) wdt
= cast(ubyte)cwdt
;
2899 case 0: wdt
= 8; break; // 8px space
2900 case 32: wdt
= 5; break; // 5px space
2901 case 17: .. case 27: wdt
= 8; break; // single frames
2902 case 48: .. case 57: wdt
= 5; break; // digits are monospaced
2903 case 127: .. case 142: wdt
= 8; break; // filled frames
2904 case 145: .. case 151: wdt
= 8; break; // filled frames
2905 case 155: .. case 159: wdt
= 8; break; // filled frames
2908 res
[cnum
] = (wdt
&0x0f)|
((shift
<<4)&0xf0);