SDL2_gfx  1.0.1
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 <= 1) {
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;
00524         Sint16 w, h, r2, tmp;
00525         Sint16 cx = 0;
00526         Sint16 cy = rad;
00527         Sint16 ocx = (Sint16) 0xffff;
00528         Sint16 ocy = (Sint16) 0xffff;
00529         Sint16 df = 1 - rad;
00530         Sint16 d_e = 3;
00531         Sint16 d_se = -2 * rad + 5;
00532         Sint16 xpcx, xmcx, xpcy, xmcy;
00533         Sint16 ypcy, ymcy, ypcx, ymcx;
00534         Sint16 x, y, dx, dy;
00535 
00536         /* 
00537         * Check destination renderer 
00538         */
00539         if (renderer == NULL)
00540         {
00541                 return -1;
00542         }
00543 
00544         /*
00545         * Check radius vor valid range
00546         */
00547         if (rad < 0) {
00548                 return -1;
00549         }
00550 
00551         /*
00552         * Special case - no rounding
00553         */
00554         if (rad <= 1) {
00555                 return rectangleRGBA(renderer, x1, y1, x2, y2, r, g, b, a);
00556         }
00557 
00558         /*
00559         * Test for special cases of straight lines or single point 
00560         */
00561         if (x1 == x2) {
00562                 if (y1 == y2) {
00563                         return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00564                 } else {
00565                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00566                 }
00567         } else {
00568                 if (y1 == y2) {
00569                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00570                 }
00571         }
00572 
00573         /*
00574         * Swap x1, x2 if required 
00575         */
00576         if (x1 > x2) {
00577                 tmp = x1;
00578                 x1 = x2;
00579                 x2 = tmp;
00580         }
00581 
00582         /*
00583         * Swap y1, y2 if required 
00584         */
00585         if (y1 > y2) {
00586                 tmp = y1;
00587                 y1 = y2;
00588                 y2 = tmp;
00589         }
00590 
00591         /*
00592         * Calculate width&height 
00593         */
00594         w = x2 - x1 + 1;
00595         h = y2 - y1 + 1;
00596 
00597         /*
00598         * Maybe adjust radius
00599         */
00600         r2 = rad + rad;
00601         if (r2 > w)  
00602         {
00603                 rad = w / 2;
00604                 r2 = rad + rad;
00605         }
00606         if (r2 > h)
00607         {
00608                 rad = h / 2;
00609         }
00610 
00611         /* Setup filled circle drawing for corners */
00612         x = x1 + rad;
00613         y = y1 + rad;
00614         dx = x2 - x1 - rad - rad;
00615         dy = y2 - y1 - rad - rad;
00616 
00617         /*
00618         * Set color
00619         */
00620         result = 0;
00621         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00622         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
00623 
00624         /*
00625         * Draw corners
00626         */
00627         do {
00628                 xpcx = x + cx;
00629                 xmcx = x - cx;
00630                 xpcy = x + cy;
00631                 xmcy = x - cy;
00632                 if (ocy != cy) {
00633                         if (cy > 0) {
00634                                 ypcy = y + cy;
00635                                 ymcy = y - cy;
00636                                 result |= hline(renderer, xmcx, xpcx + dx, ypcy + dy);
00637                                 result |= hline(renderer, xmcx, xpcx + dx, ymcy);
00638                         } else {
00639                                 result |= hline(renderer, xmcx, xpcx + dx, y);
00640                         }
00641                         ocy = cy;
00642                 }
00643                 if (ocx != cx) {
00644                         if (cx != cy) {
00645                                 if (cx > 0) {
00646                                         ypcx = y + cx;
00647                                         ymcx = y - cx;
00648                                         result |= hline(renderer, xmcy, xpcy + dx, ymcx);
00649                                         result |= hline(renderer, xmcy, xpcy + dx, ypcx + dy);
00650                                 } else {
00651                                         result |= hline(renderer, xmcy, xpcy + dx, y);
00652                                 }
00653                         }
00654                         ocx = cx;
00655                 }
00656 
00657                 /*
00658                 * Update 
00659                 */
00660                 if (df < 0) {
00661                         df += d_e;
00662                         d_e += 2;
00663                         d_se += 2;
00664                 } else {
00665                         df += d_se;
00666                         d_e += 2;
00667                         d_se += 4;
00668                         cy--;
00669                 }
00670                 cx++;
00671         } while (cx <= cy);
00672 
00673         /* Inside */
00674         if (dx > 0 && dy > 0) {
00675                 result |= boxRGBA(renderer, x1, y1 + rad + 1, x2, y2 - rad, r, g, b, a);
00676         }
00677 
00678         return (result);
00679 }
00680 
00681 /* ---- Box */
00682 
00695 int boxColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
00696 {
00697         Uint8 *c = (Uint8 *)&color; 
00698         return boxRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
00699 }
00700 
00716 int boxRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00717 {
00718         int result;
00719         Sint16 tmp;
00720         SDL_Rect rect;
00721 
00722         /*
00723         * Test for special cases of straight lines or single point 
00724         */
00725         if (x1 == x2) {
00726                 if (y1 == y2) {
00727                         return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00728                 } else {
00729                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00730                 }
00731         } else {
00732                 if (y1 == y2) {
00733                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00734                 }
00735         }
00736 
00737         /*
00738         * Swap x1, x2 if required 
00739         */
00740         if (x1 > x2) {
00741                 tmp = x1;
00742                 x1 = x2;
00743                 x2 = tmp;
00744         }
00745 
00746         /*
00747         * Swap y1, y2 if required 
00748         */
00749         if (y1 > y2) {
00750                 tmp = y1;
00751                 y1 = y2;
00752                 y2 = tmp;
00753         }
00754 
00755         /* 
00756         * Create destination rect
00757         */      
00758         rect.x = x1;
00759         rect.y = y1;
00760         rect.w = x2 - x1 + 1;
00761         rect.h = y2 - y1 + 1;
00762         
00763         /*
00764         * Draw
00765         */
00766         result = 0;
00767         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00768         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
00769         result |= SDL_RenderFillRect(renderer, &rect);
00770         return result;
00771 }
00772 
00773 /* ----- Line */
00774 
00786 int line(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
00787 {
00788         /*
00789         * Draw
00790         */
00791         return SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
00792 }
00793 
00806 int lineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
00807 {
00808         Uint8 *c = (Uint8 *)&color; 
00809         return lineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3]);
00810 }
00811 
00827 int lineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
00828 {
00829         /*
00830         * Draw
00831         */
00832         int result = 0;
00833         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
00834         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
00835         result |= SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
00836         return result;
00837 }
00838 
00839 /* ---- AA Line */
00840 
00841 #define AAlevels 256
00842 #define AAbits 8
00843 
00867 int _aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int draw_endpoint)
00868 {
00869         Sint32 xx0, yy0, xx1, yy1;
00870         int result;
00871         Uint32 intshift, erracc, erradj;
00872         Uint32 erracctmp, wgt, wgtcompmask;
00873         int dx, dy, tmp, xdir, y0p1, x0pxdir;
00874 
00875         /*
00876         * Keep on working with 32bit numbers 
00877         */
00878         xx0 = x1;
00879         yy0 = y1;
00880         xx1 = x2;
00881         yy1 = y2;
00882 
00883         /*
00884         * Reorder points to make dy positive 
00885         */
00886         if (yy0 > yy1) {
00887                 tmp = yy0;
00888                 yy0 = yy1;
00889                 yy1 = tmp;
00890                 tmp = xx0;
00891                 xx0 = xx1;
00892                 xx1 = tmp;
00893         }
00894 
00895         /*
00896         * Calculate distance 
00897         */
00898         dx = xx1 - xx0;
00899         dy = yy1 - yy0;
00900 
00901         /*
00902         * Adjust for negative dx and set xdir 
00903         */
00904         if (dx >= 0) {
00905                 xdir = 1;
00906         } else {
00907                 xdir = -1;
00908                 dx = (-dx);
00909         }
00910         
00911         /*
00912         * Check for special cases 
00913         */
00914         if (dx == 0) {
00915                 /*
00916                 * Vertical line 
00917                 */
00918                 if (draw_endpoint)
00919                 {
00920                         return (vlineRGBA(renderer, x1, y1, y2, r, g, b, a));
00921                 } else {
00922                         if (dy > 0) {
00923                                 return (vlineRGBA(renderer, x1, yy0, yy0+dy, r, g, b, a));
00924                         } else {
00925                                 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00926                         }
00927                 }
00928         } else if (dy == 0) {
00929                 /*
00930                 * Horizontal line 
00931                 */
00932                 if (draw_endpoint)
00933                 {
00934                         return (hlineRGBA(renderer, x1, x2, y1, r, g, b, a));
00935                 } else {
00936                         if (dx > 0) {
00937                                 return (hlineRGBA(renderer, xx0, xx0+dx, y1, r, g, b, a));
00938                         } else {
00939                                 return (pixelRGBA(renderer, x1, y1, r, g, b, a));
00940                         }
00941                 }
00942         } else if ((dx == dy) && (draw_endpoint)) {
00943                 /*
00944                 * Diagonal line (with endpoint)
00945                 */
00946                 return (lineRGBA(renderer, x1, y1, x2, y2,  r, g, b, a));
00947         }
00948 
00949 
00950         /*
00951         * Line is not horizontal, vertical or diagonal (with endpoint)
00952         */
00953         result = 0;
00954 
00955         /*
00956         * Zero accumulator 
00957         */
00958         erracc = 0;
00959 
00960         /*
00961         * # of bits by which to shift erracc to get intensity level 
00962         */
00963         intshift = 32 - AAbits;
00964 
00965         /*
00966         * Mask used to flip all bits in an intensity weighting 
00967         */
00968         wgtcompmask = AAlevels - 1;
00969 
00970         /*
00971         * Draw the initial pixel in the foreground color 
00972         */
00973         result |= pixelRGBA(renderer, x1, y1, r, g, b, a);
00974 
00975         /*
00976         * x-major or y-major? 
00977         */
00978         if (dy > dx) {
00979 
00980                 /*
00981                 * y-major.  Calculate 16-bit fixed point fractional part of a pixel that
00982                 * X advances every time Y advances 1 pixel, truncating the result so that
00983                 * we won't overrun the endpoint along the X axis 
00984                 */
00985                 /*
00986                 * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy; 
00987                 */
00988                 erradj = ((dx << 16) / dy) << 16;
00989 
00990                 /*
00991                 * draw all pixels other than the first and last 
00992                 */
00993                 x0pxdir = xx0 + xdir;
00994                 while (--dy) {
00995                         erracctmp = erracc;
00996                         erracc += erradj;
00997                         if (erracc <= erracctmp) {
00998                                 /*
00999                                 * rollover in error accumulator, x coord advances 
01000                                 */
01001                                 xx0 = x0pxdir;
01002                                 x0pxdir += xdir;
01003                         }
01004                         yy0++;          /* y-major so always advance Y */
01005 
01006                         /*
01007                         * the AAbits most significant bits of erracc give us the intensity
01008                         * weighting for this pixel, and the complement of the weighting for
01009                         * the paired pixel. 
01010                         */
01011                         wgt = (erracc >> intshift) & 255;
01012                         result |= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
01013                         result |= pixelRGBAWeight (renderer, x0pxdir, yy0, r, g, b, a, wgt);
01014                 }
01015 
01016         } else {
01017 
01018                 /*
01019                 * x-major line.  Calculate 16-bit fixed-point fractional part of a pixel
01020                 * that Y advances each time X advances 1 pixel, truncating the result so
01021                 * that we won't overrun the endpoint along the X axis. 
01022                 */
01023                 /*
01024                 * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx; 
01025                 */
01026                 erradj = ((dy << 16) / dx) << 16;
01027 
01028                 /*
01029                 * draw all pixels other than the first and last 
01030                 */
01031                 y0p1 = yy0 + 1;
01032                 while (--dx) {
01033 
01034                         erracctmp = erracc;
01035                         erracc += erradj;
01036                         if (erracc <= erracctmp) {
01037                                 /*
01038                                 * Accumulator turned over, advance y 
01039                                 */
01040                                 yy0 = y0p1;
01041                                 y0p1++;
01042                         }
01043                         xx0 += xdir;    /* x-major so always advance X */
01044                         /*
01045                         * the AAbits most significant bits of erracc give us the intensity
01046                         * weighting for this pixel, and the complement of the weighting for
01047                         * the paired pixel. 
01048                         */
01049                         wgt = (erracc >> intshift) & 255;
01050                         result |= pixelRGBAWeight (renderer, xx0, yy0, r, g, b, a, 255 - wgt);
01051                         result |= pixelRGBAWeight (renderer, xx0, y0p1, r, g, b, a, wgt);
01052                 }
01053         }
01054 
01055         /*
01056         * Do we have to draw the endpoint 
01057         */
01058         if (draw_endpoint) {
01059                 /*
01060                 * Draw final pixel, always exactly intersected by the line and doesn't
01061                 * need to be weighted. 
01062                 */
01063                 result |= pixelRGBA (renderer, x2, y2, r, g, b, a);
01064         }
01065 
01066         return (result);
01067 }
01068 
01081 int aalineColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
01082 {
01083         Uint8 *c = (Uint8 *)&color; 
01084         return _aalineRGBA(renderer, x1, y1, x2, y2, c[0], c[1], c[2], c[3], 1);
01085 }
01086 
01102 int aalineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01103 {
01104         return _aalineRGBA(renderer, x1, y1, x2, y2, r, g, b, a, 1);
01105 }
01106 
01107 /* ----- Circle */
01108 
01120 int circleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
01121 {
01122         Uint8 *c = (Uint8 *)&color; 
01123         return ellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
01124 }
01125 
01140 int circleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01141 {
01142         return ellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
01143 }
01144 
01145 /* ----- Arc */
01146 
01160 int arcColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
01161 {
01162         Uint8 *c = (Uint8 *)&color; 
01163         return arcRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3]);
01164 }
01165 
01182 /* TODO: rewrite algorithm; arc endpoints are not always drawn */
01183 int arcRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01184 {
01185         int result;
01186         Sint16 cx = 0;
01187         Sint16 cy = rad;
01188         Sint16 df = 1 - rad;
01189         Sint16 d_e = 3;
01190         Sint16 d_se = -2 * rad + 5;
01191         Sint16 xpcx, xmcx, xpcy, xmcy;
01192         Sint16 ypcy, ymcy, ypcx, ymcx;
01193         Uint8 drawoct;
01194         int startoct, endoct, oct, stopval_start = 0, stopval_end = 0;
01195         double dstart, dend, temp = 0.;
01196 
01197         /*
01198         * Sanity check radius 
01199         */
01200         if (rad < 0) {
01201                 return (-1);
01202         }
01203 
01204         /*
01205         * Special case for rad=0 - draw a point 
01206         */
01207         if (rad == 0) {
01208                 return (pixelRGBA(renderer, x, y, r, g, b, a));
01209         }
01210 
01211         // Octant labelling
01212         //      
01213         //  \ 5 | 6 /
01214         //   \  |  /
01215         //  4 \ | / 7
01216         //     \|/
01217         //------+------ +x
01218         //     /|\
01219         //  3 / | \ 0
01220         //   /  |  \
01221         //  / 2 | 1 \
01222         //      +y
01223 
01224         // Initially reset bitmask to 0x00000000
01225         // the set whether or not to keep drawing a given octant.
01226         // For example: 0x00111100 means we're drawing in octants 2-5
01227         drawoct = 0; 
01228 
01229         /*
01230         * Fixup angles
01231         */
01232         start %= 360;
01233         end %= 360;
01234         // 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
01235         while (start < 0) start += 360;
01236         while (end < 0) end += 360;
01237         start %= 360;
01238         end %= 360;
01239 
01240         // now, we find which octants we're drawing in.
01241         startoct = start / 45;
01242         endoct = end / 45;
01243         oct = startoct - 1; // we increment as first step in loop
01244 
01245         // stopval_start, stopval_end; 
01246         // what values of cx to stop at.
01247         do {
01248                 oct = (oct + 1) % 8;
01249 
01250                 if (oct == startoct) {
01251                         // need to compute stopval_start for this octant.  Look at picture above if this is unclear
01252                         dstart = (double)start;
01253                         switch (oct) 
01254                         {
01255                         case 0:
01256                         case 3:
01257                                 temp = sin(dstart * M_PI / 180.);
01258                                 break;
01259                         case 1:
01260                         case 6:
01261                                 temp = cos(dstart * M_PI / 180.);
01262                                 break;
01263                         case 2:
01264                         case 5:
01265                                 temp = -cos(dstart * M_PI / 180.);
01266                                 break;
01267                         case 4:
01268                         case 7:
01269                                 temp = -sin(dstart * M_PI / 180.);
01270                                 break;
01271                         }
01272                         temp *= rad;
01273                         stopval_start = (int)temp; // always round down
01274 
01275                         // This isn't arbitrary, but requires graph paper to explain well.
01276                         // The basic idea is that we're always changing drawoct after we draw, so we
01277                         // stop immediately after we render the last sensible pixel at x = ((int)temp).
01278 
01279                         // and whether to draw in this octant initially
01280                         if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
01281                         else             drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
01282                 }
01283                 if (oct == endoct) {
01284                         // need to compute stopval_end for this octant
01285                         dend = (double)end;
01286                         switch (oct)
01287                         {
01288                         case 0:
01289                         case 3:
01290                                 temp = sin(dend * M_PI / 180);
01291                                 break;
01292                         case 1:
01293                         case 6:
01294                                 temp = cos(dend * M_PI / 180);
01295                                 break;
01296                         case 2:
01297                         case 5:
01298                                 temp = -cos(dend * M_PI / 180);
01299                                 break;
01300                         case 4:
01301                         case 7:
01302                                 temp = -sin(dend * M_PI / 180);
01303                                 break;
01304                         }
01305                         temp *= rad;
01306                         stopval_end = (int)temp;
01307 
01308                         // and whether to draw in this octant initially
01309                         if (startoct == endoct) {
01310                                 // note:      we start drawing, stop, then start again in this case
01311                                 // otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
01312                                 if (start > end) {
01313                                         // unfortunately, if we're in the same octant and need to draw over the whole circle, 
01314                                         // we need to set the rest to true, because the while loop will end at the bottom.
01315                                         drawoct = 255;
01316                                 } else {
01317                                         drawoct &= 255 - (1 << oct);
01318                                 }
01319                         } 
01320                         else if (oct % 2) drawoct &= 255 - (1 << oct);
01321                         else                      drawoct |= (1 << oct);
01322                 } else if (oct != startoct) { // already verified that it's != endoct
01323                         drawoct |= (1 << oct); // draw this entire segment
01324                 }
01325         } while (oct != endoct);
01326 
01327         // so now we have what octants to draw and when to draw them. all that's left is the actual raster code.
01328 
01329         /*
01330         * Set color 
01331         */
01332         result = 0;
01333         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01334         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
01335 
01336         /*
01337         * Draw arc 
01338         */
01339         do {
01340                 ypcy = y + cy;
01341                 ymcy = y - cy;
01342                 if (cx > 0) {
01343                         xpcx = x + cx;
01344                         xmcx = x - cx;
01345 
01346                         // always check if we're drawing a certain octant before adding a pixel to that octant.
01347                         if (drawoct & 4)  result |= pixel(renderer, xmcx, ypcy);
01348                         if (drawoct & 2)  result |= pixel(renderer, xpcx, ypcy);
01349                         if (drawoct & 32) result |= pixel(renderer, xmcx, ymcy);
01350                         if (drawoct & 64) result |= pixel(renderer, xpcx, ymcy);
01351                 } else {
01352                         if (drawoct & 96) result |= pixel(renderer, x, ymcy);
01353                         if (drawoct & 6)  result |= pixel(renderer, x, ypcy);
01354                 }
01355 
01356                 xpcy = x + cy;
01357                 xmcy = x - cy;
01358                 if (cx > 0 && cx != cy) {
01359                         ypcx = y + cx;
01360                         ymcx = y - cx;
01361                         if (drawoct & 8)   result |= pixel(renderer, xmcy, ypcx);
01362                         if (drawoct & 1)   result |= pixel(renderer, xpcy, ypcx);
01363                         if (drawoct & 16)  result |= pixel(renderer, xmcy, ymcx);
01364                         if (drawoct & 128) result |= pixel(renderer, xpcy, ymcx);
01365                 } else if (cx == 0) {
01366                         if (drawoct & 24)  result |= pixel(renderer, xmcy, y);
01367                         if (drawoct & 129) result |= pixel(renderer, xpcy, y);
01368                 }
01369 
01370                 /*
01371                 * Update whether we're drawing an octant
01372                 */
01373                 if (stopval_start == cx) {
01374                         // works like an on-off switch.  
01375                         // This is just in case start & end are in the same octant.
01376                         if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);                
01377                         else                                               drawoct |= (1 << startoct);
01378                 }
01379                 if (stopval_end == cx) {
01380                         if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
01381                         else                                             drawoct |= (1 << endoct);
01382                 }
01383 
01384                 /*
01385                 * Update pixels
01386                 */
01387                 if (df < 0) {
01388                         df += d_e;
01389                         d_e += 2;
01390                         d_se += 2;
01391                 } else {
01392                         df += d_se;
01393                         d_e += 2;
01394                         d_se += 4;
01395                         cy--;
01396                 }
01397                 cx++;
01398         } while (cx <= cy);
01399 
01400         return (result);
01401 }
01402 
01403 /* ----- AA Circle */
01404 
01416 int aacircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
01417 {
01418         Uint8 *c = (Uint8 *)&color; 
01419         return aaellipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
01420 }
01421 
01436 int aacircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01437 {
01438         /*
01439         * Draw 
01440         */
01441         return aaellipseRGBA(renderer, x, y, rad, rad, r, g, b, a);
01442 }
01443 
01444 /* ----- Filled Circle */
01445 
01457 int filledCircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
01458 {
01459         Uint8 *c = (Uint8 *)&color; 
01460         return filledEllipseRGBA(renderer, x, y, rad, rad, c[0], c[1], c[2], c[3]);
01461 }
01462 
01477 int filledCircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01478 {
01479         int result;
01480         Sint16 cx = 0;
01481         Sint16 cy = rad;
01482         Sint16 ocx = (Sint16) 0xffff;
01483         Sint16 ocy = (Sint16) 0xffff;
01484         Sint16 df = 1 - rad;
01485         Sint16 d_e = 3;
01486         Sint16 d_se = -2 * rad + 5;
01487         Sint16 xpcx, xmcx, xpcy, xmcy;
01488         Sint16 ypcy, ymcy, ypcx, ymcx;
01489 
01490         /*
01491         * Sanity check radius 
01492         */
01493         if (rad < 0) {
01494                 return (-1);
01495         }
01496 
01497         /*
01498         * Special case for rad=0 - draw a point 
01499         */
01500         if (rad == 0) {
01501                 return (pixelRGBA(renderer, x, y, r, g, b, a));
01502         }
01503 
01504         /*
01505         * Set color
01506         */
01507         result = 0;
01508         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01509         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
01510 
01511         /*
01512         * Draw 
01513         */
01514         do {
01515                 xpcx = x + cx;
01516                 xmcx = x - cx;
01517                 xpcy = x + cy;
01518                 xmcy = x - cy;
01519                 if (ocy != cy) {
01520                         if (cy > 0) {
01521                                 ypcy = y + cy;
01522                                 ymcy = y - cy;
01523                                 result |= hline(renderer, xmcx, xpcx, ypcy);
01524                                 result |= hline(renderer, xmcx, xpcx, ymcy);
01525                         } else {
01526                                 result |= hline(renderer, xmcx, xpcx, y);
01527                         }
01528                         ocy = cy;
01529                 }
01530                 if (ocx != cx) {
01531                         if (cx != cy) {
01532                                 if (cx > 0) {
01533                                         ypcx = y + cx;
01534                                         ymcx = y - cx;
01535                                         result |= hline(renderer, xmcy, xpcy, ymcx);
01536                                         result |= hline(renderer, xmcy, xpcy, ypcx);
01537                                 } else {
01538                                         result |= hline(renderer, xmcy, xpcy, y);
01539                                 }
01540                         }
01541                         ocx = cx;
01542                 }
01543 
01544                 /*
01545                 * Update 
01546                 */
01547                 if (df < 0) {
01548                         df += d_e;
01549                         d_e += 2;
01550                         d_se += 2;
01551                 } else {
01552                         df += d_se;
01553                         d_e += 2;
01554                         d_se += 4;
01555                         cy--;
01556                 }
01557                 cx++;
01558         } while (cx <= cy);
01559 
01560         return (result);
01561 }
01562 
01563 /* ----- Ellipse */
01564 
01577 int ellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
01578 {
01579         Uint8 *c = (Uint8 *)&color; 
01580         return ellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
01581 }
01582 
01598 int ellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01599 {
01600         int result;
01601         int ix, iy;
01602         int h, i, j, k;
01603         int oh, oi, oj, ok;
01604         int xmh, xph, ypk, ymk;
01605         int xmi, xpi, ymj, ypj;
01606         int xmj, xpj, ymi, ypi;
01607         int xmk, xpk, ymh, yph;
01608 
01609         /*
01610         * Sanity check radii 
01611         */
01612         if ((rx < 0) || (ry < 0)) {
01613                 return (-1);
01614         }
01615 
01616         /*
01617         * Special case for rx=0 - draw a vline 
01618         */
01619         if (rx == 0) {
01620                 return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
01621         }
01622         /*
01623         * Special case for ry=0 - draw a hline 
01624         */
01625         if (ry == 0) {
01626                 return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
01627         }
01628 
01629         /*
01630         * Set color
01631         */
01632         result = 0;
01633         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01634         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
01635 
01636         /*
01637         * Init vars 
01638         */
01639         oh = oi = oj = ok = 0xFFFF;
01640 
01641         /*
01642         * Draw 
01643         */
01644         if (rx > ry) {
01645                 ix = 0;
01646                 iy = rx * 64;
01647 
01648                 do {
01649                         h = (ix + 32) >> 6;
01650                         i = (iy + 32) >> 6;
01651                         j = (h * ry) / rx;
01652                         k = (i * ry) / rx;
01653 
01654                         if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
01655                                 xph = x + h;
01656                                 xmh = x - h;
01657                                 if (k > 0) {
01658                                         ypk = y + k;
01659                                         ymk = y - k;
01660                                         result |= pixel(renderer, xmh, ypk);
01661                                         result |= pixel(renderer, xph, ypk);
01662                                         result |= pixel(renderer, xmh, ymk);
01663                                         result |= pixel(renderer, xph, ymk);
01664                                 } else {
01665                                         result |= pixel(renderer, xmh, y);
01666                                         result |= pixel(renderer, xph, y);
01667                                 }
01668                                 ok = k;
01669                                 xpi = x + i;
01670                                 xmi = x - i;
01671                                 if (j > 0) {
01672                                         ypj = y + j;
01673                                         ymj = y - j;
01674                                         result |= pixel(renderer, xmi, ypj);
01675                                         result |= pixel(renderer, xpi, ypj);
01676                                         result |= pixel(renderer, xmi, ymj);
01677                                         result |= pixel(renderer, xpi, ymj);
01678                                 } else {
01679                                         result |= pixel(renderer, xmi, y);
01680                                         result |= pixel(renderer, xpi, y);
01681                                 }
01682                                 oj = j;
01683                         }
01684 
01685                         ix = ix + iy / rx;
01686                         iy = iy - ix / rx;
01687 
01688                 } while (i > h);
01689         } else {
01690                 ix = 0;
01691                 iy = ry * 64;
01692 
01693                 do {
01694                         h = (ix + 32) >> 6;
01695                         i = (iy + 32) >> 6;
01696                         j = (h * rx) / ry;
01697                         k = (i * rx) / ry;
01698 
01699                         if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
01700                                 xmj = x - j;
01701                                 xpj = x + j;
01702                                 if (i > 0) {
01703                                         ypi = y + i;
01704                                         ymi = y - i;
01705                                         result |= pixel(renderer, xmj, ypi);
01706                                         result |= pixel(renderer, xpj, ypi);
01707                                         result |= pixel(renderer, xmj, ymi);
01708                                         result |= pixel(renderer, xpj, ymi);
01709                                 } else {
01710                                         result |= pixel(renderer, xmj, y);
01711                                         result |= pixel(renderer, xpj, y);
01712                                 }
01713                                 oi = i;
01714                                 xmk = x - k;
01715                                 xpk = x + k;
01716                                 if (h > 0) {
01717                                         yph = y + h;
01718                                         ymh = y - h;
01719                                         result |= pixel(renderer, xmk, yph);
01720                                         result |= pixel(renderer, xpk, yph);
01721                                         result |= pixel(renderer, xmk, ymh);
01722                                         result |= pixel(renderer, xpk, ymh);
01723                                 } else {
01724                                         result |= pixel(renderer, xmk, y);
01725                                         result |= pixel(renderer, xpk, y);
01726                                 }
01727                                 oh = h;
01728                         }
01729 
01730                         ix = ix + iy / ry;
01731                         iy = iy - ix / ry;
01732 
01733                 } while (i > h);
01734         }
01735 
01736         return (result);
01737 }
01738 
01739 /* ----- AA Ellipse */
01740 
01741 /* Windows targets do not have lrint, so provide a local inline version */
01742 #if defined(_MSC_VER)
01743 /* Detect 64bit and use intrinsic version */
01744 #ifdef _M_X64
01745 #include <emmintrin.h>
01746 static __inline long 
01747         lrint(float f) 
01748 {
01749         return _mm_cvtss_si32(_mm_load_ss(&f));
01750 }
01751 #elif defined(_M_IX86)
01752 __inline long int
01753         lrint (double flt)
01754 {       
01755         int intgr;
01756         _asm
01757         {
01758                 fld flt
01759                         fistp intgr
01760         };
01761         return intgr;
01762 }
01763 #elif defined(_M_ARM)
01764 #include <armintr.h>
01765 #pragma warning(push)
01766 #pragma warning(disable: 4716)
01767 __declspec(naked) long int
01768         lrint (double flt)
01769 {
01770         __emit(0xEC410B10); // fmdrr  d0, r0, r1
01771         __emit(0xEEBD0B40); // ftosid s0, d0
01772         __emit(0xEE100A10); // fmrs   r0, s0
01773         __emit(0xE12FFF1E); // bx     lr
01774 }
01775 #pragma warning(pop)
01776 #else
01777 #error lrint needed for MSVC on non X86/AMD64/ARM targets.
01778 #endif
01779 #endif
01780 
01793 int aaellipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
01794 {
01795         Uint8 *c = (Uint8 *)&color; 
01796         return aaellipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
01797 }
01798 
01814 int aaellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
01815 {
01816         int result;
01817         int i;
01818         int a2, b2, ds, dt, dxt, t, s, d;
01819         Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2;
01820         float cp;
01821         double sab;
01822         Uint8 weight, iweight;
01823 
01824         /*
01825         * Sanity check radii 
01826         */
01827         if ((rx < 0) || (ry < 0)) {
01828                 return (-1);
01829         }
01830 
01831         /*
01832         * Special case for rx=0 - draw a vline 
01833         */
01834         if (rx == 0) {
01835                 return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
01836         }
01837         /*
01838         * Special case for ry=0 - draw an hline 
01839         */
01840         if (ry == 0) {
01841                 return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
01842         }
01843 
01844         /* Variable setup */
01845         a2 = rx * rx;
01846         b2 = ry * ry;
01847 
01848         ds = 2 * a2;
01849         dt = 2 * b2;
01850 
01851         xc2 = 2 * x;
01852         yc2 = 2 * y;
01853 
01854         sab = sqrt((double)(a2 + b2));
01855         od = (Sint16)lrint(sab*0.01) + 1; /* introduce some overdraw */
01856         dxt = (Sint16)lrint((double)a2 / sab) + od;
01857 
01858         t = 0;
01859         s = -2 * a2 * ry;
01860         d = 0;
01861 
01862         xp = x;
01863         yp = y - ry;
01864 
01865         /* Draw */
01866         result = 0;
01867         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
01868 
01869         /* "End points" */
01870         result |= pixelRGBA(renderer, xp, yp, r, g, b, a);
01871         result |= pixelRGBA(renderer, xc2 - xp, yp, r, g, b, a);
01872         result |= pixelRGBA(renderer, xp, yc2 - yp, r, g, b, a);
01873         result |= pixelRGBA(renderer, xc2 - xp, yc2 - yp, r, g, b, a);
01874 
01875         for (i = 1; i <= dxt; i++) {
01876                 xp--;
01877                 d += t - b2;
01878 
01879                 if (d >= 0)
01880                         ys = yp - 1;
01881                 else if ((d - s - a2) > 0) {
01882                         if ((2 * d - s - a2) >= 0)
01883                                 ys = yp + 1;
01884                         else {
01885                                 ys = yp;
01886                                 yp++;
01887                                 d -= s + a2;
01888                                 s += ds;
01889                         }
01890                 } else {
01891                         yp++;
01892                         ys = yp + 1;
01893                         d -= s + a2;
01894                         s += ds;
01895                 }
01896 
01897                 t -= dt;
01898 
01899                 /* Calculate alpha */
01900                 if (s != 0) {
01901                         cp = (float) abs(d) / (float) abs(s);
01902                         if (cp > 1.0) {
01903                                 cp = 1.0;
01904                         }
01905                 } else {
01906                         cp = 1.0;
01907                 }
01908 
01909                 /* Calculate weights */
01910                 weight = (Uint8) (cp * 255);
01911                 iweight = 255 - weight;
01912 
01913                 /* Upper half */
01914                 xx = xc2 - xp;
01915                 result |= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
01916                 result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
01917 
01918                 result |= pixelRGBAWeight(renderer, xp, ys, r, g, b, a, weight);
01919                 result |= pixelRGBAWeight(renderer, xx, ys, r, g, b, a, weight);
01920 
01921                 /* Lower half */
01922                 yy = yc2 - yp;
01923                 result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
01924                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
01925 
01926                 yy = yc2 - ys;
01927                 result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, weight);
01928                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);
01929         }
01930 
01931         /* Replaces original approximation code dyt = abs(yp - yc); */
01932         dyt = (Sint16)lrint((double)b2 / sab ) + od;    
01933 
01934         for (i = 1; i <= dyt; i++) {
01935                 yp++;
01936                 d -= s + a2;
01937 
01938                 if (d <= 0)
01939                         xs = xp + 1;
01940                 else if ((d + t - b2) < 0) {
01941                         if ((2 * d + t - b2) <= 0)
01942                                 xs = xp - 1;
01943                         else {
01944                                 xs = xp;
01945                                 xp--;
01946                                 d += t - b2;
01947                                 t -= dt;
01948                         }
01949                 } else {
01950                         xp--;
01951                         xs = xp - 1;
01952                         d += t - b2;
01953                         t -= dt;
01954                 }
01955 
01956                 s += ds;
01957 
01958                 /* Calculate alpha */
01959                 if (t != 0) {
01960                         cp = (float) abs(d) / (float) abs(t);
01961                         if (cp > 1.0) {
01962                                 cp = 1.0;
01963                         }
01964                 } else {
01965                         cp = 1.0;
01966                 }
01967 
01968                 /* Calculate weight */
01969                 weight = (Uint8) (cp * 255);
01970                 iweight = 255 - weight;
01971 
01972                 /* Left half */
01973                 xx = xc2 - xp;
01974                 yy = yc2 - yp;
01975                 result |= pixelRGBAWeight(renderer, xp, yp, r, g, b, a, iweight);
01976                 result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, iweight);
01977 
01978                 result |= pixelRGBAWeight(renderer, xp, yy, r, g, b, a, iweight);
01979                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, iweight);
01980 
01981                 /* Right half */
01982                 xx = xc2 - xs;
01983                 result |= pixelRGBAWeight(renderer, xs, yp, r, g, b, a, weight);
01984                 result |= pixelRGBAWeight(renderer, xx, yp, r, g, b, a, weight);
01985 
01986                 result |= pixelRGBAWeight(renderer, xs, yy, r, g, b, a, weight);
01987                 result |= pixelRGBAWeight(renderer, xx, yy, r, g, b, a, weight);                
01988         }
01989 
01990         return (result);
01991 }
01992 
01993 /* ---- Filled Ellipse */
01994 
02007 int filledEllipseColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
02008 {
02009         Uint8 *c = (Uint8 *)&color; 
02010         return filledEllipseRGBA(renderer, x, y, rx, ry, c[0], c[1], c[2], c[3]);
02011 }
02012 
02028 int filledEllipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02029 {
02030         int result;
02031         int ix, iy;
02032         int h, i, j, k;
02033         int oh, oi, oj, ok;
02034         int xmh, xph;
02035         int xmi, xpi;
02036         int xmj, xpj;
02037         int xmk, xpk;
02038 
02039         /*
02040         * Sanity check radii 
02041         */
02042         if ((rx < 0) || (ry < 0)) {
02043                 return (-1);
02044         }
02045 
02046         /*
02047         * Special case for rx=0 - draw a vline 
02048         */
02049         if (rx == 0) {
02050                 return (vlineRGBA(renderer, x, y - ry, y + ry, r, g, b, a));
02051         }
02052         /*
02053         * Special case for ry=0 - draw a hline 
02054         */
02055         if (ry == 0) {
02056                 return (hlineRGBA(renderer, x - rx, x + rx, y, r, g, b, a));
02057         }
02058 
02059         /*
02060         * Set color
02061         */
02062         result = 0;
02063         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
02064         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
02065 
02066         /*
02067         * Init vars 
02068         */
02069         oh = oi = oj = ok = 0xFFFF;
02070 
02071         /*
02072         * Draw 
02073         */
02074         if (rx > ry) {
02075                 ix = 0;
02076                 iy = rx * 64;
02077 
02078                 do {
02079                         h = (ix + 32) >> 6;
02080                         i = (iy + 32) >> 6;
02081                         j = (h * ry) / rx;
02082                         k = (i * ry) / rx;
02083 
02084                         if ((ok != k) && (oj != k)) {
02085                                 xph = x + h;
02086                                 xmh = x - h;
02087                                 if (k > 0) {
02088                                         result |= hline(renderer, xmh, xph, y + k);
02089                                         result |= hline(renderer, xmh, xph, y - k);
02090                                 } else {
02091                                         result |= hline(renderer, xmh, xph, y);
02092                                 }
02093                                 ok = k;
02094                         }
02095                         if ((oj != j) && (ok != j) && (k != j)) {
02096                                 xmi = x - i;
02097                                 xpi = x + i;
02098                                 if (j > 0) {
02099                                         result |= hline(renderer, xmi, xpi, y + j);
02100                                         result |= hline(renderer, xmi, xpi, y - j);
02101                                 } else {
02102                                         result |= hline(renderer, xmi, xpi, y);
02103                                 }
02104                                 oj = j;
02105                         }
02106 
02107                         ix = ix + iy / rx;
02108                         iy = iy - ix / rx;
02109 
02110                 } while (i > h);
02111         } else {
02112                 ix = 0;
02113                 iy = ry * 64;
02114 
02115                 do {
02116                         h = (ix + 32) >> 6;
02117                         i = (iy + 32) >> 6;
02118                         j = (h * rx) / ry;
02119                         k = (i * rx) / ry;
02120 
02121                         if ((oi != i) && (oh != i)) {
02122                                 xmj = x - j;
02123                                 xpj = x + j;
02124                                 if (i > 0) {
02125                                         result |= hline(renderer, xmj, xpj, y + i);
02126                                         result |= hline(renderer, xmj, xpj, y - i);
02127                                 } else {
02128                                         result |= hline(renderer, xmj, xpj, y);
02129                                 }
02130                                 oi = i;
02131                         }
02132                         if ((oh != h) && (oi != h) && (i != h)) {
02133                                 xmk = x - k;
02134                                 xpk = x + k;
02135                                 if (h > 0) {
02136                                         result |= hline(renderer, xmk, xpk, y + h);
02137                                         result |= hline(renderer, xmk, xpk, y - h);
02138                                 } else {
02139                                         result |= hline(renderer, xmk, xpk, y);
02140                                 }
02141                                 oh = h;
02142                         }
02143 
02144                         ix = ix + iy / ry;
02145                         iy = iy - ix / ry;
02146 
02147                 } while (i > h);
02148         }
02149 
02150         return (result);
02151 }
02152 
02153 /* ----- Pie */
02154 
02174 /* TODO: rewrite algorithm; pie is not always accurate */
02175 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)
02176 {
02177         int result;
02178         double angle, start_angle, end_angle;
02179         double deltaAngle;
02180         double dr;
02181         int numpoints, i;
02182         Sint16 *vx, *vy;
02183 
02184         /*
02185         * Sanity check radii 
02186         */
02187         if (rad < 0) {
02188                 return (-1);
02189         }
02190 
02191         /*
02192         * Fixup angles
02193         */
02194         start = start % 360;
02195         end = end % 360;
02196 
02197         /*
02198         * Special case for rad=0 - draw a point 
02199         */
02200         if (rad == 0) {
02201                 return (pixelRGBA(renderer, x, y, r, g, b, a));
02202         }
02203 
02204         /*
02205         * Variable setup 
02206         */
02207         dr = (double) rad;
02208         deltaAngle = 3.0 / dr;
02209         start_angle = (double) start *(2.0 * M_PI / 360.0);
02210         end_angle = (double) end *(2.0 * M_PI / 360.0);
02211         if (start > end) {
02212                 end_angle += (2.0 * M_PI);
02213         }
02214 
02215         /* We will always have at least 2 points */
02216         numpoints = 2;
02217 
02218         /* Count points (rather than calculating it) */
02219         angle = start_angle;
02220         while (angle < end_angle) {
02221                 angle += deltaAngle;
02222                 numpoints++;
02223         }
02224 
02225         /* Allocate combined vertex array */
02226         vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
02227         if (vx == NULL) {
02228                 return (-1);
02229         }
02230 
02231         /* Update point to start of vy */
02232         vy += numpoints;
02233 
02234         /* Center */
02235         vx[0] = x;
02236         vy[0] = y;
02237 
02238         /* First vertex */
02239         angle = start_angle;
02240         vx[1] = x + (int) (dr * cos(angle));
02241         vy[1] = y + (int) (dr * sin(angle));
02242 
02243         if (numpoints<3)
02244         {
02245                 result = lineRGBA(renderer, vx[0], vy[0], vx[1], vy[1], r, g, b, a);
02246         }
02247         else
02248         {
02249                 /* Calculate other vertices */
02250                 i = 2;
02251                 angle = start_angle;
02252                 while (angle < end_angle) {
02253                         angle += deltaAngle;
02254                         if (angle>end_angle)
02255                         {
02256                                 angle = end_angle;
02257                         }
02258                         vx[i] = x + (int) (dr * cos(angle));
02259                         vy[i] = y + (int) (dr * sin(angle));
02260                         i++;
02261                 }
02262 
02263                 /* Draw */
02264                 if (filled) {
02265                         result = filledPolygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
02266                 } else {
02267                         result = polygonRGBA(renderer, vx, vy, numpoints, r, g, b, a);
02268                 }
02269         }
02270 
02271         /* Free combined vertex array */
02272         free(vx);
02273 
02274         return (result);
02275 }
02276 
02290 int pieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, 
02291         Sint16 start, Sint16 end, Uint32 color) 
02292 {
02293         Uint8 *c = (Uint8 *)&color; 
02294         return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 0);
02295 }
02296 
02313 int pieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
02314         Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02315 {
02316         return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 0);
02317 }
02318 
02332 int filledPieColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
02333 {
02334         Uint8 *c = (Uint8 *)&color; 
02335         return _pieRGBA(renderer, x, y, rad, start, end, c[0], c[1], c[2], c[3], 1);
02336 }
02337 
02354 int filledPieRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad,
02355         Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02356 {
02357         return _pieRGBA(renderer, x, y, rad, start, end, r, g, b, a, 1);
02358 }
02359 
02360 /* ------ Trigon */
02361 
02378 int trigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
02379 {
02380         Sint16 vx[3]; 
02381         Sint16 vy[3];
02382 
02383         vx[0]=x1;
02384         vx[1]=x2;
02385         vx[2]=x3;
02386         vy[0]=y1;
02387         vy[1]=y2;
02388         vy[2]=y3;
02389 
02390         return(polygonColor(renderer,vx,vy,3,color));
02391 }
02392 
02410 int trigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
02411         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02412 {
02413         Sint16 vx[3]; 
02414         Sint16 vy[3];
02415 
02416         vx[0]=x1;
02417         vx[1]=x2;
02418         vx[2]=x3;
02419         vy[0]=y1;
02420         vy[1]=y2;
02421         vy[2]=y3;
02422 
02423         return(polygonRGBA(renderer,vx,vy,3,r,g,b,a));
02424 }                                
02425 
02426 /* ------ AA-Trigon */
02427 
02444 int aatrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
02445 {
02446         Sint16 vx[3]; 
02447         Sint16 vy[3];
02448 
02449         vx[0]=x1;
02450         vx[1]=x2;
02451         vx[2]=x3;
02452         vy[0]=y1;
02453         vy[1]=y2;
02454         vy[2]=y3;
02455 
02456         return(aapolygonColor(renderer,vx,vy,3,color));
02457 }
02458 
02476 int aatrigonRGBA(SDL_Renderer * renderer,  Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
02477         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02478 {
02479         Sint16 vx[3]; 
02480         Sint16 vy[3];
02481 
02482         vx[0]=x1;
02483         vx[1]=x2;
02484         vx[2]=x3;
02485         vy[0]=y1;
02486         vy[1]=y2;
02487         vy[2]=y3;
02488 
02489         return(aapolygonRGBA(renderer,vx,vy,3,r,g,b,a));
02490 }                                  
02491 
02492 /* ------ Filled Trigon */
02493 
02510 int filledTrigonColor(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
02511 {
02512         Sint16 vx[3]; 
02513         Sint16 vy[3];
02514 
02515         vx[0]=x1;
02516         vx[1]=x2;
02517         vx[2]=x3;
02518         vy[0]=y1;
02519         vy[1]=y2;
02520         vy[2]=y3;
02521 
02522         return(filledPolygonColor(renderer,vx,vy,3,color));
02523 }
02524 
02544 int filledTrigonRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
02545         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02546 {
02547         Sint16 vx[3]; 
02548         Sint16 vy[3];
02549 
02550         vx[0]=x1;
02551         vx[1]=x2;
02552         vx[2]=x3;
02553         vy[0]=y1;
02554         vy[1]=y2;
02555         vy[2]=y3;
02556 
02557         return(filledPolygonRGBA(renderer,vx,vy,3,r,g,b,a));
02558 }
02559 
02560 /* ---- Polygon */
02561 
02573 int polygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
02574 {
02575         Uint8 *c = (Uint8 *)&color; 
02576         return polygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
02577 }
02578 
02589 int polygon(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n)
02590 {
02591         /*
02592         * Draw 
02593         */
02594         int result;
02595         int i, nn;
02596         SDL_Point* points;
02597 
02598         /*
02599         * Vertex array NULL check 
02600         */
02601         if (vx == NULL) {
02602                 return (-1);
02603         }
02604         if (vy == NULL) {
02605                 return (-1);
02606         }
02607 
02608         /*
02609         * Sanity check 
02610         */
02611         if (n < 3) {
02612                 return (-1);
02613         }
02614 
02615         /*
02616         * Create array of points
02617         */
02618         nn = n + 1;
02619         points = (SDL_Point*)malloc(sizeof(SDL_Point) * nn);
02620         if (points == NULL)
02621         {
02622                 return -1;
02623         }
02624         for (i=0; i<n; i++)
02625         {
02626                 points[i].x = vx[i];
02627                 points[i].y = vy[i];
02628         }
02629         points[n].x = vx[0];
02630         points[n].y = vy[0];
02631 
02632         /*
02633         * Draw 
02634         */
02635         result |= SDL_RenderDrawLines(renderer, points, nn);
02636         free(points);
02637 
02638         return (result);
02639 }
02640 
02655 int polygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02656 {
02657         /*
02658         * Draw 
02659         */
02660         int result;
02661         const Sint16 *x1, *y1, *x2, *y2;
02662 
02663         /*
02664         * Vertex array NULL check 
02665         */
02666         if (vx == NULL) {
02667                 return (-1);
02668         }
02669         if (vy == NULL) {
02670                 return (-1);
02671         }
02672 
02673         /*
02674         * Sanity check 
02675         */
02676         if (n < 3) {
02677                 return (-1);
02678         }
02679 
02680         /*
02681         * Pointer setup 
02682         */
02683         x1 = x2 = vx;
02684         y1 = y2 = vy;
02685         x2++;
02686         y2++;
02687 
02688         /*
02689         * Set color 
02690         */
02691         result = 0;
02692         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
02693         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
02694 
02695         /*
02696         * Draw 
02697         */
02698         result |= polygon(renderer, vx, vy, n);
02699 
02700         return (result);
02701 }
02702 
02703 /* ---- AA-Polygon */
02704 
02716 int aapolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
02717 {
02718         Uint8 *c = (Uint8 *)&color; 
02719         return aapolygonRGBA(renderer, vx, vy, n, c[0], c[1], c[2], c[3]);
02720 }
02721 
02736 int aapolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
02737 {
02738         int result;
02739         int i;
02740         const Sint16 *x1, *y1, *x2, *y2;
02741 
02742         /*
02743         * Vertex array NULL check 
02744         */
02745         if (vx == NULL) {
02746                 return (-1);
02747         }
02748         if (vy == NULL) {
02749                 return (-1);
02750         }
02751 
02752         /*
02753         * Sanity check 
02754         */
02755         if (n < 3) {
02756                 return (-1);
02757         }
02758 
02759         /*
02760         * Pointer setup 
02761         */
02762         x1 = x2 = vx;
02763         y1 = y2 = vy;
02764         x2++;
02765         y2++;
02766 
02767         /*
02768         * Draw 
02769         */
02770         result = 0;
02771         for (i = 1; i < n; i++) {
02772                 result |= _aalineRGBA(renderer, *x1, *y1, *x2, *y2, r, g, b, a, 0);
02773                 x1 = x2;
02774                 y1 = y2;
02775                 x2++;
02776                 y2++;
02777         }
02778 
02779         result |= _aalineRGBA(renderer, *x1, *y1, *vx, *vy, r, g, b, a, 0);
02780 
02781         return (result);
02782 }
02783 
02784 /* ---- Filled Polygon */
02785 
02794 int _gfxPrimitivesCompareInt(const void *a, const void *b)
02795 {
02796         return (*(const int *) a) - (*(const int *) b);
02797 }
02798 
02804 static int *gfxPrimitivesPolyIntsGlobal = NULL;
02805 
02811 static int gfxPrimitivesPolyAllocatedGlobal = 0;
02812 
02831 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)
02832 {
02833         int result;
02834         int i;
02835         int y, xa, xb;
02836         int miny, maxy;
02837         int x1, y1;
02838         int x2, y2;
02839         int ind1, ind2;
02840         int ints;
02841         int *gfxPrimitivesPolyInts = NULL;
02842         int *gfxPrimitivesPolyIntsNew = NULL;
02843         int gfxPrimitivesPolyAllocated = 0;
02844 
02845         /*
02846         * Vertex array NULL check 
02847         */
02848         if (vx == NULL) {
02849                 return (-1);
02850         }
02851         if (vy == NULL) {
02852                 return (-1);
02853         }
02854 
02855         /*
02856         * Sanity check number of edges
02857         */
02858         if (n < 3) {
02859                 return -1;
02860         }
02861 
02862         /*
02863         * Map polygon cache  
02864         */
02865         if ((polyInts==NULL) || (polyAllocated==NULL)) {
02866                 /* Use global cache */
02867                 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
02868                 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
02869         } else {
02870                 /* Use local cache */
02871                 gfxPrimitivesPolyInts = *polyInts;
02872                 gfxPrimitivesPolyAllocated = *polyAllocated;
02873         }
02874 
02875         /*
02876         * Allocate temp array, only grow array 
02877         */
02878         if (!gfxPrimitivesPolyAllocated) {
02879                 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
02880                 gfxPrimitivesPolyAllocated = n;
02881         } else {
02882                 if (gfxPrimitivesPolyAllocated < n) {
02883                         gfxPrimitivesPolyIntsNew = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
02884                         if (!gfxPrimitivesPolyIntsNew) {
02885                                 if (!gfxPrimitivesPolyInts) {
02886                                         free(gfxPrimitivesPolyInts);
02887                                         gfxPrimitivesPolyInts = NULL;
02888                                 }
02889                                 gfxPrimitivesPolyAllocated = 0;
02890                         } else {
02891                                 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsNew;
02892                                 gfxPrimitivesPolyAllocated = n;
02893                         }
02894                 }
02895         }
02896 
02897         /*
02898         * Check temp array
02899         */
02900         if (gfxPrimitivesPolyInts==NULL) {        
02901                 gfxPrimitivesPolyAllocated = 0;
02902         }
02903 
02904         /*
02905         * Update cache variables
02906         */
02907         if ((polyInts==NULL) || (polyAllocated==NULL)) { 
02908                 gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
02909                 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
02910         } else {
02911                 *polyInts = gfxPrimitivesPolyInts;
02912                 *polyAllocated = gfxPrimitivesPolyAllocated;
02913         }
02914 
02915         /*
02916         * Check temp array again
02917         */
02918         if (gfxPrimitivesPolyInts==NULL) {        
02919                 return(-1);
02920         }
02921 
02922         /*
02923         * Determine Y maxima 
02924         */
02925         miny = vy[0];
02926         maxy = vy[0];
02927         for (i = 1; (i < n); i++) {
02928                 if (vy[i] < miny) {
02929                         miny = vy[i];
02930                 } else if (vy[i] > maxy) {
02931                         maxy = vy[i];
02932                 }
02933         }
02934 
02935         /*
02936         * Draw, scanning y 
02937         */
02938         result = 0;
02939         for (y = miny; (y <= maxy); y++) {
02940                 ints = 0;
02941                 for (i = 0; (i < n); i++) {
02942                         if (!i) {
02943                                 ind1 = n - 1;
02944                                 ind2 = 0;
02945                         } else {
02946                                 ind1 = i - 1;
02947                                 ind2 = i;
02948                         }
02949                         y1 = vy[ind1];
02950                         y2 = vy[ind2];
02951                         if (y1 < y2) {
02952                                 x1 = vx[ind1];
02953                                 x2 = vx[ind2];
02954                         } else if (y1 > y2) {
02955                                 y2 = vy[ind1];
02956                                 y1 = vy[ind2];
02957                                 x2 = vx[ind1];
02958                                 x1 = vx[ind2];
02959                         } else {
02960                                 continue;
02961                         }
02962                         if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
02963                                 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
02964                         }           
02965                 }
02966 
02967                 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
02968 
02969                 /*
02970                 * Set color 
02971                 */
02972                 result = 0;
02973             result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
02974                 result |= SDL_SetRenderDrawColor(renderer, r, g, b, a); 
02975 
02976                 for (i = 0; (i < ints); i += 2) {
02977                         xa = gfxPrimitivesPolyInts[i] + 1;
02978                         xa = (xa >> 16) + ((xa & 32768) >> 15);
02979                         xb = gfxPrimitivesPolyInts[i+1] - 1;
02980                         xb = (xb >> 16) + ((xb & 32768) >> 15);
02981                         result |= hline(renderer, xa, xb, y);
02982                 }
02983         }
02984 
02985         return (result);
02986 }
02987 
02999 int filledPolygonColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
03000 {
03001         Uint8 *c = (Uint8 *)&color; 
03002         return filledPolygonRGBAMT(renderer, vx, vy, n, c[0], c[1], c[2], c[3], NULL, NULL);
03003 }
03004 
03019 int filledPolygonRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
03020 {
03021         return filledPolygonRGBAMT(renderer, vx, vy, n, r, g, b, a, NULL, NULL);
03022 }
03023 
03024 /* ---- Textured Polygon */
03025 
03041 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)
03042 {
03043         Sint16 w;
03044         Sint16 xtmp;
03045         int result = 0;
03046         int texture_x_walker;    
03047         int texture_y_start;    
03048         SDL_Rect source_rect,dst_rect;
03049         int pixels_written,write_width;
03050 
03051         /*
03052         * Swap x1, x2 if required to ensure x1<=x2
03053         */
03054         if (x1 > x2) {
03055                 xtmp = x1;
03056                 x1 = x2;
03057                 x2 = xtmp;
03058         }
03059 
03060         /*
03061         * Calculate width to draw
03062         */
03063         w = x2 - x1 + 1;
03064 
03065         /*
03066         * Determine where in the texture we start drawing
03067         */
03068         texture_x_walker =   (x1 - texture_dx)  % texture_w;
03069         if (texture_x_walker < 0){
03070                 texture_x_walker = texture_w + texture_x_walker ;
03071         }
03072 
03073         texture_y_start = (y + texture_dy) % texture_h;
03074         if (texture_y_start < 0){
03075                 texture_y_start = texture_h + texture_y_start;
03076         }
03077 
03078         // setup the source rectangle; we are only drawing one horizontal line
03079         source_rect.y = texture_y_start;
03080         source_rect.x = texture_x_walker;
03081         source_rect.h = 1;
03082 
03083         // we will draw to the current y
03084         dst_rect.y = y;
03085         dst_rect.h = 1;
03086 
03087         // if there are enough pixels left in the current row of the texture
03088         // draw it all at once
03089         if (w <= texture_w -texture_x_walker){
03090                 source_rect.w = w;
03091                 source_rect.x = texture_x_walker;
03092                 dst_rect.x= x1;
03093                 dst_rect.w = source_rect.w;
03094                 result = (SDL_RenderCopy(renderer, texture, &source_rect, &dst_rect) == 0);
03095         } else { 
03096                 // we need to draw multiple times
03097                 // draw the first segment
03098                 pixels_written = texture_w  - texture_x_walker;
03099                 source_rect.w = pixels_written;
03100                 source_rect.x = texture_x_walker;
03101                 dst_rect.x= x1;
03102                 dst_rect.w = source_rect.w;
03103                 result |= (SDL_RenderCopy(renderer, texture, &source_rect, &dst_rect) == 0);
03104                 write_width = texture_w;
03105 
03106                 // now draw the rest
03107                 // set the source x to 0
03108                 source_rect.x = 0;
03109                 while (pixels_written < w){
03110                         if (write_width >= w - pixels_written) {
03111                                 write_width =  w - pixels_written;
03112                         }
03113                         source_rect.w = write_width;
03114                         dst_rect.x = x1 + pixels_written;
03115                         dst_rect.w = source_rect.w;
03116                         result |= (SDL_RenderCopy(renderer, texture, &source_rect, &dst_rect) == 0);
03117                         pixels_written += write_width;
03118                 }
03119         }
03120 
03121         return result;
03122 }
03123 
03140 int texturedPolygonMT(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n, 
03141         SDL_Surface * texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated)
03142 {
03143         int result;
03144         int i;
03145         int y, xa, xb;
03146         int minx,maxx,miny, maxy;
03147         int x1, y1;
03148         int x2, y2;
03149         int ind1, ind2;
03150         int ints;
03151         int *gfxPrimitivesPolyInts = NULL;
03152         int gfxPrimitivesPolyAllocated = 0;
03153         SDL_Texture *textureAsTexture = NULL;
03154 
03155         /*
03156         * Sanity check number of edges
03157         */
03158         if (n < 3) {
03159                 return -1;
03160         }
03161 
03162         /*
03163         * Map polygon cache  
03164         */
03165         if ((polyInts==NULL) || (polyAllocated==NULL)) {
03166                 /* Use global cache */
03167                 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
03168                 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
03169         } else {
03170                 /* Use local cache */
03171                 gfxPrimitivesPolyInts = *polyInts;
03172                 gfxPrimitivesPolyAllocated = *polyAllocated;
03173         }
03174 
03175         /*
03176         * Allocate temp array, only grow array 
03177         */
03178         if (!gfxPrimitivesPolyAllocated) {
03179                 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
03180                 gfxPrimitivesPolyAllocated = n;
03181         } else {
03182                 if (gfxPrimitivesPolyAllocated < n) {
03183                         gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
03184                         gfxPrimitivesPolyAllocated = n;
03185                 }
03186         }
03187 
03188         /*
03189         * Check temp array
03190         */
03191         if (gfxPrimitivesPolyInts==NULL) {        
03192                 gfxPrimitivesPolyAllocated = 0;
03193         }
03194 
03195         /*
03196         * Update cache variables
03197         */
03198         if ((polyInts==NULL) || (polyAllocated==NULL)) { 
03199                 gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
03200                 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
03201         } else {
03202                 *polyInts = gfxPrimitivesPolyInts;
03203                 *polyAllocated = gfxPrimitivesPolyAllocated;
03204         }
03205 
03206         /*
03207         * Check temp array again
03208         */
03209         if (gfxPrimitivesPolyInts==NULL) {        
03210                 return(-1);
03211         }
03212 
03213         /*
03214         * Determine X,Y minima,maxima 
03215         */
03216         miny = vy[0];
03217         maxy = vy[0];
03218         minx = vx[0];
03219         maxx = vx[0];
03220         for (i = 1; (i < n); i++) {
03221                 if (vy[i] < miny) {
03222                         miny = vy[i];
03223                 } else if (vy[i] > maxy) {
03224                         maxy = vy[i];
03225                 }
03226                 if (vx[i] < minx) {
03227                         minx = vx[i];
03228                 } else if (vx[i] > maxx) {
03229                         maxx = vx[i];
03230                 }
03231         }
03232 
03233     /* Create texture for drawing */
03234         textureAsTexture = SDL_CreateTextureFromSurface(renderer, texture);
03235         if (textureAsTexture == NULL)
03236         {
03237                 return -1;
03238         }
03239         SDL_SetTextureBlendMode(textureAsTexture, SDL_BLENDMODE_BLEND);
03240         
03241         /*
03242         * Draw, scanning y 
03243         */
03244         result = 0;
03245         for (y = miny; (y <= maxy); y++) {
03246                 ints = 0;
03247                 for (i = 0; (i < n); i++) {
03248                         if (!i) {
03249                                 ind1 = n - 1;
03250                                 ind2 = 0;
03251                         } else {
03252                                 ind1 = i - 1;
03253                                 ind2 = i;
03254                         }
03255                         y1 = vy[ind1];
03256                         y2 = vy[ind2];
03257                         if (y1 < y2) {
03258                                 x1 = vx[ind1];
03259                                 x2 = vx[ind2];
03260                         } else if (y1 > y2) {
03261                                 y2 = vy[ind1];
03262                                 y1 = vy[ind2];
03263                                 x2 = vx[ind1];
03264                                 x1 = vx[ind2];
03265                         } else {
03266                                 continue;
03267                         }
03268                         if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
03269                                 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
03270                         } 
03271                 }
03272 
03273                 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
03274 
03275                 for (i = 0; (i < ints); i += 2) {
03276                         xa = gfxPrimitivesPolyInts[i] + 1;
03277                         xa = (xa >> 16) + ((xa & 32768) >> 15);
03278                         xb = gfxPrimitivesPolyInts[i+1] - 1;
03279                         xb = (xb >> 16) + ((xb & 32768) >> 15);
03280                         result |= _HLineTextured(renderer, xa, xb, y, textureAsTexture, texture->w, texture->h, texture_dx, texture_dy);
03281                 }
03282         }
03283 
03284         SDL_RenderPresent(renderer);
03285         SDL_DestroyTexture(textureAsTexture);
03286 
03287         return (result);
03288 }
03289 
03306 int texturedPolygon(SDL_Renderer *renderer, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
03307 {
03308         /*
03309         * Draw
03310         */
03311         return (texturedPolygonMT(renderer, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
03312 }
03313 
03314 /* ---- Character */
03315 
03319 static SDL_Texture *gfxPrimitivesFont[256];
03320 
03324 static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
03325 
03329 static Uint32 charWidth = 8;
03330 
03334 static Uint32 charHeight = 8;
03335 
03339 static Uint32 charWidthLocal = 8;
03340 
03344 static Uint32 charHeightLocal = 8;
03345 
03349 static Uint32 charPitch = 1;
03350 
03354 static Uint32 charRotation = 0;
03355 
03359 static Uint32 charSize = 8;
03360 
03374 void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch)
03375 {
03376         int i;
03377 
03378         if ((fontdata) && (cw) && (ch)) {
03379                 currentFontdata = (unsigned char *)fontdata;
03380                 charWidth = cw;
03381                 charHeight = ch;
03382         } else {
03383                 currentFontdata = gfxPrimitivesFontdata;
03384                 charWidth = 8;
03385                 charHeight = 8;
03386         }
03387 
03388         charPitch = (charWidth+7)/8;
03389         charSize = charPitch * charHeight;
03390 
03391         /* Maybe flip width/height for rendering */
03392         if ((charRotation==1) || (charRotation==3))
03393         {
03394                 charWidthLocal = charHeight;
03395                 charHeightLocal = charWidth;
03396         }
03397         else
03398         {
03399                 charWidthLocal = charWidth;
03400                 charHeightLocal = charHeight;
03401         }
03402 
03403         /* Clear character cache */
03404         for (i = 0; i < 256; i++) {
03405                 if (gfxPrimitivesFont[i]) {
03406                         SDL_DestroyTexture(gfxPrimitivesFont[i]);
03407                         gfxPrimitivesFont[i] = NULL;
03408                 }
03409         }
03410 }
03411 
03420 void gfxPrimitivesSetFontRotation(Uint32 rotation)
03421 {
03422         int i;
03423 
03424         rotation = rotation & 3;
03425         if (charRotation != rotation)
03426         {
03427                 /* Store rotation */
03428                 charRotation = rotation;
03429 
03430                 /* Maybe flip width/height for rendering */
03431                 if ((charRotation==1) || (charRotation==3))
03432                 {
03433                         charWidthLocal = charHeight;
03434                         charHeightLocal = charWidth;
03435                 }
03436                 else
03437                 {
03438                         charWidthLocal = charWidth;
03439                         charHeightLocal = charHeight;
03440                 }
03441 
03442                 /* Clear character cache */
03443                 for (i = 0; i < 256; i++) {
03444                         if (gfxPrimitivesFont[i]) {
03445                                 SDL_DestroyTexture(gfxPrimitivesFont[i]);
03446                                 gfxPrimitivesFont[i] = NULL;
03447                         }
03448                 }
03449         }
03450 }
03451 
03466 int characterRGBA(SDL_Renderer *renderer, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
03467 {
03468         SDL_Rect srect;
03469         SDL_Rect drect;
03470         int result;
03471         Uint32 ix, iy;
03472         const unsigned char *charpos;
03473         Uint8 *curpos;
03474         Uint8 patt, mask;
03475         Uint8 *linepos;
03476         Uint32 pitch;
03477         SDL_Surface *character;
03478         SDL_Surface *rotatedCharacter;
03479         Uint32 ci;
03480 
03481         /*
03482         * Setup source rectangle
03483         */
03484         srect.x = 0;
03485         srect.y = 0;
03486         srect.w = charWidthLocal;
03487         srect.h = charHeightLocal;
03488 
03489         /*
03490         * Setup destination rectangle
03491         */
03492         drect.x = x;
03493         drect.y = y;
03494         drect.w = charWidthLocal;
03495         drect.h = charHeightLocal;
03496 
03497         /* Character index in cache */
03498         ci = (unsigned char) c;
03499 
03500         /*
03501         * Create new charWidth x charHeight bitmap surface if not already present.
03502         * Might get rotated later.
03503         */
03504         if (gfxPrimitivesFont[ci] == NULL) {
03505                 /*
03506                 * Redraw character into surface
03507                 */
03508                 character =     SDL_CreateRGBSurface(SDL_SWSURFACE,
03509                         charWidth, charHeight, 32,
03510                         0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
03511                 if (character == NULL) {
03512                         return (-1);
03513                 }
03514 
03515                 charpos = currentFontdata + ci * charSize;
03516                                 linepos = (Uint8 *)character->pixels;
03517                 pitch = character->pitch;
03518 
03519                 /*
03520                 * Drawing loop 
03521                 */
03522                 patt = 0;
03523                 for (iy = 0; iy < charHeight; iy++) {
03524                         mask = 0x00;
03525                         curpos = linepos;
03526                         for (ix = 0; ix < charWidth; ix++) {
03527                                 if (!(mask >>= 1)) {
03528                                         patt = *charpos++;
03529                                         mask = 0x80;
03530                                 }
03531                                 if (patt & mask) {
03532                                         *(Uint32 *)curpos = 0xffffffff;
03533                                 } else {
03534                                         *(Uint32 *)curpos = 0;
03535                                 }
03536                                 curpos += 4;
03537                         }
03538                         linepos += pitch;
03539                 }
03540 
03541                 /* Maybe rotate and replace cached image */
03542                 if (charRotation>0)
03543                 {
03544                         rotatedCharacter = rotateSurface90Degrees(character, charRotation);
03545                         SDL_FreeSurface(character);
03546                         character = rotatedCharacter;
03547                 }
03548 
03549                 /* Convert temp surface into texture */
03550                 gfxPrimitivesFont[ci] = SDL_CreateTextureFromSurface(renderer, character);
03551                 SDL_FreeSurface(character);
03552 
03553                 /*
03554                 * Check pointer 
03555                 */
03556                 if (gfxPrimitivesFont[ci] == NULL) {
03557                         return (-1);
03558                 }
03559         }
03560 
03561         /*
03562         * Set color 
03563         */
03564         result = 0;
03565         result |= SDL_SetTextureColorMod(gfxPrimitivesFont[ci], r, g, b);
03566         result |= SDL_SetTextureAlphaMod(gfxPrimitivesFont[ci], a);
03567 
03568         /*
03569         * Draw texture onto destination 
03570         */
03571         result |= SDL_RenderCopy(renderer, gfxPrimitivesFont[ci], &srect, &drect);
03572 
03573         return (result);
03574 }
03575 
03576 
03588 int characterColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, char c, Uint32 color)
03589 {
03590         Uint8 *co = (Uint8 *)&color; 
03591         return characterRGBA(renderer, x, y, c, co[0], co[1], co[2], co[3]);
03592 }
03593 
03594 
03609 int stringColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint32 color)
03610 {
03611         Uint8 *c = (Uint8 *)&color; 
03612         return stringRGBA(renderer, x, y, s, c[0], c[1], c[2], c[3]);
03613 }
03614 
03629 int stringRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
03630 {
03631         int result = 0;
03632         Sint16 curx = x;
03633         Sint16 cury = y;
03634         const char *curchar = s;
03635 
03636         while (*curchar && !result) {
03637                 result |= characterRGBA(renderer, curx, cury, *curchar, r, g, b, a);
03638                 switch (charRotation)
03639                 {
03640                 case 0:
03641                         curx += charWidthLocal;
03642                         break;
03643                 case 2:
03644                         curx -= charWidthLocal;
03645                         break;
03646                 case 1:
03647                         cury += charHeightLocal;
03648                         break;
03649                 case 3:
03650                         cury -= charHeightLocal;
03651                         break;
03652                 }
03653                 curchar++;
03654         }
03655 
03656         return (result);
03657 }
03658 
03659 /* ---- Bezier curve */
03660 
03670 double _evaluateBezier (double *data, int ndata, double t) 
03671 {
03672         double mu, result;
03673         int n,k,kn,nn,nkn;
03674         double blend,muk,munk;
03675 
03676         /* Sanity check bounds */
03677         if (t<0.0) {
03678                 return(data[0]);
03679         }
03680         if (t>=(double)ndata) {
03681                 return(data[ndata-1]);
03682         }
03683 
03684         /* Adjust t to the range 0.0 to 1.0 */ 
03685         mu=t/(double)ndata;
03686 
03687         /* Calculate interpolate */
03688         n=ndata-1;
03689         result=0.0;
03690         muk = 1;
03691         munk = pow(1-mu,(double)n);
03692         for (k=0;k<=n;k++) {
03693                 nn = n;
03694                 kn = k;
03695                 nkn = n - k;
03696                 blend = muk * munk;
03697                 muk *= mu;
03698                 munk /= (1-mu);
03699                 while (nn >= 1) {
03700                         blend *= nn;
03701                         nn--;
03702                         if (kn > 1) {
03703                                 blend /= (double)kn;
03704                                 kn--;
03705                         }
03706                         if (nkn > 1) {
03707                                 blend /= (double)nkn;
03708                                 nkn--;
03709                         }
03710                 }
03711                 result += data[k] * blend;
03712         }
03713 
03714         return (result);
03715 }
03716 
03729 int bezierColor(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
03730 {
03731         Uint8 *c = (Uint8 *)&color; 
03732         return bezierRGBA(renderer, vx, vy, n, s, c[0], c[1], c[2], c[3]);
03733 }
03734 
03750 int bezierRGBA(SDL_Renderer * renderer, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
03751 {
03752         int result;
03753         int i;
03754         double *x, *y, t, stepsize;
03755         Sint16 x1, y1, x2, y2;
03756 
03757         /*
03758         * Sanity check 
03759         */
03760         if (n < 3) {
03761                 return (-1);
03762         }
03763         if (s < 2) {
03764                 return (-1);
03765         }
03766 
03767         /*
03768         * Variable setup 
03769         */
03770         stepsize=(double)1.0/(double)s;
03771 
03772         /* Transfer vertices into float arrays */
03773         if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
03774                 return(-1);
03775         }
03776         if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
03777                 free(x);
03778                 return(-1);
03779         }    
03780         for (i=0; i<n; i++) {
03781                 x[i]=(double)vx[i];
03782                 y[i]=(double)vy[i];
03783         }      
03784         x[n]=(double)vx[0];
03785         y[n]=(double)vy[0];
03786 
03787         /*
03788         * Set color 
03789         */
03790         result = 0;
03791         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
03792         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
03793 
03794         /*
03795         * Draw 
03796         */
03797         t=0.0;
03798         x1=(Sint16)lrint(_evaluateBezier(x,n+1,t));
03799         y1=(Sint16)lrint(_evaluateBezier(y,n+1,t));
03800         for (i = 0; i <= (n*s); i++) {
03801                 t += stepsize;
03802                 x2=(Sint16)_evaluateBezier(x,n,t);
03803                 y2=(Sint16)_evaluateBezier(y,n,t);
03804                 result |= line(renderer, x1, y1, x2, y2);
03805                 x1 = x2;
03806                 y1 = y2;
03807         }
03808 
03809         /* Clean up temporary array */
03810         free(x);
03811         free(y);
03812 
03813         return (result);
03814 }
03815 
03816 
03817 /* ---- Thick Line */
03818 
03837 int _bresenhamInitialize(SDL2_gfxBresenhamIterator *b, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
03838 {
03839         int temp;
03840 
03841         if (b==NULL) {
03842                 return(-1);
03843         }
03844 
03845         b->x = x1;
03846         b->y = y1;
03847 
03848         /* dx = abs(x2-x1), s1 = sign(x2-x1) */
03849         if ((b->dx = x2 - x1) != 0) {
03850                 if (b->dx < 0) {
03851                         b->dx = -b->dx;
03852                         b->s1 = -1;
03853                 } else {
03854                         b->s1 = 1;
03855                 }
03856         } else {
03857                 b->s1 = 0;      
03858         }
03859 
03860         /* dy = abs(y2-y1), s2 = sign(y2-y1)    */
03861         if ((b->dy = y2 - y1) != 0) {
03862                 if (b->dy < 0) {
03863                         b->dy = -b->dy;
03864                         b->s2 = -1;
03865                 } else {
03866                         b->s2 = 1;
03867                 }
03868         } else {
03869                 b->s2 = 0;      
03870         }
03871 
03872         if (b->dy > b->dx) {
03873                 temp = b->dx;
03874                 b->dx = b->dy;
03875                 b->dy = temp;
03876                 b->swapdir = 1;
03877         } else {
03878                 b->swapdir = 0;
03879         }
03880 
03881         b->count = (b->dx<0) ? 0 : (unsigned int)b->dx;
03882         b->dy <<= 1;
03883         b->error = b->dy - b->dx;
03884         b->dx <<= 1;    
03885 
03886         return(0);
03887 }
03888 
03889 
03899 int _bresenhamIterate(SDL2_gfxBresenhamIterator *b)
03900 {       
03901         if (b==NULL) {
03902                 return (-1);
03903         }
03904 
03905         /* last point check */
03906         if (b->count==0) {
03907                 return (2);
03908         }
03909 
03910         while (b->error >= 0) {
03911                 if (b->swapdir) {
03912                         b->x += b->s1;
03913                 } else  {
03914                         b->y += b->s2;
03915                 }
03916 
03917                 b->error -= b->dx;
03918         }
03919 
03920         if (b->swapdir) {
03921                 b->y += b->s2;
03922         } else {
03923                 b->x += b->s1;
03924         }
03925 
03926         b->error += b->dy;      
03927         b->count--;             
03928 
03929         /* count==0 indicates "end-of-line" */
03930         return ((b->count) ? 0 : 1);
03931 }
03932 
03933 
03942 void _murphyParaline(SDL2_gfxMurphyIterator *m, Sint16 x, Sint16 y, int d1)
03943 {
03944         int p;
03945         d1 = -d1;
03946 
03947         for (p = 0; p <= m->u; p++) {
03948 
03949                 pixel(m->renderer, x, y);
03950 
03951                 if (d1 <= m->kt) {
03952                         if (m->oct2 == 0) {
03953                                 x++;
03954                         } else {
03955                                 if (m->quad4 == 0) {
03956                                         y++;
03957                                 } else {
03958                                         y--;
03959                                 }
03960                         }
03961                         d1 += m->kv;
03962                 } else {        
03963                         x++;
03964                         if (m->quad4 == 0) {
03965                                 y++;
03966                         } else {
03967                                 y--;
03968                         }
03969                         d1 += m->kd;
03970                 }
03971         }
03972 
03973         m->tempx = x;
03974         m->tempy = y;
03975 }
03976 
03992 void _murphyIteration(SDL2_gfxMurphyIterator *m, Uint8 miter, 
03993         Uint16 ml1bx, Uint16 ml1by, Uint16 ml2bx, Uint16 ml2by, 
03994         Uint16 ml1x, Uint16 ml1y, Uint16 ml2x, Uint16 ml2y)
03995 {
03996         int atemp1, atemp2;
03997         int ftmp1, ftmp2;
03998         Uint16 m1x, m1y, m2x, m2y;      
03999         Uint16 fix, fiy, lax, lay, curx, cury;
04000         Sint16 px[4], py[4];
04001         SDL2_gfxBresenhamIterator b;
04002 
04003         if (miter > 1) {
04004                 if (m->first1x != -32768) {
04005                         fix = (m->first1x + m->first2x) / 2;
04006                         fiy = (m->first1y + m->first2y) / 2;
04007                         lax = (m->last1x + m->last2x) / 2;
04008                         lay = (m->last1y + m->last2y) / 2;
04009                         curx = (ml1x + ml2x) / 2;
04010                         cury = (ml1y + ml2y) / 2;
04011 
04012                         atemp1 = (fix - curx);
04013                         atemp2 = (fiy - cury);
04014                         ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
04015                         atemp1 = (lax - curx);
04016                         atemp2 = (lay - cury);
04017                         ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
04018 
04019                         if (ftmp1 <= ftmp2) {
04020                                 m1x = m->first1x;
04021                                 m1y = m->first1y;
04022                                 m2x = m->first2x;
04023                                 m2y = m->first2y;
04024                         } else {
04025                                 m1x = m->last1x;
04026                                 m1y = m->last1y;
04027                                 m2x = m->last2x;
04028                                 m2y = m->last2y;
04029                         }
04030 
04031                         atemp1 = (m2x - ml2x);
04032                         atemp2 = (m2y - ml2y);
04033                         ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
04034                         atemp1 = (m2x - ml2bx);
04035                         atemp2 = (m2y - ml2by);
04036                         ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
04037 
04038                         if (ftmp2 >= ftmp1) {
04039                                 ftmp1 = ml2bx;
04040                                 ftmp2 = ml2by;
04041                                 ml2bx = ml2x;
04042                                 ml2by = ml2y;
04043                                 ml2x = ftmp1;
04044                                 ml2y = ftmp2;
04045                                 ftmp1 = ml1bx;
04046                                 ftmp2 = ml1by;
04047                                 ml1bx = ml1x;
04048                                 ml1by = ml1y;
04049                                 ml1x = ftmp1;
04050                                 ml1y = ftmp2;
04051                         }
04052 
04053                         /*
04054                         * Lock the surface 
04055                         */
04056                         _bresenhamInitialize(&b, m2x, m2y, m1x, m1y);
04057                         do {
04058                                 pixel(m->renderer, b.x, b.y);
04059                         } while (_bresenhamIterate(&b)==0);
04060 
04061                         _bresenhamInitialize(&b, m1x, m1y, ml1bx, ml1by);
04062                         do {
04063                                 pixel(m->renderer, b.x, b.y);
04064                         } while (_bresenhamIterate(&b)==0);
04065 
04066                         _bresenhamInitialize(&b, ml1bx, ml1by, ml2bx, ml2by);
04067                         do {
04068                                 pixel(m->renderer, b.x, b.y);
04069                         } while (_bresenhamIterate(&b)==0);
04070 
04071                         _bresenhamInitialize(&b, ml2bx, ml2by, m2x, m2y);
04072                         do {
04073                                 pixel(m->renderer, b.x, b.y);
04074                         } while (_bresenhamIterate(&b)==0);
04075 
04076                         px[0] = m1x;
04077                         px[1] = m2x;
04078                         px[2] = ml1bx;
04079                         px[3] = ml2bx;
04080                         py[0] = m1y;
04081                         py[1] = m2y;
04082                         py[2] = ml1by;
04083                         py[3] = ml2by;                  
04084                         polygon(m->renderer, px, py, 4);                                                
04085                 }
04086         }
04087 
04088         m->last1x = ml1x;
04089         m->last1y = ml1y;
04090         m->last2x = ml2x;
04091         m->last2y = ml2y;
04092         m->first1x = ml1bx;
04093         m->first1y = ml1by;
04094         m->first2x = ml2bx;
04095         m->first2y = ml2by;
04096 }
04097 
04098 
04099 #define HYPOT(x,y) sqrt((double)(x)*(double)(x)+(double)(y)*(double)(y)) 
04100 
04115 void _murphyWideline(SDL2_gfxMurphyIterator *m, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 miter)
04116 {       
04117         float offset = (float)width / 2.f;
04118 
04119         Sint16 temp;
04120         Sint16 ptx, pty, ptxx, ptxy, ml1x, ml1y, ml2x, ml2y, ml1bx, ml1by, ml2bx, ml2by;
04121 
04122         int d0, d1;             /* difference terms d0=perpendicular to line, d1=along line */
04123 
04124         int q;                  /* pel counter,q=perpendicular to line */
04125         int tmp;
04126 
04127         int dd;                 /* distance along line */
04128         int tk;                 /* thickness threshold */
04129         double ang;             /* angle for initial point calculation */
04130         double sang, cang;
04131 
04132         /* Initialisation */
04133         m->u = x2 - x1; /* delta x */
04134         m->v = y2 - y1; /* delta y */
04135 
04136         if (m->u < 0) { /* swap to make sure we are in quadrants 1 or 4 */
04137                 temp = x1;
04138                 x1 = x2;
04139                 x2 = temp;
04140                 temp = y1;
04141                 y1 = y2;
04142                 y2 = temp;              
04143                 m->u *= -1;
04144                 m->v *= -1;
04145         }
04146 
04147         if (m->v < 0) { /* swap to 1st quadrant and flag */
04148                 m->v *= -1;
04149                 m->quad4 = 1;
04150         } else {
04151                 m->quad4 = 0;
04152         }
04153 
04154         if (m->v > m->u) {      /* swap things if in 2 octant */
04155                 tmp = m->u;
04156                 m->u = m->v;
04157                 m->v = tmp;
04158                 m->oct2 = 1;
04159         } else {
04160                 m->oct2 = 0;
04161         }
04162 
04163         m->ku = m->u + m->u;    /* change in l for square shift */
04164         m->kv = m->v + m->v;    /* change in d for square shift */
04165         m->kd = m->kv - m->ku;  /* change in d for diagonal shift */
04166         m->kt = m->u - m->kv;   /* diag/square decision threshold */
04167 
04168         d0 = 0;
04169         d1 = 0;
04170         dd = 0;
04171 
04172         ang = atan((double) m->v / (double) m->u);      /* calc new initial point - offset both sides of ideal */       
04173         sang = sin(ang);
04174         cang = cos(ang);
04175 
04176         if (m->oct2 == 0) {
04177                 ptx = x1 + (Sint16)lrint(offset * sang);
04178                 if (m->quad4 == 0) {
04179                         pty = y1 - (Sint16)lrint(offset * cang);
04180                 } else {
04181                         pty = y1 + (Sint16)lrint(offset * cang);
04182                 }
04183         } else {
04184                 ptx = x1 - (Sint16)lrint(offset * cang);
04185                 if (m->quad4 == 0) {
04186                         pty = y1 + (Sint16)lrint(offset * sang);
04187                 } else {
04188                         pty = y1 - (Sint16)lrint(offset * sang);
04189                 }
04190         }
04191 
04192         /* used here for constant thickness line */
04193         tk = (int) (4. * HYPOT(ptx - x1, pty - y1) * HYPOT(m->u, m->v));
04194 
04195         if (miter == 0) {
04196                 m->first1x = -32768;
04197                 m->first1y = -32768;
04198                 m->first2x = -32768;
04199                 m->first2y = -32768;
04200                 m->last1x = -32768;
04201                 m->last1y = -32768;
04202                 m->last2x = -32768;
04203                 m->last2y = -32768;
04204         }
04205         ptxx = ptx;
04206         ptxy = pty;
04207 
04208         for (q = 0; dd <= tk; q++) {    /* outer loop, stepping perpendicular to line */
04209 
04210                 _murphyParaline(m, ptx, pty, d1);       /* call to inner loop - right edge */
04211                 if (q == 0) {
04212                         ml1x = ptx;
04213                         ml1y = pty;
04214                         ml1bx = m->tempx;
04215                         ml1by = m->tempy;
04216                 } else {
04217                         ml2x = ptx;
04218                         ml2y = pty;
04219                         ml2bx = m->tempx;
04220                         ml2by = m->tempy;
04221                 }
04222                 if (d0 < m->kt) {       /* square move */
04223                         if (m->oct2 == 0) {
04224                                 if (m->quad4 == 0) {
04225                                         pty++;
04226                                 } else {
04227                                         pty--;
04228                                 }
04229                         } else {
04230                                 ptx++;
04231                         }
04232                 } else {        /* diagonal move */
04233                         dd += m->kv;
04234                         d0 -= m->ku;
04235                         if (d1 < m->kt) {       /* normal diagonal */
04236                                 if (m->oct2 == 0) {
04237                                         ptx--;
04238                                         if (m->quad4 == 0) {
04239                                                 pty++;
04240                                         } else {
04241                                                 pty--;
04242                                         }
04243                                 } else {
04244                                         ptx++;
04245                                         if (m->quad4 == 0) {
04246                                                 pty--;
04247                                         } else {
04248                                                 pty++;
04249                                         }
04250                                 }
04251                                 d1 += m->kv;
04252                         } else {        /* double square move, extra parallel line */
04253                                 if (m->oct2 == 0) {
04254                                         ptx--;
04255                                 } else {
04256                                         if (m->quad4 == 0) {
04257                                                 pty--;
04258                                         } else {
04259                                                 pty++;
04260                                         }
04261                                 }
04262                                 d1 += m->kd;
04263                                 if (dd > tk) {
04264                                         _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
04265                                         return; /* breakout on the extra line */
04266                                 }
04267                                 _murphyParaline(m, ptx, pty, d1);
04268                                 if (m->oct2 == 0) {
04269                                         if (m->quad4 == 0) {
04270                                                 pty++;
04271                                         } else {
04272 
04273                                                 pty--;
04274                                         }
04275                                 } else {
04276                                         ptx++;
04277                                 }
04278                         }
04279                 }
04280                 dd += m->ku;
04281                 d0 += m->kv;
04282         }
04283 
04284         _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
04285 }
04286 
04287 
04301 int thickLineColor(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
04302 {       
04303         Uint8 *c = (Uint8 *)&color; 
04304         return thickLineRGBA(renderer, x1, y1, x2, y2, width, c[0], c[1], c[2], c[3]);
04305 }
04306 
04323 int thickLineRGBA(SDL_Renderer *renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
04324 {
04325         int result;
04326         int wh;
04327         SDL2_gfxMurphyIterator m;
04328 
04329         if (renderer == NULL) {
04330                 return -1;
04331         }
04332         if (width < 1) {
04333                 return -1;
04334         }
04335 
04336         /* Special case: thick "point" */
04337         if ((x1 == x2) && (y1 == y2)) {
04338                 wh = width / 2;
04339                 return boxRGBA(renderer, x1 - wh, y1 - wh, x2 + width, y2 + width, r, g, b, a);         
04340         }
04341 
04342         /*
04343         * Set color
04344         */
04345         result = 0;
04346         result |= SDL_SetRenderDrawBlendMode(renderer, (a == 255) ? SDL_BLENDMODE_NONE : SDL_BLENDMODE_BLEND);
04347         result |= SDL_SetRenderDrawColor(renderer, r, g, b, a);
04348 
04349         /* 
04350         * Draw
04351         */
04352         m.renderer = renderer;
04353         _murphyWideline(&m, x1, y1, x2, y2, width, 0);
04354         _murphyWideline(&m, x1, y1, x2, y2, width, 1);
04355 
04356         return(0);
04357 }