1 /*
2 
3 SDL_gfxPrimitives - Graphics primitives for SDL surfaces
4 
5 LGPL (c) A. Schiffler
6 
7 */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #include <string.h>
13 
14 #include "SDL_gfxPrimitives.h"
15 #include "SDL_rotozoom.h"
16 
17 /* -===================- */
18 
19 #define DEFAULT_ALPHA_PIXEL_ROUTINE
20 #undef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
21 
22 /* ---- Structures */
23 
24 /*!
25 \brief The structure passed to the internal Bresenham iterator.
26 */
27 typedef struct {
28   Sint16 x, y;
29   int dx, dy, s1, s2, swapdir, error;
30   Uint32 count;
31 } SDL_gfxBresenhamIterator;
32 
33 /*!
34 \brief The structure passed to the internal Murphy iterator.
35 */
36 typedef struct {
37   Uint32 color;
38   SDL_Surface *dst;
39   int u, v;   /* delta x , delta y */
40   int ku, kt, kv, kd; /* loop constants */
41   int oct2;
42   int quad4;
43   Sint16 last1x, last1y, last2x, last2y, first1x, first1y, first2x, first2y, tempx, tempy;
44 } SDL_gfxMurphyIterator;
45 
46 /* ----- Defines for pixel clipping tests */
47 
48 #define clip_xmin(surface) surface->clip_rect.x
49 #define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1
50 #define clip_ymin(surface) surface->clip_rect.y
51 #define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1
52 
53 /*!
54 \brief Internal pixel drawing - fast, no blending, no locking, clipping.
55 
56 \param dst The surface to draw on.
57 \param x The horizontal coordinate of the pixel.
58 \param y The vertical position of the pixel.
59 \param color The color value of the pixel to draw.
60 
61 \returns Returns 0 on success, -1 on failure.
62 */
fastPixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)63 int fastPixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
64 {
65   int bpp;
66   Uint8 *p;
67 
68   /*
69   * Honor clipping setup at pixel level
70   */
71   if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) {
72 
73     /*
74     * Get destination format
75     */
76     bpp = dst->format->BytesPerPixel;
77     p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
78     switch (bpp) {
79   case 1:
80     *p = color;
81     break;
82   case 2:
83     *(Uint16 *) p = color;
84     break;
85   case 3:
86     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
87       p[0] = (color >> 16) & 0xff;
88       p[1] = (color >> 8) & 0xff;
89       p[2] = color & 0xff;
90     } else {
91       p[0] = color & 0xff;
92       p[1] = (color >> 8) & 0xff;
93       p[2] = (color >> 16) & 0xff;
94     }
95     break;
96   case 4:
97     *(Uint32 *) p = color;
98     break;
99     }     /* switch */
100 
101 
102   }
103 
104   return (0);
105 }
106 
107 /*!
108 \brief Internal pixel drawing - fast, no blending, no locking, no clipping.
109 
110 Function is faster but dangerous since no clipping check is done.
111 Code needs to make sure we stay in surface bounds before calling.
112 
113 \param dst The surface to draw on.
114 \param x The horizontal coordinate of the pixel.
115 \param y The vertical position of the pixel.
116 \param color The color value of the pixel to draw.
117 
118 \returns Returns 0 on success, -1 on failure.
119 */
fastPixelColorNolockNoclip(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)120 int fastPixelColorNolockNoclip(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
121 {
122   int bpp;
123   Uint8 *p;
124 
125   /*
126   * Get destination format
127   */
128   bpp = dst->format->BytesPerPixel;
129   p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
130   switch (bpp) {
131   case 1:
132     *p = color;
133     break;
134   case 2:
135     *(Uint16 *) p = color;
136     break;
137   case 3:
138     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
139       p[0] = (color >> 16) & 0xff;
140       p[1] = (color >> 8) & 0xff;
141       p[2] = color & 0xff;
142     } else {
143       p[0] = color & 0xff;
144       p[1] = (color >> 8) & 0xff;
145       p[2] = (color >> 16) & 0xff;
146     }
147     break;
148   case 4:
149     *(Uint32 *) p = color;
150     break;
151   }       /* switch */
152 
153   return (0);
154 }
155 
156 /*!
157 \brief Internal pixel drawing - fast, no blending, locking, clipping.
158 
159 \param dst The surface to draw on.
160 \param x The horizontal coordinate of the pixel.
161 \param y The vertical position of the pixel.
162 \param color The color value of the pixel to draw.
163 
164 \returns Returns 0 on success, -1 on failure.
165 */
fastPixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)166 int fastPixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
167 {
168   int result;
169 
170   /*
171   * Lock the surface
172   */
173   if (SDL_MUSTLOCK(dst)) {
174     if (SDL_LockSurface(dst) < 0) {
175       return (-1);
176     }
177   }
178 
179   result = fastPixelColorNolock(dst, x, y, color);
180 
181   /*
182   * Unlock surface
183   */
184   if (SDL_MUSTLOCK(dst)) {
185     SDL_UnlockSurface(dst);
186   }
187 
188   return (result);
189 }
190 
191 /*!
192 \brief Internal pixel drawing - fast, no blending, locking, RGB input.
193 
194 \param dst The surface to draw on.
195 \param x The horizontal coordinate of the pixel.
196 \param y The vertical position of the pixel.
197 \param r The red value of the pixel to draw.
198 \param g The green value of the pixel to draw.
199 \param b The blue value of the pixel to draw.
200 \param a The alpha value of the pixel to draw.
201 
202 \returns Returns 0 on success, -1 on failure.
203 */
fastPixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)204 int fastPixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
205 {
206   Uint32 color;
207 
208   /*
209   * Setup color
210   */
211   color = SDL_MapRGBA(dst->format, r, g, b, a);
212 
213   /*
214   * Draw
215   */
216   return (fastPixelColor(dst, x, y, color));
217 }
218 
219 /*!
220 \brief Internal pixel drawing - fast, no blending, no locking RGB input.
221 
222 \param dst The surface to draw on.
223 \param x The horizontal coordinate of the pixel.
224 \param y The vertical position of the pixel.
225 \param r The red value of the pixel to draw.
226 \param g The green value of the pixel to draw.
227 \param b The blue value of the pixel to draw.
228 \param a The alpha value of the pixel to draw.
229 
230 \returns Returns 0 on success, -1 on failure.
231 */
fastPixelRGBANolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)232 int fastPixelRGBANolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
233 {
234   Uint32 color;
235 
236   /*
237   * Setup color
238   */
239   color = SDL_MapRGBA(dst->format, r, g, b, a);
240 
241   /*
242   * Draw
243   */
244   return (fastPixelColorNolock(dst, x, y, color));
245 }
246 
247 /*!
248 \brief Internal pixel drawing function with alpha blending where input color in in destination format.
249 
250 Contains two alternative 32 bit alpha blending routines which can be enabled at the source
251 level with the defines DEFAULT_ALPHA_PIXEL_ROUTINE or EXPERIMENTAL_ALPHA_PIXEL_ROUTINE.
252 Only the bits up to the surface depth are significant in the color value.
253 
254 \param dst The surface to draw on.
255 \param x The horizontal coordinate of the pixel.
256 \param y The vertical position of the pixel.
257 \param color The color value of the pixel to draw.
258 \param alpha The blend factor to apply while drawing.
259 
260 \returns Returns 0 on success, -1 on failure.
261 */
_putPixelAlpha(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint8 alpha)262 int _putPixelAlpha(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
263 {
264   SDL_PixelFormat *format;
265   Uint32 Rmask, Gmask, Bmask, Amask;
266   Uint32 Rshift, Gshift, Bshift, Ashift;
267   Uint32 R, G, B, A;
268 
269   if (dst == NULL)
270   {
271     return (-1);
272   }
273 
274   if (x >= clip_xmin(dst) && x <= clip_xmax(dst) &&
275     y >= clip_ymin(dst) && y <= clip_ymax(dst))
276   {
277 
278     format = dst->format;
279 
280     switch (format->BytesPerPixel) {
281   case 1:
282     {   /* Assuming 8-bpp */
283       if (alpha == 255) {
284         *((Uint8 *) dst->pixels + y * dst->pitch + x) = color;
285       } else {
286         Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x;
287         SDL_Palette *palette = format->palette;
288         SDL_Color *colors = palette->colors;
289         SDL_Color dColor = colors[*pixel];
290         SDL_Color sColor = colors[color];
291         Uint8 dR = dColor.r;
292         Uint8 dG = dColor.g;
293         Uint8 dB = dColor.b;
294         Uint8 sR = sColor.r;
295         Uint8 sG = sColor.g;
296         Uint8 sB = sColor.b;
297 
298         dR = dR + ((sR - dR) * alpha >> 8);
299         dG = dG + ((sG - dG) * alpha >> 8);
300         dB = dB + ((sB - dB) * alpha >> 8);
301 
302         *pixel = SDL_MapRGB(format, dR, dG, dB);
303       }
304     }
305     break;
306 
307   case 2:
308     {   /* Probably 15-bpp or 16-bpp */
309       if (alpha == 255) {
310         *((Uint16 *) dst->pixels + y * dst->pitch / 2 + x) = color;
311       } else {
312         Uint16 *pixel = (Uint16 *) dst->pixels + y * dst->pitch / 2 + x;
313         Uint32 dc = *pixel;
314 
315         Rmask = format->Rmask;
316         Gmask = format->Gmask;
317         Bmask = format->Bmask;
318         Amask = format->Amask;
319         R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask;
320         G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask;
321         B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask;
322         if (Amask) {
323           A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask;
324         }
325         *pixel = R | G | B | A;
326       }
327     }
328     break;
329 
330   case 3:
331     {   /* Slow 24-bpp mode, usually not used */
332       Uint8 Rshift8, Gshift8, Bshift8, Ashift8;
333       Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x * 3;
334 
335       Rshift = format->Rshift;
336       Gshift = format->Gshift;
337       Bshift = format->Bshift;
338       Ashift = format->Ashift;
339 
340       Rshift8 = Rshift / 8;
341       Gshift8 = Gshift / 8;
342       Bshift8 = Bshift / 8;
343       Ashift8 = Ashift / 8;
344 
345       if (alpha == 255) {
346         *(pixel + Rshift8) = color >> Rshift;
347         *(pixel + Gshift8) = color >> Gshift;
348         *(pixel + Bshift8) = color >> Bshift;
349         *(pixel + Ashift8) = color >> Ashift;
350       } else {
351         Uint8 dR, dG, dB, dA = 0;
352         Uint8 sR, sG, sB, sA = 0;
353 
354         dR = *((pixel) + Rshift8);
355         dG = *((pixel) + Gshift8);
356         dB = *((pixel) + Bshift8);
357         dA = *((pixel) + Ashift8);
358 
359         sR = (color >> Rshift) & 0xff;
360         sG = (color >> Gshift) & 0xff;
361         sB = (color >> Bshift) & 0xff;
362         sA = (color >> Ashift) & 0xff;
363 
364         dR = dR + ((sR - dR) * alpha >> 8);
365         dG = dG + ((sG - dG) * alpha >> 8);
366         dB = dB + ((sB - dB) * alpha >> 8);
367         dA = dA + ((sA - dA) * alpha >> 8);
368 
369         *((pixel) + Rshift8) = dR;
370         *((pixel) + Gshift8) = dG;
371         *((pixel) + Bshift8) = dB;
372         *((pixel) + Ashift8) = dA;
373       }
374     }
375     break;
376 
377 #ifdef DEFAULT_ALPHA_PIXEL_ROUTINE
378 
379   case 4:
380     {   /* Probably :-) 32-bpp */
381       if (alpha == 255) {
382         *((Uint32 *) dst->pixels + y * dst->pitch / 4 + x) = color;
383       } else {
384         Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x;
385         Uint32 dc = *pixel;
386 
387         Rmask = format->Rmask;
388         Gmask = format->Gmask;
389         Bmask = format->Bmask;
390         Amask = format->Amask;
391 
392         Rshift = format->Rshift;
393         Gshift = format->Gshift;
394         Bshift = format->Bshift;
395         Ashift = format->Ashift;
396 
397         A = 0;
398         R = ((dc & Rmask) + (((((color & Rmask) - (dc & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask;
399         G = ((dc & Gmask) + (((((color & Gmask) - (dc & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask;
400         B = ((dc & Bmask) + (((((color & Bmask) - (dc & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask;
401         if (Amask) {
402           A = ((dc & Amask) + (((((color & Amask) - (dc & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask;
403         }
404         *pixel = R | G | B | A;
405       }
406     }
407     break;
408 #endif
409 
410 #ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
411 
412   case 4:{    /* Probably :-) 32-bpp */
413     if (alpha == 255) {
414       *((Uint32 *) dst->pixels + y * dst->pitch / 4 + x) = color;
415     } else {
416       Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x;
417       Uint32 dR, dG, dB, dA;
418       Uint32 dc = *pixel;
419 
420       Uint32 surfaceAlpha, preMultR, preMultG, preMultB;
421       Uint32 aTmp;
422 
423       Rmask = format->Rmask;
424       Gmask = format->Gmask;
425       Bmask = format->Bmask;
426       Amask = format->Amask;
427 
428       dR = (color & Rmask);
429       dG = (color & Gmask);
430       dB = (color & Bmask);
431       dA = (color & Amask);
432 
433       Rshift = format->Rshift;
434       Gshift = format->Gshift;
435       Bshift = format->Bshift;
436       Ashift = format->Ashift;
437 
438       preMultR = (alpha * (dR >> Rshift));
439       preMultG = (alpha * (dG >> Gshift));
440       preMultB = (alpha * (dB >> Bshift));
441 
442       surfaceAlpha = ((dc & Amask) >> Ashift);
443       aTmp = (255 - alpha);
444       if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) {
445         aTmp *= surfaceAlpha;
446         R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask;
447         G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask;
448         B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask;
449       }
450       *pixel = R | G | B | (A << Ashift & Amask);
451 
452     }
453        }
454        break;
455 #endif
456     }
457   }
458 
459   return (0);
460 }
461 
462 /*!
463 \brief Pixel draw with blending enabled if a<255.
464 
465 \param dst The surface to draw on.
466 \param x X (horizontal) coordinate of the pixel.
467 \param y Y (vertical) coordinate of the pixel.
468 \param color The color value of the pixel to draw (0xRRGGBBAA).
469 
470 \returns Returns 0 on success, -1 on failure.
471 */
pixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)472 int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
473 {
474   Uint8 alpha;
475   Uint32 mcolor;
476   int result = 0;
477 
478   /*
479   * Lock the surface
480   */
481   if (SDL_MUSTLOCK(dst)) {
482     if (SDL_LockSurface(dst) < 0) {
483       return (-1);
484     }
485   }
486 
487   /*
488   * Setup color
489   */
490   alpha = color & 0x000000ff;
491   mcolor =
492     SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
493     (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
494 
495   /*
496   * Draw
497   */
498   result = _putPixelAlpha(dst, x, y, mcolor, alpha);
499 
500   /*
501   * Unlock the surface
502   */
503   if (SDL_MUSTLOCK(dst)) {
504     SDL_UnlockSurface(dst);
505   }
506 
507   return (result);
508 }
509 
510 /*!
511 \brief Pixel draw with blending enabled if a<255 - no surface locking.
512 
513 \param dst The surface to draw on.
514 \param x X (horizontal) coordinate of the pixel.
515 \param y Y (vertical) coordinate of the pixel.
516 \param color The color value of the pixel to draw (0xRRGGBBAA).
517 
518 \returns Returns 0 on success, -1 on failure.
519 */
pixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)520 int pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
521 {
522   Uint8 alpha;
523   Uint32 mcolor;
524   int result = 0;
525 
526   /*
527   * Setup color
528   */
529   alpha = color & 0x000000ff;
530   mcolor =
531     SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
532     (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
533 
534   /*
535   * Draw
536   */
537   result = _putPixelAlpha(dst, x, y, mcolor, alpha);
538 
539   return (result);
540 }
541 
542 
543 /*!
544 \brief Internal function to draw filled rectangle with alpha blending.
545 
546 Assumes color is in destination format.
547 
548 \param dst The surface to draw on.
549 \param x1 X coordinate of the first corner (upper left) of the rectangle.
550 \param y1 Y coordinate of the first corner (upper left) of the rectangle.
551 \param x2 X coordinate of the second corner (lower right) of the rectangle.
552 \param y2 Y coordinate of the second corner (lower right) of the rectangle.
553 \param color The color value of the rectangle to draw (0xRRGGBBAA).
554 \param alpha Alpha blending amount for pixels.
555 
556 \returns Returns 0 on success, -1 on failure.
557 */
_filledRectAlpha(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,Uint8 alpha)558 int _filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
559 {
560   SDL_PixelFormat *format;
561   Uint32 Rmask, Bmask, Gmask, Amask;
562   Uint32 Rshift, Bshift, Gshift, Ashift;
563   Uint8 sR, sG, sB, sA;
564   Uint32 R, G, B, A;
565   Sint16 x, y;
566 
567   format = dst->format;
568   switch (format->BytesPerPixel) {
569   case 1:
570     {     /* Assuming 8-bpp */
571       Uint8 *row, *pixel;
572       Uint8 dR, dG, dB;
573       SDL_Palette *palette = format->palette;
574       SDL_Color *colors = palette->colors;
575       sR = colors[color].r;
576       sG = colors[color].g;
577       sB = colors[color].b;
578 
579       for (y = y1; y <= y2; y++) {
580         row = (Uint8 *) dst->pixels + y * dst->pitch;
581         for (x = x1; x <= x2; x++) {
582           pixel = row + x;
583 
584           dR = colors[*pixel].r;
585           dG = colors[*pixel].g;
586           dB = colors[*pixel].b;
587 
588           dR = dR + ((sR - dR) * alpha >> 8);
589           dG = dG + ((sG - dG) * alpha >> 8);
590           dB = dB + ((sB - dB) * alpha >> 8);
591 
592           *pixel = SDL_MapRGB(format, dR, dG, dB);
593         }
594       }
595     }
596     break;
597 
598   case 2:
599     {     /* Probably 15-bpp or 16-bpp */
600       Uint16 *row, *pixel;
601       Uint32 dR, dG, dB, dA;
602       Rmask = format->Rmask;
603       Gmask = format->Gmask;
604       Bmask = format->Bmask;
605       Amask = format->Amask;
606 
607       dR = (color & Rmask);
608       dG = (color & Gmask);
609       dB = (color & Bmask);
610       dA = (color & Amask);
611 
612       A = 0;
613 
614       for (y = y1; y <= y2; y++) {
615         row = (Uint16 *) dst->pixels + y * dst->pitch / 2;
616         for (x = x1; x <= x2; x++) {
617           pixel = row + x;
618 
619           R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask;
620           G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask;
621           B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask;
622           if (Amask)
623           {
624             A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask;
625             *pixel = R | G | B | A;
626           } else {
627             *pixel = R | G | B;
628           }
629         }
630       }
631     }
632     break;
633 
634   case 3:
635     {     /* Slow 24-bpp mode, usually not used */
636       Uint8 *row, *pix;
637       Uint8 dR, dG, dB, dA;
638       Uint8 Rshift8, Gshift8, Bshift8, Ashift8;
639 
640       Rshift = format->Rshift;
641       Gshift = format->Gshift;
642       Bshift = format->Bshift;
643       Ashift = format->Ashift;
644 
645       Rshift8 = Rshift / 8;
646       Gshift8 = Gshift / 8;
647       Bshift8 = Bshift / 8;
648       Ashift8 = Ashift / 8;
649 
650       sR = (color >> Rshift) & 0xff;
651       sG = (color >> Gshift) & 0xff;
652       sB = (color >> Bshift) & 0xff;
653       sA = (color >> Ashift) & 0xff;
654 
655       for (y = y1; y <= y2; y++) {
656         row = (Uint8 *) dst->pixels + y * dst->pitch;
657         for (x = x1; x <= x2; x++) {
658           pix = row + x * 3;
659 
660           dR = *((pix) + Rshift8);
661           dG = *((pix) + Gshift8);
662           dB = *((pix) + Bshift8);
663           dA = *((pix) + Ashift8);
664 
665           dR = dR + ((sR - dR) * alpha >> 8);
666           dG = dG + ((sG - dG) * alpha >> 8);
667           dB = dB + ((sB - dB) * alpha >> 8);
668           dA = dA + ((sA - dA) * alpha >> 8);
669 
670           *((pix) + Rshift8) = dR;
671           *((pix) + Gshift8) = dG;
672           *((pix) + Bshift8) = dB;
673           *((pix) + Ashift8) = dA;
674         }
675       }
676     }
677     break;
678 
679 #ifdef DEFAULT_ALPHA_PIXEL_ROUTINE
680   case 4:
681     {     /* Probably :-) 32-bpp */
682       Uint32 *row, *pixel;
683       Uint32 dR, dG, dB, dA;
684 
685       Rmask = format->Rmask;
686       Gmask = format->Gmask;
687       Bmask = format->Bmask;
688       Amask = format->Amask;
689 
690       Rshift = format->Rshift;
691       Gshift = format->Gshift;
692       Bshift = format->Bshift;
693       Ashift = format->Ashift;
694 
695       dR = (color & Rmask);
696       dG = (color & Gmask);
697       dB = (color & Bmask);
698       dA = (color & Amask);
699 
700       for (y = y1; y <= y2; y++) {
701         row = (Uint32 *) dst->pixels + y * dst->pitch / 4;
702         for (x = x1; x <= x2; x++) {
703           pixel = row + x;
704 
705           R = ((*pixel & Rmask) + ((((dR - (*pixel & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask;
706           G = ((*pixel & Gmask) + ((((dG - (*pixel & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask;
707           B = ((*pixel & Bmask) + ((((dB - (*pixel & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask;
708           if (Amask)
709           {
710             A = ((*pixel & Amask) + ((((dA - (*pixel & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask;
711             *pixel = R | G | B | A;
712           } else {
713             *pixel = R | G | B;
714           }
715         }
716       }
717     }
718     break;
719 #endif
720 
721 #ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
722   case 4:{      /* Probably :-) 32-bpp */
723     Uint32 *row, *pixel;
724     Uint32 dR, dG, dB, dA;
725     Uint32 dc;
726     Uint32 surfaceAlpha, preMultR, preMultG, preMultB;
727     Uint32 aTmp;
728 
729     Rmask = format->Rmask;
730     Gmask = format->Gmask;
731     Bmask = format->Bmask;
732     Amask = format->Amask;
733 
734     dR = (color & Rmask);
735     dG = (color & Gmask);
736     dB = (color & Bmask);
737     dA = (color & Amask);
738 
739     Rshift = format->Rshift;
740     Gshift = format->Gshift;
741     Bshift = format->Bshift;
742     Ashift = format->Ashift;
743 
744     preMultR = (alpha * (dR >> Rshift));
745     preMultG = (alpha * (dG >> Gshift));
746     preMultB = (alpha * (dB >> Bshift));
747 
748     for (y = y1; y <= y2; y++) {
749       row = (Uint32 *) dst->pixels + y * dst->pitch / 4;
750       for (x = x1; x <= x2; x++) {
751         pixel = row + x;
752         dc = *pixel;
753 
754         surfaceAlpha = ((dc & Amask) >> Ashift);
755         aTmp = (255 - alpha);
756         if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) {
757           aTmp *= surfaceAlpha;
758           R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask;
759           G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask;
760           B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask;
761         }
762         *pixel = R | G | B | (A << Ashift & Amask);
763 
764       }
765     }
766        }
767        break;
768 #endif
769 
770   }
771 
772   return (0);
773 }
774 
775 /*!
776 \brief Draw filled rectangle of RGBA color with alpha blending.
777 
778 \param dst The surface to draw on.
779 \param x1 X coordinate of the first corner (upper left) of the rectangle.
780 \param y1 Y coordinate of the first corner (upper left) of the rectangle.
781 \param x2 X coordinate of the second corner (lower right) of the rectangle.
782 \param y2 Y coordinate of the second corner (lower right) of the rectangle.
783 \param color The color value of the rectangle to draw (0xRRGGBBAA).
784 
785 \returns Returns 0 on success, -1 on failure.
786 */
filledRectAlpha(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)787 int filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
788 {
789   Uint8 alpha;
790   Uint32 mcolor;
791   int result = 0;
792 
793   /*
794   * Lock the surface
795   */
796   if (SDL_MUSTLOCK(dst)) {
797     if (SDL_LockSurface(dst) < 0) {
798       return (-1);
799     }
800   }
801 
802   /*
803   * Setup color
804   */
805   alpha = color & 0x000000ff;
806   mcolor =
807     SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
808     (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
809 
810   /*
811   * Draw
812   */
813   result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha);
814 
815   /*
816   * Unlock the surface
817   */
818   if (SDL_MUSTLOCK(dst)) {
819     SDL_UnlockSurface(dst);
820   }
821 
822   return (result);
823 }
824 
825 /*!
826 \brief Internal function to draw horizontal line of RGBA color with alpha blending.
827 
828 \param dst The surface to draw on.
829 \param x1 X coordinate of the first point (i.e. left) of the line.
830 \param x2 X coordinate of the second point (i.e. right) of the line.
831 \param y Y coordinate of the points of the line.
832 \param color The color value of the line to draw (0xRRGGBBAA).
833 
834 \returns Returns 0 on success, -1 on failure.
835 */
_HLineAlpha(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)836 int _HLineAlpha(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
837 {
838   return (filledRectAlpha(dst, x1, y, x2, y, color));
839 }
840 
841 /*!
842 \brief Internal function to draw vertical line of RGBA color with alpha blending.
843 
844 \param dst The surface to draw on.
845 \param x X coordinate of the points of the line.
846 \param y1 Y coordinate of the first point (top) of the line.
847 \param y2 Y coordinate of the second point (bottom) of the line.
848 \param color The color value of the line to draw (0xRRGGBBAA).
849 
850 \returns Returns 0 on success, -1 on failure.
851 */
_VLineAlpha(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)852 int _VLineAlpha(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
853 {
854   return (filledRectAlpha(dst, x, y1, x, y2, color));
855 }
856 
857 /*!
858 \brief Pixel draw with blending enabled and using alpha weight on color.
859 
860 \param dst The surface to draw on.
861 \param x The horizontal coordinate of the pixel.
862 \param y The vertical position of the pixel.
863 \param color The color value of the pixel to draw (0xRRGGBBAA).
864 \param weight The weight multiplied into the alpha value of the pixel.
865 
866 \returns Returns 0 on success, -1 on failure.
867 */
pixelColorWeight(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)868 int pixelColorWeight(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
869 {
870   Uint32 a;
871 
872   /*
873   * Get alpha
874   */
875   a = (color & (Uint32) 0x000000ff);
876 
877   /*
878   * Modify Alpha by weight
879   */
880   a = ((a * weight) >> 8);
881 
882   return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
883 }
884 
885 /*!
886 \brief Pixel draw with blending enabled and using alpha weight on color - no locking.
887 
888 \param dst The surface to draw on.
889 \param x The horizontal coordinate of the pixel.
890 \param y The vertical position of the pixel.
891 \param color The color value of the pixel to draw (0xRRGGBBAA).
892 \param weight The weight multiplied into the alpha value of the pixel.
893 
894 \returns Returns 0 on success, -1 on failure.
895 */
pixelColorWeightNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)896 int pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
897 {
898   Uint32 a;
899 
900   /*
901   * Get alpha
902   */
903   a = (color & (Uint32) 0x000000ff);
904 
905   /*
906   * Modify Alpha by weight
907   */
908   a = ((a * weight) >> 8);
909 
910   return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
911 }
912 
913 /*!
914 \brief Pixel draw with blending enabled if a<255.
915 
916 \param dst The surface to draw on.
917 \param x X (horizontal) coordinate of the pixel.
918 \param y Y (vertical) coordinate of the pixel.
919 \param r The red color value of the pixel to draw.
920 \param g The green color value of the pixel to draw.
921 \param b The blue color value of the pixel to draw.
922 \param a The alpha value of the pixel to draw.
923 
924 \returns Returns 0 on success, -1 on failure.
925 */
pixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)926 int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
927 {
928   Uint32 color;
929 
930   /*
931   * Check Alpha
932   */
933   if (a == 255) {
934     /*
935     * No alpha blending required
936     */
937     /*
938     * Setup color
939     */
940     color = SDL_MapRGBA(dst->format, r, g, b, a);
941     /*
942     * Draw
943     */
944     return (fastPixelColor(dst, x, y, color));
945   } else {
946     /*
947     * Alpha blending required
948     */
949     /*
950     * Draw
951     */
952     return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
953   }
954 }
955 
956 
957 /*!
958 \brief Draw horizontal line without blending;
959 
960 Just stores the color value (including the alpha component) without blending.
961 Only the same number of bits of the destination surface are transfered
962 from the input color value.
963 
964 \param dst The surface to draw on.
965 \param x1 X coordinate of the first point (i.e. left) of the line.
966 \param x2 X coordinate of the second point (i.e. right) of the line.
967 \param y Y coordinate of the points of the line.
968 \param color The color value of the line to draw.
969 
970 \returns Returns 0 on success, -1 on failure.
971 */
hlineColorStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)972 int hlineColorStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
973 {
974   Sint16 left, right, top, bottom;
975   Uint8 *pixel, *pixellast;
976   int dx;
977   int pixx, pixy;
978   Sint16 w;
979   Sint16 xtmp;
980   int result = -1;
981 
982   /*
983   * Check visibility of clipping rectangle
984   */
985   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
986     return(0);
987   }
988 
989   /*
990   * Swap x1, x2 if required to ensure x1<=x2
991   */
992   if (x1 > x2) {
993     xtmp = x1;
994     x1 = x2;
995     x2 = xtmp;
996   }
997 
998   /*
999   * Get clipping boundary and
1000   * check visibility of hline
1001   */
1002   left = dst->clip_rect.x;
1003   if (x2<left) {
1004     return(0);
1005   }
1006   right = dst->clip_rect.x + dst->clip_rect.w - 1;
1007   if (x1>right) {
1008     return(0);
1009   }
1010   top = dst->clip_rect.y;
1011   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1012   if ((y<top) || (y>bottom)) {
1013     return (0);
1014   }
1015 
1016   /*
1017   * Clip x
1018   */
1019   if (x1 < left) {
1020     x1 = left;
1021   }
1022   if (x2 > right) {
1023     x2 = right;
1024   }
1025 
1026   /*
1027   * Calculate width
1028   */
1029   w = x2 - x1;
1030 
1031   /*
1032   * Lock the surface
1033   */
1034   if (SDL_MUSTLOCK(dst)) {
1035     if (SDL_LockSurface(dst) < 0) {
1036       return (-1);
1037     }
1038   }
1039 
1040   /*
1041   * More variable setup
1042   */
1043   dx = w;
1044   pixx = dst->format->BytesPerPixel;
1045   pixy = dst->pitch;
1046   pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
1047 
1048   /*
1049   * Draw
1050   */
1051   switch (dst->format->BytesPerPixel) {
1052   case 1:
1053     memset(pixel, color, dx+1);
1054     break;
1055   case 2:
1056     pixellast = pixel + dx + dx;
1057     for (; pixel <= pixellast; pixel += pixx) {
1058       *(Uint16 *) pixel = color;
1059     }
1060     break;
1061   case 3:
1062     pixellast = pixel + dx + dx + dx;
1063     for (; pixel <= pixellast; pixel += pixx) {
1064       if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1065         pixel[0] = (color >> 16) & 0xff;
1066         pixel[1] = (color >> 8) & 0xff;
1067         pixel[2] = color & 0xff;
1068       } else {
1069         pixel[0] = color & 0xff;
1070         pixel[1] = (color >> 8) & 0xff;
1071         pixel[2] = (color >> 16) & 0xff;
1072       }
1073     }
1074     break;
1075   default:    /* case 4 */
1076     dx = dx + dx;
1077     pixellast = pixel + dx + dx;
1078     for (; pixel <= pixellast; pixel += pixx) {
1079       *(Uint32 *) pixel = color;
1080     }
1081     break;
1082   }
1083 
1084   /*
1085   * Unlock surface
1086   */
1087   if (SDL_MUSTLOCK(dst)) {
1088     SDL_UnlockSurface(dst);
1089   }
1090 
1091   /*
1092   * Set result code
1093   */
1094   result = 0;
1095 
1096   return (result);
1097 }
1098 
1099 /*!
1100 \brief Draw horizontal line without blending
1101 
1102 Just stores the color value (including the alpha component) without blending.
1103 Function should only be used for 32 bit target surfaces.
1104 
1105 \param dst The surface to draw on.
1106 \param x1 X coordinate of the first point (i.e. left) of the line.
1107 \param x2 X coordinate of the second point (i.e. right) of the line.
1108 \param y Y coordinate of the points of the line.
1109 \param r The red value of the line to draw.
1110 \param g The green value of the line to draw.
1111 \param b The blue value of the line to draw.
1112 \param a The alpha value of the line to draw.
1113 
1114 \returns Returns 0 on success, -1 on failure.
1115 */
hlineRGBAStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1116 int hlineRGBAStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1117 {
1118   /*
1119   * Draw
1120   */
1121   return (hlineColorStore(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1122 }
1123 
1124 /*!
1125 \brief Draw horizontal line with blending.
1126 
1127 \param dst The surface to draw on.
1128 \param x1 X coordinate of the first point (i.e. left) of the line.
1129 \param x2 X coordinate of the second point (i.e. right) of the line.
1130 \param y Y coordinate of the points of the line.
1131 \param color The color value of the line to draw (0xRRGGBBAA).
1132 
1133 \returns Returns 0 on success, -1 on failure.
1134 */
hlineColor(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)1135 int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
1136 {
1137   Sint16 left, right, top, bottom;
1138   Uint8 *pixel, *pixellast;
1139   int dx;
1140   int pixx, pixy;
1141   Sint16 xtmp;
1142   int result = -1;
1143   Uint8 *colorptr;
1144   Uint8 color3[3];
1145 
1146   /*
1147   * Check visibility of clipping rectangle
1148   */
1149   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1150     return(0);
1151   }
1152 
1153   /*
1154   * Swap x1, x2 if required to ensure x1<=x2
1155   */
1156   if (x1 > x2) {
1157     xtmp = x1;
1158     x1 = x2;
1159     x2 = xtmp;
1160   }
1161 
1162   /*
1163   * Get clipping boundary and
1164   * check visibility of hline
1165   */
1166   left = dst->clip_rect.x;
1167   if (x2<left) {
1168     return(0);
1169   }
1170   right = dst->clip_rect.x + dst->clip_rect.w - 1;
1171   if (x1>right) {
1172     return(0);
1173   }
1174   top = dst->clip_rect.y;
1175   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1176   if ((y<top) || (y>bottom)) {
1177     return (0);
1178   }
1179 
1180   /*
1181   * Clip x
1182   */
1183   if (x1 < left) {
1184     x1 = left;
1185   }
1186   if (x2 > right) {
1187     x2 = right;
1188   }
1189 
1190   /*
1191   * Calculate width difference
1192   */
1193   dx = x2 - x1;
1194 
1195   /*
1196   * Alpha check
1197   */
1198   if ((color & 255) == 255) {
1199 
1200     /*
1201     * No alpha-blending required
1202     */
1203 
1204     /*
1205     * Setup color
1206     */
1207     colorptr = (Uint8 *) & color;
1208     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1209       color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1210     } else {
1211       color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1212     }
1213 
1214     /*
1215     * Lock the surface
1216     */
1217     if (SDL_MUSTLOCK(dst)) {
1218       if (SDL_LockSurface(dst) < 0) {
1219         return (-1);
1220       }
1221     }
1222 
1223     /*
1224     * More variable setup
1225     */
1226     pixx = dst->format->BytesPerPixel;
1227     pixy = dst->pitch;
1228     pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
1229 
1230     /*
1231     * Draw
1232     */
1233     switch (dst->format->BytesPerPixel) {
1234   case 1:
1235     memset(pixel, color, dx + 1);
1236     break;
1237   case 2:
1238     pixellast = pixel + dx + dx;
1239     for (; pixel <= pixellast; pixel += pixx) {
1240       *(Uint16 *) pixel = color;
1241     }
1242     break;
1243   case 3:
1244     pixellast = pixel + dx + dx + dx;
1245     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1246       color3[0] = (color >> 16) & 0xff;
1247       color3[1] = (color >> 8) & 0xff;
1248       color3[2] = color & 0xff;
1249     } else {
1250       color3[0] = color & 0xff;
1251       color3[1] = (color >> 8) & 0xff;
1252       color3[2] = (color >> 16) & 0xff;
1253     }
1254     for (; pixel <= pixellast; pixel += pixx) {
1255       memcpy(pixel, color3, 3);
1256     }
1257     break;
1258   default:    /* case 4 */
1259     dx = dx + dx;
1260     pixellast = pixel + dx + dx;
1261     for (; pixel <= pixellast; pixel += pixx) {
1262       *(Uint32 *) pixel = color;
1263     }
1264     break;
1265     }
1266 
1267     /*
1268     * Unlock surface
1269     */
1270     if (SDL_MUSTLOCK(dst)) {
1271       SDL_UnlockSurface(dst);
1272     }
1273 
1274     /*
1275     * Set result code
1276     */
1277     result = 0;
1278 
1279   } else {
1280 
1281     /*
1282     * Alpha blending blit
1283     */
1284     result = _HLineAlpha(dst, x1, x1 + dx, y, color);
1285   }
1286 
1287   return (result);
1288 }
1289 
1290 /*!
1291 \brief Draw horizontal line with blending.
1292 
1293 \param dst The surface to draw on.
1294 \param x1 X coordinate of the first point (i.e. left) of the line.
1295 \param x2 X coordinate of the second point (i.e. right) of the line.
1296 \param y Y coordinate of the points of the line.
1297 \param r The red value of the line to draw.
1298 \param g The green value of the line to draw.
1299 \param b The blue value of the line to draw.
1300 \param a The alpha value of the line to draw.
1301 
1302 \returns Returns 0 on success, -1 on failure.
1303 */
hlineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1304 int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1305 {
1306   /*
1307   * Draw
1308   */
1309   return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1310 }
1311 
1312 /*!
1313 \brief Draw vertical line with blending.
1314 
1315 \param dst The surface to draw on.
1316 \param x X coordinate of the points of the line.
1317 \param y1 Y coordinate of the first point (i.e. top) of the line.
1318 \param y2 Y coordinate of the second point (i.e. bottom) of the line.
1319 \param color The color value of the line to draw (0xRRGGBBAA).
1320 
1321 \returns Returns 0 on success, -1 on failure.
1322 */
vlineColor(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)1323 int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
1324 {
1325   Sint16 left, right, top, bottom;
1326   Uint8 *pixel, *pixellast;
1327   int dy;
1328   int pixx, pixy;
1329   Sint16 h;
1330   Sint16 ytmp;
1331   int result = -1;
1332   Uint8 *colorptr;
1333 
1334   /*
1335   * Check visibility of clipping rectangle
1336   */
1337   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1338     return(0);
1339   }
1340 
1341   /*
1342   * Swap y1, y2 if required to ensure y1<=y2
1343   */
1344   if (y1 > y2) {
1345     ytmp = y1;
1346     y1 = y2;
1347     y2 = ytmp;
1348   }
1349 
1350   /*
1351   * Get clipping boundary and
1352   * check visibility of vline
1353   */
1354   left = dst->clip_rect.x;
1355   right = dst->clip_rect.x + dst->clip_rect.w - 1;
1356   if ((x<left) || (x>right)) {
1357     return (0);
1358   }
1359   top = dst->clip_rect.y;
1360   if (y2<top) {
1361     return(0);
1362   }
1363   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1364   if (y1>bottom) {
1365     return(0);
1366   }
1367 
1368   /*
1369   * Clip x
1370   */
1371   if (y1 < top) {
1372     y1 = top;
1373   }
1374   if (y2 > bottom) {
1375     y2 = bottom;
1376   }
1377 
1378   /*
1379   * Calculate height
1380   */
1381   h = y2 - y1;
1382 
1383   /*
1384   * Alpha check
1385   */
1386   if ((color & 255) == 255) {
1387 
1388     /*
1389     * No alpha-blending required
1390     */
1391 
1392     /*
1393     * Setup color
1394     */
1395     colorptr = (Uint8 *) & color;
1396     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1397       color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1398     } else {
1399       color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1400     }
1401 
1402     /*
1403     * Lock the surface
1404     */
1405     if (SDL_MUSTLOCK(dst)) {
1406       if (SDL_LockSurface(dst) < 0) {
1407         return (-1);
1408       }
1409     }
1410 
1411     /*
1412     * More variable setup
1413     */
1414     dy = h;
1415     pixx = dst->format->BytesPerPixel;
1416     pixy = dst->pitch;
1417     pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1;
1418     pixellast = pixel + pixy * dy;
1419 
1420     /*
1421     * Draw
1422     */
1423     switch (dst->format->BytesPerPixel) {
1424   case 1:
1425     for (; pixel <= pixellast; pixel += pixy) {
1426       *(Uint8 *) pixel = color;
1427     }
1428     break;
1429   case 2:
1430     for (; pixel <= pixellast; pixel += pixy) {
1431       *(Uint16 *) pixel = color;
1432     }
1433     break;
1434   case 3:
1435     for (; pixel <= pixellast; pixel += pixy) {
1436       if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1437         pixel[0] = (color >> 16) & 0xff;
1438         pixel[1] = (color >> 8) & 0xff;
1439         pixel[2] = color & 0xff;
1440       } else {
1441         pixel[0] = color & 0xff;
1442         pixel[1] = (color >> 8) & 0xff;
1443         pixel[2] = (color >> 16) & 0xff;
1444       }
1445     }
1446     break;
1447   default:    /* case 4 */
1448     for (; pixel <= pixellast; pixel += pixy) {
1449       *(Uint32 *) pixel = color;
1450     }
1451     break;
1452     }
1453 
1454     /* Unlock surface */
1455     if (SDL_MUSTLOCK(dst)) {
1456       SDL_UnlockSurface(dst);
1457     }
1458 
1459     /*
1460     * Set result code
1461     */
1462     result = 0;
1463 
1464   } else {
1465 
1466     /*
1467     * Alpha blending blit
1468     */
1469 
1470     result = _VLineAlpha(dst, x, y1, y1 + h, color);
1471 
1472   }
1473 
1474   return (result);
1475 }
1476 
1477 /*!
1478 \brief Draw vertical line with blending.
1479 
1480 \param dst The surface to draw on.
1481 \param x X coordinate of the points of the line.
1482 \param y1 Y coordinate of the first point (i.e. top) of the line.
1483 \param y2 Y coordinate of the second point (i.e. bottom) of the line.
1484 \param r The red value of the line to draw.
1485 \param g The green value of the line to draw.
1486 \param b The blue value of the line to draw.
1487 \param a The alpha value of the line to draw.
1488 
1489 \returns Returns 0 on success, -1 on failure.
1490 */
vlineRGBA(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1491 int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1492 {
1493   /*
1494   * Draw
1495   */
1496   return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1497 }
1498 
1499 /*!
1500 \brief Draw rectangle with blending.
1501 
1502 \param dst The surface to draw on.
1503 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1504 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1505 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1506 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1507 \param color The color value of the rectangle to draw (0xRRGGBBAA).
1508 
1509 \returns Returns 0 on success, -1 on failure.
1510 */
rectangleColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1511 int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1512 {
1513   int result;
1514   Sint16 tmp;
1515 
1516   /* Check destination surface */
1517   if (dst == NULL)
1518   {
1519     return -1;
1520   }
1521 
1522   /*
1523   * Check visibility of clipping rectangle
1524   */
1525   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1526     return 0;
1527   }
1528 
1529   /*
1530   * Test for special cases of straight lines or single point
1531   */
1532   if (x1 == x2) {
1533     if (y1 == y2) {
1534       return (pixelColor(dst, x1, y1, color));
1535     } else {
1536       return (vlineColor(dst, x1, y1, y2, color));
1537     }
1538   } else {
1539     if (y1 == y2) {
1540       return (hlineColor(dst, x1, x2, y1, color));
1541     }
1542   }
1543 
1544   /*
1545   * Swap x1, x2 if required
1546   */
1547   if (x1 > x2) {
1548     tmp = x1;
1549     x1 = x2;
1550     x2 = tmp;
1551   }
1552 
1553   /*
1554   * Swap y1, y2 if required
1555   */
1556   if (y1 > y2) {
1557     tmp = y1;
1558     y1 = y2;
1559     y2 = tmp;
1560   }
1561 
1562   /*
1563   * Draw rectangle
1564   */
1565   result = 0;
1566   result |= hlineColor(dst, x1, x2, y1, color);
1567   result |= hlineColor(dst, x1, x2, y2, color);
1568   y1 += 1;
1569   y2 -= 1;
1570   if (y1 <= y2) {
1571     result |= vlineColor(dst, x1, y1, y2, color);
1572     result |= vlineColor(dst, x2, y1, y2, color);
1573   }
1574 
1575   return (result);
1576 
1577 }
1578 
1579 /*!
1580 \brief Draw rectangle with blending.
1581 
1582 \param dst The surface to draw on.
1583 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1584 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1585 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1586 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1587 \param r The red value of the rectangle to draw.
1588 \param g The green value of the rectangle to draw.
1589 \param b The blue value of the rectangle to draw.
1590 \param a The alpha value of the rectangle to draw.
1591 
1592 \returns Returns 0 on success, -1 on failure.
1593 */
rectangleRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1594 int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1595 {
1596   /*
1597   * Draw
1598   */
1599   return (rectangleColor
1600     (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1601 }
1602 
1603 /*!
1604 \brief Draw rounded-corner rectangle with blending.
1605 
1606 \param dst The surface to draw on.
1607 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1608 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1609 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1610 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1611 \param rad The radius of the corner arc.
1612 \param color The color value of the rectangle to draw (0xRRGGBBAA).
1613 
1614 \returns Returns 0 on success, -1 on failure.
1615 */
roundedRectangleColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint32 color)1616 int roundedRectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
1617 {
1618   int result;
1619   Sint16 w, h, tmp;
1620   Sint16 xx1, xx2, yy1, yy2;
1621 
1622   /*
1623   * Check destination surface
1624   */
1625   if (dst == NULL)
1626   {
1627     return -1;
1628   }
1629 
1630   /*
1631   * Check radius vor valid range
1632   */
1633   if (rad < 0) {
1634     return -1;
1635   }
1636 
1637   /*
1638   * Special case - no rounding
1639   */
1640   if (rad == 0) {
1641     return rectangleColor(dst, x1, y1, x2, y2, color);
1642   }
1643 
1644   /*
1645   * Check visibility of clipping rectangle
1646   */
1647   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1648     return 0;
1649   }
1650 
1651   /*
1652   * Test for special cases of straight lines or single point
1653   */
1654   if (x1 == x2) {
1655     if (y1 == y2) {
1656       return (pixelColor(dst, x1, y1, color));
1657     } else {
1658       return (vlineColor(dst, x1, y1, y2, color));
1659     }
1660   } else {
1661     if (y1 == y2) {
1662       return (hlineColor(dst, x1, x2, y1, color));
1663     }
1664   }
1665 
1666   /*
1667   * Swap x1, x2 if required
1668   */
1669   if (x1 > x2) {
1670     tmp = x1;
1671     x1 = x2;
1672     x2 = tmp;
1673   }
1674 
1675   /*
1676   * Swap y1, y2 if required
1677   */
1678   if (y1 > y2) {
1679     tmp = y1;
1680     y1 = y2;
1681     y2 = tmp;
1682   }
1683 
1684   /*
1685   * Calculate width&height
1686   */
1687   w = x2 - x1;
1688   h = y2 - y1;
1689 
1690   /*
1691   * Maybe adjust radius
1692   */
1693   if ((rad * 2) > w)
1694   {
1695     rad = w / 2;
1696   }
1697   if ((rad * 2) > h)
1698   {
1699     rad = h / 2;
1700   }
1701 
1702   /*
1703   * Draw corners
1704   */
1705   result = 0;
1706   xx1 = x1 + rad;
1707   xx2 = x2 - rad;
1708   yy1 = y1 + rad;
1709   yy2 = y2 - rad;
1710   result |= arcColor(dst, xx1, yy1, rad, 180, 270, color);
1711   result |= arcColor(dst, xx2, yy1, rad, 270, 360, color);
1712   result |= arcColor(dst, xx1, yy2, rad,  90, 180, color);
1713   result |= arcColor(dst, xx2, yy2, rad,   0,  90, color);
1714 
1715   /*
1716   * Draw lines
1717   */
1718   if (xx1 <= xx2) {
1719     result |= hlineColor(dst, xx1, xx2, y1, color);
1720     result |= hlineColor(dst, xx1, xx2, y2, color);
1721   }
1722   if (yy1 <= yy2) {
1723     result |= vlineColor(dst, x1, yy1, yy2, color);
1724     result |= vlineColor(dst, x2, yy1, yy2, color);
1725   }
1726 
1727   return result;
1728 }
1729 
1730 /*!
1731 \brief Draw rounded-corner rectangle with blending.
1732 
1733 \param dst The surface to draw on.
1734 \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
1735 \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
1736 \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
1737 \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
1738 \param rad The radius of the corner arc.
1739 \param r The red value of the rectangle to draw.
1740 \param g The green value of the rectangle to draw.
1741 \param b The blue value of the rectangle to draw.
1742 \param a The alpha value of the rectangle to draw.
1743 
1744 \returns Returns 0 on success, -1 on failure.
1745 */
roundedRectangleRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1746 int roundedRectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1747 {
1748   /*
1749   * Draw
1750   */
1751   return (roundedRectangleColor
1752     (dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1753 }
1754 
1755 /*!
1756 \brief Draw rounded-corner box (filled rectangle) with blending.
1757 
1758 \param dst The surface to draw on.
1759 \param x1 X coordinate of the first point (i.e. top right) of the box.
1760 \param y1 Y coordinate of the first point (i.e. top right) of the box.
1761 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
1762 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
1763 \param rad The radius of the corner arcs of the box.
1764 \param color The color value of the box to draw (0xRRGGBBAA).
1765 
1766 \returns Returns 0 on success, -1 on failure.
1767 */
roundedBoxColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint32 color)1768 int roundedBoxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color)
1769 {
1770   int result;
1771   Sint16 w, h, tmp;
1772   Sint16 xx1, xx2, yy1, yy2;
1773 
1774   /*
1775   * Check destination surface
1776   */
1777   if (dst == NULL)
1778   {
1779     return -1;
1780   }
1781 
1782   /*
1783   * Check radius vor valid range
1784   */
1785   if (rad < 0) {
1786     return -1;
1787   }
1788 
1789   /*
1790   * Special case - no rounding
1791   */
1792   if (rad == 0) {
1793     return rectangleColor(dst, x1, y1, x2, y2, color);
1794   }
1795 
1796   /*
1797   * Check visibility of clipping rectangle
1798   */
1799   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1800     return 0;
1801   }
1802 
1803   /*
1804   * Test for special cases of straight lines or single point
1805   */
1806   if (x1 == x2) {
1807     if (y1 == y2) {
1808       return (pixelColor(dst, x1, y1, color));
1809     } else {
1810       return (vlineColor(dst, x1, y1, y2, color));
1811     }
1812   } else {
1813     if (y1 == y2) {
1814       return (hlineColor(dst, x1, x2, y1, color));
1815     }
1816   }
1817 
1818   /*
1819   * Swap x1, x2 if required
1820   */
1821   if (x1 > x2) {
1822     tmp = x1;
1823     x1 = x2;
1824     x2 = tmp;
1825   }
1826 
1827   /*
1828   * Swap y1, y2 if required
1829   */
1830   if (y1 > y2) {
1831     tmp = y1;
1832     y1 = y2;
1833     y2 = tmp;
1834   }
1835 
1836   /*
1837   * Calculate width&height
1838   */
1839   w = x2 - x1;
1840   h = y2 - y1;
1841 
1842   /*
1843   * Maybe adjust radius
1844   */
1845   if ((rad * 2) > w)
1846   {
1847     rad = w / 2;
1848   }
1849   if ((rad * 2) > h)
1850   {
1851     rad = h / 2;
1852   }
1853 
1854   /*
1855   * Draw corners
1856   */
1857   result = 0;
1858   xx1 = x1 + rad;
1859   xx2 = x2 - rad;
1860   yy1 = y1 + rad;
1861   yy2 = y2 - rad;
1862   result |= filledPieColor(dst, xx1, yy1, rad, 180, 270, color);
1863   result |= filledPieColor(dst, xx2, yy1, rad, 270, 360, color);
1864   result |= filledPieColor(dst, xx1, yy2, rad,  90, 180, color);
1865   result |= filledPieColor(dst, xx2, yy2, rad,   0,  90, color);
1866 
1867   /*
1868   * Draw body
1869   */
1870   xx1++;
1871   xx2--;
1872   yy1++;
1873   yy2--;
1874   if (xx1 <= xx2) {
1875     result |= boxColor(dst, xx1, y1, xx2, y2, color);
1876   }
1877   if (yy1 <= yy2) {
1878     result |= boxColor(dst, x1, yy1, xx1-1, yy2, color);
1879     result |= boxColor(dst, xx2+1, yy1, x2, yy2, color);
1880   }
1881 
1882   return result;
1883 }
1884 
1885 /*!
1886 \brief Draw rounded-corner box (filled rectangle) with blending.
1887 
1888 \param dst The surface to draw on.
1889 \param x1 X coordinate of the first point (i.e. top right) of the box.
1890 \param y1 Y coordinate of the first point (i.e. top right) of the box.
1891 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
1892 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
1893 \param rad The radius of the corner arcs of the box.
1894 \param r The red value of the box to draw.
1895 \param g The green value of the box to draw.
1896 \param b The blue value of the box to draw.
1897 \param a The alpha value of the box to draw.
1898 
1899 \returns Returns 0 on success, -1 on failure.
1900 */
roundedBoxRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1901 int roundedBoxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2,
1902            Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1903 {
1904   /*
1905   * Draw
1906   */
1907   return (roundedBoxColor
1908     (dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1909 }
1910 
1911 /* --------- Clipping routines for line */
1912 
1913 /* Clipping based heavily on code from                       */
1914 /* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c   */
1915 
1916 #define CLIP_LEFT_EDGE   0x1
1917 #define CLIP_RIGHT_EDGE  0x2
1918 #define CLIP_BOTTOM_EDGE 0x4
1919 #define CLIP_TOP_EDGE    0x8
1920 #define CLIP_INSIDE(a)   (!a)
1921 #define CLIP_REJECT(a,b) (a&b)
1922 #define CLIP_ACCEPT(a,b) (!(a|b))
1923 
1924 /*!
1925 \brief Internal clip-encoding routine.
1926 
1927 Calculates a segement-based clipping encoding for a point against a rectangle.
1928 
1929 \param x X coordinate of point.
1930 \param y Y coordinate of point.
1931 \param left X coordinate of left edge of the rectangle.
1932 \param top Y coordinate of top edge of the rectangle.
1933 \param right X coordinate of right edge of the rectangle.
1934 \param bottom Y coordinate of bottom edge of the rectangle.
1935 */
_clipEncode(Sint16 x,Sint16 y,Sint16 left,Sint16 top,Sint16 right,Sint16 bottom)1936 static int _clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom)
1937 {
1938   int code = 0;
1939 
1940   if (x < left) {
1941     code |= CLIP_LEFT_EDGE;
1942   } else if (x > right) {
1943     code |= CLIP_RIGHT_EDGE;
1944   }
1945   if (y < top) {
1946     code |= CLIP_TOP_EDGE;
1947   } else if (y > bottom) {
1948     code |= CLIP_BOTTOM_EDGE;
1949   }
1950   return code;
1951 }
1952 
1953 /*!
1954 \brief Clip line to a the clipping rectangle of a surface.
1955 
1956 \param dst Target surface to draw on.
1957 \param x1 Pointer to X coordinate of first point of line.
1958 \param y1 Pointer to Y coordinate of first point of line.
1959 \param x2 Pointer to X coordinate of second point of line.
1960 \param y2 Pointer to Y coordinate of second point of line.
1961 */
_clipLine(SDL_Surface * dst,Sint16 * x1,Sint16 * y1,Sint16 * x2,Sint16 * y2)1962 static int _clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2)
1963 {
1964   Sint16 left, right, top, bottom;
1965   int code1, code2;
1966   int draw = 0;
1967   Sint16 swaptmp;
1968   float m;
1969 
1970   /*
1971   * Get clipping boundary
1972   */
1973   left = dst->clip_rect.x;
1974   right = dst->clip_rect.x + dst->clip_rect.w - 1;
1975   top = dst->clip_rect.y;
1976   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1977 
1978   while (1) {
1979     code1 = _clipEncode(*x1, *y1, left, top, right, bottom);
1980     code2 = _clipEncode(*x2, *y2, left, top, right, bottom);
1981     if (CLIP_ACCEPT(code1, code2)) {
1982       draw = 1;
1983       break;
1984     } else if (CLIP_REJECT(code1, code2))
1985       break;
1986     else {
1987       if (CLIP_INSIDE(code1)) {
1988         swaptmp = *x2;
1989         *x2 = *x1;
1990         *x1 = swaptmp;
1991         swaptmp = *y2;
1992         *y2 = *y1;
1993         *y1 = swaptmp;
1994         swaptmp = code2;
1995         code2 = code1;
1996         code1 = swaptmp;
1997       }
1998       if (*x2 != *x1) {
1999         m = (*y2 - *y1) / (float) (*x2 - *x1);
2000       } else {
2001         m = 1.0f;
2002       }
2003       if (code1 & CLIP_LEFT_EDGE) {
2004         *y1 += (Sint16) ((left - *x1) * m);
2005         *x1 = left;
2006       } else if (code1 & CLIP_RIGHT_EDGE) {
2007         *y1 += (Sint16) ((right - *x1) * m);
2008         *x1 = right;
2009       } else if (code1 & CLIP_BOTTOM_EDGE) {
2010         if (*x2 != *x1) {
2011           *x1 += (Sint16) ((bottom - *y1) / m);
2012         }
2013         *y1 = bottom;
2014       } else if (code1 & CLIP_TOP_EDGE) {
2015         if (*x2 != *x1) {
2016           *x1 += (Sint16) ((top - *y1) / m);
2017         }
2018         *y1 = top;
2019       }
2020     }
2021   }
2022 
2023   return draw;
2024 }
2025 
2026 /*!
2027 \brief Draw box (filled rectangle) with blending.
2028 
2029 \param dst The surface to draw on.
2030 \param x1 X coordinate of the first point (i.e. top right) of the box.
2031 \param y1 Y coordinate of the first point (i.e. top right) of the box.
2032 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
2033 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
2034 \param color The color value of the box to draw (0xRRGGBBAA).
2035 
2036 \returns Returns 0 on success, -1 on failure.
2037 */
boxColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2038 int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2039 {
2040   Sint16 left, right, top, bottom;
2041   Uint8 *pixel, *pixellast;
2042   int x, dx;
2043   int dy;
2044   int pixx, pixy;
2045   Sint16 w, h, tmp;
2046   int result;
2047   Uint8 *colorptr;
2048 
2049   /*
2050   * Check visibility of clipping rectangle
2051   */
2052   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2053     return(0);
2054   }
2055 
2056   /*
2057   * Order coordinates to ensure that
2058   * x1<=x2 and y1<=y2
2059   */
2060   if (x1 > x2) {
2061     tmp = x1;
2062     x1 = x2;
2063     x2 = tmp;
2064   }
2065   if (y1 > y2) {
2066     tmp = y1;
2067     y1 = y2;
2068     y2 = tmp;
2069   }
2070 
2071   /*
2072   * Get clipping boundary and
2073   * check visibility
2074   */
2075   left = dst->clip_rect.x;
2076   if (x2<left) {
2077     return(0);
2078   }
2079   right = dst->clip_rect.x + dst->clip_rect.w - 1;
2080   if (x1>right) {
2081     return(0);
2082   }
2083   top = dst->clip_rect.y;
2084   if (y2<top) {
2085     return(0);
2086   }
2087   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2088   if (y1>bottom) {
2089     return(0);
2090   }
2091 
2092   /* Clip all points */
2093   if (x1<left) {
2094     x1=left;
2095   } else if (x1>right) {
2096     x1=right;
2097   }
2098   if (x2<left) {
2099     x2=left;
2100   } else if (x2>right) {
2101     x2=right;
2102   }
2103   if (y1<top) {
2104     y1=top;
2105   } else if (y1>bottom) {
2106     y1=bottom;
2107   }
2108   if (y2<top) {
2109     y2=top;
2110   } else if (y2>bottom) {
2111     y2=bottom;
2112   }
2113 
2114   /*
2115   * Test for special cases of straight line or single point
2116   */
2117   if (x1 == x2) {
2118     if (y1 == y2) {
2119       return (pixelColor(dst, x1, y1, color));
2120     } else {
2121       return (vlineColor(dst, x1, y1, y2, color));
2122     }
2123   }
2124   if (y1 == y2) {
2125     return (hlineColor(dst, x1, x2, y1, color));
2126   }
2127 
2128   /*
2129   * Calculate width&height
2130   */
2131   w = x2 - x1;
2132   h = y2 - y1;
2133 
2134   /*
2135   * Alpha check
2136   */
2137   if ((color & 255) == 255) {
2138 
2139     /*
2140     * No alpha-blending required
2141     */
2142 
2143     /*
2144     * Setup color
2145     */
2146     colorptr = (Uint8 *) & color;
2147     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2148       color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2149     } else {
2150       color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2151     }
2152 
2153     /*
2154     * Lock the surface
2155     */
2156     if (SDL_MUSTLOCK(dst)) {
2157       if (SDL_LockSurface(dst) < 0) {
2158         return (-1);
2159       }
2160     }
2161 
2162     /*
2163     * More variable setup
2164     */
2165     dx = w;
2166     dy = h;
2167     pixx = dst->format->BytesPerPixel;
2168     pixy = dst->pitch;
2169     pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
2170     pixellast = pixel + pixx * dx + pixy * dy;
2171     dx++;
2172 
2173     /*
2174     * Draw
2175     */
2176     switch (dst->format->BytesPerPixel) {
2177   case 1:
2178     for (; pixel <= pixellast; pixel += pixy) {
2179       memset(pixel, (Uint8) color, dx);
2180     }
2181     break;
2182   case 2:
2183     pixy -= (pixx * dx);
2184     for (; pixel <= pixellast; pixel += pixy) {
2185       for (x = 0; x < dx; x++) {
2186         *(Uint16*) pixel = color;
2187         pixel += pixx;
2188       }
2189     }
2190     break;
2191   case 3:
2192     pixy -= (pixx * dx);
2193     for (; pixel <= pixellast; pixel += pixy) {
2194       for (x = 0; x < dx; x++) {
2195         if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2196           pixel[0] = (color >> 16) & 0xff;
2197           pixel[1] = (color >> 8) & 0xff;
2198           pixel[2] = color & 0xff;
2199         } else {
2200           pixel[0] = color & 0xff;
2201           pixel[1] = (color >> 8) & 0xff;
2202           pixel[2] = (color >> 16) & 0xff;
2203         }
2204         pixel += pixx;
2205       }
2206     }
2207     break;
2208   default:    /* case 4 */
2209     pixy -= (pixx * dx);
2210     for (; pixel <= pixellast; pixel += pixy) {
2211       for (x = 0; x < dx; x++) {
2212         *(Uint32 *) pixel = color;
2213         pixel += pixx;
2214       }
2215     }
2216     break;
2217     }
2218 
2219     /* Unlock surface */
2220     if (SDL_MUSTLOCK(dst)) {
2221       SDL_UnlockSurface(dst);
2222     }
2223 
2224     result = 0;
2225 
2226   } else {
2227 
2228     result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color);
2229 
2230   }
2231 
2232   return (result);
2233 }
2234 
2235 /*!
2236 \brief Draw box (filled rectangle) with blending.
2237 
2238 \param dst The surface to draw on.
2239 \param x1 X coordinate of the first point (i.e. top right) of the box.
2240 \param y1 Y coordinate of the first point (i.e. top right) of the box.
2241 \param x2 X coordinate of the second point (i.e. bottom left) of the box.
2242 \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
2243 \param r The red value of the box to draw.
2244 \param g The green value of the box to draw.
2245 \param b The blue value of the box to draw.
2246 \param a The alpha value of the box to draw.
2247 
2248 \returns Returns 0 on success, -1 on failure.
2249 */
boxRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2250 int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2251 {
2252   /*
2253   * Draw
2254   */
2255   return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2256 }
2257 
2258 /* ----- Line */
2259 
2260 /* Non-alpha line drawing code adapted from routine          */
2261 /* by Pete Shinners, pete@shinners.org                       */
2262 /* Originally from pygame, http://pygame.seul.org            */
2263 
2264 #define ABS(a) (((a)<0) ? -(a) : (a))
2265 
2266 /*!
2267 \brief Draw line with alpha blending.
2268 
2269 \param dst The surface to draw on.
2270 \param x1 X coordinate of the first point of the line.
2271 \param y1 Y coordinate of the first point of the line.
2272 \param x2 X coordinate of the second point of the line.
2273 \param y2 Y coordinate of the second point of the line.
2274 \param color The color value of the line to draw (0xRRGGBBAA).
2275 
2276 \returns Returns 0 on success, -1 on failure.
2277 */
lineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2278 int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2279 {
2280   int pixx, pixy;
2281   int x, y;
2282   int dx, dy;
2283   int ax, ay;
2284   int sx, sy;
2285   int swaptmp;
2286   Uint8 *pixel;
2287   Uint8 *colorptr;
2288 
2289   /*
2290   * Clip line and test if we have to draw
2291   */
2292   if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) {
2293     return (0);
2294   }
2295 
2296   /*
2297   * Test for special cases of straight lines or single point
2298   */
2299   if (x1 == x2) {
2300     if (y1 < y2) {
2301       return (vlineColor(dst, x1, y1, y2, color));
2302     } else if (y1 > y2) {
2303       return (vlineColor(dst, x1, y2, y1, color));
2304     } else {
2305       return (pixelColor(dst, x1, y1, color));
2306     }
2307   }
2308   if (y1 == y2) {
2309     if (x1 < x2) {
2310       return (hlineColor(dst, x1, x2, y1, color));
2311     } else if (x1 > x2) {
2312       return (hlineColor(dst, x2, x1, y1, color));
2313     }
2314   }
2315 
2316   /*
2317   * Variable setup
2318   */
2319   dx = x2 - x1;
2320   dy = y2 - y1;
2321   sx = (dx >= 0) ? 1 : -1;
2322   sy = (dy >= 0) ? 1 : -1;
2323 
2324   /* Lock surface */
2325   if (SDL_MUSTLOCK(dst)) {
2326     if (SDL_LockSurface(dst) < 0) {
2327       return (-1);
2328     }
2329   }
2330 
2331   /*
2332   * Check for alpha blending
2333   */
2334   if ((color & 255) == 255) {
2335 
2336     /*
2337     * No alpha blending - use fast pixel routines
2338     */
2339 
2340     /*
2341     * Setup color
2342     */
2343     colorptr = (Uint8 *) & color;
2344     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2345       color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2346     } else {
2347       color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2348     }
2349 
2350     /*
2351     * More variable setup
2352     */
2353     dx = sx * dx + 1;
2354     dy = sy * dy + 1;
2355     pixx = dst->format->BytesPerPixel;
2356     pixy = dst->pitch;
2357     pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
2358     pixx *= sx;
2359     pixy *= sy;
2360     if (dx < dy) {
2361       swaptmp = dx;
2362       dx = dy;
2363       dy = swaptmp;
2364       swaptmp = pixx;
2365       pixx = pixy;
2366       pixy = swaptmp;
2367     }
2368 
2369     /*
2370     * Draw
2371     */
2372     x = 0;
2373     y = 0;
2374     switch (dst->format->BytesPerPixel) {
2375   case 1:
2376     for (; x < dx; x++, pixel += pixx) {
2377       *pixel = color;
2378       y += dy;
2379       if (y >= dx) {
2380         y -= dx;
2381         pixel += pixy;
2382       }
2383     }
2384     break;
2385   case 2:
2386     for (; x < dx; x++, pixel += pixx) {
2387       *(Uint16 *) pixel = color;
2388       y += dy;
2389       if (y >= dx) {
2390         y -= dx;
2391         pixel += pixy;
2392       }
2393     }
2394     break;
2395   case 3:
2396     for (; x < dx; x++, pixel += pixx) {
2397       if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2398         pixel[0] = (color >> 16) & 0xff;
2399         pixel[1] = (color >> 8) & 0xff;
2400         pixel[2] = color & 0xff;
2401       } else {
2402         pixel[0] = color & 0xff;
2403         pixel[1] = (color >> 8) & 0xff;
2404         pixel[2] = (color >> 16) & 0xff;
2405       }
2406       y += dy;
2407       if (y >= dx) {
2408         y -= dx;
2409         pixel += pixy;
2410       }
2411     }
2412     break;
2413   default:    /* case 4 */
2414     for (; x < dx; x++, pixel += pixx) {
2415       *(Uint32 *) pixel = color;
2416       y += dy;
2417       if (y >= dx) {
2418         y -= dx;
2419         pixel += pixy;
2420       }
2421     }
2422     break;
2423     }
2424 
2425   } else {
2426 
2427     /*
2428     * Alpha blending required - use single-pixel blits
2429     */
2430 
2431     ax = ABS(dx) << 1;
2432     ay = ABS(dy) << 1;
2433     x = x1;
2434     y = y1;
2435     if (ax > ay) {
2436       int d = ay - (ax >> 1);
2437 
2438       while (x != x2) {
2439         pixelColorNolock (dst, x, y, color);
2440         if (d > 0 || (d == 0 && sx == 1)) {
2441           y += sy;
2442           d -= ax;
2443         }
2444         x += sx;
2445         d += ay;
2446       }
2447     } else {
2448       int d = ax - (ay >> 1);
2449 
2450       while (y != y2) {
2451         pixelColorNolock (dst, x, y, color);
2452         if (d > 0 || ((d == 0) && (sy == 1))) {
2453           x += sx;
2454           d -= ay;
2455         }
2456         y += sy;
2457         d += ax;
2458       }
2459     }
2460     pixelColorNolock (dst, x, y, color);
2461 
2462   }
2463 
2464   /* Unlock surface */
2465   if (SDL_MUSTLOCK(dst)) {
2466     SDL_UnlockSurface(dst);
2467   }
2468 
2469   return (0);
2470 }
2471 
2472 /*!
2473 \brief Draw line with alpha blending.
2474 
2475 \param dst The surface to draw on.
2476 \param x1 X coordinate of the first point of the line.
2477 \param y1 Y coordinate of the first point of the line.
2478 \param x2 X coordinate of the second point of the line.
2479 \param y2 Y coordinate of the second point of the line.
2480 \param r The red value of the line to draw.
2481 \param g The green value of the line to draw.
2482 \param b The blue value of the line to draw.
2483 \param a The alpha value of the line to draw.
2484 
2485 \returns Returns 0 on success, -1 on failure.
2486 */
lineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2487 int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2488 {
2489   /*
2490   * Draw
2491   */
2492   return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2493 }
2494 
2495 /* AA Line */
2496 
2497 #define AAlevels 256
2498 #define AAbits 8
2499 
2500 /*!
2501 \brief Internal function to draw anti-aliased line with alpha blending and endpoint control.
2502 
2503 This implementation of the Wu antialiasing code is based on Mike Abrash's
2504 DDJ article which was reprinted as Chapter 42 of his Graphics Programming
2505 Black Book, but has been optimized to work with SDL and utilizes 32-bit
2506 fixed-point arithmetic by A. Schiffler. The endpoint control allows the
2507 supression to draw the last pixel useful for rendering continous aa-lines
2508 with alpha<255.
2509 
2510 \param dst The surface to draw on.
2511 \param x1 X coordinate of the first point of the aa-line.
2512 \param y1 Y coordinate of the first point of the aa-line.
2513 \param x2 X coordinate of the second point of the aa-line.
2514 \param y2 Y coordinate of the second point of the aa-line.
2515 \param color The color value of the aa-line to draw (0xRRGGBBAA).
2516 \param draw_endpoint Flag indicating if the endpoint should be drawn; draw if non-zero.
2517 
2518 \returns Returns 0 on success, -1 on failure.
2519 */
_aalineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,int draw_endpoint)2520 int _aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint)
2521 {
2522   Sint32 xx0, yy0, xx1, yy1;
2523   int result;
2524   Uint32 intshift, erracc, erradj;
2525   Uint32 erracctmp, wgt, wgtcompmask;
2526   int dx, dy, tmp, xdir, y0p1, x0pxdir;
2527 
2528   /*
2529   * Check visibility of clipping rectangle
2530   */
2531   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2532     return(0);
2533   }
2534 
2535   /*
2536   * Clip line and test if we have to draw
2537   */
2538   if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) {
2539     return (0);
2540   }
2541 
2542   /*
2543   * Keep on working with 32bit numbers
2544   */
2545   xx0 = x1;
2546   yy0 = y1;
2547   xx1 = x2;
2548   yy1 = y2;
2549 
2550   /*
2551   * Reorder points if required
2552   */
2553   if (yy0 > yy1) {
2554     tmp = yy0;
2555     yy0 = yy1;
2556     yy1 = tmp;
2557     tmp = xx0;
2558     xx0 = xx1;
2559     xx1 = tmp;
2560   }
2561 
2562   /*
2563   * Calculate distance
2564   */
2565   dx = xx1 - xx0;
2566   dy = yy1 - yy0;
2567 
2568   /*
2569   * Check for special cases
2570   */
2571   if (dx == 0) {
2572     /*
2573     * Vertical line
2574     */
2575     if (draw_endpoint)
2576     {
2577       return (vlineColor(dst, x1, y1, y2, color));
2578     } else {
2579       if (dy>0) {
2580         return (vlineColor(dst, x1, yy0, yy0+dy, color));
2581       } else {
2582         return (pixelColor(dst, x1, y1, color));
2583       }
2584     }
2585   } else if (dy == 0) {
2586     /*
2587     * Horizontal line
2588     */
2589     if (draw_endpoint)
2590     {
2591       return (hlineColor(dst, x1, x2, y1, color));
2592     } else {
2593       if (dx>0) {
2594         return (hlineColor(dst, xx0, xx0+dx, y1, color));
2595       } else {
2596         return (pixelColor(dst, x1, y1, color));
2597       }
2598     }
2599   } else if ((dx == dy) && (draw_endpoint)) {
2600     /*
2601     * Diagonal line (with endpoint)
2602     */
2603     return (lineColor(dst, x1, y1, x2, y2, color));
2604   }
2605 
2606   /*
2607   * Adjust for negative dx and set xdir
2608   */
2609   if (dx >= 0) {
2610     xdir = 1;
2611   } else {
2612     xdir = -1;
2613     dx = (-dx);
2614   }
2615 
2616   /*
2617   * Line is not horizontal, vertical or diagonal (with endpoint)
2618   */
2619   result = 0;
2620 
2621   /*
2622   * Zero accumulator
2623   */
2624   erracc = 0;
2625 
2626   /*
2627   * # of bits by which to shift erracc to get intensity level
2628   */
2629   intshift = 32 - AAbits;
2630 
2631   /*
2632   * Mask used to flip all bits in an intensity weighting
2633   */
2634   wgtcompmask = AAlevels - 1;
2635 
2636   /* Lock surface */
2637   if (SDL_MUSTLOCK(dst)) {
2638     if (SDL_LockSurface(dst) < 0) {
2639       return (-1);
2640     }
2641   }
2642 
2643   /*
2644   * Draw the initial pixel in the foreground color
2645   */
2646   result |= pixelColorNolock(dst, x1, y1, color);
2647 
2648   /*
2649   * x-major or y-major?
2650   */
2651   if (dy > dx) {
2652 
2653     /*
2654     * y-major.  Calculate 16-bit fixed point fractional part of a pixel that
2655     * X advances every time Y advances 1 pixel, truncating the result so that
2656     * we won't overrun the endpoint along the X axis
2657     */
2658     /*
2659     * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
2660     */
2661     erradj = ((dx << 16) / dy) << 16;
2662 
2663     /*
2664     * draw all pixels other than the first and last
2665     */
2666     x0pxdir = xx0 + xdir;
2667     while (--dy) {
2668       erracctmp = erracc;
2669       erracc += erradj;
2670       if (erracc <= erracctmp) {
2671         /*
2672         * rollover in error accumulator, x coord advances
2673         */
2674         xx0 = x0pxdir;
2675         x0pxdir += xdir;
2676       }
2677       yy0++;    /* y-major so always advance Y */
2678 
2679       /*
2680       * the AAbits most significant bits of erracc give us the intensity
2681       * weighting for this pixel, and the complement of the weighting for
2682       * the paired pixel.
2683       */
2684       wgt = (erracc >> intshift) & 255;
2685       result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
2686       result |= pixelColorWeightNolock (dst, x0pxdir, yy0, color, wgt);
2687     }
2688 
2689   } else {
2690 
2691     /*
2692     * x-major line.  Calculate 16-bit fixed-point fractional part of a pixel
2693     * that Y advances each time X advances 1 pixel, truncating the result so
2694     * that we won't overrun the endpoint along the X axis.
2695     */
2696     /*
2697     * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
2698     */
2699     erradj = ((dy << 16) / dx) << 16;
2700 
2701     /*
2702     * draw all pixels other than the first and last
2703     */
2704     y0p1 = yy0 + 1;
2705     while (--dx) {
2706 
2707       erracctmp = erracc;
2708       erracc += erradj;
2709       if (erracc <= erracctmp) {
2710         /*
2711         * Accumulator turned over, advance y
2712         */
2713         yy0 = y0p1;
2714         y0p1++;
2715       }
2716       xx0 += xdir;  /* x-major so always advance X */
2717       /*
2718       * the AAbits most significant bits of erracc give us the intensity
2719       * weighting for this pixel, and the complement of the weighting for
2720       * the paired pixel.
2721       */
2722       wgt = (erracc >> intshift) & 255;
2723       result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
2724       result |= pixelColorWeightNolock (dst, xx0, y0p1, color, wgt);
2725     }
2726   }
2727 
2728   /*
2729   * Do we have to draw the endpoint
2730   */
2731   if (draw_endpoint) {
2732     /*
2733     * Draw final pixel, always exactly intersected by the line and doesn't
2734     * need to be weighted.
2735     */
2736     result |= pixelColorNolock (dst, x2, y2, color);
2737   }
2738 
2739   /* Unlock surface */
2740   if (SDL_MUSTLOCK(dst)) {
2741     SDL_UnlockSurface(dst);
2742   }
2743 
2744   return (result);
2745 }
2746 
2747 /*!
2748 \brief Ddraw anti-aliased line with alpha blending.
2749 
2750 \param dst The surface to draw on.
2751 \param x1 X coordinate of the first point of the aa-line.
2752 \param y1 Y coordinate of the first point of the aa-line.
2753 \param x2 X coordinate of the second point of the aa-line.
2754 \param y2 Y coordinate of the second point of the aa-line.
2755 \param color The color value of the aa-line to draw (0xRRGGBBAA).
2756 
2757 \returns Returns 0 on success, -1 on failure.
2758 */
aalineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2759 int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2760 {
2761   return (_aalineColor(dst, x1, y1, x2, y2, color, 1));
2762 }
2763 
2764 /*!
2765 \brief Draw anti-aliased line with alpha blending.
2766 
2767 \param dst The surface to draw on.
2768 \param x1 X coordinate of the first point of the aa-line.
2769 \param y1 Y coordinate of the first point of the aa-line.
2770 \param x2 X coordinate of the second point of the aa-line.
2771 \param y2 Y coordinate of the second point of the aa-line.
2772 \param r The red value of the aa-line to draw.
2773 \param g The green value of the aa-line to draw.
2774 \param b The blue value of the aa-line to draw.
2775 \param a The alpha value of the aa-line to draw.
2776 
2777 \returns Returns 0 on success, -1 on failure.
2778 */
aalineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2779 int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2780 {
2781   return (_aalineColor
2782     (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
2783 }
2784 
2785 
2786 /* ----- Circle */
2787 
2788 /*!
2789 \brief Draw circle with blending.
2790 
2791 Note: Circle drawing routine is based on an algorithms from the sge library,
2792 but modified by A. Schiffler for multiple pixel-draw removal and other
2793 minor speedup changes.
2794 
2795 \param dst The surface to draw on.
2796 \param x X coordinate of the center of the circle.
2797 \param y Y coordinate of the center of the circle.
2798 \param rad Radius in pixels of the circle.
2799 \param color The color value of the circle to draw (0xRRGGBBAA).
2800 
2801 \returns Returns 0 on success, -1 on failure.
2802 */
circleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)2803 int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
2804 {
2805   Sint16 left, right, top, bottom;
2806   int result;
2807   Sint16 x1, y1, x2, y2;
2808   Sint16 cx = 0;
2809   Sint16 cy = rad;
2810   Sint16 ocx = (Sint16) 0xffff;
2811   Sint16 ocy = (Sint16) 0xffff;
2812   Sint16 df = 1 - rad;
2813   Sint16 d_e = 3;
2814   Sint16 d_se = -2 * rad + 5;
2815   Sint16 xpcx, xmcx, xpcy, xmcy;
2816   Sint16 ypcy, ymcy, ypcx, ymcx;
2817   Uint8 *colorptr;
2818 
2819   /*
2820   * Check visibility of clipping rectangle
2821   */
2822   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2823     return(0);
2824   }
2825 
2826   /*
2827   * Sanity check radius
2828   */
2829   if (rad < 0) {
2830     return (-1);
2831   }
2832 
2833   /*
2834   * Special case for rad=0 - draw a point
2835   */
2836   if (rad == 0) {
2837     return (pixelColor(dst, x, y, color));
2838   }
2839 
2840   /*
2841   * Get circle and clipping boundary and
2842   * test if bounding box of circle is visible
2843   */
2844   x2 = x + rad;
2845   left = dst->clip_rect.x;
2846   if (x2<left) {
2847     return(0);
2848   }
2849   x1 = x - rad;
2850   right = dst->clip_rect.x + dst->clip_rect.w - 1;
2851   if (x1>right) {
2852     return(0);
2853   }
2854   y2 = y + rad;
2855   top = dst->clip_rect.y;
2856   if (y2<top) {
2857     return(0);
2858   }
2859   y1 = y - rad;
2860   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2861   if (y1>bottom) {
2862     return(0);
2863   }
2864 
2865   /*
2866   * Draw circle
2867   */
2868   result = 0;
2869 
2870   /* Lock surface */
2871   if (SDL_MUSTLOCK(dst)) {
2872     if (SDL_LockSurface(dst) < 0) {
2873       return (-1);
2874     }
2875   }
2876 
2877   /*
2878   * Alpha Check
2879   */
2880   if ((color & 255) == 255) {
2881 
2882     /*
2883     * No Alpha - direct memory writes
2884     */
2885 
2886     /*
2887     * Setup color
2888     */
2889     colorptr = (Uint8 *) & color;
2890     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2891       color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2892     } else {
2893       color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2894     }
2895 
2896     /*
2897     * Draw
2898     */
2899     do {
2900       ypcy = y + cy;
2901       ymcy = y - cy;
2902       if (cx > 0) {
2903         xpcx = x + cx;
2904         xmcx = x - cx;
2905         result |= fastPixelColorNolock(dst, xmcx, ypcy, color);
2906         result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
2907         result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
2908         result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
2909       } else {
2910         result |= fastPixelColorNolock(dst, x, ymcy, color);
2911         result |= fastPixelColorNolock(dst, x, ypcy, color);
2912       }
2913       xpcy = x + cy;
2914       xmcy = x - cy;
2915       if ((cx > 0) && (cx != cy)) {
2916         ypcx = y + cx;
2917         ymcx = y - cx;
2918         result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
2919         result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
2920         result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
2921         result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
2922       } else if (cx == 0) {
2923         result |= fastPixelColorNolock(dst, xmcy, y, color);
2924         result |= fastPixelColorNolock(dst, xpcy, y, color);
2925       }
2926       /*
2927       * Update
2928       */
2929       if (df < 0) {
2930         df += d_e;
2931         d_e += 2;
2932         d_se += 2;
2933       } else {
2934         df += d_se;
2935         d_e += 2;
2936         d_se += 4;
2937         cy--;
2938       }
2939       cx++;
2940     } while (cx <= cy);
2941 
2942     /*
2943     * Unlock surface
2944     */
2945     SDL_UnlockSurface(dst);
2946 
2947   } else {
2948 
2949     /*
2950     * Using Alpha - blended pixel blits
2951     */
2952 
2953     do {
2954       /*
2955       * Draw
2956       */
2957       ypcy = y + cy;
2958       ymcy = y - cy;
2959       if (cx > 0) {
2960         xpcx = x + cx;
2961         xmcx = x - cx;
2962         result |= pixelColorNolock (dst, xmcx, ypcy, color);
2963         result |= pixelColorNolock (dst, xpcx, ypcy, color);
2964         result |= pixelColorNolock (dst, xmcx, ymcy, color);
2965         result |= pixelColorNolock (dst, xpcx, ymcy, color);
2966       } else {
2967         result |= pixelColorNolock (dst, x, ymcy, color);
2968         result |= pixelColorNolock (dst, x, ypcy, color);
2969       }
2970       xpcy = x + cy;
2971       xmcy = x - cy;
2972       if ((cx > 0) && (cx != cy)) {
2973         ypcx = y + cx;
2974         ymcx = y - cx;
2975         result |= pixelColorNolock (dst, xmcy, ypcx, color);
2976         result |= pixelColorNolock (dst, xpcy, ypcx, color);
2977         result |= pixelColorNolock (dst, xmcy, ymcx, color);
2978         result |= pixelColorNolock (dst, xpcy, ymcx, color);
2979       } else if (cx == 0) {
2980         result |= pixelColorNolock (dst, xmcy, y, color);
2981         result |= pixelColorNolock (dst, xpcy, y, color);
2982       }
2983       /*
2984       * Update
2985       */
2986       if (df < 0) {
2987         df += d_e;
2988         d_e += 2;
2989         d_se += 2;
2990       } else {
2991         df += d_se;
2992         d_e += 2;
2993         d_se += 4;
2994         cy--;
2995       }
2996       cx++;
2997     } while (cx <= cy);
2998 
2999   }       /* Alpha check */
3000 
3001   /* Unlock surface */
3002   if (SDL_MUSTLOCK(dst)) {
3003     SDL_UnlockSurface(dst);
3004   }
3005 
3006   return (result);
3007 }
3008 
3009 /*!
3010 \brief Draw circle with blending.
3011 
3012 \param dst The surface to draw on.
3013 \param x X coordinate of the center of the circle.
3014 \param y Y coordinate of the center of the circle.
3015 \param rad Radius in pixels of the circle.
3016 \param r The red value of the circle to draw.
3017 \param g The green value of the circle to draw.
3018 \param b The blue value of the circle to draw.
3019 \param a The alpha value of the circle to draw.
3020 
3021 \returns Returns 0 on success, -1 on failure.
3022 */
circleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3023 int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3024 {
3025   /*
3026   * Draw
3027   */
3028   return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3029 }
3030 
3031 /* ----- Arc */
3032 
3033 /*!
3034 \brief Arc with blending.
3035 
3036 Note Arc drawing is based on circle algorithm by A. Schiffler and
3037 written by D. Raber. Calculates which octants arc goes through and
3038 renders pixels accordingly.
3039 
3040 \param dst The surface to draw on.
3041 \param x X coordinate of the center of the arc.
3042 \param y Y coordinate of the center of the arc.
3043 \param rad Radius in pixels of the arc.
3044 \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3045 \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3046 \param color The color value of the arc to draw (0xRRGGBBAA).
3047 
3048 \returns Returns 0 on success, -1 on failure.
3049 */
arcColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)3050 int arcColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
3051 {
3052   Sint16 left, right, top, bottom;
3053   int result;
3054   Sint16 x1, y1, x2, y2;
3055   Sint16 cx = 0;
3056   Sint16 cy = rad;
3057   Sint16 ocx = (Sint16) 0xffff;
3058   Sint16 ocy = (Sint16) 0xffff;
3059   Sint16 df = 1 - rad;
3060   Sint16 d_e = 3;
3061   Sint16 d_se = -2 * rad + 5;
3062   Sint16 xpcx, xmcx, xpcy, xmcy;
3063   Sint16 ypcy, ymcy, ypcx, ymcx;
3064   Uint8 *colorptr;
3065   Uint8 drawoct;
3066   int startoct, endoct, oct, stopval_start, stopval_end;
3067   double temp;
3068 
3069   /*
3070   * Check visibility of clipping rectangle
3071   */
3072   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3073     return(0);
3074   }
3075 
3076   /*
3077   * Sanity check radius
3078   */
3079   if (rad < 0) {
3080     return (-1);
3081   }
3082 
3083   /*
3084   * Special case for rad=0 - draw a point
3085   */
3086   if (rad == 0) {
3087     return (pixelColor(dst, x, y, color));
3088   }
3089 
3090   /*
3091   * Get arc's circle and clipping boundary and
3092   * test if bounding box of circle is visible
3093   */
3094   x2 = x + rad;
3095   left = dst->clip_rect.x;
3096   if (x2<left) {
3097     return(0);
3098   }
3099   x1 = x - rad;
3100   right = dst->clip_rect.x + dst->clip_rect.w - 1;
3101   if (x1>right) {
3102     return(0);
3103   }
3104   y2 = y + rad;
3105   top = dst->clip_rect.y;
3106   if (y2<top) {
3107     return(0);
3108   }
3109   y1 = y - rad;
3110   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3111   if (y1>bottom) {
3112     return(0);
3113   }
3114 
3115   // Octant labelling
3116   //
3117   //  \ 5 | 6 /
3118   //   \  |  /
3119   //  4 \ | / 7
3120   //     \|/
3121   //------+------ +x
3122   //     /|\
3123   //  3 / | \ 0
3124   //   /  |  \
3125   //  / 2 | 1 \
3126   //      +y
3127 
3128   // Initially reset bitmask to 0x00000000
3129   // the set whether or not to keep drawing a given octant.
3130   // For example: 0x00111100 means we're drawing in octants 2-5
3131   drawoct = 0;
3132 
3133   /*
3134   * Fixup angles
3135   */
3136   start %= 360;
3137   end %= 360;
3138   // 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
3139   while (start < 0) start += 360;
3140   while (end < 0) end += 360;
3141   start %= 360;
3142   end %= 360;
3143 
3144   // now, we find which octants we're drawing in.
3145   startoct = start / 45;
3146   endoct = end / 45;
3147   oct = startoct - 1; // we increment as first step in loop
3148 
3149   // stopval_start, stopval_end;
3150   // what values of cx to stop at.
3151   do {
3152     oct = (oct + 1) % 8;
3153 
3154     if (oct == startoct) {
3155       // need to compute stopval_start for this octant.  Look at picture above if this is unclear
3156       switch (oct)
3157       {
3158       case 0:
3159       case 3:
3160         temp = sin(start * M_PI / 180);
3161         break;
3162       case 1:
3163       case 6:
3164         temp = cos(start * M_PI / 180);
3165         break;
3166       case 2:
3167       case 5:
3168         temp = -cos(start * M_PI / 180);
3169         break;
3170       case 4:
3171       case 7:
3172         temp = -sin(start * M_PI / 180);
3173         break;
3174       }
3175       temp *= rad;
3176       stopval_start = (int)temp; // always round down.
3177       // This isn't arbitrary, but requires graph paper to explain well.
3178       // The basic idea is that we're always changing drawoct after we draw, so we
3179       // stop immediately after we render the last sensible pixel at x = ((int)temp).
3180 
3181       // and whether to draw in this octant initially
3182       if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
3183       else     drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
3184     }
3185     if (oct == endoct) {
3186       // need to compute stopval_end for this octant
3187       switch (oct)
3188       {
3189       case 0:
3190       case 3:
3191         temp = sin(end * M_PI / 180);
3192         break;
3193       case 1:
3194       case 6:
3195         temp = cos(end * M_PI / 180);
3196         break;
3197       case 2:
3198       case 5:
3199         temp = -cos(end * M_PI / 180);
3200         break;
3201       case 4:
3202       case 7:
3203         temp = -sin(end * M_PI / 180);
3204         break;
3205       }
3206       temp *= rad;
3207       stopval_end = (int)temp;
3208 
3209       // and whether to draw in this octant initially
3210       if (startoct == endoct) {
3211         // note:      we start drawing, stop, then start again in this case
3212         // otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
3213         if (start > end) {
3214           // unfortunately, if we're in the same octant and need to draw over the whole circle,
3215           // we need to set the rest to true, because the while loop will end at the bottom.
3216           drawoct = 255;
3217         } else {
3218           drawoct &= 255 - (1 << oct);
3219         }
3220       }
3221       else if (oct % 2) drawoct &= 255 - (1 << oct);
3222       else        drawoct |= (1 << oct);
3223     } else if (oct != startoct) { // already verified that it's != endoct
3224       drawoct |= (1 << oct); // draw this entire segment
3225     }
3226   } while (oct != endoct);
3227 
3228   // so now we have what octants to draw and when to draw them.  all that's left is the actual raster code.
3229 
3230   /* Lock surface */
3231   if (SDL_MUSTLOCK(dst)) {
3232     if (SDL_LockSurface(dst) < 0) {
3233       return (-1);
3234     }
3235   }
3236 
3237   /*
3238   * Draw arc
3239   */
3240   result = 0;
3241 
3242   /*
3243   * Alpha Check
3244   */
3245   if ((color & 255) == 255) {
3246 
3247     /*
3248     * No Alpha - direct memory writes
3249     */
3250 
3251     /*
3252     * Setup color
3253     */
3254     colorptr = (Uint8 *) & color;
3255     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
3256       color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
3257     } else {
3258       color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
3259     }
3260 
3261     /*
3262     * Draw
3263     */
3264     do {
3265       ypcy = y + cy;
3266       ymcy = y - cy;
3267       if (cx > 0) {
3268         xpcx = x + cx;
3269         xmcx = x - cx;
3270         // always check if we're drawing a certain octant before adding a pixel to that octant.
3271         if (drawoct & 4)  result |= fastPixelColorNolock(dst, xmcx, ypcy, color); // drawoct & 4 = 22; drawoct[2]
3272         if (drawoct & 2)  result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
3273         if (drawoct & 32) result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
3274         if (drawoct & 64) result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
3275       } else {
3276         if (drawoct & 6)  result |= fastPixelColorNolock(dst, x, ypcy, color); // 4 + 2; drawoct[2] || drawoct[1]
3277         if (drawoct & 96) result |= fastPixelColorNolock(dst, x, ymcy, color); // 32 + 64
3278       }
3279 
3280       xpcy = x + cy;
3281       xmcy = x - cy;
3282       if (cx > 0 && cx != cy) {
3283         ypcx = y + cx;
3284         ymcx = y - cx;
3285         if (drawoct & 8)   result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
3286         if (drawoct & 1)   result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
3287         if (drawoct & 16)  result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
3288         if (drawoct & 128) result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
3289       } else if (cx == 0) {
3290         if (drawoct & 24)  result |= fastPixelColorNolock(dst, xmcy, y, color); // 8 + 16
3291         if (drawoct & 129) result |= fastPixelColorNolock(dst, xpcy, y, color); // 1 + 128
3292       }
3293 
3294       /*
3295       * Update whether we're drawing an octant
3296       */
3297       if (stopval_start == cx) {
3298         // works like an on-off switch because start & end may be in the same octant.
3299         if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
3300         else drawoct |= (1 << startoct);
3301       }
3302       if (stopval_end == cx) {
3303         if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
3304         else drawoct |= (1 << endoct);
3305       }
3306 
3307       /*
3308       * Update pixels
3309       */
3310       if (df < 0) {
3311         df += d_e;
3312         d_e += 2;
3313         d_se += 2;
3314       } else {
3315         df += d_se;
3316         d_e += 2;
3317         d_se += 4;
3318         cy--;
3319       }
3320       cx++;
3321     } while (cx <= cy);
3322 
3323     /*
3324     * Unlock surface
3325     */
3326     SDL_UnlockSurface(dst);
3327 
3328   } else {
3329 
3330     /*
3331     * Using Alpha - blended pixel blits
3332     */
3333 
3334     do {
3335       ypcy = y + cy;
3336       ymcy = y - cy;
3337       if (cx > 0) {
3338         xpcx = x + cx;
3339         xmcx = x - cx;
3340 
3341         // always check if we're drawing a certain octant before adding a pixel to that octant.
3342         if (drawoct & 4)  result |= pixelColorNolock(dst, xmcx, ypcy, color);
3343         if (drawoct & 2)  result |= pixelColorNolock(dst, xpcx, ypcy, color);
3344         if (drawoct & 32) result |= pixelColorNolock(dst, xmcx, ymcy, color);
3345         if (drawoct & 64) result |= pixelColorNolock(dst, xpcx, ymcy, color);
3346       } else {
3347         if (drawoct & 96) result |= pixelColorNolock(dst, x, ymcy, color);
3348         if (drawoct & 6)  result |= pixelColorNolock(dst, x, ypcy, color);
3349       }
3350 
3351       xpcy = x + cy;
3352       xmcy = x - cy;
3353       if (cx > 0 && cx != cy) {
3354         ypcx = y + cx;
3355         ymcx = y - cx;
3356         if (drawoct & 8)   result |= pixelColorNolock(dst, xmcy, ypcx, color);
3357         if (drawoct & 1)   result |= pixelColorNolock(dst, xpcy, ypcx, color);
3358         if (drawoct & 16)  result |= pixelColorNolock(dst, xmcy, ymcx, color);
3359         if (drawoct & 128) result |= pixelColorNolock(dst, xpcy, ymcx, color);
3360       } else if (cx == 0) {
3361         if (drawoct & 24)  result |= pixelColorNolock(dst, xmcy, y, color);
3362         if (drawoct & 129) result |= pixelColorNolock(dst, xpcy, y, color);
3363       }
3364 
3365       /*
3366       * Update whether we're drawing an octant
3367       */
3368       if (stopval_start == cx) {
3369         // works like an on-off switch.
3370         // This is just in case start & end are in the same octant.
3371         if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
3372         else               drawoct |= (1 << startoct);
3373       }
3374       if (stopval_end == cx) {
3375         if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
3376         else             drawoct |= (1 << endoct);
3377       }
3378 
3379       /*
3380       * Update pixels
3381       */
3382       if (df < 0) {
3383         df += d_e;
3384         d_e += 2;
3385         d_se += 2;
3386       } else {
3387         df += d_se;
3388         d_e += 2;
3389         d_se += 4;
3390         cy--;
3391       }
3392       cx++;
3393     } while (cx <= cy);
3394 
3395   }       /* Alpha check */
3396 
3397   /* Unlock surface */
3398   if (SDL_MUSTLOCK(dst)) {
3399     SDL_UnlockSurface(dst);
3400   }
3401 
3402   return (result);
3403 }
3404 
3405 /*!
3406 \brief Arc with blending.
3407 
3408 \param dst The surface to draw on.
3409 \param x X coordinate of the center of the arc.
3410 \param y Y coordinate of the center of the arc.
3411 \param rad Radius in pixels of the arc.
3412 \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3413 \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
3414 \param r The red value of the arc to draw.
3415 \param g The green value of the arc to draw.
3416 \param b The blue value of the arc to draw.
3417 \param a The alpha value of the arc to draw.
3418 
3419 \returns Returns 0 on success, -1 on failure.
3420 */
arcRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3421 int arcRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3422 {
3423   /*
3424   * Draw
3425   */
3426   return (arcColor(dst, x, y, rad, start, end, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3427 }
3428 
3429 /* ----- AA Circle */
3430 
3431 
3432 /*!
3433 \brief Draw anti-aliased circle with blending.
3434 
3435 Note: The AA-circle routine is based on AA-ellipse with identical radii.
3436 
3437 \param dst The surface to draw on.
3438 \param x X coordinate of the center of the aa-circle.
3439 \param y Y coordinate of the center of the aa-circle.
3440 \param rad Radius in pixels of the aa-circle.
3441 \param color The color value of the aa-circle to draw (0xRRGGBBAA).
3442 
3443 \returns Returns 0 on success, -1 on failure.
3444 */
aacircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)3445 int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
3446 {
3447   return (aaellipseColor(dst, x, y, rad, rad, color));
3448 }
3449 
3450 /*!
3451 \brief Draw anti-aliased circle with blending.
3452 
3453 \param dst The surface to draw on.
3454 \param x X coordinate of the center of the aa-circle.
3455 \param y Y coordinate of the center of the aa-circle.
3456 \param rad Radius in pixels of the aa-circle.
3457 \param r The red value of the aa-circle to draw.
3458 \param g The green value of the aa-circle to draw.
3459 \param b The blue value of the aa-circle to draw.
3460 \param a The alpha value of the aa-circle to draw.
3461 
3462 \returns Returns 0 on success, -1 on failure.
3463 */
aacircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3464 int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3465 {
3466   /*
3467   * Draw
3468   */
3469   return (aaellipseColor
3470     (dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3471 }
3472 
3473 /* ----- Filled Circle */
3474 
3475 /*!
3476 \brief Draw filled circle with blending.
3477 
3478 Note: Based on algorithms from sge library with modifications by A. Schiffler for
3479 multiple-hline draw removal and other minor speedup changes.
3480 
3481 \param dst The surface to draw on.
3482 \param x X coordinate of the center of the filled circle.
3483 \param y Y coordinate of the center of the filled circle.
3484 \param rad Radius in pixels of the filled circle.
3485 \param color The color value of the filled circle to draw (0xRRGGBBAA).
3486 
3487 \returns Returns 0 on success, -1 on failure.
3488 */
filledCircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint32 color)3489 int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color)
3490 {
3491   Sint16 left, right, top, bottom;
3492   int result;
3493   Sint16 x1, y1, x2, y2;
3494   Sint16 cx = 0;
3495   Sint16 cy = rad;
3496   Sint16 ocx = (Sint16) 0xffff;
3497   Sint16 ocy = (Sint16) 0xffff;
3498   Sint16 df = 1 - rad;
3499   Sint16 d_e = 3;
3500   Sint16 d_se = -2 * rad + 5;
3501   Sint16 xpcx, xmcx, xpcy, xmcy;
3502   Sint16 ypcy, ymcy, ypcx, ymcx;
3503 
3504   /*
3505   * Check visibility of clipping rectangle
3506   */
3507   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3508     return(0);
3509   }
3510 
3511   /*
3512   * Sanity check radius
3513   */
3514   if (rad < 0) {
3515     return (-1);
3516   }
3517 
3518   /*
3519   * Special case for rad=0 - draw a point
3520   */
3521   if (rad == 0) {
3522     return (pixelColor(dst, x, y, color));
3523   }
3524 
3525   /*
3526   * Get circle and clipping boundary and
3527   * test if bounding box of circle is visible
3528   */
3529   x2 = x + rad;
3530   left = dst->clip_rect.x;
3531   if (x2<left) {
3532     return(0);
3533   }
3534   x1 = x - rad;
3535   right = dst->clip_rect.x + dst->clip_rect.w - 1;
3536   if (x1>right) {
3537     return(0);
3538   }
3539   y2 = y + rad;
3540   top = dst->clip_rect.y;
3541   if (y2<top) {
3542     return(0);
3543   }
3544   y1 = y - rad;
3545   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3546   if (y1>bottom) {
3547     return(0);
3548   }
3549 
3550   /*
3551   * Draw
3552   */
3553   result = 0;
3554   do {
3555     xpcx = x + cx;
3556     xmcx = x - cx;
3557     xpcy = x + cy;
3558     xmcy = x - cy;
3559     if (ocy != cy) {
3560       if (cy > 0) {
3561         ypcy = y + cy;
3562         ymcy = y - cy;
3563         result |= hlineColor(dst, xmcx, xpcx, ypcy, color);
3564         result |= hlineColor(dst, xmcx, xpcx, ymcy, color);
3565       } else {
3566         result |= hlineColor(dst, xmcx, xpcx, y, color);
3567       }
3568       ocy = cy;
3569     }
3570     if (ocx != cx) {
3571       if (cx != cy) {
3572         if (cx > 0) {
3573           ypcx = y + cx;
3574           ymcx = y - cx;
3575           result |= hlineColor(dst, xmcy, xpcy, ymcx, color);
3576           result |= hlineColor(dst, xmcy, xpcy, ypcx, color);
3577         } else {
3578           result |= hlineColor(dst, xmcy, xpcy, y, color);
3579         }
3580       }
3581       ocx = cx;
3582     }
3583     /*
3584     * Update
3585     */
3586     if (df < 0) {
3587       df += d_e;
3588       d_e += 2;
3589       d_se += 2;
3590     } else {
3591       df += d_se;
3592       d_e += 2;
3593       d_se += 4;
3594       cy--;
3595     }
3596     cx++;
3597   } while (cx <= cy);
3598 
3599   return (result);
3600 }
3601 
3602 /*!
3603 \brief Draw filled circle with blending.
3604 
3605 \param dst The surface to draw on.
3606 \param x X coordinate of the center of the filled circle.
3607 \param y Y coordinate of the center of the filled circle.
3608 \param rad Radius in pixels of the filled circle.
3609 \param r The red value of the filled circle to draw.
3610 \param g The green value of the filled circle to draw.
3611 \param b The blue value of the filled circle to draw.
3612 \param a The alpha value of the filled circle to draw.
3613 
3614 \returns Returns 0 on success, -1 on failure.
3615 */
filledCircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3616 int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3617 {
3618   /*
3619   * Draw
3620   */
3621   return (filledCircleColor
3622     (dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3623 }
3624 
3625 /* ----- Ellipse */
3626 
3627 /*!
3628 \brief Draw ellipse with blending.
3629 
3630 Note: Based on algorithms from sge library with modifications by A. Schiffler for
3631 multiple-pixel draw removal and other minor speedup changes.
3632 
3633 \param dst The surface to draw on.
3634 \param x X coordinate of the center of the ellipse.
3635 \param y Y coordinate of the center of the ellipse.
3636 \param rx Horizontal radius in pixels of the ellipse.
3637 \param ry Vertical radius in pixels of the ellipse.
3638 \param color The color value of the ellipse to draw (0xRRGGBBAA).
3639 
3640 \returns Returns 0 on success, -1 on failure.
3641 */
ellipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)3642 int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
3643 {
3644   Sint16 left, right, top, bottom;
3645   int result;
3646   Sint16 x1, y1, x2, y2;
3647   int ix, iy;
3648   int h, i, j, k;
3649   int oh, oi, oj, ok;
3650   int xmh, xph, ypk, ymk;
3651   int xmi, xpi, ymj, ypj;
3652   int xmj, xpj, ymi, ypi;
3653   int xmk, xpk, ymh, yph;
3654   Uint8 *colorptr;
3655 
3656   /*
3657   * Check visibility of clipping rectangle
3658   */
3659   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3660     return(0);
3661   }
3662 
3663   /*
3664   * Sanity check radii
3665   */
3666   if ((rx < 0) || (ry < 0)) {
3667     return (-1);
3668   }
3669 
3670   /*
3671   * Special case for rx=0 - draw a vline
3672   */
3673   if (rx == 0) {
3674     return (vlineColor(dst, x, y - ry, y + ry, color));
3675   }
3676   /*
3677   * Special case for ry=0 - draw a hline
3678   */
3679   if (ry == 0) {
3680     return (hlineColor(dst, x - rx, x + rx, y, color));
3681   }
3682 
3683   /*
3684   * Get circle and clipping boundary and
3685   * test if bounding box of circle is visible
3686   */
3687   x2 = x + rx;
3688   left = dst->clip_rect.x;
3689   if (x2<left) {
3690     return(0);
3691   }
3692   x1 = x - rx;
3693   right = dst->clip_rect.x + dst->clip_rect.w - 1;
3694   if (x1>right) {
3695     return(0);
3696   }
3697   y2 = y + ry;
3698   top = dst->clip_rect.y;
3699   if (y2<top) {
3700     return(0);
3701   }
3702   y1 = y - ry;
3703   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3704   if (y1>bottom) {
3705     return(0);
3706   }
3707 
3708   /*
3709   * Init vars
3710   */
3711   oh = oi = oj = ok = 0xFFFF;
3712 
3713   /*
3714   * Draw
3715   */
3716   result = 0;
3717 
3718   /* Lock surface */
3719   if (SDL_MUSTLOCK(dst)) {
3720     if (SDL_LockSurface(dst) < 0) {
3721       return (-1);
3722     }
3723   }
3724 
3725   /*
3726   * Check alpha
3727   */
3728   if ((color & 255) == 255) {
3729 
3730     /*
3731     * No Alpha - direct memory writes
3732     */
3733 
3734     /*
3735     * Setup color
3736     */
3737     colorptr = (Uint8 *) & color;
3738     if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
3739       color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
3740     } else {
3741       color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
3742     }
3743 
3744 
3745     if (rx > ry) {
3746       ix = 0;
3747       iy = rx * 64;
3748 
3749       do {
3750         h = (ix + 32) >> 6;
3751         i = (iy + 32) >> 6;
3752         j = (h * ry) / rx;
3753         k = (i * ry) / rx;
3754 
3755         if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
3756           xph = x + h;
3757           xmh = x - h;
3758           if (k > 0) {
3759             ypk = y + k;
3760             ymk = y - k;
3761             result |= fastPixelColorNolock(dst, xmh, ypk, color);
3762             result |= fastPixelColorNolock(dst, xph, ypk, color);
3763             result |= fastPixelColorNolock(dst, xmh, ymk, color);
3764             result |= fastPixelColorNolock(dst, xph, ymk, color);
3765           } else {
3766             result |= fastPixelColorNolock(dst, xmh, y, color);
3767             result |= fastPixelColorNolock(dst, xph, y, color);
3768           }
3769           ok = k;
3770           xpi = x + i;
3771           xmi = x - i;
3772           if (j > 0) {
3773             ypj = y + j;
3774             ymj = y - j;
3775             result |= fastPixelColorNolock(dst, xmi, ypj, color);
3776             result |= fastPixelColorNolock(dst, xpi, ypj, color);
3777             result |= fastPixelColorNolock(dst, xmi, ymj, color);
3778             result |= fastPixelColorNolock(dst, xpi, ymj, color);
3779           } else {
3780             result |= fastPixelColorNolock(dst, xmi, y, color);
3781             result |= fastPixelColorNolock(dst, xpi, y, color);
3782           }
3783           oj = j;
3784         }
3785 
3786         ix = ix + iy / rx;
3787         iy = iy - ix / rx;
3788 
3789       } while (i > h);
3790     } else {
3791       ix = 0;
3792       iy = ry * 64;
3793 
3794       do {
3795         h = (ix + 32) >> 6;
3796         i = (iy + 32) >> 6;
3797         j = (h * rx) / ry;
3798         k = (i * rx) / ry;
3799 
3800         if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3801           xmj = x - j;
3802           xpj = x + j;
3803           if (i > 0) {
3804             ypi = y + i;
3805             ymi = y - i;
3806             result |= fastPixelColorNolock(dst, xmj, ypi, color);
3807             result |= fastPixelColorNolock(dst, xpj, ypi, color);
3808             result |= fastPixelColorNolock(dst, xmj, ymi, color);
3809             result |= fastPixelColorNolock(dst, xpj, ymi, color);
3810           } else {
3811             result |= fastPixelColorNolock(dst, xmj, y, color);
3812             result |= fastPixelColorNolock(dst, xpj, y, color);
3813           }
3814           oi = i;
3815           xmk = x - k;
3816           xpk = x + k;
3817           if (h > 0) {
3818             yph = y + h;
3819             ymh = y - h;
3820             result |= fastPixelColorNolock(dst, xmk, yph, color);
3821             result |= fastPixelColorNolock(dst, xpk, yph, color);
3822             result |= fastPixelColorNolock(dst, xmk, ymh, color);
3823             result |= fastPixelColorNolock(dst, xpk, ymh, color);
3824           } else {
3825             result |= fastPixelColorNolock(dst, xmk, y, color);
3826             result |= fastPixelColorNolock(dst, xpk, y, color);
3827           }
3828           oh = h;
3829         }
3830 
3831         ix = ix + iy / ry;
3832         iy = iy - ix / ry;
3833 
3834       } while (i > h);
3835     }
3836 
3837   } else {
3838 
3839     if (rx > ry) {
3840       ix = 0;
3841       iy = rx * 64;
3842 
3843       do {
3844         h = (ix + 32) >> 6;
3845         i = (iy + 32) >> 6;
3846         j = (h * ry) / rx;
3847         k = (i * ry) / rx;
3848 
3849         if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
3850           xph = x + h;
3851           xmh = x - h;
3852           if (k > 0) {
3853             ypk = y + k;
3854             ymk = y - k;
3855             result |= pixelColorNolock (dst, xmh, ypk, color);
3856             result |= pixelColorNolock (dst, xph, ypk, color);
3857             result |= pixelColorNolock (dst, xmh, ymk, color);
3858             result |= pixelColorNolock (dst, xph, ymk, color);
3859           } else {
3860             result |= pixelColorNolock (dst, xmh, y, color);
3861             result |= pixelColorNolock (dst, xph, y, color);
3862           }
3863           ok = k;
3864           xpi = x + i;
3865           xmi = x - i;
3866           if (j > 0) {
3867             ypj = y + j;
3868             ymj = y - j;
3869             result |= pixelColorNolock (dst, xmi, ypj, color);
3870             result |= pixelColorNolock (dst, xpi, ypj, color);
3871             result |= pixelColorNolock (dst, xmi, ymj, color);
3872             result |= pixelColor(dst, xpi, ymj, color);
3873           } else {
3874             result |= pixelColorNolock (dst, xmi, y, color);
3875             result |= pixelColorNolock (dst, xpi, y, color);
3876           }
3877           oj = j;
3878         }
3879 
3880         ix = ix + iy / rx;
3881         iy = iy - ix / rx;
3882 
3883       } while (i > h);
3884     } else {
3885       ix = 0;
3886       iy = ry * 64;
3887 
3888       do {
3889         h = (ix + 32) >> 6;
3890         i = (iy + 32) >> 6;
3891         j = (h * rx) / ry;
3892         k = (i * rx) / ry;
3893 
3894         if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3895           xmj = x - j;
3896           xpj = x + j;
3897           if (i > 0) {
3898             ypi = y + i;
3899             ymi = y - i;
3900             result |= pixelColorNolock (dst, xmj, ypi, color);
3901             result |= pixelColorNolock (dst, xpj, ypi, color);
3902             result |= pixelColorNolock (dst, xmj, ymi, color);
3903             result |= pixelColorNolock (dst, xpj, ymi, color);
3904           } else {
3905             result |= pixelColorNolock (dst, xmj, y, color);
3906             result |= pixelColorNolock (dst, xpj, y, color);
3907           }
3908           oi = i;
3909           xmk = x - k;
3910           xpk = x + k;
3911           if (h > 0) {
3912             yph = y + h;
3913             ymh = y - h;
3914             result |= pixelColorNolock (dst, xmk, yph, color);
3915             result |= pixelColorNolock (dst, xpk, yph, color);
3916             result |= pixelColorNolock (dst, xmk, ymh, color);
3917             result |= pixelColorNolock (dst, xpk, ymh, color);
3918           } else {
3919             result |= pixelColorNolock (dst, xmk, y, color);
3920             result |= pixelColorNolock (dst, xpk, y, color);
3921           }
3922           oh = h;
3923         }
3924 
3925         ix = ix + iy / ry;
3926         iy = iy - ix / ry;
3927 
3928       } while (i > h);
3929     }
3930 
3931   }       /* Alpha check */
3932 
3933   /* Unlock surface */
3934   if (SDL_MUSTLOCK(dst)) {
3935     SDL_UnlockSurface(dst);
3936   }
3937 
3938   return (result);
3939 }
3940 
3941 /*!
3942 \brief Draw ellipse with blending.
3943 
3944 \param dst The surface to draw on.
3945 \param x X coordinate of the center of the ellipse.
3946 \param y Y coordinate of the center of the ellipse.
3947 \param rx Horizontal radius in pixels of the ellipse.
3948 \param ry Vertical radius in pixels of the ellipse.
3949 \param r The red value of the ellipse to draw.
3950 \param g The green value of the ellipse to draw.
3951 \param b The blue value of the ellipse to draw.
3952 \param a The alpha value of the ellipse to draw.
3953 
3954 \returns Returns 0 on success, -1 on failure.
3955 */
ellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3956 int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3957 {
3958   /*
3959   * Draw
3960   */
3961   return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3962 }
3963 
3964 /* ----- AA Ellipse */
3965 
3966 /* Win32 does not have lrint, so provide a local inline version */
3967 #if defined(_MSC_VER)
3968 /* Detect 64bit and use intrinsic version */
3969 #ifdef _M_X64
3970 #include <emmintrin.h>
3971 static __inline long
lrint(float f)3972 lrint(float f)
3973 {
3974   return _mm_cvtss_si32(_mm_load_ss(&f));
3975 }
3976 #elif defined(_M_IX86)
3977 __inline long int
lrint(double flt)3978 lrint (double flt)
3979 {
3980   int intgr;
3981   _asm
3982   {
3983     fld flt
3984       fistp intgr
3985   };
3986   return intgr;
3987 }
3988 #else
3989 #error lrint needed for MSVC on non X86/AMD64 targets.
3990 #endif
3991 #endif
3992 
3993 /*!
3994 \brief Draw anti-aliased ellipse with blending.
3995 
3996 Note: Based on code from Anders Lindstroem, which is based on code from sge library,
3997 which is based on code from TwinLib.
3998 
3999 \param dst The surface to draw on.
4000 \param x X coordinate of the center of the aa-ellipse.
4001 \param y Y coordinate of the center of the aa-ellipse.
4002 \param rx Horizontal radius in pixels of the aa-ellipse.
4003 \param ry Vertical radius in pixels of the aa-ellipse.
4004 \param color The color value of the aa-ellipse to draw (0xRRGGBBAA).
4005 
4006 \returns Returns 0 on success, -1 on failure.
4007 */
aaellipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)4008 int aaellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
4009 {
4010   Sint16 left, right, top, bottom;
4011   Sint16 x1,y1,x2,y2;
4012   int i;
4013   int a2, b2, ds, dt, dxt, t, s, d;
4014   Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2;
4015   float cp;
4016   double sab;
4017   Uint8 weight, iweight;
4018   int result;
4019 
4020   /*
4021   * Check visibility of clipping rectangle
4022   */
4023   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4024     return(0);
4025   }
4026 
4027   /*
4028   * Sanity check radii
4029   */
4030   if ((rx < 0) || (ry < 0)) {
4031     return (-1);
4032   }
4033 
4034   /*
4035   * Special case for rx=0 - draw a vline
4036   */
4037   if (rx == 0) {
4038     return (vlineColor(dst, x, y - ry, y + ry, color));
4039   }
4040   /*
4041   * Special case for ry=0 - draw an hline
4042   */
4043   if (ry == 0) {
4044     return (hlineColor(dst, x - rx, x + rx, y, color));
4045   }
4046 
4047   /*
4048   * Get circle and clipping boundary and
4049   * test if bounding box of circle is visible
4050   */
4051   x2 = x + rx;
4052   left = dst->clip_rect.x;
4053   if (x2<left) {
4054     return(0);
4055   }
4056   x1 = x - rx;
4057   right = dst->clip_rect.x + dst->clip_rect.w - 1;
4058   if (x1>right) {
4059     return(0);
4060   }
4061   y2 = y + ry;
4062   top = dst->clip_rect.y;
4063   if (y2<top) {
4064     return(0);
4065   }
4066   y1 = y - ry;
4067   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4068   if (y1>bottom) {
4069     return(0);
4070   }
4071 
4072   /* Variable setup */
4073   a2 = rx * rx;
4074   b2 = ry * ry;
4075 
4076   ds = 2 * a2;
4077   dt = 2 * b2;
4078 
4079   xc2 = 2 * x;
4080   yc2 = 2 * y;
4081 
4082   sab = sqrt(a2 + b2);
4083   od = (Sint16)lrint(sab*0.01) + 1; /* introduce some overdraw */
4084   dxt = (Sint16)lrint((double)a2 / sab) + od;
4085 
4086   t = 0;
4087   s = -2 * a2 * ry;
4088   d = 0;
4089 
4090   xp = x;
4091   yp = y - ry;
4092 
4093   /* Lock surface */
4094   if (SDL_MUSTLOCK(dst)) {
4095     if (SDL_LockSurface(dst) < 0) {
4096       return (-1);
4097     }
4098   }
4099 
4100   /* Draw */
4101   result = 0;
4102 
4103   /* "End points" */
4104   result |= pixelColorNolock(dst, xp, yp, color);
4105   result |= pixelColorNolock(dst, xc2 - xp, yp, color);
4106   result |= pixelColorNolock(dst, xp, yc2 - yp, color);
4107   result |= pixelColorNolock(dst, xc2 - xp, yc2 - yp, color);
4108 
4109   for (i = 1; i <= dxt; i++) {
4110     xp--;
4111     d += t - b2;
4112 
4113     if (d >= 0)
4114       ys = yp - 1;
4115     else if ((d - s - a2) > 0) {
4116       if ((2 * d - s - a2) >= 0)
4117         ys = yp + 1;
4118       else {
4119         ys = yp;
4120         yp++;
4121         d -= s + a2;
4122         s += ds;
4123       }
4124     } else {
4125       yp++;
4126       ys = yp + 1;
4127       d -= s + a2;
4128       s += ds;
4129     }
4130 
4131     t -= dt;
4132 
4133     /* Calculate alpha */
4134     if (s != 0.0) {
4135       cp = (float) abs(d) / (float) abs(s);
4136       if (cp > 1.0) {
4137         cp = 1.0;
4138       }
4139     } else {
4140       cp = 1.0;
4141     }
4142 
4143     /* Calculate weights */
4144     weight = (Uint8) (cp * 255);
4145     iweight = 255 - weight;
4146 
4147     /* Upper half */
4148     xx = xc2 - xp;
4149     result |= pixelColorWeightNolock(dst, xp, yp, color, iweight);
4150     result |= pixelColorWeightNolock(dst, xx, yp, color, iweight);
4151 
4152     result |= pixelColorWeightNolock(dst, xp, ys, color, weight);
4153     result |= pixelColorWeightNolock(dst, xx, ys, color, weight);
4154 
4155     /* Lower half */
4156     yy = yc2 - yp;
4157     result |= pixelColorWeightNolock(dst, xp, yy, color, iweight);
4158     result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
4159 
4160     yy = yc2 - ys;
4161     result |= pixelColorWeightNolock(dst, xp, yy, color, weight);
4162     result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
4163   }
4164 
4165   /* Replaces original approximation code dyt = abs(yp - yc); */
4166   dyt = (Sint16)lrint((double)b2 / sab ) + od;
4167 
4168   for (i = 1; i <= dyt; i++) {
4169     yp++;
4170     d -= s + a2;
4171 
4172     if (d <= 0)
4173       xs = xp + 1;
4174     else if ((d + t - b2) < 0) {
4175       if ((2 * d + t - b2) <= 0)
4176         xs = xp - 1;
4177       else {
4178         xs = xp;
4179         xp--;
4180         d += t - b2;
4181         t -= dt;
4182       }
4183     } else {
4184       xp--;
4185       xs = xp - 1;
4186       d += t - b2;
4187       t -= dt;
4188     }
4189 
4190     s += ds;
4191 
4192     /* Calculate alpha */
4193     if (t != 0.0) {
4194       cp = (float) abs(d) / (float) abs(t);
4195       if (cp > 1.0) {
4196         cp = 1.0;
4197       }
4198     } else {
4199       cp = 1.0;
4200     }
4201 
4202     /* Calculate weight */
4203     weight = (Uint8) (cp * 255);
4204     iweight = 255 - weight;
4205 
4206     /* Left half */
4207     xx = xc2 - xp;
4208     yy = yc2 - yp;
4209     result |= pixelColorWeightNolock(dst, xp, yp, color, iweight);
4210     result |= pixelColorWeightNolock(dst, xx, yp, color, iweight);
4211 
4212     result |= pixelColorWeightNolock(dst, xp, yy, color, iweight);
4213     result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
4214 
4215     /* Right half */
4216     xx = xc2 - xs;
4217     result |= pixelColorWeightNolock(dst, xs, yp, color, weight);
4218     result |= pixelColorWeightNolock(dst, xx, yp, color, weight);
4219 
4220     result |= pixelColorWeightNolock(dst, xs, yy, color, weight);
4221     result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
4222 
4223   }
4224 
4225   /* Unlock surface */
4226   if (SDL_MUSTLOCK(dst)) {
4227     SDL_UnlockSurface(dst);
4228   }
4229 
4230   return (result);
4231 }
4232 
4233 /*!
4234 \brief Draw anti-aliased ellipse with blending.
4235 
4236 \param dst The surface to draw on.
4237 \param x X coordinate of the center of the aa-ellipse.
4238 \param y Y coordinate of the center of the aa-ellipse.
4239 \param rx Horizontal radius in pixels of the aa-ellipse.
4240 \param ry Vertical radius in pixels of the aa-ellipse.
4241 \param r The red value of the aa-ellipse to draw.
4242 \param g The green value of the aa-ellipse to draw.
4243 \param b The blue value of the aa-ellipse to draw.
4244 \param a The alpha value of the aa-ellipse to draw.
4245 
4246 \returns Returns 0 on success, -1 on failure.
4247 */
aaellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4248 int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4249 {
4250   /*
4251   * Draw
4252   */
4253   return (aaellipseColor
4254     (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4255 }
4256 
4257 /* ---- Filled Ellipse */
4258 
4259 /* Note: */
4260 /* Based on algorithm from sge library with multiple-hline draw removal */
4261 /* and other speedup changes. */
4262 
4263 /*!
4264 \brief Draw filled ellipse with blending.
4265 
4266 Note: Based on algorithm from sge library with multiple-hline draw removal
4267 and other speedup changes.
4268 
4269 \param dst The surface to draw on.
4270 \param x X coordinate of the center of the filled ellipse.
4271 \param y Y coordinate of the center of the filled ellipse.
4272 \param rx Horizontal radius in pixels of the filled ellipse.
4273 \param ry Vertical radius in pixels of the filled ellipse.
4274 \param color The color value of the filled ellipse to draw (0xRRGGBBAA).
4275 
4276 \returns Returns 0 on success, -1 on failure.
4277 */
filledEllipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)4278 int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
4279 {
4280   Sint16 left, right, top, bottom;
4281   int result;
4282   Sint16 x1, y1, x2, y2;
4283   int ix, iy;
4284   int h, i, j, k;
4285   int oh, oi, oj, ok;
4286   int xmh, xph;
4287   int xmi, xpi;
4288   int xmj, xpj;
4289   int xmk, xpk;
4290 
4291   /*
4292   * Check visibility of clipping rectangle
4293   */
4294   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4295     return(0);
4296   }
4297 
4298   /*
4299   * Sanity check radii
4300   */
4301   if ((rx < 0) || (ry < 0)) {
4302     return (-1);
4303   }
4304 
4305   /*
4306   * Special case for rx=0 - draw a vline
4307   */
4308   if (rx == 0) {
4309     return (vlineColor(dst, x, y - ry, y + ry, color));
4310   }
4311   /*
4312   * Special case for ry=0 - draw a hline
4313   */
4314   if (ry == 0) {
4315     return (hlineColor(dst, x - rx, x + rx, y, color));
4316   }
4317 
4318   /*
4319   * Get circle and clipping boundary and
4320   * test if bounding box of circle is visible
4321   */
4322   x2 = x + rx;
4323   left = dst->clip_rect.x;
4324   if (x2<left) {
4325     return(0);
4326   }
4327   x1 = x - rx;
4328   right = dst->clip_rect.x + dst->clip_rect.w - 1;
4329   if (x1>right) {
4330     return(0);
4331   }
4332   y2 = y + ry;
4333   top = dst->clip_rect.y;
4334   if (y2<top) {
4335     return(0);
4336   }
4337   y1 = y - ry;
4338   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4339   if (y1>bottom) {
4340     return(0);
4341   }
4342 
4343   /*
4344   * Init vars
4345   */
4346   oh = oi = oj = ok = 0xFFFF;
4347 
4348   /*
4349   * Draw
4350   */
4351   result = 0;
4352   if (rx > ry) {
4353     ix = 0;
4354     iy = rx * 64;
4355 
4356     do {
4357       h = (ix + 32) >> 6;
4358       i = (iy + 32) >> 6;
4359       j = (h * ry) / rx;
4360       k = (i * ry) / rx;
4361 
4362       if ((ok != k) && (oj != k)) {
4363         xph = x + h;
4364         xmh = x - h;
4365         if (k > 0) {
4366           result |= hlineColor(dst, xmh, xph, y + k, color);
4367           result |= hlineColor(dst, xmh, xph, y - k, color);
4368         } else {
4369           result |= hlineColor(dst, xmh, xph, y, color);
4370         }
4371         ok = k;
4372       }
4373       if ((oj != j) && (ok != j) && (k != j)) {
4374         xmi = x - i;
4375         xpi = x + i;
4376         if (j > 0) {
4377           result |= hlineColor(dst, xmi, xpi, y + j, color);
4378           result |= hlineColor(dst, xmi, xpi, y - j, color);
4379         } else {
4380           result |= hlineColor(dst, xmi, xpi, y, color);
4381         }
4382         oj = j;
4383       }
4384 
4385       ix = ix + iy / rx;
4386       iy = iy - ix / rx;
4387 
4388     } while (i > h);
4389   } else {
4390     ix = 0;
4391     iy = ry * 64;
4392 
4393     do {
4394       h = (ix + 32) >> 6;
4395       i = (iy + 32) >> 6;
4396       j = (h * rx) / ry;
4397       k = (i * rx) / ry;
4398 
4399       if ((oi != i) && (oh != i)) {
4400         xmj = x - j;
4401         xpj = x + j;
4402         if (i > 0) {
4403           result |= hlineColor(dst, xmj, xpj, y + i, color);
4404           result |= hlineColor(dst, xmj, xpj, y - i, color);
4405         } else {
4406           result |= hlineColor(dst, xmj, xpj, y, color);
4407         }
4408         oi = i;
4409       }
4410       if ((oh != h) && (oi != h) && (i != h)) {
4411         xmk = x - k;
4412         xpk = x + k;
4413         if (h > 0) {
4414           result |= hlineColor(dst, xmk, xpk, y + h, color);
4415           result |= hlineColor(dst, xmk, xpk, y - h, color);
4416         } else {
4417           result |= hlineColor(dst, xmk, xpk, y, color);
4418         }
4419         oh = h;
4420       }
4421 
4422       ix = ix + iy / ry;
4423       iy = iy - ix / ry;
4424 
4425     } while (i > h);
4426   }
4427 
4428   return (result);
4429 }
4430 
4431 /*!
4432 \brief Draw filled ellipse with blending.
4433 
4434 \param dst The surface to draw on.
4435 \param x X coordinate of the center of the filled ellipse.
4436 \param y Y coordinate of the center of the filled ellipse.
4437 \param rx Horizontal radius in pixels of the filled ellipse.
4438 \param ry Vertical radius in pixels of the filled ellipse.
4439 \param r The red value of the filled ellipse to draw.
4440 \param g The green value of the filled ellipse to draw.
4441 \param b The blue value of the filled ellipse to draw.
4442 \param a The alpha value of the filled ellipse to draw.
4443 
4444 \returns Returns 0 on success, -1 on failure.
4445 */
filledEllipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4446 int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4447 {
4448   /*
4449   * Draw
4450   */
4451   return (filledEllipseColor
4452     (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4453 }
4454 
4455 /* ----- pie */
4456 
4457 /*!
4458 \brief Internal float (low-speed) pie-calc implementation by drawing polygons.
4459 
4460 Note: Determines vertex array and uses polygon or filledPolygon drawing routines to render.
4461 
4462 \param dst The surface to draw on.
4463 \param x X coordinate of the center of the pie.
4464 \param y Y coordinate of the center of the pie.
4465 \param rad Radius in pixels of the pie.
4466 \param start Starting radius in degrees of the pie.
4467 \param end Ending radius in degrees of the pie.
4468 \param color The color value of the pie to draw (0xRRGGBBAA).
4469 \param filled Flag indicating if the pie should be filled (=1) or not (=0).
4470 
4471 \returns Returns 0 on success, -1 on failure.
4472 */
_pieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color,Uint8 filled)4473 int _pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color, Uint8 filled)
4474 {
4475   Sint16 left, right, top, bottom;
4476   Sint16 x1, y1, x2, y2;
4477   int result;
4478   double angle, start_angle, end_angle;
4479   double deltaAngle;
4480   double dr;
4481   int numpoints, i;
4482   Sint16 *vx, *vy;
4483 
4484   /*
4485   * Check visibility of clipping rectangle
4486   */
4487   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4488     return(0);
4489   }
4490 
4491   /*
4492   * Sanity check radii
4493   */
4494   if (rad < 0) {
4495     return (-1);
4496   }
4497 
4498   /*
4499   * Fixup angles
4500   */
4501   start = start % 360;
4502   end = end % 360;
4503 
4504   /*
4505   * Special case for rad=0 - draw a point
4506   */
4507   if (rad == 0) {
4508     return (pixelColor(dst, x, y, color));
4509   }
4510 
4511   /*
4512   * Clip against circle, not pie (not 100% optimal).
4513   * Get pie's circle and clipping boundary and
4514   * test if bounding box of circle is visible
4515   */
4516   x2 = x + rad;
4517   left = dst->clip_rect.x;
4518   if (x2<left) {
4519     return(0);
4520   }
4521   x1 = x - rad;
4522   right = dst->clip_rect.x + dst->clip_rect.w - 1;
4523   if (x1>right) {
4524     return(0);
4525   }
4526   y2 = y + rad;
4527   top = dst->clip_rect.y;
4528   if (y2<top) {
4529     return(0);
4530   }
4531   y1 = y - rad;
4532   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4533   if (y1>bottom) {
4534     return(0);
4535   }
4536 
4537   /*
4538   * Variable setup
4539   */
4540   dr = (double) rad;
4541   deltaAngle = 3.0 / dr;
4542   start_angle = (double) start *(2.0 * M_PI / 360.0);
4543   end_angle = (double) end *(2.0 * M_PI / 360.0);
4544   if (start > end) {
4545     end_angle += (2.0 * M_PI);
4546   }
4547 
4548   /* We will always have at least 2 points */
4549   numpoints = 2;
4550 
4551   /* Count points (rather than calculating it) */
4552   angle = start_angle;
4553   while (angle < end_angle) {
4554     angle += deltaAngle;
4555     numpoints++;
4556   }
4557 
4558   /* Allocate combined vertex array */
4559   vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
4560   if (vx == NULL) {
4561     return (-1);
4562   }
4563 
4564   /* Update point to start of vy */
4565   vy += numpoints;
4566 
4567   /* Center */
4568   vx[0] = x;
4569   vy[0] = y;
4570 
4571   /* First vertex */
4572   angle = start_angle;
4573   vx[1] = x + (int) (dr * cos(angle));
4574   vy[1] = y + (int) (dr * sin(angle));
4575 
4576   if (numpoints<3)
4577   {
4578     result = lineColor(dst, vx[0], vy[0], vx[1], vy[1], color);
4579   }
4580   else
4581   {
4582     /* Calculate other vertices */
4583     i = 2;
4584     angle = start_angle;
4585     while (angle < end_angle) {
4586       angle += deltaAngle;
4587       if (angle>end_angle)
4588       {
4589         angle = end_angle;
4590       }
4591       vx[i] = x + (int) (dr * cos(angle));
4592       vy[i] = y + (int) (dr * sin(angle));
4593       i++;
4594     }
4595 
4596     /* Draw */
4597     if (filled) {
4598       result = filledPolygonColor(dst, vx, vy, numpoints, color);
4599     } else {
4600       result = polygonColor(dst, vx, vy, numpoints, color);
4601     }
4602   }
4603 
4604   /* Free combined vertex array */
4605   free(vx);
4606 
4607   return (result);
4608 }
4609 
4610 /*!
4611 \brief Draw pie (outline) with alpha blending.
4612 
4613 \param dst The surface to draw on.
4614 \param x X coordinate of the center of the pie.
4615 \param y Y coordinate of the center of the pie.
4616 \param rad Radius in pixels of the pie.
4617 \param start Starting radius in degrees of the pie.
4618 \param end Ending radius in degrees of the pie.
4619 \param color The color value of the pie to draw (0xRRGGBBAA).
4620 
4621 \returns Returns 0 on success, -1 on failure.
4622 */
pieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)4623 int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
4624        Sint16 start, Sint16 end, Uint32 color)
4625 {
4626   return (_pieColor(dst, x, y, rad, start, end, color, 0));
4627 
4628 }
4629 
4630 /*!
4631 \brief Draw pie (outline) with alpha blending.
4632 
4633 \param dst The surface to draw on.
4634 \param x X coordinate of the center of the pie.
4635 \param y Y coordinate of the center of the pie.
4636 \param rad Radius in pixels of the pie.
4637 \param start Starting radius in degrees of the pie.
4638 \param end Ending radius in degrees of the pie.
4639 \param r The red value of the pie to draw.
4640 \param g The green value of the pie to draw.
4641 \param b The blue value of the pie to draw.
4642 \param a The alpha value of the pie to draw.
4643 
4644 \returns Returns 0 on success, -1 on failure.
4645 */
pieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4646 int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
4647       Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4648 {
4649   return (_pieColor(dst, x, y, rad, start, end,
4650     ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 0));
4651 
4652 }
4653 
4654 /*!
4655 \brief Draw filled pie with alpha blending.
4656 
4657 \param dst The surface to draw on.
4658 \param x X coordinate of the center of the filled pie.
4659 \param y Y coordinate of the center of the filled pie.
4660 \param rad Radius in pixels of the filled pie.
4661 \param start Starting radius in degrees of the filled pie.
4662 \param end Ending radius in degrees of the filled pie.
4663 \param color The color value of the filled pie to draw (0xRRGGBBAA).
4664 
4665 \returns Returns 0 on success, -1 on failure.
4666 */
filledPieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)4667 int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
4668 {
4669   return (_pieColor(dst, x, y, rad, start, end, color, 1));
4670 }
4671 
4672 /*!
4673 \brief Draw filled pie with alpha blending.
4674 
4675 \param dst The surface to draw on.
4676 \param x X coordinate of the center of the filled pie.
4677 \param y Y coordinate of the center of the filled pie.
4678 \param rad Radius in pixels of the filled pie.
4679 \param start Starting radius in degrees of the filled pie.
4680 \param end Ending radius in degrees of the filled pie.
4681 \param r The red value of the filled pie to draw.
4682 \param g The green value of the filled pie to draw.
4683 \param b The blue value of the filled pie to draw.
4684 \param a The alpha value of the filled pie to draw.
4685 
4686 \returns Returns 0 on success, -1 on failure.
4687 */
filledPieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4688 int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
4689           Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4690 {
4691   return (_pieColor(dst, x, y, rad, start, end,
4692     ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
4693 }
4694 
4695 /* ------ Trigon */
4696 
4697 /*!
4698 \brief Draw trigon (triangle outline) with alpha blending.
4699 
4700 Note: Creates vertex array and uses polygon routine to render.
4701 
4702 \param dst The surface to draw on.
4703 \param x1 X coordinate of the first point of the trigon.
4704 \param y1 Y coordinate of the first point of the trigon.
4705 \param x2 X coordinate of the second point of the trigon.
4706 \param y2 Y coordinate of the second point of the trigon.
4707 \param x3 X coordinate of the third point of the trigon.
4708 \param y3 Y coordinate of the third point of the trigon.
4709 \param color The color value of the trigon to draw (0xRRGGBBAA).
4710 
4711 \returns Returns 0 on success, -1 on failure.
4712 */
trigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)4713 int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
4714 {
4715   Sint16 vx[3];
4716   Sint16 vy[3];
4717 
4718   vx[0]=x1;
4719   vx[1]=x2;
4720   vx[2]=x3;
4721   vy[0]=y1;
4722   vy[1]=y2;
4723   vy[2]=y3;
4724 
4725   return(polygonColor(dst,vx,vy,3,color));
4726 }
4727 
4728 /*!
4729 \brief Draw trigon (triangle outline) with alpha blending.
4730 
4731 \param dst The surface to draw on.
4732 \param x1 X coordinate of the first point of the trigon.
4733 \param y1 Y coordinate of the first point of the trigon.
4734 \param x2 X coordinate of the second point of the trigon.
4735 \param y2 Y coordinate of the second point of the trigon.
4736 \param x3 X coordinate of the third point of the trigon.
4737 \param y3 Y coordinate of the third point of the trigon.
4738 \param r The red value of the trigon to draw.
4739 \param g The green value of the trigon to draw.
4740 \param b The blue value of the trigon to draw.
4741 \param a The alpha value of the trigon to draw.
4742 
4743 \returns Returns 0 on success, -1 on failure.
4744 */
trigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4745 int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
4746          Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4747 {
4748   Sint16 vx[3];
4749   Sint16 vy[3];
4750 
4751   vx[0]=x1;
4752   vx[1]=x2;
4753   vx[2]=x3;
4754   vy[0]=y1;
4755   vy[1]=y2;
4756   vy[2]=y3;
4757 
4758   return(polygonRGBA(dst,vx,vy,3,r,g,b,a));
4759 }
4760 
4761 /* ------ AA-Trigon */
4762 
4763 /*!
4764 \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
4765 
4766 Note: Creates vertex array and uses aapolygon routine to render.
4767 
4768 \param dst The surface to draw on.
4769 \param x1 X coordinate of the first point of the aa-trigon.
4770 \param y1 Y coordinate of the first point of the aa-trigon.
4771 \param x2 X coordinate of the second point of the aa-trigon.
4772 \param y2 Y coordinate of the second point of the aa-trigon.
4773 \param x3 X coordinate of the third point of the aa-trigon.
4774 \param y3 Y coordinate of the third point of the aa-trigon.
4775 \param color The color value of the aa-trigon to draw (0xRRGGBBAA).
4776 
4777 \returns Returns 0 on success, -1 on failure.
4778 */
aatrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)4779 int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
4780 {
4781   Sint16 vx[3];
4782   Sint16 vy[3];
4783 
4784   vx[0]=x1;
4785   vx[1]=x2;
4786   vx[2]=x3;
4787   vy[0]=y1;
4788   vy[1]=y2;
4789   vy[2]=y3;
4790 
4791   return(aapolygonColor(dst,vx,vy,3,color));
4792 }
4793 
4794 /*!
4795 \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
4796 
4797 \param dst The surface to draw on.
4798 \param x1 X coordinate of the first point of the aa-trigon.
4799 \param y1 Y coordinate of the first point of the aa-trigon.
4800 \param x2 X coordinate of the second point of the aa-trigon.
4801 \param y2 Y coordinate of the second point of the aa-trigon.
4802 \param x3 X coordinate of the third point of the aa-trigon.
4803 \param y3 Y coordinate of the third point of the aa-trigon.
4804 \param r The red value of the aa-trigon to draw.
4805 \param g The green value of the aa-trigon to draw.
4806 \param b The blue value of the aa-trigon to draw.
4807 \param a The alpha value of the aa-trigon to draw.
4808 
4809 \returns Returns 0 on success, -1 on failure.
4810 */
aatrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4811 int aatrigonRGBA(SDL_Surface * dst,  Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
4812          Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4813 {
4814   Sint16 vx[3];
4815   Sint16 vy[3];
4816 
4817   vx[0]=x1;
4818   vx[1]=x2;
4819   vx[2]=x3;
4820   vy[0]=y1;
4821   vy[1]=y2;
4822   vy[2]=y3;
4823 
4824   return(aapolygonRGBA(dst,vx,vy,3,r,g,b,a));
4825 }
4826 
4827 /* ------ Filled Trigon */
4828 
4829 /*!
4830 \brief Draw filled trigon (triangle) with alpha blending.
4831 
4832 Note: Creates vertex array and uses aapolygon routine to render.
4833 
4834 \param dst The surface to draw on.
4835 \param x1 X coordinate of the first point of the filled trigon.
4836 \param y1 Y coordinate of the first point of the filled trigon.
4837 \param x2 X coordinate of the second point of the filled trigon.
4838 \param y2 Y coordinate of the second point of the filled trigon.
4839 \param x3 X coordinate of the third point of the filled trigon.
4840 \param y3 Y coordinate of the third point of the filled trigon.
4841 \param color The color value of the filled trigon to draw (0xRRGGBBAA).
4842 
4843 \returns Returns 0 on success, -1 on failure.
4844 */
filledTrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)4845 int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
4846 {
4847   Sint16 vx[3];
4848   Sint16 vy[3];
4849 
4850   vx[0]=x1;
4851   vx[1]=x2;
4852   vx[2]=x3;
4853   vy[0]=y1;
4854   vy[1]=y2;
4855   vy[2]=y3;
4856 
4857   return(filledPolygonColor(dst,vx,vy,3,color));
4858 }
4859 
4860 /*!
4861 \brief Draw filled trigon (triangle) with alpha blending.
4862 
4863 Note: Creates vertex array and uses aapolygon routine to render.
4864 
4865 \param dst The surface to draw on.
4866 \param x1 X coordinate of the first point of the filled trigon.
4867 \param y1 Y coordinate of the first point of the filled trigon.
4868 \param x2 X coordinate of the second point of the filled trigon.
4869 \param y2 Y coordinate of the second point of the filled trigon.
4870 \param x3 X coordinate of the third point of the filled trigon.
4871 \param y3 Y coordinate of the third point of the filled trigon.
4872 \param r The red value of the filled trigon to draw.
4873 \param g The green value of the filled trigon to draw.
4874 \param b The blue value of the filled trigon to draw.
4875 \param a The alpha value of the filled trigon to draw.
4876 
4877 \returns Returns 0 on success, -1 on failure.
4878 */
filledTrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4879 int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
4880            Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4881 {
4882   Sint16 vx[3];
4883   Sint16 vy[3];
4884 
4885   vx[0]=x1;
4886   vx[1]=x2;
4887   vx[2]=x3;
4888   vy[0]=y1;
4889   vy[1]=y2;
4890   vy[2]=y3;
4891 
4892   return(filledPolygonRGBA(dst,vx,vy,3,r,g,b,a));
4893 }
4894 
4895 /* ---- Polygon */
4896 
4897 /*!
4898 \brief Draw polygon with alpha blending.
4899 
4900 \param dst The surface to draw on.
4901 \param vx Vertex array containing X coordinates of the points of the polygon.
4902 \param vy Vertex array containing Y coordinates of the points of the polygon.
4903 \param n Number of points in the vertex array. Minimum number is 3.
4904 \param color The color value of the polygon to draw (0xRRGGBBAA).
4905 
4906 \returns Returns 0 on success, -1 on failure.
4907 */
polygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)4908 int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
4909 {
4910   int result;
4911   int i;
4912   const Sint16 *x1, *y1, *x2, *y2;
4913 
4914   /*
4915   * Check visibility of clipping rectangle
4916   */
4917   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4918     return(0);
4919   }
4920 
4921   /*
4922   * Vertex array NULL check
4923   */
4924   if (vx == NULL) {
4925     return (-1);
4926   }
4927   if (vy == NULL) {
4928     return (-1);
4929   }
4930 
4931   /*
4932   * Sanity check
4933   */
4934   if (n < 3) {
4935     return (-1);
4936   }
4937 
4938   /*
4939   * Pointer setup
4940   */
4941   x1 = x2 = vx;
4942   y1 = y2 = vy;
4943   x2++;
4944   y2++;
4945 
4946   /*
4947   * Draw
4948   */
4949   result = 0;
4950   for (i = 1; i < n; i++) {
4951     result |= lineColor(dst, *x1, *y1, *x2, *y2, color);
4952     x1 = x2;
4953     y1 = y2;
4954     x2++;
4955     y2++;
4956   }
4957   result |= lineColor(dst, *x1, *y1, *vx, *vy, color);
4958 
4959   return (result);
4960 }
4961 
4962 /*!
4963 \brief Draw polygon with alpha blending.
4964 
4965 \param dst The surface to draw on.
4966 \param vx Vertex array containing X coordinates of the points of the polygon.
4967 \param vy Vertex array containing Y coordinates of the points of the polygon.
4968 \param n Number of points in the vertex array. Minimum number is 3.
4969 \param r The red value of the polygon to draw.
4970 \param g The green value of the polygon to draw.
4971 \param b The blue value of the polygon to draw.
4972 \param a The alpha value of the polygon to draw.
4973 
4974 \returns Returns 0 on success, -1 on failure.
4975 */
polygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4976 int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4977 {
4978   /*
4979   * Draw
4980   */
4981   return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4982 }
4983 
4984 /* ---- AA-Polygon */
4985 
4986 /*!
4987 \brief Draw anti-aliased polygon with alpha blending.
4988 
4989 \param dst The surface to draw on.
4990 \param vx Vertex array containing X coordinates of the points of the aa-polygon.
4991 \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
4992 \param n Number of points in the vertex array. Minimum number is 3.
4993 \param color The color value of the aa-polygon to draw (0xRRGGBBAA).
4994 
4995 \returns Returns 0 on success, -1 on failure.
4996 */
aapolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)4997 int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
4998 {
4999   int result;
5000   int i;
5001   const Sint16 *x1, *y1, *x2, *y2;
5002 
5003   /*
5004   * Check visibility of clipping rectangle
5005   */
5006   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5007     return(0);
5008   }
5009 
5010   /*
5011   * Vertex array NULL check
5012   */
5013   if (vx == NULL) {
5014     return (-1);
5015   }
5016   if (vy == NULL) {
5017     return (-1);
5018   }
5019 
5020   /*
5021   * Sanity check
5022   */
5023   if (n < 3) {
5024     return (-1);
5025   }
5026 
5027   /*
5028   * Pointer setup
5029   */
5030   x1 = x2 = vx;
5031   y1 = y2 = vy;
5032   x2++;
5033   y2++;
5034 
5035   /*
5036   * Draw
5037   */
5038   result = 0;
5039   for (i = 1; i < n; i++) {
5040     result |= _aalineColor(dst, *x1, *y1, *x2, *y2, color, 0);
5041     x1 = x2;
5042     y1 = y2;
5043     x2++;
5044     y2++;
5045   }
5046   result |= _aalineColor(dst, *x1, *y1, *vx, *vy, color, 0);
5047 
5048   return (result);
5049 }
5050 
5051 /*!
5052 \brief Draw anti-aliased polygon with alpha blending.
5053 
5054 \param dst The surface to draw on.
5055 \param vx Vertex array containing X coordinates of the points of the aa-polygon.
5056 \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
5057 \param n Number of points in the vertex array. Minimum number is 3.
5058 \param r The red value of the aa-polygon to draw.
5059 \param g The green value of the aa-polygon to draw.
5060 \param b The blue value of the aa-polygon to draw.
5061 \param a The alpha value of the aa-polygon to draw.
5062 
5063 \returns Returns 0 on success, -1 on failure.
5064 */
aapolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)5065 int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
5066 {
5067   /*
5068   * Draw
5069   */
5070   return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
5071 }
5072 
5073 /* ---- Filled Polygon */
5074 
5075 /*!
5076 \brief Internal helper qsort callback functions used in filled polygon drawing.
5077 
5078 \param a The surface to draw on.
5079 \param b Vertex array containing X coordinates of the points of the polygon.
5080 
5081 \returns Returns 0 if a==b, a negative number if a<b or a positive number if a>b.
5082 */
_gfxPrimitivesCompareInt(const void * a,const void * b)5083 int _gfxPrimitivesCompareInt(const void *a, const void *b)
5084 {
5085   return (*(const int *) a) - (*(const int *) b);
5086 }
5087 
5088 /*!
5089 \brief Global vertex array to use if optional parameters are not given in filledPolygonMT calls.
5090 
5091 Note: Used for non-multithreaded (default) operation of filledPolygonMT.
5092 */
5093 static int *gfxPrimitivesPolyIntsGlobal = NULL;
5094 
5095 /*!
5096 \brief Flag indicating if global vertex array was already allocated.
5097 
5098 Note: Used for non-multithreaded (default) operation of filledPolygonMT.
5099 */
5100 static int gfxPrimitivesPolyAllocatedGlobal = 0;
5101 
5102 /*!
5103 \brief Draw filled polygon with alpha blending (multi-threaded capable).
5104 
5105 Note: The last two parameters are optional; but are required for multithreaded operation.
5106 
5107 \param dst The surface to draw on.
5108 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5109 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5110 \param n Number of points in the vertex array. Minimum number is 3.
5111 \param color The color value of the filled polygon to draw (0xRRGGBBAA).
5112 \param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise.
5113 \param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise.
5114 
5115 \returns Returns 0 on success, -1 on failure.
5116 */
filledPolygonColorMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color,int ** polyInts,int * polyAllocated)5117 int filledPolygonColorMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color, int **polyInts, int *polyAllocated)
5118 {
5119   int result;
5120   int i;
5121   int y, xa, xb;
5122   int miny, maxy;
5123   int x1, y1;
5124   int x2, y2;
5125   int ind1, ind2;
5126   int ints;
5127   int *gfxPrimitivesPolyInts = NULL;
5128   int gfxPrimitivesPolyAllocated = 0;
5129 
5130   /*
5131   * Check visibility of clipping rectangle
5132   */
5133   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5134     return(0);
5135   }
5136 
5137   /*
5138   * Vertex array NULL check
5139   */
5140   if (vx == NULL) {
5141     return (-1);
5142   }
5143   if (vy == NULL) {
5144     return (-1);
5145   }
5146 
5147   /*
5148   * Sanity check number of edges
5149   */
5150   if (n < 3) {
5151     return -1;
5152   }
5153 
5154   /*
5155   * Map polygon cache
5156   */
5157   if ((polyInts==NULL) || (polyAllocated==NULL)) {
5158     /* Use global cache */
5159     gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
5160     gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
5161   } else {
5162     /* Use local cache */
5163     gfxPrimitivesPolyInts = *polyInts;
5164     gfxPrimitivesPolyAllocated = *polyAllocated;
5165   }
5166 
5167   /*
5168   * Allocate temp array, only grow array
5169   */
5170   if (!gfxPrimitivesPolyAllocated) {
5171     gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
5172     gfxPrimitivesPolyAllocated = n;
5173   } else {
5174     if (gfxPrimitivesPolyAllocated < n) {
5175       gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
5176       gfxPrimitivesPolyAllocated = n;
5177     }
5178   }
5179 
5180   /*
5181   * Check temp array
5182   */
5183   if (gfxPrimitivesPolyInts==NULL) {
5184     gfxPrimitivesPolyAllocated = 0;
5185   }
5186 
5187   /*
5188   * Update cache variables
5189   */
5190   if ((polyInts==NULL) || (polyAllocated==NULL)) {
5191     gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
5192     gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
5193   } else {
5194     *polyInts = gfxPrimitivesPolyInts;
5195     *polyAllocated = gfxPrimitivesPolyAllocated;
5196   }
5197 
5198   /*
5199   * Check temp array again
5200   */
5201   if (gfxPrimitivesPolyInts==NULL) {
5202     return(-1);
5203   }
5204 
5205   /*
5206   * Determine Y maxima
5207   */
5208   miny = vy[0];
5209   maxy = vy[0];
5210   for (i = 1; (i < n); i++) {
5211     if (vy[i] < miny) {
5212       miny = vy[i];
5213     } else if (vy[i] > maxy) {
5214       maxy = vy[i];
5215     }
5216   }
5217 
5218   /*
5219   * Draw, scanning y
5220   */
5221   result = 0;
5222   for (y = miny; (y <= maxy); y++) {
5223     ints = 0;
5224     for (i = 0; (i < n); i++) {
5225       if (!i) {
5226         ind1 = n - 1;
5227         ind2 = 0;
5228       } else {
5229         ind1 = i - 1;
5230         ind2 = i;
5231       }
5232       y1 = vy[ind1];
5233       y2 = vy[ind2];
5234       if (y1 < y2) {
5235         x1 = vx[ind1];
5236         x2 = vx[ind2];
5237       } else if (y1 > y2) {
5238         y2 = vy[ind1];
5239         y1 = vy[ind2];
5240         x2 = vx[ind1];
5241         x1 = vx[ind2];
5242       } else {
5243         continue;
5244       }
5245       if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
5246         gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
5247       }
5248     }
5249 
5250     qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
5251 
5252     for (i = 0; (i < ints); i += 2) {
5253       xa = gfxPrimitivesPolyInts[i] + 1;
5254       xa = (xa >> 16) + ((xa & 32768) >> 15);
5255       xb = gfxPrimitivesPolyInts[i+1] - 1;
5256       xb = (xb >> 16) + ((xb & 32768) >> 15);
5257       result |= hlineColor(dst, xa, xb, y, color);
5258     }
5259   }
5260 
5261   return (result);
5262 }
5263 
5264 /*!
5265 \brief Draw filled polygon with alpha blending (multi-threaded capable).
5266 
5267 Note: The last two parameters are optional; but are required for multithreaded operation.
5268 
5269 \param dst The surface to draw on.
5270 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5271 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5272 \param n Number of points in the vertex array. Minimum number is 3.
5273 \param r The red value of the filled polygon to draw.
5274 \param g The green value of the filled polygon to draw.
5275 \param b The blue value of the filed polygon to draw.
5276 \param a The alpha value of the filled polygon to draw.
5277 \param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise.
5278 \param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise.
5279 
5280 \returns Returns 0 on success, -1 on failure.
5281 */
filledPolygonRGBAMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a,int ** polyInts,int * polyAllocated)5282 int filledPolygonRGBAMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int **polyInts, int *polyAllocated)
5283 {
5284   /*
5285   * Draw
5286   */
5287   return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, polyInts, polyAllocated));
5288 }
5289 
5290 /*!
5291 \brief Draw filled polygon with alpha blending.
5292 
5293 Note: Standard filledPolygon function is calling multithreaded version with NULL parameters
5294 to use the global vertex cache.
5295 
5296 \param dst The surface to draw on.
5297 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5298 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5299 \param n Number of points in the vertex array. Minimum number is 3.
5300 \param color The color value of the filled polygon to draw (0xRRGGBBAA).
5301 
5302 \returns Returns 0 on success, -1 on failure.
5303 */
filledPolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)5304 int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
5305 {
5306   /*
5307   * Draw
5308   */
5309   return (filledPolygonColorMT(dst, vx, vy, n, color, NULL, NULL));
5310 }
5311 
5312 /*!
5313 \brief Draw filled polygon with alpha blending.
5314 
5315 \param dst The surface to draw on.
5316 \param vx Vertex array containing X coordinates of the points of the filled polygon.
5317 \param vy Vertex array containing Y coordinates of the points of the filled polygon.
5318 \param n Number of points in the vertex array. Minimum number is 3.
5319 \param r The red value of the filled polygon to draw.
5320 \param g The green value of the filled polygon to draw.
5321 \param b The blue value of the filed polygon to draw.
5322 \param a The alpha value of the filled polygon to draw.
5323 
5324 \returns Returns 0 on success, -1 on failure.
5325 */
filledPolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)5326 int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
5327 {
5328   /*
5329   * Draw
5330   */
5331   return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, NULL, NULL));
5332 }
5333 
5334 /*!
5335 \brief Internal function to draw a textured horizontal line.
5336 
5337 \param dst The surface to draw on.
5338 \param x1 X coordinate of the first point (i.e. left) of the line.
5339 \param x2 X coordinate of the second point (i.e. right) of the line.
5340 \param y Y coordinate of the points of the line.
5341 \param texture The texture surface to retrieve color information from.
5342 \param texture_dx The X offset for the texture lookup.
5343 \param texture_dy The Y offset for the textured lookup.
5344 
5345 \returns Returns 0 on success, -1 on failure.
5346 */
_HLineTextured(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,SDL_Surface * texture,int texture_dx,int texture_dy)5347 int _HLineTextured(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface *texture, int texture_dx, int texture_dy)
5348 {
5349   Sint16 left, right, top, bottom;
5350   Sint16 w;
5351   Sint16 xtmp;
5352   int result = 0;
5353   int texture_x_walker;
5354   int texture_y_start;
5355   SDL_Rect source_rect,dst_rect;
5356   int pixels_written,write_width;
5357 
5358   /*
5359   * Check visibility of clipping rectangle
5360   */
5361   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5362     return(0);
5363   }
5364 
5365   /*
5366   * Swap x1, x2 if required to ensure x1<=x2
5367   */
5368   if (x1 > x2) {
5369     xtmp = x1;
5370     x1 = x2;
5371     x2 = xtmp;
5372   }
5373 
5374   /*
5375   * Get clipping boundary and
5376   * check visibility of hline
5377   */
5378   left = dst->clip_rect.x;
5379   if (x2<left) {
5380     return(0);
5381   }
5382   right = dst->clip_rect.x + dst->clip_rect.w - 1;
5383   if (x1>right) {
5384     return(0);
5385   }
5386   top = dst->clip_rect.y;
5387   bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
5388   if ((y<top) || (y>bottom)) {
5389     return (0);
5390   }
5391 
5392   /*
5393   * Clip x
5394   */
5395   if (x1 < left) {
5396     x1 = left;
5397   }
5398   if (x2 > right) {
5399     x2 = right;
5400   }
5401 
5402   /*
5403   * Calculate width to draw
5404   */
5405   w = x2 - x1 + 1;
5406 
5407   /*
5408   * Determine where in the texture we start drawing
5409   */
5410   texture_x_walker =   (x1 - texture_dx)  % texture->w;
5411   if (texture_x_walker < 0){
5412     texture_x_walker = texture->w + texture_x_walker ;
5413   }
5414 
5415   texture_y_start = (y + texture_dy) % texture->h;
5416   if (texture_y_start < 0){
5417     texture_y_start = texture->h + texture_y_start;
5418   }
5419 
5420   // setup the source rectangle; we are only drawing one horizontal line
5421   source_rect.y = texture_y_start;
5422   source_rect.x = texture_x_walker;
5423   source_rect.h = 1;
5424 
5425   // we will draw to the current y
5426   dst_rect.y = y;
5427 
5428   // if there are enough pixels left in the current row of the texture
5429   // draw it all at once
5430   if (w <= texture->w -texture_x_walker){
5431     source_rect.w = w;
5432     source_rect.x = texture_x_walker;
5433     dst_rect.x= x1;
5434     result = (SDL_BlitSurface  (texture, &source_rect , dst, &dst_rect) == 0);
5435   } else { // we need to draw multiple times
5436     // draw the first segment
5437     pixels_written = texture->w  - texture_x_walker;
5438     source_rect.w = pixels_written;
5439     source_rect.x = texture_x_walker;
5440     dst_rect.x= x1;
5441     result |= (SDL_BlitSurface (texture, &source_rect , dst, &dst_rect) == 0);
5442     write_width = texture->w;
5443 
5444     // now draw the rest
5445     // set the source x to 0
5446     source_rect.x = 0;
5447     while (pixels_written < w){
5448       if (write_width >= w - pixels_written) {
5449         write_width =  w - pixels_written;
5450       }
5451       source_rect.w = write_width;
5452       dst_rect.x = x1 + pixels_written;
5453       result  |= (SDL_BlitSurface  (texture,&source_rect , dst, &dst_rect) == 0);
5454       pixels_written += write_width;
5455     }
5456   }
5457 
5458   return result;
5459 }
5460 
5461 /*!
5462 \brief Draws a polygon filled with the given texture (Multi-Threading Capable).
5463 
5464 This operation use internally SDL_BlitSurface for lines of the source texture. It supports
5465 alpha drawing.
5466 
5467 To get the best performance of this operation you need to make sure the texture and the dst surface have the same format
5468 (see  http://docs.mandragor.org/files/Common_libs_documentation/SDL/SDL_Documentation_project_en/sdlblitsurface.html).
5469 The last two parameters are optional, but required for multithreaded operation. When set to NULL, uses global static temp array.
5470 
5471 \param dst the destination surface,
5472 \param vx array of x vector components
5473 \param vy array of x vector components
5474 \param n the amount of vectors in the vx and vy array
5475 \param texture the sdl surface to use to fill the polygon
5476 \param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
5477 to the left and want the texture to apear the same you need to increase the texture_dx value
5478 \param texture_dy see texture_dx
5479 \param polyInts preallocated temp array storage for vertex sorting (used for multi-threaded operation)
5480 \param polyAllocated flag indicating oif the temp array was allocated (used for multi-threaded operation)
5481 
5482 \returns Returns 0 on success, -1 on failure.
5483 */
texturedPolygonMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy,int ** polyInts,int * polyAllocated)5484 int texturedPolygonMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n,
5485             SDL_Surface * texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated)
5486 {
5487   int result;
5488   int i;
5489   int y, xa, xb;
5490   int minx,maxx,miny, maxy;
5491   int x1, y1;
5492   int x2, y2;
5493   int ind1, ind2;
5494   int ints;
5495   int *gfxPrimitivesPolyInts = NULL;
5496   int gfxPrimitivesPolyAllocated = 0;
5497 
5498   /*
5499   * Check visibility of clipping rectangle
5500   */
5501   if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
5502     return(0);
5503   }
5504 
5505   /*
5506   * Sanity check number of edges
5507   */
5508   if (n < 3) {
5509     return -1;
5510   }
5511 
5512   /*
5513   * Map polygon cache
5514   */
5515   if ((polyInts==NULL) || (polyAllocated==NULL)) {
5516     /* Use global cache */
5517     gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
5518     gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
5519   } else {
5520     /* Use local cache */
5521     gfxPrimitivesPolyInts = *polyInts;
5522     gfxPrimitivesPolyAllocated = *polyAllocated;
5523   }
5524 
5525   /*
5526   * Allocate temp array, only grow array
5527   */
5528   if (!gfxPrimitivesPolyAllocated) {
5529     gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
5530     gfxPrimitivesPolyAllocated = n;
5531   } else {
5532     if (gfxPrimitivesPolyAllocated < n) {
5533       gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
5534       gfxPrimitivesPolyAllocated = n;
5535     }
5536   }
5537 
5538   /*
5539   * Check temp array
5540   */
5541   if (gfxPrimitivesPolyInts==NULL) {
5542     gfxPrimitivesPolyAllocated = 0;
5543   }
5544 
5545   /*
5546   * Update cache variables
5547   */
5548   if ((polyInts==NULL) || (polyAllocated==NULL)) {
5549     gfxPrimitivesPolyIntsGlobal =  gfxPrimitivesPolyInts;
5550     gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
5551   } else {
5552     *polyInts = gfxPrimitivesPolyInts;
5553     *polyAllocated = gfxPrimitivesPolyAllocated;
5554   }
5555 
5556   /*
5557   * Check temp array again
5558   */
5559   if (gfxPrimitivesPolyInts==NULL) {
5560     return(-1);
5561   }
5562 
5563   /*
5564   * Determine X,Y minima,maxima
5565   */
5566   miny = vy[0];
5567   maxy = vy[0];
5568   minx = vx[0];
5569   maxx = vx[0];
5570   for (i = 1; (i < n); i++) {
5571     if (vy[i] < miny) {
5572       miny = vy[i];
5573     } else if (vy[i] > maxy) {
5574       maxy = vy[i];
5575     }
5576     if (vx[i] < minx) {
5577       minx = vx[i];
5578     } else if (vx[i] > maxx) {
5579       maxx = vx[i];
5580     }
5581   }
5582   if (maxx <0 || minx > dst->w){
5583     return -1;
5584   }
5585   if (maxy <0 || miny > dst->h){
5586     return -1;
5587   }
5588 
5589   /*
5590   * Draw, scanning y
5591   */
5592   result = 0;
5593   for (y = miny; (y <= maxy); y++) {
5594     ints = 0;
5595     for (i = 0; (i < n); i++) {
5596       if (!i) {
5597         ind1 = n - 1;
5598         ind2 = 0;
5599       } else {
5600         ind1 = i - 1;
5601         ind2 = i;
5602       }
5603       y1 = vy[ind1];
5604       y2 = vy[ind2];
5605       if (y1 < y2) {
5606         x1 = vx[ind1];
5607         x2 = vx[ind2];
5608       } else if (y1 > y2) {
5609         y2 = vy[ind1];
5610         y1 = vy[ind2];
5611         x2 = vx[ind1];
5612         x1 = vx[ind2];
5613       } else {
5614         continue;
5615       }
5616       if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
5617         gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
5618       }
5619     }
5620 
5621     qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
5622 
5623     for (i = 0; (i < ints); i += 2) {
5624       xa = gfxPrimitivesPolyInts[i] + 1;
5625       xa = (xa >> 16) + ((xa & 32768) >> 15);
5626       xb = gfxPrimitivesPolyInts[i+1] - 1;
5627       xb = (xb >> 16) + ((xb & 32768) >> 15);
5628       result |= _HLineTextured(dst, xa, xb, y, texture, texture_dx, texture_dy);
5629     }
5630   }
5631 
5632   return (result);
5633 }
5634 
5635 /*!
5636 \brief Draws a polygon filled with the given texture.
5637 
5638 This standard version is calling multithreaded versions with NULL cache parameters.
5639 
5640 \param dst the destination surface,
5641 \param vx array of x vector components
5642 \param vy array of x vector components
5643 \param n the amount of vectors in the vx and vy array
5644 \param texture the sdl surface to use to fill the polygon
5645 \param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
5646 to the left and want the texture to apear the same you need to increase the texture_dx value
5647 \param texture_dy see texture_dx
5648 
5649 \returns Returns 0 on success, -1 on failure.
5650 */
texturedPolygon(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy)5651 int texturedPolygon(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
5652 {
5653   /*
5654   * Draw
5655   */
5656   return (texturedPolygonMT(dst, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
5657 }
5658 
5659 
5660 /* ---- Character */
5661 
5662 /*!
5663 \brief Global cache for NxM pixel font surfaces created at runtime.
5664 */
5665 static SDL_Surface *gfxPrimitivesFont[256];
5666 
5667 /*!
5668 \brief Global cache of the color used for the font surfaces created at runtime.
5669 */
5670 static Uint32 gfxPrimitivesFontColor[256];
5671 
5672 /*!
5673 \brief Width of the current font. Default is 8.
5674 */
5675 static Uint32 charWidth = 8;
5676 
5677 /*!
5678 \brief Height of the current font. Default is 8.
5679 */
5680 static Uint32 charHeight = 8;
5681 
5682 /*!
5683 \brief Width for rendering. Autocalculated.
5684 */
5685 static Uint32 charWidthLocal = 8;
5686 
5687 /*!
5688 \brief Height for rendering. Autocalculated.
5689 */
5690 static Uint32 charHeightLocal = 8;
5691 
5692 /*!
5693 \brief Pitch of the current font in bytes. Default is 1.
5694 */
5695 static Uint32 charPitch = 1;
5696 
5697 /*!
5698 \brief Characters 90deg clockwise rotations. Default is 0. Max is 3.
5699 */
5700 static Uint32 charRotation = 0;
5701 
5702 /*!
5703 \brief Character data size in bytes of the current font. Default is 8.
5704 */
5705 static Uint32 charSize = 8;
5706 
5707 /* ---- Bezier curve */
5708 
5709 /*!
5710 \brief Internal function to calculate bezier interpolator of data array with ndata values at position 't'.
5711 
5712 \param data Array of values.
5713 \param ndata Size of array.
5714 \param t Position for which to calculate interpolated value. t should be between [0, ndata].
5715 
5716 \returns Interpolated value at position t, value[0] when t<0, value[n-1] when t>n.
5717 */
_evaluateBezier(double * data,int ndata,double t)5718 double _evaluateBezier (double *data, int ndata, double t)
5719 {
5720   double mu, result;
5721   int n,k,kn,nn,nkn;
5722   double blend,muk,munk;
5723 
5724   /* Sanity check bounds */
5725   if (t<0.0) {
5726     return(data[0]);
5727   }
5728   if (t>=(double)ndata) {
5729     return(data[ndata-1]);
5730   }
5731 
5732   /* Adjust t to the range 0.0 to 1.0 */
5733   mu=t/(double)ndata;
5734 
5735   /* Calculate interpolate */
5736   n=ndata-1;
5737   result=0.0;
5738   muk = 1;
5739   munk = pow(1-mu,(double)n);
5740   for (k=0;k<=n;k++) {
5741     nn = n;
5742     kn = k;
5743     nkn = n - k;
5744     blend = muk * munk;
5745     muk *= mu;
5746     munk /= (1-mu);
5747     while (nn >= 1) {
5748       blend *= nn;
5749       nn--;
5750       if (kn > 1) {
5751         blend /= (double)kn;
5752         kn--;
5753       }
5754       if (nkn > 1) {
5755         blend /= (double)nkn;
5756         nkn--;
5757       }
5758     }
5759     result += data[k] * blend;
5760   }
5761 
5762   return (result);
5763 }
5764 
5765 /*!
5766 \brief Draw a bezier curve with alpha blending.
5767 
5768 \param dst The surface to draw on.
5769 \param vx Vertex array containing X coordinates of the points of the bezier curve.
5770 \param vy Vertex array containing Y coordinates of the points of the bezier curve.
5771 \param n Number of points in the vertex array. Minimum number is 3.
5772 \param s Number of steps for the interpolation. Minimum number is 2.
5773 \param color The color value of the bezier curve to draw (0xRRGGBBAA).
5774 
5775 \returns Returns 0 on success, -1 on failure.
5776 */
bezierColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint32 color)5777 int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
5778 {
5779   int result;
5780   int i;
5781   double *x, *y, t, stepsize;
5782   Sint16 x1, y1, x2, y2;
5783 
5784   /*
5785   * Sanity check
5786   */
5787   if (n < 3) {
5788     return (-1);
5789   }
5790   if (s < 2) {
5791     return (-1);
5792   }
5793 
5794   /*
5795   * Variable setup
5796   */
5797   stepsize=(double)1.0/(double)s;
5798 
5799   /* Transfer vertices into float arrays */
5800   if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
5801     return(-1);
5802   }
5803   if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
5804     free(x);
5805     return(-1);
5806   }
5807   for (i=0; i<n; i++) {
5808     x[i]=vx[i];
5809     y[i]=vy[i];
5810   }
5811   x[n]=vx[0];
5812   y[n]=vy[0];
5813 
5814   /*
5815   * Draw
5816   */
5817   result = 0;
5818   t=0.0;
5819   x1=(Sint16)lrint(_evaluateBezier(x,n+1,t));
5820   y1=(Sint16)lrint(_evaluateBezier(y,n+1,t));
5821   for (i = 0; i <= (n*s); i++) {
5822     t += stepsize;
5823     x2=(Sint16)_evaluateBezier(x,n,t);
5824     y2=(Sint16)_evaluateBezier(y,n,t);
5825     result |= lineColor(dst, x1, y1, x2, y2, color);
5826     x1 = x2;
5827     y1 = y2;
5828   }
5829 
5830   /* Clean up temporary array */
5831   free(x);
5832   free(y);
5833 
5834   return (result);
5835 }
5836 
5837 /*!
5838 \brief Draw a bezier curve with alpha blending.
5839 
5840 \param dst The surface to draw on.
5841 \param vx Vertex array containing X coordinates of the points of the bezier curve.
5842 \param vy Vertex array containing Y coordinates of the points of the bezier curve.
5843 \param n Number of points in the vertex array. Minimum number is 3.
5844 \param s Number of steps for the interpolation. Minimum number is 2.
5845 \param r The red value of the bezier curve to draw.
5846 \param g The green value of the bezier curve to draw.
5847 \param b The blue value of the bezier curve to draw.
5848 \param a The alpha value of the bezier curve to draw.
5849 
5850 \returns Returns 0 on success, -1 on failure.
5851 */
bezierRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint8 r,Uint8 g,Uint8 b,Uint8 a)5852 int bezierRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
5853 {
5854   /*
5855   * Draw
5856   */
5857   return (bezierColor(dst, vx, vy, n, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
5858 }
5859 
5860 
5861 /*!
5862 \brief Internal function to initialize the Bresenham line iterator.
5863 
5864 Example of use:
5865 SDL_gfxBresenhamIterator b;
5866 _bresenhamInitialize (&b, x1, y1, x2, y2);
5867 do {
5868 plot(b.x, b.y);
5869 } while (_bresenhamIterate(&b)==0);
5870 
5871 \param b Pointer to struct for bresenham line drawing state.
5872 \param x1 X coordinate of the first point of the line.
5873 \param y1 Y coordinate of the first point of the line.
5874 \param x2 X coordinate of the second point of the line.
5875 \param y2 Y coordinate of the second point of the line.
5876 
5877 \returns Returns 0 on success, -1 on failure.
5878 */
_bresenhamInitialize(SDL_gfxBresenhamIterator * b,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2)5879 int _bresenhamInitialize(SDL_gfxBresenhamIterator *b, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2)
5880 {
5881   int temp;
5882 
5883   if (b==NULL) {
5884     return(-1);
5885   }
5886 
5887   b->x = x1;
5888   b->y = y1;
5889 
5890   /* dx = abs(x2-x1), s1 = sign(x2-x1) */
5891   if ((b->dx = x2 - x1) != 0) {
5892     if (b->dx < 0) {
5893       b->dx = -b->dx;
5894       b->s1 = -1;
5895     } else {
5896       b->s1 = 1;
5897     }
5898   } else {
5899     b->s1 = 0;
5900   }
5901 
5902   /* dy = abs(y2-y1), s2 = sign(y2-y1)    */
5903   if ((b->dy = y2 - y1) != 0) {
5904     if (b->dy < 0) {
5905       b->dy = -b->dy;
5906       b->s2 = -1;
5907     } else {
5908       b->s2 = 1;
5909     }
5910   } else {
5911     b->s2 = 0;
5912   }
5913 
5914   if (b->dy > b->dx) {
5915     temp = b->dx;
5916     b->dx = b->dy;
5917     b->dy = temp;
5918     b->swapdir = 1;
5919   } else {
5920     b->swapdir = 0;
5921   }
5922 
5923   b->count = b->dx;
5924   b->dy <<= 1;
5925   b->error = b->dy - b->dx;
5926   b->dx <<= 1;
5927 
5928   return(0);
5929 }
5930 
5931 
5932 /*!
5933 \brief Internal function to move Bresenham line iterator to the next position.
5934 
5935 Maybe updates the x and y coordinates of the iterator struct.
5936 
5937 \param b Pointer to struct for bresenham line drawing state.
5938 
5939 \returns Returns 0 on success, 1 if last point was reached, 2 if moving past end-of-line, -1 on failure.
5940 */
_bresenhamIterate(SDL_gfxBresenhamIterator * b)5941 int _bresenhamIterate(SDL_gfxBresenhamIterator *b)
5942 {
5943   if (b==NULL) {
5944     return (-1);
5945   }
5946 
5947   /* last point check */
5948   if (b->count <= 0) {
5949     return (2);
5950   }
5951 
5952   while (b->error >= 0) {
5953     if (b->swapdir) {
5954       b->x += b->s1;
5955     } else  {
5956       b->y += b->s2;
5957     }
5958 
5959     b->error -= b->dx;
5960   }
5961 
5962   if (b->swapdir) {
5963     b->y += b->s2;
5964   } else {
5965     b->x += b->s1;
5966   }
5967 
5968   b->error += b->dy;
5969   b->count--;
5970 
5971   /* count==0 indicates "end-of-line" */
5972   return ((b->count) ? 0 : 1);
5973 }
5974 
5975 
5976 /*!
5977 \brief Internal function to to draw parallel lines with Murphy algorithm.
5978 
5979 \param m Pointer to struct for murphy iterator.
5980 \param x X coordinate of point.
5981 \param y Y coordinate of point.
5982 \param d1 Direction square/diagonal.
5983 */
_murphyParaline(SDL_gfxMurphyIterator * m,Sint16 x,Sint16 y,int d1)5984 void _murphyParaline(SDL_gfxMurphyIterator *m, Sint16 x, Sint16 y, int d1)
5985 {
5986   int p;
5987   d1 = -d1;
5988 
5989   /*
5990   * Lock the surface
5991   */
5992   if (SDL_MUSTLOCK(m->dst)) {
5993     SDL_LockSurface(m->dst);
5994   }
5995 
5996   for (p = 0; p <= m->u; p++) {
5997 
5998     pixelColorNolock(m->dst, x, y, m->color);
5999 
6000     if (d1 <= m->kt) {
6001       if (m->oct2 == 0) {
6002         x++;
6003       } else {
6004         if (m->quad4 == 0) {
6005           y++;
6006         } else {
6007           y--;
6008         }
6009       }
6010       d1 += m->kv;
6011     } else {
6012       x++;
6013       if (m->quad4 == 0) {
6014         y++;
6015       } else {
6016         y--;
6017       }
6018       d1 += m->kd;
6019     }
6020   }
6021 
6022   /* Unlock surface */
6023   if (SDL_MUSTLOCK(m->dst)) {
6024     SDL_UnlockSurface(m->dst);
6025   }
6026 
6027   m->tempx = x;
6028   m->tempy = y;
6029 }
6030 
6031 /*!
6032 \brief Internal function to to draw one iteration of the Murphy algorithm.
6033 
6034 \param m Pointer to struct for murphy iterator.
6035 \param miter Iteration count.
6036 \param ml1bx X coordinate of a point.
6037 \param ml1by Y coordinate of a point.
6038 \param ml2bx X coordinate of a point.
6039 \param ml2by Y coordinate of a point.
6040 \param ml1x X coordinate of a point.
6041 \param ml1y Y coordinate of a point.
6042 \param ml2x X coordinate of a point.
6043 \param ml2y Y coordinate of a point.
6044 
6045 */
_murphyIteration(SDL_gfxMurphyIterator * m,Uint8 miter,Uint16 ml1bx,Uint16 ml1by,Uint16 ml2bx,Uint16 ml2by,Uint16 ml1x,Uint16 ml1y,Uint16 ml2x,Uint16 ml2y)6046 void _murphyIteration(SDL_gfxMurphyIterator *m, Uint8 miter,
6047             Uint16 ml1bx, Uint16 ml1by, Uint16 ml2bx, Uint16 ml2by,
6048             Uint16 ml1x, Uint16 ml1y, Uint16 ml2x, Uint16 ml2y)
6049 {
6050   int atemp1, atemp2;
6051   int ftmp1, ftmp2;
6052   Uint16 m1x, m1y, m2x, m2y;
6053   Uint16 fix, fiy, lax, lay, curx, cury;
6054   Uint16 px[4], py[4];
6055   SDL_gfxBresenhamIterator b;
6056 
6057   if (miter > 1) {
6058     if (m->first1x != -32768) {
6059       fix = (m->first1x + m->first2x) / 2;
6060       fiy = (m->first1y + m->first2y) / 2;
6061       lax = (m->last1x + m->last2x) / 2;
6062       lay = (m->last1y + m->last2y) / 2;
6063       curx = (ml1x + ml2x) / 2;
6064       cury = (ml1y + ml2y) / 2;
6065 
6066       atemp1 = (fix - curx);
6067       atemp2 = (fiy - cury);
6068       ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
6069       atemp1 = (lax - curx);
6070       atemp2 = (lay - cury);
6071       ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
6072 
6073       if (ftmp1 <= ftmp2) {
6074         m1x = m->first1x;
6075         m1y = m->first1y;
6076         m2x = m->first2x;
6077         m2y = m->first2y;
6078       } else {
6079         m1x = m->last1x;
6080         m1y = m->last1y;
6081         m2x = m->last2x;
6082         m2y = m->last2y;
6083       }
6084 
6085       atemp1 = (m2x - ml2x);
6086       atemp2 = (m2y - ml2y);
6087       ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
6088       atemp1 = (m2x - ml2bx);
6089       atemp2 = (m2y - ml2by);
6090       ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
6091 
6092       if (ftmp2 >= ftmp1) {
6093         ftmp1 = ml2bx;
6094         ftmp2 = ml2by;
6095         ml2bx = ml2x;
6096         ml2by = ml2y;
6097         ml2x = ftmp1;
6098         ml2y = ftmp2;
6099         ftmp1 = ml1bx;
6100         ftmp2 = ml1by;
6101         ml1bx = ml1x;
6102         ml1by = ml1y;
6103         ml1x = ftmp1;
6104         ml1y = ftmp2;
6105       }
6106 
6107       /*
6108       * Lock the surface
6109       */
6110       if (SDL_MUSTLOCK(m->dst)) {
6111         SDL_LockSurface(m->dst);
6112       }
6113 
6114       _bresenhamInitialize(&b, m2x, m2y, m1x, m1y);
6115       do {
6116         pixelColorNolock(m->dst, b.x, b.y, m->color);
6117       } while (_bresenhamIterate(&b)==0);
6118 
6119       _bresenhamInitialize(&b, m1x, m1y, ml1bx, ml1by);
6120       do {
6121         pixelColorNolock(m->dst, b.x, b.y, m->color);
6122       } while (_bresenhamIterate(&b)==0);
6123 
6124       _bresenhamInitialize(&b, ml1bx, ml1by, ml2bx, ml2by);
6125       do {
6126         pixelColorNolock(m->dst, b.x, b.y, m->color);
6127       } while (_bresenhamIterate(&b)==0);
6128 
6129       _bresenhamInitialize(&b, ml2bx, ml2by, m2x, m2y);
6130       do {
6131         pixelColorNolock(m->dst, b.x, b.y, m->color);
6132       } while (_bresenhamIterate(&b)==0);
6133 
6134       /* Unlock surface */
6135       if (SDL_MUSTLOCK(m->dst)) {
6136         SDL_UnlockSurface(m->dst);
6137       }
6138 
6139       px[0] = m1x;
6140       px[1] = m2x;
6141       px[2] = ml1bx;
6142       px[3] = ml2bx;
6143       py[0] = m1y;
6144       py[1] = m2y;
6145       py[2] = ml1by;
6146       py[3] = ml2by;
6147       polygonColor(m->dst, px, py, 4, m->color);
6148     }
6149   }
6150 
6151   m->last1x = ml1x;
6152   m->last1y = ml1y;
6153   m->last2x = ml2x;
6154   m->last2y = ml2y;
6155   m->first1x = ml1bx;
6156   m->first1y = ml1by;
6157   m->first2x = ml2bx;
6158   m->first2y = ml2by;
6159 }
6160 
6161 
6162 #define HYPOT(x,y) sqrt((double)(x)*(double)(x)+(double)(y)*(double)(y))
6163 
6164 /*!
6165 \brief Internal function to to draw wide lines with Murphy algorithm.
6166 
6167 Draws lines parallel to ideal line.
6168 
6169 \param m Pointer to struct for murphy iterator.
6170 \param x1 X coordinate of first point.
6171 \param y1 Y coordinate of first point.
6172 \param x2 X coordinate of second point.
6173 \param y2 Y coordinate of second point.
6174 \param width Width of line.
6175 \param miter Iteration count.
6176 
6177 */
_murphyWideline(SDL_gfxMurphyIterator * m,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint8 miter)6178 void _murphyWideline(SDL_gfxMurphyIterator *m, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 miter)
6179 {
6180   float offset = width / 2.f;
6181 
6182   Sint16 temp;
6183   Sint16 ptx, pty, ptxx, ptxy, ml1x, ml1y, ml2x, ml2y, ml1bx, ml1by, ml2bx, ml2by;
6184 
6185   int d0, d1;   /* difference terms d0=perpendicular to line, d1=along line */
6186 
6187   int q;      /* pel counter,q=perpendicular to line */
6188   int tmp;
6189 
6190   int dd;     /* distance along line */
6191   int tk;     /* thickness threshold */
6192   double ang;   /* angle for initial point calculation */
6193   double sang, cang;
6194 
6195   /* Initialisation */
6196   m->u = x2 - x1; /* delta x */
6197   m->v = y2 - y1; /* delta y */
6198 
6199   if (m->u < 0) { /* swap to make sure we are in quadrants 1 or 4 */
6200     temp = x1;
6201     x1 = x2;
6202     x2 = temp;
6203     temp = y1;
6204     y1 = y2;
6205     y1 = temp;
6206     m->u *= -1;
6207     m->v *= -1;
6208   }
6209 
6210   if (m->v < 0) { /* swap to 1st quadrant and flag */
6211     m->v *= -1;
6212     m->quad4 = 1;
6213   } else {
6214     m->quad4 = 0;
6215   }
6216 
6217   if (m->v > m->u) {  /* swap things if in 2 octant */
6218     tmp = m->u;
6219     m->u = m->v;
6220     m->v = tmp;
6221     m->oct2 = 1;
6222   } else {
6223     m->oct2 = 0;
6224   }
6225 
6226   m->ku = m->u + m->u;  /* change in l for square shift */
6227   m->kv = m->v + m->v;  /* change in d for square shift */
6228   m->kd = m->kv - m->ku;  /* change in d for diagonal shift */
6229   m->kt = m->u - m->kv; /* diag/square decision threshold */
6230 
6231   d0 = 0;
6232   d1 = 0;
6233   dd = 0;
6234 
6235   ang = atan((double) m->v / (double) m->u);  /* calc new initial point - offset both sides of ideal */
6236   sang = sin(ang);
6237   cang = cos(ang);
6238 
6239   if (m->oct2 == 0) {
6240     ptx = x1 + (Sint16)lrint(offset * sang);
6241     if (m->quad4 == 0) {
6242       pty = y1 - (Sint16)lrint(offset * cang);
6243     } else {
6244       pty = y1 + (Sint16)lrint(offset * cang);
6245     }
6246   } else {
6247     ptx = x1 - (Sint16)lrint(offset * cang);
6248     if (m->quad4 == 0) {
6249       pty = y1 + (Sint16)lrint(offset * sang);
6250     } else {
6251       pty = y1 - (Sint16)lrint(offset * sang);
6252     }
6253   }
6254 
6255   /* used here for constant thickness line */
6256   tk = (int) (4. * HYPOT(ptx - x1, pty - y1) * HYPOT(m->u, m->v));
6257 
6258   if (miter == 0) {
6259     m->first1x = -32768;
6260     m->first1y = -32768;
6261     m->first2x = -32768;
6262     m->first2y = -32768;
6263     m->last1x = -32768;
6264     m->last1y = -32768;
6265     m->last2x = -32768;
6266     m->last2y = -32768;
6267   }
6268   ptxx = ptx;
6269   ptxy = pty;
6270 
6271   for (q = 0; dd <= tk; q++) {  /* outer loop, stepping perpendicular to line */
6272 
6273     _murphyParaline(m, ptx, pty, d1); /* call to inner loop - right edge */
6274     if (q == 0) {
6275       ml1x = ptx;
6276       ml1y = pty;
6277       ml1bx = m->tempx;
6278       ml1by = m->tempy;
6279     } else {
6280       ml2x = ptx;
6281       ml2y = pty;
6282       ml2bx = m->tempx;
6283       ml2by = m->tempy;
6284     }
6285     if (d0 < m->kt) { /* square move */
6286       if (m->oct2 == 0) {
6287         if (m->quad4 == 0) {
6288           pty++;
6289         } else {
6290           pty--;
6291         }
6292       } else {
6293         ptx++;
6294       }
6295     } else {  /* diagonal move */
6296       dd += m->kv;
6297       d0 -= m->ku;
6298       if (d1 < m->kt) { /* normal diagonal */
6299         if (m->oct2 == 0) {
6300           ptx--;
6301           if (m->quad4 == 0) {
6302             pty++;
6303           } else {
6304             pty--;
6305           }
6306         } else {
6307           ptx++;
6308           if (m->quad4 == 0) {
6309             pty--;
6310           } else {
6311             pty++;
6312           }
6313         }
6314         d1 += m->kv;
6315       } else {  /* double square move, extra parallel line */
6316         if (m->oct2 == 0) {
6317           ptx--;
6318         } else {
6319           if (m->quad4 == 0) {
6320             pty--;
6321           } else {
6322             pty++;
6323           }
6324         }
6325         d1 += m->kd;
6326         if (dd > tk) {
6327           _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
6328           return; /* breakout on the extra line */
6329         }
6330         _murphyParaline(m, ptx, pty, d1);
6331         if (m->oct2 == 0) {
6332           if (m->quad4 == 0) {
6333             pty++;
6334           } else {
6335 
6336             pty--;
6337           }
6338         } else {
6339           ptx++;
6340         }
6341       }
6342     }
6343     dd += m->ku;
6344     d0 += m->kv;
6345   }
6346 
6347   _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
6348 }
6349 
6350 
6351 /*!
6352 \brief Draw a thick line with alpha blending.
6353 
6354 \param dst The surface to draw on.
6355 \param x1 X coordinate of the first point of the line.
6356 \param y1 Y coordinate of the first point of the line.
6357 \param x2 X coordinate of the second point of the line.
6358 \param y2 Y coordinate of the second point of the line.
6359 \param width Width of the line in pixels. Must be >0.
6360 \param color The color value of the line to draw (0xRRGGBBAA).
6361 
6362 \returns Returns 0 on success, -1 on failure.
6363 */
thickLineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint32 color)6364 int thickLineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color)
6365 {
6366   SDL_gfxMurphyIterator m;
6367 
6368   if (dst == NULL) return -1;
6369   if (width < 1) return -1;
6370 
6371   m.dst = dst;
6372   m.color = color;
6373 
6374   _murphyWideline(&m, x1, y1, x2, y2, width, 0);
6375   _murphyWideline(&m, x1, y1, x2, y2, width, 1);
6376 
6377   return(0);
6378 }
6379 
6380 /*!
6381 \brief Draw a thick line with alpha blending.
6382 
6383 \param dst The surface to draw on.
6384 \param x1 X coordinate of the first point of the line.
6385 \param y1 Y coordinate of the first point of the line.
6386 \param x2 X coordinate of the second point of the line.
6387 \param y2 Y coordinate of the second point of the line.
6388 \param width Width of the line in pixels. Must be >0.
6389 \param r The red value of the character to draw.
6390 \param g The green value of the character to draw.
6391 \param b The blue value of the character to draw.
6392 \param a The alpha value of the character to draw.
6393 
6394 \returns Returns 0 on success, -1 on failure.
6395 */
thickLineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 width,Uint8 r,Uint8 g,Uint8 b,Uint8 a)6396 int thickLineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
6397 {
6398   return (thickLineColor(dst, x1, y1, x2, y2, width,
6399     ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
6400 }
6401