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