+; Reconstructed Commander Keen 4-6 Source Code\r
+; Copyright (C) 2021 K1n9_Duk3\r
+;\r
+; This file is primarily based on:\r
+; Catacomb 3-D Source Code\r
+; Copyright (C) 1993-2014 Flat Rock Software\r
+;\r
+; This program is free software; you can redistribute it and/or modify\r
+; it under the terms of the GNU General Public License as published by\r
+; the Free Software Foundation; either version 2 of the License, or\r
+; (at your option) any later version.\r
+;\r
+; This program is distributed in the hope that it will be useful,\r
+; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+; GNU General Public License for more details.\r
+;\r
+; You should have received a copy of the GNU General Public License along\r
+; with this program; if not, write to the Free Software Foundation, Inc.,\r
+; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+\r
+;=================================\r
+;\r
+; EGA view manager routines\r
+;\r
+;=================================\r
+\r
+;============================================================================\r
+;\r
+; All EGA drawing routines that write out words need to have alternate forms\r
+; for starting on even and odd addresses, because writing a word at segment\r
+; offset 0xffff causes an exception! To work around this, write a single\r
+; byte out to make the address even, so it wraps cleanly at the end.\r
+;\r
+; All of these routines assume read/write mode 0, and will allways return\r
+; in that state.\r
+; The direction flag should be clear\r
+; readmap/writemask is left in an undefined state\r
+;\r
+;============================================================================\r
+\r
+\r
+;============================================================================\r
+;\r
+; VW_Plot (int x,y,color)\r
+;\r
+;============================================================================\r
+\r
+DATASEG\r
+\r
+plotpixels db 128,64,32,16,8,4,2,1\r
+\r
+CODESEG\r
+\r
+PROC VW_Plot x:WORD, y:WORD, color:WORD\r
+PUBLIC VW_Plot\r
+USES SI,DI\r
+\r
+ mov es,[screenseg]\r
+\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK+15*256\r
+ WORDOUT\r
+\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_MODE+2*256 ;write mode 2\r
+ WORDOUT\r
+\r
+ mov di,[bufferofs]\r
+ mov bx,[y]\r
+ shl bx,1\r
+ add di,[ylookup+bx]\r
+ mov bx,[x]\r
+ mov ax,bx\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ add di,ax ; di = byte on screen\r
+\r
+ and bx,7\r
+ mov ah,[plotpixels+bx]\r
+ mov al,GC_BITMASK ;mask off other pixels\r
+ WORDOUT\r
+\r
+ mov bl,[BYTE color]\r
+ xchg bl,[es:di] ; load latches and write pixel\r
+\r
+ mov dx,GC_INDEX\r
+ mov ah,0ffh ;no bit mask\r
+ WORDOUT\r
+ mov ax,GC_MODE+0*256 ;write mode 0\r
+ WORDOUT\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+\r
+;============================================================================\r
+;\r
+; VW_Vlin (int yl,yh,x,color)\r
+;\r
+;============================================================================\r
+\r
+PROC VW_Vlin yl:WORD, yh:WORD, x:WORD, color:WORD\r
+PUBLIC VW_Vlin\r
+USES SI,DI\r
+\r
+ mov es,[screenseg]\r
+\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK+15*256\r
+ WORDOUT\r
+\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_MODE+2*256 ;write mode 2\r
+ WORDOUT\r
+\r
+ mov di,[bufferofs]\r
+ mov bx,[yl]\r
+ shl bx,1\r
+ add di,[ylookup+bx]\r
+ mov bx,[x]\r
+ mov ax,bx\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ add di,ax ; di = byte on screen\r
+\r
+ and bx,7\r
+ mov ah,[plotpixels+bx]\r
+ mov al,GC_BITMASK ;mask off other pixels\r
+ WORDOUT\r
+\r
+ mov cx,[yh]\r
+ sub cx,[yl]\r
+ inc cx ;number of pixels to plot\r
+\r
+ mov bh,[BYTE color]\r
+ mov dx,[linewidth]\r
+\r
+@@plot:\r
+ mov bl,bh\r
+ xchg bl,[es:di] ; load latches and write pixel\r
+ add di,dx\r
+\r
+ loop @@plot\r
+\r
+ mov dx,GC_INDEX\r
+ mov ah,0ffh ;no bit mask\r
+ WORDOUT\r
+ mov ax,GC_MODE+0*256 ;write mode 0\r
+ WORDOUT\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+\r
+;============================================================================\r
+\r
+\r
+;===================\r
+;\r
+; VW_DrawTile8\r
+;\r
+; xcoord in bytes (8 pixels), ycoord in pixels\r
+; All Tile8s are in one grseg, so an offset is calculated inside it\r
+;\r
+;===================\r
+\r
+PROC VW_DrawTile8 xcoord:WORD, ycoord:WORD, tile:WORD\r
+PUBLIC VW_DrawTile8\r
+USES SI,DI\r
+\r
+ mov es,[screenseg]\r
+\r
+ mov di,[bufferofs]\r
+ add di,[xcoord]\r
+ mov bx,[ycoord]\r
+ shl bx,1\r
+ add di,[ylookup+bx]\r
+ mov [ss:screendest],di ;screen destination\r
+\r
+ mov bx,[linewidth]\r
+ dec bx\r
+\r
+ mov si,[tile]\r
+ shl si,1\r
+ shl si,1\r
+ shl si,1\r
+ shl si,1\r
+ shl si,1\r
+\r
+ mov ds,[grsegs+STARTTILE8*2] ; segment for all tile8s\r
+\r
+ mov cx,4 ;planes to draw\r
+ mov ah,0001b ;map mask\r
+\r
+ mov dx,SC_INDEX\r
+ mov al,SC_MAPMASK\r
+\r
+;\r
+; start drawing\r
+;\r
+\r
+@@planeloop:\r
+ WORDOUT\r
+ shl ah,1 ;shift plane mask over for next plane\r
+\r
+ mov di,[ss:screendest] ;start at same place in all planes\r
+\r
+REPT 7\r
+ movsb\r
+ add di,bx\r
+ENDM\r
+ movsb\r
+\r
+ loop @@planeloop\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+\r
+;============================================================================\r
+;\r
+; VW_MaskBlock\r
+;\r
+; Draws a masked block shape to the screen. bufferofs is NOT accounted for.\r
+; The mask comes first, then four planes of data.\r
+;\r
+;============================================================================\r
+\r
+DATASEG\r
+\r
+UNWOUNDMASKS = 10\r
+\r
+\r
+maskroutines dw mask0,mask0,mask1E,mask1E,mask2E,mask2O,mask3E,mask3O\r
+ dw mask4E,mask4O,mask5E,mask5O,mask6E,mask6O\r
+ dw mask7E,mask7O,mask8E,mask8O,mask9E,mask9O\r
+ dw mask10E,mask10O\r
+\r
+\r
+routinetouse dw ?\r
+\r
+CODESEG\r
+\r
+PROC VW_MaskBlock segm:WORD, ofs:WORD, dest:WORD, wide:WORD, height:WORD, planesize:WORD\r
+PUBLIC VW_MaskBlock\r
+USES SI,DI\r
+\r
+ mov es,[screenseg]\r
+\r
+ mov [BYTE planemask],1\r
+ mov [BYTE planenum],0\r
+\r
+ mov di,[wide]\r
+ mov dx,[linewidth]\r
+ sub dx,[wide]\r
+ mov [linedelta],dx ;amount to add after drawing each line\r
+\r
+ mov bx,[planesize] ; si+bx = data location\r
+\r
+ cmp di,UNWOUNDMASKS\r
+ jbe @@unwoundroutine\r
+ mov [routinetouse],OFFSET generalmask\r
+ jmp NEAR @@startloop\r
+\r
+;=================\r
+;\r
+; use the unwound routines\r
+;\r
+;=================\r
+\r
+@@unwoundroutine:\r
+ mov cx,[dest]\r
+ shr cx,1\r
+ rcl di,1 ;shift a 1 in if destination is odd\r
+ shl di,1 ;to index into a word width table\r
+ mov ax,[maskroutines+di] ;call the right routine\r
+ mov [routinetouse],ax\r
+\r
+@@startloop:\r
+ mov ds,[segm]\r
+\r
+@@drawplane:\r
+ mov dx,SC_INDEX\r
+ mov al,SC_MAPMASK\r
+ mov ah,[ss:planemask]\r
+ WORDOUT\r
+ mov dx,GC_INDEX\r
+ mov al,GC_READMAP\r
+ mov ah,[ss:planenum]\r
+ WORDOUT\r
+\r
+ mov si,[ofs] ;start back at the top of the mask\r
+ mov di,[dest] ;start at same place in all planes\r
+ mov cx,[height] ;scan lines to draw\r
+ mov dx,[ss:linedelta]\r
+\r
+ jmp [ss:routinetouse] ;draw one plane\r
+planereturn: ;routine jmps back here\r
+\r
+ add bx,[ss:planesize] ;start of mask = start of next plane\r
+\r
+ inc [ss:planenum]\r
+ shl [ss:planemask],1 ;shift plane mask over for next plane\r
+ cmp [ss:planemask],10000b ;done all four planes?\r
+ jne @@drawplane\r
+\r
+mask0:\r
+ mov ax,ss\r
+ mov ds,ax\r
+ ret ;width of 0 = no drawing\r
+\r
+;==============\r
+;\r
+; General purpose masked block drawing. This could be optimised into\r
+; four routines to use words, but few play loop sprites should be this big!\r
+;\r
+;==============\r
+\r
+generalmask:\r
+ mov dx,cx\r
+\r
+@@lineloopgen:\r
+ mov cx,[wide]\r
+@@byteloop:\r
+ mov al,[es:di]\r
+ and al,[si]\r
+ or al,[bx+si]\r
+ inc si\r
+ stosb\r
+ loop @@byteloop\r
+\r
+ add di,[ss:linedelta]\r
+ dec dx\r
+ jnz @@lineloopgen\r
+ jmp planereturn\r
+\r
+;=================\r
+;\r
+; Horizontally unwound routines to draw certain masked blocks faster\r
+;\r
+;=================\r
+\r
+MACRO MASKBYTE\r
+ lodsb\r
+ and al,[es:di]\r
+ or al,[bx+si-1]\r
+ stosb\r
+ENDM\r
+\r
+MACRO MASKWORD\r
+ lodsw\r
+ and ax,[es:di]\r
+ or ax,[bx+si-2]\r
+ stosw\r
+ENDM\r
+\r
+MACRO SPRITELOOP addr\r
+ add di,dx\r
+ loop addr\r
+ jmp planereturn\r
+ENDM\r
+\r
+\r
+EVEN\r
+mask1E:\r
+ MASKBYTE\r
+ SPRITELOOP mask1E\r
+\r
+EVEN\r
+mask2E:\r
+ MASKWORD\r
+ SPRITELOOP mask2E\r
+\r
+EVEN\r
+mask2O:\r
+ MASKBYTE\r
+ MASKBYTE\r
+ SPRITELOOP mask2O\r
+\r
+EVEN\r
+mask3E:\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask3E\r
+\r
+EVEN\r
+mask3O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ SPRITELOOP mask3O\r
+\r
+EVEN\r
+mask4E:\r
+ MASKWORD\r
+ MASKWORD\r
+ SPRITELOOP mask4E\r
+\r
+EVEN\r
+mask4O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask4O\r
+\r
+EVEN\r
+mask5E:\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask5E\r
+\r
+EVEN\r
+mask5O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ MASKWORD\r
+ SPRITELOOP mask5O\r
+\r
+EVEN\r
+mask6E:\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ SPRITELOOP mask6E\r
+\r
+EVEN\r
+mask6O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask6O\r
+\r
+EVEN\r
+mask7E:\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask7E\r
+\r
+EVEN\r
+mask7O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ SPRITELOOP mask7O\r
+\r
+EVEN\r
+mask8E:\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ SPRITELOOP mask8E\r
+\r
+EVEN\r
+mask8O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask8O\r
+\r
+EVEN\r
+mask9E:\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask9E\r
+\r
+EVEN\r
+mask9O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ SPRITELOOP mask9O\r
+\r
+EVEN\r
+mask10E:\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ SPRITELOOP mask10E\r
+\r
+EVEN\r
+mask10O:\r
+ MASKBYTE\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKWORD\r
+ MASKBYTE\r
+ SPRITELOOP mask10O\r
+\r
+\r
+ENDP\r
+\r
+\r
+;============================================================================\r
+;\r
+; VW_InverseMask\r
+;\r
+; Draws a masked block shape to the screen. bufferofs is NOT accounted for.\r
+; The mask comes first, then four planes of data.\r
+;\r
+;============================================================================\r
+\r
+PROC VW_InverseMask segm:WORD, ofs:WORD, dest:WORD, wide:WORD, height:WORD\r
+PUBLIC VW_InverseMask\r
+USES SI,DI\r
+\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK+15*256\r
+ WORDOUT\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_DATAROTATE+16*256 ;set function = OR\r
+ WORDOUT\r
+\r
+ mov es, [screenseg]\r
+ mov ax, [wide]\r
+ mov dx, [linewidth]\r
+ sub dx, ax;\r
+ mov ds, [segm]\r
+ mov si, [ofs]\r
+ mov di, [dest]\r
+ mov bx, [height]\r
+@@yloop:\r
+ mov cx, [wide]\r
+@@xloop:\r
+ lodsb\r
+ not al\r
+ xchg al, [es:di]\r
+ inc di\r
+ loop @@xloop\r
+ add di, dx\r
+ dec bx\r
+ jnz @@yloop\r
+\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_DATAROTATE+0*256 ;set function = no change\r
+ WORDOUT\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+;============================================================================\r
+;\r
+; VW_ScreenToScreen\r
+;\r
+; Basic block copy routine. Copies one block of screen memory to another,\r
+; using write mode 1 (sets it and returns with write mode 0). bufferofs is\r
+; NOT accounted for.\r
+;\r
+;============================================================================\r
+\r
+PROC VW_ScreenToScreen source:WORD, dest:WORD, wide:WORD, height:WORD\r
+PUBLIC VW_ScreenToScreen\r
+USES SI,DI\r
+\r
+ pushf\r
+ cli\r
+\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK+15*256\r
+ WORDOUT\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_MODE+1*256\r
+ WORDOUT\r
+\r
+ popf\r
+\r
+ mov bx,[linewidth]\r
+ sub bx,[wide]\r
+\r
+ mov ax,[screenseg]\r
+ mov es,ax\r
+ mov ds,ax\r
+\r
+ mov si,[source]\r
+ mov di,[dest] ;start at same place in all planes\r
+ mov dx,[height] ;scan lines to draw\r
+ mov ax,[wide]\r
+\r
+@@lineloop:\r
+ mov cx,ax\r
+ rep movsb\r
+ add si,bx\r
+ add di,bx\r
+\r
+ dec dx\r
+ jnz @@lineloop\r
+\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_MODE+0*256\r
+ WORDOUT\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+\r
+;============================================================================\r
+;\r
+; VW_MemToScreen\r
+;\r
+; Basic block drawing routine. Takes a block shape at segment pointer source\r
+; with four planes of width by height data, and draws it to dest in the\r
+; virtual screen, based on linewidth. bufferofs is NOT accounted for.\r
+; There are four drawing routines to provide the best optimized code while\r
+; accounting for odd segment wrappings due to the floating screens.\r
+;\r
+;============================================================================\r
+\r
+DATASEG\r
+\r
+memtoscreentable dw eventoeven,eventoodd,oddtoeven,oddtoodd\r
+\r
+CODESEG\r
+\r
+\r
+PROC VW_MemToScreen source:WORD, dest:WORD, wide:WORD, height:WORD\r
+PUBLIC VW_MemToScreen\r
+USES SI,DI\r
+\r
+ mov es,[screenseg]\r
+\r
+ mov bx,[linewidth]\r
+ sub bx,[wide]\r
+\r
+ mov ds,[source]\r
+\r
+\r
+ xor si,si ;block is segment aligned\r
+\r
+ xor di,di\r
+ shr [wide],1 ;change wide to words, and see if carry is set\r
+ rcl di,1 ;1 if wide is odd\r
+ mov ax,[dest]\r
+ shr ax,1\r
+ rcl di,1 ;shift a 1 in if destination is odd\r
+ shl di,1 ;to index into a word width table\r
+ mov ax,SC_MAPMASK+0001b*256 ;map mask for plane 0\r
+ jmp [ss:memtoscreentable+di] ;call the right routine\r
+\r
+;==============\r
+;\r
+; Copy an even width block to an even video address\r
+;\r
+;==============\r
+\r
+eventoeven:\r
+ mov dx,SC_INDEX\r
+ WORDOUT\r
+\r
+ mov di,[dest] ;start at same place in all planes\r
+ mov dx,[height] ;scan lines to draw\r
+\r
+@@lineloopEE:\r
+ mov cx,[wide]\r
+ rep movsw\r
+\r
+ add di,bx\r
+\r
+ dec dx\r
+ jnz @@lineloopEE\r
+\r
+ shl ah,1 ;shift plane mask over for next plane\r
+ cmp ah,10000b ;done all four planes?\r
+ jne eventoeven\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+;==============\r
+;\r
+; Copy an odd width block to an even video address\r
+;\r
+;==============\r
+\r
+oddtoeven:\r
+ mov dx,SC_INDEX\r
+ WORDOUT\r
+\r
+ mov di,[dest] ;start at same place in all planes\r
+ mov dx,[height] ;scan lines to draw\r
+\r
+@@lineloopOE:\r
+ mov cx,[wide]\r
+ rep movsw\r
+ movsb ;copy the last byte\r
+\r
+ add di,bx\r
+\r
+ dec dx\r
+ jnz @@lineloopOE\r
+\r
+ shl ah,1 ;shift plane mask over for next plane\r
+ cmp ah,10000b ;done all four planes?\r
+ jne oddtoeven\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+;==============\r
+;\r
+; Copy an even width block to an odd video address\r
+;\r
+;==============\r
+\r
+eventoodd:\r
+ dec [wide] ;one word has to be handled seperately\r
+EOplaneloop:\r
+ mov dx,SC_INDEX\r
+ WORDOUT\r
+\r
+ mov di,[dest] ;start at same place in all planes\r
+ mov dx,[height] ;scan lines to draw\r
+\r
+@@lineloopEO:\r
+ movsb\r
+ mov cx,[wide]\r
+ rep movsw\r
+ movsb\r
+\r
+ add di,bx\r
+\r
+ dec dx\r
+ jnz @@lineloopEO\r
+\r
+ shl ah,1 ;shift plane mask over for next plane\r
+ cmp ah,10000b ;done all four planes?\r
+ jne EOplaneloop\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+;==============\r
+;\r
+; Copy an odd width block to an odd video address\r
+;\r
+;==============\r
+\r
+oddtoodd:\r
+ mov dx,SC_INDEX\r
+ WORDOUT\r
+\r
+ mov di,[dest] ;start at same place in all planes\r
+ mov dx,[height] ;scan lines to draw\r
+\r
+@@lineloopOO:\r
+ movsb\r
+ mov cx,[wide]\r
+ rep movsw\r
+\r
+ add di,bx\r
+\r
+ dec dx\r
+ jnz @@lineloopOO\r
+\r
+ shl ah,1 ;shift plane mask over for next plane\r
+ cmp ah,10000b ;done all four planes?\r
+ jne oddtoodd\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+\r
+ENDP\r
+\r
+;===========================================================================\r
+;\r
+; VW_ScreenToMem\r
+;\r
+; Copies a block of video memory to main memory, in order from planes 0-3.\r
+; This could be optimized along the lines of VW_MemToScreen to take advantage\r
+; of word copies, but this is an infrequently called routine.\r
+;\r
+;===========================================================================\r
+\r
+PROC VW_ScreenToMem source:WORD, dest:WORD, wide:WORD, height:WORD\r
+PUBLIC VW_ScreenToMem\r
+USES SI,DI\r
+\r
+ mov es,[dest]\r
+\r
+ mov bx,[linewidth]\r
+ sub bx,[wide]\r
+\r
+ mov ds,[screenseg]\r
+\r
+ mov ax,GC_READMAP ;read map for plane 0\r
+\r
+ xor di,di\r
+\r
+@@planeloop:\r
+ mov dx,GC_INDEX\r
+ WORDOUT\r
+\r
+ mov si,[source] ;start at same place in all planes\r
+ mov dx,[height] ;scan lines to draw\r
+\r
+@@lineloop:\r
+ mov cx,[wide]\r
+ rep movsb\r
+\r
+ add si,bx\r
+\r
+ dec dx\r
+ jnz @@lineloop\r
+\r
+ inc ah\r
+ cmp ah,4 ;done all four planes?\r
+ jne @@planeloop\r
+\r
+ mov ax,ss\r
+ mov ds,ax ;restore turbo's data segment\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+\r
+;============================================================================\r
+;\r
+; VWL_UpdateScreenBlocks\r
+;\r
+; Scans through the update matrix and copies any areas that have changed\r
+; to the visable screen, then zeros the update array\r
+;\r
+;============================================================================\r
+\r
+\r
+\r
+; AX 0/1 for scasb, temp for segment register transfers\r
+; BX width for block copies\r
+; CX REP counter\r
+; DX line width deltas\r
+; SI source for copies\r
+; DI scas dest / movsb dest\r
+; BP pointer to end of bufferblocks\r
+\r
+PROC VWL_UpdateScreenBlocks\r
+PUBLIC VWL_UpdateScreenBlocks\r
+USES SI,DI,BP\r
+\r
+ jmp SHORT @@realstart\r
+@@done:\r
+;\r
+; all tiles have been scanned\r
+;\r
+ mov dx,GC_INDEX ; restore write mode 0\r
+ mov ax,GC_MODE+0*256\r
+ WORDOUT\r
+\r
+ xor ax,ax ; clear out the update matrix\r
+ mov cx,UPDATEWIDE*UPDATEHIGH/2\r
+\r
+ mov di,[updateptr]\r
+ rep stosw\r
+\r
+ ret\r
+\r
+@@realstart:\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK+15*256\r
+ WORDOUT\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_MODE+1*256\r
+ WORDOUT\r
+\r
+ mov di,[updateptr] ; start of floating update screen\r
+ mov bp,di\r
+ add bp,UPDATEWIDE*UPDATEHIGH+1 ; when di = bp, all tiles have been scanned\r
+\r
+ push di\r
+ mov cx,-1 ; definately scan the entire thing\r
+\r
+;\r
+; scan for a 1 in the update list, meaning a tile needs to be copied\r
+; from the master screen to the current screen\r
+;\r
+@@findtile:\r
+ pop di ; place to continue scaning from\r
+ mov ax,ss\r
+ mov es,ax ; search in the data segment\r
+ mov ds,ax\r
+ mov al,1\r
+ repne scasb\r
+ cmp di,bp\r
+ jae @@done\r
+\r
+ cmp [BYTE di],al\r
+ jne @@singletile\r
+ jmp @@tileblock\r
+\r
+;============\r
+;\r
+; copy a single tile\r
+;\r
+;============\r
+@@singletile:\r
+ inc di ; we know the next tile is nothing\r
+ push di ; save off the spot being scanned\r
+ sub di,[updateptr]\r
+ shl di,1\r
+ mov di,[blockstarts-4+di] ; start of tile location on screen\r
+ mov si,di\r
+ add si,[bufferofs]\r
+ add di,[displayofs]\r
+\r
+ mov dx,[linewidth]\r
+ sub dx,2\r
+ mov ax,[screenseg]\r
+ mov ds,ax\r
+ mov es,ax\r
+\r
+REPT 15\r
+ movsb\r
+ movsb\r
+ add si,dx\r
+ add di,dx\r
+ENDM\r
+ movsb\r
+ movsb\r
+\r
+ jmp @@findtile\r
+\r
+;============\r
+;\r
+; more than one tile in a row needs to be updated, so do it as a group\r
+;\r
+;============\r
+EVEN\r
+@@tileblock:\r
+ mov dx,di ; hold starting position + 1 in dx\r
+ inc di ; we know the next tile also gets updated\r
+ repe scasb ; see how many more in a row\r
+ push di ; save off the spot being scanned\r
+\r
+ mov bx,di\r
+ sub bx,dx ; number of tiles in a row\r
+ shl bx,1 ; number of bytes / row\r
+\r
+ mov di,dx ; lookup position of start tile\r
+ sub di,[updateptr]\r
+ shl di,1\r
+ mov di,[blockstarts-2+di] ; start of tile location\r
+ mov si,di\r
+ add si,[bufferofs]\r
+ add di,[displayofs]\r
+\r
+ mov dx,[linewidth]\r
+ sub dx,bx ; offset to next line on screen\r
+\r
+ mov ax,[screenseg]\r
+ mov ds,ax\r
+ mov es,ax\r
+\r
+REPT 15\r
+ mov cx,bx\r
+ rep movsb\r
+ add si,dx\r
+ add di,dx\r
+ENDM\r
+ mov cx,bx\r
+ rep movsb\r
+\r
+ dec cx ; was 0 from last rep movsb, now $ffff for scasb\r
+ jmp @@findtile\r
+\r
+ENDP\r
+\r
+\r
+;===========================================================================\r
+;\r
+; MISC EGA ROUTINES\r
+;\r
+;===========================================================================\r
+\r
+;=================\r
+;\r
+; SyncVBL\r
+;\r
+;=================\r
+\r
+DATASEG\r
+\r
+EXTRN TimeCount :DWORD\r
+EXTRN jerk :WORD\r
+EXTRN nopan :WORD\r
+\r
+CODESEG\r
+\r
+PROC SyncVBL\r
+ mov dx,STATUS_REGISTER_1\r
+ mov bx,[WORD TimeCount]\r
+ add bx,3\r
+@@waitloop:\r
+ sti\r
+ jmp $+2\r
+ cli\r
+ cmp [WORD TimeCount],bx\r
+ je @@done\r
+@@waitnovert:\r
+ in al,dx\r
+ test al,1\r
+ jnz @@waitnovert\r
+@@waitvert:\r
+ in al,dx\r
+ test al,1\r
+ jz @@waitvert\r
+\r
+REPT 5\r
+ in al,dx\r
+ test al,8\r
+ jnz @@waitloop\r
+ test al,1\r
+ jz @@waitloop\r
+ENDM\r
+\r
+ test [jerk],1\r
+ jz @@done\r
+\r
+REPT 5\r
+ in al,dx\r
+ test al,8\r
+ jnz @@waitloop\r
+ test al,1\r
+ jz @@waitloop\r
+ENDM\r
+\r
+@@done:\r
+ ret\r
+ENDP\r
+\r
+\r
+;==============\r
+;\r
+; VW_SetScreen\r
+;\r
+;==============\r
+\r
+PROC VW_SetScreen crtc:WORD, pel:WORD\r
+PUBLIC VW_SetScreen\r
+\r
+ call SyncVBL\r
+;\r
+; set CRTC start\r
+;\r
+; for some reason, my XT's EGA card doesn't like word outs to the CRTC\r
+; index...\r
+;\r
+ mov cx,[crtc]\r
+ mov dx,CRTC_INDEX\r
+ mov al,0ch ;start address high register\r
+ out dx,al\r
+ inc dx\r
+ mov al,ch\r
+ out dx,al\r
+ dec dx\r
+ mov al,0dh ;start address low register\r
+ out dx,al\r
+ mov al,cl\r
+ inc dx\r
+ out dx,al\r
+\r
+ test [nopan],1\r
+ jnz @@done\r
+;\r
+; set horizontal panning\r
+;\r
+\r
+ mov dx,ATR_INDEX\r
+ mov al,ATR_PELPAN or 20h\r
+ out dx,al\r
+ jmp $+2\r
+ mov al,[BYTE pel] ;pel pan value\r
+ out dx,al\r
+\r
+@@done:\r
+ sti\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+\r
+if NUMFONT+NUMFONTM\r
+\r
+;===========================================================================\r
+;\r
+; GENERAL FONT DRAWING ROUTINES\r
+;\r
+;===========================================================================\r
+\r
+DATASEG\r
+\r
+px dw ? ; proportional character drawing coordinates\r
+py dw ?\r
+pdrawmode db 11000b ; 8 = OR, 24 = XOR, put in GC_DATAROTATE\r
+fontcolor db 15 ;0-15 mapmask value\r
+\r
+PUBLIC px,py,pdrawmode,fontcolor\r
+\r
+;\r
+; offsets in font structure\r
+;\r
+pcharheight = 0 ;lines high\r
+charloc = 2 ;pointers to every character\r
+charwidth = 514 ;every character's width in pixels\r
+\r
+\r
+propchar dw ? ; the character number to shift\r
+stringptr dw ?,?\r
+\r
+\r
+BUFFWIDTH = 50\r
+BUFFHEIGHT = 32 ; must be twice as high as font for masked fonts\r
+\r
+databuffer db BUFFWIDTH*BUFFHEIGHT dup (?)\r
+\r
+bufferwidth dw ? ; bytes with valid info / line\r
+bufferheight dw ? ; number of lines currently used\r
+\r
+bufferbyte dw ?\r
+bufferbit dw ?\r
+\r
+screenspot dw ? ; where the buffer is going\r
+\r
+bufferextra dw ? ; add at end of a line copy\r
+screenextra dw ?\r
+\r
+PUBLIC bufferwidth,bufferheight,screenspot\r
+\r
+CODESEG\r
+\r
+;======================\r
+;\r
+; Macros to table shift a byte of font\r
+;\r
+;======================\r
+\r
+MACRO SHIFTNOXOR\r
+ mov al,[es:bx] ; source\r
+ xor ah,ah\r
+ shl ax,1\r
+ mov si,ax\r
+ mov ax,[bp+si] ; table shift into two bytes\r
+ or [di],al ; or with first byte\r
+ inc di\r
+ mov [di],ah ; replace next byte\r
+ inc bx ; next source byte\r
+ENDM\r
+\r
+MACRO SHIFTWITHXOR\r
+ mov al,[es:bx] ; source\r
+ xor ah,ah\r
+ shl ax,1\r
+ mov si,ax\r
+ mov ax,[bp+si] ; table shift into two bytes\r
+ not ax\r
+ and [di],al ; and with first byte\r
+ inc di\r
+ mov [di],ah ; replace next byte\r
+ inc bx ; next source byte\r
+ENDM\r
+\r
+\r
+;=======================\r
+;\r
+; BufferToScreen\r
+;\r
+; Pass buffer start in SI (somewhere in databuffer)\r
+; Draws the buffer to the EGA screen in the current write mode\r
+;\r
+;========================\r
+\r
+PROC BufferToScreen NEAR\r
+\r
+ mov es,[screenseg]\r
+ mov di,[screenspot]\r
+\r
+ mov bx,[bufferwidth] ;calculate offsets for end of each line\r
+ or bx,bx\r
+ jnz @@isthere\r
+ ret ;nothing to draw\r
+\r
+@@isthere:\r
+ mov ax,[linewidth]\r
+ sub ax,bx\r
+ mov [screenextra],ax\r
+ mov ax,BUFFWIDTH\r
+ sub ax,bx\r
+ mov [bufferextra],ax\r
+\r
+ mov bx,[bufferheight] ;lines to copy\r
+@@lineloop:\r
+ mov cx,[bufferwidth] ;bytes to copy\r
+@@byteloop:\r
+ lodsb ;get a byte from the buffer\r
+ xchg [es:di],al ;load latches and store back to screen\r
+ inc di\r
+\r
+ loop @@byteloop\r
+\r
+ add si,[bufferextra]\r
+ add di,[screenextra]\r
+\r
+ dec bx\r
+ jnz @@lineloop\r
+\r
+ ret\r
+ENDP\r
+\r
+\r
+;============================================================================\r
+;\r
+; NON MASKED FONT DRAWING ROUTINES\r
+;\r
+;============================================================================\r
+\r
+if numfont\r
+\r
+DATASEG\r
+\r
+shiftdrawtable dw 0,shift1wide,shift2wide,shift3wide,shift4wide\r
+ dw shift5wide\r
+\r
+CODESEG\r
+\r
+;==================\r
+;\r
+; ShiftPropChar\r
+;\r
+; Call with BX = character number (0-255)\r
+; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts\r
+; them to the new position\r
+;\r
+;==================\r
+\r
+PROC ShiftPropChar NEAR\r
+\r
+ mov si,[fontnumber]\r
+ shl si,1\r
+ mov es,[grsegs+STARTFONT*2+si] ;segment of font to use\r
+\r
+;\r
+; find character location, width, and height\r
+;\r
+ mov si,[es:charwidth+bx]\r
+ and si,0ffh ;SI hold width in pixels\r
+ shl bx,1\r
+ mov bx,[es:charloc+bx] ;BX holds pointer to character data\r
+\r
+;\r
+; look up which shift table to use, based on bufferbit\r
+;\r
+ mov di,[bufferbit]\r
+ shl di,1\r
+ mov bp,[shifttabletable+di] ;BP holds pointer to shift table\r
+\r
+ mov di,OFFSET databuffer\r
+ add di,[bufferbyte] ;DI holds pointer to buffer\r
+\r
+;\r
+; advance position by character width\r
+;\r
+ mov cx,[bufferbit]\r
+ add cx,si ;new bit position\r
+ mov ax,cx\r
+ and ax,7\r
+ mov [bufferbit],ax ;new bit position\r
+ mov ax,cx\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ add [bufferbyte],ax ;new byte position\r
+\r
+ add si,7\r
+ shr si,1\r
+ shr si,1\r
+ shr si,1 ;bytes the character is wide\r
+ shl si,1 ;*2 to look up in shiftdrawtable\r
+\r
+ mov cx,[es:pcharheight]\r
+ mov dx,BUFFWIDTH\r
+ jmp [ss:shiftdrawtable+si] ;procedure to draw this width\r
+\r
+;\r
+; one byte character\r
+;\r
+shift1wide:\r
+ dec dx\r
+EVEN\r
+@@loop1:\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop1\r
+ ret\r
+\r
+;\r
+; two byte character\r
+;\r
+shift2wide:\r
+ dec dx\r
+ dec dx\r
+EVEN\r
+@@loop2:\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop2\r
+ ret\r
+\r
+;\r
+; three byte character\r
+;\r
+shift3wide:\r
+ sub dx,3\r
+EVEN\r
+@@loop3:\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop3\r
+ ret\r
+\r
+;\r
+; four byte character\r
+;\r
+shift4wide:\r
+ sub dx,4\r
+EVEN\r
+@@loop4:\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop4\r
+ ret\r
+\r
+;\r
+; five byte character\r
+;\r
+shift5wide:\r
+ sub dx,5\r
+EVEN\r
+@@loop5:\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop5\r
+ ret\r
+\r
+\r
+\r
+ENDP\r
+\r
+;============================================================================\r
+\r
+;==================\r
+;\r
+; VW_DrawPropString\r
+;\r
+; Draws a C string of characters at px/py and advances px\r
+;\r
+; Assumes write mode 0\r
+;\r
+;==================\r
+\r
+CODESEG\r
+\r
+PROC VW_DrawPropString string:DWORD\r
+PUBLIC VW_DrawPropString\r
+USES SI,DI\r
+\r
+;\r
+; proportional spaceing, which clears the buffer ahead of it, so only\r
+; clear the first collumn\r
+;\r
+ mov al,0\r
+line = 0\r
+REPT BUFFHEIGHT\r
+ mov [BYTE databuffer+BUFFWIDTH*line],al\r
+line = line+1\r
+ENDM\r
+\r
+;\r
+; shift the characters into the buffer\r
+;\r
+@@shiftchars:\r
+ mov ax,[px]\r
+ and ax,7\r
+ mov [bufferbit],ax\r
+ mov [bufferbyte],0\r
+\r
+ mov ax,[WORD string]\r
+ mov [stringptr],ax\r
+ mov ax,[WORD string+2]\r
+ mov [stringptr+2],ax\r
+\r
+@@shiftone:\r
+ mov es,[stringptr+2]\r
+ mov bx,[stringptr]\r
+ inc [stringptr]\r
+ mov bx,[es:bx]\r
+ xor bh,bh\r
+ or bl,bl\r
+ jz @@allshifted\r
+ call ShiftPropChar\r
+ jmp @@shiftone\r
+\r
+@@allshifted:\r
+;\r
+; calculate position to draw buffer on screen\r
+;\r
+ mov bx,[py]\r
+ shl bx,1\r
+ mov di,[ylookup+bx]\r
+ add di,[bufferofs]\r
+ add di,[panadjust]\r
+\r
+ mov ax,[px]\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1 ;x location in bytes\r
+ add di,ax\r
+ mov [screenspot],di\r
+\r
+;\r
+; advance px\r
+;\r
+ mov ax,[bufferbyte]\r
+ shl ax,1\r
+ shl ax,1\r
+ shl ax,1\r
+ or ax,[bufferbit]\r
+ add [px],ax\r
+\r
+;\r
+; draw it\r
+;\r
+\r
+; set xor/or mode\r
+ mov dx,GC_INDEX\r
+ mov al,GC_DATAROTATE\r
+ mov ah,[pdrawmode]\r
+ WORDOUT\r
+\r
+; set mapmask to color\r
+ mov dx,SC_INDEX\r
+ mov al,SC_MAPMASK\r
+ mov ah,[fontcolor]\r
+ WORDOUT\r
+\r
+ mov ax,[bufferbyte]\r
+ test [bufferbit],7\r
+ jz @@go\r
+ inc ax ;so the partial byte also gets drawn\r
+@@go:\r
+ mov [bufferwidth],ax\r
+ mov si,[fontnumber]\r
+ shl si,1\r
+ mov es,[grsegs+STARTFONT*2+si]\r
+ mov ax,[es:pcharheight]\r
+ mov [bufferheight],ax\r
+\r
+ mov si,OFFSET databuffer\r
+ call BufferToScreen\r
+\r
+; set copy mode\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_DATAROTATE\r
+ WORDOUT\r
+\r
+; set mapmask to all\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK + 15*256\r
+ WORDOUT\r
+\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+endif ;numfont\r
+\r
+;============================================================================\r
+;\r
+; MASKED FONT DRAWING ROUTINES\r
+;\r
+;============================================================================\r
+\r
+if numfontm\r
+\r
+DATASEG\r
+\r
+mshiftdrawtable dw 0,mshift1wide,mshift2wide,mshift3wide\r
+\r
+\r
+CODESEG\r
+\r
+;==================\r
+;\r
+; ShiftMPropChar\r
+;\r
+; Call with BX = character number (0-255)\r
+; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts\r
+; them to the new position\r
+;\r
+;==================\r
+\r
+PROC ShiftMPropChar NEAR\r
+\r
+ mov si,[fontnumber]\r
+ shl si,1\r
+ mov es,[grsegs+STARTFONTM*2+si] ;segment of font to use\r
+\r
+;\r
+; find character location, width, and height\r
+;\r
+ mov si,[es:charwidth+bx]\r
+ and si,0ffh ;SI hold width in pixels\r
+ shl bx,1\r
+ mov bx,[es:charloc+bx] ;BX holds pointer to character data\r
+\r
+;\r
+; look up which shift table to use, based on bufferbit\r
+;\r
+ mov di,[bufferbit]\r
+ shl di,1\r
+ mov bp,[shifttabletable+di] ;BP holds pointer to shift table\r
+\r
+ mov di,OFFSET databuffer\r
+ add di,[bufferbyte] ;DI holds pointer to buffer\r
+\r
+ mov cx,[bufferbit]\r
+ add cx,si ;new bit position\r
+ mov ax,cx\r
+ and ax,7\r
+ mov [bufferbit],ax ;new bit position\r
+ mov ax,cx\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ add [bufferbyte],ax ;new byte position\r
+\r
+ add si,7\r
+ shr si,1\r
+ shr si,1\r
+ shr si,1 ;bytes the character is wide\r
+ shl si,1 ;*2 to look up in shiftdrawtable\r
+\r
+ mov cx,[es:pcharheight]\r
+ mov dx,BUFFWIDTH\r
+ jmp [ss:mshiftdrawtable+si] ;procedure to draw this width\r
+\r
+;\r
+; one byte character\r
+;\r
+mshift1wide:\r
+ dec dx\r
+\r
+EVEN\r
+@@loop1m:\r
+ SHIFTWITHXOR\r
+ add di,dx ; next line in buffer\r
+\r
+ loop @@loop1m\r
+\r
+ mov cx,[es:pcharheight]\r
+\r
+EVEN\r
+@@loop1:\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop1\r
+\r
+ ret\r
+\r
+;\r
+; two byte character\r
+;\r
+mshift2wide:\r
+ dec dx\r
+ dec dx\r
+EVEN\r
+@@loop2m:\r
+ SHIFTWITHXOR\r
+ SHIFTWITHXOR\r
+ add di,dx ; next line in buffer\r
+\r
+ loop @@loop2m\r
+\r
+ mov cx,[es:pcharheight]\r
+\r
+EVEN\r
+@@loop2:\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop2\r
+\r
+ ret\r
+\r
+;\r
+; three byte character\r
+;\r
+mshift3wide:\r
+ sub dx,3\r
+EVEN\r
+@@loop3m:\r
+ SHIFTWITHXOR\r
+ SHIFTWITHXOR\r
+ SHIFTWITHXOR\r
+ add di,dx ; next line in buffer\r
+\r
+ loop @@loop3m\r
+\r
+ mov cx,[es:pcharheight]\r
+\r
+EVEN\r
+@@loop3:\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ SHIFTNOXOR\r
+ add di,dx ; next line in buffer\r
+ loop @@loop3\r
+\r
+ ret\r
+\r
+\r
+ENDP\r
+\r
+;============================================================================\r
+\r
+;==================\r
+;\r
+; VW_DrawMPropString\r
+;\r
+; Draws a C string of characters at px/py and advances px\r
+;\r
+; Assumes write mode 0\r
+;\r
+;==================\r
+\r
+\r
+\r
+PROC VW_DrawMPropString string:DWORD\r
+PUBLIC VW_DrawMPropString\r
+USES SI,DI\r
+\r
+;\r
+; clear out the first byte of the buffer, the rest will automatically be\r
+; cleared as characters are drawn into it\r
+;\r
+ mov si,[fontnumber]\r
+ shl si,1\r
+ mov es,[grsegs+STARTFONTM*2+si]\r
+ mov dx,[es:pcharheight]\r
+ mov di,OFFSET databuffer\r
+ mov ax,ds\r
+ mov es,ax\r
+ mov bx,BUFFWIDTH-1\r
+\r
+ mov cx,dx\r
+ mov al,0ffh\r
+@@maskfill:\r
+ stosb ; fill the mask part with $ff\r
+ add di,bx\r
+ loop @@maskfill\r
+\r
+ mov cx,dx\r
+ xor al,al\r
+@@datafill:\r
+ stosb ; fill the data part with $0\r
+ add di,bx\r
+ loop @@datafill\r
+\r
+;\r
+; shift the characters into the buffer\r
+;\r
+ mov ax,[px]\r
+ and ax,7\r
+ mov [bufferbit],ax\r
+ mov [bufferbyte],0\r
+\r
+ mov ax,[WORD string]\r
+ mov [stringptr],ax\r
+ mov ax,[WORD string+2]\r
+ mov [stringptr+2],ax\r
+\r
+@@shiftone:\r
+ mov es,[stringptr+2]\r
+ mov bx,[stringptr]\r
+ inc [stringptr]\r
+ mov bx,[es:bx]\r
+ xor bh,bh\r
+ or bl,bl\r
+ jz @@allshifted\r
+ call ShiftMPropChar\r
+ jmp @@shiftone\r
+\r
+@@allshifted:\r
+;\r
+; calculate position to draw buffer on screen\r
+;\r
+ mov bx,[py]\r
+ shl bx,1\r
+ mov di,[ylookup+bx]\r
+ add di,[bufferofs]\r
+ add di,[panadjust]\r
+\r
+ mov ax,[px]\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1 ;x location in bytes\r
+ add di,ax\r
+ mov [screenspot],di\r
+\r
+;\r
+; advance px\r
+;\r
+ mov ax,[bufferbyte]\r
+ shl ax,1\r
+ shl ax,1\r
+ shl ax,1\r
+ or ax,[bufferbit]\r
+ add [px],ax\r
+\r
+;\r
+; draw it\r
+;\r
+ mov ax,[bufferbyte]\r
+ test [bufferbit],7\r
+ jz @@go\r
+ inc ax ;so the partial byte also gets drawn\r
+@@go:\r
+ mov [bufferwidth],ax\r
+ mov es,[grsegs+STARTFONTM*2]\r
+ mov ax,[es:pcharheight]\r
+ mov [bufferheight],ax\r
+\r
+; set AND mode to punch out the mask\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_DATAROTATE + 8*256\r
+ WORDOUT\r
+\r
+; set mapmask to all\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK + 15*256\r
+ WORDOUT\r
+\r
+ mov si,OFFSET databuffer\r
+ call BufferToScreen\r
+\r
+; set OR mode to fill in the color\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_DATAROTATE + 16*256\r
+ WORDOUT\r
+\r
+; set mapmask to color\r
+ mov dx,SC_INDEX\r
+ mov al,SC_MAPMASK\r
+ mov ah,[fontcolor]\r
+ WORDOUT\r
+\r
+ call BufferToScreen ; SI is still in the right position in buffer\r
+\r
+; set copy mode\r
+ mov dx,GC_INDEX\r
+ mov ax,GC_DATAROTATE\r
+ WORDOUT\r
+\r
+; set mapmask to all\r
+ mov dx,SC_INDEX\r
+ mov ax,SC_MAPMASK + 15*256\r
+ WORDOUT\r
+\r
+\r
+ ret\r
+\r
+ENDP\r
+\r
+endif ; if numfontm\r
+\r
+endif ; if fonts\r