SDL2_gfx 1.0.2
Graphics primitives and surface functions for SDL2
SDL2_gfxPrimitives.c
Go to the documentation of this file.
1/*
2
3SDL2_gfxPrimitives.c: graphics primitives for SDL2 renderers
4
5Copyright (C) 2012-2014 Andreas Schiffler
6
7This software is provided 'as-is', without any express or implied
8warranty. In no event will the authors be held liable for any damages
9arising from the use of this software.
10
11Permission is granted to anyone to use this software for any purpose,
12including commercial applications, and to alter it and redistribute it
13freely, subject to the following restrictions:
14
151. The origin of this software must not be misrepresented; you must not
16claim that you wrote the original software. If you use this software
17in a product, an acknowledgment in the product documentation would be
18appreciated but is not required.
19
202. Altered source versions must be plainly marked as such, and must not be
21misrepresented as being the original software.
22
233. This notice may not be removed or altered from any source
24distribution.
25
26Andreas 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"
38
39/* ---- Structures */
40
44typedef struct {
45 Sint16 x, y;
46 int dx, dy, s1, s2, swapdir, error;
47 Uint32 count;
49
53typedef 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;
61
62/* ---- Pixel */
63
73int pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
74{
75 return SDL_RenderDrawPoint(renderer, x, y);
76}
77
88int 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
107int 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
130int 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
158int hline(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y)
159{
160 return SDL_RenderDrawLine(renderer, x1, y, x2, y);;
161}
162
163
175int 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
195int 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
216int vline(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2)
217{
218 return SDL_RenderDrawLine(renderer, x, y1, x, y2);;
219}
220
232int 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
252int 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
275int 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
296int 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
368int 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
390int 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
513int 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
535int 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
710int 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
731int 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
801int 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
821int 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
842int 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
882int _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
1096int 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
1117int 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
1135int 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
1155int 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
1175int 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
1197/* TODO: rewrite algorithm; arc endpoints are not always drawn */
1198int 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
1433int 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
1453int 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
1475int _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
1529#define DEFAULT_ELLIPSE_OVERSCAN 4
1530int _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
1692int 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
1713int 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
1731int 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
1751int 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>
1764static __inline long
1765 lrint(float f)
1766{
1767 return _mm_cvtss_si32(_mm_load_ss(&f));
1768}
1769#elif defined(_M_IX86)
1770__inline long int
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
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
1811int 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
1832int 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
2027int 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
2048int 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
2074/* TODO: rewrite algorithm; pie is not always accurate */
2075int _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
2190int 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
2213int 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
2232int 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
2254int 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
2278int 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
2310int 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
2344int 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
2376int 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
2410int 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
2444int 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
2473int 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
2489int 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
2555int 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
2616int 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
2636int 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
2694int _gfxPrimitivesCompareInt(const void *a, const void *b)
2695{
2696 return (*(const int *) a) - (*(const int *) b);
2697}
2698
2704static int *gfxPrimitivesPolyIntsGlobal = NULL;
2705
2711static int gfxPrimitivesPolyAllocatedGlobal = 0;
2712
2731int 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
2899int 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
2919int 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
2941int _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
3040int 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
3212int 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
3225static SDL_Texture *gfxPrimitivesFont[256];
3226
3230static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
3231
3235static Uint32 charWidth = 8;
3236
3240static Uint32 charHeight = 8;
3241
3245static Uint32 charWidthLocal = 8;
3246
3250static Uint32 charHeightLocal = 8;
3251
3255static Uint32 charPitch = 1;
3256
3260static Uint32 charRotation = 0;
3261
3265static Uint32 charSize = 8;
3266
3280void 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
3326void 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
3372int 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
3494int 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
3515int 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
3535int 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
3576double _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
3635int 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
3656int 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
3736int 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
3758int 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}
int arcRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Arc with blending.
int roundedBoxColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
Draw rounded-corner box (filled rectangle) with blending.
int aalineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw anti-aliased line with alpha blending.
int stringColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, const char *s, Uint32 color)
Draw a string in the currently set font.
int ellipseRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw ellipse with blending.
int aalineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw anti-aliased line with alpha blending.
int pixelRGBAWeight(SDL_Renderer *renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Uint32 weight)
Draw pixel with blending enabled and using alpha weight on color.
int thickLineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw a thick line with alpha blending.
int stringRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw a string in the currently set font.
int rectangleRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw rectangle with blending.
int _ellipseRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Sint32 f)
int bezierColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, int s, Uint32 color)
Draw a bezier curve with alpha blending.
int pieColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
Draw pie (outline) with alpha blending.
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)
Draw filled polygon with alpha blending (multi-threaded capable).
int texturedPolygon(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
Draws a polygon filled with the given texture.
#define AAbits
int filledPolygonRGBA(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw filled polygon with alpha blending.
int pixelColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Uint32 color)
Draw pixel with blending enabled if a<255.
int pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
Draw pixel in currently set color.
int filledEllipseRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw filled ellipse with blending.
int aapolygonRGBA(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw anti-aliased polygon with alpha blending.
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)
Internal float (low-speed) pie-calc implementation by drawing polygons.
int arcColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
Arc with blending.
#define AAlevels
int circleColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
Draw circle with blending.
int filledEllipseColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
Draw filled ellipse with blending.
int circleRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw circle with blending.
int polygon(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n)
Draw polygon with the currently set color and blend mode.
int thickLineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
Draw a thick line with alpha blending.
int hlineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw horizontal line with blending.
int boxRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw box (filled rectangle) with blending.
int aatrigonRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw anti-aliased trigon (triangle outline) with alpha blending.
int vline(SDL_Renderer *renderer, Sint16 x, Sint16 y1, Sint16 y2)
Draw vertical line in currently set color.
int polygonColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color)
Draw polygon with alpha blending.
int vlineColor(SDL_Renderer *renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
Draw vertical line with blending.
int rectangleColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw rectangle with blending.
int _drawQuadrants(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 dx, Sint16 dy, Sint32 f)
Internal function to draw pixels or lines in 4 quadrants.
int aacircleRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw anti-aliased circle with blending.
int filledTrigonColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
Draw filled trigon (triangle) with alpha blending.
int vlineRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw vertical line with blending.
int hlineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
Draw horizontal line with blending.
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)
Internal function to draw a textured horizontal line.
int lineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw line with alpha blending.
int filledCircleRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw filled circle with blending.
int aatrigonColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
Draw anti-aliased trigon (triangle outline) with alpha blending.
double _evaluateBezier(double *data, int ndata, double t)
Internal function to calculate bezier interpolator of data array with ndata values at position 't'.
int filledPieColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
Draw filled pie with alpha blending.
int ellipseColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
Draw ellipse with blending.
int roundedRectangleRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw rounded-corner rectangle with blending.
int characterColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, char c, Uint32 color)
Draw a character of the currently set font.
int roundedBoxRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw rounded-corner box (filled rectangle) with blending.
int 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)
Draws a polygon filled with the given texture (Multi-Threading Capable).
int characterRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw a character of the currently set font.
int filledPieRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw filled pie with alpha blending.
int hline(SDL_Renderer *renderer, Sint16 x1, Sint16 x2, Sint16 y)
Draw horizontal line in currently set color.
int filledTrigonRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw filled trigon (triangle) with alpha blending.
int lineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw line with alpha blending.
int roundedRectangleColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
Draw rounded-corner rectangle with blending.
int pieRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw pie (outline) with alpha blending.
int filledPolygonColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color)
Draw filled polygon with alpha blending.
int trigonColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
Draw trigon (triangle outline) with alpha blending.
int _aalineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int draw_endpoint)
Internal function to draw anti-aliased line with alpha blending and endpoint control.
int filledCircleColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
Draw filled circle with blending.
int aaellipseRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw anti-aliased ellipse with blending.
int line(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
Draw line with alpha blending using the currently set color.
int polygonRGBA(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw polygon with alpha blending.
#define DEFAULT_ELLIPSE_OVERSCAN
Internal function to draw ellipse or filled ellipse with blending.
int aapolygonColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color)
Draw anti-aliased polygon with alpha blending.
int aacircleColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
Draw anti-aliased circle with blending.
int pixelRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw pixel with blending enabled if a<255.
int trigonRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw trigon (triangle outline) with alpha blending.
int _gfxPrimitivesCompareInt(const void *a, const void *b)
Internal helper qsort callback functions used in filled polygon drawing.
int bezierRGBA(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw a bezier curve with alpha blending.
void gfxPrimitivesSetFontRotation(Uint32 rotation)
Sets current global font character rotation steps.
int boxColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw box (filled rectangle) with blending.
void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch)
Sets or resets the current global font data.
int aaellipseColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
Draw anti-aliased ellipse with blending.
#define M_PI
SDL_Surface * rotateSurface90Degrees(SDL_Surface *src, int numClockwiseTurns)
Rotates a 8/16/24/32 bit surface in increments of 90 degrees.
The structure passed to the internal Bresenham iterator.
The structure passed to the internal Murphy iterator.