1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2020 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
21 void vDrawChar (VExSurface
*sfc
, int x
, int y
, char ch
, Uint8 ink
, Uint8 paper
) {
22 int ca
= ((uint8_t)ch
)*8;
24 for (int dy
= 0; dy
< 8; ++dy
, ++y
, x
-= 6) {
25 uint8_t b
= font6x8
[ca
++];
27 for (int dx
= 0; dx
< 6; ++dx
, ++x
, b
<<= 1) {
28 vPutPixel(sfc
, x
, y
, b
&0x80?ink
:paper
);
34 void vDrawText (VExSurface
*sfc
, int x
, int y
, const char *str
, Uint8 ink
, Uint8 paper
) {
37 for (; *str
; ++str
, x
+= 6) {
39 case '\n': x
= sx
-6; y
+= 8; break;
41 vDrawChar(sfc
, x
, y
, *str
, ink
, paper
);
48 void vDrawOutlineText (VExSurface
*sfc
, int x
, int y
, const char *str
, Uint8 ink
, int oink
) {
49 for (int dy
= -1; dy
<= 1; ++dy
) {
50 for (int dx
= -1; dx
<= 1; ++dx
) {
51 if (dx
|| dy
) vDrawText(sfc
, x
+dx
, y
+dy
, str
, oink
, -1);
54 vDrawText(sfc
, x
, y
, str
, ink
, -1);
58 void vDrawHLine (VExSurface
*sfc
, int x
, int y
, int len
, Uint8 clr
) {
59 for (; len
> 0; --len
, ++x
) vPutPixel(sfc
, x
, y
, clr
);
63 void vDrawVLine (VExSurface
*sfc
, int x
, int y
, int len
, Uint8 clr
) {
64 for (; len
> 0; --len
, ++y
) vPutPixel(sfc
, x
, y
, clr
);
68 void vDrawBar (VExSurface
*sfc
, int x
, int y
, int width
, int height
, Uint8 clr
) {
69 for (int dy
= 0; dy
< height
; ++dy
, ++y
) vDrawHLine(sfc
, x
, y
, width
, clr
);
73 void vDrawRect (VExSurface
*sfc
, int x
, int y
, int width
, int height
, Uint8 clr
) {
74 if (width
> 0 && height
> 0) {
75 vDrawHLine(sfc
, x
, y
, width
, clr
);
76 vDrawHLine(sfc
, x
, y
+height
-1, width
, clr
);
77 vDrawVLine(sfc
, x
, y
+1, height
-2, clr
);
78 vDrawVLine(sfc
, x
+width
-1, y
+1, height
-2, clr
);
83 void vDrawRectW (VExSurface
*sfc
, int x
, int y
, int width
, int height
, Uint8 clr
) {
84 if (width
> 0 && height
> 0) {
85 vDrawHLine(sfc
, x
+1, y
, width
-2, clr
);
86 vDrawHLine(sfc
, x
+1, y
+height
-1, width
-2, clr
);
87 vDrawVLine(sfc
, x
, y
+1, height
-2, clr
);
88 vDrawVLine(sfc
, x
+width
-1, y
+1, height
-2, clr
);
93 void vDrawZXStripe (VExSurface
*sfc
, int x
, int y
, int dim
) {
94 static const Uint8 clrs
[4] = {2+8, 6+8, 4+8, 5+8};
97 for (int f
= 0; f
< 4; ++f
, x
+= 8) {
98 for (int y
= 0; y
< 8; ++y
) vDrawHLine(sfc
, x
+(7-y
), y
, 8, clrs
[f
]-dim
);
103 void vDrawWindow (VExSurface
*sfc
, int x
, int y
, int width
, int height
, const char *title
, int tink
, int tpaper
, int wpaper
, int flags
) {
107 if (width
< 1 || (title
&& height
< 9) || (!title
&& height
< 1)) return;
108 strncpy(tit
, (title
? title
: ""), sizeof(tit
));
109 tit
[sizeof(tit
)-1] = '\0';
111 if (strlen(tit
) > w
) tit
[w
] = '\0';
113 vDrawRectW(sfc
, x
, y
, width
, height
, tpaper
);
114 vDrawBar(sfc
, x
+1, y
+1, width
-2, 7, tpaper
);
115 if (width
>= 56 && (flags
&ZXVIDWF_STRIPES
)) vDrawZXStripe(sfc
, x
+width
-44, y
, (flags
&ZXVIDWF_STRIPES_DIM
));
117 if (title
!= NULL
&& title
[0]) {
121 vRestrictClip(sfc
, x
+1, y
, width
-2, 8);
122 vDrawText(sfc
, x
+1, y
, tit
, tink
, 255);
123 vRestoreClip(sfc
, &ci
);
126 vDrawBar(sfc
, x
+1, y
+8, width
-2, height
-9, wpaper
);
128 vPutPixel(sfc
, x
+1, y
+height
-2, tpaper
);
129 vPutPixel(sfc
, x
+width
-2, y
+height
-2, tpaper
);
133 ////////////////////////////////////////////////////////////////////////////////
134 static void vDrawVArrow (VExSurface
*sfc
, const char *bmp
, int x
, int y
, Uint8 ink
, Uint8 paper
) {
135 for (int dy
= 0; dy
< 3; ++dy
) {
136 for (int dx
= 0; dx
< 5; ++dx
) {
137 vPutPixel(sfc
, x
+dx
, y
+dy
, bmp
[dy
*5+dx
]?ink
:paper
);
143 static void vDrawHArrow (VExSurface
*sfc
, const char *bmp
, int x
, int y
, Uint8 ink
, Uint8 paper
) {
144 for (int dy
= 0; dy
< 5; ++dy
) {
145 for (int dx
= 0; dx
< 3; ++dx
) {
146 vPutPixel(sfc
, x
+dx
, y
+dy
, bmp
[dy
*3+dx
]?ink
:paper
);
152 void vDrawUpArrow (VExSurface
*sfc
, int x
, int y
, Uint8 ink
, Uint8 paper
) {
153 static const char bmp
[3][5] = {
158 vDrawVArrow(sfc
, (const char *)bmp
, x
, y
, ink
, paper
);
162 void vDrawDownArrow (VExSurface
*sfc
, int x
, int y
, Uint8 ink
, Uint8 paper
) {
163 static const char bmp
[3][5] = {
168 vDrawVArrow(sfc
, (const char *)bmp
, x
, y
, ink
, paper
);
172 void vDrawLeftArrow (VExSurface
*sfc
, int x
, int y
, Uint8 ink
, Uint8 paper
) {
173 static const char bmp
[5][3] = {
180 vDrawHArrow(sfc
, (const char *)bmp
, x
, y
, ink
, paper
);
184 void vDrawRightArrow (VExSurface
*sfc
, int x
, int y
, Uint8 ink
, Uint8 paper
) {
185 static const char bmp
[5][3] = {
192 vDrawHArrow(sfc
, (const char *)bmp
, x
, y
, ink
, paper
);
196 ////////////////////////////////////////////////////////////////////////////////
197 int vLineCountMaxLen (const char *str
, int *maxlenp
) {
198 int maxlen
= 0, lineCnt
= 0;
202 const char *np
= strchr(str
, '\n');
204 if (!np
) np
= str
+strlen(str
);
205 if (np
-str
> maxlen
) maxlen
= np
-str
;
211 if (maxlenp
) *maxlenp
= maxlen
;
216 ////////////////////////////////////////////////////////////////////////////////
217 void vDrawLine (VExSurface
*sfc
, int x0
, int y0
, int x1
, int y1
, Uint8 clr
) {
218 int dx
= abs(x1
-x0
), sx
= x0
<x1
? 1 : -1;
219 int dy
= -abs(y1
-y0
), sy
= y0
<y1
? 1 : -1;
220 int err
= dx
+dy
; /* error value e_xy */
225 vPutPixel(sfc
, x0
, y0
, clr
);
226 if (x0
== x1
&& y0
== y1
) break;
228 if (e2
>= dy
) { err
+= dy
; x0
+= sx
; } /* e_xy+e_x > 0 */
229 if (e2
<= dx
) { err
+= dx
; y0
+= sy
; } /* e_xy+e_y < 0 */
234 void vDrawCircle (VExSurface
*sfc
, int cx
, int cy
, int radius
, Uint8 clr
) {
235 int error
= -radius
, x
= radius
, y
= 0;
237 void plot4points (int cx
, int cy
, int x
, int y
) {
238 vPutPixel(sfc
, cx
+x
, cy
+y
, clr
);
239 if (x
!= 0) vPutPixel(sfc
, cx
-x
, cy
+y
, clr
);
240 if (y
!= 0) vPutPixel(sfc
, cx
+x
, cy
-y
, clr
);
241 vPutPixel(sfc
, cx
-x
, cy
-y
, clr
);
244 void plot8points (int cx
, int cy
, int x
, int y
) {
245 plot4points(cx
, cy
, x
, y
);
246 plot4points(cx
, cy
, y
, x
);
249 if (radius
<= 0) return;
250 //if (radius == 1) { vPutPixel(sfc, cx, cy, clr); return; }
253 plot8points(cx
, cy
, x
, y
);
256 if (error
>= 0) { --x
; error
-= x
*2; }
258 plot4points(cx
, cy
, x
, y
);
262 void vDrawEllipse (VExSurface
*sfc
, int x0
, int y0
, int x1
, int y1
, Uint8 clr
) {
263 int a
= abs(x1
-x0
), b
= abs(y1
-y0
), b1
= b
&1; /* values of diameter */
264 long dx
= 4*(1-a
)*b
*b
, dy
= 4*(b1
+1)*a
*a
; /* error increment */
265 long err
= dx
+dy
+b1
*a
*a
; /* error of 1.step */
267 if (x0
> x1
) { x0
= x1
; x1
+= a
; } /* if called with swapped points... */
268 if (y0
> y1
) y0
= y1
; /* ...exchange them */
269 y0
+= (b
+1)/2; y1
= y0
-b1
; /* starting pixel */
270 a
*= 8*a
; b1
= 8*b
*b
;
275 vPutPixel(sfc
, x1
, y0
, clr
); /* I. Quadrant */
276 vPutPixel(sfc
, x0
, y0
, clr
); /* II. Quadrant */
277 vPutPixel(sfc
, x0
, y1
, clr
); /* III. Quadrant */
278 vPutPixel(sfc
, x1
, y1
, clr
); /* IV. Quadrant */
280 if (e2
>= dx
) { ++x0
; --x1
; err
+= dx
+= b1
; } /* x step */
281 if (e2
<= dy
) { ++y0
; --y1
; err
+= dy
+= a
; } /* y step */
285 /* too early stop of flat ellipses a=1 */
286 vPutPixel(sfc
, x0
-1, ++y0
, clr
); /* -> complete tip of ellipse */
287 vPutPixel(sfc
, x0
-1, --y1
, clr
);
292 void vDrawFilledCircle (VExSurface
*sfc
, int cx
, int cy
, int radius
, Uint8 clr
) {
293 int error
= -radius
, x
= radius
, y
= 0;
295 void plothline (int cx
, int cy
, int x
) {
298 if (x0
> x1
) { int t
= x0
; x0
= x1
; x1
= t
; }
300 vPutPixel(sfc
, x0
, cy
, clr
);
302 vDrawHLine(sfc
, x0
, cy
, x1
-x0
+1, clr
);
306 void plothlines (int cx
, int cy
, int x
, int y
) {
307 plothline(cx
, cy
+y
, x
);
308 if (y
!= 0) plothline(cx
, cy
-y
, x
);
311 if (radius
<= 0) return;
312 //if (radius == 1) { vPutPixel(sfc, cx, cy, clr); return; }
315 plothlines(cx
, cy
, x
, y
);
316 plothlines(cx
, cy
, y
, x
);
319 if (error
>= 0) { --x
; error
-= x
*2; }
321 plothlines(cx
, cy
, x
, y
);
325 void vDrawFilledEllipse (VExSurface
*sfc
, int x0
, int y0
, int x1
, int y1
, Uint8 clr
) {
326 int a
= abs(x1
-x0
), b
= abs(y1
-y0
), b1
= b
&1; /* values of diameter */
327 long dx
= 4*(1-a
)*b
*b
, dy
= 4*(b1
+1)*a
*a
; /* error increment */
328 long err
= dx
+dy
+b1
*a
*a
; /* error of 1.step */
330 if (x0
> x1
) { x0
= x1
; x1
+= a
; } /* if called with swapped points... */
331 if (y0
> y1
) y0
= y1
; /* ...exchange them */
332 y0
+= (b
+1)/2; y1
= y0
-b1
; /* starting pixel */
333 a
*= 8*a
; b1
= 8*b
*b
;
338 vDrawHLine(sfc
, x0
, y0
, x1
-x0
+1, clr
);
339 vDrawHLine(sfc
, x0
, y1
, x1
-x0
+1, clr
);
340 //vPutPixel(sfc, x1, y0, 2); /* I. Quadrant */
341 //vPutPixel(sfc, x0, y0, 2); /* II. Quadrant */
342 //vPutPixel(sfc, x0, y1, clr); /* III. Quadrant */
343 //vPutPixel(sfc, x1, y1, clr); /* IV. Quadrant */
345 if (e2
>= dx
) { ++x0
; --x1
; err
+= dx
+= b1
; } /* x step */
346 if (e2
<= dy
) { ++y0
; --y1
; err
+= dy
+= a
; } /* y step */
350 /* too early stop of flat ellipses a=1 */
351 vPutPixel(sfc
, x0
-1, ++y0
, clr
); /* -> complete tip of ellipse */
352 vPutPixel(sfc
, x0
-1, --y1
, clr
);
357 ////////////////////////////////////////////////////////////////////////////////
358 void vDrawSelectionRect (VExSurface
*sfc
, int phase
, int x0
, int y0
, int wdt
, int hgt
, Uint8 col0
, Uint8 col1
) {
359 if (wdt
< 1 || hgt
< 1) return;
361 for (int f
= x0
; f
< x0
+wdt
; ++f
, ++phase
) vPutPixel(sfc
, f
, y0
, ((phase
%= 4)<2)?col0
:col1
);
363 for (int f
= y0
+1; f
< y0
+hgt
; ++f
, ++phase
) vPutPixel(sfc
, x0
+wdt
-1, f
, ((phase
%= 4)<2)?col0
:col1
);
365 for (int f
= x0
+wdt
-2; f
>= x0
; --f
, ++phase
) vPutPixel(sfc
, f
, y0
+hgt
-1, ((phase
%= 4)<2)?col0
:col1
);
367 for (int f
= y0
+hgt
-2; f
>= y0
; --f
, ++phase
) vPutPixel(sfc
, x0
, f
, ((phase
%= 4)<2)?col0
:col1
);
371 ////////////////////////////////////////////////////////////////////////////////
375 Uint8 msCurClr1
= 15;
378 void drawMouseCursor (int x
, int y
, int type
) {
379 if (type
< 0) type
= AID_COOKE
; else if (type
> AID_EMPTY
) type
= AID_COOKE
;
380 for (int dy
= 0; dy
< 16; ++dy
, ++y
) {
381 for (int dx
= 0; dx
< 16; ++dx
) {
382 switch (winCur
[type
][dy
][dx
]) {
383 case 1: putPixel(x
+dx
, y
, msCurClr0
); break;
384 case 2: putPixel(x
+dx
, y
, msCurClr1
); break;