|
|
1.1 root 1: ;---------------------------Module-Header------------------------------;
2: ; Module Name: fasttext.asm
3: ;
4: ; Copyright (c) 1992 Microsoft Corporation
5: ;-----------------------------------------------------------------------;
6: ;-----------------------------------------------------------------------;
7: ; VOID vFastText(GLYPHPOS * pGlyphPos, ULONG ulGlyphCount, PBYTE pTempBuffer,
8: ; ULONG ulBufDelta, ULONG ulCharInc, DEVSURF * pdsurf,
9: ; RECTL * prclText, RECTL * prclOpaque, INT iFgColor,
10: ; INT iBgColor, ULONG fDrawFlags, RECTL * prclClip);
11: ; pGlyphPos -
12: ; ulGlyphCount - # of glyphs to draw. Must never be 0.
13: ; pTempBuffer -
14: ; ulBufDelta -
15: ; ulCharInc -
16: ; pdsurf -
17: ; prclText -
18: ; prclOpaque -
19: ; iFgColor -
20: ; iBgColor -
21: ; fDrawFlags -
22: ; prclClip -
23: ;
24: ; Performs accelerated proportional text drawing.
25: ;
26: ;-----------------------------------------------------------------------;
27: ;
28: ; Note: Assumes the text rectangle has a positive height and width. Will
29: ; not work properly if this is not the case.
30: ;
31: ; Note: The opaquing rectangle is assumed to match the text bounding
32: ; rectangle exactly; prclOpaque is used only to determine whether or
33: ; not opaquing is required.
34: ;
35: ; Note: Handles clipping only for opaque text.
36: ;
37: ; Note: For opaque text, handles only unclipped and rectangle-clipped
38: ; cases, not complex-clipped.
39: ;
40: ; Note: For maximum performance, we should not bother to draw fully-
41: ; clipped characters to the temp buffer.
42: ;
43: ; Note: We do not yet support extra rectangles (underlines). We should.
44: ;
45: ; Note: We do not handle clipping or bank spanning in the very fast
46: ; byte-wide-aligned-fixed-pitch console text. This would be an
47: ; opportunity for somewhat faster console text performance.
48: ;
49: ;-----------------------------------------------------------------------;
50: ;
51: ; Set LOOP_UNROLL_SHIFT to the log2 of the number of times you want to unroll
52: ; loops in this module that are implemented with the unrolling macros. For
53: ; example, LOOP_UNROLL_SHIFT of 3 yields 2**3 = 8 times unrolling. This is
54: ; the only thing you need to change to control unrolling.
55:
56: LOOP_UNROLL_SHIFT equ 2
57:
58: ;-----------------------------------------------------------------------;
59:
60: comment $
61:
62: The overall approach of this module is to draw the text into a system
63: memory buffer, then copy the buffer to the screen a word at a time
64: using write mode 3 so that no OUTs and a minimum of display memory reads
65: are required.
66:
67: commend $
68:
69: .386
70:
71: ifndef DOS_PLATFORM
72: .model small,c
73: else
74: ifdef STD_CALL
75: .model small,c
76: else
77: .model small,pascal
78: endif; STD_CALL
79: endif; DOS_PLATFORM
80:
81: assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
82: assume fs:nothing,gs:nothing
83:
84: .xlist
85: include stdcall.inc ;calling convention cmacros
86: include i386\egavga.inc
87: include i386\strucs.inc
88: include i386\unroll.inc
89:
90: .list
91:
92: ;-----------------------------------------------------------------------;
93:
94: .data
95:
96: ;-----------------------------------------------------------------------;
97: ; Tables used to branch into glyph-drawing optimizations.
98: ;
99: ; Handles narrow (1-4 bytes wide) glyph drawing, for case where initial byte
100: ; should be MOVed even if it's not aligned (intended for use in drawing the
101: ; first glyph in a string). Table format is:
102: ; Bits 3-2: dest width
103: ; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
104: ; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
105: align 4
106: MovInitialTableNarrow label dword
107: dd draw_prop_done ;0 wide
108: dd draw_prop_done ;0 wide
109: dd draw_prop_done ;0 wide
110: dd draw_prop_done ;0 wide
111: dd mov_first_1_wide_rotated_need_last ;nonalign, 1 wide, need last
112: dd mov_first_1_wide_unrotated ;aligned, 1 wide
113: dd mov_first_1_wide_rotated_no_last ;nonalign, 1 wide, no last
114: dd mov_first_1_wide_unrotated ;aligned, 1 wide
115: dd mov_first_2_wide_rotated_need_last ;nonalign, 2 wide, need last
116: dd mov_first_2_wide_unrotated ;aligned, 2 wide
117: dd mov_first_2_wide_rotated_no_last ;nonalign, 2 wide, no last
118: dd mov_first_2_wide_unrotated ;aligned, 2 wide
119: dd mov_first_3_wide_rotated_need_last ;nonalign, 3 wide, need last
120: dd mov_first_3_wide_unrotated ;aligned, 3 wide
121: dd mov_first_3_wide_rotated_no_last ;nonalign, 3 wide, no last
122: dd mov_first_3_wide_unrotated ;aligned, 3 wide
123: dd mov_first_4_wide_rotated_need_last ;nonalign, 4 wide, need last
124: dd mov_first_4_wide_unrotated ;aligned, 4 wide
125: dd mov_first_4_wide_rotated_no_last ;nonalign, 4 wide, no last
126: dd mov_first_4_wide_unrotated ;aligned, 4 wide
127:
128: ; Handles narrow (1-4 bytes wide) glyph drawing, for case where initial byte
129: ; ORed if it's not aligned (intended for use in drawing all but the first glyph
130: ; in a string). Table format is:
131: ; Bits 3-2: dest width
132: ; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
133: ; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
134: align 4
135: OrInitialTableNarrow label dword
136: dd draw_prop_done ;0 wide
137: dd draw_prop_done ;0 wide
138: dd draw_prop_done ;0 wide
139: dd draw_prop_done ;0 wide
140: dd or_first_1_wide_rotated_need_last ;nonalign, 1 wide, need last
141: dd mov_first_1_wide_unrotated ;aligned, 1 wide
142: dd or_first_1_wide_rotated_no_last ;nonalign, 1 wide, no last
143: dd mov_first_1_wide_unrotated ;aligned, 1 wide
144: dd or_first_2_wide_rotated_need_last ;nonalign, 2 wide, need last
145: dd mov_first_2_wide_unrotated ;aligned, 2 wide
146: dd or_first_2_wide_rotated_no_last ;nonalign, 2 wide, no last
147: dd mov_first_2_wide_unrotated ;aligned, 2 wide
148: dd or_first_3_wide_rotated_need_last ;nonalign, 3 wide, need last
149: dd mov_first_3_wide_unrotated ;aligned, 3 wide
150: dd or_first_3_wide_rotated_no_last ;nonalign, 3 wide, no last
151: dd mov_first_3_wide_unrotated ;aligned, 3 wide
152: dd or_first_4_wide_rotated_need_last ;nonalign, 4 wide, need last
153: dd mov_first_4_wide_unrotated ;aligned, 4 wide
154: dd or_first_4_wide_rotated_no_last ;nonalign, 4 wide, no last
155: dd mov_first_4_wide_unrotated ;aligned, 4 wide
156:
157: ; Handles narrow (1-4 bytes wide) glyph drawing, for case where all bytes
158: ; should be ORed (intended for use in drawing potentially overlapping glyphs).
159: ; Table format is:
160: ; Bits 3-2: dest width
161: ; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
162: ; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
163: align 4
164: OrAllTableNarrow label dword
165: dd draw_prop_done ;0 wide
166: dd draw_prop_done ;0 wide
167: dd draw_prop_done ;0 wide
168: dd draw_prop_done ;0 wide
169: dd or_all_1_wide_rotated_need_last ;nonalign, 1 wide, need last
170: dd or_all_1_wide_unrotated ;aligned, 1 wide
171: dd or_all_1_wide_rotated_no_last ;nonalign, 1 wide, no last
172: dd or_all_1_wide_unrotated ;aligned, 1 wide
173: dd or_all_2_wide_rotated_need_last ;nonalign, 2 wide, need last
174: dd or_all_2_wide_unrotated ;aligned, 2 wide
175: dd or_all_2_wide_rotated_no_last ;nonalign, 2 wide, no last
176: dd or_all_2_wide_unrotated ;aligned, 2 wide
177: dd or_all_3_wide_rotated_need_last ;nonalign, 3 wide, need last
178: dd or_all_3_wide_unrotated ;aligned, 3 wide
179: dd or_all_3_wide_rotated_no_last ;nonalign, 3 wide, no last
180: dd or_all_3_wide_unrotated ;aligned, 3 wide
181: dd or_all_4_wide_rotated_need_last ;nonalign, 4 wide, need last
182: dd or_all_4_wide_unrotated ;aligned, 4 wide
183: dd or_all_4_wide_rotated_no_last ;nonalign, 4 wide, no last
184: dd or_all_4_wide_unrotated ;aligned, 4 wide
185:
186: ; Handles arbitrarily wide glyph drawing, for case where initial byte should be
187: ; MOVed even if it's not aligned (intended for use in drawing the first glyph
188: ; in a string). Table format is:
189: ; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
190: ; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
191: align 4
192: MovInitialTableWide label dword
193: dd mov_first_N_wide_rotated_need_last ;nonalign, need last
194: dd mov_first_N_wide_unrotated ;aligned
195: dd mov_first_N_wide_rotated_no_last ;nonalign, no last
196: dd mov_first_N_wide_unrotated ;aligned
197:
198: ; Handles arbitrarily wide glyph drawing, for case where initial byte should be
199: ; ORed if it's not aligned (intended for use in drawing all but the first glyph
200: ; in a string). Table format is:
201: ; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
202: ; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
203: align 4
204: OrInitialTableWide label dword
205: dd or_first_N_wide_rotated_need_last ;nonalign, need last
206: dd mov_first_N_wide_unrotated ;aligned
207: dd or_first_N_wide_rotated_no_last ;nonalign, no last
208: dd mov_first_N_wide_unrotated ;aligned
209:
210: ; Handles arbitrarily wide glyph drawing, for case where all bytes should
211: ; be ORed (intended for use in drawing potentially overlapping glyphs).
212: ; Table format is:
213: ; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
214: ; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
215: align 4
216: OrAllTableWide label dword
217: dd or_all_N_wide_rotated_need_last ;nonalign, need last
218: dd or_all_N_wide_unrotated ;aligned
219: dd or_all_N_wide_rotated_no_last ;nonalign, no last
220: dd or_all_N_wide_unrotated ;aligned
221:
222: ; Vectors to entry points for drawing various types of text. '*' means works as
223: ; is but could be acclerated with a custom scanning loop.
224: align 4
225: MasterTextTypeTable label dword ;tops aligned overlap fixed pitch
226: dd draw_nf_ntb_o_to_temp_start ; N N N *
227: dd draw_f_ntb_o_to_temp_start ; N N Y *
228: dd draw_nf_ntb_o_to_temp_start ; N Y N
229: dd draw_f_ntb_o_to_temp_start ; N Y Y
230: dd draw_nf_tb_no_to_temp_start ; Y N N
231: dd draw_f_tb_no_to_temp_start ; Y N Y
232: dd draw_nf_ntb_o_to_temp_start ; Y Y N *
233: dd draw_f_ntb_o_to_temp_start ; Y Y Y *
234:
235: ; Masks for clipping for the eight possible left and right edge alignments
236: jOpaqueLeftMasks label byte
237: db 0ffh,07fh,03fh,01fh,00fh,007h,003h,001h
238:
239: jOpaqueRightMasks label byte
240: db 0ffh,080h,0c0h,0e0h,0f0h,0f8h,0fch,0feh
241:
242: ;-----------------------------------------------------------------------;
243:
244: .code
245:
246: _TEXT$01 SEGMENT DWORD USE32 PUBLIC 'CODE'
247: ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
248:
249: ;-----------------------------------------------------------------------;
250:
251: cProc vFastText,48,<\
252: uses esi edi ebx,\
253: pGlyphPos:ptr,\
254: ulGlyphCount:dword,\
255: pTempBuffer:ptr,\
256: ulBufDelta:dword,\
257: ulCharInc:dword,\
258: pdsurf:ptr,\
259: prclText:ptr,\
260: prclOpaque:ptr,\
261: iFgColor:dword,\
262: iBgColor:dword,\
263: fDrawFlags:dword,\
264: prclClip:dword>
265:
266: local ulGlyDelta:dword ;width per scan of source glyph, in bytes
267: local ulWidthInBytes:dword ;width of glyph, in bytes
268: local ulTmpWidthInBytes:dword ;working byte-width count
269: local ulGlyphX:dword ;for fixed-pitch text, maintains the current
270: ; glyph's left-edge X coordinate
271: local pGlyphLoop:dword ;pointer to glyph-processing loop
272: local ulTempLeft:dword ;X coordinate on screen of left edge of temp
273: ; buffer
274: local ulTempTop:dword ;Y coordinate on screen of top edge of temp
275: ; buffer
276: local pfnEntry:dword ;pointer to unrolled loop entry point
277: local ulLoopCount:dword ;general loop count storage
278: local ulTmpSrcDelta:dword ;distance from end of one buffer text scan to
279: ; start of next
280: local ulTmpDstDelta:dword ;distance from end of one screen text scan to
281: ; start of next
282: local ulTopScan:dword ;top scan of dest text rect in current bank
283: local ulBottomScan:dword ;bottom scan of dest text rect
284: local ulNumScans:dword ;# of scans to draw
285: local ulScreenDelta:dword ;scan-to-scan offset in screen
286: local ulTextWidthInBytes:dword ;# of bytes across spanned by text
287: local pScreen:dword ;pointer to first screen byte to which to draw
288: local pfnEdgeVector:dword ;pointer to routine to draw any needed edges
289: local pfnFirstOpaqVector:dword ;pointer to initial drawing routine
290: ; called for opaque (either whole
291: ; bytes, or edge(s) if no whole bytes)
292: local ulWholeWidthInWords:dword ;# of whole words to copy
293: local ulWholeWidthInWordsMinus1:dword ;# of whole words to copy, -1
294: local ulOddByte:dword ;1 if odd byte in whole word copy
295: local ulTextLeft:dword ;left edge of leftmost glyph
296: local ulLeftMask:dword ;for opaque text, left edge mask for string
297: local ulRightMask:dword ;for opaque text, right edge mask for string
298: local ulUnrolledCount:dword ;# of unrolled loop reps
299: local ulUnrolledOddCount:dword ;# of unrolled loop odd reps
300: local ulYOrigin:dword ;Y origin of text in string (all glyphs are at
301: ; the same Y origin)
302: local rclClippedBounds[16]:byte ;clipped destination rectangle;
303: ; defined as "byte" due to assembler
304: ; limitations
305:
306: ;-----------------------------------------------------------------------;
307:
308: cld
309:
310: ;-----------------------------------------------------------------------;
311: ; Draws either a fixed or a non-fixed-pitch string to the temporary
312: ; buffer. Assumes this is a horizontal string, so the origins of all glyphs
313: ; are at the same Y coordinate. Draws leftmost glyph entirely with MOVs,
314: ; even if it's not aligned, in order to ensure that the leftmost byte
315: ; gets cleared when we're working with butted characters. For other
316: ; non-aligned glyphs, leftmost byte is ORed, other bytes are MOVed.
317: ;
318: ; Input:
319: ; pGlyphPos = pointer to array of GLYPHPOS structures to draw
320: ; ulGlyphCount = # of glyphs to draw
321: ; ulTempLeft = X coordinate on dest of left edge of temp buffer pointed
322: ; to by pTempBuffer
323: ; pTempBuffer = pointer to first byte (upper left corner) of
324: ; temp buffer into which we're drawing. This should be
325: ; word-aligned with the destination
326: ; ulBufDelta = destination scan-to-scan offset
327: ; ulCharInc = offset from one glyph to next (fixed-pitch only)
328: ; fDrawFlags = indicate the type of text to be drawn
329: ; Temp buffer zeroed if text doesn't cover every single pixel
330: ;
331: ; Fixed-pitch means equal spacing between glyph positions, not that all
332: ; glyphs butt together or equal spacing between upper left corners.
333: ;-----------------------------------------------------------------------;
334:
335: ;-----------------------------------------------------------------------;
336: ; If 8 wide, byte aligned, and opaque, handle with very fast special-case
337: ; code.
338: ;-----------------------------------------------------------------------;
339:
340: mov ebx,prclText
341: cmp ulCharInc,8 ;8 wide?
342: jnz short @F ;no
343: cmp fDrawFlags,5 ;fixed pitch?
344: jnz short @F ;no
345: cmp prclOpaque,0 ;opaque?
346: jz short @F ;no
347: cmp prclClip,0 ;is there clipping?
348: jnz short @F ;yes
349: test [ebx].xLeft,111b ;byte aligned?
350: jz special_8_wide_aligned_opaque ;yes, special-case
351: @@:
352:
353: ;-----------------------------------------------------------------------;
354: ; Handle all cases other than 8-wide byte-aligned.
355: ;-----------------------------------------------------------------------;
356:
357: general_handler:
358: mov esi,pdsurf
359: mov eax,[ebx].yTop
360: mov ulTempTop,eax ;Y screen coordinate of top edge of temp buf
361: mov eax,[ebx].xLeft
362: and eax,not 7
363: mov ulTempLeft,eax ;X screen coordinate of left edge of temp buf
364: mov eax,[esi].dsurf_lNextScan
365: mov ulScreenDelta,eax
366:
367: mov eax,fDrawFlags
368:
369: jmp MasterTextTypeTable[eax*4]
370:
371: ;-----------------------------------------------------------------------;
372: ; Entry point for fixed-pitch | tops and bottoms aligned | no overlap.
373: ; Sets up to draw first glyph.
374: ;-----------------------------------------------------------------------;
375: draw_f_tb_no_to_temp_start:
376: mov ebx,pGlyphPos ;point to the first glyph to draw
377: mov esi,[ebx].gp_pgdf ;point to glyph def
378:
379: mov edi,[ebx].gp_x ;dest X coordinate
380: sub edi,ulTempLeft ;adjust relative to the left of the
381: ; temp buffer (we assume the text is
382: ; right at the top of the text rect
383: ; and hence the buffer)
384: mov ulGlyphX,edi ;remember where this glyph started
385: mov esi,[esi].gdf_pgb ;point to glyph bits
386: mov pGlyphLoop,offset draw_f_tb_no_to_temp_loop
387: ;draw additional characters with this
388: ; loop
389: jmp short draw_to_temp_start_entry
390:
391: ;-----------------------------------------------------------------------;
392: ; Entry point for non-fixed-pitch | tops and bottoms aligned | no overlap.
393: ; Sets up to draw first glyph.
394: ;-----------------------------------------------------------------------;
395: draw_nf_tb_no_to_temp_start:
396: mov ebx,pGlyphPos ;point to the first glyph to draw
397: mov esi,[ebx].gp_pgdf ;point to glyph def
398:
399: mov edi,[ebx].gp_x ;dest X coordinate
400: sub edi,ulTempLeft ;adjust relative to the left of the
401: ; temp buffer
402: mov esi,[esi].gdf_pgb ;point to glyph bits
403: mov pGlyphLoop,offset draw_nf_tb_no_to_temp_loop
404: ;draw additional characters with this
405: ; loop
406: draw_to_temp_start_entry:
407: add edi,[esi].gb_x ;adjust to position of upper left glyph
408: ; corner in dest
409: ;BUGBUG add or sub?
410: mov ecx,edi
411: shr edi,3 ;byte offset of first column of glyph
412: ; offset of upper left of glyph in temp
413: ; buffer
414: add edi,pTempBuffer ;initial dest byte in temp buffer
415:
416: and ecx,111b ;bit alignment of upper left in temp
417:
418: ;calculate scan-to-scan glyph width
419: mov ebx,[esi].gb_cx ;glyph width in pixels
420:
421: lea eax,[ebx+ecx+7]
422: shr eax,3 ;# of dest bytes per scan
423:
424: add ebx,7
425: shr ebx,3 ;# of source bytes per scan
426:
427: mov edx,ulBufDelta ;width of destination buffer in bytes
428:
429: cmp eax,4 ;do we have special case code for this
430: ; dest width?
431: ja short @F ;no, handle as general case
432: ;yes, handle as special case
433: cmp ebx,eax ;carry if more dest than source bytes
434: ; (last source byte not needed)
435: rcl eax,1 ;factor last source byte status in
436: cmp cl,1 ;carry if aligned
437: rcl eax,1 ;factor in alignment (aligned or not)
438: mov ebx,[esi].gb_cy ;# of scans in glyph
439: add esi,gb_aj ;point to the first glyph byte
440:
441: jmp MovInitialTableNarrow[eax*4]
442: ;branch to draw the first glyph; never
443: ; need to OR first glyph, because
444: ; there's nothing there yet
445:
446: @@: ;too wide to special case
447: mov ulWidthInBytes,eax ;# of bytes across dest
448: cmp ebx,eax ;carry if more dest than source bytes
449: ; (last source byte not needed)
450: mov eax,0
451: rcl eax,1 ;factor last source byte status in
452: cmp cl,1 ;carry if aligned
453: rcl eax,1 ;factor in alignment (aligned or not)
454:
455: mov ebx,[esi].gb_cx ;glyph width in pixels
456: add ebx,7
457: shr ebx,3 ;glyph width in bytes
458: mov ulGlyDelta,ebx
459:
460: mov ebx,[esi].gb_cy ;# of scans in glyph
461: add esi,gb_aj ;point to the first glyph byte
462:
463: jmp MovInitialTableWide[eax*4]
464: ;branch to draw the first glyph; never
465: ; need to OR first glyph, because
466: ; there's nothing there yet
467:
468: ;-----------------------------------------------------------------------;
469: ; Entry point for fixed-pitch | tops and bottoms not aligned | overlap.
470: ; Sets up to draw first glyph.
471: ;-----------------------------------------------------------------------;
472: draw_f_ntb_o_to_temp_start:
473: mov ebx,pGlyphPos ;point to the first glyph to draw
474: mov pGlyphLoop,offset draw_f_ntb_o_to_temp_loop
475: ;draw additional characters with this
476: ; loop
477: mov edi,[ebx].gp_x ;dest X coordinate
478: mov esi,[ebx].gp_pgdf ;point to glyph def
479: sub edi,ulTempLeft ;adjust relative to the left of the
480: ; temp buffer
481: mov ulGlyphX,edi ;remember where this glyph started
482: mov esi,[esi].gdf_pgb ;point to glyph bits
483: add edi,[esi].gb_x ;adjust to position of upper left glyph
484: ; corner in dest
485: mov ecx,edi
486: shr edi,3 ;byte offset of first column of glyph
487: ; offset of upper left of glyph in temp
488: ; buffer
489: jmp short draw_to_temp_start_entry2
490:
491: ;-----------------------------------------------------------------------;
492: ; Entry point for non-fixed-pitch | tops and bottoms not aligned | overlap.
493: ; Sets up to draw first glyph.
494: ;-----------------------------------------------------------------------;
495: draw_nf_ntb_o_to_temp_start:
496: mov ebx,pGlyphPos ;point to the first glyph to draw
497: mov pGlyphLoop,offset draw_nf_ntb_o_to_temp_loop
498: ;draw additional characters with this
499: ; loop
500: mov edi,[ebx].gp_x ;dest X coordinate
501: mov esi,[ebx].gp_pgdf ;point to glyph def
502: sub edi,ulTempLeft ;adjust relative to the left of the
503: ; temp buffer
504: mov esi,[esi].gdf_pgb ;point to glyph bits
505: add edi,[esi].gb_x ;adjust to position of upper left glyph
506: ; corner in dest
507: ;BUGBUG add or sub?
508: mov ecx,edi
509: shr edi,3 ;byte offset of first column of glyph
510: ; offset of upper left of glyph in temp
511: ; buffer
512: draw_to_temp_start_entry2:
513: mov eax,[ebx].gp_y ;dest origin Y coordinate
514: sub eax,ulTempTop ;coord of glyph origin in temp buffer
515: mov ulYOrigin,eax ;remember the Y origin of all glyphs
516: ; (necessary because glyph positions
517: ; after first aren't set for fixed-
518: ; pitch strings)
519: add eax,[esi].gb_y ;adjust to position of upper left glyph
520: ; corner in dest
521: mul ulBufDelta ;offset in buffer of top glyph scan
522: add eax,pTempBuffer ;initial dest byte
523: add edi,eax
524:
525: and ecx,111b ;bit alignment of upper left in temp
526:
527: ;calculate scan-to-scan glyph width
528: mov ebx,[esi].gb_cx ;glyph width in pixels
529:
530: lea eax,[ebx+ecx+7]
531: shr eax,3 ;# of dest bytes per scan
532:
533: add ebx,7
534: shr ebx,3 ;# of source bytes per scan
535:
536: mov edx,ulBufDelta ;width of destination buffer in bytes
537:
538: cmp eax,4 ;do we have special case code for this
539: ; dest width?
540: ja short @F ;no, handle as general case
541: ;yes, handle as special case
542: cmp ebx,eax ;carry if more dest than source bytes
543: ; (last source byte not needed)
544: rcl eax,1 ;factor last source byte status in
545: cmp cl,1 ;carry if aligned
546: rcl eax,1 ;factor in alignment (aligned or not)
547: mov ebx,[esi].gb_cy ;# of scans in glyph
548: add esi,gb_aj ;point to the first glyph byte
549:
550: jmp OrAllTableNarrow[eax*4] ;branch to draw the first glyph; OR all
551: ; glyphs, because text may overlap
552:
553: @@: ;too wide to special case
554: mov ulWidthInBytes,eax ;# of bytes across dest
555: cmp ebx,eax ;carry if more dest than source bytes
556: ; (last source byte not needed)
557: mov eax,0
558: rcl eax,1 ;factor last source byte status in
559: cmp cl,1 ;carry if aligned
560: rcl eax,1 ;factor in alignment (aligned or not)
561:
562: mov ebx,[esi].gb_cx ;glyph width in pixels
563: add ebx,7
564: shr ebx,3 ;glyph width in bytes
565: mov ulGlyDelta,ebx
566:
567: mov ebx,[esi].gb_cy ;# of scans in glyph
568: add esi,gb_aj ;point to the first glyph byte
569:
570: jmp OrAllTableWide[eax*4] ;branch to draw the first glyph; OR all ; glyphs, because text may overlap never
571: ; glyphs, because text may overlap
572:
573: ;-----------------------------------------------------------------------;
574: ; Loop to draw all fixed-pitch | tops and bottoms aligned | no overlap
575: ; glyphs after first.
576: ;-----------------------------------------------------------------------;
577: draw_f_tb_no_to_temp_loop:
578: dec ulGlyphCount ;any more glyphs to draw?
579: jz draw_to_screen ;no, done
580: mov ebx,pGlyphPos
581: add ebx,size GLYPHPOS ;point to the next glyph (the one
582: mov pGlyphPos,ebx ; we're going to draw this time)
583: mov esi,[ebx].gp_pgdf ;point to glyph def
584:
585: mov edi,ulGlyphX ;last glyph's dest X start in temp buf
586: add edi,ulCharInc ;this glyph's dest X start in temp buf
587: mov ulGlyphX,edi ;remember for next glyph
588: mov esi,[esi].gdf_pgb ;point to glyph bits
589: jmp short draw_to_temp_loop_entry
590:
591: ;-----------------------------------------------------------------------;
592: ; Loop to draw all non-fixed-pitch | tops and bottoms aligned | no overlap
593: ; glyphs after first.
594: ;-----------------------------------------------------------------------;
595: draw_nf_tb_no_to_temp_loop:
596: dec ulGlyphCount ;any more glyphs to draw?
597: jz draw_to_screen ;no, done
598: mov ebx,pGlyphPos
599: add ebx,size GLYPHPOS ;point to the next glyph (the one we're
600: mov pGlyphPos,ebx ; going to draw this time)
601: mov esi,[ebx].gp_pgdf ;point to glyph def
602: mov edi,[ebx].gp_x ;dest X coordinate
603: mov esi,[esi].gdf_pgb ;point to glyph bits
604: sub edi,ulTempLeft ;adjust relative to the left edge of
605: ; the temp buffer
606:
607: draw_to_temp_loop_entry:
608: add edi,[esi].gb_x ;adjust to position of upper left glyph
609: ; corner in dest
610: mov ecx,edi ;pixel X coordinate in temp buffer
611: shr edi,3 ;byte offset of first column = dest
612: ; offset of upper left of glyph in temp
613: ; buffer
614: add edi,pTempBuffer ;initial dest byte
615:
616: and ecx,111b ;bit alignment of upper left in temp
617:
618: ;calculate scan-to-scan glyph width
619: mov ebx,[esi].gb_cx ;glyph width in pixels
620:
621: lea eax,[ebx+ecx+7]
622: shr eax,3 ;# of dest bytes to copy to per scan
623:
624: add ebx,7
625: shr ebx,3 ;# of source bytes to copy from per
626: ; scan
627: mov edx,ulBufDelta ;width of destination buffer in bytes
628:
629: cmp eax,4 ;do we have special case code for this
630: ; dest width?
631: ja short @F ;no, handle as general case
632: ;yes, handle as special case
633: cmp ebx,eax ;carry if more dest than source bytes
634: ; (last source byte not needed)
635: rcl eax,1 ;factor last source byte status in
636: cmp cl,1 ;carry if aligned
637: rcl eax,1 ;factor in alignment (aligned or not)
638: mov ebx,[esi].gb_cy ;# of scans in glyph
639: add esi,gb_aj ;point to the first glyph byte
640:
641: jmp OrInitialTableNarrow[eax*4] ;branch to draw the first glyph;
642: ; need to OR the 1st byte if
643: ; non-aligned to avoid overwriting
644: ; what's already there
645: @@: ;too wide to special case
646: mov ulWidthInBytes,eax ;# of bytes across dest
647: cmp ebx,eax ;carry if more dest than source bytes
648: ; (last source byte not needed)
649: mov eax,0
650: rcl eax,1 ;factor last source byte status in
651: cmp cl,1 ;carry if aligned
652: rcl eax,1 ;factor in alignment (aligned or not)
653:
654: mov ebx,[esi].gb_cx ;glyph width in pixels
655: add ebx,7
656: shr ebx,3 ;glyph width in bytes
657: mov ulGlyDelta,ebx
658:
659: mov ebx,[esi].gb_cy ;# of scans in glyph
660: add esi,gb_aj ;point to the first glyph byte
661:
662: jmp OrInitialTableWide[eax*4] ;branch to draw the next glyph;
663: ; need to OR the 1st byte if
664: ; non-aligned to avoid overwriting
665: ; what's already there
666:
667: ;-----------------------------------------------------------------------;
668: ; Loop to draw all fixed-pitch | tops and bottoms not aligned | overlap
669: ; glyphs after first.
670: ;-----------------------------------------------------------------------;
671: draw_f_ntb_o_to_temp_loop:
672: dec ulGlyphCount ;any more glyphs to draw?
673: jz draw_to_screen ;no, done
674: mov ebx,pGlyphPos
675: add ebx,size GLYPHPOS ;point to the next glyph (the one we're
676: mov pGlyphPos,ebx ; going to draw this time)
677:
678: mov esi,[ebx].gp_pgdf ;point to glyph def
679: mov edi,ulGlyphX ;last glyph's dest X start in temp buf
680: add edi,ulCharInc ;this glyph's dest X start in temp buf
681: mov ulGlyphX,edi ;remember for next glyph
682: mov esi,[esi].gdf_pgb ;point to glyph bits
683:
684: jmp short draw_to_temp_loop_entry2
685:
686: ;-----------------------------------------------------------------------;
687: ; Loop to draw all non-fixed-pitch | tops and bottoms not aligned | overlap
688: ; glyphs after first.
689: ;-----------------------------------------------------------------------;
690: draw_nf_ntb_o_to_temp_loop:
691: dec ulGlyphCount ;any more glyphs to draw?
692: jz draw_to_screen ;no, done
693: mov ebx,pGlyphPos
694: add ebx,size GLYPHPOS ;point to the next glyph (the one we're
695: mov pGlyphPos,ebx ; going to draw this time)
696:
697: mov esi,[ebx].gp_pgdf ;point to glyph def
698: mov edi,[ebx].gp_x ;dest X coordinate
699: mov esi,[esi].gdf_pgb ;point to glyph bits
700: sub edi,ulTempLeft ;adjust relative to the left edge of
701: ; the temp buffer
702: draw_to_temp_loop_entry2:
703: add edi,[esi].gb_x ;adjust to position of upper left glyph
704: ; corner in dest
705: mov ecx,edi ;pixel X coordinate in temp buffer
706: shr edi,3 ;byte offset of first column = dest
707: ; offset of upper left of glyph in temp
708: ; buffer
709: mov eax,ulYOrigin ;dest Y coordinate
710:
711: add eax,[esi].gb_y ;adjust to position of upper left glyph
712: ; corner in dest
713: mul ulBufDelta ;offset in buffer of top glyph scan
714: add eax,pTempBuffer ;initial dest byte
715: add edi,eax
716:
717: and ecx,111b ;bit alignment of upper left in temp
718:
719: ;calculate scan-to-scan glyph width
720: mov ebx,[esi].gb_cx ;glyph width in pixels
721:
722: lea eax,[ebx+ecx+7]
723: shr eax,3 ;# of dest bytes to copy to per scan
724:
725: add ebx,7
726: shr ebx,3 ;# of source bytes to copy from per
727: ; scan
728: mov edx,ulBufDelta ;width of destination buffer in bytes
729:
730: cmp eax,4 ;do we have special case code for this
731: ; dest width?
732: ja short @F ;no, handle as general case
733: ;yes, handle as special case
734: cmp ebx,eax ;carry if more dest than source bytes
735: ; (last source byte not needed)
736: rcl eax,1 ;factor last source byte status in
737: cmp cl,1 ;carry if aligned
738: rcl eax,1 ;factor in alignment (aligned or not)
739: mov ebx,[esi].gb_cy ;# of scans in glyph
740: add esi,gb_aj ;point to the first glyph byte
741:
742: jmp OrAllTableNarrow[eax*4] ;branch to draw the next glyph
743:
744: @@: ;too wide to special case
745: mov ulWidthInBytes,eax ;# of bytes across dest
746: cmp ebx,eax ;carry if more dest than source bytes
747: ; (last source byte not needed)
748: mov eax,0
749: rcl eax,1 ;factor last source byte status in
750: cmp cl,1 ;carry if aligned
751: rcl eax,1 ;factor in alignment (aligned or not)
752:
753: mov ebx,[esi].gb_cx ;glyph width in pixels
754: add ebx,7
755: shr ebx,3 ;glyph width in bytes
756: mov ulGlyDelta,ebx
757:
758: mov ebx,[esi].gb_cy ;# of scans in glyph
759: add esi,gb_aj ;point to the first glyph byte
760:
761: jmp OrAllTableWide[eax*4] ;branch to draw the next glyph
762:
763: ;-----------------------------------------------------------------------;
764: ; Routines to draw all scans of a single glyph into the temp buffer,
765: ; optimized for the following cases:
766: ;
767: ; 1 to 4 byte-wide destination rectangles for each of:
768: ; No rotation needed
769: ; Rotation needed, same # of source as dest bytes needed
770: ; Rotation needed, one less source than dest bytes needed
771: ;
772: ; Additionally, the three cases are handled for 5 and wider cases by a
773: ; general routine for each case.
774: ;
775: ; If rotation is needed, there are three sorts of routines:
776: ;
777: ; 1) The leftmost byte is MOVed, to initialize the byte. Succeeding bytes are
778: ; MOVed. This is generally used for the leftmost glyph of a string.
779: ; 2) The leftmost byte is ORed into the existing byte. Succeeding bytes are
780: ; MOVed. This is generally used after the leftmost glyph, because this may
781: ; not be the first data written to that byte.
782: ; 3) All bytes are ORed. This is for drawing when characters might overlap.
783: ;
784: ; If rotation is not needed, there are two sorts of routines:
785: ;
786: ; 1) The leftmost byte is MOVed, to initialize the byte. Succeeding bytes are
787: ; MOVed. This is generally used for the leftmost glyph of a string.
788: ; 2) All bytes are ORed. This is for drawing when characters might overlap.
789: ;
790: ; On entry:
791: ; EBX = # of scans to copy
792: ; CL = right rotation
793: ; EDX = ulBufDelta = width per scan of destination buffer, in bytes
794: ; ESI = pointer to first glyph byte
795: ; EDI = pointer to first dest buffer byte
796: ; DF = cleared
797: ; ulGlyDelta = width per scan of source glyph, in bytes (wide case only)
798: ; ulWidthInBytes = width of glyph, in bytes (required only for 5 and
799: ; wider cases)
800: ;
801: ; On exit:
802: ; Any or all of EAX, EBX, ECX, EDX, ESI, and EDI may be trashed.
803:
804: ;-----------------------------------------------------------------------;
805: ; OR first byte, 1 byte wide dest, rotated.
806: ;-----------------------------------------------------------------------;
807: or_all_1_wide_rotated_need_last:
808: or_all_1_wide_rotated_no_last:
809: or_first_1_wide_rotated_need_last:
810: or_first_1_wide_rotated_no_last:
811: SET_UP_UNROLL_AND_BRANCH ebx,eax,or_first_1_wide_rotated_table, \
812: LOOP_UNROLL_SHIFT
813:
814: UNROLL_LOOP_ENTRY_TABLE or_first_1_wide_rotated_table,OF1WR, \
815: LOOP_UNROLL_COUNT
816:
817: MOR_FIRST_1_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
818: &ENTRY_LABEL&ENTRY_INDEX&:
819: mov ch,[esi]
820: inc esi
821: shr ch,cl
822: or [edi],ch
823: add edi,edx
824: endm ;-----------------------------------;
825:
826: or_first_1_wide_rotated_loop:
827: UNROLL_LOOP MOR_FIRST_1_WIDE_ROTATED,OF1WR,LOOP_UNROLL_COUNT
828: dec ebx
829: jnz or_first_1_wide_rotated_loop
830: jmp pGlyphLoop
831:
832: ;-----------------------------------------------------------------------;
833: ; MOV first byte, 1 byte wide dest, rotated.
834: ;-----------------------------------------------------------------------;
835: mov_first_1_wide_rotated_need_last:
836: mov_first_1_wide_rotated_no_last:
837: SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_1_wide_rotated_table, \
838: LOOP_UNROLL_SHIFT
839:
840: UNROLL_LOOP_ENTRY_TABLE mov_first_1_wide_rotated_table,MF1WR, \
841: LOOP_UNROLL_COUNT
842:
843: MMOV_FIRST_1_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
844: &ENTRY_LABEL&ENTRY_INDEX&:
845: mov ch,[esi]
846: inc esi
847: shr ch,cl
848: mov [edi],ch
849: add edi,edx
850: endm ;-----------------------------------;
851:
852: mov_first_1_wide_rotated_loop:
853: UNROLL_LOOP MMOV_FIRST_1_WIDE_ROTATED,MF1WR,LOOP_UNROLL_COUNT
854: dec ebx
855: jnz mov_first_1_wide_rotated_loop
856: jmp pGlyphLoop
857:
858: ;-----------------------------------------------------------------------;
859: ; MOV first byte, 1 byte wide dest, unrotated.
860: ;-----------------------------------------------------------------------;
861: mov_first_1_wide_unrotated:
862:
863: SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_1_wide_unrotated_table, \
864: LOOP_UNROLL_SHIFT
865:
866: UNROLL_LOOP_ENTRY_TABLE mov_first_1_wide_unrotated_table,MF1WU, \
867: LOOP_UNROLL_COUNT
868:
869: MMOV_FIRST_1_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
870: &ENTRY_LABEL&ENTRY_INDEX&:
871: mov al,[esi]
872: inc esi
873: mov [edi],al
874: add edi,edx
875: endm ;-----------------------------------;
876:
877: mov_first_1_wide_unrotated_loop:
878: UNROLL_LOOP MMOV_FIRST_1_WIDE_UNROTATED,MF1WU,LOOP_UNROLL_COUNT
879: dec ebx
880: jnz mov_first_1_wide_unrotated_loop
881: jmp pGlyphLoop
882:
883: ;-----------------------------------------------------------------------;
884: ; OR all bytes, 1 byte wide dest, unrotated.
885: ;-----------------------------------------------------------------------;
886: or_all_1_wide_unrotated:
887: SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_1_wide_unrotated_table, \
888: LOOP_UNROLL_SHIFT
889:
890: UNROLL_LOOP_ENTRY_TABLE or_all_1_wide_unrotated_table,OA1WU, \
891: LOOP_UNROLL_COUNT
892:
893: MOR_ALL_1_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
894: &ENTRY_LABEL&ENTRY_INDEX&:
895: mov al,[esi]
896: inc esi
897: or [edi],al
898: add edi,edx
899: endm ;-----------------------------------;
900:
901: or_all_1_wide_unrotated_loop:
902: UNROLL_LOOP MOR_ALL_1_WIDE_UNROTATED,OA1WU,LOOP_UNROLL_COUNT
903: dec ebx
904: jnz or_all_1_wide_unrotated_loop
905: jmp pGlyphLoop
906:
907: ;-----------------------------------------------------------------------;
908: ; OR first byte, 2 bytes wide dest, rotated, need final source byte.
909: ;-----------------------------------------------------------------------;
910: or_first_2_wide_rotated_need_last:
911: SET_UP_UNROLL_AND_BRANCH ebx,eax,or_first_2_wide_rotated_need_table, \
912: LOOP_UNROLL_SHIFT
913:
914: UNROLL_LOOP_ENTRY_TABLE or_first_2_wide_rotated_need_table,OF2WRN, \
915: LOOP_UNROLL_COUNT
916:
917: MOR_FIRST_2_WIDE_ROTATED_NEED macro ENTRY_LABEL,ENTRY_INDEX
918: &ENTRY_LABEL&ENTRY_INDEX&:
919: mov ax,[esi]
920: add esi,2
921: ror ax,cl
922: or [edi],al
923: mov [edi+1],ah
924: add edi,edx
925: endm ;-----------------------------------;
926:
927: or_first_2_wide_rotated_need_loop:
928: UNROLL_LOOP MOR_FIRST_2_WIDE_ROTATED_NEED,OF2WRN,LOOP_UNROLL_COUNT
929: dec ebx
930: jnz or_first_2_wide_rotated_need_loop
931: jmp pGlyphLoop
932:
933: ;-----------------------------------------------------------------------;
934: ; OR all bytes, 2 bytes wide dest, rotated, need final source byte.
935: ;-----------------------------------------------------------------------;
936: or_all_2_wide_rotated_need_last:
937: SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_2_wide_rotated_need_table, \
938: LOOP_UNROLL_SHIFT
939:
940: UNROLL_LOOP_ENTRY_TABLE or_all_2_wide_rotated_need_table,OA2WRN, \
941: LOOP_UNROLL_COUNT
942:
943: MOR_ALL_2_WIDE_ROTATED_NEED macro ENTRY_LABEL,ENTRY_INDEX
944: &ENTRY_LABEL&ENTRY_INDEX&:
945: mov ax,[esi]
946: add esi,2
947: ror ax,cl
948: or [edi],ax
949: add edi,edx
950: endm ;-----------------------------------;
951:
952: or_all_2_wide_rotated_need_loop:
953: UNROLL_LOOP MOR_ALL_2_WIDE_ROTATED_NEED,OA2WRN,LOOP_UNROLL_COUNT
954: dec ebx
955: jnz or_all_2_wide_rotated_need_loop
956: jmp pGlyphLoop
957:
958: ;-----------------------------------------------------------------------;
959: ; MOV first byte, 2 bytes wide dest, rotated, need final source byte.
960: ;-----------------------------------------------------------------------;
961: mov_first_2_wide_rotated_need_last:
962: SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_2_wide_rotated_need_table, \
963: LOOP_UNROLL_SHIFT
964:
965: UNROLL_LOOP_ENTRY_TABLE mov_first_2_wide_rotated_need_table,MF2WRN, \
966: LOOP_UNROLL_COUNT
967:
968: MMOV_FIRST_2_WIDE_ROTATED_NEED macro ENTRY_LABEL,ENTRY_INDEX
969: &ENTRY_LABEL&ENTRY_INDEX&:
970: mov ax,[esi]
971: add esi,2
972: ror ax,cl
973: mov [edi],ax
974: add edi,edx
975: endm ;-----------------------------------;
976:
977: mov_first_2_wide_rotated_need_loop:
978: UNROLL_LOOP MMOV_FIRST_2_WIDE_ROTATED_NEED,MF2WRN,LOOP_UNROLL_COUNT
979: dec ebx
980: jnz mov_first_2_wide_rotated_need_loop
981: jmp pGlyphLoop
982:
983: ;-----------------------------------------------------------------------;
984: ; OR first byte, 2 bytes wide dest, rotated, don't need final source byte.
985: ;-----------------------------------------------------------------------;
986: or_first_2_wide_rotated_no_last:
987: SET_UP_UNROLL_AND_BRANCH ebx,eax,or_first_2_wide_rotated_table, \
988: LOOP_UNROLL_SHIFT
989:
990: UNROLL_LOOP_ENTRY_TABLE or_first_2_wide_rotated_table,OF2WR, \
991: LOOP_UNROLL_COUNT
992:
993: MOR_FIRST_2_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
994: &ENTRY_LABEL&ENTRY_INDEX&:
995: sub eax,eax
996: mov ah,[esi]
997: inc esi
998: shr eax,cl
999: or [edi],ah
1000: mov [edi+1],al
1001: add edi,edx
1002: endm ;-----------------------------------;
1003:
1004: or_first_2_wide_rotated_loop:
1005: UNROLL_LOOP MOR_FIRST_2_WIDE_ROTATED,OF2WR,LOOP_UNROLL_COUNT
1006: dec ebx
1007: jnz or_first_2_wide_rotated_loop
1008: jmp pGlyphLoop
1009:
1010: ;-----------------------------------------------------------------------;
1011: ; OR all bytes, 2 bytes wide dest, rotated, don't need final source byte.
1012: ;-----------------------------------------------------------------------;
1013: or_all_2_wide_rotated_no_last:
1014: SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_2_wide_rotated_table, \
1015: LOOP_UNROLL_SHIFT
1016:
1017: UNROLL_LOOP_ENTRY_TABLE or_all_2_wide_rotated_table,OA2WR, \
1018: LOOP_UNROLL_COUNT
1019:
1020: MOR_ALL_2_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
1021: &ENTRY_LABEL&ENTRY_INDEX&:
1022: sub eax,eax
1023: mov al,[esi]
1024: inc esi
1025: ror ax,cl
1026: or [edi],ax
1027: add edi,edx
1028: endm ;-----------------------------------;
1029:
1030: or_all_2_wide_rotated_loop:
1031: UNROLL_LOOP MOR_ALL_2_WIDE_ROTATED,OA2WR,LOOP_UNROLL_COUNT
1032: dec ebx
1033: jnz or_all_2_wide_rotated_loop
1034: jmp pGlyphLoop
1035:
1036: ;-----------------------------------------------------------------------;
1037: ; MOV first byte, 2 bytes wide dest, rotated, don't need final source byte.
1038: ;-----------------------------------------------------------------------;
1039: mov_first_2_wide_rotated_no_last:
1040: SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_2_wide_rotated_table, \
1041: LOOP_UNROLL_SHIFT
1042:
1043: UNROLL_LOOP_ENTRY_TABLE mov_first_2_wide_rotated_table,MF2WR, \
1044: LOOP_UNROLL_COUNT
1045:
1046: MMOV_FIRST_2_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
1047: &ENTRY_LABEL&ENTRY_INDEX&:
1048: sub eax,eax
1049: mov al,[esi]
1050: inc esi
1051: ror ax,cl
1052: mov [edi],ax
1053: add edi,edx
1054: endm ;-----------------------------------;
1055:
1056: mov_first_2_wide_rotated_loop:
1057: UNROLL_LOOP MMOV_FIRST_2_WIDE_ROTATED,MF2WR,LOOP_UNROLL_COUNT
1058: dec ebx
1059: jnz mov_first_2_wide_rotated_loop
1060: jmp pGlyphLoop
1061:
1062: ;-----------------------------------------------------------------------;
1063: ; MOV first byte, 2 bytes wide dest, unrotated.
1064: ;-----------------------------------------------------------------------;
1065: mov_first_2_wide_unrotated:
1066: SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_2_wide_unrotated_table, \
1067: LOOP_UNROLL_SHIFT
1068:
1069: UNROLL_LOOP_ENTRY_TABLE mov_first_2_wide_unrotated_table,MF2WU, \
1070: LOOP_UNROLL_COUNT
1071:
1072: MMOV_FIRST_2_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
1073: &ENTRY_LABEL&ENTRY_INDEX&:
1074: mov ax,[esi]
1075: add esi,2
1076: mov [edi],ax
1077: add edi,edx
1078: endm ;-----------------------------------;
1079:
1080: mov_first_2_wide_unrotated_loop:
1081: UNROLL_LOOP MMOV_FIRST_2_WIDE_UNROTATED,MF2WU,LOOP_UNROLL_COUNT
1082: dec ebx
1083: jnz mov_first_2_wide_unrotated_loop
1084: jmp pGlyphLoop
1085:
1086: ;-----------------------------------------------------------------------;
1087: ; OR all bytes, 2 bytes wide dest, unrotated.
1088: ;-----------------------------------------------------------------------;
1089: or_all_2_wide_unrotated:
1090: SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_2_wide_unrotated_table, \
1091: LOOP_UNROLL_SHIFT
1092:
1093: UNROLL_LOOP_ENTRY_TABLE or_all_2_wide_unrotated_table,OA2WU, \
1094: LOOP_UNROLL_COUNT
1095:
1096: MOR_ALL_2_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
1097: &ENTRY_LABEL&ENTRY_INDEX&:
1098: mov ax,[esi]
1099: add esi,2
1100: or [edi],ax
1101: add edi,edx
1102: endm ;-----------------------------------;
1103:
1104: or_all_2_wide_unrotated_loop:
1105: UNROLL_LOOP MOR_ALL_2_WIDE_UNROTATED,OA2WU,LOOP_UNROLL_COUNT
1106: dec ebx
1107: jnz or_all_2_wide_unrotated_loop
1108: jmp pGlyphLoop
1109:
1110: ;-----------------------------------------------------------------------;
1111: ; OR first byte, 3 bytes wide dest, rotated, need final source byte.
1112: ;-----------------------------------------------------------------------;
1113: or_first_3_wide_rotated_need_last:
1114: @@:
1115: mov al,[esi]
1116: shr al,cl
1117: or [edi],al
1118: mov ax,[esi]
1119: ror ax,cl
1120: mov [edi+1],ah
1121: mov ax,[esi+1]
1122: add esi,3
1123: ror ax,cl
1124: mov [edi+2],ah
1125: add edi,edx
1126: dec ebx
1127: jnz @B
1128: jmp pGlyphLoop
1129:
1130: ;-----------------------------------------------------------------------;
1131: ; OR first byte, 3 bytes wide dest, rotated, need final source byte.
1132: ;-----------------------------------------------------------------------;
1133: or_all_3_wide_rotated_need_last:
1134: @@:
1135: mov al,[esi]
1136: shr al,cl
1137: or [edi],al
1138: mov ax,[esi]
1139: ror ax,cl
1140: or [edi+1],ah
1141: mov ax,[esi+1]
1142: add esi,3
1143: ror ax,cl
1144: or [edi+2],ah
1145: add edi,edx
1146: dec ebx
1147: jnz @B
1148: jmp pGlyphLoop
1149:
1150: ;-----------------------------------------------------------------------;
1151: ; MOV first byte, 3 bytes wide dest, rotated, need final source byte.
1152: ;-----------------------------------------------------------------------;
1153: mov_first_3_wide_rotated_need_last:
1154: @@:
1155: mov al,[esi]
1156: shr al,cl
1157: mov [edi],al
1158: mov ax,[esi]
1159: ror ax,cl
1160: mov [edi+1],ah
1161: mov ax,[esi+1]
1162: add esi,3
1163: ror ax,cl
1164: mov [edi+2],ah
1165: add edi,edx
1166: dec ebx
1167: jnz @B
1168: jmp pGlyphLoop
1169:
1170: ;-----------------------------------------------------------------------;
1171: ; OR first byte, 3 bytes wide dest, rotated, don't need final source byte.
1172: ;-----------------------------------------------------------------------;
1173: or_first_3_wide_rotated_no_last:
1174: neg cl
1175: and cl,111b ;convert from right shift to left shift
1176: @@:
1177: sub eax,eax
1178: mov ax,[esi]
1179: add esi,2
1180: xchg ah,al
1181: shl eax,cl
1182: mov [edi+1],ah
1183: mov [edi+2],al
1184: shr eax,16
1185: or [edi],al
1186: add edi,edx
1187: dec ebx
1188: jnz @B
1189: jmp pGlyphLoop
1190:
1191: ;-----------------------------------------------------------------------;
1192: ; OR all bytes, 3 bytes wide dest, rotated, don't need final source byte.
1193: ;-----------------------------------------------------------------------;
1194: or_all_3_wide_rotated_no_last:
1195: neg cl
1196: and cl,111b ;convert from right shift to left shift
1197: @@:
1198: sub eax,eax
1199: mov ax,[esi]
1200: add esi,2
1201: xchg ah,al
1202: shl eax,cl
1203: xchg ah,al
1204: or [edi+1],ax
1205: shr eax,16
1206: or [edi],al
1207: add edi,edx
1208: dec ebx
1209: jnz @B
1210: jmp pGlyphLoop
1211:
1212: ;-----------------------------------------------------------------------;
1213: ; MOV first byte, 3 bytes wide dest, rotated, don't need final source byte.
1214: ;-----------------------------------------------------------------------;
1215: mov_first_3_wide_rotated_no_last:
1216: neg cl
1217: and cl,111b ;convert from right shift to left shift
1218: @@:
1219: sub eax,eax
1220: mov ax,[esi]
1221: add esi,2
1222: xchg ah,al
1223: shl eax,cl
1224: mov [edi+1],ah
1225: mov [edi+2],al
1226: shr eax,16
1227: mov [edi],al
1228: add edi,edx
1229: dec ebx
1230: jnz @B
1231: jmp pGlyphLoop
1232:
1233: ;-----------------------------------------------------------------------;
1234: ; MOV first byte, 3 bytes wide dest, unrotated.
1235: ;-----------------------------------------------------------------------;
1236: mov_first_3_wide_unrotated:
1237: @@:
1238: mov ax,[esi]
1239: mov [edi],ax
1240: mov al,[esi+2]
1241: add esi,3
1242: mov [edi+2],al
1243: add edi,edx
1244: dec ebx
1245: jnz @B
1246: jmp pGlyphLoop
1247:
1248: ;-----------------------------------------------------------------------;
1249: ; OR all bytes, 3 bytes wide dest, unrotated.
1250: ;-----------------------------------------------------------------------;
1251: or_all_3_wide_unrotated:
1252: @@:
1253: mov ax,[esi]
1254: or [edi],ax
1255: mov al,[esi+2]
1256: add esi,3
1257: or [edi+2],al
1258: add edi,edx
1259: dec ebx
1260: jnz @B
1261: jmp pGlyphLoop
1262:
1263: ;-----------------------------------------------------------------------;
1264: ; OR first byte, 4 bytes wide dest, rotated, need final source byte.
1265: ;-----------------------------------------------------------------------;
1266: or_first_4_wide_rotated_need_last:
1267: @@:
1268: mov eax,[esi]
1269: add esi,4
1270: xchg ah,al
1271: ror eax,16
1272: xchg ah,al
1273: shr eax,cl
1274: xchg ah,al
1275: mov [edi+2],ax
1276: shr eax,16
1277: mov [edi+1],al
1278: or [edi],ah
1279: add edi,edx
1280: dec ebx
1281: jnz @B
1282: jmp pGlyphLoop
1283:
1284: ;-----------------------------------------------------------------------;
1285: ; OR all bytes, 4 bytes wide dest, rotated, need final source byte.
1286: ;-----------------------------------------------------------------------;
1287: or_all_4_wide_rotated_need_last:
1288: @@:
1289: mov eax,[esi]
1290: add esi,4
1291: xchg ah,al
1292: ror eax,16
1293: xchg ah,al
1294: shr eax,cl
1295: xchg ah,al
1296: ror eax,16
1297: xchg al,ah
1298: or [edi],eax
1299: add edi,edx
1300: dec ebx
1301: jnz @B
1302: jmp pGlyphLoop
1303:
1304: ;-----------------------------------------------------------------------;
1305: ; MOV first byte, 4 bytes wide dest, rotated, need final source byte.
1306: ;-----------------------------------------------------------------------;
1307: mov_first_4_wide_rotated_need_last:
1308: @@:
1309: mov eax,[esi]
1310: add esi,4
1311: xchg ah,al
1312: ror eax,16
1313: xchg ah,al
1314: shr eax,cl
1315: xchg ah,al
1316: ror eax,16
1317: xchg ah,al
1318: mov [edi],eax
1319: add edi,edx
1320: dec ebx
1321: jnz @B
1322: jmp pGlyphLoop
1323:
1324: ;-----------------------------------------------------------------------;
1325: ; OR first byte, 4 bytes wide dest, rotated, don't need final source byte.
1326: ;-----------------------------------------------------------------------;
1327: or_first_4_wide_rotated_no_last:
1328: @@:
1329: mov ax,[esi]
1330: xchg ah,al
1331: shl eax,16
1332: mov ah,[esi+2]
1333: add esi,3
1334: shr eax,cl
1335: xchg ah,al
1336: mov [edi+2],ax
1337: shr eax,16
1338: mov [edi+1],al
1339: or [edi],ah
1340: add edi,edx
1341: dec ebx
1342: jnz @B
1343: jmp pGlyphLoop
1344:
1345: ;-----------------------------------------------------------------------;
1346: ; OR all bytes, 4 bytes wide dest, rotated, don't need final source byte.
1347: ;-----------------------------------------------------------------------;
1348: or_all_4_wide_rotated_no_last:
1349: @@:
1350: mov ax,[esi]
1351: xchg ah,al
1352: shl eax,16
1353: mov ah,[esi+2]
1354: add esi,3
1355: shr eax,cl
1356: xchg ah,al
1357: ror eax,16
1358: xchg ah,al
1359: or [edi],eax
1360: add edi,edx
1361: dec ebx
1362: jnz @B
1363: jmp pGlyphLoop
1364:
1365: ;-----------------------------------------------------------------------;
1366: ; MOV first byte, 4 bytes wide dest, rotated, don't need final source byte.
1367: ;-----------------------------------------------------------------------;
1368: mov_first_4_wide_rotated_no_last:
1369: @@:
1370: mov ax,[esi]
1371: xchg ah,al
1372: shl eax,16
1373: mov ah,[esi+2]
1374: add esi,3
1375: shr eax,cl
1376: xchg ah,al
1377: ror eax,16
1378: xchg ah,al
1379: mov [edi],eax
1380: add edi,edx
1381: dec ebx
1382: jnz @B
1383: jmp pGlyphLoop
1384:
1385: ;-----------------------------------------------------------------------;
1386: ; MOV first byte, 4 bytes wide dest, unrotated.
1387: ;-----------------------------------------------------------------------;
1388: mov_first_4_wide_unrotated:
1389: @@:
1390: mov eax,[esi]
1391: add esi,4
1392: mov [edi],eax
1393: add edi,edx
1394: dec ebx
1395: jnz @B
1396: jmp pGlyphLoop
1397:
1398: ;-----------------------------------------------------------------------;
1399: ; OR all bytes, 4 bytes wide dest, unrotated.
1400: ;-----------------------------------------------------------------------;
1401: or_all_4_wide_unrotated:
1402: @@:
1403: mov eax,[esi]
1404: add esi,4
1405: or [edi],eax
1406: add edi,edx
1407: dec ebx
1408: jnz @B
1409: jmp pGlyphLoop
1410:
1411: ;-----------------------------------------------------------------------;
1412: ; OR first byte, n bytes wide dest, rotated, need final source byte.
1413: ;-----------------------------------------------------------------------;
1414: or_first_N_wide_rotated_need_last:
1415: mov eax,ulWidthInBytes
1416: mov edx,ulBufDelta
1417: sub edx,eax
1418: mov ulTmpDstDelta,edx
1419: dec eax ;source doesn't advance after first byte, and
1420: ; we do the first byte outside the loop
1421: mov edx,ulGlyDelta
1422: sub edx,eax
1423: mov ulTmpSrcDelta,edx
1424: mov ulTmpWidthInBytes,eax
1425: ofNwrnl_scan_loop:
1426: mov al,[esi] ;do the initial, ORed byte separately
1427: shr al,cl
1428: or [edi],al
1429: inc edi
1430: mov edx,ulTmpWidthInBytes
1431: @@:
1432: mov ax,[esi]
1433: inc esi
1434: ror ax,cl
1435: mov [edi],ah
1436: inc edi
1437: dec edx
1438: jnz @B
1439: add esi,ulTmpSrcDelta
1440: add edi,ulTmpDstDelta
1441: dec ebx
1442: jnz ofNwrnl_scan_loop
1443: jmp pGlyphLoop
1444:
1445: ;-----------------------------------------------------------------------;
1446: ; OR all bytes, n bytes wide dest, rotated, need final source byte.
1447: ;-----------------------------------------------------------------------;
1448: or_all_N_wide_rotated_need_last:
1449: mov eax,ulWidthInBytes
1450: mov edx,ulBufDelta
1451: sub edx,eax
1452: mov ulTmpDstDelta,edx
1453: dec eax ;source doesn't advance after first byte, and
1454: ; we do the first byte outside the loop
1455: mov edx,ulGlyDelta
1456: sub edx,eax
1457: mov ulTmpSrcDelta,edx
1458: mov ulTmpWidthInBytes,eax
1459: oaNwrnl_scan_loop:
1460: mov al,[esi] ;do the initial, ORed byte separately
1461: shr al,cl
1462: or [edi],al
1463: inc edi
1464: mov edx,ulTmpWidthInBytes
1465: @@:
1466: mov ax,[esi]
1467: inc esi
1468: ror ax,cl
1469: or [edi],ah
1470: inc edi
1471: dec edx
1472: jnz @B
1473: add esi,ulTmpSrcDelta
1474: add edi,ulTmpDstDelta
1475: dec ebx
1476: jnz oaNwrnl_scan_loop
1477: jmp pGlyphLoop
1478:
1479: ;-----------------------------------------------------------------------;
1480: ; MOV first byte, n bytes wide dest, rotated, need final source byte.
1481: ;-----------------------------------------------------------------------;
1482: mov_first_N_wide_rotated_need_last:
1483: mov eax,ulWidthInBytes
1484: mov edx,ulBufDelta
1485: sub edx,eax
1486: mov ulTmpDstDelta,edx
1487: mov eax,ulWidthInBytes
1488: dec eax ;source doesn't advance after first byte, and
1489: ; we do the first byte outside the loop
1490: mov edx,ulGlyDelta
1491: sub edx,eax
1492: mov ulTmpSrcDelta,edx
1493: mov ulTmpWidthInBytes,eax
1494: mfNwrnl_scan_loop:
1495: mov al,[esi] ;do the initial byte separately
1496: shr al,cl
1497: mov [edi],al
1498: inc edi
1499: mov edx,ulTmpWidthInBytes
1500: @@:
1501: mov ax,[esi]
1502: inc esi
1503: ror ax,cl
1504: mov [edi],ah
1505: inc edi
1506: dec edx
1507: jnz @B
1508: add esi,ulTmpSrcDelta
1509: add edi,ulTmpDstDelta
1510: dec ebx
1511: jnz mfNwrnl_scan_loop
1512: jmp pGlyphLoop
1513:
1514: ;-----------------------------------------------------------------------;
1515: ; OR first byte, N bytes wide dest, rotated, don't need final source byte.
1516: ;-----------------------------------------------------------------------;
1517: or_first_N_wide_rotated_no_last:
1518: mov eax,ulWidthInBytes
1519: dec eax ;one less because we don't advance after the
1520: ; last byte
1521: mov edx,ulBufDelta
1522: sub edx,eax
1523: mov ulTmpDstDelta,edx
1524: dec eax ;source doesn't advance after first byte, and
1525: ; we do the first & last bytes outside the
1526: ; loop; already subtracted 1 above
1527: mov edx,ulGlyDelta
1528: sub edx,eax
1529: mov ulTmpSrcDelta,edx
1530: mov ulTmpWidthInBytes,eax
1531: ofNwr_scan_loop:
1532: mov al,[esi] ;do the initial, ORed byte separately
1533: shr al,cl
1534: or [edi],al
1535: inc edi
1536: mov edx,ulTmpWidthInBytes
1537: @@:
1538: mov ax,[esi]
1539: inc esi
1540: ror ax,cl
1541: mov [edi],ah
1542: inc edi
1543: dec edx
1544: jnz @B
1545:
1546: mov ah,[esi] ;do the final byte separately
1547: sub al,al
1548: shr eax,cl
1549: mov [edi],al
1550:
1551: add esi,ulTmpSrcDelta
1552: add edi,ulTmpDstDelta
1553: dec ebx
1554: jnz ofNwr_scan_loop
1555: jmp pGlyphLoop
1556:
1557: ;-----------------------------------------------------------------------;
1558: ; OR all bytes, N bytes wide dest, rotated, don't need final source byte.
1559: ;-----------------------------------------------------------------------;
1560: or_all_N_wide_rotated_no_last:
1561: mov eax,ulWidthInBytes
1562: dec eax ;one less because we don't advance after the
1563: ; last byte
1564: mov edx,ulBufDelta
1565: sub edx,eax
1566: mov ulTmpDstDelta,edx
1567: dec eax ;source doesn't advance after first byte, and
1568: ; we do the first & last bytes outside the
1569: ; loop; already subtracted 1 above
1570: mov edx,ulGlyDelta
1571: sub edx,eax
1572: mov ulTmpSrcDelta,edx
1573: mov ulTmpWidthInBytes,eax
1574: oaNwr_scan_loop:
1575: mov al,[esi] ;do the initial, ORed byte separately
1576: shr al,cl
1577: or [edi],al
1578: inc edi
1579: mov edx,ulTmpWidthInBytes
1580: @@:
1581: mov ax,[esi]
1582: inc esi
1583: ror ax,cl
1584: or [edi],ah
1585: inc edi
1586: dec edx
1587: jnz @B
1588:
1589: mov ah,[esi] ;do the final byte separately
1590: sub al,al
1591: shr eax,cl
1592: or [edi],al
1593:
1594: add esi,ulTmpSrcDelta
1595: add edi,ulTmpDstDelta
1596: dec ebx
1597: jnz oaNwr_scan_loop
1598: jmp pGlyphLoop
1599:
1600: ;-----------------------------------------------------------------------;
1601: ; MOV first byte, N bytes wide dest, rotated, don't need final source byte.
1602: ;-----------------------------------------------------------------------;
1603: mov_first_N_wide_rotated_no_last:
1604: mov eax,ulWidthInBytes
1605: dec eax ;one less because we don't advance after the
1606: ; last byte
1607: mov edx,ulBufDelta
1608: sub edx,eax
1609: mov ulTmpDstDelta,edx
1610: dec eax ;source doesn't advance after first byte, and
1611: ; we do the first & last bytes outside the
1612: ; loop; already subtracted 1 above
1613: mov edx,ulGlyDelta
1614: sub edx,eax
1615: mov ulTmpSrcDelta,edx
1616: mov ulTmpWidthInBytes,eax
1617: mfNwr_scan_loop:
1618: mov al,[esi] ;do the initial byte separately
1619: shr al,cl
1620: mov [edi],al
1621: inc edi
1622: mov edx,ulTmpWidthInBytes
1623: @@:
1624: mov ax,[esi]
1625: inc esi
1626: ror ax,cl
1627: mov [edi],ah
1628: inc edi
1629: dec edx
1630: jnz @B
1631:
1632: mov ah,[esi] ;do the final byte separately
1633: sub al,al
1634: shr eax,cl
1635: mov [edi],al
1636:
1637: add esi,ulTmpSrcDelta
1638: add edi,ulTmpDstDelta
1639: dec ebx
1640: jnz mfNwr_scan_loop
1641: jmp pGlyphLoop
1642:
1643: ;-----------------------------------------------------------------------;
1644: ; MOV first byte, N bytes wide dest, unrotated.
1645: ;-----------------------------------------------------------------------;
1646: mov_first_N_wide_unrotated:
1647: mov edx,ulBufDelta
1648: mov eax,ulWidthInBytes
1649: sub edx,eax
1650: shr eax,1 ;width in words
1651: jc short odd_width ;there's at least one odd byte
1652: shr eax,1 ;width in dwords
1653: jc short two_odd_bytes ;there's an odd word
1654: ;copy width is a dword multiple
1655: @@:
1656: mov ecx,eax
1657: rep movsd ;copy as many dwords as possible
1658: add edi,edx
1659: dec ebx
1660: jnz @B
1661: jmp pGlyphLoop
1662:
1663: odd_width:
1664: shr eax,1 ;width in dwords
1665: jc short three_odd_bytes ;there's an odd word and an odd byte
1666: ;there's just an odd byte
1667: inc edx ;because we won't advance after last byte
1668: @@:
1669: mov ecx,eax
1670: rep movsd ;copy as many dwords as possible
1671: mov cl,[esi]
1672: inc esi
1673: mov [edi],cl
1674: add edi,edx
1675: dec ebx
1676: jnz @B
1677: jmp pGlyphLoop
1678:
1679: two_odd_bytes:
1680: add edx,2 ;because we won't advance after last word
1681: @@:
1682: mov ecx,eax
1683: rep movsd ;copy as many dwords as possible
1684: mov cx,[esi]
1685: add esi,2
1686: mov [edi],cx
1687: add edi,edx
1688: dec ebx
1689: jnz @B
1690: jmp pGlyphLoop
1691:
1692: three_odd_bytes:
1693: add edx,3 ;because we won't advance after last word/byte
1694: @@:
1695: mov ecx,eax
1696: rep movsd ;copy as many dwords as possible
1697: mov cx,[esi]
1698: mov [edi],cx
1699: mov cl,[esi+2]
1700: add esi,3
1701: mov [edi+2],cl
1702: add edi,edx
1703: dec ebx
1704: jnz @B
1705: jmp pGlyphLoop
1706:
1707: ;-----------------------------------------------------------------------;
1708: ; OR all bytes, N bytes wide dest, unrotated.
1709: ;-----------------------------------------------------------------------;
1710: or_all_N_wide_unrotated:
1711: mov edx,ulBufDelta
1712: mov eax,ulWidthInBytes
1713: sub edx,eax
1714: shr eax,1 ;width in words
1715: jc short or_odd_width ;there's at least one odd byte
1716: shr eax,1 ;width in dwords
1717: jc short or_two_odd_bytes ;there's an odd word
1718: ;copy width is a dword multiple
1719: or_no_odd_bytes_loop:
1720: push ebx ;preserve scan count
1721: mov ebx,eax
1722: @@:
1723: mov ecx,[esi]
1724: add esi,4
1725: or [edi],ecx
1726: add edi,4 ;copy as many dwords as possible
1727: dec ebx
1728: jnz @B
1729: add edi,edx
1730: pop ebx ;restore scan count
1731: dec ebx
1732: jnz or_no_odd_bytes_loop
1733: jmp pGlyphLoop
1734:
1735: or_odd_width:
1736: shr eax,1 ;width in dwords
1737: jc short three_odd_bytes ;there's an odd word and an odd byte
1738: ;there's just an odd byte
1739: inc edx ;skip over last byte too
1740: or_one_odd_bytes_loop:
1741: push ebx ;preserve scan count
1742: mov ebx,eax
1743: @@:
1744: mov ecx,[esi]
1745: add esi,4
1746: or [edi],ecx
1747: add edi,4 ;copy as many dwords as possible
1748: dec ebx
1749: jnz @B
1750: mov cl,[esi]
1751: or [edi],cl
1752: inc esi
1753: add edi,edx
1754: pop ebx ;restore scan count
1755: dec ebx
1756: jnz or_one_odd_bytes_loop
1757: jmp pGlyphLoop
1758:
1759: or_two_odd_bytes:
1760: add edx,2 ;skip over last 2 bytes too
1761: or_two_odd_bytes_loop:
1762: push ebx ;preserve scan count
1763: mov ebx,eax
1764: @@:
1765: mov ecx,[esi]
1766: add esi,4
1767: or [edi],ecx
1768: add edi,4 ;copy as many dwords as possible
1769: dec ebx
1770: jnz @B
1771: mov cx,[esi]
1772: or [edi],cx
1773: add esi,2
1774: add edi,edx
1775: pop ebx ;restore scan count
1776: dec ebx
1777: jnz or_two_odd_bytes_loop
1778: jmp pGlyphLoop
1779:
1780: or_three_odd_bytes:
1781: add edx,3 ;skip over last 3 bytes too
1782: or_three_odd_bytes_loop:
1783: push ebx ;preserve scan count
1784: mov ebx,eax
1785: @@:
1786: mov ecx,[esi]
1787: add esi,4
1788: or [edi],ecx
1789: add edi,4 ;copy as many dwords as possible
1790: dec ebx
1791: jnz @B
1792: mov cx,[esi]
1793: or [edi],cx
1794: mov cl,[esi+2]
1795: or [edi+2],cl
1796: add esi,3
1797: add edi,edx
1798: pop ebx ;restore scan count
1799: dec ebx
1800: jnz or_three_odd_bytes_loop
1801: jmp pGlyphLoop
1802:
1803: ;-----------------------------------------------------------------------;
1804: ; At this point, the text is drawn to the temp buffer.
1805: ; Now, draw the temp buffer to the screen.
1806: ;
1807: ; Input:
1808: ; pdsurf = pointer to target surface (screen)
1809: ; prclText = pointer to text bounding rectangle
1810: ; prclOpaque = pointer to opaquing rectangle, if there is one
1811: ; iFgColor = text color
1812: ; iBgColor = opaquing rectangle color, if there is one
1813: ; ulTempLeft = X coordinate on dest of left edge of temp buffer pointed
1814: ; to by pTempBuffer
1815: ; pTempBuffer = pointer to first byte (upper left corner) of
1816: ; temp buffer into which we're drawing. This should be
1817: ; word-aligned with the destination
1818: ; ulBufDelta = destination scan-to-scan offset
1819: ; Text drawn to temp buffer
1820: ;
1821: ;-----------------------------------------------------------------------;
1822: draw_to_screen:
1823:
1824: ;-----------------------------------------------------------------------;
1825: ; Is this transparent or opaque text?
1826: ;-----------------------------------------------------------------------;
1827:
1828: mov esi,prclText
1829: cmp prclOpaque,0
1830: jnz opaque_text
1831:
1832: ;-----------------------------------------------------------------------;
1833: ; Transparent text.
1834: ; ESI = prclText
1835: ;-----------------------------------------------------------------------;
1836:
1837: ;-----------------------------------------------------------------------;
1838: ; Set up the VGA's hardware for read mode 1 and write mode 3.
1839: ;-----------------------------------------------------------------------;
1840:
1841: mov edx,VGA_BASE + GRAF_ADDR
1842: mov eax,GRAF_MODE + ((M_AND_WRITE + M_COLOR_READ) SHL 8)
1843: out dx,ax ;write mode 3 so we can do masking
1844: ; without OUTs, read mode 1 so we can
1845: ; read 0xFF from memory always, for
1846: ; ANDing (because Color Don't Care is
1847: ; all zeros)
1848:
1849: mov al,GRAF_SET_RESET
1850: mov ah,byte ptr iFgColor
1851: out dx,ax ;set the drawing color
1852:
1853: ;-----------------------------------------------------------------------;
1854: ; Calculate drawing parameters.
1855: ;-----------------------------------------------------------------------;
1856:
1857: mov eax,[esi].yBottom
1858: mov ulBottomScan,eax ;bottom scan of text area
1859: mov eax,[esi].xRight
1860: mov edx,[esi].xLeft
1861: and edx,not 7
1862: add eax,7
1863: sub eax,edx
1864: shr eax,3 ;width of text in bytes, rounded up
1865:
1866: mov edx,eax ;width in bytes
1867: mov ecx,eax
1868: and edx,7 ;# of odd (non-qword) bytes
1869: mov edi,XparEntryTable[edx*4]
1870: mov pfnEntry,edi ;entry point into unrolled loop for odd bytes
1871: add ecx,7
1872: shr ecx,3 ;width in qwords (unrolled loop count)
1873: mov ulLoopCount,ecx
1874:
1875: neg edx ;amount by which we have to compensate back
1876: and edx,07h ; before starting, because of the hard-wired
1877: ; displacements used in the unrolled loop
1878:
1879: add eax,edx ;adjust effective width for compensation
1880:
1881: mov ecx,ulBufDelta
1882: sub ecx,eax ;offset to next scan in temp buffer
1883: mov ulTmpSrcDelta,ecx
1884:
1885: mov ebx,pdsurf
1886: mov ecx,ulScreenDelta
1887: sub ecx,eax ;offset to next scan in screen
1888: mov ulTmpDstDelta,ecx
1889:
1890: mov eax,[esi].yTop
1891: imul eax,ulScreenDelta ;this form of IMUL so we can avoid wiping
1892: ; out EDX
1893: mov edi,[esi].xLeft
1894: shr edi,3
1895: add edi,eax
1896: sub edi,edx ;compensate back for displacement of initial
1897: ; entry point into unrolled loop, below
1898:
1899: ;-----------------------------------------------------------------------;
1900: ; Map in the bank containing the top scan of the text, if it's not
1901: ; mapped in already.
1902: ;-----------------------------------------------------------------------;
1903:
1904: mov eax,[esi].yTop ;top scan line of text
1905: mov ulTopScan,eax
1906: mov esi,pTempBuffer ;initial source address
1907: sub esi,edx ;compensate back for displacement of initial
1908: ; entry point into unrolled loop, below
1909: cmp eax,[ebx].dsurf_rcl1WindowClip.yTop ;is text top less than
1910: ; current bank?
1911: jl short xpar_map_init_bank ;yes, map in proper bank
1912: cmp eax,[ebx].dsurf_rcl1WindowClip.yBottom ;text top greater than
1913: ; current bank?
1914: jl short xpar_init_bank_mapped ;no, proper bank already mapped
1915: xpar_map_init_bank:
1916:
1917: ; Map in the bank containing the top scan line of the fill.
1918: ; Preserves EBX, ESI, and EDI.
1919:
1920: ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,eax,JustifyTop>
1921:
1922: xpar_init_bank_mapped:
1923:
1924: add edi,[ebx].dsurf_pvBitmapStart ;initial destination address
1925:
1926: ;-----------------------------------------------------------------------;
1927: ; Main loop for processing fill in each bank.
1928: ;
1929: ; At start of loop, EBX->pdsurf
1930: ;-----------------------------------------------------------------------;
1931:
1932: xpar_bank_loop:
1933: mov edx,ulBottomScan ;bottom of destination rectangle
1934: cmp edx,[ebx].dsurf_rcl1WindowClip.yBottom
1935: ;which comes first, the bottom of the
1936: ; text rect or the bottom of the
1937: ; current bank?
1938: jl short @F ;text bottom comes first, so draw to
1939: ; that; this is the last bank in text
1940: mov edx,[ebx].dsurf_rcl1WindowClip.yBottom
1941: ;bank bottom comes first; draw to
1942: ; bottom of bank
1943: @@:
1944: sub edx,ulTopScan ;# of scans to draw in bank
1945: mov ebx,ulTmpSrcDelta
1946:
1947: xpar_scan_loop:
1948: mov ecx,ulLoopCount ;unrolled loop count
1949: jmp pfnEntry ;jump into the unrolled loop
1950:
1951: ;-----------------------------------------------------------------------
1952: ; Entry points into unrolled xpar loop for various odd byte counts.
1953: align 4
1954: XparEntryTable label dword
1955: dd xpar_enter_8
1956: dd xpar_enter_1
1957: dd xpar_enter_2
1958: dd xpar_enter_3
1959: dd xpar_enter_4
1960: dd xpar_enter_5
1961: dd xpar_enter_6
1962: dd xpar_enter_7
1963:
1964: ;-----------------------------------------------------------------------
1965: ; Unrolled xpar loop.
1966: xpar_byte_loop:
1967: xpar_enter_8:
1968: mov al,[esi] ;get next temp buffer byte
1969: and al,al ;is it zero?
1970: jz short @F ;yes, skip it
1971: and [edi],al ;draw the byte with transparency
1972: @@:
1973: xpar_enter_7:
1974: mov al,[esi+1] ;get next temp buffer byte
1975: and al,al ;is it zero?
1976: jz short @F ;yes, skip it
1977: and [edi+1],al ;draw the byte with transparency
1978: @@:
1979: xpar_enter_6:
1980: mov al,[esi+2] ;get next temp buffer byte
1981: and al,al ;is it zero?
1982: jz short @F ;yes, skip it
1983: and [edi+2],al ;draw the byte with transparency
1984: @@:
1985: xpar_enter_5:
1986: mov al,[esi+3] ;get next temp buffer byte
1987: and al,al ;is it zero?
1988: jz short @F ;yes, skip it
1989: and [edi+3],al ;draw the byte with transparency
1990: @@:
1991: xpar_enter_4:
1992: mov al,[esi+4] ;get next temp buffer byte
1993: and al,al ;is it zero?
1994: jz short @F ;yes, skip it
1995: and [edi+4],al ;draw the byte with transparency
1996: @@:
1997: xpar_enter_3:
1998: mov al,[esi+5] ;get next temp buffer byte
1999: and al,al ;is it zero?
2000: jz short @F ;yes, skip it
2001: and [edi+5],al ;draw the byte with transparency
2002: @@:
2003: xpar_enter_2:
2004: mov al,[esi+6] ;get next temp buffer byte
2005: and al,al ;is it zero?
2006: jz short @F ;yes, skip it
2007: and [edi+6],al ;draw the byte with transparency
2008: @@:
2009: xpar_enter_1:
2010: mov al,[esi+7] ;get next temp buffer byte
2011: and al,al ;is it zero?
2012: jz short @F ;yes, skip it
2013: and [edi+7],al ;draw the byte with transparency
2014: @@:
2015: add esi,8
2016: add edi,8
2017: dec ecx
2018: jnz xpar_byte_loop
2019:
2020: add esi,ebx ;point to next buffer scan
2021: add edi,ulTmpDstDelta ;point to next screen scan
2022:
2023: dec edx ;count down scans
2024: jnz xpar_scan_loop
2025:
2026: ;-----------------------------------------------------------------------;
2027: ; See if there are more banks to draw.
2028: ;-----------------------------------------------------------------------;
2029:
2030: mov ebx,pdsurf
2031: mov eax,[ebx].dsurf_rcl1WindowClip.yBottom ;is the text bottom in
2032: cmp ulBottomScan,eax ; the current bank?
2033: jnle short do_next_xpar_bank ;no, map in the next bank and draw
2034: ;yes, so we're done
2035:
2036: ;-----------------------------------------------------------------------;
2037: ; Restore the VGA's hardware state and we're done.
2038: ;-----------------------------------------------------------------------;
2039:
2040: mov edx,VGA_BASE + GRAF_ADDR
2041: mov eax,GRAF_MODE + ((M_PROC_WRITE + M_DATA_READ) SHL 8)
2042: out dx,ax ;restore read mode 0 and write mode 0
2043:
2044: draw_prop_done:
2045: cRet vFastText
2046:
2047: do_next_xpar_bank:
2048: mov ulTopScan,eax
2049: sub edi,[ebx].dsurf_pvBitmapStart ;convert from address to offset
2050: ; within bitmap
2051: ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,eax,JustifyTop>
2052: ;map in the bank (call preserves EBX,
2053: ; ESI, and EDI)
2054: add edi,[ebx].dsurf_pvBitmapStart ;convert from offset within
2055: ; bitmap to address (bitmap start
2056: ; just moved)
2057: jmp xpar_bank_loop ;we're ready to draw in the new bank
2058:
2059: ;-----------------------------------------------------------------------;
2060: ; Handle opaque clipping.
2061: ;-----------------------------------------------------------------------;
2062:
2063: do_opaque_clip:
2064: mov ebx,[esi].yBottom
2065: cmp [edi].yBottom,ebx ;is the bottom edge of the text box clipped?
2066: jg short @F ;no
2067: mov ebx,[edi].yBottom ;yes
2068: @@:
2069: mov dword ptr rclClippedBounds.yBottom,ebx ;set the (possibly
2070: ; clipped) bottom edge
2071: mov eax,[esi].yTop
2072: cmp [edi].yTop,eax ;is the top edge of the text box clipped?
2073: jle short @F ;no
2074: ;yes
2075: sub eax,[edi].yTop
2076: neg eax ;# of scans we just clipped off
2077: mul ulBufDelta ;# of bytes by which to advance through source
2078: add pTempBuffer,eax ;advance in source to account for Y clipping
2079: mov eax,[edi].yTop ;new top edge
2080: @@:
2081: mov dword ptr rclClippedBounds.yTop,eax ;set the (possibly clipped)
2082: ; top edge
2083: cmp eax,ebx ;is there a gap between clipped top & bottom?
2084: jnl short opaq_fully_clipped ;no, fully clipped
2085:
2086: mov edx,[esi].xRight
2087: cmp [edi].xRight,edx ;is the right edge of the text box clipped?
2088: jg short @F ;no
2089: mov edx,[edi].xRight ;yes
2090: @@:
2091: mov dword ptr rclClippedBounds.xRight,edx ;set the (possibly
2092: ; clipped) right edge
2093: mov eax,[esi].xLeft
2094: cmp [edi].xLeft,eax ;is the left edge of the text box clipped?
2095: jle short @F ;no
2096: ;yes
2097: mov ebx,[edi].xLeft ;EBX = new left edge
2098: and eax,not 0111b ;floor the old left edge in its byte
2099: sub ebx,eax
2100: shr ebx,3 ;# of bytes to advance in source
2101: add pTempBuffer,ebx ;advance in source to account for X clipping
2102: mov eax,[edi].xLeft ;new left edge
2103: @@:
2104: mov dword ptr rclClippedBounds.xLeft,eax ;set the (possibly
2105: ; clipped) left edge
2106: cmp eax,edx ;is there a gap between clipped left & right?
2107: jnl short opaq_fully_clipped ;no, fully clipped
2108:
2109: lea esi,rclClippedBounds ;this is now the destination rect
2110: jmp short clip_set
2111:
2112: opaq_fully_clipped:
2113: jmp done
2114:
2115: ;-----------------------------------------------------------------------;
2116: ; Opaque text.
2117: ; ESI = prclText
2118: ;-----------------------------------------------------------------------;
2119:
2120: opaque_text:
2121:
2122: ;-----------------------------------------------------------------------;
2123: ; Clip to the clip rectangle, if necessary.
2124: ;-----------------------------------------------------------------------;
2125:
2126: mov edi,prclClip
2127: and edi,edi ;is there clipping?
2128: jnz short do_opaque_clip ;yes
2129:
2130: ; ESI->destination text rectangle at this point
2131: clip_set:
2132:
2133: ;-----------------------------------------------------------------------;
2134: ; Set up the VGA's hardware for read mode 1 and write mode 3.
2135: ;-----------------------------------------------------------------------;
2136:
2137: mov edx,VGA_BASE + GRAF_ADDR
2138: mov eax,GRAF_MODE + ((M_AND_WRITE + M_COLOR_READ) SHL 8)
2139: out dx,ax ;write mode 3 so we can do masking
2140: ; without OUTs, read mode 1 so we can
2141: ; read 0xFF from memory always, for
2142: ; ANDing (because Color Don't Care is
2143: ; all zeros)
2144:
2145: ;-----------------------------------------------------------------------;
2146: ; Calculate the drawing parameters.
2147: ;-----------------------------------------------------------------------;
2148:
2149: mov eax,[esi].yBottom
2150: mov ulBottomScan,eax ;bottom scan of text area
2151: mov eax,[esi].xRight
2152: mov ebx,eax
2153: and ebx,111b
2154: mov edx,[esi].xLeft
2155: mov ch,jOpaqueRightMasks[ebx] ;set right edge clip mask
2156: mov ebx,edx
2157: and ebx,111b
2158: mov ulRightMask,ecx ;mask is expected to be in CH
2159: mov ch,jOpaqueLeftMasks[ebx] ;set left edge clip mask
2160: mov ulLeftMask,ecx ;mask is expected to be in CH
2161:
2162: mov ulTextLeft,edx
2163: and edx,not 7
2164: add eax,7
2165: sub eax,edx
2166: shr eax,3 ;width of text in bytes, rounded up
2167: mov ulTextWidthInBytes,eax
2168:
2169: ;-----------------------------------------------------------------------;
2170: ; Figure out what edges we need to handle, and calculate some info for
2171: ; doing whole bytes.
2172: ;-----------------------------------------------------------------------;
2173:
2174: cmp eax,1 ;only one byte total?
2175: jnz short @F ;no
2176: ;yes, special case
2177: mov ecx,offset opaq_check_more_banks ;assume it's a solid byte
2178: mov ebx,ulLeftMask
2179: and ebx,ulRightMask
2180: cmp bh,0ffh ;solid byte?
2181: jz short opaq_set_edge_vector ;yes, all set
2182: mov ulLeftMask,ebx ;no, draw as a left edge
2183: dec eax ;there are no whole bytes
2184: mov ecx,offset opaq_draw_left_edge_only
2185: jmp short opaq_set_edge_vector ;yes, all set
2186:
2187: @@:
2188: test [esi].xLeft,111b ;is left edge a solid byte?
2189: jz short opaq_left_edge_solid ;yes
2190: dec eax ;no, count off from whole bytes
2191: mov ecx,offset opaq_draw_left_edge_only ;assume right edge is solid
2192: test [esi].xRight,111b ;is right edge a solid byte?
2193: jz short opaq_set_edge_vector ;yes, all set
2194: dec eax ;no, count off from whole bytes
2195: mov ecx,offset opaq_draw_both_edges ;both edges are non-solid
2196: jmp short opaq_set_edge_vector
2197:
2198: opaq_left_edge_solid:
2199: mov ecx,offset opaq_check_more_banks ;assume right edge is solid
2200: test [esi].xRight,111b ;is right edge a solid byte?
2201: jz short opaq_set_edge_vector ;yes, all set
2202: dec eax ;no, count off from whole bytes
2203: mov ecx,offset opaq_draw_right_edge_only ;no, do non-solid right
2204: ; edge
2205: opaq_set_edge_vector:
2206: mov edi,ulBufDelta
2207: sub edi,eax ;whole bytes offset to next scan in temp buffer
2208: mov ulTmpSrcDelta,edi
2209:
2210: mov edi,ulScreenDelta
2211: sub edi,eax ;whole bytes offset to next scan in screen
2212: mov ulTmpDstDelta,edi
2213:
2214: mov pfnEdgeVector,ecx
2215: mov edx,eax
2216: mov pfnFirstOpaqVector,offset opaq_whole_bytes
2217: ;assume there are whole bytes, in which
2218: ; case we'll draw them first, then the
2219: ; edge bytes
2220: sub edi,edi
2221: shr edx,1 ;whole words
2222: mov ulWholeWidthInWords,edx
2223: adc edi,edi ;odd byte status
2224: mov ulOddByte,edi
2225: dec edx ;whole words - 1
2226: mov ulWholeWidthInWordsMinus1,edx
2227: cmp eax,0 ;are there any whole bytes at all?
2228: jg short opaq_edges_set ;yes, we're all set
2229: ;no, set up for edge(s) only
2230: mov pfnFirstOpaqVector,ecx ;the edges are first, because there are
2231: ; no whole bytes
2232:
2233: opaq_edges_set:
2234:
2235: ;-----------------------------------------------------------------------;
2236: ; Determine the screen offset of the first destination byte.
2237: ;-----------------------------------------------------------------------;
2238:
2239: mov eax,[esi].yTop
2240: mov ulTopScan,eax
2241: mov ecx,eax
2242: mul ulScreenDelta
2243: mov edi,[esi].xLeft
2244: shr edi,3
2245: mov ulTempLeft,edi ;remember the offset to the first dest byte
2246: add edi,eax
2247:
2248: ;-----------------------------------------------------------------------;
2249: ; Map in the bank containing the top scan of the text, if it's not
2250: ; mapped in already.
2251: ;-----------------------------------------------------------------------;
2252:
2253: mov ebx,pdsurf
2254: cmp ecx,[ebx].dsurf_rcl1WindowClip.yTop ;is text top less than
2255: ; current bank?
2256: jl short opaq_map_init_bank ;yes, map in proper bank
2257: cmp ecx,[ebx].dsurf_rcl1WindowClip.yBottom ;text top greater than
2258: ; current bank?
2259: jl short opaq_init_bank_mapped ;no, proper bank already mapped
2260: opaq_map_init_bank:
2261:
2262: ; Map in the bank containing the top scan line of the fill.
2263: ; Preserves EBX, ESI, and EDI.
2264:
2265: ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,ecx,JustifyTop>
2266:
2267: opaq_init_bank_mapped:
2268:
2269: add edi,[ebx].dsurf_pvBitmapStart ;initial destination address
2270: mov pScreen,edi
2271:
2272: mov edx,VGA_BASE + GRAF_ADDR
2273: mov al,GRAF_SET_RESET
2274: out dx,al ;leave the GC Index pointing to
2275: ; set/reset
2276:
2277: ;-----------------------------------------------------------------------;
2278: ; Main loop for processing fill in each bank.
2279: ;
2280: ; At start of loop and on each loop, EBX->pdsurf and EDI->first destination
2281: ; byte.
2282: ;-----------------------------------------------------------------------;
2283:
2284: opaq_bank_loop:
2285: mov edx,ulBottomScan ;bottom of destination rectangle
2286: cmp edx,[ebx].dsurf_rcl1WindowClip.yBottom
2287: ;which comes first, the bottom of the
2288: ; text rect or the bottom of the
2289: ; current bank?
2290: jl short @F ;text bottom comes first, so draw to
2291: ; that; this is the last bank in text
2292: mov edx,[ebx].dsurf_rcl1WindowClip.yBottom
2293: ;bank bottom comes first; draw to
2294: ; bottom of bank
2295: @@:
2296: sub edx,ulTopScan ;# of scans to draw in bank
2297: mov ulNumScans,edx
2298: jmp pfnFirstOpaqVector ;do first sort of drawing (whole
2299: ; bytes, or edge(s) if no whole
2300: ; bytes)
2301:
2302: ;-----------------------------------------------------------------------;
2303: ; Draws whole bytes, which can be handled by simply loading the latches
2304: ; with the background color and using write mode 3 to punch the
2305: ; foreground color through.
2306: ;
2307: ; On entry:
2308: ; EDI = first destination byte
2309: ;-----------------------------------------------------------------------;
2310: opaq_whole_bytes:
2311: mov esi,pTempBuffer
2312: test ulTextLeft,111b ;is left edge solid?
2313: jz short @F ;yes
2314: inc esi ;no, point to leftmost source and dest
2315: inc edi ; bytes (skip over partial left edge)
2316: @@:
2317:
2318: ;-----------------------------------------------------------------------;
2319: ; Load the latches with the background color.
2320: ;-----------------------------------------------------------------------;
2321:
2322: mov edx,VGA_BASE + GRAF_DATA
2323: mov eax,iBgColor
2324: out dx,al ;set/reset color = background
2325:
2326: mov byte ptr [edi],0ffh ;we're in write mode 3, so write the
2327: ; set/reset = background color
2328: mov al,byte ptr [edi] ;latch the background color
2329:
2330: mov eax,iFgColor
2331: out dx,al ;set/reset color = foreground now
2332:
2333: mov eax,ulTmpSrcDelta
2334: mov ebx,ulTmpDstDelta
2335: mov edx,ulNumScans
2336: ;decide which copy loop to use
2337: test edi,1 ;is dest word-aligned?
2338: jnz short @F ;no, need leading byte
2339: ;yes, no leading byte
2340: cmp ulOddByte,1 ;odd width?
2341: jnz short opaq_scan_loop ;no, no trailing byte
2342: jmp short opaq_scan_loop_t ;yes, trailing byte
2343:
2344: @@:
2345: cmp ulOddByte,1 ;odd width?
2346: jz short opaq_scan_loop_l ;yes, no trailing byte
2347: jmp short opaq_scan_loop_lt ;no, trailing byte
2348:
2349: ;-----------------------------------------------------------------------;
2350: ; Loops for copying whole bytes to the screen, as much as possible a word
2351: ; at a time.
2352: ; On entry:
2353: ; EAX = offset to next buffer scan
2354: ; EBX = offset to next screen scan
2355: ; EDX = # of scans to draw
2356: ; ESI = pointer to first buffer byte from which to copy
2357: ; EDI = pointer to first screen byte to which to copy
2358: ; DF = cleared
2359: ; LATER could break out and optimize short runs, such as 1, 2, 3, 4 wide.
2360: ;-----------------------------------------------------------------------;
2361:
2362: ; Loop for doing whole opaque words: no leading byte, no trailing byte.
2363: opaq_scan_loop:
2364: @@:
2365: mov ecx,ulWholeWidthInWords
2366: rep movsw
2367: add esi,eax ;point to next buffer scan
2368: add edi,ebx ;point to next screen scan
2369: dec edx ;count down scans
2370: jnz @B
2371: jmp pfnEdgeVector ;do the edge(s)
2372:
2373: ; Loop for doing whole opaque words: leading byte, no trailing byte.
2374: opaq_scan_loop_l:
2375: @@:
2376: movsb
2377: mov ecx,ulWholeWidthInWords
2378: rep movsw
2379: add esi,eax ;point to next buffer scan
2380: add edi,ebx ;point to next screen scan
2381: dec edx ;count down scans
2382: jnz @B
2383: jmp pfnEdgeVector ;do the edge(s)
2384:
2385: ; Loop for doing whole opaque words: leading byte, trailing byte.
2386: opaq_scan_loop_lt:
2387: @@:
2388: movsb
2389: mov ecx,ulWholeWidthInWordsMinus1 ;one word gets done as 2 bytes
2390: rep movsw
2391: movsb
2392: add esi,eax ;point to next buffer scan
2393: add edi,ebx ;point to next screen scan
2394: dec edx ;count down scans
2395: jnz @B
2396: jmp pfnEdgeVector ;do the edge(s)
2397:
2398: ; Loop for doing whole opaque words: no leading byte, trailing byte.
2399: opaq_scan_loop_t:
2400: @@:
2401: mov ecx,ulWholeWidthInWords
2402: rep movsw
2403: movsb
2404: add esi,eax ;point to next buffer scan
2405: add edi,ebx ;point to next screen scan
2406: dec edx ;count down scans
2407: jnz @B
2408: jmp pfnEdgeVector ;do the edge(s)
2409:
2410: ;-----------------------------------------------------------------------;
2411: ; Draw the left edge only.
2412: ;-----------------------------------------------------------------------;
2413: opaq_draw_left_edge_only:
2414:
2415: ;-----------------------------------------------------------------------;
2416: ; First, draw the foreground pixels.
2417: ;-----------------------------------------------------------------------;
2418:
2419: push offset opaq_check_more_banks ;return here when done with edge
2420:
2421: opaq_draw_left_edge_only_entry:
2422: mov edx,VGA_BASE + GRAF_DATA
2423: mov eax,iFgColor
2424: out dx,al ;set/reset color = foreground
2425:
2426: mov ebx,ulBufDelta
2427: mov edx,ulScreenDelta
2428: mov esi,pTempBuffer
2429: mov edi,pScreen
2430: push esi ;remember starting buffer and screen offsets
2431: push edi ; for when we do the background pass
2432: mov eax,ulLeftMask ;AH = clip mask
2433: push eax ;preserve clip mask for background pass
2434: push ebp ;preserve stack frame pointer
2435: mov ecx,ulNumScans
2436: mov ebp,ecx
2437: add ecx,3
2438: shr ecx,2 ;# of quadscans
2439: and ebp,11b
2440: jmp dword ptr OpaqFgEdgeTable[ebp*4]
2441:
2442: align 4
2443: OpaqFgEdgeTable label dword
2444: dd opaq_fg_edge_entry_4
2445: dd opaq_fg_edge_entry_1
2446: dd opaq_fg_edge_entry_2
2447: dd opaq_fg_edge_entry_3
2448:
2449: opaq_fg_edge_loop:
2450: opaq_fg_edge_entry_4:
2451: mov al,[esi]
2452: add esi,ebx
2453: and al,ah
2454: and [edi],al
2455: add edi,edx
2456: opaq_fg_edge_entry_3:
2457: mov al,[esi]
2458: add esi,ebx
2459: and al,ah
2460: and [edi],al
2461: add edi,edx
2462: opaq_fg_edge_entry_2:
2463: mov al,[esi]
2464: add esi,ebx
2465: and al,ah
2466: and [edi],al
2467: add edi,edx
2468: opaq_fg_edge_entry_1:
2469: mov al,[esi]
2470: add esi,ebx
2471: and al,ah
2472: and [edi],al
2473: add edi,edx
2474:
2475: dec ecx
2476: jnz opaq_fg_edge_loop
2477:
2478: pop ebp ;restore stack frame pointer
2479:
2480: ;-----------------------------------------------------------------------;
2481: ; Now draw the background pixels with inverted buffer contents.
2482: ;-----------------------------------------------------------------------;
2483:
2484: mov edx,VGA_BASE + GRAF_DATA
2485: mov eax,iBgColor
2486: out dx,al ;set/reset color = background
2487:
2488: pop eax ;retrieve clip mask
2489: pop edi ;retrieve the initial screen and
2490: pop esi ; buffer offsets
2491:
2492: mov edx,ulScreenDelta
2493:
2494: push ebp ;preserve stack frame pointer
2495: mov ecx,ulNumScans
2496: mov ebp,ecx
2497: and ebp,11b
2498: add ecx,3
2499: shr ecx,2 ;# of quadscans
2500: jmp dword ptr OpaqBgEdgeTable[ebp*4]
2501:
2502: align 4
2503: OpaqBgEdgeTable label dword
2504: dd opaq_bg_edge_entry_4
2505: dd opaq_bg_edge_entry_1
2506: dd opaq_bg_edge_entry_2
2507: dd opaq_bg_edge_entry_3
2508:
2509: opaq_bg_edge_loop:
2510: opaq_bg_edge_entry_4:
2511: mov al,[esi]
2512: add esi,ebx
2513: not al
2514: and al,ah
2515: and [edi],al
2516: add edi,edx
2517: opaq_bg_edge_entry_3:
2518: mov al,[esi]
2519: add esi,ebx
2520: not al
2521: and al,ah
2522: and [edi],al
2523: add edi,edx
2524: opaq_bg_edge_entry_2:
2525: mov al,[esi]
2526: add esi,ebx
2527: not al
2528: and al,ah
2529: and [edi],al
2530: add edi,edx
2531: opaq_bg_edge_entry_1:
2532: mov al,[esi]
2533: add esi,ebx
2534: not al
2535: and al,ah
2536: and [edi],al
2537: add edi,edx
2538:
2539: dec ecx
2540: jnz opaq_bg_edge_loop
2541:
2542: pop ebp ;restore stack frame pointer
2543:
2544: retn
2545:
2546: ;-----------------------------------------------------------------------;
2547: ; Draw the right edge only. Once we've set up the pointers, this is done
2548: ; with exactly the same code as the left edge.
2549: ;-----------------------------------------------------------------------;
2550: opaq_draw_right_edge_only:
2551: push offset opaq_check_more_banks ;return here when done with edge
2552:
2553: opaq_draw_right_edge_only_entry:
2554: mov edx,VGA_BASE + GRAF_DATA
2555: mov eax,iFgColor
2556: out dx,al ;set/reset color = foreground
2557:
2558: mov ebx,ulBufDelta
2559: mov edx,ulScreenDelta
2560: mov edi,ulTextWidthInBytes
2561: dec edi
2562: mov esi,pTempBuffer
2563: add esi,edi ;point to right edge start in buffer
2564: add edi,pScreen ;point to right edge start in screen
2565: push esi ;remember starting buffer and screen offsets
2566: push edi ; for when we do the background pass
2567: mov eax,ulRightMask ;AH = clip mask
2568: push eax ;preserve clip mask for background pass
2569: push ebp ;preserve stack frame pointer
2570: mov ecx,ulNumScans
2571: mov ebp,ecx
2572: add ecx,3
2573: shr ecx,2 ;# of quadscans
2574: and ebp,11b
2575: jmp OpaqFgEdgeTable[ebp*4]
2576:
2577: ;-----------------------------------------------------------------------;
2578: ; Draw both the left and right edges. We do this by calling first the
2579: ; left and then the right edge drawing code.
2580: ;-----------------------------------------------------------------------;
2581: opaq_draw_both_edges:
2582: call opaq_draw_left_edge_only_entry
2583: call opaq_draw_right_edge_only_entry
2584:
2585: ;-----------------------------------------------------------------------;
2586: ; See if there are more banks to draw.
2587: ;-----------------------------------------------------------------------;
2588:
2589: opaq_check_more_banks:
2590: mov ebx,pdsurf
2591: mov eax,[ebx].dsurf_rcl1WindowClip.yBottom ;is the text bottom in
2592: cmp ulBottomScan,eax ; the current bank?
2593: jnle short do_next_opaq_bank ;no, map in the next bank and draw
2594: ;yes, so we're done
2595:
2596: ;-----------------------------------------------------------------------;
2597: ; Restore the VGA's hardware state and we're done.
2598: ;-----------------------------------------------------------------------;
2599:
2600: opaq_done:
2601: mov edx,VGA_BASE + GRAF_ADDR
2602: mov eax,GRAF_MODE + ((M_PROC_WRITE + M_DATA_READ) SHL 8)
2603: out dx,ax ;restore read mode 0 and write mode 0
2604: done:
2605: cRet vFastText
2606:
2607: do_next_opaq_bank:
2608: mov ulTopScan,eax ;this will be the top of the next bank
2609: mov ecx,eax ;set aside scan # for bank manager call
2610: mul ulScreenDelta
2611: mov edi,ulTempLeft
2612: add edi,eax ;next screen byte to which to copy
2613:
2614: ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,ecx,JustifyTop>
2615: ;map in the bank (call preserves EBX,
2616: ; ESI, and EDI)
2617:
2618: add edi,[ebx].dsurf_pvBitmapStart ;initial destination address
2619: mov pScreen,edi
2620:
2621: mov eax,ulBufDelta
2622: mul ulNumScans
2623: add pTempBuffer,eax ;advance to next temp buffer scan to
2624: ; copy
2625: jmp opaq_bank_loop ;we're ready to draw in the new bank
2626:
2627: ;-----------------------------------------------------------------------;
2628: ; Special 8-wide aligned opaque drawing code. Loads the latches with the
2629: ; background color, sets the Set/Reset color to the foreground color,
2630: ; then uses write mode 3 to draw the glyphs. Joyously, there are no
2631: ; partial bytes to worry about, so we can really crank up the code.
2632: ;
2633: ; On entry:
2634: ; EBX = prclText
2635: ;-----------------------------------------------------------------------;
2636: special_8_wide_aligned_opaque:
2637:
2638: mov esi,pdsurf
2639: mov edi,[ebx].yBottom
2640: mov eax,[ebx].yTop
2641: sub edi,eax ;height of glyphs
2642:
2643: ;-----------------------------------------------------------------------;
2644: ; Map in the bank containing the top scan of the text, if it's not
2645: ; mapped in already.
2646: ;-----------------------------------------------------------------------;
2647:
2648: cmp eax,[esi].dsurf_rcl1WindowClip.yTop ;is text top less than
2649: ; current bank?
2650: jl short s8wao_map_init_bank ;yes, map in proper bank
2651: cmp eax,[esi].dsurf_rcl1WindowClip.yBottom ;text top greater than
2652: ; current bank?
2653: jl short s8wa0_init_bank_mapped ;no, proper bank already mapped
2654: s8wao_map_init_bank:
2655:
2656: ; Map in the bank containing the top scan line of the text.
2657: ; Preserves EBX, ESI, and EDI.
2658:
2659: ptrCall <dword ptr [esi].dsurf_pfnBankControl>,<esi,eax,JustifyTop>
2660:
2661: s8wa0_init_bank_mapped:
2662:
2663: mov eax,[esi].dsurf_rcl1WindowClip.yBottom
2664: sub eax,[ebx].yTop ;maximum run in bank
2665: cmp edi,eax ;does all the text fit in the bank?
2666: jg general_handler ;no, let general code handle it
2667: ;LATER could handle here
2668:
2669: ;-----------------------------------------------------------------------;
2670: ; Set up variables.
2671: ;-----------------------------------------------------------------------;
2672:
2673: mov eax,edi ;# of scans in glyphs
2674: add eax,7
2675: shr eax,3 ;# of unrolled loops needed to draw
2676: ; glyph scans
2677: mov ulUnrolledCount,eax ;# of unrolled loop reps
2678: and edi,111b ;# of odd scans in first unrolled
2679: ; loop
2680: mov ulUnrolledOddCount,edi ;# of odd unrolled loop reps
2681:
2682: ;-----------------------------------------------------------------------;
2683: ; Point to the first screen byte at which to draw.
2684: ;-----------------------------------------------------------------------;
2685:
2686: mov eax,[ebx].yTop
2687: mul [esi].dsurf_lNextScan
2688: mov edi,[ebx].xLeft
2689: shr edi,3
2690: add edi,eax ;next screen byte to which to copy
2691: add edi,[esi].dsurf_pvBitmapStart ;initial destination address
2692: mov pScreen,edi
2693:
2694: ;-----------------------------------------------------------------------;
2695: ; Set up the VGA's hardware for read mode 0 and write mode 3.
2696: ;-----------------------------------------------------------------------;
2697:
2698: mov edx,VGA_BASE + GRAF_ADDR
2699: mov eax,GRAF_MODE + ((M_AND_WRITE + M_DATA_READ) SHL 8)
2700: out dx,ax ;write mode 3 so we can do masking
2701: ; without OUTs
2702:
2703: ;-----------------------------------------------------------------------;
2704: ; Load the latches with the background color.
2705: ;-----------------------------------------------------------------------;
2706:
2707: mov ah,byte ptr iBgColor
2708: mov al,GRAF_SET_RESET
2709: out dx,ax ;set/reset color = background
2710:
2711: mov byte ptr [edi],0ffh ;we're in write mode 3, so write the
2712: ; set/reset = background color
2713: mov al,byte ptr [edi] ;latch the background color
2714:
2715: inc edx ;point to GC Data register
2716: mov eax,iFgColor
2717: out dx,al ;set/reset color = foreground now
2718:
2719: ;-----------------------------------------------------------------------;
2720: ; Set up the screen scan offset in EDX, and decide whether we need to do
2721: ; a leading glyph or not.
2722: ;-----------------------------------------------------------------------;
2723:
2724: mov edx,[esi].dsurf_lNextScan ;offset from one scan to next
2725:
2726: test edi,1 ;is leading glyph address even or odd?
2727: jz short s8wa0_word ;even, so no leading glyph
2728:
2729: ;-----------------------------------------------------------------------;
2730: ; Do the leading glyph.
2731: ;-----------------------------------------------------------------------;
2732:
2733: mov ebx,pGlyphPos ;point to the first glyph to draw
2734: add pGlyphPos,size GLYPHPOS ;point to the next glyph
2735: inc pScreen ;point to the next glyph's screen
2736: ; location
2737: dec ulGlyphCount ;count off this character
2738: mov ecx,ulUnrolledCount ;# of unrolled loop reps
2739: mov esi,[ebx].gp_pgdf ;point to glyph def
2740: mov eax,ulUnrolledOddCount ;# of odd unrolled loop reps
2741: mov esi,[esi].gdf_pgb ;point to glyph bits
2742: add esi,gb_aj ;point to the first glyph byte
2743: push offset s8wa0_word ;return here to do glyph pairs
2744: jmp dword ptr s8wao_byte_table[eax*4] ;branch into unrolled loop
2745:
2746: s8wa0_word:
2747: mov ecx,ulGlyphCount
2748: shr ecx,1 ;# of words we can copy, now that
2749: ; we're word-aligned
2750: jz s8wa0_trailing ;no words to copy
2751: mov eax,ulUnrolledOddCount ;# of odd unrolled loop reps
2752: mov ulWholeWidthInWords,ecx
2753: mov eax,dword ptr s8wao_word_table[eax*4] ;entry point into
2754: mov pGlyphLoop,eax ; unrolled loop
2755:
2756: s8wa0_word_loop:
2757: mov ebx,pGlyphPos ;point to the next glyph pair to draw
2758: add pGlyphPos,((size GLYPHPOS)*2) ;point to the next glyph pair
2759: mov edi,pScreen ;point to current glyph pair's screen
2760: ; location
2761: add pScreen,2 ;point to the next glyph pair's
2762: ; screen location
2763: mov esi,[ebx].gp_pgdf ;point to first glyph def
2764: mov ebx,[ebx+(size GLYPHPOS)].gp_pgdf ;point to second glyph def
2765: mov esi,[esi].gdf_pgb ;point to first glyph
2766: mov ebx,[ebx].gdf_pgb ;point to second glyph
2767: add esi,gb_aj ;point to the first glyph's bits
2768: add ebx,gb_aj ;point to the second glyph's bits
2769: mov ecx,ulUnrolledCount ;# of unrolled loop reps
2770: jmp pGlyphLoop ;branch into unrolled loop
2771:
2772: align 4
2773: s8wao_word_table label dword
2774: dd s8wao_word_8
2775: dd s8wao_word_1
2776: dd s8wao_word_2
2777: dd s8wao_word_3
2778: dd s8wao_word_4
2779: dd s8wao_word_5
2780: dd s8wao_word_6
2781: dd s8wao_word_7
2782:
2783: s8wao_word_loop:
2784: s8wao_word_8:
2785: mov al,[esi]
2786: inc esi
2787: mov ah,[ebx]
2788: inc ebx
2789: mov [edi],ax
2790: add edi,edx
2791: s8wao_word_7:
2792: mov al,[esi]
2793: inc esi
2794: mov ah,[ebx]
2795: inc ebx
2796: mov [edi],ax
2797: add edi,edx
2798: s8wao_word_6:
2799: mov al,[esi]
2800: inc esi
2801: mov ah,[ebx]
2802: inc ebx
2803: mov [edi],ax
2804: add edi,edx
2805: s8wao_word_5:
2806: mov al,[esi]
2807: inc esi
2808: mov ah,[ebx]
2809: inc ebx
2810: mov [edi],ax
2811: add edi,edx
2812: s8wao_word_4:
2813: mov al,[esi]
2814: inc esi
2815: mov ah,[ebx]
2816: inc ebx
2817: mov [edi],ax
2818: add edi,edx
2819: s8wao_word_3:
2820: mov al,[esi]
2821: inc esi
2822: mov ah,[ebx]
2823: inc ebx
2824: mov [edi],ax
2825: add edi,edx
2826: s8wao_word_2:
2827: mov al,[esi]
2828: inc esi
2829: mov ah,[ebx]
2830: inc ebx
2831: mov [edi],ax
2832: add edi,edx
2833: s8wao_word_1:
2834: mov al,[esi]
2835: inc esi
2836: mov ah,[ebx]
2837: inc ebx
2838: mov [edi],ax
2839: add edi,edx
2840:
2841: dec ecx ;count down glyph scans
2842: jnz s8wao_word_loop
2843:
2844: dec ulWholeWidthInWords ;count down glyph pairs
2845: jnz s8wa0_word_loop
2846:
2847: ;-----------------------------------------------------------------------;
2848: ; Do the trailing character, if there is one.
2849: ;-----------------------------------------------------------------------;
2850:
2851: s8wa0_trailing:
2852: test ulGlyphCount,1 ;trailing byte count
2853: ;is there a trailing character?
2854: jz opaq_done ;no, we're done
2855:
2856: mov ebx,pGlyphPos ;point to the last glyph to draw
2857: mov edi,pScreen ;point to the final glyph's screen
2858: ; location
2859: mov esi,[ebx].gp_pgdf ;point to glyph def
2860: mov ecx,ulUnrolledCount ;# of unrolled loop reps
2861: mov esi,[esi].gdf_pgb ;point to glyph bits
2862: mov eax,ulUnrolledOddCount ;# of odd unrolled loop reps
2863: add esi,gb_aj ;point to the first glyph byte
2864: push offset opaq_done ;return here to finish up
2865: jmp dword ptr s8wao_byte_table[eax*4] ;branch into unrolled loop
2866:
2867: align 4
2868: s8wao_byte_table label dword
2869: dd s8wao_byte_8
2870: dd s8wao_byte_1
2871: dd s8wao_byte_2
2872: dd s8wao_byte_3
2873: dd s8wao_byte_4
2874: dd s8wao_byte_5
2875: dd s8wao_byte_6
2876: dd s8wao_byte_7
2877:
2878: s8wao_byte_loop:
2879: s8wao_byte_8:
2880: mov al,[esi]
2881: inc esi
2882: mov [edi],al
2883: add edi,edx
2884: s8wao_byte_7:
2885: mov al,[esi]
2886: inc esi
2887: mov [edi],al
2888: add edi,edx
2889: s8wao_byte_6:
2890: mov al,[esi]
2891: inc esi
2892: mov [edi],al
2893: add edi,edx
2894: s8wao_byte_5:
2895: mov al,[esi]
2896: inc esi
2897: mov [edi],al
2898: add edi,edx
2899: s8wao_byte_4:
2900: mov al,[esi]
2901: inc esi
2902: mov [edi],al
2903: add edi,edx
2904: s8wao_byte_3:
2905: mov al,[esi]
2906: inc esi
2907: mov [edi],al
2908: add edi,edx
2909: s8wao_byte_2:
2910: mov al,[esi]
2911: inc esi
2912: mov [edi],al
2913: add edi,edx
2914: s8wao_byte_1:
2915: mov al,[esi]
2916: inc esi
2917: mov [edi],al
2918: add edi,edx
2919:
2920: dec ecx
2921: jnz s8wao_byte_loop
2922:
2923: retn
2924:
2925: endProc vFastText
2926:
2927: ;-----------------------------------------------------------------------;
2928: ; VOID vClearMemDword(PULONG * pulBuffer, ULONG ulDwordCount);
2929: ;
2930: ; Clears ulCount dwords starting at pjBuffer.
2931: ;-----------------------------------------------------------------------;
2932:
2933: pulBuffer equ [esp+8]
2934: ulDwordCount equ [esp+12]
2935:
2936: cProc vClearMemDword,8,<>
2937:
2938: push edi
2939: mov edi,pulBuffer
2940: mov ecx,ulDwordCount
2941: sub eax,eax
2942: rep stosd
2943: pop edi
2944:
2945: cRet vClearMemDword
2946:
2947: endProc vClearMemDword
2948:
2949: public draw_f_tb_no_to_temp_start
2950: public draw_nf_tb_no_to_temp_start
2951: public draw_to_temp_start_entry
2952: public draw_f_ntb_o_to_temp_start
2953: public draw_nf_ntb_o_to_temp_start
2954: public draw_to_temp_start_entry2
2955: public draw_f_tb_no_to_temp_loop
2956: public draw_nf_tb_no_to_temp_loop
2957: public draw_to_temp_loop_entry
2958: public draw_f_ntb_o_to_temp_loop
2959: public draw_nf_ntb_o_to_temp_loop
2960: public draw_to_temp_loop_entry2
2961: public or_all_1_wide_rotated_need_last
2962: public or_all_1_wide_rotated_no_last
2963: public or_first_1_wide_rotated_need_last
2964: public or_first_1_wide_rotated_no_last
2965: public or_first_1_wide_rotated_loop
2966: public mov_first_1_wide_rotated_need_last
2967: public mov_first_1_wide_rotated_no_last
2968: public mov_first_1_wide_rotated_loop
2969: public mov_first_1_wide_unrotated
2970: public mov_first_1_wide_unrotated_loop
2971: public or_all_1_wide_unrotated
2972: public or_all_1_wide_unrotated_loop
2973: public or_first_2_wide_rotated_need_last
2974: public or_first_2_wide_rotated_need_loop
2975: public or_all_2_wide_rotated_need_last
2976: public or_all_2_wide_rotated_need_loop
2977: public mov_first_2_wide_rotated_need_last
2978: public mov_first_2_wide_rotated_need_loop
2979: public or_first_2_wide_rotated_no_last
2980: public or_first_2_wide_rotated_loop
2981: public or_all_2_wide_rotated_no_last
2982: public or_all_2_wide_rotated_loop
2983: public mov_first_2_wide_rotated_no_last
2984: public mov_first_2_wide_rotated_loop
2985: public mov_first_2_wide_unrotated
2986: public mov_first_2_wide_unrotated_loop
2987: public or_all_2_wide_unrotated
2988: public or_all_2_wide_unrotated_loop
2989: public or_first_3_wide_rotated_need_last
2990: public or_all_3_wide_rotated_need_last
2991: public mov_first_3_wide_rotated_need_last
2992: public or_first_3_wide_rotated_no_last
2993: public or_all_3_wide_rotated_no_last
2994: public mov_first_3_wide_rotated_no_last
2995: public mov_first_3_wide_unrotated
2996: public or_all_3_wide_unrotated
2997: public or_first_4_wide_rotated_need_last
2998: public or_all_4_wide_rotated_need_last
2999: public mov_first_4_wide_rotated_need_last
3000: public or_first_4_wide_rotated_no_last
3001: public or_all_4_wide_rotated_no_last
3002: public mov_first_4_wide_rotated_no_last
3003: public mov_first_4_wide_unrotated
3004: public or_all_4_wide_unrotated
3005: public or_first_N_wide_rotated_need_last
3006: public or_all_N_wide_rotated_need_last
3007: public mov_first_N_wide_rotated_need_last
3008: public or_first_N_wide_rotated_no_last
3009: public or_all_N_wide_rotated_no_last
3010: public mov_first_N_wide_rotated_no_last
3011: public mov_first_N_wide_unrotated
3012: public odd_width
3013: public two_odd_bytes
3014: public three_odd_bytes
3015: public or_all_N_wide_unrotated
3016: public or_no_odd_bytes_loop
3017: public or_odd_width
3018: public or_one_odd_bytes_loop
3019: public or_two_odd_bytes
3020: public or_two_odd_bytes_loop
3021: public or_three_odd_bytes
3022: public or_three_odd_bytes_loop
3023: public draw_to_screen
3024: public xpar_map_init_bank
3025: public xpar_init_bank_mapped
3026: public xpar_bank_loop
3027: public xpar_scan_loop
3028: public xpar_byte_loop
3029: public xpar_enter_8
3030: public xpar_enter_7
3031: public xpar_enter_6
3032: public xpar_enter_5
3033: public xpar_enter_4
3034: public xpar_enter_3
3035: public xpar_enter_2
3036: public xpar_enter_1
3037: public draw_prop_done
3038: public do_next_xpar_bank
3039: public opaque_text
3040: public opaq_left_edge_solid
3041: public opaq_set_edge_vector
3042: public opaq_edges_set
3043: public opaq_map_init_bank
3044: public opaq_init_bank_mapped
3045: public opaq_bank_loop
3046: public opaq_whole_bytes
3047: public opaq_scan_loop
3048: public opaq_scan_loop_l
3049: public opaq_scan_loop_lt
3050: public opaq_scan_loop_t
3051: public opaq_draw_left_edge_only
3052: public opaq_draw_left_edge_only_entry
3053: public opaq_fg_edge_loop
3054: public opaq_fg_edge_entry_4
3055: public opaq_fg_edge_entry_3
3056: public opaq_fg_edge_entry_2
3057: public opaq_fg_edge_entry_1
3058: public opaq_bg_edge_loop
3059: public opaq_bg_edge_entry_4
3060: public opaq_bg_edge_entry_3
3061: public opaq_bg_edge_entry_2
3062: public opaq_bg_edge_entry_1
3063: public opaq_draw_right_edge_only
3064: public opaq_draw_right_edge_only_entry
3065: public opaq_draw_both_edges
3066: public opaq_check_more_banks
3067: public do_next_opaq_bank
3068: public opaq_done
3069: public special_8_wide_aligned_opaque
3070: public s8wa0_init_bank_mapped
3071: public s8wa0_word
3072: public s8wao_word_loop
3073: public s8wao_word_8
3074: public s8wao_word_7
3075: public s8wao_word_6
3076: public s8wao_word_5
3077: public s8wao_word_4
3078: public s8wao_word_3
3079: public s8wao_word_2
3080: public s8wao_word_1
3081: public s8wa0_trailing
3082: public s8wao_byte_loop
3083: public s8wao_byte_8
3084: public s8wao_byte_7
3085: public s8wao_byte_6
3086: public s8wao_byte_5
3087: public s8wao_byte_4
3088: public s8wao_byte_3
3089: public s8wao_byte_2
3090: public s8wao_byte_1
3091: public s8wao_map_init_bank
3092: public do_opaque_clip
3093: public opaq_fully_clipped
3094:
3095: _TEXT$01 ends
3096:
3097: end
3098:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.