original 1.0.1 release
[xwelltris.git] / src / sdl / sdl_gfxprimitives.c
blobaf84a4cd59b06ce4971e60204ba344d1284e72a3
1 /*
3 SDL_gfxPrimitives - Graphics primitives for SDL surfaces
5 LGPL (c) A. Schiffler
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #include <string.h>
14 #include "SDL.h"
16 #include "sdl_gfxprimitives.h"
17 #include "sdl_gfxprimitives_font.h"
19 /* -===================- */
21 /* Define this flag to use surface blits for alpha blended drawing. */
22 /* This is usually slower that direct surface calculations. */
24 #undef SURFACE_ALPHA_PIXEL
26 /* ----- Defines for pixel clipping tests */
28 #define clip_xmin(surface) surface->clip_rect.x
29 #define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1
30 #define clip_ymin(surface) surface->clip_rect.y
31 #define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1
33 /* ----- Pixel - fast, no blending, no locking, clipping */
35 int fastPixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
37 int bpp;
38 Uint8 *p;
41 * Honor clipping setup at pixel level
43 if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) {
46 * Get destination format
48 bpp = dst->format->BytesPerPixel;
49 p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
50 switch (bpp) {
51 case 1:
52 *p = color;
53 break;
54 case 2:
55 *(Uint16 *) p = color;
56 break;
57 case 3:
58 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
59 p[0] = (color >> 16) & 0xff;
60 p[1] = (color >> 8) & 0xff;
61 p[2] = color & 0xff;
62 } else {
63 p[0] = color & 0xff;
64 p[1] = (color >> 8) & 0xff;
65 p[2] = (color >> 16) & 0xff;
67 break;
68 case 4:
69 *(Uint32 *) p = color;
70 break;
71 } /* switch */
76 return (0);
79 /* ----- Pixel - fast, no blending, no locking, no clipping */
81 /* (faster but dangerous, make sure we stay in surface bounds) */
83 int fastPixelColorNolockNoclip(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
85 int bpp;
86 Uint8 *p;
89 * Get destination format
91 bpp = dst->format->BytesPerPixel;
92 p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
93 switch (bpp) {
94 case 1:
95 *p = color;
96 break;
97 case 2:
98 *(Uint16 *) p = color;
99 break;
100 case 3:
101 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
102 p[0] = (color >> 16) & 0xff;
103 p[1] = (color >> 8) & 0xff;
104 p[2] = color & 0xff;
105 } else {
106 p[0] = color & 0xff;
107 p[1] = (color >> 8) & 0xff;
108 p[2] = (color >> 16) & 0xff;
110 break;
111 case 4:
112 *(Uint32 *) p = color;
113 break;
114 } /* switch */
116 return (0);
119 /* ----- Pixel - fast, no blending, locking, clipping */
121 int fastPixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
123 int result;
126 * Lock the surface
128 if (SDL_MUSTLOCK(dst)) {
129 if (SDL_LockSurface(dst) < 0) {
130 return (-1);
134 result = fastPixelColorNolock(dst, x, y, color);
137 * Unlock surface
139 if (SDL_MUSTLOCK(dst)) {
140 SDL_UnlockSurface(dst);
143 return (result);
146 /* ----- Pixel - fast, no blending, locking, RGB input */
148 int fastPixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
150 Uint32 color;
153 * Setup color
155 color = SDL_MapRGBA(dst->format, r, g, b, a);
158 * Draw
160 return (fastPixelColor(dst, x, y, color));
164 /* ----- Pixel - fast, no blending, no locking RGB input */
166 int fastPixelRGBANolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
168 Uint32 color;
171 * Setup color
173 color = SDL_MapRGBA(dst->format, r, g, b, a);
176 * Draw
178 return (fastPixelColorNolock(dst, x, y, color));
181 #ifdef SURFACE_ALPHA_PIXEL
183 /* ----- Pixel - using single pixel blit with blending enabled if a<255 */
185 /* Old, slower routine - normally disabled */
187 static SDL_Surface *gfxPrimitivesSinglePixel = NULL;
189 int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
191 SDL_Rect srect;
192 SDL_Rect drect;
193 int result;
196 * Setup source rectangle for pixel
198 srect.x = 0;
199 srect.y = 0;
200 srect.w = 1;
201 srect.h = 1;
204 * Setup destination rectangle for pixel
206 drect.x = x;
207 drect.y = y;
208 drect.w = 1;
209 drect.h = 1;
212 * Create single pixel in 32bit RGBA format
214 if (gfxPrimitivesSinglePixel == NULL) {
215 gfxPrimitivesSinglePixel =
216 SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA, 1, 1,
217 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
221 * Draw color into pixel
223 SDL_FillRect(gfxPrimitivesSinglePixel, &srect, color);
226 * Draw pixel onto destination surface
228 result = SDL_BlitSurface(gfxPrimitivesSinglePixel, &srect, dst, &drect);
230 return (result);
233 #else
235 /* PutPixel routine with alpha blending, input color in destination format */
237 /* New, faster routine - default blending pixel */
239 int _putPixelAlpha(SDL_Surface * surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
241 Uint32 Rmask = surface->format->Rmask, Gmask =
242 surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
243 Uint32 R, G, B, A = 0;
245 if (x >= clip_xmin(surface) && x <= clip_xmax(surface)
246 && y >= clip_ymin(surface) && y <= clip_ymax(surface)) {
248 switch (surface->format->BytesPerPixel) {
249 case 1:{ /* Assuming 8-bpp */
250 if (alpha == 255) {
251 *((Uint8 *) surface->pixels + y * surface->pitch + x) = color;
252 } else {
253 Uint8 *pixel = (Uint8 *) surface->pixels + y * surface->pitch + x;
255 Uint8 dR = surface->format->palette->colors[*pixel].r;
256 Uint8 dG = surface->format->palette->colors[*pixel].g;
257 Uint8 dB = surface->format->palette->colors[*pixel].b;
258 Uint8 sR = surface->format->palette->colors[color].r;
259 Uint8 sG = surface->format->palette->colors[color].g;
260 Uint8 sB = surface->format->palette->colors[color].b;
262 dR = dR + ((sR - dR) * alpha >> 8);
263 dG = dG + ((sG - dG) * alpha >> 8);
264 dB = dB + ((sB - dB) * alpha >> 8);
266 *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
269 break;
271 case 2:{ /* Probably 15-bpp or 16-bpp */
272 if (alpha == 255) {
273 *((Uint16 *) surface->pixels + y * surface->pitch / 2 + x) = color;
274 } else {
275 Uint16 *pixel = (Uint16 *) surface->pixels + y * surface->pitch / 2 + x;
276 Uint32 dc = *pixel;
278 R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask;
279 G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask;
280 B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask;
281 if (Amask)
282 A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask;
284 *pixel = R | G | B | A;
287 break;
289 case 3:{ /* Slow 24-bpp mode, usually not used */
290 Uint8 *pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
291 Uint8 rshift8 = surface->format->Rshift / 8;
292 Uint8 gshift8 = surface->format->Gshift / 8;
293 Uint8 bshift8 = surface->format->Bshift / 8;
294 Uint8 ashift8 = surface->format->Ashift / 8;
297 if (alpha == 255) {
298 *(pix + rshift8) = color >> surface->format->Rshift;
299 *(pix + gshift8) = color >> surface->format->Gshift;
300 *(pix + bshift8) = color >> surface->format->Bshift;
301 *(pix + ashift8) = color >> surface->format->Ashift;
302 } else {
303 Uint8 dR, dG, dB, dA = 0;
304 Uint8 sR, sG, sB, sA = 0;
306 pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
308 dR = *((pix) + rshift8);
309 dG = *((pix) + gshift8);
310 dB = *((pix) + bshift8);
311 dA = *((pix) + ashift8);
313 sR = (color >> surface->format->Rshift) & 0xff;
314 sG = (color >> surface->format->Gshift) & 0xff;
315 sB = (color >> surface->format->Bshift) & 0xff;
316 sA = (color >> surface->format->Ashift) & 0xff;
318 dR = dR + ((sR - dR) * alpha >> 8);
319 dG = dG + ((sG - dG) * alpha >> 8);
320 dB = dB + ((sB - dB) * alpha >> 8);
321 dA = dA + ((sA - dA) * alpha >> 8);
323 *((pix) + rshift8) = dR;
324 *((pix) + gshift8) = dG;
325 *((pix) + bshift8) = dB;
326 *((pix) + ashift8) = dA;
329 break;
331 case 4:{ /* Probably 32-bpp */
332 if (alpha == 255) {
333 *((Uint32 *) surface->pixels + y * surface->pitch / 4 + x) = color;
334 } else {
335 Uint32 *pixel = (Uint32 *) surface->pixels + y * surface->pitch / 4 + x;
336 Uint32 dc = *pixel;
338 R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask;
339 G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask;
340 B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask;
341 if (Amask)
342 A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask;
344 *pixel = R | G | B | A;
347 break;
351 return (0);
354 /* ----- Pixel - pixel draw with blending enabled if a<255 */
356 int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
358 Uint8 alpha;
359 Uint32 mcolor;
360 int result = 0;
363 * Lock the surface
365 if (SDL_MUSTLOCK(dst)) {
366 if (SDL_LockSurface(dst) < 0) {
367 return (-1);
372 * Setup color
374 alpha = color & 0x000000ff;
375 mcolor =
376 SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
377 (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
380 * Draw
382 result = _putPixelAlpha(dst, x, y, mcolor, alpha);
385 * Unlock the surface
387 if (SDL_MUSTLOCK(dst)) {
388 SDL_UnlockSurface(dst);
391 return (result);
394 int pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
396 Uint8 alpha;
397 Uint32 mcolor;
398 int result = 0;
401 * Setup color
403 alpha = color & 0x000000ff;
404 mcolor =
405 SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
406 (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
409 * Draw
411 result = _putPixelAlpha(dst, x, y, mcolor, alpha);
413 return (result);
417 /* Filled rectangle with alpha blending, color in destination format */
419 int _filledRectAlpha(SDL_Surface * surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
421 Uint32 Rmask = surface->format->Rmask, Gmask =
422 surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
423 Uint32 R, G, B, A = 0;
424 Sint16 x, y;
426 switch (surface->format->BytesPerPixel) {
427 case 1:{ /* Assuming 8-bpp */
428 Uint8 *row, *pixel;
429 Uint8 dR, dG, dB;
431 Uint8 sR = surface->format->palette->colors[color].r;
432 Uint8 sG = surface->format->palette->colors[color].g;
433 Uint8 sB = surface->format->palette->colors[color].b;
435 for (y = y1; y <= y2; y++) {
436 row = (Uint8 *) surface->pixels + y * surface->pitch;
437 for (x = x1; x <= x2; x++) {
438 pixel = row + x;
440 dR = surface->format->palette->colors[*pixel].r;
441 dG = surface->format->palette->colors[*pixel].g;
442 dB = surface->format->palette->colors[*pixel].b;
444 dR = dR + ((sR - dR) * alpha >> 8);
445 dG = dG + ((sG - dG) * alpha >> 8);
446 dB = dB + ((sB - dB) * alpha >> 8);
448 *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
452 break;
454 case 2:{ /* Probably 15-bpp or 16-bpp */
455 Uint16 *row, *pixel;
456 Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
458 for (y = y1; y <= y2; y++) {
459 row = (Uint16 *) surface->pixels + y * surface->pitch / 2;
460 for (x = x1; x <= x2; x++) {
461 pixel = row + x;
463 R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask;
464 G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask;
465 B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask;
466 if (Amask)
467 A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask;
469 *pixel = R | G | B | A;
473 break;
475 case 3:{ /* Slow 24-bpp mode, usually not used */
476 Uint8 *row, *pix;
477 Uint8 dR, dG, dB, dA;
478 Uint8 rshift8 = surface->format->Rshift / 8;
479 Uint8 gshift8 = surface->format->Gshift / 8;
480 Uint8 bshift8 = surface->format->Bshift / 8;
481 Uint8 ashift8 = surface->format->Ashift / 8;
483 Uint8 sR = (color >> surface->format->Rshift) & 0xff;
484 Uint8 sG = (color >> surface->format->Gshift) & 0xff;
485 Uint8 sB = (color >> surface->format->Bshift) & 0xff;
486 Uint8 sA = (color >> surface->format->Ashift) & 0xff;
488 for (y = y1; y <= y2; y++) {
489 row = (Uint8 *) surface->pixels + y * surface->pitch;
490 for (x = x1; x <= x2; x++) {
491 pix = row + x * 3;
493 dR = *((pix) + rshift8);
494 dG = *((pix) + gshift8);
495 dB = *((pix) + bshift8);
496 dA = *((pix) + ashift8);
498 dR = dR + ((sR - dR) * alpha >> 8);
499 dG = dG + ((sG - dG) * alpha >> 8);
500 dB = dB + ((sB - dB) * alpha >> 8);
501 dA = dA + ((sA - dA) * alpha >> 8);
503 *((pix) + rshift8) = dR;
504 *((pix) + gshift8) = dG;
505 *((pix) + bshift8) = dB;
506 *((pix) + ashift8) = dA;
511 break;
513 case 4:{ /* Probably 32-bpp */
514 Uint32 *row, *pixel;
515 Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
517 for (y = y1; y <= y2; y++) {
518 row = (Uint32 *) surface->pixels + y * surface->pitch / 4;
519 for (x = x1; x <= x2; x++) {
520 pixel = row + x;
522 R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask;
523 G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask;
524 B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask;
525 if (Amask)
526 A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask;
528 *pixel = R | G | B | A;
532 break;
535 return (0);
538 /* Draw rectangle with alpha enabled from RGBA color. */
540 int filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
542 Uint8 alpha;
543 Uint32 mcolor;
544 int result = 0;
547 * Lock the surface
549 if (SDL_MUSTLOCK(dst)) {
550 if (SDL_LockSurface(dst) < 0) {
551 return (-1);
556 * Setup color
558 alpha = color & 0x000000ff;
559 mcolor =
560 SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
561 (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
564 * Draw
566 result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha);
569 * Unlock the surface
571 if (SDL_MUSTLOCK(dst)) {
572 SDL_UnlockSurface(dst);
575 return (result);
578 /* Draw horizontal line with alpha enabled from RGBA color */
580 int HLineAlpha(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
582 return (filledRectAlpha(dst, x1, y, x2, y, color));
586 /* Draw vertical line with alpha enabled from RGBA color */
588 int VLineAlpha(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
590 return (filledRectAlpha(dst, x, y1, x, y2, color));
593 #endif
596 /* Pixel - using alpha weight on color for AA-drawing */
598 int pixelColorWeight(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
600 Uint32 a;
603 * Get alpha
605 a = (color & (Uint32) 0x000000ff);
608 * Modify Alpha by weight
610 a = ((a * weight) >> 8);
612 return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
615 /* Pixel - using alpha weight on color for AA-drawing - no locking */
617 int pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
619 Uint32 a;
622 * Get alpha
624 a = (color & (Uint32) 0x000000ff);
627 * Modify Alpha by weight
629 a = ((a * weight) >> 8);
631 return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
634 int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
636 Uint32 color;
639 * Check Alpha
641 if (a == 255) {
643 * No alpha blending required
646 * Setup color
648 color = SDL_MapRGBA(dst->format, r, g, b, a);
650 * Draw
652 return (fastPixelColor(dst, x, y, color));
653 } else {
655 * Alpha blending required
658 * Draw
660 return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
664 /* ----- Horizontal line */
666 #ifdef SURFACE_ALPHA_PIXEL
667 static SDL_Surface *gfxPrimitivesHline = NULL;
668 #endif
670 int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
672 Sint16 left, right, top, bottom;
673 Uint8 *pixel, *pixellast;
674 int dx;
675 int pixx, pixy;
676 Sint16 w;
677 Sint16 xtmp;
678 int result = -1;
679 Uint8 *colorptr;
681 #ifdef SURFACE_ALPHA_PIXEL
682 Uint32 a;
683 SDL_Rect srect;
684 SDL_Rect drect;
685 #endif
688 * Get clipping boundary
690 left = dst->clip_rect.x;
691 right = dst->clip_rect.x + dst->clip_rect.w - 1;
692 top = dst->clip_rect.y;
693 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
696 * Swap x1, x2 if required
698 if (x1 > x2) {
699 xtmp = x1;
700 x1 = x2;
701 x2 = xtmp;
705 * Visible
707 if ((x1 > right) || (x2 < left) || (y < top) || (y > bottom)) {
708 return (0);
712 * Clip x
714 if (x1 < left) {
715 x1 = left;
717 if (x2 > right) {
718 x2 = right;
722 * Calculate width
724 w = x2 - x1;
727 * Sanity check on width
729 if (w < 0) {
730 return (0);
734 * Alpha check
736 if ((color & 255) == 255) {
739 * No alpha-blending required
743 * Setup color
745 colorptr = (Uint8 *) & color;
746 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
747 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
748 } else {
749 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
753 * Lock surface
755 SDL_LockSurface(dst);
758 * More variable setup
760 dx = w;
761 pixx = dst->format->BytesPerPixel;
762 pixy = dst->pitch;
763 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
766 * Draw
768 switch (dst->format->BytesPerPixel) {
769 case 1:
770 memset(pixel, color, dx);
771 break;
772 case 2:
773 pixellast = pixel + dx + dx;
774 for (; pixel <= pixellast; pixel += pixx) {
775 *(Uint16 *) pixel = color;
777 break;
778 case 3:
779 pixellast = pixel + dx + dx + dx;
780 for (; pixel <= pixellast; pixel += pixx) {
781 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
782 pixel[0] = (color >> 16) & 0xff;
783 pixel[1] = (color >> 8) & 0xff;
784 pixel[2] = color & 0xff;
785 } else {
786 pixel[0] = color & 0xff;
787 pixel[1] = (color >> 8) & 0xff;
788 pixel[2] = (color >> 16) & 0xff;
791 break;
792 default: /* case 4 */
793 dx = dx + dx;
794 pixellast = pixel + dx + dx;
795 for (; pixel <= pixellast; pixel += pixx) {
796 *(Uint32 *) pixel = color;
798 break;
802 * Unlock surface
804 SDL_UnlockSurface(dst);
807 * Set result code
809 result = 0;
811 } else {
814 * Alpha blending blit
817 #ifdef SURFACE_ALPHA_PIXEL
820 * Adjust width for Rect setup
822 w++;
825 * Setup source rectangle for pixel
827 srect.x = 0;
828 srect.y = 0;
829 srect.w = w;
830 srect.h = 1;
833 * Setup rectangle for destination line
835 drect.x = x1;
836 drect.y = y;
837 drect.w = w;
838 drect.h = 1;
841 * Maybe deallocate existing surface if size is too small
843 if ((gfxPrimitivesHline != NULL) && (gfxPrimitivesHline->w < w)) {
844 SDL_FreeSurface(gfxPrimitivesHline);
845 gfxPrimitivesHline = NULL;
849 * Create horizontal line surface in destination format if necessary
851 if (gfxPrimitivesHline == NULL) {
852 gfxPrimitivesHline =
853 SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA, w,
854 1, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
858 * Get alpha
860 a = (color & (Uint32) 0x000000ff);
863 * Toggle alpha blending if necessary, reset otherwise
865 if (a != 255) {
866 SDL_SetAlpha(gfxPrimitivesHline, SDL_SRCALPHA, 255);
867 } else {
868 SDL_SetAlpha(gfxPrimitivesHline, 0, 255);
872 * Draw color into pixel
874 SDL_FillRect(gfxPrimitivesHline, &srect, color);
877 * Draw pixel onto destination surface
879 result = SDL_BlitSurface(gfxPrimitivesHline, &srect, dst, &drect);
881 #else
883 result = HLineAlpha(dst, x1, x1 + w, y, color);
885 #endif
889 return (result);
892 int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
895 * Draw
897 return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
900 /* ----- Vertical line */
902 #ifdef SURFACE_ALPHA_PIXEL
903 static SDL_Surface *gfxPrimitivesVline = NULL;
904 #endif
906 int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
908 Sint16 left, right, top, bottom;
909 Uint8 *pixel, *pixellast;
910 int dy;
911 int pixx, pixy;
912 Sint16 h;
913 Sint16 ytmp;
914 int result = -1;
915 Uint8 *colorptr;
917 #ifdef SURFACE_ALPHA_PIXEL
918 SDL_Rect srect;
919 SDL_Rect drect;
920 Uint32 a;
921 #endif
924 * Get clipping boundary
926 left = dst->clip_rect.x;
927 right = dst->clip_rect.x + dst->clip_rect.w - 1;
928 top = dst->clip_rect.y;
929 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
932 * Swap y1, y2 if required
934 if (y1 > y2) {
935 ytmp = y1;
936 y1 = y2;
937 y2 = ytmp;
941 * Visible
943 if ((y2 < top) || (y1 > bottom) || (x < left) || (x > right)) {
944 return (0);
948 * Clip y
950 if (y1 < top) {
951 y1 = top;
953 if (y2 > bottom) {
954 y2 = bottom;
958 * Calculate height
960 h = y2 - y1;
963 * Sanity check on height
965 if (h < 0) {
966 return (0);
970 * Alpha check
972 if ((color & 255) == 255) {
975 * No alpha-blending required
979 * Setup color
981 colorptr = (Uint8 *) & color;
982 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
983 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
984 } else {
985 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
989 * Lock surface
991 SDL_LockSurface(dst);
994 * More variable setup
996 dy = h;
997 pixx = dst->format->BytesPerPixel;
998 pixy = dst->pitch;
999 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1;
1000 pixellast = pixel + pixy * dy;
1003 * Draw
1005 switch (dst->format->BytesPerPixel) {
1006 case 1:
1007 for (; pixel <= pixellast; pixel += pixy) {
1008 *(Uint8 *) pixel = color;
1010 break;
1011 case 2:
1012 for (; pixel <= pixellast; pixel += pixy) {
1013 *(Uint16 *) pixel = color;
1015 break;
1016 case 3:
1017 for (; pixel <= pixellast; pixel += pixy) {
1018 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1019 pixel[0] = (color >> 16) & 0xff;
1020 pixel[1] = (color >> 8) & 0xff;
1021 pixel[2] = color & 0xff;
1022 } else {
1023 pixel[0] = color & 0xff;
1024 pixel[1] = (color >> 8) & 0xff;
1025 pixel[2] = (color >> 16) & 0xff;
1028 break;
1029 default: /* case 4 */
1030 for (; pixel <= pixellast; pixel += pixy) {
1031 *(Uint32 *) pixel = color;
1033 break;
1037 * Unlock surface
1039 SDL_UnlockSurface(dst);
1042 * Set result code
1044 result = 0;
1046 } else {
1049 * Alpha blending blit
1052 #ifdef SURFACE_ALPHA_PIXEL
1055 * Adjust height for Rect setup
1057 h++;
1060 * Setup source rectangle for pixel
1062 srect.x = 0;
1063 srect.y = 0;
1064 srect.w = 1;
1065 srect.h = h;
1068 * Setup rectangle for line
1070 drect.x = x;
1071 drect.y = y1;
1072 drect.w = 1;
1073 drect.h = h;
1076 * Maybe deallocate existing surface if size is too small
1078 if ((gfxPrimitivesVline != NULL) && (gfxPrimitivesVline->h < h)) {
1079 SDL_FreeSurface(gfxPrimitivesVline);
1080 gfxPrimitivesVline = NULL;
1084 * Create horizontal line surface in destination format if necessary
1086 if (gfxPrimitivesVline == NULL) {
1087 gfxPrimitivesVline =
1088 SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA, 1,
1089 h, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
1093 * Get alpha
1095 a = (color & (Uint32) 0x000000ff);
1098 * Toggle alpha blending if necessary, reset otherwise
1100 if (a != 255) {
1101 SDL_SetAlpha(gfxPrimitivesVline, SDL_SRCALPHA, 255);
1102 } else {
1103 SDL_SetAlpha(gfxPrimitivesVline, 0, 255);
1107 * Draw color into pixel
1109 SDL_FillRect(gfxPrimitivesVline, &srect, color);
1112 * Draw Vline onto destination surface
1114 result = SDL_BlitSurface(gfxPrimitivesVline, &srect, dst, &drect);
1116 #else
1118 result = VLineAlpha(dst, x, y1, y1 + h, color);
1120 #endif
1124 return (result);
1127 int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1130 * Draw
1132 return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1135 /* ----- Rectangle */
1137 int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1139 int result;
1140 Sint16 w, h, xtmp, ytmp;
1144 * Swap x1, x2 if required
1146 if (x1 > x2) {
1147 xtmp = x1;
1148 x1 = x2;
1149 x2 = xtmp;
1153 * Swap y1, y2 if required
1155 if (y1 > y2) {
1156 ytmp = y1;
1157 y1 = y2;
1158 y2 = ytmp;
1162 * Calculate width&height
1164 w = x2 - x1;
1165 h = y2 - y1;
1168 * Sanity check
1170 if ((w < 0) || (h < 0)) {
1171 return (0);
1175 * Test for special cases of straight lines or single point
1177 if (x1 == x2) {
1178 if (y1 == y2) {
1179 return (pixelColor(dst, x1, y1, color));
1180 } else {
1181 return (vlineColor(dst, x1, y1, y2, color));
1183 } else {
1184 if (y1 == y2) {
1185 return (hlineColor(dst, x1, x2, y1, color));
1190 * Draw rectangle
1192 result = 0;
1193 result |= vlineColor(dst, x1, y1, y2, color);
1194 result |= vlineColor(dst, x2, y1, y2, color);
1195 result |= hlineColor(dst, x1, x2, y1, color);
1196 result |= hlineColor(dst, x1, x2, y2, color);
1198 return (result);
1202 int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1205 * Draw
1207 return (rectangleColor
1208 (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1211 /* --------- Clipping routines for box/line */
1213 /* Clipping based heavily on code from */
1215 /* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c */
1217 #define CLIP_LEFT_EDGE 0x1
1218 #define CLIP_RIGHT_EDGE 0x2
1219 #define CLIP_BOTTOM_EDGE 0x4
1220 #define CLIP_TOP_EDGE 0x8
1221 #define CLIP_INSIDE(a) (!a)
1222 #define CLIP_REJECT(a,b) (a&b)
1223 #define CLIP_ACCEPT(a,b) (!(a|b))
1225 static int clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom)
1227 int code = 0;
1229 if (x < left) {
1230 code |= CLIP_LEFT_EDGE;
1231 } else if (x > right) {
1232 code |= CLIP_RIGHT_EDGE;
1234 if (y < top) {
1235 code |= CLIP_TOP_EDGE;
1236 } else if (y > bottom) {
1237 code |= CLIP_BOTTOM_EDGE;
1239 return code;
1242 static int clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2)
1244 Sint16 left, right, top, bottom;
1245 int code1, code2;
1246 int draw = 0;
1247 Sint16 swaptmp;
1248 float m;
1251 * Get clipping boundary
1253 left = dst->clip_rect.x;
1254 right = dst->clip_rect.x + dst->clip_rect.w - 1;
1255 top = dst->clip_rect.y;
1256 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1258 while (1) {
1259 code1 = clipEncode(*x1, *y1, left, top, right, bottom);
1260 code2 = clipEncode(*x2, *y2, left, top, right, bottom);
1261 if (CLIP_ACCEPT(code1, code2)) {
1262 draw = 1;
1263 break;
1264 } else if (CLIP_REJECT(code1, code2))
1265 break;
1266 else {
1267 if (CLIP_INSIDE(code1)) {
1268 swaptmp = *x2;
1269 *x2 = *x1;
1270 *x1 = swaptmp;
1271 swaptmp = *y2;
1272 *y2 = *y1;
1273 *y1 = swaptmp;
1274 swaptmp = code2;
1275 code2 = code1;
1276 code1 = swaptmp;
1278 if (*x2 != *x1) {
1279 m = (*y2 - *y1) / (float) (*x2 - *x1);
1280 } else {
1281 m = 1.0f;
1283 if (code1 & CLIP_LEFT_EDGE) {
1284 *y1 += (Sint16) ((left - *x1) * m);
1285 *x1 = left;
1286 } else if (code1 & CLIP_RIGHT_EDGE) {
1287 *y1 += (Sint16) ((right - *x1) * m);
1288 *x1 = right;
1289 } else if (code1 & CLIP_BOTTOM_EDGE) {
1290 if (*x2 != *x1) {
1291 *x1 += (Sint16) ((bottom - *y1) / m);
1293 *y1 = bottom;
1294 } else if (code1 & CLIP_TOP_EDGE) {
1295 if (*x2 != *x1) {
1296 *x1 += (Sint16) ((top - *y1) / m);
1298 *y1 = top;
1303 return draw;
1306 /* ----- Filled rectangle (Box) */
1308 #ifdef SURFACE_ALPHA_PIXEL
1309 static SDL_Surface *gfxPrimitivesBox = NULL;
1310 #endif
1312 int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1314 Uint8 *pixel, *pixellast;
1315 int x, dx;
1316 int dy;
1317 int pixx, pixy;
1318 Sint16 w, h, tmp;
1319 int result;
1320 Uint8 *colorptr;
1322 #ifdef SURFACE_ALPHA_PIXEL
1323 Uint32 a;
1324 SDL_Rect srect;
1325 SDL_Rect drect;
1326 #endif
1329 * Clip diagonal and test if we have to draw
1331 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
1332 return (0);
1336 * Test for special cases of straight lines or single point
1338 if (x1 == x2) {
1339 if (y1 < y2) {
1340 return (vlineColor(dst, x1, y1, y2, color));
1341 } else if (y1 > y2) {
1342 return (vlineColor(dst, x1, y2, y1, color));
1343 } else {
1344 return (pixelColor(dst, x1, y1, color));
1347 if (y1 == y2) {
1348 if (x1 < x2) {
1349 return (hlineColor(dst, x1, x2, y1, color));
1350 } else if (x1 > x2) {
1351 return (hlineColor(dst, x2, x1, y1, color));
1356 * Order coordinates
1358 if (x1 > x2) {
1359 tmp = x1;
1360 x1 = x2;
1361 x2 = tmp;
1363 if (y1 > y2) {
1364 tmp = y1;
1365 y1 = y2;
1366 y2 = tmp;
1370 * Calculate width&height
1372 w = x2 - x1;
1373 h = y2 - y1;
1376 * Alpha check
1378 if ((color & 255) == 255) {
1381 * No alpha-blending required
1385 * Setup color
1387 colorptr = (Uint8 *) & color;
1388 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1389 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1390 } else {
1391 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1395 * Lock surface
1397 SDL_LockSurface(dst);
1400 * More variable setup
1402 dx = w;
1403 dy = h;
1404 pixx = dst->format->BytesPerPixel;
1405 pixy = dst->pitch;
1406 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
1407 pixellast = pixel + pixx * dx + pixy * dy;
1410 * Draw
1412 switch (dst->format->BytesPerPixel) {
1413 case 1:
1414 for (; pixel <= pixellast; pixel += pixy) {
1415 memset(pixel, (Uint8) color, dx);
1417 break;
1418 case 2:
1419 pixy -= (pixx * dx);
1420 for (; pixel <= pixellast; pixel += pixy) {
1421 for (x = 0; x < dx; x++) {
1422 *(Uint16 *) pixel = color;
1423 pixel += pixx;
1426 break;
1427 case 3:
1428 pixy -= (pixx * dx);
1429 for (; pixel <= pixellast; pixel += pixy) {
1430 for (x = 0; x < dx; x++) {
1431 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1432 pixel[0] = (color >> 16) & 0xff;
1433 pixel[1] = (color >> 8) & 0xff;
1434 pixel[2] = color & 0xff;
1435 } else {
1436 pixel[0] = color & 0xff;
1437 pixel[1] = (color >> 8) & 0xff;
1438 pixel[2] = (color >> 16) & 0xff;
1440 pixel += pixx;
1443 break;
1444 default: /* case 4 */
1445 pixy -= (pixx * dx);
1446 for (; pixel <= pixellast; pixel += pixy) {
1447 for (x = 0; x < dx; x++) {
1448 *(Uint32 *) pixel = color;
1449 pixel += pixx;
1452 break;
1456 * Unlock surface
1458 SDL_UnlockSurface(dst);
1460 result = 0;
1462 } else {
1464 #ifdef SURFACE_ALPHA_PIXEL
1467 * Setup source rectangle for pixel
1469 srect.x = 0;
1470 srect.y = 0;
1471 srect.w = w;
1472 srect.h = h;
1475 * Setup rectangle for line
1477 drect.x = x1;
1478 drect.y = y1;
1479 drect.w = w;
1480 drect.h = h;
1483 * Maybe deallocate existing surface if size is too small
1485 if ((gfxPrimitivesBox != NULL)
1486 && ((gfxPrimitivesBox->w < w) || (gfxPrimitivesBox->h < h))) {
1487 SDL_FreeSurface(gfxPrimitivesBox);
1488 gfxPrimitivesBox = NULL;
1492 * Create box surface in destination format if necessary
1494 if (gfxPrimitivesBox == NULL) {
1495 gfxPrimitivesBox =
1496 SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA, w,
1497 h, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
1501 * Get alpha
1503 a = (color & (Uint32) 0x000000ff);
1506 * Toggle alpha blending if necessary, reset otherwise
1508 if (a != 255) {
1509 SDL_SetAlpha(gfxPrimitivesBox, SDL_SRCALPHA, 255);
1510 } else {
1511 SDL_SetAlpha(gfxPrimitivesBox, 0, 255);
1515 * Draw color into pixel
1517 SDL_FillRect(gfxPrimitivesBox, &srect, color);
1520 * Draw pixel onto destination surface
1522 result = SDL_BlitSurface(gfxPrimitivesBox, &srect, dst, &drect);
1524 #else
1526 result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color);
1528 #endif
1532 return (result);
1535 int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1538 * Draw
1540 return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1543 /* ----- Line */
1545 /* Non-alpha line drawing code adapted from routine */
1546 /* by Pete Shinners, pete@shinners.org */
1547 /* Originally from pygame, http://pygame.seul.org */
1549 #define ABS(a) (((a)<0) ? -(a) : (a))
1551 int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1553 int pixx, pixy;
1554 int x, y;
1555 int dx, dy;
1556 int ax, ay;
1557 int sx, sy;
1558 int swaptmp;
1559 Uint8 *pixel;
1560 Uint8 *colorptr;
1563 * Clip line and test if we have to draw
1565 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
1566 return (0);
1570 * Test for special cases of straight lines or single point
1572 if (x1 == x2) {
1573 if (y1 < y2) {
1574 return (vlineColor(dst, x1, y1, y2, color));
1575 } else if (y1 > y2) {
1576 return (vlineColor(dst, x1, y2, y1, color));
1577 } else {
1578 return (pixelColor(dst, x1, y1, color));
1581 if (y1 == y2) {
1582 if (x1 < x2) {
1583 return (hlineColor(dst, x1, x2, y1, color));
1584 } else if (x1 > x2) {
1585 return (hlineColor(dst, x2, x1, y1, color));
1590 * Variable setup
1592 dx = x2 - x1;
1593 dy = y2 - y1;
1594 sx = (dx >= 0) ? 1 : -1;
1595 sy = (dy >= 0) ? 1 : -1;
1597 /* Lock surface */
1598 if (SDL_MUSTLOCK(dst)) {
1599 if (SDL_LockSurface(dst) < 0) {
1600 return (-1);
1605 * Check for alpha blending
1607 if ((color & 255) == 255) {
1610 * No alpha blending - use fast pixel routines
1614 * Setup color
1616 colorptr = (Uint8 *) & color;
1617 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1618 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1619 } else {
1620 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1624 * More variable setup
1626 dx = sx * dx + 1;
1627 dy = sy * dy + 1;
1628 pixx = dst->format->BytesPerPixel;
1629 pixy = dst->pitch;
1630 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
1631 pixx *= sx;
1632 pixy *= sy;
1633 if (dx < dy) {
1634 swaptmp = dx;
1635 dx = dy;
1636 dy = swaptmp;
1637 swaptmp = pixx;
1638 pixx = pixy;
1639 pixy = swaptmp;
1643 * Draw
1645 x = 0;
1646 y = 0;
1647 switch (dst->format->BytesPerPixel) {
1648 case 1:
1649 for (; x < dx; x++, pixel += pixx) {
1650 *pixel = color;
1651 y += dy;
1652 if (y >= dx) {
1653 y -= dx;
1654 pixel += pixy;
1657 break;
1658 case 2:
1659 for (; x < dx; x++, pixel += pixx) {
1660 *(Uint16 *) pixel = color;
1661 y += dy;
1662 if (y >= dx) {
1663 y -= dx;
1664 pixel += pixy;
1667 break;
1668 case 3:
1669 for (; x < dx; x++, pixel += pixx) {
1670 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1671 pixel[0] = (color >> 16) & 0xff;
1672 pixel[1] = (color >> 8) & 0xff;
1673 pixel[2] = color & 0xff;
1674 } else {
1675 pixel[0] = color & 0xff;
1676 pixel[1] = (color >> 8) & 0xff;
1677 pixel[2] = (color >> 16) & 0xff;
1679 y += dy;
1680 if (y >= dx) {
1681 y -= dx;
1682 pixel += pixy;
1685 break;
1686 default: /* case 4 */
1687 for (; x < dx; x++, pixel += pixx) {
1688 *(Uint32 *) pixel = color;
1689 y += dy;
1690 if (y >= dx) {
1691 y -= dx;
1692 pixel += pixy;
1695 break;
1698 } else {
1701 * Alpha blending required - use single-pixel blits
1704 ax = ABS(dx) << 1;
1705 ay = ABS(dy) << 1;
1706 x = x1;
1707 y = y1;
1708 if (ax > ay) {
1709 int d = ay - (ax >> 1);
1711 while (x != x2) {
1712 pixelColorNolock (dst, x, y, color);
1713 if (d > 0 || (d == 0 && sx == 1)) {
1714 y += sy;
1715 d -= ax;
1717 x += sx;
1718 d += ay;
1720 } else {
1721 int d = ax - (ay >> 1);
1723 while (y != y2) {
1724 pixelColorNolock (dst, x, y, color);
1725 if (d > 0 || ((d == 0) && (sy == 1))) {
1726 x += sx;
1727 d -= ay;
1729 y += sy;
1730 d += ax;
1733 pixelColorNolock (dst, x, y, color);
1737 /* Unlock surface */
1738 if (SDL_MUSTLOCK(dst)) {
1739 SDL_UnlockSurface(dst);
1742 return (0);
1745 int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1748 * Draw
1750 return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1753 /* AA Line */
1755 #define AAlevels 256
1756 #define AAbits 8
1760 This implementation of the Wu antialiasing code is based on Mike Abrash's
1761 DDJ article which was reprinted as Chapter 42 of his Graphics Programming
1762 Black Book, but has been optimized to work with SDL and utilizes 32-bit
1763 fixed-point arithmetic. (A. Schiffler).
1767 int aalineColorInt(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint)
1769 Sint32 xx0, yy0, xx1, yy1;
1770 int result;
1771 Uint32 intshift, erracc, erradj;
1772 Uint32 erracctmp, wgt, wgtcompmask;
1773 int dx, dy, tmp, xdir, y0p1, x0pxdir;
1776 * Clip line and test if we have to draw
1778 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
1779 return (0);
1783 * Keep on working with 32bit numbers
1785 xx0 = x1;
1786 yy0 = y1;
1787 xx1 = x2;
1788 yy1 = y2;
1791 * Reorder points if required
1793 if (yy0 > yy1) {
1794 tmp = yy0;
1795 yy0 = yy1;
1796 yy1 = tmp;
1797 tmp = xx0;
1798 xx0 = xx1;
1799 xx1 = tmp;
1803 * Calculate distance
1805 dx = xx1 - xx0;
1806 dy = yy1 - yy0;
1809 * Adjust for negative dx and set xdir
1811 if (dx >= 0) {
1812 xdir = 1;
1813 } else {
1814 xdir = -1;
1815 dx = (-dx);
1819 * Check for special cases
1821 if (dx == 0) {
1823 * Vertical line
1825 return (vlineColor(dst, x1, y1, y2, color));
1826 } else if (dy == 0) {
1828 * Horizontal line
1830 return (hlineColor(dst, x1, x2, y1, color));
1831 } else if (dx == dy) {
1833 * Diagonal line
1835 return (lineColor(dst, x1, y1, x2, y2, color));
1839 * Line is not horizontal, vertical or diagonal
1841 result = 0;
1844 * Zero accumulator
1846 erracc = 0;
1849 * # of bits by which to shift erracc to get intensity level
1851 intshift = 32 - AAbits;
1853 * Mask used to flip all bits in an intensity weighting
1855 wgtcompmask = AAlevels - 1;
1857 /* Lock surface */
1858 if (SDL_MUSTLOCK(dst)) {
1859 if (SDL_LockSurface(dst) < 0) {
1860 return (-1);
1865 * Draw the initial pixel in the foreground color
1867 result |= pixelColorNolock(dst, x1, y1, color);
1870 * x-major or y-major?
1872 if (dy > dx) {
1875 * y-major. Calculate 16-bit fixed point fractional part of a pixel that
1876 * X advances every time Y advances 1 pixel, truncating the result so that
1877 * we won't overrun the endpoint along the X axis
1880 * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
1882 erradj = ((dx << 16) / dy) << 16;
1885 * draw all pixels other than the first and last
1887 x0pxdir = xx0 + xdir;
1888 while (--dy) {
1889 erracctmp = erracc;
1890 erracc += erradj;
1891 if (erracc <= erracctmp) {
1893 * rollover in error accumulator, x coord advances
1895 xx0 = x0pxdir;
1896 x0pxdir += xdir;
1898 yy0++; /* y-major so always advance Y */
1901 * the AAbits most significant bits of erracc give us the intensity
1902 * weighting for this pixel, and the complement of the weighting for
1903 * the paired pixel.
1905 wgt = (erracc >> intshift) & 255;
1906 result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
1907 result |= pixelColorWeightNolock (dst, x0pxdir, yy0, color, wgt);
1910 } else {
1913 * x-major line. Calculate 16-bit fixed-point fractional part of a pixel
1914 * that Y advances each time X advances 1 pixel, truncating the result so
1915 * that we won't overrun the endpoint along the X axis.
1918 * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
1920 erradj = ((dy << 16) / dx) << 16;
1923 * draw all pixels other than the first and last
1925 y0p1 = yy0 + 1;
1926 while (--dx) {
1928 erracctmp = erracc;
1929 erracc += erradj;
1930 if (erracc <= erracctmp) {
1932 * Accumulator turned over, advance y
1934 yy0 = y0p1;
1935 y0p1++;
1937 xx0 += xdir; /* x-major so always advance X */
1939 * the AAbits most significant bits of erracc give us the intensity
1940 * weighting for this pixel, and the complement of the weighting for
1941 * the paired pixel.
1943 wgt = (erracc >> intshift) & 255;
1944 result |= pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
1945 result |= pixelColorWeightNolock (dst, xx0, y0p1, color, wgt);
1950 * Do we have to draw the endpoint
1952 if (draw_endpoint) {
1954 * Draw final pixel, always exactly intersected by the line and doesn't
1955 * need to be weighted.
1957 result |= pixelColorNolock (dst, x2, y2, color);
1960 /* Unlock surface */
1961 if (SDL_MUSTLOCK(dst)) {
1962 SDL_UnlockSurface(dst);
1965 return (result);
1968 int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1970 return (aalineColorInt(dst, x1, y1, x2, y2, color, 1));
1973 int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1975 return (aalineColorInt
1976 (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
1980 /* ----- Circle */
1982 /* Note: Based on algorithm from sge library, modified by A. Schiffler */
1984 /* with multiple pixel-draw removal and other minor speedup changes. */
1986 int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
1988 int result;
1989 Sint16 x1, y1, x2, y2;
1990 Sint16 cx = 0;
1991 Sint16 cy = r;
1992 Sint16 ocx = (Sint16) 0xffff;
1993 Sint16 ocy = (Sint16) 0xffff;
1994 Sint16 df = 1 - r;
1995 Sint16 d_e = 3;
1996 Sint16 d_se = -2 * r + 5;
1997 Sint16 xpcx, xmcx, xpcy, xmcy;
1998 Sint16 ypcy, ymcy, ypcx, ymcx;
1999 Uint8 *colorptr;
2002 * Sanity check radius
2004 if (r < 0) {
2005 return (-1);
2009 * Special case for r=0 - draw a point
2011 if (r == 0) {
2012 return (pixelColor(dst, x, y, color));
2016 * Test if bounding box of circle is visible
2018 x1 = x - r;
2019 y1 = y - r;
2020 x2 = x + r;
2021 y2 = y + r;
2022 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
2023 return (0);
2027 * Draw circle
2029 result = 0;
2031 /* Lock surface */
2032 if (SDL_MUSTLOCK(dst)) {
2033 if (SDL_LockSurface(dst) < 0) {
2034 return (-1);
2039 * Alpha Check
2041 if ((color & 255) == 255) {
2044 * No Alpha - direct memory writes
2048 * Setup color
2050 colorptr = (Uint8 *) & color;
2051 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2052 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2053 } else {
2054 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2058 * Draw
2060 do {
2061 if ((ocy != cy) || (ocx != cx)) {
2062 xpcx = x + cx;
2063 xmcx = x - cx;
2064 if (cy > 0) {
2065 ypcy = y + cy;
2066 ymcy = y - cy;
2067 result |= fastPixelColorNolock(dst, xmcx, ypcy, color);
2068 result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
2069 result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
2070 result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
2071 } else {
2072 result |= fastPixelColorNolock(dst, xmcx, y, color);
2073 result |= fastPixelColorNolock(dst, xpcx, y, color);
2075 ocy = cy;
2076 xpcy = x + cy;
2077 xmcy = x - cy;
2078 if (cx > 0) {
2079 ypcx = y + cx;
2080 ymcx = y - cx;
2081 result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
2082 result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
2083 result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
2084 result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
2085 } else {
2086 result |= fastPixelColorNolock(dst, xmcy, y, color);
2087 result |= fastPixelColorNolock(dst, xpcy, y, color);
2089 ocx = cx;
2092 * Update
2094 if (df < 0) {
2095 df += d_e;
2096 d_e += 2;
2097 d_se += 2;
2098 } else {
2099 df += d_se;
2100 d_e += 2;
2101 d_se += 4;
2102 cy--;
2104 cx++;
2105 } while (cx <= cy);
2108 * Unlock surface
2110 SDL_UnlockSurface(dst);
2112 } else {
2115 * Using Alpha - blended pixel blits
2118 do {
2120 * Draw
2122 if ((ocy != cy) || (ocx != cx)) {
2123 xpcx = x + cx;
2124 xmcx = x - cx;
2125 if (cy > 0) {
2126 ypcy = y + cy;
2127 ymcy = y - cy;
2128 result |= pixelColorNolock (dst, xmcx, ypcy, color);
2129 result |= pixelColorNolock (dst, xpcx, ypcy, color);
2130 result |= pixelColorNolock (dst, xmcx, ymcy, color);
2131 result |= pixelColorNolock (dst, xpcx, ymcy, color);
2132 } else {
2133 result |= pixelColorNolock (dst, xmcx, y, color);
2134 result |= pixelColorNolock (dst, xpcx, y, color);
2136 ocy = cy;
2137 xpcy = x + cy;
2138 xmcy = x - cy;
2139 if (cx > 0) {
2140 ypcx = y + cx;
2141 ymcx = y - cx;
2142 result |= pixelColorNolock (dst, xmcy, ypcx, color);
2143 result |= pixelColorNolock (dst, xpcy, ypcx, color);
2144 result |= pixelColorNolock (dst, xmcy, ymcx, color);
2145 result |= pixelColorNolock (dst, xpcy, ymcx, color);
2146 } else {
2147 result |= pixelColorNolock (dst, xmcy, y, color);
2148 result |= pixelColorNolock (dst, xpcy, y, color);
2150 ocx = cx;
2153 * Update
2155 if (df < 0) {
2156 df += d_e;
2157 d_e += 2;
2158 d_se += 2;
2159 } else {
2160 df += d_se;
2161 d_e += 2;
2162 d_se += 4;
2163 cy--;
2165 cx++;
2166 } while (cx <= cy);
2168 } /* Alpha check */
2170 /* Unlock surface */
2171 if (SDL_MUSTLOCK(dst)) {
2172 SDL_UnlockSurface(dst);
2175 return (result);
2178 int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2181 * Draw
2183 return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2186 /* ----- AA Circle */
2188 /* AA circle is based on AAellipse */
2190 int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2192 return (aaellipseColor(dst, x, y, r, r, color));
2195 int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2198 * Draw
2200 return (aaellipseColor
2201 (dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2204 /* ----- Filled Circle */
2206 /* Note: Based on algorithm from sge library with multiple-hline draw removal */
2208 /* and other speedup changes. */
2210 int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2212 int result;
2213 Sint16 x1, y1, x2, y2;
2214 Sint16 cx = 0;
2215 Sint16 cy = r;
2216 Sint16 ocx = (Sint16) 0xffff;
2217 Sint16 ocy = (Sint16) 0xffff;
2218 Sint16 df = 1 - r;
2219 Sint16 d_e = 3;
2220 Sint16 d_se = -2 * r + 5;
2221 Sint16 xpcx, xmcx, xpcy, xmcy;
2222 Sint16 ypcy, ymcy, ypcx, ymcx;
2225 * Sanity check radius
2227 if (r < 0) {
2228 return (-1);
2232 * Special case for r=0 - draw a point
2234 if (r == 0) {
2235 return (pixelColor(dst, x, y, color));
2239 * Test bounding box
2241 x1 = x - r;
2242 y1 = y - r;
2243 x2 = x + r;
2244 y2 = y + r;
2245 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
2246 return (0);
2250 * Draw
2252 result = 0;
2253 do {
2254 xpcx = x + cx;
2255 xmcx = x - cx;
2256 xpcy = x + cy;
2257 xmcy = x - cy;
2258 if (ocy != cy) {
2259 if (cy > 0) {
2260 ypcy = y + cy;
2261 ymcy = y - cy;
2262 result |= hlineColor(dst, xmcx, xpcx, ypcy, color);
2263 result |= hlineColor(dst, xmcx, xpcx, ymcy, color);
2264 } else {
2265 result |= hlineColor(dst, xmcx, xpcx, y, color);
2267 ocy = cy;
2269 if (ocx != cx) {
2270 if (cx != cy) {
2271 if (cx > 0) {
2272 ypcx = y + cx;
2273 ymcx = y - cx;
2274 result |= hlineColor(dst, xmcy, xpcy, ymcx, color);
2275 result |= hlineColor(dst, xmcy, xpcy, ypcx, color);
2276 } else {
2277 result |= hlineColor(dst, xmcy, xpcy, y, color);
2280 ocx = cx;
2283 * Update
2285 if (df < 0) {
2286 df += d_e;
2287 d_e += 2;
2288 d_se += 2;
2289 } else {
2290 df += d_se;
2291 d_e += 2;
2292 d_se += 4;
2293 cy--;
2295 cx++;
2296 } while (cx <= cy);
2298 return (result);
2301 int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2304 * Draw
2306 return (filledCircleColor
2307 (dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2311 /* ----- Ellipse */
2313 /* Note: Based on algorithm from sge library with multiple-hline draw removal */
2315 /* and other speedup changes. */
2317 int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
2319 int result;
2320 Sint16 x1, y1, x2, y2;
2321 int ix, iy;
2322 int h, i, j, k;
2323 int oh, oi, oj, ok;
2324 int xmh, xph, ypk, ymk;
2325 int xmi, xpi, ymj, ypj;
2326 int xmj, xpj, ymi, ypi;
2327 int xmk, xpk, ymh, yph;
2328 Uint8 *colorptr;
2331 * Sanity check radii
2333 if ((rx < 0) || (ry < 0)) {
2334 return (-1);
2338 * Special case for rx=0 - draw a vline
2340 if (rx == 0) {
2341 return (vlineColor(dst, x, y - ry, y + ry, color));
2344 * Special case for ry=0 - draw a hline
2346 if (ry == 0) {
2347 return (hlineColor(dst, x - rx, x + rx, y, color));
2351 * Test bounding box
2353 x1 = x - rx;
2354 y1 = y - ry;
2355 x2 = x + rx;
2356 y2 = y + ry;
2357 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
2358 return (0);
2362 * Init vars
2364 oh = oi = oj = ok = 0xFFFF;
2367 * Draw
2369 result = 0;
2371 /* Lock surface */
2372 if (SDL_MUSTLOCK(dst)) {
2373 if (SDL_LockSurface(dst) < 0) {
2374 return (-1);
2379 * Check alpha
2381 if ((color & 255) == 255) {
2384 * No Alpha - direct memory writes
2388 * Setup color
2390 colorptr = (Uint8 *) & color;
2391 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2392 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2393 } else {
2394 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2398 if (rx > ry) {
2399 ix = 0;
2400 iy = rx * 64;
2402 do {
2403 h = (ix + 32) >> 6;
2404 i = (iy + 32) >> 6;
2405 j = (h * ry) / rx;
2406 k = (i * ry) / rx;
2408 if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
2409 xph = x + h;
2410 xmh = x - h;
2411 if (k > 0) {
2412 ypk = y + k;
2413 ymk = y - k;
2414 result |= fastPixelColorNolock(dst, xmh, ypk, color);
2415 result |= fastPixelColorNolock(dst, xph, ypk, color);
2416 result |= fastPixelColorNolock(dst, xmh, ymk, color);
2417 result |= fastPixelColorNolock(dst, xph, ymk, color);
2418 } else {
2419 result |= fastPixelColorNolock(dst, xmh, y, color);
2420 result |= fastPixelColorNolock(dst, xph, y, color);
2422 ok = k;
2423 xpi = x + i;
2424 xmi = x - i;
2425 if (j > 0) {
2426 ypj = y + j;
2427 ymj = y - j;
2428 result |= fastPixelColorNolock(dst, xmi, ypj, color);
2429 result |= fastPixelColorNolock(dst, xpi, ypj, color);
2430 result |= fastPixelColorNolock(dst, xmi, ymj, color);
2431 result |= fastPixelColorNolock(dst, xpi, ymj, color);
2432 } else {
2433 result |= fastPixelColorNolock(dst, xmi, y, color);
2434 result |= fastPixelColorNolock(dst, xpi, y, color);
2436 oj = j;
2439 ix = ix + iy / rx;
2440 iy = iy - ix / rx;
2442 } while (i > h);
2443 } else {
2444 ix = 0;
2445 iy = ry * 64;
2447 do {
2448 h = (ix + 32) >> 6;
2449 i = (iy + 32) >> 6;
2450 j = (h * rx) / ry;
2451 k = (i * rx) / ry;
2453 if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
2454 xmj = x - j;
2455 xpj = x + j;
2456 if (i > 0) {
2457 ypi = y + i;
2458 ymi = y - i;
2459 result |= fastPixelColorNolock(dst, xmj, ypi, color);
2460 result |= fastPixelColorNolock(dst, xpj, ypi, color);
2461 result |= fastPixelColorNolock(dst, xmj, ymi, color);
2462 result |= fastPixelColorNolock(dst, xpj, ymi, color);
2463 } else {
2464 result |= fastPixelColorNolock(dst, xmj, y, color);
2465 result |= fastPixelColorNolock(dst, xpj, y, color);
2467 oi = i;
2468 xmk = x - k;
2469 xpk = x + k;
2470 if (h > 0) {
2471 yph = y + h;
2472 ymh = y - h;
2473 result |= fastPixelColorNolock(dst, xmk, yph, color);
2474 result |= fastPixelColorNolock(dst, xpk, yph, color);
2475 result |= fastPixelColorNolock(dst, xmk, ymh, color);
2476 result |= fastPixelColorNolock(dst, xpk, ymh, color);
2477 } else {
2478 result |= fastPixelColorNolock(dst, xmk, y, color);
2479 result |= fastPixelColorNolock(dst, xpk, y, color);
2481 oh = h;
2484 ix = ix + iy / ry;
2485 iy = iy - ix / ry;
2487 } while (i > h);
2490 } else {
2492 if (rx > ry) {
2493 ix = 0;
2494 iy = rx * 64;
2496 do {
2497 h = (ix + 32) >> 6;
2498 i = (iy + 32) >> 6;
2499 j = (h * ry) / rx;
2500 k = (i * ry) / rx;
2502 if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
2503 xph = x + h;
2504 xmh = x - h;
2505 if (k > 0) {
2506 ypk = y + k;
2507 ymk = y - k;
2508 result |= pixelColorNolock (dst, xmh, ypk, color);
2509 result |= pixelColorNolock (dst, xph, ypk, color);
2510 result |= pixelColorNolock (dst, xmh, ymk, color);
2511 result |= pixelColorNolock (dst, xph, ymk, color);
2512 } else {
2513 result |= pixelColorNolock (dst, xmh, y, color);
2514 result |= pixelColorNolock (dst, xph, y, color);
2516 ok = k;
2517 xpi = x + i;
2518 xmi = x - i;
2519 if (j > 0) {
2520 ypj = y + j;
2521 ymj = y - j;
2522 result |= pixelColorNolock (dst, xmi, ypj, color);
2523 result |= pixelColorNolock (dst, xpi, ypj, color);
2524 result |= pixelColorNolock (dst, xmi, ymj, color);
2525 result |= pixelColor(dst, xpi, ymj, color);
2526 } else {
2527 result |= pixelColorNolock (dst, xmi, y, color);
2528 result |= pixelColorNolock (dst, xpi, y, color);
2530 oj = j;
2533 ix = ix + iy / rx;
2534 iy = iy - ix / rx;
2536 } while (i > h);
2537 } else {
2538 ix = 0;
2539 iy = ry * 64;
2541 do {
2542 h = (ix + 32) >> 6;
2543 i = (iy + 32) >> 6;
2544 j = (h * rx) / ry;
2545 k = (i * rx) / ry;
2547 if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
2548 xmj = x - j;
2549 xpj = x + j;
2550 if (i > 0) {
2551 ypi = y + i;
2552 ymi = y - i;
2553 result |= pixelColorNolock (dst, xmj, ypi, color);
2554 result |= pixelColorNolock (dst, xpj, ypi, color);
2555 result |= pixelColorNolock (dst, xmj, ymi, color);
2556 result |= pixelColorNolock (dst, xpj, ymi, color);
2557 } else {
2558 result |= pixelColorNolock (dst, xmj, y, color);
2559 result |= pixelColorNolock (dst, xpj, y, color);
2561 oi = i;
2562 xmk = x - k;
2563 xpk = x + k;
2564 if (h > 0) {
2565 yph = y + h;
2566 ymh = y - h;
2567 result |= pixelColorNolock (dst, xmk, yph, color);
2568 result |= pixelColorNolock (dst, xpk, yph, color);
2569 result |= pixelColorNolock (dst, xmk, ymh, color);
2570 result |= pixelColorNolock (dst, xpk, ymh, color);
2571 } else {
2572 result |= pixelColorNolock (dst, xmk, y, color);
2573 result |= pixelColorNolock (dst, xpk, y, color);
2575 oh = h;
2578 ix = ix + iy / ry;
2579 iy = iy - ix / ry;
2581 } while (i > h);
2584 } /* Alpha check */
2586 /* Unlock surface */
2587 if (SDL_MUSTLOCK(dst)) {
2588 SDL_UnlockSurface(dst);
2591 return (result);
2594 int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2597 * Draw
2599 return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2602 /* ----- AA Ellipse */
2604 /* Based on code from Anders Lindstroem, based on code from SGE, based on code from TwinLib */
2606 int aaellipseColor(SDL_Surface * dst, Sint16 xc, Sint16 yc, Sint16 rx, Sint16 ry, Uint32 color)
2608 int i;
2609 int a2, b2, ds, dt, dxt, t, s, d;
2610 Sint16 x, y, xs, ys, dyt, xx, yy, xc2, yc2;
2611 float cp;
2612 Uint8 weight, iweight;
2613 int result;
2615 /* Sanity check radius */
2616 if (rx < 1)
2617 rx = 1;
2618 if (ry < 1)
2619 ry = 1;
2621 /* Variable setup */
2622 a2 = rx * rx;
2623 b2 = ry * ry;
2625 ds = 2 * a2;
2626 dt = 2 * b2;
2628 xc2 = 2 * xc;
2629 yc2 = 2 * yc;
2631 dxt = (int) (a2 / sqrt(a2 + b2));
2633 t = 0;
2634 s = -2 * a2 * ry;
2635 d = 0;
2637 x = xc;
2638 y = yc - ry;
2641 /* Draw */
2642 result = 0;
2644 /* Lock surface */
2645 if (SDL_MUSTLOCK(dst)) {
2646 if (SDL_LockSurface(dst) < 0) {
2647 return (-1);
2651 /* "End points" */
2652 result |= pixelColorNolock(dst, x, y, color);
2653 result |= pixelColorNolock(dst, xc2 - x, y, color);
2654 result |= pixelColorNolock(dst, x, yc2 - y, color);
2655 result |= pixelColorNolock(dst, xc2 - x, yc2 - y, color);
2657 for (i = 1; i <= dxt; i++) {
2658 x--;
2659 d += t - b2;
2661 if (d >= 0)
2662 ys = y - 1;
2663 else if ((d - s - a2) > 0) {
2664 if ((2 * d - s - a2) >= 0)
2665 ys = y + 1;
2666 else {
2667 ys = y;
2668 y++;
2669 d -= s + a2;
2670 s += ds;
2672 } else {
2673 y++;
2674 ys = y + 1;
2675 d -= s + a2;
2676 s += ds;
2679 t -= dt;
2681 /* Calculate alpha */
2682 if (s != 0.0) {
2683 cp = (float) abs(d) / (float) abs(s);
2684 if (cp > 1.0) {
2685 cp = 1.0;
2687 } else {
2688 cp = 1.0;
2691 /* Calculate weights */
2692 weight = (Uint8) (cp * 255);
2693 iweight = 255 - weight;
2695 /* Upper half */
2696 xx = xc2 - x;
2697 result |= pixelColorWeightNolock(dst, x, y, color, iweight);
2698 result |= pixelColorWeightNolock(dst, xx, y, color, iweight);
2700 result |= pixelColorWeightNolock(dst, x, ys, color, weight);
2701 result |= pixelColorWeightNolock(dst, xx, ys, color, weight);
2703 /* Lower half */
2704 yy = yc2 - y;
2705 result |= pixelColorWeightNolock(dst, x, yy, color, iweight);
2706 result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
2708 yy = yc2 - ys;
2709 result |= pixelColorWeightNolock(dst, x, yy, color, weight);
2710 result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
2713 dyt = abs(y - yc);
2715 for (i = 1; i <= dyt; i++) {
2716 y++;
2717 d -= s + a2;
2719 if (d <= 0)
2720 xs = x + 1;
2721 else if ((d + t - b2) < 0) {
2722 if ((2 * d + t - b2) <= 0)
2723 xs = x - 1;
2724 else {
2725 xs = x;
2726 x--;
2727 d += t - b2;
2728 t -= dt;
2730 } else {
2731 x--;
2732 xs = x - 1;
2733 d += t - b2;
2734 t -= dt;
2737 s += ds;
2739 /* Calculate alpha */
2740 if (t != 0.0) {
2741 cp = (float) abs(d) / (float) abs(t);
2742 if (cp > 1.0) {
2743 cp = 1.0;
2745 } else {
2746 cp = 1.0;
2749 /* Calculate weight */
2750 weight = (Uint8) (cp * 255);
2751 iweight = 255 - weight;
2753 /* Left half */
2754 xx = xc2 - x;
2755 yy = yc2 - y;
2756 result |= pixelColorWeightNolock(dst, x, y, color, iweight);
2757 result |= pixelColorWeightNolock(dst, xx, y, color, iweight);
2759 result |= pixelColorWeightNolock(dst, x, yy, color, iweight);
2760 result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
2762 /* Right half */
2763 xx = 2 * xc - xs;
2764 result |= pixelColorWeightNolock(dst, xs, y, color, weight);
2765 result |= pixelColorWeightNolock(dst, xx, y, color, weight);
2767 result |= pixelColorWeightNolock(dst, xs, yy, color, weight);
2768 result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
2773 /* Unlock surface */
2774 if (SDL_MUSTLOCK(dst)) {
2775 SDL_UnlockSurface(dst);
2778 return (result);
2781 int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2784 * Draw
2786 return (aaellipseColor
2787 (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2790 /* ---- Filled Ellipse */
2792 /* Note: */
2793 /* Based on algorithm from sge library with multiple-hline draw removal */
2794 /* and other speedup changes. */
2796 int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
2798 int result;
2799 Sint16 x1, y1, x2, y2;
2800 int ix, iy;
2801 int h, i, j, k;
2802 int oh, oi, oj, ok;
2803 int xmh, xph;
2804 int xmi, xpi;
2805 int xmj, xpj;
2806 int xmk, xpk;
2809 * Sanity check radii
2811 if ((rx < 0) || (ry < 0)) {
2812 return (-1);
2816 * Special case for rx=0 - draw a vline
2818 if (rx == 0) {
2819 return (vlineColor(dst, x, y - ry, y + ry, color));
2822 * Special case for ry=0 - draw a hline
2824 if (ry == 0) {
2825 return (hlineColor(dst, x - rx, x + rx, y, color));
2829 * Test bounding box
2831 x1 = x - rx;
2832 y1 = y - ry;
2833 x2 = x + rx;
2834 y2 = y + ry;
2835 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
2836 return (0);
2840 * Init vars
2842 oh = oi = oj = ok = 0xFFFF;
2845 * Draw
2847 result = 0;
2848 if (rx > ry) {
2849 ix = 0;
2850 iy = rx * 64;
2852 do {
2853 h = (ix + 32) >> 6;
2854 i = (iy + 32) >> 6;
2855 j = (h * ry) / rx;
2856 k = (i * ry) / rx;
2858 if ((ok != k) && (oj != k)) {
2859 xph = x + h;
2860 xmh = x - h;
2861 if (k > 0) {
2862 result |= hlineColor(dst, xmh, xph, y + k, color);
2863 result |= hlineColor(dst, xmh, xph, y - k, color);
2864 } else {
2865 result |= hlineColor(dst, xmh, xph, y, color);
2867 ok = k;
2869 if ((oj != j) && (ok != j) && (k != j)) {
2870 xmi = x - i;
2871 xpi = x + i;
2872 if (j > 0) {
2873 result |= hlineColor(dst, xmi, xpi, y + j, color);
2874 result |= hlineColor(dst, xmi, xpi, y - j, color);
2875 } else {
2876 result |= hlineColor(dst, xmi, xpi, y, color);
2878 oj = j;
2881 ix = ix + iy / rx;
2882 iy = iy - ix / rx;
2884 } while (i > h);
2885 } else {
2886 ix = 0;
2887 iy = ry * 64;
2889 do {
2890 h = (ix + 32) >> 6;
2891 i = (iy + 32) >> 6;
2892 j = (h * rx) / ry;
2893 k = (i * rx) / ry;
2895 if ((oi != i) && (oh != i)) {
2896 xmj = x - j;
2897 xpj = x + j;
2898 if (i > 0) {
2899 result |= hlineColor(dst, xmj, xpj, y + i, color);
2900 result |= hlineColor(dst, xmj, xpj, y - i, color);
2901 } else {
2902 result |= hlineColor(dst, xmj, xpj, y, color);
2904 oi = i;
2906 if ((oh != h) && (oi != h) && (i != h)) {
2907 xmk = x - k;
2908 xpk = x + k;
2909 if (h > 0) {
2910 result |= hlineColor(dst, xmk, xpk, y + h, color);
2911 result |= hlineColor(dst, xmk, xpk, y - h, color);
2912 } else {
2913 result |= hlineColor(dst, xmk, xpk, y, color);
2915 oh = h;
2918 ix = ix + iy / ry;
2919 iy = iy - ix / ry;
2921 } while (i > h);
2924 return (result);
2928 int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2931 * Draw
2933 return (filledEllipseColor
2934 (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2937 /* ----- filled pie */
2939 /* Low-speed float pie-calc implementation by drawing polygons. */
2941 int filledpieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
2943 int result;
2944 Sint16 x1, y1, x2, y2;
2945 double angle, start_angle, end_angle;
2946 double deltaAngle;
2947 double dr;
2948 int posX, posY;
2949 int numpoints, i;
2950 Sint16 *vx, *vy;
2953 * Sanity check radii
2955 if (rad < 0) {
2956 return (-1);
2960 * Fixup angles
2962 start = start % 360;
2963 end = end % 360;
2966 * Special case for rad=0 - draw a point
2968 if (rad == 0) {
2969 return (pixelColor(dst, x, y, color));
2973 * Test bounding box for visibility
2975 x1 = x - rad;
2976 y1 = y - rad;
2977 x2 = x + rad;
2978 y2 = y + rad;
2979 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
2980 return (0);
2984 * Variable setup
2986 dr = (double) rad;
2987 deltaAngle = 3.0 / dr;
2988 start_angle = (double) start *(2.0 * M_PI / 360.0);
2989 end_angle = (double) end *(2.0 * M_PI / 360.0);
2990 if (start > end) {
2991 end_angle += (2.0 * M_PI);
2994 /* Count points (rather than calculate it) */
2995 numpoints = 1;
2996 angle = start_angle;
2997 while (angle <= end_angle) {
2998 angle += deltaAngle;
2999 numpoints++;
3002 /* Check size of array */
3003 if (numpoints == 1) {
3004 return (pixelColor(dst, x, y, color));
3005 } else if (numpoints == 2) {
3006 posX = x + (int) (dr * cos(start_angle));
3007 posY = y + (int) (dr * sin(start_angle));
3008 return (lineColor(dst, x, y, posX, posY, color));
3011 /* Allocate vertex array */
3012 vx = vy = (Uint16 *) malloc(2 * sizeof(Uint16) * numpoints);
3013 if (vx == NULL) {
3014 return (-1);
3016 vy += numpoints;
3018 /* Center */
3019 vx[0] = x;
3020 vy[0] = y;
3022 /* Calculate and store vertices */
3023 i = 1;
3024 angle = start_angle;
3025 while (angle <= end_angle) {
3026 vx[i] = x + (int) (dr * cos(angle));
3027 vy[i] = y + (int) (dr * sin(angle));
3028 angle += deltaAngle;
3029 i++;
3032 /* Draw */
3033 result = filledPolygonColor(dst, vx, vy, numpoints, color);
3035 /* Free vertex */
3036 free(vx);
3038 return (result);
3041 int filledpieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
3042 Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3044 return (filledpieColor(dst, x, y, rad, start, end,
3045 ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3049 /* ---- Polygon */
3051 int polygonColor(SDL_Surface * dst, Sint16 * vx, Sint16 * vy, int n, Uint32 color)
3053 int result;
3054 int i;
3055 Sint16 *x1, *y1, *x2, *y2;
3058 * Sanity check
3060 if (n < 3) {
3061 return (-1);
3065 * Pointer setup
3067 x1 = x2 = vx;
3068 y1 = y2 = vy;
3069 x2++;
3070 y2++;
3073 * Draw
3075 result = 0;
3076 for (i = 1; i < n; i++) {
3077 result |= lineColor(dst, *x1, *y1, *x2, *y2, color);
3078 x1 = x2;
3079 y1 = y2;
3080 x2++;
3081 y2++;
3083 result |= lineColor(dst, *x1, *y1, *vx, *vy, color);
3085 return (result);
3088 int polygonRGBA(SDL_Surface * dst, Sint16 * vx, Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3091 * Draw
3093 return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3096 /* ---- AA-Polygon */
3098 int aapolygonColor(SDL_Surface * dst, Sint16 * vx, Sint16 * vy, int n, Uint32 color)
3100 int result;
3101 int i;
3102 Sint16 *x1, *y1, *x2, *y2;
3105 * Sanity check
3107 if (n < 3) {
3108 return (-1);
3112 * Pointer setup
3114 x1 = x2 = vx;
3115 y1 = y2 = vy;
3116 x2++;
3117 y2++;
3120 * Draw
3122 result = 0;
3123 for (i = 1; i < n; i++) {
3124 result |= aalineColorInt(dst, *x1, *y1, *x2, *y2, color, 0);
3125 x1 = x2;
3126 y1 = y2;
3127 x2++;
3128 y2++;
3130 result |= aalineColorInt(dst, *x1, *y1, *vx, *vy, color, 0);
3132 return (result);
3135 int aapolygonRGBA(SDL_Surface * dst, Sint16 * vx, Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3138 * Draw
3140 return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3143 /* ---- Filled Polygon */
3145 int gfxPrimitivesCompareInt(const void *a, const void *b);
3147 static int *gfxPrimitivesPolyInts = NULL;
3148 static int gfxPrimitivesPolyAllocated = 0;
3150 int filledPolygonColor(SDL_Surface * dst, Sint16 * vx, Sint16 * vy, int n, int color)
3152 int result;
3153 int i;
3154 int y;
3155 int miny, maxy;
3156 int x1, y1;
3157 int x2, y2;
3158 int ind1, ind2;
3159 int ints;
3162 * Sanity check
3164 if (n < 3) {
3165 return -1;
3169 * Allocate temp array, only grow array
3171 if (!gfxPrimitivesPolyAllocated) {
3172 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
3173 gfxPrimitivesPolyAllocated = n;
3174 } else {
3175 if (gfxPrimitivesPolyAllocated < n) {
3176 gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
3177 gfxPrimitivesPolyAllocated = n;
3182 * Determine Y maxima
3184 miny = vy[0];
3185 maxy = vy[0];
3186 for (i = 1; (i < n); i++) {
3187 if (vy[i] < miny) {
3188 miny = vy[i];
3189 } else if (vy[i] > maxy) {
3190 maxy = vy[i];
3195 * Draw, scanning y
3197 result = 0;
3198 for (y = miny; (y <= maxy); y++) {
3199 ints = 0;
3200 for (i = 0; (i < n); i++) {
3201 if (!i) {
3202 ind1 = n - 1;
3203 ind2 = 0;
3204 } else {
3205 ind1 = i - 1;
3206 ind2 = i;
3208 y1 = vy[ind1];
3209 y2 = vy[ind2];
3210 if (y1 < y2) {
3211 x1 = vx[ind1];
3212 x2 = vx[ind2];
3213 } else if (y1 > y2) {
3214 y2 = vy[ind1];
3215 y1 = vy[ind2];
3216 x2 = vx[ind1];
3217 x1 = vx[ind2];
3218 } else {
3219 continue;
3221 if ((y >= y1) && (y < y2)) {
3222 gfxPrimitivesPolyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
3223 } else if ((y == maxy) && (y > y1) && (y <= y2)) {
3224 gfxPrimitivesPolyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
3227 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt);
3229 for (i = 0; (i < ints); i += 2) {
3230 result |= hlineColor(dst, gfxPrimitivesPolyInts[i], gfxPrimitivesPolyInts[i + 1], y, color);
3234 return (result);
3237 int filledPolygonRGBA(SDL_Surface * dst, Sint16 * vx, Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3240 * Draw
3242 return (filledPolygonColor
3243 (dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3246 int gfxPrimitivesCompareInt(const void *a, const void *b)
3248 return (*(const int *) a) - (*(const int *) b);
3251 /* ---- Character (8x8 internal font) */
3253 static SDL_Surface *gfxPrimitivesFont[256];
3254 static Uint32 gfxPrimitivesFontColor[256];
3256 int characterColor(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint32 color)
3258 SDL_Rect srect;
3259 SDL_Rect drect;
3260 int result;
3261 int ix, iy, k;
3262 unsigned char *charpos;
3263 unsigned char bits[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
3264 unsigned char *bitpos;
3265 Uint8 *curpos;
3266 int forced_redraw;
3269 * Setup source rectangle for 8x8 bitmap
3271 srect.x = 0;
3272 srect.y = 0;
3273 srect.w = 8;
3274 srect.h = 8;
3277 * Setup destination rectangle for 8x8 bitmap
3279 drect.x = x;
3280 drect.y = y;
3281 drect.w = 8;
3282 drect.h = 8;
3285 * Create new 8x8 bitmap surface if not already present
3287 if (gfxPrimitivesFont[(unsigned char) c] == NULL) {
3288 gfxPrimitivesFont[(unsigned char) c] =
3289 SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA, 8, 8,
3290 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
3292 * Check pointer
3294 if (gfxPrimitivesFont[(unsigned char) c] == NULL) {
3295 return (-1);
3298 * Definitely redraw
3300 forced_redraw = 1;
3301 } else {
3302 forced_redraw = 0;
3306 * Check if color has changed
3308 if ((gfxPrimitivesFontColor[(unsigned char) c] != color) || (forced_redraw)) {
3310 * Redraw character
3312 SDL_SetAlpha(gfxPrimitivesFont[(unsigned char) c], SDL_SRCALPHA, 255);
3313 gfxPrimitivesFontColor[(unsigned char) c] = color;
3316 * Variable setup
3318 k = (unsigned char) c;
3319 k *= 8;
3320 charpos = gfxPrimitivesFontdata;
3321 charpos += k;
3324 * Clear bitmap
3326 curpos = (Uint8 *) gfxPrimitivesFont[(unsigned char) c]->pixels;
3327 memset(curpos, 0, 8 * 8 * 4);
3330 * Drawing loop
3332 for (iy = 0; iy < 8; iy++) {
3333 bitpos = bits;
3334 for (ix = 0; ix < 8; ix++) {
3335 if ((*charpos & *bitpos) == *bitpos) {
3336 memcpy(curpos, &color, 4);
3338 bitpos++;
3339 curpos += 4;;
3341 charpos++;
3346 * Draw bitmap onto destination surface
3348 result = SDL_BlitSurface(gfxPrimitivesFont[(unsigned char) c], &srect, dst, &drect);
3350 return (result);
3353 int characterRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3356 * Draw
3358 return (characterColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3361 int stringColor(SDL_Surface * dst, Sint16 x, Sint16 y, char *c, Uint32 color)
3363 int result;
3364 int i, length;
3365 char *curchar;
3366 int curx;
3368 length = strlen(c);
3369 curchar = c;
3370 curx = x;
3371 result = 0;
3372 for (i = 0; i < length; i++) {
3373 result |= characterColor(dst, curx, y, *curchar, color);
3374 curchar++;
3375 curx += 8;
3378 return (result);
3381 int stringRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, char *c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3384 * Draw
3386 return (stringColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));