data segment
  extrn vscreen:dword           ;pointer to landscape data
  extrn x,y: word               ;coordinates of trapezoid
  extrn vpage:word              ;current video page
data ends

code segment
assume cs:code,ds:data


;variables with fractional part (lower 8 bits):

offst dd 0                      ;current offset
step dd 0                       ;pixel size
row_start dd 0                  ;beginning of current row
row_step dd 0                   ;distance from next row


r_count dw 0                    ;counter for depth
shrink dw 0                     ;correction on lower screen border

row dd 0                        ;current screen row number
vpage_cs dw 0                   ;video page in the code segment


.386
public Draw_Voxel
Draw_Voxel proc pascal
;shows landscape on current video page
;reads data from vscreen starting from position (x/y)

  mov ax,vpage                  ;note number of video page
  mov vpage_cs,ax

  push ds
  mov ax,0a000h                 ;load destination segment
  mov es,ax

  mov ax,320                    ;calculate offset in landscape
  imul y
  add ax,x

  lds si,vscreen                ;take data from vscreen
  add si,ax                     ;add offset
  shl esi,8                     ;convert to fixed point number

  mov offst,esi                 ;initial values for pixel ...
  mov row_start,esi             ;... and row

  mov step,100h                 ;first scaling factor 1
  mov row,100*256               ;begin in screen row 100
  mov row_step,14040h           ;distance of rows 320,25
  mov shrink,0                  ;first no correction
  mov r_count,160               ;number of rows to calculate

next_y:
  mov eax,row                   ;get current (screen) row number
  mov ebx,eax                   ;store
  shr eax,8                     ;convert to whole number
  add eax,50                    ;50 pixels down
  imul eax,80                   ;convert to offset
  mov di,ax                     ;store as destination pointer

  cmp di,199*80                 ;screen border exceeded ?
  jb normal
  mov di,199*80                 ;yes, then position on last row

  mov eax,row                   ;difference to bottom screen border
  shr eax,8
  sub eax,149
  mov shrink,ax                 ;and note as correction

normal:
  add di,vpage_cs               ;add current video page

  imul ebx,16500                ;multiply row number by 1,007
  shr ebx,14                    ;calculate * 16500 / 16384
  mov row,ebx                   ;and store

  mov bp,80                     ;number of pixels per row
next_x:
  mov esi,offst                 ;load current pixel offset
  shr esi,8                     ;convert to whole number
  xor eax,eax
  mov al,[si]                   ;load dot from landscape
  mov cx,ax                     ;store

  cmp cx,99                     ;color (=height) < 100
  ja fill_bar
  mov ax,99                     ;then set to 99

fill_bar:
  shl ax,5                      ;vanishing point projection: height * 32
  xor dx,dx
  push bp
  mov bp,r_count                ;divides by the distance
  add bp,50
  idiv bp
  pop bp

  sub ax,shrink                 ;perform correction
  jbe continue                  ;if <= 0, don't even draw

  push di
next_fill:
  mov es:[di],cl                ;enter color
  sub di,80                     ;address next highest row
  dec al                        ;decrement counter
  jne next_fill                 ;continue ?
  pop di

continue:
  inc di                        ;address next byte on the screen
  mov esi,step                  ;get step
  add esi,offst                 ;increment
  mov offst,esi                 ;and rewrite

  dec bp                        ;next dot
  jne next_x

  mov esi,row_step              ;shift beginning of row
  add esi,row_start
  mov row_start,esi
  mov offst,esi                 ;reload pixel offset also

  dec step                      ;decrement scaling factor
  dec r_count                   ;continue row counter
  jne next_y
  pop ds
  ret
Draw_Voxel endp

code ends
end
