1 /*
2  * SDL_prim.c
3  *
4  * Copyright (C) 2003-2005 Ryan McGuigan <ryan@tempestgames.com>
5  *
6  * See the included 'COPYING' file for license information.
7  *
8  * Simple SDL Primitive C functions.  My goal while writing this
9  * was to keep everything as simple as possible, both in the design
10  * of these functions and in the usage of these functions.
11  *
12  * I hope someone finds this useful.
13  *
14  * Adapted to compile without warning on g++ -W -Wall -O2 by tdd@insia.org
15  * (20050413)
16  *
17  */
18 
19 
20 #include "SDL_prim.h"
21 
22 
23 /*
24  * simple pixel drawing function.
25  *
26  * tests to be sure pixel is within bounds of the surface, so you
27  * can draw off the surface to your hearts content
28  *
29  * it's probably not good practice to be drawing off the surface though...
30  *
31  */
32 inline
SDL_putPixel(SDL_Surface * surf,int x,int y,Uint32 clr)33 void SDL_putPixel(SDL_Surface *surf, int x, int y, Uint32 clr)
34 {
35 	int Bpp = surf->format->BytesPerPixel;
36 	Uint8 *p;
37 
38 	if (! (x < 0 || x >= surf->w || y < 0 || y >= surf->h) )
39 	{
40 		p = (Uint8*)surf->pixels + y * surf->pitch + x * Bpp;
41 
42 		switch(Bpp) {
43 		case 1:
44 		  	*p = clr;
45 			break;
46 
47 		case 2:
48 		  	*(Uint16*)p = clr;
49 			break;
50 
51 		case 3:
52 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
53 				p[0] = (clr >> 16) & 0xff;
54 				p[1] = (clr >> 8) & 0xff;
55 				p[2] = clr & 0xff;
56 			} else {
57 				p[0] = clr & 0xff;
58 				p[1] = (clr >> 8) & 0xff;
59 				p[2] = (clr >> 16) & 0xff;
60 			}
61 			break;
62 
63 		case 4:
64 			*(Uint32*)p = clr;
65 			break;
66 		}
67 	}
68 }
69 
70 
71 /*
72  * returns pointer to pixel at x, y
73  */
74 inline
SDL_getPixel(SDL_Surface * surf,int x,int y)75 Uint8* SDL_getPixel(SDL_Surface *surf, int x, int y)
76 {
77 	if (! (x < 0 || x >= surf->w || y < 0 || y >= surf->h) )
78 		return (Uint8*)surf->pixels + y * surf->pitch + x * surf->format->BytesPerPixel;
79 	else
80 		return 0;
81 }
82 
83 
84 /*
85  * slow pixel blending function
86  *
87  * called from SDL_blendPixel for 8 bit surfaces.
88  * may be useful for something else, I dunno.
89  *
90  */
91 inline
__slow_SDL_blendPixel(SDL_Surface * surf,int x,int y,Uint32 clr,Uint8 alpha)92 void __slow_SDL_blendPixel( SDL_Surface *surf, int x, int y, Uint32 clr,
93                             Uint8 alpha)
94 {
95 	Uint8 *p;
96 	Uint8 r, g, b, r2, g2, b2;
97 
98 	if ( (p = SDL_getPixel(surf, x, y)) ) {
99 		SDL_GetRGB(clr, surf->format, &r, &g, &b);
100 		SDL_GetRGB(*p, surf->format, &r2, &g2, &b2);
101 
102 		/* The 3 following lines use explicit cast now - tdd */
103 		r = r2 + (int) (( r - r2 ) * ( alpha / 255.0 ));
104 		g = g2 + (int) (( g - g2 ) * ( alpha / 255.0 ));
105 		b = b2 + (int) (( b - b2 ) * ( alpha / 255.0 ));
106 
107 		clr = SDL_MapRGB(surf->format, r, g, b);
108 
109 		SDL_putPixel(surf, x, y, clr);
110 	}
111 }
112 
113 
114 /*
115  * blends pixel onto surface according to alpha
116  */
117 inline
SDL_blendPixel(SDL_Surface * surf,int x,int y,Uint32 clr,Uint8 alpha)118 void SDL_blendPixel( SDL_Surface *surf, int x, int y, Uint32 clr,
119                      Uint8 alpha)
120 {
121 	Uint8 *p;
122 	Uint32 R, G, B;
123 
124 	if ( (p = SDL_getPixel(surf, x, y)) ) {
125 		switch(surf->format->BytesPerPixel) {
126 		case 1:  /* 8 bpp */
127 			__slow_SDL_blendPixel(surf, x, y, clr, alpha);
128 			break;
129 
130 		case 2:  /* 16 bpp */
131 			R = ( (*(Uint16*)p & surf->format->Rmask) + ( ((clr & surf->format->Rmask) - ((*(Uint16*)p) & surf->format->Rmask)) * alpha >> 8) ) & surf->format->Rmask;
132 			G = ( (*(Uint16*)p & surf->format->Gmask) + ( ((clr & surf->format->Gmask) - ((*(Uint16*)p) & surf->format->Gmask)) * alpha >> 8) ) & surf->format->Gmask;
133 			B = ( (*(Uint16*)p & surf->format->Bmask) + ( ((clr & surf->format->Bmask) - ((*(Uint16*)p) & surf->format->Bmask)) * alpha >> 8) ) & surf->format->Bmask;
134 			*(Uint16*)p = R | G | B;
135 			break;
136 
137 		case 3:  /* 24 bpp */
138 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
139 				p[0] = ( p[0] + ((((clr >> 16) & 0xff) - p[0]) * alpha >> 8) ) & 0xff;
140 				p[1] = ( p[1] + ((((clr >> 8) & 0xff) - p[1]) * alpha >> 8) ) & 0xff;
141 				p[2] = ( p[2] + (((clr & 0xff) - p[2]) * alpha >> 8) ) & 0xff;
142 			} else {
143 				p[0] = ( p[0] + (((clr & 0xff) - p[0]) * alpha >> 8) ) & 0xff;
144 				p[1] = ( p[1] + ((((clr >> 8) & 0xff) - p[1]) * alpha >> 8) ) & 0xff;
145 				p[2] = ( p[2] + ((((clr >> 16) & 0xff) - p[2]) * alpha >> 8) ) & 0xff;
146 			}
147 			break;
148 
149 		case 4:  /* 32 bpp */
150 			R = ( (*(Uint32*)p & surf->format->Rmask) + ( ((clr & surf->format->Rmask) - (*(Uint32*)p & surf->format->Rmask)) * alpha >> 8) ) & surf->format->Rmask;
151 			G = ( (*(Uint32*)p & surf->format->Gmask) + ( ((clr & surf->format->Gmask) - (*(Uint32*)p & surf->format->Gmask)) * alpha >> 8) ) & surf->format->Gmask;
152 			B = ( (*(Uint32*)p & surf->format->Bmask) + ( ((clr & surf->format->Bmask) - (*(Uint32*)p & surf->format->Bmask)) * alpha >> 8) ) & surf->format->Bmask;
153 			*(Uint32*)p = R | G | B;
154 			break;
155 		}
156 	}
157 }
158 
159 
160 /*
161  * Self explanatory.  draws lines, supports anti-aliasing and
162  * alpha blending
163  *
164  */
SDL_drawLine_TG(SDL_Surface * surf,int x,int y,int x2,int y2,Uint32 clr,Uint8 alpha,Uint8 flags)165 void SDL_drawLine_TG( SDL_Surface *surf, int x, int y, int x2, int y2,
166                       Uint32 clr, Uint8 alpha, Uint8 flags )
167 {
168 	int xaa, yaa, *a, *b, *a2, *b2, da, xd, yd;
169 	float aa, db;
170 	float realb;
171 
172 	/*
173 	 * for the sake of my sanity when i look at this again...
174 	 *
175 	 * xaa:   the x aa offset value, either 1 or 0
176 	 * yaa:   the y aa offset value, either 1 or 0
177 	 * *a:    reference to either x or y, depending on which way we are
178 	 *        drawing.
179 	 * *b:    reference to either x or y, depending on which way we are
180 	 *        drawing.
181 	 * *a2:   reference to either x2 or y2, depending on which way we are
182 	 *        drawing.
183 	 * *b2:   reference to either x2 or y2, depending on which way we are
184 	 *        drawing.
185 	 * x:     starting x value, current x value
186 	 * y:     starting y value, current y value
187 	 * x2:    ending x value
188 	 * y2:    ending y value
189 	 * xd:    distance from x to x2
190 	 * yd:    distance from y to y2
191 	 * da:    change in a for each iteration, either 1 or -1
192 	 * db:    change in b with respect to a
193 	 * realb: real b value, as b is an int, and db is going to be a
194 	 *        fraction
195 	 * aa:    anti-aliasing value, fraction part of realb
196 	 *
197 	 */
198 
199 	/* find x and y distances */
200 	xd = x2 - x;
201 	yd = y2 - y;
202 
203 	if (abs(xd) >= abs(yd)) {
204 	/* draw left/right to left/right */
205 		xaa = 0;
206 		yaa = 1;
207 		a = &x;
208 		b = &y;
209 		a2 = &x2;
210 		b2 = &y2;
211 		db = (float)yd / xd;
212 	} else {
213 	/* draw top/bottom to top/bottom */
214 		xaa = 1;
215 		yaa = 0;
216 		a = &y;
217 		b = &x;
218 		a2 = &y2;
219 		b2 = &x2;
220 		db = (float)xd / yd;
221 	}
222 
223 	if (!(alpha < 255 && (flags & SDL_TG_ALPHA)))
224 		alpha = 255;
225 
226 	/* left or right? */
227 	da = (*a <= *a2) ? 1 : -1;
228 	/* up or down? */
229 	db *= da;
230 	/* init realb */
231 	realb = (float)*b;
232 	/* we're stopping when we hit *a2, so we have to add +/-1 to it */
233 	*a2 += da;
234 
235 	if (flags & SDL_TG_LOCK)
236 		__SDL_PRIM_LOCKSURFACE(surf)
237 
238 	for (; *a != *a2; *a += da) {
239 	    	/* Explicit cast now - tdd */
240 		*b = (int) floor(realb + 0.5);
241 
242 		if (flags & SDL_TG_ANTIALIAS) {
243 			aa = (realb + 0.5 - *b) * alpha;
244 			SDL_blendPixel(surf, x + xaa, y + yaa, clr, (int)aa);
245 			SDL_blendPixel(surf, x - xaa, y - yaa, clr, alpha - (int)aa);
246 		}
247 
248 		if (alpha < 255)
249 			SDL_blendPixel(surf, x, y, clr, alpha);
250 		else
251 			SDL_putPixel(surf, x, y, clr);
252 
253 		realb += db;
254 	}
255 
256 	if (flags & SDL_TG_LOCK)
257 		__SDL_PRIM_UNLOCKSURFACE(surf)
258 }
259 
260 
261 
262 /*
263  * Circle drawing/filling function.  Uses a more optimized algorithm
264  * when drawing non-anti-aliased circles, uses a mathematically correct algo
265  * when drawing anti-aliased circles.  After much trial and error, I have
266  * removed 100% of pixel overlapping, no more spots in anti-aliased circles.
267  *
268  */
SDL_drawCircle_TG(SDL_Surface * surf,int x1,int y1,int r,Uint32 clr,Uint8 alpha,Uint8 flags)269 void SDL_drawCircle_TG( SDL_Surface *surf, int x1, int y1, int r, Uint32 clr,
270                         Uint8 alpha, Uint8 flags )
271 {
272 	int x = 0, tmp, dy = 0, y = r, r2, aa = 0, fy = 0;
273 	int r2p = r * r;
274 	float aatmp;
275 
276 #	define __CIRCLE_OUTAA \
277 	{ \
278 		if (x) { \
279 			SDL_blendPixel(surf, x1 + x, y1 + y + 1, clr, aa); \
280 			SDL_blendPixel(surf, x1 + x, y1 - y - 1, clr, aa); \
281 		} \
282 		SDL_blendPixel(surf, x1 - x, y1 + y + 1, clr, aa); \
283 		SDL_blendPixel(surf, x1 - x, y1 - y - 1, clr, aa); \
284 	}
285 
286 #	define __CIRCLE_INAA \
287 	{ \
288 		if (x) { \
289 			SDL_blendPixel(surf, x1 + x, y1 + y - 1, clr, alpha - aa); \
290 			SDL_blendPixel(surf, x1 + x, y1 - y + 1, clr, alpha - aa); \
291 		} \
292 		SDL_blendPixel(surf, x1 - x, y1 + y - 1, clr, alpha - aa); \
293 		SDL_blendPixel(surf, x1 - x, y1 - y + 1, clr, alpha - aa); \
294 	}
295 
296 #	define __CIRCLE_OUTAA_ROT90 \
297 	{ \
298 		if (x) { \
299 			SDL_blendPixel(surf, x1 + y + 1, y1 + x, clr, aa); \
300 			SDL_blendPixel(surf, x1 - y - 1, y1 - x, clr, aa); \
301 		} \
302 		SDL_blendPixel(surf, x1 - y - 1, y1 + x, clr, aa); \
303 		SDL_blendPixel(surf, x1 + y + 1, y1 - x, clr, aa); \
304 	}
305 
306 #	define __CIRCLE_INAA_ROT90 \
307 	{ \
308 		if (x) { \
309 			SDL_blendPixel(surf, x1 + y - 1, y1 + x, clr, alpha - aa); \
310 			SDL_blendPixel(surf, x1 - y + 1, y1 - x, clr, alpha - aa); \
311 		} \
312 		SDL_blendPixel(surf, x1 - y + 1, y1 + x, clr, alpha - aa); \
313 		SDL_blendPixel(surf, x1 + y - 1, y1 - x, clr, alpha - aa); \
314 	}
315 
316 #	define __CIRCLE_BLEND \
317 	{ \
318 		if (x) { \
319 			SDL_blendPixel(surf, x1 + x, y1 + y, clr, alpha); \
320 			SDL_blendPixel(surf, x1 + x, y1 - y, clr, alpha); \
321 		} \
322 		SDL_blendPixel(surf, x1 - x, y1 + y, clr, alpha); \
323 		SDL_blendPixel(surf, x1 - x, y1 - y, clr, alpha); \
324 	}
325 
326 #	define __CIRCLE_BLEND_ROT90 \
327 	{ \
328 		if (x) { \
329 			SDL_blendPixel(surf, x1 - y, y1 + x, clr, alpha); \
330 			SDL_blendPixel(surf, x1 + y, y1 + x, clr, alpha); \
331 		} \
332 		SDL_blendPixel(surf, x1 + y, y1 - x, clr, alpha); \
333 		SDL_blendPixel(surf, x1 - y, y1 - x, clr, alpha); \
334 	}
335 
336 #	define __CIRCLE_DRAW \
337 	{ \
338 		if (x) { \
339 			SDL_putPixel(surf, x1 + x, y1 + y, clr); \
340 			SDL_putPixel(surf, x1 + x, y1 - y, clr); \
341 		} \
342 		SDL_putPixel(surf, x1 - x, y1 + y, clr); \
343 		SDL_putPixel(surf, x1 - x, y1 - y, clr); \
344 	}
345 
346 #	define __CIRCLE_DRAW_ROT90 \
347 	{ \
348 		if (x) { \
349 			SDL_putPixel(surf, x1 - y, y1 + x, clr); \
350 			SDL_putPixel(surf, x1 + y, y1 + x, clr); \
351 		} \
352 		SDL_putPixel(surf, x1 + y, y1 - x, clr); \
353 		SDL_putPixel(surf, x1 - y, y1 - x, clr); \
354 	}
355 
356 	if (!(alpha < 255 && (flags & SDL_TG_ALPHA)))
357 		alpha = 255;
358 
359 	if (r < 6)
360 		r2 = 0;
361 	else
362 		r2 = r / 2;
363 
364 	if (flags & SDL_TG_LOCK)
365 		__SDL_PRIM_LOCKSURFACE(surf)
366 
367 	if (flags & SDL_TG_FILL) {
368 		if (alpha < 255)
369 			SDL_blendPixel(surf, x1, y1, clr, alpha);
370 		else
371 			SDL_putPixel(surf, x1, y1, clr);
372 	}
373 
374 	do {
375 		if (alpha < 255) {
376 			__CIRCLE_BLEND
377 			__CIRCLE_BLEND_ROT90
378 		} else {
379 			__CIRCLE_DRAW
380 			__CIRCLE_DRAW_ROT90
381 		}
382 
383 		if (flags & SDL_TG_FILL) {
384 			/* Fill the circle... */
385 			if (alpha < 255) {
386 				for (fy = y - 1; fy >= (x ? x : 1); fy--) {
387 					if (x) {
388 						SDL_blendPixel(surf, x1 - x, y1 + fy, clr, alpha);
389 						SDL_blendPixel(surf, x1 - x, y1 - fy, clr, alpha);
390 					}
391 					SDL_blendPixel(surf, x1 + x, y1 + fy, clr, alpha);
392 					SDL_blendPixel(surf, x1 + x, y1 - fy, clr, alpha);
393 
394 					if (fy > x) {
395 						if (x) {
396 							SDL_blendPixel(surf, x1 - fy, y1 + x, clr, alpha);
397 							SDL_blendPixel(surf, x1 + fy, y1 + x, clr, alpha);
398 						}
399 						SDL_blendPixel(surf, x1 - fy, y1 - x, clr, alpha);
400 						SDL_blendPixel(surf, x1 + fy, y1 - x, clr, alpha);
401 					}
402 				}
403 			} else {
404 				for (fy = y - 1; fy >= (x ? x : 1); fy--) {
405 					if (x) {
406 						SDL_putPixel(surf, x1 - x, y1 + fy, clr);
407 						SDL_putPixel(surf, x1 - x, y1 - fy, clr);
408 					}
409 					SDL_putPixel(surf, x1 + x, y1 + fy, clr);
410 					SDL_putPixel(surf, x1 + x, y1 - fy, clr);
411 
412 					if (fy > x) {
413 						if (x) {
414 							SDL_putPixel(surf, x1 - fy, y1 + x, clr);
415 							SDL_putPixel(surf, x1 + fy, y1 + x, clr);
416 						}
417 						SDL_putPixel(surf, x1 - fy, y1 - x, clr);
418 						SDL_putPixel(surf, x1 + fy, y1 - x, clr);
419 					}
420 				}
421 			}
422 		}
423 
424 		if (flags & SDL_TG_ANTIALIAS) {
425 			/*
426 			 * anti-aliased circle algorithm.  this is
427 			 * mathematically correct, but fairly expensive.
428 			 * looks extremely good though.
429 			 *
430 			 * this is also very simple, we simply find the y
431 			 * value with respect to each x value, using a circle
432 			 * equation.  the anti-alias values are based on the
433 			 * real y coordinates.
434 			 */
435 			__CIRCLE_OUTAA
436 			__CIRCLE_OUTAA_ROT90
437 			if (!(flags & SDL_TG_FILL)) {
438 				__CIRCLE_INAA
439 				if (x < y-1)
440 					__CIRCLE_INAA_ROT90
441 			}
442 
443 			aatmp = sqrt((float)r2p - x*x);
444 			/* Explicit cast now - tdd */
445 			y = (int) aatmp;
446 			aatmp = aatmp - (int)aatmp;
447 			/* Explicit cast now - tdd */
448 			aa = (int) (aatmp * alpha);
449 			x++;
450 		} else {
451 			/*
452 			 * i came up with this circle drawing algorithm on my
453 			 * own.  i don't know how it compares to other circle
454 			 * drawing algos as far as optimization, but this seems
455 			 * to work pretty well.  it's also pretty damn
456 			 * simple, which is what i'm all about.
457 			 */
458 
459 			/* move along x axis */
460 			x++;
461 
462 			/*
463 			 * adjust y if we're moving too far out of the circle.
464 			 * the r2 is simply the radius over 2, unless the
465 			 * radius is less than a particular value(above).
466 			 * this simply makes the circle look more accurate,
467 			 * as we're working with integers so it's never exact,
468 			 * and we don't want to change the y value unless we're
469 			 * going off by a particular amount.  this also more
470 			 * closely approximates the above, mathematically
471 			 * correct, algo.
472 			 */
473 			if (dy)
474 				y += dy;
475 			tmp = (r2p - x*x - y*y + r2);
476 			if (tmp < 0)
477 				dy = -1;
478 			else if (dy)
479 				dy = 0;
480 		}
481 	} while (x < y);
482 
483 	if (x == y) {
484 		if (alpha < 255)
485 			__CIRCLE_BLEND
486 		else
487 			__CIRCLE_DRAW
488 
489 		if (flags & SDL_TG_ANTIALIAS) {
490 			__CIRCLE_OUTAA
491 			__CIRCLE_OUTAA_ROT90
492 		}
493 	}
494 	else if (flags & SDL_TG_ANTIALIAS)
495 		__CIRCLE_OUTAA
496 
497 	if (flags & SDL_TG_LOCK)
498 		__SDL_PRIM_UNLOCKSURFACE(surf)
499 }
500 
501 
502 /*
503  * draws triangles
504  *
505  * this isn't very good, there is a good amount of pixel overlapping,
506  * and there are sometimes pixels dangling off the corners...
507  *
508  * bleh, fuck it, i'll fix it later
509  *
510  */
SDL_drawTriangle_TG(SDL_Surface * surf,int x1,int y1,int x2,int y2,int x3,int y3,Uint32 clr,Uint8 alpha,Uint8 flags)511 void SDL_drawTriangle_TG(SDL_Surface *surf, int x1, int y1, int x2, int y2,
512                          int x3, int y3, Uint32 clr, Uint8 alpha, Uint8 flags)
513 {
514 	int x, y, c, xlen, ylen, i, aaoffset;
515 	float a1, b1, a2, b2, slopea, slopeb, aa, aastep, pb1, pb2;
516 	float slope1, slope2, slope3;
517 
518 	/* avoid compiler warnings... */
519 	aa = 0.0;
520 	aastep = 0.0;
521 	aaoffset = 0;
522 
523 #	define __TRI_DRAW(PB, B, SLOPE) \
524 	{ \
525 		if (fabs(SLOPE) > 1.0) { \
526 			c = (PB) > (B) ? -1 : 1; \
527 			if (flags & SDL_TG_ANTIALIAS) { \
528 				aastep = alpha / fabs(SLOPE); \
529 				aa = alpha; \
530 			} \
531 		        /* Explicit cast now - tdd */ \
532 			for (y = (int) (PB); ( c > 0 ? y < floor(B) : y > (B) ); y += c) { \
533 				if (alpha < 255) \
534 					SDL_blendPixel(surf, x, y, clr, alpha); \
535 				else \
536 					SDL_putPixel(surf, x, y, clr); \
537 				if (flags & SDL_TG_ANTIALIAS) { \
538 					SDL_blendPixel(surf, x - 1, y, clr, (int)aa); \
539 					SDL_blendPixel(surf, x + 1, y, clr, (int)(alpha - aa)); \
540 					aa -= aastep; \
541 				} \
542 			} \
543 		} else { \
544 			if (alpha < 255) \
545 				SDL_blendPixel(surf, x, (int)(B), clr, (int)alpha); \
546 			else \
547 				SDL_putPixel(surf, x, (int)(B), clr); \
548 			if (flags & SDL_TG_ANTIALIAS) { \
549 				aa = (B) - (int)(B); \
550 				aa *= alpha; \
551 				SDL_blendPixel(surf, x, (int)(B) + 1, clr, (int)aa); \
552 				SDL_blendPixel(surf, x, (int)(B) - 1, clr, (int)(alpha - aa)); \
553 			} \
554 		} \
555 	}
556 
557 #	define __TRI_FILL_AA(PB, B, B2, SLOPE) \
558 	{ \
559 		if (fabs(SLOPE) > 2.0) { \
560 			c = (SLOPE > 0) ? 1 : -1; \
561 			if (SLOPE > 0) { \
562 				if (SLOPE == slope3) { \
563 					aaoffset = 0; \
564 					aa = 0; \
565 					aastep = alpha / SLOPE; \
566 				} \
567 				else { \
568 					aaoffset = -1; \
569 					aa = alpha; \
570 					aastep = alpha / SLOPE * -1; \
571 				} \
572 			} \
573 			else { \
574 				if (SLOPE == slope3) { \
575 					aaoffset = 0; \
576 					aa = 0; \
577 					aastep = alpha / SLOPE * -1; \
578 				} \
579 				else { \
580 					aaoffset = -1; \
581 					aa = alpha; \
582 					aastep = alpha / SLOPE; \
583 				} \
584 			} \
585 		        /* Explicit cast now - tdd */ \
586 			for (y = (int) ((PB) + c); ( c > 0 ? y < floor(B) : y > (B) ); y += c) { \
587 				SDL_blendPixel(surf, x + aaoffset, y, clr, (int)aa); \
588 				aa += aastep; \
589 			} \
590 		} else { \
591 			if (B > B2) \
592 				c = 1; \
593 			else \
594 				c = -1; \
595 			aa = fabs( (B) - (int)(B) ); \
596 			if (c < 0) \
597 				aa = alpha - aa * alpha; \
598 			else \
599 				aa *= alpha; \
600 		        /* Explicit cast now - tdd */ \
601 			SDL_blendPixel(surf, x, (int) ((B) + c), clr, (int)aa); \
602 		} \
603 	}
604 
605 	if ( !(flags & SDL_TG_ALPHA && alpha < 255) )
606 		alpha = 255;
607 
608 	/*
609 	 * sort points by X coordinate so we can split the drawing
610 	 * at a slope change
611 	 */
612 	while ( !(x1 <= x2 && x1 <= x3) ) {
613 		x = x1;
614 		y = y1;
615 		x1 = x2;
616 		y1 = y2;
617 		x2 = x3;
618 		y2 = y3;
619 		x3 = x;
620 		y3 = y;
621 	}
622 	while ( !(x2 <= x3) ) {
623 		x = x2;
624 		y = y2;
625 		x2 = x3;
626 		y2 = y3;
627 		x3 = x;
628 		y3 = y;
629 	}
630 
631 	xlen = x3 - x1;
632 	ylen = y3 - y1;
633 	slope1 = (float)ylen / xlen;
634 
635 	xlen = x1 - x2;
636 	ylen = y1 - y2;
637 	slope2 = (float)ylen / xlen;
638 
639 	xlen = x2 - x3;
640 	ylen = y2 - y3;
641 	slope3 = (float)ylen / xlen;
642 
643 	a1 = x1;
644 	a2 = x2;
645 	b1 = y1;
646 	b2 = y1;
647 	slopea = slope1;
648 	slopeb = slope2;
649 
650 	pb1 = b1;
651 	pb2 = b2;
652 
653 	if (flags & SDL_TG_LOCK)
654 		__SDL_PRIM_LOCKSURFACE(surf)
655 
656 	for (i = 0; i <= 1; i++) {
657 		if ((a1 == x1 && a1 != a2) || (a1 != x1 && a1 - 1 != a2)) {
658 		        /* Explicit cast now - tdd */
659 			for (x = (int) a1; x <= a2; x++) {
660 				if (flags & SDL_TG_FILL) {
661 					c = ((int)b1 < (int)b2) ? 1 : -1;
662 					for (y = (int)b1; (c > 0 ? y <= (int)b2 : y >= (int)b2); y += c) {
663 						if (alpha < 255)
664 							SDL_blendPixel(surf, x, y, clr, alpha);
665 						else
666 							SDL_putPixel(surf, x, y, clr);
667 					}
668 					if (flags & SDL_TG_ANTIALIAS) {
669 						__TRI_FILL_AA(pb1, b1, b2, slopea)
670 						__TRI_FILL_AA(pb2, b2, b1, slopeb)
671 					}
672 				}
673 				else {
674 					__TRI_DRAW(pb1, b1, slopea)
675 					__TRI_DRAW(pb2, b2, slopeb)
676 				}
677 				pb1 = b1;
678 				pb2 = b2;
679 
680 				b1 += slopea;
681 				b2 += slopeb;
682 			}
683 		} else if (!(flags & SDL_TG_FILL)) {
684 			if (a1 == x1)
685 				SDL_drawLine_TG(surf, x1,y1, x2,y2, clr, alpha, flags);
686 			else
687 				SDL_drawLine_TG(surf, x2,y2, x3,y3, clr, alpha, flags);
688 		}
689 
690 		a1 = x2 + 1;
691 		a2 = x3;
692 		b2 = y2;
693 		slopeb = slope3;
694 		b2 += slopeb;
695 	}
696 
697 	if (flags & SDL_TG_LOCK)
698 		__SDL_PRIM_UNLOCKSURFACE(surf)
699 }
700 
701 
702