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