|
|
1.1 root 1: ;---------------------------Module-Header------------------------------;
2: ; Module Name: glyphblt.asm
3: ;
4: ; Output a glyph onto VGA screen
5: ;
6: ; Copyright (c) 1992 Microsoft Corporation
7: ;-----------------------------------------------------------------------;
8:
9: .386
10:
11: ifndef DOS_PLATFORM
12: .model small,c
13: else
14: ifdef STD_CALL
15: .model small,c
16: else
17: .model small,pascal
18: endif; STD_CALL
19: endif; DOS_PLATFORM
20:
21: assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
22: assume fs:nothing,gs:nothing
23:
24: .xlist
25: include stdcall.inc ;calling convention cmacros
26: include i386\egavga.inc
27: include i386\strucs.inc
28: .list
29:
30: include i386\strblt.inc
31:
32: .code
33:
34: ;---------------------------Public-Routine------------------------------;
35: ; vGlyphBlt
36: ;
37: ; Draw a glyph to the VGA screen
38: ;
39: ;-----------------------------------------------------------------------;
40:
41: _TEXT$01 SEGMENT DWORD USE32 PUBLIC 'CODE'
42: ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
43:
44: ProcName xxxvGlyphBlt,vGlyphBlt,32
45:
46: xxxvGlyphBlt proc uses esi edi ebx, \
47: pdsurf: ptr DEVSURF, \
48: prcl: ptr RECTL, \
49: cStr: DWORD, \
50: pgp: ptr GLYPHPOS, \
51: iForeClr: dword, \
52: iBackClr: dword, \
53: ulMode: dword, \
54: flOption: dword
55:
56: local pjScreen :ptr ; screen pointer
57: local pjGlyph :ptr ; pointer to glyph bits
58: local cScan :dword ; visible glyph height
59: local cPels :dword ; visible glyph width
60: local cjBytes :dword ; glyph scan size
61: local cTmp :dword ; temporary scan count
62: local cInnerBytes :dword
63: local ulNextScan :dword ;offset from one screen scan to next
64: local cfBits :byte
65: local cfLeft :byte
66: local fjMask :byte
67: local fjLastMask :byte
68: local cfLastBits :byte
69:
70: ; Initialize stuff
71:
72: cld
73: mov edi,pdsurf
74: mov esi,prcl
75:
76: ; Set the offset from one scan to the next
77:
78: mov eax,[edi].dsurf_lNextScan
79: mov ulNextScan,eax
80:
81: ; Calculate number of scans for bltting cell
82:
83: gblt_calc_dest_addr:
84: mov eax,[esi].yTop
85: mov edx,[esi].yBottom
86: sub edx,eax
87: mov cScan,edx ; Number of scans
88:
89: ; Can we assume positive value?
90:
91: mov edx,ulNextScan
92: mul edx ; EAX = byte offset to scan
93:
94: ; Calculate cell width in pels
95:
96: mov ebx,[esi].xRight
97: mov ecx,[esi].xLeft
98: sub ebx,ecx
99: mov cPels,ebx ; Width in pels
100:
101: ; Calculate pointer to the 1st screen byte to blt
102:
103: mov edx,ecx
104: shr edx,3
105: add eax,edx
106: add eax,[edi].dsurf_pvBitmapStart
107: mov pjScreen,eax ; Base address of blit
108:
109: ; Calculate the destination left edge mask
110:
111: gblt_left_mask:
112: xor eax,eax
113: cdq
114: mov cInnerBytes,eax ; Assume glyph fits one byte
115: mov fjLastMask,al
116: and cl,7
117: mov dl,8
118: sub dl,cl ; DL = bits in mask
119:
120: dec al
121: shr al,cl ; AL = left mask
122:
123: ; Assume cell is at least one byte wide
124:
125: mov fjMask,al ; then we have this left mask
126: mov cfBits,dl ; along with 1 bits count
127: sub ebx,edx ; EBX = cPels, EDX = bits in left mask
128: jg short gblt_inner_count ; but if the assume is true?
129: je short gblt_glyph_info
130:
131: ; It is less than one byte wide, calculate the right edge mask
132:
133: mov cl,bl
134: neg cl
135: inc ah ; AH = 1
136: shl ah,cl
137: neg ah ; AH = right mask
138: and al,ah ; AL = composite mask
139: mov fjMask,al
140: jmp short gblt_glyph_info ; no middle or last bytes
141:
142: ; Calculate the inner count
143:
144: gblt_inner_count:
145: mov ecx,ebx ; EBX = # bits left in cell
146: shr ebx,3
147: mov cInnerBytes,ebx ; inner byte count
148:
149: ; Calculate the last byte mask
150:
151: gblt_last_mask:
152: and cl,7 ; CL = # of trailing bits
153: mov cfLastBits,cl
154: dec ah ; AH = 0FFh
155: shr ah,cl
156: not ah
157: mov fjLastMask,ah
158:
159: ; Now get the glyph information
160:
161: gblt_glyph_info:
162: mov edi,pgp
163: mov ebx,[edi].gp_pgdf
164: mov ebx,[ebx].gdf_pgb ; ptr to glyph bits
165:
166: ; Calculate the glyph scan size
167:
168: gblt_glyph_scan:
169: mov eax,[ebx].gb_cx ; Glyph width in pels
170: add eax,7
171: ; and al,0e0h ; DWORD aligned
172: shr eax,3
173: mov cjBytes,eax ; Count to move to next line of glyph
174:
175: ; Assume the glyph is not clipped
176:
177: lea edx,[ebx].gb_aj
178: mov pjGlyph,edx ; Start of glyph
179: mov dl,8
180: mov cfLeft,dl ; Bits left in glyph byte
181: test flOption,VGB_VERT_CLIPPED_GLYPH or VGB_HORIZ_CLIPPED_GLYPH
182: jz short gblt_draw_glyph
183:
184: ; Calculate byte offset of the 1st scan in glyph
185:
186: gblt_glyph_offset:
187: mov edx,[esi].yTop
188: sub edx,[edi].gp_y ; Vertical offset into glyph
189: mul edx ; Can we assume positive value?
190:
191: ; Calculate offset to the 1st byte in Glyph
192:
193: mov edx,[esi].xLeft
194: sub edx,[edi].gp_x ; Horizontal offset into glyph
195: mov ecx,edx
196: shr edx,3
197: add eax,edx ; Offset into glyph
198: add pjGlyph,eax ; Start of glyph
199:
200: ; Calculate glyph's left mask
201:
202: gblt_glyph_left_mask:
203: and cl,7
204: sub cfLeft,cl ; Bits left in glyph byte
205:
206: ; Setup the drawing parameters
207:
208: gblt_draw_glyph:
209: mov eax,ulMode ; determine the write mode
210: call offset FLAT:vgblt_table.[eax*4]
211:
212: ; Everything is done, go home
213:
214: glyph_blt_exit:
215:
216: cRet vGlyphBlt
217:
218: vgblt_table equ this dword
219: dd offset FLAT:vgblt_mix_glyph
220: dd offset FLAT:vgblt_opaque_glyph
221:
222: .errnz VGB_MIX_STRING
223: .errnz VGB_OPAQUE_STRING-1
224:
225: ;---------------------------Public-Routine------------------------------;
226: ; vgblt_mix_glyph
227: ;
228: ; Draw a glyph to the VGA screen using the write mode 0
229: ;
230: ;-----------------------------------------------------------------------;
231:
232: vgblt_mix_glyph::
233:
234: mov dx,VGA_BASE + GRAF_ADDR ; Leave this in a register
235: mov eax,cScan
236: mov cTmp,eax ; Scans to draw
237: mov esi,pjGlyph ; Read glyph from here
238: mov edi,pjScreen ; Write glyph to there
239: mov bh,fjMask ; Current mask
240: mov cl,cfLeft ; Bits available in current byte
241:
242: sub cl,cfBits
243: jl short vmg_fetch_two_bytes
244:
245: ;
246: ; Fetching one byte means we are at the left edge of the glyph, or
247: ; by some miracle we are aligned with the VGA memory. Either way
248: ; we will still mask the data with fjMask.
249: ;
250:
251: vmg_fetch_one_byte:
252: mov al,GRAF_BIT_MASK ; leave it in AL
253:
254: vmg_fetch_one_byte_next:
255: mov ah,[esi] ; AH = glyph data
256:
257: shr ah,cl ; Put usable glyph data in place
258:
259: and ah,bh ; AH = masked glyph data
260: jz short @F ; Don't waste time
261:
262: out dx,ax
263: xchg ah,[edi] ; Set the bits
264:
265: @@:
266: add edi,ulNextScan ; Next scan on VGA
267: add esi,cjBytes ; Next line of glyph
268: dec cTmp
269: jnz short vmg_fetch_one_byte_next ; finish column
270:
271: neg cl
272: and cl,7 ; CL = # usable bits in next byte
273: jnz short vmg_advance_screen_ptr
274: jmp short vmg_advance_glyph_ptr
275:
276: ; The current screen byte covers two glyph bytes
277:
278: vmg_fetch_two_bytes:
279: mov bl,GRAF_BIT_MASK ; Set bitmask for altered bits
280: neg cl ; CL = # bits required from next byte
281: add cl,8 ; we will have to swap AH and AL
282:
283: vmg_fetch_two_bytes_next:
284: mov ax,[esi] ; AL = current byte, AH = next byte
285: rol ax,cl ; AH = glyph data
286:
287: and ah,bh ; AH = masked glyph data
288: jz short @F ; Don't waste time
289:
290: mov al,bl
291: out dx,ax
292: xchg al,[edi] ; Set the bits
293:
294: @@:
295: add edi,ulNextScan ; Next scan on VGA
296: add esi,cjBytes ; Next line of glyph
297: dec cTmp
298: jnz short vmg_fetch_two_bytes_next ; finish column
299: sub cl,8 ; CL = # bits required from next byte
300:
301: ; We will start the next screen column byte. Recalculate parameters.
302:
303: vmg_advance_glyph_ptr:
304: inc pjGlyph ; increment glyph pointer
305:
306: vmg_advance_screen_ptr:
307: inc pjScreen ; Increment screen pointer
308:
309: vmg_inner_bytes:
310: mov ebx,cInnerBytes ; do we have inner bytes?
311: or ebx,ebx
312: jz short vmg_last_byte
313:
314: mov eax,cScan
315: mov cTmp,eax ; Scans to draw
316: mov esi,pjGlyph ; Read glyph from here
317: mov edi,pjScreen ; Write glyph to there
318: add pjGlyph,ebx ; advance pointer
319: add pjScreen,ebx
320: sub cjBytes,ebx ; glyph scan incremental
321: or cl,cl
322: jnz short vmg_inner_fetch_two_bytes
323:
324: mov al,GRAF_BIT_MASK ; leave it in AL
325:
326: vmg_inner_fetch_one_byte:
327: mov ah,[esi] ; AH = glyph data
328: or ah,ah
329: jz short @F ; Don't waste time
330:
331: out dx,ax
332: xchg ah,[edi] ; Set the bits
333:
334: @@:
335: inc esi
336: inc edi
337: dec ebx
338: jnz short vmg_inner_fetch_one_byte
339:
340: mov ebx,cInnerBytes
341: add edi,ulNextScan ; Next scan on VGA
342: add esi,cjBytes ; Next line of glyph
343: sub edi,ebx ; adjust for previous increment
344: dec cTmp
345: jnz short vmg_inner_fetch_one_byte ; finish column
346:
347: jmp short vmg_inner_byte_end
348:
349: ; The current screen byte covers two glyph bytes
350:
351: vmg_inner_fetch_two_bytes:
352: add cl,8 ; we will have to swap AH and AL
353:
354: vmg_inner_fetch_two_bytes_next:
355: mov ax,[esi] ; AL = curr byte, AH = next byte
356: rol ax,cl ; AH = glyph data
357: jz short @F ; Don't waste time
358:
359: mov al,GRAF_BIT_MASK
360: out dx,ax
361: xchg al,[edi] ; Set the bits
362: @@:
363: inc esi
364: inc edi
365: dec ebx
366: jnz short vmg_inner_fetch_two_bytes_next
367:
368: mov ebx,cInnerBytes
369: add edi,ulNextScan ; Next scan on VGA
370: add esi,cjBytes ; Next line of glyph
371: sub edi,ebx ; adjust for previous increment
372: dec cTmp
373: jnz short vmg_inner_fetch_two_bytes_next ; finish column
374: sub cl,8
375:
376: vmg_inner_byte_end:
377: add cjBytes,ebx ; restore its actual value
378:
379: vmg_last_byte:
380: mov bl,fjLastMask ; BL = last byte mask
381: or bl,bl
382: jz short vmg_exit
383:
384: mov esi,pjGlyph ; Read glyph from here
385: mov edi,pjScreen ; Write glyph to there
386: mov ch,8
387: sub ch,cl ; CH = # usable bits in current byte
388: cmp ch,cfLastBits ; do we need the next byte?
389: jl short vmg_last_fetch_two_bytes
390:
391: mov al,GRAF_BIT_MASK
392:
393: vmg_last_fetch_one_byte:
394: mov ah,[esi] ; AH = glyph data
395: shl ah,cl
396: and ah,bl
397: jz short @F ; Don't waste time
398:
399: out dx,ax
400: xchg ah,[edi] ; Set the bits
401:
402: @@:
403: add edi,ulNextScan ; Next scan on VGA
404: add esi,cjBytes ; Next line of glyph
405: dec cScan
406: jnz short vmg_last_fetch_one_byte ; finish column
407:
408: jmp short vmg_exit
409:
410: ; The current screen byte covers two glyph bytes
411:
412: vmg_last_fetch_two_bytes:
413: add cl,8 ; we will swap AH and AL
414: mov bh,GRAF_BIT_MASK
415:
416: vmg_last_fetch_two_bytes_next:
417: mov ax,[esi]
418: rol ax,cl ; AH = glyph data
419: and ah,bl
420: jz short @F ; Don't waste time
421:
422: mov al,bh
423: out dx,ax
424: xchg al,[edi] ; Set the bits
425:
426: @@:
427: add edi,ulNextScan ; Next scan on VGA
428: add esi,cjBytes ; Next line of glyph
429: dec cScan
430: jnz short vmg_last_fetch_two_bytes_next ; finish column
431:
432: vmg_exit:
433: retn
434:
435: ;---------------------------Public-Routine------------------------------;
436: ; vgblt_opaque_glyph
437: ;
438: ; Draw a glyph to the VGA screen using the write mode 3
439: ;
440: ;-----------------------------------------------------------------------;
441:
442: vgblt_opaque_glyph:
443:
444: mov eax,cScan
445: mov cTmp,eax ; Scans to draw
446: mov esi,pjGlyph ; Read glyph from here
447: mov edi,pjScreen ; Write glyph to there
448: mov bh,fjMask ; Current mask
449: mov edx,ulNextScan
450:
451: mov cl,cfLeft ; Bits available in current byte
452: sub cl,cfBits
453: jl short vog_fetch_two_bytes
454:
455: ;
456: ; Fetching one byte means we are at the left edge of the glyph, or
457: ; by some miracle we are aligned with the VGA memory. Either way
458: ; we will still mask the data with fjMask.
459: ;
460:
461: vog_fetch_one_byte:
462: mov ah,[esi] ; AH = glyph data
463: shr ah,cl ; Put usable glyph data in place
464: and ah,bh
465: jz short @F ; don't waste time
466: xchg ah,[edi] ; Set the bits
467: @@:
468: add edi,edx ; Next scan on VGA
469: add esi,cjBytes ; Next line of glyph
470: dec cTmp
471: jnz short vog_fetch_one_byte ; finish column
472:
473: neg cl
474: and cl,7 ; CL = # usable bits in next byte
475: jnz short vog_advance_screen_ptr
476: jmp short vog_advance_glyph_ptr
477:
478: ; The current screen byte covers two glyph bytes
479:
480: vog_fetch_two_bytes:
481: neg cl ; CL = cfBits - cfLeft
482: add cl,8 ; we will swap AH and AL
483:
484: vog_fetch_two_bytes_next:
485: mov ax,[esi] ; AL = curr byte, AH = next byte
486: rol ax,cl ; AH = glyph data
487: and ah,bh
488: jz short @F ; don't waste time
489: xchg ah,[edi] ; Set the bits
490: @@:
491: add edi,edx ; Next scan on VGA
492: add esi,cjBytes ; Next line of glyph
493: dec cTmp
494: jnz short vog_fetch_two_bytes_next ; finish column
495: sub cl,8
496:
497: ; We will start the next screen column byte. Recalculate parameters.
498:
499: vog_advance_glyph_ptr:
500: inc pjGlyph
501:
502: vog_advance_screen_ptr:
503: inc pjScreen ; Increment screen pointer
504:
505: vog_inner_bytes:
506: mov ebx,cInnerBytes ; do we have inner bytes?
507: or ebx,ebx
508: jz short vog_last_byte
509:
510: mov eax,cScan
511: mov cTmp,eax ; Scans to draw
512: mov esi,pjGlyph ; Read glyph from here
513: mov edi,pjScreen ; Write glyph to there
514: add pjGlyph,ebx ; advance pointer
515: add pjScreen,ebx
516: sub cjBytes,ebx ; glyph scan size
517: sub edx,ebx ; screen scan size
518: or cl,cl
519: jnz short vog_inner_fetch_two_bytes
520:
521: vog_inner_fetch_one_byte:
522: mov ecx,ebx
523:
524: vog_inner_loop:
525: lodsb
526: or al,al
527: jz short @F
528: xchg al,[edi]
529: @@:
530: inc edi
531: loop short vog_inner_loop
532:
533: add edi,edx ; Next scan on VGA
534: add esi,cjBytes ; Next line of glyph
535: dec cTmp
536: jnz short vog_inner_fetch_one_byte ; finish column
537:
538: jmp short vog_inner_byte_end
539:
540: ; The current screen byte covers two glyph bytes
541:
542: vog_inner_fetch_two_bytes:
543: add cl,8
544:
545: vog_inner_fetch_two_bytes_next:
546: mov ax,[esi] ; AL = curr byte, AH = next byte
547: rol ax,cl ; AH = glyph data
548: or ah,ah
549: jz short @F
550: xchg ah,[edi] ; Set the bits
551: @@:
552: inc esi
553: inc edi
554: dec ebx
555: jnz short vog_inner_fetch_two_bytes_next
556:
557: mov ebx,cInnerBytes
558: add edi,edx ; Next scan on VGA
559: add esi,cjBytes ; Next line of glyph
560: dec cTmp
561: jnz short vog_inner_fetch_two_bytes_next ; finish column
562: sub cl,8
563:
564: vog_inner_byte_end:
565: add edx,ebx ; restore its original value
566: add cjBytes,ebx ; restore its original value
567:
568: vog_last_byte:
569: mov bl,fjLastMask ; BL = last byte mask
570: or bl,bl
571: jz short vog_exit
572:
573: mov esi,pjGlyph ; Read glyph from here
574: mov edi,pjScreen ; Write glyph to there
575: mov ch,8
576: sub ch,cl ; CH = # usable bits in current byte
577: cmp ch,cfLastBits ; do we need the next byte?
578: jl short vog_last_fetch_two_bytes
579:
580:
581: vog_last_fetch_one_byte:
582: mov ah,[esi] ; AH = glyph data
583: shl ah,cl
584: and ah,bl
585: jz short @F
586: xchg ah,[edi] ; Set the bits
587: @@:
588: add edi,edx ; Next scan on VGA
589: add esi,cjBytes ; Next line of glyph
590: dec cScan
591: jnz short vog_last_fetch_one_byte ; finish column
592:
593: jmp short vog_exit
594:
595: ; The current screen byte covers two glyph bytes
596:
597: vog_last_fetch_two_bytes:
598: add cl,8 ; we will swap AH and AL
599:
600: vog_last_fetch_two_bytes_next:
601: mov ax,[esi]
602: rol ax,cl ; AH = glyph data
603: and ah,bl
604: jz short @F
605: xchg ah,[edi] ; Set the bits
606: @@:
607: add edi,edx ; Next scan on VGA
608: add esi,cjBytes ; Next line of glyph
609: dec cScan
610: jnz short vog_last_fetch_two_bytes_next ; finish column
611:
612: vog_exit:
613: retn
614:
615: xxxvGlyphBlt endp
616:
617:
618: ;---------------------------Public-Routine------------------------------;
619: ; ulSetXParentRegs
620: ;
621: ; Set the VGA control registers for the specified Rop4 and foreground
622: ; color when background is transparent.
623: ;
624: ;-----------------------------------------------------------------------;
625:
626: cProc ulSetXParentRegs,12,< \
627: uses ebx edi, \
628: rop4: dword, \
629: pclr: ptr, \
630: bSet: dword >
631:
632: mov edi,VGB_OPAQUE_STRING
633: mov ebx,rop4
634: xor ecx,ecx ; Color = 00, mode = set
635: or ebx,ebx
636: jz short vsv_set_vga_mode
637:
638: dec ch ; Color = FF, mode = set
639: inc bx
640: jz short vsv_set_vga_mode
641:
642: mov eax,pclr
643: mov ch,byte ptr [eax] ; Color = passed color, mode = set
644: cmp bx,0f0f0h + 1
645: je short vsv_set_vga_mode
646:
647: not ch ; ~passed color
648: cmp bx,00f0fh + 1
649: je short vsv_set_vga_mode
650:
651: mov cx,0FF00h + DR_XOR ; Color = FF, mode = xor
652: mov edi,VGB_MIX_STRING ; We will actually do mode 0
653:
654: vsv_set_vga_mode:
655: mov eax,bSet ; set flag
656: or eax,eax
657: jz short vsv_exit
658:
659: mov dx,VGA_BASE + GRAF_ADDR
660: mov al,GRAF_SET_RESET
661: mov ah,ch
662: out dx,ax
663: mov ax,0f00h + GRAF_ENAB_SR
664: out dx,ax
665: mov ah,cl
666: mov al,GRAF_DATA_ROT
667: out dx,ax
668:
669: or edi,edi
670: .errnz VGB_MIX_STRING
671: jz short vsv_exit
672: mov ax,(M_AND_WRITE shl 8)+GRAF_MODE
673: out dx,ax
674:
675: vsv_exit:
676: mov eax,edi ; return VGA mode
677: mov edi,pclr
678: mov byte ptr [edi],ch ; CH = actual foreground color
679: cRet ulSetXParentRegs
680:
681: endProc ulSetXParentRegs
682:
683: ;---------------------------Public-Routine------------------------------;
684: ; vResetVGARegs
685: ;
686: ; Reset the VGA control registers to a default state.
687: ;
688: ;-----------------------------------------------------------------------;
689:
690: cProc vResetVGARegs
691:
692: mov dx,VGA_BASE + GRAF_ADDR
693: mov ax,0ff00h + GRAF_BIT_MASK
694: out dx,ax
695: mov ax,0000h + GRAF_SET_RESET
696: out dx,ax
697: mov ax,0000h + GRAF_ENAB_SR
698: out dx,ax
699: mov ax,(DR_SET shl 8) + GRAF_DATA_ROT
700: out dx,ax
701: mov ax,((M_PROC_WRITE or M_DATA_READ) shl 8) + GRAF_MODE
702: out dx,ax
703:
704: cRet vResetVGARegs
705:
706: endProc vResetVGARegs
707:
708: public gblt_calc_dest_addr
709: public gblt_left_mask
710: public gblt_inner_count
711: public gblt_last_mask
712: public gblt_glyph_info
713: public gblt_glyph_offset
714: public gblt_draw_glyph
715: public glyph_blt_exit
716: public vgblt_mix_glyph
717: public vmg_fetch_one_byte
718: public vmg_fetch_two_bytes
719: public vmg_advance_glyph_ptr
720: public vmg_advance_screen_ptr
721: public vmg_inner_bytes
722: public vmg_inner_fetch_one_byte
723: public vmg_inner_fetch_two_bytes
724: public vmg_last_byte
725: public vmg_last_fetch_one_byte
726: public vmg_last_fetch_two_bytes
727: public vmg_exit
728: public vgblt_opaque_glyph
729: public vog_fetch_one_byte
730: public vog_fetch_two_bytes
731: public vog_advance_glyph_ptr
732: public vog_advance_screen_ptr
733: public vog_inner_bytes
734: public vog_inner_fetch_one_byte
735: public vog_inner_fetch_two_bytes
736: public vog_last_byte
737: public vog_last_fetch_one_byte
738: public vog_last_fetch_two_bytes
739: public vog_exit
740:
741: _TEXT$01 ends
742:
743: end
744:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.