home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / turbo_c / blit.arc / BLIT.ASM next >
Assembly Source File  |  1988-02-21  |  24KB  |  1,071 lines

  1. _DATA    segment    word public 'DATA'
  2.  
  3.     include    blit.def
  4.  
  5. count_begin    macro
  6. thisone    =    $
  7.     dw    ?
  8.     endm
  9.  
  10. count_end    macro    a
  11.   ifdif <a>,<>
  12.     org    $-a
  13.   endif
  14. thatone    =    $
  15.     org    thisone
  16.     dw    thatone-thisone-2
  17.     org    thatone
  18.     endm
  19.  
  20. ;note that the two words previous to the given verb must be the offsets
  21. ;  (in the data segment!) of two routines.  The first (cs:put_byte_subr-4) is
  22. ;  a routine that puts the byte in al with a mask of 0ffh.  The second
  23. ;  (cs:put_byte_subr-2) is a routine that puts the byte in al using the mask
  24. ;  in dl.
  25.  
  26. put_byte_subr    dw    ?        ;our transfer mode.
  27.  
  28. count        dw    ?
  29.  
  30. smaller_delta    dw    ?
  31. larger_delta    dw    ?
  32. epsilon        dw    ?
  33.  
  34. new_x_size    dw    ?
  35. old_x_size    dw    ?
  36. smaller_line    dw    ?
  37. larger_line    dw    ?
  38. compression    db    ?
  39. not_compression    db    ?
  40.  
  41. bit_count    dw    ?        ;count of bits in source bitmap.
  42. line_count    dw    ?        ;count of lines in source bitmap.
  43. scan_line_count    dw    ?        ;count of lines so far done.
  44.  
  45. ;we precompute several things:
  46.  
  47. src_align    dw    ?        ;source bit alignment, 0..7
  48. src_seg        dw    ?        ;segment of source bitmap
  49. src_bytes    dw    ?        ;width of source bitmap in bytes
  50. src_left_bit    db    ?        ;leftmost bit in source bitmap
  51.  
  52. dest_align    dw    ?        ;destination bit alignment, 0..7
  53. dest_bytes    dw    ?        ;width of dest bitmap in bytes
  54. dest_left_bit    db    ?        ;leftmost bit in dest bitmap
  55.  
  56. ;this following table is used to provide shifts of differing counts.
  57. ;  On a V20, and 80x86; x=1,2,3 we could use the shift with immediate count
  58. ;  instruction, but then we're screwed on 808x processors.
  59.  
  60. get_byte_ptr    dw    ?
  61. get_ptrs    label    word
  62.     dw    0            ;shift count of zero - not used.
  63.     dw    shifted_1_get        ;special case - shift count of 1.
  64.     dw    shifted_get
  65.     dw    shifted_get
  66.     dw    shifted_get
  67.     dw    shifted_get
  68.     dw    shifted_get
  69.     dw    shifted_7_get        ;special case = shift count of -1 mod 8.
  70.  
  71. shifted_get    label    byte
  72.     count_begin
  73.     mov    ax,[si]            ;get the next two bytes.
  74.     inc    si
  75.     rol    ax,cl            ;align to screen byte.
  76.     count_end
  77.  
  78. shifted_1_get    label    byte
  79.     count_begin
  80.     mov    ax,[si]            ;get the next two bytes.
  81.     inc    si
  82.     rol    ax,1            ;align to screen byte.
  83.     count_end
  84.  
  85. shifted_7_get    label    byte
  86.     count_begin
  87.     mov    ax,[si]            ;get the next two bytes.
  88.     inc    si
  89.     xchg    ah,al            ;rol ax,7 == xchg ah,al;ror ax,1
  90.     ror    ax,1            ;align to screen byte.
  91.     count_end
  92.  
  93. pset_verb_1    label    byte
  94.     count_begin
  95.     stosb
  96.     count_end
  97. pset_verb_2    label    byte
  98.     count_begin
  99.     xor    al,es:[di]
  100.     and    al,dl
  101.     xor    es:[di],al
  102.     inc    di            ;go to the next byte.
  103.     count_end
  104.  
  105. and_not_verb_1    label    byte
  106.     count_begin
  107.     not    al
  108.     and    es:[di],al
  109.     inc    di            ;go to the next byte.
  110.     count_end
  111. and_not_verb_2    label    byte
  112.     count_begin
  113.     not    al
  114.     not    dl
  115.     or    al,dl
  116.     and    es:[di],al
  117.     inc    di            ;go to the next byte.
  118.     count_end
  119.  
  120. preset_verb_1    label    byte
  121.     count_begin
  122.     not    al
  123.     stosb
  124.     count_end
  125. preset_verb_2    label    byte
  126.     count_begin
  127.     not    al
  128.     xor    al,es:[di]
  129.     and    al,dl
  130.     xor    es:[di],al
  131.     inc    di            ;go to the next byte.
  132.     count_end
  133.  
  134. and_verb_1    label    byte
  135.     count_begin
  136.     and    es:[di],al
  137.     inc    di            ;go to the next byte.
  138.     count_end
  139. and_verb_2    label    byte
  140.     count_begin
  141.     not    dl
  142.     or    al,dl
  143.     and    es:[di],al
  144.     inc    di            ;go to the next byte.
  145.     count_end
  146.  
  147. or_verb_1    label    byte
  148.     count_begin
  149.     or    es:[di],al
  150.     inc    di            ;go to the next byte.
  151.     count_end
  152. or_verb_2    label    byte
  153.     count_begin
  154.     and    al,dl            ;only set the bits given in al.
  155.     or    es:[di],al
  156.     inc    di            ;go to the next byte.
  157.     count_end
  158.  
  159. or_not_verb_1    label    byte
  160.     count_begin
  161.     not    al
  162.     or    es:[di],al
  163.     inc    di            ;go to the next byte.
  164.     count_end
  165. or_not_verb_2    label    byte
  166.     count_begin
  167.     not    al
  168.     and    al,dl            ;only set the bits given in al.
  169.     or    es:[di],al
  170.     inc    di            ;go to the next byte.
  171.     count_end
  172.  
  173. xor_verb_1    label    byte
  174.     count_begin
  175.     xor    es:[di],al
  176.     inc    di            ;go to the next byte.
  177.     count_end
  178. xor_verb_2    label    byte
  179.     count_begin
  180.     and    al,dl            ;only xor the bits given in al.
  181.     xor    es:[di],al
  182.     inc    di            ;go to the next byte.
  183.     count_end
  184.  
  185. _DATA    ends
  186.  
  187. _TEXT    segment    byte public 'CODE'
  188.     assume    cs:_TEXT, ds:_DATA, ss:_DATA
  189.  
  190. put_sized:
  191.     mov    compression,1        ;assume we're compressing zeroes.
  192.     mov    not_compression,0
  193.     cmp    put_byte_subr,offset _pset_verb
  194.     jne    put_sized_1
  195.     mov    compression,-1        ;we're compressing ones
  196.     mov    not_compression,1
  197. put_sized_1:
  198.  
  199.     mov    ax,bit_count
  200.     mov    old_x_size,ax        ;remember the old h size.
  201.  
  202.     mov    cx,src_align        ;compute the src left bit.
  203.     mov    al,80h
  204.     shr    al,cl
  205.     mov    src_left_bit,al
  206.  
  207.     mov    ax,[di].right        ;compute the new h size.
  208.     sub    ax,[di].left
  209.     mov    new_x_size,ax        ;remember the new h size.
  210.  
  211.     mov    dest_align,bp        ;compute the dest left bit.
  212.     mov    cx,bp
  213.     mov    al,80h
  214.     shr    al,cl
  215.     mov    dest_left_bit,al
  216.  
  217.     mov    ax,[di].bot        ;compute the new v size.
  218.     sub    ax,[di].top
  219.  
  220.     cmp    ax,line_count        ;which is larger?
  221.     jb    put_shrink_1        ;go if we're shrinking
  222. ;expand it here.  We have more lines in the dest than the source.
  223.     mov    bx,line_count        ;don't include the last scan line.
  224.     mov    smaller_delta,bx
  225.  
  226.     mov    larger_delta,ax
  227.     mov    line_count,ax
  228.     mov    epsilon,0
  229.  
  230.     call    blit_setup
  231.     mov    src_seg,ax
  232.  
  233.     mov    bx,src_bytes
  234.     mov    scan_line_count,bx
  235. put_expand_2:
  236.     push    si
  237.     push    di
  238.     call    put_sized_line
  239.     pop    di
  240.     pop    si
  241.  
  242.     mov    bx,epsilon
  243.     mov    dx,larger_delta
  244.     add    bx,smaller_delta
  245.     cmp    bx,dx            ;past the larger yet?
  246.     jl    put_expand_3        ;no.
  247.     sub    bx,dx            ;yes - subtract it.
  248.     add    si,src_bytes        ;advance to next line.
  249. put_expand_3:
  250.     mov    epsilon,bx
  251.  
  252.     add    di,dest_bytes
  253.     dec    line_count
  254.     jne    put_expand_2
  255.     ret
  256.  
  257. put_shrink_1:
  258. ;shrink it here.  We have more lines in the source than in the dest.
  259.     mov    smaller_delta,ax
  260.  
  261.     mov    ax,line_count
  262.     mov    larger_delta,ax
  263.     mov    epsilon,0
  264.  
  265.     call    blit_setup
  266.     mov    src_seg,ax
  267.  
  268.     mov    scan_line_count,0
  269.  
  270. put_shrink_2:
  271.     mov    bx,src_bytes
  272.     add    scan_line_count,bx    ;include another scan line in the processing.
  273.  
  274.     mov    bx,epsilon
  275.     mov    dx,larger_delta
  276.     add    bx,smaller_delta
  277.     mov    epsilon,bx
  278.     cmp    bx,dx            ;past the larger yet?
  279.     jl    put_shrink_3        ;no.
  280.     sub    bx,dx            ;yes - subtract it off.
  281.     mov    epsilon,bx
  282.  
  283.     push    si
  284.     push    di
  285.     call    put_sized_line
  286.     pop    di
  287.     pop    si
  288.  
  289.     add    si,scan_line_count    ;move the source down a line.
  290.     mov    scan_line_count,0
  291.  
  292.     add    di,dest_bytes        ;move to the next line.
  293.  
  294. put_shrink_3:
  295.     dec    line_count
  296.     jne    put_shrink_2
  297.     ret
  298.  
  299.  
  300. put_sized_line:
  301. ;ds:si->array, es:di->screen, bp=destination alignment,
  302. ;  scan_line_count=number of scan lines to process.
  303. ;don't destroy bp.
  304.  
  305.     mov    ax,new_x_size        ;are we changing the x size?
  306.     cmp    ax,old_x_size
  307.     jb    put_smaller_line    ;yes - it's shorter.
  308.     ja    put_larger_line        ;yes - it's longer.
  309.     mov    bx,ax
  310.     mov    bp,dest_align        ;get the destination alignment.
  311.     jmp    put_scan_line        ;no - same size.
  312.  
  313. put_larger_line:
  314.     mov    larger_line,ax        ;new is larger.
  315.     mov    bit_count,ax
  316.     xor    bx,bx
  317.  
  318.     mov    ax,old_x_size
  319.     mov    smaller_line,ax
  320.  
  321.     mov    dl,dest_left_bit
  322.     mov    dh,src_left_bit        ;dh=source mask.
  323.  
  324.     mov    cx,bit_count
  325.  
  326.     push    ds
  327.     mov    ds,src_seg
  328.     assume    ds:nothing
  329.  
  330.     mov    ah,[si]            ;get the first source byte.
  331.     inc    si
  332. put_larger_line_1:
  333.  
  334.     xor    al,al
  335.     test    dh,ah            ;is the source bit set?
  336.     je    put_larger_line_2    ;no.
  337.     mov    al,dl            ;yes - get the dest bit in question.
  338. put_larger_line_2:
  339.     call    put_byte_subr        ;put this byte.
  340.  
  341.     add    bx,smaller_line
  342.     cmp    bx,larger_line
  343.     jb    put_larger_line_3
  344.     sub    bx,larger_line
  345.  
  346.     ror    dh,1            ;move over a source bit.
  347.     jnc    put_larger_line_3
  348.     mov    ah,[si]
  349.     inc    si
  350. put_larger_line_3:
  351.  
  352.     ror    dl,1            ;move over a dest bit.
  353.     adc    di,0            ;if cy, move over in di.
  354.     loop    put_larger_line_1    ;no.
  355.  
  356.     cmp    dh,80h            ;did we use any of the source bits?
  357.     jne    put_larger_line_5
  358.     dec    si            ;no - backup.
  359. put_larger_line_5:
  360.     pop    ds
  361.     assume    ds:_DATA
  362.     ret
  363.  
  364.  
  365. put_smaller_line:
  366.     mov    smaller_line,ax
  367.  
  368.     mov    ax,old_x_size
  369.     mov    larger_line,ax
  370.     mov    bit_count,ax
  371.     xor    bx,bx
  372.  
  373.     mov    cx,bit_count
  374.  
  375.     mov    dl,dest_left_bit
  376.     mov    dh,src_left_bit        ;dh=source mask.
  377.  
  378.     push    ds
  379.     mov    ds,src_seg
  380.     assume    ds:nothing
  381.  
  382.     mov    ah,7fh            ;init the sampling sum.
  383. put_smaller_line_1:
  384.  
  385.     push    bx
  386.  
  387.     mov    bx,0
  388. put_smaller_line_6:
  389.     add    ah,not_compression
  390.     test    [si+bx],dh        ;is the source bit set?
  391.     je    put_smaller_line_2    ;no.
  392.     add    ah,compression        ;yes - count this bit.
  393. put_smaller_line_2:
  394.     add    bx,src_bytes        ;move down a scan line.
  395.     cmp    bx,scan_line_count    ;have we done all of them?
  396.     jne    put_smaller_line_6    ;no.
  397.  
  398.     pop    bx
  399.  
  400.     add    bx,smaller_line
  401.     cmp    bx,larger_line
  402.     jb    put_smaller_line_4
  403.     sub    bx,larger_line
  404.  
  405.     xor    al,al            ;assume not set.
  406.     xor    ah,compression        ;flip the sense if necessary.
  407.     test    ah,80h            ;more ones than zeroes?
  408.     je    put_smaller_line_3    ;no.
  409.     mov    al,dl            ;yes - set this bit.
  410. put_smaller_line_3:
  411.     call    put_byte_subr        ;put this byte.
  412.     mov    ah,7fh            ;init the sampling sum.
  413.  
  414.     ror    dl,1            ;move over a dest bit.
  415.     adc    di,0            ;if cy, move over in di.
  416. put_smaller_line_4:
  417.  
  418.     ror    dh,1            ;move over a source bit.
  419.     adc    si,0
  420.     loop    put_smaller_line_1    ;no.
  421.  
  422.     cmp    dh,80h            ;did we use any of the dest bits?
  423.     je    put_smaller_line_5    ;no.
  424.     inc    si            ;yes - skip to next byte.
  425. put_smaller_line_5:
  426.     pop    ds
  427.     assume    ds:_DATA
  428.     ret
  429.  
  430.  
  431. put_sized_j_1:
  432.     jmp    put_sized
  433.  
  434.     public    _blit
  435. _blit:
  436.     push    bp
  437.     mov    bp,sp
  438.     push    si
  439.     push    di
  440.     mov    si,4[bp]
  441.     mov    di,6[bp]
  442.     mov    ax,8[bp]
  443.     mov    put_byte_subr,ax
  444.     call    blit
  445.     pop    di
  446.     pop    si
  447.     pop    bp
  448.     ret
  449.  
  450. blit_1:
  451.     ret
  452. blit:
  453. ;enter with si->source bitmap, di->dest bitmap, put_byte_subr=transfer mode.
  454.     mov    ax,[si].right        ;compute the h size.
  455.     sub    ax,[si].left
  456.     je    blit_1            ;if empty, exit now.
  457.     mov    bit_count,ax
  458.     mov    ax,[si].bot        ;compute the v size.
  459.     sub    ax,[si].top
  460.     je    blit_1            ;if empty, exit now.
  461.     mov    line_count,ax
  462.  
  463.     mov    bp,[di].left        ;compute the destination alignment.
  464.     and    bp,7
  465.  
  466.     mov    ax,[si].left        ;compute the source alignment.
  467.     and    ax,7
  468.     mov    src_align,ax
  469.  
  470.     mov    ax,[si].bytes        ;get the source width.
  471.     mov    src_bytes,ax
  472.  
  473.     mov    ax,[di].bytes        ;get the destination width.
  474.     mov    dest_bytes,ax
  475.  
  476.     mov    ax,[di].right        ;are we changing the h size?
  477.     sub    ax,[di].left
  478.     cmp    ax,bit_count
  479.     jne    put_sized_j_1        ;yes.
  480.     mov    ax,[di].bot        ;are we changing the v size?
  481.     sub    ax,[di].top
  482.     cmp    ax,line_count
  483.     jne    put_sized_j_1        ;yes.
  484.  
  485.     cmp    bit_count,8        ;does it fit in one byte?
  486.     jbe    blit_2            ;yes - do it "quickly"
  487.     jmp    compile_blit        ;no - do it "slowly"
  488. blit_2:
  489.     call    blit_setup
  490.  
  491.     mov    dx,00ffh        ;compute the mask.
  492.     mov    cx,bit_count
  493.     ror    dx,cl            ;make the necessary number of bits.
  494.  
  495.     mov    dl,0            ;get rid of the unnecessary bits.
  496.     mov    cx,bp
  497.     shr    dx,cl            ;shift the mask to where it should be.
  498.  
  499.     mov    cx,bp            ;shift count is dest align-src align.
  500.     sub    cx,src_align
  501.     and    cl,16-1            ;only 16 bits in a register.
  502.  
  503.     mov    bx,put_byte_subr    ;get the byte store routine.
  504.     mov    bp,dest_bytes
  505.     dec    bp
  506.     push    ds            ;save our data segment,
  507.     mov    ds,ax            ;  and get the source segment.
  508.     assume    ds:nothing
  509. blit_3:
  510.     mov    ax,[si]            ;get the byte into ax
  511.     add    si,src_bytes        ;move down a line.
  512.     ror    ax,cl            ;shift it to where it should be.
  513.     xchg    dh,dl
  514. ;put the byte in al at es:di using the mask in dl
  515.     call    bx            ;bx=put_byte_subr
  516.     inc    di            ;move over one byte.
  517.     xchg    dh,dl            ;get the right mask.
  518.     mov    al,ah            ;get the right byte.
  519.     call    bx            ;bx=put_byte_subr
  520.     add    di,bp            ;bp=dest_bytes.
  521.     dec    line_count
  522.     jne    blit_3
  523.  
  524.     pop    ds
  525.     assume    ds:_DATA
  526.     ret
  527.  
  528.  
  529. copy_code    macro
  530.     lodsw
  531.     mov    cx,ax
  532.     rep    movsb
  533.     endm
  534.  
  535.  
  536. compile_blit:
  537.  
  538.     push    si
  539.     push    di
  540.  
  541.     push    cs
  542.     pop    es
  543.     mov    di,offset put_rect_subr
  544.  
  545. ;in the following code, bp is the destination alignment,
  546. ;  dx is the byte count, si and cx are scratch, bx is used temporarily,
  547. ;  and es:di->the code that we're compiling.
  548.  
  549.     cmp    bp,src_align
  550.     je    compile_aligned
  551.     jmp    compile_shifted
  552. compile_aligned:
  553.     push    di            ;remember where to loop back to.
  554.  
  555.     mov    bx,bit_count        ;get the number of bits left to do.
  556.  
  557.     or    bp,bp            ;dest alignment zero?
  558.     je    compile_aligned_2    ;yes - don't mask on the left.
  559.  
  560.     mov    al,0b2h            ;opcode of "mov dl,immed8"
  561.     mov    cx,bp            ;store the mask.
  562.     mov    ah,0ffh
  563.     shr    ah,cl
  564.     stosw
  565.  
  566.     mov    al,0ach            ;opcode of lodsb
  567.     stosb
  568.  
  569.     mov    si,put_byte_subr    ;compile the masked version.
  570.     mov    si,cs:[si-2]
  571.     copy_code
  572.  
  573.     add    bx,bp            ;say that we've done the first few bits.
  574.     sub    bx,8            ;. .
  575. compile_aligned_2:
  576.     shr    bx,1            ;truncate to an even number of bytes.
  577.     shr    bx,1
  578.     shr    bx,1
  579.     cmp    put_byte_subr,offset _pset_verb    ;are we doing pset?
  580.     jne    compile_aligned_7    ;no - have to do it "slowly"
  581.  
  582.     shr    bx,1            ;prepare to move words.
  583.     jnc    compile_aligned_8    ;is the count odd? go if not.
  584.     mov    al,0a4h            ;opcode of "movsb"
  585.     stosb
  586. compile_aligned_8:
  587.     mov    al,0b9h            ;opcode of "mov cx,immed16"
  588.     stosb
  589.     mov    ax,bx
  590.     stosw
  591.     mov    ax,0f3h + 0a5h*256    ;opcode of "rep movsw"
  592.     stosw
  593.     jmp    short compile_aligned_5
  594. compile_aligned_7:
  595.     mov    dx,bx            ;remember the total number of bytes.
  596.     inc    bx            ;round up.
  597.     shr    bx,1            ;remember the number of loop iterations.
  598.     or    bx,bx            ;are there any iterations at all?
  599.     je    compile_aligned_5    ;no - skip the loop.
  600.     mov    al,0b9h            ;opcode of "mov cx,immed16"
  601.     stosb
  602.     mov    ax,bx
  603.     stosw
  604.  
  605.     test    dx,1            ;do we need to jump to the second store?
  606.     je    compile_aligned_6    ;no.
  607.     mov    ax,0ebh + 256*0        ;opcode of "jmp short $+2"
  608.     stosw
  609. compile_aligned_6:
  610.  
  611.     mov    bx,di            ;remember where the jump is.
  612. ;bx now holds the offset of the jump into the loop, which is also
  613. ;  the beginning of the loop.
  614.  
  615.     mov    al,0ach            ;opcode of lodsb
  616.     stosb
  617.  
  618.     mov    si,put_byte_subr    ;compile the unmasked version.
  619.     mov    si,cs:[si-4]        ;get the address of it.
  620.     copy_code
  621.  
  622.     test    dx,1            ;are we jumping into the loop here?
  623.     je    compile_aligned_4    ;no.
  624.     mov    ax,di            ;yes - compute the jump offset.
  625.     sub    ax,bx
  626.     mov    cs:[bx-1],al        ;store it.
  627. compile_aligned_4:
  628.  
  629.     mov    al,0ach            ;opcode of lodsb
  630.     stosb
  631.  
  632.     mov    si,put_byte_subr    ;compile the unmasked version.
  633.     mov    si,cs:[si-4]        ;get the address of it.
  634.     copy_code
  635.  
  636.     mov    al,0e2h            ;opcode of "loop"
  637.     stosb
  638.  
  639.     mov    ax,bx            ;compute the jump offset.
  640.     sub    ax,di
  641.     dec    ax            ;because bx->jump offset, not afterward.
  642.     stosb
  643.  
  644. compile_aligned_5:
  645.     mov    cx,bit_count
  646.     add    cx,bp            ;dest_align
  647.     and    cx,7            ;does it align to a right edge?
  648.     je    compile_aligned_1    ;yes - skip the right mask.
  649.  
  650. ;cx now holds the right mask bit count.
  651.     mov    ax,00ffh        ;rotate the bits into ah.
  652.     ror    ax,cl
  653.     mov    al,0b2h            ;opcode of "mov dl,immed8"
  654.     stosw
  655.  
  656.     mov    al,0ach            ;opcode of lodsb
  657.     stosb
  658.  
  659.     mov    si,put_byte_subr    ;compile the masked version.
  660.     mov    si,cs:[si-2]
  661.     copy_code
  662.  
  663. compile_aligned_1:
  664.     jmp    compile_blit_2        ;join with the shifting code.
  665.  
  666.  
  667. compile_shifted:
  668.     mov    si,src_align        ;use the proper get byte routine.
  669.     sub    si,bp
  670.     and    si,7            ;only eight different ones.
  671.     shl    si,1            ;index into word table.
  672.     mov    si,get_ptrs[si]
  673.     mov    get_byte_ptr,si
  674.  
  675.     mov    al,0b1h            ;opcode of "mov cl,immed8"
  676.     stosb
  677.     mov    ax,src_align        ;shift count is src align-dest align.
  678.     sub    ax,bp
  679.     and    al,7            ;don't shift too far.
  680.     stosb
  681.  
  682.     cmp    bp,src_align        ;if we're shifting right, we need to
  683.     jbe    compile_shifted_0    ;  backup the source by one.
  684.     mov    al,4eh            ;opcode of "dec si"
  685.     stosb
  686. compile_shifted_0:
  687.  
  688.     push    di            ;remember where the loop code starts.
  689.  
  690.     mov    bx,bit_count        ;get the bit count.
  691.  
  692.     or    bp,bp            ;is dest alignment zero?
  693.     je    compile_shifted_2    ;yes - don't bother masking the left.
  694.  
  695.     mov    al,0b2h            ;opcode of "mov dl,immed8"
  696.     mov    cx,bp            ;store the mask.
  697.     mov    ah,0ffh
  698.     shr    ah,cl
  699.     stosw
  700.  
  701.     mov    si,get_byte_ptr        ;compile the code to get a byte.
  702.     copy_code
  703.  
  704.     mov    si,put_byte_subr    ;compile the masked version.
  705.     mov    si,cs:[si-2]
  706.     copy_code
  707.  
  708.     add    bx,bp            ;say that we've done the first few bits.
  709.     sub    bx,8            ;. .
  710. compile_shifted_2:
  711.  
  712.     shr    bx,1            ;truncate to an even number of bytes.
  713.     shr    bx,1
  714.     shr    bx,1
  715.     mov    dx,bx            ;remember the total number of bytes.
  716.     inc    bx            ;round up.
  717.     shr    bx,1            ;remember the number of loop iterations.
  718.     or    bx,bx            ;are there any iterations at all?
  719.     je    compile_shifted_5    ;no - skip the loop.
  720.  
  721.     mov    al,0bbh            ;opcode of "mov bx,immed16"
  722.     stosb
  723.     mov    ax,bx
  724.     stosw
  725.  
  726.     test    dx,1            ;do we need to jump to the second store?
  727.     je    compile_shifted_6    ;no.
  728.     mov    ax,0ebh + 256*0        ;opcode of "jmp short $+2"
  729.     stosw
  730. compile_shifted_6:
  731.  
  732.     mov    bx,di            ;remember where the jump is.
  733. ;bx now holds the offset of the jump into the loop, which is also
  734. ;  the beginning of the loop.
  735.  
  736.     mov    si,get_byte_ptr        ;compile the code to get a byte.
  737.     copy_code
  738.  
  739.     mov    si,put_byte_subr    ;compile the unmasked version.
  740.     mov    si,cs:[si-4]        ;get the address of it.
  741.     copy_code
  742.  
  743.     test    dx,1            ;are we jumping into the loop here?
  744.     je    compile_shifted_4    ;no.
  745.     mov    ax,di            ;yes - compute the jump offset.
  746.     sub    ax,bx
  747.     mov    cs:[bx-1],al        ;store it.
  748. compile_shifted_4:
  749.  
  750.     mov    si,get_byte_ptr        ;compile the code to get a byte.
  751.     copy_code
  752.  
  753.     mov    si,put_byte_subr    ;compile the unmasked version.
  754.     mov    si,cs:[si-4]        ;get the address of it.
  755.     copy_code
  756.  
  757.     mov    ax,4bh + 256*75h    ;opcodes of "dec bx" and "jne"
  758.     stosw
  759.  
  760.     mov    ax,bx            ;compute the jump offset.
  761.     sub    ax,di
  762.     dec    ax            ;because bx->jump offset, not afterward.
  763.     stosb
  764.  
  765. compile_shifted_5:
  766.     mov    cx,bit_count
  767.     add    cx,bp            ;dest_align
  768.     and    cx,7            ;does it align to a right edge?
  769.     je    compile_blit_2        ;yes - skip the right mask.
  770.  
  771. ;bx now holds the right mask bit count.
  772.     mov    ax,00ffh        ;rotate the bits into ah.
  773.     ror    ax,cl
  774.     mov    al,0b2h            ;opcode of "mov dl,immed8"
  775.     stosw
  776.  
  777.     mov    si,get_byte_ptr        ;compile the code to get a byte.
  778.     copy_code
  779.  
  780.     mov    si,put_byte_subr    ;compile the masked version.
  781.     mov    si,cs:[si-2]
  782.     copy_code
  783.  
  784. compile_blit_2:
  785. ;compute the number of bytes that we've affected.
  786.     mov    ax,81h+11000111b*256    ;opcode of "add di,immed16"
  787.     stosw
  788.  
  789.     mov    bx,bit_count        ;get the bit count.
  790.     add    bx,bp            ;add align (take care of left edge)
  791.     add    bx,7            ;round up (take care of right edge)
  792.     shr    bx,1
  793.     shr    bx,1
  794.     shr    bx,1
  795.  
  796.     mov    ax,dest_bytes        ;get the width of the dest bitmap.
  797.     sub    ax,bx            ;sub the number of bytes we've done.
  798.     stosw                ;ax=# bytes to next line.
  799.  
  800.     mov    ax,81h+11000110b*256    ;opcode of "add si,immed16"
  801.     stosw
  802.  
  803.     mov    ax,src_bytes        ;get the width of the dest bitmap.
  804.     sub    ax,bx            ;sub the number of bytes we've done.
  805.     stosw                ;ax=# bytes to next line.
  806.  
  807.     mov    ax,4dh + 256*75h    ;opcodes of "dec bp" and "jne"
  808.     stosw
  809.  
  810.     pop    ax            ;jump back to the beginning.
  811.     sub    ax,di            ;subtract target-(di+1),
  812.     dec    ax            ;  because di->after opcode, not operand
  813.     stosb                ;store the jump offset
  814.  
  815. ;if we're shifting right, include the following code:
  816.     cmp    bp,src_align        ;are we shifting right?
  817.     jbe    compile_blit_3        ;no.
  818.     mov    al,46h            ;opcode of "inc si"
  819.     stosb
  820. compile_blit_3:
  821.  
  822.     mov    ax,01fh + 0c3h*256    ;opcodes of "pop ds" and  "ret"
  823.     stosw
  824.  
  825.     pop    di            ;restore the bitmap pointers.
  826.     pop    si
  827.  
  828.     mov    bp,line_count        ;get the scan line count.
  829.     call    blit_setup
  830.     push    ds
  831.     mov    ds,ax
  832.  
  833. put_rect_subr:
  834.     db    100h dup(90h)
  835.  
  836.  
  837. blit_setup:
  838. ;enter with ds:si->source bitmap, ds:di->dest bitmap.
  839. ;exit with ax:si->source bits, es:di->dest bits
  840.     mov    bx,[di].left        ;get x
  841.     shr    bx,1            ;get rid of bit position
  842.     shr    bx,1
  843.     shr    bx,1
  844.     mov    ax,[di].top        ;compute y-position*dest_bytes
  845.     mul    [di].bytes
  846.     add    bx,ax
  847.     les    di,[di].pntr        ;get the pointer to the bitmap.
  848.     add    di,bx            ;add the offset into the bitmap.
  849.  
  850.     mov    bx,[si].left        ;get x
  851.     shr    bx,1            ;get rid of bit position
  852.     shr    bx,1
  853.     shr    bx,1
  854.     mov    ax,[si].top        ;compute y-position*src_bytes
  855.     mul    [si].bytes
  856.     add    bx,ax
  857.     mov    ax,[si].pntr.segm    ;get the segment into ax.
  858.     mov    si,[si].pntr.offs    ;get the offset into si.
  859.     add    si,bx            ;add the offset into the bitmap.
  860.     ret
  861.  
  862.  
  863. put_scan_line:
  864. ;ds:si->array, es:di->screen, bx=bit count, bp=destination alignment
  865. ;don't destroy bp.
  866.     mov    cx,bp            ;get destination alignment.
  867.     jcxz    put_noshift        ;go if it aligns.
  868.     mov    dl,0ffh            ;al=source mask
  869.     shr    dl,cl
  870.     mov    al,[si]            ;dh=source byte
  871.     shr    al,cl            ;align to screen byte.
  872.     add    bx,bp            ;pretend that we've done a whole byte.
  873.     sub    bx,8            ;more bytes?
  874.     jle    put_scan_line_2
  875.     mov    cx,8            ;make cl=8-shift count.
  876.     sub    cx,bp
  877.     cmp    put_byte_subr,offset _pset_verb
  878.     je    put_scan_line_8
  879.     call    put_byte_subr
  880.     inc    di            ;go to the next byte.
  881.     mov    dl,0ffh            ;eight bits in the rest of the bytes.
  882.     jmp    short put_scan_line_5
  883. put_scan_line_8:
  884.     mov    ah,es:[di]        ;get the dest byte.
  885.     xor    al,ah            ;flip the pattern using the dest bits.
  886.     and    al,dl            ;get rid of the bits we won't change.
  887.     xor    al,ah            ;flip using only the bits that change.
  888. put_scan_line_7:
  889.     stosb
  890.     mov    ax,[si]            ;get the next two bytes.
  891.     inc    si            ;go to the this byte.
  892.     rol    ax,cl            ;align to screen byte.
  893.     sub    bx,8            ;more bytes?
  894.     ja    put_scan_line_7        ;yes - keep doing them
  895.     mov    dl,0ffh            ;eight bits in the next byte.
  896.     jmp    short put_scan_line_2    ;no - finish off the last.
  897. put_scan_line_4:
  898. ;put the byte in al at es:di using the mask in dl
  899.     call    put_byte_subr
  900.     inc    di
  901. put_scan_line_5:
  902.     mov    ax,[si]            ;get the next two bytes.
  903.     inc    si            ;go to the next byte.
  904.     rol    ax,cl            ;align to screen byte.
  905.     sub    bx,8            ;more bytes?
  906.     ja    put_scan_line_4        ;yes - keep doing them
  907. put_scan_line_2:
  908.     add    bx,8
  909.     mov    cl,bl
  910.     shr    dl,cl
  911.     not    dl            ;we're not including the bits to the right.
  912.     call    put_byte_subr
  913.     cmp    bp,bx            ;did we use any bits from the right byte.
  914.     jae    put_scan_line_3        ;no.
  915.     inc    si            ;yes - skip past it.
  916. put_scan_line_3:
  917.     ret
  918.  
  919.  
  920. put_noshift:
  921. ;ds:si->array, es:di->screen, bx=bit count, bp=destination alignment (0).
  922.     mov    dl,0ffh            ;eight bits in the rest of the bytes.
  923.     mov    cx,bx
  924.     shr    cx,1
  925.     shr    cx,1
  926.     shr    cx,1
  927.     and    bx,7
  928.     jcxz    put_noshift_2
  929.     cmp    put_byte_subr,offset _pset_verb
  930.     jne    put_noshift_4
  931.     shr    cx,1            ;move words.
  932.     jnc    put_noshift_1
  933.     movsb
  934. put_noshift_1:
  935.     rep    movsw
  936.     jmp    short put_noshift_2
  937. put_noshift_4:
  938. ;put the byte in al at es:di using the mask in dl
  939.     lodsb
  940.     call    put_byte_subr
  941.     inc    di
  942.     loop    put_noshift_4
  943. put_noshift_2:
  944.     mov    cx,bx            ;get the number of bits in the next byte.
  945.     jcxz    put_noshift_3        ;if none, just skip.
  946.     mov    al,[si]
  947.     inc    si
  948.     mov    dx,0ff00h        ;shift the bits in from ah.
  949.     shr    dx,cl
  950.     call    put_byte_subr
  951. put_noshift_3:
  952.     ret
  953.  
  954.  
  955. ;note that the two words previous to the given verb must be the offsets
  956. ;  (in the data segment!) of two routines.  The first (cs:put_byte_subr-4) is
  957. ;  a routine that puts the byte in al with a mask of 0ffh.  The second
  958. ;  (cs:put_byte_subr-2) is a routine that puts the byte in al using the mask
  959. ;  in dl.
  960.  
  961. ;new    old
  962. ;    | 0   1
  963. ;-----------
  964. ;  0 | 0   0
  965. ;  1 | 1   1
  966.     dw    pset_verb_1
  967.     dw    pset_verb_2
  968.     public    _pset_verb
  969. _pset_verb:
  970.     xor    al,es:[di]
  971.     and    al,dl
  972.     xor    es:[di],al
  973.     ret
  974.  
  975.  
  976. ;new    old
  977. ;    | 0   1
  978. ;-----------
  979. ;  0 | 0   1
  980. ;  1 | 0   0
  981.     dw    and_not_verb_1
  982.     dw    and_not_verb_2
  983.     public    _and_not_verb
  984. _and_not_verb:
  985.     not    al
  986.     not    dl
  987.     or    al,dl
  988.     not    dl
  989.     and    es:[di],al
  990.     ret
  991.  
  992.  
  993. ;new    old
  994. ;    | 0   1
  995. ;-----------
  996. ;  0 | 1   1
  997. ;  1 | 0   0
  998.     dw    preset_verb_1
  999.     dw    preset_verb_2
  1000.     public    _preset_verb
  1001. _preset_verb:
  1002.     not    al
  1003.     xor    al,es:[di]
  1004.     and    al,dl
  1005.     xor    es:[di],al
  1006.     ret
  1007.  
  1008.  
  1009. ;new    old
  1010. ;    | 0   1
  1011. ;-----------
  1012. ;  0 | 0   0
  1013. ;  1 | 0   1
  1014.     dw    and_verb_1
  1015.     dw    and_verb_2
  1016.     public    _and_verb
  1017. _and_verb:
  1018.     not    dl
  1019.     or    al,dl
  1020.     not    dl
  1021.     and    es:[di],al
  1022.     ret
  1023.  
  1024.  
  1025. ;new    old
  1026. ;    | 0   1
  1027. ;-----------
  1028. ;  0 | 0   1
  1029. ;  1 | 1   1
  1030.     dw    or_verb_1
  1031.     dw    or_verb_2
  1032.     public    _or_verb
  1033. _or_verb:
  1034.     and    al,dl            ;only set the bits given in dl.
  1035.     or    es:[di],al
  1036.     ret
  1037.  
  1038.  
  1039. ;new    old
  1040. ;    | 0   1
  1041. ;-----------
  1042. ;  0 | 1   1
  1043. ;  1 | 0   1
  1044.     dw    or_not_verb_1
  1045.     dw    or_not_verb_2
  1046.     public    _or_not_verb
  1047. _or_not_verb:
  1048.     not    al
  1049.     and    al,dl            ;only set the bits given in dl.
  1050.     or    es:[di],al
  1051.     ret
  1052.  
  1053.  
  1054. ;new    old
  1055. ;    | 0   1
  1056. ;-----------
  1057. ;  0 | 0   1
  1058. ;  1 | 1   0
  1059.     dw    xor_verb_1
  1060.     dw    xor_verb_2
  1061.     public    _xor_verb
  1062. _xor_verb:
  1063.     and    al,dl            ;only xor the bits given in dl.
  1064.     xor    es:[di],al
  1065.     ret
  1066.  
  1067.  
  1068. _TEXT    ends
  1069.  
  1070.     end
  1071.