2 ;-----------------------------------------------------------------------
\r
9 ; This module was written by Matthew MacKenzie
\r
11 ;-----------------------------------------------------------------------
\r
16 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\r
19 ; Plot a Bezier curve, which is described by a box of two endpoints
\r
20 ; and two control points:
\r
24 ; E1..............E2
\r
26 ; All coordinates must be in the range -1024 to 3071.
\r
27 ; No clipping is performed.
\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
34 ; All four main registers are totaled.
\r
35 ; This function may use as many as 162 bytes of stack space.
\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
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
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
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
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
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
74 ; to take the average of two registers (result is in first register) --
\r
98 ; to take the average of a register and data --
\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
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
115 ; to turn a 32-bit fixed point data into a regular integer --
\r
117 Extract macro reg, source, field
\r
118 mov reg, word ptr [bp + source + field + HighWord]
\r
124 ; to turn an integer argument into a 32-bit fixed point number
\r
125 ; and store it as local data --
\r
127 Convert macro source, dest, field
\r
136 ; useful numbers for dealing with Bezier boxes (sets of four points) --
\r
141 ; stack offsets for splitting boxes
\r
155 ; stack offsets for drawing boxes
\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
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
175 AdjustedOffs dw (?)
\r
194 ; by the same token we need a copy of this argument
\r
198 ColumnMasks label byte
\r
199 db 011h, 022h, 044h, 088h
\r
205 ARG E1x, E1y, C1x, C1y, C2x, C2y, E2x, E2y, Levels, Color, PageOffs:word
\r
208 mov bp, sp ; caller's stack frame
\r
213 ; set local variables
\r
214 mov ax, -1024 ; 1024 rows
\r
215 imul [_ScrnLogicalByteWidth]
\r
217 sub ax, 256 ; 1024 columns
\r
218 mov AdjustedOffs, ax ; subtract 1024 rows and 1024 columns
\r
220 ; copy color into data segment so we can change bp & sp
\r
225 dec cx ; gencount (number of boxes we will actually plot) =
\r
226 mov ax,1 ; 2^(Levels - 1)
\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
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
250 mov bp, sp ; we are using them as basically one pointer
\r
252 mov ax, 0a000h ; point extra segment to VGA memory
\r
262 mov al, WhenToDraw[si]
\r
263 cmp ax, level ; are we at a terminal curve?
\r
268 ; not at a terminal -- so expand this curve into two more and recurse
\r
275 ; stack looks like: E1 C1 C2 E2
\r
277 ; expand like this:
\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
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
298 StoreV0 P1Dest, XCoord
\r
299 AverageV1nData C2Src, XCoord
\r
300 StoreV1 P2Dest, XCoord
\r
301 AverageV2nData C2Src, XCoord
\r
303 StoreV0 P4Dest, XCoord
\r
305 StoreV1 P5Dest, XCoord
\r
307 StoreV0 P6Dest, XCoord
\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
315 StoreV0 P1Dest, YCoord
\r
316 AverageV1nData C2Src, YCoord
\r
317 StoreV1 P2Dest, YCoord
\r
318 AverageV2nData C2Src, YCoord
\r
320 StoreV0 P4Dest, YCoord
\r
322 StoreV1 P5Dest, YCoord
\r
324 StoreV0 P6Dest, YCoord
\r
326 inc level ; one level further into stack
\r
330 ; pull 16-bit coordinates back out of 32-bit fixed-point coordinates;
\r
331 ; integer part is highest 13 bits
\r
333 Extract cx, C1Draw, XCoord
\r
334 Extract di, E1Draw, XCoord
\r
340 Extract ax, C1Draw, YCoord
\r
341 Extract si, E1Draw, YCoord
\r
346 call ShortLine ; line from P1 to E1
\r
348 Extract cx, E2Draw, XCoord
\r
349 Extract di, C2Draw, XCoord
\r
355 Extract ax, E2Draw, YCoord
\r
356 Extract si, C2Draw, YCoord
\r
361 call ShortLine ; line from E2 to P2
\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
372 ; find P5 x and save for later lines
\r
377 ; find P4 x for this line
\r
384 ; find P5 y and save for later lines
\r
389 ; find P4 y for this line
\r
395 call ShortLine ; line from P4 to P1 -- finally!
\r
397 ; we've already done all the work for these last two --
\r
402 call ShortLine ; line from P2 to P5
\r
408 call ShortLine ; line from P5 to P4
\r
410 ; we've drawn our five lines; this bezier box
\r
411 ; can be dropped off the stack
\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
425 ; plot the final point, which is simply the original E1
\r
427 mov bp, bptemp ; back where we started
\r
430 mul [_ScrnLogicalByteWidth]
\r
436 add di, AdjustedOffs
\r
438 mov al, ColumnMasks[si]
\r
439 mov ah, byte ptr Color
\r
440 mov dx, SC_INDEX + 1
\r
451 ; ShortLine subfunction --
\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
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
474 ; You are in a maze of little subroutines, all alike...
\r
496 jge LRXMajorIterate
\r
510 mov xdiff, di ; store distance across line
\r
512 mov cx, [_ScrnLogicalByteWidth]
\r
513 cmp si, 0 ; check if height is positive, negative, or zero
\r
533 jge LRYMajorIterate
\r
545 ; This is the actual starting point.
\r
546 ; On entry, registers look like this:
\r
552 sub si, ax ; height goes out in si
\r
553 sub di, cx ; width goes out in di
\r
555 mul [_ScrnLogicalByteWidth]
\r
559 add ax, AdjustedOffs
\r
560 mov bx, ax ; starting byte of X1, Y1 goes out in bx
\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
567 mov es:[bx], ah ; plot first point
\r
576 neg di ; much more useful this way
\r
579 mov cx, [_ScrnLogicalByteWidth]
\r
580 cmp si, 0 ; check if height is positive, negative, or zero
\r
600 jge RLYMajorIterate
\r
613 mov cx, [_ScrnLogicalByteWidth]
\r
614 cmp si, 0 ; check if height is positive
\r
659 jge RLXMajorIterate
\r