]> 4ch.mooo.com Git - 16.git/blob - 16/xlib/xbezier.asm
more
[16.git] / 16 / xlib / xbezier.asm
1 \r
2 ;-----------------------------------------------------------------------\r
3 ; MODULE XBEZIER\r
4 ;\r
5 ;\r
6 ; Compile with TASM.\r
7 ; C near-callable.\r
8 ;\r
9 ; This module was written by Matthew MacKenzie\r
10 ; matm@eng.umd.edu\r
11 ;-----------------------------------------------------------------------\r
12 include xlib.inc\r
13 include xbezier.inc\r
14 \r
15 \r
16 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
17 ; _x_bezier\r
18 ;\r
19 ; Plot a Bezier curve, which is described by a box of two endpoints\r
20 ; and two control points:\r
21 ;                           C1--------C2\r
22 ;                           /           \\r
23 ;                          /             \\r
24 ;                        E1..............E2\r
25 ;\r
26 ; All coordinates must be in the range -1024 to 3071.\r
27 ; No clipping is performed.\r
28 ;\r
29 ; C near-callable as:\r
30 ; x_bezier (int E1x, int E1y, int C1x, int C1y, int C2x, int C2y,\r
31 ;           int E2x, int E2y, int levels, char color,\r
32 ;           unsigned int PageOffset);\r
33 ;\r
34 ; All four main registers are totaled.\r
35 ; This function may use as many as 162 bytes of stack space.\r
36 \r
37 ; Bezier curves need 32-bit precision, so we'll define macros and\r
38 ; constants for operations on 32-bit virtual registers V0, V1, and V2.\r
39 ; V0 is made up of DI and AX, V1 of SI and BX, and V2 of CX and DX.\r
40 \r
41 LowWord         equ     0\r
42 HighWord        equ     2\r
43 \r
44 ; to load data --\r
45 \r
46 LoadV0 macro loc, field\r
47     mov ax, word ptr [bp + loc + field + LowWord]\r
48     mov di, word ptr [bp + loc + field + HighWord]\r
49     endm\r
50 \r
51 LoadV1 macro loc, field\r
52     mov bx, word ptr [bp + loc + field + LowWord]\r
53     mov si, word ptr [bp + loc + field + HighWord]\r
54     endm\r
55 \r
56 LoadV2 macro loc, field\r
57     mov dx, word ptr [bp + loc + field + LowWord]\r
58     mov cx, word ptr [bp + loc + field + HighWord]\r
59     endm\r
60 \r
61 ; to store data --\r
62 \r
63 StoreV0 macro loc, field\r
64     mov word ptr [bp + loc + field + LowWord], ax\r
65     mov word ptr [bp + loc + field + HighWord], di\r
66     endm\r
67 \r
68 StoreV1 macro loc, field\r
69     mov word ptr [bp + loc + field + LowWord], bx\r
70     mov word ptr [bp + loc + field + HighWord], si\r
71     endm\r
72 \r
73 \r
74 ; to take the average of two registers (result is in first register) --\r
75 \r
76 AverageV0nV1 macro\r
77         add ax, bx\r
78         adc di, si\r
79         shr di, 1\r
80         rcr ax, 1\r
81         endm\r
82 \r
83 AverageV0nV2 macro\r
84         add ax, dx\r
85         adc di, cx\r
86         shr di, 1\r
87         rcr ax, 1\r
88         endm\r
89 \r
90 AverageV1nV2 macro\r
91         add bx, dx\r
92         adc si, cx\r
93         shr si, 1\r
94         rcr bx, 1\r
95         endm\r
96 \r
97 \r
98 ; to take the average of a register and data --\r
99 \r
100 AverageV1nData macro loc, field\r
101     add bx, word ptr [bp + loc + field + LowWord]\r
102     adc si, word ptr [bp + loc + field + HighWord]\r
103     shr si, 1\r
104     rcr bx, 1\r
105     endm\r
106 \r
107 AverageV2nData macro loc, field\r
108     add dx, word ptr [bp + loc + field + LowWord]\r
109     adc cx, word ptr [bp + loc + field + HighWord]\r
110     shr cx, 1\r
111     rcr dx, 1\r
112     endm\r
113 \r
114 \r
115 ; to turn a 32-bit fixed point data into a regular integer --\r
116 \r
117 Extract macro reg, source, field\r
118         mov reg, word ptr [bp + source + field + HighWord]\r
119         shr reg, 3\r
120         adc reg, 0          ; round\r
121         endm\r
122 \r
123 \r
124 ; to turn an integer argument into a 32-bit fixed point number\r
125 ; and store it as local data --\r
126 \r
127 Convert macro source, dest, field\r
128         mov ax, source\r
129         add ax, 1024\r
130         shl ax, 3\r
131         push ax\r
132         push 0\r
133         endm\r
134 \r
135 \r
136 ; useful numbers for dealing with Bezier boxes (sets of four points) --\r
137 \r
138 XCoord      equ     4\r
139 YCoord      equ     0\r
140 \r
141 ; stack offsets for splitting boxes\r
142 E1Src       equ     48\r
143 C1Src       equ     40\r
144 C2Src       equ     32\r
145 E2Src       equ     24\r
146 \r
147 E1Dest      equ     48\r
148 P1Dest      equ     40\r
149 P4Dest      equ     32\r
150 P6Dest      equ     24\r
151 P5Dest      equ     16\r
152 P2Dest      equ     8\r
153 E2Dest      equ     0\r
154 \r
155 ; stack offsets for drawing boxes\r
156 E1Draw      equ     24\r
157 C1Draw      equ     16\r
158 C2Draw      equ     8\r
159 E2Draw      equ     0\r
160 \r
161     .data\r
162 \r
163     align 2\r
164 \r
165 ; depth of recursion at which to plot\r
166 WhenToDraw label byte\r
167    db 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4\r
168    db 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5\r
169 \r
170 \r
171 ; since we'll be moving bp and sp in our recursion,\r
172 ; we need to put local storage in the data segment\r
173 level           dw  (?)\r
174 gencount        dw  (?)\r
175 AdjustedOffs    dw  (?)\r
176 p1xt            dw  (?)\r
177 p1yt            dw  (?)\r
178 p2xt            dw  (?)\r
179 p2yt            dw  (?)\r
180 p4xt            dw  (?)\r
181 p4yt            dw  (?)\r
182 p5xt            dw  (?)\r
183 p5yt            dw  (?)\r
184 c1xt            dw  (?)\r
185 c1yt            dw  (?)\r
186 c2xt            dw  (?)\r
187 c2yt            dw  (?)\r
188 xdiff           dw  (?)\r
189 ydiff           dw  (?)\r
190 moveline        dw  (?)\r
191 stepper         dw  (?)\r
192 bptemp          dw  (?)\r
193 \r
194 ; by the same token we need a copy of this argument\r
195 Colort          dw  (?)\r
196 \r
197 \r
198 ColumnMasks label byte\r
199     db 011h, 022h, 044h, 088h\r
200 \r
201     .code\r
202 \r
203     align 2\r
204 _x_bezier proc\r
205 ARG     E1x, E1y, C1x, C1y, C2x, C2y, E2x, E2y, Levels, Color, PageOffs:word\r
206 \r
207     push bp\r
208     mov bp, sp          ; caller's stack frame\r
209     push si\r
210     push di\r
211     push es\r
212 \r
213         ; set local variables\r
214     mov ax, -1024       ; 1024 rows\r
215     imul [_ScrnLogicalByteWidth]\r
216     add ax, PageOffs\r
217     sub ax, 256         ; 1024 columns\r
218     mov AdjustedOffs, ax ; subtract 1024 rows and 1024 columns\r
219 \r
220 ; copy color into data segment so we can change bp & sp\r
221     mov ax, Color\r
222         mov Colort, ax\r
223 \r
224         mov cx, Levels\r
225         dec cx              ; gencount (number of boxes we will actually plot) =\r
226         mov ax,1            ; 2^(Levels - 1)\r
227         shl ax,cl\r
228         dec ax\r
229         mov gencount, ax\r
230 \r
231         mov [level], 0      ; variable to tell us where we are in the stack\r
232         mov bptemp, bp          ; when the dust settles at the end\r
233 \r
234 ; translate coordinates for adjusted offset, convert 'em to fixed-point\r
235 ; with 13 bits for the integer part and 19 for the fractional part,\r
236 ; and push them onto the stack in the right order to for a Bezier box\r
237 \r
238         Convert E2x\r
239         Convert E2y\r
240 \r
241         Convert C2x\r
242         Convert C2y\r
243 \r
244         Convert C1x\r
245         Convert C1y\r
246 \r
247         Convert E1x\r
248         Convert E1y\r
249 \r
250         mov bp, sp          ; we are using them as basically one pointer\r
251 \r
252         mov ax, 0a000h      ; point extra segment to VGA memory\r
253     mov es, ax\r
254 \r
255     mov dx, SC_INDEX\r
256     mov al, MAP_MASK\r
257     out dx, al\r
258 \r
259 MainLoop:\r
260     mov si, gencount\r
261     mov ax, 0\r
262     mov al, WhenToDraw[si]\r
263     cmp ax, level       ; are we at a terminal curve?\r
264     jne Recurse\r
265     jmp PlotCurve\r
266 \r
267 Recurse:\r
268 ; not at a terminal -- so expand this curve into two more and recurse\r
269 \r
270 ; start with:\r
271 ;    C1___C2\r
272 ;     |    |\r
273 ;    E1...E2\r
274 ;\r
275 ; stack looks like:  E1 C1 C2 E2\r
276 \r
277 ; expand like this:\r
278 ;    C1.....P3.....C2\r
279 ;     .   .     .   .\r
280 ;     . _P4_P6__P5_ .\r
281 ;    P1-   .. ..   P2\r
282 ;     |  ..     ..  |\r
283 ;     |..         ..|\r
284 ;    E1............E2\r
285 ;\r
286 ; stack looks like:  E1 P1 P4 P6 P5 P2 E2\r
287 ; Since P6 is part of both new boxes, we use it twice.\r
288 \r
289     sub sp, 24\r
290     sub bp, 24\r
291 \r
292 ; new points for X --\r
293     LoadV0      E1Src, XCoord\r
294     LoadV1      E2Src, XCoord\r
295     StoreV1     E2Dest, XCoord\r
296     LoadV2      C1Src, XCoord\r
297     AverageV0nV2\r
298     StoreV0     P1Dest, XCoord\r
299     AverageV1nData C2Src, XCoord\r
300     StoreV1     P2Dest, XCoord\r
301     AverageV2nData C2Src, XCoord\r
302     AverageV0nV2\r
303     StoreV0     P4Dest, XCoord\r
304     AverageV1nV2\r
305     StoreV1     P5Dest, XCoord\r
306     AverageV0nV1\r
307         StoreV0     P6Dest, XCoord\r
308 \r
309 ; same thing for Y --\r
310     LoadV0      E1Src, YCoord\r
311     LoadV1      E2Src, YCoord\r
312     StoreV1     E2Dest, YCoord\r
313     LoadV2      C1Src, YCoord\r
314     AverageV0nV2\r
315     StoreV0     P1Dest, YCoord\r
316     AverageV1nData C2Src, YCoord\r
317     StoreV1     P2Dest, YCoord\r
318     AverageV2nData C2Src, YCoord\r
319     AverageV0nV2\r
320     StoreV0     P4Dest, YCoord\r
321     AverageV1nV2\r
322     StoreV1     P5Dest, YCoord\r
323     AverageV0nV1\r
324     StoreV0     P6Dest, YCoord\r
325 \r
326     inc level           ; one level further into stack\r
327     jmp MainLoop\r
328 \r
329 PlotCurve:\r
330 ; pull 16-bit coordinates back out of 32-bit fixed-point coordinates;\r
331 ; integer part is highest 13 bits\r
332 \r
333         Extract cx, C1Draw, XCoord\r
334         Extract di, E1Draw, XCoord\r
335     mov c1xt, cx\r
336     add cx, di\r
337     shr cx, 1\r
338     mov p1xt, cx\r
339 \r
340     Extract ax, C1Draw, YCoord\r
341     Extract si, E1Draw, YCoord\r
342     mov c1yt, ax\r
343     add ax, si\r
344     shr ax, 1\r
345         mov p1yt, ax\r
346         call ShortLine      ; line from P1 to E1\r
347 \r
348         Extract cx, E2Draw, XCoord\r
349         Extract di, C2Draw, XCoord\r
350         mov c2xt, di\r
351         add di, cx\r
352         shr di, 1\r
353         mov p2xt, di\r
354 \r
355         Extract ax, E2Draw, YCoord\r
356         Extract si, C2Draw, YCoord\r
357         mov c2yt, si\r
358         add si, ax\r
359         shr si, 1\r
360         mov p2yt, si\r
361         call ShortLine      ; line from E2 to P2\r
362 \r
363 ; P3 is not in any line we draw, so we'll use it now to find both P5\r
364 ; for the line after this on, and P4 for this line, then discard it --\r
365         mov bx, c1xt\r
366         add bx, c2xt\r
367         shr bx, 1\r
368         mov dx, c1yt\r
369         add dx, c2yt\r
370         shr dx, 1\r
371 \r
372 ; find P5 x and save for later lines\r
373         mov cx, p2xt\r
374         add cx, bx\r
375         shr cx, 1\r
376         mov p5xt, cx\r
377 ; find P4 x for this line\r
378         mov cx, p1xt\r
379         add cx, bx\r
380         shr cx, 1\r
381         mov p4xt, cx\r
382         mov di, p1xt\r
383 \r
384 ; find P5 y and save for later lines\r
385         mov ax, p2yt\r
386         add ax, dx\r
387         shr ax, 1\r
388         mov p5yt, ax\r
389 ; find P4 y for this line\r
390         mov ax, p1yt\r
391         add ax, dx\r
392         shr ax, 1\r
393         mov p4yt, ax\r
394         mov si, p1yt\r
395         call ShortLine      ; line from P4 to P1 -- finally!\r
396 \r
397 ; we've already done all the work for these last two --\r
398         mov cx, p2xt\r
399         mov di, p5xt\r
400         mov ax, p2yt\r
401         mov si, p5yt\r
402         call ShortLine      ; line from P2 to P5\r
403 \r
404         mov cx, p5xt\r
405         mov di, p4xt\r
406         mov ax, p5yt\r
407         mov si, p4yt\r
408         call ShortLine      ; line from P5 to P4\r
409 \r
410 ; we've drawn our five lines; this bezier box\r
411 ; can be dropped off the stack\r
412     add bp, 24\r
413     add sp, 24\r
414 \r
415     dec gencount\r
416     mov cx, gencount\r
417     cmp cx, -1\r
418 \r
419     je WrapUp           ; if we've generated all the terminal nodes we\r
420                         ; are supposed to, we pack our bags and go.\r
421         dec level\r
422     jmp MainLoop\r
423 \r
424 WrapUp:\r
425 ; plot the final point, which is simply the original E1\r
426 \r
427     mov bp, bptemp      ; back where we started\r
428     mov ax, E1y\r
429     add ax, 1024\r
430     mul [_ScrnLogicalByteWidth]\r
431     mov di, E1x\r
432     add di, 1024\r
433     mov si, di\r
434     shr di, 2\r
435     add di, ax\r
436     add di, AdjustedOffs\r
437     and si, 3\r
438     mov al, ColumnMasks[si]\r
439     mov ah, byte ptr Color\r
440     mov dx, SC_INDEX + 1\r
441     out dx, al\r
442     mov es:[di], ah\r
443 \r
444     pop es\r
445     pop di\r
446     pop si\r
447     mov sp, bp\r
448     pop bp\r
449     ret                 ; git\r
450 \r
451 ; ShortLine subfunction --\r
452 ;\r
453 ; This is designed for short line segments.  For longer lines,\r
454 ; especially horizontal ones, the x_line routine in the XLINE module\r
455 ; would be faster.  But calling that from here it would be a lot of\r
456 ; extra complication.  This is part of the x_bezier routine because\r
457 ; it has no particular outside use, and we can call it much faster\r
458 ; through registers than through the stack.\r
459 ;\r
460 ; Since our line segments overlap, the second endpoint is not drawn.\r
461 ; These routines are all out of order for the sake of conditional jumps.\r
462 \r
463 LRHorz:\r
464         dec di\r
465 LRHorzLoop:\r
466         rol al, 1\r
467         adc bx, 0\r
468         out dx, al\r
469         mov es:[bx], ah\r
470         sub di, 1\r
471         jg LRHorzLoop\r
472         retn\r
473 \r
474 ; You are in a maze of little subroutines, all alike...\r
475 \r
476 \r
477 LR45Deg:\r
478     dec si\r
479 LR45DegLoop:\r
480     add bx, cx\r
481     rol al, 1\r
482     adc bx, 0\r
483     out dx, al\r
484     mov es:[bx], ah\r
485     sub si, 1\r
486     jg LR45DegLoop\r
487         retn\r
488 \r
489 \r
490 LRXMajor:\r
491     mov cx, di\r
492     dec cx\r
493     shr di, 1\r
494 LRXMajorLoop:\r
495     sub di, si\r
496     jge LRXMajorIterate\r
497     add di, xdiff\r
498     add bx, moveline\r
499 LRXMajorIterate:\r
500     rol al, 1\r
501     adc bx, 0\r
502     out dx, al\r
503     mov es:[bx], ah\r
504     sub cx, 1\r
505     jg LRXMajorLoop\r
506         retn\r
507 \r
508 \r
509 LeftToRight:\r
510     mov xdiff, di       ; store distance across line\r
511 \r
512     mov cx, [_ScrnLogicalByteWidth]\r
513     cmp si, 0           ; check if height is positive, negative, or zero\r
514     je LRHorz\r
515     jg LRTopToBottom\r
516     neg si\r
517     neg cx\r
518 LRTopToBottom:\r
519     mov ydiff, si\r
520     mov moveline, cx\r
521     cmp di, si\r
522     jg LRXMajor\r
523     je LR45Deg\r
524 \r
525 \r
526 LRYMajor:\r
527     mov cx, si\r
528     dec cx\r
529     shr si, 1\r
530 LRYMajorLoop:\r
531     add bx, moveline\r
532     sub si, di\r
533     jge LRYMajorIterate\r
534     add si, ydiff\r
535     rol al, 1\r
536     adc bx, 0\r
537 LRYMajorIterate:\r
538     out dx, al\r
539     mov es:[bx], ah\r
540     sub cx, 1\r
541     jg LRYMajorLoop\r
542         retn\r
543 \r
544 \r
545 ; This is the actual starting point.\r
546 ; On entry, registers look like this:\r
547 ; X1: cx\r
548 ; Y1: ax\r
549 ; X2: di\r
550 ; Y2: si\r
551 ShortLine:\r
552     sub si, ax          ; height goes out in si\r
553     sub di, cx          ; width goes out in di\r
554 \r
555     mul [_ScrnLogicalByteWidth]\r
556     mov dx, cx\r
557     shr dx, 2\r
558     add ax, dx\r
559     add ax, AdjustedOffs\r
560     mov bx, ax          ; starting byte of X1, Y1 goes out in bx\r
561     and cx, 3\r
562     mov ax, 011h\r
563     shl al, cl          ; column mask goes out in al\r
564     mov dx, SC_INDEX + 1\r
565     mov ah, byte ptr Colort; color goes out in ah\r
566     out dx, al\r
567     mov es:[bx], ah     ; plot first point\r
568 \r
569     cmp di, 0\r
570 \r
571     jg LeftToRight\r
572     je VerticalLine\r
573 \r
574 \r
575 RightToLeft:\r
576     neg di              ; much more useful this way\r
577     mov xdiff, di\r
578 \r
579     mov cx, [_ScrnLogicalByteWidth]\r
580     cmp si, 0           ; check if height is positive, negative, or zero\r
581     je RLHorz\r
582     jg RLTopToBottom\r
583     neg si\r
584     neg cx\r
585 RLTopToBottom:\r
586     mov ydiff, si\r
587     mov moveline, cx\r
588     cmp di, si\r
589     jg RLXMajor\r
590     je RL45Deg\r
591 \r
592 \r
593 RLYMajor:\r
594     mov cx, si\r
595     dec cx\r
596     shr si, 1\r
597 RLYMajorLoop:\r
598     add bx, moveline\r
599     sub si, di\r
600     jge RLYMajorIterate\r
601     add si, ydiff\r
602     ror al, 1\r
603     sbb bx, 0\r
604 RLYMajorIterate:\r
605     out dx, al\r
606     mov es:[bx], ah\r
607     sub cx, 1\r
608     jg RLYMajorLoop\r
609         retn\r
610 \r
611 \r
612 VerticalLine:\r
613     mov cx, [_ScrnLogicalByteWidth]\r
614     cmp si, 0           ; check if height is positive\r
615     jg VTopToBottom\r
616     neg si\r
617     neg cx\r
618 VTopToBottom:\r
619     dec si\r
620 VLoop:\r
621     add bx, cx\r
622     mov es:[bx], ah\r
623     sub si, 1\r
624     jg VLoop\r
625         retn\r
626 \r
627 \r
628 RLHorz:\r
629     dec di\r
630 RLHorzLoop:\r
631     ror al, 1\r
632     sbb bx, 0\r
633     out dx, al\r
634     mov es:[bx], ah\r
635     sub di, 1\r
636     jg RLHorzLoop\r
637         retn\r
638 \r
639 \r
640 RL45Deg:\r
641     dec si\r
642 RL45DegLoop:\r
643     add bx, cx\r
644     ror al, 1\r
645     sbb bx, 0\r
646     out dx, al\r
647     mov es:[bx], ah\r
648     sub si, 1\r
649     jg RL45DegLoop\r
650         retn\r
651 \r
652 \r
653 RLXMajor:\r
654     mov cx, di\r
655     dec cx\r
656     shr di, 1\r
657 RLXMajorLoop:\r
658     sub di, si\r
659     jge RLXMajorIterate\r
660     add di, xdiff\r
661     add bx, moveline\r
662 RLXMajorIterate:\r
663     ror al, 1\r
664     sbb bx, 0\r
665     out dx, al\r
666     mov es:[bx], ah\r
667     sub cx,1\r
668     jg RLXMajorLoop\r
669         retn\r
670 \r
671 \r
672 _x_bezier endp\r
673 \r
674     end\r
675 \r