1 /*
2 
3 SDL_gfxPrimitives.c: graphics primitives for SDL surfaces
4 
5 Copyright (C) 2001-2012  Andreas Schiffler
6 
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any damages
9 arising from the use of this software.
10 
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it
13 freely, subject to the following restrictions:
14 
15 1. The origin of this software must not be misrepresented; you must not
16 claim that you wrote the original software. If you use this software
17 in a product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
19 
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
22 
23 3. This notice may not be removed or altered from any source
24 distribution.
25 
26 Andreas Schiffler -- aschiffler at ferzkopp dot net
27 
28 */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <string.h>
34 
35 #include "SDL_gfxPrimitives.h"
36 #include "SDL_rotozoom.h"
37 #include "SDL_gfxPrimitives_font.h"
38 #include "SDL_gfxBlitFunc.h"
39 
40 /* -===================- */
41 
42 #define DEFAULT_ALPHA_PIXEL_ROUTINE
43 #undef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
44 #define ALPHA_PIXEL_ADDITIVE_BLEND
45 
46 /* ---- Structures */
47 
48 /*!
49 \brief The structure passed to the internal Bresenham iterator.
50 */
51 typedef struct {
52 	Sint16 x, y;
53 	int dx, dy, s1, s2, swapdir, error;
54 	Uint32 count;
55 } SDL_gfxBresenhamIterator;
56 
57 /*!
58 \brief The structure passed to the internal Murphy iterator.
59 */
60 typedef struct {
61 	Uint32 color;
62 	SDL_Surface *dst;
63 	int u, v;		/* delta x , delta y */
64 	int ku, kt, kv, kd;	/* loop constants */
65 	int oct2;
66 	int quad4;
67 	Sint16 last1x, last1y, last2x, last2y, first1x, first1y, first2x, first2y, tempx, tempy;
68 } SDL_gfxMurphyIterator;
69 
70 /* ----- Defines for pixel clipping tests */
71 
72 #define clip_xmin(surface) surface->clip_rect.x
73 #define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1
74 #define clip_ymin(surface) surface->clip_rect.y
75 #define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1
76 
77 /*!
78 \brief Internal pixel drawing - fast, no blending, no locking, clipping.
79 
80 \param dst The surface to draw on.
81 \param x The horizontal coordinate of the pixel.
82 \param y The vertical position of the pixel.
83 \param color The color value of the pixel to draw.
84 
85 \returns Returns 0 on success, -1 on failure.
86 */
fastPixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)87 int fastPixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
88 {
89 	int bpp;
90 	Uint8 *p;
91 
92 	/*
93 	* Honor clipping setup at pixel level
94 	*/
95 	if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) {
96 
97 		/*
98 		* Get destination format
99 		*/
100 		bpp = dst->format->BytesPerPixel;
101 		p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
102 		switch (bpp) {
103 		case 1:
104 			*p = color;
105 			break;
106 		case 2:
107 			*(Uint16 *) p = color;
108 			break;
109 		case 3:
110 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
111 				p[0] = (color >> 16) & 0xff;
112 				p[1] = (color >> 8) & 0xff;
113 				p[2] = color & 0xff;
114 			} else {
115 				p[0] = color & 0xff;
116 				p[1] = (color >> 8) & 0xff;
117 				p[2] = (color >> 16) & 0xff;
118 			}
119 			break;
120 		case 4:
121 			*(Uint32 *) p = color;
122 			break;
123 		}			/* switch */
124 
125 
126 	}
127 
128 	return (0);
129 }
130 
131 /*!
132 \brief Internal pixel drawing - fast, no blending, no locking, no clipping.
133 
134 Function is faster but dangerous since no clipping check is done.
135 Code needs to make sure we stay in surface bounds before calling.
136 
137 \param dst The surface to draw on.
138 \param x The horizontal coordinate of the pixel.
139 \param y The vertical position of the pixel.
140 \param color The color value of the pixel to draw.
141 
142 \returns Returns 0 on success, -1 on failure.
143 */
fastPixelColorNolockNoclip(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)144 int fastPixelColorNolockNoclip(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
145 {
146 	int bpp;
147 	Uint8 *p;
148 
149 	/*
150 	* Get destination format
151 	*/
152 	bpp = dst->format->BytesPerPixel;
153 	p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
154 	switch (bpp) {
155 	case 1:
156 		*p = color;
157 		break;
158 	case 2:
159 		*(Uint16 *) p = color;
160 		break;
161 	case 3:
162 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
163 			p[0] = (color >> 16) & 0xff;
164 			p[1] = (color >> 8) & 0xff;
165 			p[2] = color & 0xff;
166 		} else {
167 			p[0] = color & 0xff;
168 			p[1] = (color >> 8) & 0xff;
169 			p[2] = (color >> 16) & 0xff;
170 		}
171 		break;
172 	case 4:
173 		*(Uint32 *) p = color;
174 		break;
175 	}				/* switch */
176 
177 	return (0);
178 }
179 
180 /*!
181 \brief Internal pixel drawing - fast, no blending, locking, clipping.
182 
183 \param dst The surface to draw on.
184 \param x The horizontal coordinate of the pixel.
185 \param y The vertical position of the pixel.
186 \param color The color value of the pixel to draw.
187 
188 \returns Returns 0 on success, -1 on failure.
189 */
fastPixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)190 int fastPixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
191 {
192 	int result;
193 
194 	/*
195 	* Lock the surface
196 	*/
197 	if (SDL_MUSTLOCK(dst)) {
198 		if (SDL_LockSurface(dst) < 0) {
199 			return (-1);
200 		}
201 	}
202 
203 	result = fastPixelColorNolock(dst, x, y, color);
204 
205 	/*
206 	* Unlock surface
207 	*/
208 	if (SDL_MUSTLOCK(dst)) {
209 		SDL_UnlockSurface(dst);
210 	}
211 
212 	return (result);
213 }
214 
215 /*!
216 \brief Internal pixel drawing - fast, no blending, locking, RGB input.
217 
218 \param dst The surface to draw on.
219 \param x The horizontal coordinate of the pixel.
220 \param y The vertical position of the pixel.
221 \param r The red value of the pixel to draw.
222 \param g The green value of the pixel to draw.
223 \param b The blue value of the pixel to draw.
224 \param a The alpha value of the pixel to draw.
225 
226 \returns Returns 0 on success, -1 on failure.
227 */
fastPixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)228 int fastPixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
229 {
230 	Uint32 color;
231 
232 	/*
233 	* Setup color
234 	*/
235 	color = SDL_MapRGBA(dst->format, r, g, b, a);
236 
237 	/*
238 	* Draw
239 	*/
240 	return (fastPixelColor(dst, x, y, color));
241 }
242 
243 /*!
244 \brief Internal pixel drawing - fast, no blending, no locking RGB input.
245 
246 \param dst The surface to draw on.
247 \param x The horizontal coordinate of the pixel.
248 \param y The vertical position of the pixel.
249 \param r The red value of the pixel to draw.
250 \param g The green value of the pixel to draw.
251 \param b The blue value of the pixel to draw.
252 \param a The alpha value of the pixel to draw.
253 
254 \returns Returns 0 on success, -1 on failure.
255 */
fastPixelRGBANolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)256 int fastPixelRGBANolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
257 {
258 	Uint32 color;
259 
260 	/*
261 	* Setup color
262 	*/
263 	color = SDL_MapRGBA(dst->format, r, g, b, a);
264 
265 	/*
266 	* Draw
267 	*/
268 	return (fastPixelColorNolock(dst, x, y, color));
269 }
270 
271 /*!
272 \brief Internal pixel drawing function with alpha blending where input color in in destination format.
273 
274 Contains two alternative 32 bit alpha blending routines which can be enabled at the source
275 level with the defines DEFAULT_ALPHA_PIXEL_ROUTINE or EXPERIMENTAL_ALPHA_PIXEL_ROUTINE.
276 Only the bits up to the surface depth are significant in the color value.
277 
278 \param dst The surface to draw on.
279 \param x The horizontal coordinate of the pixel.
280 \param y The vertical position of the pixel.
281 \param color The color value of the pixel to draw.
282 \param alpha The blend factor to apply while drawing.
283 
284 \returns Returns 0 on success, -1 on failure.
285 */
_putPixelAlpha(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint8 alpha)286 int _putPixelAlpha(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
287 {
288 	SDL_PixelFormat *format;
289 	Uint32 Rmask, Gmask, Bmask, Amask;
290 	Uint32 Rshift, Gshift, Bshift, Ashift;
291 	Uint32 sR, sG, sB;
292 	Uint32 dR, dG, dB, dA;
293 
294 	if (dst == NULL)
295 	{
296 		return (-1);
297 	}
298 
299 	if (x >= clip_xmin(dst) && x <= clip_xmax(dst) &&
300 		y >= clip_ymin(dst) && y <= clip_ymax(dst))
301 	{
302 
303 		format = dst->format;
304 
305 		switch (format->BytesPerPixel) {
306 		case 1:
307 			{		/* Assuming 8-bpp */
308 				Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x;
309 				if (alpha == 255) {
310 					*pixel = color;
311 				} else {
312 					Uint8 R, G, B;
313 					SDL_Palette *palette = format->palette;
314 					SDL_Color *colors = palette->colors;
315 					SDL_Color dColor = colors[*pixel];
316 					SDL_Color sColor = colors[color];
317 					dR = dColor.r;
318 					dG = dColor.g;
319 					dB = dColor.b;
320 					sR = sColor.r;
321 					sG = sColor.g;
322 					sB = sColor.b;
323 
324 					R = dR + ((sR - dR) * alpha >> 8);
325 					G = dG + ((sG - dG) * alpha >> 8);
326 					B = dB + ((sB - dB) * alpha >> 8);
327 
328 					*pixel = SDL_MapRGB(format, R, G, B);
329 				}
330 			}
331 			break;
332 
333 		case 2:
334 			{		/* Probably 15-bpp or 16-bpp */
335 				Uint16 *pixel = (Uint16 *) dst->pixels + y * dst->pitch / 2 + x;
336 				if (alpha == 255) {
337 					*pixel = color;
338 				} else {
339 					Uint16 R, G, B, A;
340 					Uint16 dc = *pixel;
341 
342 					Rmask = format->Rmask;
343 					Gmask = format->Gmask;
344 					Bmask = format->Bmask;
345 					Amask = format->Amask;
346 
347 					dR = (dc & Rmask);
348 					dG = (dc & Gmask);
349 					dB = (dc & Bmask);
350 
351 					R = (dR + (((color & Rmask) - dR) * alpha >> 8)) & Rmask;
352 					G = (dG + (((color & Gmask) - dG) * alpha >> 8)) & Gmask;
353 					B = (dB + (((color & Bmask) - dB) * alpha >> 8)) & Bmask;
354 					*pixel = R | G | B;
355 					if (Amask!=0) {
356 						dA = (dc & Amask);
357 						A = (dA + (((color & Amask) - dA) * alpha >> 8)) & Amask;
358 						*pixel |= A;
359 					}
360 				}
361 			}
362 			break;
363 
364 		case 3:
365 			{		/* Slow 24-bpp mode, usually not used */
366 				Uint8 R, G, B;
367 				Uint8 Rshift8, Gshift8, Bshift8;
368 				Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x * 3;
369 
370 				Rshift = format->Rshift;
371 				Gshift = format->Gshift;
372 				Bshift = format->Bshift;
373 
374 				Rshift8 = Rshift >> 3;
375 				Gshift8 = Gshift >> 3;
376 				Bshift8 = Bshift >> 3;
377 
378 				sR = (color >> Rshift) & 0xFF;
379 				sG = (color >> Gshift) & 0xFF;
380 				sB = (color >> Bshift) & 0xFF;
381 
382 				if (alpha == 255) {
383 					*(pixel + Rshift8) = sR;
384 					*(pixel + Gshift8) = sG;
385 					*(pixel + Bshift8) = sB;
386 				} else {
387 					dR = *((pixel) + Rshift8);
388 					dG = *((pixel) + Gshift8);
389 					dB = *((pixel) + Bshift8);
390 
391 					R = dR + ((sR - dR) * alpha >> 8);
392 					G = dG + ((sG - dG) * alpha >> 8);
393 					B = dB + ((sB - dB) * alpha >> 8);
394 
395 					*((pixel) + Rshift8) = R;
396 					*((pixel) + Gshift8) = G;
397 					*((pixel) + Bshift8) = B;
398 				}
399 			}
400 			break;
401 
402 #ifdef DEFAULT_ALPHA_PIXEL_ROUTINE
403 
404 		case 4:
405 			{		/* Probably :-) 32-bpp */
406 				Uint32 R, G, B, A;
407 				Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x;
408 				if (alpha == 255) {
409 					*pixel = color;
410 				} else {
411 					Uint32 dc = *pixel;
412 
413 					Rmask = format->Rmask;
414 					Gmask = format->Gmask;
415 					Bmask = format->Bmask;
416 					Amask = format->Amask;
417 
418 					Rshift = format->Rshift;
419 					Gshift = format->Gshift;
420 					Bshift = format->Bshift;
421 					Ashift = format->Ashift;
422 
423 					dR = (dc & Rmask) >> Rshift;
424 					dG = (dc & Gmask) >> Gshift;
425 					dB = (dc & Bmask) >> Bshift;
426 
427 
428 					R = ((dR + ((((color & Rmask) >> Rshift) - dR) * alpha >> 8)) << Rshift) & Rmask;
429 					G = ((dG + ((((color & Gmask) >> Gshift) - dG) * alpha >> 8)) << Gshift) & Gmask;
430 					B = ((dB + ((((color & Bmask) >> Bshift) - dB) * alpha >> 8)) << Bshift) & Bmask;
431 					*pixel = R | G | B;
432 					if (Amask!=0) {
433 						dA = (dc & Amask) >> Ashift;
434 
435 #ifdef ALPHA_PIXEL_ADDITIVE_BLEND
436 						A = (dA | GFX_ALPHA_ADJUST_ARRAY[alpha & 255]) << Ashift; // make destination less transparent...
437 #else
438 						A = ((dA + ((((color & Amask) >> Ashift) - dA) * alpha >> 8)) << Ashift) & Amask;
439 #endif
440 						*pixel |= A;
441 					}
442 				}
443 			}
444 			break;
445 #endif
446 
447 #ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
448 
449 		case 4:{		/* Probably :-) 32-bpp */
450 			if (alpha == 255) {
451 				*((Uint32 *) dst->pixels + y * dst->pitch / 4 + x) = color;
452 			} else {
453 				Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x;
454 				Uint32 dR, dG, dB, dA;
455 				Uint32 dc = *pixel;
456 
457 				Uint32 surfaceAlpha, preMultR, preMultG, preMultB;
458 				Uint32 aTmp;
459 
460 				Rmask = format->Rmask;
461 				Gmask = format->Gmask;
462 				Bmask = format->Bmask;
463 				Amask = format->Amask;
464 
465 				dR = (color & Rmask);
466 				dG = (color & Gmask);
467 				dB = (color & Bmask);
468 				dA = (color & Amask);
469 
470 				Rshift = format->Rshift;
471 				Gshift = format->Gshift;
472 				Bshift = format->Bshift;
473 				Ashift = format->Ashift;
474 
475 				preMultR = (alpha * (dR >> Rshift));
476 				preMultG = (alpha * (dG >> Gshift));
477 				preMultB = (alpha * (dB >> Bshift));
478 
479 				surfaceAlpha = ((dc & Amask) >> Ashift);
480 				aTmp = (255 - alpha);
481 				if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) {
482 					aTmp *= surfaceAlpha;
483 					R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask;
484 					G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask;
485 					B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask;
486 				}
487 				*pixel = R | G | B | (A << Ashift & Amask);
488 
489 			}
490 			   }
491 			   break;
492 #endif
493 		}
494 	}
495 
496 	return (0);
497 }
498 
499 /*!
500 \brief Pixel draw with blending enabled if a<255.
501 
502 \param dst The surface to draw on.
503 \param x X (horizontal) coordinate of the pixel.
504 \param y Y (vertical) coordinate of the pixel.
505 \param color The color value of the pixel to draw (0xRRGGBBAA).
506 
507 \returns Returns 0 on success, -1 on failure.
508 */
pixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)509 int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
510 {
511 	Uint8 alpha;
512 	Uint32 mcolor;
513 	int result = 0;
514 
515 	/*
516 	* Lock the surface
517 	*/
518 	if (SDL_MUSTLOCK(dst)) {
519 		if (SDL_LockSurface(dst) < 0) {
520 			return (-1);
521 		}
522 	}
523 
524 	/*
525 	* Setup color
526 	*/
527 	alpha = color & 0x000000ff;
528 	mcolor =
529 		SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
530 		(color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
531 
532 	/*
533 	* Draw
534 	*/
535 	result = _putPixelAlpha(dst, x, y, mcolor, alpha);
536 
537 	/*
538 	* Unlock the surface
539 	*/
540 	if (SDL_MUSTLOCK(dst)) {
541 		SDL_UnlockSurface(dst);
542 	}
543 
544 	return (result);
545 }
546 
547 /*!
548 \brief Pixel draw with blending enabled if a<255 - no surface locking.
549 
550 \param dst The surface to draw on.
551 \param x X (horizontal) coordinate of the pixel.
552 \param y Y (vertical) coordinate of the pixel.
553 \param color The color value of the pixel to draw (0xRRGGBBAA).
554 
555 \returns Returns 0 on success, -1 on failure.
556 */
pixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)557 int pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
558 {
559 	Uint8 alpha;
560 	Uint32 mcolor;
561 	int result = 0;
562 
563 	/*
564 	* Setup color
565 	*/
566 	alpha = color & 0x000000ff;
567 	mcolor =
568 		SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
569 		(color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
570 
571 	/*
572 	* Draw
573 	*/
574 	result = _putPixelAlpha(dst, x, y, mcolor, alpha);
575 
576 	return (result);
577 }
578 
579 
580 /*!
581 \brief Internal function to draw filled rectangle with alpha blending.
582 
583 Assumes color is in destination format.
584 
585 \param dst The surface to draw on.
586 \param x1 X coordinate of the first corner (upper left) of the rectangle.
587 \param y1 Y coordinate of the first corner (upper left) of the rectangle.
588 \param x2 X coordinate of the second corner (lower right) of the rectangle.
589 \param y2 Y coordinate of the second corner (lower right) of the rectangle.
590 \param color The color value of the rectangle to draw (0xRRGGBBAA).
591 \param alpha Alpha blending amount for pixels.
592 
593 \returns Returns 0 on success, -1 on failure.
594 */
_filledRectAlpha(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,Uint8 alpha)595 int _filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
596 {
597 	SDL_PixelFormat *format;
598 	Uint32 Rmask, Gmask, Bmask, Amask;
599 	Uint32 Rshift, Gshift, Bshift, Ashift;
600 	Uint32 sR, sG, sB, sA;
601 	Uint32 dR, dG, dB, dA;
602 	Sint16 x, y;
603 
604 	if (dst == NULL) {
605 		return (-1);
606 	}
607 
608 	format = dst->format;
609 	switch (format->BytesPerPixel) {
610 	case 1:
611 		{			/* Assuming 8-bpp */
612 			Uint8 *row, *pixel;
613 			Uint8 R, G, B;
614 			SDL_Color *colors = format->palette->colors;
615 			SDL_Color dColor;
616 			SDL_Color sColor = colors[color];
617 			sR = sColor.r;
618 			sG = sColor.g;
619 			sB = sColor.b;
620 
621 			for (y = y1; y <= y2; y++) {
622 				row = (Uint8 *) dst->pixels + y * dst->pitch;
623 				for (x = x1; x <= x2; x++) {
624 					if (alpha == 255) {
625 						*(row + x) = color;
626 					} else {
627 						pixel = row + x;
628 
629 						dColor = colors[*pixel];
630 						dR = dColor.r;
631 						dG = dColor.g;
632 						dB = dColor.b;
633 
634 						R = dR + ((sR - dR) * alpha >> 8);
635 						G = dG + ((sG - dG) * alpha >> 8);
636 						B = dB + ((sB - dB) * alpha >> 8);
637 
638 						*pixel = SDL_MapRGB(format, R, G, B);
639 					}
640 				}
641 			}
642 		}
643 		break;
644 
645 	case 2:
646 		{			/* Probably 15-bpp or 16-bpp */
647 			Uint16 *row, *pixel;
648 			Uint16 R, G, B, A;
649 			Uint16 dc;
650 			Rmask = format->Rmask;
651 			Gmask = format->Gmask;
652 			Bmask = format->Bmask;
653 			Amask = format->Amask;
654 
655 			sR = (color & Rmask);
656 			sG = (color & Gmask);
657 			sB = (color & Bmask);
658 			sA = (color & Amask);
659 
660 			for (y = y1; y <= y2; y++) {
661 				row = (Uint16 *) dst->pixels + y * dst->pitch / 2;
662 				for (x = x1; x <= x2; x++) {
663 					if (alpha == 255) {
664 						*(row + x) = color;
665 					} else {
666 						pixel = row + x;
667 						dc = *pixel;
668 
669 						dR = (dc & Rmask);
670 						dG = (dc & Gmask);
671 						dB = (dc & Bmask);
672 
673 						R = (dR + ((sR - dR) * alpha >> 8)) & Rmask;
674 						G = (dG + ((sG - dG) * alpha >> 8)) & Gmask;
675 						B = (dB + ((sB - dB) * alpha >> 8)) & Bmask;
676 						*pixel = R | G | B;
677 						if (Amask!=0) {
678 							dA = (dc & Amask);
679 							A = (dA + ((sA - dA) * alpha >> 8)) & Amask;
680 							*pixel |= A;
681 						}
682 					}
683 				}
684 			}
685 		}
686 		break;
687 
688 	case 3:
689 		{			/* Slow 24-bpp mode, usually not used */
690 			Uint8 *row, *pixel;
691 			Uint8 R, G, B;
692 			Uint8 Rshift8, Gshift8, Bshift8;
693 
694 			Rshift = format->Rshift;
695 			Gshift = format->Gshift;
696 			Bshift = format->Bshift;
697 
698 			Rshift8 = Rshift >> 3;
699 			Gshift8 = Gshift >> 3;
700 			Bshift8 = Bshift >> 3;
701 
702 			sR = (color >> Rshift) & 0xff;
703 			sG = (color >> Gshift) & 0xff;
704 			sB = (color >> Bshift) & 0xff;
705 
706 			for (y = y1; y <= y2; y++) {
707 				row = (Uint8 *) dst->pixels + y * dst->pitch;
708 				for (x = x1; x <= x2; x++) {
709 					pixel = row + x * 3;
710 
711 					if (alpha == 255) {
712 						*(pixel + Rshift8) = sR;
713 						*(pixel + Gshift8) = sG;
714 						*(pixel + Bshift8) = sB;
715 					} else {
716 						dR = *((pixel) + Rshift8);
717 						dG = *((pixel) + Gshift8);
718 						dB = *((pixel) + Bshift8);
719 
720 						R = dR + ((sR - dR) * alpha >> 8);
721 						G = dG + ((sG - dG) * alpha >> 8);
722 						B = dB + ((sB - dB) * alpha >> 8);
723 
724 						*((pixel) + Rshift8) = R;
725 						*((pixel) + Gshift8) = G;
726 						*((pixel) + Bshift8) = B;
727 					}
728 				}
729 			}
730 		}
731 		break;
732 
733 #ifdef DEFAULT_ALPHA_PIXEL_ROUTINE
734 	case 4:
735 		{			/* Probably :-) 32-bpp */
736 			Uint32 *row, *pixel;
737 			Uint32 R, G, B, A;
738 			Uint32 dc;
739 			Rmask = format->Rmask;
740 			Gmask = format->Gmask;
741 			Bmask = format->Bmask;
742 			Amask = format->Amask;
743 
744 			Rshift = format->Rshift;
745 			Gshift = format->Gshift;
746 			Bshift = format->Bshift;
747 			Ashift = format->Ashift;
748 
749 			sR = (color & Rmask) >> Rshift;
750 			sG = (color & Gmask) >> Gshift;
751 			sB = (color & Bmask) >> Bshift;
752 			sA = (color & Amask) >> Ashift;
753 
754 			for (y = y1; y <= y2; y++) {
755 				row = (Uint32 *) dst->pixels + y * dst->pitch / 4;
756 				for (x = x1; x <= x2; x++) {
757 					if (alpha == 255) {
758 						*(row + x) = color;
759 					} else {
760 						pixel = row + x;
761 						dc = *pixel;
762 
763 						dR = (dc & Rmask) >> Rshift;
764 						dG = (dc & Gmask) >> Gshift;
765 						dB = (dc & Bmask) >> Bshift;
766 
767 						R = ((dR + ((sR - dR) * alpha >> 8)) << Rshift) & Rmask;
768 						G = ((dG + ((sG - dG) * alpha >> 8)) << Gshift) & Gmask;
769 						B = ((dB + ((sB - dB) * alpha >> 8)) << Bshift) & Bmask;
770 						*pixel = R | G | B;
771 						if (Amask!=0) {
772 							dA = (dc & Amask) >> Ashift;
773 #ifdef ALPHA_PIXEL_ADDITIVE_BLEND
774 							A = (dA | GFX_ALPHA_ADJUST_ARRAY[sA & 255]) << Ashift; // make destination less transparent...
775 #else
776 							A = ((dA + ((sA - dA) * alpha >> 8)) << Ashift) & Amask;
777 #endif
778 							*pixel |= A;
779 						}
780 					}
781 				}
782 			}
783 		}
784 		break;
785 #endif
786 
787 #ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
788 	case 4:{			/* Probably :-) 32-bpp */
789 		Uint32 *row, *pixel;
790 		Uint32 dR, dG, dB, dA;
791 		Uint32 dc;
792 		Uint32 surfaceAlpha, preMultR, preMultG, preMultB;
793 		Uint32 aTmp;
794 
795 		Rmask = format->Rmask;
796 		Gmask = format->Gmask;
797 		Bmask = format->Bmask;
798 		Amask = format->Amask;
799 
800 		dR = (color & Rmask);
801 		dG = (color & Gmask);
802 		dB = (color & Bmask);
803 		dA = (color & Amask);
804 
805 		Rshift = format->Rshift;
806 		Gshift = format->Gshift;
807 		Bshift = format->Bshift;
808 		Ashift = format->Ashift;
809 
810 		preMultR = (alpha * (dR >> Rshift));
811 		preMultG = (alpha * (dG >> Gshift));
812 		preMultB = (alpha * (dB >> Bshift));
813 
814 		for (y = y1; y <= y2; y++) {
815 			row = (Uint32 *) dst->pixels + y * dst->pitch / 4;
816 			for (x = x1; x <= x2; x++) {
817 				if (alpha == 255) {
818 					*(row + x) = color;
819 				} else {
820 					pixel = row + x;
821 					dc = *pixel;
822 
823 					surfaceAlpha = ((dc & Amask) >> Ashift);
824 					aTmp = (255 - alpha);
825 					if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) {
826 						aTmp *= surfaceAlpha;
827 						R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask;
828 						G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask;
829 						B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask;
830 					}
831 					*pixel = R | G | B | (A << Ashift & Amask);
832 				}
833 			}
834 		}
835 		   }
836 		   break;
837 #endif
838 
839 	}
840 
841 	return (0);
842 }
843 
844 /*!
845 \brief Draw filled rectangle of RGBA color with alpha blending.
846 
847 \param dst The surface to draw on.
848 \param x1 X coordinate of the first corner (upper left) of the rectangle.
849 \param y1 Y coordinate of the first corner (upper left) of the rectangle.
850 \param x2 X coordinate of the second corner (lower right) of the rectangle.
851 \param y2 Y coordinate of the second corner (lower right) of the rectangle.
852 \param color The color value of the rectangle to draw (0xRRGGBBAA).
853 
854 \returns Returns 0 on success, -1 on failure.
855 */
filledRectAlpha(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)856 int filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
857 {
858 	Uint8 alpha;
859 	Uint32 mcolor;
860 	int result = 0;
861 
862 	/*
863 	* Lock the surface
864 	*/
865 	if (SDL_MUSTLOCK(dst)) {
866 		if (SDL_LockSurface(dst) < 0) {
867 			return (-1);
868 		}
869 	}
870 
871 	/*
872 	* Setup color
873 	*/
874 	alpha = color & 0x000000ff;
875 	mcolor =
876 		SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
877 		(color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
878 
879 	/*
880 	* Draw
881 	*/
882 	result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha);
883 
884 	/*
885 	* Unlock the surface
886 	*/
887 	if (SDL_MUSTLOCK(dst)) {
888 		SDL_UnlockSurface(dst);
889 	}
890 
891 	return (result);
892 }
893 
894 /*!
895 \brief Internal function to draw horizontal line of RGBA color with alpha blending.
896 
897 \param dst The surface to draw on.
898 \param x1 X coordinate of the first point (i.e. left) of the line.
899 \param x2 X coordinate of the second point (i.e. right) of the line.
900 \param y Y coordinate of the points of the line.
901 \param color The color value of the line to draw (0xRRGGBBAA).
902 
903 \returns Returns 0 on success, -1 on failure.
904 */
_HLineAlpha(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)905 int _HLineAlpha(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
906 {
907 	return (filledRectAlpha(dst, x1, y, x2, y, color));
908 }
909 
910 /*!
911 \brief Internal function to draw vertical line of RGBA color with alpha blending.
912 
913 \param dst The surface to draw on.
914 \param x X coordinate of the points of the line.
915 \param y1 Y coordinate of the first point (top) of the line.
916 \param y2 Y coordinate of the second point (bottom) of the line.
917 \param color The color value of the line to draw (0xRRGGBBAA).
918 
919 \returns Returns 0 on success, -1 on failure.
920 */
_VLineAlpha(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)921 int _VLineAlpha(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
922 {
923 	return (filledRectAlpha(dst, x, y1, x, y2, color));
924 }
925 
926 /*!
927 \brief Pixel draw with blending enabled and using alpha weight on color.
928 
929 \param dst The surface to draw on.
930 \param x The horizontal coordinate of the pixel.
931 \param y The vertical position of the pixel.
932 \param color The color value of the pixel to draw (0xRRGGBBAA).
933 \param weight The weight multiplied into the alpha value of the pixel.
934 
935 \returns Returns 0 on success, -1 on failure.
936 */
pixelColorWeight(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)937 int pixelColorWeight(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
938 {
939 	Uint32 a;
940 
941 	/*
942 	* Get alpha
943 	*/
944 	a = (color & (Uint32) 0x000000ff);
945 
946 	/*
947 	* Modify Alpha by weight
948 	*/
949 	a = ((a * weight) >> 8);
950 
951 	return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
952 }
953 
954 /*!
955 \brief Pixel draw with blending enabled and using alpha weight on color - no locking.
956 
957 \param dst The surface to draw on.
958 \param x The horizontal coordinate of the pixel.
959 \param y The vertical position of the pixel.
960 \param color The color value of the pixel to draw (0xRRGGBBAA).
961 \param weight The weight multiplied into the alpha value of the pixel.
962 
963 \returns Returns 0 on success, -1 on failure.
964 */
pixelColorWeightNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)965 int pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
966 {
967 	Uint32 a;
968 
969 	/*
970 	* Get alpha
971 	*/
972 	a = (color & (Uint32) 0x000000ff);
973 
974 	/*
975 	* Modify Alpha by weight
976 	*/
977 	a = ((a * weight) >> 8);
978 
979 	return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
980 }
981 
982 /*!
983 \brief Pixel draw with blending enabled if a<255.
984 
985 \param dst The surface to draw on.
986 \param x X (horizontal) coordinate of the pixel.
987 \param y Y (vertical) coordinate of the pixel.
988 \param r The red color value of the pixel to draw.
989 \param g The green color value of the pixel to draw.
990 \param b The blue color value of the pixel to draw.
991 \param a The alpha value of the pixel to draw.
992 
993 \returns Returns 0 on success, -1 on failure.
994 */
pixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)995 int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
996 {
997 	Uint32 color;
998 
999 	/*
1000 	* Check Alpha
1001 	*/
1002 	if (a == 255) {
1003 		/*
1004 		* No alpha blending required
1005 		*/
1006 		/*
1007 		* Setup color
1008 		*/
1009 		color = SDL_MapRGBA(dst->format, r, g, b, a);
1010 		/*
1011 		* Draw
1012 		*/
1013 		return (fastPixelColor(dst, x, y, color));
1014 	} else {
1015 		/*
1016 		* Alpha blending required
1017 		*/
1018 		/*
1019 		* Draw
1020 		*/
1021 		return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1022 	}
1023 }
1024 
1025 
1026 /*!
1027 \brief Draw horizontal line without blending;
1028 
1029 Just stores the color value (including the alpha component) without blending.
1030 Only the same number of bits of the destination surface are transfered
1031 from the input color value.
1032 
1033 \param dst The surface to draw on.
1034 \param x1 X coordinate of the first point (i.e. left) of the line.
1035 \param x2 X coordinate of the second point (i.e. right) of the line.
1036 \param y Y coordinate of the points of the line.
1037 \param color The color value of the line to draw.
1038 
1039 \returns Returns 0 on success, -1 on failure.
1040 */
hlineColorStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)1041 int hlineColorStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
1042 {
1043 	Sint16 left, right, top, bottom;
1044 	Uint8 *pixel, *pixellast;
1045 	int dx;
1046 	int pixx, pixy;
1047 	Sint16 w;
1048 	Sint16 xtmp;
1049 	int result = -1;
1050 
1051 	/*
1052 	* Check visibility of clipping rectangle
1053 	*/
1054 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1055 		return(0);
1056 	}
1057 
1058 	/*
1059 	* Swap x1, x2 if required to ensure x1<=x2
1060 	*/
1061 	if (x1 > x2) {
1062 		xtmp = x1;
1063 		x1 = x2;
1064 		x2 = xtmp;
1065 	}
1066 
1067 	/*
1068 	* Get clipping boundary and
1069 	* check visibility of hline
1070 	*/
1071 	left = dst->clip_rect.x;
1072 	if (x2<left) {
1073 		return(0);
1074 	}
1075 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
1076 	if (x1>right) {
1077 		return(0);
1078 	}
1079 	top = dst->clip_rect.y;
1080 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1081 	if ((y<top) || (y>bottom)) {
1082 		return (0);
1083 	}
1084 
1085 	/*
1086 	* Clip x
1087 	*/
1088 	if (x1 < left) {
1089 		x1 = left;
1090 	}
1091 	if (x2 > right) {
1092 		x2 = right;
1093 	}
1094 
1095 	/*
1096 	* Calculate width
1097 	*/
1098 	w = x2 - x1;
1099 
1100 	/*
1101 	* Lock the surface
1102 	*/
1103 	if (SDL_MUSTLOCK(dst)) {
1104 		if (SDL_LockSurface(dst) < 0) {
1105 			return (-1);
1106 		}
1107 	}
1108 
1109 	/*
1110 	* More variable setup
1111 	*/
1112 	dx = w;
1113 	pixx = dst->format->BytesPerPixel;
1114 	pixy = dst->pitch;
1115 	pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
1116 
1117 	/*
1118 	* Draw
1119 	*/
1120 	switch (dst->format->BytesPerPixel) {
1121 	case 1:
1122 		memset(pixel, color, dx+1);
1123 		break;
1124 	case 2:
1125 		pixellast = pixel + dx + dx;
1126 		for (; pixel <= pixellast; pixel += pixx) {
1127 			*(Uint16 *) pixel = color;
1128 		}
1129 		break;
1130 	case 3:
1131 		pixellast = pixel + dx + dx + dx;
1132 		for (; pixel <= pixellast; pixel += pixx) {
1133 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1134 				pixel[0] = (color >> 16) & 0xff;
1135 				pixel[1] = (color >> 8) & 0xff;
1136 				pixel[2] = color & 0xff;
1137 			} else {
1138 				pixel[0] = color & 0xff;
1139 				pixel[1] = (color >> 8) & 0xff;
1140 				pixel[2] = (color >> 16) & 0xff;
1141 			}
1142 		}
1143 		break;
1144 	default:		/* case 4 */
1145 		dx = dx + dx;
1146 		pixellast = pixel + dx + dx;
1147 		for (; pixel <= pixellast; pixel += pixx) {
1148 			*(Uint32 *) pixel = color;
1149 		}
1150 		break;
1151 	}
1152 
1153 	/*
1154 	* Unlock surface
1155 	*/
1156 	if (SDL_MUSTLOCK(dst)) {
1157 		SDL_UnlockSurface(dst);
1158 	}
1159 
1160 	/*
1161 	* Set result code
1162 	*/
1163 	result = 0;
1164 
1165 	return (result);
1166 }
1167 
1168 /*!
1169 \brief Draw horizontal line without blending
1170 
1171 Just stores the color value (including the alpha component) without blending.
1172 Function should only be used for 32 bit target surfaces.
1173 
1174 \param dst The surface to draw on.
1175 \param x1 X coordinate of the first point (i.e. left) of the line.
1176 \param x2 X coordinate of the second point (i.e. right) of the line.
1177 \param y Y coordinate of the points of the line.
1178 \param r The red value of the line to draw.
1179 \param g The green value of the line to draw.
1180 \param b The blue value of the line to draw.
1181 \param a The alpha value of the line to draw.
1182 
1183 \returns Returns 0 on success, -1 on failure.
1184 */
hlineRGBAStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1185 int hlineRGBAStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1186 {
1187 	/*
1188 	* Draw
1189 	*/
1190 	return (hlineColorStore(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1191 }
1192 
1193 /*!
1194 \brief Draw horizontal line with blending.
1195 
1196 \param dst The surface to draw on.
1197 \param x1 X coordinate of the first point (i.e. left) of the line.
1198 \param x2 X coordinate of the second point (i.e. right) of the line.
1199 \param y Y coordinate of the points of the line.
1200 \param color The color value of the line to draw (0xRRGGBBAA).
1201 
1202 \returns Returns 0 on success, -1 on failure.
1203 */
hlineColor(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)1204 int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
1205 {
1206 	Sint16 left, right, top, bottom;
1207 	Uint8 *pixel, *pixellast;
1208 	int dx;
1209 	int pixx, pixy;
1210 	Sint16 xtmp;
1211 	int result = -1;
1212 	Uint8 *colorptr;
1213 	Uint8 color3[3];
1214 
1215 	/*
1216 	* Check visibility of clipping rectangle
1217 	*/
1218 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1219 		return(0);
1220 	}
1221 
1222 	/*
1223 	* Swap x1, x2 if required to ensure x1<=x2
1224 	*/
1225 	if (x1 > x2) {
1226 		xtmp = x1;
1227 		x1 = x2;
1228 		x2 = xtmp;
1229 	}
1230 
1231 	/*
1232 	* Get clipping boundary and
1233 	* check visibility of hline
1234 	*/
1235 	left = dst->clip_rect.x;
1236 	if (x2<left) {
1237 		return(0);
1238 	}
1239 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
1240 	if (x1>right) {
1241 		return(0);
1242 	}
1243 	top = dst->clip_rect.y;
1244 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1245 	if ((y<top) || (y>bottom)) {
1246 		return (0);
1247 	}
1248 
1249 	/*
1250 	* Clip x
1251 	*/
1252 	if (x1 < left) {
1253 		x1 = left;
1254 	}
1255 	if (x2 > right) {
1256 		x2 = right;
1257 	}
1258 
1259 	/*
1260 	* Calculate width difference
1261 	*/
1262 	dx = x2 - x1;
1263 
1264 	/*
1265 	* Alpha check
1266 	*/
1267 	if ((color & 255) == 255) {
1268 
1269 		/*
1270 		* No alpha-blending required
1271 		*/
1272 
1273 		/*
1274 		* Setup color
1275 		*/
1276 		colorptr = (Uint8 *) & color;
1277 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1278 			color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1279 		} else {
1280 			color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1281 		}
1282 
1283 		/*
1284 		* Lock the surface
1285 		*/
1286 		if (SDL_MUSTLOCK(dst)) {
1287 			if (SDL_LockSurface(dst) < 0) {
1288 				return (-1);
1289 			}
1290 		}
1291 
1292 		/*
1293 		* More variable setup
1294 		*/
1295 		pixx = dst->format->BytesPerPixel;
1296 		pixy = dst->pitch;
1297 		pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
1298 
1299 		/*
1300 		* Draw
1301 		*/
1302 		switch (dst->format->BytesPerPixel) {
1303 		case 1:
1304 			memset(pixel, color, dx + 1);
1305 			break;
1306 		case 2:
1307 			pixellast = pixel + dx + dx;
1308 			for (; pixel <= pixellast; pixel += pixx) {
1309 				*(Uint16 *) pixel = color;
1310 			}
1311 			break;
1312 		case 3:
1313 			pixellast = pixel + dx + dx + dx;
1314 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1315 				color3[0] = (color >> 16) & 0xff;
1316 				color3[1] = (color >> 8) & 0xff;
1317 				color3[2] = color & 0xff;
1318 			} else {
1319 				color3[0] = color & 0xff;
1320 				color3[1] = (color >> 8) & 0xff;
1321 				color3[2] = (color >> 16) & 0xff;
1322 			}
1323 			for (; pixel <= pixellast; pixel += pixx) {
1324 				memcpy(pixel, color3, 3);
1325 			}
1326 			break;
1327 		default:		/* case 4 */
1328 			dx = dx + dx;
1329 			pixellast = pixel + dx + dx;
1330 			for (; pixel <= pixellast; pixel += pixx) {
1331 				*(Uint32 *) pixel = color;
1332 			}
1333 			break;
1334 		}
1335 
1336 		/*
1337 		* Unlock surface
1338 		*/
1339 		if (SDL_MUSTLOCK(dst)) {
1340 			SDL_UnlockSurface(dst);
1341 		}
1342 
1343 		/*
1344 		* Set result code
1345 		*/
1346 		result = 0;
1347 
1348 	} else {
1349 
1350 		/*
1351 		* Alpha blending blit
1352 		*/
1353 		result = _HLineAlpha(dst, x1, x1 + dx, y, color);
1354 	}
1355 
1356 	return (result);
1357 }
1358 
1359 /*!
1360 \brief Draw horizontal line with blending.
1361 
1362 \param dst The surface to draw on.
1363 \param x1 X coordinate of the first point (i.e. left) of the line.
1364 \param x2 X coordinate of the second point (i.e. right) of the line.
1365 \param y Y coordinate of the points of the line.
1366 \param r The red value of the line to draw.
1367 \param g The green value of the line to draw.
1368 \param b The blue value of the line to draw.
1369 \param a The alpha value of the line to draw.
1370 
1371 \returns Returns 0 on success, -1 on failure.
1372 */
hlineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1373 int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1374 {
1375 	/*
1376 	* Draw
1377 	*/
1378 	return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1379 }
1380 
1381 /*!
1382 \brief Draw vertical line with blending.
1383 
1384 \param dst The surface to draw on.
1385 \param x X coordinate of the points of the line.
1386 \param y1 Y coordinate of the first point (i.e. top) of the line.
1387 \param y2 Y coordinate of the second point (i.e. bottom) of the line.
1388 \param color The color value of the line to draw (0xRRGGBBAA).
1389 
1390 \returns Returns 0 on success, -1 on failure.
1391 */
vlineColor(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)1392 int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
1393 {
1394 	Sint16 left, right, top, bottom;
1395 	Uint8 *pixel, *pixellast;
1396 	int dy;
1397 	int pixx, pixy;
1398 	Sint16 h;
1399 	Sint16 ytmp;
1400 	int result = -1;
1401 	Uint8 *colorptr;
1402 
1403 	/*
1404 	* Check visibility of clipping rectangle
1405 	*/
1406 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1407 		return(0);
1408 	}
1409 
1410 	/*
1411 	* Swap y1, y2 if required to ensure y1<=y2
1412 	*/
1413 	if (y1 > y2) {
1414 		ytmp = y1;
1415 		y1 = y2;
1416 		y2 = ytmp;
1417 	}
1418 
1419 	/*
1420 	* Get clipping boundary and
1421 	* check visibility of vline
1422 	*/
1423 	left = dst->clip_rect.x;
1424 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
1425 	if ((x<left) || (x>right)) {
1426 		return (0);
1427 	}
1428 	top = dst->clip_rect.y;
1429 	if (y2<top) {
1430 		return(0);
1431 	}
1432 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1433 	if (y1>bottom) {
1434 		return(0);
1435 	}
1436 
1437 	/*
1438 	* Clip x
1439 	*/
1440 	if (y1 < top) {
1441 		y1 = top;
1442 	}
1443 	if (y2 > bottom) {
1444 		y2 = bottom;
1445 	}
1446 
1447 	/*
1448 	* Calculate height
1449 	*/
1450 	h = y2 - y1;
1451 
1452 	/*
1453 	* Alpha check
1454 	*/
1455 	if ((color & 255) == 255) {
1456 
1457 		/*
1458 		* No alpha-blending required
1459 		*/
1460 
1461 		/*
1462 		* Setup color
1463 		*/
1464 		colorptr = (Uint8 *) & color;
1465 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1466 			color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1467 		} else {
1468 			color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1469 		}
1470 
1471 		/*
1472 		* Lock the surface
1473 		*/
1474 		if (SDL_MUSTLOCK(dst)) {
1475 			if (SDL_LockSurface(dst) < 0) {
1476 				return (-1);
1477 			}
1478 		}
1479 
1480 		/*
1481 		* More variable setup
1482 		*/
1483 		dy = h;
1484 		pixx = dst->format->BytesPerPixel;
1485 		pixy = dst->pitch;
1486 		pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1;
1487 		pixellast = pixel + pixy * dy;
1488 
1489 		/*
1490 		* Draw
1491 		*/
1492 		switch (dst->format->BytesPerPixel) {
1493 		case 1:
1494 			for (; pixel <= pixellast; pixel += pixy) {
1495 				*(Uint8 *) pixel = color;
1496 			}
1497 			break;
1498 		case 2:
1499 			for (; pixel <= pixellast; pixel += pixy) {
1500 				*(Uint16 *) pixel = color;
1501 			}
1502 			break;
1503 		case 3:
1504 			for (; pixel <= pixellast; pixel += pixy) {
1505 				if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1506 					pixel[0] = (color >> 16) & 0xff;
1507 					pixel[1] = (color >> 8) & 0xff;
1508 					pixel[2] = color & 0xff;
1509 				} else {
1510 					pixel[0] = color & 0xff;
1511 					pixel[1] = (color >> 8) & 0xff;
1512 					pixel[2] = (color >> 16) & 0xff;
1513 				}
1514 			}
1515 			break;
1516 		default:		/* case 4 */
1517 			for (; pixel <= pixellast; pixel += pixy) {
1518 				*(Uint32 *) pixel = color;
1519 			}
1520 			break;
1521 		}
1522 
1523 		/* Unlock surface */
1524 		if (SDL_MUSTLOCK(dst)) {
1525 			SDL_UnlockSurface(dst);
1526 		}
1527 
1528 		/*
1529 		* Set result code
1530 		*/
1531 		result = 0;
1532 
1533 	} else {
1534 
1535 		/*
1536 		* Alpha blending blit
1537 		*/
1538 
1539 		result = _VLineAlpha(dst, x, y1, y1 + h, color);
1540 
1541 	}
1542 
1543 	return (result);
1544 }
1545 
1546 /*!
1547 \brief Draw vertical line with blending.
1548 
1549 \param dst The surface to draw on.
1550 \param x X coordinate of the points of the line.
1551 \param y1 Y coordinate of the first point (i.e. top) of the line.
1552 \param y2 Y coordinate of the second point (i.e. bottom) of the line.
1553 \param r The red value of the line to draw.
1554 \param g The green value of the line to draw.
1555 \param b The blue value of the line to draw.
1556 \param a The alpha value of the line to draw.
1557 
1558 \returns Returns 0 on success, -1 on failure.
1559 */
vlineRGBA(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1560 int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1561 {
1562 	/*
1563 	* Draw
1564 	*/
1565 	return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1566 }
1567 
1568 /*!
1569 \brief Draw rectangle with blending.
1570 
1571 \param dst The surface to draw on.
1572 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1573 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1574 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1575 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1576 \param color The color value of the rectangle to draw (0xRRGGBBAA).
1577 
1578 \returns Returns 0 on success, -1 on failure.
1579 */
rectangleColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1580 int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1581 {
1582 	int result;
1583 	Sint16 tmp;
1584 
1585 	/* Check destination surface */
1586 	if (dst == NULL)
1587 	{
1588 		return -1;
1589 	}
1590 
1591 	/*
1592 	* Check visibility of clipping rectangle
1593 	*/
1594 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1595 		return 0;
1596 	}
1597 
1598 	/*
1599 	* Test for special cases of straight lines or single point
1600 	*/
1601 	if (x1 == x2) {
1602 		if (y1 == y2) {
1603 			return (pixelColor(dst, x1, y1, color));
1604 		} else {
1605 			return (vlineColor(dst, x1, y1, y2, color));
1606 		}
1607 	} else {
1608 		if (y1 == y2) {
1609 			return (hlineColor(dst, x1, x2, y1, color));
1610 		}
1611 	}
1612 
1613 	/*
1614 	* Swap x1, x2 if required
1615 	*/
1616 	if (x1 > x2) {
1617 		tmp = x1;
1618 		x1 = x2;
1619 		x2 = tmp;
1620 	}
1621 
1622 	/*
1623 	* Swap y1, y2 if required
1624 	*/
1625 	if (y1 > y2) {
1626 		tmp = y1;
1627 		y1 = y2;
1628 		y2 = tmp;
1629 	}
1630 
1631 	/*
1632 	* Draw rectangle
1633 	*/
1634 	result = 0;
1635 	result |= hlineColor(dst, x1, x2, y1, color);
1636 	result |= hlineColor(dst, x1, x2, y2, color);
1637 	y1 += 1;
1638 	y2 -= 1;
1639 	if (y1 <= y2) {
1640 		result |= vlineColor(dst, x1, y1, y2, color);
1641 		result |= vlineColor(dst, x2, y1, y2, color);
1642 	}
1643 
1644 	return (result);
1645 
1646 }
1647 
1648 /*!
1649 \brief Draw rectangle with blending.
1650 
1651 \param dst The surface to draw on.
1652 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1653 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1654 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1655 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1656 \param r The red value of the rectangle to draw.
1657 \param g The green value of the rectangle to draw.
1658 \param b The blue value of the rectangle to draw.
1659 \param a The alpha value of the rectangle to draw.
1660 
1661 \returns Returns 0 on success, -1 on failure.
1662 */
rectangleRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1663 int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1664 {
1665 	/*
1666 	* Draw
1667 	*/
1668 	return (rectangleColor
1669 		(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1670 }
1671 
1672 /*!
1673 \brief Draw rounded-corner rectangle with blending.
1674 
1675 \param dst The surface to draw on.
1676 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1677 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1678 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1679 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1680 \param rad The radius of the corner arc.
1681 \param color The color value of the rectangle to draw (0xRRGGBBAA).
1682 
1683 \returns Returns 0 on success, -1 on failure.
1684 */
roundedRectangleColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint32 color)1685 int roundedRectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
1686 {
1687 	int result;
1688 	Sint16 w, h, tmp;
1689 	Sint16 xx1, xx2, yy1, yy2;
1690 
1691 	/*
1692 	* Check destination surface
1693 	*/
1694 	if (dst == NULL)
1695 	{
1696 		return -1;
1697 	}
1698 
1699 	/*
1700 	* Check radius vor valid range
1701 	*/
1702 	if (rad < 0) {
1703 		return -1;
1704 	}
1705 
1706 	/*
1707 	* Special case - no rounding
1708 	*/
1709 	if (rad == 0) {
1710 		return rectangleColor(dst, x1, y1, x2, y2, color);
1711 	}
1712 
1713 	/*
1714 	* Check visibility of clipping rectangle
1715 	*/
1716 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1717 		return 0;
1718 	}
1719 
1720 	/*
1721 	* Test for special cases of straight lines or single point
1722 	*/
1723 	if (x1 == x2) {
1724 		if (y1 == y2) {
1725 			return (pixelColor(dst, x1, y1, color));
1726 		} else {
1727 			return (vlineColor(dst, x1, y1, y2, color));
1728 		}
1729 	} else {
1730 		if (y1 == y2) {
1731 			return (hlineColor(dst, x1, x2, y1, color));
1732 		}
1733 	}
1734 
1735 	/*
1736 	* Swap x1, x2 if required
1737 	*/
1738 	if (x1 > x2) {
1739 		tmp = x1;
1740 		x1 = x2;
1741 		x2 = tmp;
1742 	}
1743 
1744 	/*
1745 	* Swap y1, y2 if required
1746 	*/
1747 	if (y1 > y2) {
1748 		tmp = y1;
1749 		y1 = y2;
1750 		y2 = tmp;
1751 	}
1752 
1753 	/*
1754 	* Calculate width&height
1755 	*/
1756 	w = x2 - x1;
1757 	h = y2 - y1;
1758 
1759 	/*
1760 	* Maybe adjust radius
1761 	*/
1762 	if ((rad * 2) > w)
1763 	{
1764 		rad = w / 2;
1765 	}
1766 	if ((rad * 2) > h)
1767 	{
1768 		rad = h / 2;
1769 	}
1770 
1771 	/*
1772 	* Draw corners
1773 	*/
1774 	result = 0;
1775 	xx1 = x1 + rad;
1776 	xx2 = x2 - rad;
1777 	yy1 = y1 + rad;
1778 	yy2 = y2 - rad;
1779 	result |= arcColor(dst, xx1, yy1, rad, 180, 270, color);
1780 	result |= arcColor(dst, xx2, yy1, rad, 270, 360, color);
1781 	result |= arcColor(dst, xx1, yy2, rad,  90, 180, color);
1782 	result |= arcColor(dst, xx2, yy2, rad,   0,  90, color);
1783 
1784 	/*
1785 	* Draw lines
1786 	*/
1787 	if (xx1 <= xx2) {
1788 		result |= hlineColor(dst, xx1, xx2, y1, color);
1789 		result |= hlineColor(dst, xx1, xx2, y2, color);
1790 	}
1791 	if (yy1 <= yy2) {
1792 		result |= vlineColor(dst, x1, yy1, yy2, color);
1793 		result |= vlineColor(dst, x2, yy1, yy2, color);
1794 	}
1795 
1796 	return result;
1797 }
1798 
1799 /*!
1800 \brief Draw rounded-corner rectangle with blending.
1801 
1802 \param dst The surface to draw on.
1803 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1804 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1805 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1806 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1807 \param rad The radius of the corner arc.
1808 \param r The red value of the rectangle to draw.
1809 \param g The green value of the rectangle to draw.
1810 \param b The blue value of the rectangle to draw.
1811 \param a The alpha value of the rectangle to draw.
1812 
1813 \returns Returns 0 on success, -1 on failure.
1814 */
roundedRectangleRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1815 int roundedRectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1816 {
1817 	/*
1818 	* Draw
1819 	*/
1820 	return (roundedRectangleColor
1821 		(dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1822 }
1823 
1824 /*!
1825 \brief Draw rounded-corner box (filled rectangle) with blending.
1826 
1827 \param dst The surface to draw on.
1828 \param x1 X coordinate of the first point (i.e. top right) of the box.
1829 \param y1 Y coordinate of the first point (i.e. top right) of the box.
1830 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
1831 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
1832 \param rad The radius of the corner arcs of the box.
1833 \param color The color value of the box to draw (0xRRGGBBAA).
1834 
1835 \returns Returns 0 on success, -1 on failure.
1836 */
roundedBoxColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint32 color)1837 int roundedBoxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
1838 {
1839 	int result;
1840 	Sint16 w, h, tmp;
1841 	Sint16 xx1, xx2, yy1, yy2;
1842 
1843 	/*
1844 	* Check destination surface
1845 	*/
1846 	if (dst == NULL)
1847 	{
1848 		return -1;
1849 	}
1850 
1851 	/*
1852 	* Check radius vor valid range
1853 	*/
1854 	if (rad < 0) {
1855 		return -1;
1856 	}
1857 
1858 	/*
1859 	* Special case - no rounding
1860 	*/
1861 	if (rad == 0) {
1862 		return rectangleColor(dst, x1, y1, x2, y2, color);
1863 	}
1864 
1865 	/*
1866 	* Check visibility of clipping rectangle
1867 	*/
1868 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1869 		return 0;
1870 	}
1871 
1872 	/*
1873 	* Test for special cases of straight lines or single point
1874 	*/
1875 	if (x1 == x2) {
1876 		if (y1 == y2) {
1877 			return (pixelColor(dst, x1, y1, color));
1878 		} else {
1879 			return (vlineColor(dst, x1, y1, y2, color));
1880 		}
1881 	} else {
1882 		if (y1 == y2) {
1883 			return (hlineColor(dst, x1, x2, y1, color));
1884 		}
1885 	}
1886 
1887 	/*
1888 	* Swap x1, x2 if required
1889 	*/
1890 	if (x1 > x2) {
1891 		tmp = x1;
1892 		x1 = x2;
1893 		x2 = tmp;
1894 	}
1895 
1896 	/*
1897 	* Swap y1, y2 if required
1898 	*/
1899 	if (y1 > y2) {
1900 		tmp = y1;
1901 		y1 = y2;
1902 		y2 = tmp;
1903 	}
1904 
1905 	/*
1906 	* Calculate width&height
1907 	*/
1908 	w = x2 - x1;
1909 	h = y2 - y1;
1910 
1911 	/*
1912 	* Maybe adjust radius
1913 	*/
1914 	if ((rad * 2) > w)
1915 	{
1916 		rad = w / 2;
1917 	}
1918 	if ((rad * 2) > h)
1919 	{
1920 		rad = h / 2;
1921 	}
1922 
1923 	/*
1924 	* Draw corners
1925 	*/
1926 	result = 0;
1927 	xx1 = x1 + rad;
1928 	xx2 = x2 - rad;
1929 	yy1 = y1 + rad;
1930 	yy2 = y2 - rad;
1931 	result |= filledPieColor(dst, xx1, yy1, rad, 180, 270, color);
1932 	result |= filledPieColor(dst, xx2, yy1, rad, 270, 360, color);
1933 	result |= filledPieColor(dst, xx1, yy2, rad,  90, 180, color);
1934 	result |= filledPieColor(dst, xx2, yy2, rad,   0,  90, color);
1935 
1936 	/*
1937 	* Draw body
1938 	*/
1939 	xx1++;
1940 	xx2--;
1941 	yy1++;
1942 	yy2--;
1943 	if (xx1 <= xx2) {
1944 		result |= boxColor(dst, xx1, y1, xx2, y2, color);
1945 	}
1946 	if (yy1 <= yy2) {
1947 		result |= boxColor(dst, x1, yy1, xx1-1, yy2, color);
1948 		result |= boxColor(dst, xx2+1, yy1, x2, yy2, color);
1949 	}
1950 
1951 	return result;
1952 }
1953 
1954 /*!
1955 \brief Draw rounded-corner box (filled rectangle) with blending.
1956 
1957 \param dst The surface to draw on.
1958 \param x1 X coordinate of the first point (i.e. top right) of the box.
1959 \param y1 Y coordinate of the first point (i.e. top right) of the box.
1960 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
1961 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
1962 \param rad The radius of the corner arcs of the box.
1963 \param r The red value of the box to draw.
1964 \param g The green value of the box to draw.
1965 \param b The blue value of the box to draw.
1966 \param a The alpha value of the box to draw.
1967 
1968 \returns Returns 0 on success, -1 on failure.
1969 */
roundedBoxRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1970 int roundedBoxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2,
1971 	Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1972 {
1973 	/*
1974 	* Draw
1975 	*/
1976 	return (roundedBoxColor
1977 		(dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1978 }
1979 
1980 /* --------- Clipping routines for line */
1981 
1982 /* Clipping based heavily on code from                       */
1983 /* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c   */
1984 
1985 #define CLIP_LEFT_EDGE   0x1
1986 #define CLIP_RIGHT_EDGE  0x2
1987 #define CLIP_BOTTOM_EDGE 0x4
1988 #define CLIP_TOP_EDGE    0x8
1989 #define CLIP_INSIDE(a)   (!a)
1990 #define CLIP_REJECT(a,b) (a&b)
1991 #define CLIP_ACCEPT(a,b) (!(a|b))
1992 
1993 /*!
1994 \brief Internal clip-encoding routine.
1995 
1996 Calculates a segement-based clipping encoding for a point against a rectangle.
1997 
1998 \param x X coordinate of point.
1999 \param y Y coordinate of point.
2000 \param left X coordinate of left edge of the rectangle.
2001 \param top Y coordinate of top edge of the rectangle.
2002 \param right X coordinate of right edge of the rectangle.
2003 \param bottom Y coordinate of bottom edge of the rectangle.
2004 */
_clipEncode(Sint16 x,Sint16 y,Sint16 left,Sint16 top,Sint16 right,Sint16 bottom)2005 static int _clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom)
2006 {
2007 	int code = 0;
2008 
2009 	if (x < left) {
2010 		code |= CLIP_LEFT_EDGE;
2011 	} else if (x > right) {
2012 		code |= CLIP_RIGHT_EDGE;
2013 	}
2014 	if (y < top) {
2015 		code |= CLIP_TOP_EDGE;
2016 	} else if (y > bottom) {
2017 		code |= CLIP_BOTTOM_EDGE;
2018 	}
2019 	return code;
2020 }
2021 
2022 /*!
2023 \brief Clip line to a the clipping rectangle of a surface.
2024 
2025 \param dst Target surface to draw on.
2026 \param x1 Pointer to X coordinate of first point of line.
2027 \param y1 Pointer to Y coordinate of first point of line.
2028 \param x2 Pointer to X coordinate of second point of line.
2029 \param y2 Pointer to Y coordinate of second point of line.
2030 */
_clipLine(SDL_Surface * dst,Sint16 * x1,Sint16 * y1,Sint16 * x2,Sint16 * y2)2031 static int _clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2)
2032 {
2033 	Sint16 left, right, top, bottom;
2034 	int code1, code2;
2035 	int draw = 0;
2036 	Sint16 swaptmp;
2037 	float m;
2038 
2039 	/*
2040 	* Get clipping boundary
2041 	*/
2042 	left = dst->clip_rect.x;
2043 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
2044 	top = dst->clip_rect.y;
2045 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2046 
2047 	while (1) {
2048 		code1 = _clipEncode(*x1, *y1, left, top, right, bottom);
2049 		code2 = _clipEncode(*x2, *y2, left, top, right, bottom);
2050 		if (CLIP_ACCEPT(code1, code2)) {
2051 			draw = 1;
2052 			break;
2053 		} else if (CLIP_REJECT(code1, code2))
2054 			break;
2055 		else {
2056 			if (CLIP_INSIDE(code1)) {
2057 				swaptmp = *x2;
2058 				*x2 = *x1;
2059 				*x1 = swaptmp;
2060 				swaptmp = *y2;
2061 				*y2 = *y1;
2062 				*y1 = swaptmp;
2063 				swaptmp = code2;
2064 				code2 = code1;
2065 				code1 = swaptmp;
2066 			}
2067 			if (*x2 != *x1) {
2068 				m = (float)(*y2 - *y1) / (float)(*x2 - *x1);
2069 			} else {
2070 				m = 1.0f;
2071 			}
2072 			if (code1 & CLIP_LEFT_EDGE) {
2073 				*y1 += (Sint16) ((left - *x1) * m);
2074 				*x1 = left;
2075 			} else if (code1 & CLIP_RIGHT_EDGE) {
2076 				*y1 += (Sint16) ((right - *x1) * m);
2077 				*x1 = right;
2078 			} else if (code1 & CLIP_BOTTOM_EDGE) {
2079 				if (*x2 != *x1) {
2080 					*x1 += (Sint16) ((bottom - *y1) / m);
2081 				}
2082 				*y1 = bottom;
2083 			} else if (code1 & CLIP_TOP_EDGE) {
2084 				if (*x2 != *x1) {
2085 					*x1 += (Sint16) ((top - *y1) / m);
2086 				}
2087 				*y1 = top;
2088 			}
2089 		}
2090 	}
2091 
2092 	return draw;
2093 }
2094 
2095 /*!
2096 \brief Draw box (filled rectangle) with blending.
2097 
2098 \param dst The surface to draw on.
2099 \param x1 X coordinate of the first point (i.e. top right) of the box.
2100 \param y1 Y coordinate of the first point (i.e. top right) of the box.
2101 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
2102 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
2103 \param color The color value of the box to draw (0xRRGGBBAA).
2104 
2105 \returns Returns 0 on success, -1 on failure.
2106 */
boxColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2107 int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2108 {
2109 	Sint16 left, right, top, bottom;
2110 	Uint8 *pixel, *pixellast;
2111 	int x, dx;
2112 	int dy;
2113 	int pixx, pixy;
2114 	Sint16 w, h, tmp;
2115 	int result;
2116 	Uint8 *colorptr;
2117 
2118 	/*
2119 	* Check visibility of clipping rectangle
2120 	*/
2121 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2122 		return(0);
2123 	}
2124 
2125 	/*
2126 	* Order coordinates to ensure that
2127 	* x1<=x2 and y1<=y2
2128 	*/
2129 	if (x1 > x2) {
2130 		tmp = x1;
2131 		x1 = x2;
2132 		x2 = tmp;
2133 	}
2134 	if (y1 > y2) {
2135 		tmp = y1;
2136 		y1 = y2;
2137 		y2 = tmp;
2138 	}
2139 
2140 	/*
2141 	* Get clipping boundary and
2142 	* check visibility
2143 	*/
2144 	left = dst->clip_rect.x;
2145 	if (x2<left) {
2146 		return(0);
2147 	}
2148 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
2149 	if (x1>right) {
2150 		return(0);
2151 	}
2152 	top = dst->clip_rect.y;
2153 	if (y2<top) {
2154 		return(0);
2155 	}
2156 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2157 	if (y1>bottom) {
2158 		return(0);
2159 	}
2160 
2161 	/* Clip all points */
2162 	if (x1<left) {
2163 		x1=left;
2164 	} else if (x1>right) {
2165 		x1=right;
2166 	}
2167 	if (x2<left) {
2168 		x2=left;
2169 	} else if (x2>right) {
2170 		x2=right;
2171 	}
2172 	if (y1<top) {
2173 		y1=top;
2174 	} else if (y1>bottom) {
2175 		y1=bottom;
2176 	}
2177 	if (y2<top) {
2178 		y2=top;
2179 	} else if (y2>bottom) {
2180 		y2=bottom;
2181 	}
2182 
2183 	/*
2184 	* Test for special cases of straight line or single point
2185 	*/
2186 	if (x1 == x2) {
2187 		if (y1 == y2) {
2188 			return (pixelColor(dst, x1, y1, color));
2189 		} else {
2190 			return (vlineColor(dst, x1, y1, y2, color));
2191 		}
2192 	}
2193 	if (y1 == y2) {
2194 		return (hlineColor(dst, x1, x2, y1, color));
2195 	}
2196 
2197 	/*
2198 	* Calculate width&height
2199 	*/
2200 	w = x2 - x1;
2201 	h = y2 - y1;
2202 
2203 	/*
2204 	* Alpha check
2205 	*/
2206 	if ((color & 255) == 255) {
2207 
2208 		/*
2209 		* No alpha-blending required
2210 		*/
2211 
2212 		/*
2213 		* Setup color
2214 		*/
2215 		colorptr = (Uint8 *) & color;
2216 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2217 			color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2218 		} else {
2219 			color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2220 		}
2221 
2222 		/*
2223 		* Lock the surface
2224 		*/
2225 		if (SDL_MUSTLOCK(dst)) {
2226 			if (SDL_LockSurface(dst) < 0) {
2227 				return (-1);
2228 			}
2229 		}
2230 
2231 		/*
2232 		* More variable setup
2233 		*/
2234 		dx = w;
2235 		dy = h;
2236 		pixx = dst->format->BytesPerPixel;
2237 		pixy = dst->pitch;
2238 		pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
2239 		pixellast = pixel + pixx * dx + pixy * dy;
2240 		dx++;
2241 
2242 		/*
2243 		* Draw
2244 		*/
2245 		switch (dst->format->BytesPerPixel) {
2246 		case 1:
2247 			for (; pixel <= pixellast; pixel += pixy) {
2248 				memset(pixel, (Uint8) color, dx);
2249 			}
2250 			break;
2251 		case 2:
2252 			pixy -= (pixx * dx);
2253 			for (; pixel <= pixellast; pixel += pixy) {
2254 				for (x = 0; x < dx; x++) {
2255 					*(Uint16*) pixel = color;
2256 					pixel += pixx;
2257 				}
2258 			}
2259 			break;
2260 		case 3:
2261 			pixy -= (pixx * dx);
2262 			for (; pixel <= pixellast; pixel += pixy) {
2263 				for (x = 0; x < dx; x++) {
2264 					if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2265 						pixel[0] = (color >> 16) & 0xff;
2266 						pixel[1] = (color >> 8) & 0xff;
2267 						pixel[2] = color & 0xff;
2268 					} else {
2269 						pixel[0] = color & 0xff;
2270 						pixel[1] = (color >> 8) & 0xff;
2271 						pixel[2] = (color >> 16) & 0xff;
2272 					}
2273 					pixel += pixx;
2274 				}
2275 			}
2276 			break;
2277 		default:		/* case 4 */
2278 			pixy -= (pixx * dx);
2279 			for (; pixel <= pixellast; pixel += pixy) {
2280 				for (x = 0; x < dx; x++) {
2281 					*(Uint32 *) pixel = color;
2282 					pixel += pixx;
2283 				}
2284 			}
2285 			break;
2286 		}
2287 
2288 		/* Unlock surface */
2289 		if (SDL_MUSTLOCK(dst)) {
2290 			SDL_UnlockSurface(dst);
2291 		}
2292 
2293 		result = 0;
2294 
2295 	} else {
2296 
2297 		result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color);
2298 
2299 	}
2300 
2301 	return (result);
2302 }
2303 
2304 /*!
2305 \brief Draw box (filled rectangle) with blending.
2306 
2307 \param dst The surface to draw on.
2308 \param x1 X coordinate of the first point (i.e. top right) of the box.
2309 \param y1 Y coordinate of the first point (i.e. top right) of the box.
2310 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
2311 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
2312 \param r The red value of the box to draw.
2313 \param g The green value of the box to draw.
2314 \param b The blue value of the box to draw.
2315 \param a The alpha value of the box to draw.
2316 
2317 \returns Returns 0 on success, -1 on failure.
2318 */
boxRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2319 int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2320 {
2321 	/*
2322 	* Draw
2323 	*/
2324 	return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2325 }
2326 
2327 /* ----- Line */
2328 
2329 /* Non-alpha line drawing code adapted from routine          */
2330 /* by Pete Shinners, pete@shinners.org                       */
2331 /* Originally from pygame, http://pygame.seul.org            */
2332 
2333 #define ABS(a) (((a)<0) ? -(a) : (a))
2334 
2335 /*!
2336 \brief Draw line with alpha blending.
2337 
2338 \param dst The surface to draw on.
2339 \param x1 X coordinate of the first point of the line.
2340 \param y1 Y coordinate of the first point of the line.
2341 \param x2 X coordinate of the second point of the line.
2342 \param y2 Y coordinate of the second point of the line.
2343 \param color The color value of the line to draw (0xRRGGBBAA).
2344 
2345 \returns Returns 0 on success, -1 on failure.
2346 */
lineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2347 int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2348 {
2349 	int pixx, pixy;
2350 	int x, y;
2351 	int dx, dy;
2352 	int ax, ay;
2353 	int sx, sy;
2354 	int swaptmp;
2355 	Uint8 *pixel;
2356 	Uint8 *colorptr;
2357 
2358 	/*
2359 	* Clip line and test if we have to draw
2360 	*/
2361 	if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) {
2362 		return (0);
2363 	}
2364 
2365 	/*
2366 	* Test for special cases of straight lines or single point
2367 	*/
2368 	if (x1 == x2) {
2369 		if (y1 < y2) {
2370 			return (vlineColor(dst, x1, y1, y2, color));
2371 		} else if (y1 > y2) {
2372 			return (vlineColor(dst, x1, y2, y1, color));
2373 		} else {
2374 			return (pixelColor(dst, x1, y1, color));
2375 		}
2376 	}
2377 	if (y1 == y2) {
2378 		if (x1 < x2) {
2379 			return (hlineColor(dst, x1, x2, y1, color));
2380 		} else if (x1 > x2) {
2381 			return (hlineColor(dst, x2, x1, y1, color));
2382 		}
2383 	}
2384 
2385 	/*
2386 	* Variable setup
2387 	*/
2388 	dx = x2 - x1;
2389 	dy = y2 - y1;
2390 	sx = (dx >= 0) ? 1 : -1;
2391 	sy = (dy >= 0) ? 1 : -1;
2392 
2393 	/* Lock surface */
2394 	if (SDL_MUSTLOCK(dst)) {
2395 		if (SDL_LockSurface(dst) < 0) {
2396 			return (-1);
2397 		}
2398 	}
2399 
2400 	/*
2401 	* Check for alpha blending
2402 	*/
2403 	if ((color & 255) == 255) {
2404 
2405 		/*
2406 		* No alpha blending - use fast pixel routines
2407 		*/
2408 
2409 		/*
2410 		* Setup color
2411 		*/
2412 		colorptr = (Uint8 *) & color;
2413 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2414 			color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2415 		} else {
2416 			color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2417 		}
2418 
2419 		/*
2420 		* More variable setup
2421 		*/
2422 		dx = sx * dx + 1;
2423 		dy = sy * dy + 1;
2424 		pixx = dst->format->BytesPerPixel;
2425 		pixy = dst->pitch;
2426 		pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
2427 		pixx *= sx;
2428 		pixy *= sy;
2429 		if (dx < dy) {
2430 			swaptmp = dx;
2431 			dx = dy;
2432 			dy = swaptmp;
2433 			swaptmp = pixx;
2434 			pixx = pixy;
2435 			pixy = swaptmp;
2436 		}
2437 
2438 		/*
2439 		* Draw
2440 		*/
2441 		x = 0;
2442 		y = 0;
2443 		switch (dst->format->BytesPerPixel) {
2444 		case 1:
2445 			for (; x < dx; x++, pixel += pixx) {
2446 				*pixel = color;
2447 				y += dy;
2448 				if (y >= dx) {
2449 					y -= dx;
2450 					pixel += pixy;
2451 				}
2452 			}
2453 			break;
2454 		case 2:
2455 			for (; x < dx; x++, pixel += pixx) {
2456 				*(Uint16 *) pixel = color;
2457 				y += dy;
2458 				if (y >= dx) {
2459 					y -= dx;
2460 					pixel += pixy;
2461 				}
2462 			}
2463 			break;
2464 		case 3:
2465 			for (; x < dx; x++, pixel += pixx) {
2466 				if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2467 					pixel[0] = (color >> 16) & 0xff;
2468 					pixel[1] = (color >> 8) & 0xff;
2469 					pixel[2] = color & 0xff;
2470 				} else {
2471 					pixel[0] = color & 0xff;
2472 					pixel[1] = (color >> 8) & 0xff;
2473 					pixel[2] = (color >> 16) & 0xff;
2474 				}
2475 				y += dy;
2476 				if (y >= dx) {
2477 					y -= dx;
2478 					pixel += pixy;
2479 				}
2480 			}
2481 			break;
2482 		default:		/* case 4 */
2483 			for (; x < dx; x++, pixel += pixx) {
2484 				*(Uint32 *) pixel = color;
2485 				y += dy;
2486 				if (y >= dx) {
2487 					y -= dx;
2488 					pixel += pixy;
2489 				}
2490 			}
2491 			break;
2492 		}
2493 
2494 	} else {
2495 
2496 		/*
2497 		* Alpha blending required - use single-pixel blits
2498 		*/
2499 
2500 		ax = ABS(dx) << 1;
2501 		ay = ABS(dy) << 1;
2502 		x = x1;
2503 		y = y1;
2504 		if (ax > ay) {
2505 			int d = ay - (ax >> 1);
2506 
2507 			while (x != x2) {
2508 				pixelColorNolock (dst, x, y, color);
2509 				if (d > 0 || (d == 0 && sx == 1)) {
2510 					y += sy;
2511 					d -= ax;
2512 				}
2513 				x += sx;
2514 				d += ay;
2515 			}
2516 		} else {
2517 			int d = ax - (ay >> 1);
2518 
2519 			while (y != y2) {
2520 				pixelColorNolock (dst, x, y, color);
2521 				if (d > 0 || ((d == 0) && (sy == 1))) {
2522 					x += sx;
2523 					d -= ay;
2524 				}
2525 				y += sy;
2526 				d += ax;
2527 			}
2528 		}
2529 		pixelColorNolock (dst, x, y, color);
2530 
2531 	}
2532 
2533 	/* Unlock surface */
2534 	if (SDL_MUSTLOCK(dst)) {
2535 		SDL_UnlockSurface(dst);
2536 	}
2537 
2538 	return (0);
2539 }
2540 
2541 /*!
2542 \brief Draw line with alpha blending.
2543 
2544 \param dst The surface to draw on.
2545 \param x1 X coordinate of the first point of the line.
2546 \param y1 Y coordinate of the first point of the line.
2547 \param x2 X coordinate of the second point of the line.
2548 \param y2 Y coordinate of the second point of the line.
2549 \param r The red value of the line to draw.
2550 \param g The green value of the line to draw.
2551 \param b The blue value of the line to draw.
2552 \param a The alpha value of the line to draw.
2553 
2554 \returns Returns 0 on success, -1 on failure.
2555 */
lineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2556 int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2557 {
2558 	/*
2559 	* Draw
2560 	*/
2561 	return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2562 }
2563 
2564 /* AA Line */
2565 
2566 #define AAlevels 256
2567 #define AAbits 8
2568 
2569 /*!
2570 \brief Internal function to draw anti-aliased line with alpha blending and endpoint control.
2571 
2572 This implementation of the Wu antialiasing code is based on Mike Abrash's
2573 DDJ article which was reprinted as Chapter 42 of his Graphics Programming
2574 Black Book, but has been optimized to work with SDL and utilizes 32-bit
2575 fixed-point arithmetic by A. Schiffler. The endpoint control allows the
2576 supression to draw the last pixel useful for rendering continous aa-lines
2577 with alpha<255.
2578 
2579 \param dst The surface to draw on.
2580 \param x1 X coordinate of the first point of the aa-line.
2581 \param y1 Y coordinate of the first point of the aa-line.
2582 \param x2 X coordinate of the second point of the aa-line.
2583 \param y2 Y coordinate of the second point of the aa-line.
2584 \param color The color value of the aa-line to draw (0xRRGGBBAA).
2585 \param draw_endpoint Flag indicating if the endpoint should be drawn; draw if non-zero.
2586 
2587 \returns Returns 0 on success, -1 on failure.
2588 */
_aalineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,int draw_endpoint)2589 int _aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint)
2590 {
2591 	Sint32 xx0, yy0, xx1, yy1;
2592 	int result;
2593 	Uint32 intshift, erracc, erradj;
2594 	Uint32 erracctmp, wgt, wgtcompmask;
2595 	int dx, dy, tmp, xdir, y0p1, x0pxdir;
2596 
2597 	/*
2598 	* Check visibility of clipping rectangle
2599 	*/
2600 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2601 		return(0);
2602 	}
2603 
2604 	/*
2605 	* Clip line and test if we have to draw
2606 	*/
2607 	if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) {
2608 		return (0);
2609 	}
2610 
2611 	/*
2612 	* Keep on working with 32bit numbers
2613 	*/
2614 	xx0 = x1;
2615 	yy0 = y1;
2616 	xx1 = x2;
2617 	yy1 = y2;
2618 
2619 	/*
2620 	* Reorder points if required
2621 	*/
2622 	if (yy0 > yy1) {
2623 		tmp = yy0;
2624 		yy0 = yy1;
2625 		yy1 = tmp;
2626 		tmp = xx0;
2627 		xx0 = xx1;
2628 		xx1 = tmp;
2629 	}
2630 
2631 	/*
2632 	* Calculate distance
2633 	*/
2634 	dx = xx1 - xx0;
2635 	dy = yy1 - yy0;
2636 
2637 	/*
2638 	* Check for special cases
2639 	*/
2640 	if (dx == 0) {
2641 		/*
2642 		* Vertical line
2643 		*/
2644 		if (draw_endpoint)
2645 		{
2646 			return (vlineColor(dst, x1, y1, y2, color));
2647 		} else {
2648 			if (dy>0) {
2649 				return (vlineColor(dst, x1, yy0, yy0+dy, color));
2650 			} else {
2651 				return (pixelColor(dst, x1, y1, color));
2652 			}
2653 		}
2654 	} else if (dy == 0) {
2655 		/*
2656 		* Horizontal line
2657 		*/
2658 		if (draw_endpoint)
2659 		{
2660 			return (hlineColor(dst, x1, x2, y1, color));
2661 		} else {
2662 			if (dx!=0) {
2663 				return (hlineColor(dst, xx0, xx0+dx, y1, color));
2664 			} else {
2665 				return (pixelColor(dst, x1, y1, color));
2666 			}
2667 		}
2668 	} else if ((dx == dy) && (draw_endpoint)) {
2669 		/*
2670 		* Diagonal line (with endpoint)
2671 		*/
2672 		return (lineColor(dst, x1, y1, x2, y2, color));
2673 	}
2674 
2675 	/*
2676 	* Adjust for negative dx and set xdir
2677 	*/
2678 	if (dx >= 0) {
2679 		xdir = 1;
2680 	} else {
2681 		xdir = -1;
2682 		dx = (-dx);
2683 	}
2684 
2685 	/*
2686 	* Line is not horizontal, vertical or diagonal (with endpoint)
2687 	*/
2688 	result = 0;
2689 
2690 	/*
2691 	* Zero accumulator
2692 	*/
2693 	erracc = 0;
2694 
2695 	/*
2696 	* # of bits by which to shift erracc to get intensity level
2697 	*/
2698 	intshift = 32 - AAbits;
2699 
2700 	/*
2701 	* Mask used to flip all bits in an intensity weighting
2702 	*/
2703 	wgtcompmask = AAlevels - 1;
2704 
2705 	/* Lock surface */
2706 	if (SDL_MUSTLOCK(dst)) {
2707 		if (SDL_LockSurface(dst) < 0) {
2708 			return (-1);
2709 		}
2710 	}
2711 
2712 	/*
2713 	* Draw the initial pixel in the foreground color
2714 	*/
2715 	result |= pixelColorNolock(dst, x1, y1, color);
2716 
2717 	/*
2718 	* x-major or y-major?
2719 	*/
2720 	if (dy > dx) {
2721 
2722 		/*
2723 		* y-major.  Calculate 16-bit fixed point fractional part of a pixel that
2724 		* X advances every time Y advances 1 pixel, truncating the result so that
2725 		* we won't overrun the endpoint along the X axis
2726 		*/
2727 		/*
2728 		* Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
2729 		*/
2730 		erradj = ((dx << 16) / dy) << 16;
2731 
2732 		/*
2733 		* draw all pixels other than the first and last
2734 		*/
2735 		x0pxdir = xx0 + xdir;
2736 		while (--dy) {
2737 			erracctmp = erracc;
2738 			erracc += erradj;
2739 			if (erracc <= erracctmp) {
2740 				/*
2741 				* rollover in error accumulator, x coord advances
2742 				*/
2743 				xx0 = x0pxdir;
2744 				x0pxdir += xdir;
2745 			}
2746 			yy0++;		/* y-major so always advance Y */
2747 
2748 			/*
2749 			* the AAbits most significant bits of erracc give us the intensity
2750 			* weighting for this pixel, and the complement of the weighting for
2751 			* the paired pixel.
2752 			*/
2753 			wgt = (erracc >> intshift) & 255;
2754 			result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
2755 			result |= pixelColorWeightNolock (dst, x0pxdir, yy0, color, wgt);
2756 		}
2757 
2758 	} else {
2759 
2760 		/*
2761 		* x-major line.  Calculate 16-bit fixed-point fractional part of a pixel
2762 		* that Y advances each time X advances 1 pixel, truncating the result so
2763 		* that we won't overrun the endpoint along the X axis.
2764 		*/
2765 		/*
2766 		* Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
2767 		*/
2768 		erradj = ((dy << 16) / dx) << 16;
2769 
2770 		/*
2771 		* draw all pixels other than the first and last
2772 		*/
2773 		y0p1 = yy0 + 1;
2774 		while (--dx) {
2775 
2776 			erracctmp = erracc;
2777 			erracc += erradj;
2778 			if (erracc <= erracctmp) {
2779 				/*
2780 				* Accumulator turned over, advance y
2781 				*/
2782 				yy0 = y0p1;
2783 				y0p1++;
2784 			}
2785 			xx0 += xdir;	/* x-major so always advance X */
2786 			/*
2787 			* the AAbits most significant bits of erracc give us the intensity
2788 			* weighting for this pixel, and the complement of the weighting for
2789 			* the paired pixel.
2790 			*/
2791 			wgt = (erracc >> intshift) & 255;
2792 			result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
2793 			result |= pixelColorWeightNolock (dst, xx0, y0p1, color, wgt);
2794 		}
2795 	}
2796 
2797 	/*
2798 	* Do we have to draw the endpoint
2799 	*/
2800 	if (draw_endpoint) {
2801 		/*
2802 		* Draw final pixel, always exactly intersected by the line and doesn't
2803 		* need to be weighted.
2804 		*/
2805 		result |= pixelColorNolock (dst, x2, y2, color);
2806 	}
2807 
2808 	/* Unlock surface */
2809 	if (SDL_MUSTLOCK(dst)) {
2810 		SDL_UnlockSurface(dst);
2811 	}
2812 
2813 	return (result);
2814 }
2815 
2816 /*!
2817 \brief Ddraw anti-aliased line with alpha blending.
2818 
2819 \param dst The surface to draw on.
2820 \param x1 X coordinate of the first point of the aa-line.
2821 \param y1 Y coordinate of the first point of the aa-line.
2822 \param x2 X coordinate of the second point of the aa-line.
2823 \param y2 Y coordinate of the second point of the aa-line.
2824 \param color The color value of the aa-line to draw (0xRRGGBBAA).
2825 
2826 \returns Returns 0 on success, -1 on failure.
2827 */
aalineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2828 int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2829 {
2830 	return (_aalineColor(dst, x1, y1, x2, y2, color, 1));
2831 }
2832 
2833 /*!
2834 \brief Draw anti-aliased line with alpha blending.
2835 
2836 \param dst The surface to draw on.
2837 \param x1 X coordinate of the first point of the aa-line.
2838 \param y1 Y coordinate of the first point of the aa-line.
2839 \param x2 X coordinate of the second point of the aa-line.
2840 \param y2 Y coordinate of the second point of the aa-line.
2841 \param r The red value of the aa-line to draw.
2842 \param g The green value of the aa-line to draw.
2843 \param b The blue value of the aa-line to draw.
2844 \param a The alpha value of the aa-line to draw.
2845 
2846 \returns Returns 0 on success, -1 on failure.
2847 */
aalineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2848 int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2849 {
2850 	return (_aalineColor
2851 		(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
2852 }
2853 
2854 
2855 /* ----- Circle */
2856 
2857 /*!
2858 \brief Draw circle with blending.
2859 
2860 Note: Circle drawing routine is based on an algorithms from the sge library,
2861 but modified by A. Schiffler for multiple pixel-draw removal and other
2862 minor speedup changes.
2863 
2864 \param dst The surface to draw on.
2865 \param x X coordinate of the center of the circle.
2866 \param y Y coordinate of the center of the circle.
2867 \param rad Radius in pixels of the circle.
2868 \param color The color value of the circle to draw (0xRRGGBBAA).
2869 
2870 \returns Returns 0 on success, -1 on failure.
2871 */
circleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)2872 int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
2873 {
2874 	Sint16 left, right, top, bottom;
2875 	int result;
2876 	Sint16 x1, y1, x2, y2;
2877 	Sint16 cx = 0;
2878 	Sint16 cy = rad;
2879 	Sint16 df = 1 - rad;
2880 	Sint16 d_e = 3;
2881 	Sint16 d_se = -2 * rad + 5;
2882 	Sint16 xpcx, xmcx, xpcy, xmcy;
2883 	Sint16 ypcy, ymcy, ypcx, ymcx;
2884 	Uint8 *colorptr;
2885 
2886 	/*
2887 	* Check visibility of clipping rectangle
2888 	*/
2889 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2890 		return(0);
2891 	}
2892 
2893 	/*
2894 	* Sanity check radius
2895 	*/
2896 	if (rad < 0) {
2897 		return (-1);
2898 	}
2899 
2900 	/*
2901 	* Special case for rad=0 - draw a point
2902 	*/
2903 	if (rad == 0) {
2904 		return (pixelColor(dst, x, y, color));
2905 	}
2906 
2907 	/*
2908 	* Get circle and clipping boundary and
2909 	* test if bounding box of circle is visible
2910 	*/
2911 	x2 = x + rad;
2912 	left = dst->clip_rect.x;
2913 	if (x2<left) {
2914 		return(0);
2915 	}
2916 	x1 = x - rad;
2917 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
2918 	if (x1>right) {
2919 		return(0);
2920 	}
2921 	y2 = y + rad;
2922 	top = dst->clip_rect.y;
2923 	if (y2<top) {
2924 		return(0);
2925 	}
2926 	y1 = y - rad;
2927 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2928 	if (y1>bottom) {
2929 		return(0);
2930 	}
2931 
2932 	/*
2933 	* Draw circle
2934 	*/
2935 	result = 0;
2936 
2937 	/* Lock surface */
2938 	if (SDL_MUSTLOCK(dst)) {
2939 		if (SDL_LockSurface(dst) < 0) {
2940 			return (-1);
2941 		}
2942 	}
2943 
2944 	/*
2945 	* Alpha Check
2946 	*/
2947 	if ((color & 255) == 255) {
2948 
2949 		/*
2950 		* No Alpha - direct memory writes
2951 		*/
2952 
2953 		/*
2954 		* Setup color
2955 		*/
2956 		colorptr = (Uint8 *) & color;
2957 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2958 			color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2959 		} else {
2960 			color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2961 		}
2962 
2963 		/*
2964 		* Draw
2965 		*/
2966 		do {
2967 			ypcy = y + cy;
2968 			ymcy = y - cy;
2969 			if (cx > 0) {
2970 				xpcx = x + cx;
2971 				xmcx = x - cx;
2972 				result |= fastPixelColorNolock(dst, xmcx, ypcy, color);
2973 				result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
2974 				result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
2975 				result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
2976 			} else {
2977 				result |= fastPixelColorNolock(dst, x, ymcy, color);
2978 				result |= fastPixelColorNolock(dst, x, ypcy, color);
2979 			}
2980 			xpcy = x + cy;
2981 			xmcy = x - cy;
2982 			if ((cx > 0) && (cx != cy)) {
2983 				ypcx = y + cx;
2984 				ymcx = y - cx;
2985 				result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
2986 				result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
2987 				result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
2988 				result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
2989 			} else if (cx == 0) {
2990 				result |= fastPixelColorNolock(dst, xmcy, y, color);
2991 				result |= fastPixelColorNolock(dst, xpcy, y, color);
2992 			}
2993 			/*
2994 			* Update
2995 			*/
2996 			if (df < 0) {
2997 				df += d_e;
2998 				d_e += 2;
2999 				d_se += 2;
3000 			} else {
3001 				df += d_se;
3002 				d_e += 2;
3003 				d_se += 4;
3004 				cy--;
3005 			}
3006 			cx++;
3007 		} while (cx <= cy);
3008 
3009 		/*
3010 		* Unlock surface
3011 		*/
3012 		SDL_UnlockSurface(dst);
3013 
3014 	} else {
3015 
3016 		/*
3017 		* Using Alpha - blended pixel blits
3018 		*/
3019 
3020 		do {
3021 			/*
3022 			* Draw
3023 			*/
3024 			ypcy = y + cy;
3025 			ymcy = y - cy;
3026 			if (cx > 0) {
3027 				xpcx = x + cx;
3028 				xmcx = x - cx;
3029 				result |= pixelColorNolock (dst, xmcx, ypcy, color);
3030 				result |= pixelColorNolock (dst, xpcx, ypcy, color);
3031 				result |= pixelColorNolock (dst, xmcx, ymcy, color);
3032 				result |= pixelColorNolock (dst, xpcx, ymcy, color);
3033 			} else {
3034 				result |= pixelColorNolock (dst, x, ymcy, color);
3035 				result |= pixelColorNolock (dst, x, ypcy, color);
3036 			}
3037 			xpcy = x + cy;
3038 			xmcy = x - cy;
3039 			if ((cx > 0) && (cx != cy)) {
3040 				ypcx = y + cx;
3041 				ymcx = y - cx;
3042 				result |= pixelColorNolock (dst, xmcy, ypcx, color);
3043 				result |= pixelColorNolock (dst, xpcy, ypcx, color);
3044 				result |= pixelColorNolock (dst, xmcy, ymcx, color);
3045 				result |= pixelColorNolock (dst, xpcy, ymcx, color);
3046 			} else if (cx == 0) {
3047 				result |= pixelColorNolock (dst, xmcy, y, color);
3048 				result |= pixelColorNolock (dst, xpcy, y, color);
3049 			}
3050 			/*
3051 			* Update
3052 			*/
3053 			if (df < 0) {
3054 				df += d_e;
3055 				d_e += 2;
3056 				d_se += 2;
3057 			} else {
3058 				df += d_se;
3059 				d_e += 2;
3060 				d_se += 4;
3061 				cy--;
3062 			}
3063 			cx++;
3064 		} while (cx <= cy);
3065 
3066 	}				/* Alpha check */
3067 
3068 	/* Unlock surface */
3069 	if (SDL_MUSTLOCK(dst)) {
3070 		SDL_UnlockSurface(dst);
3071 	}
3072 
3073 	return (result);
3074 }
3075 
3076 /*!
3077 \brief Draw circle with blending.
3078 
3079 \param dst The surface to draw on.
3080 \param x X coordinate of the center of the circle.
3081 \param y Y coordinate of the center of the circle.
3082 \param rad Radius in pixels of the circle.
3083 \param r The red value of the circle to draw.
3084 \param g The green value of the circle to draw.
3085 \param b The blue value of the circle to draw.
3086 \param a The alpha value of the circle to draw.
3087 
3088 \returns Returns 0 on success, -1 on failure.
3089 */
circleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3090 int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3091 {
3092 	/*
3093 	* Draw
3094 	*/
3095 	return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3096 }
3097 
3098 /* ----- Arc */
3099 
3100 /*!
3101 \brief Arc with blending.
3102 
3103 Note Arc drawing is based on circle algorithm by A. Schiffler and
3104 written by D. Raber. Calculates which octants arc goes through and
3105 renders pixels accordingly.
3106 
3107 \param dst The surface to draw on.
3108 \param x X coordinate of the center of the arc.
3109 \param y Y coordinate of the center of the arc.
3110 \param rad Radius in pixels of the arc.
3111 \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3112 \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3113 \param color The color value of the arc to draw (0xRRGGBBAA).
3114 
3115 \returns Returns 0 on success, -1 on failure.
3116 */
arcColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)3117 int arcColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
3118 {
3119 	Sint16 left, right, top, bottom;
3120 	int result;
3121 	Sint16 x1, y1, x2, y2;
3122 	Sint16 cx = 0;
3123 	Sint16 cy = rad;
3124 	Sint16 df = 1 - rad;
3125 	Sint16 d_e = 3;
3126 	Sint16 d_se = -2 * rad + 5;
3127 	Sint16 xpcx, xmcx, xpcy, xmcy;
3128 	Sint16 ypcy, ymcy, ypcx, ymcx;
3129 	Uint8 *colorptr;
3130 	Uint8 drawoct;
3131 	int startoct, endoct, oct, stopval_start = 0, stopval_end = 0;
3132 	double dstart, dend, temp = 0.;
3133 
3134 	/*
3135 	* Check visibility of clipping rectangle
3136 	*/
3137 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3138 		return(0);
3139 	}
3140 
3141 	/*
3142 	* Sanity check radius
3143 	*/
3144 	if (rad < 0) {
3145 		return (-1);
3146 	}
3147 
3148 	/*
3149 	* Special case for rad=0 - draw a point
3150 	*/
3151 	if (rad == 0) {
3152 		return (pixelColor(dst, x, y, color));
3153 	}
3154 
3155 	/*
3156 	* Get arc's circle and clipping boundary and
3157 	* test if bounding box of circle is visible
3158 	*/
3159 	x2 = x + rad;
3160 	left = dst->clip_rect.x;
3161 	if (x2<left) {
3162 		return(0);
3163 	}
3164 	x1 = x - rad;
3165 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
3166 	if (x1>right) {
3167 		return(0);
3168 	}
3169 	y2 = y + rad;
3170 	top = dst->clip_rect.y;
3171 	if (y2<top) {
3172 		return(0);
3173 	}
3174 	y1 = y - rad;
3175 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3176 	if (y1>bottom) {
3177 		return(0);
3178 	}
3179 
3180 	// Octant labelling
3181 	//
3182 	//  \ 5 | 6 /
3183 	//   \  |  /
3184 	//  4 \ | / 7
3185 	//     \|/
3186 	//------+------ +x
3187 	//     /|\
3188 	//  3 / | \ 0
3189 	//   /  |  \
3190 	//  / 2 | 1 \
3191 	//      +y
3192 
3193 	// Initially reset bitmask to 0x00000000
3194 	// the set whether or not to keep drawing a given octant.
3195 	// For example: 0x00111100 means we're drawing in octants 2-5
3196 	drawoct = 0;
3197 
3198 	/*
3199 	* Fixup angles
3200 	*/
3201 	start %= 360;
3202 	end %= 360;
3203 	// 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
3204 	while (start < 0) start += 360;
3205 	while (end < 0) end += 360;
3206 	start %= 360;
3207 	end %= 360;
3208 
3209 	// now, we find which octants we're drawing in.
3210 	startoct = start / 45;
3211 	endoct = end / 45;
3212 	oct = startoct - 1; // we increment as first step in loop
3213 
3214 	// stopval_start, stopval_end;
3215 	// what values of cx to stop at.
3216 	do {
3217 		oct = (oct + 1) % 8;
3218 
3219 		if (oct == startoct) {
3220 			// need to compute stopval_start for this octant.  Look at picture above if this is unclear
3221 			dstart = (double)start;
3222 			switch (oct)
3223 			{
3224 			case 0:
3225 			case 3:
3226 				temp = sin(dstart * M_PI / 180.);
3227 				break;
3228 			case 1:
3229 			case 6:
3230 				temp = cos(dstart * M_PI / 180.);
3231 				break;
3232 			case 2:
3233 			case 5:
3234 				temp = -cos(dstart * M_PI / 180.);
3235 				break;
3236 			case 4:
3237 			case 7:
3238 				temp = -sin(dstart * M_PI / 180.);
3239 				break;
3240 			}
3241 			temp *= rad;
3242 			stopval_start = (int)temp; // always round down.
3243 			// This isn't arbitrary, but requires graph paper to explain well.
3244 			// The basic idea is that we're always changing drawoct after we draw, so we
3245 			// stop immediately after we render the last sensible pixel at x = ((int)temp).
3246 
3247 			// and whether to draw in this octant initially
3248 			if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
3249 			else		 drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
3250 		}
3251 		if (oct == endoct) {
3252 			// need to compute stopval_end for this octant
3253 			dend = (double)end;
3254 			switch (oct)
3255 			{
3256 			case 0:
3257 			case 3:
3258 				temp = sin(dend * M_PI / 180);
3259 				break;
3260 			case 1:
3261 			case 6:
3262 				temp = cos(dend * M_PI / 180);
3263 				break;
3264 			case 2:
3265 			case 5:
3266 				temp = -cos(dend * M_PI / 180);
3267 				break;
3268 			case 4:
3269 			case 7:
3270 				temp = -sin(dend * M_PI / 180);
3271 				break;
3272 			}
3273 			temp *= rad;
3274 			stopval_end = (int)temp;
3275 
3276 			// and whether to draw in this octant initially
3277 			if (startoct == endoct)	{
3278 				// note:      we start drawing, stop, then start again in this case
3279 				// otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
3280 				if (start > end) {
3281 					// unfortunately, if we're in the same octant and need to draw over the whole circle,
3282 					// we need to set the rest to true, because the while loop will end at the bottom.
3283 					drawoct = 255;
3284 				} else {
3285 					drawoct &= 255 - (1 << oct);
3286 				}
3287 			}
3288 			else if (oct % 2) drawoct &= 255 - (1 << oct);
3289 			else			  drawoct |= (1 << oct);
3290 		} else if (oct != startoct) { // already verified that it's != endoct
3291 			drawoct |= (1 << oct); // draw this entire segment
3292 		}
3293 	} while (oct != endoct);
3294 
3295 	// so now we have what octants to draw and when to draw them.  all that's left is the actual raster code.
3296 
3297 	/* Lock surface */
3298 	if (SDL_MUSTLOCK(dst)) {
3299 		if (SDL_LockSurface(dst) < 0) {
3300 			return (-1);
3301 		}
3302 	}
3303 
3304 	/*
3305 	* Draw arc
3306 	*/
3307 	result = 0;
3308 
3309 	/*
3310 	* Alpha Check
3311 	*/
3312 	if ((color & 255) == 255) {
3313 
3314 		/*
3315 		* No Alpha - direct memory writes
3316 		*/
3317 
3318 		/*
3319 		* Setup color
3320 		*/
3321 		colorptr = (Uint8 *) & color;
3322 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
3323 			color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
3324 		} else {
3325 			color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
3326 		}
3327 
3328 		/*
3329 		* Draw
3330 		*/
3331 		do {
3332 			ypcy = y + cy;
3333 			ymcy = y - cy;
3334 			if (cx > 0) {
3335 				xpcx = x + cx;
3336 				xmcx = x - cx;
3337 				// always check if we're drawing a certain octant before adding a pixel to that octant.
3338 				if (drawoct & 4)  result |= fastPixelColorNolock(dst, xmcx, ypcy, color); // drawoct & 4 = 22; drawoct[2]
3339 				if (drawoct & 2)  result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
3340 				if (drawoct & 32) result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
3341 				if (drawoct & 64) result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
3342 			} else {
3343 				if (drawoct & 6)  result |= fastPixelColorNolock(dst, x, ypcy, color); // 4 + 2; drawoct[2] || drawoct[1]
3344 				if (drawoct & 96) result |= fastPixelColorNolock(dst, x, ymcy, color); // 32 + 64
3345 			}
3346 
3347 			xpcy = x + cy;
3348 			xmcy = x - cy;
3349 			if (cx > 0 && cx != cy) {
3350 				ypcx = y + cx;
3351 				ymcx = y - cx;
3352 				if (drawoct & 8)   result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
3353 				if (drawoct & 1)   result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
3354 				if (drawoct & 16)  result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
3355 				if (drawoct & 128) result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
3356 			} else if (cx == 0) {
3357 				if (drawoct & 24)  result |= fastPixelColorNolock(dst, xmcy, y, color); // 8 + 16
3358 				if (drawoct & 129) result |= fastPixelColorNolock(dst, xpcy, y, color); // 1 + 128
3359 			}
3360 
3361 			/*
3362 			* Update whether we're drawing an octant
3363 			*/
3364 			if (stopval_start == cx) {
3365 				// works like an on-off switch because start & end may be in the same octant.
3366 				if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
3367 				else drawoct |= (1 << startoct);
3368 			}
3369 			if (stopval_end == cx) {
3370 				if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
3371 				else drawoct |= (1 << endoct);
3372 			}
3373 
3374 			/*
3375 			* Update pixels
3376 			*/
3377 			if (df < 0) {
3378 				df += d_e;
3379 				d_e += 2;
3380 				d_se += 2;
3381 			} else {
3382 				df += d_se;
3383 				d_e += 2;
3384 				d_se += 4;
3385 				cy--;
3386 			}
3387 			cx++;
3388 		} while (cx <= cy);
3389 
3390 		/*
3391 		* Unlock surface
3392 		*/
3393 		SDL_UnlockSurface(dst);
3394 
3395 	} else {
3396 
3397 		/*
3398 		* Using Alpha - blended pixel blits
3399 		*/
3400 
3401 		do {
3402 			ypcy = y + cy;
3403 			ymcy = y - cy;
3404 			if (cx > 0) {
3405 				xpcx = x + cx;
3406 				xmcx = x - cx;
3407 
3408 				// always check if we're drawing a certain octant before adding a pixel to that octant.
3409 				if (drawoct & 4)  result |= pixelColorNolock(dst, xmcx, ypcy, color);
3410 				if (drawoct & 2)  result |= pixelColorNolock(dst, xpcx, ypcy, color);
3411 				if (drawoct & 32) result |= pixelColorNolock(dst, xmcx, ymcy, color);
3412 				if (drawoct & 64) result |= pixelColorNolock(dst, xpcx, ymcy, color);
3413 			} else {
3414 				if (drawoct & 96) result |= pixelColorNolock(dst, x, ymcy, color);
3415 				if (drawoct & 6)  result |= pixelColorNolock(dst, x, ypcy, color);
3416 			}
3417 
3418 			xpcy = x + cy;
3419 			xmcy = x - cy;
3420 			if (cx > 0 && cx != cy) {
3421 				ypcx = y + cx;
3422 				ymcx = y - cx;
3423 				if (drawoct & 8)   result |= pixelColorNolock(dst, xmcy, ypcx, color);
3424 				if (drawoct & 1)   result |= pixelColorNolock(dst, xpcy, ypcx, color);
3425 				if (drawoct & 16)  result |= pixelColorNolock(dst, xmcy, ymcx, color);
3426 				if (drawoct & 128) result |= pixelColorNolock(dst, xpcy, ymcx, color);
3427 			} else if (cx == 0) {
3428 				if (drawoct & 24)  result |= pixelColorNolock(dst, xmcy, y, color);
3429 				if (drawoct & 129) result |= pixelColorNolock(dst, xpcy, y, color);
3430 			}
3431 
3432 			/*
3433 			* Update whether we're drawing an octant
3434 			*/
3435 			if (stopval_start == cx) {
3436 				// works like an on-off switch.
3437 				// This is just in case start & end are in the same octant.
3438 				if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
3439 				else						   drawoct |= (1 << startoct);
3440 			}
3441 			if (stopval_end == cx) {
3442 				if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
3443 				else						 drawoct |= (1 << endoct);
3444 			}
3445 
3446 			/*
3447 			* Update pixels
3448 			*/
3449 			if (df < 0) {
3450 				df += d_e;
3451 				d_e += 2;
3452 				d_se += 2;
3453 			} else {
3454 				df += d_se;
3455 				d_e += 2;
3456 				d_se += 4;
3457 				cy--;
3458 			}
3459 			cx++;
3460 		} while (cx <= cy);
3461 
3462 	}				/* Alpha check */
3463 
3464 	/* Unlock surface */
3465 	if (SDL_MUSTLOCK(dst)) {
3466 		SDL_UnlockSurface(dst);
3467 	}
3468 
3469 	return (result);
3470 }
3471 
3472 /*!
3473 \brief Arc with blending.
3474 
3475 \param dst The surface to draw on.
3476 \param x X coordinate of the center of the arc.
3477 \param y Y coordinate of the center of the arc.
3478 \param rad Radius in pixels of the arc.
3479 \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3480 \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3481 \param r The red value of the arc to draw.
3482 \param g The green value of the arc to draw.
3483 \param b The blue value of the arc to draw.
3484 \param a The alpha value of the arc to draw.
3485 
3486 \returns Returns 0 on success, -1 on failure.
3487 */
arcRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3488 int arcRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3489 {
3490 	/*
3491 	* Draw
3492 	*/
3493 	return (arcColor(dst, x, y, rad, start, end, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3494 }
3495 
3496 /* ----- AA Circle */
3497 
3498 
3499 /*!
3500 \brief Draw anti-aliased circle with blending.
3501 
3502 Note: The AA-circle routine is based on AA-ellipse with identical radii.
3503 
3504 \param dst The surface to draw on.
3505 \param x X coordinate of the center of the aa-circle.
3506 \param y Y coordinate of the center of the aa-circle.
3507 \param rad Radius in pixels of the aa-circle.
3508 \param color The color value of the aa-circle to draw (0xRRGGBBAA).
3509 
3510 \returns Returns 0 on success, -1 on failure.
3511 */
aacircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)3512 int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
3513 {
3514 	return (aaellipseColor(dst, x, y, rad, rad, color));
3515 }
3516 
3517 /*!
3518 \brief Draw anti-aliased circle with blending.
3519 
3520 \param dst The surface to draw on.
3521 \param x X coordinate of the center of the aa-circle.
3522 \param y Y coordinate of the center of the aa-circle.
3523 \param rad Radius in pixels of the aa-circle.
3524 \param r The red value of the aa-circle to draw.
3525 \param g The green value of the aa-circle to draw.
3526 \param b The blue value of the aa-circle to draw.
3527 \param a The alpha value of the aa-circle to draw.
3528 
3529 \returns Returns 0 on success, -1 on failure.
3530 */
aacircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3531 int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3532 {
3533 	/*
3534 	* Draw
3535 	*/
3536 	return (aaellipseColor
3537 		(dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3538 }
3539 
3540 /* ----- Filled Circle */
3541 
3542 /*!
3543 \brief Draw filled circle with blending.
3544 
3545 Note: Based on algorithms from sge library with modifications by A. Schiffler for
3546 multiple-hline draw removal and other minor speedup changes.
3547 
3548 \param dst The surface to draw on.
3549 \param x X coordinate of the center of the filled circle.
3550 \param y Y coordinate of the center of the filled circle.
3551 \param rad Radius in pixels of the filled circle.
3552 \param color The color value of the filled circle to draw (0xRRGGBBAA).
3553 
3554 \returns Returns 0 on success, -1 on failure.
3555 */
filledCircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)3556 int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
3557 {
3558 	Sint16 left, right, top, bottom;
3559 	int result;
3560 	Sint16 x1, y1, x2, y2;
3561 	Sint16 cx = 0;
3562 	Sint16 cy = rad;
3563 	Sint16 ocx = (Sint16) 0xffff;
3564 	Sint16 ocy = (Sint16) 0xffff;
3565 	Sint16 df = 1 - rad;
3566 	Sint16 d_e = 3;
3567 	Sint16 d_se = -2 * rad + 5;
3568 	Sint16 xpcx, xmcx, xpcy, xmcy;
3569 	Sint16 ypcy, ymcy, ypcx, ymcx;
3570 
3571 	/*
3572 	* Check visibility of clipping rectangle
3573 	*/
3574 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3575 		return(0);
3576 	}
3577 
3578 	/*
3579 	* Sanity check radius
3580 	*/
3581 	if (rad < 0) {
3582 		return (-1);
3583 	}
3584 
3585 	/*
3586 	* Special case for rad=0 - draw a point
3587 	*/
3588 	if (rad == 0) {
3589 		return (pixelColor(dst, x, y, color));
3590 	}
3591 
3592 	/*
3593 	* Get circle and clipping boundary and
3594 	* test if bounding box of circle is visible
3595 	*/
3596 	x2 = x + rad;
3597 	left = dst->clip_rect.x;
3598 	if (x2<left) {
3599 		return(0);
3600 	}
3601 	x1 = x - rad;
3602 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
3603 	if (x1>right) {
3604 		return(0);
3605 	}
3606 	y2 = y + rad;
3607 	top = dst->clip_rect.y;
3608 	if (y2<top) {
3609 		return(0);
3610 	}
3611 	y1 = y - rad;
3612 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3613 	if (y1>bottom) {
3614 		return(0);
3615 	}
3616 
3617 	/*
3618 	* Draw
3619 	*/
3620 	result = 0;
3621 	do {
3622 		xpcx = x + cx;
3623 		xmcx = x - cx;
3624 		xpcy = x + cy;
3625 		xmcy = x - cy;
3626 		if (ocy != cy) {
3627 			if (cy > 0) {
3628 				ypcy = y + cy;
3629 				ymcy = y - cy;
3630 				result |= hlineColor(dst, xmcx, xpcx, ypcy, color);
3631 				result |= hlineColor(dst, xmcx, xpcx, ymcy, color);
3632 			} else {
3633 				result |= hlineColor(dst, xmcx, xpcx, y, color);
3634 			}
3635 			ocy = cy;
3636 		}
3637 		if (ocx != cx) {
3638 			if (cx != cy) {
3639 				if (cx > 0) {
3640 					ypcx = y + cx;
3641 					ymcx = y - cx;
3642 					result |= hlineColor(dst, xmcy, xpcy, ymcx, color);
3643 					result |= hlineColor(dst, xmcy, xpcy, ypcx, color);
3644 				} else {
3645 					result |= hlineColor(dst, xmcy, xpcy, y, color);
3646 				}
3647 			}
3648 			ocx = cx;
3649 		}
3650 		/*
3651 		* Update
3652 		*/
3653 		if (df < 0) {
3654 			df += d_e;
3655 			d_e += 2;
3656 			d_se += 2;
3657 		} else {
3658 			df += d_se;
3659 			d_e += 2;
3660 			d_se += 4;
3661 			cy--;
3662 		}
3663 		cx++;
3664 	} while (cx <= cy);
3665 
3666 	return (result);
3667 }
3668 
3669 /*!
3670 \brief Draw filled circle with blending.
3671 
3672 \param dst The surface to draw on.
3673 \param x X coordinate of the center of the filled circle.
3674 \param y Y coordinate of the center of the filled circle.
3675 \param rad Radius in pixels of the filled circle.
3676 \param r The red value of the filled circle to draw.
3677 \param g The green value of the filled circle to draw.
3678 \param b The blue value of the filled circle to draw.
3679 \param a The alpha value of the filled circle to draw.
3680 
3681 \returns Returns 0 on success, -1 on failure.
3682 */
filledCircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3683 int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3684 {
3685 	/*
3686 	* Draw
3687 	*/
3688 	return (filledCircleColor
3689 		(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3690 }
3691 
3692 /* ----- Ellipse */
3693 
3694 /*!
3695 \brief Draw ellipse with blending.
3696 
3697 Note: Based on algorithms from sge library with modifications by A. Schiffler for
3698 multiple-pixel draw removal and other minor speedup changes.
3699 
3700 \param dst The surface to draw on.
3701 \param x X coordinate of the center of the ellipse.
3702 \param y Y coordinate of the center of the ellipse.
3703 \param rx Horizontal radius in pixels of the ellipse.
3704 \param ry Vertical radius in pixels of the ellipse.
3705 \param color The color value of the ellipse to draw (0xRRGGBBAA).
3706 
3707 \returns Returns 0 on success, -1 on failure.
3708 */
ellipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)3709 int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
3710 {
3711 	Sint16 left, right, top, bottom;
3712 	int result;
3713 	Sint16 x1, y1, x2, y2;
3714 	int ix, iy;
3715 	int h, i, j, k;
3716 	int oh, oi, oj, ok;
3717 	int xmh, xph, ypk, ymk;
3718 	int xmi, xpi, ymj, ypj;
3719 	int xmj, xpj, ymi, ypi;
3720 	int xmk, xpk, ymh, yph;
3721 	Uint8 *colorptr;
3722 
3723 	/*
3724 	* Check visibility of clipping rectangle
3725 	*/
3726 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3727 		return(0);
3728 	}
3729 
3730 	/*
3731 	* Sanity check radii
3732 	*/
3733 	if ((rx < 0) || (ry < 0)) {
3734 		return (-1);
3735 	}
3736 
3737 	/*
3738 	* Special case for rx=0 - draw a vline
3739 	*/
3740 	if (rx == 0) {
3741 		return (vlineColor(dst, x, y - ry, y + ry, color));
3742 	}
3743 	/*
3744 	* Special case for ry=0 - draw a hline
3745 	*/
3746 	if (ry == 0) {
3747 		return (hlineColor(dst, x - rx, x + rx, y, color));
3748 	}
3749 
3750 	/*
3751 	* Get circle and clipping boundary and
3752 	* test if bounding box of circle is visible
3753 	*/
3754 	x2 = x + rx;
3755 	left = dst->clip_rect.x;
3756 	if (x2<left) {
3757 		return(0);
3758 	}
3759 	x1 = x - rx;
3760 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
3761 	if (x1>right) {
3762 		return(0);
3763 	}
3764 	y2 = y + ry;
3765 	top = dst->clip_rect.y;
3766 	if (y2<top) {
3767 		return(0);
3768 	}
3769 	y1 = y - ry;
3770 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3771 	if (y1>bottom) {
3772 		return(0);
3773 	}
3774 
3775 	/*
3776 	* Init vars
3777 	*/
3778 	oh = oi = oj = ok = 0xFFFF;
3779 
3780 	/*
3781 	* Draw
3782 	*/
3783 	result = 0;
3784 
3785 	/* Lock surface */
3786 	if (SDL_MUSTLOCK(dst)) {
3787 		if (SDL_LockSurface(dst) < 0) {
3788 			return (-1);
3789 		}
3790 	}
3791 
3792 	/*
3793 	* Check alpha
3794 	*/
3795 	if ((color & 255) == 255) {
3796 
3797 		/*
3798 		* No Alpha - direct memory writes
3799 		*/
3800 
3801 		/*
3802 		* Setup color
3803 		*/
3804 		colorptr = (Uint8 *) & color;
3805 		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
3806 			color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
3807 		} else {
3808 			color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
3809 		}
3810 
3811 
3812 		if (rx > ry) {
3813 			ix = 0;
3814 			iy = rx * 64;
3815 
3816 			do {
3817 				h = (ix + 32) >> 6;
3818 				i = (iy + 32) >> 6;
3819 				j = (h * ry) / rx;
3820 				k = (i * ry) / rx;
3821 
3822 				if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
3823 					xph = x + h;
3824 					xmh = x - h;
3825 					if (k > 0) {
3826 						ypk = y + k;
3827 						ymk = y - k;
3828 						result |= fastPixelColorNolock(dst, xmh, ypk, color);
3829 						result |= fastPixelColorNolock(dst, xph, ypk, color);
3830 						result |= fastPixelColorNolock(dst, xmh, ymk, color);
3831 						result |= fastPixelColorNolock(dst, xph, ymk, color);
3832 					} else {
3833 						result |= fastPixelColorNolock(dst, xmh, y, color);
3834 						result |= fastPixelColorNolock(dst, xph, y, color);
3835 					}
3836 					ok = k;
3837 					xpi = x + i;
3838 					xmi = x - i;
3839 					if (j > 0) {
3840 						ypj = y + j;
3841 						ymj = y - j;
3842 						result |= fastPixelColorNolock(dst, xmi, ypj, color);
3843 						result |= fastPixelColorNolock(dst, xpi, ypj, color);
3844 						result |= fastPixelColorNolock(dst, xmi, ymj, color);
3845 						result |= fastPixelColorNolock(dst, xpi, ymj, color);
3846 					} else {
3847 						result |= fastPixelColorNolock(dst, xmi, y, color);
3848 						result |= fastPixelColorNolock(dst, xpi, y, color);
3849 					}
3850 					oj = j;
3851 				}
3852 
3853 				ix = ix + iy / rx;
3854 				iy = iy - ix / rx;
3855 
3856 			} while (i > h);
3857 		} else {
3858 			ix = 0;
3859 			iy = ry * 64;
3860 
3861 			do {
3862 				h = (ix + 32) >> 6;
3863 				i = (iy + 32) >> 6;
3864 				j = (h * rx) / ry;
3865 				k = (i * rx) / ry;
3866 
3867 				if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3868 					xmj = x - j;
3869 					xpj = x + j;
3870 					if (i > 0) {
3871 						ypi = y + i;
3872 						ymi = y - i;
3873 						result |= fastPixelColorNolock(dst, xmj, ypi, color);
3874 						result |= fastPixelColorNolock(dst, xpj, ypi, color);
3875 						result |= fastPixelColorNolock(dst, xmj, ymi, color);
3876 						result |= fastPixelColorNolock(dst, xpj, ymi, color);
3877 					} else {
3878 						result |= fastPixelColorNolock(dst, xmj, y, color);
3879 						result |= fastPixelColorNolock(dst, xpj, y, color);
3880 					}
3881 					oi = i;
3882 					xmk = x - k;
3883 					xpk = x + k;
3884 					if (h > 0) {
3885 						yph = y + h;
3886 						ymh = y - h;
3887 						result |= fastPixelColorNolock(dst, xmk, yph, color);
3888 						result |= fastPixelColorNolock(dst, xpk, yph, color);
3889 						result |= fastPixelColorNolock(dst, xmk, ymh, color);
3890 						result |= fastPixelColorNolock(dst, xpk, ymh, color);
3891 					} else {
3892 						result |= fastPixelColorNolock(dst, xmk, y, color);
3893 						result |= fastPixelColorNolock(dst, xpk, y, color);
3894 					}
3895 					oh = h;
3896 				}
3897 
3898 				ix = ix + iy / ry;
3899 				iy = iy - ix / ry;
3900 
3901 			} while (i > h);
3902 		}
3903 
3904 	} else {
3905 
3906 		if (rx > ry) {
3907 			ix = 0;
3908 			iy = rx * 64;
3909 
3910 			do {
3911 				h = (ix + 32) >> 6;
3912 				i = (iy + 32) >> 6;
3913 				j = (h * ry) / rx;
3914 				k = (i * ry) / rx;
3915 
3916 				if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
3917 					xph = x + h;
3918 					xmh = x - h;
3919 					if (k > 0) {
3920 						ypk = y + k;
3921 						ymk = y - k;
3922 						result |= pixelColorNolock (dst, xmh, ypk, color);
3923 						result |= pixelColorNolock (dst, xph, ypk, color);
3924 						result |= pixelColorNolock (dst, xmh, ymk, color);
3925 						result |= pixelColorNolock (dst, xph, ymk, color);
3926 					} else {
3927 						result |= pixelColorNolock (dst, xmh, y, color);
3928 						result |= pixelColorNolock (dst, xph, y, color);
3929 					}
3930 					ok = k;
3931 					xpi = x + i;
3932 					xmi = x - i;
3933 					if (j > 0) {
3934 						ypj = y + j;
3935 						ymj = y - j;
3936 						result |= pixelColorNolock (dst, xmi, ypj, color);
3937 						result |= pixelColorNolock (dst, xpi, ypj, color);
3938 						result |= pixelColorNolock (dst, xmi, ymj, color);
3939 						result |= pixelColor(dst, xpi, ymj, color);
3940 					} else {
3941 						result |= pixelColorNolock (dst, xmi, y, color);
3942 						result |= pixelColorNolock (dst, xpi, y, color);
3943 					}
3944 					oj = j;
3945 				}
3946 
3947 				ix = ix + iy / rx;
3948 				iy = iy - ix / rx;
3949 
3950 			} while (i > h);
3951 		} else {
3952 			ix = 0;
3953 			iy = ry * 64;
3954 
3955 			do {
3956 				h = (ix + 32) >> 6;
3957 				i = (iy + 32) >> 6;
3958 				j = (h * rx) / ry;
3959 				k = (i * rx) / ry;
3960 
3961 				if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3962 					xmj = x - j;
3963 					xpj = x + j;
3964 					if (i > 0) {
3965 						ypi = y + i;
3966 						ymi = y - i;
3967 						result |= pixelColorNolock (dst, xmj, ypi, color);
3968 						result |= pixelColorNolock (dst, xpj, ypi, color);
3969 						result |= pixelColorNolock (dst, xmj, ymi, color);
3970 						result |= pixelColorNolock (dst, xpj, ymi, color);
3971 					} else {
3972 						result |= pixelColorNolock (dst, xmj, y, color);
3973 						result |= pixelColorNolock (dst, xpj, y, color);
3974 					}
3975 					oi = i;
3976 					xmk = x - k;
3977 					xpk = x + k;
3978 					if (h > 0) {
3979 						yph = y + h;
3980 						ymh = y - h;
3981 						result |= pixelColorNolock (dst, xmk, yph, color);
3982 						result |= pixelColorNolock (dst, xpk, yph, color);
3983 						result |= pixelColorNolock (dst, xmk, ymh, color);
3984 						result |= pixelColorNolock (dst, xpk, ymh, color);
3985 					} else {
3986 						result |= pixelColorNolock (dst, xmk, y, color);
3987 						result |= pixelColorNolock (dst, xpk, y, color);
3988 					}
3989 					oh = h;
3990 				}
3991 
3992 				ix = ix + iy / ry;
3993 				iy = iy - ix / ry;
3994 
3995 			} while (i > h);
3996 		}
3997 
3998 	}				/* Alpha check */
3999 
4000 	/* Unlock surface */
4001 	if (SDL_MUSTLOCK(dst)) {
4002 		SDL_UnlockSurface(dst);
4003 	}
4004 
4005 	return (result);
4006 }
4007 
4008 /*!
4009 \brief Draw ellipse with blending.
4010 
4011 \param dst The surface to draw on.
4012 \param x X coordinate of the center of the ellipse.
4013 \param y Y coordinate of the center of the ellipse.
4014 \param rx Horizontal radius in pixels of the ellipse.
4015 \param ry Vertical radius in pixels of the ellipse.
4016 \param r The red value of the ellipse to draw.
4017 \param g The green value of the ellipse to draw.
4018 \param b The blue value of the ellipse to draw.
4019 \param a The alpha value of the ellipse to draw.
4020 
4021 \returns Returns 0 on success, -1 on failure.
4022 */
ellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4023 int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4024 {
4025 	/*
4026 	* Draw
4027 	*/
4028 	return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4029 }
4030 
4031 /* ----- AA Ellipse */
4032 
4033 /* Windows targets do not have lrint, so provide a local inline version */
4034 #if defined(_MSC_VER)
4035 /* Detect 64bit and use intrinsic version */
4036 #ifdef _M_X64
4037 #include <emmintrin.h>
4038 static __inline long
lrint(float f)4039 	lrint(float f)
4040 {
4041 	return _mm_cvtss_si32(_mm_load_ss(&f));
4042 }
4043 #elif defined(_M_IX86)
4044 __inline long int
lrint(double flt)4045 	lrint (double flt)
4046 {
4047 	int intgr;
4048 	_asm
4049 	{
4050 		fld flt
4051 			fistp intgr
4052 	};
4053 	return intgr;
4054 }
4055 #elif defined(_M_ARM)
4056 #include <armintr.h>
4057 #pragma warning(push)
4058 #pragma warning(disable: 4716)
4059 __declspec(naked) long int
lrint(double flt)4060 	lrint (double flt)
4061 {
4062 	__emit(0xEC410B10); // fmdrr  d0, r0, r1
4063 	__emit(0xEEBD0B40); // ftosid s0, d0
4064 	__emit(0xEE100A10); // fmrs   r0, s0
4065 	__emit(0xE12FFF1E); // bx     lr
4066 }
4067 #pragma warning(pop)
4068 #else
4069 #error lrint needed for MSVC on non X86/AMD64/ARM targets.
4070 #endif
4071 #endif
4072 
4073 /*!
4074 \brief Draw anti-aliased ellipse with blending.
4075 
4076 Note: Based on code from Anders Lindstroem, which is based on code from sge library,
4077 which is based on code from TwinLib.
4078 
4079 \param dst The surface to draw on.
4080 \param x X coordinate of the center of the aa-ellipse.
4081 \param y Y coordinate of the center of the aa-ellipse.
4082 \param rx Horizontal radius in pixels of the aa-ellipse.
4083 \param ry Vertical radius in pixels of the aa-ellipse.
4084 \param color The color value of the aa-ellipse to draw (0xRRGGBBAA).
4085 
4086 \returns Returns 0 on success, -1 on failure.
4087 */
aaellipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)4088 int aaellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
4089 {
4090 	Sint16 left, right, top, bottom;
4091 	Sint16 x1,y1,x2,y2;
4092 	int i;
4093 	int a2, b2, ds, dt, dxt, t, s, d;
4094 	Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2;
4095 	float cp;
4096 	double sab;
4097 	Uint8 weight, iweight;
4098 	int result;
4099 
4100 	/*
4101 	* Check visibility of clipping rectangle
4102 	*/
4103 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4104 		return(0);
4105 	}
4106 
4107 	/*
4108 	* Sanity check radii
4109 	*/
4110 	if ((rx < 0) || (ry < 0)) {
4111 		return (-1);
4112 	}
4113 
4114 	/*
4115 	* Special case for rx=0 - draw a vline
4116 	*/
4117 	if (rx == 0) {
4118 		return (vlineColor(dst, x, y - ry, y + ry, color));
4119 	}
4120 	/*
4121 	* Special case for ry=0 - draw an hline
4122 	*/
4123 	if (ry == 0) {
4124 		return (hlineColor(dst, x - rx, x + rx, y, color));
4125 	}
4126 
4127 	/*
4128 	* Get circle and clipping boundary and
4129 	* test if bounding box of circle is visible
4130 	*/
4131 	x2 = x + rx;
4132 	left = dst->clip_rect.x;
4133 	if (x2<left) {
4134 		return(0);
4135 	}
4136 	x1 = x - rx;
4137 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
4138 	if (x1>right) {
4139 		return(0);
4140 	}
4141 	y2 = y + ry;
4142 	top = dst->clip_rect.y;
4143 	if (y2<top) {
4144 		return(0);
4145 	}
4146 	y1 = y - ry;
4147 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4148 	if (y1>bottom) {
4149 		return(0);
4150 	}
4151 
4152 	/* Variable setup */
4153 	a2 = rx * rx;
4154 	b2 = ry * ry;
4155 
4156 	ds = 2 * a2;
4157 	dt = 2 * b2;
4158 
4159 	xc2 = 2 * x;
4160 	yc2 = 2 * y;
4161 
4162 	sab = sqrt((double)(a2 + b2));
4163 	od = (Sint16)lrint(sab*0.01) + 1; /* introduce some overdraw */
4164 	dxt = (Sint16)lrint((double)a2 / sab) + od;
4165 
4166 	t = 0;
4167 	s = -2 * a2 * ry;
4168 	d = 0;
4169 
4170 	xp = x;
4171 	yp = y - ry;
4172 
4173 	/* Lock surface */
4174 	if (SDL_MUSTLOCK(dst)) {
4175 		if (SDL_LockSurface(dst) < 0) {
4176 			return (-1);
4177 		}
4178 	}
4179 
4180 	/* Draw */
4181 	result = 0;
4182 
4183 	/* "End points" */
4184 	result |= pixelColorNolock(dst, xp, yp, color);
4185 	result |= pixelColorNolock(dst, xc2 - xp, yp, color);
4186 	result |= pixelColorNolock(dst, xp, yc2 - yp, color);
4187 	result |= pixelColorNolock(dst, xc2 - xp, yc2 - yp, color);
4188 
4189 	for (i = 1; i <= dxt; i++) {
4190 		xp--;
4191 		d += t - b2;
4192 
4193 		if (d >= 0)
4194 			ys = yp - 1;
4195 		else if ((d - s - a2) > 0) {
4196 			if ((2 * d - s - a2) >= 0)
4197 				ys = yp + 1;
4198 			else {
4199 				ys = yp;
4200 				yp++;
4201 				d -= s + a2;
4202 				s += ds;
4203 			}
4204 		} else {
4205 			yp++;
4206 			ys = yp + 1;
4207 			d -= s + a2;
4208 			s += ds;
4209 		}
4210 
4211 		t -= dt;
4212 
4213 		/* Calculate alpha */
4214 		if (s != 0) {
4215 			cp = (float) abs(d) / (float) abs(s);
4216 			if (cp > 1.0) {
4217 				cp = 1.0;
4218 			}
4219 		} else {
4220 			cp = 1.0;
4221 		}
4222 
4223 		/* Calculate weights */
4224 		weight = (Uint8) (cp * 255);
4225 		iweight = 255 - weight;
4226 
4227 		/* Upper half */
4228 		xx = xc2 - xp;
4229 		result |= pixelColorWeightNolock(dst, xp, yp, color, iweight);
4230 		result |= pixelColorWeightNolock(dst, xx, yp, color, iweight);
4231 
4232 		result |= pixelColorWeightNolock(dst, xp, ys, color, weight);
4233 		result |= pixelColorWeightNolock(dst, xx, ys, color, weight);
4234 
4235 		/* Lower half */
4236 		yy = yc2 - yp;
4237 		result |= pixelColorWeightNolock(dst, xp, yy, color, iweight);
4238 		result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
4239 
4240 		yy = yc2 - ys;
4241 		result |= pixelColorWeightNolock(dst, xp, yy, color, weight);
4242 		result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
4243 	}
4244 
4245 	/* Replaces original approximation code dyt = abs(yp - yc); */
4246 	dyt = (Sint16)lrint((double)b2 / sab ) + od;
4247 
4248 	for (i = 1; i <= dyt; i++) {
4249 		yp++;
4250 		d -= s + a2;
4251 
4252 		if (d <= 0)
4253 			xs = xp + 1;
4254 		else if ((d + t - b2) < 0) {
4255 			if ((2 * d + t - b2) <= 0)
4256 				xs = xp - 1;
4257 			else {
4258 				xs = xp;
4259 				xp--;
4260 				d += t - b2;
4261 				t -= dt;
4262 			}
4263 		} else {
4264 			xp--;
4265 			xs = xp - 1;
4266 			d += t - b2;
4267 			t -= dt;
4268 		}
4269 
4270 		s += ds;
4271 
4272 		/* Calculate alpha */
4273 		if (t != 0) {
4274 			cp = (float) abs(d) / (float) abs(t);
4275 			if (cp > 1.0) {
4276 				cp = 1.0;
4277 			}
4278 		} else {
4279 			cp = 1.0;
4280 		}
4281 
4282 		/* Calculate weight */
4283 		weight = (Uint8) (cp * 255);
4284 		iweight = 255 - weight;
4285 
4286 		/* Left half */
4287 		xx = xc2 - xp;
4288 		yy = yc2 - yp;
4289 		result |= pixelColorWeightNolock(dst, xp, yp, color, iweight);
4290 		result |= pixelColorWeightNolock(dst, xx, yp, color, iweight);
4291 
4292 		result |= pixelColorWeightNolock(dst, xp, yy, color, iweight);
4293 		result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
4294 
4295 		/* Right half */
4296 		xx = xc2 - xs;
4297 		result |= pixelColorWeightNolock(dst, xs, yp, color, weight);
4298 		result |= pixelColorWeightNolock(dst, xx, yp, color, weight);
4299 
4300 		result |= pixelColorWeightNolock(dst, xs, yy, color, weight);
4301 		result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
4302 
4303 	}
4304 
4305 	/* Unlock surface */
4306 	if (SDL_MUSTLOCK(dst)) {
4307 		SDL_UnlockSurface(dst);
4308 	}
4309 
4310 	return (result);
4311 }
4312 
4313 /*!
4314 \brief Draw anti-aliased ellipse with blending.
4315 
4316 \param dst The surface to draw on.
4317 \param x X coordinate of the center of the aa-ellipse.
4318 \param y Y coordinate of the center of the aa-ellipse.
4319 \param rx Horizontal radius in pixels of the aa-ellipse.
4320 \param ry Vertical radius in pixels of the aa-ellipse.
4321 \param r The red value of the aa-ellipse to draw.
4322 \param g The green value of the aa-ellipse to draw.
4323 \param b The blue value of the aa-ellipse to draw.
4324 \param a The alpha value of the aa-ellipse to draw.
4325 
4326 \returns Returns 0 on success, -1 on failure.
4327 */
aaellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4328 int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4329 {
4330 	/*
4331 	* Draw
4332 	*/
4333 	return (aaellipseColor
4334 		(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4335 }
4336 
4337 /* ---- Filled Ellipse */
4338 
4339 /* Note: */
4340 /* Based on algorithm from sge library with multiple-hline draw removal */
4341 /* and other speedup changes. */
4342 
4343 /*!
4344 \brief Draw filled ellipse with blending.
4345 
4346 Note: Based on algorithm from sge library with multiple-hline draw removal
4347 and other speedup changes.
4348 
4349 \param dst The surface to draw on.
4350 \param x X coordinate of the center of the filled ellipse.
4351 \param y Y coordinate of the center of the filled ellipse.
4352 \param rx Horizontal radius in pixels of the filled ellipse.
4353 \param ry Vertical radius in pixels of the filled ellipse.
4354 \param color The color value of the filled ellipse to draw (0xRRGGBBAA).
4355 
4356 \returns Returns 0 on success, -1 on failure.
4357 */
filledEllipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)4358 int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
4359 {
4360 	Sint16 left, right, top, bottom;
4361 	int result;
4362 	Sint16 x1, y1, x2, y2;
4363 	int ix, iy;
4364 	int h, i, j, k;
4365 	int oh, oi, oj, ok;
4366 	int xmh, xph;
4367 	int xmi, xpi;
4368 	int xmj, xpj;
4369 	int xmk, xpk;
4370 
4371 	/*
4372 	* Check visibility of clipping rectangle
4373 	*/
4374 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4375 		return(0);
4376 	}
4377 
4378 	/*
4379 	* Sanity check radii
4380 	*/
4381 	if ((rx < 0) || (ry < 0)) {
4382 		return (-1);
4383 	}
4384 
4385 	/*
4386 	* Special case for rx=0 - draw a vline
4387 	*/
4388 	if (rx == 0) {
4389 		return (vlineColor(dst, x, y - ry, y + ry, color));
4390 	}
4391 	/*
4392 	* Special case for ry=0 - draw a hline
4393 	*/
4394 	if (ry == 0) {
4395 		return (hlineColor(dst, x - rx, x + rx, y, color));
4396 	}
4397 
4398 	/*
4399 	* Get circle and clipping boundary and
4400 	* test if bounding box of circle is visible
4401 	*/
4402 	x2 = x + rx;
4403 	left = dst->clip_rect.x;
4404 	if (x2<left) {
4405 		return(0);
4406 	}
4407 	x1 = x - rx;
4408 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
4409 	if (x1>right) {
4410 		return(0);
4411 	}
4412 	y2 = y + ry;
4413 	top = dst->clip_rect.y;
4414 	if (y2<top) {
4415 		return(0);
4416 	}
4417 	y1 = y - ry;
4418 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4419 	if (y1>bottom) {
4420 		return(0);
4421 	}
4422 
4423 	/*
4424 	* Init vars
4425 	*/
4426 	oh = oi = oj = ok = 0xFFFF;
4427 
4428 	/*
4429 	* Draw
4430 	*/
4431 	result = 0;
4432 	if (rx > ry) {
4433 		ix = 0;
4434 		iy = rx * 64;
4435 
4436 		do {
4437 			h = (ix + 32) >> 6;
4438 			i = (iy + 32) >> 6;
4439 			j = (h * ry) / rx;
4440 			k = (i * ry) / rx;
4441 
4442 			if ((ok != k) && (oj != k)) {
4443 				xph = x + h;
4444 				xmh = x - h;
4445 				if (k > 0) {
4446 					result |= hlineColor(dst, xmh, xph, y + k, color);
4447 					result |= hlineColor(dst, xmh, xph, y - k, color);
4448 				} else {
4449 					result |= hlineColor(dst, xmh, xph, y, color);
4450 				}
4451 				ok = k;
4452 			}
4453 			if ((oj != j) && (ok != j) && (k != j)) {
4454 				xmi = x - i;
4455 				xpi = x + i;
4456 				if (j > 0) {
4457 					result |= hlineColor(dst, xmi, xpi, y + j, color);
4458 					result |= hlineColor(dst, xmi, xpi, y - j, color);
4459 				} else {
4460 					result |= hlineColor(dst, xmi, xpi, y, color);
4461 				}
4462 				oj = j;
4463 			}
4464 
4465 			ix = ix + iy / rx;
4466 			iy = iy - ix / rx;
4467 
4468 		} while (i > h);
4469 	} else {
4470 		ix = 0;
4471 		iy = ry * 64;
4472 
4473 		do {
4474 			h = (ix + 32) >> 6;
4475 			i = (iy + 32) >> 6;
4476 			j = (h * rx) / ry;
4477 			k = (i * rx) / ry;
4478 
4479 			if ((oi != i) && (oh != i)) {
4480 				xmj = x - j;
4481 				xpj = x + j;
4482 				if (i > 0) {
4483 					result |= hlineColor(dst, xmj, xpj, y + i, color);
4484 					result |= hlineColor(dst, xmj, xpj, y - i, color);
4485 				} else {
4486 					result |= hlineColor(dst, xmj, xpj, y, color);
4487 				}
4488 				oi = i;
4489 			}
4490 			if ((oh != h) && (oi != h) && (i != h)) {
4491 				xmk = x - k;
4492 				xpk = x + k;
4493 				if (h > 0) {
4494 					result |= hlineColor(dst, xmk, xpk, y + h, color);
4495 					result |= hlineColor(dst, xmk, xpk, y - h, color);
4496 				} else {
4497 					result |= hlineColor(dst, xmk, xpk, y, color);
4498 				}
4499 				oh = h;
4500 			}
4501 
4502 			ix = ix + iy / ry;
4503 			iy = iy - ix / ry;
4504 
4505 		} while (i > h);
4506 	}
4507 
4508 	return (result);
4509 }
4510 
4511 /*!
4512 \brief Draw filled ellipse with blending.
4513 
4514 \param dst The surface to draw on.
4515 \param x X coordinate of the center of the filled ellipse.
4516 \param y Y coordinate of the center of the filled ellipse.
4517 \param rx Horizontal radius in pixels of the filled ellipse.
4518 \param ry Vertical radius in pixels of the filled ellipse.
4519 \param r The red value of the filled ellipse to draw.
4520 \param g The green value of the filled ellipse to draw.
4521 \param b The blue value of the filled ellipse to draw.
4522 \param a The alpha value of the filled ellipse to draw.
4523 
4524 \returns Returns 0 on success, -1 on failure.
4525 */
filledEllipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4526 int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4527 {
4528 	/*
4529 	* Draw
4530 	*/
4531 	return (filledEllipseColor
4532 		(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4533 }
4534 
4535 /* ----- pie */
4536 
4537 /*!
4538 \brief Internal float (low-speed) pie-calc implementation by drawing polygons.
4539 
4540 Note: Determines vertex array and uses polygon or filledPolygon drawing routines to render.
4541 
4542 \param dst The surface to draw on.
4543 \param x X coordinate of the center of the pie.
4544 \param y Y coordinate of the center of the pie.
4545 \param rad Radius in pixels of the pie.
4546 \param start Starting radius in degrees of the pie.
4547 \param end Ending radius in degrees of the pie.
4548 \param color The color value of the pie to draw (0xRRGGBBAA).
4549 \param filled Flag indicating if the pie should be filled (=1) or not (=0).
4550 
4551 \returns Returns 0 on success, -1 on failure.
4552 */
_pieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color,Uint8 filled)4553 int _pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color, Uint8 filled)
4554 {
4555 	Sint16 left, right, top, bottom;
4556 	Sint16 x1, y1, x2, y2;
4557 	int result;
4558 	double angle, start_angle, end_angle;
4559 	double deltaAngle;
4560 	double dr;
4561 	int numpoints, i;
4562 	Sint16 *vx, *vy;
4563 
4564 	/*
4565 	* Check visibility of clipping rectangle
4566 	*/
4567 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4568 		return(0);
4569 	}
4570 
4571 	/*
4572 	* Sanity check radii
4573 	*/
4574 	if (rad < 0) {
4575 		return (-1);
4576 	}
4577 
4578 	/*
4579 	* Fixup angles
4580 	*/
4581 	start = start % 360;
4582 	end = end % 360;
4583 
4584 	/*
4585 	* Special case for rad=0 - draw a point
4586 	*/
4587 	if (rad == 0) {
4588 		return (pixelColor(dst, x, y, color));
4589 	}
4590 
4591 	/*
4592 	* Clip against circle, not pie (not 100% optimal).
4593 	* Get pie's circle and clipping boundary and
4594 	* test if bounding box of circle is visible
4595 	*/
4596 	x2 = x + rad;
4597 	left = dst->clip_rect.x;
4598 	if (x2<left) {
4599 		return(0);
4600 	}
4601 	x1 = x - rad;
4602 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
4603 	if (x1>right) {
4604 		return(0);
4605 	}
4606 	y2 = y + rad;
4607 	top = dst->clip_rect.y;
4608 	if (y2<top) {
4609 		return(0);
4610 	}
4611 	y1 = y - rad;
4612 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4613 	if (y1>bottom) {
4614 		return(0);
4615 	}
4616 
4617 	/*
4618 	* Variable setup
4619 	*/
4620 	dr = (double) rad;
4621 	deltaAngle = 3.0 / dr;
4622 	start_angle = (double) start *(2.0 * M_PI / 360.0);
4623 	end_angle = (double) end *(2.0 * M_PI / 360.0);
4624 	if (start > end) {
4625 		end_angle += (2.0 * M_PI);
4626 	}
4627 
4628 	/* We will always have at least 2 points */
4629 	numpoints = 2;
4630 
4631 	/* Count points (rather than calculating it) */
4632 	angle = start_angle;
4633 	while (angle < end_angle) {
4634 		angle += deltaAngle;
4635 		numpoints++;
4636 	}
4637 
4638 	/* Allocate combined vertex array */
4639 	vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
4640 	if (vx == NULL) {
4641 		return (-1);
4642 	}
4643 
4644 	/* Update point to start of vy */
4645 	vy += numpoints;
4646 
4647 	/* Center */
4648 	vx[0] = x;
4649 	vy[0] = y;
4650 
4651 	/* First vertex */
4652 	angle = start_angle;
4653 	vx[1] = x + (int) (dr * cos(angle));
4654 	vy[1] = y + (int) (dr * sin(angle));
4655 
4656 	if (numpoints<3)
4657 	{
4658 		result = lineColor(dst, vx[0], vy[0], vx[1], vy[1], color);
4659 	}
4660 	else
4661 	{
4662 		/* Calculate other vertices */
4663 		i = 2;
4664 		angle = start_angle;
4665 		while (angle < end_angle) {
4666 			angle += deltaAngle;
4667 			if (angle>end_angle)
4668 			{
4669 				angle = end_angle;
4670 			}
4671 			vx[i] = x + (int) (dr * cos(angle));
4672 			vy[i] = y + (int) (dr * sin(angle));
4673 			i++;
4674 		}
4675 
4676 		/* Draw */
4677 		if (filled) {
4678 			result = filledPolygonColor(dst, vx, vy, numpoints, color);
4679 		} else {
4680 			result = polygonColor(dst, vx, vy, numpoints, color);
4681 		}
4682 	}
4683 
4684 	/* Free combined vertex array */
4685 	free(vx);
4686 
4687 	return (result);
4688 }
4689 
4690 /*!
4691 \brief Draw pie (outline) with alpha blending.
4692 
4693 \param dst The surface to draw on.
4694 \param x X coordinate of the center of the pie.
4695 \param y Y coordinate of the center of the pie.
4696 \param rad Radius in pixels of the pie.
4697 \param start Starting radius in degrees of the pie.
4698 \param end Ending radius in degrees of the pie.
4699 \param color The color value of the pie to draw (0xRRGGBBAA).
4700 
4701 \returns Returns 0 on success, -1 on failure.
4702 */
pieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)4703 int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
4704 	Sint16 start, Sint16 end, Uint32 color)
4705 {
4706 	return (_pieColor(dst, x, y, rad, start, end, color, 0));
4707 
4708 }
4709 
4710 /*!
4711 \brief Draw pie (outline) with alpha blending.
4712 
4713 \param dst The surface to draw on.
4714 \param x X coordinate of the center of the pie.
4715 \param y Y coordinate of the center of the pie.
4716 \param rad Radius in pixels of the pie.
4717 \param start Starting radius in degrees of the pie.
4718 \param end Ending radius in degrees of the pie.
4719 \param r The red value of the pie to draw.
4720 \param g The green value of the pie to draw.
4721 \param b The blue value of the pie to draw.
4722 \param a The alpha value of the pie to draw.
4723 
4724 \returns Returns 0 on success, -1 on failure.
4725 */
pieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4726 int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
4727 	Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4728 {
4729 	return (_pieColor(dst, x, y, rad, start, end,
4730 		((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 0));
4731 
4732 }
4733 
4734 /*!
4735 \brief Draw filled pie with alpha blending.
4736 
4737 \param dst The surface to draw on.
4738 \param x X coordinate of the center of the filled pie.
4739 \param y Y coordinate of the center of the filled pie.
4740 \param rad Radius in pixels of the filled pie.
4741 \param start Starting radius in degrees of the filled pie.
4742 \param end Ending radius in degrees of the filled pie.
4743 \param color The color value of the filled pie to draw (0xRRGGBBAA).
4744 
4745 \returns Returns 0 on success, -1 on failure.
4746 */
filledPieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)4747 int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
4748 {
4749 	return (_pieColor(dst, x, y, rad, start, end, color, 1));
4750 }
4751 
4752 /*!
4753 \brief Draw filled pie with alpha blending.
4754 
4755 \param dst The surface to draw on.
4756 \param x X coordinate of the center of the filled pie.
4757 \param y Y coordinate of the center of the filled pie.
4758 \param rad Radius in pixels of the filled pie.
4759 \param start Starting radius in degrees of the filled pie.
4760 \param end Ending radius in degrees of the filled pie.
4761 \param r The red value of the filled pie to draw.
4762 \param g The green value of the filled pie to draw.
4763 \param b The blue value of the filled pie to draw.
4764 \param a The alpha value of the filled pie to draw.
4765 
4766 \returns Returns 0 on success, -1 on failure.
4767 */
filledPieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4768 int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
4769 	Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4770 {
4771 	return (_pieColor(dst, x, y, rad, start, end,
4772 		((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
4773 }
4774 
4775 /* ------ Trigon */
4776 
4777 /*!
4778 \brief Draw trigon (triangle outline) with alpha blending.
4779 
4780 Note: Creates vertex array and uses polygon routine to render.
4781 
4782 \param dst The surface to draw on.
4783 \param x1 X coordinate of the first point of the trigon.
4784 \param y1 Y coordinate of the first point of the trigon.
4785 \param x2 X coordinate of the second point of the trigon.
4786 \param y2 Y coordinate of the second point of the trigon.
4787 \param x3 X coordinate of the third point of the trigon.
4788 \param y3 Y coordinate of the third point of the trigon.
4789 \param color The color value of the trigon to draw (0xRRGGBBAA).
4790 
4791 \returns Returns 0 on success, -1 on failure.
4792 */
trigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)4793 int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
4794 {
4795 	Sint16 vx[3];
4796 	Sint16 vy[3];
4797 
4798 	vx[0]=x1;
4799 	vx[1]=x2;
4800 	vx[2]=x3;
4801 	vy[0]=y1;
4802 	vy[1]=y2;
4803 	vy[2]=y3;
4804 
4805 	return(polygonColor(dst,vx,vy,3,color));
4806 }
4807 
4808 /*!
4809 \brief Draw trigon (triangle outline) with alpha blending.
4810 
4811 \param dst The surface to draw on.
4812 \param x1 X coordinate of the first point of the trigon.
4813 \param y1 Y coordinate of the first point of the trigon.
4814 \param x2 X coordinate of the second point of the trigon.
4815 \param y2 Y coordinate of the second point of the trigon.
4816 \param x3 X coordinate of the third point of the trigon.
4817 \param y3 Y coordinate of the third point of the trigon.
4818 \param r The red value of the trigon to draw.
4819 \param g The green value of the trigon to draw.
4820 \param b The blue value of the trigon to draw.
4821 \param a The alpha value of the trigon to draw.
4822 
4823 \returns Returns 0 on success, -1 on failure.
4824 */
trigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4825 int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
4826 	Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4827 {
4828 	Sint16 vx[3];
4829 	Sint16 vy[3];
4830 
4831 	vx[0]=x1;
4832 	vx[1]=x2;
4833 	vx[2]=x3;
4834 	vy[0]=y1;
4835 	vy[1]=y2;
4836 	vy[2]=y3;
4837 
4838 	return(polygonRGBA(dst,vx,vy,3,r,g,b,a));
4839 }
4840 
4841 /* ------ AA-Trigon */
4842 
4843 /*!
4844 \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
4845 
4846 Note: Creates vertex array and uses aapolygon routine to render.
4847 
4848 \param dst The surface to draw on.
4849 \param x1 X coordinate of the first point of the aa-trigon.
4850 \param y1 Y coordinate of the first point of the aa-trigon.
4851 \param x2 X coordinate of the second point of the aa-trigon.
4852 \param y2 Y coordinate of the second point of the aa-trigon.
4853 \param x3 X coordinate of the third point of the aa-trigon.
4854 \param y3 Y coordinate of the third point of the aa-trigon.
4855 \param color The color value of the aa-trigon to draw (0xRRGGBBAA).
4856 
4857 \returns Returns 0 on success, -1 on failure.
4858 */
aatrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)4859 int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
4860 {
4861 	Sint16 vx[3];
4862 	Sint16 vy[3];
4863 
4864 	vx[0]=x1;
4865 	vx[1]=x2;
4866 	vx[2]=x3;
4867 	vy[0]=y1;
4868 	vy[1]=y2;
4869 	vy[2]=y3;
4870 
4871 	return(aapolygonColor(dst,vx,vy,3,color));
4872 }
4873 
4874 /*!
4875 \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
4876 
4877 \param dst The surface to draw on.
4878 \param x1 X coordinate of the first point of the aa-trigon.
4879 \param y1 Y coordinate of the first point of the aa-trigon.
4880 \param x2 X coordinate of the second point of the aa-trigon.
4881 \param y2 Y coordinate of the second point of the aa-trigon.
4882 \param x3 X coordinate of the third point of the aa-trigon.
4883 \param y3 Y coordinate of the third point of the aa-trigon.
4884 \param r The red value of the aa-trigon to draw.
4885 \param g The green value of the aa-trigon to draw.
4886 \param b The blue value of the aa-trigon to draw.
4887 \param a The alpha value of the aa-trigon to draw.
4888 
4889 \returns Returns 0 on success, -1 on failure.
4890 */
aatrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4891 int aatrigonRGBA(SDL_Surface * dst,  Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
4892 	Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4893 {
4894 	Sint16 vx[3];
4895 	Sint16 vy[3];
4896 
4897 	vx[0]=x1;
4898 	vx[1]=x2;
4899 	vx[2]=x3;
4900 	vy[0]=y1;
4901 	vy[1]=y2;
4902 	vy[2]=y3;
4903 
4904 	return(aapolygonRGBA(dst,vx,vy,3,r,g,b,a));
4905 }
4906 
4907 /* ------ Filled Trigon */
4908 
4909 /*!
4910 \brief Draw filled trigon (triangle) with alpha blending.
4911 
4912 Note: Creates vertex array and uses aapolygon routine to render.
4913 
4914 \param dst The surface to draw on.
4915 \param x1 X coordinate of the first point of the filled trigon.
4916 \param y1 Y coordinate of the first point of the filled trigon.
4917 \param x2 X coordinate of the second point of the filled trigon.
4918 \param y2 Y coordinate of the second point of the filled trigon.
4919 \param x3 X coordinate of the third point of the filled trigon.
4920 \param y3 Y coordinate of the third point of the filled trigon.
4921 \param color The color value of the filled trigon to draw (0xRRGGBBAA).
4922 
4923 \returns Returns 0 on success, -1 on failure.
4924 */
filledTrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)4925 int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
4926 {
4927 	Sint16 vx[3];
4928 	Sint16 vy[3];
4929 
4930 	vx[0]=x1;
4931 	vx[1]=x2;
4932 	vx[2]=x3;
4933 	vy[0]=y1;
4934 	vy[1]=y2;
4935 	vy[2]=y3;
4936 
4937 	return(filledPolygonColor(dst,vx,vy,3,color));
4938 }
4939 
4940 /*!
4941 \brief Draw filled trigon (triangle) with alpha blending.
4942 
4943 Note: Creates vertex array and uses aapolygon routine to render.
4944 
4945 \param dst The surface to draw on.
4946 \param x1 X coordinate of the first point of the filled trigon.
4947 \param y1 Y coordinate of the first point of the filled trigon.
4948 \param x2 X coordinate of the second point of the filled trigon.
4949 \param y2 Y coordinate of the second point of the filled trigon.
4950 \param x3 X coordinate of the third point of the filled trigon.
4951 \param y3 Y coordinate of the third point of the filled trigon.
4952 \param r The red value of the filled trigon to draw.
4953 \param g The green value of the filled trigon to draw.
4954 \param b The blue value of the filled trigon to draw.
4955 \param a The alpha value of the filled trigon to draw.
4956 
4957 \returns Returns 0 on success, -1 on failure.
4958 */
filledTrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4959 int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
4960 	Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4961 {
4962 	Sint16 vx[3];
4963 	Sint16 vy[3];
4964 
4965 	vx[0]=x1;
4966 	vx[1]=x2;
4967 	vx[2]=x3;
4968 	vy[0]=y1;
4969 	vy[1]=y2;
4970 	vy[2]=y3;
4971 
4972 	return(filledPolygonRGBA(dst,vx,vy,3,r,g,b,a));
4973 }
4974 
4975 /* ---- Polygon */
4976 
4977 /*!
4978 \brief Draw polygon with alpha blending.
4979 
4980 \param dst The surface to draw on.
4981 \param vx Vertex array containing X coordinates of the points of the polygon.
4982 \param vy Vertex array containing Y coordinates of the points of the polygon.
4983 \param n Number of points in the vertex array. Minimum number is 3.
4984 \param color The color value of the polygon to draw (0xRRGGBBAA).
4985 
4986 \returns Returns 0 on success, -1 on failure.
4987 */
polygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)4988 int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
4989 {
4990 	int result;
4991 	int i;
4992 	const Sint16 *x1, *y1, *x2, *y2;
4993 
4994 	/*
4995 	* Check visibility of clipping rectangle
4996 	*/
4997 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4998 		return(0);
4999 	}
5000 
5001 	/*
5002 	* Vertex array NULL check
5003 	*/
5004 	if (vx == NULL) {
5005 		return (-1);
5006 	}
5007 	if (vy == NULL) {
5008 		return (-1);
5009 	}
5010 
5011 	/*
5012 	* Sanity check
5013 	*/
5014 	if (n < 3) {
5015 		return (-1);
5016 	}
5017 
5018 	/*
5019 	* Pointer setup
5020 	*/
5021 	x1 = x2 = vx;
5022 	y1 = y2 = vy;
5023 	x2++;
5024 	y2++;
5025 
5026 	/*
5027 	* Draw
5028 	*/
5029 	result = 0;
5030 	for (i = 1; i < n; i++) {
5031 		result |= lineColor(dst, *x1, *y1, *x2, *y2, color);
5032 		x1 = x2;
5033 		y1 = y2;
5034 		x2++;
5035 		y2++;
5036 	}
5037 	result |= lineColor(dst, *x1, *y1, *vx, *vy, color);
5038 
5039 	return (result);
5040 }
5041 
5042 /*!
5043 \brief Draw polygon with alpha blending.
5044 
5045 \param dst The surface to draw on.
5046 \param vx Vertex array containing X coordinates of the points of the polygon.
5047 \param vy Vertex array containing Y coordinates of the points of the polygon.
5048 \param n Number of points in the vertex array. Minimum number is 3.
5049 \param r The red value of the polygon to draw.
5050 \param g The green value of the polygon to draw.
5051 \param b The blue value of the polygon to draw.
5052 \param a The alpha value of the polygon to draw.
5053 
5054 \returns Returns 0 on success, -1 on failure.
5055 */
polygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)5056 int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
5057 {
5058 	/*
5059 	* Draw
5060 	*/
5061 	return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
5062 }
5063 
5064 /* ---- AA-Polygon */
5065 
5066 /*!
5067 \brief Draw anti-aliased polygon with alpha blending.
5068 
5069 \param dst The surface to draw on.
5070 \param vx Vertex array containing X coordinates of the points of the aa-polygon.
5071 \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
5072 \param n Number of points in the vertex array. Minimum number is 3.
5073 \param color The color value of the aa-polygon to draw (0xRRGGBBAA).
5074 
5075 \returns Returns 0 on success, -1 on failure.
5076 */
aapolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)5077 int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
5078 {
5079 	int result;
5080 	int i;
5081 	const Sint16 *x1, *y1, *x2, *y2;
5082 
5083 	/*
5084 	* Check visibility of clipping rectangle
5085 	*/
5086 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5087 		return(0);
5088 	}
5089 
5090 	/*
5091 	* Vertex array NULL check
5092 	*/
5093 	if (vx == NULL) {
5094 		return (-1);
5095 	}
5096 	if (vy == NULL) {
5097 		return (-1);
5098 	}
5099 
5100 	/*
5101 	* Sanity check
5102 	*/
5103 	if (n < 3) {
5104 		return (-1);
5105 	}
5106 
5107 	/*
5108 	* Pointer setup
5109 	*/
5110 	x1 = x2 = vx;
5111 	y1 = y2 = vy;
5112 	x2++;
5113 	y2++;
5114 
5115 	/*
5116 	* Draw
5117 	*/
5118 	result = 0;
5119 	for (i = 1; i < n; i++) {
5120 		result |= _aalineColor(dst, *x1, *y1, *x2, *y2, color, 0);
5121 		x1 = x2;
5122 		y1 = y2;
5123 		x2++;
5124 		y2++;
5125 	}
5126 	result |= _aalineColor(dst, *x1, *y1, *vx, *vy, color, 0);
5127 
5128 	return (result);
5129 }
5130 
5131 /*!
5132 \brief Draw anti-aliased polygon with alpha blending.
5133 
5134 \param dst The surface to draw on.
5135 \param vx Vertex array containing X coordinates of the points of the aa-polygon.
5136 \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
5137 \param n Number of points in the vertex array. Minimum number is 3.
5138 \param r The red value of the aa-polygon to draw.
5139 \param g The green value of the aa-polygon to draw.
5140 \param b The blue value of the aa-polygon to draw.
5141 \param a The alpha value of the aa-polygon to draw.
5142 
5143 \returns Returns 0 on success, -1 on failure.
5144 */
aapolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)5145 int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
5146 {
5147 	/*
5148 	* Draw
5149 	*/
5150 	return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
5151 }
5152 
5153 /* ---- Filled Polygon */
5154 
5155 /*!
5156 \brief Internal helper qsort callback functions used in filled polygon drawing.
5157 
5158 \param a The surface to draw on.
5159 \param b Vertex array containing X coordinates of the points of the polygon.
5160 
5161 \returns Returns 0 if a==b, a negative number if a<b or a positive number if a>b.
5162 */
_gfxPrimitivesCompareInt(const void * a,const void * b)5163 int _gfxPrimitivesCompareInt(const void *a, const void *b)
5164 {
5165 	return (*(const int *) a) - (*(const int *) b);
5166 }
5167 
5168 /*!
5169 \brief Global vertex array to use if optional parameters are not given in filledPolygonMT calls.
5170 
5171 Note: Used for non-multithreaded (default) operation of filledPolygonMT.
5172 */
5173 static int *gfxPrimitivesPolyIntsGlobal = NULL;
5174 
5175 /*!
5176 \brief Flag indicating if global vertex array was already allocated.
5177 
5178 Note: Used for non-multithreaded (default) operation of filledPolygonMT.
5179 */
5180 static int gfxPrimitivesPolyAllocatedGlobal = 0;
5181 
5182 /*!
5183 \brief Draw filled polygon with alpha blending (multi-threaded capable).
5184 
5185 Note: The last two parameters are optional; but are required for multithreaded operation.
5186 
5187 \param dst The surface to draw on.
5188 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5189 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5190 \param n Number of points in the vertex array. Minimum number is 3.
5191 \param color The color value of the filled polygon to draw (0xRRGGBBAA).
5192 \param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise.
5193 \param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise.
5194 
5195 \returns Returns 0 on success, -1 on failure.
5196 */
filledPolygonColorMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color,int ** polyInts,int * polyAllocated)5197 int filledPolygonColorMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color, int **polyInts, int *polyAllocated)
5198 {
5199 	int result;
5200 	int i;
5201 	int y, xa, xb;
5202 	int miny, maxy;
5203 	int x1, y1;
5204 	int x2, y2;
5205 	int ind1, ind2;
5206 	int ints;
5207 	int *gfxPrimitivesPolyInts = NULL;
5208 	int *gfxPrimitivesPolyIntsNew = NULL;
5209 	int gfxPrimitivesPolyAllocated = 0;
5210 
5211 	/*
5212 	* Check visibility of clipping rectangle
5213 	*/
5214 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5215 		return(0);
5216 	}
5217 
5218 	/*
5219 	* Vertex array NULL check
5220 	*/
5221 	if (vx == NULL) {
5222 		return (-1);
5223 	}
5224 	if (vy == NULL) {
5225 		return (-1);
5226 	}
5227 
5228 	/*
5229 	* Sanity check number of edges
5230 	*/
5231 	if (n < 3) {
5232 		return -1;
5233 	}
5234 
5235 	/*
5236 	* Map polygon cache
5237 	*/
5238 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
5239 		/* Use global cache */
5240 		gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
5241 		gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
5242 	} else {
5243 		/* Use local cache */
5244 		gfxPrimitivesPolyInts = *polyInts;
5245 		gfxPrimitivesPolyAllocated = *polyAllocated;
5246 	}
5247 
5248 	/*
5249 	* Allocate temp array, only grow array
5250 	*/
5251 	if (!gfxPrimitivesPolyAllocated) {
5252 		gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
5253 		gfxPrimitivesPolyAllocated = n;
5254 	} else {
5255 		if (gfxPrimitivesPolyAllocated < n) {
5256 			gfxPrimitivesPolyIntsNew = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
5257 			if (!gfxPrimitivesPolyIntsNew) {
5258 				if (!gfxPrimitivesPolyInts) {
5259 					free(gfxPrimitivesPolyInts);
5260 					gfxPrimitivesPolyInts = NULL;
5261 				}
5262 				gfxPrimitivesPolyAllocated = 0;
5263 			} else {
5264 				gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsNew;
5265 				gfxPrimitivesPolyAllocated = n;
5266 			}
5267 		}
5268 	}
5269 
5270 	/*
5271 	* Check temp array
5272 	*/
5273 	if (gfxPrimitivesPolyInts==NULL) {
5274 		gfxPrimitivesPolyAllocated = 0;
5275 	}
5276 
5277 	/*
5278 	* Update cache variables
5279 	*/
5280 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
5281 		gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
5282 		gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
5283 	} else {
5284 		*polyInts = gfxPrimitivesPolyInts;
5285 		*polyAllocated = gfxPrimitivesPolyAllocated;
5286 	}
5287 
5288 	/*
5289 	* Check temp array again
5290 	*/
5291 	if (gfxPrimitivesPolyInts==NULL) {
5292 		return(-1);
5293 	}
5294 
5295 	/*
5296 	* Determine Y maxima
5297 	*/
5298 	miny = vy[0];
5299 	maxy = vy[0];
5300 	for (i = 1; (i < n); i++) {
5301 		if (vy[i] < miny) {
5302 			miny = vy[i];
5303 		} else if (vy[i] > maxy) {
5304 			maxy = vy[i];
5305 		}
5306 	}
5307 
5308 	/*
5309 	* Draw, scanning y
5310 	*/
5311 	result = 0;
5312 	for (y = miny; (y <= maxy); y++) {
5313 		ints = 0;
5314 		for (i = 0; (i < n); i++) {
5315 			if (!i) {
5316 				ind1 = n - 1;
5317 				ind2 = 0;
5318 			} else {
5319 				ind1 = i - 1;
5320 				ind2 = i;
5321 			}
5322 			y1 = vy[ind1];
5323 			y2 = vy[ind2];
5324 			if (y1 < y2) {
5325 				x1 = vx[ind1];
5326 				x2 = vx[ind2];
5327 			} else if (y1 > y2) {
5328 				y2 = vy[ind1];
5329 				y1 = vy[ind2];
5330 				x2 = vx[ind1];
5331 				x1 = vx[ind2];
5332 			} else {
5333 				continue;
5334 			}
5335 			if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
5336 				gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
5337 			}
5338 		}
5339 
5340 		qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
5341 
5342 		for (i = 0; (i < ints); i += 2) {
5343 			xa = gfxPrimitivesPolyInts[i] + 1;
5344 			xa = (xa >> 16) + ((xa & 32768) >> 15);
5345 			xb = gfxPrimitivesPolyInts[i+1] - 1;
5346 			xb = (xb >> 16) + ((xb & 32768) >> 15);
5347 			result |= hlineColor(dst, xa, xb, y, color);
5348 		}
5349 	}
5350 
5351 	return (result);
5352 }
5353 
5354 /*!
5355 \brief Draw filled polygon with alpha blending (multi-threaded capable).
5356 
5357 Note: The last two parameters are optional; but are required for multithreaded operation.
5358 
5359 \param dst The surface to draw on.
5360 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5361 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5362 \param n Number of points in the vertex array. Minimum number is 3.
5363 \param r The red value of the filled polygon to draw.
5364 \param g The green value of the filled polygon to draw.
5365 \param b The blue value of the filed polygon to draw.
5366 \param a The alpha value of the filled polygon to draw.
5367 \param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise.
5368 \param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise.
5369 
5370 \returns Returns 0 on success, -1 on failure.
5371 */
filledPolygonRGBAMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a,int ** polyInts,int * polyAllocated)5372 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)
5373 {
5374 	/*
5375 	* Draw
5376 	*/
5377 	return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, polyInts, polyAllocated));
5378 }
5379 
5380 /*!
5381 \brief Draw filled polygon with alpha blending.
5382 
5383 Note: Standard filledPolygon function is calling multithreaded version with NULL parameters
5384 to use the global vertex cache.
5385 
5386 \param dst The surface to draw on.
5387 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5388 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5389 \param n Number of points in the vertex array. Minimum number is 3.
5390 \param color The color value of the filled polygon to draw (0xRRGGBBAA).
5391 
5392 \returns Returns 0 on success, -1 on failure.
5393 */
filledPolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)5394 int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
5395 {
5396 	/*
5397 	* Draw
5398 	*/
5399 	return (filledPolygonColorMT(dst, vx, vy, n, color, NULL, NULL));
5400 }
5401 
5402 /*!
5403 \brief Draw filled polygon with alpha blending.
5404 
5405 \param dst The surface to draw on.
5406 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5407 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5408 \param n Number of points in the vertex array. Minimum number is 3.
5409 \param r The red value of the filled polygon to draw.
5410 \param g The green value of the filled polygon to draw.
5411 \param b The blue value of the filed polygon to draw.
5412 \param a The alpha value of the filled polygon to draw.
5413 
5414 \returns Returns 0 on success, -1 on failure.
5415 */
filledPolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)5416 int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
5417 {
5418 	/*
5419 	* Draw
5420 	*/
5421 	return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, NULL, NULL));
5422 }
5423 
5424 /*!
5425 \brief Internal function to draw a textured horizontal line.
5426 
5427 \param dst The surface to draw on.
5428 \param x1 X coordinate of the first point (i.e. left) of the line.
5429 \param x2 X coordinate of the second point (i.e. right) of the line.
5430 \param y Y coordinate of the points of the line.
5431 \param texture The texture surface to retrieve color information from.
5432 \param texture_dx The X offset for the texture lookup.
5433 \param texture_dy The Y offset for the textured lookup.
5434 
5435 \returns Returns 0 on success, -1 on failure.
5436 */
_HLineTextured(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,SDL_Surface * texture,int texture_dx,int texture_dy)5437 int _HLineTextured(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface *texture, int texture_dx, int texture_dy)
5438 {
5439 	Sint16 left, right, top, bottom;
5440 	Sint16 w;
5441 	Sint16 xtmp;
5442 	int result = 0;
5443 	int texture_x_walker;
5444 	int texture_y_start;
5445 	SDL_Rect source_rect,dst_rect;
5446 	int pixels_written,write_width;
5447 
5448 	/*
5449 	* Check visibility of clipping rectangle
5450 	*/
5451 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5452 		return(0);
5453 	}
5454 
5455 	/*
5456 	* Swap x1, x2 if required to ensure x1<=x2
5457 	*/
5458 	if (x1 > x2) {
5459 		xtmp = x1;
5460 		x1 = x2;
5461 		x2 = xtmp;
5462 	}
5463 
5464 	/*
5465 	* Get clipping boundary and
5466 	* check visibility of hline
5467 	*/
5468 	left = dst->clip_rect.x;
5469 	if (x2<left) {
5470 		return(0);
5471 	}
5472 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
5473 	if (x1>right) {
5474 		return(0);
5475 	}
5476 	top = dst->clip_rect.y;
5477 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
5478 	if ((y<top) || (y>bottom)) {
5479 		return (0);
5480 	}
5481 
5482 	/*
5483 	* Clip x
5484 	*/
5485 	if (x1 < left) {
5486 		x1 = left;
5487 	}
5488 	if (x2 > right) {
5489 		x2 = right;
5490 	}
5491 
5492 	/*
5493 	* Calculate width to draw
5494 	*/
5495 	w = x2 - x1 + 1;
5496 
5497 	/*
5498 	* Determine where in the texture we start drawing
5499 	*/
5500 	texture_x_walker =   (x1 - texture_dx)  % texture->w;
5501 	if (texture_x_walker < 0){
5502 		texture_x_walker = texture->w + texture_x_walker ;
5503 	}
5504 
5505 	texture_y_start = (y + texture_dy) % texture->h;
5506 	if (texture_y_start < 0){
5507 		texture_y_start = texture->h + texture_y_start;
5508 	}
5509 
5510 	// setup the source rectangle; we are only drawing one horizontal line
5511 	source_rect.y = texture_y_start;
5512 	source_rect.x = texture_x_walker;
5513 	source_rect.h = 1;
5514 
5515 	// we will draw to the current y
5516 	dst_rect.y = y;
5517 
5518 	// if there are enough pixels left in the current row of the texture
5519 	// draw it all at once
5520 	if (w <= texture->w -texture_x_walker){
5521 		source_rect.w = w;
5522 		source_rect.x = texture_x_walker;
5523 		dst_rect.x= x1;
5524 		result = (SDL_BlitSurface  (texture, &source_rect , dst, &dst_rect) == 0);
5525 	} else { // we need to draw multiple times
5526 		// draw the first segment
5527 		pixels_written = texture->w  - texture_x_walker;
5528 		source_rect.w = pixels_written;
5529 		source_rect.x = texture_x_walker;
5530 		dst_rect.x= x1;
5531 		result |= (SDL_BlitSurface (texture, &source_rect , dst, &dst_rect) == 0);
5532 		write_width = texture->w;
5533 
5534 		// now draw the rest
5535 		// set the source x to 0
5536 		source_rect.x = 0;
5537 		while (pixels_written < w){
5538 			if (write_width >= w - pixels_written) {
5539 				write_width =  w - pixels_written;
5540 			}
5541 			source_rect.w = write_width;
5542 			dst_rect.x = x1 + pixels_written;
5543 			result  |= (SDL_BlitSurface  (texture,&source_rect , dst, &dst_rect) == 0);
5544 			pixels_written += write_width;
5545 		}
5546 	}
5547 
5548 	return result;
5549 }
5550 
5551 /*!
5552 \brief Draws a polygon filled with the given texture (Multi-Threading Capable).
5553 
5554 This operation use internally SDL_BlitSurface for lines of the source texture. It supports
5555 alpha drawing.
5556 
5557 To get the best performance of this operation you need to make sure the texture and the dst surface have the same format
5558 (see  http://docs.mandragor.org/files/Common_libs_documentation/SDL/SDL_Documentation_project_en/sdlblitsurface.html).
5559 The last two parameters are optional, but required for multithreaded operation. When set to NULL, uses global static temp array.
5560 
5561 \param dst the destination surface,
5562 \param vx array of x vector components
5563 \param vy array of x vector components
5564 \param n the amount of vectors in the vx and vy array
5565 \param texture the sdl surface to use to fill the polygon
5566 \param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
5567 to the left and want the texture to apear the same you need to increase the texture_dx value
5568 \param texture_dy see texture_dx
5569 \param polyInts preallocated temp array storage for vertex sorting (used for multi-threaded operation)
5570 \param polyAllocated flag indicating oif the temp array was allocated (used for multi-threaded operation)
5571 
5572 \returns Returns 0 on success, -1 on failure.
5573 */
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)5574 int texturedPolygonMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n,
5575 	SDL_Surface * texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated)
5576 {
5577 	int result;
5578 	int i;
5579 	int y, xa, xb;
5580 	int minx,maxx,miny, maxy;
5581 	int x1, y1;
5582 	int x2, y2;
5583 	int ind1, ind2;
5584 	int ints;
5585 	int *gfxPrimitivesPolyInts = NULL;
5586 	int gfxPrimitivesPolyAllocated = 0;
5587 
5588 	/*
5589 	* Check visibility of clipping rectangle
5590 	*/
5591 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5592 		return(0);
5593 	}
5594 
5595 	/*
5596 	* Sanity check number of edges
5597 	*/
5598 	if (n < 3) {
5599 		return -1;
5600 	}
5601 
5602 	/*
5603 	* Map polygon cache
5604 	*/
5605 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
5606 		/* Use global cache */
5607 		gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
5608 		gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
5609 	} else {
5610 		/* Use local cache */
5611 		gfxPrimitivesPolyInts = *polyInts;
5612 		gfxPrimitivesPolyAllocated = *polyAllocated;
5613 	}
5614 
5615 	/*
5616 	* Allocate temp array, only grow array
5617 	*/
5618 	if (!gfxPrimitivesPolyAllocated) {
5619 		gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
5620 		gfxPrimitivesPolyAllocated = n;
5621 	} else {
5622 		if (gfxPrimitivesPolyAllocated < n) {
5623 			gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
5624 			gfxPrimitivesPolyAllocated = n;
5625 		}
5626 	}
5627 
5628 	/*
5629 	* Check temp array
5630 	*/
5631 	if (gfxPrimitivesPolyInts==NULL) {
5632 		gfxPrimitivesPolyAllocated = 0;
5633 	}
5634 
5635 	/*
5636 	* Update cache variables
5637 	*/
5638 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
5639 		gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
5640 		gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
5641 	} else {
5642 		*polyInts = gfxPrimitivesPolyInts;
5643 		*polyAllocated = gfxPrimitivesPolyAllocated;
5644 	}
5645 
5646 	/*
5647 	* Check temp array again
5648 	*/
5649 	if (gfxPrimitivesPolyInts==NULL) {
5650 		return(-1);
5651 	}
5652 
5653 	/*
5654 	* Determine X,Y minima,maxima
5655 	*/
5656 	miny = vy[0];
5657 	maxy = vy[0];
5658 	minx = vx[0];
5659 	maxx = vx[0];
5660 	for (i = 1; (i < n); i++) {
5661 		if (vy[i] < miny) {
5662 			miny = vy[i];
5663 		} else if (vy[i] > maxy) {
5664 			maxy = vy[i];
5665 		}
5666 		if (vx[i] < minx) {
5667 			minx = vx[i];
5668 		} else if (vx[i] > maxx) {
5669 			maxx = vx[i];
5670 		}
5671 	}
5672 	if (maxx <0 || minx > dst->w){
5673 		return -1;
5674 	}
5675 	if (maxy <0 || miny > dst->h){
5676 		return -1;
5677 	}
5678 
5679 	/*
5680 	* Draw, scanning y
5681 	*/
5682 	result = 0;
5683 	for (y = miny; (y <= maxy); y++) {
5684 		ints = 0;
5685 		for (i = 0; (i < n); i++) {
5686 			if (!i) {
5687 				ind1 = n - 1;
5688 				ind2 = 0;
5689 			} else {
5690 				ind1 = i - 1;
5691 				ind2 = i;
5692 			}
5693 			y1 = vy[ind1];
5694 			y2 = vy[ind2];
5695 			if (y1 < y2) {
5696 				x1 = vx[ind1];
5697 				x2 = vx[ind2];
5698 			} else if (y1 > y2) {
5699 				y2 = vy[ind1];
5700 				y1 = vy[ind2];
5701 				x2 = vx[ind1];
5702 				x1 = vx[ind2];
5703 			} else {
5704 				continue;
5705 			}
5706 			if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
5707 				gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
5708 			}
5709 		}
5710 
5711 		qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
5712 
5713 		for (i = 0; (i < ints); i += 2) {
5714 			xa = gfxPrimitivesPolyInts[i] + 1;
5715 			xa = (xa >> 16) + ((xa & 32768) >> 15);
5716 			xb = gfxPrimitivesPolyInts[i+1] - 1;
5717 			xb = (xb >> 16) + ((xb & 32768) >> 15);
5718 			result |= _HLineTextured(dst, xa, xb, y, texture, texture_dx, texture_dy);
5719 		}
5720 	}
5721 
5722 	return (result);
5723 }
5724 
5725 /*!
5726 \brief Draws a polygon filled with the given texture.
5727 
5728 This standard version is calling multithreaded versions with NULL cache parameters.
5729 
5730 \param dst the destination surface,
5731 \param vx array of x vector components
5732 \param vy array of x vector components
5733 \param n the amount of vectors in the vx and vy array
5734 \param texture the sdl surface to use to fill the polygon
5735 \param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
5736 to the left and want the texture to apear the same you need to increase the texture_dx value
5737 \param texture_dy see texture_dx
5738 
5739 \returns Returns 0 on success, -1 on failure.
5740 */
texturedPolygon(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy)5741 int texturedPolygon(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
5742 {
5743 	/*
5744 	* Draw
5745 	*/
5746 	return (texturedPolygonMT(dst, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
5747 }
5748 
5749 
5750 /* ---- Character */
5751 
5752 /*!
5753 \brief Global cache for NxM pixel font surfaces created at runtime.
5754 */
5755 static SDL_Surface *gfxPrimitivesFont[256];
5756 
5757 /*!
5758 \brief Global cache of the color used for the font surfaces created at runtime.
5759 */
5760 static Uint32 gfxPrimitivesFontColor[256];
5761 
5762 /*!
5763 \brief Pointer to the current font data. Default is a 8x8 pixel internal font.
5764 */
5765 static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
5766 
5767 /*!
5768 \brief Width of the current font. Default is 8.
5769 */
5770 static Uint32 charWidth = 8;
5771 
5772 /*!
5773 \brief Height of the current font. Default is 8.
5774 */
5775 static Uint32 charHeight = 8;
5776 
5777 /*!
5778 \brief Width for rendering. Autocalculated.
5779 */
5780 static Uint32 charWidthLocal = 8;
5781 
5782 /*!
5783 \brief Height for rendering. Autocalculated.
5784 */
5785 static Uint32 charHeightLocal = 8;
5786 
5787 /*!
5788 \brief Pitch of the current font in bytes. Default is 1.
5789 */
5790 static Uint32 charPitch = 1;
5791 
5792 /*!
5793 \brief Characters 90deg clockwise rotations. Default is 0. Max is 3.
5794 */
5795 static Uint32 charRotation = 0;
5796 
5797 /*!
5798 \brief Character data size in bytes of the current font. Default is 8.
5799 */
5800 static Uint32 charSize = 8;
5801 
5802 /*!
5803 \brief Sets or resets the current global font data.
5804 
5805 The font data array is organized in follows:
5806 [fontdata] = [character 0][character 1]...[character 255] where
5807 [character n] = [byte 1 row 1][byte 2 row 1]...[byte {pitch} row 1][byte 1 row 2] ...[byte {pitch} row height] where
5808 [byte n] = [bit 0]...[bit 7] where
5809 [bit n] = [0 for transparent pixel|1 for colored pixel]
5810 
5811 \param fontdata Pointer to array of font data. Set to NULL, to reset global font to the default 8x8 font.
5812 \param cw Width of character in bytes. Ignored if fontdata==NULL.
5813 \param ch Height of character in bytes. Ignored if fontdata==NULL.
5814 */
gfxPrimitivesSetFont(const void * fontdata,Uint32 cw,Uint32 ch)5815 void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch)
5816 {
5817 	int i;
5818 
5819 	if ((fontdata) && (cw) && (ch)) {
5820 		currentFontdata = fontdata;
5821 		charWidth = cw;
5822 		charHeight = ch;
5823 	} else {
5824 		currentFontdata = gfxPrimitivesFontdata;
5825 		charWidth = 8;
5826 		charHeight = 8;
5827 	}
5828 
5829 	charPitch = (charWidth+7)/8;
5830 	charSize = charPitch * charHeight;
5831 
5832 	/* Maybe flip width/height for rendering */
5833 	if ((charRotation==1) || (charRotation==3))
5834 	{
5835 		charWidthLocal = charHeight;
5836 		charHeightLocal = charWidth;
5837 	}
5838 	else
5839 	{
5840 		charWidthLocal = charWidth;
5841 		charHeightLocal = charHeight;
5842 	}
5843 
5844 	/* Clear character cache */
5845 	for (i = 0; i < 256; i++) {
5846 		if (gfxPrimitivesFont[i]) {
5847 			SDL_FreeSurface(gfxPrimitivesFont[i]);
5848 			gfxPrimitivesFont[i] = NULL;
5849 		}
5850 	}
5851 }
5852 
5853 /*!
5854 \brief Sets current global font character rotation steps.
5855 
5856 Default is 0 (no rotation). 1 = 90deg clockwise. 2 = 180deg clockwise. 3 = 270deg clockwise.
5857 Changing the rotation, will reset the character cache.
5858 
5859 \param rotation Number of 90deg clockwise steps to rotate
5860 */
gfxPrimitivesSetFontRotation(Uint32 rotation)5861 void gfxPrimitivesSetFontRotation(Uint32 rotation)
5862 {
5863 	int i;
5864 
5865 	rotation = rotation & 3;
5866 	if (charRotation != rotation)
5867 	{
5868 		/* Store rotation */
5869 		charRotation = rotation;
5870 
5871 		/* Maybe flip width/height for rendering */
5872 		if ((charRotation==1) || (charRotation==3))
5873 		{
5874 			charWidthLocal = charHeight;
5875 			charHeightLocal = charWidth;
5876 		}
5877 		else
5878 		{
5879 			charWidthLocal = charWidth;
5880 			charHeightLocal = charHeight;
5881 		}
5882 
5883 		/* Clear character cache */
5884 		for (i = 0; i < 256; i++) {
5885 			if (gfxPrimitivesFont[i]) {
5886 				SDL_FreeSurface(gfxPrimitivesFont[i]);
5887 				gfxPrimitivesFont[i] = NULL;
5888 			}
5889 		}
5890 	}
5891 }
5892 
5893 /*!
5894 \brief Draw a character of the currently set font.
5895 
5896 On first call for a particular character and color combination, the function needs to
5897 generate the character surface (slower. Subsequent calls blit a cached surface (fast).
5898 Uses alpha blending if A<255 in color.
5899 
5900 \param dst The surface to draw on.
5901 \param x X (horizontal) coordinate of the upper left corner of the character.
5902 \param y Y (vertical) coordinate of the upper left corner of the character.
5903 \param c The character to draw.
5904 \param color The color value of the character to draw (0xRRGGBBAA).
5905 
5906 \returns Returns 0 on success, -1 on failure.
5907 */
characterColor(SDL_Surface * dst,Sint16 x,Sint16 y,char c,Uint32 color)5908 int characterColor(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint32 color)
5909 {
5910 	Sint16 left, right, top, bottom;
5911 	Sint16 x1, y1, x2, y2;
5912 	SDL_Rect srect;
5913 	SDL_Rect drect;
5914 	int result;
5915 	Uint32 ix, iy;
5916 	const unsigned char *charpos;
5917 	Uint8 *curpos;
5918 	int forced_redraw;
5919 	Uint8 patt, mask;
5920 	Uint8 *linepos;
5921 	Uint32 pitch;
5922 	SDL_Surface *rotatedCharacter;
5923 	Uint32 ci;
5924 
5925 	/*
5926 	* Check visibility of clipping rectangle
5927 	*/
5928 	if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5929 		return(0);
5930 	}
5931 
5932 	/*
5933 	* Get text and clipping boundary and
5934 	* test if bounding box of character is visible
5935 	*/
5936 
5937 	left = dst->clip_rect.x;
5938 	x2 = x + charWidthLocal;
5939 	if (x2<left) {
5940 		return(0);
5941 	}
5942 	right = dst->clip_rect.x + dst->clip_rect.w - 1;
5943 	x1 = x;
5944 	if (x1>right) {
5945 		return(0);
5946 	}
5947 	top = dst->clip_rect.y;
5948 	y2 = y + charHeightLocal;
5949 	if (y2<top) {
5950 		return(0);
5951 	}
5952 	bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
5953 	y1 = y;
5954 	if (y1>bottom) {
5955 		return(0);
5956 	}
5957 
5958 	/*
5959 	* Setup source rectangle
5960 	*/
5961 	srect.x = 0;
5962 	srect.y = 0;
5963 	srect.w = charWidthLocal;
5964 	srect.h = charHeightLocal;
5965 
5966 	/*
5967 	* Setup destination rectangle
5968 	*/
5969 	drect.x = x;
5970 	drect.y = y;
5971 	drect.w = charWidthLocal;
5972 	drect.h = charHeightLocal;
5973 
5974 	/* Character index in cache */
5975 	ci = (unsigned char) c;
5976 
5977 	/*
5978 	* Create new charWidth x charHeight bitmap surface if not already present.
5979 	* Might get rotated later.
5980 	*/
5981 	if (gfxPrimitivesFont[ci] == NULL) {
5982 		gfxPrimitivesFont[ci] =
5983 			SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA,
5984 			charWidth, charHeight, 32,
5985 			0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
5986 		/*
5987 		* Check pointer
5988 		*/
5989 		if (gfxPrimitivesFont[ci] == NULL) {
5990 			return (-1);
5991 		}
5992 		/*
5993 		* Definitely redraw
5994 		*/
5995 		forced_redraw = 1;
5996 	} else {
5997 		forced_redraw = 0;
5998 	}
5999 
6000 	/*
6001 	* Check if color has changed
6002 	*/
6003 	if ((gfxPrimitivesFontColor[ci] != color) || (forced_redraw)) {
6004 		/*
6005 		* Redraw character
6006 		*/
6007 		SDL_SetAlpha(gfxPrimitivesFont[ci], SDL_SRCALPHA, 255);
6008 		gfxPrimitivesFontColor[ci] = color;
6009 
6010 		/* Lock font-surface */
6011 		if (SDL_LockSurface(gfxPrimitivesFont[ci]) != 0)
6012 			return (-1);
6013 
6014 		/*
6015 		* Variable setup
6016 		*/
6017 		charpos = currentFontdata + ci * charSize;
6018 		linepos = (Uint8 *) gfxPrimitivesFont[ci]->pixels;
6019 		pitch = gfxPrimitivesFont[ci]->pitch;
6020 
6021 		/*
6022 		* Drawing loop
6023 		*/
6024 		patt = 0;
6025 		for (iy = 0; iy < charHeight; iy++) {
6026 			mask = 0x00;
6027 			curpos = linepos;
6028 			for (ix = 0; ix < charWidth; ix++) {
6029 				if (!(mask >>= 1)) {
6030 					patt = *charpos++;
6031 					mask = 0x80;
6032 				}
6033 
6034 				if (patt & mask)
6035 					*(Uint32 *)curpos = color;
6036 				else
6037 					*(Uint32 *)curpos = 0;
6038 				curpos += 4;
6039 			}
6040 			linepos += pitch;
6041 		}
6042 
6043 		/* Unlock font-surface */
6044 		SDL_UnlockSurface(gfxPrimitivesFont[ci]);
6045 
6046 		/* Maybe rotate and replace cached image */
6047 		if (charRotation>0)
6048 		{
6049 			rotatedCharacter = rotateSurface90Degrees(gfxPrimitivesFont[ci], charRotation);
6050 			SDL_FreeSurface(gfxPrimitivesFont[ci]);
6051 			gfxPrimitivesFont[ci] = rotatedCharacter;
6052 		}
6053 	}
6054 
6055 	/*
6056 	* Draw bitmap onto destination surface
6057 	*/
6058 	result = SDL_BlitSurface(gfxPrimitivesFont[ci], &srect, dst, &drect);
6059 
6060 	return (result);
6061 }
6062 
6063 /*!
6064 \brief Draw a character of the currently set font.
6065 
6066 \param dst The surface to draw on.
6067 \param x X (horizontal) coordinate of the upper left corner of the character.
6068 \param y Y (vertical) coordinate of the upper left corner of the character.
6069 \param c The character to draw.
6070 \param r The red value of the character to draw.
6071 \param g The green value of the character to draw.
6072 \param b The blue value of the character to draw.
6073 \param a The alpha value of the character to draw.
6074 
6075 \returns Returns 0 on success, -1 on failure.
6076 */
characterRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,char c,Uint8 r,Uint8 g,Uint8 b,Uint8 a)6077 int characterRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
6078 {
6079 	/*
6080 	* Draw
6081 	*/
6082 	return (characterColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
6083 }
6084 
6085 /*!
6086 \brief Draw a string in the currently set font.
6087 
6088 The spacing between consequtive characters in the string is the fixed number of pixels
6089 of the character width of the current global font.
6090 
6091 \param dst The surface to draw on.
6092 \param x X (horizontal) coordinate of the upper left corner of the string.
6093 \param y Y (vertical) coordinate of the upper left corner of the string.
6094 \param s The string to draw.
6095 \param color The color value of the string to draw (0xRRGGBBAA).
6096 
6097 \returns Returns 0 on success, -1 on failure.
6098 */
stringColor(SDL_Surface * dst,Sint16 x,Sint16 y,const char * s,Uint32 color)6099 int stringColor(SDL_Surface * dst, Sint16 x, Sint16 y, const char *s, Uint32 color)
6100 {
6101 	int result = 0;
6102 	Sint16 curx = x;
6103 	Sint16 cury = y;
6104 	const char *curchar = s;
6105 
6106 	while (*curchar && !result) {
6107 		result |= characterColor(dst, curx, cury, *curchar, color);
6108 		switch (charRotation)
6109 		{
6110 		case 0:
6111 			curx += charWidthLocal;
6112 			break;
6113 		case 2:
6114 			curx -= charWidthLocal;
6115 			break;
6116 		case 1:
6117 			cury += charHeightLocal;
6118 			break;
6119 		case 3:
6120 			cury -= charHeightLocal;
6121 			break;
6122 		}
6123 		curchar++;
6124 	}
6125 
6126 	return (result);
6127 }
6128 
6129 /*!
6130 \brief Draw a string in the currently set font.
6131 
6132 \param dst The surface to draw on.
6133 \param x X (horizontal) coordinate of the upper left corner of the string.
6134 \param y Y (vertical) coordinate of the upper left corner of the string.
6135 \param s The string to draw.
6136 \param r The red value of the string to draw.
6137 \param g The green value of the string to draw.
6138 \param b The blue value of the string to draw.
6139 \param a The alpha value of the string to draw.
6140 
6141 \returns Returns 0 on success, -1 on failure.
6142 */
stringRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,const char * s,Uint8 r,Uint8 g,Uint8 b,Uint8 a)6143 int stringRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
6144 {
6145 	/*
6146 	* Draw
6147 	*/
6148 	return (stringColor(dst, x, y, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
6149 }
6150 
6151 /* ---- Bezier curve */
6152 
6153 /*!
6154 \brief Internal function to calculate bezier interpolator of data array with ndata values at position 't'.
6155 
6156 \param data Array of values.
6157 \param ndata Size of array.
6158 \param t Position for which to calculate interpolated value. t should be between [0, ndata].
6159 
6160 \returns Interpolated value at position t, value[0] when t<0, value[n-1] when t>n.
6161 */
_evaluateBezier(double * data,int ndata,double t)6162 double _evaluateBezier (double *data, int ndata, double t)
6163 {
6164 	double mu, result;
6165 	int n,k,kn,nn,nkn;
6166 	double blend,muk,munk;
6167 
6168 	/* Sanity check bounds */
6169 	if (t<0.0) {
6170 		return(data[0]);
6171 	}
6172 	if (t>=(double)ndata) {
6173 		return(data[ndata-1]);
6174 	}
6175 
6176 	/* Adjust t to the range 0.0 to 1.0 */
6177 	mu=t/(double)ndata;
6178 
6179 	/* Calculate interpolate */
6180 	n=ndata-1;
6181 	result=0.0;
6182 	muk = 1;
6183 	munk = pow(1-mu,(double)n);
6184 	for (k=0;k<=n;k++) {
6185 		nn = n;
6186 		kn = k;
6187 		nkn = n - k;
6188 		blend = muk * munk;
6189 		muk *= mu;
6190 		munk /= (1-mu);
6191 		while (nn >= 1) {
6192 			blend *= nn;
6193 			nn--;
6194 			if (kn > 1) {
6195 				blend /= (double)kn;
6196 				kn--;
6197 			}
6198 			if (nkn > 1) {
6199 				blend /= (double)nkn;
6200 				nkn--;
6201 			}
6202 		}
6203 		result += data[k] * blend;
6204 	}
6205 
6206 	return (result);
6207 }
6208 
6209 /*!
6210 \brief Draw a bezier curve with alpha blending.
6211 
6212 \param dst The surface to draw on.
6213 \param vx Vertex array containing X coordinates of the points of the bezier curve.
6214 \param vy Vertex array containing Y coordinates of the points of the bezier curve.
6215 \param n Number of points in the vertex array. Minimum number is 3.
6216 \param s Number of steps for the interpolation. Minimum number is 2.
6217 \param color The color value of the bezier curve to draw (0xRRGGBBAA).
6218 
6219 \returns Returns 0 on success, -1 on failure.
6220 */
bezierColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint32 color)6221 int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
6222 {
6223 	int result;
6224 	int i;
6225 	double *x, *y, t, stepsize;
6226 	Sint16 x1, y1, x2, y2;
6227 
6228 	/*
6229 	* Sanity check
6230 	*/
6231 	if (n < 3) {
6232 		return (-1);
6233 	}
6234 	if (s < 2) {
6235 		return (-1);
6236 	}
6237 
6238 	/*
6239 	* Variable setup
6240 	*/
6241 	stepsize=(double)1.0/(double)s;
6242 
6243 	/* Transfer vertices into float arrays */
6244 	if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
6245 		return(-1);
6246 	}
6247 	if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
6248 		free(x);
6249 		return(-1);
6250 	}
6251 	for (i=0; i<n; i++) {
6252 		x[i]=(double)vx[i];
6253 		y[i]=(double)vy[i];
6254 	}
6255 	x[n]=(double)vx[0];
6256 	y[n]=(double)vy[0];
6257 
6258 	/*
6259 	* Draw
6260 	*/
6261 	result = 0;
6262 	t=0.0;
6263 	x1=(Sint16)lrint(_evaluateBezier(x,n+1,t));
6264 	y1=(Sint16)lrint(_evaluateBezier(y,n+1,t));
6265 	for (i = 0; i <= (n*s); i++) {
6266 		t += stepsize;
6267 		x2=(Sint16)_evaluateBezier(x,n,t);
6268 		y2=(Sint16)_evaluateBezier(y,n,t);
6269 		result |= lineColor(dst, x1, y1, x2, y2, color);
6270 		x1 = x2;
6271 		y1 = y2;
6272 	}
6273 
6274 	/* Clean up temporary array */
6275 	free(x);
6276 	free(y);
6277 
6278 	return (result);
6279 }
6280 
6281 /*!
6282 \brief Draw a bezier curve with alpha blending.
6283 
6284 \param dst The surface to draw on.
6285 \param vx Vertex array containing X coordinates of the points of the bezier curve.
6286 \param vy Vertex array containing Y coordinates of the points of the bezier curve.
6287 \param n Number of points in the vertex array. Minimum number is 3.
6288 \param s Number of steps for the interpolation. Minimum number is 2.
6289 \param r The red value of the bezier curve to draw.
6290 \param g The green value of the bezier curve to draw.
6291 \param b The blue value of the bezier curve to draw.
6292 \param a The alpha value of the bezier curve to draw.
6293 
6294 \returns Returns 0 on success, -1 on failure.
6295 */
bezierRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint8 r,Uint8 g,Uint8 b,Uint8 a)6296 int bezierRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
6297 {
6298 	/*
6299 	* Draw
6300 	*/
6301 	return (bezierColor(dst, vx, vy, n, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
6302 }
6303 
6304 
6305 /*!
6306 \brief Internal function to initialize the Bresenham line iterator.
6307 
6308 Example of use:
6309 SDL_gfxBresenhamIterator b;
6310 _bresenhamInitialize (&b, x1, y1, x2, y2);
6311 do {
6312 plot(b.x, b.y);
6313 } while (_bresenhamIterate(&b)==0);
6314 
6315 \param b Pointer to struct for bresenham line drawing state.
6316 \param x1 X coordinate of the first point of the line.
6317 \param y1 Y coordinate of the first point of the line.
6318 \param x2 X coordinate of the second point of the line.
6319 \param y2 Y coordinate of the second point of the line.
6320 
6321 \returns Returns 0 on success, -1 on failure.
6322 */
_bresenhamInitialize(SDL_gfxBresenhamIterator * b,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2)6323 int _bresenhamInitialize(SDL_gfxBresenhamIterator *b, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
6324 {
6325 	int temp;
6326 
6327 	if (b==NULL) {
6328 		return(-1);
6329 	}
6330 
6331 	b->x = x1;
6332 	b->y = y1;
6333 
6334 	/* dx = abs(x2-x1), s1 = sign(x2-x1) */
6335 	if ((b->dx = x2 - x1) != 0) {
6336 		if (b->dx < 0) {
6337 			b->dx = -b->dx;
6338 			b->s1 = -1;
6339 		} else {
6340 			b->s1 = 1;
6341 		}
6342 	} else {
6343 		b->s1 = 0;
6344 	}
6345 
6346 	/* dy = abs(y2-y1), s2 = sign(y2-y1)    */
6347 	if ((b->dy = y2 - y1) != 0) {
6348 		if (b->dy < 0) {
6349 			b->dy = -b->dy;
6350 			b->s2 = -1;
6351 		} else {
6352 			b->s2 = 1;
6353 		}
6354 	} else {
6355 		b->s2 = 0;
6356 	}
6357 
6358 	if (b->dy > b->dx) {
6359 		temp = b->dx;
6360 		b->dx = b->dy;
6361 		b->dy = temp;
6362 		b->swapdir = 1;
6363 	} else {
6364 		b->swapdir = 0;
6365 	}
6366 
6367 	b->count = (b->dx<0) ? 0 : (unsigned int)b->dx;
6368 	b->dy <<= 1;
6369 	b->error = b->dy - b->dx;
6370 	b->dx <<= 1;
6371 
6372 	return(0);
6373 }
6374 
6375 
6376 /*!
6377 \brief Internal function to move Bresenham line iterator to the next position.
6378 
6379 Maybe updates the x and y coordinates of the iterator struct.
6380 
6381 \param b Pointer to struct for bresenham line drawing state.
6382 
6383 \returns Returns 0 on success, 1 if last point was reached, 2 if moving past end-of-line, -1 on failure.
6384 */
_bresenhamIterate(SDL_gfxBresenhamIterator * b)6385 int _bresenhamIterate(SDL_gfxBresenhamIterator *b)
6386 {
6387 	if (b==NULL) {
6388 		return (-1);
6389 	}
6390 
6391 	/* last point check */
6392 	if (b->count==0) {
6393 		return (2);
6394 	}
6395 
6396 	while (b->error >= 0) {
6397 		if (b->swapdir) {
6398 			b->x += b->s1;
6399 		} else  {
6400 			b->y += b->s2;
6401 		}
6402 
6403 		b->error -= b->dx;
6404 	}
6405 
6406 	if (b->swapdir) {
6407 		b->y += b->s2;
6408 	} else {
6409 		b->x += b->s1;
6410 	}
6411 
6412 	b->error += b->dy;
6413 	b->count--;
6414 
6415 	/* count==0 indicates "end-of-line" */
6416 	return ((b->count) ? 0 : 1);
6417 }
6418 
6419 
6420 /*!
6421 \brief Internal function to to draw parallel lines with Murphy algorithm.
6422 
6423 \param m Pointer to struct for murphy iterator.
6424 \param x X coordinate of point.
6425 \param y Y coordinate of point.
6426 \param d1 Direction square/diagonal.
6427 */
_murphyParaline(SDL_gfxMurphyIterator * m,Sint16 x,Sint16 y,int d1)6428 void _murphyParaline(SDL_gfxMurphyIterator *m, Sint16 x, Sint16 y, int d1)
6429 {
6430 	int p;
6431 	d1 = -d1;
6432 
6433 	/*
6434 	* Lock the surface
6435 	*/
6436 	if (SDL_MUSTLOCK(m->dst)) {
6437 		SDL_LockSurface(m->dst);
6438 	}
6439 
6440 	for (p = 0; p <= m->u; p++) {
6441 
6442 		pixelColorNolock(m->dst, x, y, m->color);
6443 
6444 		if (d1 <= m->kt) {
6445 			if (m->oct2 == 0) {
6446 				x++;
6447 			} else {
6448 				if (m->quad4 == 0) {
6449 					y++;
6450 				} else {
6451 					y--;
6452 				}
6453 			}
6454 			d1 += m->kv;
6455 		} else {
6456 			x++;
6457 			if (m->quad4 == 0) {
6458 				y++;
6459 			} else {
6460 				y--;
6461 			}
6462 			d1 += m->kd;
6463 		}
6464 	}
6465 
6466 	/* Unlock surface */
6467 	if (SDL_MUSTLOCK(m->dst)) {
6468 		SDL_UnlockSurface(m->dst);
6469 	}
6470 
6471 	m->tempx = x;
6472 	m->tempy = y;
6473 }
6474 
6475 /*!
6476 \brief Internal function to to draw one iteration of the Murphy algorithm.
6477 
6478 \param m Pointer to struct for murphy iterator.
6479 \param miter Iteration count.
6480 \param ml1bx X coordinate of a point.
6481 \param ml1by Y coordinate of a point.
6482 \param ml2bx X coordinate of a point.
6483 \param ml2by Y coordinate of a point.
6484 \param ml1x X coordinate of a point.
6485 \param ml1y Y coordinate of a point.
6486 \param ml2x X coordinate of a point.
6487 \param ml2y Y coordinate of a point.
6488 
6489 */
_murphyIteration(SDL_gfxMurphyIterator * m,Uint8 miter,Uint16 ml1bx,Uint16 ml1by,Uint16 ml2bx,Uint16 ml2by,Uint16 ml1x,Uint16 ml1y,Uint16 ml2x,Uint16 ml2y)6490 void _murphyIteration(SDL_gfxMurphyIterator *m, Uint8 miter,
6491 	Uint16 ml1bx, Uint16 ml1by, Uint16 ml2bx, Uint16 ml2by,
6492 	Uint16 ml1x, Uint16 ml1y, Uint16 ml2x, Uint16 ml2y)
6493 {
6494 	int atemp1, atemp2;
6495 	int ftmp1, ftmp2;
6496 	Uint16 m1x, m1y, m2x, m2y;
6497 	Uint16 fix, fiy, lax, lay, curx, cury;
6498 	Uint16 px[4], py[4];
6499 	SDL_gfxBresenhamIterator b;
6500 
6501 	if (miter > 1) {
6502 		if (m->first1x != -32768) {
6503 			fix = (m->first1x + m->first2x) / 2;
6504 			fiy = (m->first1y + m->first2y) / 2;
6505 			lax = (m->last1x + m->last2x) / 2;
6506 			lay = (m->last1y + m->last2y) / 2;
6507 			curx = (ml1x + ml2x) / 2;
6508 			cury = (ml1y + ml2y) / 2;
6509 
6510 			atemp1 = (fix - curx);
6511 			atemp2 = (fiy - cury);
6512 			ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
6513 			atemp1 = (lax - curx);
6514 			atemp2 = (lay - cury);
6515 			ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
6516 
6517 			if (ftmp1 <= ftmp2) {
6518 				m1x = m->first1x;
6519 				m1y = m->first1y;
6520 				m2x = m->first2x;
6521 				m2y = m->first2y;
6522 			} else {
6523 				m1x = m->last1x;
6524 				m1y = m->last1y;
6525 				m2x = m->last2x;
6526 				m2y = m->last2y;
6527 			}
6528 
6529 			atemp1 = (m2x - ml2x);
6530 			atemp2 = (m2y - ml2y);
6531 			ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
6532 			atemp1 = (m2x - ml2bx);
6533 			atemp2 = (m2y - ml2by);
6534 			ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
6535 
6536 			if (ftmp2 >= ftmp1) {
6537 				ftmp1 = ml2bx;
6538 				ftmp2 = ml2by;
6539 				ml2bx = ml2x;
6540 				ml2by = ml2y;
6541 				ml2x = ftmp1;
6542 				ml2y = ftmp2;
6543 				ftmp1 = ml1bx;
6544 				ftmp2 = ml1by;
6545 				ml1bx = ml1x;
6546 				ml1by = ml1y;
6547 				ml1x = ftmp1;
6548 				ml1y = ftmp2;
6549 			}
6550 
6551 			/*
6552 			* Lock the surface
6553 			*/
6554 			if (SDL_MUSTLOCK(m->dst)) {
6555 				SDL_LockSurface(m->dst);
6556 			}
6557 
6558 			_bresenhamInitialize(&b, m2x, m2y, m1x, m1y);
6559 			do {
6560 				pixelColorNolock(m->dst, b.x, b.y, m->color);
6561 			} while (_bresenhamIterate(&b)==0);
6562 
6563 			_bresenhamInitialize(&b, m1x, m1y, ml1bx, ml1by);
6564 			do {
6565 				pixelColorNolock(m->dst, b.x, b.y, m->color);
6566 			} while (_bresenhamIterate(&b)==0);
6567 
6568 			_bresenhamInitialize(&b, ml1bx, ml1by, ml2bx, ml2by);
6569 			do {
6570 				pixelColorNolock(m->dst, b.x, b.y, m->color);
6571 			} while (_bresenhamIterate(&b)==0);
6572 
6573 			_bresenhamInitialize(&b, ml2bx, ml2by, m2x, m2y);
6574 			do {
6575 				pixelColorNolock(m->dst, b.x, b.y, m->color);
6576 			} while (_bresenhamIterate(&b)==0);
6577 
6578 			/* Unlock surface */
6579 			if (SDL_MUSTLOCK(m->dst)) {
6580 				SDL_UnlockSurface(m->dst);
6581 			}
6582 
6583 			px[0] = m1x;
6584 			px[1] = m2x;
6585 			px[2] = ml1bx;
6586 			px[3] = ml2bx;
6587 			py[0] = m1y;
6588 			py[1] = m2y;
6589 			py[2] = ml1by;
6590 			py[3] = ml2by;
6591 			polygonColor(m->dst, px, py, 4, m->color);
6592 		}
6593 	}
6594 
6595 	m->last1x = ml1x;
6596 	m->last1y = ml1y;
6597 	m->last2x = ml2x;
6598 	m->last2y = ml2y;
6599 	m->first1x = ml1bx;
6600 	m->first1y = ml1by;
6601 	m->first2x = ml2bx;
6602 	m->first2y = ml2by;
6603 }
6604 
6605 
6606 #define HYPOT(x,y) sqrt((double)(x)*(double)(x)+(double)(y)*(double)(y))
6607 
6608 /*!
6609 \brief Internal function to to draw wide lines with Murphy algorithm.
6610 
6611 Draws lines parallel to ideal line.
6612 
6613 \param m Pointer to struct for murphy iterator.
6614 \param x1 X coordinate of first point.
6615 \param y1 Y coordinate of first point.
6616 \param x2 X coordinate of second point.
6617 \param y2 Y coordinate of second point.
6618 \param width Width of line.
6619 \param miter Iteration count.
6620 
6621 */
_murphyWideline(SDL_gfxMurphyIterator * m,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint8 miter)6622 void _murphyWideline(SDL_gfxMurphyIterator *m, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 miter)
6623 {
6624 	float offset = (float)width / 2.f;
6625 
6626 	Sint16 temp;
6627 	Sint16 ptx, pty, ptxx, ptxy, ml1x, ml1y, ml2x, ml2y, ml1bx, ml1by, ml2bx, ml2by;
6628 
6629 	int d0, d1;		/* difference terms d0=perpendicular to line, d1=along line */
6630 
6631 	int q;			/* pel counter,q=perpendicular to line */
6632 	int tmp;
6633 
6634 	int dd;			/* distance along line */
6635 	int tk;			/* thickness threshold */
6636 	double ang;		/* angle for initial point calculation */
6637 	double sang, cang;
6638 
6639 	/* Initialisation */
6640 	m->u = x2 - x1;	/* delta x */
6641 	m->v = y2 - y1;	/* delta y */
6642 
6643 	if (m->u < 0) {	/* swap to make sure we are in quadrants 1 or 4 */
6644 		temp = x1;
6645 		x1 = x2;
6646 		x2 = temp;
6647 		temp = y1;
6648 		y1 = y2;
6649 		y2 = temp;
6650 		m->u *= -1;
6651 		m->v *= -1;
6652 	}
6653 
6654 	if (m->v < 0) {	/* swap to 1st quadrant and flag */
6655 		m->v *= -1;
6656 		m->quad4 = 1;
6657 	} else {
6658 		m->quad4 = 0;
6659 	}
6660 
6661 	if (m->v > m->u) {	/* swap things if in 2 octant */
6662 		tmp = m->u;
6663 		m->u = m->v;
6664 		m->v = tmp;
6665 		m->oct2 = 1;
6666 	} else {
6667 		m->oct2 = 0;
6668 	}
6669 
6670 	m->ku = m->u + m->u;	/* change in l for square shift */
6671 	m->kv = m->v + m->v;	/* change in d for square shift */
6672 	m->kd = m->kv - m->ku;	/* change in d for diagonal shift */
6673 	m->kt = m->u - m->kv;	/* diag/square decision threshold */
6674 
6675 	d0 = 0;
6676 	d1 = 0;
6677 	dd = 0;
6678 
6679 	ang = atan((double) m->v / (double) m->u);	/* calc new initial point - offset both sides of ideal */
6680 	sang = sin(ang);
6681 	cang = cos(ang);
6682 
6683 	if (m->oct2 == 0) {
6684 		ptx = x1 + (Sint16)lrint(offset * sang);
6685 		if (m->quad4 == 0) {
6686 			pty = y1 - (Sint16)lrint(offset * cang);
6687 		} else {
6688 			pty = y1 + (Sint16)lrint(offset * cang);
6689 		}
6690 	} else {
6691 		ptx = x1 - (Sint16)lrint(offset * cang);
6692 		if (m->quad4 == 0) {
6693 			pty = y1 + (Sint16)lrint(offset * sang);
6694 		} else {
6695 			pty = y1 - (Sint16)lrint(offset * sang);
6696 		}
6697 	}
6698 
6699 	/* used here for constant thickness line */
6700 	tk = (int) (4. * HYPOT(ptx - x1, pty - y1) * HYPOT(m->u, m->v));
6701 
6702 	if (miter == 0) {
6703 		m->first1x = -32768;
6704 		m->first1y = -32768;
6705 		m->first2x = -32768;
6706 		m->first2y = -32768;
6707 		m->last1x = -32768;
6708 		m->last1y = -32768;
6709 		m->last2x = -32768;
6710 		m->last2y = -32768;
6711 	}
6712 	ptxx = ptx;
6713 	ptxy = pty;
6714 
6715 	for (q = 0; dd <= tk; q++) {	/* outer loop, stepping perpendicular to line */
6716 
6717 		_murphyParaline(m, ptx, pty, d1);	/* call to inner loop - right edge */
6718 		if (q == 0) {
6719 			ml1x = ptx;
6720 			ml1y = pty;
6721 			ml1bx = m->tempx;
6722 			ml1by = m->tempy;
6723 		} else {
6724 			ml2x = ptx;
6725 			ml2y = pty;
6726 			ml2bx = m->tempx;
6727 			ml2by = m->tempy;
6728 		}
6729 		if (d0 < m->kt) {	/* square move */
6730 			if (m->oct2 == 0) {
6731 				if (m->quad4 == 0) {
6732 					pty++;
6733 				} else {
6734 					pty--;
6735 				}
6736 			} else {
6737 				ptx++;
6738 			}
6739 		} else {	/* diagonal move */
6740 			dd += m->kv;
6741 			d0 -= m->ku;
6742 			if (d1 < m->kt) {	/* normal diagonal */
6743 				if (m->oct2 == 0) {
6744 					ptx--;
6745 					if (m->quad4 == 0) {
6746 						pty++;
6747 					} else {
6748 						pty--;
6749 					}
6750 				} else {
6751 					ptx++;
6752 					if (m->quad4 == 0) {
6753 						pty--;
6754 					} else {
6755 						pty++;
6756 					}
6757 				}
6758 				d1 += m->kv;
6759 			} else {	/* double square move, extra parallel line */
6760 				if (m->oct2 == 0) {
6761 					ptx--;
6762 				} else {
6763 					if (m->quad4 == 0) {
6764 						pty--;
6765 					} else {
6766 						pty++;
6767 					}
6768 				}
6769 				d1 += m->kd;
6770 				if (dd > tk) {
6771 					_murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
6772 					return;	/* breakout on the extra line */
6773 				}
6774 				_murphyParaline(m, ptx, pty, d1);
6775 				if (m->oct2 == 0) {
6776 					if (m->quad4 == 0) {
6777 						pty++;
6778 					} else {
6779 
6780 						pty--;
6781 					}
6782 				} else {
6783 					ptx++;
6784 				}
6785 			}
6786 		}
6787 		dd += m->ku;
6788 		d0 += m->kv;
6789 	}
6790 
6791 	_murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
6792 }
6793 
6794 
6795 /*!
6796 \brief Draw a thick line with alpha blending.
6797 
6798 \param dst The surface to draw on.
6799 \param x1 X coordinate of the first point of the line.
6800 \param y1 Y coordinate of the first point of the line.
6801 \param x2 X coordinate of the second point of the line.
6802 \param y2 Y coordinate of the second point of the line.
6803 \param width Width of the line in pixels. Must be >0.
6804 \param color The color value of the line to draw (0xRRGGBBAA).
6805 
6806 \returns Returns 0 on success, -1 on failure.
6807 */
thickLineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint32 color)6808 int thickLineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
6809 {
6810 	int wh;
6811 	SDL_gfxMurphyIterator m;
6812 
6813 	if (dst == NULL) return -1;
6814 	if (width < 1) return -1;
6815 
6816 	/* Special case: thick "point" */
6817 	if ((x1 == x2) && (y1 == y2)) {
6818 		wh = width / 2;
6819 		return boxColor(dst, x1 - wh, y1 - wh, x2 + width, y2 + width, color);
6820 	}
6821 
6822 	m.dst = dst;
6823 	m.color = color;
6824 
6825 	_murphyWideline(&m, x1, y1, x2, y2, width, 0);
6826 	_murphyWideline(&m, x1, y1, x2, y2, width, 1);
6827 
6828 	return(0);
6829 }
6830 
6831 /*!
6832 \brief Draw a thick line with alpha blending.
6833 
6834 \param dst The surface to draw on.
6835 \param x1 X coordinate of the first point of the line.
6836 \param y1 Y coordinate of the first point of the line.
6837 \param x2 X coordinate of the second point of the line.
6838 \param y2 Y coordinate of the second point of the line.
6839 \param width Width of the line in pixels. Must be >0.
6840 \param r The red value of the character to draw.
6841 \param g The green value of the character to draw.
6842 \param b The blue value of the character to draw.
6843 \param a The alpha value of the character to draw.
6844 
6845 \returns Returns 0 on success, -1 on failure.
6846 */
thickLineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint8 r,Uint8 g,Uint8 b,Uint8 a)6847 int thickLineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
6848 {
6849 	return (thickLineColor(dst, x1, y1, x2, y2, width,
6850 		((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
6851 }
6852