        .width    132
        .title    'horizon fill'

*----------------------------------------------------------------------
*                                    TIGA
*          Copyright (C) 1989-1990  Texas Instruments Incorporated.
*                            All Rights Reserved
*----------------------------------------------------------------------
* horizon0 and horizon1 functions
*
*   These two functions draw the horizon as seen from the cockpit of a
*   moving aircraft.  The mathematical model used assumes that the
*   horizon is at infinity.  With this model, the distance rh from the
*   vanishing point to the nearest point on the horizon is calculated as
*              rh = view_dist * sin(-pitch) / cos(-pitch)
*   where view_dist is the second argument, and represents the viewer's
*   assumed distance from the screen.  The legal range of view_dist is
*   0 to 2047.
*
*   The horizon0 and horizon1 functions are nearly identical.  Whereas
*   the horizon0 function attempts to represent the horizon line
*   exactly, the horizon1 function adds a couple of scan lines to the
*   position of the horizon (moving the earth's horizon a couple of
*   lines further toward the sky).  The extra padding added to the
*   horizon by the horizon1 function is necessary to prevent narrow
*   strips of sky from being visible beneath distant objects lying flat
*   on the ground where the jaggies of the horizon line beat against the
*   jaggies of the flat bottom of the objects.
*
*   The first argument is a pointer to a structure containing the cosine
*   and sine of the yaw, pitch and roll angles.  Each value is a 32-bit
*   fixed-point number with 30 bits of fraction.  The structure is
*   organized as follows:
*       typedef struct {
*           long csyaw, snyaw;   /* cos(yaw angle), sin(yaw angle)    */
*           long cspch, snpch;   /* cos(pitch angle), sin(pitch angle)*/
*           long csrol, snrol;   /* cos(roll angle), sin(roll angle)  */
*       } VUPARAMS
*
*   The last two arguments, gnd and sky, are the colors specified for
*   the ground and sky, respectively.  The function assumes that the
*   pixel value has been replicated throughout the 32-bit integer value,
*   and that the color arguments are in a form that can be loaded
*   directly into the COLOR1 register (B9).
*
*   A global structure "vpclip" provides information regarding the size
*   and position of the viewport, and the viewer's assumed distance from
*   the screen for perspective calculations.  The structure is organized
*   as follows:
*       typedef struct {
*           short d;            /* viewer's distance from screen    */
*           short znear;        /* z value at "near" clipping plane */
*           short scale[2];     /* viewport half width, half height */
*           short center[2];    /* viewport center coordinates      */
*           long k[2];          /* clipping normalization factors   */
*           long *buf[2];       /* pointers to temp. buffers        */
*           short rdiag;        /* viewport half diagonal length    */
*       } CLIPVALS;
*   The horizon function uses the d, scale, center and rdiag fields.
*   The d field is the viewer's assumed distance from the screen.  The
*   scale array contains the half width Sx and half height Sy of the
*   viewport.  The center array contains the x and y coordinates Cx and
*   Cy of the center of the viewport with respect to the top left corner
*   of the screen.  The rdiag field contains the radius of the minimum
*   circle containing the screen, and is half the length of the viewport
*   diagonal.
*----------------------------------------------------------------------
* Usage:  horizon0(gnd, sky);
*         horizon1(gnd, sky);
*
* Stack arguments:
*     long sky, gnd;    /* colors for sky and ground */
*
* Value returned in A8:  void (undefined)
*
* Registers altered:  A8
*----------------------------------------------------------------------
* Revision history:
*   03/21/89...Original version written..................Jerry Van Aken
*   09/28/90...Modified to use 34020 VFILL......M. Asal and J. Van Aken
*   10/01/90...support for device independence..........Jeffrey Ort
*----------------------------------------------------------------------
;
;
;
         .include    gsptypes.inc
         .include    gspglobs.inc
         .include    gspreg.inc

VFILLL:	 $macro
         move     @_config+CONFIG_DEVICE_REV, B14
         btst     REV_34010,B14
         jreq     IS_34020?
         fill     XY
         jruc     endfill?
IS_34020?:
         vlcol
         clrc
         clip
         jrz      endfill?
	     cvdxyl   B2
         vfill	  L
