SDL2_gfx  1.0.0
GraphicsprimitivesandsurfacefunctionsforSDL2
I:/Sources/sdl2gfx/SDL2_gfxPrimitives.c
Go to the documentation of this file.
00001 /* 
00002 
00003 SDL2_gfxPrimitives.c: graphics primitives for SDL2 renderers
00004 
00005 Copyright (C) 2012  Andreas Schiffler
00006 
00007 This software is provided 'as-is', without any express or implied
00008 warranty. In no event will the authors be held liable for any damages
00009 arising from the use of this software.
00010 
00011 Permission is granted to anyone to use this software for any purpose,
00012 including commercial applications, and to alter it and redistribute it
00013 freely, subject to the following restrictions:
00014 
00015 1. The origin of this software must not be misrepresented; you must not
00016 claim that you wrote the original software. If you use this software
00017 in a product, an acknowledgment in the product documentation would be
00018 appreciated but is not required.
00019 
00020 2. Altered source versions must be plainly marked as such, and must not be
00021 misrepresented as being the original software.
00022 
00023 3. This notice may not be removed or altered from any source
00024 distribution.
00025 
00026 Andreas Schiffler -- aschiffler at ferzkopp dot net
00027 
00028 */
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <math.h>
00033 #include <string.h>
00034 
00035 #include "SDL2_gfxPrimitives.h"
00036 #include "SDL2_rotozoom.h"
00037 #include "SDL2_gfxPrimitives_font.h"
00038 
00039 /* ---- Structures */
00040 
00044 typedef struct {
00045         Sint16 x, y;
00046         int dx, dy, s1, s2, swapdir, error;
00047         Uint32 count;
00048 } SDL2_gfxBresenhamIterator;
00049 
00053 typedef struct {
00054         SDL_Renderer *renderer;
00055         int u, v;               /* delta x , delta y */
00056         int ku, kt, kv, kd;     /* loop constants */
00057         int oct2;
00058         int quad4;
00059         Sint16 last1x, last1y, last2x, last2y, first1x, first1y, first2x, first2y, tempx, tempy;
00060 } SDL2_gfxMurphyIterator;
00061 
00062 /* ---- Pixel */
00063 
00073 int pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
00074 {
00075         return SDL_RenderDrawPoint(renderer, x, y);
00076 }
00077 
00088 int pixelColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint32 color)
00089 {
00090         Uint8 *c = (Uint8 *)&color; 
00091         return pixelRGBA(renderer, x, y, c[0], c[1], c[2], c[3]);
00092 }
00093 
00107 int pixelRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00108 {
00109         int result = 0;
00110         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00111         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
00112         result |= SDL_RenderDrawPoint(renderer, x, y);
00113         return result;
00114 }
00115 
00130 int pixelRGBAWeight(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Uint32 weight)
00131 {
00132         /*
00133         * Modify Alpha by weight 
00134         */
00135         Uint32 ax = a;
00136         ax = ((ax * weight) >> 8);
00137         if (ax > 255) {
00138                 a = 255;
00139         } else {
00140                 a = (Uint8)(ax & 0x000000ff);
00141         }
00142 
00143         return pixelRGBA(renderer, x, y, r, g, b, a);
00144 }
00145 
00146 /* ---- Hline */
00147 
00158 int hline(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y)
00159 {
00160         return SDL_RenderDrawLine(renderer, x1, y, x2, y);;
00161 }
00162 
00163 
00175 int hlineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
00176 {
00177         Uint8 *c = (Uint8 *)&color; 
00178         return hlineRGBA(renderer, x1, x2, y, c[0], c[1], c[2], c[3]);
00179 }
00180 
00195 int hlineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00196 {
00197         int result = 0;
00198         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00199         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
00200         result |= SDL_RenderDrawLine(renderer, x1, y, x2, y);
00201         return result;
00202 }
00203 
00204 /* ---- Vline */
00205 
00217 int vlineColor(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
00218 {
00219         Uint8 *c = (Uint8 *)&color; 
00220         return vlineRGBA(renderer, x, y1, y2, c[0], c[1], c[2], c[3]);
00221 }
00222 
00237 int vlineRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00238 {
00239         int result = 0;
00240         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00241         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
00242         result |= SDL_RenderDrawLine(renderer, x, y1, x, y2);
00243         return result;
00244 }
00245 
00246 /* ---- Rectangle */
00247 
00260 int rectangleColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
00261 {
00262         Uint8 *c = (Uint8 *)&color; 
00263         return rectangleRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
00264 }
00265 
00281 int rectangleRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00282 {
00283         int result;
00284         Sint16 tmp;
00285         SDL_Rect rect;
00286 
00287         /*
00288         * Test for special cases of straight lines or single point 
00289         */
00290         if (x1 == x2) {
00291                 if (y1 == y2) {
00292                         return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00293                 } else {
00294                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00295                 }
00296         } else {
00297                 if (y1 == y2) {
00298                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00299                 }
00300         }
00301 
00302         /*
00303         * Swap x1, x2 if required 
00304         */
00305         if (x1 > x2) {
00306                 tmp = x1;
00307                 x1 = x2;
00308                 x2 = tmp;
00309         }
00310 
00311         /*
00312         * Swap y1, y2 if required 
00313         */
00314         if (y1 > y2) {
00315                 tmp = y1;
00316                 y1 = y2;
00317                 y2 = tmp;
00318         }
00319 
00320         /* 
00321         * Create destination rect
00322         */      
00323         rect.x = x1;
00324         rect.y = y1;
00325         rect.w = x2 - x1;
00326         rect.h = y2 - y1;
00327         
00328         /*
00329         * Draw
00330         */
00331         result = 0;
00332         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00333         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
00334         result |= SDL_RenderDrawRect(renderer, &rect);
00335         return result;
00336 }
00337 
00338 /* ---- Rounded Rectangle */
00339 
00353 int roundedRectangleColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
00354 {
00355         Uint8 *c = (Uint8 *)&color; 
00356         return roundedRectangleRGBA(renderer, x1, y1, x2, y2, rad, c[0], c[1], c[2], c[3]);
00357 }
00358 
00375 int roundedRectangleRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00376 {
00377         int result = 0;
00378         Sint16 tmp;
00379         Sint16 w, h;
00380         Sint16 xx1, xx2;
00381         Sint16 yy1, yy2;
00382         
00383         /*
00384         * Check renderer
00385         */
00386         if (renderer == NULL)
00387         {
00388                 return -1;
00389         }
00390 
00391         /*
00392         * Check radius vor valid range
00393         */
00394         if (rad < 0) {
00395                 return -1;
00396         }
00397 
00398         /*
00399         * Special case - no rounding
00400         */
00401         if (rad == 0) {
00402                 return rectangleRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
00403         }
00404 
00405         /*
00406         * Test for special cases of straight lines or single point 
00407         */
00408         if (x1 == x2) {
00409                 if (y1 == y2) {
00410                         return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00411                 } else {
00412                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00413                 }
00414         } else {
00415                 if (y1 == y2) {
00416                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00417                 }
00418         }
00419 
00420         /*
00421         * Swap x1, x2 if required 
00422         */
00423         if (x1 > x2) {
00424                 tmp = x1;
00425                 x1 = x2;
00426                 x2 = tmp;
00427         }
00428 
00429         /*
00430         * Swap y1, y2 if required 
00431         */
00432         if (y1 > y2) {
00433                 tmp = y1;
00434                 y1 = y2;
00435                 y2 = tmp;
00436         }
00437 
00438         /*
00439         * Calculate width&height 
00440         */
00441         w = x2 - x1;
00442         h = y2 - y1;
00443 
00444         /*
00445         * Maybe adjust radius
00446         */
00447         if ((rad * 2) > w)  
00448         {
00449                 rad = w / 2;
00450         }
00451         if ((rad * 2) > h)
00452         {
00453                 rad = h / 2;
00454         }
00455 
00456         /*
00457         * Draw corners
00458         */
00459         xx1 = x1 + rad;
00460         xx2 = x2 - rad;
00461         yy1 = y1 + rad;
00462         yy2 = y2 - rad;
00463         result |= arcRGBA(renderer, xx1, yy1, rad, 180, 270, r, g, b, a);
00464         result |= arcRGBA(renderer, xx2, yy1, rad, 270, 360, r, g, b, a);
00465         result |= arcRGBA(renderer, xx1, yy2, rad,  90, 180, r, g, b, a);
00466         result |= arcRGBA(renderer, xx2, yy2, rad,   0,  90, r, g, b, a);
00467 
00468         /*
00469         * Draw lines
00470         */
00471         if (xx1 <= xx2) {
00472                 result |= hlineRGBA(renderer, xx1, xx2, y1, r, g, b, a);
00473                 result |= hlineRGBA(renderer, xx1, xx2, y2, r, g, b, a);
00474         }
00475         if (yy1 <= yy2) {
00476                 result |= vlineRGBA(renderer, x1, yy1, yy2, r, g, b, a);
00477                 result |= vlineRGBA(renderer, x2, yy1, yy2, r, g, b, a);
00478         }
00479 
00480         return result;
00481 }
00482 
00483 /* ---- Rounded Box */
00484 
00498 int roundedBoxColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
00499 {
00500         Uint8 *c = (Uint8 *)&color; 
00501         return roundedBoxRGBA(renderer, x1, y1, x2, y2, rad, c[0], c[1], c[2], c[3]);
00502 }
00503 
00520 int roundedBoxRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2,
00521         Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00522 {
00523         int result = 0;
00524         Sint16 w, h, tmp;
00525         Sint16 xx1, xx2, yy1, yy2;
00526 
00527         /* 
00528         * Check destination renderer 
00529         */
00530         if (renderer == NULL)
00531         {
00532                 return -1;
00533         }
00534 
00535         /*
00536         * Check radius vor valid range
00537         */
00538         if (rad < 0) {
00539                 return -1;
00540         }
00541 
00542         /*
00543         * Special case - no rounding
00544         */
00545         if (rad == 0) {
00546                 return rectangleRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
00547         }
00548 
00549         /*
00550         * Test for special cases of straight lines or single point 
00551         */
00552         if (x1 == x2) {
00553                 if (y1 == y2) {
00554                         return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00555                 } else {
00556                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00557                 }
00558         } else {
00559                 if (y1 == y2) {
00560                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00561                 }
00562         }
00563 
00564         /*
00565         * Swap x1, x2 if required 
00566         */
00567         if (x1 > x2) {
00568                 tmp = x1;
00569                 x1 = x2;
00570                 x2 = tmp;
00571         }
00572 
00573         /*
00574         * Swap y1, y2 if required 
00575         */
00576         if (y1 > y2) {
00577                 tmp = y1;
00578                 y1 = y2;
00579                 y2 = tmp;
00580         }
00581 
00582         /*
00583         * Calculate width&height 
00584         */
00585         w = x2 - x1;
00586         h = y2 - y1;
00587 
00588         /*
00589         * Maybe adjust radius
00590         */
00591         if ((rad * 2) > w)  
00592         {
00593                 rad = w / 2;
00594         }
00595         if ((rad * 2) > h)
00596         {
00597                 rad = h / 2;
00598         }
00599 
00600         /*
00601         * Draw corners
00602         */
00603         xx1 = x1 + rad;
00604         xx2 = x2 - rad;
00605         yy1 = y1 + rad;
00606         yy2 = y2 - rad;
00607         result |= filledPieRGBA(renderer, xx1, yy1, rad, 180, 270, r, g, b, a);
00608         result |= filledPieRGBA(renderer, xx2, yy1, rad, 270, 360, r, g, b, a);
00609         result |= filledPieRGBA(renderer, xx1, yy2, rad,  90, 180, r, g, b, a);
00610         result |= filledPieRGBA(renderer, xx2, yy2, rad,   0,  90, r, g, b, a);
00611 
00612         /*
00613         * Draw body
00614         */
00615         xx1++;
00616         xx2--;
00617         yy1++;
00618         yy2--;
00619         if (xx1 <= xx2) {
00620                 result |= boxRGBA(renderer, xx1, y1, xx2, y2, r, g, b, a);
00621         }
00622         if (yy1 <= yy2) {
00623                 result |= boxRGBA(renderer, x1, yy1, xx1-1, yy2, r, g, b, a);
00624                 result |= boxRGBA(renderer, xx2+1, yy1, x2, yy2, r, g, b, a);
00625         }
00626 
00627         return result;
00628 }
00629 
00630 /* ---- Box */
00631 
00644 int boxColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
00645 {
00646         Uint8 *c = (Uint8 *)&color; 
00647         return boxRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
00648 }
00649 
00665 int boxRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00666 {
00667         int result;
00668         Sint16 tmp;
00669         SDL_Rect rect;
00670 
00671         /*
00672         * Test for special cases of straight lines or single point 
00673         */
00674         if (x1 == x2) {
00675                 if (y1 == y2) {
00676                         return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00677                 } else {
00678                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00679                 }
00680         } else {
00681                 if (y1 == y2) {
00682                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00683                 }
00684         }
00685 
00686         /*
00687         * Swap x1, x2 if required 
00688         */
00689         if (x1 > x2) {
00690                 tmp = x1;
00691                 x1 = x2;
00692                 x2 = tmp;
00693         }
00694 
00695         /*
00696         * Swap y1, y2 if required 
00697         */
00698         if (y1 > y2) {
00699                 tmp = y1;
00700                 y1 = y2;
00701                 y2 = tmp;
00702         }
00703 
00704         /* 
00705         * Create destination rect
00706         */      
00707         rect.x = x1;
00708         rect.y = y1;
00709         rect.w = x2 - x1;
00710         rect.h = y2 - y1;
00711         
00712         /*
00713         * Draw
00714         */
00715         result = 0;
00716         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00717         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
00718         result |= SDL_RenderFillRect(renderer, &rect);
00719         return result;
00720 }
00721 
00722 /* ----- Line */
00723 
00735 int line(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
00736 {
00737         /*
00738         * Draw
00739         */
00740         return SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
00741 }
00742 
00755 int lineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
00756 {
00757         Uint8 *c = (Uint8 *)&color; 
00758         return lineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
00759 }
00760 
00776 int lineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00777 {
00778         /*
00779         * Draw
00780         */
00781         int result = 0;
00782         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00783         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
00784         result |= SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
00785         return result;
00786 }
00787 
00788 /* ---- AA Line */
00789 
00790 #define AAlevels 256
00791 #define AAbits 8
00792 
00816 int _aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int draw_endpoint)
00817 {
00818         Sint32 xx0, yy0, xx1, yy1;
00819         int result;
00820         Uint32 intshift, erracc, erradj;
00821         Uint32 erracctmp, wgt, wgtcompmask;
00822         int dx, dy, tmp, xdir, y0p1, x0pxdir;
00823 
00824         /*
00825         * Keep on working with 32bit numbers 
00826         */
00827         xx0 = x1;
00828         yy0 = y1;
00829         xx1 = x2;
00830         yy1 = y2;
00831 
00832         /*
00833         * Reorder points to make dy positive 
00834         */
00835         if (yy0 > yy1) {
00836                 tmp = yy0;
00837                 yy0 = yy1;
00838                 yy1 = tmp;
00839                 tmp = xx0;
00840                 xx0 = xx1;
00841                 xx1 = tmp;
00842         }
00843 
00844         /*
00845         * Calculate distance 
00846         */
00847         dx = xx1 - xx0;
00848         dy = yy1 - yy0;
00849 
00850         /*
00851         * Adjust for negative dx and set xdir 
00852         */
00853         if (dx >= 0) {
00854                 xdir = 1;
00855         } else {
00856                 xdir = -1;
00857                 dx = (-dx);
00858         }
00859         
00860         /*
00861         * Check for special cases 
00862         */
00863         if (dx == 0) {
00864                 /*
00865                 * Vertical line 
00866                 */
00867                 if (draw_endpoint)
00868                 {
00869                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00870                 } else {
00871                         if (dy > 0) {
00872                                 return (vlineRGBA(renderer, x1, yy0, yy0+dy, r, g, b, a));
00873                         } else {
00874                                 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00875                         }
00876                 }
00877         } else if (dy == 0) {
00878                 /*
00879                 * Horizontal line 
00880                 */
00881                 if (draw_endpoint)
00882                 {
00883                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00884                 } else {
00885                         if (dx > 0) {
00886                                 return (hlineRGBA(renderer, xx0, xx0+dx, y1, r, g, b, a));
00887                         } else {
00888                                 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00889                         }
00890                 }
00891         } else if ((dx == dy) && (draw_endpoint)) {
00892                 /*
00893                 * Diagonal line (with endpoint)
00894                 */
00895                 return (lineRGBA(renderer, x1, y1, x2, y2,  r, g, b, a));
00896         }
00897 
00898 
00899         /*
00900         * Line is not horizontal, vertical or diagonal (with endpoint)
00901         */
00902         result = 0;
00903 
00904         /*
00905         * Zero accumulator 
00906         */
00907         erracc = 0;
00908 
00909         /*
00910         * # of bits by which to shift erracc to get intensity level 
00911         */
00912         intshift = 32 - AAbits;
00913 
00914         /*
00915         * Mask used to flip all bits in an intensity weighting 
00916         */
00917         wgtcompmask = AAlevels - 1;
00918 
00919         /*
00920         * Draw the initial pixel in the foreground color 
00921         */
00922         result |= pixelRGBA(renderer, x1, y1, r, g, b, a);
00923 
00924         /*
00925         * x-major or y-major? 
00926         */
00927         if (dy > dx) {
00928 
00929                 /*
00930                 * y-major.  Calculate 16-bit fixed point fractional part of a pixel that
00931                 * X advances every time Y advances 1 pixel, truncating the result so that
00932                 * we won't overrun the endpoint along the X axis 
00933                 */
00934                 /*
00935                 * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy; 
00936                 */
00937                 erradj = ((dx << 16) / dy) << 16;
00938 
00939                 /*
00940                 * draw all pixels other than the first and last 
00941                 */
00942                 x0pxdir = xx0 + xdir;
00943                 while (--dy) {
00944                         erracctmp = erracc;
00945                         erracc += erradj;
00946                         if (erracc <= erracctmp) {
00947                                 /*
00948                                 * rollover in error accumulator, x coord advances 
00949                                 */
00950                                 xx0 = x0pxdir;
00951                                 x0pxdir += xdir;
00952                         }
00953                         yy0++;          /* y-major so always advance Y */
00954 
00955                         /*
00956                         * the AAbits most significant bits of erracc give us the intensity
00957                         * weighting for this pixel, and the complement of the weighting for
00958                         * the paired pixel. 
00959                         */
00960                         wgt = (erracc >> intshift) & 255;
00961                         result |= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
00962                         result |= pixelRGBAWeight (renderer, x0pxdir, yy0, r, g, b, a, wgt);
00963                 }
00964 
00965         } else {
00966 
00967                 /*
00968                 * x-major line.  Calculate 16-bit fixed-point fractional part of a pixel
00969                 * that Y advances each time X advances 1 pixel, truncating the result so
00970                 * that we won't overrun the endpoint along the X axis. 
00971                 */
00972                 /*
00973                 * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx; 
00974                 */
00975                 erradj = ((dy << 16) / dx) << 16;
00976 
00977                 /*
00978                 * draw all pixels other than the first and last 
00979                 */
00980                 y0p1 = yy0 + 1;
00981                 while (--dx) {
00982 
00983                         erracctmp = erracc;
00984                         erracc += erradj;
00985                         if (erracc <= erracctmp) {
00986                                 /*
00987                                 * Accumulator turned over, advance y 
00988                                 */
00989                                 yy0 = y0p1;
00990                                 y0p1++;
00991                         }
00992                         xx0 += xdir;    /* x-major so always advance X */
00993                         /*
00994                         * the AAbits most significant bits of erracc give us the intensity
00995                         * weighting for this pixel, and the complement of the weighting for
00996                         * the paired pixel. 
00997                         */
00998                         wgt = (erracc >> intshift) & 255;
00999                         result |= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
01000                         result |= pixelRGBAWeight (renderer, xx0, y0p1, r, g, b, a, wgt);
01001                 }
01002         }
01003 
01004         /*
01005         * Do we have to draw the endpoint 
01006         */
01007         if (draw_endpoint) {
01008                 /*
01009                 * Draw final pixel, always exactly intersected by the line and doesn't
01010                 * need to be weighted. 
01011                 */
01012                 result |= pixelRGBA (renderer, x2, y2, r, g, b, a);
01013         }
01014 
01015         return (result);
01016 }
01017 
01030 int aalineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
01031 {
01032         Uint8 *c = (Uint8 *)&color; 
01033         return _aalineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3], 1);
01034 }
01035 
01051 int aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01052 {
01053         return _aalineRGBA(renderer, x1, y1, x2, y2, r, g, b, a, 1);
01054 }
01055 
01056 /* ----- Circle */
01057 
01069 int circleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
01070 {
01071         Uint8 *c = (Uint8 *)&color; 
01072         return ellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
01073 }
01074 
01089 int circleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01090 {
01091         return ellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
01092 }
01093 
01094 /* ----- Arc */
01095 
01109 int arcColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
01110 {
01111         Uint8 *c = (Uint8 *)&color; 
01112         return arcRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3]);
01113 }
01114 
01131 int arcRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01132 {
01133         int result;
01134         Sint16 cx = 0;
01135         Sint16 cy = rad;
01136         Sint16 df = 1 - rad;
01137         Sint16 d_e = 3;
01138         Sint16 d_se = -2 * rad + 5;
01139         Sint16 xpcx, xmcx, xpcy, xmcy;
01140         Sint16 ypcy, ymcy, ypcx, ymcx;
01141         Uint8 drawoct;
01142         int startoct, endoct, oct, stopval_start = 0, stopval_end = 0;
01143         double dstart, dend, temp = 0.;
01144 
01145         /*
01146         * Sanity check radius 
01147         */
01148         if (rad < 0) {
01149                 return (-1);
01150         }
01151 
01152         /*
01153         * Special case for rad=0 - draw a point 
01154         */
01155         if (rad == 0) {
01156                 return (pixelRGBA(renderer, x, y, r, g, b, a));
01157         }
01158 
01159         // Octant labelling
01160         //      
01161         //  \ 5 | 6 /
01162         //   \  |  /
01163         //  4 \ | / 7
01164         //     \|/
01165         //------+------ +x
01166         //     /|\
01167         //  3 / | \ 0
01168         //   /  |  \
01169         //  / 2 | 1 \
01170         //      +y
01171 
01172         // Initially reset bitmask to 0x00000000
01173         // the set whether or not to keep drawing a given octant.
01174         // For example: 0x00111100 means we're drawing in octants 2-5
01175         drawoct = 0; 
01176 
01177         /*
01178         * Fixup angles
01179         */
01180         start %= 360;
01181         end %= 360;
01182         // 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
01183         while (start < 0) start += 360;
01184         while (end < 0) end += 360;
01185         start %= 360;
01186         end %= 360;
01187 
01188         // now, we find which octants we're drawing in.
01189         startoct = start / 45;
01190         endoct = end / 45;
01191         oct = startoct - 1; // we increment as first step in loop
01192 
01193         // stopval_start, stopval_end; 
01194         // what values of cx to stop at.
01195         do {
01196                 oct = (oct + 1) % 8;
01197 
01198                 if (oct == startoct) {
01199                         // need to compute stopval_start for this octant.  Look at picture above if this is unclear
01200                         dstart = (double)start;
01201                         switch (oct) 
01202                         {
01203                         case 0:
01204                         case 3:
01205                                 temp = sin(dstart * M_PI / 180.);
01206                                 break;
01207                         case 1:
01208                         case 6:
01209                                 temp = cos(dstart * M_PI / 180.);
01210                                 break;
01211                         case 2:
01212                         case 5:
01213                                 temp = -cos(dstart * M_PI / 180.);
01214                                 break;
01215                         case 4:
01216                         case 7:
01217                                 temp = -sin(dstart * M_PI / 180.);
01218                                 break;
01219                         }
01220                         temp *= rad;
01221                         stopval_start = (int)temp; // always round down.
01222 
01223                         // This isn't arbitrary, but requires graph paper to explain well.
01224                         // The basic idea is that we're always changing drawoct after we draw, so we
01225                         // stop immediately after we render the last sensible pixel at x = ((int)temp).
01226 
01227                         // and whether to draw in this octant initially
01228                         if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
01229                         else             drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
01230                 }
01231                 if (oct == endoct) {
01232                         // need to compute stopval_end for this octant
01233                         dend = (double)end;
01234                         switch (oct)
01235                         {
01236                         case 0:
01237                         case 3:
01238                                 temp = sin(dend * M_PI / 180);
01239                                 break;
01240                         case 1:
01241                         case 6:
01242                                 temp = cos(dend * M_PI / 180);
01243                                 break;
01244                         case 2:
01245                         case 5:
01246                                 temp = -cos(dend * M_PI / 180);
01247                                 break;
01248                         case 4:
01249                         case 7:
01250                                 temp = -sin(dend * M_PI / 180);
01251                                 break;
01252                         }
01253                         temp *= rad;
01254                         stopval_end = (int)temp;
01255 
01256                         // and whether to draw in this octant initially
01257                         if (startoct == endoct) {
01258                                 // note:      we start drawing, stop, then start again in this case
01259                                 // otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
01260                                 if (start > end) {
01261                                         // unfortunately, if we're in the same octant and need to draw over the whole circle, 
01262                                         // we need to set the rest to true, because the while loop will end at the bottom.
01263                                         drawoct = 255;
01264                                 } else {
01265                                         drawoct &= 255 - (1 << oct);
01266                                 }
01267                         } 
01268                         else if (oct % 2) drawoct &= 255 - (1 << oct);
01269                         else                      drawoct |= (1 << oct);
01270                 } else if (oct != startoct) { // already verified that it's != endoct
01271                         drawoct |= (1 << oct); // draw this entire segment
01272                 }
01273         } while (oct != endoct);
01274 
01275         // so now we have what octants to draw and when to draw them. all that's left is the actual raster code.
01276 
01277         /*
01278         * Set color 
01279         */
01280         result = 0;
01281         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01282         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
01283 
01284         /*
01285         * Draw arc 
01286         */
01287         do {
01288                 ypcy = y + cy;
01289                 ymcy = y - cy;
01290                 if (cx > 0) {
01291                         xpcx = x + cx;
01292                         xmcx = x - cx;
01293 
01294                         // always check if we're drawing a certain octant before adding a pixel to that octant.
01295                         if (drawoct & 4)  result |= pixel(renderer, xmcx, ypcy);
01296                         if (drawoct & 2)  result |= pixel(renderer, xpcx, ypcy);
01297                         if (drawoct & 32) result |= pixel(renderer, xmcx, ymcy);
01298                         if (drawoct & 64) result |= pixel(renderer, xpcx, ymcy);
01299                 } else {
01300                         if (drawoct & 96) result |= pixel(renderer, x, ymcy);
01301                         if (drawoct & 6)  result |= pixel(renderer, x, ypcy);
01302                 }
01303 
01304                 xpcy = x + cy;
01305                 xmcy = x - cy;
01306                 if (cx > 0 && cx != cy) {
01307                         ypcx = y + cx;
01308                         ymcx = y - cx;
01309                         if (drawoct & 8)   result |= pixel(renderer, xmcy, ypcx);
01310                         if (drawoct & 1)   result |= pixel(renderer, xpcy, ypcx);
01311                         if (drawoct & 16)  result |= pixel(renderer, xmcy, ymcx);
01312                         if (drawoct & 128) result |= pixel(renderer, xpcy, ymcx);
01313                 } else if (cx == 0) {
01314                         if (drawoct & 24)  result |= pixel(renderer, xmcy, y);
01315                         if (drawoct & 129) result |= pixel(renderer, xpcy, y);
01316                 }
01317 
01318                 /*
01319                 * Update whether we're drawing an octant
01320                 */
01321                 if (stopval_start == cx) {
01322                         // works like an on-off switch.  
01323                         // This is just in case start & end are in the same octant.
01324                         if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);                
01325                         else                                               drawoct |= (1 << startoct);
01326                 }
01327                 if (stopval_end == cx) {
01328                         if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
01329                         else                                             drawoct |= (1 << endoct);
01330                 }
01331 
01332                 /*
01333                 * Update pixels
01334                 */
01335                 if (df < 0) {
01336                         df += d_e;
01337                         d_e += 2;
01338                         d_se += 2;
01339                 } else {
01340                         df += d_se;
01341                         d_e += 2;
01342                         d_se += 4;
01343                         cy--;
01344                 }
01345                 cx++;
01346         } while (cx <= cy);
01347 
01348         return (result);
01349 }
01350 
01351 /* ----- AA Circle */
01352 
01364 int aacircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
01365 {
01366         Uint8 *c = (Uint8 *)&color; 
01367         return aaellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
01368 }
01369 
01384 int aacircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01385 {
01386         /*
01387         * Draw 
01388         */
01389         return aaellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
01390 }
01391 
01392 /* ----- Filled Circle */
01393 
01405 int filledCircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
01406 {
01407         Uint8 *c = (Uint8 *)&color; 
01408         return filledEllipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
01409 }
01410 
01425 int filledCircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01426 {
01427         int result;
01428         Sint16 cx = 0;
01429         Sint16 cy = rad;
01430         Sint16 ocx = (Sint16) 0xffff;
01431         Sint16 ocy = (Sint16) 0xffff;
01432         Sint16 df = 1 - rad;
01433         Sint16 d_e = 3;
01434         Sint16 d_se = -2 * rad + 5;
01435         Sint16 xpcx, xmcx, xpcy, xmcy;
01436         Sint16 ypcy, ymcy, ypcx, ymcx;
01437 
01438         /*
01439         * Sanity check radius 
01440         */
01441         if (rad < 0) {
01442                 return (-1);
01443         }
01444 
01445         /*
01446         * Special case for rad=0 - draw a point 
01447         */
01448         if (rad == 0) {
01449                 return (pixelRGBA(renderer, x, y, r, g, b, a));
01450         }
01451 
01452         /*
01453         * Set color
01454         */
01455         result = 0;
01456         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01457         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
01458 
01459         /*
01460         * Draw 
01461         */
01462         do {
01463                 xpcx = x + cx;
01464                 xmcx = x - cx;
01465                 xpcy = x + cy;
01466                 xmcy = x - cy;
01467                 if (ocy != cy) {
01468                         if (cy > 0) {
01469                                 ypcy = y + cy;
01470                                 ymcy = y - cy;
01471                                 result |= hline(renderer, xmcx, xpcx, ypcy);
01472                                 result |= hline(renderer, xmcx, xpcx, ymcy);
01473                         } else {
01474                                 result |= hline(renderer, xmcx, xpcx, y);
01475                         }
01476                         ocy = cy;
01477                 }
01478                 if (ocx != cx) {
01479                         if (cx != cy) {
01480                                 if (cx > 0) {
01481                                         ypcx = y + cx;
01482                                         ymcx = y - cx;
01483                                         result |= hline(renderer, xmcy, xpcy, ymcx);
01484                                         result |= hline(renderer, xmcy, xpcy, ypcx);
01485                                 } else {
01486                                         result |= hline(renderer, xmcy, xpcy, y);
01487                                 }
01488                         }
01489                         ocx = cx;
01490                 }
01491 
01492                 /*
01493                 * Update 
01494                 */
01495                 if (df < 0) {
01496                         df += d_e;
01497                         d_e += 2;
01498                         d_se += 2;
01499                 } else {
01500                         df += d_se;
01501                         d_e += 2;
01502                         d_se += 4;
01503                         cy--;
01504                 }
01505                 cx++;
01506         } while (cx <= cy);
01507 
01508         return (result);
01509 }
01510 
01511 /* ----- Ellipse */
01512 
01525 int ellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
01526 {
01527         Uint8 *c = (Uint8 *)&color; 
01528         return ellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
01529 }
01530 
01546 int ellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01547 {
01548         int result;
01549         int ix, iy;
01550         int h, i, j, k;
01551         int oh, oi, oj, ok;
01552         int xmh, xph, ypk, ymk;
01553         int xmi, xpi, ymj, ypj;
01554         int xmj, xpj, ymi, ypi;
01555         int xmk, xpk, ymh, yph;
01556 
01557         /*
01558         * Sanity check radii 
01559         */
01560         if ((rx < 0) || (ry < 0)) {
01561                 return (-1);
01562         }
01563 
01564         /*
01565         * Special case for rx=0 - draw a vline 
01566         */
01567         if (rx == 0) {
01568                 return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
01569         }
01570         /*
01571         * Special case for ry=0 - draw a hline 
01572         */
01573         if (ry == 0) {
01574                 return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
01575         }
01576 
01577         /*
01578         * Set color
01579         */
01580         result = 0;
01581         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01582         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
01583 
01584         /*
01585         * Init vars 
01586         */
01587         oh = oi = oj = ok = 0xFFFF;
01588 
01589         /*
01590         * Draw 
01591         */
01592         if (rx > ry) {
01593                 ix = 0;
01594                 iy = rx * 64;
01595 
01596                 do {
01597                         h = (ix + 32) >> 6;
01598                         i = (iy + 32) >> 6;
01599                         j = (h * ry) / rx;
01600                         k = (i * ry) / rx;
01601 
01602                         if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
01603                                 xph = x + h;
01604                                 xmh = x - h;
01605                                 if (k > 0) {
01606                                         ypk = y + k;
01607                                         ymk = y - k;
01608                                         result |= pixel(renderer, xmh, ypk);
01609                                         result |= pixel(renderer, xph, ypk);
01610                                         result |= pixel(renderer, xmh, ymk);
01611                                         result |= pixel(renderer, xph, ymk);
01612                                 } else {
01613                                         result |= pixel(renderer, xmh, y);
01614                                         result |= pixel(renderer, xph, y);
01615                                 }
01616                                 ok = k;
01617                                 xpi = x + i;
01618                                 xmi = x - i;
01619                                 if (j > 0) {
01620                                         ypj = y + j;
01621                                         ymj = y - j;
01622                                         result |= pixel(renderer, xmi, ypj);
01623                                         result |= pixel(renderer, xpi, ypj);
01624                                         result |= pixel(renderer, xmi, ymj);
01625                                         result |= pixel(renderer, xpi, ymj);
01626                                 } else {
01627                                         result |= pixel(renderer, xmi, y);
01628                                         result |= pixel(renderer, xpi, y);
01629                                 }
01630                                 oj = j;
01631                         }
01632 
01633                         ix = ix + iy / rx;
01634                         iy = iy - ix / rx;
01635 
01636                 } while (i > h);
01637         } else {
01638                 ix = 0;
01639                 iy = ry * 64;
01640 
01641                 do {
01642                         h = (ix + 32) >> 6;
01643                         i = (iy + 32) >> 6;
01644                         j = (h * rx) / ry;
01645                         k = (i * rx) / ry;
01646 
01647                         if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
01648                                 xmj = x - j;
01649                                 xpj = x + j;
01650                                 if (i > 0) {
01651                                         ypi = y + i;
01652                                         ymi = y - i;
01653                                         result |= pixel(renderer, xmj, ypi);
01654                                         result |= pixel(renderer, xpj, ypi);
01655                                         result |= pixel(renderer, xmj, ymi);
01656                                         result |= pixel(renderer, xpj, ymi);
01657                                 } else {
01658                                         result |= pixel(renderer, xmj, y);
01659                                         result |= pixel(renderer, xpj, y);
01660                                 }
01661                                 oi = i;
01662                                 xmk = x - k;
01663                                 xpk = x + k;
01664                                 if (h > 0) {
01665                                         yph = y + h;
01666                                         ymh = y - h;
01667                                         result |= pixel(renderer, xmk, yph);
01668                                         result |= pixel(renderer, xpk, yph);
01669                                         result |= pixel(renderer, xmk, ymh);
01670                                         result |= pixel(renderer, xpk, ymh);
01671                                 } else {
01672                                         result |= pixel(renderer, xmk, y);
01673                                         result |= pixel(renderer, xpk, y);
01674                                 }
01675                                 oh = h;
01676                         }
01677 
01678                         ix = ix + iy / ry;
01679                         iy = iy - ix / ry;
01680 
01681                 } while (i > h);
01682         }
01683 
01684         return (result);
01685 }
01686 
01687 /* ----- AA Ellipse */
01688 
01689 /* Windows targets do not have lrint, so provide a local inline version */
01690 #if defined(_MSC_VER)
01691 /* Detect 64bit and use intrinsic version */
01692 #ifdef _M_X64
01693 #include <emmintrin.h>
01694 static __inline long 
01695         lrint(float f) 
01696 {
01697         return _mm_cvtss_si32(_mm_load_ss(&f));
01698 }
01699 #elif defined(_M_IX86)
01700 __inline long int
01701         lrint (double flt)
01702 {       
01703         int intgr;
01704         _asm
01705         {
01706                 fld flt
01707                         fistp intgr
01708         };
01709         return intgr;
01710 }
01711 #elif defined(_M_ARM)
01712 #include <armintr.h>
01713 #pragma warning(push)
01714 #pragma warning(disable: 4716)
01715 __declspec(naked) long int
01716         lrint (double flt)
01717 {
01718         __emit(0xEC410B10); // fmdrr  d0, r0, r1
01719         __emit(0xEEBD0B40); // ftosid s0, d0
01720         __emit(0xEE100A10); // fmrs   r0, s0
01721         __emit(0xE12FFF1E); // bx     lr
01722 }
01723 #pragma warning(pop)
01724 #else
01725 #error lrint needed for MSVC on non X86/AMD64/ARM targets.
01726 #endif
01727 #endif
01728 
01741 int aaellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
01742 {
01743         Uint8 *c = (Uint8 *)&color; 
01744         return aaellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
01745 }
01746 
01762 int aaellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01763 {
01764         int result;
01765         int i;
01766         int a2, b2, ds, dt, dxt, t, s, d;
01767         Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2;
01768         float cp;
01769         double sab;
01770         Uint8 weight, iweight;
01771 
01772         /*
01773         * Sanity check radii 
01774         */
01775         if ((rx < 0) || (ry < 0)) {
01776                 return (-1);
01777         }
01778 
01779         /*
01780         * Special case for rx=0 - draw a vline 
01781         */
01782         if (rx == 0) {
01783                 return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
01784         }
01785         /*
01786         * Special case for ry=0 - draw an hline 
01787         */
01788         if (ry == 0) {
01789                 return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
01790         }
01791 
01792         /* Variable setup */
01793         a2 = rx * rx;
01794         b2 = ry * ry;
01795 
01796         ds = 2 * a2;
01797         dt = 2 * b2;
01798 
01799         xc2 = 2 * x;
01800         yc2 = 2 * y;
01801 
01802         sab = sqrt((double)(a2 + b2));
01803         od = (Sint16)lrint(sab*0.01) + 1; /* introduce some overdraw */
01804         dxt = (Sint16)lrint((double)a2 / sab) + od;
01805 
01806         t = 0;
01807         s = -2 * a2 * ry;
01808         d = 0;
01809 
01810         xp = x;
01811         yp = y - ry;
01812 
01813         /* Draw */
01814         result = 0;
01815         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01816 
01817         /* "End points" */
01818         result |= pixelRGBA(renderer, xp, yp, r, g, b, a);
01819         result |= pixelRGBA(renderer, xc2 - xp, yp, r, g, b, a);
01820         result |= pixelRGBA(renderer, xp, yc2 - yp, r, g, b, a);
01821         result |= pixelRGBA(renderer, xc2 - xp, yc2 - yp, r, g, b, a);
01822 
01823         for (i = 1; i <= dxt; i++) {
01824                 xp--;
01825                 d += t - b2;
01826 
01827                 if (d >= 0)
01828                         ys = yp - 1;
01829                 else if ((d - s - a2) > 0) {
01830                         if ((2 * d - s - a2) >= 0)
01831                                 ys = yp + 1;
01832                         else {
01833                                 ys = yp;
01834                                 yp++;
01835                                 d -= s + a2;
01836                                 s += ds;
01837                         }
01838                 } else {
01839                         yp++;
01840                         ys = yp + 1;
01841                         d -= s + a2;
01842                         s += ds;
01843                 }
01844 
01845                 t -= dt;
01846 
01847                 /* Calculate alpha */
01848                 if (s != 0) {
01849                         cp = (float) abs(d) / (float) abs(s);
01850                         if (cp > 1.0) {
01851                                 cp = 1.0;
01852                         }
01853                 } else {
01854                         cp = 1.0;
01855                 }
01856 
01857                 /* Calculate weights */
01858                 weight = (Uint8) (cp * 255);
01859                 iweight = 255 - weight;
01860 
01861                 /* Upper half */
01862                 xx = xc2 - xp;
01863                 result |= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
01864                 result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
01865 
01866                 result |= pixelRGBAWeight(renderer, xp, ys, r, g, b, a, weight);
01867                 result |= pixelRGBAWeight(renderer, xx, ys, r, g, b, a, weight);
01868 
01869                 /* Lower half */
01870                 yy = yc2 - yp;
01871                 result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
01872                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
01873 
01874                 yy = yc2 - ys;
01875                 result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, weight);
01876                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);
01877         }
01878 
01879         /* Replaces original approximation code dyt = abs(yp - yc); */
01880         dyt = (Sint16)lrint((double)b2 / sab ) + od;    
01881 
01882         for (i = 1; i <= dyt; i++) {
01883                 yp++;
01884                 d -= s + a2;
01885 
01886                 if (d <= 0)
01887                         xs = xp + 1;
01888                 else if ((d + t - b2) < 0) {
01889                         if ((2 * d + t - b2) <= 0)
01890                                 xs = xp - 1;
01891                         else {
01892                                 xs = xp;
01893                                 xp--;
01894                                 d += t - b2;
01895                                 t -= dt;
01896                         }
01897                 } else {
01898                         xp--;
01899                         xs = xp - 1;
01900                         d += t - b2;
01901                         t -= dt;
01902                 }
01903 
01904                 s += ds;
01905 
01906                 /* Calculate alpha */
01907                 if (t != 0) {
01908                         cp = (float) abs(d) / (float) abs(t);
01909                         if (cp > 1.0) {
01910                                 cp = 1.0;
01911                         }
01912                 } else {
01913                         cp = 1.0;
01914                 }
01915 
01916                 /* Calculate weight */
01917                 weight = (Uint8) (cp * 255);
01918                 iweight = 255 - weight;
01919 
01920                 /* Left half */
01921                 xx = xc2 - xp;
01922                 yy = yc2 - yp;
01923                 result |= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
01924                 result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
01925 
01926                 result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
01927                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
01928 
01929                 /* Right half */
01930                 xx = xc2 - xs;
01931                 result |= pixelRGBAWeight(renderer, xs, yp, r, g, b, a, weight);
01932                 result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, weight);
01933 
01934                 result |= pixelRGBAWeight(renderer, xs, yy, r, g, b, a, weight);
01935                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);                
01936         }
01937 
01938         return (result);
01939 }
01940 
01941 /* ---- Filled Ellipse */
01942 
01955 int filledEllipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
01956 {
01957         Uint8 *c = (Uint8 *)&color; 
01958         return filledEllipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
01959 }
01960 
01976 int filledEllipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01977 {
01978         int result;
01979         int ix, iy;
01980         int h, i, j, k;
01981         int oh, oi, oj, ok;
01982         int xmh, xph;
01983         int xmi, xpi;
01984         int xmj, xpj;
01985         int xmk, xpk;
01986 
01987         /*
01988         * Sanity check radii 
01989         */
01990         if ((rx < 0) || (ry < 0)) {
01991                 return (-1);
01992         }
01993 
01994         /*
01995         * Special case for rx=0 - draw a vline 
01996         */
01997         if (rx == 0) {
01998                 return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
01999         }
02000         /*
02001         * Special case for ry=0 - draw a hline 
02002         */
02003         if (ry == 0) {
02004                 return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
02005         }
02006 
02007         /*
02008         * Set color
02009         */
02010         result = 0;
02011         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
02012         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
02013 
02014         /*
02015         * Init vars 
02016         */
02017         oh = oi = oj = ok = 0xFFFF;
02018 
02019         /*
02020         * Draw 
02021         */
02022         if (rx > ry) {
02023                 ix = 0;
02024                 iy = rx * 64;
02025 
02026                 do {
02027                         h = (ix + 32) >> 6;
02028                         i = (iy + 32) >> 6;
02029                         j = (h * ry) / rx;
02030                         k = (i * ry) / rx;
02031 
02032                         if ((ok != k) && (oj != k)) {
02033                                 xph = x + h;
02034                                 xmh = x - h;
02035                                 if (k > 0) {
02036                                         result |= hline(renderer, xmh, xph, y + k);
02037                                         result |= hline(renderer, xmh, xph, y - k);
02038                                 } else {
02039                                         result |= hline(renderer, xmh, xph, y);
02040                                 }
02041                                 ok = k;
02042                         }
02043                         if ((oj != j) && (ok != j) && (k != j)) {
02044                                 xmi = x - i;
02045                                 xpi = x + i;
02046                                 if (j > 0) {
02047                                         result |= hline(renderer, xmi, xpi, y + j);
02048                                         result |= hline(renderer, xmi, xpi, y - j);
02049                                 } else {
02050                                         result |= hline(renderer, xmi, xpi, y);
02051                                 }
02052                                 oj = j;
02053                         }
02054 
02055                         ix = ix + iy / rx;
02056                         iy = iy - ix / rx;
02057 
02058                 } while (i > h);
02059         } else {
02060                 ix = 0;
02061                 iy = ry * 64;
02062 
02063                 do {
02064                         h = (ix + 32) >> 6;
02065                         i = (iy + 32) >> 6;
02066                         j = (h * rx) / ry;
02067                         k = (i * rx) / ry;
02068 
02069                         if ((oi != i) && (oh != i)) {
02070                                 xmj = x - j;
02071                                 xpj = x + j;
02072                                 if (i > 0) {
02073                                         result |= hline(renderer, xmj, xpj, y + i);
02074                                         result |= hline(renderer, xmj, xpj, y - i);
02075                                 } else {
02076                                         result |= hline(renderer, xmj, xpj, y);
02077                                 }
02078                                 oi = i;
02079                         }
02080                         if ((oh != h) && (oi != h) && (i != h)) {
02081                                 xmk = x - k;
02082                                 xpk = x + k;
02083                                 if (h > 0) {
02084                                         result |= hline(renderer, xmk, xpk, y + h);
02085                                         result |= hline(renderer, xmk, xpk, y - h);
02086                                 } else {
02087                                         result |= hline(renderer, xmk, xpk, y);
02088                                 }
02089                                 oh = h;
02090                         }
02091 
02092                         ix = ix + iy / ry;
02093                         iy = iy - ix / ry;
02094 
02095                 } while (i > h);
02096         }
02097 
02098         return (result);
02099 }
02100 
02101 /* ----- Pie */
02102 
02122 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)
02123 {
02124         int result;
02125         double angle, start_angle, end_angle;
02126         double deltaAngle;
02127         double dr;
02128         int numpoints, i;
02129         Sint16 *vx, *vy;
02130 
02131         /*
02132         * Sanity check radii 
02133         */
02134         if (rad < 0) {
02135                 return (-1);
02136         }
02137 
02138         /*
02139         * Fixup angles
02140         */
02141         start = start % 360;
02142         end = end % 360;
02143 
02144         /*
02145         * Special case for rad=0 - draw a point 
02146         */
02147         if (rad == 0) {
02148                 return (pixelRGBA(renderer, x, y, r, g, b, a));
02149         }
02150 
02151         /*
02152         * Variable setup 
02153         */
02154         dr = (double) rad;
02155         deltaAngle = 3.0 / dr;
02156         start_angle = (double) start *(2.0 * M_PI / 360.0);
02157         end_angle = (double) end *(2.0 * M_PI / 360.0);
02158         if (start > end) {
02159                 end_angle += (2.0 * M_PI);
02160         }
02161 
02162         /* We will always have at least 2 points */
02163         numpoints = 2;
02164 
02165         /* Count points (rather than calculating it) */
02166         angle = start_angle;
02167         while (angle < end_angle) {
02168                 angle += deltaAngle;
02169                 numpoints++;
02170         }
02171 
02172         /* Allocate combined vertex array */
02173         vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
02174         if (vx == NULL) {
02175                 return (-1);
02176         }
02177 
02178         /* Update point to start of vy */
02179         vy += numpoints;
02180 
02181         /* Center */
02182         vx[0] = x;
02183         vy[0] = y;
02184 
02185         /* First vertex */
02186         angle = start_angle;
02187         vx[1] = x + (int) (dr * cos(angle));
02188         vy[1] = y + (int) (dr * sin(angle));
02189 
02190         if (numpoints<3)
02191         {
02192                 result = lineRGBA(renderer, vx[0], vy[0], vx[1], vy[1], r, g, b, a);
02193         }
02194         else
02195         {
02196                 /* Calculate other vertices */
02197                 i = 2;
02198                 angle = start_angle;
02199                 while (angle < end_angle) {
02200                         angle += deltaAngle;
02201                         if (angle>end_angle)
02202                         {
02203                                 angle = end_angle;
02204                         }
02205                         vx[i] = x + (int) (dr * cos(angle));
02206                         vy[i] = y + (int) (dr * sin(angle));
02207                         i++;
02208                 }
02209 
02210                 /* Draw */
02211                 if (filled) {
02212                         result = filledPolygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
02213                 } else {
02214                         result = polygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
02215                 }
02216         }
02217 
02218         /* Free combined vertex array */
02219         free(vx);
02220 
02221         return (result);
02222 }
02223 
02237 int pieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, 
02238         Sint16 start, Sint16 end, Uint32 color) 
02239 {
02240         Uint8 *c = (Uint8 *)&color; 
02241         return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 0);
02242 }
02243 
02260 int pieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
02261         Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02262 {
02263         return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 0);
02264 }
02265 
02279 int filledPieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
02280 {
02281         Uint8 *c = (Uint8 *)&color; 
02282         return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 1);
02283 }
02284 
02301 int filledPieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
02302         Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02303 {
02304         return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 1);
02305 }
02306 
02307 /* ------ Trigon */
02308 
02325 int trigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
02326 {
02327         Sint16 vx[3]; 
02328         Sint16 vy[3];
02329 
02330         vx[0]=x1;
02331         vx[1]=x2;
02332         vx[2]=x3;
02333         vy[0]=y1;
02334         vy[1]=y2;
02335         vy[2]=y3;
02336 
02337         return(polygonColor(renderer,vx,vy,3,color));
02338 }
02339 
02357 int trigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
02358         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02359 {
02360         Sint16 vx[3]; 
02361         Sint16 vy[3];
02362 
02363         vx[0]=x1;
02364         vx[1]=x2;
02365         vx[2]=x3;
02366         vy[0]=y1;
02367         vy[1]=y2;
02368         vy[2]=y3;
02369 
02370         return(polygonRGBA(renderer,vx,vy,3,r,g,b,a));
02371 }                                
02372 
02373 /* ------ AA-Trigon */
02374 
02391 int aatrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
02392 {
02393         Sint16 vx[3]; 
02394         Sint16 vy[3];
02395 
02396         vx[0]=x1;
02397         vx[1]=x2;
02398         vx[2]=x3;
02399         vy[0]=y1;
02400         vy[1]=y2;
02401         vy[2]=y3;
02402 
02403         return(aapolygonColor(renderer,vx,vy,3,color));
02404 }
02405 
02423 int aatrigonRGBA(SDL_Renderer * renderer,  Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
02424         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02425 {
02426         Sint16 vx[3]; 
02427         Sint16 vy[3];
02428 
02429         vx[0]=x1;
02430         vx[1]=x2;
02431         vx[2]=x3;
02432         vy[0]=y1;
02433         vy[1]=y2;
02434         vy[2]=y3;
02435 
02436         return(aapolygonRGBA(renderer,vx,vy,3,r,g,b,a));
02437 }                                  
02438 
02439 /* ------ Filled Trigon */
02440 
02457 int filledTrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
02458 {
02459         Sint16 vx[3]; 
02460         Sint16 vy[3];
02461 
02462         vx[0]=x1;
02463         vx[1]=x2;
02464         vx[2]=x3;
02465         vy[0]=y1;
02466         vy[1]=y2;
02467         vy[2]=y3;
02468 
02469         return(filledPolygonColor(renderer,vx,vy,3,color));
02470 }
02471 
02491 int filledTrigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
02492         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02493 {
02494         Sint16 vx[3]; 
02495         Sint16 vy[3];
02496 
02497         vx[0]=x1;
02498         vx[1]=x2;
02499         vx[2]=x3;
02500         vy[0]=y1;
02501         vy[1]=y2;
02502         vy[2]=y3;
02503 
02504         return(filledPolygonRGBA(renderer,vx,vy,3,r,g,b,a));
02505 }
02506 
02507 /* ---- Polygon */
02508 
02520 int polygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
02521 {
02522         Uint8 *c = (Uint8 *)&color; 
02523         return polygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
02524 }
02525 
02536 int polygon(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n)
02537 {
02538         /*
02539         * Draw 
02540         */
02541         int result;
02542         int i, nn;
02543         SDL_Point* points;
02544 
02545         /*
02546         * Vertex array NULL check 
02547         */
02548         if (vx == NULL) {
02549                 return (-1);
02550         }
02551         if (vy == NULL) {
02552                 return (-1);
02553         }
02554 
02555         /*
02556         * Sanity check 
02557         */
02558         if (n < 3) {
02559                 return (-1);
02560         }
02561 
02562         /*
02563         * Create array of points
02564         */
02565         nn = n + 1;
02566         points = (SDL_Point*)malloc(sizeof(SDL_Point) * nn);
02567         if (points == NULL)
02568         {
02569                 return -1;
02570         }
02571         for (i=0; i<n; i++)
02572         {
02573                 points[i].x = vx[i];
02574                 points[i].y = vy[i];
02575         }
02576         points[n].x = vx[0];
02577         points[n].y = vy[0];
02578 
02579         /*
02580         * Draw 
02581         */
02582         result |= SDL_RenderDrawLines(renderer, points, nn);
02583         free(points);
02584 
02585         return (result);
02586 }
02587 
02602 int polygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02603 {
02604         /*
02605         * Draw 
02606         */
02607         int result;
02608         const Sint16 *x1, *y1, *x2, *y2;
02609 
02610         /*
02611         * Vertex array NULL check 
02612         */
02613         if (vx == NULL) {
02614                 return (-1);
02615         }
02616         if (vy == NULL) {
02617                 return (-1);
02618         }
02619 
02620         /*
02621         * Sanity check 
02622         */
02623         if (n < 3) {
02624                 return (-1);
02625         }
02626 
02627         /*
02628         * Pointer setup 
02629         */
02630         x1 = x2 = vx;
02631         y1 = y2 = vy;
02632         x2++;
02633         y2++;
02634 
02635         /*
02636         * Set color 
02637         */
02638         result = 0;
02639         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
02640         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
02641 
02642         /*
02643         * Draw 
02644         */
02645         result |= polygon(renderer, vx, vy, n);
02646 
02647         return (result);
02648 }
02649 
02650 /* ---- AA-Polygon */
02651 
02663 int aapolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
02664 {
02665         Uint8 *c = (Uint8 *)&color; 
02666         return aapolygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
02667 }
02668 
02683 int aapolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02684 {
02685         int result;
02686         int i;
02687         const Sint16 *x1, *y1, *x2, *y2;
02688 
02689         /*
02690         * Vertex array NULL check 
02691         */
02692         if (vx == NULL) {
02693                 return (-1);
02694         }
02695         if (vy == NULL) {
02696                 return (-1);
02697         }
02698 
02699         /*
02700         * Sanity check 
02701         */
02702         if (n < 3) {
02703                 return (-1);
02704         }
02705 
02706         /*
02707         * Pointer setup 
02708         */
02709         x1 = x2 = vx;
02710         y1 = y2 = vy;
02711         x2++;
02712         y2++;
02713 
02714         /*
02715         * Draw 
02716         */
02717         result = 0;
02718         for (i = 1; i < n; i++) {
02719                 result |= _aalineRGBA(renderer, *x1, *y1, *x2, *y2, r, g, b, a, 0);
02720                 x1 = x2;
02721                 y1 = y2;
02722                 x2++;
02723                 y2++;
02724         }
02725 
02726         result |= _aalineRGBA(renderer, *x1, *y1, *vx, *vy, r, g, b, a, 0);
02727 
02728         return (result);
02729 }
02730 
02731 /* ---- Filled Polygon */
02732 
02741 int _gfxPrimitivesCompareInt(const void *a, const void *b)
02742 {
02743         return (*(const int *) a) - (*(const int *) b);
02744 }
02745 
02751 static int *gfxPrimitivesPolyIntsGlobal = NULL;
02752 
02758 static int gfxPrimitivesPolyAllocatedGlobal = 0;
02759 
02778 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)
02779 {
02780         int result;
02781         int i;
02782         int y, xa, xb;
02783         int miny, maxy;
02784         int x1, y1;
02785         int x2, y2;
02786         int ind1, ind2;
02787         int ints;
02788         int *gfxPrimitivesPolyInts = NULL;
02789         int *gfxPrimitivesPolyIntsNew = NULL;
02790         int gfxPrimitivesPolyAllocated = 0;
02791 
02792         /*
02793         * Vertex array NULL check 
02794         */
02795         if (vx == NULL) {
02796                 return (-1);
02797         }
02798         if (vy == NULL) {
02799                 return (-1);
02800         }
02801 
02802         /*
02803         * Sanity check number of edges
02804         */
02805         if (n < 3) {
02806                 return -1;
02807         }
02808 
02809         /*
02810         * Map polygon cache  
02811         */
02812         if ((polyInts==NULL) || (polyAllocated==NULL)) {
02813                 /* Use global cache */
02814                 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
02815                 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
02816         } else {
02817                 /* Use local cache */
02818                 gfxPrimitivesPolyInts = *polyInts;
02819                 gfxPrimitivesPolyAllocated = *polyAllocated;
02820         }
02821 
02822         /*
02823         * Allocate temp array, only grow array 
02824         */
02825         if (!gfxPrimitivesPolyAllocated) {
02826                 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
02827                 gfxPrimitivesPolyAllocated = n;
02828         } else {
02829                 if (gfxPrimitivesPolyAllocated < n) {
02830                         gfxPrimitivesPolyIntsNew = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
02831                         if (!gfxPrimitivesPolyIntsNew) {
02832                                 if (!gfxPrimitivesPolyInts) {
02833                                         free(gfxPrimitivesPolyInts);
02834                                         gfxPrimitivesPolyInts = NULL;
02835                                 }
02836                                 gfxPrimitivesPolyAllocated = 0;
02837                         } else {
02838                                 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsNew;
02839                                 gfxPrimitivesPolyAllocated = n;
02840                         }
02841                 }
02842         }
02843 
02844         /*
02845         * Check temp array
02846         */
02847         if (gfxPrimitivesPolyInts==NULL) {        
02848                 gfxPrimitivesPolyAllocated = 0;
02849         }
02850 
02851         /*
02852         * Update cache variables
02853         */
02854         if ((polyInts==NULL) || (polyAllocated==NULL)) { 
02855                 gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
02856                 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
02857         } else {
02858                 *polyInts = gfxPrimitivesPolyInts;
02859                 *polyAllocated = gfxPrimitivesPolyAllocated;
02860         }
02861 
02862         /*
02863         * Check temp array again
02864         */
02865         if (gfxPrimitivesPolyInts==NULL) {        
02866                 return(-1);
02867         }
02868 
02869         /*
02870         * Determine Y maxima 
02871         */
02872         miny = vy[0];
02873         maxy = vy[0];
02874         for (i = 1; (i < n); i++) {
02875                 if (vy[i] < miny) {
02876                         miny = vy[i];
02877                 } else if (vy[i] > maxy) {
02878                         maxy = vy[i];
02879                 }
02880         }
02881 
02882         /*
02883         * Draw, scanning y 
02884         */
02885         result = 0;
02886         for (y = miny; (y <= maxy); y++) {
02887                 ints = 0;
02888                 for (i = 0; (i < n); i++) {
02889                         if (!i) {
02890                                 ind1 = n - 1;
02891                                 ind2 = 0;
02892                         } else {
02893                                 ind1 = i - 1;
02894                                 ind2 = i;
02895                         }
02896                         y1 = vy[ind1];
02897                         y2 = vy[ind2];
02898                         if (y1 < y2) {
02899                                 x1 = vx[ind1];
02900                                 x2 = vx[ind2];
02901                         } else if (y1 > y2) {
02902                                 y2 = vy[ind1];
02903                                 y1 = vy[ind2];
02904                                 x2 = vx[ind1];
02905                                 x1 = vx[ind2];
02906                         } else {
02907                                 continue;
02908                         }
02909                         if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
02910                                 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
02911                         }           
02912                 }
02913 
02914                 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
02915 
02916                 /*
02917                 * Set color 
02918                 */
02919                 result = 0;
02920             result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
02921                 result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
02922 
02923                 for (i = 0; (i < ints); i += 2) {
02924                         xa = gfxPrimitivesPolyInts[i] + 1;
02925                         xa = (xa >> 16) + ((xa & 32768) >> 15);
02926                         xb = gfxPrimitivesPolyInts[i+1] - 1;
02927                         xb = (xb >> 16) + ((xb & 32768) >> 15);
02928                         result |= hline(renderer, xa, xb, y);
02929                 }
02930         }
02931 
02932         return (result);
02933 }
02934 
02946 int filledPolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
02947 {
02948         Uint8 *c = (Uint8 *)&color; 
02949         return filledPolygonRGBAMT(renderer, vx, vy, n, c[0], c[1], c[2], c[3], NULL, NULL);
02950 }
02951 
02966 int filledPolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02967 {
02968         return filledPolygonRGBAMT(renderer, vx, vy, n, r, g, b, a, NULL, NULL);
02969 }
02970 
02971 /* ---- Textured Polygon */
02972 
02988 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)
02989 {
02990         Sint16 w;
02991         Sint16 xtmp;
02992         int result = 0;
02993         int texture_x_walker;    
02994         int texture_y_start;    
02995         SDL_Rect source_rect,dst_rect;
02996         int pixels_written,write_width;
02997 
02998         /*
02999         * Swap x1, x2 if required to ensure x1<=x2
03000         */
03001         if (x1 > x2) {
03002                 xtmp = x1;
03003                 x1 = x2;
03004                 x2 = xtmp;
03005         }
03006 
03007         /*
03008         * Calculate width to draw
03009         */
03010         w = x2 - x1 + 1;
03011 
03012         /*
03013         * Determine where in the texture we start drawing
03014         */
03015         texture_x_walker =   (x1 - texture_dx)  % texture_w;
03016         if (texture_x_walker < 0){
03017                 texture_x_walker = texture_w + texture_x_walker ;
03018         }
03019 
03020         texture_y_start = (y + texture_dy) % texture_h;
03021         if (texture_y_start < 0){
03022                 texture_y_start = texture_h + texture_y_start;
03023         }
03024 
03025         // setup the source rectangle; we are only drawing one horizontal line
03026         source_rect.y = texture_y_start;
03027         source_rect.x = texture_x_walker;
03028         source_rect.h = 1;
03029 
03030         // we will draw to the current y
03031         dst_rect.y = y;
03032 
03033         // if there are enough pixels left in the current row of the texture
03034         // draw it all at once
03035         if (w <= texture_w -texture_x_walker){
03036                 source_rect.w = w;
03037                 source_rect.x = texture_x_walker;
03038                 dst_rect.x= x1;
03039                 result = (SDL_RenderCopy(renderer, texture, &source_rect ,&dst_rect) == 0);
03040         } else { // we need to draw multiple times
03041                 // draw the first segment
03042                 pixels_written = texture_w  - texture_x_walker;
03043                 source_rect.w = pixels_written;
03044                 source_rect.x = texture_x_walker;
03045                 dst_rect.x= x1;
03046                 result |= (SDL_RenderCopy(renderer, texture, &source_rect , &dst_rect) == 0);
03047                 write_width = texture_w;
03048 
03049                 // now draw the rest
03050                 // set the source x to 0
03051                 source_rect.x = 0;
03052                 while (pixels_written < w){
03053                         if (write_width >= w - pixels_written) {
03054                                 write_width =  w - pixels_written;
03055                         }
03056                         source_rect.w = write_width;
03057                         dst_rect.x = x1 + pixels_written;
03058                         result  |= (SDL_RenderCopy(renderer,texture,&source_rect , &dst_rect) == 0);
03059                         pixels_written += write_width;
03060                 }
03061         }
03062 
03063         return result;
03064 }
03065 
03082 int texturedPolygonMT(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n, 
03083         SDL_Surface * texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated)
03084 {
03085         int result;
03086         int i;
03087         int y, xa, xb;
03088         int minx,maxx,miny, maxy;
03089         int x1, y1;
03090         int x2, y2;
03091         int ind1, ind2;
03092         int ints;
03093         int *gfxPrimitivesPolyInts = NULL;
03094         int gfxPrimitivesPolyAllocated = 0;
03095         SDL_Texture *textureAsTexture;
03096 
03097         /*
03098         * Sanity check number of edges
03099         */
03100         if (n < 3) {
03101                 return -1;
03102         }
03103 
03104         /*
03105         * Map polygon cache  
03106         */
03107         if ((polyInts==NULL) || (polyAllocated==NULL)) {
03108                 /* Use global cache */
03109                 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
03110                 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
03111         } else {
03112                 /* Use local cache */
03113                 gfxPrimitivesPolyInts = *polyInts;
03114                 gfxPrimitivesPolyAllocated = *polyAllocated;
03115         }
03116 
03117         /*
03118         * Allocate temp array, only grow array 
03119         */
03120         if (!gfxPrimitivesPolyAllocated) {
03121                 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
03122                 gfxPrimitivesPolyAllocated = n;
03123         } else {
03124                 if (gfxPrimitivesPolyAllocated < n) {
03125                         gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
03126                         gfxPrimitivesPolyAllocated = n;
03127                 }
03128         }
03129 
03130         /*
03131         * Check temp array
03132         */
03133         if (gfxPrimitivesPolyInts==NULL) {        
03134                 gfxPrimitivesPolyAllocated = 0;
03135         }
03136 
03137         /*
03138         * Update cache variables
03139         */
03140         if ((polyInts==NULL) || (polyAllocated==NULL)) { 
03141                 gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
03142                 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
03143         } else {
03144                 *polyInts = gfxPrimitivesPolyInts;
03145                 *polyAllocated = gfxPrimitivesPolyAllocated;
03146         }
03147 
03148         /*
03149         * Check temp array again
03150         */
03151         if (gfxPrimitivesPolyInts==NULL) {        
03152                 return(-1);
03153         }
03154 
03155         /*
03156         * Determine X,Y minima,maxima 
03157         */
03158         miny = vy[0];
03159         maxy = vy[0];
03160         minx = vx[0];
03161         maxx = vx[0];
03162         for (i = 1; (i < n); i++) {
03163                 if (vy[i] < miny) {
03164                         miny = vy[i];
03165                 } else if (vy[i] > maxy) {
03166                         maxy = vy[i];
03167                 }
03168                 if (vx[i] < minx) {
03169                         minx = vx[i];
03170                 } else if (vx[i] > maxx) {
03171                         maxx = vx[i];
03172                 }
03173         }
03174 
03175         /*
03176         * Draw, scanning y 
03177         */
03178         result = 0;
03179         for (y = miny; (y <= maxy); y++) {
03180                 ints = 0;
03181                 for (i = 0; (i < n); i++) {
03182                         if (!i) {
03183                                 ind1 = n - 1;
03184                                 ind2 = 0;
03185                         } else {
03186                                 ind1 = i - 1;
03187                                 ind2 = i;
03188                         }
03189                         y1 = vy[ind1];
03190                         y2 = vy[ind2];
03191                         if (y1 < y2) {
03192                                 x1 = vx[ind1];
03193                                 x2 = vx[ind2];
03194                         } else if (y1 > y2) {
03195                                 y2 = vy[ind1];
03196                                 y1 = vy[ind2];
03197                                 x2 = vx[ind1];
03198                                 x1 = vx[ind2];
03199                         } else {
03200                                 continue;
03201                         }
03202                         if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
03203                                 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
03204                         } 
03205                 }
03206 
03207                 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
03208 
03209                 textureAsTexture = SDL_CreateTextureFromSurface(renderer, texture);
03210                 if (textureAsTexture == NULL)
03211                 {
03212                         return (-1);
03213                 }
03214 
03215                 for (i = 0; (i < ints); i += 2) {
03216                         xa = gfxPrimitivesPolyInts[i] + 1;
03217                         xa = (xa >> 16) + ((xa & 32768) >> 15);
03218                         xb = gfxPrimitivesPolyInts[i+1] - 1;
03219                         xb = (xb >> 16) + ((xb & 32768) >> 15);
03220                         result |= _HLineTextured(renderer, xa, xb, y, textureAsTexture, texture->w, texture->h, texture_dx, texture_dy);
03221                 }
03222                 SDL_DestroyTexture(textureAsTexture);
03223         }
03224 
03225         return (result);
03226 }
03227 
03244 int texturedPolygon(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
03245 {
03246         /*
03247         * Draw
03248         */
03249         return (texturedPolygonMT(renderer, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
03250 }
03251 
03252 /* ---- Character */
03253 
03257 static SDL_Texture *gfxPrimitivesFont[256];
03258 
03262 static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
03263 
03267 static Uint32 charWidth = 8;
03268 
03272 static Uint32 charHeight = 8;
03273 
03277 static Uint32 charWidthLocal = 8;
03278 
03282 static Uint32 charHeightLocal = 8;
03283 
03287 static Uint32 charPitch = 1;
03288 
03292 static Uint32 charRotation = 0;
03293 
03297 static Uint32 charSize = 8;
03298 
03312 void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch)
03313 {
03314         int i;
03315 
03316         if ((fontdata) && (cw) && (ch)) {
03317                 currentFontdata = (unsigned char *)fontdata;
03318                 charWidth = cw;
03319                 charHeight = ch;
03320         } else {
03321                 currentFontdata = gfxPrimitivesFontdata;
03322                 charWidth = 8;
03323                 charHeight = 8;
03324         }
03325 
03326         charPitch = (charWidth+7)/8;
03327         charSize = charPitch * charHeight;
03328 
03329         /* Maybe flip width/height for rendering */
03330         if ((charRotation==1) || (charRotation==3))
03331         {
03332                 charWidthLocal = charHeight;
03333                 charHeightLocal = charWidth;
03334         }
03335         else
03336         {
03337                 charWidthLocal = charWidth;
03338                 charHeightLocal = charHeight;
03339         }
03340 
03341         /* Clear character cache */
03342         for (i = 0; i < 256; i++) {
03343                 if (gfxPrimitivesFont[i]) {
03344                         SDL_DestroyTexture(gfxPrimitivesFont[i]);
03345                         gfxPrimitivesFont[i] = NULL;
03346                 }
03347         }
03348 }
03349 
03358 void gfxPrimitivesSetFontRotation(Uint32 rotation)
03359 {
03360         int i;
03361 
03362         rotation = rotation & 3;
03363         if (charRotation != rotation)
03364         {
03365                 /* Store rotation */
03366                 charRotation = rotation;
03367 
03368                 /* Maybe flip width/height for rendering */
03369                 if ((charRotation==1) || (charRotation==3))
03370                 {
03371                         charWidthLocal = charHeight;
03372                         charHeightLocal = charWidth;
03373                 }
03374                 else
03375                 {
03376                         charWidthLocal = charWidth;
03377                         charHeightLocal = charHeight;
03378                 }
03379 
03380                 /* Clear character cache */
03381                 for (i = 0; i < 256; i++) {
03382                         if (gfxPrimitivesFont[i]) {
03383                                 SDL_DestroyTexture(gfxPrimitivesFont[i]);
03384                                 gfxPrimitivesFont[i] = NULL;
03385                         }
03386                 }
03387         }
03388 }
03389 
03404 int characterRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
03405 {
03406         SDL_Rect srect;
03407         SDL_Rect drect;
03408         int result;
03409         Uint32 ix, iy;
03410         const unsigned char *charpos;
03411         Uint8 *curpos;
03412         Uint8 patt, mask;
03413         Uint8 *linepos;
03414         Uint32 pitch;
03415         SDL_Surface *character;
03416         SDL_Surface *rotatedCharacter;
03417         Uint32 ci;
03418 
03419         /*
03420         * Setup source rectangle
03421         */
03422         srect.x = 0;
03423         srect.y = 0;
03424         srect.w = charWidthLocal;
03425         srect.h = charHeightLocal;
03426 
03427         /*
03428         * Setup destination rectangle
03429         */
03430         drect.x = x;
03431         drect.y = y;
03432         drect.w = charWidthLocal;
03433         drect.h = charHeightLocal;
03434 
03435         /* Character index in cache */
03436         ci = (unsigned char) c;
03437 
03438         /*
03439         * Create new charWidth x charHeight bitmap surface if not already present.
03440         * Might get rotated later.
03441         */
03442         if (gfxPrimitivesFont[ci] == NULL) {
03443                 /*
03444                 * Redraw character into surface
03445                 */
03446                 character =     SDL_CreateRGBSurface(SDL_SWSURFACE,
03447                         charWidth, charHeight, 32,
03448                         0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
03449                 if (character == NULL) {
03450                         return (-1);
03451                 }
03452 
03453                 charpos = currentFontdata + ci * charSize;
03454                                 linepos = (Uint8 *)character->pixels;
03455                 pitch = character->pitch;
03456 
03457                 /*
03458                 * Drawing loop 
03459                 */
03460                 patt = 0;
03461                 for (iy = 0; iy < charHeight; iy++) {
03462                         mask = 0x00;
03463                         curpos = linepos;
03464                         for (ix = 0; ix < charWidth; ix++) {
03465                                 if (!(mask >>= 1)) {
03466                                         patt = *charpos++;
03467                                         mask = 0x80;
03468                                 }
03469                                 if (patt & mask) {
03470                                         *(Uint32 *)curpos = 0xffffffff;
03471                                 } else {
03472                                         *(Uint32 *)curpos = 0;
03473                                 }
03474                                 curpos += 4;
03475                         }
03476                         linepos += pitch;
03477                 }
03478 
03479                 /* Maybe rotate and replace cached image */
03480                 if (charRotation>0)
03481                 {
03482                         rotatedCharacter = rotateSurface90Degrees(character, charRotation);
03483                         SDL_FreeSurface(character);
03484                         character = rotatedCharacter;
03485                 }
03486 
03487                 /* Convert temp surface into texture */
03488                 gfxPrimitivesFont[ci] = SDL_CreateTextureFromSurface(renderer, character);
03489                 SDL_FreeSurface(character);
03490 
03491                 /*
03492                 * Check pointer 
03493                 */
03494                 if (gfxPrimitivesFont[ci] == NULL) {
03495                         return (-1);
03496                 }
03497         }
03498 
03499         /*
03500         * Set color 
03501         */
03502         result = 0;
03503         result |= SDL_SetTextureColorMod(gfxPrimitivesFont[ci], r, g, b);
03504         result |= SDL_SetTextureAlphaMod(gfxPrimitivesFont[ci], a);
03505 
03506         /*
03507         * Draw texture onto destination 
03508         */
03509         result |= SDL_RenderCopy(renderer, gfxPrimitivesFont[ci], &srect, &drect);
03510 
03511         return (result);
03512 }
03513 
03514 
03526 int characterColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, char c, Uint32 color)
03527 {
03528         Uint8 *co = (Uint8 *)&color; 
03529         return characterRGBA(renderer, x, y, c, co[0], co[1], co[2], co[3]);
03530 }
03531 
03532 
03547 int stringColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint32 color)
03548 {
03549         Uint8 *c = (Uint8 *)&color; 
03550         return stringRGBA(renderer, x, y, s, c[0], c[1], c[2], c[3]);
03551 }
03552 
03567 int stringRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
03568 {
03569         int result = 0;
03570         Sint16 curx = x;
03571         Sint16 cury = y;
03572         const char *curchar = s;
03573 
03574         while (*curchar && !result) {
03575                 result |= characterRGBA(renderer, curx, cury, *curchar, r, g, b, a);
03576                 switch (charRotation)
03577                 {
03578                 case 0:
03579                         curx += charWidthLocal;
03580                         break;
03581                 case 2:
03582                         curx -= charWidthLocal;
03583                         break;
03584                 case 1:
03585                         cury += charHeightLocal;
03586                         break;
03587                 case 3:
03588                         cury -= charHeightLocal;
03589                         break;
03590                 }
03591                 curchar++;
03592         }
03593 
03594         return (result);
03595 }
03596 
03597 /* ---- Bezier curve */
03598 
03608 double _evaluateBezier (double *data, int ndata, double t) 
03609 {
03610         double mu, result;
03611         int n,k,kn,nn,nkn;
03612         double blend,muk,munk;
03613 
03614         /* Sanity check bounds */
03615         if (t<0.0) {
03616                 return(data[0]);
03617         }
03618         if (t>=(double)ndata) {
03619                 return(data[ndata-1]);
03620         }
03621 
03622         /* Adjust t to the range 0.0 to 1.0 */ 
03623         mu=t/(double)ndata;
03624 
03625         /* Calculate interpolate */
03626         n=ndata-1;
03627         result=0.0;
03628         muk = 1;
03629         munk = pow(1-mu,(double)n);
03630         for (k=0;k<=n;k++) {
03631                 nn = n;
03632                 kn = k;
03633                 nkn = n - k;
03634                 blend = muk * munk;
03635                 muk *= mu;
03636                 munk /= (1-mu);
03637                 while (nn >= 1) {
03638                         blend *= nn;
03639                         nn--;
03640                         if (kn > 1) {
03641                                 blend /= (double)kn;
03642                                 kn--;
03643                         }
03644                         if (nkn > 1) {
03645                                 blend /= (double)nkn;
03646                                 nkn--;
03647                         }
03648                 }
03649                 result += data[k] * blend;
03650         }
03651 
03652         return (result);
03653 }
03654 
03667 int bezierColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
03668 {
03669         Uint8 *c = (Uint8 *)&color; 
03670         return bezierRGBA(renderer, vx, vy, n, s, c[0], c[1], c[2], c[3]);
03671 }
03672 
03688 int bezierRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
03689 {
03690         int result;
03691         int i;
03692         double *x, *y, t, stepsize;
03693         Sint16 x1, y1, x2, y2;
03694 
03695         /*
03696         * Sanity check 
03697         */
03698         if (n < 3) {
03699                 return (-1);
03700         }
03701         if (s < 2) {
03702                 return (-1);
03703         }
03704 
03705         /*
03706         * Variable setup 
03707         */
03708         stepsize=(double)1.0/(double)s;
03709 
03710         /* Transfer vertices into float arrays */
03711         if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
03712                 return(-1);
03713         }
03714         if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
03715                 free(x);
03716                 return(-1);
03717         }    
03718         for (i=0; i<n; i++) {
03719                 x[i]=(double)vx[i];
03720                 y[i]=(double)vy[i];
03721         }      
03722         x[n]=(double)vx[0];
03723         y[n]=(double)vy[0];
03724 
03725         /*
03726         * Set color 
03727         */
03728         result = 0;
03729         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
03730         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
03731 
03732         /*
03733         * Draw 
03734         */
03735         t=0.0;
03736         x1=(Sint16)lrint(_evaluateBezier(x,n+1,t));
03737         y1=(Sint16)lrint(_evaluateBezier(y,n+1,t));
03738         for (i = 0; i <= (n*s); i++) {
03739                 t += stepsize;
03740                 x2=(Sint16)_evaluateBezier(x,n,t);
03741                 y2=(Sint16)_evaluateBezier(y,n,t);
03742                 result |= line(renderer, x1, y1, x2, y2);
03743                 x1 = x2;
03744                 y1 = y2;
03745         }
03746 
03747         /* Clean up temporary array */
03748         free(x);
03749         free(y);
03750 
03751         return (result);
03752 }
03753 
03754 
03755 /* ---- Thick Line */
03756 
03775 int _bresenhamInitialize(SDL2_gfxBresenhamIterator *b, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
03776 {
03777         int temp;
03778 
03779         if (b==NULL) {
03780                 return(-1);
03781         }
03782 
03783         b->x = x1;
03784         b->y = y1;
03785 
03786         /* dx = abs(x2-x1), s1 = sign(x2-x1) */
03787         if ((b->dx = x2 - x1) != 0) {
03788                 if (b->dx < 0) {
03789                         b->dx = -b->dx;
03790                         b->s1 = -1;
03791                 } else {
03792                         b->s1 = 1;
03793                 }
03794         } else {
03795                 b->s1 = 0;      
03796         }
03797 
03798         /* dy = abs(y2-y1), s2 = sign(y2-y1)    */
03799         if ((b->dy = y2 - y1) != 0) {
03800                 if (b->dy < 0) {
03801                         b->dy = -b->dy;
03802                         b->s2 = -1;
03803                 } else {
03804                         b->s2 = 1;
03805                 }
03806         } else {
03807                 b->s2 = 0;      
03808         }
03809 
03810         if (b->dy > b->dx) {
03811                 temp = b->dx;
03812                 b->dx = b->dy;
03813                 b->dy = temp;
03814                 b->swapdir = 1;
03815         } else {
03816                 b->swapdir = 0;
03817         }
03818 
03819         b->count = (b->dx<0) ? 0 : (unsigned int)b->dx;
03820         b->dy <<= 1;
03821         b->error = b->dy - b->dx;
03822         b->dx <<= 1;    
03823 
03824         return(0);
03825 }
03826 
03827 
03837 int _bresenhamIterate(SDL2_gfxBresenhamIterator *b)
03838 {       
03839         if (b==NULL) {
03840                 return (-1);
03841         }
03842 
03843         /* last point check */
03844         if (b->count==0) {
03845                 return (2);
03846         }
03847 
03848         while (b->error >= 0) {
03849                 if (b->swapdir) {
03850                         b->x += b->s1;
03851                 } else  {
03852                         b->y += b->s2;
03853                 }
03854 
03855                 b->error -= b->dx;
03856         }
03857 
03858         if (b->swapdir) {
03859                 b->y += b->s2;
03860         } else {
03861                 b->x += b->s1;
03862         }
03863 
03864         b->error += b->dy;      
03865         b->count--;             
03866 
03867         /* count==0 indicates "end-of-line" */
03868         return ((b->count) ? 0 : 1);
03869 }
03870 
03871 
03880 void _murphyParaline(SDL2_gfxMurphyIterator *m, Sint16 x, Sint16 y, int d1)
03881 {
03882         int p;
03883         d1 = -d1;
03884 
03885         for (p = 0; p <= m->u; p++) {
03886 
03887                 pixel(m->renderer, x, y);
03888 
03889                 if (d1 <= m->kt) {
03890                         if (m->oct2 == 0) {
03891                                 x++;
03892                         } else {
03893                                 if (m->quad4 == 0) {
03894                                         y++;
03895                                 } else {
03896                                         y--;
03897                                 }
03898                         }
03899                         d1 += m->kv;
03900                 } else {        
03901                         x++;
03902                         if (m->quad4 == 0) {
03903                                 y++;
03904                         } else {
03905                                 y--;
03906                         }
03907                         d1 += m->kd;
03908                 }
03909         }
03910 
03911         m->tempx = x;
03912         m->tempy = y;
03913 }
03914 
03930 void _murphyIteration(SDL2_gfxMurphyIterator *m, Uint8 miter, 
03931         Uint16 ml1bx, Uint16 ml1by, Uint16 ml2bx, Uint16 ml2by, 
03932         Uint16 ml1x, Uint16 ml1y, Uint16 ml2x, Uint16 ml2y)
03933 {
03934         int atemp1, atemp2;
03935         int ftmp1, ftmp2;
03936         Uint16 m1x, m1y, m2x, m2y;      
03937         Uint16 fix, fiy, lax, lay, curx, cury;
03938         Sint16 px[4], py[4];
03939         SDL2_gfxBresenhamIterator b;
03940 
03941         if (miter > 1) {
03942                 if (m->first1x != -32768) {
03943                         fix = (m->first1x + m->first2x) / 2;
03944                         fiy = (m->first1y + m->first2y) / 2;
03945                         lax = (m->last1x + m->last2x) / 2;
03946                         lay = (m->last1y + m->last2y) / 2;
03947                         curx = (ml1x + ml2x) / 2;
03948                         cury = (ml1y + ml2y) / 2;
03949 
03950                         atemp1 = (fix - curx);
03951                         atemp2 = (fiy - cury);
03952                         ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
03953                         atemp1 = (lax - curx);
03954                         atemp2 = (lay - cury);
03955                         ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
03956 
03957                         if (ftmp1 <= ftmp2) {
03958                                 m1x = m->first1x;
03959                                 m1y = m->first1y;
03960                                 m2x = m->first2x;
03961                                 m2y = m->first2y;
03962                         } else {
03963                                 m1x = m->last1x;
03964                                 m1y = m->last1y;
03965                                 m2x = m->last2x;
03966                                 m2y = m->last2y;
03967                         }
03968 
03969                         atemp1 = (m2x - ml2x);
03970                         atemp2 = (m2y - ml2y);
03971                         ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
03972                         atemp1 = (m2x - ml2bx);
03973                         atemp2 = (m2y - ml2by);
03974                         ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
03975 
03976                         if (ftmp2 >= ftmp1) {
03977                                 ftmp1 = ml2bx;
03978                                 ftmp2 = ml2by;
03979                                 ml2bx = ml2x;
03980                                 ml2by = ml2y;
03981                                 ml2x = ftmp1;
03982                                 ml2y = ftmp2;
03983                                 ftmp1 = ml1bx;
03984                                 ftmp2 = ml1by;
03985                                 ml1bx = ml1x;
03986                                 ml1by = ml1y;
03987                                 ml1x = ftmp1;
03988                                 ml1y = ftmp2;
03989                         }
03990 
03991                         /*
03992                         * Lock the surface 
03993                         */
03994                         _bresenhamInitialize(&b, m2x, m2y, m1x, m1y);
03995                         do {
03996                                 pixel(m->renderer, b.x, b.y);
03997                         } while (_bresenhamIterate(&b)==0);
03998 
03999                         _bresenhamInitialize(&b, m1x, m1y, ml1bx, ml1by);
04000                         do {
04001                                 pixel(m->renderer, b.x, b.y);
04002                         } while (_bresenhamIterate(&b)==0);
04003 
04004                         _bresenhamInitialize(&b, ml1bx, ml1by, ml2bx, ml2by);
04005                         do {
04006                                 pixel(m->renderer, b.x, b.y);
04007                         } while (_bresenhamIterate(&b)==0);
04008 
04009                         _bresenhamInitialize(&b, ml2bx, ml2by, m2x, m2y);
04010                         do {
04011                                 pixel(m->renderer, b.x, b.y);
04012                         } while (_bresenhamIterate(&b)==0);
04013 
04014                         px[0] = m1x;
04015                         px[1] = m2x;
04016                         px[2] = ml1bx;
04017                         px[3] = ml2bx;
04018                         py[0] = m1y;
04019                         py[1] = m2y;
04020                         py[2] = ml1by;
04021                         py[3] = ml2by;                  
04022                         polygon(m->renderer, px, py, 4);                                                
04023                 }
04024         }
04025 
04026         m->last1x = ml1x;
04027         m->last1y = ml1y;
04028         m->last2x = ml2x;
04029         m->last2y = ml2y;
04030         m->first1x = ml1bx;
04031         m->first1y = ml1by;
04032         m->first2x = ml2bx;
04033         m->first2y = ml2by;
04034 }
04035 
04036 
04037 #define HYPOT(x,y) sqrt((double)(x)*(double)(x)+(double)(y)*(double)(y)) 
04038 
04053 void _murphyWideline(SDL2_gfxMurphyIterator *m, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 miter)
04054 {       
04055         float offset = (float)width / 2.f;
04056 
04057         Sint16 temp;
04058         Sint16 ptx, pty, ptxx, ptxy, ml1x, ml1y, ml2x, ml2y, ml1bx, ml1by, ml2bx, ml2by;
04059 
04060         int d0, d1;             /* difference terms d0=perpendicular to line, d1=along line */
04061 
04062         int q;                  /* pel counter,q=perpendicular to line */
04063         int tmp;
04064 
04065         int dd;                 /* distance along line */
04066         int tk;                 /* thickness threshold */
04067         double ang;             /* angle for initial point calculation */
04068         double sang, cang;
04069 
04070         /* Initialisation */
04071         m->u = x2 - x1; /* delta x */
04072         m->v = y2 - y1; /* delta y */
04073 
04074         if (m->u < 0) { /* swap to make sure we are in quadrants 1 or 4 */
04075                 temp = x1;
04076                 x1 = x2;
04077                 x2 = temp;
04078                 temp = y1;
04079                 y1 = y2;
04080                 y2 = temp;              
04081                 m->u *= -1;
04082                 m->v *= -1;
04083         }
04084 
04085         if (m->v < 0) { /* swap to 1st quadrant and flag */
04086                 m->v *= -1;
04087                 m->quad4 = 1;
04088         } else {
04089                 m->quad4 = 0;
04090         }
04091 
04092         if (m->v > m->u) {      /* swap things if in 2 octant */
04093                 tmp = m->u;
04094                 m->u = m->v;
04095                 m->v = tmp;
04096                 m->oct2 = 1;
04097         } else {
04098                 m->oct2 = 0;
04099         }
04100 
04101         m->ku = m->u + m->u;    /* change in l for square shift */
04102         m->kv = m->v + m->v;    /* change in d for square shift */
04103         m->kd = m->kv - m->ku;  /* change in d for diagonal shift */
04104         m->kt = m->u - m->kv;   /* diag/square decision threshold */
04105 
04106         d0 = 0;
04107         d1 = 0;
04108         dd = 0;
04109 
04110         ang = atan((double) m->v / (double) m->u);      /* calc new initial point - offset both sides of ideal */       
04111         sang = sin(ang);
04112         cang = cos(ang);
04113 
04114         if (m->oct2 == 0) {
04115                 ptx = x1 + (Sint16)lrint(offset * sang);
04116                 if (m->quad4 == 0) {
04117                         pty = y1 - (Sint16)lrint(offset * cang);
04118                 } else {
04119                         pty = y1 + (Sint16)lrint(offset * cang);
04120                 }
04121         } else {
04122                 ptx = x1 - (Sint16)lrint(offset * cang);
04123                 if (m->quad4 == 0) {
04124                         pty = y1 + (Sint16)lrint(offset * sang);
04125                 } else {
04126                         pty = y1 - (Sint16)lrint(offset * sang);
04127                 }
04128         }
04129 
04130         /* used here for constant thickness line */
04131         tk = (int) (4. * HYPOT(ptx - x1, pty - y1) * HYPOT(m->u, m->v));
04132 
04133         if (miter == 0) {
04134                 m->first1x = -32768;
04135                 m->first1y = -32768;
04136                 m->first2x = -32768;
04137                 m->first2y = -32768;
04138                 m->last1x = -32768;
04139                 m->last1y = -32768;
04140                 m->last2x = -32768;
04141                 m->last2y = -32768;
04142         }
04143         ptxx = ptx;
04144         ptxy = pty;
04145 
04146         for (q = 0; dd <= tk; q++) {    /* outer loop, stepping perpendicular to line */
04147 
04148                 _murphyParaline(m, ptx, pty, d1);       /* call to inner loop - right edge */
04149                 if (q == 0) {
04150                         ml1x = ptx;
04151                         ml1y = pty;
04152                         ml1bx = m->tempx;
04153                         ml1by = m->tempy;
04154                 } else {
04155                         ml2x = ptx;
04156                         ml2y = pty;
04157                         ml2bx = m->tempx;
04158                         ml2by = m->tempy;
04159                 }
04160                 if (d0 < m->kt) {       /* square move */
04161                         if (m->oct2 == 0) {
04162                                 if (m->quad4 == 0) {
04163                                         pty++;
04164                                 } else {
04165                                         pty--;
04166                                 }
04167                         } else {
04168                                 ptx++;
04169                         }
04170                 } else {        /* diagonal move */
04171                         dd += m->kv;
04172                         d0 -= m->ku;
04173                         if (d1 < m->kt) {       /* normal diagonal */
04174                                 if (m->oct2 == 0) {
04175                                         ptx--;
04176                                         if (m->quad4 == 0) {
04177                                                 pty++;
04178                                         } else {
04179                                                 pty--;
04180                                         }
04181                                 } else {
04182                                         ptx++;
04183                                         if (m->quad4 == 0) {
04184                                                 pty--;
04185                                         } else {
04186                                                 pty++;
04187                                         }
04188                                 }
04189                                 d1 += m->kv;
04190                         } else {        /* double square move, extra parallel line */
04191                                 if (m->oct2 == 0) {
04192                                         ptx--;
04193                                 } else {
04194                                         if (m->quad4 == 0) {
04195                                                 pty--;
04196                                         } else {
04197                                                 pty++;
04198                                         }
04199                                 }
04200                                 d1 += m->kd;
04201                                 if (dd > tk) {
04202                                         _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
04203                                         return; /* breakout on the extra line */
04204                                 }
04205                                 _murphyParaline(m, ptx, pty, d1);
04206                                 if (m->oct2 == 0) {
04207                                         if (m->quad4 == 0) {
04208                                                 pty++;
04209                                         } else {
04210 
04211                                                 pty--;
04212                                         }
04213                                 } else {
04214                                         ptx++;
04215                                 }
04216                         }
04217                 }
04218                 dd += m->ku;
04219                 d0 += m->kv;
04220         }
04221 
04222         _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
04223 }
04224 
04225 
04239 int thickLineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
04240 {       
04241         Uint8 *c = (Uint8 *)&color; 
04242         return thickLineRGBA(renderer, x1, y1, x2, y2, width, c[0], c[1], c[2], c[3]);
04243 }
04244 
04261 int thickLineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
04262 {
04263         int result;
04264         int wh;
04265         SDL2_gfxMurphyIterator m;
04266 
04267         if (renderer == NULL) {
04268                 return -1;
04269         }
04270         if (width < 1) {
04271                 return -1;
04272         }
04273 
04274         /* Special case: thick "point" */
04275         if ((x1 == x2) && (y1 == y2)) {
04276                 wh = width / 2;
04277                 return boxRGBA(renderer, x1 - wh, y1 - wh, x2 + width, y2 + width, r, g, b, a);         
04278         }
04279 
04280         /*
04281         * Set color
04282         */
04283         result = 0;
04284         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
04285         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
04286 
04287         /* 
04288         * Draw
04289         */
04290         m.renderer = renderer;
04291         _murphyWideline(&m, x1, y1, x2, y2, width, 0);
04292         _murphyWideline(&m, x1, y1, x2, y2, width, 1);
04293 
04294         return(0);
04295 }