]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/aaline.cpp
added _splitpath.
[taylor/freespace2.git] / src / graphics / aaline.cpp
1 /*
2  * $Logfile: /Freespace2/code/Graphics/aaline.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code to draw antialiased lines
8  *
9  * $Log$
10  * Revision 1.4  2002/06/09 03:16:04  relnev
11  * added _splitpath.
12  *
13  * removed unneeded asm, old sdl 2d setup.
14  *
15  * fixed crash caused by opengl_get_region.
16  *
17  * Revision 1.3  2002/05/28 08:52:03  relnev
18  * implemented two assembly stubs.
19  *
20  * cleaned up a few warnings.
21  *
22  * added a little demo hackery to make it progress a little farther.
23  *
24  * Revision 1.2  2002/05/07 03:16:45  theoddone33
25  * The Great Newline Fix
26  *
27  * Revision 1.1.1.1  2002/05/03 03:28:09  root
28  * Initial import.
29  *
30  * 
31  * 3     12/02/98 5:47p Dave
32  * Put in interface xstr code. Converted barracks screen to new format.
33  * 
34  * 2     10/07/98 10:52a Dave
35  * Initial checkin.
36  * 
37  * 1     10/07/98 10:48a Dave
38  * 
39  * 13    5/06/98 5:30p John
40  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
41  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
42  * DirectX header files and libs that fixed the Direct3D alpha blending
43  * problems.
44  * 
45  * 12    3/24/98 4:03p Lawrance
46  * JOHN: Fix up outline drawing code to support different colors
47  * 
48  * 11    3/10/98 4:18p John
49  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
50  * & Glide have popups and print screen.  Took out all >8bpp software
51  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
52  * support Fred.  Made zbuffering key off of functions rather than one
53  * global variable.
54  * 
55  * 10    1/19/98 6:15p John
56  * Fixed all my Optimized Build compiler warnings
57  * 
58  * 9     11/30/97 4:26p John
59  * Added 32-bpp antialiased line.   Took gamma out of alphacolor
60  * calculation.
61  * 
62  * 8     11/29/97 2:06p John
63  * added mode 16-bpp support
64  * 
65  * 7     10/20/97 8:47a John
66  * fixed gr_lock bug in aaline
67  * 
68  * 6     10/19/97 12:55p John
69  * new code to lock / unlock surfaces for smooth directx integration.
70  * 
71  * 5     10/14/97 8:08a John
72  * added a bunch more 16 bit support
73  * 
74  * 4     10/04/97 11:27a John
75  * took out debug code
76  * 
77  * 3     10/03/97 9:50a John
78  * enabled antialiasing lines in alphacolor set.
79  * 
80  * 2     10/03/97 9:10a John
81  * added better antialiased line drawer
82  * 
83  * 1     10/03/97 9:07a John
84  *
85  * $NoKeywords: $
86  */
87
88 /*
89
90  Code for drawing antialiased lines.  Taken from some code
91  published in the Journal of Graphic Tools at www.acm.org/jgt
92
93  Here is the README that came with the source code:
94
95         Sample code to draw antialiased lines as described in the Journal of
96         Graphic Tools article High Quality Hardware Line Antialiasing by
97         Scott R. Nelson of Sun Microsystems.
98
99         The code is written in C and designed to run on any machine with the
100         addition of a proper "display" module.  Currently, display modules
101         exist for Macintosh, Unix, and Wintel machines.  Thanks to Sanjay Gupta
102         (sanjay.gupta@eng.sun.com) for the Unix X11 display code and Chris
103         Babcock (babcock@rtp.idt.com) for the Windows code.
104
105         This code is not 100% bug free and is definitely not optimized for
106         performance.  It does, however, illustrate all of the points made in
107         the JGT article.
108 */
109
110
111 #include <stdio.h>
112 #include <stdlib.h>
113
114 #include "pstypes.h"
115 #include "2d.h"
116 #include "line.h"
117 #include "grinternal.h"
118 #include "palman.h"
119
120 // Convert from floating-point to internal fixed-point formats
121 #define ONE_XY                  (long int) 0x00100000
122 #define FIX_XY_SHIFT    (long int) 20
123 #define ONEHALF_XY      (long int) 0x00080000
124 #define ONE_Z                   (long int) 0x40000000
125 #define ONE_RGB         (long int) 0x40000000
126 #define ONE_16                  (long int) 0x4000
127
128 #define FLOAT_TO_FIX_XY(x)      ((long int) ((x) * (float) ONE_XY))
129
130 #define FLOAT_TO_FIX_RGB(x)     ((long int) ((x) * (float) ONE_RGB))
131 #define FLOAT_TO_FIX_16(x)      ((long int) ((x) * (float) ONE_16))
132 #define FIX_TO_INT_XY(x)        ((x) >> FIX_XY_SHIFT)
133 #define FIX_16_TO_FLOAT(x)      ((float) (x) / (float) ONE_16)
134 #define FIX_TO_FLOAT_XY(x)      ((float) (x) / (float) ONE_XY)
135 #define FIX_TO_FLOAT_RGB(x)     ((float) (x) / (float) ONE_RGB)
136
137 // Get fractional part, next lowest integer part
138 #define FRACT_XY(x)             ((x) & (long int) 0x000fffff)
139 #define FLOOR_XY(x)             ((x) & (long int) 0xfff00000)
140 #define FIX_XY_TO_INT(x)        ((long int) (x) >> (long int) FIX_XY_SHIFT)
141
142 // Sizes for tables in Draw
143 #define FILTER_WIDTH    0.75            // Line filter width adjustment // .75          // .5 works good with 5.0 gamma
144 #define F_TABLE_SIZE    64                      // Filter table size
145 #define SC_TABLE_SIZE   32              // Slope correction table size
146 #define SRT_INT         5                       // Sqrt table index integer bits
147 #define SRT_FRACT       4                               //   ...fraction bits
148 #define SR_INT          3                               // Square root result integer bits
149 #define SR_FRACT        5                               //   ...fraction bits
150 #define SR_TABLE_SIZE   (1 << (SRT_INT + SRT_FRACT))
151 #define INV_FILTER 47
152
153 #define EP_MASK (long int) 0x000f0000u  // AA line end-point filter mask
154 #define EP_SHIFT        13u                     // Number of bits to shift end-point
155
156
157 typedef long int fix_xy;        // S11.20
158
159 // One vertex at any of the various stages of the pipeline
160
161 typedef struct aa_vertex {
162         float x, y;
163 } aa_vertex;
164
165 // All values needed to draw one line
166 typedef struct aa_setup_line {
167         int x_major;
168         int negative;
169
170         fix_xy vs;                      // Starting point
171         fix_xy us;
172         fix_xy ue;                      // End (along major axis)
173         fix_xy dvdu;            // Delta for minor axis step
174
175 } aa_setup_line;
176
177
178 // Tables that need to be initialized
179 long int slope_corr_table[SC_TABLE_SIZE];
180 long int filter_table[F_TABLE_SIZE];
181 long int sqrt_table[SR_TABLE_SIZE];
182
183 ubyte new_table[F_TABLE_SIZE*512];
184
185 int aaline_inited = 0;
186
187 // Initialize the tables normally found in ROM in the hardware.
188 void aaline_init_tables()
189 {
190         int i,j;                                        // Iterative counter
191         double m;                               // Slope
192         double d;                               // Distance from center of curve
193         double v;                               // Value to put in table
194         double sr;                              //      The square root value
195
196         aaline_inited = 1;
197
198         // Build slope correction table.  The index into this table
199         // is the truncated 5-bit fraction of the slope used to draw
200         // the line.  Round the computed values here to get the closest
201         // fit for all slopes matching an entry.
202
203         for (i = 0; i < SC_TABLE_SIZE; i++) {
204                 // Round and make a fraction
205                 m = ((double) i + 0.5) / (float) SC_TABLE_SIZE;
206                 v = sqrt(m * m + 1) * 0.707106781; /* (m + 1)^2 / sqrt(2) */
207                 slope_corr_table[i] = (long int) (v * 256.0);
208         }
209
210         // Build the Gaussian filter table, round to the middle of the sample region.
211         for (i = 0; i < F_TABLE_SIZE; i++) {
212                 d = ((double) i + 0.5) / (float) (F_TABLE_SIZE / 2.0);
213                 d = d / FILTER_WIDTH;
214                 v = 1.0 / exp(d * d);           // Gaussian function
215                 filter_table[i] = (long int) (v * 256.0);
216         }
217
218         for ( i=0; i<512; i++ ) {
219                 long int corr_slope = i<<8;
220                 for (j=0; j<F_TABLE_SIZE; j++ ) {
221                         new_table[i*F_TABLE_SIZE+j] = (ubyte)(((corr_slope * filter_table[j]) & 0xf00000) >> (16+4));
222                         if (new_table[i*F_TABLE_SIZE+j]==15 )   {
223                                 // HACK!!! Account for "glass" pixel for hud bitmaps.
224                                 new_table[i*F_TABLE_SIZE+j] = 14;
225                         }
226                 }
227         }
228         
229
230         // Build the square root table for big dots.
231         for (i = 0; i < SR_TABLE_SIZE; i++) {
232                 v = (double) ((i << 1) + 1) / (double) (1 << (SRT_FRACT + 1));
233                 sr = sqrt(v);
234                 sqrt_table[i] = (long int) (sr * (double) (1 << SR_FRACT));
235         }
236
237
238 }
239
240
241
242 // Multiply a fixed-point number by a s11.20 fixed-point
243 // number.  The actual multiply uses less bits for the
244 // multiplier, since it always represents a fraction
245 // less than 1.0 and less total bits are sufficient.
246 // Some of the steps here are not needed.  This was originally
247 // written to simulate exact hardware behavior.
248 long int fix_xy_mult(long int oa, fix_xy ob)
249 {
250 #ifdef PLAT_UNIX
251         STUB_FUNCTION;
252
253         return 0;       
254 #else
255         int retval;
256         
257         _asm {
258                 mov     edx, oa
259                 mov     eax, ob
260                 imul    edx
261                 shrd    eax,edx,20
262                 mov     retval, eax
263         }
264         
265         return retval;
266 #endif
267 }
268
269
270
271 // Draw one span of an antialiased line (for horizontal lines).
272 void draw_aa_hspan8(fix_xy x, fix_xy y, long int ep_corr, long int slope)
273 {
274 #ifndef HARDWARE_ONLY
275         long int sample_dist;           // Distance from line to sample point
276         long int filter_index;          // Index into filter table
277         long int i;                                             // Count pixels across span
278         long int index;                         // Final filter table index
279         int a;                                                  // Alpha
280
281         sample_dist = (FRACT_XY(y) >> (FIX_XY_SHIFT - 5)) - 16;
282         y = y - ONE_XY;
283         filter_index = sample_dist + 32;
284
285
286         int yi = FIX_XY_TO_INT( y );
287         int xi = FIX_XY_TO_INT( x );
288
289         if ( xi < gr_screen.clip_left ) return;
290         if ( xi > gr_screen.clip_right ) return;
291
292         int clipped = 0;
293         
294         if ( yi < gr_screen.clip_top ) clipped++;
295         if ( yi+3 > gr_screen.clip_bottom ) clipped++;
296
297         long int corr_slope = (slope * ep_corr) & 0x1ff00;
298
299         ubyte * lookup = (ubyte *)&Current_alphacolor->table.lookup[0][0];
300
301         ubyte * filter_lookup = (ubyte *)&new_table[(corr_slope>>8)*F_TABLE_SIZE];
302
303
304         if ( clipped )  {
305                 ubyte * dptr;
306                 
307                 for (i = 0; i < 4; i++) {
308                         if (filter_index < 0)
309                                 index = ~filter_index;  // Invert when negative
310                         else
311                                 index = filter_index;
312
313                         if (index > INV_FILTER) {
314                                 Assert( i == 3 );
315                                 return;                 // Not a valid pixel
316                         }
317
318                         //a = ((corr_slope * filter_table[index]) & 0xf00000) >> (16+4-8);
319                         a = filter_lookup[index]<<8;
320
321                         // Should include the alpha value as well...
322                         if ( (yi >= gr_screen.clip_top) && (yi <= gr_screen.clip_bottom) )      {
323                                 dptr = GR_SCREEN_PTR(ubyte,xi, yi);
324
325                                 *dptr = lookup[*dptr+a];
326                         }
327
328                         filter_index -= 32;
329                         //y += ONE_XY;
330                         yi++;
331                 }
332         } else {
333                 ubyte * dptr;
334
335                 dptr = GR_SCREEN_PTR(ubyte,xi, yi);
336         
337                 for (i = 0; i < 4; i++) {
338                         if (filter_index < 0)
339                                 index = ~filter_index;  // Invert when negative
340                         else
341                                 index = filter_index;
342
343                         if (index > INV_FILTER) {
344                                 Assert( i == 3 );
345                                 return;                 // Not a valid pixel
346                         }
347
348                         a = filter_lookup[index]<<8;
349
350                         // Should include the alpha value as well...
351                         *dptr = lookup[*dptr+a];
352
353                         dptr += gr_screen.rowsize;
354
355                         filter_index -= 32;
356                 }
357
358
359         }
360 #else
361         Int3();
362 #endif
363 }
364
365 // draw_aa_vspan
366 // Draw one span of an antialiased line (for vertical lines).
367
368 void draw_aa_vspan8(fix_xy x, fix_xy y, long int ep_corr, long int slope)
369 {
370 #ifndef HARDWARE_ONLY
371         long int sample_dist;           // Distance from line to sample point
372         long int filter_index;          // Index into filter table 
373         long int i;                                             // Count pixels across span
374         long int index;                         // Final filter table index
375         int a;                                                  // Alpha
376
377         sample_dist = (FRACT_XY(x) >> (FIX_XY_SHIFT - 5)) - 16;
378         x = x - ONE_XY;
379         filter_index = sample_dist + 32;
380
381         int yi = FIX_XY_TO_INT( y );
382         int xi = FIX_XY_TO_INT( x );
383
384         if ( yi < gr_screen.clip_top ) return;
385         if ( yi > gr_screen.clip_bottom ) return;
386
387         int clipped = 0;
388         
389         if ( xi < gr_screen.clip_left ) clipped++;
390         if ( xi+3 > gr_screen.clip_right ) clipped++;
391
392         long int corr_slope = (slope * ep_corr) & 0x1ff00;
393
394         ubyte * lookup = (ubyte *)&Current_alphacolor->table.lookup[0][0];
395
396         ubyte * filter_lookup = (ubyte *)&new_table[(corr_slope>>8)*F_TABLE_SIZE];
397
398
399         if ( clipped )  {
400                 ubyte * dptr;
401
402                 for (i = 0; i < 4; i++) {
403                         if (filter_index < 0)
404                                 index = ~filter_index;  // Invert when negative
405                         else
406                                 index = filter_index;
407
408                         if (index > INV_FILTER) {
409                                 Assert( i == 3 );
410                                 return;                 // Not a valid pixel
411                         }
412
413                         //a = ((corr_slope * filter_table[index]) & 0xf00000) >> (16+4-8);
414                         a = filter_lookup[index]<<8;
415
416                         // Draw the pixel
417                         if ( (xi >= gr_screen.clip_left) && (xi <= gr_screen.clip_right) )      {
418                                 dptr = GR_SCREEN_PTR(ubyte,xi, yi);
419
420                                 *dptr = lookup[*dptr+a];
421                         }
422
423                         filter_index -= 32;
424                         xi++;
425                 }
426         } else {
427
428                 ubyte *dptr = GR_SCREEN_PTR(ubyte,xi, yi);
429
430                 for (i = 0; i < 4; i++) {
431                         if (filter_index < 0)
432                                 index = ~filter_index;  // Invert when negative
433                         else
434                                 index = filter_index;
435
436                         if (index > INV_FILTER) {
437                                 Assert( i == 3 );
438                                 return;                 // Not a valid pixel
439                         }
440
441                         a = filter_lookup[index]<<8;
442
443                         // Should include the alpha value as well...
444
445                         // Draw the pixel
446                         *dptr = lookup[*dptr+a];
447
448                         filter_index -= 32;
449                         dptr++;
450                 }
451         }
452 #else
453         Int3();
454 #endif
455 }
456
457
458 void draw_line(aa_setup_line *line)
459 {
460         fix_xy x, y;                                    //  Start value
461         fix_xy dudu;                                    //  Constant 1 or -1 for step
462         fix_xy dx, dy;                                  //  Steps in X and Y
463         fix_xy u_off;                                   //  Offset to starting sample grid
464         fix_xy us, vs, ue;                      //  Start and end for drawing
465         fix_xy count;                                   //  How many pixels to draw
466         long int slope_index;           //  Index into slope correction table
467         long int slope;                         //  Slope correction value
468         long int ep_corr;                               //  End-point correction value
469         long int scount, ecount;        //  Start/end count for endpoints
470         long int sf, ef;                                //  Sand and end fractions
471         long int ep_code;                               //  One of 9 endpoint codes
472
473         // Get directions
474         if (line->negative)     {
475                 dudu = -ONE_XY;
476         } else {
477                 dudu = ONE_XY;
478         }
479
480         if (line->x_major) {
481                 dx = dudu;
482                 dy = line->dvdu;
483         } else {
484                 dx = line->dvdu;
485                 dy = dudu;
486         }
487
488         // Get initial values and count
489         if (line->negative) {
490                 u_off = FRACT_XY(line->us) - ONE_XY;
491                 us = line->us + ONE_XY;
492                 ue = line->ue;
493                 count = FLOOR_XY(us) - FLOOR_XY(ue);
494         } else {
495                 u_off = 0 - FRACT_XY(line->us);
496                 us = line->us;
497                 ue = line->ue + ONE_XY;
498                 count = FLOOR_XY(ue) - FLOOR_XY(us);
499         }
500
501         vs = line->vs + fix_xy_mult(line->dvdu, u_off) + ONEHALF_XY;
502
503         if (line->x_major) {
504                 x = us;
505                 y = vs;
506         } else {
507                 x = vs;
508                 y = us;
509         }
510
511         //a = line->as + fix_xy_mult(line->dadu, u_off);
512
513         // Compute slope correction once per line
514         slope_index = (line->dvdu >> (FIX_XY_SHIFT - 5)) & 0x3fu;
515
516         if (line->dvdu < 0)     {
517                 slope_index ^= 0x3fu;
518         }
519
520         if ((slope_index & 0x20u) == 0) {
521                 slope = slope_corr_table[slope_index];
522         } else {
523                 slope = 0x100;          /* True 1.0 */
524         }
525
526         // Set up counters for determining endpoint regions
527         scount = 0;
528         ecount = FIX_TO_INT_XY(count);
529
530         // Get 4-bit fractions for end-point adjustments
531         sf = (us & EP_MASK) >> EP_SHIFT;
532         ef = (ue & EP_MASK) >> EP_SHIFT;
533
534         // Interpolate the edges
535         while (count >= 0) {
536
537                 /*-
538                 * Compute end-point code (defined as follows):
539                 *  0 =  0, 0: short, no boundary crossing
540                 *  1 =  0, 1: short line overlap (< 1.0)
541                 *  2 =  0, 2: 1st pixel of 1st endpoint
542                 *  3 =  1, 0: short line overlap (< 1.0)
543                 *  4 =  1, 1: short line overlap (> 1.0)
544                 *  5 =  1, 2: 2nd pixel of 1st endpoint
545                 *  6 =  2, 0: last of 2nd endpoint
546                 *  7 =  2, 1: first of 2nd endpoint
547                 *  8 =  2, 2: regular part of line
548                 */
549
550                 ep_code = ((scount < 2) ? scount : 2) * 3 + ((ecount < 2) ? ecount : 2);
551
552                 if (line->negative) {
553
554                         // Drawing in the negative direction
555
556                         // Compute endpoint information
557                         switch (ep_code) {
558                                 case 0: ep_corr = 0;                                                                    break;
559                                 case 1: ep_corr = ((sf - ef) & 0x78) | 4;               break;
560                                 case 2: ep_corr = sf | 4;                                                       break;
561                                 case 3: ep_corr = ((sf - ef) & 0x78) | 4;               break;
562                                 case 4: ep_corr = ((sf - ef) + 0x80) | 4;               break;
563                                 case 5: ep_corr = (sf + 0x80) | 4;                              break;
564                                 case 6: ep_corr = (0x78 - ef) | 4;                              break;
565                                 case 7: ep_corr = ((0x78 - ef) + 0x80) | 4;     break;
566                                 case 8: ep_corr = 0x100;                                                        break;
567                                 default:        ep_corr = 0;                                                            break;  
568                         }
569
570                 } else {
571                         // Drawing in the positive direction
572
573                         // Compute endpoint information
574                         switch (ep_code) {
575                                 case 0: ep_corr = 0;                                                                    break;
576                                 case 1: ep_corr = ((ef - sf) & 0x78) | 4;               break;
577                                 case 2: ep_corr = (0x78 - sf) | 4;                              break;
578                                 case 3: ep_corr = ((ef - sf) & 0x78) | 4;               break;
579                                 case 4: ep_corr = ((ef - sf) + 0x80) | 4;               break;
580                                 case 5: ep_corr = ((0x78 - sf) + 0x80) | 4;     break;
581                                 case 6: ep_corr = ef | 4;                                                       break;
582                                 case 7: ep_corr = (ef + 0x80) | 4;                              break;
583                                 case 8: ep_corr = 0x100;                                                        break;
584                                 default:        ep_corr = 0;                                                            break;  
585                         } 
586                 }
587
588                 if (line->x_major)      {
589                         draw_aa_hspan8(x, y, ep_corr, slope);
590                 } else  {
591                         draw_aa_vspan8(x, y, ep_corr, slope);
592                 }
593
594                 x += dx;
595                 y += dy;
596                 //a += line->dadu;
597
598                 scount++;
599                 ecount--;
600                 count -= ONE_XY;
601         }
602
603 }
604
605
606 // Perform the setup operation for a line, then draw it
607
608 void aaline_setup(aa_vertex *v1, aa_vertex *v2)
609 {
610         float dx, dy;                   // Deltas in X and Y
611         float udx, udy;         // Positive version of deltas
612         float one_du;                   // 1.0 / udx or udy
613         aa_setup_line line;
614
615         if ( !aaline_inited )
616                 aaline_init_tables();
617
618
619         dx = v1->x - v2->x;
620         dy = v1->y - v2->y;
621
622         if (dx < 0.0)   {
623                 udx = -dx;
624         } else  {
625                 udx = dx;
626         }
627
628         if (dy < 0.0)   {
629                 udy = -dy;
630         } else  {
631                 udy = dy;
632         }
633
634         if (udx > udy) {
635                 // X major line
636                 line.x_major = 1;
637                 line.negative = (dx < 0.0);
638                 line.us = FLOAT_TO_FIX_XY(v2->x);
639                 line.vs = FLOAT_TO_FIX_XY(v2->y);
640                 line.ue = FLOAT_TO_FIX_XY(v1->x);
641                 one_du = 1.0f / udx;
642                 line.dvdu = FLOAT_TO_FIX_XY(dy * one_du);
643         } else {
644                 // Y major line
645                 line.x_major = 0;
646                 line.negative = (dy < 0.0);
647                 line.us = FLOAT_TO_FIX_XY(v2->y);
648                 line.vs = FLOAT_TO_FIX_XY(v2->x);
649                 line.ue = FLOAT_TO_FIX_XY(v1->y);
650                 one_du = 1.0f / udy;
651                 line.dvdu = FLOAT_TO_FIX_XY(dx * one_du);
652         }
653
654         // Convert colors to fixed-point
655         //line.as = FLOAT_TO_FIX_RGB(v2->a);
656
657         // Compute delta values for colors
658         //line.dadu = FLOAT_TO_FIX_RGB((v1->a - v2->a) * one_du);
659
660         // Now go draw it
661
662         gr_lock();
663         draw_line(&line);
664         gr_unlock();
665 }
666
667
668 void gr8_aaline( vertex *v1, vertex *v2 )
669 {
670         aa_vertex aa1, aa2;
671
672         if ( !Current_alphacolor ) {
673                 gr_line(fl2i(v1->sx),fl2i(v1->sy),fl2i(v2->sx),fl2i(v2->sy));
674                 return;
675         }
676
677 //      return;
678
679         aa1.x = v1->sx;
680         aa1.y = v1->sy;
681
682         aa2.x = v2->sx;
683         aa2.y = v2->sy;
684
685         {
686                 int clipped = 0, swapped = 0;
687                 float a1, b1, a2, b2;
688                 a1 = (float)gr_screen.clip_left;
689                 b1 = (float)gr_screen.clip_top;
690                 a2 = (float)gr_screen.clip_right;
691                 b2 = (float)gr_screen.clip_bottom;
692
693                 FL_CLIPLINE(aa1.x,aa1.y,aa2.x,aa2.y,a1,b1,a2,b2,return,clipped=1,swapped=1);
694         }
695
696         aaline_setup( &aa1, &aa2 );
697 }
698