.286
w equ word ptr
b equ byte ptr

include texture.inc             ;implement texture macros

setnewlinel macro               ;use only ax and bx here !
local dylpos,dxlpos,dxlgreat,macro_finished
  mov bx,4043h                  ;code for inc ax (in bh) and inc bx (in bl)
  mov bp,left
  mov ax,poly2d[bp+8]           ;store destination coordinates
  mov xl1,ax
  mov ax,poly2d[bp+10d]
  mov yl1,ax

  mov ax,poly2d[bp]             ;left x/y start in glob. var
  mov xl0,ax
  sub ax,xl1                    ;make delta x
  inc xl1                       ;for the condition of truncation
  neg ax                        ;xl1-xl0
  jns dxlpos                    ;dxl negative ?
  neg ax                        ;then obtain amount
  mov bh,48h                    ;code for dec ax (dec xl0)
  sub xl1,2                     ;extension of destination coordinate to negative
dxlpos:
  mov dxl,ax                    ;and store glob.
  mov incflagl,ax               ;store in increment flag
  mov ax,poly2d[bp+2]
  mov yl0,ax
  sub ax,yl1                    ;obtain |delta y|
  inc yl1                       ;for the condition of trunctation
  neg ax
  jns dylpos                    ;negative ?
  neg ax                        ;then obtain amount
  mov bl,4bh                    ;code for dec bx (dec yl1)
  sub yl1,2                     ;extension of destination coordinate to negative
dylpos:
  mov dyl,ax                    ;and store glob.
  cmp dxl,ax                    ;dx < dy
  jae dxlgreat
  neg incflagl                  ;then sign change for increment flag
dxlgreat:
  mov cs:byte ptr incxl,bh      ;perform self modification
  mov cs:byte ptr incyl,bl

  cmp texture,1                 ;textures required ?
  jne macro_finished              ;no, then skip

  txt_makevarl                  ;otherwise calculate texture variables

macro_finished:
  mov ax,xl0                    ;use register as control variable
  mov bx,yl0
  mov si,incflagl
endm

setnewliner macro               ;use only cx and dx here !
local dyrpos,dxrpos,dxrgreat,macro_finished
  mov cx,4142h                  ;code for inc cx (in ch) and inc dx (in cl)
  mov bp,right
  mov dx,poly2d[bp]             ;get destination coordinates
  mov xr1,dx
  mov dx,poly2d[bp+2]
  mov yr1,dx
  mov dx,poly2d[bp+8]           ;right x/y in glob. var
  mov xr0,dx
  sub dx,xr1                    ;make |delta x|
  inc xr1                       ;for the condition of truncation
  neg dx
  jns dxrpos                    ;negative ?
  neg dx                        ;then obtain amount
  mov ch,49h                    ;code for dec cx
  sub xr1,2                     ;extension of destination coordinate to negative
dxrpos:
  mov dxr,dx                    ;store in glob. var
  mov incflagr,dx
  mov dx,poly2d[bp+10d]         ;make |delta y|
  mov yr0,dx
  sub dx,yr1
  inc yr1                       ;for the condition of truncation
  neg dx
  jns dyrpos                    ;negative ?
  neg dx                        ;then obtain amount
  mov cl,4ah                    ;code for dec dx
  sub yr1,2                     ;extension of destination coordinate to negative
dyrpos:
  mov dyr,dx                    ;and store in glob. var
  cmp dxr,dx                    ;dx < dy ?
  jae dxrgreat
  neg incflagr                  ;then sign change for increment flag
dxrgreat:
  mov cs:byte ptr incxr,ch      ;self modification
  mov cs:byte ptr incyr,cl

  cmp texture,1                 ;textures needed ?
  jne macro_finished            ;no, then skip

  txt_makevarr                  ;otherwise calculate texture variables

macro_finished:
  mov cx,xr0                    ;load register
  mov dx,yr0
  mov di,incflagr
endm

data segment public
  extrn vpage:word              ;current video page
  extrn sf_shift                ;flag for surface shift suppression
  extrn glass:byte;             ;flag for glass surfaces

;texture variables:
  extrn texture:byte            ;texture needed  ?
  extrn txt_data:dataptr        ;array with pointer to graphic data
  extrn txt_offs:dataptr        ;array with offsets within the texture image
  extrn txt_size:dataptr        ;array with size specifications

d_x  dd 0                       ;relative x-coordinate
d_y dd 0                        ;relative y-coordinate
D    dd 0                       ;main determinant
column1 dd 0                    ;components of the main determinant
        dd 0
column2 dd 0
        dd 0
upper_row dw 0                  ;which coordinates were used ?
lower_row dw 0

xl_3d dd 0                      ;control values for 3d-coordinates when filling
yl_3d dd 0
zl_3d dd 0
xr_3d dd 0
yr_3d dd 0
zr_3d dd 0