endfill?:
	    $endm
;
;     DECLARE GLOBAL FUNCTION NAME
;
        .globl    _horizon0           ;compensation constant = 0
        .globl    _horizon1           ;compensation constant = 1
;
;
;     DECLARE EXTERNAL GLOBALS
;
        .globl    _vpclip             ;viewport clipping parameters
        .globl    _vuparams           ;sin/cos of yaw/pitch/roll
;
;
;     DEFINE CONSTANTS
;
        .nolist
        .copy     "fly3d.inc"         ;define flight sim. structures
        .list
;
;
;     ENTRY POINTS
;
_horizon0:
        CLR       A8                  ;compensation constant = 0
        JRUC      HORIZON             ;

_horizon1:
        MOVK      32,A8               ;compensation constant = 2

HORIZON:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        MMTM      SP,B0,B1,B2,B4,B5,B6,B7,B8,B10,B11,B12,B13,B14
* Pop both arguments off the parameter stack.
        MOVE      *-A14,A2,1          ;get gnd argument
        MOVE      *-A14,A3,1          ;get sky argument
* Point to structure containing sin(yaw), cos(yaw), sin(pitch),
* cos(pitch), sin(roll) and cos(roll).
        MOVI      _vuparams,A0        ;get pointer to vuparams struct
* Load x, y displacements of xy origin from top left corner of screen.
        MOVE      @_vpclip+CX,B8,1    ;CX in 16 LSBs, CY in 16 MSBs
* Set window clipping rectangle to specified viewport.
        MOVE      @_vpclip+SX,B6,1    ;SX in 16 LSBs, SY in 16 MSBs
        MOVE      B8,B5               ;copy xyorigin
        SUBXY     B6,B5               ;WSTART = y0-SY::x0-SX
        MOVI      -1,B1               ;
        ADDXY     B1,B6               ;
        ADDXY     B8,B6               ;WEND = y0+SY-1::x0+SX-1
* Extract the sines and cosines of the pitch and roll angles.
        MOVE      *A0(SNPCH),A4,1     ;
        NEG       A4                  ;sin(-pitch)
        MOVE      *A0(CSPCH),A5,1     ;cos(-pitch)
        MOVE      *A0(SNROL),A6,1     ;
        NEG       A6                  ;sin(-roll)
        MOVE      *A0(CSROL),A7,1     ;cos(-roll)
* Get viewer's assumed distance from screen for perspective.
        SETF      16,1,0              ;
        MOVE      @_vpclip+D,A1,0     ;get view_dist argument
* Calculate rh = distance from vanishing point to horizon.
        MOVE      A4,A0               ;copy sin(-pitch)
        SLL       4,A1                ;view_dist << 4
        MPYS      A1,A0               ;temp = view_dist * sin(-pitch)
        DIVS      A5,A0               ;rh = temp / cos(-pitch)
        JRV       H1                  ;jump if horizon not visible
* Add compensation factor.
        ADD       A8,A0               ;
* Is horizon too far from vanishing point to be visible on screen?
        MOVE      A0,A8               ;copy rh
        ABS       A8                  ;abs(rh)
        SETF      16,1,1              ;
        MOVE      @_vpclip+RDIAG,A9,0 ;radius of circle enclosing screen
        SLL       4,A9                ;rhmax << 4
        CMP       A8,A9               ;|rh| > rhmax ? (invisible?)
        JRNN      H3                  ;jump if |rh| <= rhmax (visible)
* Horizon invisible.  Entire screen is either sky or ground, but which?
H1:
        MOVE      A2,B9               ;COLOR1 = gnd (color of ground)
        MOVE      A4,A4               ;is sin(-pitch) >= 0 ?
        JRNN      H2                  ;jump if sin(-pitch) >= 0
        MOVE      A3,B9               ;COLOR1 = sky (color of sky)
H2:
        MOVX      B9,B7               ;
        SLL       16,B7               ;
        MOVY      B7,B9               ;replicate color to 32 bits

        MOVI      40004000h,B7        ;DYDX = entire window
        CLR       B2                  ;DADDR = upper left corner of crt
;        FILL      XY                  ;fill entire window with COLOR1

        VFILLL
        JRUC      DONE                ;exit
