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