1 /*
2 
3  SDL_gfxPrimitives - Graphics primitives for SDL surfaces
4 
5  GPLv3 (c) A. Schiffler
6 
7  License changed from LGPL to GPLv3, as per section 3 of the LGPL,
8      by M. Bays 2008.
9  Dirty pixels/rects handling added by M. Bays 2008.
10 
11 */
12 
13 #include <cstdio>
14 #include <cstdlib>
15 #include <cmath>
16 #include <cstring>
17 
18 #include <vector>
19 
20 #include "SDL_gfxPrimitivesDirty.h"
21 #include "SDL_gfxPrimitives_font.h"
22 
23 /* -===================- */
24 
25 //#define MODIFIED_ALPHA_PIXEL_ROUTINE
26 #define ORIGINAL_ALPHA_PIXEL_ROUTINE
27 
28 /* ----- Defines for pixel clipping tests */
29 
30 #define clip_xmin(surface) surface->clip_rect.x
31 #define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1
32 #define clip_ymin(surface) surface->clip_rect.y
33 #define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1
34 
35 SDL_Surface* dirtyDst = NULL;
36 SDL_Surface* dirtyBackground = NULL;
37 std::vector<Uint8*> dirtyPixels;
38 std::vector<SDL_Rect> dirtyRects;
39 
40 // Set surface to accumulate dirtiness information for subsequent calls to
41 // blankDirty, which will then redraw the background over dirtied pixels.
42 // &background should be either a surface of the same size and format as &dst,
43 // or NULL to indicate a black background.
setDirty(SDL_Surface * dst,SDL_Surface * background)44 void setDirty(SDL_Surface* dst, SDL_Surface* background)
45 {
46     dirtyDst = dst;
47     dirtyBackground = background;
48     dirtyPixels.clear();
49     dirtyRects.clear();
50 }
51 
blankDirty()52 int blankDirty()
53 {
54     if (!dirtyDst)
55 	return -1;
56 
57     /*
58      * Lock the surface
59      */
60     if (SDL_MUSTLOCK(dirtyDst)) {
61 	if (SDL_LockSurface(dirtyDst) < 0) {
62 	    return (-1);
63 	}
64     }
65 
66     const Uint32 black = 0;
67 
68     while (!dirtyPixels.empty())
69     {
70 	Uint8* p = dirtyPixels.back();
71 	dirtyPixels.pop_back();
72 	int bpp = dirtyDst->format->BytesPerPixel;
73 	if (dirtyBackground)
74 	{
75 	    const Uint8* bp = (Uint8*)dirtyBackground->pixels + (p -
76 		    (Uint8*)dirtyDst->pixels);
77 	    for (int i=0; i<bpp; i++)
78 		*(p+i) = *(bp+i);
79 	}
80 	else
81 	{
82 	    switch (bpp) {
83 		case 1:
84 		    *p = black;
85 		    break;
86 		case 2:
87 		    *(Uint16 *) p = black;
88 		    break;
89 		case 3:
90 		    {
91 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
92 			    p[0] = (black >> 16) & 0xff;
93 			    p[1] = (black >> 8) & 0xff;
94 			    p[2] = black & 0xff;
95 			} else {
96 			    p[0] = black & 0xff;
97 			    p[1] = (black >> 8) & 0xff;
98 			    p[2] = (black >> 16) & 0xff;
99 			}
100 		    }
101 		    break;
102 		case 4:
103 		    *(Uint32 *) p = black;
104 		    break;
105 	    }			/* switch */
106 	}
107     }
108 
109     /*
110      * Unlock the surface
111      */
112     if (SDL_MUSTLOCK(dirtyDst)) {
113 	SDL_UnlockSurface(dirtyDst);
114     }
115 
116     while (!dirtyRects.empty())
117     {
118 	SDL_Rect rect = dirtyRects.back();
119 	dirtyRects.pop_back();
120 	if (dirtyBackground)
121 	    SDL_BlitSurface(dirtyBackground, &rect, dirtyDst, &rect);
122 	else
123 	    SDL_FillRect(dirtyDst, &rect, 0);
124     }
125 
126     return 0;
127 }
128 
129 /* ----- Pixel - fast, no blending, no locking, clipping */
130 
fastPixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)131 int fastPixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
132 {
133     int bpp;
134     Uint8 *p;
135 
136     /*
137      * Honor clipping setup at pixel level
138      */
139     if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) {
140 
141 	/*
142 	 * Get destination format
143 	 */
144 	bpp = dst->format->BytesPerPixel;
145 	p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
146 	if (dirtyDst == dst)
147 	    dirtyPixels.push_back(p);
148 	switch (bpp) {
149 	case 1:
150 	    *p = color;
151 	    break;
152 	case 2:
153 	    *(Uint16 *) p = color;
154 	    break;
155 	case 3:
156 	    if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
157 		p[0] = (color >> 16) & 0xff;
158 		p[1] = (color >> 8) & 0xff;
159 		p[2] = color & 0xff;
160 	    } else {
161 		p[0] = color & 0xff;
162 		p[1] = (color >> 8) & 0xff;
163 		p[2] = (color >> 16) & 0xff;
164 	    }
165 	    break;
166 	case 4:
167 	    *(Uint32 *) p = color;
168 	    break;
169 	}			/* switch */
170 
171 
172     }
173 
174     return (0);
175 }
176 
177 /* ----- Pixel - fast, no blending, no locking, no clipping */
178 
179 /* (faster but dangerous, make sure we stay in surface bounds) */
180 
fastPixelColorNolockNoclip(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)181 int fastPixelColorNolockNoclip(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
182 {
183     int bpp;
184     Uint8 *p;
185 
186     /*
187      * Get destination format
188      */
189     bpp = dst->format->BytesPerPixel;
190     p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
191     if (dirtyDst == dst)
192 	dirtyPixels.push_back(p);
193     switch (bpp) {
194     case 1:
195 	*p = color;
196 	break;
197     case 2:
198 	*(Uint16 *) p = color;
199 	break;
200     case 3:
201 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
202 	    p[0] = (color >> 16) & 0xff;
203 	    p[1] = (color >> 8) & 0xff;
204 	    p[2] = color & 0xff;
205 	} else {
206 	    p[0] = color & 0xff;
207 	    p[1] = (color >> 8) & 0xff;
208 	    p[2] = (color >> 16) & 0xff;
209 	}
210 	break;
211     case 4:
212 	*(Uint32 *) p = color;
213 	break;
214     }				/* switch */
215 
216     return (0);
217 }
218 
219 /* ----- Pixel - fast, no blending, locking, clipping */
220 
fastPixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)221 int fastPixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
222 {
223     int result;
224 
225     /*
226      * Lock the surface
227      */
228     if (SDL_MUSTLOCK(dst)) {
229 	if (SDL_LockSurface(dst) < 0) {
230 	    return (-1);
231 	}
232     }
233 
234     result = fastPixelColorNolock(dst, x, y, color);
235 
236     /*
237      * Unlock surface
238      */
239     if (SDL_MUSTLOCK(dst)) {
240 	SDL_UnlockSurface(dst);
241     }
242 
243     return (result);
244 }
245 
246 /* ----- Pixel - fast, no blending, locking, RGB input */
247 
fastPixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)248 int fastPixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
249 {
250     Uint32 color;
251 
252     /*
253      * Setup color
254      */
255     color = SDL_MapRGBA(dst->format, r, g, b, a);
256 
257     /*
258      * Draw
259      */
260     return (fastPixelColor(dst, x, y, color));
261 
262 }
263 
264 /* ----- Pixel - fast, no blending, no locking RGB input */
265 
fastPixelRGBANolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)266 int fastPixelRGBANolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
267 {
268     Uint32 color;
269 
270     /*
271      * Setup color
272      */
273     color = SDL_MapRGBA(dst->format, r, g, b, a);
274 
275     /*
276      * Draw
277      */
278     return (fastPixelColorNolock(dst, x, y, color));
279 }
280 
281 /* PutPixel routine with alpha blending, input color in destination format */
282 
283 /* New, faster routine - default blending pixel */
284 
_putPixelAlpha(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color,Uint8 alpha)285 int _putPixelAlpha(SDL_Surface * surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
286 {
287     Uint32 Rmask = surface->format->Rmask, Gmask =
288 	surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
289     Uint32 R, G, B, A = 0;
290 
291     if (x >= clip_xmin(surface) && x <= clip_xmax(surface)
292 	&& y >= clip_ymin(surface) && y <= clip_ymax(surface)) {
293 
294 	if (dirtyDst == surface)
295 	    dirtyPixels.push_back(
296 		    (Uint8 *) surface->pixels + y * surface->pitch +
297 		    x * surface->format->BytesPerPixel);
298 
299 	switch (surface->format->BytesPerPixel) {
300 	case 1:{		/* Assuming 8-bpp */
301 		if (alpha == 255) {
302 		    *((Uint8 *) surface->pixels + y * surface->pitch + x) = color;
303 		} else {
304 		    Uint8 *pixel = (Uint8 *) surface->pixels + y * surface->pitch + x;
305 
306 		    Uint8 dR = surface->format->palette->colors[*pixel].r;
307 		    Uint8 dG = surface->format->palette->colors[*pixel].g;
308 		    Uint8 dB = surface->format->palette->colors[*pixel].b;
309 		    Uint8 sR = surface->format->palette->colors[color].r;
310 		    Uint8 sG = surface->format->palette->colors[color].g;
311 		    Uint8 sB = surface->format->palette->colors[color].b;
312 
313 		    dR = dR + ((sR - dR) * alpha >> 8);
314 		    dG = dG + ((sG - dG) * alpha >> 8);
315 		    dB = dB + ((sB - dB) * alpha >> 8);
316 
317 		    *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
318 		}
319 	    }
320 	    break;
321 
322 	case 2:{		/* Probably 15-bpp or 16-bpp */
323 		if (alpha == 255) {
324 		    *((Uint16 *) surface->pixels + y * surface->pitch / 2 + x) = color;
325 		} else {
326 		    Uint16 *pixel = (Uint16 *) surface->pixels + y * surface->pitch / 2 + x;
327 		    Uint32 dc = *pixel;
328 
329 		    R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask;
330 		    G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask;
331 		    B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask;
332 		    if (Amask)
333 			A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask;
334 
335 		    *pixel = R | G | B | A;
336 		}
337 	    }
338 	    break;
339 
340 	case 3:{		/* Slow 24-bpp mode, usually not used */
341 		Uint8 *pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
342 		Uint8 rshift8 = surface->format->Rshift / 8;
343 		Uint8 gshift8 = surface->format->Gshift / 8;
344 		Uint8 bshift8 = surface->format->Bshift / 8;
345 		Uint8 ashift8 = surface->format->Ashift / 8;
346 
347 
348 		if (alpha == 255) {
349 		    *(pix + rshift8) = color >> surface->format->Rshift;
350 		    *(pix + gshift8) = color >> surface->format->Gshift;
351 		    *(pix + bshift8) = color >> surface->format->Bshift;
352 		    *(pix + ashift8) = color >> surface->format->Ashift;
353 		} else {
354 		    Uint8 dR, dG, dB, dA = 0;
355 		    Uint8 sR, sG, sB, sA = 0;
356 
357 		    pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
358 
359 		    dR = *((pix) + rshift8);
360 		    dG = *((pix) + gshift8);
361 		    dB = *((pix) + bshift8);
362 		    dA = *((pix) + ashift8);
363 
364 		    sR = (color >> surface->format->Rshift) & 0xff;
365 		    sG = (color >> surface->format->Gshift) & 0xff;
366 		    sB = (color >> surface->format->Bshift) & 0xff;
367 		    sA = (color >> surface->format->Ashift) & 0xff;
368 
369 		    dR = dR + ((sR - dR) * alpha >> 8);
370 		    dG = dG + ((sG - dG) * alpha >> 8);
371 		    dB = dB + ((sB - dB) * alpha >> 8);
372 		    dA = dA + ((sA - dA) * alpha >> 8);
373 
374 		    *((pix) + rshift8) = dR;
375 		    *((pix) + gshift8) = dG;
376 		    *((pix) + bshift8) = dB;
377 		    *((pix) + ashift8) = dA;
378 		}
379 	    }
380 	    break;
381 
382 	case 4:{		/* Probably :-) 32-bpp */
383 		if (alpha == 255) {
384 		    *((Uint32 *) surface->pixels + y * surface->pitch / 4 + x) = color;
385 		} else {
386 		    Uint32 Rshift, Gshift, Bshift, Ashift;
387 		    Uint32 *pixel = (Uint32 *) surface->pixels + y * surface->pitch / 4 + x;
388 		    Uint32 dc = *pixel;
389 
390 		    Rshift = surface->format->Rshift;
391 		    Gshift = surface->format->Gshift;
392 		    Bshift = surface->format->Bshift;
393 		    Ashift = surface->format->Ashift;
394 
395 		    R = ((dc & Rmask) + (((((color & Rmask) - (dc & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask;
396 		    G = ((dc & Gmask) + (((((color & Gmask) - (dc & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask;
397 		    B = ((dc & Bmask) + (((((color & Bmask) - (dc & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask;
398 		    if (Amask)
399 			A = ((dc & Amask) + (((((color & Amask) - (dc & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask;
400 
401 		    *pixel = R | G | B | A;
402 		}
403 	    }
404 	    break;
405 	}
406     }
407 
408     return (0);
409 }
410 
411 /* ----- Pixel - pixel draw with blending enabled if a<255 */
412 
pixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)413 int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
414 {
415     Uint8 alpha;
416     Uint32 mcolor;
417     int result = 0;
418 
419     /*
420      * Lock the surface
421      */
422     if (SDL_MUSTLOCK(dst)) {
423 	if (SDL_LockSurface(dst) < 0) {
424 	    return (-1);
425 	}
426     }
427 
428     /*
429      * Setup color
430      */
431     alpha = color & 0x000000ff;
432     mcolor =
433 	SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
434 		    (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
435 
436     /*
437      * Draw
438      */
439     result = _putPixelAlpha(dst, x, y, mcolor, alpha);
440 
441     /*
442      * Unlock the surface
443      */
444     if (SDL_MUSTLOCK(dst)) {
445 	SDL_UnlockSurface(dst);
446     }
447 
448     return (result);
449 }
450 
pixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)451 int pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
452 {
453     Uint8 alpha;
454     Uint32 mcolor;
455     int result = 0;
456 
457     /*
458      * Setup color
459      */
460     alpha = color & 0x000000ff;
461     mcolor =
462 	SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
463 		    (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
464 
465     /*
466      * Draw
467      */
468     result = _putPixelAlpha(dst, x, y, mcolor, alpha);
469 
470     return (result);
471 }
472 
473 
474 /* Filled rectangle with alpha blending, color in destination format */
475 
_filledRectAlpha(SDL_Surface * surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,Uint8 alpha)476 int _filledRectAlpha(SDL_Surface * surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
477 {
478     Uint32 Rmask = surface->format->Rmask, Gmask =
479 	surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
480     Uint32 R, G, B, A = 0;
481     Sint16 x, y;
482 
483     switch (surface->format->BytesPerPixel) {
484     case 1:{			/* Assuming 8-bpp */
485 	    Uint8 *row, *pixel;
486 	    Uint8 dR, dG, dB;
487 
488 	    Uint8 sR = surface->format->palette->colors[color].r;
489 	    Uint8 sG = surface->format->palette->colors[color].g;
490 	    Uint8 sB = surface->format->palette->colors[color].b;
491 
492 	    for (y = y1; y <= y2; y++) {
493 		row = (Uint8 *) surface->pixels + y * surface->pitch;
494 		for (x = x1; x <= x2; x++) {
495 		    pixel = row + x;
496 
497 		    dR = surface->format->palette->colors[*pixel].r;
498 		    dG = surface->format->palette->colors[*pixel].g;
499 		    dB = surface->format->palette->colors[*pixel].b;
500 
501 		    dR = dR + ((sR - dR) * alpha >> 8);
502 		    dG = dG + ((sG - dG) * alpha >> 8);
503 		    dB = dB + ((sB - dB) * alpha >> 8);
504 
505 		    *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
506 		    if (dirtyDst == surface)
507 			dirtyPixels.push_back(pixel);
508 		}
509 	    }
510 	}
511 	break;
512 
513     case 2:{			/* Probably 15-bpp or 16-bpp */
514 	    Uint16 *row, *pixel;
515 	    Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
516 
517 	    for (y = y1; y <= y2; y++) {
518 		row = (Uint16 *) surface->pixels + y * surface->pitch / 2;
519 		for (x = x1; x <= x2; x++) {
520 		    pixel = row + x;
521 
522 		    R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask;
523 		    G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask;
524 		    B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask;
525 		    if (Amask)
526 			A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask;
527 
528 		    *pixel = R | G | B | A;
529 		    if (dirtyDst == surface)
530 			dirtyPixels.push_back( (Uint8*) pixel );
531 		}
532 	    }
533 	}
534 	break;
535 
536     case 3:{			/* Slow 24-bpp mode, usually not used */
537 	    Uint8 *row, *pix;
538 	    Uint8 dR, dG, dB, dA;
539 	    Uint8 rshift8 = surface->format->Rshift / 8;
540 	    Uint8 gshift8 = surface->format->Gshift / 8;
541 	    Uint8 bshift8 = surface->format->Bshift / 8;
542 	    Uint8 ashift8 = surface->format->Ashift / 8;
543 
544 	    Uint8 sR = (color >> surface->format->Rshift) & 0xff;
545 	    Uint8 sG = (color >> surface->format->Gshift) & 0xff;
546 	    Uint8 sB = (color >> surface->format->Bshift) & 0xff;
547 	    Uint8 sA = (color >> surface->format->Ashift) & 0xff;
548 
549 	    for (y = y1; y <= y2; y++) {
550 		row = (Uint8 *) surface->pixels + y * surface->pitch;
551 		for (x = x1; x <= x2; x++) {
552 		    pix = row + x * 3;
553 
554 		    dR = *((pix) + rshift8);
555 		    dG = *((pix) + gshift8);
556 		    dB = *((pix) + bshift8);
557 		    dA = *((pix) + ashift8);
558 
559 		    dR = dR + ((sR - dR) * alpha >> 8);
560 		    dG = dG + ((sG - dG) * alpha >> 8);
561 		    dB = dB + ((sB - dB) * alpha >> 8);
562 		    dA = dA + ((sA - dA) * alpha >> 8);
563 
564 		    *((pix) + rshift8) = dR;
565 		    *((pix) + gshift8) = dG;
566 		    *((pix) + bshift8) = dB;
567 		    *((pix) + ashift8) = dA;
568 		    if (dirtyDst == surface)
569 			dirtyPixels.push_back(pix);
570 		}
571 	    }
572 
573 	}
574 	break;
575 
576 #ifdef ORIGINAL_ALPHA_PIXEL_ROUTINE
577     case 4:{			/* Probably :-) 32-bpp */
578 	    Uint32 Rshift, Gshift, Bshift, Ashift;
579 	    Uint32 *row, *pixel;
580 	    Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
581 
582 	    Rshift = surface->format->Rshift;
583 	    Gshift = surface->format->Gshift;
584 	    Bshift = surface->format->Bshift;
585 	    Ashift = surface->format->Ashift;
586 
587 	    for (y = y1; y <= y2; y++) {
588 		row = (Uint32 *) surface->pixels + y * surface->pitch / 4;
589 		for (x = x1; x <= x2; x++) {
590 		    pixel = row + x;
591 
592 		    R = ((*pixel & Rmask) + ((((dR - (*pixel & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask;
593 		    G = ((*pixel & Gmask) + ((((dG - (*pixel & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask;
594 		    B = ((*pixel & Bmask) + ((((dB - (*pixel & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask;
595 		    if (Amask)
596 			A = ((*pixel & Amask) + ((((dA - (*pixel & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask;
597 
598 		    *pixel = R | G | B | A;
599 		    if (dirtyDst == surface)
600 			dirtyPixels.push_back( (Uint8*) pixel );
601 		}
602 	    }
603 	}
604 	break;
605 #endif
606 
607 #ifdef MODIFIED_ALPHA_PIXEL_ROUTINE
608     case 4:{			/* Probably :-) 32-bpp */
609 	    Uint32 Rshift, Gshift, Bshift, Ashift;
610 	    Uint32 *row, *pixel;
611 	    Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
612             Uint32 dc;
613             Uint32 preMultR, preMultG, preMultB, preMultA;
614             Uint32 aTmp;
615 
616 	    Rshift = surface->format->Rshift;
617 	    Gshift = surface->format->Gshift;
618 	    Bshift = surface->format->Bshift;
619 	    Ashift = surface->format->Ashift;
620 
621             preMultR = (alpha * (dR>>Rshift));
622             preMultG = (alpha * (dG>>Gshift));
623             preMultB = (alpha * (dB>>Bshift));
624             preMultA = (alpha * (dA>>Ashift));
625 
626 	    for (y = y1; y <= y2; y++) {
627 		row = (Uint32 *) surface->pixels + y * surface->pitch / 4;
628 		for (x = x1; x <= x2; x++) {
629 		    pixel = row + x;
630 		    dc = *pixel;
631 
632                     aTmp = (255 - alpha);
633 		    R = (preMultR + (aTmp * ((dc & Rmask) >> Rshift))) >> 8 << Rshift & Rmask;
634 		    G = (preMultG + (aTmp * ((dc & Gmask) >> Gshift))) >> 8 << Gshift & Gmask;
635 		    B = (preMultB + (aTmp * ((dc & Bmask) >> Bshift))) >> 8 << Bshift & Bmask;
636 		    if (Amask)
637 			A = (preMultA + (aTmp * ((dc & Amask) >> Ashift))) >> 8 << Ashift & Amask;
638 		    *pixel = R | G | B | A;
639 		    if (dirtyDst == surface)
640 			dirtyPixels.push_back(pixel);
641 		}
642 	    }
643 	}
644 	break;
645 #endif
646 
647     }
648 
649     return (0);
650 }
651 
652 /* Draw rectangle with alpha enabled from RGBA color. */
653 
filledRectAlpha(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)654 int filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
655 {
656     Uint8 alpha;
657     Uint32 mcolor;
658     int result = 0;
659 
660     /*
661      * Lock the surface
662      */
663     if (SDL_MUSTLOCK(dst)) {
664 	if (SDL_LockSurface(dst) < 0) {
665 	    return (-1);
666 	}
667     }
668 
669     /*
670      * Setup color
671      */
672     alpha = color & 0x000000ff;
673     mcolor =
674 	SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
675 		    (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
676 
677     /*
678      * Draw
679      */
680     result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha);
681 
682     /*
683      * Unlock the surface
684      */
685     if (SDL_MUSTLOCK(dst)) {
686 	SDL_UnlockSurface(dst);
687     }
688 
689     return (result);
690 }
691 
692 /* Draw horizontal line with alpha enabled from RGBA color */
693 
HLineAlpha(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)694 int HLineAlpha(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
695 {
696     return (filledRectAlpha(dst, x1, y, x2, y, color));
697 }
698 
699 
700 /* Draw vertical line with alpha enabled from RGBA color */
701 
VLineAlpha(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)702 int VLineAlpha(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
703 {
704     return (filledRectAlpha(dst, x, y1, x, y2, color));
705 }
706 
707 
708 /* Pixel - using alpha weight on color for AA-drawing */
709 
pixelColorWeight(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)710 int pixelColorWeight(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
711 {
712     Uint32 a;
713 
714     /*
715      * Get alpha
716      */
717     a = (color & (Uint32) 0x000000ff);
718 
719     /*
720      * Modify Alpha by weight
721      */
722     a = ((a * weight) >> 8);
723 
724     return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
725 }
726 
727 /* Pixel - using alpha weight on color for AA-drawing - no locking */
728 
pixelColorWeightNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)729 int pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
730 {
731     Uint32 a;
732 
733     /*
734      * Get alpha
735      */
736     a = (color & (Uint32) 0x000000ff);
737 
738     /*
739      * Modify Alpha by weight
740      */
741     a = ((a * weight) >> 8);
742 
743     return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
744 }
745 
pixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)746 int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
747 {
748     Uint32 color;
749 
750     /*
751      * Check Alpha
752      */
753     if (a == 255) {
754 	/*
755 	 * No alpha blending required
756 	 */
757 	/*
758 	 * Setup color
759 	 */
760 	color = SDL_MapRGBA(dst->format, r, g, b, a);
761 	/*
762 	 * Draw
763 	 */
764 	return (fastPixelColor(dst, x, y, color));
765     } else {
766 	/*
767 	 * Alpha blending required
768 	 */
769 	/*
770 	 * Draw
771 	 */
772 	return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
773     }
774 }
775 
776 /* ----- Horizontal line */
777 
778 /* Just store color including alpha, no blending */
779 
hlineColorStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)780 int hlineColorStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
781 {
782     Sint16 left, right, top, bottom;
783     Uint8 *pixel, *pixellast;
784     int dx;
785     int pixx, pixy;
786     Sint16 w;
787     Sint16 xtmp;
788     int result = -1;
789 
790     /*
791      * Check visibility of clipping rectangle
792      */
793     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
794      return(0);
795     }
796 
797     /*
798      * Swap x1, x2 if required to ensure x1<=x2
799      */
800     if (x1 > x2) {
801 	xtmp = x1;
802 	x1 = x2;
803 	x2 = xtmp;
804     }
805 
806     /*
807      * Get clipping boundary and
808      * check visibility of hline
809      */
810     left = dst->clip_rect.x;
811     if (x2<left) {
812      return(0);
813     }
814     right = dst->clip_rect.x + dst->clip_rect.w - 1;
815     if (x1>right) {
816      return(0);
817     }
818     top = dst->clip_rect.y;
819     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
820     if ((y<top) || (y>bottom)) {
821      return (0);
822     }
823 
824     /*
825      * Clip x
826      */
827     if (x1 < left) {
828 	x1 = left;
829     }
830     if (x2 > right) {
831 	x2 = right;
832     }
833 
834     /*
835      * Calculate width
836      */
837     w = x2 - x1;
838 
839     /*
840      * Lock surface
841      */
842     SDL_LockSurface(dst);
843 
844     /*
845      * More variable setup
846      */
847     dx = w;
848     pixx = dst->format->BytesPerPixel;
849 	pixy = dst->pitch;
850 	pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
851 	pixellast = pixel + dx * pixx;
852 	for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixx)
853 	    if (dirtyDst == dst)
854 		dirtyPixels.push_back(tpixel);
855 
856 	/*
857 	 * Draw
858 	 */
859 	switch (dst->format->BytesPerPixel) {
860 	case 1:
861 	    memset(pixel, color, dx);
862 	    break;
863 	case 2:
864 	    for (; pixel <= pixellast; pixel += pixx) {
865 		*(Uint16 *) pixel = color;
866 	    }
867 	    break;
868 	case 3:
869 	    for (; pixel <= pixellast; pixel += pixx) {
870 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
871 		    pixel[0] = (color >> 16) & 0xff;
872 		    pixel[1] = (color >> 8) & 0xff;
873 		    pixel[2] = color & 0xff;
874 		} else {
875 		    pixel[0] = color & 0xff;
876 		    pixel[1] = (color >> 8) & 0xff;
877 		    pixel[2] = (color >> 16) & 0xff;
878 		}
879 	    }
880 	    break;
881 	default:		/* case 4 */
882 	    for (; pixel <= pixellast; pixel += pixx) {
883 		*(Uint32 *) pixel = color;
884 	    }
885 	    break;
886 	}
887 
888 	/*
889 	 * Unlock surface
890 	 */
891 	SDL_UnlockSurface(dst);
892 
893 	/*
894 	 * Set result code
895 	 */
896 	result = 0;
897 
898     return (result);
899 }
900 
hlineRGBAStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)901 int hlineRGBAStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
902 {
903     /*
904      * Draw
905      */
906     return (hlineColorStore(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
907 }
908 
hlineColor(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)909 int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
910 {
911     Sint16 left, right, top, bottom;
912     Uint8 *pixel, *pixellast;
913     int dx;
914     int pixx, pixy;
915     Sint16 w;
916     Sint16 xtmp;
917     int result = -1;
918     Uint8 *colorptr;
919 
920     /*
921      * Check visibility of clipping rectangle
922      */
923     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
924      return(0);
925     }
926 
927     /*
928      * Swap x1, x2 if required to ensure x1<=x2
929      */
930     if (x1 > x2) {
931 	xtmp = x1;
932 	x1 = x2;
933 	x2 = xtmp;
934     }
935 
936     /*
937      * Get clipping boundary and
938      * check visibility of hline
939      */
940     left = dst->clip_rect.x;
941     if (x2<left) {
942      return(0);
943     }
944     right = dst->clip_rect.x + dst->clip_rect.w - 1;
945     if (x1>right) {
946      return(0);
947     }
948     top = dst->clip_rect.y;
949     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
950     if ((y<top) || (y>bottom)) {
951      return (0);
952     }
953 
954     /*
955      * Clip x
956      */
957     if (x1 < left) {
958 	x1 = left;
959     }
960     if (x2 > right) {
961 	x2 = right;
962     }
963 
964     /*
965      * Calculate width
966      */
967     w = x2 - x1;
968 
969     /*
970      * Alpha check
971      */
972     if ((color & 255) == 255) {
973 
974 	/*
975 	 * No alpha-blending required
976 	 */
977 
978 	/*
979 	 * Setup color
980 	 */
981 	colorptr = (Uint8 *) & color;
982 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
983 	    color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
984 	} else {
985 	    color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
986 	}
987 
988 	/*
989 	 * Lock surface
990 	 */
991 	SDL_LockSurface(dst);
992 
993 	/*
994 	 * More variable setup
995 	 */
996 	dx = w;
997 	pixx = dst->format->BytesPerPixel;
998 	pixy = dst->pitch;
999 	pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
1000 	pixellast = pixel + dx * dst->format->BytesPerPixel;
1001 	for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixx)
1002 	    if (dirtyDst == dst)
1003 		dirtyPixels.push_back(tpixel);
1004 
1005 	/*
1006 	 * Draw
1007 	 */
1008 	switch (dst->format->BytesPerPixel) {
1009 	case 1:
1010 	    memset(pixel, color, dx);
1011 	    break;
1012 	case 2:
1013 	    for (; pixel <= pixellast; pixel += pixx) {
1014 		*(Uint16 *) pixel = color;
1015 	    }
1016 	    break;
1017 	case 3:
1018 	    for (; pixel <= pixellast; pixel += pixx) {
1019 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1020 		    pixel[0] = (color >> 16) & 0xff;
1021 		    pixel[1] = (color >> 8) & 0xff;
1022 		    pixel[2] = color & 0xff;
1023 		} else {
1024 		    pixel[0] = color & 0xff;
1025 		    pixel[1] = (color >> 8) & 0xff;
1026 		    pixel[2] = (color >> 16) & 0xff;
1027 		}
1028 	    }
1029 	    break;
1030 	default:		/* case 4 */
1031 	    dx = dx + dx;
1032 	    for (; pixel <= pixellast; pixel += pixx) {
1033 		*(Uint32 *) pixel = color;
1034 	    }
1035 	    break;
1036 	}
1037 
1038 	/*
1039 	 * Unlock surface
1040 	 */
1041 	SDL_UnlockSurface(dst);
1042 
1043 	/*
1044 	 * Set result code
1045 	 */
1046 	result = 0;
1047 
1048     } else {
1049 
1050 	/*
1051 	 * Alpha blending blit
1052 	 */
1053 
1054 	result = HLineAlpha(dst, x1, x1 + w, y, color);
1055 
1056     }
1057 
1058     return (result);
1059 }
1060 
hlineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1061 int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1062 {
1063     /*
1064      * Draw
1065      */
1066     return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1067 }
1068 
1069 /* ----- Vertical line */
1070 
vlineColor(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)1071 int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
1072 {
1073     Sint16 left, right, top, bottom;
1074     Uint8 *pixel, *pixellast;
1075     int dy;
1076     int pixx, pixy;
1077     Sint16 h;
1078     Sint16 ytmp;
1079     int result = -1;
1080     Uint8 *colorptr;
1081 
1082     /*
1083      * Check visibility of clipping rectangle
1084      */
1085     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1086      return(0);
1087     }
1088 
1089     /*
1090      * Swap y1, y2 if required to ensure y1<=y2
1091      */
1092     if (y1 > y2) {
1093 	ytmp = y1;
1094 	y1 = y2;
1095 	y2 = ytmp;
1096     }
1097 
1098     /*
1099      * Get clipping boundary and
1100      * check visibility of vline
1101      */
1102     left = dst->clip_rect.x;
1103     right = dst->clip_rect.x + dst->clip_rect.w - 1;
1104     if ((x<left) || (x>right)) {
1105      return (0);
1106     }
1107     top = dst->clip_rect.y;
1108     if (y2<top) {
1109      return(0);
1110     }
1111     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1112     if (y1>bottom) {
1113      return(0);
1114     }
1115 
1116     /*
1117      * Clip x
1118      */
1119     if (y1 < top) {
1120 	y1 = top;
1121     }
1122     if (y2 > bottom) {
1123 	y2 = bottom;
1124     }
1125 
1126     /*
1127      * Calculate height
1128      */
1129     h = y2 - y1;
1130 
1131     /*
1132      * Alpha check
1133      */
1134     if ((color & 255) == 255) {
1135 
1136 	/*
1137 	 * No alpha-blending required
1138 	 */
1139 
1140 	/*
1141 	 * Setup color
1142 	 */
1143 	colorptr = (Uint8 *) & color;
1144 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1145 	    color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1146 	} else {
1147 	    color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1148 	}
1149 
1150 	/*
1151 	 * Lock surface
1152 	 */
1153 	SDL_LockSurface(dst);
1154 
1155 	/*
1156 	 * More variable setup
1157 	 */
1158 	dy = h;
1159 	pixx = dst->format->BytesPerPixel;
1160 	pixy = dst->pitch;
1161 	pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1;
1162 	pixellast = pixel + pixy * dy;
1163 	for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixy)
1164 	    if (dirtyDst == dst)
1165 		dirtyPixels.push_back(tpixel);
1166 
1167 	/*
1168 	 * Draw
1169 	 */
1170 	switch (dst->format->BytesPerPixel) {
1171 	case 1:
1172 	    for (; pixel <= pixellast; pixel += pixy) {
1173 		*(Uint8 *) pixel = color;
1174 	    }
1175 	    break;
1176 	case 2:
1177 	    for (; pixel <= pixellast; pixel += pixy) {
1178 		*(Uint16 *) pixel = color;
1179 	    }
1180 	    break;
1181 	case 3:
1182 	    for (; pixel <= pixellast; pixel += pixy) {
1183 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1184 		    pixel[0] = (color >> 16) & 0xff;
1185 		    pixel[1] = (color >> 8) & 0xff;
1186 		    pixel[2] = color & 0xff;
1187 		} else {
1188 		    pixel[0] = color & 0xff;
1189 		    pixel[1] = (color >> 8) & 0xff;
1190 		    pixel[2] = (color >> 16) & 0xff;
1191 		}
1192 	    }
1193 	    break;
1194 	default:		/* case 4 */
1195 	    for (; pixel <= pixellast; pixel += pixy) {
1196 		*(Uint32 *) pixel = color;
1197 	    }
1198 	    break;
1199 	}
1200 
1201 	/*
1202 	 * Unlock surface
1203 	 */
1204 	SDL_UnlockSurface(dst);
1205 
1206 	/*
1207 	 * Set result code
1208 	 */
1209 	result = 0;
1210 
1211     } else {
1212 
1213 	/*
1214 	 * Alpha blending blit
1215 	 */
1216 
1217 	result = VLineAlpha(dst, x, y1, y1 + h, color);
1218 
1219     }
1220 
1221     return (result);
1222 }
1223 
vlineRGBA(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1224 int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1225 {
1226     /*
1227      * Draw
1228      */
1229     return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1230 }
1231 
1232 /* ----- Rectangle */
1233 
rectangleColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1234 int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1235 {
1236     int result;
1237     Sint16 w, h, xtmp, ytmp;
1238 
1239     /*
1240      * Check visibility of clipping rectangle
1241      */
1242     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1243      return(0);
1244     }
1245 
1246     /*
1247      * Swap x1, x2 if required
1248      */
1249     if (x1 > x2) {
1250 	xtmp = x1;
1251 	x1 = x2;
1252 	x2 = xtmp;
1253     }
1254 
1255     /*
1256      * Swap y1, y2 if required
1257      */
1258     if (y1 > y2) {
1259 	ytmp = y1;
1260 	y1 = y2;
1261 	y2 = ytmp;
1262     }
1263 
1264     /*
1265      * Calculate width&height
1266      */
1267     w = x2 - x1;
1268     h = y2 - y1;
1269 
1270     /*
1271      * Sanity check
1272      */
1273     if ((w < 0) || (h < 0)) {
1274 	return (0);
1275     }
1276 
1277     /*
1278      * Test for special cases of straight lines or single point
1279      */
1280     if (x1 == x2) {
1281 	if (y1 == y2) {
1282 	    return (pixelColor(dst, x1, y1, color));
1283 	} else {
1284 	    return (vlineColor(dst, x1, y1, y2, color));
1285 	}
1286     } else {
1287 	if (y1 == y2) {
1288 	    return (hlineColor(dst, x1, x2, y1, color));
1289 	}
1290     }
1291 
1292     /*
1293      * Draw rectangle
1294      */
1295     result = 0;
1296     result |= hlineColor(dst, x1, x2, y1, color);
1297     result |= hlineColor(dst, x1, x2, y2, color);
1298     y1 += 1;
1299     y2 -= 1;
1300     if (y1<=y2) {
1301      result |= vlineColor(dst, x1, y1, y2, color);
1302      result |= vlineColor(dst, x2, y1, y2, color);
1303     }
1304     return (result);
1305 
1306 }
1307 
rectangleRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1308 int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1309 {
1310     /*
1311      * Draw
1312      */
1313     return (rectangleColor
1314 	    (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1315 }
1316 
1317 /* --------- Clipping routines for line */
1318 
1319 /* Clipping based heavily on code from                       */
1320 /* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c   */
1321 
1322 #define CLIP_LEFT_EDGE   0x1
1323 #define CLIP_RIGHT_EDGE  0x2
1324 #define CLIP_BOTTOM_EDGE 0x4
1325 #define CLIP_TOP_EDGE    0x8
1326 #define CLIP_INSIDE(a)   (!a)
1327 #define CLIP_REJECT(a,b) (a&b)
1328 #define CLIP_ACCEPT(a,b) (!(a|b))
1329 
clipEncode(Sint16 x,Sint16 y,Sint16 left,Sint16 top,Sint16 right,Sint16 bottom)1330 static int clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom)
1331 {
1332     int code = 0;
1333 
1334     if (x < left) {
1335 	code |= CLIP_LEFT_EDGE;
1336     } else if (x > right) {
1337 	code |= CLIP_RIGHT_EDGE;
1338     }
1339     if (y < top) {
1340 	code |= CLIP_TOP_EDGE;
1341     } else if (y > bottom) {
1342 	code |= CLIP_BOTTOM_EDGE;
1343     }
1344     return code;
1345 }
1346 
clipLine(SDL_Surface * dst,Sint16 * x1,Sint16 * y1,Sint16 * x2,Sint16 * y2)1347 static int clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2)
1348 {
1349     Sint16 left, right, top, bottom;
1350     int code1, code2;
1351     int draw = 0;
1352     Sint16 swaptmp;
1353     float m;
1354 
1355     /*
1356      * Get clipping boundary
1357      */
1358     left = dst->clip_rect.x;
1359     right = dst->clip_rect.x + dst->clip_rect.w - 1;
1360     top = dst->clip_rect.y;
1361     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1362 
1363     while (1) {
1364 	code1 = clipEncode(*x1, *y1, left, top, right, bottom);
1365 	code2 = clipEncode(*x2, *y2, left, top, right, bottom);
1366 	if (CLIP_ACCEPT(code1, code2)) {
1367 	    draw = 1;
1368 	    break;
1369 	} else if (CLIP_REJECT(code1, code2))
1370 	    break;
1371 	else {
1372 	    if (CLIP_INSIDE(code1)) {
1373 		swaptmp = *x2;
1374 		*x2 = *x1;
1375 		*x1 = swaptmp;
1376 		swaptmp = *y2;
1377 		*y2 = *y1;
1378 		*y1 = swaptmp;
1379 		swaptmp = code2;
1380 		code2 = code1;
1381 		code1 = swaptmp;
1382 	    }
1383 	    if (*x2 != *x1) {
1384 		m = (*y2 - *y1) / (float) (*x2 - *x1);
1385 	    } else {
1386 		m = 1.0f;
1387 	    }
1388 	    if (code1 & CLIP_LEFT_EDGE) {
1389 		*y1 += (Sint16) ((left - *x1) * m);
1390 		*x1 = left;
1391 	    } else if (code1 & CLIP_RIGHT_EDGE) {
1392 		*y1 += (Sint16) ((right - *x1) * m);
1393 		*x1 = right;
1394 	    } else if (code1 & CLIP_BOTTOM_EDGE) {
1395 		if (*x2 != *x1) {
1396 		    *x1 += (Sint16) ((bottom - *y1) / m);
1397 		}
1398 		*y1 = bottom;
1399 	    } else if (code1 & CLIP_TOP_EDGE) {
1400 		if (*x2 != *x1) {
1401 		    *x1 += (Sint16) ((top - *y1) / m);
1402 		}
1403 		*y1 = top;
1404 	    }
1405 	}
1406     }
1407 
1408     return draw;
1409 }
1410 
1411 /* ----- Filled rectangle (Box) */
1412 
boxColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1413 int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1414 {
1415     Sint16 left, right, top, bottom;
1416     Uint8 *pixel, *pixellast;
1417     int x, dx;
1418     int dy;
1419     int pixx, pixy;
1420     Sint16 w, h, tmp;
1421     int result;
1422     Uint8 *colorptr;
1423 
1424     /*
1425      * Check visibility of clipping rectangle
1426      */
1427     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1428      return(0);
1429     }
1430 
1431     /*
1432      * Order coordinates to ensure that
1433      * x1<=x2 and y1<=y2
1434      */
1435     if (x1 > x2) {
1436 	tmp = x1;
1437 	x1 = x2;
1438 	x2 = tmp;
1439     }
1440     if (y1 > y2) {
1441 	tmp = y1;
1442 	y1 = y2;
1443 	y2 = tmp;
1444     }
1445 
1446     /*
1447      * Get clipping boundary and
1448      * check visibility
1449      */
1450     left = dst->clip_rect.x;
1451     if (x2<left) {
1452      return(0);
1453     }
1454     right = dst->clip_rect.x + dst->clip_rect.w - 1;
1455     if (x1>right) {
1456      return(0);
1457     }
1458     top = dst->clip_rect.y;
1459     if (y2<top) {
1460      return(0);
1461     }
1462     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1463     if (y1>bottom) {
1464      return(0);
1465     }
1466 
1467     /* Clip all points */
1468     if (x1<left) {
1469      x1=left;
1470     } else if (x1>right) {
1471      x1=right;
1472     }
1473     if (x2<left) {
1474      x2=left;
1475     } else if (x2>right) {
1476      x2=right;
1477     }
1478     if (y1<top) {
1479      y1=top;
1480     } else if (y1>bottom) {
1481      y1=bottom;
1482     }
1483     if (y2<top) {
1484      y2=top;
1485     } else if (y2>bottom) {
1486      y2=bottom;
1487     }
1488 
1489     /*
1490      * Test for special cases of straight line or single point
1491      */
1492     if (x1 == x2) {
1493 	if (y1 == y2) {
1494 	    return (pixelColor(dst, x1, y1, color));
1495 	} else {
1496 	    return (vlineColor(dst, x1, y1, y2, color));
1497 	}
1498     }
1499     if (y1 == y2) {
1500 	return (hlineColor(dst, x1, x2, y1, color));
1501     }
1502 
1503     /*
1504      * Calculate width&height
1505      */
1506     w = x2 - x1;
1507     h = y2 - y1;
1508 
1509     /*
1510      * Alpha check
1511      */
1512     if ((color & 255) == 255) {
1513 
1514 	/*
1515 	 * No alpha-blending required
1516 	 */
1517 
1518 	/*
1519 	 * Setup color
1520 	 */
1521 	colorptr = (Uint8 *) & color;
1522 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1523 	    color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1524 	} else {
1525 	    color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1526 	}
1527 
1528 	/*
1529 	 * Lock surface
1530 	 */
1531 	SDL_LockSurface(dst);
1532 
1533 	/*
1534 	 * More variable setup
1535 	 */
1536 	dx = w;
1537 	dy = h;
1538 	pixx = dst->format->BytesPerPixel;
1539 	pixy = dst->pitch;
1540 	pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
1541 	pixellast = pixel + pixx * dx + pixy * dy;
1542 	dx++;
1543 
1544 	for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixy)
1545 	    for (x = 0; x < dx; x++)
1546 	    {
1547 		if (dirtyDst == dst)
1548 		    dirtyPixels.push_back(tpixel);
1549 		tpixel += pixx;
1550 	    }
1551 
1552 	/*
1553 	 * Draw
1554 	 */
1555 	switch (dst->format->BytesPerPixel) {
1556 	case 1:
1557 	    for (; pixel <= pixellast; pixel += pixy) {
1558 		memset(pixel, (Uint8) color, dx);
1559 	    }
1560 	    break;
1561 	case 2:
1562 	    pixy -= (pixx * dx);
1563 	    for (; pixel <= pixellast; pixel += pixy) {
1564 		for (x = 0; x < dx; x++) {
1565 		    *(Uint16*) pixel = color;
1566 		    pixel += pixx;
1567 		}
1568 	    }
1569 	    break;
1570 	case 3:
1571 	    pixy -= (pixx * dx);
1572 	    for (; pixel <= pixellast; pixel += pixy) {
1573 		for (x = 0; x < dx; x++) {
1574 		    if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1575 			pixel[0] = (color >> 16) & 0xff;
1576 			pixel[1] = (color >> 8) & 0xff;
1577 			pixel[2] = color & 0xff;
1578 		    } else {
1579 			pixel[0] = color & 0xff;
1580 			pixel[1] = (color >> 8) & 0xff;
1581 			pixel[2] = (color >> 16) & 0xff;
1582 		    }
1583 		    pixel += pixx;
1584 		}
1585 	    }
1586 	    break;
1587 	default:		/* case 4 */
1588 	    pixy -= (pixx * dx);
1589 	    for (; pixel <= pixellast; pixel += pixy) {
1590 		for (x = 0; x < dx; x++) {
1591 		    *(Uint32 *) pixel = color;
1592 		    pixel += pixx;
1593 		}
1594 	    }
1595 	    break;
1596 	}
1597 
1598 	/*
1599 	 * Unlock surface
1600 	 */
1601 	SDL_UnlockSurface(dst);
1602 
1603 	result = 0;
1604 
1605     } else {
1606 
1607 	result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color);
1608 
1609     }
1610 
1611     return (result);
1612 }
1613 
boxRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1614 int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1615 {
1616     /*
1617      * Draw
1618      */
1619     return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1620 }
1621 
1622 /* ----- Line */
1623 
1624 /* Non-alpha line drawing code adapted from routine          */
1625 /* by Pete Shinners, pete@shinners.org                       */
1626 /* Originally from pygame, http://pygame.seul.org            */
1627 
1628 #define ABS(a) (((a)<0) ? -(a) : (a))
1629 
lineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1630 int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1631 {
1632     int pixx, pixy;
1633     int x, y;
1634     int dx, dy;
1635     int ax, ay;
1636     int sx, sy;
1637     int swaptmp;
1638     Uint8 *pixel;
1639     Uint8 *colorptr;
1640 
1641     /*
1642      * Clip line and test if we have to draw
1643      */
1644     if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
1645 	return (0);
1646     }
1647 
1648     /*
1649      * Test for special cases of straight lines or single point
1650      */
1651     if (x1 == x2) {
1652 	if (y1 < y2) {
1653 	    return (vlineColor(dst, x1, y1, y2, color));
1654 	} else if (y1 > y2) {
1655 	    return (vlineColor(dst, x1, y2, y1, color));
1656 	} else {
1657 	    return (pixelColor(dst, x1, y1, color));
1658 	}
1659     }
1660     if (y1 == y2) {
1661 	if (x1 < x2) {
1662 	    return (hlineColor(dst, x1, x2, y1, color));
1663 	} else if (x1 > x2) {
1664 	    return (hlineColor(dst, x2, x1, y1, color));
1665 	}
1666     }
1667 
1668     /*
1669      * Variable setup
1670      */
1671     dx = x2 - x1;
1672     dy = y2 - y1;
1673     sx = (dx >= 0) ? 1 : -1;
1674     sy = (dy >= 0) ? 1 : -1;
1675 
1676     /* Lock surface */
1677     if (SDL_MUSTLOCK(dst)) {
1678 	if (SDL_LockSurface(dst) < 0) {
1679 	    return (-1);
1680 	}
1681     }
1682 
1683     /*
1684      * Check for alpha blending
1685      */
1686     if ((color & 255) == 255) {
1687 
1688 	/*
1689 	 * No alpha blending - use fast pixel routines
1690 	 */
1691 
1692 	/*
1693 	 * Setup color
1694 	 */
1695 	colorptr = (Uint8 *) & color;
1696 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1697 	    color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1698 	} else {
1699 	    color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1700 	}
1701 
1702 	/*
1703 	 * More variable setup
1704 	 */
1705 	dx = sx * dx + 1;
1706 	dy = sy * dy + 1;
1707 	pixx = dst->format->BytesPerPixel;
1708 	pixy = dst->pitch;
1709 	pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
1710 	pixx *= sx;
1711 	pixy *= sy;
1712 	if (dx < dy) {
1713 	    swaptmp = dx;
1714 	    dx = dy;
1715 	    dy = swaptmp;
1716 	    swaptmp = pixx;
1717 	    pixx = pixy;
1718 	    pixy = swaptmp;
1719 	}
1720 
1721 	/*
1722 	 * Draw
1723 	 */
1724 	x = 0;
1725 	y = 0;
1726 	switch (dst->format->BytesPerPixel) {
1727 	case 1:
1728 	    for (; x < dx; x++, pixel += pixx) {
1729 		*pixel = color;
1730 		if (dirtyDst == dst)
1731 		    dirtyPixels.push_back(pixel);
1732 		y += dy;
1733 		if (y >= dx) {
1734 		    y -= dx;
1735 		    pixel += pixy;
1736 		}
1737 	    }
1738 	    break;
1739 	case 2:
1740 	    for (; x < dx; x++, pixel += pixx) {
1741 		*(Uint16 *) pixel = color;
1742 		if (dirtyDst == dst)
1743 		    dirtyPixels.push_back(pixel);
1744 		y += dy;
1745 		if (y >= dx) {
1746 		    y -= dx;
1747 		    pixel += pixy;
1748 		}
1749 	    }
1750 	    break;
1751 	case 3:
1752 	    for (; x < dx; x++, pixel += pixx) {
1753 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1754 		    pixel[0] = (color >> 16) & 0xff;
1755 		    pixel[1] = (color >> 8) & 0xff;
1756 		    pixel[2] = color & 0xff;
1757 		} else {
1758 		    pixel[0] = color & 0xff;
1759 		    pixel[1] = (color >> 8) & 0xff;
1760 		    pixel[2] = (color >> 16) & 0xff;
1761 		}
1762 		if (dirtyDst == dst)
1763 		    dirtyPixels.push_back(pixel);
1764 		y += dy;
1765 		if (y >= dx) {
1766 		    y -= dx;
1767 		    pixel += pixy;
1768 		}
1769 	    }
1770 	    break;
1771 	default:		/* case 4 */
1772 	    for (; x < dx; x++, pixel += pixx) {
1773 		*(Uint32 *) pixel = color;
1774 		if (dirtyDst == dst)
1775 		    dirtyPixels.push_back(pixel);
1776 		y += dy;
1777 		if (y >= dx) {
1778 		    y -= dx;
1779 		    pixel += pixy;
1780 		}
1781 	    }
1782 	    break;
1783 	}
1784 
1785     } else {
1786 
1787 	/*
1788 	 * Alpha blending required - use single-pixel blits
1789 	 */
1790 
1791 	ax = ABS(dx) << 1;
1792 	ay = ABS(dy) << 1;
1793 	x = x1;
1794 	y = y1;
1795 	if (ax > ay) {
1796 	    int d = ay - (ax >> 1);
1797 
1798 	    while (x != x2) {
1799 		pixelColorNolock (dst, x, y, color);
1800 		if (d > 0 || (d == 0 && sx == 1)) {
1801 		    y += sy;
1802 		    d -= ax;
1803 		}
1804 		x += sx;
1805 		d += ay;
1806 	    }
1807 	} else {
1808 	    int d = ax - (ay >> 1);
1809 
1810 	    while (y != y2) {
1811 		pixelColorNolock (dst, x, y, color);
1812 		if (d > 0 || ((d == 0) && (sy == 1))) {
1813 		    x += sx;
1814 		    d -= ay;
1815 		}
1816 		y += sy;
1817 		d += ax;
1818 	    }
1819 	}
1820 	pixelColorNolock (dst, x, y, color);
1821 
1822     }
1823 
1824     /* Unlock surface */
1825     if (SDL_MUSTLOCK(dst)) {
1826 	SDL_UnlockSurface(dst);
1827     }
1828 
1829     return (0);
1830 }
1831 
lineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1832 int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1833 {
1834     /*
1835      * Draw
1836      */
1837     return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1838 }
1839 
1840 /* AA Line */
1841 
1842 #define AAlevels 256
1843 #define AAbits 8
1844 
1845 struct WeightPair
1846 {
1847     Uint8 main;
1848     Uint8 complement;
1849 };
1850 
1851 double antialiasGamma = 2.2;
getWeights(Uint8 balance)1852 WeightPair getWeights(Uint8 balance)
1853 {
1854     // Gamma-correction for anti-aliasing calculations - get weights for a
1855     // pair of pixels.
1856     //
1857     // We take gamma to be 2.2 by default, which seems generally to be about
1858     // right (the exact value being system-dependent...)
1859 
1860     static WeightPair precalced[256];
1861     static double precalcedGamma = -1;
1862 
1863     if (precalcedGamma != antialiasGamma)
1864     {
1865 	for (Uint16 b = 0; b < 256; b++)
1866 	{
1867 	    precalced[b].main =
1868 		(Uint8) (255.0*pow(b/255.0, 1.0/antialiasGamma));
1869 	    precalced[b].complement =
1870 		(Uint8) (255.0*pow((255-b)/255.0, 1.0/antialiasGamma));
1871 	}
1872 	precalcedGamma = antialiasGamma;
1873     }
1874 
1875     return precalced[balance];
1876 }
1877 
1878 /*
1879 
1880 This implementation of the Wu antialiasing code is based on Mike Abrash's
1881 DDJ article which was reprinted as Chapter 42 of his Graphics Programming
1882 Black Book, but has been optimized to work with SDL and utilizes 32-bit
1883 fixed-point arithmetic. (A. Schiffler).
1884 
1885 */
1886 
aalineColorInt(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,int draw_endpoint)1887 int aalineColorInt(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint)
1888 {
1889     Sint32 xx0, yy0, xx1, yy1;
1890     int result;
1891     Uint32 intshift, erracc, erradj;
1892     Uint32 erracctmp, wgtcompmask;
1893     Uint16 balance;
1894     int dx, dy, tmp, xdir, y0p1, x0pxdir;
1895     WeightPair weightPair;
1896 
1897     /*
1898      * Check visibility of clipping rectangle
1899      */
1900     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1901      return(0);
1902     }
1903 
1904     /*
1905      * Clip line and test if we have to draw
1906      */
1907     if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
1908 	return (0);
1909     }
1910 
1911     /*
1912      * Keep on working with 32bit numbers
1913      */
1914     xx0 = x1;
1915     yy0 = y1;
1916     xx1 = x2;
1917     yy1 = y2;
1918 
1919     /*
1920      * Reorder points if required
1921      */
1922     if (yy0 > yy1) {
1923 	tmp = yy0;
1924 	yy0 = yy1;
1925 	yy1 = tmp;
1926 	tmp = xx0;
1927 	xx0 = xx1;
1928 	xx1 = tmp;
1929     }
1930 
1931     /*
1932      * Calculate distance
1933      */
1934     dx = xx1 - xx0;
1935     dy = yy1 - yy0;
1936 
1937     /*
1938      * Adjust for negative dx and set xdir
1939      */
1940     if (dx >= 0) {
1941 	xdir = 1;
1942     } else {
1943 	xdir = -1;
1944 	dx = (-dx);
1945     }
1946 
1947     /*
1948      * Check for special cases
1949      */
1950     if (dx == 0) {
1951 	/*
1952 	 * Vertical line
1953 	 */
1954 	return (vlineColor(dst, x1, y1, y2, color));
1955     } else if (dy == 0) {
1956 	/*
1957 	 * Horizontal line
1958 	 */
1959 	return (hlineColor(dst, x1, x2, y1, color));
1960     } else if (dx == dy) {
1961 	/*
1962 	 * Diagonal line
1963 	 */
1964 	return (lineColor(dst, x1, y1, x2, y2, color));
1965     }
1966 
1967     /*
1968      * Line is not horizontal, vertical or diagonal
1969      */
1970     result = 0;
1971 
1972     /*
1973      * Zero accumulator
1974      */
1975     erracc = 0;
1976 
1977     /*
1978      * # of bits by which to shift erracc to get intensity level
1979      */
1980     intshift = 32 - AAbits;
1981     /*
1982      * Mask used to flip all bits in an intensity weighting
1983      */
1984     wgtcompmask = AAlevels - 1;
1985 
1986     /* Lock surface */
1987     if (SDL_MUSTLOCK(dst)) {
1988 	if (SDL_LockSurface(dst) < 0) {
1989 	    return (-1);
1990 	}
1991     }
1992 
1993     /*
1994      * Draw the initial pixel in the foreground color
1995      */
1996     result |= pixelColorNolock(dst, x1, y1, color);
1997 
1998     /*
1999      * x-major or y-major?
2000      */
2001     if (dy > dx) {
2002 
2003 	/*
2004 	 * y-major.  Calculate 16-bit fixed point fractional part of a pixel that
2005 	 * X advances every time Y advances 1 pixel, truncating the result so that
2006 	 * we won't overrun the endpoint along the X axis
2007 	 */
2008 	/*
2009 	 * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
2010 	 */
2011 	erradj = ((dx << 16) / dy) << 16;
2012 
2013 	/*
2014 	 * draw all pixels other than the first and last
2015 	 */
2016 	x0pxdir = xx0 + xdir;
2017 	while (--dy) {
2018 	    erracctmp = erracc;
2019 	    erracc += erradj;
2020 	    if (erracc <= erracctmp) {
2021 		/*
2022 		 * rollover in error accumulator, x coord advances
2023 		 */
2024 		xx0 = x0pxdir;
2025 		x0pxdir += xdir;
2026 	    }
2027 	    yy0++;		/* y-major so always advance Y */
2028 
2029 	    /*
2030 	     * the AAbits most significant bits of erracc give us the intensity
2031 	     * weighting for this pixel, and the complement of the weighting for
2032 	     * the paired pixel.
2033 	     */
2034 	    balance = (erracc >> intshift) & 255;
2035 	    weightPair = getWeights(balance);
2036 
2037 	    result |= pixelColorWeightNolock (dst, xx0, yy0, color,
2038 		    weightPair.complement);
2039 	    result |= pixelColorWeightNolock (dst, x0pxdir, yy0, color,
2040 		    weightPair.main);
2041 	}
2042 
2043     } else {
2044 
2045 	/*
2046 	 * x-major line.  Calculate 16-bit fixed-point fractional part of a pixel
2047 	 * that Y advances each time X advances 1 pixel, truncating the result so
2048 	 * that we won't overrun the endpoint along the X axis.
2049 	 */
2050 	/*
2051 	 * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
2052 	 */
2053 	erradj = ((dy << 16) / dx) << 16;
2054 
2055 	/*
2056 	 * draw all pixels other than the first and last
2057 	 */
2058 	y0p1 = yy0 + 1;
2059 	while (--dx) {
2060 
2061 	    erracctmp = erracc;
2062 	    erracc += erradj;
2063 	    if (erracc <= erracctmp) {
2064 		/*
2065 		 * Accumulator turned over, advance y
2066 		 */
2067 		yy0 = y0p1;
2068 		y0p1++;
2069 	    }
2070 	    xx0 += xdir;	/* x-major so always advance X */
2071 	    /*
2072 	     * the AAbits most significant bits of erracc give us the intensity
2073 	     * weighting for this pixel, and the complement of the weighting for
2074 	     * the paired pixel.
2075 	     */
2076 	    balance = (erracc >> intshift) & 255;
2077 	    weightPair = getWeights(balance);
2078 
2079 	    result |= pixelColorWeightNolock (dst, xx0, yy0, color,
2080 		    weightPair.complement);
2081 	    result |= pixelColorWeightNolock (dst, xx0, y0p1, color,
2082 		    weightPair.main);
2083 	}
2084     }
2085 
2086     /*
2087      * Do we have to draw the endpoint
2088      */
2089     if (draw_endpoint) {
2090 	/*
2091 	 * Draw final pixel, always exactly intersected by the line and doesn't
2092 	 * need to be weighted.
2093 	 */
2094 	result |= pixelColorNolock (dst, x2, y2, color);
2095     }
2096 
2097     /* Unlock surface */
2098     if (SDL_MUSTLOCK(dst)) {
2099 	SDL_UnlockSurface(dst);
2100     }
2101 
2102     return (result);
2103 }
2104 
aalineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2105 int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2106 {
2107     return (aalineColorInt(dst, x1, y1, x2, y2, color, 1));
2108 }
2109 
aalineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2110 int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2111 {
2112     return (aalineColorInt
2113 	    (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
2114 }
2115 
2116 
2117 /* ----- Circle */
2118 
2119 /* Note: Based on algorithm from sge library, modified by A. Schiffler */
2120 /* with multiple pixel-draw removal and other minor speedup changes.   */
2121 
circleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Uint32 color)2122 int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2123 {
2124     Sint16 left, right, top, bottom;
2125     int result;
2126     Sint16 x1, y1, x2, y2;
2127     Sint16 cx = 0;
2128     Sint16 cy = r;
2129     Sint16 df = 1 - r;
2130     Sint16 d_e = 3;
2131     Sint16 d_se = -2 * r + 5;
2132     Sint16 xpcx, xmcx, xpcy, xmcy;
2133     Sint16 ypcy, ymcy, ypcx, ymcx;
2134     Uint8 *colorptr;
2135 
2136     /*
2137      * Check visibility of clipping rectangle
2138      */
2139     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2140      return(0);
2141     }
2142 
2143     /*
2144      * Sanity check radius
2145      */
2146     if (r < 0) {
2147 	return (-1);
2148     }
2149 
2150     /*
2151      * Special case for r=0 - draw a point
2152      */
2153     if (r == 0) {
2154 	return (pixelColor(dst, x, y, color));
2155     }
2156 
2157     /*
2158      * Get circle and clipping boundary and
2159      * test if bounding box of circle is visible
2160      */
2161     x2 = x + r;
2162     left = dst->clip_rect.x;
2163     if (x2<left) {
2164      return(0);
2165     }
2166     x1 = x - r;
2167     right = dst->clip_rect.x + dst->clip_rect.w - 1;
2168     if (x1>right) {
2169      return(0);
2170     }
2171     y2 = y + r;
2172     top = dst->clip_rect.y;
2173     if (y2<top) {
2174      return(0);
2175     }
2176     y1 = y - r;
2177     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2178     if (y1>bottom) {
2179      return(0);
2180     }
2181 
2182     /*
2183      * Draw circle
2184      */
2185     result = 0;
2186 
2187     /* Lock surface */
2188     if (SDL_MUSTLOCK(dst)) {
2189 	if (SDL_LockSurface(dst) < 0) {
2190 	    return (-1);
2191 	}
2192     }
2193 
2194     /*
2195      * Alpha Check
2196      */
2197     if ((color & 255) == 255) {
2198 
2199 	/*
2200 	 * No Alpha - direct memory writes
2201 	 */
2202 
2203 	/*
2204 	 * Setup color
2205 	 */
2206 	colorptr = (Uint8 *) & color;
2207 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2208 	    color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2209 	} else {
2210 	    color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2211 	}
2212 
2213 	/*
2214 	 * Draw
2215 	 */
2216 	do {
2217 		ypcy = y + cy;
2218 		ymcy = y - cy;
2219 		if (cx > 0) {
2220 		    xpcx = x + cx;
2221 		    xmcx = x - cx;
2222 		    result |= fastPixelColorNolock(dst, xmcx, ypcy, color);
2223 		    result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
2224 		    result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
2225 		    result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
2226 		} else {
2227 		    result |= fastPixelColorNolock(dst, x, ymcy, color);
2228 		    result |= fastPixelColorNolock(dst, x, ypcy, color);
2229 		}
2230 		xpcy = x + cy;
2231 		xmcy = x - cy;
2232 		if ((cx > 0) && (cx != cy)) {
2233 		    ypcx = y + cx;
2234 		    ymcx = y - cx;
2235 		    result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
2236 		    result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
2237 		    result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
2238 		    result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
2239 		} else if (cx == 0) {
2240 		    result |= fastPixelColorNolock(dst, xmcy, y, color);
2241 		    result |= fastPixelColorNolock(dst, xpcy, y, color);
2242 		}
2243 	    /*
2244 	     * Update
2245 	     */
2246 	    if (df < 0) {
2247 		df += d_e;
2248 		d_e += 2;
2249 		d_se += 2;
2250 	    } else {
2251 		df += d_se;
2252 		d_e += 2;
2253 		d_se += 4;
2254 		cy--;
2255 	    }
2256 	    cx++;
2257 	} while (cx <= cy);
2258 
2259 	/*
2260 	 * Unlock surface
2261 	 */
2262 	SDL_UnlockSurface(dst);
2263 
2264     } else {
2265 
2266 	/*
2267 	 * Using Alpha - blended pixel blits
2268 	 */
2269 
2270 	do {
2271 	    /*
2272 	     * Draw
2273 	     */
2274 		ypcy = y + cy;
2275 		ymcy = y - cy;
2276 		if (cx > 0) {
2277 		    xpcx = x + cx;
2278 		    xmcx = x - cx;
2279 		    result |= pixelColorNolock (dst, xmcx, ypcy, color);
2280 		    result |= pixelColorNolock (dst, xpcx, ypcy, color);
2281 		    result |= pixelColorNolock (dst, xmcx, ymcy, color);
2282 		    result |= pixelColorNolock (dst, xpcx, ymcy, color);
2283 		} else {
2284 		    result |= pixelColorNolock (dst, x, ymcy, color);
2285 		    result |= pixelColorNolock (dst, x, ypcy, color);
2286 		}
2287 		xpcy = x + cy;
2288 		xmcy = x - cy;
2289 		if ((cx > 0) && (cx != cy)) {
2290 		    ypcx = y + cx;
2291 		    ymcx = y - cx;
2292 		    result |= pixelColorNolock (dst, xmcy, ypcx, color);
2293 		    result |= pixelColorNolock (dst, xpcy, ypcx, color);
2294 		    result |= pixelColorNolock (dst, xmcy, ymcx, color);
2295 		    result |= pixelColorNolock (dst, xpcy, ymcx, color);
2296 		} else if (cx == 0) {
2297 		    result |= pixelColorNolock (dst, xmcy, y, color);
2298 		    result |= pixelColorNolock (dst, xpcy, y, color);
2299 		}
2300 	    /*
2301 	     * Update
2302 	     */
2303 	    if (df < 0) {
2304 		df += d_e;
2305 		d_e += 2;
2306 		d_se += 2;
2307 	    } else {
2308 		df += d_se;
2309 		d_e += 2;
2310 		d_se += 4;
2311 		cy--;
2312 	    }
2313 	    cx++;
2314 	} while (cx <= cy);
2315 
2316     }				/* Alpha check */
2317 
2318     /* Unlock surface */
2319     if (SDL_MUSTLOCK(dst)) {
2320 	SDL_UnlockSurface(dst);
2321     }
2322 
2323     return (result);
2324 }
2325 
circleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2326 int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2327 {
2328     /*
2329      * Draw
2330      */
2331     return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2332 }
2333 
2334 /* ----- Arc */
2335 
2336 /* Note: Based on above circle algorithm by A. Schiffler below.  Written by D. Raber */
2337 /* Calculates which octants arc goes through and renders accordingly */
2338 
arcColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Sint16 start,Sint16 end,Uint32 color)2339 int arcColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Sint16 start, Sint16 end, Uint32 color)
2340 {
2341     Sint16 left, right, top, bottom;
2342     int result;
2343     Sint16 x1, y1, x2, y2;
2344     Sint16 cx = 0;
2345     Sint16 cy = r;
2346     Sint16 df = 1 - r;
2347     Sint16 d_e = 3;
2348     Sint16 d_se = -2 * r + 5;
2349     Sint16 xpcx, xmcx, xpcy, xmcy;
2350     Sint16 ypcy, ymcy, ypcx, ymcx;
2351     Uint8 *colorptr;
2352 
2353     /*
2354      * Check visibility of clipping rectangle
2355      */
2356     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2357      return(0);
2358     }
2359 
2360     /*
2361      * Sanity check radius
2362      */
2363     if (r < 0) {
2364 	return (-1);
2365     }
2366 
2367     /*
2368      * Special case for r=0 - draw a point
2369      */
2370     if (r == 0) {
2371 	return (pixelColor(dst, x, y, color));
2372     }
2373 
2374     /*
2375      * Fixup angles
2376      */
2377     start = start % 360;
2378     end = end % 360;
2379 
2380     /*
2381      * Get arc's circle and clipping boundary and
2382      * test if bounding box of circle is visible
2383      */
2384     x2 = x + r;
2385     left = dst->clip_rect.x;
2386     if (x2<left) {
2387      return(0);
2388     }
2389     x1 = x - r;
2390     right = dst->clip_rect.x + dst->clip_rect.w - 1;
2391     if (x1>right) {
2392      return(0);
2393     }
2394     y2 = y + r;
2395     top = dst->clip_rect.y;
2396     if (y2<top) {
2397      return(0);
2398     }
2399     y1 = y - r;
2400     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2401     if (y1>bottom) {
2402      return(0);
2403     }
2404 
2405     /*
2406      * Draw arc
2407      */
2408     result = 0;
2409 
2410     /* Lock surface */
2411     if (SDL_MUSTLOCK(dst)) {
2412 	if (SDL_LockSurface(dst) < 0) {
2413 	    return (-1);
2414 	}
2415     }
2416 
2417     /* Octant labelling
2418 
2419         \ 5 | 6 /
2420          \  |  /
2421         4 \ | / 7
2422            \|/
2423       ------+------ +x
2424            /|\
2425         3 / | \ 0
2426          /  |  \
2427         / 2 | 1 \
2428             +y        */
2429 
2430 	Uint8 drawoct = 0; // 0x00000000
2431 					   // whether or not to keep drawing a given octant.
2432 					   // For example: 0x00111100 means we're drawing in octants 2-5
2433 
2434 	// 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
2435 	while (start < 0) start += 360;
2436 	while (end < 0) end += 360;
2437 	start %= 360;
2438 	end %= 360;
2439 
2440 	// now, we find which octants we're drawing in.
2441 	int startoct = start / 45;
2442 	int endoct = end / 45;
2443 	int oct = startoct - 1; // we increment as first step in loop
2444 
2445 	int stopval_start=0, stopval_end=0; // what values of cx to stop at.
2446 	double temp=0;
2447 
2448 	do {
2449 		oct = (oct + 1) % 8;
2450 
2451 		if (oct == startoct) {
2452 			// need to compute stopval_start for this octant.  Look at picture above if this is unclear
2453 			switch (oct)
2454 			{
2455 			case 0:
2456 			case 3:
2457 				temp = sin(start * M_PI / 180);
2458 				break;
2459 			case 1:
2460 			case 6:
2461 				temp = cos(start * M_PI / 180);
2462 				break;
2463 			case 2:
2464 			case 5:
2465 				temp = -cos(start * M_PI / 180);
2466 				break;
2467 			case 4:
2468 			case 7:
2469 				temp = -sin(start * M_PI / 180);
2470 				break;
2471 			}
2472 			temp *= r;
2473 			stopval_start = (int)temp; // always round down.
2474 									   // This isn't arbitrary, but requires graph paper to explain well.
2475 									   // The basic idea is that we're always changing drawoct after we draw, so we
2476 									   // stop immediately after we render the last sensible pixel at x = ((int)temp).
2477 
2478 			// and whether to draw in this octant initially
2479 			if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
2480 			else		 drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
2481 		}
2482 		if (oct == endoct) {
2483 			// need to compute stopval_end for this octant
2484 			switch (oct)
2485 			{
2486 			case 0:
2487 			case 3:
2488 				temp = sin(end * M_PI / 180);
2489 				break;
2490 			case 1:
2491 			case 6:
2492 				temp = cos(end * M_PI / 180);
2493 				break;
2494 			case 2:
2495 			case 5:
2496 				temp = -cos(end * M_PI / 180);
2497 				break;
2498 			case 4:
2499 			case 7:
2500 				temp = -sin(end * M_PI / 180);
2501 				break;
2502 			}
2503 			temp *= r;
2504 			stopval_end = (int)temp;
2505 
2506 			// and whether to draw in this octant initially
2507 			if (startoct == endoct)	{
2508 				// note:      we start drawing, stop, then start again in this case
2509 				// otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
2510 				if (start > end) {
2511 					// unfortunately, if we're in the same octant and need to draw over the whole circle,
2512 					// we need to set the rest to true, because the while loop will end at the bottom.
2513 					drawoct = 255;
2514 				} else {
2515 					drawoct &= 255 - (1 << oct);
2516 				}
2517 			}
2518 			else if (oct % 2) drawoct &= 255 - (1 << oct);
2519 			else			  drawoct |= (1 << oct);
2520 		} else if (oct != startoct) { // already verified that it's != endoct
2521 			drawoct |= (1 << oct); // draw this entire segment
2522 		}
2523 	} while (oct != endoct);
2524 
2525 	// so now we have what octants to draw and when to draw them.  all that's left is the actual raster code.
2526 
2527 
2528     /*
2529      * Alpha Check
2530      */
2531     if ((color & 255) == 255) {
2532 
2533 	/*
2534 	 * No Alpha - direct memory writes
2535 	 */
2536 
2537 	/*
2538 	 * Setup color
2539 	 */
2540 	colorptr = (Uint8 *) & color;
2541 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2542 	    color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2543 	} else {
2544 	    color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2545 	}
2546 
2547 	/*
2548 	 * Draw
2549 	 */
2550 	do {
2551 		ypcy = y + cy;
2552 		ymcy = y - cy;
2553 		if (cx > 0) {
2554 			xpcx = x + cx;
2555 			xmcx = x - cx;
2556 			// always check if we're drawing a certain octant before adding a pixel to that octant.
2557 			if (drawoct & 4)  result |= fastPixelColorNolock(dst, xmcx, ypcy, color); // drawoct & 4 = 22; drawoct[2]
2558 			if (drawoct & 2)  result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
2559 			if (drawoct & 32) result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
2560 			if (drawoct & 64) result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
2561 		} else {
2562 			if (drawoct & 6)  result |= fastPixelColorNolock(dst, x, ypcy, color); // 4 + 2; drawoct[2] || drawoct[1]
2563 			if (drawoct & 96) result |= fastPixelColorNolock(dst, x, ymcy, color); // 32 + 64
2564 		}
2565 
2566 		xpcy = x + cy;
2567 		xmcy = x - cy;
2568 		if (cx > 0 && cx != cy) {
2569 			ypcx = y + cx;
2570 			ymcx = y - cx;
2571 			if (drawoct & 8)   result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
2572 			if (drawoct & 1)   result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
2573 			if (drawoct & 16)  result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
2574 			if (drawoct & 128) result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
2575 		} else if (cx == 0) {
2576 			if (drawoct & 24)  result |= fastPixelColorNolock(dst, xmcy, y, color); // 8 + 16
2577 			if (drawoct & 129) result |= fastPixelColorNolock(dst, xpcy, y, color); // 1 + 128
2578 		}
2579 
2580 
2581 	    /*
2582 	     * Update whether we're drawing an octant
2583 	     */
2584 		if (stopval_start == cx) {
2585 			// works like an on-off switch because start & end may be in the same octant.
2586 			if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
2587 			else drawoct |= (1 << startoct);
2588 		}
2589 		if (stopval_end == cx) {
2590 			if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
2591 			else drawoct |= (1 << endoct);
2592 		}
2593 
2594 		/*
2595 	     * Update pixels
2596 	     */
2597 	    if (df < 0) {
2598 			df += d_e;
2599 			d_e += 2;
2600 			d_se += 2;
2601 	    } else {
2602 			df += d_se;
2603 			d_e += 2;
2604 			d_se += 4;
2605 			cy--;
2606 	    }
2607 	    cx++;
2608 	} while (cx <= cy);
2609 
2610 	/*
2611 	 * Unlock surface
2612 	 */
2613 	SDL_UnlockSurface(dst);
2614 
2615     } else {
2616 
2617 	/*
2618 	 * Using Alpha - blended pixel blits
2619 	 */
2620 
2621 	do {
2622 		ypcy = y + cy;
2623 		ymcy = y - cy;
2624 		if (cx > 0) {
2625 			xpcx = x + cx;
2626 			xmcx = x - cx;
2627 
2628 			// always check if we're drawing a certain octant before adding a pixel to that octant.
2629 			if (drawoct & 4)  result |= pixelColorNolock(dst, xmcx, ypcy, color);
2630 			if (drawoct & 2)  result |= pixelColorNolock(dst, xpcx, ypcy, color);
2631 			if (drawoct & 32) result |= pixelColorNolock(dst, xmcx, ymcy, color);
2632 			if (drawoct & 64) result |= pixelColorNolock(dst, xpcx, ymcy, color);
2633 		} else {
2634 			if (drawoct & 96) result |= pixelColorNolock(dst, x, ymcy, color);
2635 			if (drawoct & 6)  result |= pixelColorNolock(dst, x, ypcy, color);
2636 		}
2637 
2638 		xpcy = x + cy;
2639 		xmcy = x - cy;
2640 		if (cx > 0 && cx != cy) {
2641 			ypcx = y + cx;
2642 			ymcx = y - cx;
2643 			if (drawoct & 8)   result |= pixelColorNolock(dst, xmcy, ypcx, color);
2644 			if (drawoct & 1)   result |= pixelColorNolock(dst, xpcy, ypcx, color);
2645 			if (drawoct & 16)  result |= pixelColorNolock(dst, xmcy, ymcx, color);
2646 			if (drawoct & 128) result |= pixelColorNolock(dst, xpcy, ymcx, color);
2647 		} else if (cx == 0) {
2648 			if (drawoct & 24)  result |= pixelColorNolock(dst, xmcy, y, color);
2649 			if (drawoct & 129) result |= pixelColorNolock(dst, xpcy, y, color);
2650 		}
2651 
2652 
2653 	    /*
2654 	     * Update whether we're drawing an octant
2655 	     */
2656 		if (stopval_start == cx) {
2657 			// works like an on-off switch.
2658 			// This is just in case start & end are in the same octant.
2659 			if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
2660 			else						   drawoct |= (1 << startoct);
2661 		}
2662 		if (stopval_end == cx) {
2663 			if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
2664 			else						 drawoct |= (1 << endoct);
2665 		}
2666 
2667 		/*
2668 	     * Update pixels
2669 	     */
2670 	    if (df < 0) {
2671 			df += d_e;
2672 			d_e += 2;
2673 			d_se += 2;
2674 	    } else {
2675 			df += d_se;
2676 			d_e += 2;
2677 			d_se += 4;
2678 			cy--;
2679 	    }
2680 	    cx++;
2681 	} while (cx <= cy);
2682 
2683     }				/* Alpha check */
2684 
2685     /* Unlock surface */
2686     if (SDL_MUSTLOCK(dst)) {
2687 	SDL_UnlockSurface(dst);
2688     }
2689 
2690     return (result);
2691 }
2692 
arcRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2693 int arcRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2694 {
2695     /*
2696      * Draw
2697      */
2698     return (arcColor(dst, x, y, rad, start, end, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2699 }
2700 
2701 /* ----- AA Circle */
2702 
2703 /* AA circle is based on AAellipse  */
2704 
aacircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Uint32 color)2705 int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2706 {
2707     return (aaellipseColor(dst, x, y, r, r, color));
2708 }
2709 
aacircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2710 int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2711 {
2712     /*
2713      * Draw
2714      */
2715     return (aaellipseColor
2716 	    (dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2717 }
2718 
2719 /* ----- Filled Circle */
2720 
2721 /* Note: Based on algorithm from sge library with multiple-hline draw removal */
2722 
2723 /* and other speedup changes. */
2724 
filledCircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Uint32 color)2725 int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2726 {
2727     Sint16 left, right, top, bottom;
2728     int result;
2729     Sint16 x1, y1, x2, y2;
2730     Sint16 cx = 0;
2731     Sint16 cy = r;
2732     Sint16 ocx = (Sint16) 0xffff;
2733     Sint16 ocy = (Sint16) 0xffff;
2734     Sint16 df = 1 - r;
2735     Sint16 d_e = 3;
2736     Sint16 d_se = -2 * r + 5;
2737     Sint16 xpcx, xmcx, xpcy, xmcy;
2738     Sint16 ypcy, ymcy, ypcx, ymcx;
2739 
2740     /*
2741      * Check visibility of clipping rectangle
2742      */
2743     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2744      return(0);
2745     }
2746 
2747     /*
2748      * Sanity check radius
2749      */
2750     if (r < 0) {
2751 	return (-1);
2752     }
2753 
2754     /*
2755      * Special case for r=0 - draw a point
2756      */
2757     if (r == 0) {
2758 	return (pixelColor(dst, x, y, color));
2759     }
2760 
2761     /*
2762      * Get circle and clipping boundary and
2763      * test if bounding box of circle is visible
2764      */
2765     x2 = x + r;
2766     left = dst->clip_rect.x;
2767     if (x2<left) {
2768      return(0);
2769     }
2770     x1 = x - r;
2771     right = dst->clip_rect.x + dst->clip_rect.w - 1;
2772     if (x1>right) {
2773      return(0);
2774     }
2775     y2 = y + r;
2776     top = dst->clip_rect.y;
2777     if (y2<top) {
2778      return(0);
2779     }
2780     y1 = y - r;
2781     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2782     if (y1>bottom) {
2783      return(0);
2784     }
2785 
2786     /*
2787      * Draw
2788      */
2789     result = 0;
2790     do {
2791 	xpcx = x + cx;
2792 	xmcx = x - cx;
2793 	xpcy = x + cy;
2794 	xmcy = x - cy;
2795 	if (ocy != cy) {
2796 	    if (cy > 0) {
2797 		ypcy = y + cy;
2798 		ymcy = y - cy;
2799 		result |= hlineColor(dst, xmcx, xpcx, ypcy, color);
2800 		result |= hlineColor(dst, xmcx, xpcx, ymcy, color);
2801 	    } else {
2802 		result |= hlineColor(dst, xmcx, xpcx, y, color);
2803 	    }
2804 	    ocy = cy;
2805 	}
2806 	if (ocx != cx) {
2807 	    if (cx != cy) {
2808 		if (cx > 0) {
2809 		    ypcx = y + cx;
2810 		    ymcx = y - cx;
2811 		    result |= hlineColor(dst, xmcy, xpcy, ymcx, color);
2812 		    result |= hlineColor(dst, xmcy, xpcy, ypcx, color);
2813 		} else {
2814 		    result |= hlineColor(dst, xmcy, xpcy, y, color);
2815 		}
2816 	    }
2817 	    ocx = cx;
2818 	}
2819 	/*
2820 	 * Update
2821 	 */
2822 	if (df < 0) {
2823 	    df += d_e;
2824 	    d_e += 2;
2825 	    d_se += 2;
2826 	} else {
2827 	    df += d_se;
2828 	    d_e += 2;
2829 	    d_se += 4;
2830 	    cy--;
2831 	}
2832 	cx++;
2833     } while (cx <= cy);
2834 
2835     return (result);
2836 }
2837 
filledCircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2838 int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2839 {
2840     /*
2841      * Draw
2842      */
2843     return (filledCircleColor
2844 	    (dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2845 }
2846 
2847 
2848 /* ----- Ellipse */
2849 
2850 /* Note: Based on algorithm from sge library with multiple-hline draw removal */
2851 /* and other speedup changes. */
2852 
ellipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)2853 int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
2854 {
2855     Sint16 left, right, top, bottom;
2856     int result;
2857     Sint16 x1, y1, x2, y2;
2858     int ix, iy;
2859     int h, i, j, k;
2860     int oh, oi, oj, ok;
2861     int xmh, xph, ypk, ymk;
2862     int xmi, xpi, ymj, ypj;
2863     int xmj, xpj, ymi, ypi;
2864     int xmk, xpk, ymh, yph;
2865     Uint8 *colorptr;
2866 
2867     /*
2868      * Check visibility of clipping rectangle
2869      */
2870     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2871      return(0);
2872     }
2873 
2874     /*
2875      * Sanity check radii
2876      */
2877     if ((rx < 0) || (ry < 0)) {
2878 	return (-1);
2879     }
2880 
2881     /*
2882      * Special case for rx=0 - draw a vline
2883      */
2884     if (rx == 0) {
2885 	return (vlineColor(dst, x, y - ry, y + ry, color));
2886     }
2887     /*
2888      * Special case for ry=0 - draw a hline
2889      */
2890     if (ry == 0) {
2891 	return (hlineColor(dst, x - rx, x + rx, y, color));
2892     }
2893 
2894     /*
2895      * Get circle and clipping boundary and
2896      * test if bounding box of circle is visible
2897      */
2898     x2 = x + rx;
2899     left = dst->clip_rect.x;
2900     if (x2<left) {
2901      return(0);
2902     }
2903     x1 = x - rx;
2904     right = dst->clip_rect.x + dst->clip_rect.w - 1;
2905     if (x1>right) {
2906      return(0);
2907     }
2908     y2 = y + ry;
2909     top = dst->clip_rect.y;
2910     if (y2<top) {
2911      return(0);
2912     }
2913     y1 = y - ry;
2914     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2915     if (y1>bottom) {
2916      return(0);
2917     }
2918 
2919     /*
2920      * Init vars
2921      */
2922     oh = oi = oj = ok = 0xFFFF;
2923 
2924     /*
2925      * Draw
2926      */
2927     result = 0;
2928 
2929     /* Lock surface */
2930     if (SDL_MUSTLOCK(dst)) {
2931 	if (SDL_LockSurface(dst) < 0) {
2932 	    return (-1);
2933 	}
2934     }
2935 
2936     /*
2937      * Check alpha
2938      */
2939     if ((color & 255) == 255) {
2940 
2941 	/*
2942 	 * No Alpha - direct memory writes
2943 	 */
2944 
2945 	/*
2946 	 * Setup color
2947 	 */
2948 	colorptr = (Uint8 *) & color;
2949 	if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2950 	    color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2951 	} else {
2952 	    color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2953 	}
2954 
2955 
2956 	if (rx > ry) {
2957 	    ix = 0;
2958 	    iy = rx * 64;
2959 
2960 	    do {
2961 		h = (ix + 32) >> 6;
2962 		i = (iy + 32) >> 6;
2963 		j = (h * ry) / rx;
2964 		k = (i * ry) / rx;
2965 
2966 		if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
2967 		    xph = x + h;
2968 		    xmh = x - h;
2969 		    if (k > 0) {
2970 			ypk = y + k;
2971 			ymk = y - k;
2972 			result |= fastPixelColorNolock(dst, xmh, ypk, color);
2973 			result |= fastPixelColorNolock(dst, xph, ypk, color);
2974 			result |= fastPixelColorNolock(dst, xmh, ymk, color);
2975 			result |= fastPixelColorNolock(dst, xph, ymk, color);
2976 		    } else {
2977 			result |= fastPixelColorNolock(dst, xmh, y, color);
2978 			result |= fastPixelColorNolock(dst, xph, y, color);
2979 		    }
2980 		    ok = k;
2981 		    xpi = x + i;
2982 		    xmi = x - i;
2983 		    if (j > 0) {
2984 			ypj = y + j;
2985 			ymj = y - j;
2986 			result |= fastPixelColorNolock(dst, xmi, ypj, color);
2987 			result |= fastPixelColorNolock(dst, xpi, ypj, color);
2988 			result |= fastPixelColorNolock(dst, xmi, ymj, color);
2989 			result |= fastPixelColorNolock(dst, xpi, ymj, color);
2990 		    } else {
2991 			result |= fastPixelColorNolock(dst, xmi, y, color);
2992 			result |= fastPixelColorNolock(dst, xpi, y, color);
2993 		    }
2994 		    oj = j;
2995 		}
2996 
2997 		ix = ix + iy / rx;
2998 		iy = iy - ix / rx;
2999 
3000 	    } while (i > h);
3001 	} else {
3002 	    ix = 0;
3003 	    iy = ry * 64;
3004 
3005 	    do {
3006 		h = (ix + 32) >> 6;
3007 		i = (iy + 32) >> 6;
3008 		j = (h * rx) / ry;
3009 		k = (i * rx) / ry;
3010 
3011 		if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3012 		    xmj = x - j;
3013 		    xpj = x + j;
3014 		    if (i > 0) {
3015 			ypi = y + i;
3016 			ymi = y - i;
3017 			result |= fastPixelColorNolock(dst, xmj, ypi, color);
3018 			result |= fastPixelColorNolock(dst, xpj, ypi, color);
3019 			result |= fastPixelColorNolock(dst, xmj, ymi, color);
3020 			result |= fastPixelColorNolock(dst, xpj, ymi, color);
3021 		    } else {
3022 			result |= fastPixelColorNolock(dst, xmj, y, color);
3023 			result |= fastPixelColorNolock(dst, xpj, y, color);
3024 		    }
3025 		    oi = i;
3026 		    xmk = x - k;
3027 		    xpk = x + k;
3028 		    if (h > 0) {
3029 			yph = y + h;
3030 			ymh = y - h;
3031 			result |= fastPixelColorNolock(dst, xmk, yph, color);
3032 			result |= fastPixelColorNolock(dst, xpk, yph, color);
3033 			result |= fastPixelColorNolock(dst, xmk, ymh, color);
3034 			result |= fastPixelColorNolock(dst, xpk, ymh, color);
3035 		    } else {
3036 			result |= fastPixelColorNolock(dst, xmk, y, color);
3037 			result |= fastPixelColorNolock(dst, xpk, y, color);
3038 		    }
3039 		    oh = h;
3040 		}
3041 
3042 		ix = ix + iy / ry;
3043 		iy = iy - ix / ry;
3044 
3045 	    } while (i > h);
3046 	}
3047 
3048     } else {
3049 
3050 	if (rx > ry) {
3051 	    ix = 0;
3052 	    iy = rx * 64;
3053 
3054 	    do {
3055 		h = (ix + 32) >> 6;
3056 		i = (iy + 32) >> 6;
3057 		j = (h * ry) / rx;
3058 		k = (i * ry) / rx;
3059 
3060 		if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
3061 		    xph = x + h;
3062 		    xmh = x - h;
3063 		    if (k > 0) {
3064 			ypk = y + k;
3065 			ymk = y - k;
3066 			result |= pixelColorNolock (dst, xmh, ypk, color);
3067 			result |= pixelColorNolock (dst, xph, ypk, color);
3068 			result |= pixelColorNolock (dst, xmh, ymk, color);
3069 			result |= pixelColorNolock (dst, xph, ymk, color);
3070 		    } else {
3071 			result |= pixelColorNolock (dst, xmh, y, color);
3072 			result |= pixelColorNolock (dst, xph, y, color);
3073 		    }
3074 		    ok = k;
3075 		    xpi = x + i;
3076 		    xmi = x - i;
3077 		    if (j > 0) {
3078 			ypj = y + j;
3079 			ymj = y - j;
3080 			result |= pixelColorNolock (dst, xmi, ypj, color);
3081 			result |= pixelColorNolock (dst, xpi, ypj, color);
3082 			result |= pixelColorNolock (dst, xmi, ymj, color);
3083 			result |= pixelColor(dst, xpi, ymj, color);
3084 		    } else {
3085 			result |= pixelColorNolock (dst, xmi, y, color);
3086 			result |= pixelColorNolock (dst, xpi, y, color);
3087 		    }
3088 		    oj = j;
3089 		}
3090 
3091 		ix = ix + iy / rx;
3092 		iy = iy - ix / rx;
3093 
3094 	    } while (i > h);
3095 	} else {
3096 	    ix = 0;
3097 	    iy = ry * 64;
3098 
3099 	    do {
3100 		h = (ix + 32) >> 6;
3101 		i = (iy + 32) >> 6;
3102 		j = (h * rx) / ry;
3103 		k = (i * rx) / ry;
3104 
3105 		if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3106 		    xmj = x - j;
3107 		    xpj = x + j;
3108 		    if (i > 0) {
3109 			ypi = y + i;
3110 			ymi = y - i;
3111 			result |= pixelColorNolock (dst, xmj, ypi, color);
3112 			result |= pixelColorNolock (dst, xpj, ypi, color);
3113 			result |= pixelColorNolock (dst, xmj, ymi, color);
3114 			result |= pixelColorNolock (dst, xpj, ymi, color);
3115 		    } else {
3116 			result |= pixelColorNolock (dst, xmj, y, color);
3117 			result |= pixelColorNolock (dst, xpj, y, color);
3118 		    }
3119 		    oi = i;
3120 		    xmk = x - k;
3121 		    xpk = x + k;
3122 		    if (h > 0) {
3123 			yph = y + h;
3124 			ymh = y - h;
3125 			result |= pixelColorNolock (dst, xmk, yph, color);
3126 			result |= pixelColorNolock (dst, xpk, yph, color);
3127 			result |= pixelColorNolock (dst, xmk, ymh, color);
3128 			result |= pixelColorNolock (dst, xpk, ymh, color);
3129 		    } else {
3130 			result |= pixelColorNolock (dst, xmk, y, color);
3131 			result |= pixelColorNolock (dst, xpk, y, color);
3132 		    }
3133 		    oh = h;
3134 		}
3135 
3136 		ix = ix + iy / ry;
3137 		iy = iy - ix / ry;
3138 
3139 	    } while (i > h);
3140 	}
3141 
3142     }				/* Alpha check */
3143 
3144     /* Unlock surface */
3145     if (SDL_MUSTLOCK(dst)) {
3146 	SDL_UnlockSurface(dst);
3147     }
3148 
3149     return (result);
3150 }
3151 
ellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3152 int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3153 {
3154     /*
3155      * Draw
3156      */
3157     return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3158 }
3159 
3160 /* ----- AA Ellipse */
3161 
3162 #if 0
3163 /* Win32 does not have lrint, so provide a local inline version */
3164 #ifdef WIN32
3165 
3166 __inline long int
3167 lrint (double ftl)
3168 {
3169   int intgr;
3170   _asm
3171   {
3172     fld flt
3173     fistp intgr
3174   };
3175   return intgr;
3176 }
3177 
3178 #endif
3179 #endif
3180 
3181 /* Based on code from Anders Lindstroem, based on code from SGE, based on code from TwinLib */
3182 
aaellipseColor(SDL_Surface * dst,Sint16 xc,Sint16 yc,Sint16 rx,Sint16 ry,Uint32 color)3183 int aaellipseColor(SDL_Surface * dst, Sint16 xc, Sint16 yc, Sint16 rx, Sint16 ry, Uint32 color)
3184 {
3185     Sint16 left, right, top, bottom;
3186     Sint16 x1,y1,x2,y2;
3187     int i;
3188     int a2, b2, ds, dt, dxt, t, s, d;
3189     Sint16 x, y, xs, ys, dyt, od, xx, yy, xc2, yc2;
3190     float cp;
3191     double sab;
3192     Uint16 balance;
3193     WeightPair weightPair;
3194     int result;
3195 
3196     /*
3197      * Check visibility of clipping rectangle
3198      */
3199     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3200      return(0);
3201     }
3202 
3203     /*
3204      * Sanity check radii
3205      */
3206     if ((rx < 0) || (ry < 0)) {
3207 	return (-1);
3208     }
3209 
3210     /*
3211      * Special case for rx=0 - draw a vline
3212      */
3213     if (rx == 0) {
3214 	return (vlineColor(dst, xc, yc - ry, yc + ry, color));
3215     }
3216     /*
3217      * Special case for ry=0 - draw a hline
3218      */
3219     if (ry == 0) {
3220 	return (hlineColor(dst, xc - rx, xc + rx, yc, color));
3221     }
3222 
3223     /*
3224      * Special case for rx=1=ry - draw non-aa version
3225      * (this is to work around a bug in the aa code below)
3226      */
3227     if (rx == 1 && ry == 1)
3228 	return ellipseColor(dst, xc, yc, rx, ry, color);
3229 
3230     /*
3231      * Get circle and clipping boundary and
3232      * test if bounding box of circle is visible
3233      */
3234     x2 = xc + rx;
3235     left = dst->clip_rect.x;
3236     if (x2<left) {
3237      return(0);
3238     }
3239     x1 = xc - rx;
3240     right = dst->clip_rect.x + dst->clip_rect.w - 1;
3241     if (x1>right) {
3242      return(0);
3243     }
3244     y2 = yc + ry;
3245     top = dst->clip_rect.y;
3246     if (y2<top) {
3247      return(0);
3248     }
3249     y1 = yc - ry;
3250     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3251     if (y1>bottom) {
3252      return(0);
3253     }
3254 
3255     /* Variable setup */
3256     a2 = rx * rx;
3257     b2 = ry * ry;
3258 
3259     ds = 2 * a2;
3260     dt = 2 * b2;
3261 
3262     xc2 = 2 * xc;
3263     yc2 = 2 * yc;
3264 
3265     sab = sqrt(a2 + b2);
3266     od = lrint(sab*0.01) + 1; /* introduce some overdraw */
3267     dxt = lrint((double)a2 / sab) + od;
3268 
3269     t = 0;
3270     s = -2 * a2 * ry;
3271     d = 0;
3272 
3273     x = xc;
3274     y = yc - ry;
3275 
3276     /* Draw */
3277     result = 0;
3278 
3279     /* Lock surface */
3280     if (SDL_MUSTLOCK(dst)) {
3281 	if (SDL_LockSurface(dst) < 0) {
3282 	    return (-1);
3283 	}
3284     }
3285 
3286     /* "End points" */
3287     result |= pixelColorNolock(dst, x, y, color);
3288     result |= pixelColorNolock(dst, xc2 - x, y, color);
3289     result |= pixelColorNolock(dst, x, yc2 - y, color);
3290     result |= pixelColorNolock(dst, xc2 - x, yc2 - y, color);
3291 
3292     for (i = 1; i <= dxt; i++) {
3293 	x--;
3294 	d += t - b2;
3295 
3296 	if (d >= 0)
3297 	    ys = y - 1;
3298 	else if ((d - s - a2) > 0) {
3299 	    if ((2 * d - s - a2) >= 0)
3300 		ys = y + 1;
3301 	    else {
3302 		ys = y;
3303 		y++;
3304 		d -= s + a2;
3305 		s += ds;
3306 	    }
3307 	} else {
3308 	    y++;
3309 	    ys = y + 1;
3310 	    d -= s + a2;
3311 	    s += ds;
3312 	}
3313 
3314 	t -= dt;
3315 
3316 	/* Calculate alpha */
3317 	if (s != 0.0) {
3318 	    cp = (float) abs(d) / (float) abs(s);
3319 	    if (cp > 1.0) {
3320 		cp = 1.0;
3321 	    }
3322 	} else {
3323 	    cp = 1.0;
3324 	}
3325 
3326 	/* Calculate weights */
3327 	balance = (Uint16) (cp * 255);
3328 	weightPair = getWeights(balance);
3329 
3330 	/* Upper half */
3331 	xx = xc2 - x;
3332 	result |= pixelColorWeightNolock(dst, x, y, color, weightPair.complement);
3333 	result |= pixelColorWeightNolock(dst, xx, y, color, weightPair.complement);
3334 
3335 	result |= pixelColorWeightNolock(dst, x, ys, color, weightPair.main);
3336 	result |= pixelColorWeightNolock(dst, xx, ys, color, weightPair.main);
3337 
3338 	/* Lower half */
3339 	yy = yc2 - y;
3340 	result |= pixelColorWeightNolock(dst, x, yy, color, weightPair.complement);
3341 	result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.complement);
3342 
3343 	yy = yc2 - ys;
3344 	result |= pixelColorWeightNolock(dst, x, yy, color, weightPair.main);
3345 	result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.main);
3346     }
3347 
3348     /* Replaces original approximation code dyt = abs(y - yc); */
3349     dyt = lrint((double)b2 / sab ) + od;
3350 
3351     for (i = 1; i <= dyt; i++) {
3352 	y++;
3353 	d -= s + a2;
3354 
3355 	if (d <= 0)
3356 	    xs = x + 1;
3357 	else if ((d + t - b2) < 0) {
3358 	    if ((2 * d + t - b2) <= 0)
3359 		xs = x - 1;
3360 	    else {
3361 		xs = x;
3362 		x--;
3363 		d += t - b2;
3364 		t -= dt;
3365 	    }
3366 	} else {
3367 	    x--;
3368 	    xs = x - 1;
3369 	    d += t - b2;
3370 	    t -= dt;
3371 	}
3372 
3373 	s += ds;
3374 
3375 	/* Calculate alpha */
3376 	if (t != 0.0) {
3377 	    cp = (float) abs(d) / (float) abs(t);
3378 	    if (cp > 1.0) {
3379 		cp = 1.0;
3380 	    }
3381 	} else {
3382 	    cp = 1.0;
3383 	}
3384 
3385 	/* Calculate weight */
3386 	balance = (Uint16) (cp * 255);
3387 	weightPair = getWeights(balance);
3388 
3389 	/* Left half */
3390 	xx = xc2 - x;
3391 	yy = yc2 - y;
3392 	result |= pixelColorWeightNolock(dst, x, y, color, weightPair.complement);
3393 	result |= pixelColorWeightNolock(dst, xx, y, color, weightPair.complement);
3394 
3395 	result |= pixelColorWeightNolock(dst, x, yy, color, weightPair.complement);
3396 	result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.complement);
3397 
3398 	/* Right half */
3399 	xx = 2 * xc - xs;
3400 	result |= pixelColorWeightNolock(dst, xs, y, color, weightPair.main);
3401 	result |= pixelColorWeightNolock(dst, xx, y, color, weightPair.main);
3402 
3403 	result |= pixelColorWeightNolock(dst, xs, yy, color, weightPair.main);
3404 	result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.main);
3405 
3406     }
3407 
3408     /* Unlock surface */
3409     if (SDL_MUSTLOCK(dst)) {
3410 	SDL_UnlockSurface(dst);
3411     }
3412 
3413     return (result);
3414 }
3415 
aaellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3416 int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3417 {
3418     /*
3419      * Draw
3420      */
3421     return (aaellipseColor
3422 	    (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3423 }
3424 
3425 /* ---- Filled Ellipse */
3426 
3427 /* Note: */
3428 /* Based on algorithm from sge library with multiple-hline draw removal */
3429 /* and other speedup changes. */
3430 
filledEllipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)3431 int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
3432 {
3433     Sint16 left, right, top, bottom;
3434     int result;
3435     Sint16 x1, y1, x2, y2;
3436     int ix, iy;
3437     int h, i, j, k;
3438     int oh, oi, oj, ok;
3439     int xmh, xph;
3440     int xmi, xpi;
3441     int xmj, xpj;
3442     int xmk, xpk;
3443 
3444     /*
3445      * Check visibility of clipping rectangle
3446      */
3447     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3448      return(0);
3449     }
3450 
3451     /*
3452      * Sanity check radii
3453      */
3454     if ((rx < 0) || (ry < 0)) {
3455 	return (-1);
3456     }
3457 
3458     /*
3459      * Special case for rx=0 - draw a vline
3460      */
3461     if (rx == 0) {
3462 	return (vlineColor(dst, x, y - ry, y + ry, color));
3463     }
3464     /*
3465      * Special case for ry=0 - draw a hline
3466      */
3467     if (ry == 0) {
3468 	return (hlineColor(dst, x - rx, x + rx, y, color));
3469     }
3470 
3471     /*
3472      * Get circle and clipping boundary and
3473      * test if bounding box of circle is visible
3474      */
3475     x2 = x + rx;
3476     left = dst->clip_rect.x;
3477     if (x2<left) {
3478      return(0);
3479     }
3480     x1 = x - rx;
3481     right = dst->clip_rect.x + dst->clip_rect.w - 1;
3482     if (x1>right) {
3483      return(0);
3484     }
3485     y2 = y + ry;
3486     top = dst->clip_rect.y;
3487     if (y2<top) {
3488      return(0);
3489     }
3490     y1 = y - ry;
3491     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3492     if (y1>bottom) {
3493      return(0);
3494     }
3495 
3496     /*
3497      * Init vars
3498      */
3499     oh = oi = oj = ok = 0xFFFF;
3500 
3501     /*
3502      * Draw
3503      */
3504     result = 0;
3505     if (rx > ry) {
3506 	ix = 0;
3507 	iy = rx * 64;
3508 
3509 	do {
3510 	    h = (ix + 32) >> 6;
3511 	    i = (iy + 32) >> 6;
3512 	    j = (h * ry) / rx;
3513 	    k = (i * ry) / rx;
3514 
3515 	    if ((ok != k) && (oj != k)) {
3516 		xph = x + h;
3517 		xmh = x - h;
3518 		if (k > 0) {
3519 		    result |= hlineColor(dst, xmh, xph, y + k, color);
3520 		    result |= hlineColor(dst, xmh, xph, y - k, color);
3521 		} else {
3522 		    result |= hlineColor(dst, xmh, xph, y, color);
3523 		}
3524 		ok = k;
3525 	    }
3526 	    if ((oj != j) && (ok != j) && (k != j)) {
3527 		xmi = x - i;
3528 		xpi = x + i;
3529 		if (j > 0) {
3530 		    result |= hlineColor(dst, xmi, xpi, y + j, color);
3531 		    result |= hlineColor(dst, xmi, xpi, y - j, color);
3532 		} else {
3533 		    result |= hlineColor(dst, xmi, xpi, y, color);
3534 		}
3535 		oj = j;
3536 	    }
3537 
3538 	    ix = ix + iy / rx;
3539 	    iy = iy - ix / rx;
3540 
3541 	} while (i > h);
3542     } else {
3543 	ix = 0;
3544 	iy = ry * 64;
3545 
3546 	do {
3547 	    h = (ix + 32) >> 6;
3548 	    i = (iy + 32) >> 6;
3549 	    j = (h * rx) / ry;
3550 	    k = (i * rx) / ry;
3551 
3552 	    if ((oi != i) && (oh != i)) {
3553 		xmj = x - j;
3554 		xpj = x + j;
3555 		if (i > 0) {
3556 		    result |= hlineColor(dst, xmj, xpj, y + i, color);
3557 		    result |= hlineColor(dst, xmj, xpj, y - i, color);
3558 		} else {
3559 		    result |= hlineColor(dst, xmj, xpj, y, color);
3560 		}
3561 		oi = i;
3562 	    }
3563 	    if ((oh != h) && (oi != h) && (i != h)) {
3564 		xmk = x - k;
3565 		xpk = x + k;
3566 		if (h > 0) {
3567 		    result |= hlineColor(dst, xmk, xpk, y + h, color);
3568 		    result |= hlineColor(dst, xmk, xpk, y - h, color);
3569 		} else {
3570 		    result |= hlineColor(dst, xmk, xpk, y, color);
3571 		}
3572 		oh = h;
3573 	    }
3574 
3575 	    ix = ix + iy / ry;
3576 	    iy = iy - ix / ry;
3577 
3578 	} while (i > h);
3579     }
3580 
3581     return (result);
3582 }
3583 
3584 
filledEllipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3585 int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3586 {
3587     /*
3588      * Draw
3589      */
3590     return (filledEllipseColor
3591 	    (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3592 }
3593 
3594 /* ----- filled pie */
3595 
3596 /* Low-speed float pie-calc implementation by drawing polygons/lines. */
3597 
doPieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color,Uint8 filled)3598 int doPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color, Uint8 filled)
3599 {
3600     Sint16 left, right, top, bottom;
3601     Sint16 x1, y1, x2, y2;
3602     int result;
3603     double angle, start_angle, end_angle;
3604     double deltaAngle;
3605     double dr;
3606     int posX, posY;
3607     int numpoints, i;
3608     Sint16 *vx, *vy;
3609 
3610     /*
3611      * Check visibility of clipping rectangle
3612      */
3613     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3614      return(0);
3615     }
3616 
3617     /*
3618      * Sanity check radii
3619      */
3620     if (rad < 0) {
3621 	return (-1);
3622     }
3623 
3624     /*
3625      * Fixup angles
3626      */
3627     start = start % 360;
3628     end = end % 360;
3629 
3630     /*
3631      * Special case for rad=0 - draw a point
3632      */
3633     if (rad == 0) {
3634 	return (pixelColor(dst, x, y, color));
3635     }
3636 
3637     /*
3638      * Clip against circle, not pie (not 100% optimal).
3639      * Get pie's circle and clipping boundary and
3640      * test if bounding box of circle is visible
3641      */
3642     x2 = x + rad;
3643     left = dst->clip_rect.x;
3644     if (x2<left) {
3645      return(0);
3646     }
3647     x1 = x - rad;
3648     right = dst->clip_rect.x + dst->clip_rect.w - 1;
3649     if (x1>right) {
3650      return(0);
3651     }
3652     y2 = y + rad;
3653     top = dst->clip_rect.y;
3654     if (y2<top) {
3655      return(0);
3656     }
3657     y1 = y - rad;
3658     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3659     if (y1>bottom) {
3660      return(0);
3661     }
3662 
3663     /*
3664      * Variable setup
3665      */
3666     dr = (double) rad;
3667     deltaAngle = 3.0 / dr;
3668     start_angle = (double) start *(2.0 * M_PI / 360.0);
3669     end_angle = (double) end *(2.0 * M_PI / 360.0);
3670     if (start > end) {
3671 	end_angle += (2.0 * M_PI);
3672     }
3673 
3674     /* Count points (rather than calculate it) */
3675     numpoints = 1;
3676     angle = start_angle;
3677     while (angle <= end_angle) {
3678 	angle += deltaAngle;
3679 	numpoints++;
3680     }
3681 
3682     /* Check size of array */
3683     if (numpoints == 1) {
3684 	return (pixelColor(dst, x, y, color));
3685     } else if (numpoints == 2) {
3686 	posX = x + (int) (dr * cos(start_angle));
3687 	posY = y + (int) (dr * sin(start_angle));
3688 	return (lineColor(dst, x, y, posX, posY, color));
3689     }
3690 
3691     /* Allocate vertex array */
3692     vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
3693     if (vx == NULL) {
3694 	return (-1);
3695     }
3696     vy += numpoints;
3697 
3698     /* Center */
3699     vx[0] = x;
3700     vy[0] = y;
3701 
3702     /* Calculate and store vertices */
3703     i = 1;
3704     angle = start_angle;
3705     while (angle <= end_angle) {
3706 	vx[i] = x + (int) (dr * cos(angle));
3707 	vy[i] = y + (int) (dr * sin(angle));
3708 	angle += deltaAngle;
3709 	i++;
3710     }
3711 
3712     /* Draw */
3713     if (filled) {
3714      result = filledPolygonColor(dst, vx, vy, numpoints, color);
3715     } else {
3716      result = polygonColor(dst, vx, vy, numpoints, color);
3717     }
3718 
3719     /* Free vertex array */
3720     free(vx);
3721 
3722     return (result);
3723 }
3724 
pieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)3725 int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
3726 		Sint16 start, Sint16 end, Uint32 color)
3727 {
3728     return (doPieColor(dst, x, y, rad, start, end, color, 0));
3729 
3730 }
3731 
pieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3732 int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
3733 	    Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3734 {
3735     return (doPieColor(dst, x, y, rad, start, end,
3736 			   ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 0));
3737 
3738 }
3739 
filledPieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)3740 int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
3741 {
3742     return (doPieColor(dst, x, y, rad, start, end, color, 1));
3743 }
3744 
filledPieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3745 int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
3746 		  Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3747 {
3748     return (doPieColor(dst, x, y, rad, start, end,
3749 			   ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
3750 }
3751 
3752 /* Trigon */
3753 
trigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)3754 int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
3755 {
3756  Sint16 vx[3];
3757  Sint16 vy[3];
3758 
3759  vx[0]=x1;
3760  vx[1]=x2;
3761  vx[2]=x3;
3762  vy[0]=y1;
3763  vy[1]=y2;
3764  vy[2]=y3;
3765 
3766  return(polygonColor(dst,vx,vy,3,color));
3767 }
3768 
trigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3769 int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
3770 				 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3771 {
3772  Sint16 vx[3];
3773  Sint16 vy[3];
3774 
3775  vx[0]=x1;
3776  vx[1]=x2;
3777  vx[2]=x3;
3778  vy[0]=y1;
3779  vy[1]=y2;
3780  vy[2]=y3;
3781 
3782  return(polygonRGBA(dst,vx,vy,3,r,g,b,a));
3783 }
3784 
3785 /* AA-Trigon */
3786 
aatrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)3787 int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
3788 {
3789  Sint16 vx[3];
3790  Sint16 vy[3];
3791 
3792  vx[0]=x1;
3793  vx[1]=x2;
3794  vx[2]=x3;
3795  vy[0]=y1;
3796  vy[1]=y2;
3797  vy[2]=y3;
3798 
3799  return(aapolygonColor(dst,vx,vy,3,color));
3800 }
3801 
aatrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3802 int aatrigonRGBA(SDL_Surface * dst,  Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
3803 				   Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3804 {
3805  Sint16 vx[3];
3806  Sint16 vy[3];
3807 
3808  vx[0]=x1;
3809  vx[1]=x2;
3810  vx[2]=x3;
3811  vy[0]=y1;
3812  vy[1]=y2;
3813  vy[2]=y3;
3814 
3815  return(aapolygonRGBA(dst,vx,vy,3,r,g,b,a));
3816 }
3817 
3818 /* Filled Trigon */
3819 
filledTrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)3820 int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
3821 {
3822  Sint16 vx[3];
3823  Sint16 vy[3];
3824 
3825  vx[0]=x1;
3826  vx[1]=x2;
3827  vx[2]=x3;
3828  vy[0]=y1;
3829  vy[1]=y2;
3830  vy[2]=y3;
3831 
3832  return(filledPolygonColor(dst,vx,vy,3,color));
3833 }
3834 
filledTrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3835 int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
3836 				       Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3837 {
3838  Sint16 vx[3];
3839  Sint16 vy[3];
3840 
3841  vx[0]=x1;
3842  vx[1]=x2;
3843  vx[2]=x3;
3844  vy[0]=y1;
3845  vy[1]=y2;
3846  vy[2]=y3;
3847 
3848  return(filledPolygonRGBA(dst,vx,vy,3,r,g,b,a));
3849 }
3850 
3851 /* ---- Polygon */
3852 
polygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)3853 int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
3854 {
3855     int result;
3856     int i;
3857     const Sint16 *x1, *y1, *x2, *y2;
3858 
3859     /*
3860      * Check visibility of clipping rectangle
3861      */
3862     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3863      return(0);
3864     }
3865 
3866     /*
3867      * Sanity check
3868      */
3869     if (n < 3) {
3870 	return (-1);
3871     }
3872 
3873     /*
3874      * Pointer setup
3875      */
3876     x1 = x2 = vx;
3877     y1 = y2 = vy;
3878     x2++;
3879     y2++;
3880 
3881     /*
3882      * Draw
3883      */
3884     result = 0;
3885     for (i = 1; i < n; i++) {
3886 	result |= lineColor(dst, *x1, *y1, *x2, *y2, color);
3887 	x1 = x2;
3888 	y1 = y2;
3889 	x2++;
3890 	y2++;
3891     }
3892     result |= lineColor(dst, *x1, *y1, *vx, *vy, color);
3893 
3894     return (result);
3895 }
3896 
polygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3897 int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3898 {
3899     /*
3900      * Draw
3901      */
3902     return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3903 }
3904 
3905 /* ---- AA-Polygon */
3906 
aapolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)3907 int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
3908 {
3909     int result;
3910     int i;
3911     const Sint16 *x1, *y1, *x2, *y2;
3912 
3913     /*
3914      * Check visibility of clipping rectangle
3915      */
3916     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3917      return(0);
3918     }
3919 
3920     /*
3921      * Sanity check
3922      */
3923     if (n < 3) {
3924 	return (-1);
3925     }
3926 
3927     /*
3928      * Pointer setup
3929      */
3930     x1 = x2 = vx;
3931     y1 = y2 = vy;
3932     x2++;
3933     y2++;
3934 
3935     /*
3936      * Draw
3937      */
3938     result = 0;
3939     for (i = 1; i < n; i++) {
3940 	result |= aalineColorInt(dst, *x1, *y1, *x2, *y2, color, 0);
3941 	x1 = x2;
3942 	y1 = y2;
3943 	x2++;
3944 	y2++;
3945     }
3946     result |= aalineColorInt(dst, *x1, *y1, *vx, *vy, color, 0);
3947 
3948     return (result);
3949 }
3950 
aapolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3951 int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3952 {
3953     /*
3954      * Draw
3955      */
3956     return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3957 }
3958 
3959 /* ---- Filled Polygon */
3960 
3961 int gfxPrimitivesCompareInt(const void *a, const void *b);
3962 
3963 /* Global vertex array to use if optional parameters are not given in polygon calls. */
3964 static int *gfxPrimitivesPolyIntsGlobal = NULL;
3965 static int gfxPrimitivesPolyAllocatedGlobal = 0;
3966 
3967 /* (Note: The last two parameters are optional; but required for multithreaded operation.) */
3968 
filledPolygonColorMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color,int ** polyInts,int * polyAllocated)3969 int filledPolygonColorMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color, int **polyInts, int *polyAllocated)
3970 {
3971     int result;
3972     int i;
3973     int y, xa, xb;
3974     int miny, maxy;
3975     int x1, y1;
3976     int x2, y2;
3977     int ind1, ind2;
3978     int ints;
3979     int *gfxPrimitivesPolyInts = NULL;
3980     int gfxPrimitivesPolyAllocated = 0;
3981 
3982     /*
3983      * Check visibility of clipping rectangle
3984      */
3985     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3986      return(0);
3987     }
3988 
3989     /*
3990      * Sanity check number of edges
3991      */
3992     if (n < 3) {
3993 	return -1;
3994     }
3995 
3996     /*
3997      * Map polygon cache
3998      */
3999     if ((polyInts==NULL) || (polyAllocated==NULL)) {
4000        /* Use global cache */
4001        gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
4002        gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
4003     } else {
4004        /* Use local cache */
4005        gfxPrimitivesPolyInts = *polyInts;
4006        gfxPrimitivesPolyAllocated = *polyAllocated;
4007     }
4008 
4009     /*
4010      * Allocate temp array, only grow array
4011      */
4012     if (!gfxPrimitivesPolyAllocated) {
4013 	gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
4014 	gfxPrimitivesPolyAllocated = n;
4015     } else {
4016 	if (gfxPrimitivesPolyAllocated < n) {
4017 	    gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
4018 	    gfxPrimitivesPolyAllocated = n;
4019 	}
4020     }
4021 
4022     /*
4023      * Check temp array
4024      */
4025     if (gfxPrimitivesPolyInts==NULL) {
4026       gfxPrimitivesPolyAllocated = 0;
4027     }
4028 
4029     /*
4030      * Update cache variables
4031      */
4032     if ((polyInts==NULL) || (polyAllocated==NULL)) {
4033      gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
4034      gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
4035     } else {
4036      *polyInts = gfxPrimitivesPolyInts;
4037      *polyAllocated = gfxPrimitivesPolyAllocated;
4038     }
4039 
4040     /*
4041      * Check temp array again
4042      */
4043     if (gfxPrimitivesPolyInts==NULL) {
4044 	return(-1);
4045     }
4046 
4047     /*
4048      * Determine Y maxima
4049      */
4050     miny = vy[0];
4051     maxy = vy[0];
4052     for (i = 1; (i < n); i++) {
4053 	if (vy[i] < miny) {
4054 	    miny = vy[i];
4055 	} else if (vy[i] > maxy) {
4056 	    maxy = vy[i];
4057 	}
4058     }
4059 
4060     /*
4061      * Draw, scanning y
4062      */
4063     result = 0;
4064     for (y = miny; (y <= maxy); y++) {
4065 	ints = 0;
4066 	for (i = 0; (i < n); i++) {
4067 	    if (!i) {
4068 		ind1 = n - 1;
4069 		ind2 = 0;
4070 	    } else {
4071 		ind1 = i - 1;
4072 		ind2 = i;
4073 	    }
4074 	    y1 = vy[ind1];
4075 	    y2 = vy[ind2];
4076 	    if (y1 < y2) {
4077 		x1 = vx[ind1];
4078 		x2 = vx[ind2];
4079 	    } else if (y1 > y2) {
4080 		y2 = vy[ind1];
4081 		y1 = vy[ind2];
4082 		x2 = vx[ind1];
4083 		x1 = vx[ind2];
4084 	    } else {
4085 		continue;
4086 	    }
4087 	    if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
4088 		gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
4089 	    }
4090 	}
4091 
4092 	qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt);
4093 
4094 	for (i = 0; (i < ints); i += 2) {
4095 	    xa = gfxPrimitivesPolyInts[i] + 1;
4096 	    xa = (xa >> 16) + ((xa & 32768) >> 15);
4097 	    xb = gfxPrimitivesPolyInts[i+1] - 1;
4098 	    xb = (xb >> 16) + ((xb & 32768) >> 15);
4099 	    result |= hlineColor(dst, xa, xb, y, color);
4100 	}
4101     }
4102 
4103     return (result);
4104 }
4105 
filledPolygonRGBAMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a,int ** polyInts,int * polyAllocated)4106 int filledPolygonRGBAMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int **polyInts, int *polyAllocated)
4107 {
4108     /*
4109      * Draw
4110      */
4111     return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, polyInts, polyAllocated));
4112 }
4113 
4114 /* Standard versions are calling multithreaded versions with NULL cache parameters */
4115 
filledPolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)4116 int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
4117 {
4118     /*
4119      * Draw
4120      */
4121     return (filledPolygonColorMT(dst, vx, vy, n, color, NULL, NULL));
4122 }
4123 
filledPolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4124 int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4125 {
4126     /*
4127      * Draw
4128      */
4129     return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, NULL, NULL));
4130 }
4131 
_texturedHLine(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,SDL_Surface * texture,int texture_dx,int texture_dy)4132 int _texturedHLine(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y,SDL_Surface *texture,int texture_dx,int texture_dy)
4133 {
4134     Sint16 left, right, top, bottom;
4135     Sint16 w;
4136     Sint16 xtmp;
4137     int result = 0;
4138     int texture_x_walker;
4139     int texture_y_start;
4140     SDL_Rect source_rect,dst_rect;
4141     int pixels_written,write_width;
4142 
4143     /*
4144      * Check visibility of clipping rectangle
4145      */
4146     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4147      return(0);
4148     }
4149 
4150     /*
4151      * Swap x1, x2 if required to ensure x1<=x2
4152      */
4153     if (x1 > x2) {
4154 	xtmp = x1;
4155 	x1 = x2;
4156 	x2 = xtmp;
4157     }
4158 
4159     /*
4160      * Get clipping boundary and
4161      * check visibility of hline
4162      */
4163     left = dst->clip_rect.x;
4164     if (x2<left) {
4165      return(0);
4166     }
4167     right = dst->clip_rect.x + dst->clip_rect.w - 1;
4168     if (x1>right) {
4169      return(0);
4170     }
4171     top = dst->clip_rect.y;
4172     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4173     if ((y<top) || (y>bottom)) {
4174      return (0);
4175     }
4176 
4177 
4178     /*
4179      * Clip x
4180      */
4181     if (x1 < left) {
4182 	x1 = left;
4183     }
4184     if (x2 > right) {
4185 	x2 = right;
4186     }
4187 
4188     /*
4189      * Calculate width
4190      */
4191     w = x2 - x1;
4192 
4193     /*
4194      * Determint where in the texture we start drawing
4195      **/
4196     texture_x_walker =   (x1 - texture_dx)  % texture->w;
4197     if (texture_x_walker < 0){
4198       texture_x_walker = texture->w +texture_x_walker ;
4199     }
4200 
4201     texture_y_start = (y + texture_dy) % texture->h;
4202     if (texture_y_start < 0){
4203        texture_y_start = texture->h + texture_y_start;
4204     }
4205 
4206     //setup the source rectangle  we are only drawing one horizontal line
4207     source_rect.y = texture_y_start;
4208     source_rect.x =texture_x_walker;
4209     source_rect.h =1;
4210     //we will draw to the current y
4211     dst_rect.y = y;
4212 
4213     //if there are enough pixels left in the current row of the texture
4214     //draw it all at once
4215     if (w <= texture->w -texture_x_walker){
4216       source_rect.w = w;
4217       source_rect.x = texture_x_walker;
4218       dst_rect.x= x1;
4219       if (dirtyDst == dst)
4220 	  dirtyRects.push_back(dst_rect);
4221       SDL_BlitSurface  (texture,&source_rect , dst, &dst_rect) ;
4222     } else {//we need to draw multiple times
4223       //draw the first segment
4224       pixels_written = texture->w  -texture_x_walker;
4225       source_rect.w = pixels_written;
4226       source_rect.x = texture_x_walker;
4227       dst_rect.x= x1;
4228       if (dirtyDst == dst)
4229 	  dirtyRects.push_back(dst_rect);
4230       SDL_BlitSurface  (texture,&source_rect , dst, &dst_rect);
4231       write_width = texture->w;
4232 
4233       //now draw the rest
4234       //set the source x to 0
4235       source_rect.x = 0;
4236       while(pixels_written < w){
4237         if (write_width >= w - pixels_written){
4238           write_width=  w- pixels_written;
4239         }
4240         source_rect.w = write_width;
4241         dst_rect.x = x1 + pixels_written;
4242 	if (dirtyDst == dst)
4243 	    dirtyRects.push_back(dst_rect);
4244         SDL_BlitSurface  (texture,&source_rect , dst, &dst_rect) ;
4245         pixels_written += write_width;
4246       }
4247   }
4248   return result;
4249 }
4250 
4251 /**
4252  * Draws a polygon filled with the given texture. this operation use SDL_BlitSurface. It supports
4253  * alpha drawing.
4254  * to get the best performance of this operation you need to make sure the texture and the dst surface have the same format
4255  * see  http://docs.mandragor.org/files/Common_libs_documentation/SDL/SDL_Documentation_project_en/sdlblitsurface.html
4256  *
4257  * dest the destination surface,
4258  * vx array of x vector components
4259  * vy array of x vector components
4260  * n the amount of vectors in the vx and vy array
4261  * texture the sdl surface to use to fill the polygon
4262  * texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
4263  * to the left and want the texture to apear the same you need to increase the texture_dx value
4264  * texture_dy see texture_dx
4265  *
4266  * (Note: The last two parameters are optional, but required for multithreaded operation.)
4267  **/
texturedPolygonMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy,int ** polyInts,int * polyAllocated)4268 int texturedPolygonMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface * texture,int texture_dx,int texture_dy, int **polyInts, int *polyAllocated)
4269 {
4270     int result;
4271     int i;
4272     int y, xa, xb;
4273     int minx,maxx,miny, maxy;
4274     int x1, y1;
4275     int x2, y2;
4276     int ind1, ind2;
4277     int ints;
4278     int *gfxPrimitivesPolyInts = NULL;
4279     int gfxPrimitivesPolyAllocated = 0;
4280 
4281     /*
4282      * Check visibility of clipping rectangle
4283      */
4284     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4285      return(0);
4286     }
4287 
4288     /*
4289      * Sanity check number of edges
4290      */
4291     if (n < 3) {
4292 	return -1;
4293     }
4294 
4295     /*
4296      * Map polygon cache
4297      */
4298     if ((polyInts==NULL) || (polyAllocated==NULL)) {
4299        /* Use global cache */
4300        gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
4301        gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
4302     } else {
4303        /* Use local cache */
4304        gfxPrimitivesPolyInts = *polyInts;
4305        gfxPrimitivesPolyAllocated = *polyAllocated;
4306     }
4307 
4308     /*
4309      * Allocate temp array, only grow array
4310      */
4311     if (!gfxPrimitivesPolyAllocated) {
4312 	gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
4313 	gfxPrimitivesPolyAllocated = n;
4314     } else {
4315 	if (gfxPrimitivesPolyAllocated < n) {
4316 	    gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
4317 	    gfxPrimitivesPolyAllocated = n;
4318 	}
4319     }
4320 
4321     /*
4322      * Check temp array
4323      */
4324     if (gfxPrimitivesPolyInts==NULL) {
4325       gfxPrimitivesPolyAllocated = 0;
4326     }
4327 
4328     /*
4329      * Update cache variables
4330      */
4331     if ((polyInts==NULL) || (polyAllocated==NULL)) {
4332      gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
4333      gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
4334     } else {
4335      *polyInts = gfxPrimitivesPolyInts;
4336      *polyAllocated = gfxPrimitivesPolyAllocated;
4337     }
4338 
4339     /*
4340      * Check temp array again
4341      */
4342     if (gfxPrimitivesPolyInts==NULL) {
4343 	return(-1);
4344     }
4345 
4346     /*
4347      * Determine X,Y minima,maxima
4348      */
4349     miny = vy[0];
4350     maxy = vy[0];
4351     minx = vx[0];
4352     maxx = vx[0];
4353     for (i = 1; (i < n); i++) {
4354         if (vy[i] < miny) {
4355             miny = vy[i];
4356         } else if (vy[i] > maxy) {
4357             maxy = vy[i];
4358         }
4359         if (vx[i] < minx) {
4360             minx = vx[i];
4361         } else if (vx[i] > maxx) {
4362             maxx = vx[i];
4363         }
4364     }
4365     if (maxx <0 || minx > dst->w){
4366       return -1;
4367     }
4368     if (maxy <0 || miny > dst->h){
4369       return -1;
4370     }
4371 
4372     /*
4373      * Draw, scanning y
4374      */
4375     result = 0;
4376     for (y = miny; (y <= maxy); y++) {
4377 	ints = 0;
4378 	for (i = 0; (i < n); i++) {
4379 	    if (!i) {
4380 		ind1 = n - 1;
4381 		ind2 = 0;
4382 	    } else {
4383 		ind1 = i - 1;
4384 		ind2 = i;
4385 	    }
4386 	    y1 = vy[ind1];
4387 	    y2 = vy[ind2];
4388 	    if (y1 < y2) {
4389 		x1 = vx[ind1];
4390 		x2 = vx[ind2];
4391 	    } else if (y1 > y2) {
4392 		y2 = vy[ind1];
4393 		y1 = vy[ind2];
4394 		x2 = vx[ind1];
4395 		x1 = vx[ind2];
4396 	    } else {
4397 		continue;
4398 	    }
4399 	    if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
4400 		gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
4401 	    }
4402 
4403 	}
4404 
4405 	qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt);
4406 
4407 	for (i = 0; (i < ints); i += 2) {
4408 	    xa = gfxPrimitivesPolyInts[i] + 1;
4409 	    xa = (xa >> 16) + ((xa & 32768) >> 15);
4410 	    xb = gfxPrimitivesPolyInts[i+1] - 1;
4411 	    xb = (xb >> 16) + ((xb & 32768) >> 15);
4412 	    result |= _texturedHLine(dst, xa, xb, y, texture,texture_dx,texture_dy);
4413 	}
4414     }
4415 
4416     return (result);
4417 }
4418 
4419 /* Standard version is calling multithreaded versions with NULL cache parameters. */
4420 
texturedPolygon(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy)4421 int texturedPolygon(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
4422 {
4423  /*
4424   * Draw
4425   */
4426    return (texturedPolygonMT(dst, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
4427 }
4428 
4429 /* Helper qsort callback for polygon drawing */
4430 
gfxPrimitivesCompareInt(const void * a,const void * b)4431 int gfxPrimitivesCompareInt(const void *a, const void *b)
4432 {
4433     return (*(const int *) a) - (*(const int *) b);
4434 }
4435 
4436 
4437 
4438 /* ---- Character */
4439 
4440 static SDL_Surface *gfxPrimitivesFont[256];
4441 static Uint32 gfxPrimitivesFontColor[256];
4442 
4443 /* Default is to use 8x8 internal font */
4444 static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
4445 
4446 static int charWidth = 8, charHeight = 8;
4447 static int charPitch = 1;
4448 static int charSize = 8;	/* character data size in bytes */
4449 
gfxPrimitivesSetFont(const void * fontdata,int cw,int ch)4450 void gfxPrimitivesSetFont(const void *fontdata, int cw, int ch)
4451 {
4452     int i;
4453 
4454     if (fontdata) {
4455         currentFontdata = (const unsigned char*) fontdata;
4456         charWidth = cw;
4457         charHeight = ch;
4458     } else {
4459         currentFontdata = gfxPrimitivesFontdata;
4460         charWidth = 8;
4461         charHeight = 8;
4462     }
4463 
4464     charPitch = (charWidth+7)/8;
4465     charSize = charPitch * charHeight;
4466 
4467     for (i = 0; i < 256; i++) {
4468 	if (gfxPrimitivesFont[i]) {
4469 	    SDL_FreeSurface(gfxPrimitivesFont[i]);
4470 	    gfxPrimitivesFont[i] = NULL;
4471 	}
4472     }
4473 }
4474 
characterColor(SDL_Surface * dst,Sint16 x,Sint16 y,char c,Uint32 color)4475 int characterColor(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint32 color)
4476 {
4477     Sint16 left, right, top, bottom;
4478     Sint16 x1, y1, x2, y2;
4479     SDL_Rect srect;
4480     SDL_Rect drect;
4481     int result;
4482     int ix, iy;
4483     const unsigned char *charpos;
4484     Uint8 *curpos;
4485     int forced_redraw;
4486     Uint8 patt, mask;
4487     Uint8 *linepos;
4488     int pitch;
4489 
4490     /*
4491      * Check visibility of clipping rectangle
4492      */
4493     if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4494      return(0);
4495     }
4496 
4497     /*
4498      * Get text and clipping boundary and
4499      * test if bounding box of character is visible
4500      */
4501 
4502     left = dst->clip_rect.x;
4503     x2 = x + charWidth;
4504     if (x2<left) {
4505      return(0);
4506     }
4507     right = dst->clip_rect.x + dst->clip_rect.w - 1;
4508     x1 = x;
4509     if (x1>right) {
4510      return(0);
4511     }
4512     top = dst->clip_rect.y;
4513     y2 = y + charHeight;
4514     if (y2<top) {
4515      return(0);
4516     }
4517     bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4518     y1 = y;
4519     if (y1>bottom) {
4520      return(0);
4521     }
4522 
4523     /*
4524      * Setup source rectangle
4525      */
4526     srect.x = 0;
4527     srect.y = 0;
4528     srect.w = charWidth;
4529     srect.h = charHeight;
4530 
4531     /*
4532      * Setup destination rectangle
4533      */
4534     drect.x = x;
4535     drect.y = y;
4536     drect.w = charWidth;
4537     drect.h = charHeight;
4538 
4539     /*
4540      * Create new charWidth x charHeight bitmap surface if not already present
4541      */
4542     if (gfxPrimitivesFont[(unsigned char) c] == NULL) {
4543 	gfxPrimitivesFont[(unsigned char) c] =
4544 	    SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA,
4545                                  charWidth, charHeight, 32,
4546 				 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
4547 	/*
4548 	 * Check pointer
4549 	 */
4550 	if (gfxPrimitivesFont[(unsigned char) c] == NULL) {
4551 	    return (-1);
4552 	}
4553 	/*
4554 	 * Definitely redraw
4555 	 */
4556 	forced_redraw = 1;
4557     } else {
4558 	forced_redraw = 0;
4559     }
4560 
4561     /*
4562      * Check if color has changed
4563      */
4564     if ((gfxPrimitivesFontColor[(unsigned char) c] != color) || (forced_redraw)) {
4565 	/*
4566 	 * Redraw character
4567 	 */
4568 	SDL_SetAlpha(gfxPrimitivesFont[(unsigned char) c], SDL_SRCALPHA, 255);
4569 	gfxPrimitivesFontColor[(unsigned char) c] = color;
4570 
4571 	/* Lock font-surface */
4572 	if (SDL_LockSurface(gfxPrimitivesFont[(unsigned char) c]) != 0)
4573 	    return (-1);
4574 
4575 	/*
4576 	 * Variable setup
4577 	 */
4578 	charpos = currentFontdata + (unsigned char) c * charSize;
4579 	linepos = (Uint8 *) gfxPrimitivesFont[(unsigned char) c]->pixels;
4580 	pitch = gfxPrimitivesFont[(unsigned char) c]->pitch;
4581 
4582 	/*
4583 	 * Drawing loop
4584 	 */
4585         patt = 0;
4586 	for (iy = 0; iy < charHeight; iy++) {
4587             mask = 0x00;
4588 	    curpos = linepos;
4589 	    for (ix = 0; ix < charWidth; ix++) {
4590 		if (!(mask >>= 1)) {
4591 		    patt = *charpos++;
4592 		    mask = 0x80;
4593 		}
4594 
4595 		if (patt & mask)
4596 		    *(Uint32 *)curpos = color;
4597 		else
4598 		    *(Uint32 *)curpos = 0;
4599 		curpos += 4;;
4600 	    }
4601 	    linepos += pitch;
4602 	}
4603 
4604 	/* Unlock font-surface */
4605 	SDL_UnlockSurface(gfxPrimitivesFont[(unsigned char) c]);
4606     }
4607 
4608     /*
4609      * Draw bitmap onto destination surface
4610      */
4611     if (dirtyDst == dst)
4612 	dirtyRects.push_back(drect);
4613     result = SDL_BlitSurface(gfxPrimitivesFont[(unsigned char) c], &srect, dst, &drect);
4614 
4615     return (result);
4616 }
4617 
characterRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,char c,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4618 int characterRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4619 {
4620     /*
4621      * Draw
4622      */
4623     return (characterColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4624 }
4625 
stringColor(SDL_Surface * dst,Sint16 x,Sint16 y,const char * c,Uint32 color)4626 int stringColor(SDL_Surface * dst, Sint16 x, Sint16 y, const char *c, Uint32 color)
4627 {
4628     int result = 0;
4629     int curx = x;
4630     const char *curchar = c;
4631 
4632     while (*curchar) {
4633 	result |= characterColor(dst, curx, y, *curchar, color);
4634 	curx += charWidth;
4635 	curchar++;
4636     }
4637 
4638     return (result);
4639 }
4640 
stringRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,const char * c,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4641 int stringRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, const char *c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4642 {
4643     /*
4644      * Draw
4645      */
4646     return (stringColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4647 }
4648 
4649 /* ---- Bezier curve */
4650 
4651 /*
4652  Calculate bezier interpolator of data array with ndata values at position 't'
4653 */
4654 
evaluateBezier(double * data,int ndata,double t)4655 double evaluateBezier (double *data, int ndata, double t)
4656 {
4657  double mu, result;
4658  int n,k,kn,nn,nkn;
4659  double blend,muk,munk;
4660 
4661  /* Sanity check bounds */
4662  if (t<0.0) {
4663   return(data[0]);
4664  }
4665  if (t>=(double)ndata) {
4666   return(data[ndata-1]);
4667  }
4668 
4669  /* Adjust t to the range 0.0 to 1.0 */
4670  mu=t/(double)ndata;
4671 
4672  /* Calculate interpolate */
4673  n=ndata-1;
4674  result=0.0;
4675  muk = 1;
4676  munk = pow(1-mu,(double)n);
4677  for (k=0;k<=n;k++) {
4678   nn = n;
4679   kn = k;
4680   nkn = n - k;
4681   blend = muk * munk;
4682   muk *= mu;
4683   munk /= (1-mu);
4684   while (nn >= 1) {
4685    blend *= nn;
4686    nn--;
4687    if (kn > 1) {
4688     blend /= (double)kn;
4689     kn--;
4690    }
4691    if (nkn > 1) {
4692     blend /= (double)nkn;
4693     nkn--;
4694    }
4695   }
4696   result += data[k] * blend;
4697  }
4698 
4699  return(result);
4700 }
4701 
bezierColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint32 color)4702 int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
4703 {
4704     int result;
4705     int i;
4706     double *x, *y, t, stepsize;
4707     Sint16 x1, y1, x2, y2;
4708 
4709     /*
4710      * Sanity check
4711      */
4712     if (n < 3) {
4713 	return (-1);
4714     }
4715     if (s < 2) {
4716         return (-1);
4717     }
4718 
4719     /*
4720      * Variable setup
4721      */
4722     stepsize=(double)1.0/(double)s;
4723 
4724     /* Transfer vertices into float arrays */
4725     if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
4726      return(-1);
4727     }
4728     if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
4729      free(x);
4730      return(-1);
4731     }
4732     for (i=0; i<n; i++) {
4733      x[i]=vx[i];
4734      y[i]=vy[i];
4735     }
4736     x[n]=vx[0];
4737     y[n]=vy[0];
4738 
4739     /*
4740      * Draw
4741      */
4742     result = 0;
4743     t=0.0;
4744     x1 = (Sint16) evaluateBezier(x,n+1,t);
4745     y1 = (Sint16) evaluateBezier(y,n+1,t);
4746     for (i = 0; i <= (n*s); i++) {
4747 	t += stepsize;
4748 	x2=(Sint16)evaluateBezier(x,n,t);
4749 	y2=(Sint16)evaluateBezier(y,n,t);
4750 	result |= lineColor(dst, x1, y1, x2, y2, color);
4751 	x1 = x2;
4752 	y1 = y2;
4753     }
4754 
4755     /* Clean up temporary array */
4756     free(x);
4757     free(y);
4758 
4759     return (result);
4760 }
4761 
bezierRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4762 int bezierRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4763 {
4764     /*
4765      * Draw
4766      */
4767     return (bezierColor(dst, vx, vy, n, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4768 }
4769