]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/ID_VW_AE.ASM
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / ID_VW_AE.ASM
1 ; Reconstructed Commander Keen 4-6 Source Code\r
2 ; Copyright (C) 2021 K1n9_Duk3\r
3 ;\r
4 ; This file is primarily based on:\r
5 ; Catacomb 3-D Source Code\r
6 ; Copyright (C) 1993-2014 Flat Rock Software\r
7 ;\r
8 ; This program is free software; you can redistribute it and/or modify\r
9 ; it under the terms of the GNU General Public License as published by\r
10 ; the Free Software Foundation; either version 2 of the License, or\r
11 ; (at your option) any later version.\r
12 ;\r
13 ; This program is distributed in the hope that it will be useful,\r
14 ; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16 ; GNU General Public License for more details.\r
17 ;\r
18 ; You should have received a copy of the GNU General Public License along\r
19 ; with this program; if not, write to the Free Software Foundation, Inc.,\r
20 ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
21 \r
22 ;=================================\r
23 ;\r
24 ; EGA view manager routines\r
25 ;\r
26 ;=================================\r
27 \r
28 ;============================================================================\r
29 ;\r
30 ; All EGA drawing routines that write out words need to have alternate forms\r
31 ; for starting on even and odd addresses, because writing a word at segment\r
32 ; offset 0xffff causes an exception!  To work around this, write a single\r
33 ; byte out to make the address even, so it wraps cleanly at the end.\r
34 ;\r
35 ; All of these routines assume read/write mode 0, and will allways return\r
36 ; in that state.\r
37 ; The direction flag should be clear\r
38 ; readmap/writemask is left in an undefined state\r
39 ;\r
40 ;============================================================================\r
41 \r
42 \r
43 ;============================================================================\r
44 ;\r
45 ; VW_Plot (int x,y,color)\r
46 ;\r
47 ;============================================================================\r
48 \r
49 DATASEG\r
50 \r
51 plotpixels      db      128,64,32,16,8,4,2,1\r
52 \r
53 CODESEG\r
54 \r
55 PROC    VW_Plot x:WORD, y:WORD, color:WORD\r
56 PUBLIC  VW_Plot\r
57 USES    SI,DI\r
58 \r
59         mov     es,[screenseg]\r
60 \r
61         mov     dx,SC_INDEX\r
62         mov     ax,SC_MAPMASK+15*256\r
63         WORDOUT\r
64 \r
65         mov     dx,GC_INDEX\r
66         mov     ax,GC_MODE+2*256        ;write mode 2\r
67         WORDOUT\r
68 \r
69         mov     di,[bufferofs]\r
70         mov     bx,[y]\r
71         shl     bx,1\r
72         add     di,[ylookup+bx]\r
73         mov     bx,[x]\r
74         mov     ax,bx\r
75         shr     ax,1\r
76         shr     ax,1\r
77         shr     ax,1\r
78         add     di,ax                           ; di = byte on screen\r
79 \r
80         and     bx,7\r
81         mov     ah,[plotpixels+bx]\r
82         mov     al,GC_BITMASK           ;mask off other pixels\r
83         WORDOUT\r
84 \r
85         mov             bl,[BYTE color]\r
86         xchg    bl,[es:di]              ; load latches and write pixel\r
87 \r
88         mov     dx,GC_INDEX\r
89         mov     ah,0ffh                         ;no bit mask\r
90         WORDOUT\r
91         mov     ax,GC_MODE+0*256        ;write mode 0\r
92         WORDOUT\r
93 \r
94         ret\r
95 \r
96 ENDP\r
97 \r
98 \r
99 ;============================================================================\r
100 ;\r
101 ; VW_Vlin (int yl,yh,x,color)\r
102 ;\r
103 ;============================================================================\r
104 \r
105 PROC    VW_Vlin yl:WORD, yh:WORD, x:WORD, color:WORD\r
106 PUBLIC  VW_Vlin\r
107 USES    SI,DI\r
108 \r
109         mov     es,[screenseg]\r
110 \r
111         mov     dx,SC_INDEX\r
112         mov     ax,SC_MAPMASK+15*256\r
113         WORDOUT\r
114 \r
115         mov     dx,GC_INDEX\r
116         mov     ax,GC_MODE+2*256        ;write mode 2\r
117         WORDOUT\r
118 \r
119         mov     di,[bufferofs]\r
120         mov     bx,[yl]\r
121         shl     bx,1\r
122         add     di,[ylookup+bx]\r
123         mov     bx,[x]\r
124         mov     ax,bx\r
125         shr     ax,1\r
126         shr     ax,1\r
127         shr     ax,1\r
128         add     di,ax                           ; di = byte on screen\r
129 \r
130         and     bx,7\r
131         mov     ah,[plotpixels+bx]\r
132         mov     al,GC_BITMASK           ;mask off other pixels\r
133         WORDOUT\r
134 \r
135         mov     cx,[yh]\r
136         sub     cx,[yl]\r
137         inc     cx                                      ;number of pixels to plot\r
138 \r
139         mov     bh,[BYTE color]\r
140         mov     dx,[linewidth]\r
141 \r
142 @@plot:\r
143         mov             bl,bh\r
144         xchg    bl,[es:di]              ; load latches and write pixel\r
145         add             di,dx\r
146 \r
147         loop    @@plot\r
148 \r
149         mov     dx,GC_INDEX\r
150         mov     ah,0ffh                         ;no bit mask\r
151         WORDOUT\r
152         mov     ax,GC_MODE+0*256        ;write mode 0\r
153         WORDOUT\r
154 \r
155         ret\r
156 \r
157 ENDP\r
158 \r
159 \r
160 ;============================================================================\r
161 \r
162 \r
163 ;===================\r
164 ;\r
165 ; VW_DrawTile8\r
166 ;\r
167 ; xcoord in bytes (8 pixels), ycoord in pixels\r
168 ; All Tile8s are in one grseg, so an offset is calculated inside it\r
169 ;\r
170 ;===================\r
171 \r
172 PROC    VW_DrawTile8    xcoord:WORD, ycoord:WORD, tile:WORD\r
173 PUBLIC  VW_DrawTile8\r
174 USES    SI,DI\r
175 \r
176         mov     es,[screenseg]\r
177 \r
178         mov     di,[bufferofs]\r
179         add     di,[xcoord]\r
180         mov     bx,[ycoord]\r
181         shl     bx,1\r
182         add     di,[ylookup+bx]\r
183         mov     [ss:screendest],di              ;screen destination\r
184 \r
185         mov     bx,[linewidth]\r
186         dec     bx\r
187 \r
188         mov     si,[tile]\r
189         shl     si,1\r
190         shl     si,1\r
191         shl     si,1\r
192         shl     si,1\r
193         shl     si,1\r
194 \r
195         mov     ds,[grsegs+STARTTILE8*2] ; segment for all tile8s\r
196 \r
197         mov     cx,4                                    ;planes to draw\r
198         mov     ah,0001b                                ;map mask\r
199 \r
200         mov     dx,SC_INDEX\r
201         mov     al,SC_MAPMASK\r
202 \r
203 ;\r
204 ; start drawing\r
205 ;\r
206 \r
207 @@planeloop:\r
208         WORDOUT\r
209         shl     ah,1                                    ;shift plane mask over for next plane\r
210 \r
211         mov     di,[ss:screendest]              ;start at same place in all planes\r
212 \r
213 REPT    7\r
214         movsb\r
215         add     di,bx\r
216 ENDM\r
217         movsb\r
218 \r
219         loop    @@planeloop\r
220 \r
221         mov     ax,ss\r
222         mov     ds,ax                                   ;restore turbo's data segment\r
223 \r
224         ret\r
225 \r
226 ENDP\r
227 \r
228 \r
229 ;============================================================================\r
230 ;\r
231 ; VW_MaskBlock\r
232 ;\r
233 ; Draws a masked block shape to the screen.  bufferofs is NOT accounted for.\r
234 ; The mask comes first, then four planes of data.\r
235 ;\r
236 ;============================================================================\r
237 \r
238 DATASEG\r
239 \r
240 UNWOUNDMASKS    =       10\r
241 \r
242 \r
243 maskroutines    dw      mask0,mask0,mask1E,mask1E,mask2E,mask2O,mask3E,mask3O\r
244                                 dw      mask4E,mask4O,mask5E,mask5O,mask6E,mask6O\r
245                                 dw      mask7E,mask7O,mask8E,mask8O,mask9E,mask9O\r
246                                 dw      mask10E,mask10O\r
247 \r
248 \r
249 routinetouse    dw      ?\r
250 \r
251 CODESEG\r
252 \r
253 PROC    VW_MaskBlock    segm:WORD, ofs:WORD, dest:WORD, wide:WORD, height:WORD, planesize:WORD\r
254 PUBLIC  VW_MaskBlock\r
255 USES    SI,DI\r
256 \r
257         mov     es,[screenseg]\r
258 \r
259         mov     [BYTE planemask],1\r
260         mov     [BYTE planenum],0\r
261 \r
262         mov     di,[wide]\r
263         mov     dx,[linewidth]\r
264         sub     dx,[wide]\r
265         mov     [linedelta],dx                  ;amount to add after drawing each line\r
266 \r
267         mov     bx,[planesize]                  ; si+bx = data location\r
268 \r
269         cmp     di,UNWOUNDMASKS\r
270         jbe     @@unwoundroutine\r
271         mov     [routinetouse],OFFSET generalmask\r
272         jmp     NEAR @@startloop\r
273 \r
274 ;=================\r
275 ;\r
276 ; use the unwound routines\r
277 ;\r
278 ;=================\r
279 \r
280 @@unwoundroutine:\r
281         mov     cx,[dest]\r
282         shr     cx,1\r
283         rcl     di,1                                    ;shift a 1 in if destination is odd\r
284         shl     di,1                                    ;to index into a word width table\r
285         mov     ax,[maskroutines+di]    ;call the right routine\r
286         mov     [routinetouse],ax\r
287 \r
288 @@startloop:\r
289         mov     ds,[segm]\r
290 \r
291 @@drawplane:\r
292         mov     dx,SC_INDEX\r
293         mov     al,SC_MAPMASK\r
294         mov     ah,[ss:planemask]\r
295         WORDOUT\r
296         mov     dx,GC_INDEX\r
297         mov     al,GC_READMAP\r
298         mov     ah,[ss:planenum]\r
299         WORDOUT\r
300 \r
301         mov     si,[ofs]                                ;start back at the top of the mask\r
302         mov     di,[dest]                               ;start at same place in all planes\r
303         mov     cx,[height]                             ;scan lines to draw\r
304         mov dx,[ss:linedelta]\r
305 \r
306         jmp [ss:routinetouse]           ;draw one plane\r
307 planereturn:                                    ;routine jmps back here\r
308 \r
309         add     bx,[ss:planesize]               ;start of mask = start of next plane\r
310 \r
311         inc     [ss:planenum]\r
312         shl     [ss:planemask],1                ;shift plane mask over for next plane\r
313         cmp     [ss:planemask],10000b   ;done all four planes?\r
314         jne     @@drawplane\r
315 \r
316 mask0:\r
317         mov     ax,ss\r
318         mov     ds,ax\r
319         ret                                                     ;width of 0 = no drawing\r
320 \r
321 ;==============\r
322 ;\r
323 ; General purpose masked block drawing.  This could be optimised into\r
324 ; four routines to use words, but few play loop sprites should be this big!\r
325 ;\r
326 ;==============\r
327 \r
328 generalmask:\r
329         mov     dx,cx\r
330 \r
331 @@lineloopgen:\r
332         mov     cx,[wide]\r
333 @@byteloop:\r
334         mov     al,[es:di]\r
335         and     al,[si]\r
336         or      al,[bx+si]\r
337         inc     si\r
338         stosb\r
339         loop    @@byteloop\r
340 \r
341         add     di,[ss:linedelta]\r
342         dec     dx\r
343         jnz     @@lineloopgen\r
344         jmp     planereturn\r
345 \r
346 ;=================\r
347 ;\r
348 ; Horizontally unwound routines to draw certain masked blocks faster\r
349 ;\r
350 ;=================\r
351 \r
352 MACRO   MASKBYTE\r
353         lodsb\r
354         and     al,[es:di]\r
355         or      al,[bx+si-1]\r
356         stosb\r
357 ENDM\r
358 \r
359 MACRO   MASKWORD\r
360         lodsw\r
361         and     ax,[es:di]\r
362         or      ax,[bx+si-2]\r
363         stosw\r
364 ENDM\r
365 \r
366 MACRO   SPRITELOOP      addr\r
367         add     di,dx\r
368         loop    addr\r
369         jmp     planereturn\r
370 ENDM\r
371 \r
372 \r
373 EVEN\r
374 mask1E:\r
375         MASKBYTE\r
376         SPRITELOOP      mask1E\r
377 \r
378 EVEN\r
379 mask2E:\r
380         MASKWORD\r
381         SPRITELOOP      mask2E\r
382 \r
383 EVEN\r
384 mask2O:\r
385         MASKBYTE\r
386         MASKBYTE\r
387         SPRITELOOP      mask2O\r
388 \r
389 EVEN\r
390 mask3E:\r
391         MASKWORD\r
392         MASKBYTE\r
393         SPRITELOOP      mask3E\r
394 \r
395 EVEN\r
396 mask3O:\r
397         MASKBYTE\r
398         MASKWORD\r
399         SPRITELOOP      mask3O\r
400 \r
401 EVEN\r
402 mask4E:\r
403         MASKWORD\r
404         MASKWORD\r
405         SPRITELOOP      mask4E\r
406 \r
407 EVEN\r
408 mask4O:\r
409         MASKBYTE\r
410         MASKWORD\r
411         MASKBYTE\r
412         SPRITELOOP      mask4O\r
413 \r
414 EVEN\r
415 mask5E:\r
416         MASKWORD\r
417         MASKWORD\r
418         MASKBYTE\r
419         SPRITELOOP      mask5E\r
420 \r
421 EVEN\r
422 mask5O:\r
423         MASKBYTE\r
424         MASKWORD\r
425         MASKWORD\r
426         SPRITELOOP      mask5O\r
427 \r
428 EVEN\r
429 mask6E:\r
430         MASKWORD\r
431         MASKWORD\r
432         MASKWORD\r
433         SPRITELOOP      mask6E\r
434 \r
435 EVEN\r
436 mask6O:\r
437         MASKBYTE\r
438         MASKWORD\r
439         MASKWORD\r
440         MASKBYTE\r
441         SPRITELOOP      mask6O\r
442 \r
443 EVEN\r
444 mask7E:\r
445         MASKWORD\r
446         MASKWORD\r
447         MASKWORD\r
448         MASKBYTE\r
449         SPRITELOOP      mask7E\r
450 \r
451 EVEN\r
452 mask7O:\r
453         MASKBYTE\r
454         MASKWORD\r
455         MASKWORD\r
456         MASKWORD\r
457         SPRITELOOP      mask7O\r
458 \r
459 EVEN\r
460 mask8E:\r
461         MASKWORD\r
462         MASKWORD\r
463         MASKWORD\r
464         MASKWORD\r
465         SPRITELOOP      mask8E\r
466 \r
467 EVEN\r
468 mask8O:\r
469         MASKBYTE\r
470         MASKWORD\r
471         MASKWORD\r
472         MASKWORD\r
473         MASKBYTE\r
474         SPRITELOOP      mask8O\r
475 \r
476 EVEN\r
477 mask9E:\r
478         MASKWORD\r
479         MASKWORD\r
480         MASKWORD\r
481         MASKWORD\r
482         MASKBYTE\r
483         SPRITELOOP      mask9E\r
484 \r
485 EVEN\r
486 mask9O:\r
487         MASKBYTE\r
488         MASKWORD\r
489         MASKWORD\r
490         MASKWORD\r
491         MASKWORD\r
492         SPRITELOOP      mask9O\r
493 \r
494 EVEN\r
495 mask10E:\r
496         MASKWORD\r
497         MASKWORD\r
498         MASKWORD\r
499         MASKWORD\r
500         MASKWORD\r
501         SPRITELOOP      mask10E\r
502 \r
503 EVEN\r
504 mask10O:\r
505         MASKBYTE\r
506         MASKWORD\r
507         MASKWORD\r
508         MASKWORD\r
509         MASKWORD\r
510         MASKBYTE\r
511         SPRITELOOP      mask10O\r
512 \r
513 \r
514 ENDP\r
515 \r
516 \r
517 ;============================================================================\r
518 ;\r
519 ; VW_InverseMask\r
520 ;\r
521 ; Draws a masked block shape to the screen.  bufferofs is NOT accounted for.\r
522 ; The mask comes first, then four planes of data.\r
523 ;\r
524 ;============================================================================\r
525 \r
526 PROC    VW_InverseMask  segm:WORD, ofs:WORD, dest:WORD, wide:WORD, height:WORD\r
527 PUBLIC  VW_InverseMask\r
528 USES    SI,DI\r
529 \r
530         mov     dx,SC_INDEX\r
531         mov     ax,SC_MAPMASK+15*256\r
532         WORDOUT\r
533         mov     dx,GC_INDEX\r
534         mov     ax,GC_DATAROTATE+16*256         ;set function = OR\r
535         WORDOUT\r
536 \r
537         mov     es, [screenseg]\r
538         mov     ax, [wide]\r
539         mov     dx, [linewidth]\r
540         sub     dx, ax;\r
541         mov     ds, [segm]\r
542         mov     si, [ofs]\r
543         mov     di, [dest]\r
544         mov     bx, [height]\r
545 @@yloop:\r
546         mov     cx, [wide]\r
547 @@xloop:\r
548         lodsb\r
549         not     al\r
550         xchg    al, [es:di]\r
551         inc     di\r
552         loop    @@xloop\r
553         add     di, dx\r
554         dec     bx\r
555         jnz     @@yloop\r
556 \r
557         mov     dx,GC_INDEX\r
558         mov     ax,GC_DATAROTATE+0*256          ;set function = no change\r
559         WORDOUT\r
560 \r
561         mov     ax,ss\r
562         mov     ds,ax                                   ;restore turbo's data segment\r
563 \r
564         ret\r
565 \r
566 ENDP\r
567 \r
568 ;============================================================================\r
569 ;\r
570 ; VW_ScreenToScreen\r
571 ;\r
572 ; Basic block copy routine.  Copies one block of screen memory to another,\r
573 ; using write mode 1 (sets it and returns with write mode 0).  bufferofs is\r
574 ; NOT accounted for.\r
575 ;\r
576 ;============================================================================\r
577 \r
578 PROC    VW_ScreenToScreen       source:WORD, dest:WORD, wide:WORD, height:WORD\r
579 PUBLIC  VW_ScreenToScreen\r
580 USES    SI,DI\r
581 \r
582         pushf\r
583         cli\r
584 \r
585         mov     dx,SC_INDEX\r
586         mov     ax,SC_MAPMASK+15*256\r
587         WORDOUT\r
588         mov     dx,GC_INDEX\r
589         mov     ax,GC_MODE+1*256\r
590         WORDOUT\r
591 \r
592         popf\r
593 \r
594         mov     bx,[linewidth]\r
595         sub     bx,[wide]\r
596 \r
597         mov     ax,[screenseg]\r
598         mov     es,ax\r
599         mov     ds,ax\r
600 \r
601         mov     si,[source]\r
602         mov     di,[dest]                               ;start at same place in all planes\r
603         mov     dx,[height]                             ;scan lines to draw\r
604         mov     ax,[wide]\r
605 \r
606 @@lineloop:\r
607         mov     cx,ax\r
608         rep     movsb\r
609         add     si,bx\r
610         add     di,bx\r
611 \r
612         dec     dx\r
613         jnz     @@lineloop\r
614 \r
615         mov     dx,GC_INDEX\r
616         mov     ax,GC_MODE+0*256\r
617         WORDOUT\r
618 \r
619         mov     ax,ss\r
620         mov     ds,ax                                   ;restore turbo's data segment\r
621 \r
622         ret\r
623 \r
624 ENDP\r
625 \r
626 \r
627 ;============================================================================\r
628 ;\r
629 ; VW_MemToScreen\r
630 ;\r
631 ; Basic block drawing routine. Takes a block shape at segment pointer source\r
632 ; with four planes of width by height data, and draws it to dest in the\r
633 ; virtual screen, based on linewidth.  bufferofs is NOT accounted for.\r
634 ; There are four drawing routines to provide the best optimized code while\r
635 ; accounting for odd segment wrappings due to the floating screens.\r
636 ;\r
637 ;============================================================================\r
638 \r
639 DATASEG\r
640 \r
641 memtoscreentable        dw      eventoeven,eventoodd,oddtoeven,oddtoodd\r
642 \r
643 CODESEG\r
644 \r
645 \r
646 PROC    VW_MemToScreen  source:WORD, dest:WORD, wide:WORD, height:WORD\r
647 PUBLIC  VW_MemToScreen\r
648 USES    SI,DI\r
649 \r
650         mov     es,[screenseg]\r
651 \r
652         mov     bx,[linewidth]\r
653         sub     bx,[wide]\r
654 \r
655         mov     ds,[source]\r
656 \r
657 \r
658         xor     si,si                                   ;block is segment aligned\r
659 \r
660         xor     di,di\r
661         shr     [wide],1                                ;change wide to words, and see if carry is set\r
662         rcl     di,1                                    ;1 if wide is odd\r
663         mov     ax,[dest]\r
664         shr     ax,1\r
665         rcl     di,1                                    ;shift a 1 in if destination is odd\r
666         shl     di,1                                    ;to index into a word width table\r
667         mov     ax,SC_MAPMASK+0001b*256 ;map mask for plane 0\r
668         jmp     [ss:memtoscreentable+di]        ;call the right routine\r
669 \r
670 ;==============\r
671 ;\r
672 ; Copy an even width block to an even video address\r
673 ;\r
674 ;==============\r
675 \r
676 eventoeven:\r
677         mov     dx,SC_INDEX\r
678         WORDOUT\r
679 \r
680         mov     di,[dest]                               ;start at same place in all planes\r
681         mov     dx,[height]                             ;scan lines to draw\r
682 \r
683 @@lineloopEE:\r
684         mov     cx,[wide]\r
685         rep     movsw\r
686 \r
687         add     di,bx\r
688 \r
689         dec     dx\r
690         jnz     @@lineloopEE\r
691 \r
692         shl     ah,1                                    ;shift plane mask over for next plane\r
693         cmp     ah,10000b                               ;done all four planes?\r
694         jne     eventoeven\r
695 \r
696         mov     ax,ss\r
697         mov     ds,ax                                   ;restore turbo's data segment\r
698 \r
699         ret\r
700 \r
701 ;==============\r
702 ;\r
703 ; Copy an odd width block to an even video address\r
704 ;\r
705 ;==============\r
706 \r
707 oddtoeven:\r
708         mov     dx,SC_INDEX\r
709         WORDOUT\r
710 \r
711         mov     di,[dest]                               ;start at same place in all planes\r
712         mov     dx,[height]                             ;scan lines to draw\r
713 \r
714 @@lineloopOE:\r
715         mov     cx,[wide]\r
716         rep     movsw\r
717         movsb                                           ;copy the last byte\r
718 \r
719         add     di,bx\r
720 \r
721         dec     dx\r
722         jnz     @@lineloopOE\r
723 \r
724         shl     ah,1                                    ;shift plane mask over for next plane\r
725         cmp     ah,10000b                               ;done all four planes?\r
726         jne     oddtoeven\r
727 \r
728         mov     ax,ss\r
729         mov     ds,ax                                   ;restore turbo's data segment\r
730 \r
731         ret\r
732 \r
733 ;==============\r
734 ;\r
735 ; Copy an even width block to an odd video address\r
736 ;\r
737 ;==============\r
738 \r
739 eventoodd:\r
740         dec     [wide]                                  ;one word has to be handled seperately\r
741 EOplaneloop:\r
742         mov     dx,SC_INDEX\r
743         WORDOUT\r
744 \r
745         mov     di,[dest]                               ;start at same place in all planes\r
746         mov     dx,[height]                             ;scan lines to draw\r
747 \r
748 @@lineloopEO:\r
749         movsb\r
750         mov     cx,[wide]\r
751         rep     movsw\r
752         movsb\r
753 \r
754         add     di,bx\r
755 \r
756         dec     dx\r
757         jnz     @@lineloopEO\r
758 \r
759         shl     ah,1                                    ;shift plane mask over for next plane\r
760         cmp     ah,10000b                               ;done all four planes?\r
761         jne     EOplaneloop\r
762 \r
763         mov     ax,ss\r
764         mov     ds,ax                                   ;restore turbo's data segment\r
765 \r
766         ret\r
767 \r
768 ;==============\r
769 ;\r
770 ; Copy an odd width block to an odd video address\r
771 ;\r
772 ;==============\r
773 \r
774 oddtoodd:\r
775         mov     dx,SC_INDEX\r
776         WORDOUT\r
777 \r
778         mov     di,[dest]                               ;start at same place in all planes\r
779         mov     dx,[height]                             ;scan lines to draw\r
780 \r
781 @@lineloopOO:\r
782         movsb\r
783         mov     cx,[wide]\r
784         rep     movsw\r
785 \r
786         add     di,bx\r
787 \r
788         dec     dx\r
789         jnz     @@lineloopOO\r
790 \r
791         shl     ah,1                                    ;shift plane mask over for next plane\r
792         cmp     ah,10000b                               ;done all four planes?\r
793         jne     oddtoodd\r
794 \r
795         mov     ax,ss\r
796         mov     ds,ax                                   ;restore turbo's data segment\r
797 \r
798         ret\r
799 \r
800 \r
801 ENDP\r
802 \r
803 ;===========================================================================\r
804 ;\r
805 ; VW_ScreenToMem\r
806 ;\r
807 ; Copies a block of video memory to main memory, in order from planes 0-3.\r
808 ; This could be optimized along the lines of VW_MemToScreen to take advantage\r
809 ; of word copies, but this is an infrequently called routine.\r
810 ;\r
811 ;===========================================================================\r
812 \r
813 PROC    VW_ScreenToMem  source:WORD, dest:WORD, wide:WORD, height:WORD\r
814 PUBLIC  VW_ScreenToMem\r
815 USES    SI,DI\r
816 \r
817         mov     es,[dest]\r
818 \r
819         mov     bx,[linewidth]\r
820         sub     bx,[wide]\r
821 \r
822         mov     ds,[screenseg]\r
823 \r
824         mov     ax,GC_READMAP                   ;read map for plane 0\r
825 \r
826         xor     di,di\r
827 \r
828 @@planeloop:\r
829         mov     dx,GC_INDEX\r
830         WORDOUT\r
831 \r
832         mov     si,[source]                             ;start at same place in all planes\r
833         mov     dx,[height]                             ;scan lines to draw\r
834 \r
835 @@lineloop:\r
836         mov     cx,[wide]\r
837         rep     movsb\r
838 \r
839         add     si,bx\r
840 \r
841         dec     dx\r
842         jnz     @@lineloop\r
843 \r
844         inc     ah\r
845         cmp     ah,4                                    ;done all four planes?\r
846         jne     @@planeloop\r
847 \r
848         mov     ax,ss\r
849         mov     ds,ax                                   ;restore turbo's data segment\r
850 \r
851         ret\r
852 \r
853 ENDP\r
854 \r
855 \r
856 ;============================================================================\r
857 ;\r
858 ; VWL_UpdateScreenBlocks\r
859 ;\r
860 ; Scans through the update matrix and copies any areas that have changed\r
861 ; to the visable screen, then zeros the update array\r
862 ;\r
863 ;============================================================================\r
864 \r
865 \r
866 \r
867 ; AX    0/1 for scasb, temp for segment register transfers\r
868 ; BX    width for block copies\r
869 ; CX    REP counter\r
870 ; DX    line width deltas\r
871 ; SI    source for copies\r
872 ; DI    scas dest / movsb dest\r
873 ; BP    pointer to end of bufferblocks\r
874 \r
875 PROC    VWL_UpdateScreenBlocks\r
876 PUBLIC  VWL_UpdateScreenBlocks\r
877 USES    SI,DI,BP\r
878 \r
879         jmp     SHORT @@realstart\r
880 @@done:\r
881 ;\r
882 ; all tiles have been scanned\r
883 ;\r
884         mov     dx,GC_INDEX                             ; restore write mode 0\r
885         mov     ax,GC_MODE+0*256\r
886         WORDOUT\r
887 \r
888         xor     ax,ax                                   ; clear out the update matrix\r
889         mov     cx,UPDATEWIDE*UPDATEHIGH/2\r
890 \r
891         mov     di,[updateptr]\r
892         rep     stosw\r
893 \r
894         ret\r
895 \r
896 @@realstart:\r
897         mov     dx,SC_INDEX\r
898         mov     ax,SC_MAPMASK+15*256\r
899         WORDOUT\r
900         mov     dx,GC_INDEX\r
901         mov     ax,GC_MODE+1*256\r
902         WORDOUT\r
903 \r
904         mov     di,[updateptr]                  ; start of floating update screen\r
905         mov     bp,di\r
906         add     bp,UPDATEWIDE*UPDATEHIGH+1 ; when di = bp, all tiles have been scanned\r
907 \r
908         push    di\r
909         mov     cx,-1                                   ; definately scan the entire thing\r
910 \r
911 ;\r
912 ; scan for a 1 in the update list, meaning a tile needs to be copied\r
913 ; from the master screen to the current screen\r
914 ;\r
915 @@findtile:\r
916         pop     di                                              ; place to continue scaning from\r
917         mov     ax,ss\r
918         mov     es,ax                                   ; search in the data segment\r
919         mov     ds,ax\r
920         mov al,1\r
921         repne   scasb\r
922         cmp     di,bp\r
923         jae     @@done\r
924 \r
925         cmp     [BYTE di],al\r
926         jne     @@singletile\r
927         jmp     @@tileblock\r
928 \r
929 ;============\r
930 ;\r
931 ; copy a single tile\r
932 ;\r
933 ;============\r
934 @@singletile:\r
935         inc     di                                              ; we know the next tile is nothing\r
936         push    di                                      ; save off the spot being scanned\r
937         sub     di,[updateptr]\r
938         shl     di,1\r
939         mov     di,[blockstarts-4+di]   ; start of tile location on screen\r
940         mov     si,di\r
941         add     si,[bufferofs]\r
942         add     di,[displayofs]\r
943 \r
944         mov     dx,[linewidth]\r
945         sub     dx,2\r
946         mov     ax,[screenseg]\r
947         mov     ds,ax\r
948         mov     es,ax\r
949 \r
950 REPT    15\r
951         movsb\r
952         movsb\r
953         add     si,dx\r
954         add     di,dx\r
955 ENDM\r
956         movsb\r
957         movsb\r
958 \r
959         jmp     @@findtile\r
960 \r
961 ;============\r
962 ;\r
963 ; more than one tile in a row needs to be updated, so do it as a group\r
964 ;\r
965 ;============\r
966 EVEN\r
967 @@tileblock:\r
968         mov     dx,di                                   ; hold starting position + 1 in dx\r
969         inc     di                                              ; we know the next tile also gets updated\r
970         repe    scasb                           ; see how many more in a row\r
971         push    di                                      ; save off the spot being scanned\r
972 \r
973         mov     bx,di\r
974         sub     bx,dx                                   ; number of tiles in a row\r
975         shl     bx,1                                    ; number of bytes / row\r
976 \r
977         mov     di,dx                                   ; lookup position of start tile\r
978         sub     di,[updateptr]\r
979         shl     di,1\r
980         mov     di,[blockstarts-2+di]   ; start of tile location\r
981         mov     si,di\r
982         add     si,[bufferofs]\r
983         add     di,[displayofs]\r
984 \r
985         mov     dx,[linewidth]\r
986         sub     dx,bx                                   ; offset to next line on screen\r
987 \r
988         mov     ax,[screenseg]\r
989         mov     ds,ax\r
990         mov     es,ax\r
991 \r
992 REPT    15\r
993         mov     cx,bx\r
994         rep     movsb\r
995         add     si,dx\r
996         add     di,dx\r
997 ENDM\r
998         mov     cx,bx\r
999         rep     movsb\r
1000 \r
1001         dec     cx                                              ; was 0 from last rep movsb, now $ffff for scasb\r
1002         jmp     @@findtile\r
1003 \r
1004 ENDP\r
1005 \r
1006 \r
1007 ;===========================================================================\r
1008 ;\r
1009 ;                    MISC EGA ROUTINES\r
1010 ;\r
1011 ;===========================================================================\r
1012 \r
1013 ;=================\r
1014 ;\r
1015 ; SyncVBL\r
1016 ;\r
1017 ;=================\r
1018 \r
1019 DATASEG\r
1020 \r
1021 EXTRN   TimeCount                       :DWORD\r
1022 EXTRN   jerk                    :WORD\r
1023 EXTRN   nopan                           :WORD\r
1024 \r
1025 CODESEG\r
1026 \r
1027 PROC SyncVBL\r
1028         mov     dx,STATUS_REGISTER_1\r
1029         mov     bx,[WORD TimeCount]\r
1030         add     bx,3\r
1031 @@waitloop:\r
1032         sti\r
1033         jmp     $+2\r
1034         cli\r
1035         cmp     [WORD TimeCount],bx\r
1036         je      @@done\r
1037 @@waitnovert:\r
1038         in      al,dx\r
1039         test    al,1\r
1040         jnz     @@waitnovert\r
1041 @@waitvert:\r
1042         in      al,dx\r
1043         test    al,1\r
1044         jz      @@waitvert\r
1045 \r
1046 REPT 5\r
1047         in      al,dx\r
1048         test    al,8\r
1049         jnz     @@waitloop\r
1050         test    al,1\r
1051         jz      @@waitloop\r
1052 ENDM\r
1053 \r
1054         test    [jerk],1\r
1055         jz      @@done\r
1056 \r
1057 REPT 5\r
1058         in      al,dx\r
1059         test    al,8\r
1060         jnz     @@waitloop\r
1061         test    al,1\r
1062         jz      @@waitloop\r
1063 ENDM\r
1064 \r
1065 @@done:\r
1066         ret\r
1067 ENDP\r
1068 \r
1069 \r
1070 ;==============\r
1071 ;\r
1072 ; VW_SetScreen\r
1073 ;\r
1074 ;==============\r
1075 \r
1076 PROC    VW_SetScreen  crtc:WORD, pel:WORD\r
1077 PUBLIC  VW_SetScreen\r
1078 \r
1079         call    SyncVBL\r
1080 ;\r
1081 ; set CRTC start\r
1082 ;\r
1083 ; for some reason, my XT's EGA card doesn't like word outs to the CRTC\r
1084 ; index...\r
1085 ;\r
1086         mov     cx,[crtc]\r
1087         mov     dx,CRTC_INDEX\r
1088         mov     al,0ch          ;start address high register\r
1089         out     dx,al\r
1090         inc     dx\r
1091         mov     al,ch\r
1092         out     dx,al\r
1093         dec     dx\r
1094         mov     al,0dh          ;start address low register\r
1095         out     dx,al\r
1096         mov     al,cl\r
1097         inc     dx\r
1098         out     dx,al\r
1099 \r
1100         test    [nopan],1\r
1101         jnz     @@done\r
1102 ;\r
1103 ; set horizontal panning\r
1104 ;\r
1105 \r
1106         mov     dx,ATR_INDEX\r
1107         mov     al,ATR_PELPAN or 20h\r
1108         out     dx,al\r
1109         jmp     $+2\r
1110         mov     al,[BYTE pel]           ;pel pan value\r
1111         out     dx,al\r
1112 \r
1113 @@done:\r
1114         sti\r
1115 \r
1116         ret\r
1117 \r
1118 ENDP\r
1119 \r
1120 \r
1121 if NUMFONT+NUMFONTM\r
1122 \r
1123 ;===========================================================================\r
1124 ;\r
1125 ; GENERAL FONT DRAWING ROUTINES\r
1126 ;\r
1127 ;===========================================================================\r
1128 \r
1129 DATASEG\r
1130 \r
1131 px      dw      ?                                       ; proportional character drawing coordinates\r
1132 py      dw      ?\r
1133 pdrawmode       db      11000b          ; 8 = OR, 24 = XOR, put in GC_DATAROTATE\r
1134 fontcolor       db      15              ;0-15 mapmask value\r
1135 \r
1136 PUBLIC  px,py,pdrawmode,fontcolor\r
1137 \r
1138 ;\r
1139 ; offsets in font structure\r
1140 ;\r
1141 pcharheight     =       0               ;lines high\r
1142 charloc         =       2               ;pointers to every character\r
1143 charwidth       =       514             ;every character's width in pixels\r
1144 \r
1145 \r
1146 propchar        dw      ?                       ; the character number to shift\r
1147 stringptr       dw      ?,?\r
1148 \r
1149 \r
1150 BUFFWIDTH       =       50\r
1151 BUFFHEIGHT      =   32                  ; must be twice as high as font for masked fonts\r
1152 \r
1153 databuffer      db      BUFFWIDTH*BUFFHEIGHT dup (?)\r
1154 \r
1155 bufferwidth     dw      ?                                               ; bytes with valid info / line\r
1156 bufferheight dw ?                                               ; number of lines currently used\r
1157 \r
1158 bufferbyte      dw      ?\r
1159 bufferbit       dw      ?\r
1160 \r
1161 screenspot      dw      ?                                               ; where the buffer is going\r
1162 \r
1163 bufferextra     dw      ?                                               ; add at end of a line copy\r
1164 screenextra     dw      ?\r
1165 \r
1166 PUBLIC  bufferwidth,bufferheight,screenspot\r
1167 \r
1168 CODESEG\r
1169 \r
1170 ;======================\r
1171 ;\r
1172 ; Macros to table shift a byte of font\r
1173 ;\r
1174 ;======================\r
1175 \r
1176 MACRO   SHIFTNOXOR\r
1177         mov     al,[es:bx]              ; source\r
1178         xor     ah,ah\r
1179         shl     ax,1\r
1180         mov     si,ax\r
1181         mov     ax,[bp+si]              ; table shift into two bytes\r
1182         or      [di],al                 ; or with first byte\r
1183         inc     di\r
1184         mov     [di],ah                 ; replace next byte\r
1185         inc     bx                              ; next source byte\r
1186 ENDM\r
1187 \r
1188 MACRO   SHIFTWITHXOR\r
1189         mov     al,[es:bx]              ; source\r
1190         xor     ah,ah\r
1191         shl     ax,1\r
1192         mov     si,ax\r
1193         mov     ax,[bp+si]              ; table shift into two bytes\r
1194         not     ax\r
1195         and     [di],al                 ; and with first byte\r
1196         inc     di\r
1197         mov     [di],ah                 ; replace next byte\r
1198         inc     bx                              ; next source byte\r
1199 ENDM\r
1200 \r
1201 \r
1202 ;=======================\r
1203 ;\r
1204 ; BufferToScreen\r
1205 ;\r
1206 ; Pass buffer start in SI (somewhere in databuffer)\r
1207 ; Draws the buffer to the EGA screen in the current write mode\r
1208 ;\r
1209 ;========================\r
1210 \r
1211 PROC    BufferToScreen  NEAR\r
1212 \r
1213         mov     es,[screenseg]\r
1214         mov     di,[screenspot]\r
1215 \r
1216         mov     bx,[bufferwidth]                ;calculate offsets for end of each line\r
1217         or      bx,bx\r
1218         jnz     @@isthere\r
1219         ret                                                     ;nothing to draw\r
1220 \r
1221 @@isthere:\r
1222         mov     ax,[linewidth]\r
1223         sub     ax,bx\r
1224         mov     [screenextra],ax\r
1225         mov     ax,BUFFWIDTH\r
1226         sub     ax,bx\r
1227         mov     [bufferextra],ax\r
1228 \r
1229         mov     bx,[bufferheight]               ;lines to copy\r
1230 @@lineloop:\r
1231         mov     cx,[bufferwidth]                ;bytes to copy\r
1232 @@byteloop:\r
1233         lodsb                                           ;get a byte from the buffer\r
1234         xchg    [es:di],al                      ;load latches and store back to screen\r
1235         inc     di\r
1236 \r
1237         loop    @@byteloop\r
1238 \r
1239         add     si,[bufferextra]\r
1240         add     di,[screenextra]\r
1241 \r
1242         dec     bx\r
1243         jnz     @@lineloop\r
1244 \r
1245         ret\r
1246 ENDP\r
1247 \r
1248 \r
1249 ;============================================================================\r
1250 ;\r
1251 ; NON MASKED FONT DRAWING ROUTINES\r
1252 ;\r
1253 ;============================================================================\r
1254 \r
1255 if numfont\r
1256 \r
1257 DATASEG\r
1258 \r
1259 shiftdrawtable  dw      0,shift1wide,shift2wide,shift3wide,shift4wide\r
1260                                 dw              shift5wide\r
1261 \r
1262 CODESEG\r
1263 \r
1264 ;==================\r
1265 ;\r
1266 ; ShiftPropChar\r
1267 ;\r
1268 ; Call with BX = character number (0-255)\r
1269 ; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts\r
1270 ; them to the new position\r
1271 ;\r
1272 ;==================\r
1273 \r
1274 PROC    ShiftPropChar   NEAR\r
1275 \r
1276         mov     si,[fontnumber]\r
1277         shl     si,1\r
1278         mov     es,[grsegs+STARTFONT*2+si]      ;segment of font to use\r
1279 \r
1280 ;\r
1281 ; find character location, width, and height\r
1282 ;\r
1283         mov     si,[es:charwidth+bx]\r
1284         and     si,0ffh                                 ;SI hold width in pixels\r
1285         shl     bx,1\r
1286         mov     bx,[es:charloc+bx]              ;BX holds pointer to character data\r
1287 \r
1288 ;\r
1289 ; look up which shift table to use, based on bufferbit\r
1290 ;\r
1291         mov     di,[bufferbit]\r
1292         shl     di,1\r
1293         mov     bp,[shifttabletable+di] ;BP holds pointer to shift table\r
1294 \r
1295         mov     di,OFFSET databuffer\r
1296         add     di,[bufferbyte]                 ;DI holds pointer to buffer\r
1297 \r
1298 ;\r
1299 ; advance position by character width\r
1300 ;\r
1301         mov     cx,[bufferbit]\r
1302         add     cx,si                                   ;new bit position\r
1303         mov     ax,cx\r
1304         and     ax,7\r
1305         mov     [bufferbit],ax                  ;new bit position\r
1306         mov     ax,cx\r
1307         shr     ax,1\r
1308         shr     ax,1\r
1309         shr     ax,1\r
1310         add     [bufferbyte],ax                 ;new byte position\r
1311 \r
1312         add     si,7\r
1313         shr     si,1\r
1314         shr     si,1\r
1315         shr     si,1                                    ;bytes the character is wide\r
1316         shl     si,1                    ;*2 to look up in shiftdrawtable\r
1317 \r
1318         mov     cx,[es:pcharheight]\r
1319         mov     dx,BUFFWIDTH\r
1320         jmp     [ss:shiftdrawtable+si]  ;procedure to draw this width\r
1321 \r
1322 ;\r
1323 ; one byte character\r
1324 ;\r
1325 shift1wide:\r
1326         dec     dx\r
1327 EVEN\r
1328 @@loop1:\r
1329         SHIFTNOXOR\r
1330         add     di,dx                   ; next line in buffer\r
1331         loop    @@loop1\r
1332         ret\r
1333 \r
1334 ;\r
1335 ; two byte character\r
1336 ;\r
1337 shift2wide:\r
1338         dec     dx\r
1339         dec     dx\r
1340 EVEN\r
1341 @@loop2:\r
1342         SHIFTNOXOR\r
1343         SHIFTNOXOR\r
1344         add     di,dx                   ; next line in buffer\r
1345         loop    @@loop2\r
1346         ret\r
1347 \r
1348 ;\r
1349 ; three byte character\r
1350 ;\r
1351 shift3wide:\r
1352         sub     dx,3\r
1353 EVEN\r
1354 @@loop3:\r
1355         SHIFTNOXOR\r
1356         SHIFTNOXOR\r
1357         SHIFTNOXOR\r
1358         add     di,dx                   ; next line in buffer\r
1359         loop    @@loop3\r
1360         ret\r
1361 \r
1362 ;\r
1363 ; four byte character\r
1364 ;\r
1365 shift4wide:\r
1366         sub     dx,4\r
1367 EVEN\r
1368 @@loop4:\r
1369         SHIFTNOXOR\r
1370         SHIFTNOXOR\r
1371         SHIFTNOXOR\r
1372         SHIFTNOXOR\r
1373         add     di,dx                   ; next line in buffer\r
1374         loop    @@loop4\r
1375         ret\r
1376 \r
1377 ;\r
1378 ; five byte character\r
1379 ;\r
1380 shift5wide:\r
1381         sub     dx,5\r
1382 EVEN\r
1383 @@loop5:\r
1384         SHIFTNOXOR\r
1385         SHIFTNOXOR\r
1386         SHIFTNOXOR\r
1387         SHIFTNOXOR\r
1388         add     di,dx                   ; next line in buffer\r
1389         loop    @@loop5\r
1390         ret\r
1391 \r
1392 \r
1393 \r
1394 ENDP\r
1395 \r
1396 ;============================================================================\r
1397 \r
1398 ;==================\r
1399 ;\r
1400 ; VW_DrawPropString\r
1401 ;\r
1402 ; Draws a C string of characters at px/py and advances px\r
1403 ;\r
1404 ; Assumes write mode 0\r
1405 ;\r
1406 ;==================\r
1407 \r
1408 CODESEG\r
1409 \r
1410 PROC    VW_DrawPropString       string:DWORD\r
1411 PUBLIC  VW_DrawPropString\r
1412 USES    SI,DI\r
1413 \r
1414 ;\r
1415 ; proportional spaceing, which clears the buffer ahead of it, so only\r
1416 ; clear the first collumn\r
1417 ;\r
1418         mov     al,0\r
1419 line    =       0\r
1420 REPT    BUFFHEIGHT\r
1421         mov     [BYTE databuffer+BUFFWIDTH*line],al\r
1422 line    =       line+1\r
1423 ENDM\r
1424 \r
1425 ;\r
1426 ; shift the characters into the buffer\r
1427 ;\r
1428 @@shiftchars:\r
1429         mov     ax,[px]\r
1430         and     ax,7\r
1431         mov     [bufferbit],ax\r
1432         mov     [bufferbyte],0\r
1433 \r
1434         mov     ax,[WORD string]\r
1435         mov     [stringptr],ax\r
1436         mov     ax,[WORD string+2]\r
1437         mov     [stringptr+2],ax\r
1438 \r
1439 @@shiftone:\r
1440         mov     es,[stringptr+2]\r
1441         mov     bx,[stringptr]\r
1442         inc     [stringptr]\r
1443         mov     bx,[es:bx]\r
1444         xor     bh,bh\r
1445         or      bl,bl\r
1446         jz      @@allshifted\r
1447         call    ShiftPropChar\r
1448         jmp     @@shiftone\r
1449 \r
1450 @@allshifted:\r
1451 ;\r
1452 ; calculate position to draw buffer on screen\r
1453 ;\r
1454         mov     bx,[py]\r
1455         shl     bx,1\r
1456         mov     di,[ylookup+bx]\r
1457         add     di,[bufferofs]\r
1458         add     di,[panadjust]\r
1459 \r
1460         mov     ax,[px]\r
1461         shr     ax,1\r
1462         shr     ax,1\r
1463         shr     ax,1            ;x location in bytes\r
1464         add     di,ax\r
1465         mov     [screenspot],di\r
1466 \r
1467 ;\r
1468 ; advance px\r
1469 ;\r
1470         mov     ax,[bufferbyte]\r
1471         shl     ax,1\r
1472         shl     ax,1\r
1473         shl     ax,1\r
1474         or      ax,[bufferbit]\r
1475         add     [px],ax\r
1476 \r
1477 ;\r
1478 ; draw it\r
1479 ;\r
1480 \r
1481 ; set xor/or mode\r
1482         mov     dx,GC_INDEX\r
1483         mov     al,GC_DATAROTATE\r
1484         mov     ah,[pdrawmode]\r
1485         WORDOUT\r
1486 \r
1487 ; set mapmask to color\r
1488         mov     dx,SC_INDEX\r
1489         mov     al,SC_MAPMASK\r
1490         mov     ah,[fontcolor]\r
1491         WORDOUT\r
1492 \r
1493         mov     ax,[bufferbyte]\r
1494         test    [bufferbit],7\r
1495         jz      @@go\r
1496         inc     ax                              ;so the partial byte also gets drawn\r
1497 @@go:\r
1498         mov     [bufferwidth],ax\r
1499         mov     si,[fontnumber]\r
1500         shl     si,1\r
1501         mov     es,[grsegs+STARTFONT*2+si]\r
1502         mov     ax,[es:pcharheight]\r
1503         mov     [bufferheight],ax\r
1504 \r
1505         mov     si,OFFSET databuffer\r
1506         call    BufferToScreen\r
1507 \r
1508 ; set copy mode\r
1509         mov     dx,GC_INDEX\r
1510         mov     ax,GC_DATAROTATE\r
1511         WORDOUT\r
1512 \r
1513 ; set mapmask to all\r
1514         mov     dx,SC_INDEX\r
1515         mov     ax,SC_MAPMASK + 15*256\r
1516         WORDOUT\r
1517 \r
1518 \r
1519         ret\r
1520 \r
1521 ENDP\r
1522 \r
1523 endif   ;numfont\r
1524 \r
1525 ;============================================================================\r
1526 ;\r
1527 ; MASKED FONT DRAWING ROUTINES\r
1528 ;\r
1529 ;============================================================================\r
1530 \r
1531 if      numfontm\r
1532 \r
1533 DATASEG\r
1534 \r
1535 mshiftdrawtable dw      0,mshift1wide,mshift2wide,mshift3wide\r
1536 \r
1537 \r
1538 CODESEG\r
1539 \r
1540 ;==================\r
1541 ;\r
1542 ; ShiftMPropChar\r
1543 ;\r
1544 ; Call with BX = character number (0-255)\r
1545 ; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts\r
1546 ; them to the new position\r
1547 ;\r
1548 ;==================\r
1549 \r
1550 PROC    ShiftMPropChar  NEAR\r
1551 \r
1552         mov     si,[fontnumber]\r
1553         shl     si,1\r
1554         mov     es,[grsegs+STARTFONTM*2+si]     ;segment of font to use\r
1555 \r
1556 ;\r
1557 ; find character location, width, and height\r
1558 ;\r
1559         mov     si,[es:charwidth+bx]\r
1560         and     si,0ffh                                 ;SI hold width in pixels\r
1561         shl     bx,1\r
1562         mov     bx,[es:charloc+bx]              ;BX holds pointer to character data\r
1563 \r
1564 ;\r
1565 ; look up which shift table to use, based on bufferbit\r
1566 ;\r
1567         mov     di,[bufferbit]\r
1568         shl     di,1\r
1569         mov     bp,[shifttabletable+di] ;BP holds pointer to shift table\r
1570 \r
1571         mov     di,OFFSET databuffer\r
1572         add     di,[bufferbyte]                 ;DI holds pointer to buffer\r
1573 \r
1574         mov     cx,[bufferbit]\r
1575         add     cx,si                                   ;new bit position\r
1576         mov     ax,cx\r
1577         and     ax,7\r
1578         mov     [bufferbit],ax                  ;new bit position\r
1579         mov     ax,cx\r
1580         shr     ax,1\r
1581         shr     ax,1\r
1582         shr     ax,1\r
1583         add     [bufferbyte],ax                 ;new byte position\r
1584 \r
1585         add     si,7\r
1586         shr     si,1\r
1587         shr     si,1\r
1588         shr     si,1                                    ;bytes the character is wide\r
1589         shl     si,1                    ;*2 to look up in shiftdrawtable\r
1590 \r
1591         mov     cx,[es:pcharheight]\r
1592         mov     dx,BUFFWIDTH\r
1593         jmp     [ss:mshiftdrawtable+si] ;procedure to draw this width\r
1594 \r
1595 ;\r
1596 ; one byte character\r
1597 ;\r
1598 mshift1wide:\r
1599         dec     dx\r
1600 \r
1601 EVEN\r
1602 @@loop1m:\r
1603         SHIFTWITHXOR\r
1604         add     di,dx                   ; next line in buffer\r
1605 \r
1606         loop    @@loop1m\r
1607 \r
1608         mov     cx,[es:pcharheight]\r
1609 \r
1610 EVEN\r
1611 @@loop1:\r
1612         SHIFTNOXOR\r
1613         add     di,dx                   ; next line in buffer\r
1614         loop    @@loop1\r
1615 \r
1616         ret\r
1617 \r
1618 ;\r
1619 ; two byte character\r
1620 ;\r
1621 mshift2wide:\r
1622         dec     dx\r
1623         dec     dx\r
1624 EVEN\r
1625 @@loop2m:\r
1626         SHIFTWITHXOR\r
1627         SHIFTWITHXOR\r
1628         add     di,dx                   ; next line in buffer\r
1629 \r
1630         loop    @@loop2m\r
1631 \r
1632         mov     cx,[es:pcharheight]\r
1633 \r
1634 EVEN\r
1635 @@loop2:\r
1636         SHIFTNOXOR\r
1637         SHIFTNOXOR\r
1638         add     di,dx                   ; next line in buffer\r
1639         loop    @@loop2\r
1640 \r
1641         ret\r
1642 \r
1643 ;\r
1644 ; three byte character\r
1645 ;\r
1646 mshift3wide:\r
1647         sub     dx,3\r
1648 EVEN\r
1649 @@loop3m:\r
1650         SHIFTWITHXOR\r
1651         SHIFTWITHXOR\r
1652         SHIFTWITHXOR\r
1653         add     di,dx                   ; next line in buffer\r
1654 \r
1655         loop    @@loop3m\r
1656 \r
1657         mov     cx,[es:pcharheight]\r
1658 \r
1659 EVEN\r
1660 @@loop3:\r
1661         SHIFTNOXOR\r
1662         SHIFTNOXOR\r
1663         SHIFTNOXOR\r
1664         add     di,dx                   ; next line in buffer\r
1665         loop    @@loop3\r
1666 \r
1667         ret\r
1668 \r
1669 \r
1670 ENDP\r
1671 \r
1672 ;============================================================================\r
1673 \r
1674 ;==================\r
1675 ;\r
1676 ; VW_DrawMPropString\r
1677 ;\r
1678 ; Draws a C string of characters at px/py and advances px\r
1679 ;\r
1680 ; Assumes write mode 0\r
1681 ;\r
1682 ;==================\r
1683 \r
1684 \r
1685 \r
1686 PROC    VW_DrawMPropString      string:DWORD\r
1687 PUBLIC  VW_DrawMPropString\r
1688 USES    SI,DI\r
1689 \r
1690 ;\r
1691 ; clear out the first byte of the buffer, the rest will automatically be\r
1692 ; cleared as characters are drawn into it\r
1693 ;\r
1694         mov     si,[fontnumber]\r
1695         shl     si,1\r
1696         mov     es,[grsegs+STARTFONTM*2+si]\r
1697         mov     dx,[es:pcharheight]\r
1698         mov     di,OFFSET databuffer\r
1699         mov     ax,ds\r
1700         mov     es,ax\r
1701         mov     bx,BUFFWIDTH-1\r
1702 \r
1703         mov     cx,dx\r
1704         mov     al,0ffh\r
1705 @@maskfill:\r
1706         stosb                           ; fill the mask part with $ff\r
1707         add     di,bx\r
1708         loop    @@maskfill\r
1709 \r
1710         mov     cx,dx\r
1711         xor     al,al\r
1712 @@datafill:\r
1713         stosb                           ; fill the data part with $0\r
1714         add     di,bx\r
1715         loop    @@datafill\r
1716 \r
1717 ;\r
1718 ; shift the characters into the buffer\r
1719 ;\r
1720         mov     ax,[px]\r
1721         and     ax,7\r
1722         mov     [bufferbit],ax\r
1723         mov     [bufferbyte],0\r
1724 \r
1725         mov     ax,[WORD string]\r
1726         mov     [stringptr],ax\r
1727         mov     ax,[WORD string+2]\r
1728         mov     [stringptr+2],ax\r
1729 \r
1730 @@shiftone:\r
1731         mov     es,[stringptr+2]\r
1732         mov     bx,[stringptr]\r
1733         inc     [stringptr]\r
1734         mov     bx,[es:bx]\r
1735         xor     bh,bh\r
1736         or      bl,bl\r
1737         jz      @@allshifted\r
1738         call    ShiftMPropChar\r
1739         jmp     @@shiftone\r
1740 \r
1741 @@allshifted:\r
1742 ;\r
1743 ; calculate position to draw buffer on screen\r
1744 ;\r
1745         mov     bx,[py]\r
1746         shl     bx,1\r
1747         mov     di,[ylookup+bx]\r
1748         add     di,[bufferofs]\r
1749         add     di,[panadjust]\r
1750 \r
1751         mov     ax,[px]\r
1752         shr     ax,1\r
1753         shr     ax,1\r
1754         shr     ax,1            ;x location in bytes\r
1755         add     di,ax\r
1756         mov     [screenspot],di\r
1757 \r
1758 ;\r
1759 ; advance px\r
1760 ;\r
1761         mov     ax,[bufferbyte]\r
1762         shl     ax,1\r
1763         shl     ax,1\r
1764         shl     ax,1\r
1765         or      ax,[bufferbit]\r
1766         add     [px],ax\r
1767 \r
1768 ;\r
1769 ; draw it\r
1770 ;\r
1771         mov     ax,[bufferbyte]\r
1772         test    [bufferbit],7\r
1773         jz      @@go\r
1774         inc     ax                              ;so the partial byte also gets drawn\r
1775 @@go:\r
1776         mov     [bufferwidth],ax\r
1777         mov     es,[grsegs+STARTFONTM*2]\r
1778         mov     ax,[es:pcharheight]\r
1779         mov     [bufferheight],ax\r
1780 \r
1781 ; set AND mode to punch out the mask\r
1782         mov     dx,GC_INDEX\r
1783         mov     ax,GC_DATAROTATE + 8*256\r
1784         WORDOUT\r
1785 \r
1786 ; set mapmask to all\r
1787         mov     dx,SC_INDEX\r
1788         mov     ax,SC_MAPMASK + 15*256\r
1789         WORDOUT\r
1790 \r
1791         mov     si,OFFSET databuffer\r
1792         call    BufferToScreen\r
1793 \r
1794 ; set OR mode to fill in the color\r
1795         mov     dx,GC_INDEX\r
1796         mov     ax,GC_DATAROTATE + 16*256\r
1797         WORDOUT\r
1798 \r
1799 ; set mapmask to color\r
1800         mov     dx,SC_INDEX\r
1801         mov     al,SC_MAPMASK\r
1802         mov     ah,[fontcolor]\r
1803         WORDOUT\r
1804 \r
1805         call    BufferToScreen          ; SI is still in the right position in buffer\r
1806 \r
1807 ; set copy mode\r
1808         mov     dx,GC_INDEX\r
1809         mov     ax,GC_DATAROTATE\r
1810         WORDOUT\r
1811 \r
1812 ; set mapmask to all\r
1813         mov     dx,SC_INDEX\r
1814         mov     ax,SC_MAPMASK + 15*256\r
1815         WORDOUT\r
1816 \r
1817 \r
1818         ret\r
1819 \r
1820 ENDP\r
1821 \r
1822 endif           ; if numfontm\r
1823 \r
1824 endif           ; if fonts\r