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