1 ; Catacomb Armageddon Source Code
\r
2 ; Copyright (C) 1993-2014 Flat Rock Software
\r
4 ; This program is free software; you can redistribute it and/or modify
\r
5 ; it under the terms of the GNU General Public License as published by
\r
6 ; the Free Software Foundation; either version 2 of the License, or
\r
7 ; (at your option) any later version.
\r
9 ; This program is distributed in the hope that it will be useful,
\r
10 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 ; GNU General Public License for more details.
\r
14 ; You should have received a copy of the GNU General Public License along
\r
15 ; with this program; if not, write to the Free Software Foundation, Inc.,
\r
16 ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
18 ;=================================
\r
20 ; EGA view manager routines
\r
22 ;=================================
\r
24 ;============================================================================
\r
26 ; All EGA drawing routines that write out words need to have alternate forms
\r
27 ; for starting on even and odd addresses, because writing a word at segment
\r
28 ; offset 0xffff causes an exception! To work around this, write a single
\r
29 ; byte out to make the address even, so it wraps cleanly at the end.
\r
31 ; All of these routines assume read/write mode 0, and will allways return
\r
33 ; The direction flag should be clear
\r
34 ; readmap/writemask is left in an undefined state
\r
36 ;============================================================================
\r
39 ;============================================================================
\r
41 ; VW_Plot (int x,y,color)
\r
43 ;============================================================================
\r
47 plotpixels db 128,64,32,16,8,4,2,1
\r
51 PROC VW_Plot x:WORD, y:WORD, color:WORD
\r
58 mov ax,SC_MAPMASK+15*256
\r
62 mov ax,GC_MODE+2*256 ;write mode 2
\r
74 add di,ax ; di = byte on screen
\r
77 mov ah,[plotpixels+bx]
\r
78 mov al,GC_BITMASK ;mask off other pixels
\r
82 xchg bl,[es:di] ; load latches and write pixel
\r
85 mov ah,0ffh ;no bit mask
\r
87 mov ax,GC_MODE+0*256 ;write mode 0
\r
95 ;============================================================================
\r
97 ; VW_Vlin (int yl,yh,x,color)
\r
99 ;============================================================================
\r
101 PROC VW_Vlin yl:WORD, yh:WORD, x:WORD, color:WORD
\r
108 mov ax,SC_MAPMASK+15*256
\r
112 mov ax,GC_MODE+2*256 ;write mode 2
\r
118 add di,[ylookup+bx]
\r
124 add di,ax ; di = byte on screen
\r
127 mov ah,[plotpixels+bx]
\r
128 mov al,GC_BITMASK ;mask off other pixels
\r
133 inc cx ;number of pixels to plot
\r
135 mov bh,[BYTE color]
\r
140 xchg bl,[es:di] ; load latches and write pixel
\r
146 mov ah,0ffh ;no bit mask
\r
148 mov ax,GC_MODE+0*256 ;write mode 0
\r
156 ;============================================================================
\r
159 ;===================
\r
163 ; xcoord in bytes (8 pixels), ycoord in pixels
\r
164 ; All Tile8s are in one grseg, so an offset is calculated inside it
\r
166 ;===================
\r
168 PROC VW_DrawTile8 xcoord:WORD, ycoord:WORD, tile:WORD
\r
169 PUBLIC VW_DrawTile8
\r
178 add di,[ylookup+bx]
\r
179 mov [ss:screendest],di ;screen destination
\r
191 mov ds,[grsegs+STARTTILE8*2] ; segment for all tile8s
\r
193 mov cx,4 ;planes to draw
\r
194 mov ah,0001b ;map mask
\r
205 shl ah,1 ;shift plane mask over for next plane
\r
207 mov di,[ss:screendest] ;start at same place in all planes
\r
218 mov ds,ax ;restore turbo's data segment
\r
225 ;============================================================================
\r
229 ; Draws a masked block shape to the screen. bufferofs is NOT accounted for.
\r
230 ; The mask comes first, then four planes of data.
\r
232 ;============================================================================
\r
239 maskroutines dw mask0,mask0,mask1E,mask1E,mask2E,mask2O,mask3E,mask3O
\r
240 dw mask4E,mask4O,mask5E,mask5O,mask6E,mask6O
\r
241 dw mask7E,mask7O,mask8E,mask8O,mask9E,mask9O
\r
249 PROC VW_MaskBlock segm:WORD, ofs:WORD, dest:WORD, wide:WORD, height:WORD, planesize:WORD
\r
250 PUBLIC VW_MaskBlock
\r
255 mov [BYTE planemask],1
\r
256 mov [BYTE planenum],0
\r
261 mov [linedelta],dx ;amount to add after drawing each line
\r
263 mov bx,[planesize] ; si+bx = data location
\r
265 cmp di,UNWOUNDMASKS
\r
266 jbe @@unwoundroutine
\r
267 mov [routinetouse],OFFSET generalmask
\r
268 jmp NEAR @@startloop
\r
272 ; use the unwound routines
\r
279 rcl di,1 ;shift a 1 in if destination is odd
\r
280 shl di,1 ;to index into a word width table
\r
281 mov ax,[maskroutines+di] ;call the right routine
\r
282 mov [routinetouse],ax
\r
290 mov ah,[ss:planemask]
\r
294 mov ah,[ss:planenum]
\r
297 mov si,[ofs] ;start back at the top of the mask
\r
298 mov di,[dest] ;start at same place in all planes
\r
299 mov cx,[height] ;scan lines to draw
\r
300 mov dx,[ss:linedelta]
\r
302 jmp [ss:routinetouse] ;draw one plane
\r
303 planereturn: ;routine jmps back here
\r
305 add bx,[ss:planesize] ;start of mask = start of next plane
\r
308 shl [ss:planemask],1 ;shift plane mask over for next plane
\r
309 cmp [ss:planemask],10000b ;done all four planes?
\r
315 ret ;width of 0 = no drawing
\r
319 ; General purpose masked block drawing. This could be optimised into
\r
320 ; four routines to use words, but few play loop sprites should be this big!
\r
337 add di,[ss:linedelta]
\r
344 ; Horizontally unwound routines to draw certain masked blocks faster
\r
365 MACRO SPRITELOOP addr
\r
516 ;============================================================================
\r
518 ; VW_ScreenToScreen
\r
520 ; Basic block copy routine. Copies one block of screen memory to another,
\r
521 ; using write mode 1 (sets it and returns with write mode 0). bufferofs is
\r
522 ; NOT accounted for.
\r
524 ;============================================================================
\r
526 PROC VW_ScreenToScreen source:WORD, dest:WORD, wide:WORD, height:WORD
\r
527 PUBLIC VW_ScreenToScreen
\r
534 mov ax,SC_MAPMASK+15*256
\r
537 mov ax,GC_MODE+1*256
\r
550 mov di,[dest] ;start at same place in all planes
\r
551 mov dx,[height] ;scan lines to draw
\r
564 mov ax,GC_MODE+0*256
\r
568 mov ds,ax ;restore turbo's data segment
\r
575 ;============================================================================
\r
579 ; Basic block drawing routine. Takes a block shape at segment pointer source
\r
580 ; with four planes of width by height data, and draws it to dest in the
\r
581 ; virtual screen, based on linewidth. bufferofs is NOT accounted for.
\r
582 ; There are four drawing routines to provide the best optimized code while
\r
583 ; accounting for odd segment wrappings due to the floating screens.
\r
585 ;============================================================================
\r
589 memtoscreentable dw eventoeven,eventoodd,oddtoeven,oddtoodd
\r
594 PROC VW_MemToScreen source:WORD, dest:WORD, wide:WORD, height:WORD
\r
595 PUBLIC VW_MemToScreen
\r
606 xor si,si ;block is segment aligned
\r
609 shr [wide],1 ;change wide to words, and see if carry is set
\r
610 rcl di,1 ;1 if wide is odd
\r
613 rcl di,1 ;shift a 1 in if destination is odd
\r
614 shl di,1 ;to index into a word width table
\r
615 mov ax,SC_MAPMASK+0001b*256 ;map mask for plane 0
\r
616 jmp [ss:memtoscreentable+di] ;call the right routine
\r
620 ; Copy an even width block to an even video address
\r
628 mov di,[dest] ;start at same place in all planes
\r
629 mov dx,[height] ;scan lines to draw
\r
640 shl ah,1 ;shift plane mask over for next plane
\r
641 cmp ah,10000b ;done all four planes?
\r
645 mov ds,ax ;restore turbo's data segment
\r
651 ; Copy an odd width block to an even video address
\r
659 mov di,[dest] ;start at same place in all planes
\r
660 mov dx,[height] ;scan lines to draw
\r
665 movsb ;copy the last byte
\r
672 shl ah,1 ;shift plane mask over for next plane
\r
673 cmp ah,10000b ;done all four planes?
\r
677 mov ds,ax ;restore turbo's data segment
\r
683 ; Copy an even width block to an odd video address
\r
688 dec [wide] ;one word has to be handled seperately
\r
693 mov di,[dest] ;start at same place in all planes
\r
694 mov dx,[height] ;scan lines to draw
\r
707 shl ah,1 ;shift plane mask over for next plane
\r
708 cmp ah,10000b ;done all four planes?
\r
712 mov ds,ax ;restore turbo's data segment
\r
718 ; Copy an odd width block to an odd video address
\r
726 mov di,[dest] ;start at same place in all planes
\r
727 mov dx,[height] ;scan lines to draw
\r
739 shl ah,1 ;shift plane mask over for next plane
\r
740 cmp ah,10000b ;done all four planes?
\r
744 mov ds,ax ;restore turbo's data segment
\r
751 ; MDM (GAMERS EDGE) begin
\r
755 test al,128 ; handle bit 7
\r
757 or [BYTE PTR es:di],11000000b
\r
760 test al,64 ; handle bit 6
\r
762 or [BYTE PTR es:di],00110000b
\r
765 test al,32 ; handle bit 5
\r
767 or [BYTE PTR es:di],00001100b
\r
770 test al,16 ; handle bit 4
\r
772 or [BYTE PTR es:di],00000011b
\r
775 inc di ; inc destination
\r
777 test al,8 ; handle bit 3
\r
779 or [BYTE PTR es:di],11000000b
\r
782 test al,4 ; handle bit 2
\r
784 or [BYTE PTR es:di],00110000b
\r
787 test al,2 ; handle bit 1
\r
789 or [BYTE PTR es:di],00001100b
\r
792 test al,1 ; handle bit 0
\r
794 or [BYTE PTR es:di],00000011b
\r
797 inc si ; inc source
\r
798 inc di ; inc destination
\r
802 ;============================================================================
\r
806 ; Basic block drawing routine. Takes a block shape at segment pointer source
\r
807 ; with four planes of width by height data, and draws it to dest in the
\r
808 ; virtual screen, based on linewidth. bufferofs is NOT accounted for.
\r
809 ; There are four drawing routines to provide the best optimized code while
\r
810 ; accounting for odd segment wrappings due to the floating screens.
\r
812 ;============================================================================
\r
816 xpandhorz db 00000000b,00000011b,00001100b,00001111b
\r
817 db 00110000b,00110011b,00111100b,00111111b
\r
818 db 11000000b,11000011b,11001100b,11001111b
\r
819 db 11110000b,11110011b,11111100b,11111111b
\r
824 PROC VW_MemToScreen2x source:WORD, dest:WORD, wide:WORD, height:WORD
\r
825 PUBLIC VW_MemToScreen2x
\r
837 xor si,si ;block is segment aligned
\r
839 mov ah,0001b ;map mask for plane 0
\r
842 mov al,SC_MAPMASK ;restore map mask in al
\r
846 mov di,[dest] ;start at same place in all planes
\r
847 mov dx,[height] ;scan lines to draw
\r
853 ; handle first nybble
\r
862 mov al,[ss:xpandhorz+di]
\r
867 ; handle second nybble
\r
872 mov al,[ss:xpandhorz+di]
\r
887 shl ah,1 ;shift plane mask over for next plane
\r
888 cmp ah,10000b ;done all four planes?
\r
892 mov ds,ax ;restore turbo's data segment
\r
897 ; MDM (GAMERS EDGE) end
\r
899 ;===========================================================================
\r
903 ; Copies a block of video memory to main memory, in order from planes 0-3.
\r
904 ; This could be optimized along the lines of VW_MemToScreen to take advantage
\r
905 ; of word copies, but this is an infrequently called routine.
\r
907 ;===========================================================================
\r
909 PROC VW_ScreenToMem source:WORD, dest:WORD, wide:WORD, height:WORD
\r
910 PUBLIC VW_ScreenToMem
\r
920 mov ax,GC_READMAP ;read map for plane 0
\r
928 mov si,[source] ;start at same place in all planes
\r
929 mov dx,[height] ;scan lines to draw
\r
941 cmp ah,4 ;done all four planes?
\r
945 mov ds,ax ;restore turbo's data segment
\r
952 ;============================================================================
\r
954 ; VWL_UpdateScreenBlocks
\r
956 ; Scans through the update matrix and copies any areas that have changed
\r
957 ; to the visable screen, then zeros the update array
\r
959 ;============================================================================
\r
963 ; AX 0/1 for scasb, temp for segment register transfers
\r
964 ; BX width for block copies
\r
966 ; DX line width deltas
\r
967 ; SI source for copies
\r
968 ; DI scas dest / movsb dest
\r
969 ; BP pointer to end of bufferblocks
\r
971 PROC VWL_UpdateScreenBlocks
\r
972 PUBLIC VWL_UpdateScreenBlocks
\r
975 jmp SHORT @@realstart
\r
978 ; all tiles have been scanned
\r
980 mov dx,GC_INDEX ; restore write mode 0
\r
981 mov ax,GC_MODE+0*256
\r
984 xor ax,ax ; clear out the update matrix
\r
985 mov cx,UPDATEWIDE*UPDATEHIGH/2
\r
994 mov ax,SC_MAPMASK+15*256
\r
997 mov ax,GC_MODE+1*256
\r
1000 mov di,[updateptr] ; start of floating update screen
\r
1002 add bp,UPDATEWIDE*UPDATEHIGH+1 ; when di = bp, all tiles have been scanned
\r
1005 mov cx,-1 ; definately scan the entire thing
\r
1008 ; scan for a 1 in the update list, meaning a tile needs to be copied
\r
1009 ; from the master screen to the current screen
\r
1012 pop di ; place to continue scaning from
\r
1014 mov es,ax ; search in the data segment
\r
1027 ; copy a single tile
\r
1031 inc di ; we know the next tile is nothing
\r
1032 push di ; save off the spot being scanned
\r
1033 sub di,[updateptr]
\r
1035 mov di,[blockstarts-4+di] ; start of tile location on screen
\r
1037 add si,[bufferofs]
\r
1038 add di,[displayofs]
\r
1040 mov dx,[linewidth]
\r
1042 mov ax,[screenseg]
\r
1059 ; more than one tile in a row needs to be updated, so do it as a group
\r
1064 mov dx,di ; hold starting position + 1 in dx
\r
1065 inc di ; we know the next tile also gets updated
\r
1066 repe scasb ; see how many more in a row
\r
1067 push di ; save off the spot being scanned
\r
1070 sub bx,dx ; number of tiles in a row
\r
1071 shl bx,1 ; number of bytes / row
\r
1073 mov di,dx ; lookup position of start tile
\r
1074 sub di,[updateptr]
\r
1076 mov di,[blockstarts-2+di] ; start of tile location
\r
1078 add si,[bufferofs]
\r
1079 add di,[displayofs]
\r
1081 mov dx,[linewidth]
\r
1082 sub dx,bx ; offset to next line on screen
\r
1084 mov ax,[screenseg]
\r
1097 dec cx ; was 0 from last rep movsb, now $ffff for scasb
\r
1103 ;===========================================================================
\r
1105 ; MISC EGA ROUTINES
\r
1107 ;===========================================================================
\r
1115 PROC VW_SetScreen crtc:WORD, pel:WORD
\r
1116 PUBLIC VW_SetScreen
\r
1120 mov dx,STATUS_REGISTER_1
\r
1123 ; wait util the CRTC just starts scaning a diplayed line to set the CRTC start
\r
1130 jz @@waitnodisplay
\r
1132 ; the display is now disabled (in a HBL / VBL)
\r
1136 test al,1 ;1 = display is disabled (HBL / VBL)
\r
1139 ; the display was just enabled, so a full scan line is available for CRTC set
\r
1146 ; for some reason, my XT's EGA card doesn't like word outs to the CRTC
\r
1151 mov al,0ch ;start address high register
\r
1157 mov al,0dh ;start address low register
\r
1166 ; wait for a vertical retrace to set pel panning
\r
1168 mov dx,STATUS_REGISTER_1
\r
1170 sti ;service interrupts
\r
1174 test al,00001000b ;look for vertical retrace
\r
1180 ; set horizontal panning
\r
1184 mov al,ATR_PELPAN or 20h
\r
1187 mov al,[BYTE pel] ;pel pan value
\r
1197 if NUMFONT+NUMFONTM
\r
1199 ;===========================================================================
\r
1201 ; GENERAL FONT DRAWING ROUTINES
\r
1203 ;===========================================================================
\r
1207 px dw ? ; proportional character drawing coordinates
\r
1209 pdrawmode db 11000b ; 8 = OR, 24 = XOR, put in GC_DATAROTATE
\r
1210 fontcolor db 15 ;0-15 mapmask value
\r
1212 PUBLIC px,py,pdrawmode,fontcolor
\r
1215 ; offsets in font structure
\r
1217 pcharheight = 0 ;lines high
\r
1218 charloc = 2 ;pointers to every character
\r
1219 charwidth = 514 ;every character's width in pixels
\r
1222 propchar dw ? ; the character number to shift
\r
1226 BUFFWIDTH = 82 ; MDM (GAMERS EDGE) - increased from 50
\r
1227 BUFFHEIGHT = 20 ; must be twice as high as font for masked fonts
\r
1229 databuffer db BUFFWIDTH*BUFFHEIGHT dup (?)
\r
1231 bufferwidth dw ? ; bytes with valid info / line
\r
1232 bufferheight dw ? ; number of lines currently used
\r
1237 screenspot dw ? ; where the buffer is going
\r
1239 bufferextra dw ? ; add at end of a line copy
\r
1242 PUBLIC bufferwidth,bufferheight,screenspot
\r
1246 ;======================
\r
1248 ; Macros to table shift a byte of font
\r
1250 ;======================
\r
1253 mov al,[es:bx] ; source
\r
1257 mov ax,[bp+si] ; table shift into two bytes
\r
1258 or [di],al ; or with first byte
\r
1260 mov [di],ah ; replace next byte
\r
1261 inc bx ; next source byte
\r
1264 MACRO SHIFTWITHXOR
\r
1265 mov al,[es:bx] ; source
\r
1269 mov ax,[bp+si] ; table shift into two bytes
\r
1271 and [di],al ; and with first byte
\r
1273 mov [di],ah ; replace next byte
\r
1274 inc bx ; next source byte
\r
1278 ;=======================
\r
1282 ; Pass buffer start in SI (somewhere in databuffer)
\r
1283 ; Draws the buffer to the EGA screen in the current write mode
\r
1285 ;========================
\r
1287 PROC BufferToScreen NEAR
\r
1289 mov es,[screenseg]
\r
1290 mov di,[screenspot]
\r
1292 mov bx,[bufferwidth] ;calculate offsets for end of each line
\r
1295 ret ;nothing to draw
\r
1298 mov ax,[linewidth]
\r
1300 mov [screenextra],ax
\r
1303 mov [bufferextra],ax
\r
1305 mov bx,[bufferheight] ;lines to copy
\r
1307 mov cx,[bufferwidth] ;bytes to copy
\r
1309 lodsb ;get a byte from the buffer
\r
1310 xchg [es:di],al ;load latches and store back to screen
\r
1315 add si,[bufferextra]
\r
1316 add di,[screenextra]
\r
1325 ;============================================================================
\r
1327 ; NON MASKED FONT DRAWING ROUTINES
\r
1329 ;============================================================================
\r
1335 shiftdrawtable dw 0,shift1wide,shift2wide,shift3wide,shift4wide
\r
1340 ;==================
\r
1344 ; Call with BX = character number (0-255)
\r
1345 ; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts
\r
1346 ; them to the new position
\r
1348 ;==================
\r
1350 PROC ShiftPropChar NEAR
\r
1352 mov si,[fontnumber]
\r
1354 mov es,[grsegs+STARTFONT*2+si] ;segment of font to use
\r
1357 ; find character location, width, and height
\r
1359 mov si,[es:charwidth+bx]
\r
1360 and si,0ffh ;SI hold width in pixels
\r
1362 mov bx,[es:charloc+bx] ;BX holds pointer to character data
\r
1365 ; look up which shift table to use, based on bufferbit
\r
1367 mov di,[bufferbit]
\r
1369 mov bp,[shifttabletable+di] ;BP holds pointer to shift table
\r
1371 mov di,OFFSET databuffer
\r
1372 add di,[bufferbyte] ;DI holds pointer to buffer
\r
1375 ; advance position by character width
\r
1377 mov cx,[bufferbit]
\r
1378 add cx,si ;new bit position
\r
1381 mov [bufferbit],ax ;new bit position
\r
1386 add [bufferbyte],ax ;new byte position
\r
1391 shr si,1 ;bytes the character is wide
\r
1392 shl si,1 ;*2 to look up in shiftdrawtable
\r
1394 mov cx,[es:pcharheight]
\r
1396 jmp [ss:shiftdrawtable+si] ;procedure to draw this width
\r
1399 ; one byte character
\r
1406 add di,dx ; next line in buffer
\r
1411 ; two byte character
\r
1420 add di,dx ; next line in buffer
\r
1425 ; three byte character
\r
1434 add di,dx ; next line in buffer
\r
1439 ; four byte character
\r
1449 add di,dx ; next line in buffer
\r
1454 ; five byte character
\r
1464 add di,dx ; next line in buffer
\r
1472 ;============================================================================
\r
1474 ;==================
\r
1476 ; VW_DrawPropString
\r
1478 ; Draws a C string of characters at px/py and advances px
\r
1480 ; Assumes write mode 0
\r
1482 ;==================
\r
1486 PROC VW_DrawPropString string:DWORD
\r
1487 PUBLIC VW_DrawPropString
\r
1491 ; proportional spaceing, which clears the buffer ahead of it, so only
\r
1492 ; clear the first collumn
\r
1497 mov [BYTE databuffer+BUFFWIDTH*line],al
\r
1502 ; shift the characters into the buffer
\r
1507 mov [bufferbit],ax
\r
1508 mov [bufferbyte],0
\r
1510 mov ax,[WORD string]
\r
1511 mov [stringptr],ax
\r
1512 mov ax,[WORD string+2]
\r
1513 mov [stringptr+2],ax
\r
1516 mov es,[stringptr+2]
\r
1517 mov bx,[stringptr]
\r
1523 call ShiftPropChar
\r
1528 ; calculate position to draw buffer on screen
\r
1532 mov di,[ylookup+bx]
\r
1533 add di,[bufferofs]
\r
1534 add di,[panadjust]
\r
1539 shr ax,1 ;x location in bytes
\r
1541 mov [screenspot],di
\r
1546 mov ax,[bufferbyte]
\r
1559 mov al,GC_DATAROTATE
\r
1560 mov ah,[pdrawmode]
\r
1563 ; set mapmask to color
\r
1566 mov ah,[fontcolor]
\r
1569 mov ax,[bufferbyte]
\r
1570 test [bufferbit],7
\r
1572 inc ax ;so the partial byte also gets drawn
\r
1574 mov [bufferwidth],ax
\r
1575 mov si,[fontnumber]
\r
1577 mov es,[grsegs+STARTFONT*2+si]
\r
1578 mov ax,[es:pcharheight]
\r
1579 mov [bufferheight],ax
\r
1581 mov si,OFFSET databuffer
\r
1582 call BufferToScreen
\r
1586 mov ax,GC_DATAROTATE
\r
1589 ; set mapmask to all
\r
1591 mov ax,SC_MAPMASK + 15*256
\r
1601 ;============================================================================
\r
1603 ; MASKED FONT DRAWING ROUTINES
\r
1605 ;============================================================================
\r
1611 mshiftdrawtable dw 0,mshift1wide,mshift2wide,mshift3wide
\r
1616 ;==================
\r
1620 ; Call with BX = character number (0-255)
\r
1621 ; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts
\r
1622 ; them to the new position
\r
1624 ;==================
\r
1626 PROC ShiftMPropChar NEAR
\r
1628 mov si,[fontnumber]
\r
1630 mov es,[grsegs+STARTFONTM*2+si] ;segment of font to use
\r
1633 ; find character location, width, and height
\r
1635 mov si,[es:charwidth+bx]
\r
1636 and si,0ffh ;SI hold width in pixels
\r
1638 mov bx,[es:charloc+bx] ;BX holds pointer to character data
\r
1641 ; look up which shift table to use, based on bufferbit
\r
1643 mov di,[bufferbit]
\r
1645 mov bp,[shifttabletable+di] ;BP holds pointer to shift table
\r
1647 mov di,OFFSET databuffer
\r
1648 add di,[bufferbyte] ;DI holds pointer to buffer
\r
1650 mov cx,[bufferbit]
\r
1651 add cx,si ;new bit position
\r
1654 mov [bufferbit],ax ;new bit position
\r
1659 add [bufferbyte],ax ;new byte position
\r
1664 shr si,1 ;bytes the character is wide
\r
1665 shl si,1 ;*2 to look up in shiftdrawtable
\r
1667 mov cx,[es:pcharheight]
\r
1669 jmp [ss:mshiftdrawtable+si] ;procedure to draw this width
\r
1672 ; one byte character
\r
1680 add di,dx ; next line in buffer
\r
1684 mov cx,[es:pcharheight]
\r
1689 add di,dx ; next line in buffer
\r
1695 ; two byte character
\r
1704 add di,dx ; next line in buffer
\r
1708 mov cx,[es:pcharheight]
\r
1714 add di,dx ; next line in buffer
\r
1720 ; three byte character
\r
1729 add di,dx ; next line in buffer
\r
1733 mov cx,[es:pcharheight]
\r
1740 add di,dx ; next line in buffer
\r
1748 ;============================================================================
\r
1750 ;==================
\r
1752 ; VW_DrawMPropString
\r
1754 ; Draws a C string of characters at px/py and advances px
\r
1756 ; Assumes write mode 0
\r
1758 ;==================
\r
1762 PROC VW_DrawMPropString string:DWORD
\r
1763 PUBLIC VW_DrawMPropString
\r
1767 ; clear out the first byte of the buffer, the rest will automatically be
\r
1768 ; cleared as characters are drawn into it
\r
1770 mov si,[fontnumber]
\r
1772 mov es,[grsegs+STARTFONTM*2+si]
\r
1773 mov dx,[es:pcharheight]
\r
1774 mov di,OFFSET databuffer
\r
1777 mov bx,BUFFWIDTH-1
\r
1782 stosb ; fill the mask part with $ff
\r
1789 stosb ; fill the data part with $0
\r
1794 ; shift the characters into the buffer
\r
1798 mov [bufferbit],ax
\r
1799 mov [bufferbyte],0
\r
1801 mov ax,[WORD string]
\r
1802 mov [stringptr],ax
\r
1803 mov ax,[WORD string+2]
\r
1804 mov [stringptr+2],ax
\r
1807 mov es,[stringptr+2]
\r
1808 mov bx,[stringptr]
\r
1814 call ShiftMPropChar
\r
1819 ; calculate position to draw buffer on screen
\r
1823 mov di,[ylookup+bx]
\r
1824 add di,[bufferofs]
\r
1825 add di,[panadjust]
\r
1830 shr ax,1 ;x location in bytes
\r
1832 mov [screenspot],di
\r
1837 mov ax,[bufferbyte]
\r
1847 mov ax,[bufferbyte]
\r
1848 test [bufferbit],7
\r
1850 inc ax ;so the partial byte also gets drawn
\r
1852 mov [bufferwidth],ax
\r
1853 mov es,[grsegs+STARTFONTM*2]
\r
1854 mov ax,[es:pcharheight]
\r
1855 mov [bufferheight],ax
\r
1857 ; set AND mode to punch out the mask
\r
1859 mov ax,GC_DATAROTATE + 8*256
\r
1862 ; set mapmask to all
\r
1864 mov ax,SC_MAPMASK + 15*256
\r
1867 mov si,OFFSET databuffer
\r
1868 call BufferToScreen
\r
1870 ; set OR mode to fill in the color
\r
1872 mov ax,GC_DATAROTATE + 16*256
\r
1875 ; set mapmask to color
\r
1878 mov ah,[fontcolor]
\r
1881 call BufferToScreen ; SI is still in the right position in buffer
\r
1885 mov ax,GC_DATAROTATE
\r
1888 ; set mapmask to all
\r
1890 mov ax,SC_MAPMASK + 15*256
\r
1898 endif ; if numfontm
\r