; .386 .486 ; I only need .386, but I wanted the 486 cycle timings .MODEL FLAT, C ;;--- Types --- PTRBYTE TYPEDEF PTR BYTE PTRWORD TYPEDEF PTR WORD PTRDWORD TYPEDEF PTR DWORD PTRPROC TYPEDEF PTR PROC ;;--- Constants --- ; Width and height of sections in pixels. SWIDTH equ 8 SHEIGHT equ 8 LOG2_SWIDTH equ 3 LOG2_SHEIGHT equ 3 ;;--- EXTERN pal_tbl:BYTE ;unsigned char pal_tbl[3*256]; EXTERN pal15_tbl:WORD ;unsigned short pal15_tbl[256]; ;; NextFrame working storage ; MemRec nf_mem_buf1; ; MemRec nf_mem_buf2; EXTERN nf_buf_cur: PTRBYTE ; unsigned char* nf_buf_cur; EXTERN nf_buf_prv: PTRBYTE ; unsigned char* nf_buf_prv; ;; NextFrame parameters EXTERN nf_wqty: BYTE ;unsigned char nf_wqty; // (width/SWIDTH) EXTERN nf_hqty: BYTE ;unsigned char nf_hqty; // (height/SHEIGHT) EXTERN nf_fqty: BYTE ;unsigned char nf_fqty; // Number of fields EXTERN nf_hicolor: DWORD ;unsigned nf_hicolor; // HiColor (0:none,1:normal,2:swapped) ;; EXTERN nf_width: DWORD ;unsigned nf_width; // wqty * SWIDTH EXTERN nf_height: DWORD ;unsigned nf_height; // hqty * SHEIGHT; EXTERN nf_new_line: DWORD ;unsigned nf_new_line; // width - SWIDTH EXTERN nf_new_row0: DWORD ;unsigned nf_new_row0; // SHEIGHT*width*2-width EXTERN nf_back_right: DWORD ;unsigned nf_back_right; // (SHEIGHT-1)*width ;; Frame parameters ;; Portion of current frame which has been updated ;; and needs to be sent to screen. ;; EXTERN nf_new_x: DWORD ;unsigned nf_new_x; EXTERN nf_new_y: DWORD ;unsigned nf_new_y; EXTERN nf_new_w: DWORD ;unsigned nf_new_w; EXTERN nf_new_h: DWORD ;unsigned nf_new_h; .data BYTE "(c) 1997 Interplay Productions. All Rights Reserved.\n" BYTE "This file is confidential and consists of proprietary information\n" BYTE "of Interplay Productions. This file and associated libraries\n" BYTE "may not, in whole or in part, be disclosed to third parties,\n" BYTE "incorporated into any software product which is not being created\n" BYTE "for Interplay Productions, copied or duplicated in any form,\n" BYTE "without the prior written permission of Interplay Productions.\n" BYTE "Further, you may not reverse engineer, decompile or otherwise\n" BYTE "attempt to derive source code of this material.\n",0 .code NF_DECOMP_INIT MACRO HI_COLOR_FLAG: REQ mov ax, ds ; Insure es==ds for symantec flat mode mov es, ax mov eax, nf_buf_prv ; DiffBufPtrs = nf_buf_prv - nf_buf_cur sub eax, nf_buf_cur mov DiffBufPtrs, eax xor ebx, ebx ; ebx = nf_fqty (convert to 32-bits) mov bl, nf_fqty mov eax, x ; nf_new_x = x*SWIDTH*2^HI_COLOR_FLAG; shl eax, LOG2_SWIDTH+HI_COLOR_FLAG mov nf_new_x, eax mov eax, w ; nf_new_w = w*SWIDTH*2^HI_COLOR_FLAG; shl eax, LOG2_SWIDTH+HI_COLOR_FLAG mov nf_new_w, eax mov eax, y ; nf_new_y = y*nf_fqty*SHEIGHT; shl eax, LOG2_SHEIGHT mul ebx ;nf_fqty mov nf_new_y, eax mov eax, h ; nf_new_h = h*nf_fqty*SHEIGHT; shl eax, LOG2_SHEIGHT mul ebx ;nf_fqty mov nf_new_h, eax mov eax, nf_new_row0 ; new_row = nf_new_row0 - nf_new_w; sub eax, nf_new_w mov new_row, eax ;; Move to correct place in current buffer mov eax, nf_buf_cur ; tbuf = nf_buf_cur mov tbuf, eax .if x || y ; if (x||y) mov eax, nf_new_y ; tbuf += nf_new_y*nf_width + nf_new_x; mul nf_width add eax, nf_new_x add tbuf, eax .endif ENDM ; DECOMP_INIT DECOMP_BODY MACRO HI_COLOR_FLAG:REQ LOCAL HI_COLOR_SCALE HI_COLOR_SCALE equ HI_COLOR_FLAG+1 NF_DECOMP_INIT HI_COLOR_FLAG mov eax, w ; parms_sz = (w*h*nf_fqty)<<1 mul h mul ebx ;nf_fqty shl eax, 1 mov parms_sz, eax ; esi indexes comp (to get new section data) ; edi indexes current screen buffer ; edx is a frequently used constant ; ebx indexes section params mov edi, tbuf mov edx, nf_new_line ; width - SWIDTH mov ebx, comp ; Parms index mov esi, ebx add esi, parms_sz ; Skip over flags (w*h*2) ; Iterate over params and copy new hires data to appropriate sections. mov cl, nf_fqty ns_0f: push ecx push edi mov ch, byte ptr h ns_0: mov cl, byte ptr w ns_1: cmp word ptr [ebx],0 je ns_10 add edi, SWIDTH*HI_COLOR_SCALE ns_2: add ebx, 2 dec cl jnz ns_1 add edi, new_row ; SHEIGHT*width - SWIDTH*w dec ch jnz ns_0 pop edi pop ecx add edi, nf_width dec cl jnz ns_0f jmp ns_99 ; Copy new data to one section ; Enter with esi pointing to source data, edi to screen section. ; Assumes SWIDTH=8 (16-bit data) and SHEIGHT=8 ns_10: REPEAT 7 REPEAT 2*HI_COLOR_SCALE movsd ENDM add edi, edx ENDM REPEAT 2*HI_COLOR_SCALE movsd ENDM sub edi, nf_back_right ; (SHEIGHT-1)*width jmp ns_2 ns_99: ; Iterate over flags and motion source addresses from params ; to determine which sections to move. ; ebx indexes params. ; esi indexes source from buffer ; esi will be computed as +- 16K relative to edi. sub ebx, parms_sz ; Move back to start of section parms mov edi, tbuf mov cl, nf_fqty xor esi, esi ms_0f: push ecx push edi mov ch, byte ptr h ms_0: mov cl, byte ptr w ms_1: or si, [ebx] jg ms_10 jl ms_j30 add edi, SWIDTH*HI_COLOR_SCALE ms_2: add ebx, 2 dec cl jnz ms_1 add edi, new_row ; SHEIGHT*width - SWIDTH*w dec ch jnz ms_0 pop edi pop ecx add edi, nf_width dec cl jnz ms_0f jmp ms_99 ms_j30: jmp ms_30 ; Move one section from current screen to current screen. ; Enter with ; edi pointing to destination screen section, ; relative value of source offset in esi. ; The following assumes SWIDTH==8 and SHEIGHT==8 ms_10: ; Make esi absolute lea esi, [esi*HI_COLOR_SCALE-04000h*HI_COLOR_SCALE+edi] REPEAT 7 REPEAT 2*HI_COLOR_SCALE movsd ENDM add esi, edx add edi, edx ENDM REPEAT 2*HI_COLOR_SCALE movsd ENDM sub edi, nf_back_right ; (SHEIGHT-1)*width xor esi, esi ; Reset esi to zero jmp ms_2 ms_20f: push ecx push edi mov ch, byte ptr h ms_20: mov cl, byte ptr w ms_21: or si, [ebx] jl ms_30 jg ms_j10 add edi, SWIDTH*HI_COLOR_SCALE ms_22: add ebx, 2 dec cl jnz ms_21 add edi, new_row ; SHEIGHT*width - SWIDTH*w dec ch jnz ms_20 pop edi pop ecx add edi, nf_width dec cl jnz ms_20f jmp ms_99 ms_j10: jmp ms_10 ; Move one section from previous screen to current screen. ; Enter with ; edi pointing to destination screen section, ; relative value of source offset in esi. ; The following assumes SWIDTH==8 and SHEIGHT==8 ms_30: ; Make esi absolute lea esi, [esi*HI_COLOR_SCALE-0C000h*HI_COLOR_SCALE+edi] add esi, DiffBufPtrs ; and point to other buffer REPEAT 7 REPEAT 2*HI_COLOR_SCALE movsd ENDM add esi, edx add edi, edx ENDM REPEAT 2*HI_COLOR_SCALE movsd ENDM sub edi, nf_back_right ; (SHEIGHT-1)*width xor esi, esi ; Reset esi to zero jmp ms_22 ms_99: ENDM ; DECOMP_BODY ; Non-HiColor versions ; Decompress into subsection of current buffer specified ; by x,y,w,h in units of SWIDTHxSHEIGHT (8x8). ; ;void nfDecomp(unsigned char *comp, ; unsigned x, unsigned y, unsigned w, unsigned h) ; nfDecomp PROC USES ESI EDI EBX, comp:PTRBYTE, x:DWORD, y:DWORD, w:DWORD, h:DWORD LOCAL tbuf: PTRBYTE LOCAL new_row: DWORD LOCAL DiffBufPtrs: DWORD LOCAL parms_sz: DWORD .if nf_hicolor INVOKE nfHiColorDecomp, comp,x,y,w,h ret .endif DECOMP_BODY 0 ; Not HiColor ret nfDecomp ENDP ; Decompress into subsection of current buffer specified ; by x,y,w,h in units of SWIDTHxSHEIGHT (8x8). ; ;void ;nfHiColorDecomp(unsigned char *comp, ; unsigned x, unsigned y, unsigned w, unsigned h) ; nfHiColorDecomp PROC USES ESI EDI EBX,comp:PTRBYTE,x:DWORD, y:DWORD, w:DWORD, h:DWORD LOCAL tbuf: PTRBYTE LOCAL new_row: DWORD LOCAL DiffBufPtrs: DWORD LOCAL parms_sz: DWORD DECOMP_BODY 1 ; HiColor ret nfHiColorDecomp ENDP DECOMP_CHG_BODY MACRO HI_COLOR_FLAG:REQ LOCAL HI_COLOR_SCALE HI_COLOR_SCALE equ HI_COLOR_FLAG+1 NF_DECOMP_INIT HI_COLOR_FLAG ; esi indexes comp (to get new section data) ; edi indexes current screen buffer ; edx is a frequently used constant ; ebx indexes section params mov edi, tbuf mov edx, nf_new_line ; width - SWIDTH mov esi, comp mov ebx, parms ; Iterate over params and copy new hires data to appropriate sections. mov eax, chgs mov pChgs, eax mov eax, 0 mov cl, nf_fqty ns_0f: push ecx push edi mov ch, byte ptr h ns_0: mov cl, byte ptr w ns_1: add ax, ax ja ns_1b jz ns_5 cmp word ptr [ebx],0 je ns_10 add ebx, 2 ns_1b: add edi, SWIDTH*HI_COLOR_SCALE ns_2: dec cl jnz ns_1 add edi, new_row ; SHEIGHT*width - SWIDTH*w dec ch jnz ns_0 pop edi pop ecx add edi, nf_width dec cl jnz ns_0f jmp ns_99 ns_5: mov eax, pChgs add pChgs, 2 mov ax, [eax] jmp ns_1 ; Copy new data to one section ; Enter with ds:si pointing to source data, es:di to screen section. ; Assumes SWIDTH=8 (16-bit data) and SHEIGHT=8 ns_10: REPEAT 7 REPEAT 2*HI_COLOR_SCALE movsd ENDM add edi, edx ENDM REPEAT 2*HI_COLOR_SCALE movsd ENDM sub edi, nf_back_right ; (SHEIGHT-1)*width add ebx, 2 jmp ns_2 ns_99: ; Iterate over flags and motion source addresses from params ; to determine which sections to move. ; ebx indexes params. ; esi indexes source from buffer ; esi will be computed as +- 16K relative to edi. mov edi, tbuf mov ebx, parms mov eax, chgs mov pChgs, eax mov eax, 0 mov cl, byte ptr nf_fqty xor esi, esi ms_0f: push ecx push edi mov ch, byte ptr h ms_0: mov cl, byte ptr w ms_1: add ax, ax ja ms_1b jz ms_5 or si, [ebx] jg ms_10 jl ms_j30 add ebx, 2 ms_1b: add edi, SWIDTH*HI_COLOR_SCALE ms_2: dec cl jnz ms_1 add edi, new_row ; SHEIGHT*width - SWIDTH*w dec ch jnz ms_0 pop edi pop ecx add edi, nf_width dec cl jnz ms_0f jmp ms_99 ms_5: mov eax, pChgs add pChgs, 2 mov ax, word ptr [eax] jmp ms_1 ms_j30: jmp ms_30 ; Move one section from current screen to current screen. ; Enter with ; edi pointing to destination screen section, ; relative value of source offset in esi. ; The following assumes SWIDTH==8 and SHEIGHT==8 ms_10: ; Make esi absolute lea esi, [esi*HI_COLOR_SCALE-04000h*HI_COLOR_SCALE+edi] REPEAT 7 REPEAT 2*HI_COLOR_SCALE movsd ENDM add esi, edx add edi, edx ENDM REPEAT 2*HI_COLOR_SCALE movsd ENDM sub edi, nf_back_right ; (SHEIGHT-1)*width xor esi, esi ; Reset esi to zero add ebx, 2 jmp ms_2 ms_20f: push ecx push edi mov ch, byte ptr h ms_20: mov cl, byte ptr w ms_21: add ax, ax ja ms_21b jz ms_25 or si, [ebx] jl ms_30 jg ms_j10 add ebx, 2 ms_21b: add edi, SWIDTH*HI_COLOR_SCALE ms_22: dec cl jnz ms_21 add edi, new_row ; SHEIGHT*width - SWIDTH*w dec ch jnz ms_20 pop edi pop ecx add edi, nf_width dec cl jnz ms_20f jmp ms_99 ms_25: mov eax, pChgs add pChgs, 2 mov ax, [eax] jmp ms_21 ms_j10: jmp ms_10 ; Move one section from previous screen to current screen. ; Enter with ; edi pointing to destination screen section, ; relative value of source offset in esi. ; The following assumes SWIDTH==8 and SHEIGHT==8 ms_30: ; Make esi absolute lea esi, [esi*HI_COLOR_SCALE-0C000h*HI_COLOR_SCALE+edi] add esi, DiffBufPtrs ; and point to other buffer REPEAT 7 REPEAT 2*HI_COLOR_SCALE movsd ENDM add esi, edx add edi, edx ENDM REPEAT 2*HI_COLOR_SCALE movsd ENDM sub edi, nf_back_right ; (SHEIGHT-1)*width add ebx, 2 xor esi, esi ; Reset esi to zero jmp ms_22 ms_99: ENDM ; DECOMP_CHG_BODY ; Decompress into subsection of current buffer specified ; by x,y,w,h in units of SWIDTHxSHEIGHT (8x8). ; Chgs specifies which squares to update. ; Parms are motion parms for squares to update. ; ;void ;nfDecompChg(unsigned short *chgs, ; unsigned short *parms, ; unsigned char *comp, ; unsigned x, unsigned y, unsigned w, unsigned h) ; nfDecompChg PROC USES ESI EDI EBX,chgs:PTRWORD, parms:PTRWORD,comp:PTRBYTE,x:DWORD, y:DWORD, w:DWORD, h:DWORD LOCAL tbuf: PTRBYTE LOCAL new_row: DWORD LOCAL DiffBufPtrs: DWORD LOCAL pChgs: PTRBYTE .if nf_hicolor INVOKE nfHiColorDecompChg, chgs,parms,comp,x,y,w,h ret .endif DECOMP_CHG_BODY 0 ; Not HiColor ret nfDecompChg ENDP ; Decompress into subsection of current buffer specified ; by x,y,w,h in units of SWIDTHxSHEIGHT (8x8). ; Chgs specifies which squares to update. ; Parms are motion parms for squares to update. ; ;void ;nfHiColorDecompChg(unsigned short *chgs, ; unsigned short *parms, ; unsigned char *comp, ; unsigned x, unsigned y, unsigned w, unsigned h) ; nfHiColorDecompChg PROC USES ESI EDI EBX,chgs:PTRWORD,parms:PTRWORD,comp:PTRBYTE,x:DWORD, y:DWORD, w:DWORD, h:DWORD LOCAL tbuf: PTRBYTE LOCAL new_row: DWORD LOCAL DiffBufPtrs: DWORD LOCAL pChgs: PTRBYTE DECOMP_CHG_BODY 1 ; HiColor ret nfHiColorDecompChg ENDP .data ; luminace table for palette entries lum_tbl DWORD 256 DUP (0) ; signed 8-bit y * nf_width nfpk_ShiftY DWORD 256 DUP (0) ; Constant tables ; 8-bit -8:7 x nf_width + -8:7 nfpk_ShiftP1 LABEL WORD FOR y, <-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7> FOR x, <-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7> BYTE x,y ENDM ENDM ; 8-bit to right and below in roughly 0:14*nf_width + -14:14 (-3 cases) ; negative is ; 8-bit to left and above in roughly -14:0*nf_width + -14:14 (-3 cases) nfpk_ShiftP2 LABEL WORD FOR y, <0,1,2,3,4,5,6,7> FOR x, <8,9,10,11,12,13,14> BYTE x,y ENDM ENDM FOR y, <8,9,10,11,12,13> FOR x, <-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1> BYTE x,y ENDM FOR x, <0,1,2,3,4,5,6,7,8,9,10,11,12,13,14> BYTE x,y ENDM ENDM FOR x, <-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1> BYTE x,14 ENDM FOR x, <0,1,2,3,4,5,6,7,8,9,10,11> BYTE x,14 ENDM nfpk_mov4l LABEL DWORD ; mov ax, bx,cx MOV4L_REGS TEXTEQU > %FOR m4, MOV4L_REGS % FOR m3, MOV4L_REGS % FOR m2, MOV4L_REGS % FOR m1, MOV4L_REGS BYTE m2,m1,m4,m3 ENDM ENDM ENDM ENDM nfpk_mov8 LABEL DWORD ; mov ax, bx/dx/cx/bp MOV8_REGS TEXTEQU > %FOR m4, MOV8_REGS % FOR m3, MOV8_REGS % FOR m2, MOV8_REGS % FOR m1, MOV8_REGS BYTE m2,m1,m4,m3 ENDM ENDM ENDM ENDM nfpk_mov4 LABEL DWORD ; mov al, bl/bh/cl/ch MOV4_REGS0 TEXTEQU > ; mov ah, bl/bh/cl/ch MOV4_REGS1 TEXTEQU > %FOR m4, MOV4_REGS1 % FOR m3, MOV4_REGS0 % FOR m2, MOV4_REGS1 % FOR m1, MOV4_REGS0 BYTE m3,m4,m1,m2 ENDM ENDM ENDM ENDM .code ; nfPkConfig initializes tables used by nfPkDecomp ; which are dependent on screen size. nfPkConfig PROC USES ESI EDI EBX ; Build ShiftY table ; lea edi, nfpk_ShiftY mov ebx, nf_width mov eax, 0 mov ecx, 128 lp1: mov [edi], eax add edi,4 add eax,ebx dec ecx jne lp1 mov eax, ebx shl eax, 7 neg eax mov ecx, 128 lp2: mov [edi], eax add edi,4 add eax,ebx dec ecx jne lp2 ret nfPkConfig ENDP EXTERN sf_LineWidth: DWORD ;unsigned sf_LineWidth; // Distance between lines in memory ; Banked screen parameters EXTERN sf_SetBank: PTRPROC ;unsigned long sf_SetBank; EXTERN sf_WinGran: DWORD ;unsigned sf_WinGran; EXTERN sf_WinSize: DWORD ;unsigned long sf_WinSize; EXTERN sf_WinGranPerSize: DWORD ;unsigned sf_WinGranPerSize; ;{sf_WriteWinPtr and sf_WriteWinLimit replace sf_WriteWinSeg, see mveliba.asm} EXTERN sf_WriteWinPtr: PTRBYTE ;unsigned char *sf_WriteWinPtr; EXTERN sf_WriteWinLimit: PTRBYTE ;unsigned char *WriteWinLimit; EXTERN sf_WriteWin: DWORD ;unsigned sf_WriteWin; EXTERN opt_hscale_step: DWORD EXTERN opt_hscale_adj: DWORD ;void mve_ShowFrameField( ; unsigned char *buf, unsigned bufw, unsigned bufh, ; unsigned sx, unsigned sy, unsigned w, unsigned h, ; unsigned dstx, unsigned dsty, unsigned field) mve_ShowFrameField PROC USES ESI EDI EBX, buf:PTRBYTE, bufw:DWORD, bufh:DWORD, sx:DWORD, sy:DWORD, w:DWORD, h:DWORD, dstx:DWORD, dsty:DWORD, field:DWORD LOCAL bank:DWORD LOCAL w4:DWORD LOCAL new_src_line:DWORD LOCAL linestep:DWORD LOCAL new_dst_line:DWORD mov ax, ds ; Insure es==ds for symantec flat mode mov es, ax mov eax, w ; w4 = w>>2 shr eax, 2 mov w4, eax ;;; ;;; In stretched width mode, we either keep 4/5 (a) of the source pixels, ;;; or duplicate every fourth pixel to magnify by 5/4 (b). ;;; In these cases, new_src_line is either bufw-w*5/4 (a) or bufw-w*4/5 (b). ;;; Let ScaleStep be 5 (a) or 3 (b) instead of 4. This is the amount to advance ;;; the source after copying 32-bits from source to destination. ;;; The coordinate system used for the source will be a simulated scaled system. ;;; Rather than scale height, I plan to use alternate vertical resolutions. However, ;;; it might be a good idea to also provide for scaled height in case we want a ;;; higher resolution border. ;;; Question: Do we still need to support transferring subrectangles? .if opt_hscale_step==4 mov eax, bufw ; new_src_line = bufw - w sub eax, w mov new_src_line, eax .else mov eax, opt_hscale_adj mov new_src_line, eax .endif mov eax, sf_LineWidth ; linestep = sf_LineWidth<<1; .if field ; if (field) add eax, eax ; linestep <<= 1; .endif mov linestep, eax sub eax, w ; new_dst_line = linestep - w; mov new_dst_line, eax mov eax, sy ; buf += sy*bufw + sx mul bufw add eax, sx add buf, eax mov eax, sx ; dstx += sx add dstx, eax ; This is a hack. We should pass in src x,y of origin ; or make dstx/dsty absolute. ; mov eax, bufw ; if (field && sx >= (bufw>>1) shr eax, 1 .if field && sx >= eax sub dstx, eax ; dstx -= bufw>>1 .endif mov eax, sy ; dsty += sy add dsty, eax .if sf_SetBank==0 ;------------------ ; dst = WriteWinPtr + (dsty*linestep+dstx) mov edi, sf_WriteWinPtr mov eax, dsty mul linestep add eax, dstx add edi, eax .if field & 1 add edi, sf_LineWidth; .endif mov eax, new_src_line mov edx, new_dst_line mov esi, buf mov ebx, h .if opt_hscale_step==3 sub edi, 8 sf_lp2a:mov ecx, w4 shr ecx, 2 ALIGN 4 sf_lp2b:mov eax, [esi] mov [edi+8], eax mov eax, [esi+3] mov [edi+12], eax add edi, 16 mov eax, [esi+6] mov [edi], eax mov eax, [esi+9] mov [edi+4], eax add esi, 12 dec ecx jnz sf_lp2b ; To avoid problem of last pixel coming from next line ; with arrange for w%16==12, so here is where we copy ; last 12 pixels. mov eax, [esi] mov [edi+8], eax mov eax, [esi+3] mov [edi+12], eax add edi, 12 mov eax, [esi+6] mov [edi+4], eax add esi, 9 add esi, new_src_line add edi, edx dec ebx jnz sf_lp2a add edi, 8 .else sf_lp: mov ecx, w4 ;width/4 rep movsd add esi, eax add edi, edx dec ebx jnz sf_lp .endif .else ; sf_SetBank ;------------------ mov esi, buf ; start = dsty * linestep + dstx mov eax, linestep mul dsty .if field & 1 add eax, sf_LineWidth .endif add eax, dstx ; bank = start / WinGran ; dst = (start % WinGran) + sf_WriteWinPtr mov edx, 0 div sf_WinGran mov bank, eax mov edi, edx add edi, sf_WriteWinPtr ; Select new bank mov bh, 0 mov bl, byte ptr sf_WriteWin mov edx, bank call sf_SetBank ; eax/edx destroyed by sf_SetBank sf_0: ; rem = sf_WriteWinLimit - dst mov eax, sf_WriteWinLimit sub eax, edi ; h2 = (rem+(LineWidth-w))/LineWidth add eax, linestep sub eax, w mov edx, 0 div linestep ; if (h