text: ;----------------------------- Module Header -----------------------------;
  ;
  ; dfbline.asm
  ;
  ; Contents:  Strip draw routines for writing lines onto device format bitmaps
  ;
  ; Notes:
  ;
  ; 1) We have 6 strip draw routines.  Horizontal, vertical, and diagonal
  ;    cases for each of Solid and Arbitrary styled lines.  Each routine
  ;    only has to draw left-to-right.
  ;
  ; 2) DFB Format:
  ;
  ;    The DFB format is a four plane bitmap.  Each bit in a 4 bit VGA colour
  ;    corresponds to a plane in the bitmap.  The bitmap has the format
  ;
  ;           PLANE 3	\
  ;           PLANE 2	 | - This is one scan line.
  ;           PLANE 1	 |   We are going UP in memory from PLANE 0
  ;           PLANE 0	/    on a scan line.
  ;
  ;    Where PLANE n corrosponds to bit n (counting from the right) in a VGA
  ;    colour.
  ;
  ;    The line code will call the appropriate strip routine 4 times to draw
  ;    a line: each time we'll draw on one plane of the DFB.
  ;
  ; 4) ROP Actions:
  ;
  ; 5) Output Routines:
  ;
  ;    The scope of the output routines is wildly inconsistant between functions.
  ;    Some write single bytes, some write the whole strips array onto a plane.
  ;    The overriding consideration was ease of implementation
  ;
  ;-------------------------------------------------------------------------;
  
  	PAGE , 132
  	.386
  
  	.model  small,c
  
  	assume ds:FLAT,es:FLAT,ss:FLAT
  	assume fs:nothing,gs:nothing
  
  	.xlist
  	include stdcall.inc	      ;calling convention cmacros
  	include i386\strucs.inc
  	.list
  	.code
  
  	include i386\lines.inc
  
  ;--------------------------Private-Routine------------------------------;
  ; vBitmapSolidDiagonal
  ;
  ;   Draw diagonal strips left-to-right (handles both x-major and
  ;   y-major diagonal lines).
  ;
  ;-----------------------------------------------------------------------;
  
  cProc   vBitmapSolidDiagonal,12,<  \
          uses        esi edi ebx,   \
          pStrips:    ptr STRIPS,    \
          pls:        ptr LINESTATE, \
          plStripEnd: ptr >
  
          mov     ebx, plStripEnd
          mov     esi, pStrips
  
  ; Do some initialization:
  
          mov     [ebx], esi                      ; save pStrips
          mov     [ebx + 4], ebp
          mov     al,  [esi].ST_jBitMask
          mov     edi, [esi].ST_pjScreen
          mov     ebp, [esi].ST_lNextScan
  
  ; Set up ROP registers:
  
          mov     dl, al
          mov     dh, al
          and     edx, [esi].ST_ulBitmapROP
          not     dl
  
  ;                   al  = rotating bit
  ;                   ebx = pointer to end of strips
  ;                   ecx = pixel count
  ;                   dl  = and mask
  ;                   dh  = xor mask
  ;                   esi = current strip pointer
  ;                   edi = display memory pointer
  ;                   ebp = delta
  
          test    [esi].ST_flFlips, FL_FLIP_D
          lea     esi, [esi].ST_alStrips
          jnz     y_major_next_diagonal
  
  x_major_next_diagonal:
          mov     ecx, [esi]
          add     esi, 4
  
  x_major_diagonal_loop:
          mov     ah, [edi]
          and     ah, dl
          xor     ah, dh
          mov     [edi], ah
  
          ror     dl, 1
          ror     dh, 1
          ror     al, 1
          adc     edi, ebp
          dec     ecx
          jnz     short x_major_diagonal_loop
  
          sub     edi, ebp
          cmp     esi, ebx
          jb      short x_major_next_diagonal
  
          jmp     short done_diagonal
  
  y_major_next_diagonal:
          mov     ecx, [esi]
          add     esi, 4
  
  y_major_diagonal_loop:
          mov     ah, [edi]
          and     ah, dl
          xor     ah, dh
          mov     [edi], ah
  
          ror     dl, 1
          ror     dh, 1
          ror     al, 1
          adc     edi, ebp
          dec     ecx
          jnz     short y_major_diagonal_loop
  
          rol     dl, 1
          rol     dh, 1
          rol     al, 1
          sbb     edi, 0
          cmp     esi, ebx
          jb      short y_major_next_diagonal
  
  done_diagonal:
          mov     esi, [ebx]                      ; esi = pStrips
          mov     ebp, [ebx + 4]                  ; restore ebp
          mov     [esi].ST_pjScreen, edi
          mov     [esi].ST_jBitmask, al
          cRet    vBitmapSolidDiagonal
  
  endProc vBitmapSolidDiagonal
  
  ;--------------------------Private-Routine------------------------------;
  ; vBitmapSolidVertical
  ;
  ;   Draw vertical strips left-to-right.
  ;
  ;-----------------------------------------------------------------------;
  
  cProc   vBitmapSolidVertical,12,<  \
          uses         esi edi ebx,   \
          pStrips:     ptr STRIPS,    \
          pls:         ptr LINESTATE, \
          plStripEnd: ptr >
  
          mov     ebx, plStripEnd
          mov     esi, pStrips
  
  ; Do some initialization:
  
          mov     [ebx], esi                      ; save pStrips
          mov     [ebx + 4], ebp
          mov     al,  [esi].ST_jBitMask
          mov     edi, [esi].ST_pjScreen
          mov     ebp, [esi].ST_lNextScan
  
  ; Set up ROP registers:
  
          mov     dl, al
          mov     dh, al
          and     edx, [esi].ST_ulBitmapROP
          add     esi, offset ST_alStrips
          not     dl
  
  ;                   al  = rotating bit
  ;                   ebx = pointer to end of strips
  ;                   ecx = pixel count
  ;                   dl  = and mask
  ;                   dh  = xor mask
  ;                   esi = current strip pointer
  ;                   edi = display memory pointer
  ;                   ebp = delta
  
  next_vertical:
          mov     ecx, [esi]
          add     esi, 4
  
  vertical_loop:
          mov     ah, [edi]
          and     ah, dl
          xor     ah, dh
          mov     [edi], ah
  
          add     edi, ebp
          dec     ecx
          jnz     short vertical_loop
  
  ; Okay, we're finished with the strip so we have to advance one pixel
  ; to the right:
  
          ror     dl, 1
          ror     dh, 1
          ror     al, 1
          adc     edi, 0
  
  ; See if there are any more strips:
  
          cmp     esi, ebx
          jb      short next_vertical
  
  ; We're done:
  
          mov     esi, [ebx]                      ; esi = pStrips
          mov     ebp, [ebx + 4]                  ; restore ebp
          mov     [esi].ST_pjScreen, edi
          mov     [esi].ST_jBitmask, al
          cRet    vBitmapSolidDiagonal
  
  endProc vBitmapSolidVertical
  
  ;--------------------------Private-Routine------------------------------;
  ; vBitmapSolidHorizontal
  ;
  ;   Draw vertical strips left-to-right.
  ;
  ;-----------------------------------------------------------------------;
  
  cProc   vBitmapSolidHorizontal,12,< \
          uses        esi edi ebx,    \
          pStrips:    ptr STRIPS,     \
          pls:        ptr LINESTATE,  \
          plStripEnd: ptr >
  
          mov     ebx, plStripEnd
          mov     esi, pStrips
  
  ; Do some initialization:
  
          push    ebp
          mov     [esi].ST_plStripEnd, ebx
          mov     al,  [esi].ST_jBitMask
          mov     edx, [esi].ST_ulBitmapROP
          mov     edi, [esi].ST_pjScreen
          lea     ebp, [esi].ST_alStrips
  
  ;                   al  = rotating bit
  ;                   ebx = garbage
  ;                   ecx = pixel count
  ;                   edx = ulBitmapROP
  ;                   esi = pStrips
  ;                   edi = display memory pointer
  ;                   ebp = current strip pointer
  
  next_horizontal:
          mov     ecx, [ebp]
          add     ebp, 4
  
          lea     ebx, [2 * eax - 1]      ; bl = start mask
          ror     al, cl                  ; al = rotating bit for next scan
          shr     ecx, 3
          cmp     bl, al
          adc     ecx, 0
          jnz     short extends_out_of_first_byte
  
          sub     bl, al                  ; figure out rest of mask
          sub     bl, al
          inc     bl
  
          mov     bh, bl                  ; compute ROP values
          and     ebx, edx
          not     bl
  
          mov     ah, [edi]               ; actually write the byte
          and     ah, bl
          xor     ah, bh
          mov     [edi], ah
  
          add     edi, [esi].ST_lNextScan ; increment to next scan
  
          cmp     ebp, [esi].ST_plStripEnd ; see if done all strips
          jb      short next_horizontal
  
          pop     ebp                     ; clean up and leave
          mov     [esi].ST_pjScreen, edi
          mov     [esi].ST_jBitmask, al
          cRet    vBitmapSolidHorizontal
  
  extends_out_of_first_byte:
  
  ; This part gets called when the current strip doesn't fit entirely
  ; into one byte:
  
          mov     bh, bl                  ; compute ROP values
          and     ebx, edx
          not     bl
  
          mov     ah, [edi]               ; actually write the byte
          and     ah, bl
          xor     ah, bh
          mov     [edi], ah
  
          inc     edi                     ; move to next byte
  
          dec     ecx                     ; any bytes inbetween start & end byte?
          jnz     short output_bunch
  
  last_byte:
          lea     ebx, [2 * eax - 1]      ; compute end mask
          not     bl
  
          mov     bh, bl                  ; compute ROP values
          and     ebx, edx
          not     bl
  
          mov     ah, [edi]               ; actually write the byte
          and     ah, bl
          xor     ah, bh
          mov     [edi], ah
  
          add     edi, [esi].ST_lNextScan ; go to next scan
  
          cmp     ebp, [esi].ST_plStripEnd ; was this the last strip?
          jb      short next_horizontal
  
          pop     ebp                     ; clean up and leave
          mov     [esi].ST_pjScreen, edi
          mov     [esi].ST_jBitmask, al
          cRet    vBitmapSolidHorizontal
  
  output_bunch:
          not     dl
  
  bunch_loop:
  
  ; We have a series of bytes to lay down:
  
          mov     ah, [edi]
          and     ah, dl
          xor     ah, dh
          mov     [edi], ah
          inc     edi
  
          dec     ecx                     ; we done all the whole bytes?
          jnz     short bunch_loop
  
          not     dl
          jmp     short last_byte
  
  endProc vBitmapSolidHorizontal
  
  ;--------------------------Private-Routine------------------------------;
  ; vBitmapStyledHorizontal
  ;
  ;   Draws arbitrarily styled horizontal strips left-to-right.
  ;
  ;-----------------------------------------------------------------------;
  
  cProc   vBitmapStyledHorizontal,12,< \
          uses        esi edi ebx,    \
          pStrips:    ptr STRIPS,     \
          pls:        ptr LINESTATE,  \
          plStripEnd: ptr >
  
          mov     ebx, plStripEnd
          mov     esi, pStrips
          push    ebp
          mov     ebp, esi
  
  ; Do some initialization:
  
          mov     [ebp].ST_plStripEnd, ebx
          lea     esi, [ebp].ST_alStrips
          mov     al,  [ebp].ST_jBitmask
          mov     ah,  [ebp].ST_jStyleMask
          mov     edx, [ebp].ST_spRemaining
          mov     edi, [ebp].ST_pjScreen
  
  ;                   al  = rotating bit
  ;                   ah  = 0 if working on a dash, 0ffh if working on a gap
  ;                   bl  = accumulating mask
  ;                   ecx = pixel count
  ;                   edx = # of pixels to go in dash or gap (must be 32 bits)
  ;                   esi = current strip pointer
  ;                   edi = display memory pointer
  ;                   ebp = pStrips
  
          align   4
  
  next_horizontal:
          mov     ecx, [esi]              ; get new strip count
          add     esi, 4
          xor     bl, bl                  ; clear accumulating mask
  
  horizontal_loop:
          xor     bl, ah                  ; set bit in accumulating mask if
          or      bl, al                  ;   ah says we're working on a dash
          xor     bl, ah
  
          dec     edx
          jz      short next_style_entry
  
  next_pixel:
          ror     al, 1
          jc      short output_byte
          dec     ecx                     ; another pixel done; continue with
          jnz     short horizontal_loop   ;   with strip if there's more left
  
  ; We're done a horizontal strip.  Now we do a diagonal step:
  
  side_step:
          mov     bh, bl                  ; do ROP stuff
          and     ebx, [ebp].ST_ulBitmapROP
          not     bl
  
          and     [edi], bl               ; write the byte
          xor     [edi], bh
  
          add     edi, [ebp].ST_lNextScan
  
          cmp     [ebp].ST_plStripEnd, esi ; are we finished the strip array?
          ja      short next_horizontal
  
          mov     [ebp].ST_pjScreen, edi  ; remember where we were
          mov     [ebp].ST_jBitmask, al
          mov     [ebp].ST_jStyleMask, ah
          mov     [ebp].ST_spRemaining, edx
  
          pop     ebp
  
          cRet    vBitmapStyledHorizontal
  
  output_byte:
          mov     bh, bl                  ; do ROP stuff
          and     ebx, [ebp].ST_ulBitmapROP
          not     bl
  
          and     [edi], bl               ; write the byte
          xor     [edi], bh
  
          xor     bl, bl                  ; clear accumulating mask
  
          inc     edi                     ; moved one byte to right
  
          dec     ecx
          jnz     short horizontal_loop   ; more pels to go in strip
          jmp     short side_step         ; need a new strip
  
  ; We're onto a new entry in the style array:
  
  next_style_entry:
          mov     edx, [ebp].ST_psp       ; go to next style array entry
          add     edx, 4
          cmp     [ebp].ST_pspEnd, edx    ; if past end go back to start
          jae     short @F
          mov     edx, [ebp].ST_pspStart
  @@:
          mov     [ebp].ST_psp, edx       ; save it for posterity
          mov     edx, [edx]              ; new count
          not     ah                      ; dash => gap or gap => dash
  
          jmp     short next_pixel
  
  endProc vBitmapStyledHorizontal
  
  
  ;--------------------------Private-Routine------------------------------;
  ; vBitmapStyledVertical
  ;
  ;   Draw arbitrarily styled vertical strips left-to-right.
  ;
  ;-----------------------------------------------------------------------;
  
  cProc   vBitmapStyledVertical,12,<  \
          uses        esi edi ebx,    \
          pStrips:    ptr STRIPS,     \
          pls:        ptr LINESTATE,  \
          plStripEnd: ptr >
  
          mov     ebx, plStripEnd
          mov     esi, pStrips
          push    ebp
          mov     ebp, esi
  
  ; Do some initialization:
  
          mov     [ebp].ST_plStripEnd, ebx
          lea     esi, [ebp].ST_alStrips
          mov     al,  [ebp].ST_jBitmask
          mov     ah,  [ebp].ST_jStyleMask
          mov     edx, [ebp].ST_spRemaining
          mov     edi, [ebp].ST_pjScreen
  
  ;                   al  = rotating bit
  ;                   ah  = 0 if working on a dash, 0ffh if working on a gap
  ;                   bl  = and mask
  ;                   bh  = xor mask
  ;                   ecx = pixel count
  ;                   edx = # of pixels to go in dash or gap (must be 32 bits)
  ;                   esi = current strip pointer
  ;                   edi = display memory pointer
  ;                   ebp = pStrips
  
          align   4
  
  next_vertical:
          mov     ecx, [esi]              ; get new strip count
          add     esi, 4
  
          mov     bl, al                  ; load up bl and bh to handle ROP
          mov     bh, al
          and     ebx, [ebp].ST_ulBitmapROP
          not     bl
  
  vertical_loop:
          or      ah, ah
          jnz     short @F                ; don't output pixel if in a gap
          and     [edi], bl
          xor     [edi], bh
  @@:
          dec     edx
          jz      short next_style_entry
  
  next_pixel:
          add     edi, [ebp].ST_lNextScan
          dec     ecx                     ; another pixel done; continue with
          jnz     short vertical_loop     ;   with strip if there's more left
  
  ; We're done a vertical strip.  Take a side step:
  
          ror     al, 1
          adc     edi, 0
  
          cmp     esi, [ebp].ST_plStripEnd ; we done with all the strips?
          jb      short next_vertical
  
          mov     [ebp].ST_pjScreen, edi  ; remember where we were
          mov     [ebp].ST_jBitmask, al
          mov     [ebp].ST_jStyleMask, ah
          mov     [ebp].ST_spRemaining, edx
  
          pop     ebp
  
          cRet    vBitmapStyledVertical
  
  ; We're onto a new entry in the style array:
  
  next_style_entry:
          mov     edx, [ebp].ST_psp       ; go to next style array entry
          add     edx, 4
          cmp     [ebp].ST_pspEnd, edx    ; if past end go back to start
          jae     short @F
          mov     edx, [ebp].ST_pspStart
  @@:
          mov     [ebp].ST_psp, edx       ; save it for posterity
          mov     edx, [edx]              ; new count
          not     ah                      ; dash => gap or gap => dash
  
          jmp     short next_pixel
  
  
  endProc vBitmapStyledVertical
  
          end
  