]> 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 ; VWL_WaitRetrace\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    VWL_WaitRetrace NEAR\r
1028         mov     dx,STATUS_REGISTER_1\r
1029         mov     bx,[WORD TimeCount]\r
1030 @@waitloop:\r
1031         sti\r
1032         jmp     $+2\r
1033         cli\r
1034 \r
1035         in      al,dx\r
1036         test    al,8\r
1037         jnz     @@done\r
1038         mov     ax,[WORD TimeCount]\r
1039         sub     ax,bx\r
1040         cmp     ax,1\r
1041         jbe     @@waitloop\r
1042 \r
1043 @@done:\r
1044         ret\r
1045 ENDP\r
1046 \r
1047 \r
1048 ;==============\r
1049 ;\r
1050 ; VW_SetScreen\r
1051 ;\r
1052 ;==============\r
1053 \r
1054 PROC    VW_SetScreen  crtc:WORD, pel:WORD\r
1055 PUBLIC  VW_SetScreen\r
1056 \r
1057 if waitforvbl\r
1058 \r
1059         mov     dx,STATUS_REGISTER_1\r
1060 \r
1061 ;\r
1062 ; wait util the CRTC just starts scaning a diplayed line to set the CRTC start\r
1063 ;\r
1064         cli\r
1065 \r
1066 @@waitnodisplay:\r
1067         in      al,dx\r
1068         test    al,01b\r
1069         jz      @@waitnodisplay\r
1070 \r
1071 @@waitdisplay:\r
1072         in      al,dx\r
1073         test    al,01b\r
1074         jnz     @@waitdisplay\r
1075 \r
1076 endif\r
1077 \r
1078 ;\r
1079 ; set CRTC start\r
1080 ;\r
1081 ; for some reason, my XT's EGA card doesn't like word outs to the CRTC\r
1082 ; index...\r
1083 ;\r
1084         mov     cx,[crtc]\r
1085         mov     dx,CRTC_INDEX\r
1086         mov     al,0ch          ;start address high register\r
1087         out     dx,al\r
1088         inc     dx\r
1089         mov     al,ch\r
1090         out     dx,al\r
1091         dec     dx\r
1092         mov     al,0dh          ;start address low register\r
1093         out     dx,al\r
1094         mov     al,cl\r
1095         inc     dx\r
1096         out     dx,al\r
1097 \r
1098         test    [jerk],1\r
1099         jz      @@l3\r
1100         call    VWL_WaitRetrace\r
1101 \r
1102 @@l3:\r
1103         test    [nopan],1\r
1104         jnz     @@l4\r
1105 ;\r
1106 ; set horizontal panning\r
1107 ;\r
1108 \r
1109         mov     dx,ATR_INDEX\r
1110         mov     al,ATR_PELPAN or 20h\r
1111         out     dx,al\r
1112         jmp     $+2\r
1113         mov     al,[BYTE pel]           ;pel pan value\r
1114         out     dx,al\r
1115 \r
1116 @@l4:\r
1117         test    [jerk],1\r
1118         jnz     @@done\r
1119         call    VWL_WaitRetrace\r
1120 \r
1121 @@done:\r
1122         sti\r
1123 \r
1124         ret\r
1125 \r
1126 ENDP\r
1127 \r
1128 \r
1129 if NUMFONT+NUMFONTM\r
1130 \r
1131 ;===========================================================================\r
1132 ;\r
1133 ; GENERAL FONT DRAWING ROUTINES\r
1134 ;\r
1135 ;===========================================================================\r
1136 \r
1137 DATASEG\r
1138 \r
1139 px      dw      ?                                       ; proportional character drawing coordinates\r
1140 py      dw      ?\r
1141 pdrawmode       db      11000b          ; 8 = OR, 24 = XOR, put in GC_DATAROTATE\r
1142 fontcolor       db      15              ;0-15 mapmask value\r
1143 \r
1144 PUBLIC  px,py,pdrawmode,fontcolor\r
1145 \r
1146 ;\r
1147 ; offsets in font structure\r
1148 ;\r
1149 pcharheight     =       0               ;lines high\r
1150 charloc         =       2               ;pointers to every character\r
1151 charwidth       =       514             ;every character's width in pixels\r
1152 \r
1153 \r
1154 propchar        dw      ?                       ; the character number to shift\r
1155 stringptr       dw      ?,?\r
1156 \r
1157 \r
1158 BUFFWIDTH       =       50\r
1159 BUFFHEIGHT      =   32                  ; must be twice as high as font for masked fonts\r
1160 \r
1161 databuffer      db      BUFFWIDTH*BUFFHEIGHT dup (?)\r
1162 \r
1163 bufferwidth     dw      ?                                               ; bytes with valid info / line\r
1164 bufferheight dw ?                                               ; number of lines currently used\r
1165 \r
1166 bufferbyte      dw      ?\r
1167 bufferbit       dw      ?\r
1168 \r
1169 screenspot      dw      ?                                               ; where the buffer is going\r
1170 \r
1171 bufferextra     dw      ?                                               ; add at end of a line copy\r
1172 screenextra     dw      ?\r
1173 \r
1174 PUBLIC  bufferwidth,bufferheight,screenspot\r
1175 \r
1176 CODESEG\r
1177 \r
1178 ;======================\r
1179 ;\r
1180 ; Macros to table shift a byte of font\r
1181 ;\r
1182 ;======================\r
1183 \r
1184 MACRO   SHIFTNOXOR\r
1185         mov     al,[es:bx]              ; source\r
1186         xor     ah,ah\r
1187         shl     ax,1\r
1188         mov     si,ax\r
1189         mov     ax,[bp+si]              ; table shift into two bytes\r
1190         or      [di],al                 ; or with first byte\r
1191         inc     di\r
1192         mov     [di],ah                 ; replace next byte\r
1193         inc     bx                              ; next source byte\r
1194 ENDM\r
1195 \r
1196 MACRO   SHIFTWITHXOR\r
1197         mov     al,[es:bx]              ; source\r
1198         xor     ah,ah\r
1199         shl     ax,1\r
1200         mov     si,ax\r
1201         mov     ax,[bp+si]              ; table shift into two bytes\r
1202         not     ax\r
1203         and     [di],al                 ; and with first byte\r
1204         inc     di\r
1205         mov     [di],ah                 ; replace next byte\r
1206         inc     bx                              ; next source byte\r
1207 ENDM\r
1208 \r
1209 \r
1210 ;=======================\r
1211 ;\r
1212 ; BufferToScreen\r
1213 ;\r
1214 ; Pass buffer start in SI (somewhere in databuffer)\r
1215 ; Draws the buffer to the EGA screen in the current write mode\r
1216 ;\r
1217 ;========================\r
1218 \r
1219 PROC    BufferToScreen  NEAR\r
1220 \r
1221         mov     es,[screenseg]\r
1222         mov     di,[screenspot]\r
1223 \r
1224         mov     bx,[bufferwidth]                ;calculate offsets for end of each line\r
1225         or      bx,bx\r
1226         jnz     @@isthere\r
1227         ret                                                     ;nothing to draw\r
1228 \r
1229 @@isthere:\r
1230         mov     ax,[linewidth]\r
1231         sub     ax,bx\r
1232         mov     [screenextra],ax\r
1233         mov     ax,BUFFWIDTH\r
1234         sub     ax,bx\r
1235         mov     [bufferextra],ax\r
1236 \r
1237         mov     bx,[bufferheight]               ;lines to copy\r
1238 @@lineloop:\r
1239         mov     cx,[bufferwidth]                ;bytes to copy\r
1240 @@byteloop:\r
1241         lodsb                                           ;get a byte from the buffer\r
1242         xchg    [es:di],al                      ;load latches and store back to screen\r
1243         inc     di\r
1244 \r
1245         loop    @@byteloop\r
1246 \r
1247         add     si,[bufferextra]\r
1248         add     di,[screenextra]\r
1249 \r
1250         dec     bx\r
1251         jnz     @@lineloop\r
1252 \r
1253         ret\r
1254 ENDP\r
1255 \r
1256 \r
1257 ;============================================================================\r
1258 ;\r
1259 ; NON MASKED FONT DRAWING ROUTINES\r
1260 ;\r
1261 ;============================================================================\r
1262 \r
1263 if numfont\r
1264 \r
1265 DATASEG\r
1266 \r
1267 shiftdrawtable  dw      0,shift1wide,shift2wide,shift3wide,shift4wide\r
1268                                 dw              shift5wide\r
1269 \r
1270 CODESEG\r
1271 \r
1272 ;==================\r
1273 ;\r
1274 ; ShiftPropChar\r
1275 ;\r
1276 ; Call with BX = character number (0-255)\r
1277 ; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts\r
1278 ; them to the new position\r
1279 ;\r
1280 ;==================\r
1281 \r
1282 PROC    ShiftPropChar   NEAR\r
1283 \r
1284         mov     si,[fontnumber]\r
1285         shl     si,1\r
1286         mov     es,[grsegs+STARTFONT*2+si]      ;segment of font to use\r
1287 \r
1288 ;\r
1289 ; find character location, width, and height\r
1290 ;\r
1291         mov     si,[es:charwidth+bx]\r
1292         and     si,0ffh                                 ;SI hold width in pixels\r
1293         shl     bx,1\r
1294         mov     bx,[es:charloc+bx]              ;BX holds pointer to character data\r
1295 \r
1296 ;\r
1297 ; look up which shift table to use, based on bufferbit\r
1298 ;\r
1299         mov     di,[bufferbit]\r
1300         shl     di,1\r
1301         mov     bp,[shifttabletable+di] ;BP holds pointer to shift table\r
1302 \r
1303         mov     di,OFFSET databuffer\r
1304         add     di,[bufferbyte]                 ;DI holds pointer to buffer\r
1305 \r
1306 ;\r
1307 ; advance position by character width\r
1308 ;\r
1309         mov     cx,[bufferbit]\r
1310         add     cx,si                                   ;new bit position\r
1311         mov     ax,cx\r
1312         and     ax,7\r
1313         mov     [bufferbit],ax                  ;new bit position\r
1314         mov     ax,cx\r
1315         shr     ax,1\r
1316         shr     ax,1\r
1317         shr     ax,1\r
1318         add     [bufferbyte],ax                 ;new byte position\r
1319 \r
1320         add     si,7\r
1321         shr     si,1\r
1322         shr     si,1\r
1323         shr     si,1                                    ;bytes the character is wide\r
1324         shl     si,1                    ;*2 to look up in shiftdrawtable\r
1325 \r
1326         mov     cx,[es:pcharheight]\r
1327         mov     dx,BUFFWIDTH\r
1328         jmp     [ss:shiftdrawtable+si]  ;procedure to draw this width\r
1329 \r
1330 ;\r
1331 ; one byte character\r
1332 ;\r
1333 shift1wide:\r
1334         dec     dx\r
1335 EVEN\r
1336 @@loop1:\r
1337         SHIFTNOXOR\r
1338         add     di,dx                   ; next line in buffer\r
1339         loop    @@loop1\r
1340         ret\r
1341 \r
1342 ;\r
1343 ; two byte character\r
1344 ;\r
1345 shift2wide:\r
1346         dec     dx\r
1347         dec     dx\r
1348 EVEN\r
1349 @@loop2:\r
1350         SHIFTNOXOR\r
1351         SHIFTNOXOR\r
1352         add     di,dx                   ; next line in buffer\r
1353         loop    @@loop2\r
1354         ret\r
1355 \r
1356 ;\r
1357 ; three byte character\r
1358 ;\r
1359 shift3wide:\r
1360         sub     dx,3\r
1361 EVEN\r
1362 @@loop3:\r
1363         SHIFTNOXOR\r
1364         SHIFTNOXOR\r
1365         SHIFTNOXOR\r
1366         add     di,dx                   ; next line in buffer\r
1367         loop    @@loop3\r
1368         ret\r
1369 \r
1370 ;\r
1371 ; four byte character\r
1372 ;\r
1373 shift4wide:\r
1374         sub     dx,4\r
1375 EVEN\r
1376 @@loop4:\r
1377         SHIFTNOXOR\r
1378         SHIFTNOXOR\r
1379         SHIFTNOXOR\r
1380         SHIFTNOXOR\r
1381         add     di,dx                   ; next line in buffer\r
1382         loop    @@loop4\r
1383         ret\r
1384 \r
1385 ;\r
1386 ; five byte character\r
1387 ;\r
1388 shift5wide:\r
1389         sub     dx,5\r
1390 EVEN\r
1391 @@loop5:\r
1392         SHIFTNOXOR\r
1393         SHIFTNOXOR\r
1394         SHIFTNOXOR\r
1395         SHIFTNOXOR\r
1396         add     di,dx                   ; next line in buffer\r
1397         loop    @@loop5\r
1398         ret\r
1399 \r
1400 \r
1401 \r
1402 ENDP\r
1403 \r
1404 ;============================================================================\r
1405 \r
1406 ;==================\r
1407 ;\r
1408 ; VW_DrawPropString\r
1409 ;\r
1410 ; Draws a C string of characters at px/py and advances px\r
1411 ;\r
1412 ; Assumes write mode 0\r
1413 ;\r
1414 ;==================\r
1415 \r
1416 CODESEG\r
1417 \r
1418 PROC    VW_DrawPropString       string:DWORD\r
1419 PUBLIC  VW_DrawPropString\r
1420 USES    SI,DI\r
1421 \r
1422 ;\r
1423 ; proportional spaceing, which clears the buffer ahead of it, so only\r
1424 ; clear the first collumn\r
1425 ;\r
1426         mov     al,0\r
1427 line    =       0\r
1428 REPT    BUFFHEIGHT\r
1429         mov     [BYTE databuffer+BUFFWIDTH*line],al\r
1430 line    =       line+1\r
1431 ENDM\r
1432 \r
1433 ;\r
1434 ; shift the characters into the buffer\r
1435 ;\r
1436 @@shiftchars:\r
1437         mov     ax,[px]\r
1438         and     ax,7\r
1439         mov     [bufferbit],ax\r
1440         mov     [bufferbyte],0\r
1441 \r
1442         mov     ax,[WORD string]\r
1443         mov     [stringptr],ax\r
1444         mov     ax,[WORD string+2]\r
1445         mov     [stringptr+2],ax\r
1446 \r
1447 @@shiftone:\r
1448         mov     es,[stringptr+2]\r
1449         mov     bx,[stringptr]\r
1450         inc     [stringptr]\r
1451         mov     bx,[es:bx]\r
1452         xor     bh,bh\r
1453         or      bl,bl\r
1454         jz      @@allshifted\r
1455         call    ShiftPropChar\r
1456         jmp     @@shiftone\r
1457 \r
1458 @@allshifted:\r
1459 ;\r
1460 ; calculate position to draw buffer on screen\r
1461 ;\r
1462         mov     bx,[py]\r
1463         shl     bx,1\r
1464         mov     di,[ylookup+bx]\r
1465         add     di,[bufferofs]\r
1466         add     di,[panadjust]\r
1467 \r
1468         mov     ax,[px]\r
1469         shr     ax,1\r
1470         shr     ax,1\r
1471         shr     ax,1            ;x location in bytes\r
1472         add     di,ax\r
1473         mov     [screenspot],di\r
1474 \r
1475 ;\r
1476 ; advance px\r
1477 ;\r
1478         mov     ax,[bufferbyte]\r
1479         shl     ax,1\r
1480         shl     ax,1\r
1481         shl     ax,1\r
1482         or      ax,[bufferbit]\r
1483         add     [px],ax\r
1484 \r
1485 ;\r
1486 ; draw it\r
1487 ;\r
1488 \r
1489 ; set xor/or mode\r
1490         mov     dx,GC_INDEX\r
1491         mov     al,GC_DATAROTATE\r
1492         mov     ah,[pdrawmode]\r
1493         WORDOUT\r
1494 \r
1495 ; set mapmask to color\r
1496         mov     dx,SC_INDEX\r
1497         mov     al,SC_MAPMASK\r
1498         mov     ah,[fontcolor]\r
1499         WORDOUT\r
1500 \r
1501         mov     ax,[bufferbyte]\r
1502         test    [bufferbit],7\r
1503         jz      @@go\r
1504         inc     ax                              ;so the partial byte also gets drawn\r
1505 @@go:\r
1506         mov     [bufferwidth],ax\r
1507         mov     si,[fontnumber]\r
1508         shl     si,1\r
1509         mov     es,[grsegs+STARTFONT*2+si]\r
1510         mov     ax,[es:pcharheight]\r
1511         mov     [bufferheight],ax\r
1512 \r
1513         mov     si,OFFSET databuffer\r
1514         call    BufferToScreen\r
1515 \r
1516 ; set copy mode\r
1517         mov     dx,GC_INDEX\r
1518         mov     ax,GC_DATAROTATE\r
1519         WORDOUT\r
1520 \r
1521 ; set mapmask to all\r
1522         mov     dx,SC_INDEX\r
1523         mov     ax,SC_MAPMASK + 15*256\r
1524         WORDOUT\r
1525 \r
1526 \r
1527         ret\r
1528 \r
1529 ENDP\r
1530 \r
1531 endif   ;numfont\r
1532 \r
1533 ;============================================================================\r
1534 ;\r
1535 ; MASKED FONT DRAWING ROUTINES\r
1536 ;\r
1537 ;============================================================================\r
1538 \r
1539 if      numfontm\r
1540 \r
1541 DATASEG\r
1542 \r
1543 mshiftdrawtable dw      0,mshift1wide,mshift2wide,mshift3wide\r
1544 \r
1545 \r
1546 CODESEG\r
1547 \r
1548 ;==================\r
1549 ;\r
1550 ; ShiftMPropChar\r
1551 ;\r
1552 ; Call with BX = character number (0-255)\r
1553 ; Draws one character to the buffer at bufferbyte/bufferbit, and adjusts\r
1554 ; them to the new position\r
1555 ;\r
1556 ;==================\r
1557 \r
1558 PROC    ShiftMPropChar  NEAR\r
1559 \r
1560         mov     si,[fontnumber]\r
1561         shl     si,1\r
1562         mov     es,[grsegs+STARTFONTM*2+si]     ;segment of font to use\r
1563 \r
1564 ;\r
1565 ; find character location, width, and height\r
1566 ;\r
1567         mov     si,[es:charwidth+bx]\r
1568         and     si,0ffh                                 ;SI hold width in pixels\r
1569         shl     bx,1\r
1570         mov     bx,[es:charloc+bx]              ;BX holds pointer to character data\r
1571 \r
1572 ;\r
1573 ; look up which shift table to use, based on bufferbit\r
1574 ;\r
1575         mov     di,[bufferbit]\r
1576         shl     di,1\r
1577         mov     bp,[shifttabletable+di] ;BP holds pointer to shift table\r
1578 \r
1579         mov     di,OFFSET databuffer\r
1580         add     di,[bufferbyte]                 ;DI holds pointer to buffer\r
1581 \r
1582         mov     cx,[bufferbit]\r
1583         add     cx,si                                   ;new bit position\r
1584         mov     ax,cx\r
1585         and     ax,7\r
1586         mov     [bufferbit],ax                  ;new bit position\r
1587         mov     ax,cx\r
1588         shr     ax,1\r
1589         shr     ax,1\r
1590         shr     ax,1\r
1591         add     [bufferbyte],ax                 ;new byte position\r
1592 \r
1593         add     si,7\r
1594         shr     si,1\r
1595         shr     si,1\r
1596         shr     si,1                                    ;bytes the character is wide\r
1597         shl     si,1                    ;*2 to look up in shiftdrawtable\r
1598 \r
1599         mov     cx,[es:pcharheight]\r
1600         mov     dx,BUFFWIDTH\r
1601         jmp     [ss:mshiftdrawtable+si] ;procedure to draw this width\r
1602 \r
1603 ;\r
1604 ; one byte character\r
1605 ;\r
1606 mshift1wide:\r
1607         dec     dx\r
1608 \r
1609 EVEN\r
1610 @@loop1m:\r
1611         SHIFTWITHXOR\r
1612         add     di,dx                   ; next line in buffer\r
1613 \r
1614         loop    @@loop1m\r
1615 \r
1616         mov     cx,[es:pcharheight]\r
1617 \r
1618 EVEN\r
1619 @@loop1:\r
1620         SHIFTNOXOR\r
1621         add     di,dx                   ; next line in buffer\r
1622         loop    @@loop1\r
1623 \r
1624         ret\r
1625 \r
1626 ;\r
1627 ; two byte character\r
1628 ;\r
1629 mshift2wide:\r
1630         dec     dx\r
1631         dec     dx\r
1632 EVEN\r
1633 @@loop2m:\r
1634         SHIFTWITHXOR\r
1635         SHIFTWITHXOR\r
1636         add     di,dx                   ; next line in buffer\r
1637 \r
1638         loop    @@loop2m\r
1639 \r
1640         mov     cx,[es:pcharheight]\r
1641 \r
1642 EVEN\r
1643 @@loop2:\r
1644         SHIFTNOXOR\r
1645         SHIFTNOXOR\r
1646         add     di,dx                   ; next line in buffer\r
1647         loop    @@loop2\r
1648 \r
1649         ret\r
1650 \r
1651 ;\r
1652 ; three byte character\r
1653 ;\r
1654 mshift3wide:\r
1655         sub     dx,3\r
1656 EVEN\r
1657 @@loop3m:\r
1658         SHIFTWITHXOR\r
1659         SHIFTWITHXOR\r
1660         SHIFTWITHXOR\r
1661         add     di,dx                   ; next line in buffer\r
1662 \r
1663         loop    @@loop3m\r
1664 \r
1665         mov     cx,[es:pcharheight]\r
1666 \r
1667 EVEN\r
1668 @@loop3:\r
1669         SHIFTNOXOR\r
1670         SHIFTNOXOR\r
1671         SHIFTNOXOR\r
1672         add     di,dx                   ; next line in buffer\r
1673         loop    @@loop3\r
1674 \r
1675         ret\r
1676 \r
1677 \r
1678 ENDP\r
1679 \r
1680 ;============================================================================\r
1681 \r
1682 ;==================\r
1683 ;\r
1684 ; VW_DrawMPropString\r
1685 ;\r
1686 ; Draws a C string of characters at px/py and advances px\r
1687 ;\r
1688 ; Assumes write mode 0\r
1689 ;\r
1690 ;==================\r
1691 \r
1692 \r
1693 \r
1694 PROC    VW_DrawMPropString      string:DWORD\r
1695 PUBLIC  VW_DrawMPropString\r
1696 USES    SI,DI\r
1697 \r
1698 ;\r
1699 ; clear out the first byte of the buffer, the rest will automatically be\r
1700 ; cleared as characters are drawn into it\r
1701 ;\r
1702         mov     si,[fontnumber]\r
1703         shl     si,1\r
1704         mov     es,[grsegs+STARTFONTM*2+si]\r
1705         mov     dx,[es:pcharheight]\r
1706         mov     di,OFFSET databuffer\r
1707         mov     ax,ds\r
1708         mov     es,ax\r
1709         mov     bx,BUFFWIDTH-1\r
1710 \r
1711         mov     cx,dx\r
1712         mov     al,0ffh\r
1713 @@maskfill:\r
1714         stosb                           ; fill the mask part with $ff\r
1715         add     di,bx\r
1716         loop    @@maskfill\r
1717 \r
1718         mov     cx,dx\r
1719         xor     al,al\r
1720 @@datafill:\r
1721         stosb                           ; fill the data part with $0\r
1722         add     di,bx\r
1723         loop    @@datafill\r
1724 \r
1725 ;\r
1726 ; shift the characters into the buffer\r
1727 ;\r
1728         mov     ax,[px]\r
1729         and     ax,7\r
1730         mov     [bufferbit],ax\r
1731         mov     [bufferbyte],0\r
1732 \r
1733         mov     ax,[WORD string]\r
1734         mov     [stringptr],ax\r
1735         mov     ax,[WORD string+2]\r
1736         mov     [stringptr+2],ax\r
1737 \r
1738 @@shiftone:\r
1739         mov     es,[stringptr+2]\r
1740         mov     bx,[stringptr]\r
1741         inc     [stringptr]\r
1742         mov     bx,[es:bx]\r
1743         xor     bh,bh\r
1744         or      bl,bl\r
1745         jz      @@allshifted\r
1746         call    ShiftMPropChar\r
1747         jmp     @@shiftone\r
1748 \r
1749 @@allshifted:\r
1750 ;\r
1751 ; calculate position to draw buffer on screen\r
1752 ;\r
1753         mov     bx,[py]\r
1754         shl     bx,1\r
1755         mov     di,[ylookup+bx]\r
1756         add     di,[bufferofs]\r
1757         add     di,[panadjust]\r
1758 \r
1759         mov     ax,[px]\r
1760         shr     ax,1\r
1761         shr     ax,1\r
1762         shr     ax,1            ;x location in bytes\r
1763         add     di,ax\r
1764         mov     [screenspot],di\r
1765 \r
1766 ;\r
1767 ; advance px\r
1768 ;\r
1769         mov     ax,[bufferbyte]\r
1770         shl     ax,1\r
1771         shl     ax,1\r
1772         shl     ax,1\r
1773         or      ax,[bufferbit]\r
1774         add     [px],ax\r
1775 \r
1776 ;\r
1777 ; draw it\r
1778 ;\r
1779         mov     ax,[bufferbyte]\r
1780         test    [bufferbit],7\r
1781         jz      @@go\r
1782         inc     ax                              ;so the partial byte also gets drawn\r
1783 @@go:\r
1784         mov     [bufferwidth],ax\r
1785         mov     es,[grsegs+STARTFONTM*2]\r
1786         mov     ax,[es:pcharheight]\r
1787         mov     [bufferheight],ax\r
1788 \r
1789 ; set AND mode to punch out the mask\r
1790         mov     dx,GC_INDEX\r
1791         mov     ax,GC_DATAROTATE + 8*256\r
1792         WORDOUT\r
1793 \r
1794 ; set mapmask to all\r
1795         mov     dx,SC_INDEX\r
1796         mov     ax,SC_MAPMASK + 15*256\r
1797         WORDOUT\r
1798 \r
1799         mov     si,OFFSET databuffer\r
1800         call    BufferToScreen\r
1801 \r
1802 ; set OR mode to fill in the color\r
1803         mov     dx,GC_INDEX\r
1804         mov     ax,GC_DATAROTATE + 16*256\r
1805         WORDOUT\r
1806 \r
1807 ; set mapmask to color\r
1808         mov     dx,SC_INDEX\r
1809         mov     al,SC_MAPMASK\r
1810         mov     ah,[fontcolor]\r
1811         WORDOUT\r
1812 \r
1813         call    BufferToScreen          ; SI is still in the right position in buffer\r
1814 \r
1815 ; set copy mode\r
1816         mov     dx,GC_INDEX\r
1817         mov     ax,GC_DATAROTATE\r
1818         WORDOUT\r
1819 \r
1820 ; set mapmask to all\r
1821         mov     dx,SC_INDEX\r
1822         mov     ax,SC_MAPMASK + 15*256\r
1823         WORDOUT\r
1824 \r
1825 \r
1826         ret\r
1827 \r
1828 ENDP\r
1829 \r
1830 endif           ; if numfontm\r
1831 \r
1832 endif           ; if fonts\r