My current prototype uses floating point arithmetic. For y>0 I check if each end of the line's y component is negative and if so use linear interpolation to bring it up to y=0. For y>x and y>-x I substituted y=x or y=-x into y=mx+c to produce a simple calculation to clip the line.
Here's an early version for Evaldraw.
// Stores the line position.static x1=-50,y1=100,x2=50,y2=100;// Are we holding either end?static end_held = 0;()cls(0);// Get the screen centre and maximum dimension.cx=xres/2;cy=yres/2;mres=max(xres,yres);// Draw the unclipped line.setcol(0x111111);moveto(cx+x1,cy+y1);lineto(cx+x2,cy+y2);// Draw the axes and clipping regions.setcol(0x333333);moveto(cx-mres,cy);lineto(cx+mres,cy);moveto(cx-mres,cy-mres);lineto(cx+mres,cy+mres);moveto(cx-mres,cy+mres);lineto(cx+mres,cy-mres);setcol(0xFFFFFF);moveto(cx,cy);lineto(cx+mres,cy+mres);moveto(cx,cy);lineto(cx-mres,cy+mres);// Order so x1<=x2x1c=x1;y1c=y1;x2c=x2;y2c=y2;// Set this to non-zero if the line has been culled.culled=0;if (y1 < 0 && y2 < 0) { culled = 1;} else { // Clip against Y=0. if (y1c < 0) { x1c = x1c - (x2c - x1c) * (y1c / (y2c - y1c)); y1c = 0; } if (y2c < 0) { x2c = x2c - (x2c - x1c) * (y2c / (y2c - y1c)); y2c = 0; } // "Out of right bounds" (Y=+X). or1 = x1c > y1c; or2 = x2c > y2c; // "Out of left bounds" (Y=-X). ol1 = x1c < -y1c; ol2 = x2c < -y2c; if (or1 && or2 || ol1 && ol2) { culled = 1; } else { if (ol1) { // Clip 1 to Y=-X. c = x1c - (x2c - x1c) * (y1c / (y2c - y1c)); m = (x2 - x1) / (y2 - y1); x1c = c / (m + 1); y1c = -x1c; } if (ol2) { // Clip 2 to Y=-X. c = x2c - (x2c - x1c) * (y2c / (y2c - y1c)); m = (x2 - x1) / (y2 - y1); x2c = c / (m + 1); y2c = -x2c; } if (or1) { // Clip 1 to Y=+X c = x1c - (x2c - x1c) * (y1c / (y2c - y1c)); m = (x2 - x1) / (y2 - y1); x1c = -c / (m - 1); y1c = x1c; } if (or2) { // Clip 2 to Y=+X c = x2c - (x2c - x1c) * (y2c / (y2c - y1c)); m = (x2 - x1) / (y2 - y1); x2c = -c / (m - 1); y2c = x2c; } }}// Draw the clipped line.if (culled == 0) { setcol(0x00FF00); moveto(cx+x1c,cy+y1c);lineto(cx+x2c,cy+y2c);}// Update the line position using the mouse.setcol(0xFF0000);mx = mousx - cx;my = mousy - cy;p1 = (x1-mx)*(x1-mx)+(y1-my)*(y1-my);p2 = (x2-mx)*(x2-mx)+(y2-my)*(y2-my);if (end_held == 1) { p1 = 0;} else if (end_held == 2) { p2 = 0;}if (p1 < p2) { if (p1 < 64) { drawsph(x1+cx, y1+cy, -10); if (bstatus) { end_held = 1; x1 = mx; y1 = my; } else { end_held = 0; } }} else { if (p2 < 64) { drawsph(x2+cx, y2+cy, -10); if (bstatus) { end_held = 2; x2 = mx; y2 = my; } else { end_held = 0; } }}
Unfortunately, I intend to transfer this code to a machine that does not support hardware multiplication, division or floating-point arithmetic. I am currently converting it to use fixed-point arithmetic with a variety of workarounds, such as different code paths if the line is steep or shallow. In the interest of improving performance I'd be interested to hear if anyone had any suggestions for an integer-only technique, preferably one that minimises the number of multiplication or division operations.