added 'videolib' snapshot
[k8-jellyphysics.git] / src / videolib / videolib.c
blob0247bd50fca1f9dc1c482194d109abc1554d5fbc
1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
9 */
10 #include "videolib.h"
13 ////////////////////////////////////////////////////////////////////////////////
14 int sdl_fs = 0;
15 int sdl_opengl = 1;
16 int sdl_vsync = 1;
17 int sdl_real_fs = 0;
19 int sdl_mag2x = 1;
20 int sdl_scanlines = 1;
21 sdl_filter_t sdl_filter = SDL_FILTER_NONE;
23 static int sdlc_mag2x; /* effective sdl_mag2x */
24 static int sdl_inited = 0;
27 ////////////////////////////////////////////////////////////////////////////////
28 SDL_Window *sdl_win = NULL;
29 SDL_Renderer *sdl_rend = NULL;
30 SDL_Texture *sdl_scr = NULL;
31 Uint32 *sdl_vscr = NULL;
32 static SDL_Texture *sdl_scr2x = NULL;
33 static Uint32 *sdl_vscr2x = NULL;
34 static int sdl_prev_log_size_1x = 0;
37 ////////////////////////////////////////////////////////////////////////////////
38 void videolib_args (int *argc, char *argv[]) {
39 int f = 1;
40 while (f < argc[0]) {
41 int remove = 1;
42 if (strcmp(argv[f], "--") == 0) break;
43 else if (strcmp(argv[f], "--fs") == 0) sdl_fs = 1;
44 else if (strcmp(argv[f], "--realfs") == 0) sdl_real_fs = 1;
45 else if (strcmp(argv[f], "--winfs") == 0) sdl_real_fs = 0;
46 else if (strcmp(argv[f], "--win") == 0) sdl_fs = 0;
47 else if (strcmp(argv[f], "--tv") == 0) sdl_scanlines = 1;
48 else if (strcmp(argv[f], "--notv") == 0) sdl_scanlines = 0;
49 else if (strcmp(argv[f], "--bw") == 0) sdl_filter = SDL_FILTER_BLACKNWHITE;
50 else if (strcmp(argv[f], "--green") == 0) sdl_filter = SDL_FILTER_GREEN;
51 else if (strcmp(argv[f], "--1x") == 0) sdl_mag2x = 0;
52 else if (strcmp(argv[f], "--2x") == 0) sdl_mag2x = 1;
53 else if (strcmp(argv[f], "--vbl") == 0) sdl_vsync = 1;
54 else if (strcmp(argv[f], "--novbl") == 0) sdl_vsync = 0;
55 else remove = 0;
56 if (remove) {
57 for (int c = f+1; c < *argc; ++c) argv[c-1] = argv[c];
58 --argc[0];
59 } else {
60 ++f;
66 ////////////////////////////////////////////////////////////////////////////////
67 static void cleanup (void) {
68 if (sdl_win && sdl_fs && sdl_real_fs) SDL_SetWindowFullscreen(sdl_win, 0);
69 if (sdl_scr) SDL_DestroyTexture(sdl_scr);
70 if (sdl_scr2x) SDL_DestroyTexture(sdl_scr2x);
71 if (sdl_rend) SDL_DestroyRenderer(sdl_rend);
72 if (sdl_win) SDL_DestroyWindow(sdl_win);
73 if (sdl_vscr) free(sdl_vscr);
74 if (sdl_vscr2x) free(sdl_vscr2x);
75 sdl_win = NULL;
76 sdl_rend = NULL;
77 sdl_scr = NULL;
78 sdl_vscr = NULL;
79 sdl_scr2x = NULL;
80 sdl_vscr2x = NULL;
84 static void quit_cleanup (void) {
85 cleanup();
86 if (sdl_inited) { SDL_Quit(); sdl_inited = 0; }
90 int videolib_deinit (void) {
91 quit_cleanup();
92 return 0;
96 int videolib_init (const char *window_name) {
97 if (sdl_win == NULL) {
98 SDL_Init(SDL_INIT_VIDEO|SDL_INIT_EVENTS|SDL_INIT_TIMER);
99 sdl_inited = 1;
100 atexit(quit_cleanup);
101 sdlc_mag2x = (!!sdl_mag2x)+1;
102 sdl_prev_log_size_1x = 1;
103 sdl_vscr = realloc(sdl_vscr, SCR_WIDTH*SCR_HEIGHT*sizeof(sdl_vscr[0]));
104 if (sdl_vscr == NULL) {
105 fprintf(stderr, "FATAL: out of memory for virtual screen!\n");
106 return -1;
108 sdl_vscr2x = realloc(sdl_vscr2x, SCR_WIDTH*sdlc_mag2x*SCR_HEIGHT*sdlc_mag2x*sizeof(sdl_vscr2x[0]));
109 if (sdl_vscr == NULL) {
110 fprintf(stderr, "FATAL: out of memory for 2x virtual screen!\n");
111 return -1;
113 sdl_win = SDL_CreateWindow((window_name ? window_name : "SDL Application"),
114 SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCR_WIDTH*sdlc_mag2x, SCR_HEIGHT*sdlc_mag2x,
115 (sdl_fs ? (sdl_real_fs ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP) : 0)|(sdl_opengl ? SDL_WINDOW_OPENGL : 0));
116 if (sdl_win == NULL) {
117 fprintf(stderr, "FATAL: can't create SDL window: %s\n", SDL_GetError());
118 return -1;
120 sdl_rend = SDL_CreateRenderer(sdl_win, -1, (sdl_vsync ? SDL_RENDERER_PRESENTVSYNC : 0));
121 if (sdl_rend == NULL) {
122 fprintf(stderr, "FATAL: can't create SDL renderer: %s\n", SDL_GetError());
123 return -1;
125 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); // "nearest" or "linear"
126 SDL_RenderSetLogicalSize(sdl_rend, SCR_WIDTH*(2-sdl_prev_log_size_1x), SCR_HEIGHT*(2-sdl_prev_log_size_1x));
127 sdl_scr = SDL_CreateTexture(sdl_rend, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCR_WIDTH, SCR_HEIGHT);
128 if (sdl_scr == NULL) {
129 fprintf(stderr, "FATAL: can't create SDL texture: %s\n", SDL_GetError());
130 return -1;
132 if (sdlc_mag2x == 2) {
133 sdl_scr2x = SDL_CreateTexture(sdl_rend, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCR_WIDTH*2, SCR_HEIGHT*2);
134 if (sdl_scr2x == NULL) {
135 fprintf(stderr, "FATAL: can't create SDL texture: %s\n", SDL_GetError());
136 return -1;
140 return 0;
144 ////////////////////////////////////////////////////////////////////////////////
145 void switch_fullscreen (void) {
146 sdl_fs = !sdl_fs;
147 if (SDL_SetWindowFullscreen(sdl_win, (sdl_fs ? (sdl_real_fs ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP) : 0)) != 0) {
148 fprintf(stderr, "FATAL: can't switch fullscreen mode: %s\n", SDL_GetError());
149 sdl_fs = !sdl_fs;
150 return;
152 if (!sdl_fs) {
153 SDL_SetWindowSize(sdl_win, SCR_WIDTH*sdlc_mag2x, SCR_HEIGHT*sdlc_mag2x);
154 SDL_SetWindowPosition(sdl_win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
159 ////////////////////////////////////////////////////////////////////////////////
160 extern void post_quit_message (void) {
161 SDL_Event evt;
162 memset(&evt, 0, sizeof(evt));
163 evt.type = SDL_QUIT;
164 SDL_PushEvent(&evt);
168 ////////////////////////////////////////////////////////////////////////////////
169 int sdl_frame_changed = 1;
172 ////////////////////////////////////////////////////////////////////////////////
173 static void blit1x_bw (void) {
174 const Uint8 *s = (const Uint8 *)sdl_vscr;
175 Uint8 *d = (Uint8 *)sdl_vscr2x;
176 int f = SCR_WIDTH*SCR_HEIGHT;
177 while (f--) {
178 Uint8 i = (s[0]*28+s[1]*151+s[2]*77)/256; /* intensity */
179 d[0] = d[1] = d[2] = i;
180 s += 4;
181 d += 4;
186 static void blit1x_green (void) {
187 const Uint8 *s = (const Uint8 *)sdl_vscr;
188 Uint8 *d = (Uint8 *)sdl_vscr2x;
189 int f = SCR_WIDTH*SCR_HEIGHT;
190 while (f--) {
191 Uint8 i = (s[0]*28+s[1]*151+s[2]*77)/256; /* intensity */
192 d[0] = d[2] = 0;
193 d[1] = i;
194 s += 4;
195 d += 4;
200 ////////////////////////////////////////////////////////////////////////////////
201 static void blit2xtv (void) {
202 const Uint32 *s = sdl_vscr;
203 Uint32 *d = sdl_vscr2x;
204 for (int y = 0; y < SCR_HEIGHT; ++y) {
205 int x = SCR_WIDTH;
206 while (x--) {
207 Uint32 c0 = *s++, c1;
208 c1 = (((c0&0x00ff00ff)*6)>>3)&0x00ff00ff;
209 c1 |= (((c0&0x0000ff00)*6)>>3)&0x0000ff00;
210 d[0] = d[1] = c0;
211 d[SCR_WIDTH*2+0] = d[SCR_WIDTH*2+1] = c1;
212 d += 2;
214 /* fix d: skip one scanline */
215 d += SCR_WIDTH*2;
220 static void blit2xtv_bw (void) {
221 const Uint8 *s = (const Uint8 *)sdl_vscr;
222 Uint32 *d = sdl_vscr2x;
223 for (int y = 0; y < SCR_HEIGHT; ++y) {
224 int x = SCR_WIDTH;
225 while (x--) {
226 Uint32 c0, c1;
227 Uint8 i = (s[0]*28+s[1]*151+s[2]*77)/256; /* intensity */
228 c0 = (i<<16)|(i<<8)|i;
229 c1 = (((c0&0x00ff00ff)*6)>>3)&0x00ff00ff;
230 c1 |= (((c0&0x0000ff00)*6)>>3)&0x0000ff00;
231 d[0] = d[1] = c0;
232 d[SCR_WIDTH*2+0] = d[SCR_WIDTH*2+1] = c1;
233 s += 4;
234 d += 2;
236 /* fix d: skip one scanline */
237 d += SCR_WIDTH*2;
242 static void blit2xtv_green (void) {
243 const Uint8 *s = (const Uint8 *)sdl_vscr;
244 Uint32 *d = sdl_vscr2x;
245 for (int y = 0; y < SCR_HEIGHT; ++y) {
246 int x = SCR_WIDTH;
247 while (x--) {
248 Uint32 c0, c1;
249 Uint8 i = (s[0]*28+s[1]*151+s[2]*77)/256; /* intensity */
250 c0 = i<<8;
251 c1 = (((c0&0x00ff00ff)*6)>>3)&0x00ff00ff;
252 c1 |= (((c0&0x0000ff00)*6)>>3)&0x0000ff00;
253 d[0] = d[1] = c0;
254 d[SCR_WIDTH*2+0] = d[SCR_WIDTH*2+1] = c1;
255 s += 4;
256 d += 2;
258 /* fix d: skip one scanline */
259 d += SCR_WIDTH*2;
264 ////////////////////////////////////////////////////////////////////////////////
265 void paint_screen (void) {
266 /* fix 'logical size' */
267 if (sdlc_mag2x == 2 && sdl_scanlines) {
268 /* mag2x and scanlines: size is 2x */
269 if (sdl_prev_log_size_1x) {
270 sdl_prev_log_size_1x = 0;
271 SDL_RenderSetLogicalSize(sdl_rend, SCR_WIDTH*2, SCR_HEIGHT*2);
273 } else {
274 /* any other case: size is 2x */
275 if (!sdl_prev_log_size_1x) {
276 sdl_prev_log_size_1x = 1;
277 SDL_RenderSetLogicalSize(sdl_rend, SCR_WIDTH, SCR_HEIGHT);
280 /* apply filters if any */
281 if (sdlc_mag2x == 2 && sdl_scanlines) {
282 /* heavy case: scanline filter turned on */
283 switch (sdl_filter) {
284 case SDL_FILTER_NONE: blit2xtv(); break;
285 case SDL_FILTER_BLACKNWHITE: blit2xtv_bw(); break;
286 case SDL_FILTER_GREEN: blit2xtv_green(); break;
288 SDL_UpdateTexture(sdl_scr2x, NULL, sdl_vscr2x, SCR_WIDTH*2*sizeof(sdl_vscr2x[0]));
289 SDL_RenderCopy(sdl_rend, sdl_scr2x, NULL, NULL);
290 } else {
291 /* light cases */
292 if (sdl_filter == SDL_FILTER_NONE) {
293 /* easiest case */
294 SDL_UpdateTexture(sdl_scr, NULL, sdl_vscr, SCR_WIDTH*sizeof(sdl_vscr[0]));
295 } else {
296 switch (sdl_filter) {
297 case SDL_FILTER_BLACKNWHITE: blit1x_bw(); break;
298 case SDL_FILTER_GREEN: blit1x_green(); break;
299 default: memcpy(sdl_vscr2x, sdl_vscr, SCR_WIDTH*SCR_HEIGHT); break; /* just in case */
301 SDL_UpdateTexture(sdl_scr, NULL, sdl_vscr2x, SCR_WIDTH*sizeof(sdl_vscr2x[0]));
303 SDL_RenderCopy(sdl_rend, sdl_scr, NULL, NULL);
305 SDL_RenderPresent(sdl_rend);
306 sdl_frame_changed = 0;
310 ////////////////////////////////////////////////////////////////////////////////
311 #ifdef VIDEOLIB_ENABLE_TEXT
312 #include "vfont_msx.c"
315 void draw_char (int x, int y, char ch, Uint32 col, Uint32 bkcol) {
316 int pos = (ch&0xff)*8;
317 for (int dy = 0; dy < 8; ++dy) {
318 unsigned char b = font_msx[pos++];
319 for (int dx = 0; dx < 6; ++dx) {
320 if (b&0x80) { if (col != TRANSPARENT_COLOR) put_pixel(x+dx, y+dy, col); }
321 else if (bkcol != TRANSPARENT_COLOR) put_pixel(x+dx, y+dy, bkcol);
322 b = (b&0x7f)<<1;
328 void draw_str (int x, int y, const char *str, Uint32 col, Uint32 bkcol) {
329 if (!str) return;
330 while (*str) {
331 draw_char(x, y, *str++, col, bkcol);
332 x += 6;
335 #endif
338 ////////////////////////////////////////////////////////////////////////////////
339 #ifdef VIDEOLIB_ENABLE_PRTEXT
340 #include "vfont_pr.c"
341 int char_width_pr (char ch) {
342 return (prfontwdt[ch&0xff]);
346 int str_width_pr (const char *str) {
347 int wdt = 0;
348 if (str != NULL && str[0]) {
349 while (*str) {
350 wdt += prfontwdt[str[0]&0xff]+1;
351 ++str;
353 --wdt;
355 return wdt;
359 int draw_char_pr (int x, int y, char ch, Uint32 col, Uint32 bkcol) {
360 int pos = (ch&0xff)*8;
361 int wdt = prfontwdt[ch&0xff];
362 for (int dy = 0; dy < 8; ++dy) {
363 unsigned char b = prfont[pos++];
364 for (int dx = 0; dx < wdt; ++dx) {
365 Uint32 c = (b&0x80 ? col : bkcol);
366 if (c != TRANSPARENT_COLOR) put_pixel(x+dx, y+dy, c);
367 b = (b&0x7f)<<1;
370 return wdt;
374 int draw_str_pr (int x, int y, const char *str, Uint32 col, Uint32 bkcol) {
375 int wdt = 0;
376 if (str != NULL && str[0]) {
377 while (*str) {
378 wdt += prfontwdt[str[0]&0xff]+1;
379 x += draw_char_pr(x, y, *str++, col, bkcol);
380 if (*str && bkcol != TRANSPARENT_COLOR) for (int dy = 0; dy < 8; ++dy) put_pixel(x, y+dy, bkcol);
381 ++x;
383 --wdt;
385 return wdt;
387 #endif
390 ////////////////////////////////////////////////////////////////////////////////
391 #ifdef VIDEOLIB_ENABLE_SFONT
392 #include "vfont_sf.c"
395 int char_width_sf (char ch) {
396 if (ch >= 'a' && ch <= 'z') ch -= 32;
397 if (ch < 33 || ch > 95) ch = '?';
398 if (ch != ' ') {
399 const unsigned char *st = font_sf+(ch-32)*2;
400 int ofs = st[0]+256*st[1];
401 st = font_sf+ofs;
402 return (*st)&0x0f;
404 return font_sf[1];
408 int str_width_sf (const char *str) {
409 int wdt = 0;
410 if (str != NULL) {
411 while (*str) wdt += char_width_sf(*str++);
413 return wdt;
417 int draw_char_sf (char ch, int x, int y, Uint32 c0, Uint32 c1) {
418 if (ch >= 'a' && ch <= 'z') ch -= 32;
419 if (ch < 33 || ch > 95) ch = '?';
420 if (ch != ' ') {
421 const unsigned char *st = font_sf+(ch-32)*2;
422 int ofs = st[0]+256*st[1], wdt, yofs, hgt = font_sf[0];
424 st = font_sf+ofs;
425 wdt = *st++;
426 yofs = ((wdt>>4)&0x0f);
427 wdt &= 0x0f;
428 if ((c0&0xff) == 0xff && (c1&0xff) == 0xff) return wdt;
429 y += yofs;
430 while (hgt-- > 0) {
431 int px = x;
432 for (int dx = 0; dx < wdt; dx += 4) {
433 Uint8 b = *st++;
434 for (int c = 0; c < 4; ++c, ++px) {
435 switch ((b>>6)&0x03) {
436 case 0: break;
437 case 1: put_pixel(px, y, c0); break;
438 case 2: put_pixel(px, y, c1); break;
439 case 3: /*put_pixel(x+dx+c, y+dy, 2);*/ break;
441 b = ((b&0x3f)<<2);
444 ++y;
446 return wdt;
447 } else {
448 return font_sf[1];
453 int draw_str_sf (const char *str, int x, int y, Uint32 c0, Uint32 c1) {
454 int wdt = 0;
455 if (str != NULL) {
456 while (*str) {
457 int w = draw_char_sf(*str++, x, y, c0, c1);
458 wdt += w;
459 x += w;
462 return wdt;
464 #endif
467 ////////////////////////////////////////////////////////////////////////////////
468 void draw_hline (int x0, int y0, int len, Uint32 col) {
469 while (len-- > 0) put_pixel(x0++, y0, col);
473 void draw_vline (int x0, int y0, int len, Uint32 col) {
474 while (len-- > 0) put_pixel(x0, y0++, col);
478 void draw_line (int x0, int y0, int x1, int y1, Uint32 col) {
479 int dx = abs(x1-x0), sx = (x0 < x1 ? 1 : -1);
480 int dy = -abs(y1-y0), sy = (y0 < y1 ? 1 : -1);
481 int err = dx+dy, e2; /* error value e_xy */
482 for (;;) {
483 put_pixel(x0, y0, col);
484 if (x0 == x1 && y0 == y1) break;
485 e2 = 2*err;
486 if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
487 if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
492 void draw_line_no_last (int x0, int y0, int x1, int y1, Uint32 col) {
493 int dx = abs(x1-x0), sx = (x0 < x1 ? 1 : -1);
494 int dy = -abs(y1-y0), sy = (y0 < y1 ? 1 : -1);
495 int err = dx+dy, e2; /* error value e_xy */
496 for (;;) {
497 if (x0 == x1 && y0 == y1) break;
498 put_pixel(x0, y0, col);
499 e2 = 2*err;
500 if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
501 if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
506 void fill_rect (int x, int y, int w, int h, Uint32 col) {
507 if (w > 0 && h > 0 && x < SCR_WIDTH && y < SCR_HEIGHT && x+w >= 0 && y+h >= 0) {
508 SDL_Rect r, sr, dr;
509 sr.x = 0; sr.y = 0; sr.w = SCR_WIDTH; sr.h = SCR_HEIGHT;
510 r.x = x; r.y = y; r.w = w; r.h = h;
511 if (SDL_IntersectRect(&sr, &r, &dr)) {
512 y = dr.y;
513 while (dr.h-- > 0) {
514 x = dr.x;
515 for (int dx = dr.w; dx > 0; --dx, ++x) put_pixel(x, y, col);
516 ++y;
519 Uint32 a = dr.y*SCR_WIDTH+dr.x;
520 while (dr.h-- > 0) {
521 Uint32 da = a;
522 for (int f = dr.w; f > 0; --f) sdl_vscr[da++] = col;
523 a += SCR_WIDTH;
531 void draw_rect (int x, int y, int w, int h, Uint32 col) {
532 if (w > 0 && h > 0) {
533 draw_hline(x, y, w, col);
534 draw_hline(x, y+h-1, w, col);
535 draw_vline(x, y+1, h-2, col);
536 draw_vline(x+w-1, y+1, h-2, col);
541 void draw_selection_rect (int phase, int x0, int y0, int wdt, int hgt, Uint32 col0, Uint32 col1) {
542 if (wdt > 0 && hgt > 0) {
543 // top
544 for (int f = x0; f < x0+wdt; ++f, ++phase) put_pixel(f, y0, ((phase %= 4) < 2 ? col0 : col1));
545 // right
546 for (int f = y0+1; f < y0+hgt; ++f, ++phase) put_pixel(x0+wdt-1, f, ((phase %= 4) < 2 ? col0 : col1));
547 // bottom
548 for (int f = x0+wdt-2; f >= x0; --f, ++phase) put_pixel(f, y0+hgt-1, ((phase %= 4) < 2 ? col0 : col1));
549 // left
550 for (int f = y0+hgt-2; f >= y0; --f, ++phase) put_pixel(x0, f, ((phase %= 4)<2 ? col0 : col1));
555 ////////////////////////////////////////////////////////////////////////////////
556 #ifdef VIDEOLIB_ENABLE_CIRCLE_ELLIPSE
558 #define PLOT_4_POINTS(_cx,_cy,_x,_y) do { \
559 put_pixel((_cx)+(_x), (_cy)+(_y), clr); \
560 if ((_x) != 0) put_pixel((_cx)-(_x), (_cy)+(_y), clr); \
561 if ((_y) != 0) put_pixel((_cx)+(_x), (_cy)-(_y), clr); \
562 put_pixel((_cx)-(_x), (_cy)-(_y), clr); \
563 } while (0)
566 void draw_circle (int cx, int cy, int radius, Uint32 clr) {
567 if (radius > 0 && (clr&0xff000000u) != 0xff000000u) {
568 int error = -radius, x = radius, y = 0;
569 if (radius == 1) { put_pixel(cx, cy, clr); return; }
570 while (x > y) {
571 PLOT_4_POINTS(cx, cy, x, y);
572 PLOT_4_POINTS(cx, cy, y, x);
573 error += y*2+1;
574 ++y;
575 if (error >= 0) { --x; error -= x*2; }
577 PLOT_4_POINTS(cx, cy, x, y);
582 void draw_filled_circle (int cx, int cy, int radius, Uint32 clr) {
583 if (radius > 0 && (clr&0xff000000u) != 0xff000000u) {
584 int error = -radius, x = radius, y = 0;
585 if (radius == 1) { put_pixel(cx, cy, clr); return; }
586 while (x >= y) {
587 int last_y = y;
588 error += y;
589 ++y;
590 error += y;
591 draw_hline(cx-x, cy+last_y, 2*x+1, clr);
592 if (x != 0 && last_y != 0) draw_hline(cx-x, cy-last_y, 2*x+1, clr);
593 if (error >= 0) {
594 if (x != last_y) {
595 draw_hline(cx-last_y, cy+x, 2*last_y+1, clr);
596 if (last_y != 0 && x != 0) draw_hline(cx-last_y, cy-x, 2*last_y+1, clr);
598 error -= x;
599 --x;
600 error -= x;
607 void draw_ellipse (int x0, int y0, int x1, int y1, Uint32 clr) {
608 int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */
609 long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
610 long err = dx+dy+b1*a*a; /* error of 1.step */
611 if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points... */
612 if (y0 > y1) y0 = y1; /* ...exchange them */
613 y0 += (b+1)/2; y1 = y0-b1; /* starting pixel */
614 a *= 8*a; b1 = 8*b*b;
615 do {
616 int e2;
617 put_pixel(x1, y0, clr); /* I. Quadrant */
618 put_pixel(x0, y0, clr); /* II. Quadrant */
619 put_pixel(x0, y1, clr); /* III. Quadrant */
620 put_pixel(x1, y1, clr); /* IV. Quadrant */
621 e2 = 2*err;
622 if (e2 >= dx) { ++x0; --x1; err += dx += b1; } /* x step */
623 if (e2 <= dy) { ++y0; --y1; err += dy += a; } /* y step */
624 } while (x0 <= x1);
625 while (y0-y1 < b) {
626 /* too early stop of flat ellipses a=1 */
627 put_pixel(x0-1, ++y0, clr); /* -> complete tip of ellipse */
628 put_pixel(x0-1, --y1, clr);
633 void draw_filled_ellipse (int x0, int y0, int x1, int y1, Uint32 clr) {
634 int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */
635 long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
636 long err = dx+dy+b1*a*a; /* error of 1.step */
637 int prev_y0 = -1, prev_y1 = -1;
638 if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points... */
639 if (y0 > y1) y0 = y1; /* ...exchange them */
640 y0 += (b+1)/2; y1 = y0-b1; /* starting pixel */
641 a *= 8*a; b1 = 8*b*b;
642 do {
643 int e2;
644 if (y0 != prev_y0) { draw_hline(x0, y0, x1-x0+1, clr); prev_y0 = y0; }
645 if (y1 != y0 && y1 != prev_y1) { draw_hline(x0, y1, x1-x0+1, clr); prev_y1 = y1; }
646 e2 = 2*err;
647 if (e2 >= dx) { ++x0; --x1; err += dx += b1; } /* x step */
648 if (e2 <= dy) { ++y0; --y1; err += dy += a; } /* y step */
649 } while (x0 <= x1);
650 while (y0-y1 < b) {
651 /* too early stop of flat ellipses a=1 */
652 put_pixel(x0-1, ++y0, clr); /* -> complete tip of ellipse */
653 put_pixel(x0-1, --y1, clr);
656 #endif
659 #ifdef VIDEOLIB_ENABLE_POLYMOD
660 void vl_polymod_fill_scr (Uint32 col) {
661 void hline (int x, int y, int len) { draw_hline(x, y, len, col); }
663 vl_polymod_hline_fn ocb = vl_polymod_hline;
664 vl_polymod_hline = hline;
665 vl_polymod_fill();
666 vl_polymod_hline = ocb;
668 #endif