* If aircraft flying upside down, swap sky and ground colors.
H3:
        MOVE      A2,B0               ;botcolor = gnd
        MOVE      A3,B1               ;topcolor = sky
        MOVE      A7,A11              ;copy cos(-roll)
        JRGT      H4                  ;jump if aircraft is rightside up

        MOVE      A3,B0               ;botcolor = sky
        MOVE      A2,B1               ;topcolor = gnd
H4:
        MOVX      B0,B9               ;
        SLL       16,B9               ;
        MOVY      B9,B0               ;replicate botcolor to 32 bits
        MOVX      B1,B9               ;
        SLL       16,B9               ;
        MOVY      B9,B1               ;replicate topcolor to 32 bits

        SLL       16,A0               ;rh --> fixed pt with 20-bit frac
* Calculate y intercepts of horizon with left and right window edges.
        MOVE      @_vpclip+SX,A2,1    ;xmax = right edge of window
        MOVE      A2,A1               ;
        NEG       A1                  ;xmin = left edge of windoww
        MOVE      A6,A11              ;copy sin(-roll)
        NEG       A11                 ;-sin(-roll)
        SRA       10,A11              ;-sin(-roll) >> 10
        MOVE      A11,A13             ;copy -sin(-roll) >> 10
        MPYS      A1,A11              ;-xmin*(sin(-roll)>>10)
        ADD       A0,A11              ;rh-xmin*(sin(-roll)>>10)
        MPYS      A2,A13              ;-xmax*(sin(-roll)>>10)
        ADD       A0,A13              ;rh-xmax*(sin(-roll)>>10)
        MOVE      A7,A4               ;copy cos(-roll)
        SRA       14,A4               ;cos(-roll)>>14
        DIVS      A4,A11              ;y_xmin=(rh-xmin*sin(-roll))/cos(-roll)
        DIVS      A4,A13              ;y_xmax=(rh-xmax*sin(-roll))/cos(-roll)
* Calculate x intercepts of horizon with top and bottom window edges.
        MOVE      @_vpclip+SX,A4,1    ;ymax = right edge of window
        MOVE      A4,A3               ;
        NEG       A3                  ;ymin = left edge of windoww
        MOVE      A7,A5               ;copy cos(-roll)
        NEG       A5                  ;-cos(-roll)
        SRA       10,A5               ;-cos(-roll) >> 10
        MOVE      A5,A9               ;copy -cos(-roll) >> 10
        MPYS      A3,A5               ;-ymin*(cos(-roll)>>10)
        ADD       A0,A5               ;rh-ymin*(cos(-roll)>>10)
        MPYS      A4,A9               ;-ymax*(cos(-roll)>>10)
        ADD       A0,A9               ;rh-ymax*(cos(-roll)>>10)
        MOVE      A6,A8               ;copy sin(-roll)
        SRA       14,A8               ;sin(-roll)>>14
        DIVS      A8,A5               ;x_ymin=(rh-ymin*cos(-roll))/sin(-roll)
        DIVS      A8,A9               ;x_ymax=(rh-ymax*cos(-roll))/sin(-roll)
* Copy horizon x and y intercepts with window to registers A11-A14.
        MOVE      A13,A14             ;copy y_xmax (y at x = xmax)
        MOVE      A11,A13             ;copy y_xmin (y at x = xmin)
        MOVE      A9,A12              ;copy x_ymax (x at y = ymax)
        MOVE      A5,A11              ;copy x_ymin (x at y = ymin)
* Calculate dx/dy (inverse slope of horizon).
        MOVE      A6,A8               ;copy sin(-roll)
        MOVE      A7,A9               ;copy cos(-roll)
        NEG       A9                  ;-cos(-roll)
        SRA       16,A8               ;sin(-roll)>>16
        DIVS      A8,A9               ;deltax = -cos(-roll)/sin(-roll)
        MOVE      A9,A0               ;copy deltax
* Convert xmin, xmax, ymin, ymax to fixed point with 4-bit fraction.
        SLL       4,A1                ;xmin<<4
        SLL       4,A2                ;xmax<<4
        SLL       4,A3                ;ymin<<4
        SLL       4,A4                ;ymax<<4
