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