SDL2_gfx
1.0.1
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 <= 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 }