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