inc_xl dd 0                     ;values for addition to control values
inc_yl dd 0
inc_zl dd 0
inc_xr dd 0
inc_yr dd 0
inc_zr dd 0

;variables for fill algorithm
high_point   dw 0               ;kept in dx during search
high_y      dw 0                ;kept in bx during search

left        dw 0                ;point of left side
right      dw 0                 ;point of right side

xl0  dw 0                       ;control values for left start and end points
yl0 dw 0
xl1 dw 0
yl1 dw 0
xr0 dw 0                        ;control values for right
yr0 dw 0
xr1 dw 0
yr1 dw 0
dxl dw 0                        ;delta X / Y for both pages
dyl dw 0
dxr dw 0
dyr dw 0
incflagl dw 0                   ;flags, when y has to be incremented
incflagr dw 0 

data ends

code segment public
assume cs:code,ds:data
extrn polycol:word              ;surface color
extrn polyn:word                ;number of corners
extrn poly2d:word               ;array with 2D-coordinates
extrn poly3d:word               ;array with 3D-coordinates
extrn delta1,delta2:word        ;plane vectors
extrn bline:near                ;draws line

lambda1 dd 0                    ;affine coordinates
lambda2 dd 0

inc_lambda1 dd 0                ;steps
inc_lambda2 dd 0

plane dw 0002h                  ;current plane to set
x0 dw 0                         ;coordinates for line
y0 dw 0
x1 dw 0
zz dw 0                         ;points still to be drawn

extrn txt_no:word               ;number of texture to be drawn

public drawpol
;draws wireframe model of surface in poly2d
drawpol proc near
  push es
  pusha
  xor si,si                     ;index to first entry
  mov bp,polyn                  ;get number of corners
@nline:
  mov ax,poly2d[si]             ;get coordinates from table
  mov bx,poly2d[si+2]
  mov cx,poly2d[si+8]
  mov dx,poly2d[si+10d]
  push bp
  push si
  call bline                    ;draw line
  pop si
  pop bp
  add si,8                      ;next line
  dec bp                        ;decrement number
  jne @nline
  popa
  pop es
  ret
drawpol endp

hline proc near                 ;draws horiz. line ax/bx -> cx/bx
  pusha
  push es
  mov x0,ax                     ;store coordinates for later
  mov y0,bx
  mov x1,cx
  sub cx,ax                     ;calculate number of pixels to be drawn
  jne zzok
  inc cx

zzok:
  mov zz,cx

  cmp glass,1                   ;glass surface ?
  jne Solid1
  push ax                       ;yes, then GDC mode: OR
  mov dx,3ceh
  mov ax,1003h                  ;register 3: function select
  out dx,ax
  pop ax

Solid1:
  mov dx,3c4h                   ;timing sequencer port
  mov di,0a000h
  mov es,di                     ;select VGA segment
  mov di,ax                     ;calculate offset
  shr di,2                      ;(x div 4) + y*80
  add di,vpage                  ;add current page
  mov bx,y0
  imul bx,80d
  add di,bx                     ;now in di
  cmp zz,4
  jl no_middle                  ;<draw 4 points -> no blocks of 4
  and ax,11b                    ;two lower bits are important
  je middle                     ;if 0 set blocks of 4 immediately
no_middle:
  mov bx,0f02h                  ;if no_shift, then use this mask
  mov cx,zz                     ;set number of pixels in mask
  cmp cx,20h                    ;beginning with 20h the 386 shifts back in !
  jae no_shift
  mov bx,0102h                  ;prepare mask
  shl bh,cl                     ;number of pixels=number of bits to set
  dec bh
  and bh,0fh
no_shift:
  mov cx,ax                     ;shift correctly depending on start plane
  and cl,3
  shl bh,cl
  mov ax,bx                     ;and mask finished
  sub zz,4                      ;decrement pixels to be drawn
  add zz,cx
start:
  out dx,ax                     ;set calculated write mask
  mov al,b polycol              ;get color

  mov ah,es:[di]                ;load latches, only for glass solids

  stosb                         ;set
middle:
  cmp zz,4
  jl close                    ;if no more blocks of 4 -> conclusion

  mov ax,0f02h                  ;select all planes
  out dx,ax                     ;(zz div 4) set blocks of 4
  mov cx,zz
  shr cx,2
  mov al,b polycol

  cmp glass,1                   ;glass solid ?
  jne solid

@lp:
  mov ah,es:[di]                ;load latches, only glass solids
  stosb                         ;and write back
  dec cx
  jne @lp
  jmp close

solid:
  rep stosb                     ;draw middle part

close:
  mov cx,x1                     ;set remaining pixels
  and cx,3h
  dec zz
  js hline_finished             ;if nothing more there -> end
  mov ax,0102h
  shl ah,cl                     ;create mask
  dec ah
  out dx,ax
  mov al,b polycol              ;get color

  mov ah,es:[di]                ;load latches, only for glass solids

  stosb                         ;and draw pixels
