1 /*
2 
3 SDL2_gfxPrimitives.c: graphics primitives for SDL2 renderers
4 
5 Copyright (C) 2012-2014  Andreas Schiffler
6 
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any damages
9 arising from the use of this software.
10 
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it
13 freely, subject to the following restrictions:
14 
15 1. The origin of this software must not be misrepresented; you must not
16 claim that you wrote the original software. If you use this software
17 in a product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
19 
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
22 
23 3. This notice may not be removed or altered from any source
24 distribution.
25 
26 Andreas Schiffler -- aschiffler at ferzkopp dot net
27 
28 */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <string.h>
34 
35 #include "SDL2_gfxPrimitives.h"
36 #include "SDL2_rotozoom.h"
37 #include "SDL2_gfxPrimitives_font.h"
38 
39 /* ---- Structures */
40 
41 /*!
42 \brief The structure passed to the internal Bresenham iterator.
43 */
44 typedef struct {
45 	Sint16 x, y;
46 	int dx, dy, s1, s2, swapdir, error;
47 	Uint32 count;
48 } SDL2_gfxBresenhamIterator;
49 
50 /*!
51 \brief The structure passed to the internal Murphy iterator.
52 */
53 typedef struct {
54 	SDL_Renderer *renderer;
55 	int u, v;		/* delta x , delta y */
56 	int ku, kt, kv, kd;	/* loop constants */
57 	int oct2;
58 	int quad4;
59 	Sint16 last1x, last1y, last2x, last2y, first1x, first1y, first2x, first2y, tempx, tempy;
60 } SDL2_gfxMurphyIterator;
61 
62 /* ---- Pixel */
63 
64 /*!
65 \brief Draw pixel  in currently set color.
66 
67 \param renderer The renderer to draw on.
68 \param x X (horizontal) coordinate of the pixel.
69 \param y Y (vertical) coordinate of the pixel.
70 
71 \returns Returns 0 on success, -1 on failure.
72 */
pixel(SDL_Renderer * renderer,Sint16 x,Sint16 y)73 int pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
74 {
75 	return SDL_RenderDrawPoint(renderer, x, y);
76 }
77 
78 /*!
79 \brief Draw pixel with blending enabled if a<255.
80 
81 \param renderer The renderer to draw on.
82 \param x X (horizontal) coordinate of the pixel.
83 \param y Y (vertical) coordinate of the pixel.
84 \param color The color value of the pixel to draw (0xRRGGBBAA).
85 
86 \returns Returns 0 on success, -1 on failure.
87 */
pixelColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Uint32 color)88 int pixelColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint32 color)
89 {
90 	Uint8 *c = (Uint8 *)&color;
91 	return pixelRGBA(renderer, x, y, c[0], c[1], c[2], c[3]);
92 }
93 
94 /*!
95 \brief Draw pixel with blending enabled if a<255.
96 
97 \param renderer The renderer to draw on.
98 \param x X (horizontal) coordinate of the pixel.
99 \param y Y (vertical) coordinate of the pixel.
100 \param r The red color value of the pixel to draw.
101 \param g The green color value of the pixel to draw.
102 \param b The blue color value of the pixel to draw.
103 \param a The alpha value of the pixel to draw.
104 
105 \returns Returns 0 on success, -1 on failure.
106 */
pixelRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)107 int pixelRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
108 {
109 	int result = 0;
110 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
111 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
112 	result |= SDL_RenderDrawPoint(renderer, x, y);
113 	return result;
114 }
115 
116 /*!
117 \brief Draw pixel with blending enabled and using alpha weight on color.
118 
119 \param renderer The renderer to draw on.
120 \param x The horizontal coordinate of the pixel.
121 \param y The vertical position of the pixel.
122 \param r The red color value of the pixel to draw.
123 \param g The green color value of the pixel to draw.
124 \param b The blue color value of the pixel to draw.
125 \param a The alpha value of the pixel to draw.
126 \param weight The weight multiplied into the alpha value of the pixel.
127 
128 \returns Returns 0 on success, -1 on failure.
129 */
pixelRGBAWeight(SDL_Renderer * renderer,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a,Uint32 weight)130 int pixelRGBAWeight(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Uint32 weight)
131 {
132 	/*
133 	* Modify Alpha by weight
134 	*/
135 	Uint32 ax = a;
136 	ax = ((ax * weight) >> 8);
137 	if (ax > 255) {
138 		a = 255;
139 	} else {
140 		a = (Uint8)(ax & 0x000000ff);
141 	}
142 
143 	return pixelRGBA(renderer, x, y, r, g, b, a);
144 }
145 
146 /* ---- Hline */
147 
148 /*!
149 \brief Draw horizontal line in currently set color
150 
151 \param renderer The renderer to draw on.
152 \param x1 X coordinate of the first point (i.e. left) of the line.
153 \param x2 X coordinate of the second point (i.e. right) of the line.
154 \param y Y coordinate of the points of the line.
155 
156 \returns Returns 0 on success, -1 on failure.
157 */
hline(SDL_Renderer * renderer,Sint16 x1,Sint16 x2,Sint16 y)158 int hline(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y)
159 {
160 	return SDL_RenderDrawLine(renderer, x1, y, x2, y);;
161 }
162 
163 
164 /*!
165 \brief Draw horizontal line with blending.
166 
167 \param renderer The renderer to draw on.
168 \param x1 X coordinate of the first point (i.e. left) of the line.
169 \param x2 X coordinate of the second point (i.e. right) of the line.
170 \param y Y coordinate of the points of the line.
171 \param color The color value of the line to draw (0xRRGGBBAA).
172 
173 \returns Returns 0 on success, -1 on failure.
174 */
hlineColor(SDL_Renderer * renderer,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)175 int hlineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
176 {
177 	Uint8 *c = (Uint8 *)&color;
178 	return hlineRGBA(renderer, x1, x2, y, c[0], c[1], c[2], c[3]);
179 }
180 
181 /*!
182 \brief Draw horizontal line with blending.
183 
184 \param renderer The renderer to draw on.
185 \param x1 X coordinate of the first point (i.e. left) of the line.
186 \param x2 X coordinate of the second point (i.e. right) of the line.
187 \param y Y coordinate of the points of the line.
188 \param r The red value of the line to draw.
189 \param g The green value of the line to draw.
190 \param b The blue value of the line to draw.
191 \param a The alpha value of the line to draw.
192 
193 \returns Returns 0 on success, -1 on failure.
194 */
hlineRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)195 int hlineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
196 {
197 	int result = 0;
198 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
199 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
200 	result |= SDL_RenderDrawLine(renderer, x1, y, x2, y);
201 	return result;
202 }
203 
204 /* ---- Vline */
205 
206 /*!
207 \brief Draw vertical line in currently set color
208 
209 \param renderer The renderer to draw on.
210 \param x X coordinate of points of the line.
211 \param y1 Y coordinate of the first point (i.e. top) of the line.
212 \param y2 Y coordinate of the second point (i.e. bottom) of the line.
213 
214 \returns Returns 0 on success, -1 on failure.
215 */
vline(SDL_Renderer * renderer,Sint16 x,Sint16 y1,Sint16 y2)216 int vline(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2)
217 {
218 	return SDL_RenderDrawLine(renderer, x, y1, x, y2);;
219 }
220 
221 /*!
222 \brief Draw vertical line with blending.
223 
224 \param renderer The renderer to draw on.
225 \param x X coordinate of the points of the line.
226 \param y1 Y coordinate of the first point (i.e. top) of the line.
227 \param y2 Y coordinate of the second point (i.e. bottom) of the line.
228 \param color The color value of the line to draw (0xRRGGBBAA).
229 
230 \returns Returns 0 on success, -1 on failure.
231 */
vlineColor(SDL_Renderer * renderer,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)232 int vlineColor(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
233 {
234 	Uint8 *c = (Uint8 *)&color;
235 	return vlineRGBA(renderer, x, y1, y2, c[0], c[1], c[2], c[3]);
236 }
237 
238 /*!
239 \brief Draw vertical line with blending.
240 
241 \param renderer The renderer to draw on.
242 \param x X coordinate of the points of the line.
243 \param y1 Y coordinate of the first point (i.e. top) of the line.
244 \param y2 Y coordinate of the second point (i.e. bottom) of the line.
245 \param r The red value of the line to draw.
246 \param g The green value of the line to draw.
247 \param b The blue value of the line to draw.
248 \param a The alpha value of the line to draw.
249 
250 \returns Returns 0 on success, -1 on failure.
251 */
vlineRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y1,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)252 int vlineRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
253 {
254 	int result = 0;
255 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
256 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
257 	result |= SDL_RenderDrawLine(renderer, x, y1, x, y2);
258 	return result;
259 }
260 
261 /* ---- Rectangle */
262 
263 /*!
264 \brief Draw rectangle with blending.
265 
266 \param renderer The renderer to draw on.
267 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
268 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
269 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
270 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
271 \param color The color value of the rectangle to draw (0xRRGGBBAA).
272 
273 \returns Returns 0 on success, -1 on failure.
274 */
rectangleColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)275 int rectangleColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
276 {
277 	Uint8 *c = (Uint8 *)&color;
278 	return rectangleRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
279 }
280 
281 /*!
282 \brief Draw rectangle with blending.
283 
284 \param renderer The renderer to draw on.
285 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
286 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
287 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
288 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
289 \param r The red value of the rectangle to draw.
290 \param g The green value of the rectangle to draw.
291 \param b The blue value of the rectangle to draw.
292 \param a The alpha value of the rectangle to draw.
293 
294 \returns Returns 0 on success, -1 on failure.
295 */
rectangleRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)296 int rectangleRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
297 {
298 	int result;
299 	Sint16 tmp;
300 	SDL_Rect rect;
301 
302 	/*
303 	* Test for special cases of straight lines or single point
304 	*/
305 	if (x1 == x2) {
306 		if (y1 == y2) {
307 			return (pixelRGBA(renderer, x1, y1, r, g, b, a));
308 		} else {
309 			return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
310 		}
311 	} else {
312 		if (y1 == y2) {
313 			return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
314 		}
315 	}
316 
317 	/*
318 	* Swap x1, x2 if required
319 	*/
320 	if (x1 > x2) {
321 		tmp = x1;
322 		x1 = x2;
323 		x2 = tmp;
324 	}
325 
326 	/*
327 	* Swap y1, y2 if required
328 	*/
329 	if (y1 > y2) {
330 		tmp = y1;
331 		y1 = y2;
332 		y2 = tmp;
333 	}
334 
335 	/*
336 	* Create destination rect
337 	*/
338 	rect.x = x1;
339 	rect.y = y1;
340 	rect.w = x2 - x1;
341 	rect.h = y2 - y1;
342 
343 	/*
344 	* Draw
345 	*/
346 	result = 0;
347 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
348 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
349 	result |= SDL_RenderDrawRect(renderer, &rect);
350 	return result;
351 }
352 
353 /* ---- Rounded Rectangle */
354 
355 /*!
356 \brief Draw rounded-corner rectangle with blending.
357 
358 \param renderer The renderer to draw on.
359 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
360 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
361 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
362 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
363 \param rad The radius of the corner arc.
364 \param color The color value of the rectangle to draw (0xRRGGBBAA).
365 
366 \returns Returns 0 on success, -1 on failure.
367 */
roundedRectangleColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint32 color)368 int roundedRectangleColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
369 {
370 	Uint8 *c = (Uint8 *)&color;
371 	return roundedRectangleRGBA(renderer, x1, y1, x2, y2, rad, c[0], c[1], c[2], c[3]);
372 }
373 
374 /*!
375 \brief Draw rounded-corner rectangle with blending.
376 
377 \param renderer The renderer to draw on.
378 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
379 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
380 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
381 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
382 \param rad The radius of the corner arc.
383 \param r The red value of the rectangle to draw.
384 \param g The green value of the rectangle to draw.
385 \param b The blue value of the rectangle to draw.
386 \param a The alpha value of the rectangle to draw.
387 
388 \returns Returns 0 on success, -1 on failure.
389 */
roundedRectangleRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)390 int roundedRectangleRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
391 {
392 	int result = 0;
393 	Sint16 tmp;
394 	Sint16 w, h;
395 	Sint16 xx1, xx2;
396 	Sint16 yy1, yy2;
397 
398 	/*
399 	* Check renderer
400 	*/
401 	if (renderer == NULL)
402 	{
403 		return -1;
404 	}
405 
406 	/*
407 	* Check radius vor valid range
408 	*/
409 	if (rad < 0) {
410 		return -1;
411 	}
412 
413 	/*
414 	* Special case - no rounding
415 	*/
416 	if (rad <= 1) {
417 		return rectangleRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
418 	}
419 
420 	/*
421 	* Test for special cases of straight lines or single point
422 	*/
423 	if (x1 == x2) {
424 		if (y1 == y2) {
425 			return (pixelRGBA(renderer, x1, y1, r, g, b, a));
426 		} else {
427 			return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
428 		}
429 	} else {
430 		if (y1 == y2) {
431 			return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
432 		}
433 	}
434 
435 	/*
436 	* Swap x1, x2 if required
437 	*/
438 	if (x1 > x2) {
439 		tmp = x1;
440 		x1 = x2;
441 		x2 = tmp;
442 	}
443 
444 	/*
445 	* Swap y1, y2 if required
446 	*/
447 	if (y1 > y2) {
448 		tmp = y1;
449 		y1 = y2;
450 		y2 = tmp;
451 	}
452 
453 	/*
454 	* Calculate width&height
455 	*/
456 	w = x2 - x1;
457 	h = y2 - y1;
458 
459 	/*
460 	* Maybe adjust radius
461 	*/
462 	if ((rad * 2) > w)
463 	{
464 		rad = w / 2;
465 	}
466 	if ((rad * 2) > h)
467 	{
468 		rad = h / 2;
469 	}
470 
471 	/*
472 	* Draw corners
473 	*/
474 	xx1 = x1 + rad;
475 	xx2 = x2 - rad;
476 	yy1 = y1 + rad;
477 	yy2 = y2 - rad;
478 	result |= arcRGBA(renderer, xx1, yy1, rad, 180, 270, r, g, b, a);
479 	result |= arcRGBA(renderer, xx2, yy1, rad, 270, 360, r, g, b, a);
480 	result |= arcRGBA(renderer, xx1, yy2, rad,  90, 180, r, g, b, a);
481 	result |= arcRGBA(renderer, xx2, yy2, rad,   0,  90, r, g, b, a);
482 
483 	/*
484 	* Draw lines
485 	*/
486 	if (xx1 <= xx2) {
487 		result |= hlineRGBA(renderer, xx1, xx2, y1, r, g, b, a);
488 		result |= hlineRGBA(renderer, xx1, xx2, y2, r, g, b, a);
489 	}
490 	if (yy1 <= yy2) {
491 		result |= vlineRGBA(renderer, x1, yy1, yy2, r, g, b, a);
492 		result |= vlineRGBA(renderer, x2, yy1, yy2, r, g, b, a);
493 	}
494 
495 	return result;
496 }
497 
498 /* ---- Rounded Box */
499 
500 /*!
501 \brief Draw rounded-corner box (filled rectangle) with blending.
502 
503 \param renderer The renderer to draw on.
504 \param x1 X coordinate of the first point (i.e. top right) of the box.
505 \param y1 Y coordinate of the first point (i.e. top right) of the box.
506 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
507 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
508 \param rad The radius of the corner arcs of the box.
509 \param color The color value of the box to draw (0xRRGGBBAA).
510 
511 \returns Returns 0 on success, -1 on failure.
512 */
roundedBoxColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint32 color)513 int roundedBoxColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
514 {
515 	Uint8 *c = (Uint8 *)&color;
516 	return roundedBoxRGBA(renderer, x1, y1, x2, y2, rad, c[0], c[1], c[2], c[3]);
517 }
518 
519 /*!
520 \brief Draw rounded-corner box (filled rectangle) with blending.
521 
522 \param renderer The renderer to draw on.
523 \param x1 X coordinate of the first point (i.e. top right) of the box.
524 \param y1 Y coordinate of the first point (i.e. top right) of the box.
525 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
526 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
527 \param rad The radius of the corner arcs of the box.
528 \param r The red value of the box to draw.
529 \param g The green value of the box to draw.
530 \param b The blue value of the box to draw.
531 \param a The alpha value of the box to draw.
532 
533 \returns Returns 0 on success, -1 on failure.
534 */
roundedBoxRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)535 int roundedBoxRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2,
536 	Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
537 {
538 	int result;
539 	Sint16 w, h, r2, tmp;
540 	Sint16 cx = 0;
541 	Sint16 cy = rad;
542 	Sint16 ocx = (Sint16) 0xffff;
543 	Sint16 ocy = (Sint16) 0xffff;
544 	Sint16 df = 1 - rad;
545 	Sint16 d_e = 3;
546 	Sint16 d_se = -2 * rad + 5;
547 	Sint16 xpcx, xmcx, xpcy, xmcy;
548 	Sint16 ypcy, ymcy, ypcx, ymcx;
549 	Sint16 x, y, dx, dy;
550 
551 	/*
552 	* Check destination renderer
553 	*/
554 	if (renderer == NULL)
555 	{
556 		return -1;
557 	}
558 
559 	/*
560 	* Check radius vor valid range
561 	*/
562 	if (rad < 0) {
563 		return -1;
564 	}
565 
566 	/*
567 	* Special case - no rounding
568 	*/
569 	if (rad <= 1) {
570 		return boxRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
571 	}
572 
573 	/*
574 	* Test for special cases of straight lines or single point
575 	*/
576 	if (x1 == x2) {
577 		if (y1 == y2) {
578 			return (pixelRGBA(renderer, x1, y1, r, g, b, a));
579 		} else {
580 			return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
581 		}
582 	} else {
583 		if (y1 == y2) {
584 			return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
585 		}
586 	}
587 
588 	/*
589 	* Swap x1, x2 if required
590 	*/
591 	if (x1 > x2) {
592 		tmp = x1;
593 		x1 = x2;
594 		x2 = tmp;
595 	}
596 
597 	/*
598 	* Swap y1, y2 if required
599 	*/
600 	if (y1 > y2) {
601 		tmp = y1;
602 		y1 = y2;
603 		y2 = tmp;
604 	}
605 
606 	/*
607 	* Calculate width&height
608 	*/
609 	w = x2 - x1 + 1;
610 	h = y2 - y1 + 1;
611 
612 	/*
613 	* Maybe adjust radius
614 	*/
615 	r2 = rad + rad;
616 	if (r2 > w)
617 	{
618 		rad = w / 2;
619 		r2 = rad + rad;
620 	}
621 	if (r2 > h)
622 	{
623 		rad = h / 2;
624 	}
625 
626 	/* Setup filled circle drawing for corners */
627 	x = x1 + rad;
628 	y = y1 + rad;
629 	dx = x2 - x1 - rad - rad;
630 	dy = y2 - y1 - rad - rad;
631 
632 	/*
633 	* Set color
634 	*/
635 	result = 0;
636 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
637 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
638 
639 	/*
640 	* Draw corners
641 	*/
642 	do {
643 		xpcx = x + cx;
644 		xmcx = x - cx;
645 		xpcy = x + cy;
646 		xmcy = x - cy;
647 		if (ocy != cy) {
648 			if (cy > 0) {
649 				ypcy = y + cy;
650 				ymcy = y - cy;
651 				result |= hline(renderer, xmcx, xpcx + dx, ypcy + dy);
652 				result |= hline(renderer, xmcx, xpcx + dx, ymcy);
653 			} else {
654 				result |= hline(renderer, xmcx, xpcx + dx, y);
655 			}
656 			ocy = cy;
657 		}
658 		if (ocx != cx) {
659 			if (cx != cy) {
660 				if (cx > 0) {
661 					ypcx = y + cx;
662 					ymcx = y - cx;
663 					result |= hline(renderer, xmcy, xpcy + dx, ymcx);
664 					result |= hline(renderer, xmcy, xpcy + dx, ypcx + dy);
665 				} else {
666 					result |= hline(renderer, xmcy, xpcy + dx, y);
667 				}
668 			}
669 			ocx = cx;
670 		}
671 
672 		/*
673 		* Update
674 		*/
675 		if (df < 0) {
676 			df += d_e;
677 			d_e += 2;
678 			d_se += 2;
679 		} else {
680 			df += d_se;
681 			d_e += 2;
682 			d_se += 4;
683 			cy--;
684 		}
685 		cx++;
686 	} while (cx <= cy);
687 
688 	/* Inside */
689 	if (dx > 0 && dy > 0) {
690 		result |= boxRGBA(renderer, x1, y1 + rad + 1, x2, y2 - rad, r, g, b, a);
691 	}
692 
693 	return (result);
694 }
695 
696 /* ---- Box */
697 
698 /*!
699 \brief Draw box (filled rectangle) with blending.
700 
701 \param renderer The renderer to draw on.
702 \param x1 X coordinate of the first point (i.e. top right) of the box.
703 \param y1 Y coordinate of the first point (i.e. top right) of the box.
704 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
705 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
706 \param color The color value of the box to draw (0xRRGGBBAA).
707 
708 \returns Returns 0 on success, -1 on failure.
709 */
boxColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)710 int boxColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
711 {
712 	Uint8 *c = (Uint8 *)&color;
713 	return boxRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
714 }
715 
716 /*!
717 \brief Draw box (filled rectangle) with blending.
718 
719 \param renderer The renderer to draw on.
720 \param x1 X coordinate of the first point (i.e. top right) of the box.
721 \param y1 Y coordinate of the first point (i.e. top right) of the box.
722 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
723 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
724 \param r The red value of the box to draw.
725 \param g The green value of the box to draw.
726 \param b The blue value of the box to draw.
727 \param a The alpha value of the box to draw.
728 
729 \returns Returns 0 on success, -1 on failure.
730 */
boxRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)731 int boxRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
732 {
733 	int result;
734 	Sint16 tmp;
735 	SDL_Rect rect;
736 
737 	/*
738 	* Test for special cases of straight lines or single point
739 	*/
740 	if (x1 == x2) {
741 		if (y1 == y2) {
742 			return (pixelRGBA(renderer, x1, y1, r, g, b, a));
743 		} else {
744 			return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
745 		}
746 	} else {
747 		if (y1 == y2) {
748 			return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
749 		}
750 	}
751 
752 	/*
753 	* Swap x1, x2 if required
754 	*/
755 	if (x1 > x2) {
756 		tmp = x1;
757 		x1 = x2;
758 		x2 = tmp;
759 	}
760 
761 	/*
762 	* Swap y1, y2 if required
763 	*/
764 	if (y1 > y2) {
765 		tmp = y1;
766 		y1 = y2;
767 		y2 = tmp;
768 	}
769 
770 	/*
771 	* Create destination rect
772 	*/
773 	rect.x = x1;
774 	rect.y = y1;
775 	rect.w = x2 - x1 + 1;
776 	rect.h = y2 - y1 + 1;
777 
778 	/*
779 	* Draw
780 	*/
781 	result = 0;
782 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
783 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
784 	result |= SDL_RenderFillRect(renderer, &rect);
785 	return result;
786 }
787 
788 /* ----- Line */
789 
790 /*!
791 \brief Draw line with alpha blending using the currently set color.
792 
793 \param renderer The renderer to draw on.
794 \param x1 X coordinate of the first point of the line.
795 \param y1 Y coordinate of the first point of the line.
796 \param x2 X coordinate of the second point of the line.
797 \param y2 Y coordinate of the second point of the line.
798 
799 \returns Returns 0 on success, -1 on failure.
800 */
line(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2)801 int line(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
802 {
803 	/*
804 	* Draw
805 	*/
806 	return SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
807 }
808 
809 /*!
810 \brief Draw line with alpha blending.
811 
812 \param renderer The renderer to draw on.
813 \param x1 X coordinate of the first point of the line.
814 \param y1 Y coordinate of the first point of the line.
815 \param x2 X coordinate of the second point of the line.
816 \param y2 Y coordinate of the seond point of the line.
817 \param color The color value of the line to draw (0xRRGGBBAA).
818 
819 \returns Returns 0 on success, -1 on failure.
820 */
lineColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)821 int lineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
822 {
823 	Uint8 *c = (Uint8 *)&color;
824 	return lineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
825 }
826 
827 /*!
828 \brief Draw line with alpha blending.
829 
830 \param renderer The renderer to draw on.
831 \param x1 X coordinate of the first point of the line.
832 \param y1 Y coordinate of the first point of the line.
833 \param x2 X coordinate of the second point of the line.
834 \param y2 Y coordinate of the second point of the line.
835 \param r The red value of the line to draw.
836 \param g The green value of the line to draw.
837 \param b The blue value of the line to draw.
838 \param a The alpha value of the line to draw.
839 
840 \returns Returns 0 on success, -1 on failure.
841 */
lineRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)842 int lineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
843 {
844 	/*
845 	* Draw
846 	*/
847 	int result = 0;
848 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
849 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
850 	result |= SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
851 	return result;
852 }
853 
854 /* ---- AA Line */
855 
856 #define AAlevels 256
857 #define AAbits 8
858 
859 /*!
860 \brief Internal function to draw anti-aliased line with alpha blending and endpoint control.
861 
862 This implementation of the Wu antialiasing code is based on Mike Abrash's
863 DDJ article which was reprinted as Chapter 42 of his Graphics Programming
864 Black Book, but has been optimized to work with SDL and utilizes 32-bit
865 fixed-point arithmetic by A. Schiffler. The endpoint control allows the
866 supression to draw the last pixel useful for rendering continous aa-lines
867 with alpha<255.
868 
869 \param renderer The renderer to draw on.
870 \param x1 X coordinate of the first point of the aa-line.
871 \param y1 Y coordinate of the first point of the aa-line.
872 \param x2 X coordinate of the second point of the aa-line.
873 \param y2 Y coordinate of the second point of the aa-line.
874 \param r The red value of the aa-line to draw.
875 \param g The green value of the aa-line to draw.
876 \param b The blue value of the aa-line to draw.
877 \param a The alpha value of the aa-line to draw.
878 \param draw_endpoint Flag indicating if the endpoint should be drawn; draw if non-zero.
879 
880 \returns Returns 0 on success, -1 on failure.
881 */
_aalineRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a,int draw_endpoint)882 int _aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int draw_endpoint)
883 {
884 	Sint32 xx0, yy0, xx1, yy1;
885 	int result;
886 	Uint32 intshift, erracc, erradj;
887 	Uint32 erracctmp, wgt, wgtcompmask;
888 	int dx, dy, tmp, xdir, y0p1, x0pxdir;
889 
890 	/*
891 	* Keep on working with 32bit numbers
892 	*/
893 	xx0 = x1;
894 	yy0 = y1;
895 	xx1 = x2;
896 	yy1 = y2;
897 
898 	/*
899 	* Reorder points to make dy positive
900 	*/
901 	if (yy0 > yy1) {
902 		tmp = yy0;
903 		yy0 = yy1;
904 		yy1 = tmp;
905 		tmp = xx0;
906 		xx0 = xx1;
907 		xx1 = tmp;
908 	}
909 
910 	/*
911 	* Calculate distance
912 	*/
913 	dx = xx1 - xx0;
914 	dy = yy1 - yy0;
915 
916 	/*
917 	* Adjust for negative dx and set xdir
918 	*/
919 	if (dx >= 0) {
920 		xdir = 1;
921 	} else {
922 		xdir = -1;
923 		dx = (-dx);
924 	}
925 
926 	/*
927 	* Check for special cases
928 	*/
929 	if (dx == 0) {
930 		/*
931 		* Vertical line
932 		*/
933 		if (draw_endpoint)
934 		{
935 			return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
936 		} else {
937 			if (dy > 0) {
938 				return (vlineRGBA(renderer, x1, yy0, yy0+dy, r, g, b, a));
939 			} else {
940 				return (pixelRGBA(renderer, x1, y1, r, g, b, a));
941 			}
942 		}
943 	} else if (dy == 0) {
944 		/*
945 		* Horizontal line
946 		*/
947 		if (draw_endpoint)
948 		{
949 			return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
950 		} else {
951 			if (dx > 0) {
952 				return (hlineRGBA(renderer, xx0, xx0+(xdir*dx), y1, r, g, b, a));
953 			} else {
954 				return (pixelRGBA(renderer, x1, y1, r, g, b, a));
955 			}
956 		}
957 	} else if ((dx == dy) && (draw_endpoint)) {
958 		/*
959 		* Diagonal line (with endpoint)
960 		*/
961 		return (lineRGBA(renderer, x1, y1, x2, y2,  r, g, b, a));
962 	}
963 
964 
965 	/*
966 	* Line is not horizontal, vertical or diagonal (with endpoint)
967 	*/
968 	result = 0;
969 
970 	/*
971 	* Zero accumulator
972 	*/
973 	erracc = 0;
974 
975 	/*
976 	* # of bits by which to shift erracc to get intensity level
977 	*/
978 	intshift = 32 - AAbits;
979 
980 	/*
981 	* Mask used to flip all bits in an intensity weighting
982 	*/
983 	wgtcompmask = AAlevels - 1;
984 
985 	/*
986 	* Draw the initial pixel in the foreground color
987 	*/
988 	result |= pixelRGBA(renderer, x1, y1, r, g, b, a);
989 
990 	/*
991 	* x-major or y-major?
992 	*/
993 	if (dy > dx) {
994 
995 		/*
996 		* y-major.  Calculate 16-bit fixed point fractional part of a pixel that
997 		* X advances every time Y advances 1 pixel, truncating the result so that
998 		* we won't overrun the endpoint along the X axis
999 		*/
1000 		/*
1001 		* Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
1002 		*/
1003 		erradj = ((dx << 16) / dy) << 16;
1004 
1005 		/*
1006 		* draw all pixels other than the first and last
1007 		*/
1008 		x0pxdir = xx0 + xdir;
1009 		while (--dy) {
1010 			erracctmp = erracc;
1011 			erracc += erradj;
1012 			if (erracc <= erracctmp) {
1013 				/*
1014 				* rollover in error accumulator, x coord advances
1015 				*/
1016 				xx0 = x0pxdir;
1017 				x0pxdir += xdir;
1018 			}
1019 			yy0++;		/* y-major so always advance Y */
1020 
1021 			/*
1022 			* the AAbits most significant bits of erracc give us the intensity
1023 			* weighting for this pixel, and the complement of the weighting for
1024 			* the paired pixel.
1025 			*/
1026 			wgt = (erracc >> intshift) & 255;
1027 			result |= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
1028 			result |= pixelRGBAWeight (renderer, x0pxdir, yy0, r, g, b, a, wgt);
1029 		}
1030 
1031 	} else {
1032 
1033 		/*
1034 		* x-major line.  Calculate 16-bit fixed-point fractional part of a pixel
1035 		* that Y advances each time X advances 1 pixel, truncating the result so
1036 		* that we won't overrun the endpoint along the X axis.
1037 		*/
1038 		/*
1039 		* Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
1040 		*/
1041 		erradj = ((dy << 16) / dx) << 16;
1042 
1043 		/*
1044 		* draw all pixels other than the first and last
1045 		*/
1046 		y0p1 = yy0 + 1;
1047 		while (--dx) {
1048 
1049 			erracctmp = erracc;
1050 			erracc += erradj;
1051 			if (erracc <= erracctmp) {
1052 				/*
1053 				* Accumulator turned over, advance y
1054 				*/
1055 				yy0 = y0p1;
1056 				y0p1++;
1057 			}
1058 			xx0 += xdir;	/* x-major so always advance X */
1059 			/*
1060 			* the AAbits most significant bits of erracc give us the intensity
1061 			* weighting for this pixel, and the complement of the weighting for
1062 			* the paired pixel.
1063 			*/
1064 			wgt = (erracc >> intshift) & 255;
1065 			result |= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
1066 			result |= pixelRGBAWeight (renderer, xx0, y0p1, r, g, b, a, wgt);
1067 		}
1068 	}
1069 
1070 	/*
1071 	* Do we have to draw the endpoint
1072 	*/
1073 	if (draw_endpoint) {
1074 		/*
1075 		* Draw final pixel, always exactly intersected by the line and doesn't
1076 		* need to be weighted.
1077 		*/
1078 		result |= pixelRGBA (renderer, x2, y2, r, g, b, a);
1079 	}
1080 
1081 	return (result);
1082 }
1083 
1084 /*!
1085 \brief Draw anti-aliased line with alpha blending.
1086 
1087 \param renderer The renderer to draw on.
1088 \param x1 X coordinate of the first point of the aa-line.
1089 \param y1 Y coordinate of the first point of the aa-line.
1090 \param x2 X coordinate of the second point of the aa-line.
1091 \param y2 Y coordinate of the second point of the aa-line.
1092 \param color The color value of the aa-line to draw (0xRRGGBBAA).
1093 
1094 \returns Returns 0 on success, -1 on failure.
1095 */
aalineColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1096 int aalineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1097 {
1098 	Uint8 *c = (Uint8 *)&color;
1099 	return _aalineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3], 1);
1100 }
1101 
1102 /*!
1103 \brief Draw anti-aliased line with alpha blending.
1104 
1105 \param renderer The renderer to draw on.
1106 \param x1 X coordinate of the first point of the aa-line.
1107 \param y1 Y coordinate of the first point of the aa-line.
1108 \param x2 X coordinate of the second point of the aa-line.
1109 \param y2 Y coordinate of the second point of the aa-line.
1110 \param r The red value of the aa-line to draw.
1111 \param g The green value of the aa-line to draw.
1112 \param b The blue value of the aa-line to draw.
1113 \param a The alpha value of the aa-line to draw.
1114 
1115 \returns Returns 0 on success, -1 on failure.
1116 */
aalineRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1117 int aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1118 {
1119 	return _aalineRGBA(renderer, x1, y1, x2, y2, r, g, b, a, 1);
1120 }
1121 
1122 /* ----- Circle */
1123 
1124 /*!
1125 \brief Draw circle with blending.
1126 
1127 \param renderer The renderer to draw on.
1128 \param x X coordinate of the center of the circle.
1129 \param y Y coordinate of the center of the circle.
1130 \param rad Radius in pixels of the circle.
1131 \param color The color value of the circle to draw (0xRRGGBBAA).
1132 
1133 \returns Returns 0 on success, -1 on failure.
1134 */
circleColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)1135 int circleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
1136 {
1137 	Uint8 *c = (Uint8 *)&color;
1138 	return ellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
1139 }
1140 
1141 /*!
1142 \brief Draw circle with blending.
1143 
1144 \param renderer The renderer to draw on.
1145 \param x X coordinate of the center of the circle.
1146 \param y Y coordinate of the center of the circle.
1147 \param rad Radius in pixels of the circle.
1148 \param r The red value of the circle to draw.
1149 \param g The green value of the circle to draw.
1150 \param b The blue value of the circle to draw.
1151 \param a The alpha value of the circle to draw.
1152 
1153 \returns Returns 0 on success, -1 on failure.
1154 */
circleRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1155 int circleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1156 {
1157 	return ellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
1158 }
1159 
1160 /* ----- Arc */
1161 
1162 /*!
1163 \brief Arc with blending.
1164 
1165 \param renderer The renderer to draw on.
1166 \param x X coordinate of the center of the arc.
1167 \param y Y coordinate of the center of the arc.
1168 \param rad Radius in pixels of the arc.
1169 \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
1170 \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
1171 \param color The color value of the arc to draw (0xRRGGBBAA).
1172 
1173 \returns Returns 0 on success, -1 on failure.
1174 */
arcColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)1175 int arcColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
1176 {
1177 	Uint8 *c = (Uint8 *)&color;
1178 	return arcRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3]);
1179 }
1180 
1181 /*!
1182 \brief Arc with blending.
1183 
1184 \param renderer The renderer to draw on.
1185 \param x X coordinate of the center of the arc.
1186 \param y Y coordinate of the center of the arc.
1187 \param rad Radius in pixels of the arc.
1188 \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
1189 \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
1190 \param r The red value of the arc to draw.
1191 \param g The green value of the arc to draw.
1192 \param b The blue value of the arc to draw.
1193 \param a The alpha value of the arc to draw.
1194 
1195 \returns Returns 0 on success, -1 on failure.
1196 */
1197 /* TODO: rewrite algorithm; arc endpoints are not always drawn */
arcRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1198 int arcRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1199 {
1200 	int result;
1201 	Sint16 cx = 0;
1202 	Sint16 cy = rad;
1203 	Sint16 df = 1 - rad;
1204 	Sint16 d_e = 3;
1205 	Sint16 d_se = -2 * rad + 5;
1206 	Sint16 xpcx, xmcx, xpcy, xmcy;
1207 	Sint16 ypcy, ymcy, ypcx, ymcx;
1208 	Uint8 drawoct;
1209 	int startoct, endoct, oct, stopval_start = 0, stopval_end = 0;
1210 	double dstart, dend, temp = 0.;
1211 
1212 	/*
1213 	* Sanity check radius
1214 	*/
1215 	if (rad < 0) {
1216 		return (-1);
1217 	}
1218 
1219 	/*
1220 	* Special case for rad=0 - draw a point
1221 	*/
1222 	if (rad == 0) {
1223 		return (pixelRGBA(renderer, x, y, r, g, b, a));
1224 	}
1225 
1226 	/*
1227 	 Octant labeling
1228 
1229 	  \ 5 | 6 /
1230 	   \  |  /
1231 	  4 \ | / 7
1232 	     \|/
1233 	------+------ +x
1234 	     /|\
1235 	  3 / | \ 0
1236 	   /  |  \
1237 	  / 2 | 1 \
1238 	      +y
1239 
1240 	 Initially reset bitmask to 0x00000000
1241 	 the set whether or not to keep drawing a given octant.
1242 	 For example: 0x00111100 means we're drawing in octants 2-5
1243 	*/
1244 	drawoct = 0;
1245 
1246 	/*
1247 	* Fixup angles
1248 	*/
1249 	start %= 360;
1250 	end %= 360;
1251 	/* 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0. */
1252 	while (start < 0) start += 360;
1253 	while (end < 0) end += 360;
1254 	start %= 360;
1255 	end %= 360;
1256 
1257 	/* now, we find which octants we're drawing in. */
1258 	startoct = start / 45;
1259 	endoct = end / 45;
1260 	oct = startoct - 1;
1261 
1262 	/* stopval_start, stopval_end; what values of cx to stop at. */
1263 	do {
1264 		oct = (oct + 1) % 8;
1265 
1266 		if (oct == startoct) {
1267 			/* need to compute stopval_start for this octant.  Look at picture above if this is unclear */
1268 			dstart = (double)start;
1269 			switch (oct)
1270 			{
1271 			case 0:
1272 			case 3:
1273 				temp = sin(dstart * M_PI / 180.);
1274 				break;
1275 			case 1:
1276 			case 6:
1277 				temp = cos(dstart * M_PI / 180.);
1278 				break;
1279 			case 2:
1280 			case 5:
1281 				temp = -cos(dstart * M_PI / 180.);
1282 				break;
1283 			case 4:
1284 			case 7:
1285 				temp = -sin(dstart * M_PI / 180.);
1286 				break;
1287 			}
1288 			temp *= rad;
1289 			stopval_start = (int)temp;
1290 
1291 			/*
1292 			This isn't arbitrary, but requires graph paper to explain well.
1293 			The basic idea is that we're always changing drawoct after we draw, so we
1294 			stop immediately after we render the last sensible pixel at x = ((int)temp).
1295 			and whether to draw in this octant initially
1296 			*/
1297 			if (oct % 2) drawoct |= (1 << oct);			/* this is basically like saying drawoct[oct] = true, if drawoct were a bool array */
1298 			else		 drawoct &= 255 - (1 << oct);	/* this is basically like saying drawoct[oct] = false */
1299 		}
1300 		if (oct == endoct) {
1301 			/* need to compute stopval_end for this octant */
1302 			dend = (double)end;
1303 			switch (oct)
1304 			{
1305 			case 0:
1306 			case 3:
1307 				temp = sin(dend * M_PI / 180);
1308 				break;
1309 			case 1:
1310 			case 6:
1311 				temp = cos(dend * M_PI / 180);
1312 				break;
1313 			case 2:
1314 			case 5:
1315 				temp = -cos(dend * M_PI / 180);
1316 				break;
1317 			case 4:
1318 			case 7:
1319 				temp = -sin(dend * M_PI / 180);
1320 				break;
1321 			}
1322 			temp *= rad;
1323 			stopval_end = (int)temp;
1324 
1325 			/* and whether to draw in this octant initially */
1326 			if (startoct == endoct)	{
1327 				/* note:      we start drawing, stop, then start again in this case */
1328 				/* otherwise: we only draw in this octant, so initialize it to false, it will get set back to true */
1329 				if (start > end) {
1330 					/* unfortunately, if we're in the same octant and need to draw over the whole circle, */
1331 					/* we need to set the rest to true, because the while loop will end at the bottom. */
1332 					drawoct = 255;
1333 				} else {
1334 					drawoct &= 255 - (1 << oct);
1335 				}
1336 			}
1337 			else if (oct % 2) drawoct &= 255 - (1 << oct);
1338 			else			  drawoct |= (1 << oct);
1339 		} else if (oct != startoct) { /* already verified that it's != endoct */
1340 			drawoct |= (1 << oct); /* draw this entire segment */
1341 		}
1342 	} while (oct != endoct);
1343 
1344 	/* so now we have what octants to draw and when to draw them. all that's left is the actual raster code. */
1345 
1346 	/*
1347 	* Set color
1348 	*/
1349 	result = 0;
1350 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
1351 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
1352 
1353 	/*
1354 	* Draw arc
1355 	*/
1356 	do {
1357 		ypcy = y + cy;
1358 		ymcy = y - cy;
1359 		if (cx > 0) {
1360 			xpcx = x + cx;
1361 			xmcx = x - cx;
1362 
1363 			/* always check if we're drawing a certain octant before adding a pixel to that octant. */
1364 			if (drawoct & 4)  result |= pixel(renderer, xmcx, ypcy);
1365 			if (drawoct & 2)  result |= pixel(renderer, xpcx, ypcy);
1366 			if (drawoct & 32) result |= pixel(renderer, xmcx, ymcy);
1367 			if (drawoct & 64) result |= pixel(renderer, xpcx, ymcy);
1368 		} else {
1369 			if (drawoct & 96) result |= pixel(renderer, x, ymcy);
1370 			if (drawoct & 6)  result |= pixel(renderer, x, ypcy);
1371 		}
1372 
1373 		xpcy = x + cy;
1374 		xmcy = x - cy;
1375 		if (cx > 0 && cx != cy) {
1376 			ypcx = y + cx;
1377 			ymcx = y - cx;
1378 			if (drawoct & 8)   result |= pixel(renderer, xmcy, ypcx);
1379 			if (drawoct & 1)   result |= pixel(renderer, xpcy, ypcx);
1380 			if (drawoct & 16)  result |= pixel(renderer, xmcy, ymcx);
1381 			if (drawoct & 128) result |= pixel(renderer, xpcy, ymcx);
1382 		} else if (cx == 0) {
1383 			if (drawoct & 24)  result |= pixel(renderer, xmcy, y);
1384 			if (drawoct & 129) result |= pixel(renderer, xpcy, y);
1385 		}
1386 
1387 		/*
1388 		* Update whether we're drawing an octant
1389 		*/
1390 		if (stopval_start == cx) {
1391 			/* works like an on-off switch. */
1392 			/* This is just in case start & end are in the same octant. */
1393 			if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
1394 			else						   drawoct |= (1 << startoct);
1395 		}
1396 		if (stopval_end == cx) {
1397 			if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
1398 			else						 drawoct |= (1 << endoct);
1399 		}
1400 
1401 		/*
1402 		* Update pixels
1403 		*/
1404 		if (df < 0) {
1405 			df += d_e;
1406 			d_e += 2;
1407 			d_se += 2;
1408 		} else {
1409 			df += d_se;
1410 			d_e += 2;
1411 			d_se += 4;
1412 			cy--;
1413 		}
1414 		cx++;
1415 	} while (cx <= cy);
1416 
1417 	return (result);
1418 }
1419 
1420 /* ----- AA Circle */
1421 
1422 /*!
1423 \brief Draw anti-aliased circle with blending.
1424 
1425 \param renderer The renderer to draw on.
1426 \param x X coordinate of the center of the aa-circle.
1427 \param y Y coordinate of the center of the aa-circle.
1428 \param rad Radius in pixels of the aa-circle.
1429 \param color The color value of the aa-circle to draw (0xRRGGBBAA).
1430 
1431 \returns Returns 0 on success, -1 on failure.
1432 */
aacircleColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)1433 int aacircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
1434 {
1435 	Uint8 *c = (Uint8 *)&color;
1436 	return aaellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
1437 }
1438 
1439 /*!
1440 \brief Draw anti-aliased circle with blending.
1441 
1442 \param renderer The renderer to draw on.
1443 \param x X coordinate of the center of the aa-circle.
1444 \param y Y coordinate of the center of the aa-circle.
1445 \param rad Radius in pixels of the aa-circle.
1446 \param r The red value of the aa-circle to draw.
1447 \param g The green value of the aa-circle to draw.
1448 \param b The blue value of the aa-circle to draw.
1449 \param a The alpha value of the aa-circle to draw.
1450 
1451 \returns Returns 0 on success, -1 on failure.
1452 */
aacircleRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1453 int aacircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1454 {
1455 	/*
1456 	* Draw
1457 	*/
1458 	return aaellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
1459 }
1460 
1461 /* ----- Ellipse */
1462 
1463 /*!
1464 \brief Internal function to draw pixels or lines in 4 quadrants.
1465 
1466 \param renderer The renderer to draw on.
1467 \param x X coordinate of the center of the quadrant.
1468 \param y Y coordinate of the center of the quadrant.
1469 \param dx X offset in pixels of the corners of the quadrant.
1470 \param dy Y offset in pixels of the corners of the quadrant.
1471 \param f Flag indicating if the quadrant should be filled (1) or not (0).
1472 
1473 \returns Returns 0 on success, -1 on failure.
1474 */
_drawQuadrants(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 dx,Sint16 dy,Sint32 f)1475 int _drawQuadrants(SDL_Renderer * renderer,  Sint16 x, Sint16 y, Sint16 dx, Sint16 dy, Sint32 f)
1476 {
1477 	int result = 0;
1478 	Sint16 xpdx, xmdx;
1479 	Sint16 ypdy, ymdy;
1480 
1481 	if (dx == 0) {
1482 		if (dy == 0) {
1483 			result |= pixel(renderer, x, y);
1484 		} else {
1485 			ypdy = y + dy;
1486 			ymdy = y - dy;
1487 			if (f) {
1488 				result |= vline(renderer, x, ymdy, ypdy);
1489 			} else {
1490 				result |= pixel(renderer, x, ypdy);
1491 				result |= pixel(renderer, x, ymdy);
1492 			}
1493 		}
1494 	} else {
1495 		xpdx = x + dx;
1496 		xmdx = x - dx;
1497 		ypdy = y + dy;
1498 		ymdy = y - dy;
1499 		if (f) {
1500 				result |= vline(renderer, xpdx, ymdy, ypdy);
1501 				result |= vline(renderer, xmdx, ymdy, ypdy);
1502 		} else {
1503 				result |= pixel(renderer, xpdx, ypdy);
1504 				result |= pixel(renderer, xmdx, ypdy);
1505 				result |= pixel(renderer, xpdx, ymdy);
1506 				result |= pixel(renderer, xmdx, ymdy);
1507 		}
1508 	}
1509 
1510 	return result;
1511 }
1512 
1513 /*!
1514 \brief Internal function to draw ellipse or filled ellipse with blending.
1515 
1516 \param renderer The renderer to draw on.
1517 \param x X coordinate of the center of the ellipse.
1518 \param y Y coordinate of the center of the ellipse.
1519 \param rx Horizontal radius in pixels of the ellipse.
1520 \param ry Vertical radius in pixels of the ellipse.
1521 \param r The red value of the ellipse to draw.
1522 \param g The green value of the ellipse to draw.
1523 \param b The blue value of the ellipse to draw.
1524 \param a The alpha value of the ellipse to draw.
1525 \param f Flag indicating if the ellipse should be filled (1) or not (0).
1526 
1527 \returns Returns 0 on success, -1 on failure.
1528 */
1529 #define DEFAULT_ELLIPSE_OVERSCAN	4
_ellipseRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a,Sint32 f)1530 int _ellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Sint32 f)
1531 {
1532 	int result;
1533 	Sint32 rxi, ryi;
1534 	Sint32 rx2, ry2, rx22, ry22;
1535     Sint32 error;
1536     Sint32 curX, curY, curXp1, curYm1;
1537 	Sint32 scrX, scrY, oldX, oldY;
1538     Sint32 deltaX, deltaY;
1539 	Sint32 ellipseOverscan;
1540 
1541 	/*
1542 	* Sanity check radii
1543 	*/
1544 	if ((rx < 0) || (ry < 0)) {
1545 		return (-1);
1546 	}
1547 
1548 	/*
1549 	* Set color
1550 	*/
1551 	result = 0;
1552 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
1553 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
1554 
1555 	/*
1556 	* Special cases for rx=0 and/or ry=0: draw a hline/vline/pixel
1557 	*/
1558 	if (rx == 0) {
1559 		if (ry == 0) {
1560 			return (pixel(renderer, x, y));
1561 		} else {
1562 			return (vline(renderer, x, y - ry, y + ry));
1563 		}
1564 	} else {
1565 		if (ry == 0) {
1566 			return (hline(renderer, x - rx, x + rx, y));
1567 		}
1568 	}
1569 
1570 	/*
1571  	 * Adjust overscan
1572 	 */
1573 	rxi = rx;
1574 	ryi = ry;
1575 	if (rxi >= 512 || ryi >= 512)
1576 	{
1577 		ellipseOverscan = DEFAULT_ELLIPSE_OVERSCAN / 4;
1578 	}
1579 	else if (rxi >= 256 || ryi >= 256)
1580 	{
1581 		ellipseOverscan = DEFAULT_ELLIPSE_OVERSCAN / 2;
1582 	}
1583 	else
1584 	{
1585 		ellipseOverscan = DEFAULT_ELLIPSE_OVERSCAN / 1;
1586 	}
1587 
1588 	/*
1589 	 * Top/bottom center points.
1590 	 */
1591 	oldX = scrX = 0;
1592 	oldY = scrY = ryi;
1593 	result |= _drawQuadrants(renderer, x, y, 0, ry, f);
1594 
1595 	/* Midpoint ellipse algorithm with overdraw */
1596 	rxi *= ellipseOverscan;
1597 	ryi *= ellipseOverscan;
1598 	rx2 = rxi * rxi;
1599 	rx22 = rx2 + rx2;
1600     ry2 = ryi * ryi;
1601 	ry22 = ry2 + ry2;
1602     curX = 0;
1603     curY = ryi;
1604     deltaX = 0;
1605     deltaY = rx22 * curY;
1606 
1607 	/* Points in segment 1 */
1608     error = ry2 - rx2 * ryi + rx2 / 4;
1609     while (deltaX <= deltaY)
1610     {
1611           curX++;
1612           deltaX += ry22;
1613 
1614           error +=  deltaX + ry2;
1615           if (error >= 0)
1616           {
1617                curY--;
1618                deltaY -= rx22;
1619                error -= deltaY;
1620           }
1621 
1622 		  scrX = curX / ellipseOverscan;
1623 		  scrY = curY / ellipseOverscan;
1624 		  if ((scrX != oldX && scrY == oldY) || (scrX != oldX && scrY != oldY)) {
1625 			result |= _drawQuadrants(renderer, x, y, scrX, scrY, f);
1626 			oldX = scrX;
1627 			oldY = scrY;
1628 		  }
1629     }
1630 
1631 	/* Points in segment 2 */
1632 	if (curY > 0)
1633 	{
1634 		curXp1 = curX + 1;
1635 		curYm1 = curY - 1;
1636 		error = ry2 * curX * curXp1 + ((ry2 + 3) / 4) + rx2 * curYm1 * curYm1 - rx2 * ry2;
1637 		while (curY > 0)
1638 		{
1639 			curY--;
1640 			deltaY -= rx22;
1641 
1642 			error += rx2;
1643 			error -= deltaY;
1644 
1645 			if (error <= 0)
1646 			{
1647                curX++;
1648                deltaX += ry22;
1649                error += deltaX;
1650 			}
1651 
1652 		    scrX = curX / ellipseOverscan;
1653 		    scrY = curY / ellipseOverscan;
1654 		    if ((scrX != oldX && scrY == oldY) || (scrX != oldX && scrY != oldY)) {
1655 				oldY--;
1656 				for (;oldY >= scrY; oldY--) {
1657 					result |= _drawQuadrants(renderer, x, y, scrX, oldY, f);
1658 					/* prevent overdraw */
1659 					if (f) {
1660 						oldY = scrY - 1;
1661 					}
1662 				}
1663   				oldX = scrX;
1664 				oldY = scrY;
1665 		    }
1666 		}
1667 
1668 		/* Remaining points in vertical */
1669 		if (!f) {
1670 			oldY--;
1671 			for (;oldY >= 0; oldY--) {
1672 				result |= _drawQuadrants(renderer, x, y, scrX, oldY, f);
1673 			}
1674 		}
1675 	}
1676 
1677 	return (result);
1678 }
1679 
1680 /*!
1681 \brief Draw ellipse with blending.
1682 
1683 \param renderer The renderer to draw on.
1684 \param x X coordinate of the center of the ellipse.
1685 \param y Y coordinate of the center of the ellipse.
1686 \param rx Horizontal radius in pixels of the ellipse.
1687 \param ry Vertical radius in pixels of the ellipse.
1688 \param color The color value of the ellipse to draw (0xRRGGBBAA).
1689 
1690 \returns Returns 0 on success, -1 on failure.
1691 */
ellipseColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)1692 int ellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
1693 {
1694 	Uint8 *c = (Uint8 *)&color;
1695 	return _ellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3], 0);
1696 }
1697 
1698 /*!
1699 \brief Draw ellipse with blending.
1700 
1701 \param renderer The renderer to draw on.
1702 \param x X coordinate of the center of the ellipse.
1703 \param y Y coordinate of the center of the ellipse.
1704 \param rx Horizontal radius in pixels of the ellipse.
1705 \param ry Vertical radius in pixels of the ellipse.
1706 \param r The red value of the ellipse to draw.
1707 \param g The green value of the ellipse to draw.
1708 \param b The blue value of the ellipse to draw.
1709 \param a The alpha value of the ellipse to draw.
1710 
1711 \returns Returns 0 on success, -1 on failure.
1712 */
ellipseRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1713 int ellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1714 {
1715 	return _ellipseRGBA(renderer, x, y, rx, ry, r, g, b, a, 0);
1716 }
1717 
1718 /* ----- Filled Circle */
1719 
1720 /*!
1721 \brief Draw filled circle with blending.
1722 
1723 \param renderer The renderer to draw on.
1724 \param x X coordinate of the center of the filled circle.
1725 \param y Y coordinate of the center of the filled circle.
1726 \param rad Radius in pixels of the filled circle.
1727 \param color The color value of the filled circle to draw (0xRRGGBBAA).
1728 
1729 \returns Returns 0 on success, -1 on failure.
1730 */
filledCircleColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)1731 int filledCircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
1732 {
1733 	Uint8 *c = (Uint8 *)&color;
1734 	return filledEllipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
1735 }
1736 
1737 /*!
1738 \brief Draw filled circle with blending.
1739 
1740 \param renderer The renderer to draw on.
1741 \param x X coordinate of the center of the filled circle.
1742 \param y Y coordinate of the center of the filled circle.
1743 \param rad Radius in pixels of the filled circle.
1744 \param r The red value of the filled circle to draw.
1745 \param g The green value of the filled circle to draw.
1746 \param b The blue value of the filled circle to draw.
1747 \param a The alpha value of the filled circle to draw.
1748 
1749 \returns Returns 0 on success, -1 on failure.
1750 */
filledCircleRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1751 int filledCircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1752 {
1753 	return _ellipseRGBA(renderer, x, y, rad, rad, r, g ,b, a, 1);
1754 }
1755 
1756 
1757 /* ----- AA Ellipse */
1758 
1759 /* Windows targets do not have lrint, so provide a local inline version */
1760 #if defined(_MSC_VER)
1761 /* Detect 64bit and use intrinsic version */
1762 #ifdef _M_X64
1763 #include <emmintrin.h>
1764 static __inline long
lrint(float f)1765 	lrint(float f)
1766 {
1767 	return _mm_cvtss_si32(_mm_load_ss(&f));
1768 }
1769 #elif defined(_M_IX86)
1770 __inline long int
lrint(double flt)1771 	lrint (double flt)
1772 {
1773 	int intgr;
1774 	_asm
1775 	{
1776 		fld flt
1777 			fistp intgr
1778 	};
1779 	return intgr;
1780 }
1781 #elif defined(_M_ARM)
1782 #include <armintr.h>
1783 #pragma warning(push)
1784 #pragma warning(disable: 4716)
1785 __declspec(naked) long int
lrint(double flt)1786 	lrint (double flt)
1787 {
1788 	__emit(0xEC410B10); // fmdrr  d0, r0, r1
1789 	__emit(0xEEBD0B40); // ftosid s0, d0
1790 	__emit(0xEE100A10); // fmrs   r0, s0
1791 	__emit(0xE12FFF1E); // bx     lr
1792 }
1793 #pragma warning(pop)
1794 #else
1795 #error lrint needed for MSVC on non X86/AMD64/ARM targets.
1796 #endif
1797 #endif
1798 
1799 /*!
1800 \brief Draw anti-aliased ellipse with blending.
1801 
1802 \param renderer The renderer to draw on.
1803 \param x X coordinate of the center of the aa-ellipse.
1804 \param y Y coordinate of the center of the aa-ellipse.
1805 \param rx Horizontal radius in pixels of the aa-ellipse.
1806 \param ry Vertical radius in pixels of the aa-ellipse.
1807 \param color The color value of the aa-ellipse to draw (0xRRGGBBAA).
1808 
1809 \returns Returns 0 on success, -1 on failure.
1810 */
aaellipseColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)1811 int aaellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
1812 {
1813 	Uint8 *c = (Uint8 *)&color;
1814 	return aaellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
1815 }
1816 
1817 /*!
1818 \brief Draw anti-aliased ellipse with blending.
1819 
1820 \param renderer The renderer to draw on.
1821 \param x X coordinate of the center of the aa-ellipse.
1822 \param y Y coordinate of the center of the aa-ellipse.
1823 \param rx Horizontal radius in pixels of the aa-ellipse.
1824 \param ry Vertical radius in pixels of the aa-ellipse.
1825 \param r The red value of the aa-ellipse to draw.
1826 \param g The green value of the aa-ellipse to draw.
1827 \param b The blue value of the aa-ellipse to draw.
1828 \param a The alpha value of the aa-ellipse to draw.
1829 
1830 \returns Returns 0 on success, -1 on failure.
1831 */
aaellipseRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1832 int aaellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1833 {
1834 	int result;
1835 	int i;
1836 	int a2, b2, ds, dt, dxt, t, s, d;
1837 	Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2;
1838 	float cp;
1839 	double sab;
1840 	Uint8 weight, iweight;
1841 
1842 	/*
1843 	* Sanity check radii
1844 	*/
1845 	if ((rx < 0) || (ry < 0)) {
1846 		return (-1);
1847 	}
1848 
1849 	/*
1850 	* Special cases for rx=0 and/or ry=0: draw a hline/vline/pixel
1851 	*/
1852 	if (rx == 0) {
1853 		if (ry == 0) {
1854 			return (pixelRGBA(renderer, x, y, r, g, b, a));
1855 		} else {
1856 			return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
1857 		}
1858 	} else {
1859 		if (ry == 0) {
1860 			return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
1861 		}
1862 	}
1863 
1864 	/* Variable setup */
1865 	a2 = rx * rx;
1866 	b2 = ry * ry;
1867 
1868 	ds = 2 * a2;
1869 	dt = 2 * b2;
1870 
1871 	xc2 = 2 * x;
1872 	yc2 = 2 * y;
1873 
1874 	sab = sqrt((double)(a2 + b2));
1875 	od = (Sint16)lrint(sab*0.01) + 1; /* introduce some overdraw */
1876 	dxt = (Sint16)lrint((double)a2 / sab) + od;
1877 
1878 	t = 0;
1879 	s = -2 * a2 * ry;
1880 	d = 0;
1881 
1882 	xp = x;
1883 	yp = y - ry;
1884 
1885 	/* Draw */
1886 	result = 0;
1887 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
1888 
1889 	/* "End points" */
1890 	result |= pixelRGBA(renderer, xp, yp, r, g, b, a);
1891 	result |= pixelRGBA(renderer, xc2 - xp, yp, r, g, b, a);
1892 	result |= pixelRGBA(renderer, xp, yc2 - yp, r, g, b, a);
1893 	result |= pixelRGBA(renderer, xc2 - xp, yc2 - yp, r, g, b, a);
1894 
1895 	for (i = 1; i <= dxt; i++) {
1896 		xp--;
1897 		d += t - b2;
1898 
1899 		if (d >= 0)
1900 			ys = yp - 1;
1901 		else if ((d - s - a2) > 0) {
1902 			if ((2 * d - s - a2) >= 0)
1903 				ys = yp + 1;
1904 			else {
1905 				ys = yp;
1906 				yp++;
1907 				d -= s + a2;
1908 				s += ds;
1909 			}
1910 		} else {
1911 			yp++;
1912 			ys = yp + 1;
1913 			d -= s + a2;
1914 			s += ds;
1915 		}
1916 
1917 		t -= dt;
1918 
1919 		/* Calculate alpha */
1920 		if (s != 0) {
1921 			cp = (float) abs(d) / (float) abs(s);
1922 			if (cp > 1.0) {
1923 				cp = 1.0;
1924 			}
1925 		} else {
1926 			cp = 1.0;
1927 		}
1928 
1929 		/* Calculate weights */
1930 		weight = (Uint8) (cp * 255);
1931 		iweight = 255 - weight;
1932 
1933 		/* Upper half */
1934 		xx = xc2 - xp;
1935 		result |= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
1936 		result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
1937 
1938 		result |= pixelRGBAWeight(renderer, xp, ys, r, g, b, a, weight);
1939 		result |= pixelRGBAWeight(renderer, xx, ys, r, g, b, a, weight);
1940 
1941 		/* Lower half */
1942 		yy = yc2 - yp;
1943 		result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
1944 		result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
1945 
1946 		yy = yc2 - ys;
1947 		result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, weight);
1948 		result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);
1949 	}
1950 
1951 	/* Replaces original approximation code dyt = abs(yp - yc); */
1952 	dyt = (Sint16)lrint((double)b2 / sab ) + od;
1953 
1954 	for (i = 1; i <= dyt; i++) {
1955 		yp++;
1956 		d -= s + a2;
1957 
1958 		if (d <= 0)
1959 			xs = xp + 1;
1960 		else if ((d + t - b2) < 0) {
1961 			if ((2 * d + t - b2) <= 0)
1962 				xs = xp - 1;
1963 			else {
1964 				xs = xp;
1965 				xp--;
1966 				d += t - b2;
1967 				t -= dt;
1968 			}
1969 		} else {
1970 			xp--;
1971 			xs = xp - 1;
1972 			d += t - b2;
1973 			t -= dt;
1974 		}
1975 
1976 		s += ds;
1977 
1978 		/* Calculate alpha */
1979 		if (t != 0) {
1980 			cp = (float) abs(d) / (float) abs(t);
1981 			if (cp > 1.0) {
1982 				cp = 1.0;
1983 			}
1984 		} else {
1985 			cp = 1.0;
1986 		}
1987 
1988 		/* Calculate weight */
1989 		weight = (Uint8) (cp * 255);
1990 		iweight = 255 - weight;
1991 
1992 		/* Left half */
1993 		xx = xc2 - xp;
1994 		yy = yc2 - yp;
1995 		result |= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
1996 		result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
1997 
1998 		result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
1999 		result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
2000 
2001 		/* Right half */
2002 		xx = xc2 - xs;
2003 		result |= pixelRGBAWeight(renderer, xs, yp, r, g, b, a, weight);
2004 		result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, weight);
2005 
2006 		result |= pixelRGBAWeight(renderer, xs, yy, r, g, b, a, weight);
2007 		result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);
2008 	}
2009 
2010 	return (result);
2011 }
2012 
2013 /* ---- Filled Ellipse */
2014 
2015 /*!
2016 \brief Draw filled ellipse with blending.
2017 
2018 \param renderer The renderer to draw on.
2019 \param x X coordinate of the center of the filled ellipse.
2020 \param y Y coordinate of the center of the filled ellipse.
2021 \param rx Horizontal radius in pixels of the filled ellipse.
2022 \param ry Vertical radius in pixels of the filled ellipse.
2023 \param color The color value of the filled ellipse to draw (0xRRGGBBAA).
2024 
2025 \returns Returns 0 on success, -1 on failure.
2026 */
filledEllipseColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)2027 int filledEllipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
2028 {
2029 	Uint8 *c = (Uint8 *)&color;
2030 	return _ellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3], 1);
2031 }
2032 
2033 /*!
2034 \brief Draw filled ellipse with blending.
2035 
2036 \param renderer The renderer to draw on.
2037 \param x X coordinate of the center of the filled ellipse.
2038 \param y Y coordinate of the center of the filled ellipse.
2039 \param rx Horizontal radius in pixels of the filled ellipse.
2040 \param ry Vertical radius in pixels of the filled ellipse.
2041 \param r The red value of the filled ellipse to draw.
2042 \param g The green value of the filled ellipse to draw.
2043 \param b The blue value of the filled ellipse to draw.
2044 \param a The alpha value of the filled ellipse to draw.
2045 
2046 \returns Returns 0 on success, -1 on failure.
2047 */
filledEllipseRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2048 int filledEllipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2049 {
2050 	return _ellipseRGBA(renderer, x, y, rx, ry, r, g, b, a, 1);
2051 }
2052 
2053 /* ----- Pie */
2054 
2055 /*!
2056 \brief Internal float (low-speed) pie-calc implementation by drawing polygons.
2057 
2058 Note: Determines vertex array and uses polygon or filledPolygon drawing routines to render.
2059 
2060 \param renderer The renderer to draw on.
2061 \param x X coordinate of the center of the pie.
2062 \param y Y coordinate of the center of the pie.
2063 \param rad Radius in pixels of the pie.
2064 \param start Starting radius in degrees of the pie.
2065 \param end Ending radius in degrees of the pie.
2066 \param r The red value of the pie to draw.
2067 \param g The green value of the pie to draw.
2068 \param b The blue value of the pie to draw.
2069 \param a The alpha value of the pie to draw.
2070 \param filled Flag indicating if the pie should be filled (=1) or not (=0).
2071 
2072 \returns Returns 0 on success, -1 on failure.
2073 */
2074 /* TODO: rewrite algorithm; pie is not always accurate */
_pieRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a,Uint8 filled)2075 int _pieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end,  Uint8 r, Uint8 g, Uint8 b, Uint8 a, Uint8 filled)
2076 {
2077 	int result;
2078 	double angle, start_angle, end_angle;
2079 	double deltaAngle;
2080 	double dr;
2081 	int numpoints, i;
2082 	Sint16 *vx, *vy;
2083 
2084 	/*
2085 	* Sanity check radii
2086 	*/
2087 	if (rad < 0) {
2088 		return (-1);
2089 	}
2090 
2091 	/*
2092 	* Fixup angles
2093 	*/
2094 	start = start % 360;
2095 	end = end % 360;
2096 
2097 	/*
2098 	* Special case for rad=0 - draw a point
2099 	*/
2100 	if (rad == 0) {
2101 		return (pixelRGBA(renderer, x, y, r, g, b, a));
2102 	}
2103 
2104 	/*
2105 	* Variable setup
2106 	*/
2107 	dr = (double) rad;
2108 	deltaAngle = 3.0 / dr;
2109 	start_angle = (double) start *(2.0 * M_PI / 360.0);
2110 	end_angle = (double) end *(2.0 * M_PI / 360.0);
2111 	if (start > end) {
2112 		end_angle += (2.0 * M_PI);
2113 	}
2114 
2115 	/* We will always have at least 2 points */
2116 	numpoints = 2;
2117 
2118 	/* Count points (rather than calculating it) */
2119 	angle = start_angle;
2120 	while (angle < end_angle) {
2121 		angle += deltaAngle;
2122 		numpoints++;
2123 	}
2124 
2125 	/* Allocate combined vertex array */
2126 	vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
2127 	if (vx == NULL) {
2128 		return (-1);
2129 	}
2130 
2131 	/* Update point to start of vy */
2132 	vy += numpoints;
2133 
2134 	/* Center */
2135 	vx[0] = x;
2136 	vy[0] = y;
2137 
2138 	/* First vertex */
2139 	angle = start_angle;
2140 	vx[1] = x + (int) (dr * cos(angle));
2141 	vy[1] = y + (int) (dr * sin(angle));
2142 
2143 	if (numpoints<3)
2144 	{
2145 		result = lineRGBA(renderer, vx[0], vy[0], vx[1], vy[1], r, g, b, a);
2146 	}
2147 	else
2148 	{
2149 		/* Calculate other vertices */
2150 		i = 2;
2151 		angle = start_angle;
2152 		while (angle < end_angle) {
2153 			angle += deltaAngle;
2154 			if (angle>end_angle)
2155 			{
2156 				angle = end_angle;
2157 			}
2158 			vx[i] = x + (int) (dr * cos(angle));
2159 			vy[i] = y + (int) (dr * sin(angle));
2160 			i++;
2161 		}
2162 
2163 		/* Draw */
2164 		if (filled) {
2165 			result = filledPolygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
2166 		} else {
2167 			result = polygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
2168 		}
2169 	}
2170 
2171 	/* Free combined vertex array */
2172 	free(vx);
2173 
2174 	return (result);
2175 }
2176 
2177 /*!
2178 \brief Draw pie (outline) with alpha blending.
2179 
2180 \param renderer The renderer to draw on.
2181 \param x X coordinate of the center of the pie.
2182 \param y Y coordinate of the center of the pie.
2183 \param rad Radius in pixels of the pie.
2184 \param start Starting radius in degrees of the pie.
2185 \param end Ending radius in degrees of the pie.
2186 \param color The color value of the pie to draw (0xRRGGBBAA).
2187 
2188 \returns Returns 0 on success, -1 on failure.
2189 */
pieColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)2190 int pieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
2191 	Sint16 start, Sint16 end, Uint32 color)
2192 {
2193 	Uint8 *c = (Uint8 *)&color;
2194 	return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 0);
2195 }
2196 
2197 /*!
2198 \brief Draw pie (outline) with alpha blending.
2199 
2200 \param renderer The renderer to draw on.
2201 \param x X coordinate of the center of the pie.
2202 \param y Y coordinate of the center of the pie.
2203 \param rad Radius in pixels of the pie.
2204 \param start Starting radius in degrees of the pie.
2205 \param end Ending radius in degrees of the pie.
2206 \param r The red value of the pie to draw.
2207 \param g The green value of the pie to draw.
2208 \param b The blue value of the pie to draw.
2209 \param a The alpha value of the pie to draw.
2210 
2211 \returns Returns 0 on success, -1 on failure.
2212 */
pieRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2213 int pieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
2214 	Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2215 {
2216 	return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 0);
2217 }
2218 
2219 /*!
2220 \brief Draw filled pie with alpha blending.
2221 
2222 \param renderer The renderer to draw on.
2223 \param x X coordinate of the center of the filled pie.
2224 \param y Y coordinate of the center of the filled pie.
2225 \param rad Radius in pixels of the filled pie.
2226 \param start Starting radius in degrees of the filled pie.
2227 \param end Ending radius in degrees of the filled pie.
2228 \param color The color value of the filled pie to draw (0xRRGGBBAA).
2229 
2230 \returns Returns 0 on success, -1 on failure.
2231 */
filledPieColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)2232 int filledPieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
2233 {
2234 	Uint8 *c = (Uint8 *)&color;
2235 	return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 1);
2236 }
2237 
2238 /*!
2239 \brief Draw filled pie with alpha blending.
2240 
2241 \param renderer The renderer to draw on.
2242 \param x X coordinate of the center of the filled pie.
2243 \param y Y coordinate of the center of the filled pie.
2244 \param rad Radius in pixels of the filled pie.
2245 \param start Starting radius in degrees of the filled pie.
2246 \param end Ending radius in degrees of the filled pie.
2247 \param r The red value of the filled pie to draw.
2248 \param g The green value of the filled pie to draw.
2249 \param b The blue value of the filled pie to draw.
2250 \param a The alpha value of the filled pie to draw.
2251 
2252 \returns Returns 0 on success, -1 on failure.
2253 */
filledPieRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2254 int filledPieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
2255 	Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2256 {
2257 	return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 1);
2258 }
2259 
2260 /* ------ Trigon */
2261 
2262 /*!
2263 \brief Draw trigon (triangle outline) with alpha blending.
2264 
2265 Note: Creates vertex array and uses polygon routine to render.
2266 
2267 \param renderer The renderer to draw on.
2268 \param x1 X coordinate of the first point of the trigon.
2269 \param y1 Y coordinate of the first point of the trigon.
2270 \param x2 X coordinate of the second point of the trigon.
2271 \param y2 Y coordinate of the second point of the trigon.
2272 \param x3 X coordinate of the third point of the trigon.
2273 \param y3 Y coordinate of the third point of the trigon.
2274 \param color The color value of the trigon to draw (0xRRGGBBAA).
2275 
2276 \returns Returns 0 on success, -1 on failure.
2277 */
trigonColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)2278 int trigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
2279 {
2280 	Sint16 vx[3];
2281 	Sint16 vy[3];
2282 
2283 	vx[0]=x1;
2284 	vx[1]=x2;
2285 	vx[2]=x3;
2286 	vy[0]=y1;
2287 	vy[1]=y2;
2288 	vy[2]=y3;
2289 
2290 	return(polygonColor(renderer,vx,vy,3,color));
2291 }
2292 
2293 /*!
2294 \brief Draw trigon (triangle outline) with alpha blending.
2295 
2296 \param renderer The renderer to draw on.
2297 \param x1 X coordinate of the first point of the trigon.
2298 \param y1 Y coordinate of the first point of the trigon.
2299 \param x2 X coordinate of the second point of the trigon.
2300 \param y2 Y coordinate of the second point of the trigon.
2301 \param x3 X coordinate of the third point of the trigon.
2302 \param y3 Y coordinate of the third point of the trigon.
2303 \param r The red value of the trigon to draw.
2304 \param g The green value of the trigon to draw.
2305 \param b The blue value of the trigon to draw.
2306 \param a The alpha value of the trigon to draw.
2307 
2308 \returns Returns 0 on success, -1 on failure.
2309 */
trigonRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2310 int trigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
2311 	Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2312 {
2313 	Sint16 vx[3];
2314 	Sint16 vy[3];
2315 
2316 	vx[0]=x1;
2317 	vx[1]=x2;
2318 	vx[2]=x3;
2319 	vy[0]=y1;
2320 	vy[1]=y2;
2321 	vy[2]=y3;
2322 
2323 	return(polygonRGBA(renderer,vx,vy,3,r,g,b,a));
2324 }
2325 
2326 /* ------ AA-Trigon */
2327 
2328 /*!
2329 \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
2330 
2331 Note: Creates vertex array and uses aapolygon routine to render.
2332 
2333 \param renderer The renderer to draw on.
2334 \param x1 X coordinate of the first point of the aa-trigon.
2335 \param y1 Y coordinate of the first point of the aa-trigon.
2336 \param x2 X coordinate of the second point of the aa-trigon.
2337 \param y2 Y coordinate of the second point of the aa-trigon.
2338 \param x3 X coordinate of the third point of the aa-trigon.
2339 \param y3 Y coordinate of the third point of the aa-trigon.
2340 \param color The color value of the aa-trigon to draw (0xRRGGBBAA).
2341 
2342 \returns Returns 0 on success, -1 on failure.
2343 */
aatrigonColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)2344 int aatrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
2345 {
2346 	Sint16 vx[3];
2347 	Sint16 vy[3];
2348 
2349 	vx[0]=x1;
2350 	vx[1]=x2;
2351 	vx[2]=x3;
2352 	vy[0]=y1;
2353 	vy[1]=y2;
2354 	vy[2]=y3;
2355 
2356 	return(aapolygonColor(renderer,vx,vy,3,color));
2357 }
2358 
2359 /*!
2360 \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
2361 
2362 \param renderer The renderer to draw on.
2363 \param x1 X coordinate of the first point of the aa-trigon.
2364 \param y1 Y coordinate of the first point of the aa-trigon.
2365 \param x2 X coordinate of the second point of the aa-trigon.
2366 \param y2 Y coordinate of the second point of the aa-trigon.
2367 \param x3 X coordinate of the third point of the aa-trigon.
2368 \param y3 Y coordinate of the third point of the aa-trigon.
2369 \param r The red value of the aa-trigon to draw.
2370 \param g The green value of the aa-trigon to draw.
2371 \param b The blue value of the aa-trigon to draw.
2372 \param a The alpha value of the aa-trigon to draw.
2373 
2374 \returns Returns 0 on success, -1 on failure.
2375 */
aatrigonRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2376 int aatrigonRGBA(SDL_Renderer * renderer,  Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
2377 	Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2378 {
2379 	Sint16 vx[3];
2380 	Sint16 vy[3];
2381 
2382 	vx[0]=x1;
2383 	vx[1]=x2;
2384 	vx[2]=x3;
2385 	vy[0]=y1;
2386 	vy[1]=y2;
2387 	vy[2]=y3;
2388 
2389 	return(aapolygonRGBA(renderer,vx,vy,3,r,g,b,a));
2390 }
2391 
2392 /* ------ Filled Trigon */
2393 
2394 /*!
2395 \brief Draw filled trigon (triangle) with alpha blending.
2396 
2397 Note: Creates vertex array and uses aapolygon routine to render.
2398 
2399 \param renderer The renderer to draw on.
2400 \param x1 X coordinate of the first point of the filled trigon.
2401 \param y1 Y coordinate of the first point of the filled trigon.
2402 \param x2 X coordinate of the second point of the filled trigon.
2403 \param y2 Y coordinate of the second point of the filled trigon.
2404 \param x3 X coordinate of the third point of the filled trigon.
2405 \param y3 Y coordinate of the third point of the filled trigon.
2406 \param color The color value of the filled trigon to draw (0xRRGGBBAA).
2407 
2408 \returns Returns 0 on success, -1 on failure.
2409 */
filledTrigonColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)2410 int filledTrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
2411 {
2412 	Sint16 vx[3];
2413 	Sint16 vy[3];
2414 
2415 	vx[0]=x1;
2416 	vx[1]=x2;
2417 	vx[2]=x3;
2418 	vy[0]=y1;
2419 	vy[1]=y2;
2420 	vy[2]=y3;
2421 
2422 	return(filledPolygonColor(renderer,vx,vy,3,color));
2423 }
2424 
2425 /*!
2426 \brief Draw filled trigon (triangle) with alpha blending.
2427 
2428 Note: Creates vertex array and uses aapolygon routine to render.
2429 
2430 \param renderer The renderer to draw on.
2431 \param x1 X coordinate of the first point of the filled trigon.
2432 \param y1 Y coordinate of the first point of the filled trigon.
2433 \param x2 X coordinate of the second point of the filled trigon.
2434 \param y2 Y coordinate of the second point of the filled trigon.
2435 \param x3 X coordinate of the third point of the filled trigon.
2436 \param y3 Y coordinate of the third point of the filled trigon.
2437 \param r The red value of the filled trigon to draw.
2438 \param g The green value of the filled trigon to draw.
2439 \param b The blue value of the filled trigon to draw.
2440 \param a The alpha value of the filled trigon to draw.
2441 
2442 \returns Returns 0 on success, -1 on failure.
2443 */
filledTrigonRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2444 int filledTrigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
2445 	Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2446 {
2447 	Sint16 vx[3];
2448 	Sint16 vy[3];
2449 
2450 	vx[0]=x1;
2451 	vx[1]=x2;
2452 	vx[2]=x3;
2453 	vy[0]=y1;
2454 	vy[1]=y2;
2455 	vy[2]=y3;
2456 
2457 	return(filledPolygonRGBA(renderer,vx,vy,3,r,g,b,a));
2458 }
2459 
2460 /* ---- Polygon */
2461 
2462 /*!
2463 \brief Draw polygon with alpha blending.
2464 
2465 \param renderer The renderer to draw on.
2466 \param vx Vertex array containing X coordinates of the points of the polygon.
2467 \param vy Vertex array containing Y coordinates of the points of the polygon.
2468 \param n Number of points in the vertex array. Minimum number is 3.
2469 \param color The color value of the polygon to draw (0xRRGGBBAA).
2470 
2471 \returns Returns 0 on success, -1 on failure.
2472 */
polygonColor(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)2473 int polygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
2474 {
2475 	Uint8 *c = (Uint8 *)&color;
2476 	return polygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
2477 }
2478 
2479 /*!
2480 \brief Draw polygon with the currently set color and blend mode.
2481 
2482 \param renderer The renderer to draw on.
2483 \param vx Vertex array containing X coordinates of the points of the polygon.
2484 \param vy Vertex array containing Y coordinates of the points of the polygon.
2485 \param n Number of points in the vertex array. Minimum number is 3.
2486 
2487 \returns Returns 0 on success, -1 on failure.
2488 */
polygon(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n)2489 int polygon(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n)
2490 {
2491 	/*
2492 	* Draw
2493 	*/
2494 	int result = 0;
2495 	int i, nn;
2496 	SDL_Point* points;
2497 
2498 	/*
2499 	* Vertex array NULL check
2500 	*/
2501 	if (vx == NULL) {
2502 		return (-1);
2503 	}
2504 	if (vy == NULL) {
2505 		return (-1);
2506 	}
2507 
2508 	/*
2509 	* Sanity check
2510 	*/
2511 	if (n < 3) {
2512 		return (-1);
2513 	}
2514 
2515 	/*
2516 	* Create array of points
2517 	*/
2518 	nn = n + 1;
2519 	points = (SDL_Point*)malloc(sizeof(SDL_Point) * nn);
2520 	if (points == NULL)
2521 	{
2522 		return -1;
2523 	}
2524 	for (i=0; i<n; i++)
2525 	{
2526 		points[i].x = vx[i];
2527 		points[i].y = vy[i];
2528 	}
2529 	points[n].x = vx[0];
2530 	points[n].y = vy[0];
2531 
2532 	/*
2533 	* Draw
2534 	*/
2535 	result |= SDL_RenderDrawLines(renderer, points, nn);
2536 	free(points);
2537 
2538 	return (result);
2539 }
2540 
2541 /*!
2542 \brief Draw polygon with alpha blending.
2543 
2544 \param renderer The renderer to draw on.
2545 \param vx Vertex array containing X coordinates of the points of the polygon.
2546 \param vy Vertex array containing Y coordinates of the points of the polygon.
2547 \param n Number of points in the vertex array. Minimum number is 3.
2548 \param r The red value of the polygon to draw.
2549 \param g The green value of the polygon to draw.
2550 \param b The blue value of the polygon to draw.
2551 \param a The alpha value of the polygon to draw.
2552 
2553 \returns Returns 0 on success, -1 on failure.
2554 */
polygonRGBA(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2555 int polygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2556 {
2557 	/*
2558 	* Draw
2559 	*/
2560 	int result;
2561 	const Sint16 *x1, *y1, *x2, *y2;
2562 
2563 	/*
2564 	* Vertex array NULL check
2565 	*/
2566 	if (vx == NULL) {
2567 		return (-1);
2568 	}
2569 	if (vy == NULL) {
2570 		return (-1);
2571 	}
2572 
2573 	/*
2574 	* Sanity check
2575 	*/
2576 	if (n < 3) {
2577 		return (-1);
2578 	}
2579 
2580 	/*
2581 	* Pointer setup
2582 	*/
2583 	x1 = x2 = vx;
2584 	y1 = y2 = vy;
2585 	x2++;
2586 	y2++;
2587 
2588 	/*
2589 	* Set color
2590 	*/
2591 	result = 0;
2592 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
2593 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
2594 
2595 	/*
2596 	* Draw
2597 	*/
2598 	result |= polygon(renderer, vx, vy, n);
2599 
2600 	return (result);
2601 }
2602 
2603 /* ---- AA-Polygon */
2604 
2605 /*!
2606 \brief Draw anti-aliased polygon with alpha blending.
2607 
2608 \param renderer The renderer to draw on.
2609 \param vx Vertex array containing X coordinates of the points of the aa-polygon.
2610 \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
2611 \param n Number of points in the vertex array. Minimum number is 3.
2612 \param color The color value of the aa-polygon to draw (0xRRGGBBAA).
2613 
2614 \returns Returns 0 on success, -1 on failure.
2615 */
aapolygonColor(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)2616 int aapolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
2617 {
2618 	Uint8 *c = (Uint8 *)&color;
2619 	return aapolygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
2620 }
2621 
2622 /*!
2623 \brief Draw anti-aliased polygon with alpha blending.
2624 
2625 \param renderer The renderer to draw on.
2626 \param vx Vertex array containing X coordinates of the points of the aa-polygon.
2627 \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
2628 \param n Number of points in the vertex array. Minimum number is 3.
2629 \param r The red value of the aa-polygon to draw.
2630 \param g The green value of the aa-polygon to draw.
2631 \param b The blue value of the aa-polygon to draw.
2632 \param a The alpha value of the aa-polygon to draw.
2633 
2634 \returns Returns 0 on success, -1 on failure.
2635 */
aapolygonRGBA(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2636 int aapolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2637 {
2638 	int result;
2639 	int i;
2640 	const Sint16 *x1, *y1, *x2, *y2;
2641 
2642 	/*
2643 	* Vertex array NULL check
2644 	*/
2645 	if (vx == NULL) {
2646 		return (-1);
2647 	}
2648 	if (vy == NULL) {
2649 		return (-1);
2650 	}
2651 
2652 	/*
2653 	* Sanity check
2654 	*/
2655 	if (n < 3) {
2656 		return (-1);
2657 	}
2658 
2659 	/*
2660 	* Pointer setup
2661 	*/
2662 	x1 = x2 = vx;
2663 	y1 = y2 = vy;
2664 	x2++;
2665 	y2++;
2666 
2667 	/*
2668 	* Draw
2669 	*/
2670 	result = 0;
2671 	for (i = 1; i < n; i++) {
2672 		result |= _aalineRGBA(renderer, *x1, *y1, *x2, *y2, r, g, b, a, 0);
2673 		x1 = x2;
2674 		y1 = y2;
2675 		x2++;
2676 		y2++;
2677 	}
2678 
2679 	result |= _aalineRGBA(renderer, *x1, *y1, *vx, *vy, r, g, b, a, 0);
2680 
2681 	return (result);
2682 }
2683 
2684 /* ---- Filled Polygon */
2685 
2686 /*!
2687 \brief Internal helper qsort callback functions used in filled polygon drawing.
2688 
2689 \param a The surface to draw on.
2690 \param b Vertex array containing X coordinates of the points of the polygon.
2691 
2692 \returns Returns 0 if a==b, a negative number if a<b or a positive number if a>b.
2693 */
_gfxPrimitivesCompareInt(const void * a,const void * b)2694 int _gfxPrimitivesCompareInt(const void *a, const void *b)
2695 {
2696 	return (*(const int *) a) - (*(const int *) b);
2697 }
2698 
2699 /*!
2700 \brief Global vertex array to use if optional parameters are not given in filledPolygonMT calls.
2701 
2702 Note: Used for non-multithreaded (default) operation of filledPolygonMT.
2703 */
2704 static int *gfxPrimitivesPolyIntsGlobal = NULL;
2705 
2706 /*!
2707 \brief Flag indicating if global vertex array was already allocated.
2708 
2709 Note: Used for non-multithreaded (default) operation of filledPolygonMT.
2710 */
2711 static int gfxPrimitivesPolyAllocatedGlobal = 0;
2712 
2713 /*!
2714 \brief Draw filled polygon with alpha blending (multi-threaded capable).
2715 
2716 Note: The last two parameters are optional; but are required for multithreaded operation.
2717 
2718 \param renderer The renderer to draw on.
2719 \param vx Vertex array containing X coordinates of the points of the filled polygon.
2720 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
2721 \param n Number of points in the vertex array. Minimum number is 3.
2722 \param r The red value of the filled polygon to draw.
2723 \param g The green value of the filled polygon to draw.
2724 \param b The blue value of the filled polygon to draw.
2725 \param a The alpha value of the filled polygon to draw.
2726 \param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise.
2727 \param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise.
2728 
2729 \returns Returns 0 on success, -1 on failure.
2730 */
filledPolygonRGBAMT(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a,int ** polyInts,int * polyAllocated)2731 int filledPolygonRGBAMT(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int **polyInts, int *polyAllocated)
2732 {
2733 	int result;
2734 	int i;
2735 	int y, xa, xb;
2736 	int miny, maxy;
2737 	int x1, y1;
2738 	int x2, y2;
2739 	int ind1, ind2;
2740 	int ints;
2741 	int *gfxPrimitivesPolyInts = NULL;
2742 	int *gfxPrimitivesPolyIntsNew = NULL;
2743 	int gfxPrimitivesPolyAllocated = 0;
2744 
2745 	/*
2746 	* Vertex array NULL check
2747 	*/
2748 	if (vx == NULL) {
2749 		return (-1);
2750 	}
2751 	if (vy == NULL) {
2752 		return (-1);
2753 	}
2754 
2755 	/*
2756 	* Sanity check number of edges
2757 	*/
2758 	if (n < 3) {
2759 		return -1;
2760 	}
2761 
2762 	/*
2763 	* Map polygon cache
2764 	*/
2765 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
2766 		/* Use global cache */
2767 		gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
2768 		gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
2769 	} else {
2770 		/* Use local cache */
2771 		gfxPrimitivesPolyInts = *polyInts;
2772 		gfxPrimitivesPolyAllocated = *polyAllocated;
2773 	}
2774 
2775 	/*
2776 	* Allocate temp array, only grow array
2777 	*/
2778 	if (!gfxPrimitivesPolyAllocated) {
2779 		gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
2780 		gfxPrimitivesPolyAllocated = n;
2781 	} else {
2782 		if (gfxPrimitivesPolyAllocated < n) {
2783 			gfxPrimitivesPolyIntsNew = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
2784 			if (!gfxPrimitivesPolyIntsNew) {
2785 				if (!gfxPrimitivesPolyInts) {
2786 					free(gfxPrimitivesPolyInts);
2787 					gfxPrimitivesPolyInts = NULL;
2788 				}
2789 				gfxPrimitivesPolyAllocated = 0;
2790 			} else {
2791 				gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsNew;
2792 				gfxPrimitivesPolyAllocated = n;
2793 			}
2794 		}
2795 	}
2796 
2797 	/*
2798 	* Check temp array
2799 	*/
2800 	if (gfxPrimitivesPolyInts==NULL) {
2801 		gfxPrimitivesPolyAllocated = 0;
2802 	}
2803 
2804 	/*
2805 	* Update cache variables
2806 	*/
2807 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
2808 		gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
2809 		gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
2810 	} else {
2811 		*polyInts = gfxPrimitivesPolyInts;
2812 		*polyAllocated = gfxPrimitivesPolyAllocated;
2813 	}
2814 
2815 	/*
2816 	* Check temp array again
2817 	*/
2818 	if (gfxPrimitivesPolyInts==NULL) {
2819 		return(-1);
2820 	}
2821 
2822 	/*
2823 	* Determine Y maxima
2824 	*/
2825 	miny = vy[0];
2826 	maxy = vy[0];
2827 	for (i = 1; (i < n); i++) {
2828 		if (vy[i] < miny) {
2829 			miny = vy[i];
2830 		} else if (vy[i] > maxy) {
2831 			maxy = vy[i];
2832 		}
2833 	}
2834 
2835 	/*
2836 	* Draw, scanning y
2837 	*/
2838 	result = 0;
2839 	for (y = miny; (y <= maxy); y++) {
2840 		ints = 0;
2841 		for (i = 0; (i < n); i++) {
2842 			if (!i) {
2843 				ind1 = n - 1;
2844 				ind2 = 0;
2845 			} else {
2846 				ind1 = i - 1;
2847 				ind2 = i;
2848 			}
2849 			y1 = vy[ind1];
2850 			y2 = vy[ind2];
2851 			if (y1 < y2) {
2852 				x1 = vx[ind1];
2853 				x2 = vx[ind2];
2854 			} else if (y1 > y2) {
2855 				y2 = vy[ind1];
2856 				y1 = vy[ind2];
2857 				x2 = vx[ind1];
2858 				x1 = vx[ind2];
2859 			} else {
2860 				continue;
2861 			}
2862 			if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
2863 				gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
2864 			}
2865 		}
2866 
2867 		qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
2868 
2869 		/*
2870 		* Set color
2871 		*/
2872 		result = 0;
2873 	    result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
2874 		result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
2875 
2876 		for (i = 0; (i < ints); i += 2) {
2877 			xa = gfxPrimitivesPolyInts[i] + 1;
2878 			xa = (xa >> 16) + ((xa & 32768) >> 15);
2879 			xb = gfxPrimitivesPolyInts[i+1] - 1;
2880 			xb = (xb >> 16) + ((xb & 32768) >> 15);
2881 			result |= hline(renderer, xa, xb, y);
2882 		}
2883 	}
2884 
2885 	return (result);
2886 }
2887 
2888 /*!
2889 \brief Draw filled polygon with alpha blending.
2890 
2891 \param renderer The renderer to draw on.
2892 \param vx Vertex array containing X coordinates of the points of the filled polygon.
2893 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
2894 \param n Number of points in the vertex array. Minimum number is 3.
2895 \param color The color value of the filled polygon to draw (0xRRGGBBAA).
2896 
2897 \returns Returns 0 on success, -1 on failure.
2898 */
filledPolygonColor(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)2899 int filledPolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
2900 {
2901 	Uint8 *c = (Uint8 *)&color;
2902 	return filledPolygonRGBAMT(renderer, vx, vy, n, c[0], c[1], c[2], c[3], NULL, NULL);
2903 }
2904 
2905 /*!
2906 \brief Draw filled polygon with alpha blending.
2907 
2908 \param renderer The renderer to draw on.
2909 \param vx Vertex array containing X coordinates of the points of the filled polygon.
2910 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
2911 \param n Number of points in the vertex array. Minimum number is 3.
2912 \param r The red value of the filled polygon to draw.
2913 \param g The green value of the filled polygon to draw.
2914 \param b The blue value of the filed polygon to draw.
2915 \param a The alpha value of the filled polygon to draw.
2916 
2917 \returns Returns 0 on success, -1 on failure.
2918 */
filledPolygonRGBA(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2919 int filledPolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2920 {
2921 	return filledPolygonRGBAMT(renderer, vx, vy, n, r, g, b, a, NULL, NULL);
2922 }
2923 
2924 /* ---- Textured Polygon */
2925 
2926 /*!
2927 \brief Internal function to draw a textured horizontal line.
2928 
2929 \param renderer The renderer to draw on.
2930 \param x1 X coordinate of the first point (i.e. left) of the line.
2931 \param x2 X coordinate of the second point (i.e. right) of the line.
2932 \param y Y coordinate of the points of the line.
2933 \param texture The texture to retrieve color information from.
2934 \param texture_w The width of the texture.
2935 \param texture_h The height of the texture.
2936 \param texture_dx The X offset for the texture lookup.
2937 \param texture_dy The Y offset for the textured lookup.
2938 
2939 \returns Returns 0 on success, -1 on failure.
2940 */
_HLineTextured(SDL_Renderer * renderer,Sint16 x1,Sint16 x2,Sint16 y,SDL_Texture * texture,int texture_w,int texture_h,int texture_dx,int texture_dy)2941 int _HLineTextured(SDL_Renderer *renderer, Sint16 x1, Sint16 x2, Sint16 y, SDL_Texture *texture, int texture_w, int texture_h, int texture_dx, int texture_dy)
2942 {
2943 	Sint16 w;
2944 	Sint16 xtmp;
2945 	int result = 0;
2946 	int texture_x_walker;
2947 	int texture_y_start;
2948 	SDL_Rect source_rect,dst_rect;
2949 	int pixels_written,write_width;
2950 
2951 	/*
2952 	* Swap x1, x2 if required to ensure x1<=x2
2953 	*/
2954 	if (x1 > x2) {
2955 		xtmp = x1;
2956 		x1 = x2;
2957 		x2 = xtmp;
2958 	}
2959 
2960 	/*
2961 	* Calculate width to draw
2962 	*/
2963 	w = x2 - x1 + 1;
2964 
2965 	/*
2966 	* Determine where in the texture we start drawing
2967 	*/
2968 	texture_x_walker =   (x1 - texture_dx)  % texture_w;
2969 	if (texture_x_walker < 0){
2970 		texture_x_walker = texture_w + texture_x_walker ;
2971 	}
2972 
2973 	texture_y_start = (y + texture_dy) % texture_h;
2974 	if (texture_y_start < 0){
2975 		texture_y_start = texture_h + texture_y_start;
2976 	}
2977 
2978 	/* setup the source rectangle; we are only drawing one horizontal line */
2979 	source_rect.y = texture_y_start;
2980 	source_rect.x = texture_x_walker;
2981 	source_rect.h = 1;
2982 
2983 	/* we will draw to the current y */
2984 	dst_rect.y = y;
2985 	dst_rect.h = 1;
2986 
2987 	/* if there are enough pixels left in the current row of the texture */
2988 	/* draw it all at once */
2989 	if (w <= texture_w -texture_x_walker){
2990 		source_rect.w = w;
2991 		source_rect.x = texture_x_walker;
2992 		dst_rect.x= x1;
2993 		dst_rect.w = source_rect.w;
2994 		result = (SDL_RenderCopy(renderer, texture, &source_rect, &dst_rect) == 0);
2995 	} else {
2996 		/* we need to draw multiple times */
2997 		/* draw the first segment */
2998 		pixels_written = texture_w  - texture_x_walker;
2999 		source_rect.w = pixels_written;
3000 		source_rect.x = texture_x_walker;
3001 		dst_rect.x= x1;
3002 		dst_rect.w = source_rect.w;
3003 		result |= (SDL_RenderCopy(renderer, texture, &source_rect, &dst_rect) == 0);
3004 		write_width = texture_w;
3005 
3006 		/* now draw the rest */
3007 		/* set the source x to 0 */
3008 		source_rect.x = 0;
3009 		while (pixels_written < w){
3010 			if (write_width >= w - pixels_written) {
3011 				write_width =  w - pixels_written;
3012 			}
3013 			source_rect.w = write_width;
3014 			dst_rect.x = x1 + pixels_written;
3015 			dst_rect.w = source_rect.w;
3016 			result |= (SDL_RenderCopy(renderer, texture, &source_rect, &dst_rect) == 0);
3017 			pixels_written += write_width;
3018 		}
3019 	}
3020 
3021 	return result;
3022 }
3023 
3024 /*!
3025 \brief Draws a polygon filled with the given texture (Multi-Threading Capable).
3026 
3027 \param renderer The renderer to draw on.
3028 \param vx array of x vector components
3029 \param vy array of x vector components
3030 \param n the amount of vectors in the vx and vy array
3031 \param texture the sdl surface to use to fill the polygon
3032 \param texture_dx the offset of the texture relative to the screeen. If you move the polygon 10 pixels
3033 to the left and want the texture to apear the same you need to increase the texture_dx value
3034 \param texture_dy see texture_dx
3035 \param polyInts Preallocated temp array storage for vertex sorting (used for multi-threaded operation)
3036 \param polyAllocated Flag indicating oif the temp array was allocated (used for multi-threaded operation)
3037 
3038 \returns Returns 0 on success, -1 on failure.
3039 */
texturedPolygonMT(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy,int ** polyInts,int * polyAllocated)3040 int texturedPolygonMT(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n,
3041 	SDL_Surface * texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated)
3042 {
3043 	int result;
3044 	int i;
3045 	int y, xa, xb;
3046 	int minx,maxx,miny, maxy;
3047 	int x1, y1;
3048 	int x2, y2;
3049 	int ind1, ind2;
3050 	int ints;
3051 	int *gfxPrimitivesPolyInts = NULL;
3052 	int *gfxPrimitivesPolyIntsTemp = NULL;
3053 	int gfxPrimitivesPolyAllocated = 0;
3054 	SDL_Texture *textureAsTexture = NULL;
3055 
3056 	/*
3057 	* Sanity check number of edges
3058 	*/
3059 	if (n < 3) {
3060 		return -1;
3061 	}
3062 
3063 	/*
3064 	* Map polygon cache
3065 	*/
3066 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
3067 		/* Use global cache */
3068 		gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
3069 		gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
3070 	} else {
3071 		/* Use local cache */
3072 		gfxPrimitivesPolyInts = *polyInts;
3073 		gfxPrimitivesPolyAllocated = *polyAllocated;
3074 	}
3075 
3076 	/*
3077 	* Allocate temp array, only grow array
3078 	*/
3079 	if (!gfxPrimitivesPolyAllocated) {
3080 		gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
3081 		gfxPrimitivesPolyAllocated = n;
3082 	} else {
3083 		if (gfxPrimitivesPolyAllocated < n) {
3084 			gfxPrimitivesPolyIntsTemp = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
3085 			if (gfxPrimitivesPolyIntsTemp == NULL) {
3086 				/* Realloc failed - keeps original memory block, but fails this operation */
3087 				return(-1);
3088 			}
3089 			gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsTemp;
3090 			gfxPrimitivesPolyAllocated = n;
3091 		}
3092 	}
3093 
3094 	/*
3095 	* Check temp array
3096 	*/
3097 	if (gfxPrimitivesPolyInts==NULL) {
3098 		gfxPrimitivesPolyAllocated = 0;
3099 	}
3100 
3101 	/*
3102 	* Update cache variables
3103 	*/
3104 	if ((polyInts==NULL) || (polyAllocated==NULL)) {
3105 		gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
3106 		gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
3107 	} else {
3108 		*polyInts = gfxPrimitivesPolyInts;
3109 		*polyAllocated = gfxPrimitivesPolyAllocated;
3110 	}
3111 
3112 	/*
3113 	* Check temp array again
3114 	*/
3115 	if (gfxPrimitivesPolyInts==NULL) {
3116 		return(-1);
3117 	}
3118 
3119 	/*
3120 	* Determine X,Y minima,maxima
3121 	*/
3122 	miny = vy[0];
3123 	maxy = vy[0];
3124 	minx = vx[0];
3125 	maxx = vx[0];
3126 	for (i = 1; (i < n); i++) {
3127 		if (vy[i] < miny) {
3128 			miny = vy[i];
3129 		} else if (vy[i] > maxy) {
3130 			maxy = vy[i];
3131 		}
3132 		if (vx[i] < minx) {
3133 			minx = vx[i];
3134 		} else if (vx[i] > maxx) {
3135 			maxx = vx[i];
3136 		}
3137 	}
3138 
3139     /* Create texture for drawing */
3140 	textureAsTexture = SDL_CreateTextureFromSurface(renderer, texture);
3141 	if (textureAsTexture == NULL)
3142 	{
3143 		return -1;
3144 	}
3145 	SDL_SetTextureBlendMode(textureAsTexture, SDL_BLENDMODE_BLEND);
3146 
3147 	/*
3148 	* Draw, scanning y
3149 	*/
3150 	result = 0;
3151 	for (y = miny; (y <= maxy); y++) {
3152 		ints = 0;
3153 		for (i = 0; (i < n); i++) {
3154 			if (!i) {
3155 				ind1 = n - 1;
3156 				ind2 = 0;
3157 			} else {
3158 				ind1 = i - 1;
3159 				ind2 = i;
3160 			}
3161 			y1 = vy[ind1];
3162 			y2 = vy[ind2];
3163 			if (y1 < y2) {
3164 				x1 = vx[ind1];
3165 				x2 = vx[ind2];
3166 			} else if (y1 > y2) {
3167 				y2 = vy[ind1];
3168 				y1 = vy[ind2];
3169 				x2 = vx[ind1];
3170 				x1 = vx[ind2];
3171 			} else {
3172 				continue;
3173 			}
3174 			if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
3175 				gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
3176 			}
3177 		}
3178 
3179 		qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
3180 
3181 		for (i = 0; (i < ints); i += 2) {
3182 			xa = gfxPrimitivesPolyInts[i] + 1;
3183 			xa = (xa >> 16) + ((xa & 32768) >> 15);
3184 			xb = gfxPrimitivesPolyInts[i+1] - 1;
3185 			xb = (xb >> 16) + ((xb & 32768) >> 15);
3186 			result |= _HLineTextured(renderer, xa, xb, y, textureAsTexture, texture->w, texture->h, texture_dx, texture_dy);
3187 		}
3188 	}
3189 
3190 	SDL_RenderPresent(renderer);
3191 	SDL_DestroyTexture(textureAsTexture);
3192 
3193 	return (result);
3194 }
3195 
3196 /*!
3197 \brief Draws a polygon filled with the given texture.
3198 
3199 This standard version is calling multithreaded versions with NULL cache parameters.
3200 
3201 \param renderer The renderer to draw on.
3202 \param vx array of x vector components
3203 \param vy array of x vector components
3204 \param n the amount of vectors in the vx and vy array
3205 \param texture the sdl surface to use to fill the polygon
3206 \param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
3207 to the left and want the texture to apear the same you need to increase the texture_dx value
3208 \param texture_dy see texture_dx
3209 
3210 \returns Returns 0 on success, -1 on failure.
3211 */
texturedPolygon(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy)3212 int texturedPolygon(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
3213 {
3214 	/*
3215 	* Draw
3216 	*/
3217 	return (texturedPolygonMT(renderer, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
3218 }
3219 
3220 /* ---- Character */
3221 
3222 /*!
3223 \brief Global cache for NxM pixel font textures created at runtime.
3224 */
3225 static SDL_Texture *gfxPrimitivesFont[256];
3226 
3227 /*!
3228 \brief Pointer to the current font data. Default is a 8x8 pixel internal font.
3229 */
3230 static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
3231 
3232 /*!
3233 \brief Width of the current font. Default is 8.
3234 */
3235 static Uint32 charWidth = 8;
3236 
3237 /*!
3238 \brief Height of the current font. Default is 8.
3239 */
3240 static Uint32 charHeight = 8;
3241 
3242 /*!
3243 \brief Width for rendering. Autocalculated.
3244 */
3245 static Uint32 charWidthLocal = 8;
3246 
3247 /*!
3248 \brief Height for rendering. Autocalculated.
3249 */
3250 static Uint32 charHeightLocal = 8;
3251 
3252 /*!
3253 \brief Pitch of the current font in bytes. Default is 1.
3254 */
3255 static Uint32 charPitch = 1;
3256 
3257 /*!
3258 \brief Characters 90deg clockwise rotations. Default is 0. Max is 3.
3259 */
3260 static Uint32 charRotation = 0;
3261 
3262 /*!
3263 \brief Character data size in bytes of the current font. Default is 8.
3264 */
3265 static Uint32 charSize = 8;
3266 
3267 /*!
3268 \brief Sets or resets the current global font data.
3269 
3270 The font data array is organized in follows:
3271 [fontdata] = [character 0][character 1]...[character 255] where
3272 [character n] = [byte 1 row 1][byte 2 row 1]...[byte {pitch} row 1][byte 1 row 2] ...[byte {pitch} row height] where
3273 [byte n] = [bit 0]...[bit 7] where
3274 [bit n] = [0 for transparent pixel|1 for colored pixel]
3275 
3276 \param fontdata Pointer to array of font data. Set to NULL, to reset global font to the default 8x8 font.
3277 \param cw Width of character in bytes. Ignored if fontdata==NULL.
3278 \param ch Height of character in bytes. Ignored if fontdata==NULL.
3279 */
gfxPrimitivesSetFont(const void * fontdata,Uint32 cw,Uint32 ch)3280 void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch)
3281 {
3282 	int i;
3283 
3284 	if ((fontdata) && (cw) && (ch)) {
3285 		currentFontdata = (unsigned char *)fontdata;
3286 		charWidth = cw;
3287 		charHeight = ch;
3288 	} else {
3289 		currentFontdata = gfxPrimitivesFontdata;
3290 		charWidth = 8;
3291 		charHeight = 8;
3292 	}
3293 
3294 	charPitch = (charWidth+7)/8;
3295 	charSize = charPitch * charHeight;
3296 
3297 	/* Maybe flip width/height for rendering */
3298 	if ((charRotation==1) || (charRotation==3))
3299 	{
3300 		charWidthLocal = charHeight;
3301 		charHeightLocal = charWidth;
3302 	}
3303 	else
3304 	{
3305 		charWidthLocal = charWidth;
3306 		charHeightLocal = charHeight;
3307 	}
3308 
3309 	/* Clear character cache */
3310 	for (i = 0; i < 256; i++) {
3311 		if (gfxPrimitivesFont[i]) {
3312 			SDL_DestroyTexture(gfxPrimitivesFont[i]);
3313 			gfxPrimitivesFont[i] = NULL;
3314 		}
3315 	}
3316 }
3317 
3318 /*!
3319 \brief Sets current global font character rotation steps.
3320 
3321 Default is 0 (no rotation). 1 = 90deg clockwise. 2 = 180deg clockwise. 3 = 270deg clockwise.
3322 Changing the rotation, will reset the character cache.
3323 
3324 \param rotation Number of 90deg clockwise steps to rotate
3325 */
gfxPrimitivesSetFontRotation(Uint32 rotation)3326 void gfxPrimitivesSetFontRotation(Uint32 rotation)
3327 {
3328 	int i;
3329 
3330 	rotation = rotation & 3;
3331 	if (charRotation != rotation)
3332 	{
3333 		/* Store rotation */
3334 		charRotation = rotation;
3335 
3336 		/* Maybe flip width/height for rendering */
3337 		if ((charRotation==1) || (charRotation==3))
3338 		{
3339 			charWidthLocal = charHeight;
3340 			charHeightLocal = charWidth;
3341 		}
3342 		else
3343 		{
3344 			charWidthLocal = charWidth;
3345 			charHeightLocal = charHeight;
3346 		}
3347 
3348 		/* Clear character cache */
3349 		for (i = 0; i < 256; i++) {
3350 			if (gfxPrimitivesFont[i]) {
3351 				SDL_DestroyTexture(gfxPrimitivesFont[i]);
3352 				gfxPrimitivesFont[i] = NULL;
3353 			}
3354 		}
3355 	}
3356 }
3357 
3358 /*!
3359 \brief Draw a character of the currently set font.
3360 
3361 \param renderer The Renderer to draw on.
3362 \param x X (horizontal) coordinate of the upper left corner of the character.
3363 \param y Y (vertical) coordinate of the upper left corner of the character.
3364 \param c The character to draw.
3365 \param r The red value of the character to draw.
3366 \param g The green value of the character to draw.
3367 \param b The blue value of the character to draw.
3368 \param a The alpha value of the character to draw.
3369 
3370 \returns Returns 0 on success, -1 on failure.
3371 */
characterRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,char c,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3372 int characterRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3373 {
3374 	SDL_Rect srect;
3375 	SDL_Rect drect;
3376 	int result;
3377 	Uint32 ix, iy;
3378 	const unsigned char *charpos;
3379 	Uint8 *curpos;
3380 	Uint8 patt, mask;
3381 	Uint8 *linepos;
3382 	Uint32 pitch;
3383 	SDL_Surface *character;
3384 	SDL_Surface *rotatedCharacter;
3385 	Uint32 ci;
3386 
3387 	/*
3388 	* Setup source rectangle
3389 	*/
3390 	srect.x = 0;
3391 	srect.y = 0;
3392 	srect.w = charWidthLocal;
3393 	srect.h = charHeightLocal;
3394 
3395 	/*
3396 	* Setup destination rectangle
3397 	*/
3398 	drect.x = x;
3399 	drect.y = y;
3400 	drect.w = charWidthLocal;
3401 	drect.h = charHeightLocal;
3402 
3403 	/* Character index in cache */
3404 	ci = (unsigned char) c;
3405 
3406 	/*
3407 	* Create new charWidth x charHeight bitmap surface if not already present.
3408 	* Might get rotated later.
3409 	*/
3410 	if (gfxPrimitivesFont[ci] == NULL) {
3411 		/*
3412 		* Redraw character into surface
3413 		*/
3414 		character =	SDL_CreateRGBSurface(SDL_SWSURFACE,
3415 			charWidth, charHeight, 32,
3416 			0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
3417 		if (character == NULL) {
3418 			return (-1);
3419 		}
3420 
3421 		charpos = currentFontdata + ci * charSize;
3422 				linepos = (Uint8 *)character->pixels;
3423 		pitch = character->pitch;
3424 
3425 		/*
3426 		* Drawing loop
3427 		*/
3428 		patt = 0;
3429 		for (iy = 0; iy < charHeight; iy++) {
3430 			mask = 0x00;
3431 			curpos = linepos;
3432 			for (ix = 0; ix < charWidth; ix++) {
3433 				if (!(mask >>= 1)) {
3434 					patt = *charpos++;
3435 					mask = 0x80;
3436 				}
3437 				if (patt & mask) {
3438 					*(Uint32 *)curpos = 0xffffffff;
3439 				} else {
3440 					*(Uint32 *)curpos = 0;
3441 				}
3442 				curpos += 4;
3443 			}
3444 			linepos += pitch;
3445 		}
3446 
3447 		/* Maybe rotate and replace cached image */
3448 		if (charRotation>0)
3449 		{
3450 			rotatedCharacter = rotateSurface90Degrees(character, charRotation);
3451 			SDL_FreeSurface(character);
3452 			character = rotatedCharacter;
3453 		}
3454 
3455 		/* Convert temp surface into texture */
3456 		gfxPrimitivesFont[ci] = SDL_CreateTextureFromSurface(renderer, character);
3457 		SDL_FreeSurface(character);
3458 
3459 		/*
3460 		* Check pointer
3461 		*/
3462 		if (gfxPrimitivesFont[ci] == NULL) {
3463 			return (-1);
3464 		}
3465 	}
3466 
3467 	/*
3468 	* Set color
3469 	*/
3470 	result = 0;
3471 	result |= SDL_SetTextureColorMod(gfxPrimitivesFont[ci], r, g, b);
3472 	result |= SDL_SetTextureAlphaMod(gfxPrimitivesFont[ci], a);
3473 
3474 	/*
3475 	* Draw texture onto destination
3476 	*/
3477 	result |= SDL_RenderCopy(renderer, gfxPrimitivesFont[ci], &srect, &drect);
3478 
3479 	return (result);
3480 }
3481 
3482 
3483 /*!
3484 \brief Draw a character of the currently set font.
3485 
3486 \param renderer The renderer to draw on.
3487 \param x X (horizontal) coordinate of the upper left corner of the character.
3488 \param y Y (vertical) coordinate of the upper left corner of the character.
3489 \param c The character to draw.
3490 \param color The color value of the character to draw (0xRRGGBBAA).
3491 
3492 \returns Returns 0 on success, -1 on failure.
3493 */
characterColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,char c,Uint32 color)3494 int characterColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, char c, Uint32 color)
3495 {
3496 	Uint8 *co = (Uint8 *)&color;
3497 	return characterRGBA(renderer, x, y, c, co[0], co[1], co[2], co[3]);
3498 }
3499 
3500 
3501 /*!
3502 \brief Draw a string in the currently set font.
3503 
3504 The spacing between consequtive characters in the string is the fixed number of pixels
3505 of the character width of the current global font.
3506 
3507 \param renderer The renderer to draw on.
3508 \param x X (horizontal) coordinate of the upper left corner of the string.
3509 \param y Y (vertical) coordinate of the upper left corner of the string.
3510 \param s The string to draw.
3511 \param color The color value of the string to draw (0xRRGGBBAA).
3512 
3513 \returns Returns 0 on success, -1 on failure.
3514 */
stringColor(SDL_Renderer * renderer,Sint16 x,Sint16 y,const char * s,Uint32 color)3515 int stringColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint32 color)
3516 {
3517 	Uint8 *c = (Uint8 *)&color;
3518 	return stringRGBA(renderer, x, y, s, c[0], c[1], c[2], c[3]);
3519 }
3520 
3521 /*!
3522 \brief Draw a string in the currently set font.
3523 
3524 \param renderer The renderer to draw on.
3525 \param x X (horizontal) coordinate of the upper left corner of the string.
3526 \param y Y (vertical) coordinate of the upper left corner of the string.
3527 \param s The string to draw.
3528 \param r The red value of the string to draw.
3529 \param g The green value of the string to draw.
3530 \param b The blue value of the string to draw.
3531 \param a The alpha value of the string to draw.
3532 
3533 \returns Returns 0 on success, -1 on failure.
3534 */
stringRGBA(SDL_Renderer * renderer,Sint16 x,Sint16 y,const char * s,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3535 int stringRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3536 {
3537 	int result = 0;
3538 	Sint16 curx = x;
3539 	Sint16 cury = y;
3540 	const char *curchar = s;
3541 
3542 	while (*curchar && !result) {
3543 		result |= characterRGBA(renderer, curx, cury, *curchar, r, g, b, a);
3544 		switch (charRotation)
3545 		{
3546 		case 0:
3547 			curx += charWidthLocal;
3548 			break;
3549 		case 2:
3550 			curx -= charWidthLocal;
3551 			break;
3552 		case 1:
3553 			cury += charHeightLocal;
3554 			break;
3555 		case 3:
3556 			cury -= charHeightLocal;
3557 			break;
3558 		}
3559 		curchar++;
3560 	}
3561 
3562 	return (result);
3563 }
3564 
3565 /* ---- Bezier curve */
3566 
3567 /*!
3568 \brief Internal function to calculate bezier interpolator of data array with ndata values at position 't'.
3569 
3570 \param data Array of values.
3571 \param ndata Size of array.
3572 \param t Position for which to calculate interpolated value. t should be between [0, ndata].
3573 
3574 \returns Interpolated value at position t, value[0] when t<0, value[n-1] when t>n.
3575 */
_evaluateBezier(double * data,int ndata,double t)3576 double _evaluateBezier (double *data, int ndata, double t)
3577 {
3578 	double mu, result;
3579 	int n,k,kn,nn,nkn;
3580 	double blend,muk,munk;
3581 
3582 	/* Sanity check bounds */
3583 	if (t<0.0) {
3584 		return(data[0]);
3585 	}
3586 	if (t>=(double)ndata) {
3587 		return(data[ndata-1]);
3588 	}
3589 
3590 	/* Adjust t to the range 0.0 to 1.0 */
3591 	mu=t/(double)ndata;
3592 
3593 	/* Calculate interpolate */
3594 	n=ndata-1;
3595 	result=0.0;
3596 	muk = 1;
3597 	munk = pow(1-mu,(double)n);
3598 	for (k=0;k<=n;k++) {
3599 		nn = n;
3600 		kn = k;
3601 		nkn = n - k;
3602 		blend = muk * munk;
3603 		muk *= mu;
3604 		munk /= (1-mu);
3605 		while (nn >= 1) {
3606 			blend *= nn;
3607 			nn--;
3608 			if (kn > 1) {
3609 				blend /= (double)kn;
3610 				kn--;
3611 			}
3612 			if (nkn > 1) {
3613 				blend /= (double)nkn;
3614 				nkn--;
3615 			}
3616 		}
3617 		result += data[k] * blend;
3618 	}
3619 
3620 	return (result);
3621 }
3622 
3623 /*!
3624 \brief Draw a bezier curve with alpha blending.
3625 
3626 \param renderer The renderer to draw on.
3627 \param vx Vertex array containing X coordinates of the points of the bezier curve.
3628 \param vy Vertex array containing Y coordinates of the points of the bezier curve.
3629 \param n Number of points in the vertex array. Minimum number is 3.
3630 \param s Number of steps for the interpolation. Minimum number is 2.
3631 \param color The color value of the bezier curve to draw (0xRRGGBBAA).
3632 
3633 \returns Returns 0 on success, -1 on failure.
3634 */
bezierColor(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint32 color)3635 int bezierColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
3636 {
3637 	Uint8 *c = (Uint8 *)&color;
3638 	return bezierRGBA(renderer, vx, vy, n, s, c[0], c[1], c[2], c[3]);
3639 }
3640 
3641 /*!
3642 \brief Draw a bezier curve with alpha blending.
3643 
3644 \param renderer The renderer to draw on.
3645 \param vx Vertex array containing X coordinates of the points of the bezier curve.
3646 \param vy Vertex array containing Y coordinates of the points of the bezier curve.
3647 \param n Number of points in the vertex array. Minimum number is 3.
3648 \param s Number of steps for the interpolation. Minimum number is 2.
3649 \param r The red value of the bezier curve to draw.
3650 \param g The green value of the bezier curve to draw.
3651 \param b The blue value of the bezier curve to draw.
3652 \param a The alpha value of the bezier curve to draw.
3653 
3654 \returns Returns 0 on success, -1 on failure.
3655 */
bezierRGBA(SDL_Renderer * renderer,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3656 int bezierRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3657 {
3658 	int result;
3659 	int i;
3660 	double *x, *y, t, stepsize;
3661 	Sint16 x1, y1, x2, y2;
3662 
3663 	/*
3664 	* Sanity check
3665 	*/
3666 	if (n < 3) {
3667 		return (-1);
3668 	}
3669 	if (s < 2) {
3670 		return (-1);
3671 	}
3672 
3673 	/*
3674 	* Variable setup
3675 	*/
3676 	stepsize=(double)1.0/(double)s;
3677 
3678 	/* Transfer vertices into float arrays */
3679 	if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
3680 		return(-1);
3681 	}
3682 	if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
3683 		free(x);
3684 		return(-1);
3685 	}
3686 	for (i=0; i<n; i++) {
3687 		x[i]=(double)vx[i];
3688 		y[i]=(double)vy[i];
3689 	}
3690 	x[n]=(double)vx[0];
3691 	y[n]=(double)vy[0];
3692 
3693 	/*
3694 	* Set color
3695 	*/
3696 	result = 0;
3697 	result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
3698 	result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
3699 
3700 	/*
3701 	* Draw
3702 	*/
3703 	t=0.0;
3704 	x1=(Sint16)lrint(_evaluateBezier(x,n+1,t));
3705 	y1=(Sint16)lrint(_evaluateBezier(y,n+1,t));
3706 	for (i = 0; i <= (n*s); i++) {
3707 		t += stepsize;
3708 		x2=(Sint16)_evaluateBezier(x,n,t);
3709 		y2=(Sint16)_evaluateBezier(y,n,t);
3710 		result |= line(renderer, x1, y1, x2, y2);
3711 		x1 = x2;
3712 		y1 = y2;
3713 	}
3714 
3715 	/* Clean up temporary array */
3716 	free(x);
3717 	free(y);
3718 
3719 	return (result);
3720 }
3721 
3722 
3723 /*!
3724 \brief Draw a thick line with alpha blending.
3725 
3726 \param renderer The renderer to draw on.
3727 \param x1 X coordinate of the first point of the line.
3728 \param y1 Y coordinate of the first point of the line.
3729 \param x2 X coordinate of the second point of the line.
3730 \param y2 Y coordinate of the second point of the line.
3731 \param width Width of the line in pixels. Must be >0.
3732 \param color The color value of the line to draw (0xRRGGBBAA).
3733 
3734 \returns Returns 0 on success, -1 on failure.
3735 */
thickLineColor(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint32 color)3736 int thickLineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
3737 {
3738 	Uint8 *c = (Uint8 *)&color;
3739 	return thickLineRGBA(renderer, x1, y1, x2, y2, width, c[0], c[1], c[2], c[3]);
3740 }
3741 
3742 /*!
3743 \brief Draw a thick line with alpha blending.
3744 
3745 \param renderer The renderer to draw on.
3746 \param x1 X coordinate of the first point of the line.
3747 \param y1 Y coordinate of the first point of the line.
3748 \param x2 X coordinate of the second point of the line.
3749 \param y2 Y coordinate of the second point of the line.
3750 \param width Width of the line in pixels. Must be >0.
3751 \param r The red value of the character to draw.
3752 \param g The green value of the character to draw.
3753 \param b The blue value of the character to draw.
3754 \param a The alpha value of the character to draw.
3755 
3756 \returns Returns 0 on success, -1 on failure.
3757 */
thickLineRGBA(SDL_Renderer * renderer,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3758 int thickLineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3759 {
3760 	int wh;
3761 	double dx, dy, dx1, dy1, dx2, dy2;
3762 	double l, wl2, nx, ny, ang, adj;
3763 	Sint16 px[4], py[4];
3764 
3765 	if (renderer == NULL) {
3766 		return -1;
3767 	}
3768 
3769 	if (width < 1) {
3770 		return -1;
3771 	}
3772 
3773 	/* Special case: thick "point" */
3774 	if ((x1 == x2) && (y1 == y2)) {
3775 		wh = width / 2;
3776 		return boxRGBA(renderer, x1 - wh, y1 - wh, x2 + width, y2 + width, r, g, b, a);
3777 	}
3778 
3779 	/* Special case: width == 1 */
3780 	if (width == 1) {
3781 		return lineRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
3782 	}
3783 
3784 	/* Calculate offsets for sides */
3785 	dx = (double)(x2 - x1);
3786 	dy = (double)(y2 - y1);
3787 	l = SDL_sqrt(dx*dx + dy*dy);
3788 	ang = SDL_atan2(dx, dy);
3789 	adj = 0.1 + 0.9 * SDL_fabs(SDL_cos(2.0 * ang));
3790 	wl2 = ((double)width - adj)/(2.0 * l);
3791 	nx = dx * wl2;
3792 	ny = dy * wl2;
3793 
3794 	/* Build polygon */
3795 	dx1 = (double)x1;
3796 	dy1 = (double)y1;
3797 	dx2 = (double)x2;
3798 	dy2 = (double)y2;
3799 	px[0] = (Sint16)(dx1 + ny);
3800 	px[1] = (Sint16)(dx1 - ny);
3801 	px[2] = (Sint16)(dx2 - ny);
3802 	px[3] = (Sint16)(dx2 + ny);
3803 	py[0] = (Sint16)(dy1 - nx);
3804 	py[1] = (Sint16)(dy1 + nx);
3805 	py[2] = (Sint16)(dy2 + nx);
3806 	py[3] = (Sint16)(dy2 - nx);
3807 
3808 	/* Draw polygon */
3809 	return filledPolygonRGBA(renderer, px, py, 4, r, g, b, a);
3810 }
3811