1 /*
2
3 SDL_gfxPrimitives - Graphics primitives for SDL surfaces
4
5 GPLv3 (c) A. Schiffler
6
7 License changed from LGPL to GPLv3, as per section 3 of the LGPL,
8 by M. Bays 2008.
9 Dirty pixels/rects handling added by M. Bays 2008.
10
11 */
12
13 #include <cstdio>
14 #include <cstdlib>
15 #include <cmath>
16 #include <cstring>
17
18 #include <vector>
19
20 #include "SDL_gfxPrimitivesDirty.h"
21 #include "SDL_gfxPrimitives_font.h"
22
23 /* -===================- */
24
25 //#define MODIFIED_ALPHA_PIXEL_ROUTINE
26 #define ORIGINAL_ALPHA_PIXEL_ROUTINE
27
28 /* ----- Defines for pixel clipping tests */
29
30 #define clip_xmin(surface) surface->clip_rect.x
31 #define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1
32 #define clip_ymin(surface) surface->clip_rect.y
33 #define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1
34
35 SDL_Surface* dirtyDst = NULL;
36 SDL_Surface* dirtyBackground = NULL;
37 std::vector<Uint8*> dirtyPixels;
38 std::vector<SDL_Rect> dirtyRects;
39
40 // Set surface to accumulate dirtiness information for subsequent calls to
41 // blankDirty, which will then redraw the background over dirtied pixels.
42 // &background should be either a surface of the same size and format as &dst,
43 // or NULL to indicate a black background.
setDirty(SDL_Surface * dst,SDL_Surface * background)44 void setDirty(SDL_Surface* dst, SDL_Surface* background)
45 {
46 dirtyDst = dst;
47 dirtyBackground = background;
48 dirtyPixels.clear();
49 dirtyRects.clear();
50 }
51
blankDirty()52 int blankDirty()
53 {
54 if (!dirtyDst)
55 return -1;
56
57 /*
58 * Lock the surface
59 */
60 if (SDL_MUSTLOCK(dirtyDst)) {
61 if (SDL_LockSurface(dirtyDst) < 0) {
62 return (-1);
63 }
64 }
65
66 const Uint32 black = 0;
67
68 while (!dirtyPixels.empty())
69 {
70 Uint8* p = dirtyPixels.back();
71 dirtyPixels.pop_back();
72 int bpp = dirtyDst->format->BytesPerPixel;
73 if (dirtyBackground)
74 {
75 const Uint8* bp = (Uint8*)dirtyBackground->pixels + (p -
76 (Uint8*)dirtyDst->pixels);
77 for (int i=0; i<bpp; i++)
78 *(p+i) = *(bp+i);
79 }
80 else
81 {
82 switch (bpp) {
83 case 1:
84 *p = black;
85 break;
86 case 2:
87 *(Uint16 *) p = black;
88 break;
89 case 3:
90 {
91 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
92 p[0] = (black >> 16) & 0xff;
93 p[1] = (black >> 8) & 0xff;
94 p[2] = black & 0xff;
95 } else {
96 p[0] = black & 0xff;
97 p[1] = (black >> 8) & 0xff;
98 p[2] = (black >> 16) & 0xff;
99 }
100 }
101 break;
102 case 4:
103 *(Uint32 *) p = black;
104 break;
105 } /* switch */
106 }
107 }
108
109 /*
110 * Unlock the surface
111 */
112 if (SDL_MUSTLOCK(dirtyDst)) {
113 SDL_UnlockSurface(dirtyDst);
114 }
115
116 while (!dirtyRects.empty())
117 {
118 SDL_Rect rect = dirtyRects.back();
119 dirtyRects.pop_back();
120 if (dirtyBackground)
121 SDL_BlitSurface(dirtyBackground, &rect, dirtyDst, &rect);
122 else
123 SDL_FillRect(dirtyDst, &rect, 0);
124 }
125
126 return 0;
127 }
128
129 /* ----- Pixel - fast, no blending, no locking, clipping */
130
fastPixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)131 int fastPixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
132 {
133 int bpp;
134 Uint8 *p;
135
136 /*
137 * Honor clipping setup at pixel level
138 */
139 if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) {
140
141 /*
142 * Get destination format
143 */
144 bpp = dst->format->BytesPerPixel;
145 p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
146 if (dirtyDst == dst)
147 dirtyPixels.push_back(p);
148 switch (bpp) {
149 case 1:
150 *p = color;
151 break;
152 case 2:
153 *(Uint16 *) p = color;
154 break;
155 case 3:
156 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
157 p[0] = (color >> 16) & 0xff;
158 p[1] = (color >> 8) & 0xff;
159 p[2] = color & 0xff;
160 } else {
161 p[0] = color & 0xff;
162 p[1] = (color >> 8) & 0xff;
163 p[2] = (color >> 16) & 0xff;
164 }
165 break;
166 case 4:
167 *(Uint32 *) p = color;
168 break;
169 } /* switch */
170
171
172 }
173
174 return (0);
175 }
176
177 /* ----- Pixel - fast, no blending, no locking, no clipping */
178
179 /* (faster but dangerous, make sure we stay in surface bounds) */
180
fastPixelColorNolockNoclip(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)181 int fastPixelColorNolockNoclip(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
182 {
183 int bpp;
184 Uint8 *p;
185
186 /*
187 * Get destination format
188 */
189 bpp = dst->format->BytesPerPixel;
190 p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
191 if (dirtyDst == dst)
192 dirtyPixels.push_back(p);
193 switch (bpp) {
194 case 1:
195 *p = color;
196 break;
197 case 2:
198 *(Uint16 *) p = color;
199 break;
200 case 3:
201 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
202 p[0] = (color >> 16) & 0xff;
203 p[1] = (color >> 8) & 0xff;
204 p[2] = color & 0xff;
205 } else {
206 p[0] = color & 0xff;
207 p[1] = (color >> 8) & 0xff;
208 p[2] = (color >> 16) & 0xff;
209 }
210 break;
211 case 4:
212 *(Uint32 *) p = color;
213 break;
214 } /* switch */
215
216 return (0);
217 }
218
219 /* ----- Pixel - fast, no blending, locking, clipping */
220
fastPixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)221 int fastPixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
222 {
223 int result;
224
225 /*
226 * Lock the surface
227 */
228 if (SDL_MUSTLOCK(dst)) {
229 if (SDL_LockSurface(dst) < 0) {
230 return (-1);
231 }
232 }
233
234 result = fastPixelColorNolock(dst, x, y, color);
235
236 /*
237 * Unlock surface
238 */
239 if (SDL_MUSTLOCK(dst)) {
240 SDL_UnlockSurface(dst);
241 }
242
243 return (result);
244 }
245
246 /* ----- Pixel - fast, no blending, locking, RGB input */
247
fastPixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)248 int fastPixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
249 {
250 Uint32 color;
251
252 /*
253 * Setup color
254 */
255 color = SDL_MapRGBA(dst->format, r, g, b, a);
256
257 /*
258 * Draw
259 */
260 return (fastPixelColor(dst, x, y, color));
261
262 }
263
264 /* ----- Pixel - fast, no blending, no locking RGB input */
265
fastPixelRGBANolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)266 int fastPixelRGBANolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
267 {
268 Uint32 color;
269
270 /*
271 * Setup color
272 */
273 color = SDL_MapRGBA(dst->format, r, g, b, a);
274
275 /*
276 * Draw
277 */
278 return (fastPixelColorNolock(dst, x, y, color));
279 }
280
281 /* PutPixel routine with alpha blending, input color in destination format */
282
283 /* New, faster routine - default blending pixel */
284
_putPixelAlpha(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color,Uint8 alpha)285 int _putPixelAlpha(SDL_Surface * surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
286 {
287 Uint32 Rmask = surface->format->Rmask, Gmask =
288 surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
289 Uint32 R, G, B, A = 0;
290
291 if (x >= clip_xmin(surface) && x <= clip_xmax(surface)
292 && y >= clip_ymin(surface) && y <= clip_ymax(surface)) {
293
294 if (dirtyDst == surface)
295 dirtyPixels.push_back(
296 (Uint8 *) surface->pixels + y * surface->pitch +
297 x * surface->format->BytesPerPixel);
298
299 switch (surface->format->BytesPerPixel) {
300 case 1:{ /* Assuming 8-bpp */
301 if (alpha == 255) {
302 *((Uint8 *) surface->pixels + y * surface->pitch + x) = color;
303 } else {
304 Uint8 *pixel = (Uint8 *) surface->pixels + y * surface->pitch + x;
305
306 Uint8 dR = surface->format->palette->colors[*pixel].r;
307 Uint8 dG = surface->format->palette->colors[*pixel].g;
308 Uint8 dB = surface->format->palette->colors[*pixel].b;
309 Uint8 sR = surface->format->palette->colors[color].r;
310 Uint8 sG = surface->format->palette->colors[color].g;
311 Uint8 sB = surface->format->palette->colors[color].b;
312
313 dR = dR + ((sR - dR) * alpha >> 8);
314 dG = dG + ((sG - dG) * alpha >> 8);
315 dB = dB + ((sB - dB) * alpha >> 8);
316
317 *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
318 }
319 }
320 break;
321
322 case 2:{ /* Probably 15-bpp or 16-bpp */
323 if (alpha == 255) {
324 *((Uint16 *) surface->pixels + y * surface->pitch / 2 + x) = color;
325 } else {
326 Uint16 *pixel = (Uint16 *) surface->pixels + y * surface->pitch / 2 + x;
327 Uint32 dc = *pixel;
328
329 R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask;
330 G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask;
331 B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask;
332 if (Amask)
333 A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask;
334
335 *pixel = R | G | B | A;
336 }
337 }
338 break;
339
340 case 3:{ /* Slow 24-bpp mode, usually not used */
341 Uint8 *pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
342 Uint8 rshift8 = surface->format->Rshift / 8;
343 Uint8 gshift8 = surface->format->Gshift / 8;
344 Uint8 bshift8 = surface->format->Bshift / 8;
345 Uint8 ashift8 = surface->format->Ashift / 8;
346
347
348 if (alpha == 255) {
349 *(pix + rshift8) = color >> surface->format->Rshift;
350 *(pix + gshift8) = color >> surface->format->Gshift;
351 *(pix + bshift8) = color >> surface->format->Bshift;
352 *(pix + ashift8) = color >> surface->format->Ashift;
353 } else {
354 Uint8 dR, dG, dB, dA = 0;
355 Uint8 sR, sG, sB, sA = 0;
356
357 pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
358
359 dR = *((pix) + rshift8);
360 dG = *((pix) + gshift8);
361 dB = *((pix) + bshift8);
362 dA = *((pix) + ashift8);
363
364 sR = (color >> surface->format->Rshift) & 0xff;
365 sG = (color >> surface->format->Gshift) & 0xff;
366 sB = (color >> surface->format->Bshift) & 0xff;
367 sA = (color >> surface->format->Ashift) & 0xff;
368
369 dR = dR + ((sR - dR) * alpha >> 8);
370 dG = dG + ((sG - dG) * alpha >> 8);
371 dB = dB + ((sB - dB) * alpha >> 8);
372 dA = dA + ((sA - dA) * alpha >> 8);
373
374 *((pix) + rshift8) = dR;
375 *((pix) + gshift8) = dG;
376 *((pix) + bshift8) = dB;
377 *((pix) + ashift8) = dA;
378 }
379 }
380 break;
381
382 case 4:{ /* Probably :-) 32-bpp */
383 if (alpha == 255) {
384 *((Uint32 *) surface->pixels + y * surface->pitch / 4 + x) = color;
385 } else {
386 Uint32 Rshift, Gshift, Bshift, Ashift;
387 Uint32 *pixel = (Uint32 *) surface->pixels + y * surface->pitch / 4 + x;
388 Uint32 dc = *pixel;
389
390 Rshift = surface->format->Rshift;
391 Gshift = surface->format->Gshift;
392 Bshift = surface->format->Bshift;
393 Ashift = surface->format->Ashift;
394
395 R = ((dc & Rmask) + (((((color & Rmask) - (dc & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask;
396 G = ((dc & Gmask) + (((((color & Gmask) - (dc & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask;
397 B = ((dc & Bmask) + (((((color & Bmask) - (dc & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask;
398 if (Amask)
399 A = ((dc & Amask) + (((((color & Amask) - (dc & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask;
400
401 *pixel = R | G | B | A;
402 }
403 }
404 break;
405 }
406 }
407
408 return (0);
409 }
410
411 /* ----- Pixel - pixel draw with blending enabled if a<255 */
412
pixelColor(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)413 int pixelColor(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
414 {
415 Uint8 alpha;
416 Uint32 mcolor;
417 int result = 0;
418
419 /*
420 * Lock the surface
421 */
422 if (SDL_MUSTLOCK(dst)) {
423 if (SDL_LockSurface(dst) < 0) {
424 return (-1);
425 }
426 }
427
428 /*
429 * Setup color
430 */
431 alpha = color & 0x000000ff;
432 mcolor =
433 SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
434 (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
435
436 /*
437 * Draw
438 */
439 result = _putPixelAlpha(dst, x, y, mcolor, alpha);
440
441 /*
442 * Unlock the surface
443 */
444 if (SDL_MUSTLOCK(dst)) {
445 SDL_UnlockSurface(dst);
446 }
447
448 return (result);
449 }
450
pixelColorNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color)451 int pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
452 {
453 Uint8 alpha;
454 Uint32 mcolor;
455 int result = 0;
456
457 /*
458 * Setup color
459 */
460 alpha = color & 0x000000ff;
461 mcolor =
462 SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
463 (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
464
465 /*
466 * Draw
467 */
468 result = _putPixelAlpha(dst, x, y, mcolor, alpha);
469
470 return (result);
471 }
472
473
474 /* Filled rectangle with alpha blending, color in destination format */
475
_filledRectAlpha(SDL_Surface * surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,Uint8 alpha)476 int _filledRectAlpha(SDL_Surface * surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
477 {
478 Uint32 Rmask = surface->format->Rmask, Gmask =
479 surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
480 Uint32 R, G, B, A = 0;
481 Sint16 x, y;
482
483 switch (surface->format->BytesPerPixel) {
484 case 1:{ /* Assuming 8-bpp */
485 Uint8 *row, *pixel;
486 Uint8 dR, dG, dB;
487
488 Uint8 sR = surface->format->palette->colors[color].r;
489 Uint8 sG = surface->format->palette->colors[color].g;
490 Uint8 sB = surface->format->palette->colors[color].b;
491
492 for (y = y1; y <= y2; y++) {
493 row = (Uint8 *) surface->pixels + y * surface->pitch;
494 for (x = x1; x <= x2; x++) {
495 pixel = row + x;
496
497 dR = surface->format->palette->colors[*pixel].r;
498 dG = surface->format->palette->colors[*pixel].g;
499 dB = surface->format->palette->colors[*pixel].b;
500
501 dR = dR + ((sR - dR) * alpha >> 8);
502 dG = dG + ((sG - dG) * alpha >> 8);
503 dB = dB + ((sB - dB) * alpha >> 8);
504
505 *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
506 if (dirtyDst == surface)
507 dirtyPixels.push_back(pixel);
508 }
509 }
510 }
511 break;
512
513 case 2:{ /* Probably 15-bpp or 16-bpp */
514 Uint16 *row, *pixel;
515 Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
516
517 for (y = y1; y <= y2; y++) {
518 row = (Uint16 *) surface->pixels + y * surface->pitch / 2;
519 for (x = x1; x <= x2; x++) {
520 pixel = row + x;
521
522 R = ((*pixel & Rmask) + ((dR - (*pixel & Rmask)) * alpha >> 8)) & Rmask;
523 G = ((*pixel & Gmask) + ((dG - (*pixel & Gmask)) * alpha >> 8)) & Gmask;
524 B = ((*pixel & Bmask) + ((dB - (*pixel & Bmask)) * alpha >> 8)) & Bmask;
525 if (Amask)
526 A = ((*pixel & Amask) + ((dA - (*pixel & Amask)) * alpha >> 8)) & Amask;
527
528 *pixel = R | G | B | A;
529 if (dirtyDst == surface)
530 dirtyPixels.push_back( (Uint8*) pixel );
531 }
532 }
533 }
534 break;
535
536 case 3:{ /* Slow 24-bpp mode, usually not used */
537 Uint8 *row, *pix;
538 Uint8 dR, dG, dB, dA;
539 Uint8 rshift8 = surface->format->Rshift / 8;
540 Uint8 gshift8 = surface->format->Gshift / 8;
541 Uint8 bshift8 = surface->format->Bshift / 8;
542 Uint8 ashift8 = surface->format->Ashift / 8;
543
544 Uint8 sR = (color >> surface->format->Rshift) & 0xff;
545 Uint8 sG = (color >> surface->format->Gshift) & 0xff;
546 Uint8 sB = (color >> surface->format->Bshift) & 0xff;
547 Uint8 sA = (color >> surface->format->Ashift) & 0xff;
548
549 for (y = y1; y <= y2; y++) {
550 row = (Uint8 *) surface->pixels + y * surface->pitch;
551 for (x = x1; x <= x2; x++) {
552 pix = row + x * 3;
553
554 dR = *((pix) + rshift8);
555 dG = *((pix) + gshift8);
556 dB = *((pix) + bshift8);
557 dA = *((pix) + ashift8);
558
559 dR = dR + ((sR - dR) * alpha >> 8);
560 dG = dG + ((sG - dG) * alpha >> 8);
561 dB = dB + ((sB - dB) * alpha >> 8);
562 dA = dA + ((sA - dA) * alpha >> 8);
563
564 *((pix) + rshift8) = dR;
565 *((pix) + gshift8) = dG;
566 *((pix) + bshift8) = dB;
567 *((pix) + ashift8) = dA;
568 if (dirtyDst == surface)
569 dirtyPixels.push_back(pix);
570 }
571 }
572
573 }
574 break;
575
576 #ifdef ORIGINAL_ALPHA_PIXEL_ROUTINE
577 case 4:{ /* Probably :-) 32-bpp */
578 Uint32 Rshift, Gshift, Bshift, Ashift;
579 Uint32 *row, *pixel;
580 Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
581
582 Rshift = surface->format->Rshift;
583 Gshift = surface->format->Gshift;
584 Bshift = surface->format->Bshift;
585 Ashift = surface->format->Ashift;
586
587 for (y = y1; y <= y2; y++) {
588 row = (Uint32 *) surface->pixels + y * surface->pitch / 4;
589 for (x = x1; x <= x2; x++) {
590 pixel = row + x;
591
592 R = ((*pixel & Rmask) + ((((dR - (*pixel & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask;
593 G = ((*pixel & Gmask) + ((((dG - (*pixel & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask;
594 B = ((*pixel & Bmask) + ((((dB - (*pixel & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask;
595 if (Amask)
596 A = ((*pixel & Amask) + ((((dA - (*pixel & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask;
597
598 *pixel = R | G | B | A;
599 if (dirtyDst == surface)
600 dirtyPixels.push_back( (Uint8*) pixel );
601 }
602 }
603 }
604 break;
605 #endif
606
607 #ifdef MODIFIED_ALPHA_PIXEL_ROUTINE
608 case 4:{ /* Probably :-) 32-bpp */
609 Uint32 Rshift, Gshift, Bshift, Ashift;
610 Uint32 *row, *pixel;
611 Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask);
612 Uint32 dc;
613 Uint32 preMultR, preMultG, preMultB, preMultA;
614 Uint32 aTmp;
615
616 Rshift = surface->format->Rshift;
617 Gshift = surface->format->Gshift;
618 Bshift = surface->format->Bshift;
619 Ashift = surface->format->Ashift;
620
621 preMultR = (alpha * (dR>>Rshift));
622 preMultG = (alpha * (dG>>Gshift));
623 preMultB = (alpha * (dB>>Bshift));
624 preMultA = (alpha * (dA>>Ashift));
625
626 for (y = y1; y <= y2; y++) {
627 row = (Uint32 *) surface->pixels + y * surface->pitch / 4;
628 for (x = x1; x <= x2; x++) {
629 pixel = row + x;
630 dc = *pixel;
631
632 aTmp = (255 - alpha);
633 R = (preMultR + (aTmp * ((dc & Rmask) >> Rshift))) >> 8 << Rshift & Rmask;
634 G = (preMultG + (aTmp * ((dc & Gmask) >> Gshift))) >> 8 << Gshift & Gmask;
635 B = (preMultB + (aTmp * ((dc & Bmask) >> Bshift))) >> 8 << Bshift & Bmask;
636 if (Amask)
637 A = (preMultA + (aTmp * ((dc & Amask) >> Ashift))) >> 8 << Ashift & Amask;
638 *pixel = R | G | B | A;
639 if (dirtyDst == surface)
640 dirtyPixels.push_back(pixel);
641 }
642 }
643 }
644 break;
645 #endif
646
647 }
648
649 return (0);
650 }
651
652 /* Draw rectangle with alpha enabled from RGBA color. */
653
filledRectAlpha(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)654 int filledRectAlpha(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
655 {
656 Uint8 alpha;
657 Uint32 mcolor;
658 int result = 0;
659
660 /*
661 * Lock the surface
662 */
663 if (SDL_MUSTLOCK(dst)) {
664 if (SDL_LockSurface(dst) < 0) {
665 return (-1);
666 }
667 }
668
669 /*
670 * Setup color
671 */
672 alpha = color & 0x000000ff;
673 mcolor =
674 SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
675 (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
676
677 /*
678 * Draw
679 */
680 result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha);
681
682 /*
683 * Unlock the surface
684 */
685 if (SDL_MUSTLOCK(dst)) {
686 SDL_UnlockSurface(dst);
687 }
688
689 return (result);
690 }
691
692 /* Draw horizontal line with alpha enabled from RGBA color */
693
HLineAlpha(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)694 int HLineAlpha(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
695 {
696 return (filledRectAlpha(dst, x1, y, x2, y, color));
697 }
698
699
700 /* Draw vertical line with alpha enabled from RGBA color */
701
VLineAlpha(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)702 int VLineAlpha(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
703 {
704 return (filledRectAlpha(dst, x, y1, x, y2, color));
705 }
706
707
708 /* Pixel - using alpha weight on color for AA-drawing */
709
pixelColorWeight(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)710 int pixelColorWeight(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
711 {
712 Uint32 a;
713
714 /*
715 * Get alpha
716 */
717 a = (color & (Uint32) 0x000000ff);
718
719 /*
720 * Modify Alpha by weight
721 */
722 a = ((a * weight) >> 8);
723
724 return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
725 }
726
727 /* Pixel - using alpha weight on color for AA-drawing - no locking */
728
pixelColorWeightNolock(SDL_Surface * dst,Sint16 x,Sint16 y,Uint32 color,Uint32 weight)729 int pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
730 {
731 Uint32 a;
732
733 /*
734 * Get alpha
735 */
736 a = (color & (Uint32) 0x000000ff);
737
738 /*
739 * Modify Alpha by weight
740 */
741 a = ((a * weight) >> 8);
742
743 return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
744 }
745
pixelRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)746 int pixelRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
747 {
748 Uint32 color;
749
750 /*
751 * Check Alpha
752 */
753 if (a == 255) {
754 /*
755 * No alpha blending required
756 */
757 /*
758 * Setup color
759 */
760 color = SDL_MapRGBA(dst->format, r, g, b, a);
761 /*
762 * Draw
763 */
764 return (fastPixelColor(dst, x, y, color));
765 } else {
766 /*
767 * Alpha blending required
768 */
769 /*
770 * Draw
771 */
772 return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
773 }
774 }
775
776 /* ----- Horizontal line */
777
778 /* Just store color including alpha, no blending */
779
hlineColorStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)780 int hlineColorStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
781 {
782 Sint16 left, right, top, bottom;
783 Uint8 *pixel, *pixellast;
784 int dx;
785 int pixx, pixy;
786 Sint16 w;
787 Sint16 xtmp;
788 int result = -1;
789
790 /*
791 * Check visibility of clipping rectangle
792 */
793 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
794 return(0);
795 }
796
797 /*
798 * Swap x1, x2 if required to ensure x1<=x2
799 */
800 if (x1 > x2) {
801 xtmp = x1;
802 x1 = x2;
803 x2 = xtmp;
804 }
805
806 /*
807 * Get clipping boundary and
808 * check visibility of hline
809 */
810 left = dst->clip_rect.x;
811 if (x2<left) {
812 return(0);
813 }
814 right = dst->clip_rect.x + dst->clip_rect.w - 1;
815 if (x1>right) {
816 return(0);
817 }
818 top = dst->clip_rect.y;
819 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
820 if ((y<top) || (y>bottom)) {
821 return (0);
822 }
823
824 /*
825 * Clip x
826 */
827 if (x1 < left) {
828 x1 = left;
829 }
830 if (x2 > right) {
831 x2 = right;
832 }
833
834 /*
835 * Calculate width
836 */
837 w = x2 - x1;
838
839 /*
840 * Lock surface
841 */
842 SDL_LockSurface(dst);
843
844 /*
845 * More variable setup
846 */
847 dx = w;
848 pixx = dst->format->BytesPerPixel;
849 pixy = dst->pitch;
850 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
851 pixellast = pixel + dx * pixx;
852 for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixx)
853 if (dirtyDst == dst)
854 dirtyPixels.push_back(tpixel);
855
856 /*
857 * Draw
858 */
859 switch (dst->format->BytesPerPixel) {
860 case 1:
861 memset(pixel, color, dx);
862 break;
863 case 2:
864 for (; pixel <= pixellast; pixel += pixx) {
865 *(Uint16 *) pixel = color;
866 }
867 break;
868 case 3:
869 for (; pixel <= pixellast; pixel += pixx) {
870 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
871 pixel[0] = (color >> 16) & 0xff;
872 pixel[1] = (color >> 8) & 0xff;
873 pixel[2] = color & 0xff;
874 } else {
875 pixel[0] = color & 0xff;
876 pixel[1] = (color >> 8) & 0xff;
877 pixel[2] = (color >> 16) & 0xff;
878 }
879 }
880 break;
881 default: /* case 4 */
882 for (; pixel <= pixellast; pixel += pixx) {
883 *(Uint32 *) pixel = color;
884 }
885 break;
886 }
887
888 /*
889 * Unlock surface
890 */
891 SDL_UnlockSurface(dst);
892
893 /*
894 * Set result code
895 */
896 result = 0;
897
898 return (result);
899 }
900
hlineRGBAStore(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)901 int hlineRGBAStore(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
902 {
903 /*
904 * Draw
905 */
906 return (hlineColorStore(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
907 }
908
hlineColor(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint32 color)909 int hlineColor(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
910 {
911 Sint16 left, right, top, bottom;
912 Uint8 *pixel, *pixellast;
913 int dx;
914 int pixx, pixy;
915 Sint16 w;
916 Sint16 xtmp;
917 int result = -1;
918 Uint8 *colorptr;
919
920 /*
921 * Check visibility of clipping rectangle
922 */
923 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
924 return(0);
925 }
926
927 /*
928 * Swap x1, x2 if required to ensure x1<=x2
929 */
930 if (x1 > x2) {
931 xtmp = x1;
932 x1 = x2;
933 x2 = xtmp;
934 }
935
936 /*
937 * Get clipping boundary and
938 * check visibility of hline
939 */
940 left = dst->clip_rect.x;
941 if (x2<left) {
942 return(0);
943 }
944 right = dst->clip_rect.x + dst->clip_rect.w - 1;
945 if (x1>right) {
946 return(0);
947 }
948 top = dst->clip_rect.y;
949 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
950 if ((y<top) || (y>bottom)) {
951 return (0);
952 }
953
954 /*
955 * Clip x
956 */
957 if (x1 < left) {
958 x1 = left;
959 }
960 if (x2 > right) {
961 x2 = right;
962 }
963
964 /*
965 * Calculate width
966 */
967 w = x2 - x1;
968
969 /*
970 * Alpha check
971 */
972 if ((color & 255) == 255) {
973
974 /*
975 * No alpha-blending required
976 */
977
978 /*
979 * Setup color
980 */
981 colorptr = (Uint8 *) & color;
982 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
983 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
984 } else {
985 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
986 }
987
988 /*
989 * Lock surface
990 */
991 SDL_LockSurface(dst);
992
993 /*
994 * More variable setup
995 */
996 dx = w;
997 pixx = dst->format->BytesPerPixel;
998 pixy = dst->pitch;
999 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
1000 pixellast = pixel + dx * dst->format->BytesPerPixel;
1001 for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixx)
1002 if (dirtyDst == dst)
1003 dirtyPixels.push_back(tpixel);
1004
1005 /*
1006 * Draw
1007 */
1008 switch (dst->format->BytesPerPixel) {
1009 case 1:
1010 memset(pixel, color, dx);
1011 break;
1012 case 2:
1013 for (; pixel <= pixellast; pixel += pixx) {
1014 *(Uint16 *) pixel = color;
1015 }
1016 break;
1017 case 3:
1018 for (; pixel <= pixellast; pixel += pixx) {
1019 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1020 pixel[0] = (color >> 16) & 0xff;
1021 pixel[1] = (color >> 8) & 0xff;
1022 pixel[2] = color & 0xff;
1023 } else {
1024 pixel[0] = color & 0xff;
1025 pixel[1] = (color >> 8) & 0xff;
1026 pixel[2] = (color >> 16) & 0xff;
1027 }
1028 }
1029 break;
1030 default: /* case 4 */
1031 dx = dx + dx;
1032 for (; pixel <= pixellast; pixel += pixx) {
1033 *(Uint32 *) pixel = color;
1034 }
1035 break;
1036 }
1037
1038 /*
1039 * Unlock surface
1040 */
1041 SDL_UnlockSurface(dst);
1042
1043 /*
1044 * Set result code
1045 */
1046 result = 0;
1047
1048 } else {
1049
1050 /*
1051 * Alpha blending blit
1052 */
1053
1054 result = HLineAlpha(dst, x1, x1 + w, y, color);
1055
1056 }
1057
1058 return (result);
1059 }
1060
hlineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1061 int hlineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1062 {
1063 /*
1064 * Draw
1065 */
1066 return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1067 }
1068
1069 /* ----- Vertical line */
1070
vlineColor(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint32 color)1071 int vlineColor(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
1072 {
1073 Sint16 left, right, top, bottom;
1074 Uint8 *pixel, *pixellast;
1075 int dy;
1076 int pixx, pixy;
1077 Sint16 h;
1078 Sint16 ytmp;
1079 int result = -1;
1080 Uint8 *colorptr;
1081
1082 /*
1083 * Check visibility of clipping rectangle
1084 */
1085 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1086 return(0);
1087 }
1088
1089 /*
1090 * Swap y1, y2 if required to ensure y1<=y2
1091 */
1092 if (y1 > y2) {
1093 ytmp = y1;
1094 y1 = y2;
1095 y2 = ytmp;
1096 }
1097
1098 /*
1099 * Get clipping boundary and
1100 * check visibility of vline
1101 */
1102 left = dst->clip_rect.x;
1103 right = dst->clip_rect.x + dst->clip_rect.w - 1;
1104 if ((x<left) || (x>right)) {
1105 return (0);
1106 }
1107 top = dst->clip_rect.y;
1108 if (y2<top) {
1109 return(0);
1110 }
1111 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1112 if (y1>bottom) {
1113 return(0);
1114 }
1115
1116 /*
1117 * Clip x
1118 */
1119 if (y1 < top) {
1120 y1 = top;
1121 }
1122 if (y2 > bottom) {
1123 y2 = bottom;
1124 }
1125
1126 /*
1127 * Calculate height
1128 */
1129 h = y2 - y1;
1130
1131 /*
1132 * Alpha check
1133 */
1134 if ((color & 255) == 255) {
1135
1136 /*
1137 * No alpha-blending required
1138 */
1139
1140 /*
1141 * Setup color
1142 */
1143 colorptr = (Uint8 *) & color;
1144 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1145 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1146 } else {
1147 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1148 }
1149
1150 /*
1151 * Lock surface
1152 */
1153 SDL_LockSurface(dst);
1154
1155 /*
1156 * More variable setup
1157 */
1158 dy = h;
1159 pixx = dst->format->BytesPerPixel;
1160 pixy = dst->pitch;
1161 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1;
1162 pixellast = pixel + pixy * dy;
1163 for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixy)
1164 if (dirtyDst == dst)
1165 dirtyPixels.push_back(tpixel);
1166
1167 /*
1168 * Draw
1169 */
1170 switch (dst->format->BytesPerPixel) {
1171 case 1:
1172 for (; pixel <= pixellast; pixel += pixy) {
1173 *(Uint8 *) pixel = color;
1174 }
1175 break;
1176 case 2:
1177 for (; pixel <= pixellast; pixel += pixy) {
1178 *(Uint16 *) pixel = color;
1179 }
1180 break;
1181 case 3:
1182 for (; pixel <= pixellast; pixel += pixy) {
1183 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1184 pixel[0] = (color >> 16) & 0xff;
1185 pixel[1] = (color >> 8) & 0xff;
1186 pixel[2] = color & 0xff;
1187 } else {
1188 pixel[0] = color & 0xff;
1189 pixel[1] = (color >> 8) & 0xff;
1190 pixel[2] = (color >> 16) & 0xff;
1191 }
1192 }
1193 break;
1194 default: /* case 4 */
1195 for (; pixel <= pixellast; pixel += pixy) {
1196 *(Uint32 *) pixel = color;
1197 }
1198 break;
1199 }
1200
1201 /*
1202 * Unlock surface
1203 */
1204 SDL_UnlockSurface(dst);
1205
1206 /*
1207 * Set result code
1208 */
1209 result = 0;
1210
1211 } else {
1212
1213 /*
1214 * Alpha blending blit
1215 */
1216
1217 result = VLineAlpha(dst, x, y1, y1 + h, color);
1218
1219 }
1220
1221 return (result);
1222 }
1223
vlineRGBA(SDL_Surface * dst,Sint16 x,Sint16 y1,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1224 int vlineRGBA(SDL_Surface * dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1225 {
1226 /*
1227 * Draw
1228 */
1229 return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1230 }
1231
1232 /* ----- Rectangle */
1233
rectangleColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1234 int rectangleColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1235 {
1236 int result;
1237 Sint16 w, h, xtmp, ytmp;
1238
1239 /*
1240 * Check visibility of clipping rectangle
1241 */
1242 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1243 return(0);
1244 }
1245
1246 /*
1247 * Swap x1, x2 if required
1248 */
1249 if (x1 > x2) {
1250 xtmp = x1;
1251 x1 = x2;
1252 x2 = xtmp;
1253 }
1254
1255 /*
1256 * Swap y1, y2 if required
1257 */
1258 if (y1 > y2) {
1259 ytmp = y1;
1260 y1 = y2;
1261 y2 = ytmp;
1262 }
1263
1264 /*
1265 * Calculate width&height
1266 */
1267 w = x2 - x1;
1268 h = y2 - y1;
1269
1270 /*
1271 * Sanity check
1272 */
1273 if ((w < 0) || (h < 0)) {
1274 return (0);
1275 }
1276
1277 /*
1278 * Test for special cases of straight lines or single point
1279 */
1280 if (x1 == x2) {
1281 if (y1 == y2) {
1282 return (pixelColor(dst, x1, y1, color));
1283 } else {
1284 return (vlineColor(dst, x1, y1, y2, color));
1285 }
1286 } else {
1287 if (y1 == y2) {
1288 return (hlineColor(dst, x1, x2, y1, color));
1289 }
1290 }
1291
1292 /*
1293 * Draw rectangle
1294 */
1295 result = 0;
1296 result |= hlineColor(dst, x1, x2, y1, color);
1297 result |= hlineColor(dst, x1, x2, y2, color);
1298 y1 += 1;
1299 y2 -= 1;
1300 if (y1<=y2) {
1301 result |= vlineColor(dst, x1, y1, y2, color);
1302 result |= vlineColor(dst, x2, y1, y2, color);
1303 }
1304 return (result);
1305
1306 }
1307
rectangleRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1308 int rectangleRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1309 {
1310 /*
1311 * Draw
1312 */
1313 return (rectangleColor
1314 (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1315 }
1316
1317 /* --------- Clipping routines for line */
1318
1319 /* Clipping based heavily on code from */
1320 /* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c */
1321
1322 #define CLIP_LEFT_EDGE 0x1
1323 #define CLIP_RIGHT_EDGE 0x2
1324 #define CLIP_BOTTOM_EDGE 0x4
1325 #define CLIP_TOP_EDGE 0x8
1326 #define CLIP_INSIDE(a) (!a)
1327 #define CLIP_REJECT(a,b) (a&b)
1328 #define CLIP_ACCEPT(a,b) (!(a|b))
1329
clipEncode(Sint16 x,Sint16 y,Sint16 left,Sint16 top,Sint16 right,Sint16 bottom)1330 static int clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom)
1331 {
1332 int code = 0;
1333
1334 if (x < left) {
1335 code |= CLIP_LEFT_EDGE;
1336 } else if (x > right) {
1337 code |= CLIP_RIGHT_EDGE;
1338 }
1339 if (y < top) {
1340 code |= CLIP_TOP_EDGE;
1341 } else if (y > bottom) {
1342 code |= CLIP_BOTTOM_EDGE;
1343 }
1344 return code;
1345 }
1346
clipLine(SDL_Surface * dst,Sint16 * x1,Sint16 * y1,Sint16 * x2,Sint16 * y2)1347 static int clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2)
1348 {
1349 Sint16 left, right, top, bottom;
1350 int code1, code2;
1351 int draw = 0;
1352 Sint16 swaptmp;
1353 float m;
1354
1355 /*
1356 * Get clipping boundary
1357 */
1358 left = dst->clip_rect.x;
1359 right = dst->clip_rect.x + dst->clip_rect.w - 1;
1360 top = dst->clip_rect.y;
1361 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1362
1363 while (1) {
1364 code1 = clipEncode(*x1, *y1, left, top, right, bottom);
1365 code2 = clipEncode(*x2, *y2, left, top, right, bottom);
1366 if (CLIP_ACCEPT(code1, code2)) {
1367 draw = 1;
1368 break;
1369 } else if (CLIP_REJECT(code1, code2))
1370 break;
1371 else {
1372 if (CLIP_INSIDE(code1)) {
1373 swaptmp = *x2;
1374 *x2 = *x1;
1375 *x1 = swaptmp;
1376 swaptmp = *y2;
1377 *y2 = *y1;
1378 *y1 = swaptmp;
1379 swaptmp = code2;
1380 code2 = code1;
1381 code1 = swaptmp;
1382 }
1383 if (*x2 != *x1) {
1384 m = (*y2 - *y1) / (float) (*x2 - *x1);
1385 } else {
1386 m = 1.0f;
1387 }
1388 if (code1 & CLIP_LEFT_EDGE) {
1389 *y1 += (Sint16) ((left - *x1) * m);
1390 *x1 = left;
1391 } else if (code1 & CLIP_RIGHT_EDGE) {
1392 *y1 += (Sint16) ((right - *x1) * m);
1393 *x1 = right;
1394 } else if (code1 & CLIP_BOTTOM_EDGE) {
1395 if (*x2 != *x1) {
1396 *x1 += (Sint16) ((bottom - *y1) / m);
1397 }
1398 *y1 = bottom;
1399 } else if (code1 & CLIP_TOP_EDGE) {
1400 if (*x2 != *x1) {
1401 *x1 += (Sint16) ((top - *y1) / m);
1402 }
1403 *y1 = top;
1404 }
1405 }
1406 }
1407
1408 return draw;
1409 }
1410
1411 /* ----- Filled rectangle (Box) */
1412
boxColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1413 int boxColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1414 {
1415 Sint16 left, right, top, bottom;
1416 Uint8 *pixel, *pixellast;
1417 int x, dx;
1418 int dy;
1419 int pixx, pixy;
1420 Sint16 w, h, tmp;
1421 int result;
1422 Uint8 *colorptr;
1423
1424 /*
1425 * Check visibility of clipping rectangle
1426 */
1427 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1428 return(0);
1429 }
1430
1431 /*
1432 * Order coordinates to ensure that
1433 * x1<=x2 and y1<=y2
1434 */
1435 if (x1 > x2) {
1436 tmp = x1;
1437 x1 = x2;
1438 x2 = tmp;
1439 }
1440 if (y1 > y2) {
1441 tmp = y1;
1442 y1 = y2;
1443 y2 = tmp;
1444 }
1445
1446 /*
1447 * Get clipping boundary and
1448 * check visibility
1449 */
1450 left = dst->clip_rect.x;
1451 if (x2<left) {
1452 return(0);
1453 }
1454 right = dst->clip_rect.x + dst->clip_rect.w - 1;
1455 if (x1>right) {
1456 return(0);
1457 }
1458 top = dst->clip_rect.y;
1459 if (y2<top) {
1460 return(0);
1461 }
1462 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
1463 if (y1>bottom) {
1464 return(0);
1465 }
1466
1467 /* Clip all points */
1468 if (x1<left) {
1469 x1=left;
1470 } else if (x1>right) {
1471 x1=right;
1472 }
1473 if (x2<left) {
1474 x2=left;
1475 } else if (x2>right) {
1476 x2=right;
1477 }
1478 if (y1<top) {
1479 y1=top;
1480 } else if (y1>bottom) {
1481 y1=bottom;
1482 }
1483 if (y2<top) {
1484 y2=top;
1485 } else if (y2>bottom) {
1486 y2=bottom;
1487 }
1488
1489 /*
1490 * Test for special cases of straight line or single point
1491 */
1492 if (x1 == x2) {
1493 if (y1 == y2) {
1494 return (pixelColor(dst, x1, y1, color));
1495 } else {
1496 return (vlineColor(dst, x1, y1, y2, color));
1497 }
1498 }
1499 if (y1 == y2) {
1500 return (hlineColor(dst, x1, x2, y1, color));
1501 }
1502
1503 /*
1504 * Calculate width&height
1505 */
1506 w = x2 - x1;
1507 h = y2 - y1;
1508
1509 /*
1510 * Alpha check
1511 */
1512 if ((color & 255) == 255) {
1513
1514 /*
1515 * No alpha-blending required
1516 */
1517
1518 /*
1519 * Setup color
1520 */
1521 colorptr = (Uint8 *) & color;
1522 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1523 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1524 } else {
1525 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1526 }
1527
1528 /*
1529 * Lock surface
1530 */
1531 SDL_LockSurface(dst);
1532
1533 /*
1534 * More variable setup
1535 */
1536 dx = w;
1537 dy = h;
1538 pixx = dst->format->BytesPerPixel;
1539 pixy = dst->pitch;
1540 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
1541 pixellast = pixel + pixx * dx + pixy * dy;
1542 dx++;
1543
1544 for (Uint8* tpixel = pixel; tpixel <= pixellast; tpixel += pixy)
1545 for (x = 0; x < dx; x++)
1546 {
1547 if (dirtyDst == dst)
1548 dirtyPixels.push_back(tpixel);
1549 tpixel += pixx;
1550 }
1551
1552 /*
1553 * Draw
1554 */
1555 switch (dst->format->BytesPerPixel) {
1556 case 1:
1557 for (; pixel <= pixellast; pixel += pixy) {
1558 memset(pixel, (Uint8) color, dx);
1559 }
1560 break;
1561 case 2:
1562 pixy -= (pixx * dx);
1563 for (; pixel <= pixellast; pixel += pixy) {
1564 for (x = 0; x < dx; x++) {
1565 *(Uint16*) pixel = color;
1566 pixel += pixx;
1567 }
1568 }
1569 break;
1570 case 3:
1571 pixy -= (pixx * dx);
1572 for (; pixel <= pixellast; pixel += pixy) {
1573 for (x = 0; x < dx; x++) {
1574 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1575 pixel[0] = (color >> 16) & 0xff;
1576 pixel[1] = (color >> 8) & 0xff;
1577 pixel[2] = color & 0xff;
1578 } else {
1579 pixel[0] = color & 0xff;
1580 pixel[1] = (color >> 8) & 0xff;
1581 pixel[2] = (color >> 16) & 0xff;
1582 }
1583 pixel += pixx;
1584 }
1585 }
1586 break;
1587 default: /* case 4 */
1588 pixy -= (pixx * dx);
1589 for (; pixel <= pixellast; pixel += pixy) {
1590 for (x = 0; x < dx; x++) {
1591 *(Uint32 *) pixel = color;
1592 pixel += pixx;
1593 }
1594 }
1595 break;
1596 }
1597
1598 /*
1599 * Unlock surface
1600 */
1601 SDL_UnlockSurface(dst);
1602
1603 result = 0;
1604
1605 } else {
1606
1607 result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color);
1608
1609 }
1610
1611 return (result);
1612 }
1613
boxRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1614 int boxRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1615 {
1616 /*
1617 * Draw
1618 */
1619 return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1620 }
1621
1622 /* ----- Line */
1623
1624 /* Non-alpha line drawing code adapted from routine */
1625 /* by Pete Shinners, pete@shinners.org */
1626 /* Originally from pygame, http://pygame.seul.org */
1627
1628 #define ABS(a) (((a)<0) ? -(a) : (a))
1629
lineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)1630 int lineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
1631 {
1632 int pixx, pixy;
1633 int x, y;
1634 int dx, dy;
1635 int ax, ay;
1636 int sx, sy;
1637 int swaptmp;
1638 Uint8 *pixel;
1639 Uint8 *colorptr;
1640
1641 /*
1642 * Clip line and test if we have to draw
1643 */
1644 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
1645 return (0);
1646 }
1647
1648 /*
1649 * Test for special cases of straight lines or single point
1650 */
1651 if (x1 == x2) {
1652 if (y1 < y2) {
1653 return (vlineColor(dst, x1, y1, y2, color));
1654 } else if (y1 > y2) {
1655 return (vlineColor(dst, x1, y2, y1, color));
1656 } else {
1657 return (pixelColor(dst, x1, y1, color));
1658 }
1659 }
1660 if (y1 == y2) {
1661 if (x1 < x2) {
1662 return (hlineColor(dst, x1, x2, y1, color));
1663 } else if (x1 > x2) {
1664 return (hlineColor(dst, x2, x1, y1, color));
1665 }
1666 }
1667
1668 /*
1669 * Variable setup
1670 */
1671 dx = x2 - x1;
1672 dy = y2 - y1;
1673 sx = (dx >= 0) ? 1 : -1;
1674 sy = (dy >= 0) ? 1 : -1;
1675
1676 /* Lock surface */
1677 if (SDL_MUSTLOCK(dst)) {
1678 if (SDL_LockSurface(dst) < 0) {
1679 return (-1);
1680 }
1681 }
1682
1683 /*
1684 * Check for alpha blending
1685 */
1686 if ((color & 255) == 255) {
1687
1688 /*
1689 * No alpha blending - use fast pixel routines
1690 */
1691
1692 /*
1693 * Setup color
1694 */
1695 colorptr = (Uint8 *) & color;
1696 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1697 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
1698 } else {
1699 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
1700 }
1701
1702 /*
1703 * More variable setup
1704 */
1705 dx = sx * dx + 1;
1706 dy = sy * dy + 1;
1707 pixx = dst->format->BytesPerPixel;
1708 pixy = dst->pitch;
1709 pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
1710 pixx *= sx;
1711 pixy *= sy;
1712 if (dx < dy) {
1713 swaptmp = dx;
1714 dx = dy;
1715 dy = swaptmp;
1716 swaptmp = pixx;
1717 pixx = pixy;
1718 pixy = swaptmp;
1719 }
1720
1721 /*
1722 * Draw
1723 */
1724 x = 0;
1725 y = 0;
1726 switch (dst->format->BytesPerPixel) {
1727 case 1:
1728 for (; x < dx; x++, pixel += pixx) {
1729 *pixel = color;
1730 if (dirtyDst == dst)
1731 dirtyPixels.push_back(pixel);
1732 y += dy;
1733 if (y >= dx) {
1734 y -= dx;
1735 pixel += pixy;
1736 }
1737 }
1738 break;
1739 case 2:
1740 for (; x < dx; x++, pixel += pixx) {
1741 *(Uint16 *) pixel = color;
1742 if (dirtyDst == dst)
1743 dirtyPixels.push_back(pixel);
1744 y += dy;
1745 if (y >= dx) {
1746 y -= dx;
1747 pixel += pixy;
1748 }
1749 }
1750 break;
1751 case 3:
1752 for (; x < dx; x++, pixel += pixx) {
1753 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1754 pixel[0] = (color >> 16) & 0xff;
1755 pixel[1] = (color >> 8) & 0xff;
1756 pixel[2] = color & 0xff;
1757 } else {
1758 pixel[0] = color & 0xff;
1759 pixel[1] = (color >> 8) & 0xff;
1760 pixel[2] = (color >> 16) & 0xff;
1761 }
1762 if (dirtyDst == dst)
1763 dirtyPixels.push_back(pixel);
1764 y += dy;
1765 if (y >= dx) {
1766 y -= dx;
1767 pixel += pixy;
1768 }
1769 }
1770 break;
1771 default: /* case 4 */
1772 for (; x < dx; x++, pixel += pixx) {
1773 *(Uint32 *) pixel = color;
1774 if (dirtyDst == dst)
1775 dirtyPixels.push_back(pixel);
1776 y += dy;
1777 if (y >= dx) {
1778 y -= dx;
1779 pixel += pixy;
1780 }
1781 }
1782 break;
1783 }
1784
1785 } else {
1786
1787 /*
1788 * Alpha blending required - use single-pixel blits
1789 */
1790
1791 ax = ABS(dx) << 1;
1792 ay = ABS(dy) << 1;
1793 x = x1;
1794 y = y1;
1795 if (ax > ay) {
1796 int d = ay - (ax >> 1);
1797
1798 while (x != x2) {
1799 pixelColorNolock (dst, x, y, color);
1800 if (d > 0 || (d == 0 && sx == 1)) {
1801 y += sy;
1802 d -= ax;
1803 }
1804 x += sx;
1805 d += ay;
1806 }
1807 } else {
1808 int d = ax - (ay >> 1);
1809
1810 while (y != y2) {
1811 pixelColorNolock (dst, x, y, color);
1812 if (d > 0 || ((d == 0) && (sy == 1))) {
1813 x += sx;
1814 d -= ay;
1815 }
1816 y += sy;
1817 d += ax;
1818 }
1819 }
1820 pixelColorNolock (dst, x, y, color);
1821
1822 }
1823
1824 /* Unlock surface */
1825 if (SDL_MUSTLOCK(dst)) {
1826 SDL_UnlockSurface(dst);
1827 }
1828
1829 return (0);
1830 }
1831
lineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1832 int lineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1833 {
1834 /*
1835 * Draw
1836 */
1837 return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
1838 }
1839
1840 /* AA Line */
1841
1842 #define AAlevels 256
1843 #define AAbits 8
1844
1845 struct WeightPair
1846 {
1847 Uint8 main;
1848 Uint8 complement;
1849 };
1850
1851 double antialiasGamma = 2.2;
getWeights(Uint8 balance)1852 WeightPair getWeights(Uint8 balance)
1853 {
1854 // Gamma-correction for anti-aliasing calculations - get weights for a
1855 // pair of pixels.
1856 //
1857 // We take gamma to be 2.2 by default, which seems generally to be about
1858 // right (the exact value being system-dependent...)
1859
1860 static WeightPair precalced[256];
1861 static double precalcedGamma = -1;
1862
1863 if (precalcedGamma != antialiasGamma)
1864 {
1865 for (Uint16 b = 0; b < 256; b++)
1866 {
1867 precalced[b].main =
1868 (Uint8) (255.0*pow(b/255.0, 1.0/antialiasGamma));
1869 precalced[b].complement =
1870 (Uint8) (255.0*pow((255-b)/255.0, 1.0/antialiasGamma));
1871 }
1872 precalcedGamma = antialiasGamma;
1873 }
1874
1875 return precalced[balance];
1876 }
1877
1878 /*
1879
1880 This implementation of the Wu antialiasing code is based on Mike Abrash's
1881 DDJ article which was reprinted as Chapter 42 of his Graphics Programming
1882 Black Book, but has been optimized to work with SDL and utilizes 32-bit
1883 fixed-point arithmetic. (A. Schiffler).
1884
1885 */
1886
aalineColorInt(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color,int draw_endpoint)1887 int aalineColorInt(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint)
1888 {
1889 Sint32 xx0, yy0, xx1, yy1;
1890 int result;
1891 Uint32 intshift, erracc, erradj;
1892 Uint32 erracctmp, wgtcompmask;
1893 Uint16 balance;
1894 int dx, dy, tmp, xdir, y0p1, x0pxdir;
1895 WeightPair weightPair;
1896
1897 /*
1898 * Check visibility of clipping rectangle
1899 */
1900 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
1901 return(0);
1902 }
1903
1904 /*
1905 * Clip line and test if we have to draw
1906 */
1907 if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
1908 return (0);
1909 }
1910
1911 /*
1912 * Keep on working with 32bit numbers
1913 */
1914 xx0 = x1;
1915 yy0 = y1;
1916 xx1 = x2;
1917 yy1 = y2;
1918
1919 /*
1920 * Reorder points if required
1921 */
1922 if (yy0 > yy1) {
1923 tmp = yy0;
1924 yy0 = yy1;
1925 yy1 = tmp;
1926 tmp = xx0;
1927 xx0 = xx1;
1928 xx1 = tmp;
1929 }
1930
1931 /*
1932 * Calculate distance
1933 */
1934 dx = xx1 - xx0;
1935 dy = yy1 - yy0;
1936
1937 /*
1938 * Adjust for negative dx and set xdir
1939 */
1940 if (dx >= 0) {
1941 xdir = 1;
1942 } else {
1943 xdir = -1;
1944 dx = (-dx);
1945 }
1946
1947 /*
1948 * Check for special cases
1949 */
1950 if (dx == 0) {
1951 /*
1952 * Vertical line
1953 */
1954 return (vlineColor(dst, x1, y1, y2, color));
1955 } else if (dy == 0) {
1956 /*
1957 * Horizontal line
1958 */
1959 return (hlineColor(dst, x1, x2, y1, color));
1960 } else if (dx == dy) {
1961 /*
1962 * Diagonal line
1963 */
1964 return (lineColor(dst, x1, y1, x2, y2, color));
1965 }
1966
1967 /*
1968 * Line is not horizontal, vertical or diagonal
1969 */
1970 result = 0;
1971
1972 /*
1973 * Zero accumulator
1974 */
1975 erracc = 0;
1976
1977 /*
1978 * # of bits by which to shift erracc to get intensity level
1979 */
1980 intshift = 32 - AAbits;
1981 /*
1982 * Mask used to flip all bits in an intensity weighting
1983 */
1984 wgtcompmask = AAlevels - 1;
1985
1986 /* Lock surface */
1987 if (SDL_MUSTLOCK(dst)) {
1988 if (SDL_LockSurface(dst) < 0) {
1989 return (-1);
1990 }
1991 }
1992
1993 /*
1994 * Draw the initial pixel in the foreground color
1995 */
1996 result |= pixelColorNolock(dst, x1, y1, color);
1997
1998 /*
1999 * x-major or y-major?
2000 */
2001 if (dy > dx) {
2002
2003 /*
2004 * y-major. Calculate 16-bit fixed point fractional part of a pixel that
2005 * X advances every time Y advances 1 pixel, truncating the result so that
2006 * we won't overrun the endpoint along the X axis
2007 */
2008 /*
2009 * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
2010 */
2011 erradj = ((dx << 16) / dy) << 16;
2012
2013 /*
2014 * draw all pixels other than the first and last
2015 */
2016 x0pxdir = xx0 + xdir;
2017 while (--dy) {
2018 erracctmp = erracc;
2019 erracc += erradj;
2020 if (erracc <= erracctmp) {
2021 /*
2022 * rollover in error accumulator, x coord advances
2023 */
2024 xx0 = x0pxdir;
2025 x0pxdir += xdir;
2026 }
2027 yy0++; /* y-major so always advance Y */
2028
2029 /*
2030 * the AAbits most significant bits of erracc give us the intensity
2031 * weighting for this pixel, and the complement of the weighting for
2032 * the paired pixel.
2033 */
2034 balance = (erracc >> intshift) & 255;
2035 weightPair = getWeights(balance);
2036
2037 result |= pixelColorWeightNolock (dst, xx0, yy0, color,
2038 weightPair.complement);
2039 result |= pixelColorWeightNolock (dst, x0pxdir, yy0, color,
2040 weightPair.main);
2041 }
2042
2043 } else {
2044
2045 /*
2046 * x-major line. Calculate 16-bit fixed-point fractional part of a pixel
2047 * that Y advances each time X advances 1 pixel, truncating the result so
2048 * that we won't overrun the endpoint along the X axis.
2049 */
2050 /*
2051 * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
2052 */
2053 erradj = ((dy << 16) / dx) << 16;
2054
2055 /*
2056 * draw all pixels other than the first and last
2057 */
2058 y0p1 = yy0 + 1;
2059 while (--dx) {
2060
2061 erracctmp = erracc;
2062 erracc += erradj;
2063 if (erracc <= erracctmp) {
2064 /*
2065 * Accumulator turned over, advance y
2066 */
2067 yy0 = y0p1;
2068 y0p1++;
2069 }
2070 xx0 += xdir; /* x-major so always advance X */
2071 /*
2072 * the AAbits most significant bits of erracc give us the intensity
2073 * weighting for this pixel, and the complement of the weighting for
2074 * the paired pixel.
2075 */
2076 balance = (erracc >> intshift) & 255;
2077 weightPair = getWeights(balance);
2078
2079 result |= pixelColorWeightNolock (dst, xx0, yy0, color,
2080 weightPair.complement);
2081 result |= pixelColorWeightNolock (dst, xx0, y0p1, color,
2082 weightPair.main);
2083 }
2084 }
2085
2086 /*
2087 * Do we have to draw the endpoint
2088 */
2089 if (draw_endpoint) {
2090 /*
2091 * Draw final pixel, always exactly intersected by the line and doesn't
2092 * need to be weighted.
2093 */
2094 result |= pixelColorNolock (dst, x2, y2, color);
2095 }
2096
2097 /* Unlock surface */
2098 if (SDL_MUSTLOCK(dst)) {
2099 SDL_UnlockSurface(dst);
2100 }
2101
2102 return (result);
2103 }
2104
aalineColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)2105 int aalineColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
2106 {
2107 return (aalineColorInt(dst, x1, y1, x2, y2, color, 1));
2108 }
2109
aalineRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2110 int aalineRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2111 {
2112 return (aalineColorInt
2113 (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
2114 }
2115
2116
2117 /* ----- Circle */
2118
2119 /* Note: Based on algorithm from sge library, modified by A. Schiffler */
2120 /* with multiple pixel-draw removal and other minor speedup changes. */
2121
circleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Uint32 color)2122 int circleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2123 {
2124 Sint16 left, right, top, bottom;
2125 int result;
2126 Sint16 x1, y1, x2, y2;
2127 Sint16 cx = 0;
2128 Sint16 cy = r;
2129 Sint16 df = 1 - r;
2130 Sint16 d_e = 3;
2131 Sint16 d_se = -2 * r + 5;
2132 Sint16 xpcx, xmcx, xpcy, xmcy;
2133 Sint16 ypcy, ymcy, ypcx, ymcx;
2134 Uint8 *colorptr;
2135
2136 /*
2137 * Check visibility of clipping rectangle
2138 */
2139 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2140 return(0);
2141 }
2142
2143 /*
2144 * Sanity check radius
2145 */
2146 if (r < 0) {
2147 return (-1);
2148 }
2149
2150 /*
2151 * Special case for r=0 - draw a point
2152 */
2153 if (r == 0) {
2154 return (pixelColor(dst, x, y, color));
2155 }
2156
2157 /*
2158 * Get circle and clipping boundary and
2159 * test if bounding box of circle is visible
2160 */
2161 x2 = x + r;
2162 left = dst->clip_rect.x;
2163 if (x2<left) {
2164 return(0);
2165 }
2166 x1 = x - r;
2167 right = dst->clip_rect.x + dst->clip_rect.w - 1;
2168 if (x1>right) {
2169 return(0);
2170 }
2171 y2 = y + r;
2172 top = dst->clip_rect.y;
2173 if (y2<top) {
2174 return(0);
2175 }
2176 y1 = y - r;
2177 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2178 if (y1>bottom) {
2179 return(0);
2180 }
2181
2182 /*
2183 * Draw circle
2184 */
2185 result = 0;
2186
2187 /* Lock surface */
2188 if (SDL_MUSTLOCK(dst)) {
2189 if (SDL_LockSurface(dst) < 0) {
2190 return (-1);
2191 }
2192 }
2193
2194 /*
2195 * Alpha Check
2196 */
2197 if ((color & 255) == 255) {
2198
2199 /*
2200 * No Alpha - direct memory writes
2201 */
2202
2203 /*
2204 * Setup color
2205 */
2206 colorptr = (Uint8 *) & color;
2207 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2208 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2209 } else {
2210 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2211 }
2212
2213 /*
2214 * Draw
2215 */
2216 do {
2217 ypcy = y + cy;
2218 ymcy = y - cy;
2219 if (cx > 0) {
2220 xpcx = x + cx;
2221 xmcx = x - cx;
2222 result |= fastPixelColorNolock(dst, xmcx, ypcy, color);
2223 result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
2224 result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
2225 result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
2226 } else {
2227 result |= fastPixelColorNolock(dst, x, ymcy, color);
2228 result |= fastPixelColorNolock(dst, x, ypcy, color);
2229 }
2230 xpcy = x + cy;
2231 xmcy = x - cy;
2232 if ((cx > 0) && (cx != cy)) {
2233 ypcx = y + cx;
2234 ymcx = y - cx;
2235 result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
2236 result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
2237 result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
2238 result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
2239 } else if (cx == 0) {
2240 result |= fastPixelColorNolock(dst, xmcy, y, color);
2241 result |= fastPixelColorNolock(dst, xpcy, y, color);
2242 }
2243 /*
2244 * Update
2245 */
2246 if (df < 0) {
2247 df += d_e;
2248 d_e += 2;
2249 d_se += 2;
2250 } else {
2251 df += d_se;
2252 d_e += 2;
2253 d_se += 4;
2254 cy--;
2255 }
2256 cx++;
2257 } while (cx <= cy);
2258
2259 /*
2260 * Unlock surface
2261 */
2262 SDL_UnlockSurface(dst);
2263
2264 } else {
2265
2266 /*
2267 * Using Alpha - blended pixel blits
2268 */
2269
2270 do {
2271 /*
2272 * Draw
2273 */
2274 ypcy = y + cy;
2275 ymcy = y - cy;
2276 if (cx > 0) {
2277 xpcx = x + cx;
2278 xmcx = x - cx;
2279 result |= pixelColorNolock (dst, xmcx, ypcy, color);
2280 result |= pixelColorNolock (dst, xpcx, ypcy, color);
2281 result |= pixelColorNolock (dst, xmcx, ymcy, color);
2282 result |= pixelColorNolock (dst, xpcx, ymcy, color);
2283 } else {
2284 result |= pixelColorNolock (dst, x, ymcy, color);
2285 result |= pixelColorNolock (dst, x, ypcy, color);
2286 }
2287 xpcy = x + cy;
2288 xmcy = x - cy;
2289 if ((cx > 0) && (cx != cy)) {
2290 ypcx = y + cx;
2291 ymcx = y - cx;
2292 result |= pixelColorNolock (dst, xmcy, ypcx, color);
2293 result |= pixelColorNolock (dst, xpcy, ypcx, color);
2294 result |= pixelColorNolock (dst, xmcy, ymcx, color);
2295 result |= pixelColorNolock (dst, xpcy, ymcx, color);
2296 } else if (cx == 0) {
2297 result |= pixelColorNolock (dst, xmcy, y, color);
2298 result |= pixelColorNolock (dst, xpcy, y, color);
2299 }
2300 /*
2301 * Update
2302 */
2303 if (df < 0) {
2304 df += d_e;
2305 d_e += 2;
2306 d_se += 2;
2307 } else {
2308 df += d_se;
2309 d_e += 2;
2310 d_se += 4;
2311 cy--;
2312 }
2313 cx++;
2314 } while (cx <= cy);
2315
2316 } /* Alpha check */
2317
2318 /* Unlock surface */
2319 if (SDL_MUSTLOCK(dst)) {
2320 SDL_UnlockSurface(dst);
2321 }
2322
2323 return (result);
2324 }
2325
circleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2326 int circleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2327 {
2328 /*
2329 * Draw
2330 */
2331 return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2332 }
2333
2334 /* ----- Arc */
2335
2336 /* Note: Based on above circle algorithm by A. Schiffler below. Written by D. Raber */
2337 /* Calculates which octants arc goes through and renders accordingly */
2338
arcColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Sint16 start,Sint16 end,Uint32 color)2339 int arcColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Sint16 start, Sint16 end, Uint32 color)
2340 {
2341 Sint16 left, right, top, bottom;
2342 int result;
2343 Sint16 x1, y1, x2, y2;
2344 Sint16 cx = 0;
2345 Sint16 cy = r;
2346 Sint16 df = 1 - r;
2347 Sint16 d_e = 3;
2348 Sint16 d_se = -2 * r + 5;
2349 Sint16 xpcx, xmcx, xpcy, xmcy;
2350 Sint16 ypcy, ymcy, ypcx, ymcx;
2351 Uint8 *colorptr;
2352
2353 /*
2354 * Check visibility of clipping rectangle
2355 */
2356 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2357 return(0);
2358 }
2359
2360 /*
2361 * Sanity check radius
2362 */
2363 if (r < 0) {
2364 return (-1);
2365 }
2366
2367 /*
2368 * Special case for r=0 - draw a point
2369 */
2370 if (r == 0) {
2371 return (pixelColor(dst, x, y, color));
2372 }
2373
2374 /*
2375 * Fixup angles
2376 */
2377 start = start % 360;
2378 end = end % 360;
2379
2380 /*
2381 * Get arc's circle and clipping boundary and
2382 * test if bounding box of circle is visible
2383 */
2384 x2 = x + r;
2385 left = dst->clip_rect.x;
2386 if (x2<left) {
2387 return(0);
2388 }
2389 x1 = x - r;
2390 right = dst->clip_rect.x + dst->clip_rect.w - 1;
2391 if (x1>right) {
2392 return(0);
2393 }
2394 y2 = y + r;
2395 top = dst->clip_rect.y;
2396 if (y2<top) {
2397 return(0);
2398 }
2399 y1 = y - r;
2400 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2401 if (y1>bottom) {
2402 return(0);
2403 }
2404
2405 /*
2406 * Draw arc
2407 */
2408 result = 0;
2409
2410 /* Lock surface */
2411 if (SDL_MUSTLOCK(dst)) {
2412 if (SDL_LockSurface(dst) < 0) {
2413 return (-1);
2414 }
2415 }
2416
2417 /* Octant labelling
2418
2419 \ 5 | 6 /
2420 \ | /
2421 4 \ | / 7
2422 \|/
2423 ------+------ +x
2424 /|\
2425 3 / | \ 0
2426 / | \
2427 / 2 | 1 \
2428 +y */
2429
2430 Uint8 drawoct = 0; // 0x00000000
2431 // whether or not to keep drawing a given octant.
2432 // For example: 0x00111100 means we're drawing in octants 2-5
2433
2434 // 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
2435 while (start < 0) start += 360;
2436 while (end < 0) end += 360;
2437 start %= 360;
2438 end %= 360;
2439
2440 // now, we find which octants we're drawing in.
2441 int startoct = start / 45;
2442 int endoct = end / 45;
2443 int oct = startoct - 1; // we increment as first step in loop
2444
2445 int stopval_start=0, stopval_end=0; // what values of cx to stop at.
2446 double temp=0;
2447
2448 do {
2449 oct = (oct + 1) % 8;
2450
2451 if (oct == startoct) {
2452 // need to compute stopval_start for this octant. Look at picture above if this is unclear
2453 switch (oct)
2454 {
2455 case 0:
2456 case 3:
2457 temp = sin(start * M_PI / 180);
2458 break;
2459 case 1:
2460 case 6:
2461 temp = cos(start * M_PI / 180);
2462 break;
2463 case 2:
2464 case 5:
2465 temp = -cos(start * M_PI / 180);
2466 break;
2467 case 4:
2468 case 7:
2469 temp = -sin(start * M_PI / 180);
2470 break;
2471 }
2472 temp *= r;
2473 stopval_start = (int)temp; // always round down.
2474 // This isn't arbitrary, but requires graph paper to explain well.
2475 // The basic idea is that we're always changing drawoct after we draw, so we
2476 // stop immediately after we render the last sensible pixel at x = ((int)temp).
2477
2478 // and whether to draw in this octant initially
2479 if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
2480 else drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
2481 }
2482 if (oct == endoct) {
2483 // need to compute stopval_end for this octant
2484 switch (oct)
2485 {
2486 case 0:
2487 case 3:
2488 temp = sin(end * M_PI / 180);
2489 break;
2490 case 1:
2491 case 6:
2492 temp = cos(end * M_PI / 180);
2493 break;
2494 case 2:
2495 case 5:
2496 temp = -cos(end * M_PI / 180);
2497 break;
2498 case 4:
2499 case 7:
2500 temp = -sin(end * M_PI / 180);
2501 break;
2502 }
2503 temp *= r;
2504 stopval_end = (int)temp;
2505
2506 // and whether to draw in this octant initially
2507 if (startoct == endoct) {
2508 // note: we start drawing, stop, then start again in this case
2509 // otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
2510 if (start > end) {
2511 // unfortunately, if we're in the same octant and need to draw over the whole circle,
2512 // we need to set the rest to true, because the while loop will end at the bottom.
2513 drawoct = 255;
2514 } else {
2515 drawoct &= 255 - (1 << oct);
2516 }
2517 }
2518 else if (oct % 2) drawoct &= 255 - (1 << oct);
2519 else drawoct |= (1 << oct);
2520 } else if (oct != startoct) { // already verified that it's != endoct
2521 drawoct |= (1 << oct); // draw this entire segment
2522 }
2523 } while (oct != endoct);
2524
2525 // so now we have what octants to draw and when to draw them. all that's left is the actual raster code.
2526
2527
2528 /*
2529 * Alpha Check
2530 */
2531 if ((color & 255) == 255) {
2532
2533 /*
2534 * No Alpha - direct memory writes
2535 */
2536
2537 /*
2538 * Setup color
2539 */
2540 colorptr = (Uint8 *) & color;
2541 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2542 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2543 } else {
2544 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2545 }
2546
2547 /*
2548 * Draw
2549 */
2550 do {
2551 ypcy = y + cy;
2552 ymcy = y - cy;
2553 if (cx > 0) {
2554 xpcx = x + cx;
2555 xmcx = x - cx;
2556 // always check if we're drawing a certain octant before adding a pixel to that octant.
2557 if (drawoct & 4) result |= fastPixelColorNolock(dst, xmcx, ypcy, color); // drawoct & 4 = 22; drawoct[2]
2558 if (drawoct & 2) result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
2559 if (drawoct & 32) result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
2560 if (drawoct & 64) result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
2561 } else {
2562 if (drawoct & 6) result |= fastPixelColorNolock(dst, x, ypcy, color); // 4 + 2; drawoct[2] || drawoct[1]
2563 if (drawoct & 96) result |= fastPixelColorNolock(dst, x, ymcy, color); // 32 + 64
2564 }
2565
2566 xpcy = x + cy;
2567 xmcy = x - cy;
2568 if (cx > 0 && cx != cy) {
2569 ypcx = y + cx;
2570 ymcx = y - cx;
2571 if (drawoct & 8) result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
2572 if (drawoct & 1) result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
2573 if (drawoct & 16) result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
2574 if (drawoct & 128) result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
2575 } else if (cx == 0) {
2576 if (drawoct & 24) result |= fastPixelColorNolock(dst, xmcy, y, color); // 8 + 16
2577 if (drawoct & 129) result |= fastPixelColorNolock(dst, xpcy, y, color); // 1 + 128
2578 }
2579
2580
2581 /*
2582 * Update whether we're drawing an octant
2583 */
2584 if (stopval_start == cx) {
2585 // works like an on-off switch because start & end may be in the same octant.
2586 if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
2587 else drawoct |= (1 << startoct);
2588 }
2589 if (stopval_end == cx) {
2590 if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
2591 else drawoct |= (1 << endoct);
2592 }
2593
2594 /*
2595 * Update pixels
2596 */
2597 if (df < 0) {
2598 df += d_e;
2599 d_e += 2;
2600 d_se += 2;
2601 } else {
2602 df += d_se;
2603 d_e += 2;
2604 d_se += 4;
2605 cy--;
2606 }
2607 cx++;
2608 } while (cx <= cy);
2609
2610 /*
2611 * Unlock surface
2612 */
2613 SDL_UnlockSurface(dst);
2614
2615 } else {
2616
2617 /*
2618 * Using Alpha - blended pixel blits
2619 */
2620
2621 do {
2622 ypcy = y + cy;
2623 ymcy = y - cy;
2624 if (cx > 0) {
2625 xpcx = x + cx;
2626 xmcx = x - cx;
2627
2628 // always check if we're drawing a certain octant before adding a pixel to that octant.
2629 if (drawoct & 4) result |= pixelColorNolock(dst, xmcx, ypcy, color);
2630 if (drawoct & 2) result |= pixelColorNolock(dst, xpcx, ypcy, color);
2631 if (drawoct & 32) result |= pixelColorNolock(dst, xmcx, ymcy, color);
2632 if (drawoct & 64) result |= pixelColorNolock(dst, xpcx, ymcy, color);
2633 } else {
2634 if (drawoct & 96) result |= pixelColorNolock(dst, x, ymcy, color);
2635 if (drawoct & 6) result |= pixelColorNolock(dst, x, ypcy, color);
2636 }
2637
2638 xpcy = x + cy;
2639 xmcy = x - cy;
2640 if (cx > 0 && cx != cy) {
2641 ypcx = y + cx;
2642 ymcx = y - cx;
2643 if (drawoct & 8) result |= pixelColorNolock(dst, xmcy, ypcx, color);
2644 if (drawoct & 1) result |= pixelColorNolock(dst, xpcy, ypcx, color);
2645 if (drawoct & 16) result |= pixelColorNolock(dst, xmcy, ymcx, color);
2646 if (drawoct & 128) result |= pixelColorNolock(dst, xpcy, ymcx, color);
2647 } else if (cx == 0) {
2648 if (drawoct & 24) result |= pixelColorNolock(dst, xmcy, y, color);
2649 if (drawoct & 129) result |= pixelColorNolock(dst, xpcy, y, color);
2650 }
2651
2652
2653 /*
2654 * Update whether we're drawing an octant
2655 */
2656 if (stopval_start == cx) {
2657 // works like an on-off switch.
2658 // This is just in case start & end are in the same octant.
2659 if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
2660 else drawoct |= (1 << startoct);
2661 }
2662 if (stopval_end == cx) {
2663 if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
2664 else drawoct |= (1 << endoct);
2665 }
2666
2667 /*
2668 * Update pixels
2669 */
2670 if (df < 0) {
2671 df += d_e;
2672 d_e += 2;
2673 d_se += 2;
2674 } else {
2675 df += d_se;
2676 d_e += 2;
2677 d_se += 4;
2678 cy--;
2679 }
2680 cx++;
2681 } while (cx <= cy);
2682
2683 } /* Alpha check */
2684
2685 /* Unlock surface */
2686 if (SDL_MUSTLOCK(dst)) {
2687 SDL_UnlockSurface(dst);
2688 }
2689
2690 return (result);
2691 }
2692
arcRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2693 int arcRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2694 {
2695 /*
2696 * Draw
2697 */
2698 return (arcColor(dst, x, y, rad, start, end, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2699 }
2700
2701 /* ----- AA Circle */
2702
2703 /* AA circle is based on AAellipse */
2704
aacircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Uint32 color)2705 int aacircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2706 {
2707 return (aaellipseColor(dst, x, y, r, r, color));
2708 }
2709
aacircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2710 int aacircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2711 {
2712 /*
2713 * Draw
2714 */
2715 return (aaellipseColor
2716 (dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2717 }
2718
2719 /* ----- Filled Circle */
2720
2721 /* Note: Based on algorithm from sge library with multiple-hline draw removal */
2722
2723 /* and other speedup changes. */
2724
filledCircleColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 r,Uint32 color)2725 int filledCircleColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color)
2726 {
2727 Sint16 left, right, top, bottom;
2728 int result;
2729 Sint16 x1, y1, x2, y2;
2730 Sint16 cx = 0;
2731 Sint16 cy = r;
2732 Sint16 ocx = (Sint16) 0xffff;
2733 Sint16 ocy = (Sint16) 0xffff;
2734 Sint16 df = 1 - r;
2735 Sint16 d_e = 3;
2736 Sint16 d_se = -2 * r + 5;
2737 Sint16 xpcx, xmcx, xpcy, xmcy;
2738 Sint16 ypcy, ymcy, ypcx, ymcx;
2739
2740 /*
2741 * Check visibility of clipping rectangle
2742 */
2743 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2744 return(0);
2745 }
2746
2747 /*
2748 * Sanity check radius
2749 */
2750 if (r < 0) {
2751 return (-1);
2752 }
2753
2754 /*
2755 * Special case for r=0 - draw a point
2756 */
2757 if (r == 0) {
2758 return (pixelColor(dst, x, y, color));
2759 }
2760
2761 /*
2762 * Get circle and clipping boundary and
2763 * test if bounding box of circle is visible
2764 */
2765 x2 = x + r;
2766 left = dst->clip_rect.x;
2767 if (x2<left) {
2768 return(0);
2769 }
2770 x1 = x - r;
2771 right = dst->clip_rect.x + dst->clip_rect.w - 1;
2772 if (x1>right) {
2773 return(0);
2774 }
2775 y2 = y + r;
2776 top = dst->clip_rect.y;
2777 if (y2<top) {
2778 return(0);
2779 }
2780 y1 = y - r;
2781 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2782 if (y1>bottom) {
2783 return(0);
2784 }
2785
2786 /*
2787 * Draw
2788 */
2789 result = 0;
2790 do {
2791 xpcx = x + cx;
2792 xmcx = x - cx;
2793 xpcy = x + cy;
2794 xmcy = x - cy;
2795 if (ocy != cy) {
2796 if (cy > 0) {
2797 ypcy = y + cy;
2798 ymcy = y - cy;
2799 result |= hlineColor(dst, xmcx, xpcx, ypcy, color);
2800 result |= hlineColor(dst, xmcx, xpcx, ymcy, color);
2801 } else {
2802 result |= hlineColor(dst, xmcx, xpcx, y, color);
2803 }
2804 ocy = cy;
2805 }
2806 if (ocx != cx) {
2807 if (cx != cy) {
2808 if (cx > 0) {
2809 ypcx = y + cx;
2810 ymcx = y - cx;
2811 result |= hlineColor(dst, xmcy, xpcy, ymcx, color);
2812 result |= hlineColor(dst, xmcy, xpcy, ypcx, color);
2813 } else {
2814 result |= hlineColor(dst, xmcy, xpcy, y, color);
2815 }
2816 }
2817 ocx = cx;
2818 }
2819 /*
2820 * Update
2821 */
2822 if (df < 0) {
2823 df += d_e;
2824 d_e += 2;
2825 d_se += 2;
2826 } else {
2827 df += d_se;
2828 d_e += 2;
2829 d_se += 4;
2830 cy--;
2831 }
2832 cx++;
2833 } while (cx <= cy);
2834
2835 return (result);
2836 }
2837
filledCircleRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Uint8 r,Uint8 g,Uint8 b,Uint8 a)2838 int filledCircleRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
2839 {
2840 /*
2841 * Draw
2842 */
2843 return (filledCircleColor
2844 (dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
2845 }
2846
2847
2848 /* ----- Ellipse */
2849
2850 /* Note: Based on algorithm from sge library with multiple-hline draw removal */
2851 /* and other speedup changes. */
2852
ellipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)2853 int ellipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
2854 {
2855 Sint16 left, right, top, bottom;
2856 int result;
2857 Sint16 x1, y1, x2, y2;
2858 int ix, iy;
2859 int h, i, j, k;
2860 int oh, oi, oj, ok;
2861 int xmh, xph, ypk, ymk;
2862 int xmi, xpi, ymj, ypj;
2863 int xmj, xpj, ymi, ypi;
2864 int xmk, xpk, ymh, yph;
2865 Uint8 *colorptr;
2866
2867 /*
2868 * Check visibility of clipping rectangle
2869 */
2870 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
2871 return(0);
2872 }
2873
2874 /*
2875 * Sanity check radii
2876 */
2877 if ((rx < 0) || (ry < 0)) {
2878 return (-1);
2879 }
2880
2881 /*
2882 * Special case for rx=0 - draw a vline
2883 */
2884 if (rx == 0) {
2885 return (vlineColor(dst, x, y - ry, y + ry, color));
2886 }
2887 /*
2888 * Special case for ry=0 - draw a hline
2889 */
2890 if (ry == 0) {
2891 return (hlineColor(dst, x - rx, x + rx, y, color));
2892 }
2893
2894 /*
2895 * Get circle and clipping boundary and
2896 * test if bounding box of circle is visible
2897 */
2898 x2 = x + rx;
2899 left = dst->clip_rect.x;
2900 if (x2<left) {
2901 return(0);
2902 }
2903 x1 = x - rx;
2904 right = dst->clip_rect.x + dst->clip_rect.w - 1;
2905 if (x1>right) {
2906 return(0);
2907 }
2908 y2 = y + ry;
2909 top = dst->clip_rect.y;
2910 if (y2<top) {
2911 return(0);
2912 }
2913 y1 = y - ry;
2914 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
2915 if (y1>bottom) {
2916 return(0);
2917 }
2918
2919 /*
2920 * Init vars
2921 */
2922 oh = oi = oj = ok = 0xFFFF;
2923
2924 /*
2925 * Draw
2926 */
2927 result = 0;
2928
2929 /* Lock surface */
2930 if (SDL_MUSTLOCK(dst)) {
2931 if (SDL_LockSurface(dst) < 0) {
2932 return (-1);
2933 }
2934 }
2935
2936 /*
2937 * Check alpha
2938 */
2939 if ((color & 255) == 255) {
2940
2941 /*
2942 * No Alpha - direct memory writes
2943 */
2944
2945 /*
2946 * Setup color
2947 */
2948 colorptr = (Uint8 *) & color;
2949 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
2950 color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
2951 } else {
2952 color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
2953 }
2954
2955
2956 if (rx > ry) {
2957 ix = 0;
2958 iy = rx * 64;
2959
2960 do {
2961 h = (ix + 32) >> 6;
2962 i = (iy + 32) >> 6;
2963 j = (h * ry) / rx;
2964 k = (i * ry) / rx;
2965
2966 if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
2967 xph = x + h;
2968 xmh = x - h;
2969 if (k > 0) {
2970 ypk = y + k;
2971 ymk = y - k;
2972 result |= fastPixelColorNolock(dst, xmh, ypk, color);
2973 result |= fastPixelColorNolock(dst, xph, ypk, color);
2974 result |= fastPixelColorNolock(dst, xmh, ymk, color);
2975 result |= fastPixelColorNolock(dst, xph, ymk, color);
2976 } else {
2977 result |= fastPixelColorNolock(dst, xmh, y, color);
2978 result |= fastPixelColorNolock(dst, xph, y, color);
2979 }
2980 ok = k;
2981 xpi = x + i;
2982 xmi = x - i;
2983 if (j > 0) {
2984 ypj = y + j;
2985 ymj = y - j;
2986 result |= fastPixelColorNolock(dst, xmi, ypj, color);
2987 result |= fastPixelColorNolock(dst, xpi, ypj, color);
2988 result |= fastPixelColorNolock(dst, xmi, ymj, color);
2989 result |= fastPixelColorNolock(dst, xpi, ymj, color);
2990 } else {
2991 result |= fastPixelColorNolock(dst, xmi, y, color);
2992 result |= fastPixelColorNolock(dst, xpi, y, color);
2993 }
2994 oj = j;
2995 }
2996
2997 ix = ix + iy / rx;
2998 iy = iy - ix / rx;
2999
3000 } while (i > h);
3001 } else {
3002 ix = 0;
3003 iy = ry * 64;
3004
3005 do {
3006 h = (ix + 32) >> 6;
3007 i = (iy + 32) >> 6;
3008 j = (h * rx) / ry;
3009 k = (i * rx) / ry;
3010
3011 if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3012 xmj = x - j;
3013 xpj = x + j;
3014 if (i > 0) {
3015 ypi = y + i;
3016 ymi = y - i;
3017 result |= fastPixelColorNolock(dst, xmj, ypi, color);
3018 result |= fastPixelColorNolock(dst, xpj, ypi, color);
3019 result |= fastPixelColorNolock(dst, xmj, ymi, color);
3020 result |= fastPixelColorNolock(dst, xpj, ymi, color);
3021 } else {
3022 result |= fastPixelColorNolock(dst, xmj, y, color);
3023 result |= fastPixelColorNolock(dst, xpj, y, color);
3024 }
3025 oi = i;
3026 xmk = x - k;
3027 xpk = x + k;
3028 if (h > 0) {
3029 yph = y + h;
3030 ymh = y - h;
3031 result |= fastPixelColorNolock(dst, xmk, yph, color);
3032 result |= fastPixelColorNolock(dst, xpk, yph, color);
3033 result |= fastPixelColorNolock(dst, xmk, ymh, color);
3034 result |= fastPixelColorNolock(dst, xpk, ymh, color);
3035 } else {
3036 result |= fastPixelColorNolock(dst, xmk, y, color);
3037 result |= fastPixelColorNolock(dst, xpk, y, color);
3038 }
3039 oh = h;
3040 }
3041
3042 ix = ix + iy / ry;
3043 iy = iy - ix / ry;
3044
3045 } while (i > h);
3046 }
3047
3048 } else {
3049
3050 if (rx > ry) {
3051 ix = 0;
3052 iy = rx * 64;
3053
3054 do {
3055 h = (ix + 32) >> 6;
3056 i = (iy + 32) >> 6;
3057 j = (h * ry) / rx;
3058 k = (i * ry) / rx;
3059
3060 if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
3061 xph = x + h;
3062 xmh = x - h;
3063 if (k > 0) {
3064 ypk = y + k;
3065 ymk = y - k;
3066 result |= pixelColorNolock (dst, xmh, ypk, color);
3067 result |= pixelColorNolock (dst, xph, ypk, color);
3068 result |= pixelColorNolock (dst, xmh, ymk, color);
3069 result |= pixelColorNolock (dst, xph, ymk, color);
3070 } else {
3071 result |= pixelColorNolock (dst, xmh, y, color);
3072 result |= pixelColorNolock (dst, xph, y, color);
3073 }
3074 ok = k;
3075 xpi = x + i;
3076 xmi = x - i;
3077 if (j > 0) {
3078 ypj = y + j;
3079 ymj = y - j;
3080 result |= pixelColorNolock (dst, xmi, ypj, color);
3081 result |= pixelColorNolock (dst, xpi, ypj, color);
3082 result |= pixelColorNolock (dst, xmi, ymj, color);
3083 result |= pixelColor(dst, xpi, ymj, color);
3084 } else {
3085 result |= pixelColorNolock (dst, xmi, y, color);
3086 result |= pixelColorNolock (dst, xpi, y, color);
3087 }
3088 oj = j;
3089 }
3090
3091 ix = ix + iy / rx;
3092 iy = iy - ix / rx;
3093
3094 } while (i > h);
3095 } else {
3096 ix = 0;
3097 iy = ry * 64;
3098
3099 do {
3100 h = (ix + 32) >> 6;
3101 i = (iy + 32) >> 6;
3102 j = (h * rx) / ry;
3103 k = (i * rx) / ry;
3104
3105 if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
3106 xmj = x - j;
3107 xpj = x + j;
3108 if (i > 0) {
3109 ypi = y + i;
3110 ymi = y - i;
3111 result |= pixelColorNolock (dst, xmj, ypi, color);
3112 result |= pixelColorNolock (dst, xpj, ypi, color);
3113 result |= pixelColorNolock (dst, xmj, ymi, color);
3114 result |= pixelColorNolock (dst, xpj, ymi, color);
3115 } else {
3116 result |= pixelColorNolock (dst, xmj, y, color);
3117 result |= pixelColorNolock (dst, xpj, y, color);
3118 }
3119 oi = i;
3120 xmk = x - k;
3121 xpk = x + k;
3122 if (h > 0) {
3123 yph = y + h;
3124 ymh = y - h;
3125 result |= pixelColorNolock (dst, xmk, yph, color);
3126 result |= pixelColorNolock (dst, xpk, yph, color);
3127 result |= pixelColorNolock (dst, xmk, ymh, color);
3128 result |= pixelColorNolock (dst, xpk, ymh, color);
3129 } else {
3130 result |= pixelColorNolock (dst, xmk, y, color);
3131 result |= pixelColorNolock (dst, xpk, y, color);
3132 }
3133 oh = h;
3134 }
3135
3136 ix = ix + iy / ry;
3137 iy = iy - ix / ry;
3138
3139 } while (i > h);
3140 }
3141
3142 } /* Alpha check */
3143
3144 /* Unlock surface */
3145 if (SDL_MUSTLOCK(dst)) {
3146 SDL_UnlockSurface(dst);
3147 }
3148
3149 return (result);
3150 }
3151
ellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3152 int ellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3153 {
3154 /*
3155 * Draw
3156 */
3157 return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3158 }
3159
3160 /* ----- AA Ellipse */
3161
3162 #if 0
3163 /* Win32 does not have lrint, so provide a local inline version */
3164 #ifdef WIN32
3165
3166 __inline long int
3167 lrint (double ftl)
3168 {
3169 int intgr;
3170 _asm
3171 {
3172 fld flt
3173 fistp intgr
3174 };
3175 return intgr;
3176 }
3177
3178 #endif
3179 #endif
3180
3181 /* Based on code from Anders Lindstroem, based on code from SGE, based on code from TwinLib */
3182
aaellipseColor(SDL_Surface * dst,Sint16 xc,Sint16 yc,Sint16 rx,Sint16 ry,Uint32 color)3183 int aaellipseColor(SDL_Surface * dst, Sint16 xc, Sint16 yc, Sint16 rx, Sint16 ry, Uint32 color)
3184 {
3185 Sint16 left, right, top, bottom;
3186 Sint16 x1,y1,x2,y2;
3187 int i;
3188 int a2, b2, ds, dt, dxt, t, s, d;
3189 Sint16 x, y, xs, ys, dyt, od, xx, yy, xc2, yc2;
3190 float cp;
3191 double sab;
3192 Uint16 balance;
3193 WeightPair weightPair;
3194 int result;
3195
3196 /*
3197 * Check visibility of clipping rectangle
3198 */
3199 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3200 return(0);
3201 }
3202
3203 /*
3204 * Sanity check radii
3205 */
3206 if ((rx < 0) || (ry < 0)) {
3207 return (-1);
3208 }
3209
3210 /*
3211 * Special case for rx=0 - draw a vline
3212 */
3213 if (rx == 0) {
3214 return (vlineColor(dst, xc, yc - ry, yc + ry, color));
3215 }
3216 /*
3217 * Special case for ry=0 - draw a hline
3218 */
3219 if (ry == 0) {
3220 return (hlineColor(dst, xc - rx, xc + rx, yc, color));
3221 }
3222
3223 /*
3224 * Special case for rx=1=ry - draw non-aa version
3225 * (this is to work around a bug in the aa code below)
3226 */
3227 if (rx == 1 && ry == 1)
3228 return ellipseColor(dst, xc, yc, rx, ry, color);
3229
3230 /*
3231 * Get circle and clipping boundary and
3232 * test if bounding box of circle is visible
3233 */
3234 x2 = xc + rx;
3235 left = dst->clip_rect.x;
3236 if (x2<left) {
3237 return(0);
3238 }
3239 x1 = xc - rx;
3240 right = dst->clip_rect.x + dst->clip_rect.w - 1;
3241 if (x1>right) {
3242 return(0);
3243 }
3244 y2 = yc + ry;
3245 top = dst->clip_rect.y;
3246 if (y2<top) {
3247 return(0);
3248 }
3249 y1 = yc - ry;
3250 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3251 if (y1>bottom) {
3252 return(0);
3253 }
3254
3255 /* Variable setup */
3256 a2 = rx * rx;
3257 b2 = ry * ry;
3258
3259 ds = 2 * a2;
3260 dt = 2 * b2;
3261
3262 xc2 = 2 * xc;
3263 yc2 = 2 * yc;
3264
3265 sab = sqrt(a2 + b2);
3266 od = lrint(sab*0.01) + 1; /* introduce some overdraw */
3267 dxt = lrint((double)a2 / sab) + od;
3268
3269 t = 0;
3270 s = -2 * a2 * ry;
3271 d = 0;
3272
3273 x = xc;
3274 y = yc - ry;
3275
3276 /* Draw */
3277 result = 0;
3278
3279 /* Lock surface */
3280 if (SDL_MUSTLOCK(dst)) {
3281 if (SDL_LockSurface(dst) < 0) {
3282 return (-1);
3283 }
3284 }
3285
3286 /* "End points" */
3287 result |= pixelColorNolock(dst, x, y, color);
3288 result |= pixelColorNolock(dst, xc2 - x, y, color);
3289 result |= pixelColorNolock(dst, x, yc2 - y, color);
3290 result |= pixelColorNolock(dst, xc2 - x, yc2 - y, color);
3291
3292 for (i = 1; i <= dxt; i++) {
3293 x--;
3294 d += t - b2;
3295
3296 if (d >= 0)
3297 ys = y - 1;
3298 else if ((d - s - a2) > 0) {
3299 if ((2 * d - s - a2) >= 0)
3300 ys = y + 1;
3301 else {
3302 ys = y;
3303 y++;
3304 d -= s + a2;
3305 s += ds;
3306 }
3307 } else {
3308 y++;
3309 ys = y + 1;
3310 d -= s + a2;
3311 s += ds;
3312 }
3313
3314 t -= dt;
3315
3316 /* Calculate alpha */
3317 if (s != 0.0) {
3318 cp = (float) abs(d) / (float) abs(s);
3319 if (cp > 1.0) {
3320 cp = 1.0;
3321 }
3322 } else {
3323 cp = 1.0;
3324 }
3325
3326 /* Calculate weights */
3327 balance = (Uint16) (cp * 255);
3328 weightPair = getWeights(balance);
3329
3330 /* Upper half */
3331 xx = xc2 - x;
3332 result |= pixelColorWeightNolock(dst, x, y, color, weightPair.complement);
3333 result |= pixelColorWeightNolock(dst, xx, y, color, weightPair.complement);
3334
3335 result |= pixelColorWeightNolock(dst, x, ys, color, weightPair.main);
3336 result |= pixelColorWeightNolock(dst, xx, ys, color, weightPair.main);
3337
3338 /* Lower half */
3339 yy = yc2 - y;
3340 result |= pixelColorWeightNolock(dst, x, yy, color, weightPair.complement);
3341 result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.complement);
3342
3343 yy = yc2 - ys;
3344 result |= pixelColorWeightNolock(dst, x, yy, color, weightPair.main);
3345 result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.main);
3346 }
3347
3348 /* Replaces original approximation code dyt = abs(y - yc); */
3349 dyt = lrint((double)b2 / sab ) + od;
3350
3351 for (i = 1; i <= dyt; i++) {
3352 y++;
3353 d -= s + a2;
3354
3355 if (d <= 0)
3356 xs = x + 1;
3357 else if ((d + t - b2) < 0) {
3358 if ((2 * d + t - b2) <= 0)
3359 xs = x - 1;
3360 else {
3361 xs = x;
3362 x--;
3363 d += t - b2;
3364 t -= dt;
3365 }
3366 } else {
3367 x--;
3368 xs = x - 1;
3369 d += t - b2;
3370 t -= dt;
3371 }
3372
3373 s += ds;
3374
3375 /* Calculate alpha */
3376 if (t != 0.0) {
3377 cp = (float) abs(d) / (float) abs(t);
3378 if (cp > 1.0) {
3379 cp = 1.0;
3380 }
3381 } else {
3382 cp = 1.0;
3383 }
3384
3385 /* Calculate weight */
3386 balance = (Uint16) (cp * 255);
3387 weightPair = getWeights(balance);
3388
3389 /* Left half */
3390 xx = xc2 - x;
3391 yy = yc2 - y;
3392 result |= pixelColorWeightNolock(dst, x, y, color, weightPair.complement);
3393 result |= pixelColorWeightNolock(dst, xx, y, color, weightPair.complement);
3394
3395 result |= pixelColorWeightNolock(dst, x, yy, color, weightPair.complement);
3396 result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.complement);
3397
3398 /* Right half */
3399 xx = 2 * xc - xs;
3400 result |= pixelColorWeightNolock(dst, xs, y, color, weightPair.main);
3401 result |= pixelColorWeightNolock(dst, xx, y, color, weightPair.main);
3402
3403 result |= pixelColorWeightNolock(dst, xs, yy, color, weightPair.main);
3404 result |= pixelColorWeightNolock(dst, xx, yy, color, weightPair.main);
3405
3406 }
3407
3408 /* Unlock surface */
3409 if (SDL_MUSTLOCK(dst)) {
3410 SDL_UnlockSurface(dst);
3411 }
3412
3413 return (result);
3414 }
3415
aaellipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3416 int aaellipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3417 {
3418 /*
3419 * Draw
3420 */
3421 return (aaellipseColor
3422 (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3423 }
3424
3425 /* ---- Filled Ellipse */
3426
3427 /* Note: */
3428 /* Based on algorithm from sge library with multiple-hline draw removal */
3429 /* and other speedup changes. */
3430
filledEllipseColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint32 color)3431 int filledEllipseColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
3432 {
3433 Sint16 left, right, top, bottom;
3434 int result;
3435 Sint16 x1, y1, x2, y2;
3436 int ix, iy;
3437 int h, i, j, k;
3438 int oh, oi, oj, ok;
3439 int xmh, xph;
3440 int xmi, xpi;
3441 int xmj, xpj;
3442 int xmk, xpk;
3443
3444 /*
3445 * Check visibility of clipping rectangle
3446 */
3447 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3448 return(0);
3449 }
3450
3451 /*
3452 * Sanity check radii
3453 */
3454 if ((rx < 0) || (ry < 0)) {
3455 return (-1);
3456 }
3457
3458 /*
3459 * Special case for rx=0 - draw a vline
3460 */
3461 if (rx == 0) {
3462 return (vlineColor(dst, x, y - ry, y + ry, color));
3463 }
3464 /*
3465 * Special case for ry=0 - draw a hline
3466 */
3467 if (ry == 0) {
3468 return (hlineColor(dst, x - rx, x + rx, y, color));
3469 }
3470
3471 /*
3472 * Get circle and clipping boundary and
3473 * test if bounding box of circle is visible
3474 */
3475 x2 = x + rx;
3476 left = dst->clip_rect.x;
3477 if (x2<left) {
3478 return(0);
3479 }
3480 x1 = x - rx;
3481 right = dst->clip_rect.x + dst->clip_rect.w - 1;
3482 if (x1>right) {
3483 return(0);
3484 }
3485 y2 = y + ry;
3486 top = dst->clip_rect.y;
3487 if (y2<top) {
3488 return(0);
3489 }
3490 y1 = y - ry;
3491 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3492 if (y1>bottom) {
3493 return(0);
3494 }
3495
3496 /*
3497 * Init vars
3498 */
3499 oh = oi = oj = ok = 0xFFFF;
3500
3501 /*
3502 * Draw
3503 */
3504 result = 0;
3505 if (rx > ry) {
3506 ix = 0;
3507 iy = rx * 64;
3508
3509 do {
3510 h = (ix + 32) >> 6;
3511 i = (iy + 32) >> 6;
3512 j = (h * ry) / rx;
3513 k = (i * ry) / rx;
3514
3515 if ((ok != k) && (oj != k)) {
3516 xph = x + h;
3517 xmh = x - h;
3518 if (k > 0) {
3519 result |= hlineColor(dst, xmh, xph, y + k, color);
3520 result |= hlineColor(dst, xmh, xph, y - k, color);
3521 } else {
3522 result |= hlineColor(dst, xmh, xph, y, color);
3523 }
3524 ok = k;
3525 }
3526 if ((oj != j) && (ok != j) && (k != j)) {
3527 xmi = x - i;
3528 xpi = x + i;
3529 if (j > 0) {
3530 result |= hlineColor(dst, xmi, xpi, y + j, color);
3531 result |= hlineColor(dst, xmi, xpi, y - j, color);
3532 } else {
3533 result |= hlineColor(dst, xmi, xpi, y, color);
3534 }
3535 oj = j;
3536 }
3537
3538 ix = ix + iy / rx;
3539 iy = iy - ix / rx;
3540
3541 } while (i > h);
3542 } else {
3543 ix = 0;
3544 iy = ry * 64;
3545
3546 do {
3547 h = (ix + 32) >> 6;
3548 i = (iy + 32) >> 6;
3549 j = (h * rx) / ry;
3550 k = (i * rx) / ry;
3551
3552 if ((oi != i) && (oh != i)) {
3553 xmj = x - j;
3554 xpj = x + j;
3555 if (i > 0) {
3556 result |= hlineColor(dst, xmj, xpj, y + i, color);
3557 result |= hlineColor(dst, xmj, xpj, y - i, color);
3558 } else {
3559 result |= hlineColor(dst, xmj, xpj, y, color);
3560 }
3561 oi = i;
3562 }
3563 if ((oh != h) && (oi != h) && (i != h)) {
3564 xmk = x - k;
3565 xpk = x + k;
3566 if (h > 0) {
3567 result |= hlineColor(dst, xmk, xpk, y + h, color);
3568 result |= hlineColor(dst, xmk, xpk, y - h, color);
3569 } else {
3570 result |= hlineColor(dst, xmk, xpk, y, color);
3571 }
3572 oh = h;
3573 }
3574
3575 ix = ix + iy / ry;
3576 iy = iy - ix / ry;
3577
3578 } while (i > h);
3579 }
3580
3581 return (result);
3582 }
3583
3584
filledEllipseRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rx,Sint16 ry,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3585 int filledEllipseRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3586 {
3587 /*
3588 * Draw
3589 */
3590 return (filledEllipseColor
3591 (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3592 }
3593
3594 /* ----- filled pie */
3595
3596 /* Low-speed float pie-calc implementation by drawing polygons/lines. */
3597
doPieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color,Uint8 filled)3598 int doPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color, Uint8 filled)
3599 {
3600 Sint16 left, right, top, bottom;
3601 Sint16 x1, y1, x2, y2;
3602 int result;
3603 double angle, start_angle, end_angle;
3604 double deltaAngle;
3605 double dr;
3606 int posX, posY;
3607 int numpoints, i;
3608 Sint16 *vx, *vy;
3609
3610 /*
3611 * Check visibility of clipping rectangle
3612 */
3613 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3614 return(0);
3615 }
3616
3617 /*
3618 * Sanity check radii
3619 */
3620 if (rad < 0) {
3621 return (-1);
3622 }
3623
3624 /*
3625 * Fixup angles
3626 */
3627 start = start % 360;
3628 end = end % 360;
3629
3630 /*
3631 * Special case for rad=0 - draw a point
3632 */
3633 if (rad == 0) {
3634 return (pixelColor(dst, x, y, color));
3635 }
3636
3637 /*
3638 * Clip against circle, not pie (not 100% optimal).
3639 * Get pie's circle and clipping boundary and
3640 * test if bounding box of circle is visible
3641 */
3642 x2 = x + rad;
3643 left = dst->clip_rect.x;
3644 if (x2<left) {
3645 return(0);
3646 }
3647 x1 = x - rad;
3648 right = dst->clip_rect.x + dst->clip_rect.w - 1;
3649 if (x1>right) {
3650 return(0);
3651 }
3652 y2 = y + rad;
3653 top = dst->clip_rect.y;
3654 if (y2<top) {
3655 return(0);
3656 }
3657 y1 = y - rad;
3658 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
3659 if (y1>bottom) {
3660 return(0);
3661 }
3662
3663 /*
3664 * Variable setup
3665 */
3666 dr = (double) rad;
3667 deltaAngle = 3.0 / dr;
3668 start_angle = (double) start *(2.0 * M_PI / 360.0);
3669 end_angle = (double) end *(2.0 * M_PI / 360.0);
3670 if (start > end) {
3671 end_angle += (2.0 * M_PI);
3672 }
3673
3674 /* Count points (rather than calculate it) */
3675 numpoints = 1;
3676 angle = start_angle;
3677 while (angle <= end_angle) {
3678 angle += deltaAngle;
3679 numpoints++;
3680 }
3681
3682 /* Check size of array */
3683 if (numpoints == 1) {
3684 return (pixelColor(dst, x, y, color));
3685 } else if (numpoints == 2) {
3686 posX = x + (int) (dr * cos(start_angle));
3687 posY = y + (int) (dr * sin(start_angle));
3688 return (lineColor(dst, x, y, posX, posY, color));
3689 }
3690
3691 /* Allocate vertex array */
3692 vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
3693 if (vx == NULL) {
3694 return (-1);
3695 }
3696 vy += numpoints;
3697
3698 /* Center */
3699 vx[0] = x;
3700 vy[0] = y;
3701
3702 /* Calculate and store vertices */
3703 i = 1;
3704 angle = start_angle;
3705 while (angle <= end_angle) {
3706 vx[i] = x + (int) (dr * cos(angle));
3707 vy[i] = y + (int) (dr * sin(angle));
3708 angle += deltaAngle;
3709 i++;
3710 }
3711
3712 /* Draw */
3713 if (filled) {
3714 result = filledPolygonColor(dst, vx, vy, numpoints, color);
3715 } else {
3716 result = polygonColor(dst, vx, vy, numpoints, color);
3717 }
3718
3719 /* Free vertex array */
3720 free(vx);
3721
3722 return (result);
3723 }
3724
pieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)3725 int pieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
3726 Sint16 start, Sint16 end, Uint32 color)
3727 {
3728 return (doPieColor(dst, x, y, rad, start, end, color, 0));
3729
3730 }
3731
pieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3732 int pieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
3733 Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3734 {
3735 return (doPieColor(dst, x, y, rad, start, end,
3736 ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 0));
3737
3738 }
3739
filledPieColor(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint32 color)3740 int filledPieColor(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color)
3741 {
3742 return (doPieColor(dst, x, y, rad, start, end, color, 1));
3743 }
3744
filledPieRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,Sint16 rad,Sint16 start,Sint16 end,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3745 int filledPieRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, Sint16 rad,
3746 Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3747 {
3748 return (doPieColor(dst, x, y, rad, start, end,
3749 ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
3750 }
3751
3752 /* Trigon */
3753
trigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)3754 int trigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
3755 {
3756 Sint16 vx[3];
3757 Sint16 vy[3];
3758
3759 vx[0]=x1;
3760 vx[1]=x2;
3761 vx[2]=x3;
3762 vy[0]=y1;
3763 vy[1]=y2;
3764 vy[2]=y3;
3765
3766 return(polygonColor(dst,vx,vy,3,color));
3767 }
3768
trigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3769 int trigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
3770 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3771 {
3772 Sint16 vx[3];
3773 Sint16 vy[3];
3774
3775 vx[0]=x1;
3776 vx[1]=x2;
3777 vx[2]=x3;
3778 vy[0]=y1;
3779 vy[1]=y2;
3780 vy[2]=y3;
3781
3782 return(polygonRGBA(dst,vx,vy,3,r,g,b,a));
3783 }
3784
3785 /* AA-Trigon */
3786
aatrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)3787 int aatrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
3788 {
3789 Sint16 vx[3];
3790 Sint16 vy[3];
3791
3792 vx[0]=x1;
3793 vx[1]=x2;
3794 vx[2]=x3;
3795 vy[0]=y1;
3796 vy[1]=y2;
3797 vy[2]=y3;
3798
3799 return(aapolygonColor(dst,vx,vy,3,color));
3800 }
3801
aatrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3802 int aatrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
3803 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3804 {
3805 Sint16 vx[3];
3806 Sint16 vy[3];
3807
3808 vx[0]=x1;
3809 vx[1]=x2;
3810 vx[2]=x3;
3811 vy[0]=y1;
3812 vy[1]=y2;
3813 vy[2]=y3;
3814
3815 return(aapolygonRGBA(dst,vx,vy,3,r,g,b,a));
3816 }
3817
3818 /* Filled Trigon */
3819
filledTrigonColor(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)3820 int filledTrigonColor(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color)
3821 {
3822 Sint16 vx[3];
3823 Sint16 vy[3];
3824
3825 vx[0]=x1;
3826 vx[1]=x2;
3827 vx[2]=x3;
3828 vy[0]=y1;
3829 vy[1]=y2;
3830 vy[2]=y3;
3831
3832 return(filledPolygonColor(dst,vx,vy,3,color));
3833 }
3834
filledTrigonRGBA(SDL_Surface * dst,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3835 int filledTrigonRGBA(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
3836 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3837 {
3838 Sint16 vx[3];
3839 Sint16 vy[3];
3840
3841 vx[0]=x1;
3842 vx[1]=x2;
3843 vx[2]=x3;
3844 vy[0]=y1;
3845 vy[1]=y2;
3846 vy[2]=y3;
3847
3848 return(filledPolygonRGBA(dst,vx,vy,3,r,g,b,a));
3849 }
3850
3851 /* ---- Polygon */
3852
polygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)3853 int polygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
3854 {
3855 int result;
3856 int i;
3857 const Sint16 *x1, *y1, *x2, *y2;
3858
3859 /*
3860 * Check visibility of clipping rectangle
3861 */
3862 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3863 return(0);
3864 }
3865
3866 /*
3867 * Sanity check
3868 */
3869 if (n < 3) {
3870 return (-1);
3871 }
3872
3873 /*
3874 * Pointer setup
3875 */
3876 x1 = x2 = vx;
3877 y1 = y2 = vy;
3878 x2++;
3879 y2++;
3880
3881 /*
3882 * Draw
3883 */
3884 result = 0;
3885 for (i = 1; i < n; i++) {
3886 result |= lineColor(dst, *x1, *y1, *x2, *y2, color);
3887 x1 = x2;
3888 y1 = y2;
3889 x2++;
3890 y2++;
3891 }
3892 result |= lineColor(dst, *x1, *y1, *vx, *vy, color);
3893
3894 return (result);
3895 }
3896
polygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3897 int polygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3898 {
3899 /*
3900 * Draw
3901 */
3902 return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3903 }
3904
3905 /* ---- AA-Polygon */
3906
aapolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)3907 int aapolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
3908 {
3909 int result;
3910 int i;
3911 const Sint16 *x1, *y1, *x2, *y2;
3912
3913 /*
3914 * Check visibility of clipping rectangle
3915 */
3916 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3917 return(0);
3918 }
3919
3920 /*
3921 * Sanity check
3922 */
3923 if (n < 3) {
3924 return (-1);
3925 }
3926
3927 /*
3928 * Pointer setup
3929 */
3930 x1 = x2 = vx;
3931 y1 = y2 = vy;
3932 x2++;
3933 y2++;
3934
3935 /*
3936 * Draw
3937 */
3938 result = 0;
3939 for (i = 1; i < n; i++) {
3940 result |= aalineColorInt(dst, *x1, *y1, *x2, *y2, color, 0);
3941 x1 = x2;
3942 y1 = y2;
3943 x2++;
3944 y2++;
3945 }
3946 result |= aalineColorInt(dst, *x1, *y1, *vx, *vy, color, 0);
3947
3948 return (result);
3949 }
3950
aapolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)3951 int aapolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
3952 {
3953 /*
3954 * Draw
3955 */
3956 return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
3957 }
3958
3959 /* ---- Filled Polygon */
3960
3961 int gfxPrimitivesCompareInt(const void *a, const void *b);
3962
3963 /* Global vertex array to use if optional parameters are not given in polygon calls. */
3964 static int *gfxPrimitivesPolyIntsGlobal = NULL;
3965 static int gfxPrimitivesPolyAllocatedGlobal = 0;
3966
3967 /* (Note: The last two parameters are optional; but required for multithreaded operation.) */
3968
filledPolygonColorMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color,int ** polyInts,int * polyAllocated)3969 int filledPolygonColorMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color, int **polyInts, int *polyAllocated)
3970 {
3971 int result;
3972 int i;
3973 int y, xa, xb;
3974 int miny, maxy;
3975 int x1, y1;
3976 int x2, y2;
3977 int ind1, ind2;
3978 int ints;
3979 int *gfxPrimitivesPolyInts = NULL;
3980 int gfxPrimitivesPolyAllocated = 0;
3981
3982 /*
3983 * Check visibility of clipping rectangle
3984 */
3985 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
3986 return(0);
3987 }
3988
3989 /*
3990 * Sanity check number of edges
3991 */
3992 if (n < 3) {
3993 return -1;
3994 }
3995
3996 /*
3997 * Map polygon cache
3998 */
3999 if ((polyInts==NULL) || (polyAllocated==NULL)) {
4000 /* Use global cache */
4001 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
4002 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
4003 } else {
4004 /* Use local cache */
4005 gfxPrimitivesPolyInts = *polyInts;
4006 gfxPrimitivesPolyAllocated = *polyAllocated;
4007 }
4008
4009 /*
4010 * Allocate temp array, only grow array
4011 */
4012 if (!gfxPrimitivesPolyAllocated) {
4013 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
4014 gfxPrimitivesPolyAllocated = n;
4015 } else {
4016 if (gfxPrimitivesPolyAllocated < n) {
4017 gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
4018 gfxPrimitivesPolyAllocated = n;
4019 }
4020 }
4021
4022 /*
4023 * Check temp array
4024 */
4025 if (gfxPrimitivesPolyInts==NULL) {
4026 gfxPrimitivesPolyAllocated = 0;
4027 }
4028
4029 /*
4030 * Update cache variables
4031 */
4032 if ((polyInts==NULL) || (polyAllocated==NULL)) {
4033 gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
4034 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
4035 } else {
4036 *polyInts = gfxPrimitivesPolyInts;
4037 *polyAllocated = gfxPrimitivesPolyAllocated;
4038 }
4039
4040 /*
4041 * Check temp array again
4042 */
4043 if (gfxPrimitivesPolyInts==NULL) {
4044 return(-1);
4045 }
4046
4047 /*
4048 * Determine Y maxima
4049 */
4050 miny = vy[0];
4051 maxy = vy[0];
4052 for (i = 1; (i < n); i++) {
4053 if (vy[i] < miny) {
4054 miny = vy[i];
4055 } else if (vy[i] > maxy) {
4056 maxy = vy[i];
4057 }
4058 }
4059
4060 /*
4061 * Draw, scanning y
4062 */
4063 result = 0;
4064 for (y = miny; (y <= maxy); y++) {
4065 ints = 0;
4066 for (i = 0; (i < n); i++) {
4067 if (!i) {
4068 ind1 = n - 1;
4069 ind2 = 0;
4070 } else {
4071 ind1 = i - 1;
4072 ind2 = i;
4073 }
4074 y1 = vy[ind1];
4075 y2 = vy[ind2];
4076 if (y1 < y2) {
4077 x1 = vx[ind1];
4078 x2 = vx[ind2];
4079 } else if (y1 > y2) {
4080 y2 = vy[ind1];
4081 y1 = vy[ind2];
4082 x2 = vx[ind1];
4083 x1 = vx[ind2];
4084 } else {
4085 continue;
4086 }
4087 if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
4088 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
4089 }
4090 }
4091
4092 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt);
4093
4094 for (i = 0; (i < ints); i += 2) {
4095 xa = gfxPrimitivesPolyInts[i] + 1;
4096 xa = (xa >> 16) + ((xa & 32768) >> 15);
4097 xb = gfxPrimitivesPolyInts[i+1] - 1;
4098 xb = (xb >> 16) + ((xb & 32768) >> 15);
4099 result |= hlineColor(dst, xa, xb, y, color);
4100 }
4101 }
4102
4103 return (result);
4104 }
4105
filledPolygonRGBAMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a,int ** polyInts,int * polyAllocated)4106 int filledPolygonRGBAMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a, int **polyInts, int *polyAllocated)
4107 {
4108 /*
4109 * Draw
4110 */
4111 return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, polyInts, polyAllocated));
4112 }
4113
4114 /* Standard versions are calling multithreaded versions with NULL cache parameters */
4115
filledPolygonColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint32 color)4116 int filledPolygonColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color)
4117 {
4118 /*
4119 * Draw
4120 */
4121 return (filledPolygonColorMT(dst, vx, vy, n, color, NULL, NULL));
4122 }
4123
filledPolygonRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4124 int filledPolygonRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4125 {
4126 /*
4127 * Draw
4128 */
4129 return (filledPolygonColorMT(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, NULL, NULL));
4130 }
4131
_texturedHLine(SDL_Surface * dst,Sint16 x1,Sint16 x2,Sint16 y,SDL_Surface * texture,int texture_dx,int texture_dy)4132 int _texturedHLine(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y,SDL_Surface *texture,int texture_dx,int texture_dy)
4133 {
4134 Sint16 left, right, top, bottom;
4135 Sint16 w;
4136 Sint16 xtmp;
4137 int result = 0;
4138 int texture_x_walker;
4139 int texture_y_start;
4140 SDL_Rect source_rect,dst_rect;
4141 int pixels_written,write_width;
4142
4143 /*
4144 * Check visibility of clipping rectangle
4145 */
4146 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4147 return(0);
4148 }
4149
4150 /*
4151 * Swap x1, x2 if required to ensure x1<=x2
4152 */
4153 if (x1 > x2) {
4154 xtmp = x1;
4155 x1 = x2;
4156 x2 = xtmp;
4157 }
4158
4159 /*
4160 * Get clipping boundary and
4161 * check visibility of hline
4162 */
4163 left = dst->clip_rect.x;
4164 if (x2<left) {
4165 return(0);
4166 }
4167 right = dst->clip_rect.x + dst->clip_rect.w - 1;
4168 if (x1>right) {
4169 return(0);
4170 }
4171 top = dst->clip_rect.y;
4172 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4173 if ((y<top) || (y>bottom)) {
4174 return (0);
4175 }
4176
4177
4178 /*
4179 * Clip x
4180 */
4181 if (x1 < left) {
4182 x1 = left;
4183 }
4184 if (x2 > right) {
4185 x2 = right;
4186 }
4187
4188 /*
4189 * Calculate width
4190 */
4191 w = x2 - x1;
4192
4193 /*
4194 * Determint where in the texture we start drawing
4195 **/
4196 texture_x_walker = (x1 - texture_dx) % texture->w;
4197 if (texture_x_walker < 0){
4198 texture_x_walker = texture->w +texture_x_walker ;
4199 }
4200
4201 texture_y_start = (y + texture_dy) % texture->h;
4202 if (texture_y_start < 0){
4203 texture_y_start = texture->h + texture_y_start;
4204 }
4205
4206 //setup the source rectangle we are only drawing one horizontal line
4207 source_rect.y = texture_y_start;
4208 source_rect.x =texture_x_walker;
4209 source_rect.h =1;
4210 //we will draw to the current y
4211 dst_rect.y = y;
4212
4213 //if there are enough pixels left in the current row of the texture
4214 //draw it all at once
4215 if (w <= texture->w -texture_x_walker){
4216 source_rect.w = w;
4217 source_rect.x = texture_x_walker;
4218 dst_rect.x= x1;
4219 if (dirtyDst == dst)
4220 dirtyRects.push_back(dst_rect);
4221 SDL_BlitSurface (texture,&source_rect , dst, &dst_rect) ;
4222 } else {//we need to draw multiple times
4223 //draw the first segment
4224 pixels_written = texture->w -texture_x_walker;
4225 source_rect.w = pixels_written;
4226 source_rect.x = texture_x_walker;
4227 dst_rect.x= x1;
4228 if (dirtyDst == dst)
4229 dirtyRects.push_back(dst_rect);
4230 SDL_BlitSurface (texture,&source_rect , dst, &dst_rect);
4231 write_width = texture->w;
4232
4233 //now draw the rest
4234 //set the source x to 0
4235 source_rect.x = 0;
4236 while(pixels_written < w){
4237 if (write_width >= w - pixels_written){
4238 write_width= w- pixels_written;
4239 }
4240 source_rect.w = write_width;
4241 dst_rect.x = x1 + pixels_written;
4242 if (dirtyDst == dst)
4243 dirtyRects.push_back(dst_rect);
4244 SDL_BlitSurface (texture,&source_rect , dst, &dst_rect) ;
4245 pixels_written += write_width;
4246 }
4247 }
4248 return result;
4249 }
4250
4251 /**
4252 * Draws a polygon filled with the given texture. this operation use SDL_BlitSurface. It supports
4253 * alpha drawing.
4254 * to get the best performance of this operation you need to make sure the texture and the dst surface have the same format
4255 * see http://docs.mandragor.org/files/Common_libs_documentation/SDL/SDL_Documentation_project_en/sdlblitsurface.html
4256 *
4257 * dest the destination surface,
4258 * vx array of x vector components
4259 * vy array of x vector components
4260 * n the amount of vectors in the vx and vy array
4261 * texture the sdl surface to use to fill the polygon
4262 * texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
4263 * to the left and want the texture to apear the same you need to increase the texture_dx value
4264 * texture_dy see texture_dx
4265 *
4266 * (Note: The last two parameters are optional, but required for multithreaded operation.)
4267 **/
texturedPolygonMT(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy,int ** polyInts,int * polyAllocated)4268 int texturedPolygonMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface * texture,int texture_dx,int texture_dy, int **polyInts, int *polyAllocated)
4269 {
4270 int result;
4271 int i;
4272 int y, xa, xb;
4273 int minx,maxx,miny, maxy;
4274 int x1, y1;
4275 int x2, y2;
4276 int ind1, ind2;
4277 int ints;
4278 int *gfxPrimitivesPolyInts = NULL;
4279 int gfxPrimitivesPolyAllocated = 0;
4280
4281 /*
4282 * Check visibility of clipping rectangle
4283 */
4284 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4285 return(0);
4286 }
4287
4288 /*
4289 * Sanity check number of edges
4290 */
4291 if (n < 3) {
4292 return -1;
4293 }
4294
4295 /*
4296 * Map polygon cache
4297 */
4298 if ((polyInts==NULL) || (polyAllocated==NULL)) {
4299 /* Use global cache */
4300 gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
4301 gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
4302 } else {
4303 /* Use local cache */
4304 gfxPrimitivesPolyInts = *polyInts;
4305 gfxPrimitivesPolyAllocated = *polyAllocated;
4306 }
4307
4308 /*
4309 * Allocate temp array, only grow array
4310 */
4311 if (!gfxPrimitivesPolyAllocated) {
4312 gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
4313 gfxPrimitivesPolyAllocated = n;
4314 } else {
4315 if (gfxPrimitivesPolyAllocated < n) {
4316 gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
4317 gfxPrimitivesPolyAllocated = n;
4318 }
4319 }
4320
4321 /*
4322 * Check temp array
4323 */
4324 if (gfxPrimitivesPolyInts==NULL) {
4325 gfxPrimitivesPolyAllocated = 0;
4326 }
4327
4328 /*
4329 * Update cache variables
4330 */
4331 if ((polyInts==NULL) || (polyAllocated==NULL)) {
4332 gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
4333 gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
4334 } else {
4335 *polyInts = gfxPrimitivesPolyInts;
4336 *polyAllocated = gfxPrimitivesPolyAllocated;
4337 }
4338
4339 /*
4340 * Check temp array again
4341 */
4342 if (gfxPrimitivesPolyInts==NULL) {
4343 return(-1);
4344 }
4345
4346 /*
4347 * Determine X,Y minima,maxima
4348 */
4349 miny = vy[0];
4350 maxy = vy[0];
4351 minx = vx[0];
4352 maxx = vx[0];
4353 for (i = 1; (i < n); i++) {
4354 if (vy[i] < miny) {
4355 miny = vy[i];
4356 } else if (vy[i] > maxy) {
4357 maxy = vy[i];
4358 }
4359 if (vx[i] < minx) {
4360 minx = vx[i];
4361 } else if (vx[i] > maxx) {
4362 maxx = vx[i];
4363 }
4364 }
4365 if (maxx <0 || minx > dst->w){
4366 return -1;
4367 }
4368 if (maxy <0 || miny > dst->h){
4369 return -1;
4370 }
4371
4372 /*
4373 * Draw, scanning y
4374 */
4375 result = 0;
4376 for (y = miny; (y <= maxy); y++) {
4377 ints = 0;
4378 for (i = 0; (i < n); i++) {
4379 if (!i) {
4380 ind1 = n - 1;
4381 ind2 = 0;
4382 } else {
4383 ind1 = i - 1;
4384 ind2 = i;
4385 }
4386 y1 = vy[ind1];
4387 y2 = vy[ind2];
4388 if (y1 < y2) {
4389 x1 = vx[ind1];
4390 x2 = vx[ind2];
4391 } else if (y1 > y2) {
4392 y2 = vy[ind1];
4393 y1 = vy[ind2];
4394 x2 = vx[ind1];
4395 x1 = vx[ind2];
4396 } else {
4397 continue;
4398 }
4399 if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
4400 gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
4401 }
4402
4403 }
4404
4405 qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt);
4406
4407 for (i = 0; (i < ints); i += 2) {
4408 xa = gfxPrimitivesPolyInts[i] + 1;
4409 xa = (xa >> 16) + ((xa & 32768) >> 15);
4410 xb = gfxPrimitivesPolyInts[i+1] - 1;
4411 xb = (xb >> 16) + ((xb & 32768) >> 15);
4412 result |= _texturedHLine(dst, xa, xb, y, texture,texture_dx,texture_dy);
4413 }
4414 }
4415
4416 return (result);
4417 }
4418
4419 /* Standard version is calling multithreaded versions with NULL cache parameters. */
4420
texturedPolygon(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,SDL_Surface * texture,int texture_dx,int texture_dy)4421 int texturedPolygon(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, SDL_Surface *texture, int texture_dx, int texture_dy)
4422 {
4423 /*
4424 * Draw
4425 */
4426 return (texturedPolygonMT(dst, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
4427 }
4428
4429 /* Helper qsort callback for polygon drawing */
4430
gfxPrimitivesCompareInt(const void * a,const void * b)4431 int gfxPrimitivesCompareInt(const void *a, const void *b)
4432 {
4433 return (*(const int *) a) - (*(const int *) b);
4434 }
4435
4436
4437
4438 /* ---- Character */
4439
4440 static SDL_Surface *gfxPrimitivesFont[256];
4441 static Uint32 gfxPrimitivesFontColor[256];
4442
4443 /* Default is to use 8x8 internal font */
4444 static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
4445
4446 static int charWidth = 8, charHeight = 8;
4447 static int charPitch = 1;
4448 static int charSize = 8; /* character data size in bytes */
4449
gfxPrimitivesSetFont(const void * fontdata,int cw,int ch)4450 void gfxPrimitivesSetFont(const void *fontdata, int cw, int ch)
4451 {
4452 int i;
4453
4454 if (fontdata) {
4455 currentFontdata = (const unsigned char*) fontdata;
4456 charWidth = cw;
4457 charHeight = ch;
4458 } else {
4459 currentFontdata = gfxPrimitivesFontdata;
4460 charWidth = 8;
4461 charHeight = 8;
4462 }
4463
4464 charPitch = (charWidth+7)/8;
4465 charSize = charPitch * charHeight;
4466
4467 for (i = 0; i < 256; i++) {
4468 if (gfxPrimitivesFont[i]) {
4469 SDL_FreeSurface(gfxPrimitivesFont[i]);
4470 gfxPrimitivesFont[i] = NULL;
4471 }
4472 }
4473 }
4474
characterColor(SDL_Surface * dst,Sint16 x,Sint16 y,char c,Uint32 color)4475 int characterColor(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint32 color)
4476 {
4477 Sint16 left, right, top, bottom;
4478 Sint16 x1, y1, x2, y2;
4479 SDL_Rect srect;
4480 SDL_Rect drect;
4481 int result;
4482 int ix, iy;
4483 const unsigned char *charpos;
4484 Uint8 *curpos;
4485 int forced_redraw;
4486 Uint8 patt, mask;
4487 Uint8 *linepos;
4488 int pitch;
4489
4490 /*
4491 * Check visibility of clipping rectangle
4492 */
4493 if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
4494 return(0);
4495 }
4496
4497 /*
4498 * Get text and clipping boundary and
4499 * test if bounding box of character is visible
4500 */
4501
4502 left = dst->clip_rect.x;
4503 x2 = x + charWidth;
4504 if (x2<left) {
4505 return(0);
4506 }
4507 right = dst->clip_rect.x + dst->clip_rect.w - 1;
4508 x1 = x;
4509 if (x1>right) {
4510 return(0);
4511 }
4512 top = dst->clip_rect.y;
4513 y2 = y + charHeight;
4514 if (y2<top) {
4515 return(0);
4516 }
4517 bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
4518 y1 = y;
4519 if (y1>bottom) {
4520 return(0);
4521 }
4522
4523 /*
4524 * Setup source rectangle
4525 */
4526 srect.x = 0;
4527 srect.y = 0;
4528 srect.w = charWidth;
4529 srect.h = charHeight;
4530
4531 /*
4532 * Setup destination rectangle
4533 */
4534 drect.x = x;
4535 drect.y = y;
4536 drect.w = charWidth;
4537 drect.h = charHeight;
4538
4539 /*
4540 * Create new charWidth x charHeight bitmap surface if not already present
4541 */
4542 if (gfxPrimitivesFont[(unsigned char) c] == NULL) {
4543 gfxPrimitivesFont[(unsigned char) c] =
4544 SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA,
4545 charWidth, charHeight, 32,
4546 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
4547 /*
4548 * Check pointer
4549 */
4550 if (gfxPrimitivesFont[(unsigned char) c] == NULL) {
4551 return (-1);
4552 }
4553 /*
4554 * Definitely redraw
4555 */
4556 forced_redraw = 1;
4557 } else {
4558 forced_redraw = 0;
4559 }
4560
4561 /*
4562 * Check if color has changed
4563 */
4564 if ((gfxPrimitivesFontColor[(unsigned char) c] != color) || (forced_redraw)) {
4565 /*
4566 * Redraw character
4567 */
4568 SDL_SetAlpha(gfxPrimitivesFont[(unsigned char) c], SDL_SRCALPHA, 255);
4569 gfxPrimitivesFontColor[(unsigned char) c] = color;
4570
4571 /* Lock font-surface */
4572 if (SDL_LockSurface(gfxPrimitivesFont[(unsigned char) c]) != 0)
4573 return (-1);
4574
4575 /*
4576 * Variable setup
4577 */
4578 charpos = currentFontdata + (unsigned char) c * charSize;
4579 linepos = (Uint8 *) gfxPrimitivesFont[(unsigned char) c]->pixels;
4580 pitch = gfxPrimitivesFont[(unsigned char) c]->pitch;
4581
4582 /*
4583 * Drawing loop
4584 */
4585 patt = 0;
4586 for (iy = 0; iy < charHeight; iy++) {
4587 mask = 0x00;
4588 curpos = linepos;
4589 for (ix = 0; ix < charWidth; ix++) {
4590 if (!(mask >>= 1)) {
4591 patt = *charpos++;
4592 mask = 0x80;
4593 }
4594
4595 if (patt & mask)
4596 *(Uint32 *)curpos = color;
4597 else
4598 *(Uint32 *)curpos = 0;
4599 curpos += 4;;
4600 }
4601 linepos += pitch;
4602 }
4603
4604 /* Unlock font-surface */
4605 SDL_UnlockSurface(gfxPrimitivesFont[(unsigned char) c]);
4606 }
4607
4608 /*
4609 * Draw bitmap onto destination surface
4610 */
4611 if (dirtyDst == dst)
4612 dirtyRects.push_back(drect);
4613 result = SDL_BlitSurface(gfxPrimitivesFont[(unsigned char) c], &srect, dst, &drect);
4614
4615 return (result);
4616 }
4617
characterRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,char c,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4618 int characterRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4619 {
4620 /*
4621 * Draw
4622 */
4623 return (characterColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4624 }
4625
stringColor(SDL_Surface * dst,Sint16 x,Sint16 y,const char * c,Uint32 color)4626 int stringColor(SDL_Surface * dst, Sint16 x, Sint16 y, const char *c, Uint32 color)
4627 {
4628 int result = 0;
4629 int curx = x;
4630 const char *curchar = c;
4631
4632 while (*curchar) {
4633 result |= characterColor(dst, curx, y, *curchar, color);
4634 curx += charWidth;
4635 curchar++;
4636 }
4637
4638 return (result);
4639 }
4640
stringRGBA(SDL_Surface * dst,Sint16 x,Sint16 y,const char * c,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4641 int stringRGBA(SDL_Surface * dst, Sint16 x, Sint16 y, const char *c, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4642 {
4643 /*
4644 * Draw
4645 */
4646 return (stringColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4647 }
4648
4649 /* ---- Bezier curve */
4650
4651 /*
4652 Calculate bezier interpolator of data array with ndata values at position 't'
4653 */
4654
evaluateBezier(double * data,int ndata,double t)4655 double evaluateBezier (double *data, int ndata, double t)
4656 {
4657 double mu, result;
4658 int n,k,kn,nn,nkn;
4659 double blend,muk,munk;
4660
4661 /* Sanity check bounds */
4662 if (t<0.0) {
4663 return(data[0]);
4664 }
4665 if (t>=(double)ndata) {
4666 return(data[ndata-1]);
4667 }
4668
4669 /* Adjust t to the range 0.0 to 1.0 */
4670 mu=t/(double)ndata;
4671
4672 /* Calculate interpolate */
4673 n=ndata-1;
4674 result=0.0;
4675 muk = 1;
4676 munk = pow(1-mu,(double)n);
4677 for (k=0;k<=n;k++) {
4678 nn = n;
4679 kn = k;
4680 nkn = n - k;
4681 blend = muk * munk;
4682 muk *= mu;
4683 munk /= (1-mu);
4684 while (nn >= 1) {
4685 blend *= nn;
4686 nn--;
4687 if (kn > 1) {
4688 blend /= (double)kn;
4689 kn--;
4690 }
4691 if (nkn > 1) {
4692 blend /= (double)nkn;
4693 nkn--;
4694 }
4695 }
4696 result += data[k] * blend;
4697 }
4698
4699 return(result);
4700 }
4701
bezierColor(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint32 color)4702 int bezierColor(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint32 color)
4703 {
4704 int result;
4705 int i;
4706 double *x, *y, t, stepsize;
4707 Sint16 x1, y1, x2, y2;
4708
4709 /*
4710 * Sanity check
4711 */
4712 if (n < 3) {
4713 return (-1);
4714 }
4715 if (s < 2) {
4716 return (-1);
4717 }
4718
4719 /*
4720 * Variable setup
4721 */
4722 stepsize=(double)1.0/(double)s;
4723
4724 /* Transfer vertices into float arrays */
4725 if ((x=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
4726 return(-1);
4727 }
4728 if ((y=(double *)malloc(sizeof(double)*(n+1)))==NULL) {
4729 free(x);
4730 return(-1);
4731 }
4732 for (i=0; i<n; i++) {
4733 x[i]=vx[i];
4734 y[i]=vy[i];
4735 }
4736 x[n]=vx[0];
4737 y[n]=vy[0];
4738
4739 /*
4740 * Draw
4741 */
4742 result = 0;
4743 t=0.0;
4744 x1 = (Sint16) evaluateBezier(x,n+1,t);
4745 y1 = (Sint16) evaluateBezier(y,n+1,t);
4746 for (i = 0; i <= (n*s); i++) {
4747 t += stepsize;
4748 x2=(Sint16)evaluateBezier(x,n,t);
4749 y2=(Sint16)evaluateBezier(y,n,t);
4750 result |= lineColor(dst, x1, y1, x2, y2, color);
4751 x1 = x2;
4752 y1 = y2;
4753 }
4754
4755 /* Clean up temporary array */
4756 free(x);
4757 free(y);
4758
4759 return (result);
4760 }
4761
bezierRGBA(SDL_Surface * dst,const Sint16 * vx,const Sint16 * vy,int n,int s,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4762 int bezierRGBA(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4763 {
4764 /*
4765 * Draw
4766 */
4767 return (bezierColor(dst, vx, vy, n, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
4768 }
4769