* Determine whether slope of horizon is positive or negative.
        ABS       A6                  ;absolute value of sin(-roll)
        JRNN      NEGSIN              ;jump if sin(-roll) < 0
        ABS       A7                  ;absolute value of cos(-roll)
        JRN       NEGSLOPE            ;if cos(-roll)>=0, slope is neg.
        JRUC      POSSLOPE            ;otherwise slope is positive
NEGSIN:
        ABS       A7                  ;absolute value of cos(-roll)
        JRNN      NEGSLOPE            ;jump if cos(-roll)<0 (slope neg.)
* Horizon's slope is positive.  Is horizon more vertical or horizontal?
POSSLOPE:
        CMP       A6,A7               ;is |sin(-roll)| <= |cos(-roll)| ?
        JRN       MOREVERT1           ;jump if |sin(-roll)|>|cos(-roll)|
* Slope more horizontal.  Does horizon intercept window at top or right?
        CMP       A14,A4              ;is y_xmax > ymax ?
        JRNN      H6                  ;jump if y_xmax <= ymax
* Horizon intercepts top edge of window.
        MOVE      A12,A6              ;copy x_ymax
        SLL       12,A6               ;x_ymax << 12
        ADDI      07FFFh,A6           ;(x_ymax<<12)+7FFF
        MOVE      A0,A7               ;copy deltax
        SRA       1,A7                ;deltax/2
        SUB       A7,A6               ;x = (x_ymax<<12)+7FFF-deltax/2
        MOVE      A4,A7               ;copy ymax
        SRA       4,A7                ;y = ymax>>4
        JRUC      H7                  ;
* Horizon intercepts right edge of window.
H6:
        MOVE      A14,A7              ;copy y_xmax
        ADDK      8,A7                ;y_xmax+8
        MOVE      A7,A9               ;save copy of y_xmax+8
        SRA       4,A7                ;y = y_xmax+8 >> 4
        MOVE      A2,A6               ;xmax
        SLL       12,A6               ;xmax<<12
        ADDI      07FFFh,A6           ;(xmax<<12)+7FFF
        MOVE      A7,A8               ;copy y
        SLL       4,A8                ;y<<4
        SUB       A8,A9               ;y_xmax+8-(y<<4)
        MPYS      A0,A9               ;(y_xmax+8-(y<<4))*deltax
        SRA       4,A9                ;temp = y_xmax+8-(y<<4))*deltax>>4
        SUB       A9,A6               ;x = (xmax<<12)+7FFF-temp
        MOVE      B1,B9               ;COLOR1 = topcolor
        MOVE      A4,A10              ;copy ymax
        SRA       4,A10               ;ymax>>4
        SUB       A7,A10              ;ymax-y
        SLL       16,A10              ;move ymax-y to 16 MSBs
        MOVE      @_vpclip+SX,A9,1    ;get viewport half width SX
        ADD       A9,A9               ;viewport width = 2*SX
        MOVX      A9,A10              ;
        MOVE      A10,B7              ;DY = ymax-y, DX = wide
        SLL       12,A4               ;shift ymax into 16 LSBs
        NEG       A4                  ;-ymax
        MOVE      A1,A8               ;copy xmin
        SRA       4,A8                ;
        MOVX      A8,A4               ;concatenate -ymax with xmin
        MOVE      A4,B2               ;DADDR = -ymax:xmin
        ADDXY     B8,B2               ;convert DADDR to screen coord's
   ;     FILL      XY                  ;fill top portion of window
        VFILLL
* Does horizon intercept window bottom or left edge?
H7:
        MOVE      A13,A9              ;copy y_xmin (assume left edge)
        ADDK      8,A9                ;y_xmin+8
        SRA       4,A9                ;y_xmin+8 >> 4
        MOVE      A7,A8               ;copy y
        SUB       A9,A8               ;ycount = y - (y_xmin+8 >> 4)
        SRA       4,A3                ;ymin>>4
        SUB       A3,A9               ;h = (y_xmin+8 >> 4) - ymin
        JRNN      HORIZ1              ;jump if h >= 0 (WAS left edge!)
        ADD       A9,A8               ;ycount += h (oops!--bottom edge)
        CLR       A9                  ;h = 0
        JRUC      HORIZ1              ;
