1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module iv
.vl2
.vlo
/*is aliced*/;
23 // ////////////////////////////////////////////////////////////////////////// //
25 static import gcc
.attribute
;
26 private enum gcc_inline
= gcc
.attribute
.attribute("forceinline");
27 private enum gcc_noinline
= gcc
.attribute
.attribute("noinline");
28 private enum gcc_flatten
= gcc
.attribute
.attribute("flatten");
30 // hackery for non-gcc compilers
31 private enum gcc_inline
;
32 private enum gcc_noinline
;
33 private enum gcc_flatten
;
37 // ////////////////////////////////////////////////////////////////////////// //
38 __gshared VLOverlay vlsOvl
; /// vscreen overlay
41 // ////////////////////////////////////////////////////////////////////////// //
42 private void vloInitVSO () {
43 vlsOvl
.setupWithVScr(vlVScr
, vlWidth
, vlHeight
);
47 private void vloDeinitVSO () {
48 vlsOvl
.free(); // this will not free VScr, as vlsOvl isn't own it
52 shared static this () {
53 vlInitHook
= &vloInitVSO
;
54 vlDeinitHook
= &vloDeinitVSO
;
58 // ////////////////////////////////////////////////////////////////////////// //
59 // BEWARE! ANY COPIES WILL RESET `vscrOwn` FLAG! NO REFCOUNTING HERE!
68 bool vscrOwn
; // true: `free()` mVScr in dtor
72 this (void* avscr
, int wdt
, int hgt
) @trusted nothrow @nogc { setupWithVScr(avscr
, wdt
, hgt
); }
75 this(TW
, TH
) (TW wdt
, TH hgt
) if (__traits(isIntegral
, TW
) && __traits(isIntegral
, TH
)) {
79 ~this () @trusted nothrow @nogc { free(); }
81 // any copy resets "own" flag
82 this (this) @safe nothrow @nogc { vscrOwn
= false; }
85 void setupWithVScr (void* avscr
, int wdt
, int hgt
) @trusted nothrow @nogc {
86 if (wdt
< 1 || hgt
< 1 || avscr
is null) {
89 if (avscr
!is mVScr
) free();
90 mVScr
= cast(uint*)avscr
;
98 void resize(TW
, TH
) (TW wdt
, TH hgt
) if (__traits(isIntegral
, TW
) && __traits(isIntegral
, TH
)) {
99 import core
.exception
: onOutOfMemoryError
;
100 import core
.stdc
.stdlib
: malloc
, realloc
, free
;
101 if (wdt
< 1 || wdt
> 16384 || hgt
< 1 || hgt
> 16384) throw new VideoLibError("VLOverlay: invalid size");
102 if (!vscrOwn
) throw new VideoLibError("VLOverlay: can't resize predefined overlay");
104 mWidth
= cast(int)wdt
;
105 mHeight
= cast(int)hgt
;
106 mVScr
= cast(uint*)malloc(mWidth
*mHeight
*mVScr
[0].sizeof
);
107 if (mVScr
is null) onOutOfMemoryError();
108 } else if (mWidth
!= cast(int)wdt || mHeight
!= cast(int)hgt
) {
109 mWidth
= cast(int)wdt
;
110 mHeight
= cast(int)hgt
;
111 auto scr
= cast(uint*)realloc(mVScr
, mWidth
*mHeight
*mVScr
[0].sizeof
);
112 if (scr
is null) { this.free(); onOutOfMemoryError(); }
118 /// WARNING! this will trash virtual screen!
119 @property void width(T
) (T w
) if (__traits(isIntegral
, T
)) { resize(w
, mHeight
); }
120 @property void height(T
) (T h
) if (__traits(isIntegral
, T
)) { resize(mWidth
, h
); }
124 @property bool valid () const pure { return (mVScr
!is null); }
126 void free () @trusted {
127 if (vscrOwn
&& mVScr
!is null) {
128 import core
.stdc
.stdlib
: free
;
138 * Draw (possibly semi-transparent) pixel onto virtual screen; mix colors.
148 @gcc_inline void putPixel(TX
, TY
) (TX x
, TY y
, Color col
) @trusted
149 if (__traits(isIntegral
, TX
) && __traits(isIntegral
, TY
))
151 static if (__VERSION__
> 2067) pragma(inline
, true);
152 immutable long xx
= cast(long)x
+mXOfs
;
153 immutable long yy
= cast(long)y
+mYOfs
;
154 if ((col
&vlAMask
) != vlAMask
&& xx
>= mClipX0
&& yy
>= mClipY0
&& xx
<= mClipX1
&& yy
<= mClipY1
) {
155 uint* da = mVScr
+yy
*mWidth
+xx
;
157 immutable uint a
= 256-(col
>>24); // to not loose bits
158 immutable uint dc
= (*da)&0xffffff;
159 immutable uint srb
= (col
&0xff00ff);
160 immutable uint sg
= (col
&0x00ff00);
161 immutable uint drb
= (dc
&0xff00ff);
162 immutable uint dg
= (dc
&0x00ff00);
163 immutable uint orb
= (drb
+(((srb
-drb
)*a
+0x800080)>>8))&0xff00ff;
164 immutable uint og
= (dg
+(((sg
-dg
)*a
+0x008000)>>8))&0x00ff00;
173 * Draw (possibly semi-transparent) pixel onto virtual screen; don't mix colors.
183 @gcc_inline void setPixel(TX
, TY
) (TX x
, TY y
, Color col
) @trusted
184 if (__traits(isIntegral
, TX
) && __traits(isIntegral
, TY
))
186 static if (__VERSION__
> 2067) pragma(inline
, true);
187 immutable long xx
= cast(long)x
+mXOfs
;
188 immutable long yy
= cast(long)y
+mYOfs
;
189 if (xx
>= mClipX0
&& yy
>= mClipY0
&& xx
<= mClipX1
&& yy
<= mClipY1
) {
190 uint* da = mVScr
+yy
*mWidth
+xx
;
195 void resetClipOfs () @safe {
196 if (mVScr
!is null) {
197 mClipX0
= mClipY0
= mXOfs
= mYOfs
= 0;
201 // all functions checks clipping, and this is not valid region
202 // so we can omit VScr checks
203 mClipX0
= mClipY0
= -42;
204 mClipX1
= mClipY1
= -666;
208 @property int width () const @safe pure { return mWidth
; }
209 @property int height () const @safe pure { return mHeight
; }
211 @property int xOfs () const @safe pure { return mXOfs
; }
212 @property void xOfs (int v
) @safe { mXOfs
= v
; }
214 @property int yOfs () const @safe pure { return mYOfs
; }
215 @property void yOfs (int v
) @safe { mYOfs
= v
; }
217 void getOfs (ref int x
, ref int y
) const @safe pure { x
= mXOfs
; y
= mYOfs
; }
218 void setOfs (in int x
, in int y
) @safe { mXOfs
= x
; mYOfs
= y
; }
225 void getOfs (ref Ofs ofs
) const @safe pure { ofs
.x
= mXOfs
; ofs
.y
= mYOfs
; }
226 void setOfs (in ref Ofs ofs
) @safe { mXOfs
= ofs
.x
; mYOfs
= ofs
.y
; }
227 void resetOfs () @safe { mXOfs
= mYOfs
= 0; }
234 void getClip (ref int x0
, ref int y0
, ref int wdt
, ref int hgt
) const @safe pure {
235 if (mVScr
!is null) {
238 wdt
= mClipX1
-mClipX0
+1;
239 hgt
= mClipY1
-mClipY0
+1;
241 x0
= y0
= wdt
= hgt
= 0;
245 void setClip (in int x0
, in int y0
, in int wdt
, in int hgt
) @safe {
246 if (mVScr
!is null) {
249 mClipX1
= (wdt
> 0 ? x0
+wdt
-1 : x0
-1);
250 mClipY1
= (hgt
> 0 ? y0
+hgt
-1 : y0
-1);
251 if (mClipX0
< 0) mClipX0
= 0;
252 if (mClipY0
< 0) mClipY0
= 0;
253 if (mClipX0
>= mWidth
) mClipX0
= mWidth
-1;
254 if (mClipY0
>= mHeight
) mClipY0
= mHeight
-1;
255 if (mClipX1
< 0) mClipX1
= 0;
256 if (mClipY1
< 0) mClipY1
= 0;
257 if (mClipX1
>= mWidth
) mClipX1
= mWidth
-1;
258 if (mClipY1
>= mHeight
) mClipY1
= mHeight
-1;
262 void resetClip () @safe {
263 if (mVScr
!is null) {
264 mClipX0
= mClipY0
= 0;
268 // all functions checks clipping, and this is not valid region
269 // so we can omit VScr checks
270 mClipX0
= mClipY0
= -42;
271 mClipX1
= mClipY1
= -666;
275 void getClip (ref Clip clip
) const @safe pure { getClip(clip
.x
, clip
.y
, clip
.w
, clip
.h
); }
276 void setClip (in ref Clip clip
) @safe { setClip(clip
.x
, clip
.y
, clip
.w
, clip
.h
); }
278 void clipIntrude (int dx
, int dy
) @safe {
279 if (mVScr
!is null) {
284 if (mClipX1
>= mClipX0
&& mClipY1
>= mClipY0
) {
285 setClip(mClipX0
, mClipY0
, mClipX1
-mClipX0
+1, mClipY1
-mClipY0
+1);
290 void clipExtrude (int dx
, int dy
) @safe { clipIntrude(-dx
, -dy
); }
292 // //////////////////////////////////////////////////////////////////////// //
294 * Draw character onto virtual screen in KOI8 encoding.
302 * col = foreground color
303 * bkcol = background color
308 void drawCharWdt (int x
, int y
, int wdt
, int shift
, char ch
, Color col
, Color bkcol
=vlcTransparent
) @trusted {
310 if (wdt
< 1 || shift
>= 8) return;
311 if (col
== vlcTransparent
&& bkcol
== vlcTransparent
) return;
312 if (wdt
> 8) wdt
= 8;
313 if (shift
< 0) shift
= 0;
314 foreach (immutable int dy
; 0..8) {
315 ubyte b
= cast(ubyte)(vlFont6
[pos
++]<<shift
);
316 foreach (immutable int dx
; 0..wdt
) {
317 Color c
= (b
&0x80 ? col
: bkcol
);
318 if (!vlcIsTransparent(c
)) putPixel(x
+dx
, y
+dy
, c
);
330 OutLU
= 0x10, // left-up
331 OutRU
= 0x20, // right-up
332 OutLD
= 0x40, // left-down
333 OutRD
= 0x80, // right-down
338 * Draw outlined character onto virtual screen in KOI8 encoding.
346 * col = foreground color
347 * outcol = outline color
348 * ot = outline type, OutXXX, ored
353 void drawCharWdtOut (int x
, int y
, int wdt
, int shift
, char ch
, Color col
, Color outcol
=vlcTransparent
, ubyte ot
=0) @trusted {
354 if (col
== vlcTransparent
&& outcol
== vlcTransparent
) return;
355 if (ot
== 0 || outcol
== vlcTransparent
) {
356 // no outline? simple draw
357 drawCharWdt(x
, y
, wdt
, shift
, ch
, col
, vlcTransparent
);
361 if (wdt
< 1 || shift
>= 8) return;
362 if (wdt
> 8) wdt
= 8;
363 if (shift
< 0) shift
= 0;
364 ubyte[8+2][8+2] bmp
= 0; // char bitmap; 0: empty; 1: char; 2: outline
365 foreach (immutable dy
; 1..9) {
366 ubyte b
= cast(ubyte)(vlFont6
[pos
++]<<shift
);
367 foreach (immutable dx
; 1..wdt
+1) {
372 if ((ot
&OutUp
) && bmp
[dy
-1][dx
] == 0) bmp
[dy
-1][dx
] = 2;
373 if ((ot
&OutDown
) && bmp
[dy
+1][dx
] == 0) bmp
[dy
+1][dx
] = 2;
374 if ((ot
&OutLeft
) && bmp
[dy
][dx
-1] == 0) bmp
[dy
][dx
-1] = 2;
375 if ((ot
&OutRight
) && bmp
[dy
][dx
+1] == 0) bmp
[dy
][dx
+1] = 2;
376 if ((ot
&OutLU
) && bmp
[dy
-1][dx
-1] == 0) bmp
[dy
-1][dx
-1] = 2;
377 if ((ot
&OutRU
) && bmp
[dy
-1][dx
+1] == 0) bmp
[dy
-1][dx
+1] = 2;
378 if ((ot
&OutLD
) && bmp
[dy
+1][dx
-1] == 0) bmp
[dy
+1][dx
-1] = 2;
379 if ((ot
&OutRD
) && bmp
[dy
+1][dx
+1] == 0) bmp
[dy
+1][dx
+1] = 2;
387 foreach (immutable int dy
; 0..10) {
388 foreach (immutable int dx
; 0..10) {
389 if (auto t
= bmp
[dy
][dx
]) putPixel(x
+dx
, y
+dy
, (t
== 1 ? col
: outcol
));
395 * Draw 6x8 character onto virtual screen in KOI8 encoding.
401 * col = foreground color
402 * bkcol = background color
407 void drawChar (int x
, int y
, char ch
, Color col
, Color bkcol
=vlcTransparent
) @trusted {
408 drawCharWdt(x
, y
, 6, 0, ch
, col
, bkcol
);
411 void drawCharOut (int x
, int y
, char ch
, Color col
, Color outcol
=vlcTransparent
, ubyte ot
=OutAll
) @trusted {
412 drawCharWdtOut(x
, y
, 6, 0, ch
, col
, outcol
, ot
);
415 void drawStr (int x
, int y
, string
str, Color col
, Color bkcol
=vlcTransparent
) @trusted {
416 foreach (immutable char ch
; str) {
417 drawChar(x
, y
, ch
, col
, bkcol
);
422 void drawStrOut (int x
, int y
, string
str, Color col
, Color outcol
=vlcTransparent
, ubyte ot
=OutAll
) @trusted {
423 foreach (immutable char ch
; str) {
424 drawCharOut(x
, y
, ch
, col
, outcol
, ot
);
429 static int charWidthProp (char ch
) @trusted pure { return (vlFontPropWidth
[ch
]&0x0f); }
431 int strWidthProp (string
str) @trusted pure {
433 foreach (immutable char ch
; str) wdt
+= (vlFontPropWidth
[ch
]&0x0f)+1;
434 if (wdt
> 0) --wdt
; // don't count last empty pixel
438 int drawCharProp (int x
, int y
, char ch
, Color col
, Color bkcol
=vlcTransparent
) @trusted {
439 immutable int wdt
= (vlFontPropWidth
[ch
]&0x0f);
440 drawCharWdt(x
, y
, wdt
, vlFontPropWidth
[ch
]>>4, ch
, col
, bkcol
);
444 int drawCharPropOut (int x
, int y
, char ch
, Color col
, Color outcol
=vlcTransparent
, ubyte ot
=OutAll
) @trusted {
445 immutable int wdt
= (vlFontPropWidth
[ch
]&0x0f);
446 drawCharWdtOut(x
, y
, wdt
, vlFontPropWidth
[ch
]>>4, ch
, col
, outcol
, ot
);
450 int drawStrProp (int x
, int y
, string
str, Color col
, Color bkcol
=vlcTransparent
) @trusted {
453 foreach (immutable char ch
; str) {
455 if (!vlcIsTransparent(bkcol
)) foreach (int dy
; 0..8) putPixel(x
, y
+dy
, bkcol
);
459 x
+= drawCharProp(x
, y
, ch
, col
, bkcol
);
464 int drawStrPropOut (int x
, int y
, string
str, Color col
, Color outcol
=vlcTransparent
, ubyte ot
=OutAll
) @trusted {
466 foreach (immutable char ch
; str) {
467 x
+= drawCharPropOut(x
, y
, ch
, col
, outcol
, ot
)+1;
469 if (x
> sx
) --x
; // don't count last empty pixel
473 // ////////////////////////////////////////////////////////////////////////// //
474 void clear (Color col
) @trusted {
475 if (mVScr
!is null) {
476 if (!vscrOwn
) col
&= 0xffffff;
477 mVScr
[0..mWidth
*mHeight
] = col
;
481 void hline (int x0
, int y0
, int len
, Color col
) @trusted {
482 if (isOpaque(col
) && len
> 0 && mVScr
!is null) {
485 if (y0
>= mClipY0
&& x0
<= mClipX1
&& y0
<= mClipY1
&& x0
+len
> mClipX0
) {
486 if (x0
< mClipX0
) { if ((len
+= (x0
-mClipX0
)) <= 0) return; x0
= mClipX0
; }
487 if (x0
+len
-1 > mClipX1
) len
= mClipX1
-x0
+1;
488 immutable usize ofs
= y0
*mWidth
+x0
;
489 mVScr
[ofs
..ofs
+len
] = col
;
492 while (len
-- > 0) putPixel(x0
++, y0
, col
);
496 void vline (int x0
, int y0
, int len
, Color col
) @trusted {
497 while (len
-- > 0) putPixel(x0
, y0
++, col
);
502 void drawLine(bool lastPoint) (int x0, int y0, int x1, int y1, Color col) @trusted {
503 import std.math : abs;
504 int dx = abs(x1-x0), sx = (x0 < x1 ? 1 : -1);
505 int dy = -abs(y1-y0), sy = (y0 < y1 ? 1 : -1);
506 int err = dx+dy, e2; // error value e_xy
508 static if (lastPoint) putPixel(x0, y0, col);
509 if (x0 == x1 && y0 == y1) break;
510 static if (!lastPoint) putPixel(x0, y0, col);
512 if (e2 >= dy) { err += dy; x0 += sx; } // e_xy+e_x > 0
513 if (e2 <= dx) { err += dx; y0 += sy; } // e_xy+e_y < 0
518 // as the paper on which this code is based in not available to public,
520 // knowledge must be publicly available; the ones who hides the knowledge
521 // are not deserving any credits.
522 void drawLine(bool lastPoint
) (int x0
, int y0
, int x1
, int y1
, immutable Color col
) {
523 enum swap(string a
, string b
) = "{int tmp_="~a
~";"~a
~"="~b
~";"~b
~"=tmp_;}";
525 if ((col
&vlAMask
) == vlAMask || mClipX0
> mClipX1 || mClipY0
> mClipY1 || mVScr
is null) return;
527 if (x0
== x1
&& y0
== y1
) {
528 static if (lastPoint
) putPixel(x0
, y0
, col
);
532 x0
+= mXOfs
; x1
+= mXOfs
;
533 y0
+= mYOfs
; y1
+= mYOfs
;
536 int wx0
= mClipX0
, wy0
= mClipY0
, wx1
= mClipX1
, wy1
= mClipY1
;
538 int stx
, sty
; // "steps" for x and y axes
539 int dsx
, dsy
; // "lengthes" for x and y axes
540 int dx2
, dy2
; // "double lengthes" for x and y axes
541 int xd
, yd
; // current coord
542 int e
; // "error" (as in bresenham algo)
548 // from left to right
549 if (x0
> wx1 || x1
< wx0
) return; // out of screen
550 stx
= 1; // going right
552 // from right to left
553 if (x1
> wx1 || x0
< wx0
) return; // out of screen
554 stx
= -1; // going left
559 mixin(swap
!("wx0", "wx1"));
563 // from top to bottom
564 if (y0
> wy1 || y1
< wy0
) return; // out of screen
565 sty
= 1; // going down
567 // from bottom to top
568 if (y1
> wy1 || y0
< wy0
) return; // out of screen
569 sty
= -1; // going up
574 mixin(swap
!("wy0", "wy1"));
581 mixin(swap
!("x0", "y0"));
582 mixin(swap
!("x1", "y1"));
583 mixin(swap
!("dsx", "dsy"));
584 mixin(swap
!("wx0", "wy0"));
585 mixin(swap
!("wx1", "wy1"));
586 mixin(swap
!("stx", "sty"));
600 int temp
= dx2
*(wy0
-y0
)-dsx
;
603 if (xd
> wx1
) return; // x is moved out of clipping rect, nothing to do
607 if (rem
> 0) { ++xd
; e
+= dy2
; }
611 if (!xfixed
&& x0
< wx0
) {
613 int temp
= dy2
*(wx0
-x0
);
616 if (yd
> wy1 || yd
== wy1
&& rem
>= dsx
) return;
619 if (rem
>= dsx
) { ++yd
; e
-= dx2
; }
623 int temp
= dx2
*(wy1
-y0
)+dsx
;
626 if (rem
== 0) --term
;
628 if (term
> wx1
) term
= wx1
; // clip at right
629 static if (lastPoint
) {
633 if (term
== xd
) return; // this is the only point, get out of here
635 if (sty
== -1) yd
= -yd
;
636 if (stx
== -1) { xd
= -xd
; term
= -term
; }
638 // draw it; `putPixel()` can omit checks
640 // inlined `putPixel(*d0, *d1, col)`
641 // this can be made even faster by precalculating `da` and making
642 // separate code branches for mixing and non-mixing drawing, but...
644 uint* da = mVScr
+(*d1
)*mWidth
+(*d0
);
646 immutable uint a
= 256-(col
>>24); // to not loose bits
647 immutable uint dc
= (*da)&0xffffff;
648 immutable uint srb
= (col
&0xff00ff);
649 immutable uint sg
= (col
&0x00ff00);
650 immutable uint drb
= (dc
&0xff00ff);
651 immutable uint dg
= (dc
&0x00ff00);
652 immutable uint orb
= (drb
+(((srb
-drb
)*a
+0x800080)>>8))&0xff00ff;
653 immutable uint og
= (dg
+(((sg
-dg
)*a
+0x008000)>>8))&0x00ff00;
658 // done drawing, move coords
669 void line (int x0
, int y0
, int x1
, int y1
, Color col
) @trusted { drawLine
!true(x0
, y0
, x1
, y1
, col
); }
670 void lineNoLast (int x0
, int y0
, int x1
, int y1
, Color col
) @trusted { drawLine
!false(x0
, y0
, x1
, y1
, col
); }
672 void fillRect (int x
, int y
, int w
, int h
, Color col
) @trusted {
675 if (w
> 0 && h
> 0 && x
+w
> mClipX0
&& y
+h
> mClipY0
&& x
<= mClipX1
&& y
<= mClipY1
) {
677 sr
.x
= mClipX0
; sr
.y
= mClipY0
; sr
.w
= mClipX1
-mClipX0
+1; sr
.h
= mClipY1
-mClipY0
+1;
678 r
.x
= x
; r
.y
= y
; r
.w
= w
; r
.h
= h
;
679 if (SDL_IntersectRect(&sr
, &r
, &dr
)) {
682 while (dr
.h
-- > 0) hline(x
, y
++, dr
.w
, col
);
687 void rect (int x
, int y
, int w
, int h
, Color col
) @trusted {
688 if (w
> 0 && h
> 0) {
690 hline(x
, y
+h
-1, w
, col
);
691 vline(x
, y
+1, h
-2, col
);
692 vline(x
+w
-1, y
+1, h
-2, col
);
697 void selectionRect (int phase
, int x0
, int y0
, int wdt
, int hgt
, Color col0
, Color col1
=vlcTransparent
) @trusted {
698 if (wdt
> 0 && hgt
> 0) {
700 foreach (immutable f
; x0
..x0
+wdt
) { putPixel(f
, y0
, ((phase
%= 4) < 2 ? col0
: col1
)); ++phase
; }
702 foreach (immutable f
; y0
+1..y0
+hgt
) { putPixel(x0
+wdt
-1, f
, ((phase
%= 4) < 2 ? col0
: col1
)); ++phase
; }
704 foreach_reverse (immutable f
; x0
..x0
+wdt
-1) { putPixel(f
, y0
+hgt
-1, ((phase
%= 4) < 2 ? col0
: col1
)); ++phase
; }
706 foreach_reverse (immutable f
; y0
..y0
+hgt
-1) { putPixel(x0
, f
, ((phase
%= 4) < 2 ? col0
: col1
)); ++phase
; }
710 private void plot4points() (int cx
, int cy
, int x
, int y
, Color clr
) @trusted {
711 putPixel(cx
+x
, cy
+y
, clr
);
712 if (x
!= 0) putPixel(cx
-x
, cy
+y
, clr
);
713 if (y
!= 0) putPixel(cx
+x
, cy
-y
, clr
);
714 putPixel(cx
-x
, cy
-y
, clr
);
717 void circle (int cx
, int cy
, int radius
, Color clr
) @trusted {
718 if (radius
> 0 && !vlcIsTransparent(clr
)) {
719 int error
= -radius
, x
= radius
, y
= 0;
720 if (radius
== 1) { putPixel(cx
, cy
, clr
); return; }
722 plot4points(cx
, cy
, x
, y
, clr
);
723 plot4points(cx
, cy
, y
, x
, clr
);
726 if (error
>= 0) { --x
; error
-= x
*2; }
728 plot4points(cx
, cy
, x
, y
, clr
);
732 void fillCircle (int cx
, int cy
, int radius
, Color clr
) @trusted {
733 if (radius
> 0 && !vlcIsTransparent(clr
)) {
734 int error
= -radius
, x
= radius
, y
= 0;
735 if (radius
== 1) { putPixel(cx
, cy
, clr
); return; }
741 hline(cx
-x
, cy
+last_y
, 2*x
+1, clr
);
742 if (x
!= 0 && last_y
!= 0) hline(cx
-x
, cy
-last_y
, 2*x
+1, clr
);
745 hline(cx
-last_y
, cy
+x
, 2*last_y
+1, clr
);
746 if (last_y
!= 0 && x
!= 0) hline(cx
-last_y
, cy
-x
, 2*last_y
+1, clr
);
756 void ellipse (int x0
, int y0
, int x1
, int y1
, Color clr
) @trusted {
757 import std
.math
: abs
;
758 int a
= abs(x1
-x0
), b
= abs(y1
-y0
), b1
= b
&1; // values of diameter
759 long dx
= 4*(1-a
)*b
*b
, dy
= 4*(b1
+1)*a
*a
; // error increment
760 long err
= dx
+dy
+b1
*a
*a
; // error of 1.step
761 if (x0
> x1
) { x0
= x1
; x1
+= a
; } // if called with swapped points...
762 if (y0
> y1
) y0
= y1
; // ...exchange them
763 y0
+= (b
+1)/2; y1
= y0
-b1
; // starting pixel
764 a
*= 8*a
; b1
= 8*b
*b
;
767 putPixel(x1
, y0
, clr
); // I. Quadrant
768 putPixel(x0
, y0
, clr
); // II. Quadrant
769 putPixel(x0
, y1
, clr
); // III. Quadrant
770 putPixel(x1
, y1
, clr
); // IV. Quadrant
772 if (e2
>= dx
) { ++x0
; --x1
; err
+= dx
+= b1
; } // x step
773 if (e2
<= dy
) { ++y0
; --y1
; err
+= dy
+= a
; } // y step
776 // too early stop of flat ellipses a=1
777 putPixel(x0
-1, ++y0
, clr
); // complete tip of ellipse
778 putPixel(x0
-1, --y1
, clr
);
782 void fillEllipse (int x0
, int y0
, int x1
, int y1
, Color clr
) @trusted {
783 import std
.math
: abs
;
784 int a
= abs(x1
-x0
), b
= abs(y1
-y0
), b1
= b
&1; // values of diameter
785 long dx
= 4*(1-a
)*b
*b
, dy
= 4*(b1
+1)*a
*a
; // error increment
786 long err
= dx
+dy
+b1
*a
*a
; // error of 1.step
787 int prev_y0
= -1, prev_y1
= -1;
788 if (x0
> x1
) { x0
= x1
; x1
+= a
; } // if called with swapped points...
789 if (y0
> y1
) y0
= y1
; // ...exchange them
790 y0
+= (b
+1)/2; y1
= y0
-b1
; // starting pixel
791 a
*= 8*a
; b1
= 8*b
*b
;
794 if (y0
!= prev_y0
) { hline(x0
, y0
, x1
-x0
+1, clr
); prev_y0
= y0
; }
795 if (y1
!= y0
&& y1
!= prev_y1
) { hline(x0
, y1
, x1
-x0
+1, clr
); prev_y1
= y1
; }
797 if (e2
>= dx
) { ++x0
; --x1
; err
+= dx
+= b1
; } // x step
798 if (e2
<= dy
) { ++y0
; --y1
; err
+= dy
+= a
; } // y step
801 // too early stop of flat ellipses a=1
802 putPixel(x0
-1, ++y0
, clr
); // complete tip of ellipse
803 putPixel(x0
-1, --y1
, clr
);
807 /** blit overlay to main screen */
808 void blitTpl(string btype
) (ref VLOverlay destovl
, int xd
, int yd
, ubyte alpha
=0) @trusted {
809 static if (btype
== "NoSrcAlpha") import core
.stdc
.string
: memcpy
;
810 if (!valid ||
!destovl
.valid
) return;
811 if (xd
> -mWidth
&& yd
> -mHeight
&& xd
< destovl
.mWidth
&& yd
< destovl
.mHeight
&& alpha
< 255) {
812 int w
= mWidth
, h
= mHeight
;
813 immutable uint vsPitch
= destovl
.mWidth
;
814 immutable uint myPitch
= mWidth
;
819 // skip invisible top part
820 if ((h
+= yd
) < 1) return;
824 if (yd
+h
> destovl
.mHeight
) {
825 // don't draw invisible bottom part
826 if ((h
= destovl
.mHeight
-yd
) < 1) return;
828 // horizontal clipping
830 // skip invisible left part
831 if ((w
+= xd
) < 1) return;
835 if (xd
+w
> destovl
.mWidth
) {
836 // don't draw invisible right part
837 if ((w
= destovl
.mWidth
-xd
) < 1) return;
840 dest
= destovl
.mVScr
+yd
*vsPitch
+xd
;
841 static if (btype
== "NoSrcAlpha") {
844 import core
.stdc
.string
: memcpy
;
845 memcpy(dest
, my
, w
*destovl
.mVScr
[0].sizeof
);
854 static if (btype
== "NoSrcAlpha") immutable uint a
= 256-alpha
; // to not loose bits
856 auto src
= cast(immutable(uint)*)my
;
858 foreach_reverse (immutable dx
; 0..w
) {
859 immutable uint s
= *src
++;
860 static if (btype
== "SrcAlpha") {
861 if ((s
&vlAMask
) == vlcTransparent
) { ++dst
; continue; }
862 immutable uint a
= 256-clampToByte(cast(int)(alpha
+(s
>>vlAShift
)&0xff)); // to not loose bits
864 immutable uint dc
= (*dst
)&0xffffff;
865 immutable uint srb
= (s
&0xff00ff);
866 immutable uint sg
= (s
&0x00ff00);
867 immutable uint drb
= (dc
&0xff00ff);
868 immutable uint dg
= (dc
&0x00ff00);
869 immutable uint orb
= (drb
+(((srb
-drb
)*a
+0x800080)>>8))&0xff00ff;
870 immutable uint og
= (dg
+(((sg
-dg
)*a
+0x008000)>>8))&0x00ff00;
880 alias blit
= blitTpl
!"NoSrcAlpha";
881 alias blitSrcAlpha
= blitTpl
!"SrcAlpha";