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