* Slope more vertical.  Does horizon intercept window at top or right?
MOREVERT1:
        CMP       A12,A2              ;is x_ymax <= xmax ?
        JRN       H9                  ;jump if x_ymax > xmax
* Horizon intercepts top edge of window.
        MOVE      A12,A6              ;copy x_ymax
        SLL       12,A6               ;x_ymax << 12
        ADDI      07FFFh,A6           ;(x_ymax<<12)+7FFF
        MOVE      A0,A7               ;copy deltax
        SRA       1,A7                ;deltax/2
        SUB       A7,A6               ;x = (x_ymax<<12)+7FFF-deltax/2
        MOVE      A4,A7               ;copy ymax
        SRA       4,A7                ;y = ymax>>4
        JRUC      H10                 ;
* Horizon intercepts right edge of window.
H9:
        MOVE      A14,A7              ;copy y_xmax
        ADDK      8,A7                ;y_xmax+8
        MOVE      A7,A9               ;save copy of y_xmax+8
        SRA       4,A7                ;y = y_xmax+8 >> 4
        MOVE      A2,A6               ;xmax
        SLL       12,A6               ;xmax<<12
        ADDI      07FFFh,A6           ;(xmax<<12)+7FFF
        MOVE      A7,A8               ;copy y
        SLL       4,A8                ;y<<4
        SUB       A8,A9               ;y_xmax+8-(y<<4)
        MPYS      A0,A9               ;(y_xmax+8-(y<<4))*deltax
        SRA       4,A9                ;temp = y_xmax+8-(y<<4))*deltax>>4
        SUB       A9,A6               ;x = (xmax<<12)+7FFF-temp
        MOVE      B1,B9               ;COLOR1 = topcolor
        MOVE      A4,A10              ;copy ymax
        SRA       4,A10               ;ymax>>4
        SUB       A7,A10              ;ymax-y
        SLL       16,A10              ;move ymax-y to 16 MSBs
        MOVE      @_vpclip+SX,A9,1    ;get viewport half width SX
        ADD       A9,A9               ;viewport width = 2*SX
        MOVX      A9,A10              ;
        MOVE      A10,B7              ;DY = ymax-y, DX = wide
        SLL       12,A4               ;shift ymax into 16 LSBs
        NEG       A4                  ;-ymax
        MOVE      A1,A8               ;copy xmin
        SRA       4,A8                ;
        MOVX      A8,A4               ;concatenate -ymax with xmin
        MOVE      A4,B2               ;DADDR = -ymax:xmin
        ADDXY     B8,B2               ;convert DADDR to screen coord's
    ;    FILL      XY                  ;fill top portion of window
        VFILLL
* Does horizon intercept window bottom or left edge?
H10:
        MOVE      A13,A9              ;copy y_xmin (assume left edge)
        ADDK      8,A9                ;y_xmin+8
        SRA       4,A9                ;y_xmin+8 >> 4
        MOVE      A7,A8               ;copy y
        SUB       A9,A8               ;ycount = y - (y_xmin+8 >> 4)
        SRA       4,A3                ;ymin>>4
        SUB       A3,A9               ;h = (y_xmin+8 >> 4) - ymin
        CMP       A11,A1              ;is x_ymin > xmin ?
        JRNN      HORIZ1              ;jump if x_ymin<=xmin (left edge!)
        ADD       A9,A8               ;ycount += h (oops!--bottom edge)
        CLR       A9                  ;h = 0
* Fill scan lines crossed by horizon.
HORIZ1:
        SRA       4,A1                ;truncate xmin to integer
        NEG       A7                  ;-y
        SLL       16,A7               ;-y in 16 MSBs of A7
        MOVX      A1,A7               ;concatenate xmin with -y
        MOVE      A8,A8               ;is ycount > 0 ?
        JRLE      LASTFILL            ;jump if ycount <= 0
        MOVI      10000h,A5           ;DY = 1
        SRA       4,A2                ;truncate xmax to integer
        MOVE      A1,A3               ;copy xmin
        MOVE      A2,A4               ;copy xmax
        INC       A4                  ;++xmax
        SLL       16,A3               ;xmin in 16 MSBs of A3
        SLL       16,A4               ;xmax in 16 MSBs of A4
        SUB       A6,A4               ;xmax-x (initial value)
        NEG       A3                  ;-xmin
        ADD       A6,A3               ;x-xmin (initial value)
