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