hline_finished:
  mov dx,3ceh                   ;GDC mode back to MOVE
  mov ax,0003h
  out dx,ax
  pop es
  popa
  ret
hline endp

txt_hline                       ;macro contains procedure "hline_texture"

public fillpol
fillpol proc near               ;fills polygon in mode X
  push bp
  pusha

  cmp texture,1                 ;textures being used ?
  jne fill                      ;no, then simply fill

  txt_maindet                   ;otherwise calculate main determinant

Fill:
  xor si,si                     ;search for highest point, select first entry
  mov cx,polyn                  ;number of corners
  sub cx,2
  mov bx,0ffffh                 ;very high value, in any case lower
npoint:
  mov ax,poly2d[si+2]           ;get y
  cmp ax,bx                     ;if previous minimum lower
  ja  no_min
  mov bx,ax                     ;record new minimum
  mov dx,si
no_min:
  add si,8
  dec cx                        ;next corner, if not 0ffffh
  jns npoint
  mov high_point,dx             ;record in glob var
  mov high_y,bx                 ;high point search concluded

  or dx,dx                      ;left = 0 ?
  jne dec_valid
  mov bx,polyn                  ;yes: right to the other end
  sub bx,2
  shl bx,3
  jmp lr_finished               ;position
dec_valid:
  mov bx,dx                     ;otherwise
  sub bx,8
lr_finished:
  mov left,dx                   ;record one beforehand in glob var
  mov right,bx

; ax/bx : start coordinates left    (xl0/yl0)
; cx/dx : start coordinates right   (xr0/yr0)
; si    : overflow flag left
; di    : overflow flag right
; bp    : pointer to current point

  setnewlinel                   ;load line variables
  setnewliner

loopl:
  cmp ax,xl1
  je new_linel                  ;if end reached -> set new line
  cmp bx,yl1
  je new_linel                  ;otherwise continue drawing

  or si,si                      ;increment flag <= 0
  jg flaglgreat
incyl:                          ;this place is being patched !
  inc bx                        ;continue y
  add si,dxl                    ;continue setting inc flag

  txt_incl                      ;continue 3d coordinates also

  cmp bx,yl1                    ;destination reached ?
  je new_linel                  ;then new line
  jmp left_increased            ;y has been increased left -> now right
flaglgreat:
  sub si,dyl                    ;decrement inc flag
incxl:                          ;this place being patched !
  inc ax                        ;continue x
  jmp loopl

finished__:
  jmp finished

new_linel:
  mov bx,left                   ;prepare increase
  cmp bx,right
  je finished__                 ;same, then finished
  add bx,8                      ;continue left
  mov ax,polyn                  ;is left at the end of the list ?
  shl ax,3
  sub ax,8                      ;end defined
  cmp bx,ax                     ;compare
  jb left_set
  xor bx,bx                     ;if yes, then set to 0
left_set:
  mov left,bx
  setnewlinel                   ;reload variables
  jmp loopl
finished_:
  jmp finished
left_increased:

loopr:
  cmp cx,xr1
  je new_liner                  ;if end reached -> set new line
  cmp dx,yr1
  je new_liner                  ;otherwise continue drawing

  or di,di                      ;increment flag <= 0
  jg flagrgreat
incyr:                          ;this place being patched !
  inc dx                        ;continue y
  add di,dxr                    ;continue setting inc flag

  txt_incr

  cmp dx,yr1                    ;destination reached ?
  je new_liner                  ;then new line
  jmp right_increased           ;y was increased right -> now draw line
flagrgreat:
  sub di,dyr                    ;decrement inc flag
incxr:
  inc cx                        ;this place being patched !
  jmp loopr

new_liner:
  mov dx,right                  ;prepare decrease
  cmp dx,left
  je finished_                  ;if same, then finished
  sub dx,8                      ;if previously at 0->set at other end
  jns right_set
  mov dx,polyn
  sub dx,2
  shl dx,3                      ;positioned at end
right_set:
  mov right,dx

  setnewliner                   ;reload variables
  jmp loopr

right_increased:
  push ax
  push cx
  cmp cx,ax                     ;correct sequence ?
  jae direct_ok                 ;then ok, otherwise:
  cmp w sf_shift,0              ;suppress surface shift ?
  je draw                       ;no, then draw anyway
  pop cx
  pop ax
  jmp finished                  ;polygon will not be drawn
draw:
  xchg ax,cx                    ;coordinates in correct sequence
direct_ok:

  cmp texture,1                 ;use textures ?
  jne norm_fill                 ;no, then normal fill
  call hline_texture            ;draw horizontal texture line
  pop cx
  pop ax
  jmp loopl                     ;and continue
norm_fill:
  call hline                    ;draw horizontal line
  pop cx
  pop ax
  jmp loopl                     ;and continue
finished:
  popa
  pop bp
  ret
fillpol endp
code ends
end