LOOP1:
        SUB       A0,A6               ;x -= deltax
        SUB       A0,A3               ;(x-xmin) -= deltax
        ADD       A0,A4               ;(xmax-x) += deltax

        MOVE      B1,B9               ;COLOR1 = topcolor

        MOVE      A3,A10              ;copy x-xmin
        SRL       16,A10              ;shift x-xmin to 16 LSBs
        MOVY      A5,A10              ;1 in 16 MSBs
        MOVE      A10,B7              ;DY = 1, DX = x-xmin

        MOVE      A7,B2               ;DADDR = -y:xmin
        ADDXY     B8,B2               ;convert DADDR to screen coord's
   ;     FILL      XY                  ;fill left part of scan line
        VFILLL

        MOVE      B0,B9               ;COLOR1 = botcolor

        MOVE      A4,A10              ;copy xmax-x
        SRL       16,A10              ;shift xmax-x to 16 LSBs
        MOVY      A5,A10              ;concatenate 1 with xmax-x
        MOVE      A10,B7              ;DY = 1, DX = xmax-x

        MOVE      A6,A10              ;copy x
        SRL       16,A10              ;
        MOVY      A7,A10              ;concatenate -y with x
        MOVE      A10,B2              ;DADDR = -y:x
        ADDXY     B8,B2               ;convert DADDR to screen coord's
;        FILL      XY                  ;fill right part of scan line
        VFILLL

        ADDXY     A5,A7               ;++(-y)
        DSJ       A8,LOOP1            ;loop again if --ycount > 0
        JRUC      LASTFILL            ;
* Horizon's slope is negative.  Is horizon more vertical or horizontal?
NEGSLOPE:
        CMP       A6,A7               ;is |sin(-roll)| <= |cos(-roll)| ?
        JRN       MOREVERT2           ;jump if |sin(-roll)|<|cos(-roll)|
* Slope more horizontal.  Does horizon intercept window at top or left?
        CMP       A13,A4              ;is y_xmin > ymax ?
        JRNN      H12                 ;jump if y_xmin <= ymax
* Horizon intercepts top edge of window.
        MOVE      A12,A6              ;copy x_ymax
        SLL       12,A6               ;x_ymax << 12
        ADDI      07FFFh,A6           ;(x_ymax<<12)+7FFF
        MOVE      A0,A7               ;copy deltax
        SRA       1,A7                ;deltax/2
        SUB       A7,A6               ;x = (x_ymax<<12)+7FFF-deltax/2
        MOVE      A4,A7               ;copy ymax
        SRA       4,A7                ;y = ymax>>4
        JRUC      H13                 ;
* Horizon intercepts left edge of window.
H12:
        MOVE      A13,A7              ;copy y_xmin
        ADDK      8,A7                ;y_xmin+8
        MOVE      A7,A9               ;save copy of y_xmin+8
        SRA       4,A7                ;y = y_xmin+8 >> 4
        MOVE      A1,A6               ;xmin
        SLL       12,A6               ;xmin<<12
        ADDI      07FFFh,A6           ;(xmin<<12)+7FFF
        MOVE      A7,A8               ;copy y
        SLL       4,A8                ;y<<4
        SUB       A8,A9               ;y_xmin+8-(y<<4)
        MPYS      A0,A9               ;(y_xmin+8-(y<<4))*deltax
        SRA       4,A9                ;temp = y_xmin+8-(y<<4))*deltax>>4
        SUB       A9,A6               ;x = (xmin<<12)+7FFF-temp
        MOVE      B1,B9               ;COLOR1 = topcolor
        MOVE      A4,A10              ;copy ymax
        SRA       4,A10               ;ymax>>4
        SUB       A7,A10              ;ymax-y
        SLL       16,A10              ;move ymax-y to 16 MSBs
        MOVE      @_vpclip+SX,A9,1    ;get viewport half width SX
        ADD       A9,A9               ;viewport width = 2*SX
        MOVX      A9,A10              ;
        MOVE      A10,B7              ;DY = ymax-y, DX = wide
        SLL       12,A4               ;shift ymax into 16 LSBs
        NEG       A4                  ;-ymax
        MOVE      A1,A8               ;copy xmin
        SRA       4,A8                ;
        MOVX      A8,A4               ;concatenate -ymax with xmin
        MOVE      A4,B2               ;DADDR = -ymax:xmin
        ADDXY     B8,B2               ;convert DADDR to screen coord's
