SDL3_gfx 1.0.1 Graphics primitives and surface functions for SDL3

SDL3_gfxPrimitives.c
Go to the documentation of this file.
1/*
2
3 SDL3_gfxPrimitives.c: graphics primitives for SDL3 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 "SDL3_gfxPrimitives.h"
36#include "SDL3_rotozoom.h"
37#include "SDL3_gfxPrimitives_font.h"
38
39/* ---- Pixel */
40
50 bool pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
51{
52 return SDL_RenderPoint(renderer, x, y);
53}
54
65 bool pixelColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint32 color)
66{
67 Uint8 *c = (Uint8 *)&color;
68 return pixelRGBA(renderer, x, y, c[0], c[1], c[2], c[3]);
69}
70
84 bool pixelRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
85{
86 bool result = true;
87 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
88 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
89 result &= SDL_RenderPoint(renderer, x, y);
90 return result;
91}
92
107 bool pixelRGBAWeight(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Uint32 weight)
108{
109 /*
110 * Modify Alpha by weight
111 */
112 Uint32 ax = a;
113 ax = ((ax * weight) >> 8);
114 if (ax > 255) {
115 a = 255;
116 } else {
117 a = (Uint8)(ax & 0x000000ff);
118 }
119
120 return pixelRGBA(renderer, x, y, r, g, b, a);
121}
122
123/* ---- Hline */
124
135 bool hline(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y)
136{
137 return SDL_RenderLine(renderer, x1, y, x2, y);;
138}
139
140
152 bool hlineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
153{
154 Uint8 *c = (Uint8 *)&color;
155 return hlineRGBA(renderer, x1, x2, y, c[0], c[1], c[2], c[3]);
156}
157
172 bool hlineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
173{
174 bool result = true;
175 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
176 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
177 result &= SDL_RenderLine(renderer, x1, y, x2, y);
178 return result;
179}
180
181/* ---- Vline */
182
193 bool vline(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2)
194{
195 return SDL_RenderLine(renderer, x, y1, x, y2);;
196}
197
209 bool vlineColor(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
210{
211 Uint8 *c = (Uint8 *)&color;
212 return vlineRGBA(renderer, x, y1, y2, c[0], c[1], c[2], c[3]);
213}
214
229 bool vlineRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
230{
231 bool result = true;
232 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
233 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
234 result &= SDL_RenderLine(renderer, x, y1, x, y2);
235 return result;
236}
237
238/* ---- Rectangle */
239
252 bool rectangleColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
253{
254 Uint8 *c = (Uint8 *)&color;
255 return rectangleRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
256}
257
273 bool rectangleRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
274{
275 bool result;
276 Sint16 tmp;
277 SDL_FRect rect;
278
279 /*
280 * Test for special cases of straight lines or single point
281 */
282 if (x1 == x2) {
283 if (y1 == y2) {
284 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
285 } else {
286 return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
287 }
288 } else {
289 if (y1 == y2) {
290 return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
291 }
292 }
293
294 /*
295 * Swap x1, x2 if required
296 */
297 if (x1 > x2) {
298 tmp = x1;
299 x1 = x2;
300 x2 = tmp;
301 }
302
303 /*
304 * Swap y1, y2 if required
305 */
306 if (y1 > y2) {
307 tmp = y1;
308 y1 = y2;
309 y2 = tmp;
310 }
311
312 /*
313 * Create destination rect
314 */
315 rect.x = x1;
316 rect.y = y1;
317 rect.w = x2 - x1;
318 rect.h = y2 - y1;
319
320 /*
321 * Draw
322 */
323 result = true;
324 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
325 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
326 result &= SDL_RenderRect(renderer, &rect);
327 return result;
328}
329
330/* ---- Rounded Rectangle */
331
345 bool roundedRectangleColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
346{
347 Uint8 *c = (Uint8 *)&color;
348 return roundedRectangleRGBA(renderer, x1, y1, x2, y2, rad, c[0], c[1], c[2], c[3]);
349}
350
367 bool roundedRectangleRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
368{
369 int result = 0;
370 Sint16 tmp;
371 Sint16 w, h;
372 Sint16 xx1, xx2;
373 Sint16 yy1, yy2;
374
375 /*
376 * Check renderer
377 */
378 if (renderer == NULL)
379 {
380 return false;
381 }
382
383 /*
384 * Check radius vor valid range
385 */
386 if (rad < 0) {
387 return false;
388 }
389
390 /*
391 * Special case - no rounding
392 */
393 if (rad <= 1) {
394 return rectangleRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
395 }
396
397 /*
398 * Test for special cases of straight lines or single point
399 */
400 if (x1 == x2) {
401 if (y1 == y2) {
402 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
403 } else {
404 return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
405 }
406 } else {
407 if (y1 == y2) {
408 return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
409 }
410 }
411
412 /*
413 * Swap x1, x2 if required
414 */
415 if (x1 > x2) {
416 tmp = x1;
417 x1 = x2;
418 x2 = tmp;
419 }
420
421 /*
422 * Swap y1, y2 if required
423 */
424 if (y1 > y2) {
425 tmp = y1;
426 y1 = y2;
427 y2 = tmp;
428 }
429
430 /*
431 * Calculate width&height
432 */
433 w = x2 - x1;
434 h = y2 - y1;
435
436 /*
437 * Maybe adjust radius
438 */
439 if ((rad * 2) > w)
440 {
441 rad = w / 2;
442 }
443 if ((rad * 2) > h)
444 {
445 rad = h / 2;
446 }
447
448 /*
449 * Draw corners
450 */
451 xx1 = x1 + rad;
452 xx2 = x2 - rad;
453 yy1 = y1 + rad;
454 yy2 = y2 - rad;
455 result &= arcRGBA(renderer, xx1, yy1, rad, 180, 270, r, g, b, a);
456 result &= arcRGBA(renderer, xx2, yy1, rad, 270, 360, r, g, b, a);
457 result &= arcRGBA(renderer, xx1, yy2, rad, 90, 180, r, g, b, a);
458 result &= arcRGBA(renderer, xx2, yy2, rad, 0, 90, r, g, b, a);
459
460 /*
461 * Draw lines
462 */
463 if (xx1 <= xx2) {
464 result &= hlineRGBA(renderer, xx1, xx2, y1, r, g, b, a);
465 result &= hlineRGBA(renderer, xx1, xx2, y2, r, g, b, a);
466 }
467 if (yy1 <= yy2) {
468 result &= vlineRGBA(renderer, x1, yy1, yy2, r, g, b, a);
469 result &= vlineRGBA(renderer, x2, yy1, yy2, r, g, b, a);
470 }
471
472 return result;
473}
474
475/* ---- Rounded Box */
476
490 bool roundedBoxColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
491{
492 Uint8 *c = (Uint8 *)&color;
493 return roundedBoxRGBA(renderer, x1, y1, x2, y2, rad, c[0], c[1], c[2], c[3]);
494}
495
512 bool roundedBoxRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2,
513 Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
514{
515 bool result;
516 Sint16 w, h, r2, tmp;
517 Sint16 cx = 0;
518 Sint16 cy = rad;
519 Sint16 ocx = (Sint16) 0xffff;
520 Sint16 ocy = (Sint16) 0xffff;
521 Sint16 df = 1 - rad;
522 Sint16 d_e = 3;
523 Sint16 d_se = -2 * rad + 5;
524 Sint16 xpcx, xmcx, xpcy, xmcy;
525 Sint16 ypcy, ymcy, ypcx, ymcx;
526 Sint16 x, y, dx, dy;
527
528 /*
529 * Check destination renderer
530 */
531 if (renderer == NULL)
532 {
533 return false;
534 }
535
536 /*
537 * Check radius vor valid range
538 */
539 if (rad < 0) {
540 return false;
541 }
542
543 /*
544 * Special case - no rounding
545 */
546 if (rad <= 1) {
547 return boxRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
548 }
549
550 /*
551 * Test for special cases of straight lines or single point
552 */
553 if (x1 == x2) {
554 if (y1 == y2) {
555 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
556 } else {
557 return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
558 }
559 } else {
560 if (y1 == y2) {
561 return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
562 }
563 }
564
565 /*
566 * Swap x1, x2 if required
567 */
568 if (x1 > x2) {
569 tmp = x1;
570 x1 = x2;
571 x2 = tmp;
572 }
573
574 /*
575 * Swap y1, y2 if required
576 */
577 if (y1 > y2) {
578 tmp = y1;
579 y1 = y2;
580 y2 = tmp;
581 }
582
583 /*
584 * Calculate width&height
585 */
586 w = x2 - x1 + 1;
587 h = y2 - y1 + 1;
588
589 /*
590 * Maybe adjust radius
591 */
592 r2 = rad + rad;
593 if (r2 > w)
594 {
595 rad = w / 2;
596 r2 = rad + rad;
597 }
598 if (r2 > h)
599 {
600 rad = h / 2;
601 }
602
603 /* Setup filled circle drawing for corners */
604 x = x1 + rad;
605 y = y1 + rad;
606 dx = x2 - x1 - rad - rad;
607 dy = y2 - y1 - rad - rad;
608
609 /*
610 * Set color
611 */
612 result = true;
613 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
614 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
615
616 /*
617 * Draw corners
618 */
619 do {
620 xpcx = x + cx;
621 xmcx = x - cx;
622 xpcy = x + cy;
623 xmcy = x - cy;
624 if (ocy != cy) {
625 if (cy > 0) {
626 ypcy = y + cy;
627 ymcy = y - cy;
628 result &= hline(renderer, xmcx, xpcx + dx, ypcy + dy);
629 result &= hline(renderer, xmcx, xpcx + dx, ymcy);
630 } else {
631 result &= hline(renderer, xmcx, xpcx + dx, y);
632 }
633 ocy = cy;
634 }
635 if (ocx != cx) {
636 if (cx != cy) {
637 if (cx > 0) {
638 ypcx = y + cx;
639 ymcx = y - cx;
640 result &= hline(renderer, xmcy, xpcy + dx, ymcx);
641 result &= hline(renderer, xmcy, xpcy + dx, ypcx + dy);
642 } else {
643 result &= hline(renderer, xmcy, xpcy + dx, y);
644 }
645 }
646 ocx = cx;
647 }
648
649 /*
650 * Update
651 */
652 if (df < 0) {
653 df += d_e;
654 d_e += 2;
655 d_se += 2;
656 } else {
657 df += d_se;
658 d_e += 2;
659 d_se += 4;
660 cy--;
661 }
662 cx++;
663 } while (cx <= cy);
664
665 /* Inside */
666 if (dx > 0 && dy > 0) {
667 result &= boxRGBA(renderer, x1, y1 + rad + 1, x2, y2 - rad, r, g, b, a);
668 }
669
670 return (result);
671}
672
673/* ---- Box */
674
687 bool boxColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
688{
689 Uint8 *c = (Uint8 *)&color;
690 return boxRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
691}
692
708 bool boxRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
709{
710 bool result;
711 Sint16 tmp;
712 SDL_FRect rect;
713
714 /*
715 * Test for special cases of straight lines or single point
716 */
717 if (x1 == x2) {
718 if (y1 == y2) {
719 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
720 } else {
721 return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
722 }
723 } else {
724 if (y1 == y2) {
725 return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
726 }
727 }
728
729 /*
730 * Swap x1, x2 if required
731 */
732 if (x1 > x2) {
733 tmp = x1;
734 x1 = x2;
735 x2 = tmp;
736 }
737
738 /*
739 * Swap y1, y2 if required
740 */
741 if (y1 > y2) {
742 tmp = y1;
743 y1 = y2;
744 y2 = tmp;
745 }
746
747 /*
748 * Create destination rect
749 */
750 rect.x = x1;
751 rect.y = y1;
752 rect.w = x2 - x1 + 1;
753 rect.h = y2 - y1 + 1;
754
755 /*
756 * Draw
757 */
758 result = true;
759 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
760 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
761 result &= SDL_RenderFillRect(renderer, &rect);
762 return result;
763}
764
765/* ----- Line */
766
778 bool line(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
779{
780 /*
781 * Draw
782 */
783 return SDL_RenderLine(renderer, x1, y1, x2, y2);
784}
785
798 bool lineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
799{
800 Uint8 *c = (Uint8 *)&color;
801 return lineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
802}
803
819 bool lineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
820{
821 /*
822 * Draw
823 */
824 bool result = true;
825 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
826 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
827 result &= SDL_RenderLine(renderer, x1, y1, x2, y2);
828 return result;
829}
830
831/* ---- AA Line */
832
833#define AAlevels 256
834#define AAbits 8
835
859 int _aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int draw_endpoint)
860{
861 Sint32 xx0, yy0, xx1, yy1;
862 bool result;
863 Uint32 intshift, erracc, erradj;
864 Uint32 erracctmp, wgt, wgtcompmask;
865 int dx, dy, tmp, xdir, y0p1, x0pxdir;
866
867 /*
868 * Keep on working with 32bit numbers
869 */
870 xx0 = x1;
871 yy0 = y1;
872 xx1 = x2;
873 yy1 = y2;
874
875 /*
876 * Reorder points to make dy positive
877 */
878 if (yy0 > yy1) {
879 tmp = yy0;
880 yy0 = yy1;
881 yy1 = tmp;
882 tmp = xx0;
883 xx0 = xx1;
884 xx1 = tmp;
885 }
886
887 /*
888 * Calculate distance
889 */
890 dx = xx1 - xx0;
891 dy = yy1 - yy0;
892
893 /*
894 * Adjust for negative dx and set xdir
895 */
896 if (dx >= 0) {
897 xdir = 1;
898 } else {
899 xdir = -1;
900 dx = (-dx);
901 }
902
903 /*
904 * Check for special cases
905 */
906 if (dx == 0) {
907 /*
908 * Vertical line
909 */
910 if (draw_endpoint)
911 {
912 return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
913 } else {
914 if (dy > 0) {
915 return (vlineRGBA(renderer, x1, yy0, yy0+dy, r, g, b, a));
916 } else {
917 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
918 }
919 }
920 } else if (dy == 0) {
921 /*
922 * Horizontal line
923 */
924 if (draw_endpoint)
925 {
926 return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
927 } else {
928 if (dx > 0) {
929 return (hlineRGBA(renderer, xx0, xx0+(xdir*dx), y1, r, g, b, a));
930 } else {
931 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
932 }
933 }
934 } else if ((dx == dy) && (draw_endpoint)) {
935 /*
936 * Diagonal line (with endpoint)
937 */
938 return (lineRGBA(renderer, x1, y1, x2, y2, r, g, b, a));
939 }
940
941
942 /*
943 * Line is not horizontal, vertical or diagonal (with endpoint)
944 */
945 result = true;
946
947 /*
948 * Zero accumulator
949 */
950 erracc = 0;
951
952 /*
953 * # of bits by which to shift erracc to get intensity level
954 */
955 intshift = 32 - AAbits;
956
957 /*
958 * Mask used to flip all bits in an intensity weighting
959 */
960 wgtcompmask = AAlevels - 1;
961
962 /*
963 * Draw the initial pixel in the foreground color
964 */
965 result &= pixelRGBA(renderer, x1, y1, r, g, b, a);
966
967 /*
968 * x-major or y-major?
969 */
970 if (dy > dx) {
971
972 /*
973 * y-major. Calculate 16-bit fixed point fractional part of a pixel that
974 * X advances every time Y advances 1 pixel, truncating the result so that
975 * we won't overrun the endpoint along the X axis
976 */
977 /*
978 * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
979 */
980 erradj = ((dx << 16) / dy) << 16;
981
982 /*
983 * draw all pixels other than the first and last
984 */
985 x0pxdir = xx0 + xdir;
986 while (--dy) {
987 erracctmp = erracc;
988 erracc += erradj;
989 if (erracc <= erracctmp) {
990 /*
991 * rollover in error accumulator, x coord advances
992 */
993 xx0 = x0pxdir;
994 x0pxdir += xdir;
995 }
996 yy0++; /* y-major so always advance Y */
997
998 /*
999 * the AAbits most significant bits of erracc give us the intensity
1000 * weighting for this pixel, and the complement of the weighting for
1001 * the paired pixel.
1002 */
1003 wgt = (erracc >> intshift) & 255;
1004 result &= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
1005 result &= pixelRGBAWeight (renderer, x0pxdir, yy0, r, g, b, a, wgt);
1006 }
1007
1008 } else {
1009
1010 /*
1011 * x-major line. Calculate 16-bit fixed-point fractional part of a pixel
1012 * that Y advances each time X advances 1 pixel, truncating the result so
1013 * that we won't overrun the endpoint along the X axis.
1014 */
1015 /*
1016 * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
1017 */
1018 erradj = ((dy << 16) / dx) << 16;
1019
1020 /*
1021 * draw all pixels other than the first and last
1022 */
1023 y0p1 = yy0 + 1;
1024 while (--dx) {
1025
1026 erracctmp = erracc;
1027 erracc += erradj;
1028 if (erracc <= erracctmp) {
1029 /*
1030 * Accumulator turned over, advance y
1031 */
1032 yy0 = y0p1;
1033 y0p1++;
1034 }
1035 xx0 += xdir; /* x-major so always advance X */
1036 /*
1037 * the AAbits most significant bits of erracc give us the intensity
1038 * weighting for this pixel, and the complement of the weighting for
1039 * the paired pixel.
1040 */
1041 wgt = (erracc >> intshift) & 255;
1042 result &= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
1043 result &= pixelRGBAWeight (renderer, xx0, y0p1, r, g, b, a, wgt);
1044 }
1045 }
1046
1047 /*
1048 * Do we have to draw the endpoint
1049 */
1050 if (draw_endpoint) {
1051 /*
1052 * Draw final pixel, always exactly intersected by the line and doesn't
1053 * need to be weighted.
1054 */
1055 result &= pixelRGBA (renderer, x2, y2, r, g, b, a);
1056 }
1057
1058 return (result);
1059}
1060
1073 bool aalineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1074{
1075 Uint8 *c = (Uint8 *)&color;
1076 return _aalineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3], 1);
1077}
1078
1094 bool aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1095{
1096 return _aalineRGBA(renderer, x1, y1, x2, y2, r, g, b, a, 1);
1097}
1098
1099/* ----- Circle */
1100
1112 bool circleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
1113{
1114 Uint8 *c = (Uint8 *)&color;
1115 return ellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
1116}
1117
1132 bool circleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1133{
1134 return ellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
1135}
1136
1137/* ----- Arc */
1138
1152 bool arcColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
1153{
1154 Uint8 *c = (Uint8 *)&color;
1155 return arcRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3]);
1156}
1157
1174/* TODO: rewrite algorithm; arc endpoints are not always drawn */
1175 bool arcRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1176{
1177 bool result;
1178 Sint16 cx = 0;
1179 Sint16 cy = rad;
1180 Sint16 df = 1 - rad;
1181 Sint16 d_e = 3;
1182 Sint16 d_se = -2 * rad + 5;
1183 Sint16 xpcx, xmcx, xpcy, xmcy;
1184 Sint16 ypcy, ymcy, ypcx, ymcx;
1185 Uint8 drawoct;
1186 int startoct, endoct, oct, stopval_start = 0, stopval_end = 0;
1187 double dstart, dend, temp = 0.;
1188
1189 /*
1190 * Sanity check radius
1191 */
1192 if (rad < 0) {
1193 return (false);
1194 }
1195
1196 /*
1197 * Special case for rad=0 - draw a point
1198 */
1199 if (rad == 0) {
1200 return (pixelRGBA(renderer, x, y, r, g, b, a));
1201 }
1202
1203 /*
1204 Octant labeling
1205
1206 \ 5 | 6 /
1207 \ | /
1208 4 \ | / 7
1209 \|/
1210 ------+------ +x
1211 /|\
1212 3 / | \ 0
1213 / | \
1214 / 2 | 1 \
1215 +y
1216
1217 Initially reset bitmask to 0x00000000
1218 the set whether or not to keep drawing a given octant.
1219 For example: 0x00111100 means we're drawing in octants 2-5
1220 */
1221 drawoct = 0;
1222
1223 /*
1224 * Fixup angles
1225 */
1226 start %= 360;
1227 end %= 360;
1228 /* 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0. */
1229 while (start < 0) start += 360;
1230 while (end < 0) end += 360;
1231 start %= 360;
1232 end %= 360;
1233
1234 /* now, we find which octants we're drawing in. */
1235 startoct = start / 45;
1236 endoct = end / 45;
1237 oct = startoct - 1;
1238
1239 /* stopval_start, stopval_end; what values of cx to stop at. */
1240 do {
1241 oct = (oct + 1) % 8;
1242
1243 if (oct == startoct) {
1244 /* need to compute stopval_start for this octant. Look at picture above if this is unclear */
1245 dstart = (double)start;
1246 switch (oct)
1247 {
1248 case 0:
1249 case 3:
1250 temp = sin(dstart * M_PI / 180.);
1251 break;
1252 case 1:
1253 case 6:
1254 temp = cos(dstart * M_PI / 180.);
1255 break;
1256 case 2:
1257 case 5:
1258 temp = -cos(dstart * M_PI / 180.);
1259 break;
1260 case 4:
1261 case 7:
1262 temp = -sin(dstart * M_PI / 180.);
1263 break;
1264 }
1265 temp *= rad;
1266 stopval_start = (int)temp;
1267
1268 /*
1269 This isn't arbitrary, but requires graph paper to explain well.
1270 The basic idea is that we're always changing drawoct after we draw, so we
1271 stop immediately after we render the last sensible pixel at x = ((int)temp).
1272 and whether to draw in this octant initially
1273 */
1274 if (oct % 2) drawoct |= (1 << oct); /* this is basically like saying drawoct[oct] = true, if drawoct were a bool array */
1275 else drawoct &= 255 - (1 << oct); /* this is basically like saying drawoct[oct] = false */
1276 }
1277 if (oct == endoct) {
1278 /* need to compute stopval_end for this octant */
1279 dend = (double)end;
1280 switch (oct)
1281 {
1282 case 0:
1283 case 3:
1284 temp = sin(dend * M_PI / 180);
1285 break;
1286 case 1:
1287 case 6:
1288 temp = cos(dend * M_PI / 180);
1289 break;
1290 case 2:
1291 case 5:
1292 temp = -cos(dend * M_PI / 180);
1293 break;
1294 case 4:
1295 case 7:
1296 temp = -sin(dend * M_PI / 180);
1297 break;
1298 }
1299 temp *= rad;
1300 stopval_end = (int)temp;
1301
1302 /* and whether to draw in this octant initially */
1303 if (startoct == endoct) {
1304 /* note: we start drawing, stop, then start again in this case */
1305 /* otherwise: we only draw in this octant, so initialize it to false, it will get set back to true */
1306 if (start > end) {
1307 /* unfortunately, if we're in the same octant and need to draw over the whole circle, */
1308 /* we need to set the rest to true, because the while loop will end at the bottom. */
1309 drawoct = 255;
1310 } else {
1311 drawoct &= 255 - (1 << oct);
1312 }
1313 }
1314 else if (oct % 2) drawoct &= 255 - (1 << oct);
1315 else drawoct |= (1 << oct);
1316 } else if (oct != startoct) { /* already verified that it's != endoct */
1317 drawoct |= (1 << oct); /* draw this entire segment */
1318 }
1319 } while (oct != endoct);
1320
1321 /* so now we have what octants to draw and when to draw them. all that's left is the actual raster code. */
1322
1323 /*
1324 * Set color
1325 */
1326 result = true;
1327 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
1328 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
1329
1330 /*
1331 * Draw arc
1332 */
1333 do {
1334 ypcy = y + cy;
1335 ymcy = y - cy;
1336 if (cx > 0) {
1337 xpcx = x + cx;
1338 xmcx = x - cx;
1339
1340 /* always check if we're drawing a certain octant before adding a pixel to that octant. */
1341 if (drawoct & 4) result &= pixel(renderer, xmcx, ypcy);
1342 if (drawoct & 2) result &= pixel(renderer, xpcx, ypcy);
1343 if (drawoct & 32) result &= pixel(renderer, xmcx, ymcy);
1344 if (drawoct & 64) result &= pixel(renderer, xpcx, ymcy);
1345 } else {
1346 if (drawoct & 96) result &= pixel(renderer, x, ymcy);
1347 if (drawoct & 6) result &= pixel(renderer, x, ypcy);
1348 }
1349
1350 xpcy = x + cy;
1351 xmcy = x - cy;
1352 if (cx > 0 && cx != cy) {
1353 ypcx = y + cx;
1354 ymcx = y - cx;
1355 if (drawoct & 8) result &= pixel(renderer, xmcy, ypcx);
1356 if (drawoct & 1) result &= pixel(renderer, xpcy, ypcx);
1357 if (drawoct & 16) result &= pixel(renderer, xmcy, ymcx);
1358 if (drawoct & 128) result &= pixel(renderer, xpcy, ymcx);
1359 } else if (cx == 0) {
1360 if (drawoct & 24) result &= pixel(renderer, xmcy, y);
1361 if (drawoct & 129) result &= pixel(renderer, xpcy, y);
1362 }
1363
1364 /*
1365 * Update whether we're drawing an octant
1366 */
1367 if (stopval_start == cx) {
1368 /* works like an on-off switch. */
1369 /* This is just in case start & end are in the same octant. */
1370 if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
1371 else drawoct |= (1 << startoct);
1372 }
1373 if (stopval_end == cx) {
1374 if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
1375 else drawoct |= (1 << endoct);
1376 }
1377
1378 /*
1379 * Update pixels
1380 */
1381 if (df < 0) {
1382 df += d_e;
1383 d_e += 2;
1384 d_se += 2;
1385 } else {
1386 df += d_se;
1387 d_e += 2;
1388 d_se += 4;
1389 cy--;
1390 }
1391 cx++;
1392 } while (cx <= cy);
1393
1394 return (result);
1395}
1396
1397/* ----- AA Circle */
1398
1410 bool aacircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
1411{
1412 Uint8 *c = (Uint8 *)&color;
1413 return aaellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
1414}
1415
1430 bool aacircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1431{
1432 /*
1433 * Draw
1434 */
1435 return aaellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
1436}
1437
1438/* ----- Ellipse */
1439
1452 int _drawQuadrants(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 dx, Sint16 dy, Sint32 f)
1453{
1454 bool result = true;
1455 Sint16 xpdx, xmdx;
1456 Sint16 ypdy, ymdy;
1457
1458 if (dx == 0) {
1459 if (dy == 0) {
1460 result &= pixel(renderer, x, y);
1461 } else {
1462 ypdy = y + dy;
1463 ymdy = y - dy;
1464 if (f) {
1465 result &= vline(renderer, x, ymdy, ypdy);
1466 } else {
1467 result &= pixel(renderer, x, ypdy);
1468 result &= pixel(renderer, x, ymdy);
1469 }
1470 }
1471 } else {
1472 xpdx = x + dx;
1473 xmdx = x - dx;
1474 ypdy = y + dy;
1475 ymdy = y - dy;
1476 if (f) {
1477 result &= vline(renderer, xpdx, ymdy, ypdy);
1478 result &= vline(renderer, xmdx, ymdy, ypdy);
1479 } else {
1480 result &= pixel(renderer, xpdx, ypdy);
1481 result &= pixel(renderer, xmdx, ypdy);
1482 result &= pixel(renderer, xpdx, ymdy);
1483 result &= pixel(renderer, xmdx, ymdy);
1484 }
1485 }
1486
1487 return result;
1488}
1489
1506#define DEFAULT_ELLIPSE_OVERSCAN 4
1507 bool _ellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Sint32 f)
1508{
1509 bool result;
1510 Sint32 rxi, ryi;
1511 Sint32 rx2, ry2, rx22, ry22;
1512 Sint32 error;
1513 Sint32 curX, curY, curXp1, curYm1;
1514 Sint32 scrX, scrY, oldX, oldY;
1515 Sint32 deltaX, deltaY;
1516 Sint32 ellipseOverscan;
1517
1518 /*
1519 * Sanity check radii
1520 */
1521 if ((rx < 0) || (ry < 0)) {
1522 return (false);
1523 }
1524
1525 /*
1526 * Set color
1527 */
1528 result = true;
1529 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
1530 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
1531
1532 /*
1533 * Special cases for rx=0 and/or ry=0: draw a hline/vline/pixel
1534 */
1535 if (rx == 0) {
1536 if (ry == 0) {
1537 return (pixel(renderer, x, y));
1538 } else {
1539 return (vline(renderer, x, y - ry, y + ry));
1540 }
1541 } else {
1542 if (ry == 0) {
1543 return (hline(renderer, x - rx, x + rx, y));
1544 }
1545 }
1546
1547 /*
1548 * Adjust overscan
1549 */
1550 rxi = rx;
1551 ryi = ry;
1552 if (rxi >= 512 || ryi >= 512)
1553 {
1554 ellipseOverscan = DEFAULT_ELLIPSE_OVERSCAN / 4;
1555 }
1556 else if (rxi >= 256 || ryi >= 256)
1557 {
1558 ellipseOverscan = DEFAULT_ELLIPSE_OVERSCAN / 2;
1559 }
1560 else
1561 {
1562 ellipseOverscan = DEFAULT_ELLIPSE_OVERSCAN / 1;
1563 }
1564
1565 /*
1566 * Top/bottom center points.
1567 */
1568 oldX = scrX = 0;
1569 oldY = scrY = ryi;
1570 result &= _drawQuadrants(renderer, x, y, 0, ry, f);
1571
1572 /* Midpoint ellipse algorithm with overdraw */
1573 rxi *= ellipseOverscan;
1574 ryi *= ellipseOverscan;
1575 rx2 = rxi * rxi;
1576 rx22 = rx2 + rx2;
1577 ry2 = ryi * ryi;
1578 ry22 = ry2 + ry2;
1579 curX = 0;
1580 curY = ryi;
1581 deltaX = 0;
1582 deltaY = rx22 * curY;
1583
1584 /* Points in segment 1 */
1585 error = ry2 - rx2 * ryi + rx2 / 4;
1586 while (deltaX <= deltaY)
1587 {
1588 curX++;
1589 deltaX += ry22;
1590
1591 error += deltaX + ry2;
1592 if (error >= 0)
1593 {
1594 curY--;
1595 deltaY -= rx22;
1596 error -= deltaY;
1597 }
1598
1599 scrX = curX / ellipseOverscan;
1600 scrY = curY / ellipseOverscan;
1601 if ((scrX != oldX && scrY == oldY) || (scrX != oldX && scrY != oldY)) {
1602 result &= _drawQuadrants(renderer, x, y, scrX, scrY, f);
1603 oldX = scrX;
1604 oldY = scrY;
1605 }
1606 }
1607
1608 /* Points in segment 2 */
1609 if (curY > 0)
1610 {
1611 curXp1 = curX + 1;
1612 curYm1 = curY - 1;
1613 error = ry2 * curX * curXp1 + ((ry2 + 3) / 4) + rx2 * curYm1 * curYm1 - rx2 * ry2;
1614 while (curY > 0)
1615 {
1616 curY--;
1617 deltaY -= rx22;
1618
1619 error += rx2;
1620 error -= deltaY;
1621
1622 if (error <= 0)
1623 {
1624 curX++;
1625 deltaX += ry22;
1626 error += deltaX;
1627 }
1628
1629 scrX = curX / ellipseOverscan;
1630 scrY = curY / ellipseOverscan;
1631 if ((scrX != oldX && scrY == oldY) || (scrX != oldX && scrY != oldY)) {
1632 oldY--;
1633 for (;oldY >= scrY; oldY--) {
1634 result &= _drawQuadrants(renderer, x, y, scrX, oldY, f);
1635 /* prevent overdraw */
1636 if (f) {
1637 oldY = scrY - 1;
1638 }
1639 }
1640 oldX = scrX;
1641 oldY = scrY;
1642 }
1643 }
1644
1645 /* Remaining points in vertical */
1646 if (!f) {
1647 oldY--;
1648 for (;oldY >= 0; oldY--) {
1649 result &= _drawQuadrants(renderer, x, y, scrX, oldY, f);
1650 }
1651 }
1652 }
1653
1654 return (result);
1655}
1656
1669 bool ellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
1670{
1671 Uint8 *c = (Uint8 *)&color;
1672 return _ellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3], 0);
1673}
1674
1690 bool ellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1691{
1692 return _ellipseRGBA(renderer, x, y, rx, ry, r, g, b, a, 0);
1693}
1694
1695/* ----- Filled Circle */
1696
1708 bool filledCircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
1709{
1710 Uint8 *c = (Uint8 *)&color;
1711 return filledEllipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
1712}
1713
1728 bool filledCircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1729{
1730 return _ellipseRGBA(renderer, x, y, rad, rad, r, g ,b, a, 1);
1731}
1732
1733
1734/* ----- AA Ellipse */
1735
1736/* Windows targets do not have lrint, so provide a local inline version */
1737#if defined(_MSC_VER) && _MSC_VER < 1920
1738/* Detect 64bit and use intrinsic version */
1739#ifdef _M_X64
1740#include <emmintrin.h>
1741 static __inline long
1742 lrint(float f)
1743{
1744 return _mm_cvtss_si32(_mm_load_ss(&f));
1745}
1746#elif defined(_M_IX86)
1747__inline long int
1748 lrint (double flt)
1749{
1750 int intgr;
1751 _asm
1752 {
1753 fld flt
1754 fistp intgr
1755 };
1756 return intgr;
1757}
1758#elif defined(_M_ARM)
1759#include <armintr.h>
1760#pragma warning(push)
1761#pragma warning(disable: 4716)
1762__declspec(naked) long int
1763 lrint (double flt)
1764{
1765 __emit(0xEC410B10); // fmdrr d0, r0, r1
1766 __emit(0xEEBD0B40); // ftosid s0, d0
1767 __emit(0xEE100A10); // fmrs r0, s0
1768 __emit(0xE12FFF1E); // bx lr
1769}
1770#pragma warning(pop)
1771#else
1772#error lrint needed for MSVC on non X86/AMD64/ARM targets.
1773#endif
1774#endif
1775
1788 bool aaellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
1789{
1790 Uint8 *c = (Uint8 *)&color;
1791 return aaellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
1792}
1793
1809 bool aaellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1810{
1811 bool result;
1812 int i;
1813 int a2, b2, ds, dt, dxt, t, s, d;
1814 Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2;
1815 float cp;
1816 double sab;
1817 Uint8 weight, iweight;
1818
1819 /*
1820 * Sanity check radii
1821 */
1822 if ((rx < 0) || (ry < 0)) {
1823 return (false);
1824 }
1825
1826 /*
1827 * Special cases for rx=0 and/or ry=0: draw a hline/vline/pixel
1828 */
1829 if (rx == 0) {
1830 if (ry == 0) {
1831 return (pixelRGBA(renderer, x, y, r, g, b, a));
1832 } else {
1833 return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
1834 }
1835 } else {
1836 if (ry == 0) {
1837 return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
1838 }
1839 }
1840
1841 /* Variable setup */
1842 a2 = rx * rx;
1843 b2 = ry * ry;
1844
1845 ds = 2 * a2;
1846 dt = 2 * b2;
1847
1848 xc2 = 2 * x;
1849 yc2 = 2 * y;
1850
1851 sab = sqrt((double)(a2 + b2));
1852 od = (Sint16)lrint(sab*0.01) + 1; /* introduce some overdraw */
1853 dxt = (Sint16)lrint((double)a2 / sab) + od;
1854
1855 t = 0;
1856 s = -2 * a2 * ry;
1857 d = 0;
1858
1859 xp = x;
1860 yp = y - ry;
1861
1862 /* Draw */
1863 result = true;
1864 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
1865
1866 /* "End points" */
1867 result &= pixelRGBA(renderer, xp, yp, r, g, b, a);
1868 result &= pixelRGBA(renderer, xc2 - xp, yp, r, g, b, a);
1869 result &= pixelRGBA(renderer, xp, yc2 - yp, r, g, b, a);
1870 result &= pixelRGBA(renderer, xc2 - xp, yc2 - yp, r, g, b, a);
1871
1872 for (i = 1; i <= dxt; i++) {
1873 xp--;
1874 d += t - b2;
1875
1876 if (d >= 0)
1877 ys = yp - 1;
1878 else if ((d - s - a2) > 0) {
1879 if ((2 * d - s - a2) >= 0)
1880 ys = yp + 1;
1881 else {
1882 ys = yp;
1883 yp++;
1884 d -= s + a2;
1885 s += ds;
1886 }
1887 } else {
1888 yp++;
1889 ys = yp + 1;
1890 d -= s + a2;
1891 s += ds;
1892 }
1893
1894 t -= dt;
1895
1896 /* Calculate alpha */
1897 if (s != 0) {
1898 cp = (float) abs(d) / (float) abs(s);
1899 if (cp > 1.0) {
1900 cp = 1.0;
1901 }
1902 } else {
1903 cp = 1.0;
1904 }
1905
1906 /* Calculate weights */
1907 weight = (Uint8) (cp * 255);
1908 iweight = 255 - weight;
1909
1910 /* Upper half */
1911 xx = xc2 - xp;
1912 result &= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
1913 result &= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
1914
1915 result &= pixelRGBAWeight(renderer, xp, ys, r, g, b, a, weight);
1916 result &= pixelRGBAWeight(renderer, xx, ys, r, g, b, a, weight);
1917
1918 /* Lower half */
1919 yy = yc2 - yp;
1920 result &= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
1921 result &= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
1922
1923 yy = yc2 - ys;
1924 result &= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, weight);
1925 result &= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);
1926 }
1927
1928 /* Replaces original approximation code dyt = abs(yp - yc); */
1929 dyt = (Sint16)lrint((double)b2 / sab ) + od;
1930
1931 for (i = 1; i <= dyt; i++) {
1932 yp++;
1933 d -= s + a2;
1934
1935 if (d <= 0)
1936 xs = xp + 1;
1937 else if ((d + t - b2) < 0) {
1938 if ((2 * d + t - b2) <= 0)
1939 xs = xp - 1;
1940 else {
1941 xs = xp;
1942 xp--;
1943 d += t - b2;
1944 t -= dt;
1945 }
1946 } else {
1947 xp--;
1948 xs = xp - 1;
1949 d += t - b2;
1950 t -= dt;
1951 }
1952
1953 s += ds;
1954
1955 /* Calculate alpha */
1956 if (t != 0) {
1957 cp = (float) abs(d) / (float) abs(t);
1958 if (cp > 1.0) {
1959 cp = 1.0;
1960 }
1961 } else {
1962 cp = 1.0;
1963 }
1964
1965 /* Calculate weight */
1966 weight = (Uint8) (cp * 255);
1967 iweight = 255 - weight;
1968
1969 /* Left half */
1970 xx = xc2 - xp;
1971 yy = yc2 - yp;
1972 result &= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
1973 result &= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
1974
1975 result &= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
1976 result &= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
1977
1978 /* Right half */
1979 xx = xc2 - xs;
1980 result &= pixelRGBAWeight(renderer, xs, yp, r, g, b, a, weight);
1981 result &= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, weight);
1982
1983 result &= pixelRGBAWeight(renderer, xs, yy, r, g, b, a, weight);
1984 result &= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);
1985 }
1986
1987 return (result);
1988}
1989
1990/* ---- Filled Ellipse */
1991
2004 bool filledEllipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
2005{
2006 Uint8 *c = (Uint8 *)&color;
2007 return _ellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3], 1);
2008}
2009
2025 bool filledEllipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2026{
2027 return _ellipseRGBA(renderer, x, y, rx, ry, r, g, b, a, 1);
2028}
2029
2030/* ----- Pie */
2031
2051/* TODO: rewrite algorithm; pie is not always accurate */
2052 bool _pieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Uint8 filled)
2053{
2054 bool result;
2055 double angle, start_angle, end_angle;
2056 double deltaAngle;
2057 double dr;
2058 int numpoints, i;
2059 Sint16 *vx, *vy;
2060
2061 /*
2062 * Sanity check radii
2063 */
2064 if (rad < 0) {
2065 return (false);
2066 }
2067
2068 /*
2069 * Fixup angles
2070 */
2071 start = start % 360;
2072 end = end % 360;
2073
2074 /*
2075 * Special case for rad=0 - draw a point
2076 */
2077 if (rad == 0) {
2078 return (pixelRGBA(renderer, x, y, r, g, b, a));
2079 }
2080
2081 /*
2082 * Variable setup
2083 */
2084 dr = (double) rad;
2085 deltaAngle = 3.0 / dr;
2086 start_angle = (double) start *(2.0 * M_PI / 360.0);
2087 end_angle = (double) end *(2.0 * M_PI / 360.0);
2088 if (start > end) {
2089 end_angle += (2.0 * M_PI);
2090 }
2091
2092 /* We will always have at least 2 points */
2093 numpoints = 2;
2094
2095 /* Count points (rather than calculating it) */
2096 angle = start_angle;
2097 while (angle < end_angle) {
2098 angle += deltaAngle;
2099 numpoints++;
2100 }
2101
2102 /* Allocate combined vertex array */
2103 vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
2104 if (vx == NULL) {
2105 return (false);
2106 }
2107
2108 /* Update point to start of vy */
2109 vy += numpoints;
2110
2111 /* Center */
2112 vx[0] = x;
2113 vy[0] = y;
2114
2115 /* First vertex */
2116 angle = start_angle;
2117 vx[1] = x + (int) (dr * cos(angle));
2118 vy[1] = y + (int) (dr * sin(angle));
2119
2120 if (numpoints<3)
2121 {
2122 result = lineRGBA(renderer, vx[0], vy[0], vx[1], vy[1], r, g, b, a);
2123 }
2124 else
2125 {
2126 /* Calculate other vertices */
2127 i = 2;
2128 angle = start_angle;
2129 while (angle < end_angle) {
2130 angle += deltaAngle;
2131 if (angle>end_angle)
2132 {
2133 angle = end_angle;
2134 }
2135 vx[i] = x + (int) (dr * cos(angle));
2136 vy[i] = y + (int) (dr * sin(angle));
2137 i++;
2138 }
2139
2140 /* Draw */
2141 if (filled) {
2142 result = filledPolygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
2143 } else {
2144 result = polygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
2145 }
2146 }
2147
2148 /* Free combined vertex array */
2149 free(vx);
2150
2151 return (result);
2152}
2153
2167 bool pieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
2168 Sint16 start, Sint16 end, Uint32 color)
2169{
2170 Uint8 *c = (Uint8 *)&color;
2171 return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 0);
2172}
2173
2190 bool pieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
2191 Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2192{
2193 return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 0);
2194}
2195
2209 bool filledPieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
2210{
2211 Uint8 *c = (Uint8 *)&color;
2212 return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 1);
2213}
2214
2231 bool filledPieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
2232 Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2233{
2234 return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 1);
2235}
2236
2237/* ------ Trigon */
2238
2255 bool trigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
2256{
2257 Sint16 vx[3];
2258 Sint16 vy[3];
2259
2260 vx[0]=x1;
2261 vx[1]=x2;
2262 vx[2]=x3;
2263 vy[0]=y1;
2264 vy[1]=y2;
2265 vy[2]=y3;
2266
2267 return(polygonColor(renderer,vx,vy,3,color));
2268}
2269
2287 bool trigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
2288 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2289{
2290 Sint16 vx[3];
2291 Sint16 vy[3];
2292
2293 vx[0]=x1;
2294 vx[1]=x2;
2295 vx[2]=x3;
2296 vy[0]=y1;
2297 vy[1]=y2;
2298 vy[2]=y3;
2299
2300 return(polygonRGBA(renderer,vx,vy,3,r,g,b,a));
2301}
2302
2303/* ------ AA-Trigon */
2304
2321 bool aatrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
2322{
2323 Sint16 vx[3];
2324 Sint16 vy[3];
2325
2326 vx[0]=x1;
2327 vx[1]=x2;
2328 vx[2]=x3;
2329 vy[0]=y1;
2330 vy[1]=y2;
2331 vy[2]=y3;
2332
2333 return(aapolygonColor(renderer,vx,vy,3,color));
2334}
2335
2353 bool aatrigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
2354 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2355{
2356 Sint16 vx[3];
2357 Sint16 vy[3];
2358
2359 vx[0]=x1;
2360 vx[1]=x2;
2361 vx[2]=x3;
2362 vy[0]=y1;
2363 vy[1]=y2;
2364 vy[2]=y3;
2365
2366 return(aapolygonRGBA(renderer,vx,vy,3,r,g,b,a));
2367}
2368
2369/* ------ Filled Trigon */
2370
2387 bool filledTrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
2388{
2389 Sint16 vx[3];
2390 Sint16 vy[3];
2391
2392 vx[0]=x1;
2393 vx[1]=x2;
2394 vx[2]=x3;
2395 vy[0]=y1;
2396 vy[1]=y2;
2397 vy[2]=y3;
2398
2399 return(filledPolygonColor(renderer,vx,vy,3,color));
2400}
2401
2421 bool filledTrigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
2422 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2423{
2424 Sint16 vx[3];
2425 Sint16 vy[3];
2426
2427 vx[0]=x1;
2428 vx[1]=x2;
2429 vx[2]=x3;
2430 vy[0]=y1;
2431 vy[1]=y2;
2432 vy[2]=y3;
2433
2434 return(filledPolygonRGBA(renderer,vx,vy,3,r,g,b,a));
2435}
2436
2437/* ---- Polygon */
2438
2450 bool polygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
2451{
2452 Uint8 *c = (Uint8 *)&color;
2453 return polygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
2454}
2455
2466 bool polygon(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n)
2467{
2468 /*
2469 * Draw
2470 */
2471 bool result = true;
2472 int i, nn;
2473 SDL_FPoint* points;
2474
2475 /*
2476 * Vertex array NULL check
2477 */
2478 if (vx == NULL) {
2479 return (false);
2480 }
2481 if (vy == NULL) {
2482 return (false);
2483 }
2484
2485 /*
2486 * Sanity check
2487 */
2488 if (n < 3) {
2489 return (false);
2490 }
2491
2492 /*
2493 * Create array of points
2494 */
2495 nn = n + 1;
2496 points = (SDL_FPoint*)malloc(sizeof(SDL_FPoint) * nn);
2497 if (points == NULL)
2498 {
2499 return false;
2500 }
2501 for (i=0; i<n; i++)
2502 {
2503 points[i].x = vx[i];
2504 points[i].y = vy[i];
2505 }
2506 points[n].x = vx[0];
2507 points[n].y = vy[0];
2508
2509 /*
2510 * Draw
2511 */
2512 result &= SDL_RenderLines(renderer, points, nn);
2513 free(points);
2514
2515 return (result);
2516}
2517
2532 bool polygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2533{
2534 /*
2535 * Draw
2536 */
2537 bool result;
2538 const Sint16 *x1, *y1, *x2, *y2;
2539
2540 /*
2541 * Vertex array NULL check
2542 */
2543 if (vx == NULL) {
2544 return (false);
2545 }
2546 if (vy == NULL) {
2547 return (false);
2548 }
2549
2550 /*
2551 * Sanity check
2552 */
2553 if (n < 3) {
2554 return (false);
2555 }
2556
2557 /*
2558 * Pointer setup
2559 */
2560 x1 = x2 = vx;
2561 y1 = y2 = vy;
2562 x2++;
2563 y2++;
2564
2565 /*
2566 * Set color
2567 */
2568 result = true;
2569 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
2570 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
2571
2572 /*
2573 * Draw
2574 */
2575 result &= polygon(renderer, vx, vy, n);
2576
2577 return (result);
2578}
2579
2580/* ---- AA-Polygon */
2581
2593 bool aapolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
2594{
2595 Uint8 *c = (Uint8 *)&color;
2596 return aapolygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
2597}
2598
2613 bool aapolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2614{
2615 bool result;
2616 int i;
2617 const Sint16 *x1, *y1, *x2, *y2;
2618
2619 /*
2620 * Vertex array NULL check
2621 */
2622 if (vx == NULL) {
2623 return (false);
2624 }
2625 if (vy == NULL) {
2626 return (false);
2627 }
2628
2629 /*
2630 * Sanity check
2631 */
2632 if (n < 3) {
2633 return (false);
2634 }
2635
2636 /*
2637 * Pointer setup
2638 */
2639 x1 = x2 = vx;
2640 y1 = y2 = vy;
2641 x2++;
2642 y2++;
2643
2644 /*
2645 * Draw
2646 */
2647 result = true;
2648 for (i = 1; i < n; i++) {
2649 result &= _aalineRGBA(renderer, *x1, *y1, *x2, *y2, r, g, b, a, 0);
2650 x1 = x2;
2651 y1 = y2;
2652 x2++;
2653 y2++;
2654 }
2655
2656 result &= _aalineRGBA(renderer, *x1, *y1, *vx, *vy, r, g, b, a, 0);
2657
2658 return (result);
2659}
2660
2661/* ---- Filled Polygon */
2662
2671 int _gfxPrimitivesCompareInt(const void *a, const void *b)
2672{
2673 return (*(const int *) a) - (*(const int *) b);
2674}
2675
2681 static int *gfxPrimitivesPolyIntsGlobal = NULL;
2682
2688 static int gfxPrimitivesPolyAllocatedGlobal = 0;
2689
2708 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)
2709{
2710 bool result;
2711 int i;
2712 int y, xa, xb;
2713 int miny, maxy;
2714 int x1, y1;
2715 int x2, y2;
2716 int ind1, ind2;
2717 int ints;
2718 int *gfxPrimitivesPolyInts = NULL;
2719 int *gfxPrimitivesPolyIntsNew = NULL;
2720 int gfxPrimitivesPolyAllocated = 0;
2721
2722 /*
2723 * Vertex array NULL check
2724 */
2725 if (vx == NULL) {
2726 return (false);
2727 }
2728 if (vy == NULL) {
2729 return (false);
2730 }
2731
2732 /*
2733 * Sanity check number of edges
2734 */
2735 if (n < 3) {
2736 return false;
2737 }
2738
2739 /*
2740 * Map polygon cache
2741 */
2742 if ((polyInts==NULL) || (polyAllocated==NULL)) {
2743 /* Use global cache */
2744 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
2745 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
2746 } else {
2747 /* Use local cache */
2748 gfxPrimitivesPolyInts = *polyInts;
2749 gfxPrimitivesPolyAllocated = *polyAllocated;
2750 }
2751
2752 /*
2753 * Allocate temp array, only grow array
2754 */
2755 if (!gfxPrimitivesPolyAllocated) {
2756 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
2757 gfxPrimitivesPolyAllocated = n;
2758 } else {
2759 if (gfxPrimitivesPolyAllocated < n) {
2760 gfxPrimitivesPolyIntsNew = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
2761 if (!gfxPrimitivesPolyIntsNew) {
2762 if (!gfxPrimitivesPolyInts) {
2763 free(gfxPrimitivesPolyInts);
2764 gfxPrimitivesPolyInts = NULL;
2765 }
2766 gfxPrimitivesPolyAllocated = 0;
2767 } else {
2768 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsNew;
2769 gfxPrimitivesPolyAllocated = n;
2770 }
2771 }
2772 }
2773
2774 /*
2775 * Check temp array
2776 */
2777 if (gfxPrimitivesPolyInts==NULL) {
2778 gfxPrimitivesPolyAllocated = 0;
2779 }
2780
2781 /*
2782 * Update cache variables
2783 */
2784 if ((polyInts==NULL) || (polyAllocated==NULL)) {
2785 gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
2786 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
2787 } else {
2788 *polyInts = gfxPrimitivesPolyInts;
2789 *polyAllocated = gfxPrimitivesPolyAllocated;
2790 }
2791
2792 /*
2793 * Check temp array again
2794 */
2795 if (gfxPrimitivesPolyInts==NULL) {
2796 return(false);
2797 }
2798
2799 /*
2800 * Determine Y maxima
2801 */
2802 miny = vy[0];
2803 maxy = vy[0];
2804 for (i = 1; (i < n); i++) {
2805 if (vy[i] < miny) {
2806 miny = vy[i];
2807 } else if (vy[i] > maxy) {
2808 maxy = vy[i];
2809 }
2810 }
2811
2812 /*
2813 * Draw, scanning y
2814 */
2815 for (y = miny; (y <= maxy); y++) {
2816 ints = 0;
2817 for (i = 0; (i < n); i++) {
2818 if (!i) {
2819 ind1 = n - 1;
2820 ind2 = 0;
2821 } else {
2822 ind1 = i - 1;
2823 ind2 = i;
2824 }
2825 y1 = vy[ind1];
2826 y2 = vy[ind2];
2827 if (y1 < y2) {
2828 x1 = vx[ind1];
2829 x2 = vx[ind2];
2830 } else if (y1 > y2) {
2831 y2 = vy[ind1];
2832 y1 = vy[ind2];
2833 x2 = vx[ind1];
2834 x1 = vx[ind2];
2835 } else {
2836 continue;
2837 }
2838 if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
2839 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
2840 }
2841 }
2842
2843 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
2844
2845 /*
2846 * Set color
2847 */
2848 result = true;
2849 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
2850 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
2851
2852 for (i = 0; (i < ints); i += 2) {
2853 xa = gfxPrimitivesPolyInts[i] + 1;
2854 xa = (xa >> 16) + ((xa & 32768) >> 15);
2855 xb = gfxPrimitivesPolyInts[i+1] - 1;
2856 xb = (xb >> 16) + ((xb & 32768) >> 15);
2857 result &= hline(renderer, xa, xb, y);
2858 }
2859 }
2860
2861 return (result);
2862}
2863
2875 bool filledPolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
2876{
2877 Uint8 *c = (Uint8 *)&color;
2878 return filledPolygonRGBAMT(renderer, vx, vy, n, c[0], c[1], c[2], c[3], NULL, NULL);
2879}
2880
2895 bool filledPolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2896{
2897 return filledPolygonRGBAMT(renderer, vx, vy, n, r, g, b, a, NULL, NULL);
2898}
2899
2900/* ---- Textured Polygon */
2901
2917 bool _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)
2918{
2919 Sint16 w;
2920 Sint16 xtmp;
2921 bool result = true;
2922 int texture_x_walker;
2923 int texture_y_start;
2924 SDL_FRect source_rect,dst_rect;
2925 int pixels_written,write_width;
2926
2927 /*
2928 * Swap x1, x2 if required to ensure x1<=x2
2929 */
2930 if (x1 > x2) {
2931 xtmp = x1;
2932 x1 = x2;
2933 x2 = xtmp;
2934 }
2935
2936 /*
2937 * Calculate width to draw
2938 */
2939 w = x2 - x1 + 1;
2940
2941 /*
2942 * Determine where in the texture we start drawing
2943 */
2944 texture_x_walker = (x1 - texture_dx) % texture_w;
2945 if (texture_x_walker < 0){
2946 texture_x_walker = texture_w + texture_x_walker ;
2947 }
2948
2949 texture_y_start = (y + texture_dy) % texture_h;
2950 if (texture_y_start < 0){
2951 texture_y_start = texture_h + texture_y_start;
2952 }
2953
2954 /* setup the source rectangle; we are only drawing one horizontal line */
2955 source_rect.y = texture_y_start;
2956 source_rect.x = texture_x_walker;
2957 source_rect.h = 1;
2958
2959 /* we will draw to the current y */
2960 dst_rect.y = y;
2961 dst_rect.h = 1;
2962
2963 /* if there are enough pixels left in the current row of the texture */
2964 /* draw it all at once */
2965 if (w <= texture_w -texture_x_walker){
2966 source_rect.w = w;
2967 source_rect.x = texture_x_walker;
2968 dst_rect.x= x1;
2969 dst_rect.w = source_rect.w;
2970 result = (SDL_RenderTexture(renderer, texture, &source_rect, &dst_rect) == 0);
2971 } else {
2972 /* we need to draw multiple times */
2973 /* draw the first segment */
2974 pixels_written = texture_w - texture_x_walker;
2975 source_rect.w = pixels_written;
2976 source_rect.x = texture_x_walker;
2977 dst_rect.x= x1;
2978 dst_rect.w = source_rect.w;
2979 result &= (SDL_RenderTexture(renderer, texture, &source_rect, &dst_rect) == 0);
2980 write_width = texture_w;
2981
2982 /* now draw the rest */
2983 /* set the source x to 0 */
2984 source_rect.x = 0;
2985 while (pixels_written < w){
2986 if (write_width >= w - pixels_written) {
2987 write_width = w - pixels_written;
2988 }
2989 source_rect.w = write_width;
2990 dst_rect.x = x1 + pixels_written;
2991 dst_rect.w = source_rect.w;
2992 result &= (SDL_RenderTexture(renderer, texture, &source_rect, &dst_rect) == 0);
2993 pixels_written += write_width;
2994 }
2995 }
2996
2997 return result;
2998}
2999
3016 bool texturedPolygonMT(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n,
3017 SDL_Surface * texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated)
3018{
3019 bool result;
3020 int i;
3021 int y, xa, xb;
3022 int minx,maxx,miny, maxy;
3023 int x1, y1;
3024 int x2, y2;
3025 int ind1, ind2;
3026 int ints;
3027 int *gfxPrimitivesPolyInts = NULL;
3028 int *gfxPrimitivesPolyIntsTemp = NULL;
3029 int gfxPrimitivesPolyAllocated = 0;
3030 SDL_Texture *textureAsTexture = NULL;
3031
3032 /*
3033 * Sanity check number of edges
3034 */
3035 if (n < 3) {
3036 return false;
3037 }
3038
3039 /*
3040 * Map polygon cache
3041 */
3042 if ((polyInts==NULL) || (polyAllocated==NULL)) {
3043 /* Use global cache */
3044 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
3045 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
3046 } else {
3047 /* Use local cache */
3048 gfxPrimitivesPolyInts = *polyInts;
3049 gfxPrimitivesPolyAllocated = *polyAllocated;
3050 }
3051
3052 /*
3053 * Allocate temp array, only grow array
3054 */
3055 if (!gfxPrimitivesPolyAllocated) {
3056 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
3057 gfxPrimitivesPolyAllocated = n;
3058 } else {
3059 if (gfxPrimitivesPolyAllocated < n) {
3060 gfxPrimitivesPolyIntsTemp = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
3061 if (gfxPrimitivesPolyIntsTemp == NULL) {
3062 /* Realloc failed - keeps original memory block, but fails this operation */
3063 return(false);
3064 }
3065 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsTemp;
3066 gfxPrimitivesPolyAllocated = n;
3067 }
3068 }
3069
3070 /*
3071 * Check temp array
3072 */
3073 if (gfxPrimitivesPolyInts==NULL) {
3074 gfxPrimitivesPolyAllocated = 0;
3075 }
3076
3077 /*
3078 * Update cache variables
3079 */
3080 if ((polyInts==NULL) || (polyAllocated==NULL)) {
3081 gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
3082 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
3083 } else {
3084 *polyInts = gfxPrimitivesPolyInts;
3085 *polyAllocated = gfxPrimitivesPolyAllocated;
3086 }
3087
3088 /*
3089 * Check temp array again
3090 */
3091 if (gfxPrimitivesPolyInts==NULL) {
3092 return(false);
3093 }
3094
3095 /*
3096 * Determine X,Y minima,maxima
3097 */
3098 miny = vy[0];
3099 maxy = vy[0];
3100 minx = vx[0];
3101 maxx = vx[0];
3102 for (i = 1; (i < n); i++) {
3103 if (vy[i] < miny) {
3104 miny = vy[i];
3105 } else if (vy[i] > maxy) {
3106 maxy = vy[i];
3107 }
3108 if (vx[i] < minx) {
3109 minx = vx[i];
3110 } else if (vx[i] > maxx) {
3111 maxx = vx[i];
3112 }
3113 }
3114
3115 /* Create texture for drawing */
3116 textureAsTexture = SDL_CreateTextureFromSurface(renderer, texture);
3117 if (textureAsTexture == NULL)
3118 {
3119 return false;
3120 }
3121 SDL_SetTextureBlendMode(textureAsTexture, SDL_BLENDMODE_BLEND);
3122
3123 /*
3124 * Draw, scanning y
3125 */
3126 result = true;
3127 for (y = miny; (y <= maxy); y++) {
3128 ints = 0;
3129 for (i = 0; (i < n); i++) {
3130 if (!i) {
3131 ind1 = n - 1;
3132 ind2 = 0;
3133 } else {
3134 ind1 = i - 1;
3135 ind2 = i;
3136 }
3137 y1 = vy[ind1];
3138 y2 = vy[ind2];
3139 if (y1 < y2) {
3140 x1 = vx[ind1];
3141 x2 = vx[ind2];
3142 } else if (y1 > y2) {
3143 y2 = vy[ind1];
3144 y1 = vy[ind2];
3145 x2 = vx[ind1];
3146 x1 = vx[ind2];
3147 } else {
3148 continue;
3149 }
3150 if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
3151 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
3152 }
3153 }
3154
3155 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
3156
3157 for (i = 0; (i < ints); i += 2) {
3158 xa = gfxPrimitivesPolyInts[i] + 1;
3159 xa = (xa >> 16) + ((xa & 32768) >> 15);
3160 xb = gfxPrimitivesPolyInts[i+1] - 1;
3161 xb = (xb >> 16) + ((xb & 32768) >> 15);
3162 result &= _HLineTextured(renderer, xa, xb, y, textureAsTexture, texture->w, texture->h, texture_dx, texture_dy);
3163 }
3164 }
3165
3166 SDL_DestroyTexture(textureAsTexture);
3167
3168 return (result);
3169}
3170
3187 bool texturedPolygon(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
3188{
3189 /*
3190 * Draw
3191 */
3192 return (texturedPolygonMT(renderer, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
3193}
3194
3195/* ---- Character */
3196
3200 static SDL_Texture *gfxPrimitivesFont[256];
3201
3205 static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
3206
3210 static Uint32 charWidth = 8;
3211
3215 static Uint32 charHeight = 8;
3216
3220 static Uint32 charWidthLocal = 8;
3221
3225 static Uint32 charHeightLocal = 8;
3226
3230 static Uint32 charPitch = 1;
3231
3235 static Uint32 charRotation = 0;
3236
3240 static Uint32 charSize = 8;
3241
3255 void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch)
3256{
3257 int i;
3258
3259 if ((fontdata) && (cw) && (ch)) {
3260 currentFontdata = (unsigned char *)fontdata;
3261 charWidth = cw;
3262 charHeight = ch;
3263 } else {
3264 currentFontdata = gfxPrimitivesFontdata;
3265 charWidth = 8;
3266 charHeight = 8;
3267 }
3268
3269 charPitch = (charWidth+7)/8;
3270 charSize = charPitch * charHeight;
3271
3272 /* Maybe flip width/height for rendering */
3273 if ((charRotation==1) || (charRotation==3))
3274 {
3275 charWidthLocal = charHeight;
3276 charHeightLocal = charWidth;
3277 }
3278 else
3279 {
3280 charWidthLocal = charWidth;
3281 charHeightLocal = charHeight;
3282 }
3283
3284 /* Clear character cache */
3285 for (i = 0; i < 256; i++) {
3286 if (gfxPrimitivesFont[i]) {
3287 SDL_DestroyTexture(gfxPrimitivesFont[i]);
3288 gfxPrimitivesFont[i] = NULL;
3289 }
3290 }
3291}
3292
3301 void gfxPrimitivesSetFontRotation(Uint32 rotation)
3302{
3303 int i;
3304
3305 rotation = rotation & 3;
3306 if (charRotation != rotation)
3307 {
3308 /* Store rotation */
3309 charRotation = rotation;
3310
3311 /* Maybe flip width/height for rendering */
3312 if ((charRotation==1) || (charRotation==3))
3313 {
3314 charWidthLocal = charHeight;
3315 charHeightLocal = charWidth;
3316 }
3317 else
3318 {
3319 charWidthLocal = charWidth;
3320 charHeightLocal = charHeight;
3321 }
3322
3323 /* Clear character cache */
3324 for (i = 0; i < 256; i++) {
3325 if (gfxPrimitivesFont[i]) {
3326 SDL_DestroyTexture(gfxPrimitivesFont[i]);
3327 gfxPrimitivesFont[i] = NULL;
3328 }
3329 }
3330 }
3331}
3332
3347 bool characterRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3348{
3349 SDL_FRect srect;
3350 SDL_FRect drect;
3351 bool result;
3352 Uint32 ix, iy;
3353 const unsigned char *charpos;
3354 Uint8 *curpos;
3355 Uint8 patt, mask;
3356 Uint8 *linepos;
3357 Uint32 pitch;
3358 SDL_Surface *character;
3359 SDL_Surface *rotatedCharacter;
3360 Uint32 ci;
3361
3362 /*
3363 * Setup source rectangle
3364 */
3365 srect.x = 0;
3366 srect.y = 0;
3367 srect.w = charWidthLocal;
3368 srect.h = charHeightLocal;
3369
3370 /*
3371 * Setup destination rectangle
3372 */
3373 drect.x = x;
3374 drect.y = y;
3375 drect.w = charWidthLocal;
3376 drect.h = charHeightLocal;
3377
3378 /* Character index in cache */
3379 ci = (unsigned char) c;
3380
3381 /*
3382 * Create new charWidth x charHeight bitmap surface if not already present.
3383 * Might get rotated later.
3384 */
3385 if (gfxPrimitivesFont[ci] == NULL) {
3386 /*
3387 * Redraw character into surface
3388 */
3389 character = SDL_CreateSurface(
3390 charWidth, charHeight, SDL_PIXELFORMAT_RGBA8888);
3391 if (character == NULL) {
3392 return (false);
3393 }
3394
3395 charpos = currentFontdata + ci * charSize;
3396 linepos = (Uint8 *)character->pixels;
3397 pitch = character->pitch;
3398
3399 /*
3400 * Drawing loop
3401 */
3402 patt = 0;
3403 for (iy = 0; iy < charHeight; iy++) {
3404 mask = 0x00;
3405 curpos = linepos;
3406 for (ix = 0; ix < charWidth; ix++) {
3407 if (!(mask >>= 1)) {
3408 patt = *charpos++;
3409 mask = 0x80;
3410 }
3411 if (patt & mask) {
3412 *(Uint32 *)curpos = 0xffffffff;
3413 } else {
3414 *(Uint32 *)curpos = 0;
3415 }
3416 curpos += 4;
3417 }
3418 linepos += pitch;
3419 }
3420
3421 /* Maybe rotate and replace cached image */
3422 if (charRotation>0)
3423 {
3424 rotatedCharacter = rotateSurface90Degrees(character, charRotation);
3425 SDL_DestroySurface(character);
3426 character = rotatedCharacter;
3427 }
3428
3429 /* Convert temp surface into texture */
3430 gfxPrimitivesFont[ci] = SDL_CreateTextureFromSurface(renderer, character);
3431 SDL_DestroySurface(character);
3432
3433 /*
3434 * Check pointer
3435 */
3436 if (gfxPrimitivesFont[ci] == NULL) {
3437 return (false);
3438 }
3439 }
3440
3441 /*
3442 * Set color
3443 */
3444 result = true;
3445 result &= SDL_SetTextureColorMod(gfxPrimitivesFont[ci], r, g, b);
3446 result &= SDL_SetTextureAlphaMod(gfxPrimitivesFont[ci], a);
3447
3448 /*
3449 * Draw texture onto destination
3450 */
3451 result &= SDL_RenderTexture(renderer, gfxPrimitivesFont[ci], &srect, &drect);
3452
3453 return (result);
3454}
3455
3456
3468 bool characterColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, char c, Uint32 color)
3469{
3470 Uint8 *co = (Uint8 *)&color;
3471 return characterRGBA(renderer, x, y, c, co[0], co[1], co[2], co[3]);
3472}
3473
3474
3489 bool stringColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint32 color)
3490{
3491 Uint8 *c = (Uint8 *)&color;
3492 return stringRGBA(renderer, x, y, s, c[0], c[1], c[2], c[3]);
3493}
3494
3509 bool stringRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3510{
3511 bool result = true;
3512 Sint16 curx = x;
3513 Sint16 cury = y;
3514 const char *curchar = s;
3515
3516 while (*curchar && result) {
3517 result &= characterRGBA(renderer, curx, cury, *curchar, r, g, b, a);
3518 switch (charRotation)
3519 {
3520 case 0:
3521 curx += charWidthLocal;
3522 break;
3523 case 2:
3524 curx -= charWidthLocal;
3525 break;
3526 case 1:
3527 cury += charHeightLocal;
3528 break;
3529 case 3:
3530 cury -= charHeightLocal;
3531 break;
3532 }
3533 curchar++;
3534 }
3535
3536 return (result);
3537}
3538
3539/* ---- Bezier curve */
3540
3550 double _evaluateBezier (double *data, int ndata, double t)
3551{
3552 double mu, result;
3553 int n,k,kn,nn,nkn;
3554 double blend,muk,munk;
3555
3556 /* Sanity check bounds */
3557 if (t<0.0) {
3558 return(data[0]);
3559 }
3560 if (t>=(double)ndata) {
3561 return(data[ndata-1]);
3562 }
3563
3564 /* Adjust t to the range 0.0 to 1.0 */
3565 mu=t/(double)ndata;
3566
3567 /* Calculate interpolate */
3568 n=ndata-1;
3569 result=0.0;
3570 muk = 1;
3571 munk = pow(1-mu,(double)n);
3572 for (k=0;k<=n;k++) {
3573 nn = n;
3574 kn = k;
3575 nkn = n - k;
3576 blend = muk * munk;
3577 muk *= mu;
3578 munk /= (1-mu);
3579 while (nn >= 1) {
3580 blend *= nn;
3581 nn--;
3582 if (kn > 1) {
3583 blend /= (double)kn;
3584 kn--;
3585 }
3586 if (nkn > 1) {
3587 blend /= (double)nkn;
3588 nkn--;
3589 }
3590 }
3591 result += data[k] * blend;
3592 }
3593
3594 return (result);
3595}
3596
3609 bool bezierColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
3610{
3611 Uint8 *c = (Uint8 *)&color;
3612 return bezierRGBA(renderer, vx, vy, n, s, c[0], c[1], c[2], c[3]);
3613}
3614
3630 bool bezierRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3631{
3632 bool result;
3633 int i;
3634 double *x, *y, t, stepsize;
3635 Sint16 x1, y1, x2, y2;
3636
3637 /*
3638 * Sanity check
3639 */
3640 if (n < 3) {
3641 return (false);
3642 }
3643 if (s < 2) {
3644 return (false);
3645 }
3646
3647 /*
3648 * Variable setup
3649 */
3650 stepsize=(double)1.0/(double)s;
3651
3652 /* Transfer vertices into float arrays */
3653 if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
3654 return(false);
3655 }
3656 if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
3657 free(x);
3658 return(false);
3659 }
3660 for (i=0; i<n; i++) {
3661 x[i]=(double)vx[i];
3662 y[i]=(double)vy[i];
3663 }
3664 x[n]=(double)vx[0];
3665 y[n]=(double)vy[0];
3666
3667 /*
3668 * Set color
3669 */
3670 result = true;
3671 result &= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
3672 result &= SDL_SetRenderDrawColor(renderer, r, g, b, a);
3673
3674 /*
3675 * Draw
3676 */
3677 t=0.0;
3678 x1=(Sint16)lrint(_evaluateBezier(x,n+1,t));
3679 y1=(Sint16)lrint(_evaluateBezier(y,n+1,t));
3680 for (i = 0; i <= (n*s); i++) {
3681 t += stepsize;
3682 x2=(Sint16)_evaluateBezier(x,n,t);
3683 y2=(Sint16)_evaluateBezier(y,n,t);
3684 result &= line(renderer, x1, y1, x2, y2);
3685 x1 = x2;
3686 y1 = y2;
3687 }
3688
3689 /* Clean up temporary array */
3690 free(x);
3691 free(y);
3692
3693 return (result);
3694}
3695
3696
3710 bool thickLineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
3711{
3712 Uint8 *c = (Uint8 *)&color;
3713 return thickLineRGBA(renderer, x1, y1, x2, y2, width, c[0], c[1], c[2], c[3]);
3714}
3715
3732 bool thickLineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3733{
3734 int wh;
3735 double dx, dy, dx1, dy1, dx2, dy2;
3736 double l, wl2, nx, ny, ang, adj;
3737 Sint16 px[4], py[4];
3738
3739 if (renderer == NULL) {
3740 return false;
3741 }
3742
3743 if (width < 1) {
3744 return false;
3745 }
3746
3747 /* Special case: thick "point" */
3748 if ((x1 == x2) && (y1 == y2)) {
3749 wh = width / 2;
3750 return boxRGBA(renderer, x1 - wh, y1 - wh, x2 + width, y2 + width, r, g, b, a);
3751 }
3752
3753 /* Special case: width == 1 */
3754 if (width == 1) {
3755 return lineRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
3756 }
3757
3758 /* Calculate offsets for sides */
3759 dx = (double)(x2 - x1);
3760 dy = (double)(y2 - y1);
3761 l = SDL_sqrt(dx*dx + dy*dy);
3762 ang = SDL_atan2(dx, dy);
3763 adj = 0.1 + 0.9 * SDL_fabs(SDL_cos(2.0 * ang));
3764 wl2 = ((double)width - adj)/(2.0 * l);
3765 nx = dx * wl2;
3766 ny = dy * wl2;
3767
3768 /* Build polygon */
3769 dx1 = (double)x1;
3770 dy1 = (double)y1;
3771 dx2 = (double)x2;
3772 dy2 = (double)y2;
3773 px[0] = (Sint16)(dx1 + ny);
3774 px[1] = (Sint16)(dx1 - ny);
3775 px[2] = (Sint16)(dx2 - ny);
3776 px[3] = (Sint16)(dx2 + ny);
3777 py[0] = (Sint16)(dy1 - nx);
3778 py[1] = (Sint16)(dy1 + nx);
3779 py[2] = (Sint16)(dy2 + nx);
3780 py[3] = (Sint16)(dy2 - nx);
3781
3782 /* Draw polygon */
3783 return filledPolygonRGBA(renderer, px, py, 4, r, g, b, a);
3784}
pixel
bool pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
Draw pixel in currently set color.
Definition SDL3_gfxPrimitives.c:50
polygonColor
bool polygonColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color)
Draw polygon with alpha blending.
Definition SDL3_gfxPrimitives.c:2450
characterRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:3347
aaellipseRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:1809
bezierRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:3630
filledPolygonColor
bool filledPolygonColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color)
Draw filled polygon with alpha blending.
Definition SDL3_gfxPrimitives.c:2875
aapolygonRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2613
filledPolygonRGBAMT
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).
Definition SDL3_gfxPrimitives.c:2708
AAbits
#define AAbits
Definition SDL3_gfxPrimitives.c:834
vline
bool vline(SDL_Renderer *renderer, Sint16 x, Sint16 y1, Sint16 y2)
Draw vertical line in currently set color.
Definition SDL3_gfxPrimitives.c:193
characterColor
bool characterColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, char c, Uint32 color)
Draw a character of the currently set font.
Definition SDL3_gfxPrimitives.c:3468
filledTrigonRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2421
aapolygonColor
bool aapolygonColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color)
Draw anti-aliased polygon with alpha blending.
Definition SDL3_gfxPrimitives.c:2593
thickLineRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:3732
aaellipseColor
bool aaellipseColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
Draw anti-aliased ellipse with blending.
Definition SDL3_gfxPrimitives.c:1788
aalineRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:1094
polygonRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2532
line
bool line(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
Draw line with alpha blending using the currently set color.
Definition SDL3_gfxPrimitives.c:778
bezierColor
bool bezierColor(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n, int s, Uint32 color)
Draw a bezier curve with alpha blending.
Definition SDL3_gfxPrimitives.c:3609
aatrigonRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2353
roundedRectangleRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:367
arcColor
bool arcColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
Arc with blending.
Definition SDL3_gfxPrimitives.c:1152
filledTrigonColor
bool 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.
Definition SDL3_gfxPrimitives.c:2387
stringRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:3509
_HLineTextured
bool _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.
Definition SDL3_gfxPrimitives.c:2917
boxColor
bool boxColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw box (filled rectangle) with blending.
Definition SDL3_gfxPrimitives.c:687
AAlevels
#define AAlevels
Definition SDL3_gfxPrimitives.c:833
pixelRGBAWeight
bool 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.
Definition SDL3_gfxPrimitives.c:107
circleColor
bool circleColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
Draw circle with blending.
Definition SDL3_gfxPrimitives.c:1112
lineRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:819
aacircleColor
bool aacircleColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
Draw anti-aliased circle with blending.
Definition SDL3_gfxPrimitives.c:1410
filledEllipseRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2025
pixelColor
bool pixelColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Uint32 color)
Draw pixel with blending enabled if a<255.
Definition SDL3_gfxPrimitives.c:65
rectangleColor
bool rectangleColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw rectangle with blending.
Definition SDL3_gfxPrimitives.c:252
ellipseColor
bool ellipseColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
Draw ellipse with blending.
Definition SDL3_gfxPrimitives.c:1669
lineColor
bool lineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw line with alpha blending.
Definition SDL3_gfxPrimitives.c:798
polygon
bool polygon(SDL_Renderer *renderer, const Sint16 *vx, const Sint16 *vy, int n)
Draw polygon with the currently set color and blend mode.
Definition SDL3_gfxPrimitives.c:2466
aatrigonColor
bool 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.
Definition SDL3_gfxPrimitives.c:2321
_drawQuadrants
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.
Definition SDL3_gfxPrimitives.c:1452
texturedPolygon
bool 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.
Definition SDL3_gfxPrimitives.c:3187
filledCircleRGBA
bool filledCircleRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw filled circle with blending.
Definition SDL3_gfxPrimitives.c:1728
_evaluateBezier
double _evaluateBezier(double *data, int ndata, double t)
Internal function to calculate bezier interpolator of data array with ndata values at position 't'.
Definition SDL3_gfxPrimitives.c:3550
vlineColor
bool vlineColor(SDL_Renderer *renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
Draw vertical line with blending.
Definition SDL3_gfxPrimitives.c:209
filledPieRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2231
aacircleRGBA
bool aacircleRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw anti-aliased circle with blending.
Definition SDL3_gfxPrimitives.c:1430
ellipseRGBA
bool ellipseRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw ellipse with blending.
Definition SDL3_gfxPrimitives.c:1690
filledCircleColor
bool filledCircleColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
Draw filled circle with blending.
Definition SDL3_gfxPrimitives.c:1708
trigonRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2287
filledPieColor
bool filledPieColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
Draw filled pie with alpha blending.
Definition SDL3_gfxPrimitives.c:2209
pieColor
bool pieColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
Draw pie (outline) with alpha blending.
Definition SDL3_gfxPrimitives.c:2167
arcRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:1175
roundedRectangleColor
bool roundedRectangleColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
Draw rounded-corner rectangle with blending.
Definition SDL3_gfxPrimitives.c:345
circleRGBA
bool circleRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw circle with blending.
Definition SDL3_gfxPrimitives.c:1132
roundedBoxColor
bool roundedBoxColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
Draw rounded-corner box (filled rectangle) with blending.
Definition SDL3_gfxPrimitives.c:490
filledPolygonRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2895
roundedBoxRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:512
_aalineRGBA
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.
Definition SDL3_gfxPrimitives.c:859
texturedPolygonMT
bool 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).
Definition SDL3_gfxPrimitives.c:3016
rectangleRGBA
bool rectangleRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw rectangle with blending.
Definition SDL3_gfxPrimitives.c:273
pieRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:2190
filledEllipseColor
bool filledEllipseColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
Draw filled ellipse with blending.
Definition SDL3_gfxPrimitives.c:2004
DEFAULT_ELLIPSE_OVERSCAN
#define DEFAULT_ELLIPSE_OVERSCAN
Internal function to draw ellipse or filled ellipse with blending.
Definition SDL3_gfxPrimitives.c:1506
_pieRGBA
bool _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.
Definition SDL3_gfxPrimitives.c:2052
vlineRGBA
bool vlineRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw vertical line with blending.
Definition SDL3_gfxPrimitives.c:229
_ellipseRGBA
bool _ellipseRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Sint32 f)
Definition SDL3_gfxPrimitives.c:1507
hlineColor
bool hlineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
Draw horizontal line with blending.
Definition SDL3_gfxPrimitives.c:152
hlineRGBA
bool hlineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw horizontal line with blending.
Definition SDL3_gfxPrimitives.c:172
pixelRGBA
bool pixelRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
Draw pixel with blending enabled if a<255.
Definition SDL3_gfxPrimitives.c:84
trigonColor
bool 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.
Definition SDL3_gfxPrimitives.c:2255
boxRGBA
bool 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.
Definition SDL3_gfxPrimitives.c:708
hline
bool hline(SDL_Renderer *renderer, Sint16 x1, Sint16 x2, Sint16 y)
Draw horizontal line in currently set color.
Definition SDL3_gfxPrimitives.c:135
_gfxPrimitivesCompareInt
int _gfxPrimitivesCompareInt(const void *a, const void *b)
Internal helper qsort callback functions used in filled polygon drawing.
Definition SDL3_gfxPrimitives.c:2671
thickLineColor
bool thickLineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
Draw a thick line with alpha blending.
Definition SDL3_gfxPrimitives.c:3710
gfxPrimitivesSetFontRotation
void gfxPrimitivesSetFontRotation(Uint32 rotation)
Sets current global font character rotation steps.
Definition SDL3_gfxPrimitives.c:3301
aalineColor
bool aalineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
Draw anti-aliased line with alpha blending.
Definition SDL3_gfxPrimitives.c:1073
stringColor
bool stringColor(SDL_Renderer *renderer, Sint16 x, Sint16 y, const char *s, Uint32 color)
Draw a string in the currently set font.
Definition SDL3_gfxPrimitives.c:3489
gfxPrimitivesSetFont
void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch)
Sets or resets the current global font data.
Definition SDL3_gfxPrimitives.c:3255
SDL3_gfxPrimitives.h
M_PI
#define M_PI
Definition SDL3_gfxPrimitives.h:35
SDL3_gfxPrimitives_font.h
rotateSurface90Degrees
SDL_Surface * rotateSurface90Degrees(SDL_Surface *src, int numClockwiseTurns)
Rotates a 8/16/24/32 bit surface in increments of 90 degrees.
Definition SDL3_rotozoom.c:784
SDL3_rotozoom.h