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