;        FILL      XY                  ;fill top portion of window
        VFILLL
* Does horizon intercept window bottom or right edge?
H13:
        MOVE      A14,A9              ;copy y_xmax (assume right edge)
        ADDK      8,A9                ;y_xmax+8
        SRA       4,A9                ;y_xmax+8 >> 4
        MOVE      A7,A8               ;copy y
        SUB       A9,A8               ;ycount = y - (y_xmax+8 >> 4)
        SRA       4,A3                ;ymin>>4
        SUB       A3,A9               ;h = (y_xmax+8 >> 4) - ymin
        JRNN      HORIZ2              ;jump if h >= 0 (was right edge)
        ADD       A9,A8               ;ycount += h (oops!--bottom edge)
        CLR       A9                  ;h = 0
        JRUC      HORIZ2              ;
* Slope more vertical.  Does horizon intercept window at top or left?
MOREVERT2:
        CMP       A12,A1              ;is x_ymax >= xmin ?
        JRNN      H14                 ;jump if x_ymax < xmin
* Horizon intercepts top edge of window.
        MOVE      A12,A6              ;copy x_ymax
        SLL       12,A6               ;x_ymax << 12
        ADDI      07FFFh,A6           ;(x_ymax<<12)+7FFF
        MOVE      A0,A7               ;copy deltax
        SRA       1,A7                ;deltax/2
        SUB       A7,A6               ;x = (x_ymax<<12)+7FFF-deltax/2
        MOVE      A4,A7               ;copy ymax
        SRA       4,A7                ;y = ymax>>4
        JRUC      H15                 ;
* Horizon intercepts left edge of window.
H14:
        MOVE      A13,A7              ;copy y_xmin
        ADDK      8,A7                ;y_xmin+8
        MOVE      A7,A9               ;save copy of y_xmin+8
        SRA       4,A7                ;y = y_xmin+8 >> 4
        MOVE      A1,A6               ;xmin
        SLL       12,A6               ;xmin<<12
        ADDI      07FFFh,A6           ;(xmin<<12)+7FFF
        MOVE      A7,A8               ;copy y
        SLL       4,A8                ;y<<4
        SUB       A8,A9               ;y_xmin+8-(y<<4)
        MPYS      A0,A9               ;(y_xmin+8-(y<<4))*deltax
        SRA       4,A9                ;temp = y_xmin+8-(y<<4))*deltax>>4
        SUB       A9,A6               ;x = (xmin<<12)+7FFF-temp
        MOVE      B1,B9               ;COLOR1 = topcolor
        MOVE      A4,A10              ;copy ymax
        SRA       4,A10               ;ymax>>4
        SUB       A7,A10              ;ymax-y
        SLL       16,A10              ;move ymax-y to 16 MSBs
        MOVE      @_vpclip+SX,A9,1    ;get viewport half width SX
        ADD       A9,A9               ;viewport width = 2*SX
        MOVX      A9,A10              ;
        MOVE      A10,B7              ;DY = ymax-y, DX = wide
        SLL       12,A4               ;shift ymax into 16 LSBs
        NEG       A4                  ;-ymax
        MOVE      A1,A8               ;copy xmin
        SRA       4,A8                ;
        MOVX      A8,A4               ;concatenate -ymax with xmin
        MOVE      A4,B2               ;DADDR = -ymax:xmin
        ADDXY     B8,B2               ;convert DADDR to screen coord's
;        FILL      XY                  ;fill top portion of window
        VFILLL
