|
|
1.1 root 1: ;---------------------------Module-Header------------------------------;
2: ; Module Name: lines.asm
3: ;
4: ; ASM version of the line DDA calculator.
5: ;
6: ; Copyright (c) 1992 Microsoft Corporation
7: ;-----------------------------------------------------------------------;
8:
9: .386
10:
11: .model small,c
12:
13: assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
14: assume fs:nothing,gs:nothing
15:
16: .xlist
17: include stdcall.inc ;calling convention cmacros
18: include i386\strucs.inc
19: include i386\lines.inc
20: .list
21:
22: .data
23:
24: public gaflRoundTable
25: gaflRoundTable label dword
26: dd FL_H_ROUND_DOWN + FL_V_ROUND_DOWN ; no flips
27: dd FL_H_ROUND_DOWN + FL_V_ROUND_DOWN ; D flip
28: dd FL_H_ROUND_DOWN ; V flip
29: dd FL_V_ROUND_DOWN ; D & V flip
30: dd FL_V_ROUND_DOWN ; slope one
31: dd 0baadf00dh
32: dd FL_H_ROUND_DOWN ; slope one & V flip
33: dd 0baadf00dh
34:
35: .code
36:
37: ;--------------------------------Macro----------------------------------;
38: ; testb ebx, <mask>
39: ;
40: ; Substitutes a byte compare if the mask is entirely in the lo-byte or
41: ; hi-byte (thus saving 3 bytes of code space).
42: ;
43: ;-----------------------------------------------------------------------;
44:
45: TESTB macro targ,mask,thirdarg
46: local mask2,delta
47:
48: ifnb <thirdarg>
49: .err TESTB mask must be enclosed in brackets!
50: endif
51:
52: delta = 0
53: mask2 = mask
54:
55: if mask2 AND 0ffff0000h
56: test targ,mask ; If bit set in hi-word,
57: exitm ; test entire dword
58: endif
59:
60: if mask2 AND 0ff00h
61: if mask2 AND 0ffh ; If bit set in lo-byte and
62: test targ,mask ; hi-byte, test entire dword
63: exitm
64: endif
65:
66: mask2 = mask2 SHR 8
67: delta = 1
68: endif
69:
70: ifidni <targ>,<EBX>
71: if delta
72: test bh,mask2
73: else
74: test bl,mask2
75: endif
76: exitm
77: endif
78:
79: .err Too bad TESTB doesn't support targets other than ebx!
80: endm
81:
82: ;---------------------------Public-Routine------------------------------;
83: ; bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls,
84: ; prclClip, apfn[], flStart)
85: ;
86: ; Handles lines with trivial or simple clipping.
87: ;
88: ;-----------------------------------------------------------------------;
89:
90: cProc bLines,36,< \
91: uses esi edi ebx, \
92: ppdev: ptr, \
93: pptfxFirst: ptr, \
94: pptfxBuf: ptr, \
95: prun: ptr, \
96: cptfx: dword, \
97: pls: ptr, \
98: prclClip: ptr, \
99: apfn: ptr, \
100: flStart: dword >
101:
102: local pptfxBufEnd: ptr ; Last point in pptfxBuf
103: local M0: dword ; Normalized x0 in device coords
104: local dM: dword ; Delta-x in device coords
105: local N0: dword ; Normalized y0 in device coords
106: local dN: dword ; Delta-y in device coords
107: local fl: dword ; Flags for current line
108: local x: dword ; Normalized start pixel x-coord
109: local y: dword ; Normalized start pixel y-coord
110: local eqGamma_lo: dword ; Upper 32 bits of Gamma
111: local eqGamma_hi: dword ; Lower 32 bits of Gamma
112: local x0: dword ; Start pixel x-offset
113: local y0: dword ; Start pixel y-offset
114: local ulSlopeOneAdjustment: dword ; Special offset if line of slope 1
115: local cStylePels: dword ; # of pixels in line (before clip)
116: local xStart: dword ; Start pixel x-offset before clip
117: local pfn: ptr ; Pointer to strip drawing function
118: local cPels: dword ; # pixels to be drawn (after clip)
119: local i: dword ; # pixels in strip
120: local r: dword ; Remainder (or "error") term
121: local d_I: dword ; Delta-I
122: local d_R: dword ; Delta-R
123: local plStripEnd: ptr ; Last strip in buffer
124: local ptlStart[size POINTL]: byte ; Unnormalized start coord
125: local dN_Original: dword ; dN before half-flip
126: local xClipLeft: dword ; Left side of clip rectangle
127: local xClipRight: dword ; Right side of clip rectangle
128: local strip[size STRIPS]: byte ; Our strip buffer
129:
130: mov ecx, cptfx
131: mov edx, pptfxBuf
132: lea eax, [edx + ecx * (size POINTL) - (size POINTL)]
133: mov pptfxBufEnd, eax ; pptfxBufEnd is inclusive of end point
134:
135: mov eax, [edx].ptl_x ; Load up end point (M1, N1)
136: mov edi, [edx].ptl_y
137:
138: mov edx, pptfxFirst ; Load up start point (M0, N0)
139: mov esi, [edx].ptl_x
140: mov ecx, [edx].ptl_y
141:
142: mov ebx, flStart
143:
144: ;-----------------------------------------------------------------------;
145: ; Flip to the first octant. ;
146: ;-----------------------------------------------------------------------;
147:
148: ; Register state: esi = M0
149: ; ecx = N0
150: ; eax = dM (M1)
151: ; edi = dN (N1)
152: ; ebx = fl
153:
154: ; Make sure we go left to right:
155:
156: the_main_loop:
157: cmp esi, eax
158: jle short is_left_to_right ; skip if M0 <= M1
159: xchg esi, eax ; swap M0, M1
160: xchg ecx, edi ; swap N0, N1
161: or ebx, FL_FLIP_H
162:
163: is_left_to_right:
164:
165: ; Compute the deltas, remembering that the DDI says we should get
166: ; deltas less than 2^31. If we get more, we ensure we don't crash
167: ; later on by simply skipping the line:
168:
169: sub eax, esi ; eax = dM
170: jo next_line ; dM must be less than 2^31
171: sub edi, ecx ; edi = dN
172: jo next_line ; dN must be less than 2^31
173:
174: jge short is_top_to_bottom ; skip if dN >= 0
175: neg ecx ; N0 = -N0
176: neg edi ; N1 = -N1
177: or ebx, FL_FLIP_V
178:
179: is_top_to_bottom:
180: cmp edi, eax
181: jb short done_flips ; skip if dN < dM
182: jne short slope_more_than_one
183:
184: ; We must special case slopes of one:
185:
186: or ebx, FL_FLIP_SLOPE_ONE
187: jmp short done_flips
188:
189: slope_more_than_one:
190: xchg eax, edi ; swap dM, dN
191: xchg esi, ecx ; swap M0, N0
192: or ebx, FL_FLIP_D
193:
194: done_flips:
195:
196: mov edx, ebx
197: and edx, FL_ROUND_MASK
198: .errnz FL_ROUND_SHIFT - 2
199: or ebx, [gaflRoundTable + edx] ; get our rounding flags
200:
201: mov dM, eax ; save some info
202: mov dN, edi
203: mov fl, ebx
204:
205: mov edx, esi ; x = LFLOOR(M0)
206: sar edx, FLOG2
207: mov x, edx
208:
209: mov edx, ecx ; y = LFLOOR(N0)
210: sar edx, FLOG2
211: mov y, edx
212:
213: ;-----------------------------------------------------------------------;
214: ; Compute the fractional remainder term ;
215: ;-----------------------------------------------------------------------;
216:
217: public compute_fractional
218: compute_fractional:
219: and esi, F - 1 ; M0 = FXFRAC(M0)
220: and ecx, F - 1 ; N0 = FXFRAC(N0)
221:
222: mov M0, esi ; save M0, N0 for later
223: mov N0, ecx
224:
225: lea edx, [ecx + F/2]
226: mul edx ; [edx:eax] = dM * (N0 + F/2)
227: xchg eax, edi
228: mov ecx, edx ; [ecx:edi] = dM * (N0 + F/2)
229: ; (we just nuked N0)
230:
231: mul esi ; [edx:eax] = dN * M0
232:
233: ; Now gamma = dM * (N0 + F/2) - dN * M0 - bRoundDown
234:
235: .errnz FL_V_ROUND_DOWN - 8000h
236: ror bh, 8
237: sbb edi, eax
238: sbb ecx, edx
239:
240: shrd edi, ecx, FLOG2
241: sar ecx, FLOG2 ; gamma = [ecx:edi] >>= 4
242:
243: mov eqGamma_hi, ecx
244: mov eqGamma_lo, edi
245:
246: mov eax, N0
247:
248: ; Register state:
249: ; eax = N0
250: ; ebx = fl
251: ; ecx = eqGamma_hi
252: ; edx = garbage
253: ; esi = M0
254: ; edi = eqGamma_lo
255:
256: testb ebx, FL_FLIP_H
257: jnz line_runs_right_to_left
258:
259: ;-----------------------------------------------------------------------;
260: ; Figure out which pixels are at the ends of a left-to-right line. ;
261: ; --------> ;
262: ;-----------------------------------------------------------------------;
263:
264: public line_runs_left_to_right
265: line_runs_left_to_right:
266: or esi, esi
267: jz short LtoR_check_slope_one
268: ; skip ahead if M0 == 0
269: ; (in that case, x0 = 0 which is to be
270: ; kept in esi, and is already
271: ; conventiently zero)
272:
273: or eax, eax
274: jnz short LtoR_N0_not_zero
275:
276: .errnz FL_H_ROUND_DOWN - 80h
277: ror bl, 8
278: sbb esi, -F/2
279: shr esi, FLOG2
280: jmp short LtoR_check_slope_one
281: ; esi = x0 = rounded M0
282:
283: LtoR_N0_not_zero:
284: sub eax, F/2
285: sbb edx, edx
286: xor eax, edx
287: sub eax, edx
288: cmp esi, eax
289: sbb esi, esi
290: inc esi ; esi = x0 = (abs(N0 - F/2) <= M0)
291:
292: public LtoR_check_slope_one
293: LtoR_check_slope_one:
294: mov ulSlopeOneAdjustment, 0
295: mov eax, ebx
296: and eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
297: cmp eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
298: jne short LtoR_compute_y0_from_x0
299:
300: ; We have to special case lines that are exactly of slope 1 or -1:
301:
302: mov eax, N0
303: add eax, dN
304: and eax, F - 1 ; eax = N1
305: jz short LtoR_slope_one_check_start_point
306:
307: mov edx, M0
308: add edx, dM
309: and edx, F - 1 ; edx = M1
310:
311: add eax, F/2
312: cmp edx, eax ; cmp M1, N1 + F/2
313: jne short LtoR_slope_one_check_start_point
314: mov ulSlopeOneAdjustment, -1
315:
316: LtoR_slope_one_check_start_point:
317: mov eax, M0
318: or eax, eax
319: jz short LtoR_compute_y0_from_x0
320:
321: add eax, F/2
322: cmp eax, N0 ; cmp M0 + 8, N0
323: jne short LtoR_compute_y0_from_x0
324:
325: xor esi, esi ; x0 = 0
326:
327: LtoR_compute_y0_from_x0:
328:
329: ; ecx = eqGamma_hi
330: ; esi = x0
331: ; edi = eqGamma_lo
332:
333: mov eax, dN
334: mov edx, dM
335:
336: mov x0, esi
337: mov y0, 0
338: cmp ecx, 0
339: jl short LtoR_compute_x1
340:
341: neg esi
342: and esi, eax
343: sub edx, esi
344: cmp edi, edx
345: mov edx, dM
346: jl short LtoR_compute_x1
347: mov y0, 1 ; y0 = floor((dN * x0 + eqGamma) / dM)
348:
349: LtoR_compute_x1:
350:
351: ; Register state:
352: ; eax = dN
353: ; ebx = fl
354: ; ecx = garbage
355: ; edx = dM
356: ; esi = garbage
357: ; edi = garbage
358:
359: mov esi, M0
360: add esi, edx
361: mov ecx, esi
362: shr esi, FLOG2
363: dec esi ; x1 = ((M0 + dM) >> 4) - 1
364: add esi, ulSlopeOneAdjustment
365: and ecx, F-1 ; M1 = (M0 + dM) & 15
366: jz done_first_pel_last_pel
367:
368: add eax, N0
369: and eax, F-1 ; N1 = (N0 + dN) & 15
370: jnz short LtoR_N1_not_zero
371:
372: .errnz FL_H_ROUND_DOWN - 80h
373: ror bl, 8
374: sbb ecx, -F/2
375: shr ecx, FLOG2 ; ecx = LROUND(M1, fl & FL_ROUND_DOWN)
376: add esi, ecx
377: jmp done_first_pel_last_pel
378:
379: LtoR_N1_not_zero:
380: sub eax, F/2
381: sbb edx, edx
382: xor eax, edx
383: sub eax, edx
384: cmp eax, ecx
385: jg done_first_pel_last_pel
386: inc esi
387: jmp done_first_pel_last_pel
388:
389: ;-----------------------------------------------------------------------;
390: ; Figure out which pixels are at the ends of a right-to-left line. ;
391: ; <-------- ;
392: ;-----------------------------------------------------------------------;
393:
394: ; Compute x0:
395:
396: public line_runs_right_to_left
397: line_runs_right_to_left:
398: mov x0, 1 ; x0 = 1
399: or eax, eax
400: jnz short RtoL_N0_not_zero
401:
402: xor edx, edx ; ulDelta = 0
403: .errnz FL_H_ROUND_DOWN - 80h
404: ror bl, 8
405: sbb esi, -F/2
406: shr esi, FLOG2 ; esi = LROUND(M0, fl & FL_H_ROUND_DOWN)
407: jz short RtoL_check_slope_one
408:
409: mov x0, 2
410: mov edx, dN
411: jmp short RtoL_check_slope_one
412:
413: RtoL_N0_not_zero:
414: sub eax, F/2
415: sbb edx, edx
416: xor eax, edx
417: sub eax, edx
418: add eax, esi ; eax = ABS(N0 - F/2) + M0
419: xor edx, edx ; ulDelta = 0
420: cmp eax, F
421: jle short RtoL_check_slope_one
422:
423: mov x0, 2 ; x0 = 2
424: mov edx, dN ; ulDelta = dN
425:
426: public RtoL_check_slope_one
427: RtoL_check_slope_one:
428: mov ulSlopeOneAdjustment, 0
429: mov eax, ebx
430: and eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
431: cmp eax, FL_FLIP_SLOPE_ONE
432: jne short RtoL_compute_y0_from_x0
433:
434: ; We have to special case lines that are exactly of slope 1 or -1:
435:
436: mov eax, N0
437: add eax, dN
438: and eax, F - 1 ; eax = N1
439: jz short RtoL_slope_one_check_start_point
440:
441: mov esi, M0
442: add esi, dM
443: and esi, F - 1 ; esi = M1
444:
445: add eax, F/2
446: cmp esi, eax ; cmp M1, N1 + F/2
447: jne short RtoL_slope_one_check_start_point
448: mov ulSlopeOneAdjustment, 1
449:
450: RtoL_slope_one_check_start_point:
451: mov eax, M0
452: or eax, eax
453: jz short RtoL_compute_y0_from_x0
454:
455: add eax, F/2
456: cmp eax, N0 ; cmp M0 + 8, N0
457: jne short RtoL_compute_y0_from_x0
458:
459: mov x0, 2 ; x0 = 2
460: mov edx, dN ; ulDelta = dN
461:
462: RtoL_compute_y0_from_x0:
463:
464: ; eax = garbage
465: ; ebx = fl
466: ; ecx = eqGamma_hi
467: ; edx = ulDelta
468: ; esi = garbage
469: ; edi = eqGamma_lo
470:
471: mov eax, dN ; eax = dN
472: mov y0, 0 ; y0 = 0
473:
474: add edi, edx
475: adc ecx, 0 ; eqGamma += ulDelta
476: ; NOTE: Setting flags here!
477: mov edx, dM ; edx = dM
478: jl short RtoL_compute_x1 ; NOTE: Looking at the flags here!
479: jg short RtoL_y0_is_2
480:
481: lea ecx, [edx + edx]
482: sub ecx, eax ; ecx = 2 * dM - dN
483: cmp edi, ecx
484: jge short RtoL_y0_is_2
485:
486: sub ecx, edx ; ecx = dM - dN
487: cmp edi, ecx
488: jl short RtoL_compute_x1
489:
490: mov y0, 1
491: jmp short RtoL_compute_x1
492:
493: RtoL_y0_is_2:
494: mov y0, 2
495:
496: RtoL_compute_x1:
497:
498: ; Register state:
499: ; eax = dN
500: ; ebx = fl
501: ; ecx = garbage
502: ; edx = dM
503: ; esi = garbage
504: ; edi = garbage
505:
506: mov esi, M0
507: add esi, edx
508: mov ecx, esi
509: shr esi, FLOG2 ; x1 = (M0 + dM) >> 4
510: add esi, ulSlopeOneAdjustment
511: and ecx, F-1 ; M1 = (M0 + dM) & 15
512:
513: add eax, N0
514: and eax, F-1 ; N1 = (N0 + dN) & 15
515: jnz short RtoL_N1_not_zero
516:
517: .errnz FL_H_ROUND_DOWN - 80h
518: ror bl, 8
519: sbb ecx, -F/2
520: shr ecx, FLOG2 ; ecx = LROUND(M1, fl & FL_ROUND_DOWN)
521: add esi, ecx
522: jmp done_first_pel_last_pel
523:
524: RtoL_N1_not_zero:
525: sub eax, F/2
526: sbb edx, edx
527: xor eax, edx
528: sub eax, edx
529: add eax, ecx ; eax = ABS(N1 - F/2) + M1
530: cmp eax, F+1
531: sbb esi, -1
532:
533: done_first_pel_last_pel:
534:
535: ; Register state:
536: ; eax = garbage
537: ; ebx = fl
538: ; ecx = garbage
539: ; edx = garbage
540: ; esi = x1
541: ; edi = garbage
542:
543: mov ecx, x0
544: lea edx, [esi + 1]
545: sub edx, ecx ; edx = x1 - x0 + 1
546:
547: jle next_line
548: mov cStylePels, edx
549: mov xStart, ecx
550:
551: ;-----------------------------------------------------------------------;
552: ; See if clipping or styling needs to be done. ;
553: ;-----------------------------------------------------------------------;
554:
555: testb ebx, FL_CLIP
556: jnz do_some_clipping
557:
558: ; Register state:
559: ; eax = garbage
560: ; ebx = fl
561: ; ecx = x0
562: ; edx = garbage
563: ; esi = x1
564: ; edi = garbage
565:
566: done_clipping:
567: mov eax, y0
568:
569: sub esi, ecx
570: inc esi ; esi = cPels = x1 - x0 + 1
571: mov cPels, esi
572:
573: add ecx, x ; ecx = ptlStart.ptl_x
574: add eax, y ; eax = ptlStart.ptl_y
575:
576: testb ebx, FL_FLIP_D
577: jz short do_v_unflip
578: xchg ecx, eax
579:
580: do_v_unflip:
581: testb ebx, FL_FLIP_V
582: jz short done_unflips
583: neg eax
584:
585: done_unflips:
586: testb ebx, FL_STYLED
587: jnz do_some_styling
588:
589: done_styling:
590: lea edx, [strip.ST_alStrips + (STRIP_MAX * 4)]
591: mov plStripEnd, edx
592:
593: ;-----------------------------------------------------------------------;
594: ; Setup to do DDA. ;
595: ;-----------------------------------------------------------------------;
596:
597: ; Register state:
598: ; eax = ptlStart.ptl_y
599: ; ebx = fl
600: ; ecx = ptlStart.ptl_x
601: ; edx = garbage
602: ; esi = garbage
603: ; edi = garbage
604:
605: mov strip.ST_ptlStart.ptl_x, ecx
606: mov strip.ST_ptlStart.ptl_y, eax
607:
608: mov eax, dM
609: mov ecx, dN
610: mov esi, eqGamma_lo
611: mov edi, eqGamma_hi
612:
613:
614: ; Register state:
615: ; eax = dM
616: ; ebx = fl
617: ; ecx = dN
618: ; edx = garbage
619: ; esi = eqGamma_lo
620: ; edi = eqGamma_hi
621:
622: lea edx, [ecx + ecx] ; if (2 * dN > dM)
623: cmp edx, eax
624: mov edx, y0 ; Load y0 again
625: jbe short after_half_flip
626:
627: test ebx, (FL_STYLED + FL_DONT_DO_HALF_FLIP)
628: jnz short after_half_flip
629:
630: or ebx, FL_FLIP_HALF
631: mov fl, ebx
632:
633: ; Do a half flip!
634:
635: not esi
636: not edi
637: add esi, eax
638: adc edi, 0 ; eqGamma = -eqGamma - 1 + dM
639:
640: neg ecx
641: add ecx, eax ; dN = dM - dN
642:
643: neg edx
644: add edx, x0 ; y0 = x0 - y0
645:
646: after_half_flip:
647: mov strip.ST_flFlips, ebx
648: mov eax, dM
649:
650: ; Register state:
651: ; eax = dM
652: ; ebx = fl
653: ; ecx = dN
654: ; edx = y0
655: ; esi = eqGamma_lo
656: ; edi = eqGamma_hi
657:
658: or ecx, ecx
659: jz short zero_slope
660:
661: compute_dda_stuff:
662: inc edx
663: mul edx
664: stc ; set the carry to accomplish -1
665: sbb eax, esi
666: sbb edx, edi ; (y0 + 1) * dM - eqGamma - 1
667: div ecx
668:
669: mov esi, eax ; esi = i
670: mov edi, edx ; edi = r
671:
672: xor edx, edx
673: mov eax, dM
674: div ecx ; edx = d_R, eax = d_I
675: mov d_I, eax
676:
677: sub esi, x0
678: inc esi
679:
680: done_dda_stuff:
681:
682: ; Register state:
683: ; eax = d_I
684: ; ebx = fl
685: ; ecx = dN
686: ; edx = d_R
687: ; esi = i
688: ; edi = r
689:
690: ; We're going to decide if we can call the short-vector routines. They
691: ; can only take strips that have a maximum length of 15 pixels each.
692: ; We happen to know that the longest strip in our line could be is d_I + 1.
693:
694: and ebx, FL_STRIP_MASK
695: mov eax, apfn
696:
697: .errnz FL_STRIP_SHIFT
698: lea eax, [eax + ebx * 4]
699:
700: cmp d_I, MAX_SHORT_STROKE_LENGTH
701: sbb ebx, ebx ; ffffffffh when < 15, 0 when >= 15
702: and ebx, NUM_STRIP_DRAW_DIRECTIONS * 4
703: ; Look four entries further into table
704:
705: mov eax, [eax + ebx]
706: mov pfn, eax
707:
708: lea eax, [strip.ST_alStrips]
709: mov ebx, cPels
710:
711: ;-----------------------------------------------------------------------;
712: ; Do our main DDA loop. ;
713: ;-----------------------------------------------------------------------;
714:
715: ; Register state:
716: ; eax = plStrip
717: ; ebx = cPels
718: ; ecx = dN
719: ; edx = d_R
720: ; esi = i
721: ; edi = r
722:
723: dda_loop:
724: sub ebx, esi
725: jle final_strip
726:
727: mov [eax], esi
728: add eax, 4
729: cmp plStripEnd, eax
730: jbe short output_strips
731:
732: done_output_strips:
733: mov esi, d_I
734: add edi, edx
735: cmp edi, ecx
736: jb short dda_loop
737:
738: sub edi, ecx
739: inc esi
740: jmp short dda_loop
741:
742: zero_slope:
743: mov esi, 7fffffffh ; Make run maximum length (cPels
744: ; actually decideds how long the line
745: ; is)
746: mov d_I, 7fffffffh ; Make delta maximum length so that
747: ; we don't try to do short vectors
748: mov eax, cPels ; We need this when we decide if to do
749: dec eax ; short strip routines.
750: jmp short done_dda_stuff
751:
752: ;-----------------------------------------------------------------------;
753: ; Empty strips buffer. ;
754: ;-----------------------------------------------------------------------;
755:
756: output_strips:
757: mov d_R, edx
758: mov cPels, ebx
759: mov i, esi
760: mov r, edi
761: mov dN, ecx
762:
763: lea edx, [strip.ST_alStrips]
764: sub eax, edx
765: shr eax, 2
766: mov strip.ST_cStrips, eax
767:
768: mov eax, ppdev
769: lea edx, [strip]
770: mov ecx, pls
771:
772: ptrCall <dword ptr pfn>, \
773: <eax, edx, ecx>
774:
775: mov esi, i
776: mov edi, r
777: mov ebx, cPels
778: mov edx, d_R
779: mov ecx, dN
780: lea eax, [strip.ST_alStrips]
781: jmp done_output_strips
782:
783: ;-----------------------------------------------------------------------;
784: ; Empty strips buffer and go on to next line. ;
785: ;-----------------------------------------------------------------------;
786:
787: final_strip:
788: add ebx, esi
789: mov [eax], ebx
790: add eax, 4
791:
792: very_final_strip:
793: lea edx, [strip.ST_alStrips]
794: sub eax, edx
795: shr eax, 2
796: mov strip.ST_cStrips, eax
797:
798: mov eax, ppdev
799: lea edx, [strip]
800: mov ecx, pls
801:
802: ptrCall <dword ptr pfn>, \
803: <eax, edx, ecx>
804:
805: next_line:
806: mov ebx, flStart
807: testb ebx, FL_COMPLEX_CLIP
808: jnz short see_if_done_complex_clipping
809:
810: mov edx, pptfxBuf
811: cmp edx, pptfxBufEnd
812: je short all_done
813:
814: mov esi, [edx].ptl_x
815: mov ecx, [edx].ptl_y
816: add edx, size POINTL
817: mov pptfxBuf, edx
818: mov eax, [edx].ptl_x
819: mov edi, [edx].ptl_y
820: jmp the_main_loop
821:
822: all_done:
823: mov eax, 1
824:
825: cRet bLines
826:
827: see_if_done_complex_clipping:
828: mov ebx, fl
829: dec cptfx
830: jz short all_done
831: jmp continue_complex_clipping
832:
833: ;---------------------------Private-Routine-----------------------------;
834: ; do_some_styling
835: ;
836: ; Inputs:
837: ; eax = ptlStart.ptl_y
838: ; ebx = fl
839: ; ecx = ptlStart.ptl_x
840: ; Preserves:
841: ; eax, ebx, ecx
842: ; Output:
843: ; Exits to done_styling.
844: ;
845: ;-----------------------------------------------------------------------;
846:
847: do_some_styling:
848: mov ptlStart.ptl_x, ecx
849:
850: mov esi, pls
851: mov edi, [esi].LS_spNext ; spThis
852: mov edx, edi
853: add edx, cStylePels ; spNext
854:
855: ; For styles, we don't bother to keep the style position normalized.
856: ; (we do ensure that it's positive, though). If a figure is over 2
857: ; billion pels long, we'll be a pel off in our style state (oops!).
858:
859: and edx, 7fffffffh
860: mov [esi].LS_spNext, edx
861: mov ptlStart.ptl_y, eax
862:
863: ; Do arbitrary styles:
864:
865: do_arbitrary_style:
866: testb ebx, FL_FLIP_H
867: jz short arbitrary_left_to_right
868:
869: sub edx, x0
870: add edx, xStart
871: mov eax, edx
872: xor edx, edx
873: div [esi].LS_spTotal
874:
875: neg edx
876: jge short continue_right_to_left
877: add edx, [esi].LS_spTotal
878: not eax
879:
880: continue_right_to_left:
881: mov edi, dword ptr [esi].LS_jStartMask
882: not edi
883: mov ecx, [esi].LS_aspRtoL
884: jmp short compute_arbitrary_stuff
885:
886: arbitrary_left_to_right:
887: add edi, x0
888: sub edi, xStart
889: mov eax, edi
890: xor edx, edx
891: div [esi].LS_spTotal
892: mov edi, dword ptr [esi].LS_jStartMask
893: mov ecx, [esi].LS_aspLtoR
894:
895: compute_arbitrary_stuff:
896: ; eax = sp / spTotal
897: ; ebx = fl
898: ; ecx = pspStart
899: ; edx = sp % spTotal
900: ; esi = pla
901: ; edi = jStyleMask
902:
903: and eax, [esi].LS_cStyle ; if odd length style and second run
904: and al, 1 ; through style array, flip the
905: jz short odd_style_array_done ; meaning of the elements
906: not edi
907:
908: odd_style_array_done:
909: mov [esi].LS_pspStart, ecx
910: mov eax, [esi].LS_cStyle
911: lea eax, [ecx + eax * 4 - 4]
912: mov [esi].LS_pspEnd, eax
913:
914: find_psp:
915: sub edx, [ecx]
916: jl short found_psp
917: add ecx, 4
918: jmp short find_psp
919:
920: found_psp:
921: mov [esi].LS_psp, ecx
922: neg edx
923: mov [esi].LS_spRemaining, edx
924:
925: sub ecx, [esi].LS_pspStart
926: test ecx, 4 ; size STYLEPOS
927: jz short done_arbitrary
928: not edi
929:
930: done_arbitrary:
931: mov dword ptr [esi].LS_jStyleMask, edi
932: mov eax, ptlStart.ptl_y
933: mov ecx, ptlStart.ptl_x
934: jmp done_styling
935:
936:
937: ;---------------------------Private-Routine-----------------------------;
938: ; do_some_clipping
939: ;
940: ; Inputs:
941: ; eax = garbage
942: ; ebx = fl
943: ; ecx = x0
944: ; edx = garbage
945: ; esi = x1
946: ; edi = garbage
947: ;
948: ; Decides whether to do simple or complex clipping.
949: ;
950: ;-----------------------------------------------------------------------;
951:
952: align 4
953:
954: public do_some_clipping
955: do_some_clipping:
956: testb ebx, FL_COMPLEX_CLIP
957: jnz initialize_complex_clipping
958:
959: ;-----------------------------------------------------------------------;
960: ; simple_clipping
961: ;
962: ; Inputs:
963: ; ebx = fl
964: ; ecx = x0
965: ; esi = x1
966: ; Output:
967: ; ebx = fl
968: ; ecx = new x0 (stack variable updated too)
969: ; esi = new x1
970: ; y0 stack variable updated
971: ; Uses:
972: ; All registers
973: ; Exits:
974: ; to done_clipping
975: ;
976: ; This routine handles clipping the line to the clip rectangle (it's
977: ; faster to handle this case in the driver than to call the engine to
978: ; clip for us).
979: ;
980: ; Fractional end-point lines complicate our lives a bit when doing
981: ; clipping:
982: ;
983: ; 1) For styling, we must know the unclipped line's length in pels, so
984: ; that we can correctly update the styling state when the line is
985: ; clipped. For this reason, I do clipping after doing the hard work
986: ; of figuring out which pixels are at the ends of the line (this is
987: ; wasted work if the line is not styled and is completely clipped,
988: ; but I think it's simpler this way). Another reason is that we'll
989: ; have calculated eqGamma already, which we use for the intercept
990: ; calculations.
991: ;
992: ; With the assumption that most lines will not be completely clipped
993: ; away, this strategy isn't too painful.
994: ;
995: ; 2) x0, y0 are not necessarily zero, where (x0, y0) is the start pel of
996: ; the line.
997: ;
998: ; 3) We know x0, y0 and x1, but not y1. We haven't needed to calculate
999: ; y1 until now. We'll need the actual value, and not an upper bound
1000: ; like y1 = LFLOOR(dM) + 2 because we have to be careful when
1001: ; calculating x(y) that y0 <= y <= y1, otherwise we can cause an
1002: ; overflow on the divide (which, needless to say, is bad).
1003: ;
1004: ;-----------------------------------------------------------------------;
1005:
1006: public simple_clipping
1007: simple_clipping:
1008: mov edi, prclClip ; get pointer to normalized clip rect
1009: and ebx, FL_RECTLCLIP_MASK ; (it's lower-right exclusive)
1010:
1011: .errnz (FL_RECTLCLIP_SHIFT - 2); ((ebx AND FL_RECTLCLIP_MASK) shr
1012: .errnz (size RECTL) - 16 ; FL_RECTLCLIP_SHIFT) is our index
1013: lea edi, [edi + ebx*4] ; into the array of rectangles
1014:
1015: mov edx, [edi].xRight ; load the rect coordinates
1016: mov eax, [edi].xLeft
1017: mov ebx, [edi].yBottom
1018: mov edi, [edi].yTop
1019:
1020: ; Translate to our origin and so some quick completely clipped tests:
1021:
1022: sub edx, x
1023: cmp ecx, edx
1024: jge totally_clipped ; totally clipped if x0 >= xRight
1025:
1026: sub eax, x
1027: cmp esi, eax
1028: jl totally_clipped ; totally clipped if x1 < xLeft
1029:
1030: sub ebx, y
1031: cmp y0, ebx
1032: jge totally_clipped ; totally clipped if y0 >= yBottom
1033:
1034: sub edi, y
1035:
1036: ; Save some state:
1037:
1038: mov xClipRight, edx
1039: mov xClipLeft, eax
1040:
1041: cmp esi, edx ; if (x1 >= xRight) x1 = xRight - 1
1042: jl short calculate_y1
1043: lea esi, [edx - 1]
1044:
1045: calculate_y1:
1046: mov eax, esi ; y1 = (x1 * dN + eqGamma) / dM
1047: mul dN
1048: add eax, eqGamma_lo
1049: adc edx, eqGamma_hi
1050: div dM
1051:
1052: cmp edi, eax ; if (yTop > y1) clipped
1053: jg short totally_clipped
1054:
1055: cmp ebx, eax ; if (yBottom > y1) know x1
1056: jg short x1_computed
1057:
1058: mov eax, ebx ; x1 = (yBottom * dM + eqBeta) / dN
1059: mul dM
1060: stc
1061: sbb eax, eqGamma_lo
1062: sbb edx, eqGamma_hi
1063: div dN
1064: mov esi, eax
1065:
1066: ; At this point, we've taken care of calculating the intercepts with the
1067: ; right and bottom edges. Now we work on the left and top edges:
1068:
1069: x1_computed:
1070: mov edx, y0
1071:
1072: mov eax, xClipLeft ; don't have to compute y intercept
1073: cmp eax, ecx ; at left edge if line starts to
1074: jle short top_intercept ; right of left edge
1075:
1076: mov ecx, eax ; x0 = xLeft
1077: mul dN ; y0 = (xLeft * dN + eqGamma) / dM
1078: add eax, eqGamma_lo
1079: adc edx, eqGamma_hi
1080: div dM
1081:
1082: cmp ebx, eax ; if (yBottom <= y0) clipped
1083: jle short totally_clipped
1084:
1085: mov edx, eax
1086: mov y0, eax
1087:
1088: top_intercept:
1089: mov ebx, fl ; get ready to leave
1090: mov x0, ecx
1091:
1092: cmp edi, edx ; if (yTop <= y0) done clipping
1093: jle done_clipping
1094:
1095: mov eax, edi ; x0 = (yTop * dM + eqBeta) / dN + 1
1096: mul dM
1097: stc
1098: sbb eax, eqGamma_lo
1099: sbb edx, eqGamma_hi
1100: div dN
1101: lea ecx, [eax + 1]
1102:
1103: cmp xClipRight, ecx ; if (xRight <= x0) clipped
1104: jle short totally_clipped
1105:
1106: mov y0, edi ; y0 = yTop
1107: mov x0, ecx
1108: jmp done_clipping ; all done!
1109:
1110: totally_clipped:
1111:
1112: ; The line is completely clipped. See if we have to update our style state:
1113:
1114: mov ebx, fl
1115: testb ebx, FL_STYLED
1116: jz next_line
1117:
1118: ; Adjust our style state:
1119:
1120: mov esi, pls
1121: mov eax, [esi].LS_spNext
1122: add eax, cStylePels
1123: mov [esi].LS_spNext, eax
1124:
1125: cmp eax, [esi].LS_spTotal2
1126: jb next_line
1127:
1128: ; Have to normalize first:
1129:
1130: xor edx, edx
1131: div [esi].LS_spTotal2
1132: mov [esi].LS_spNext, edx
1133:
1134: jmp next_line
1135:
1136: ;-----------------------------------------------------------------------;
1137:
1138: initialize_complex_clipping:
1139: mov eax, dN ; save a copy of original dN
1140: mov dN_Original, eax
1141:
1142: ;---------------------------Private-Routine-----------------------------;
1143: ; continue_complex_clipping
1144: ;
1145: ; Inputs:
1146: ; ebx = fl
1147: ; Output:
1148: ; ebx = fl
1149: ; ecx = x0
1150: ; esi = x1
1151: ; Uses:
1152: ; All registers.
1153: ; Exits:
1154: ; to done_clipping
1155: ;
1156: ; This routine handles the necessary initialization for the next
1157: ; run in the CLIPLINE structure.
1158: ;
1159: ; NOTE: This routine is jumped to from two places!
1160: ;-----------------------------------------------------------------------;
1161:
1162: public continue_complex_clipping
1163: continue_complex_clipping:
1164: mov edi, prun
1165: mov ecx, xStart
1166: testb ebx, FL_FLIP_H
1167: jz short complex_left_to_right
1168:
1169: complex_right_to_left:
1170:
1171: ; Figure out x0 and x1 for right-to-left lines:
1172:
1173: add ecx, cStylePels
1174: dec ecx
1175: mov esi, ecx ; esi = ecx = xStart + cStylePels - 1
1176: sub ecx, [edi].RUN_iStop ; New x0
1177: sub esi, [edi].RUN_iStart ; New x1
1178: jmp short complex_reset_variables
1179:
1180: complex_left_to_right:
1181:
1182: ; Figure out x0 and x1 for left-to-right lines:
1183:
1184: mov esi, ecx ; esi = ecx = xStart
1185: add ecx, [edi].RUN_iStart ; New x0
1186: add esi, [edi].RUN_iStop ; New x1
1187:
1188: complex_reset_variables:
1189: mov x0, ecx
1190:
1191: ; The half flip mucks with some of our variables, and we have to reset
1192: ; them every pass. We would have to reset eqGamma too, but it never
1193: ; got saved to memory in its modified form.
1194:
1195: add edi, size RUN
1196: mov prun, edi ; Increment run pointer for next time
1197:
1198: mov edi, pls
1199: mov eax, [edi].LS_spComplex
1200: mov [edi].LS_spNext, eax ; pls->spNext = pls->spComplex
1201:
1202: mov eax, dN_Original ; dN = dN_Original
1203: mov dN, eax
1204:
1205: mul ecx
1206: add eax, eqGamma_lo
1207: adc edx, eqGamma_hi ; [edx:eax] = dN*x0 + eqGamma
1208:
1209: div dM
1210: mov y0, eax
1211: jmp done_clipping
1212:
1213: endProc bLines
1214: end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.