* Does horizon intercept window bottom or right edge?
H15:
        MOVE      A14,A9              ;copy y_xmax (assume right edge)
        ADDK      8,A9                ;y_xmax+8
        SRA       4,A9                ;y_xmax+8 >> 4
        MOVE      A7,A8               ;copy y
        SUB       A9,A8               ;ycount = y - (y_xmax+8 >> 4)
        SRA       4,A3                ;ymin>>4
        SUB       A3,A9               ;h = (y_xmax+8 >> 4) - ymin
        CMP       A11,A2              ;is x_ymin < xmax ?
        JRN       HORIZ2              ;jump if x_ymin >= xmax (rt. edge)
        ADD       A9,A8               ;ycount += h (oops!--bottom edge)
        CLR       A9                  ;h = 0
* Fill scan lines crossed by horizon.
HORIZ2:
        SRA       4,A1                ;truncate xmin to integer
        NEG       A7                  ;-y
        SLL       16,A7               ;-y in 16 MSBs of A7
        MOVX      A1,A7               ;concatenate xmin with -y
        MOVE      A8,A8               ;is ycount > 0 ?
        JRLE      LASTFILL            ;jump if ycount <= 0
        MOVI      10000h,A5           ;DY = 1
        SRA       4,A2                ;truncate xmax to integer
        MOVE      A1,A3               ;copy xmin
        MOVE      A2,A4               ;copy xmax
        INC       A4                  ;++xmax
        SLL       16,A3               ;xmin in 16 MSBs of A3
        SLL       16,A4               ;xmax in 16 MSBs of A4
        SUB       A6,A4               ;xmax-x (initial value)
        NEG       A3                  ;-xmin
        ADD       A6,A3               ;x-xmin (initial value)
LOOP2:
        SUB       A0,A6               ;x -= deltax
        SUB       A0,A3               ;(x-xmin) -= deltax
        ADD       A0,A4               ;(xmax-x) += deltax

        MOVE      B0,B9               ;COLOR1 = botcolor

        MOVE      A3,A10              ;copy x-xmin
        SRL       16,A10              ;shift x-xmin to 16 LSBs
        MOVY      A5,A10              ;1 in 16 MSBs
        MOVE      A10,B7              ;DY = 1, DX = x-xmin

        MOVE      A7,B2               ;DADDR = -y:xmin
        ADDXY     B8,B2               ;convert DADDR to screen coord's
;        FILL      XY                  ;fill left part of scan line
        VFILLL

        MOVE      B1,B9               ;COLOR1 = topcolor

        MOVE      A4,A10              ;copy xmax-x
        SRL       16,A10              ;shift xmax-x to 16 LSBs
        MOVY      A5,A10              ;concatenate 1 with xmax-x
        MOVE      A10,B7              ;DY = 1, DX = xmax-x

        MOVE      A6,A10              ;copy x
        SRL       16,A10              ;
        MOVY      A7,A10              ;concatenate -y with x
        MOVE      A10,B2              ;DADDR = -y:x
        ADDXY     B8,B2               ;convert DADDR to screen coord's
    ;    FILL      XY                  ;fill right part of scan line
        VFILLL

        ADDXY     A5,A7               ;++(-y)
        DSJ       A8,LOOP2            ;loop again if --ycount > 0
* Does bottom part of window need to be filled?
LASTFILL:
        MOVE      A9,B7               ;copy h (height of bottom area)
        JRLE      DONE                ;jump if h <= 0
        SLL       16,B7               ;shift h into 16 MSBs
        MOVE      @_vpclip+SX,B1,1    ;get viewport half width SX
        ADD       B1,B1               ;viewport width = 2*SX
        MOVX      B1,B7               ;DY = h, DX = wide (window width)
        MOVE      A7,B2               ;DADDR = -y::xmin
        ADDXY     B8,B2               ;convert DADDR to screen coord's
        MOVE      B0,B9               ;COLOR1 = botcolor
    ;    FILL      XY                  ;fill bottom of window
        VFILLL
* Restore registers and return.
DONE:
        MMFM      SP,B0,B1,B2,B4,B5,B6,B7,B8,B10,B11,B12,B13,B14
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        SETF      32,0,1              ;restore default field size 1
        MOVE      *SP(32),A14,1       ;update operand stack pointer
        RETS      2                   ;
        .end

