home *** CD-ROM | disk | FTP | other *** search
-
- ;-----------------------------------------------------------------------
- ; MODULE XBEZIER
- ;
- ;
- ; Compile with TASM.
- ; C near-callable.
- ;
- ; This module was written by Matthew MacKenzie
- ; matm@eng.umd.edu
- ;-----------------------------------------------------------------------
- include xlib.inc
- include xbezier.inc
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; _x_bezier
- ;
- ; Plot a Bezier curve, which is described by a box of two endpoints
- ; and two control points:
- ; C1--------C2
- ; / \
- ; / \
- ; E1..............E2
- ;
- ; All coordinates must be in the range -1024 to 3071.
- ; No clipping is performed.
- ;
- ; C near-callable as:
- ; x_bezier (int E1x, int E1y, int C1x, int C1y, int C2x, int C2y,
- ; int E2x, int E2y, int levels, char color,
- ; unsigned int PageOffset);
- ;
- ; All four main registers are totaled.
- ; This function may use as many as 162 bytes of stack space.
-
- ; Bezier curves need 32-bit precision, so we'll define macros and
- ; constants for operations on 32-bit virtual registers V0, V1, and V2.
- ; V0 is made up of DI and AX, V1 of SI and BX, and V2 of CX and DX.
-
- LowWord equ 0
- HighWord equ 2
-
- ; to load data --
-
- LoadV0 macro loc, field
- mov ax, word ptr [bp + loc + field + LowWord]
- mov di, word ptr [bp + loc + field + HighWord]
- endm
-
- LoadV1 macro loc, field
- mov bx, word ptr [bp + loc + field + LowWord]
- mov si, word ptr [bp + loc + field + HighWord]
- endm
-
- LoadV2 macro loc, field
- mov dx, word ptr [bp + loc + field + LowWord]
- mov cx, word ptr [bp + loc + field + HighWord]
- endm
-
- ; to store data --
-
- StoreV0 macro loc, field
- mov word ptr [bp + loc + field + LowWord], ax
- mov word ptr [bp + loc + field + HighWord], di
- endm
-
- StoreV1 macro loc, field
- mov word ptr [bp + loc + field + LowWord], bx
- mov word ptr [bp + loc + field + HighWord], si
- endm
-
-
- ; to take the average of two registers (result is in first register) --
-
- AverageV0nV1 macro
- add ax, bx
- adc di, si
- shr di, 1
- rcr ax, 1
- endm
-
- AverageV0nV2 macro
- add ax, dx
- adc di, cx
- shr di, 1
- rcr ax, 1
- endm
-
- AverageV1nV2 macro
- add bx, dx
- adc si, cx
- shr si, 1
- rcr bx, 1
- endm
-
-
- ; to take the average of a register and data --
-
- AverageV1nData macro loc, field
- add bx, word ptr [bp + loc + field + LowWord]
- adc si, word ptr [bp + loc + field + HighWord]
- shr si, 1
- rcr bx, 1
- endm
-
- AverageV2nData macro loc, field
- add dx, word ptr [bp + loc + field + LowWord]
- adc cx, word ptr [bp + loc + field + HighWord]
- shr cx, 1
- rcr dx, 1
- endm
-
-
- ; to turn a 32-bit fixed point data into a regular integer --
-
- Extract macro reg, source, field
- mov reg, word ptr [bp + source + field + HighWord]
- shr reg, 3
- adc reg, 0 ; round
- endm
-
-
- ; to turn an integer argument into a 32-bit fixed point number
- ; and store it as local data --
-
- Convert macro source, dest, field
- mov ax, source
- add ax, 1024
- shl ax, 3
- push ax
- push 0
- endm
-
-
- ; useful numbers for dealing with Bezier boxes (sets of four points) --
-
- XCoord equ 4
- YCoord equ 0
-
- ; stack offsets for splitting boxes
- E1Src equ 48
- C1Src equ 40
- C2Src equ 32
- E2Src equ 24
-
- E1Dest equ 48
- P1Dest equ 40
- P4Dest equ 32
- P6Dest equ 24
- P5Dest equ 16
- P2Dest equ 8
- E2Dest equ 0
-
- ; stack offsets for drawing boxes
- E1Draw equ 24
- C1Draw equ 16
- C2Draw equ 8
- E2Draw equ 0
-
- .data
-
- align 2
-
- ; depth of recursion at which to plot
- WhenToDraw label byte
- db 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
- db 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5
-
-
- ; since we'll be moving bp and sp in our recursion,
- ; we need to put local storage in the data segment
- level dw (?)
- gencount dw (?)
- AdjustedOffs dw (?)
- p1xt dw (?)
- p1yt dw (?)
- p2xt dw (?)
- p2yt dw (?)
- p4xt dw (?)
- p4yt dw (?)
- p5xt dw (?)
- p5yt dw (?)
- c1xt dw (?)
- c1yt dw (?)
- c2xt dw (?)
- c2yt dw (?)
- xdiff dw (?)
- ydiff dw (?)
- moveline dw (?)
- stepper dw (?)
- bptemp dw (?)
-
- ; by the same token we need a copy of this argument
- Colort dw (?)
-
-
- ColumnMasks label byte
- db 011h, 022h, 044h, 088h
-
- .code
-
- align 2
- _x_bezier proc
- ARG E1x, E1y, C1x, C1y, C2x, C2y, E2x, E2y, Levels, Color, PageOffs:word
-
- push bp
- mov bp, sp ; caller's stack frame
- push si
- push di
- push es
-
- ; set local variables
- mov ax, -1024 ; 1024 rows
- imul [_ScrnLogicalByteWidth]
- add ax, PageOffs
- sub ax, 256 ; 1024 columns
- mov AdjustedOffs, ax ; subtract 1024 rows and 1024 columns
-
- ; copy color into data segment so we can change bp & sp
- mov ax, Color
- mov Colort, ax
-
- mov cx, Levels
- dec cx ; gencount (number of boxes we will actually plot) =
- mov ax,1 ; 2^(Levels - 1)
- shl ax,cl
- dec ax
- mov gencount, ax
-
- mov [level], 0 ; variable to tell us where we are in the stack
- mov bptemp, bp ; when the dust settles at the end
-
- ; translate coordinates for adjusted offset, convert 'em to fixed-point
- ; with 13 bits for the integer part and 19 for the fractional part,
- ; and push them onto the stack in the right order to for a Bezier box
-
- Convert E2x
- Convert E2y
-
- Convert C2x
- Convert C2y
-
- Convert C1x
- Convert C1y
-
- Convert E1x
- Convert E1y
-
- mov bp, sp ; we are using them as basically one pointer
-
- mov ax, 0a000h ; point extra segment to VGA memory
- mov es, ax
-
- mov dx, SC_INDEX
- mov al, MAP_MASK
- out dx, al
-
- MainLoop:
- mov si, gencount
- mov ax, 0
- mov al, WhenToDraw[si]
- cmp ax, level ; are we at a terminal curve?
- jne Recurse
- jmp PlotCurve
-
- Recurse:
- ; not at a terminal -- so expand this curve into two more and recurse
-
- ; start with:
- ; C1___C2
- ; | |
- ; E1...E2
- ;
- ; stack looks like: E1 C1 C2 E2
-
- ; expand like this:
- ; C1.....P3.....C2
- ; . . . .
- ; . _P4_P6__P5_ .
- ; P1- .. .. P2
- ; | .. .. |
- ; |.. ..|
- ; E1............E2
- ;
- ; stack looks like: E1 P1 P4 P6 P5 P2 E2
- ; Since P6 is part of both new boxes, we use it twice.
-
- sub sp, 24
- sub bp, 24
-
- ; new points for X --
- LoadV0 E1Src, XCoord
- LoadV1 E2Src, XCoord
- StoreV1 E2Dest, XCoord
- LoadV2 C1Src, XCoord
- AverageV0nV2
- StoreV0 P1Dest, XCoord
- AverageV1nData C2Src, XCoord
- StoreV1 P2Dest, XCoord
- AverageV2nData C2Src, XCoord
- AverageV0nV2
- StoreV0 P4Dest, XCoord
- AverageV1nV2
- StoreV1 P5Dest, XCoord
- AverageV0nV1
- StoreV0 P6Dest, XCoord
-
- ; same thing for Y --
- LoadV0 E1Src, YCoord
- LoadV1 E2Src, YCoord
- StoreV1 E2Dest, YCoord
- LoadV2 C1Src, YCoord
- AverageV0nV2
- StoreV0 P1Dest, YCoord
- AverageV1nData C2Src, YCoord
- StoreV1 P2Dest, YCoord
- AverageV2nData C2Src, YCoord
- AverageV0nV2
- StoreV0 P4Dest, YCoord
- AverageV1nV2
- StoreV1 P5Dest, YCoord
- AverageV0nV1
- StoreV0 P6Dest, YCoord
-
- inc level ; one level further into stack
- jmp MainLoop
-
- PlotCurve:
- ; pull 16-bit coordinates back out of 32-bit fixed-point coordinates;
- ; integer part is highest 13 bits
-
- Extract cx, C1Draw, XCoord
- Extract di, E1Draw, XCoord
- mov c1xt, cx
- add cx, di
- shr cx, 1
- mov p1xt, cx
-
- Extract ax, C1Draw, YCoord
- Extract si, E1Draw, YCoord
- mov c1yt, ax
- add ax, si
- shr ax, 1
- mov p1yt, ax
- call ShortLine ; line from P1 to E1
-
- Extract cx, E2Draw, XCoord
- Extract di, C2Draw, XCoord
- mov c2xt, di
- add di, cx
- shr di, 1
- mov p2xt, di
-
- Extract ax, E2Draw, YCoord
- Extract si, C2Draw, YCoord
- mov c2yt, si
- add si, ax
- shr si, 1
- mov p2yt, si
- call ShortLine ; line from E2 to P2
-
- ; P3 is not in any line we draw, so we'll use it now to find both P5
- ; for the line after this on, and P4 for this line, then discard it --
- mov bx, c1xt
- add bx, c2xt
- shr bx, 1
- mov dx, c1yt
- add dx, c2yt
- shr dx, 1
-
- ; find P5 x and save for later lines
- mov cx, p2xt
- add cx, bx
- shr cx, 1
- mov p5xt, cx
- ; find P4 x for this line
- mov cx, p1xt
- add cx, bx
- shr cx, 1
- mov p4xt, cx
- mov di, p1xt
-
- ; find P5 y and save for later lines
- mov ax, p2yt
- add ax, dx
- shr ax, 1
- mov p5yt, ax
- ; find P4 y for this line
- mov ax, p1yt
- add ax, dx
- shr ax, 1
- mov p4yt, ax
- mov si, p1yt
- call ShortLine ; line from P4 to P1 -- finally!
-
- ; we've already done all the work for these last two --
- mov cx, p2xt
- mov di, p5xt
- mov ax, p2yt
- mov si, p5yt
- call ShortLine ; line from P2 to P5
-
- mov cx, p5xt
- mov di, p4xt
- mov ax, p5yt
- mov si, p4yt
- call ShortLine ; line from P5 to P4
-
- ; we've drawn our five lines; this bezier box
- ; can be dropped off the stack
- add bp, 24
- add sp, 24
-
- dec gencount
- mov cx, gencount
- cmp cx, -1
-
- je WrapUp ; if we've generated all the terminal nodes we
- ; are supposed to, we pack our bags and go.
- dec level
- jmp MainLoop
-
- WrapUp:
- ; plot the final point, which is simply the original E1
-
- mov bp, bptemp ; back where we started
- mov ax, E1y
- add ax, 1024
- mul [_ScrnLogicalByteWidth]
- mov di, E1x
- add di, 1024
- mov si, di
- shr di, 2
- add di, ax
- add di, AdjustedOffs
- and si, 3
- mov al, ColumnMasks[si]
- mov ah, byte ptr Color
- mov dx, SC_INDEX + 1
- out dx, al
- mov es:[di], ah
-
- pop es
- pop di
- pop si
- mov sp, bp
- pop bp
- ret ; git
-
- ; ShortLine subfunction --
- ;
- ; This is designed for short line segments. For longer lines,
- ; especially horizontal ones, the x_line routine in the XLINE module
- ; would be faster. But calling that from here it would be a lot of
- ; extra complication. This is part of the x_bezier routine because
- ; it has no particular outside use, and we can call it much faster
- ; through registers than through the stack.
- ;
- ; Since our line segments overlap, the second endpoint is not drawn.
- ; These routines are all out of order for the sake of conditional jumps.
-
- LRHorz:
- dec di
- LRHorzLoop:
- rol al, 1
- adc bx, 0
- out dx, al
- mov es:[bx], ah
- sub di, 1
- jg LRHorzLoop
- retn
-
- ; You are in a maze of little subroutines, all alike...
-
-
- LR45Deg:
- dec si
- LR45DegLoop:
- add bx, cx
- rol al, 1
- adc bx, 0
- out dx, al
- mov es:[bx], ah
- sub si, 1
- jg LR45DegLoop
- retn
-
-
- LRXMajor:
- mov cx, di
- dec cx
- shr di, 1
- LRXMajorLoop:
- sub di, si
- jge LRXMajorIterate
- add di, xdiff
- add bx, moveline
- LRXMajorIterate:
- rol al, 1
- adc bx, 0
- out dx, al
- mov es:[bx], ah
- sub cx, 1
- jg LRXMajorLoop
- retn
-
-
- LeftToRight:
- mov xdiff, di ; store distance across line
-
- mov cx, [_ScrnLogicalByteWidth]
- cmp si, 0 ; check if height is positive, negative, or zero
- je LRHorz
- jg LRTopToBottom
- neg si
- neg cx
- LRTopToBottom:
- mov ydiff, si
- mov moveline, cx
- cmp di, si
- jg LRXMajor
- je LR45Deg
-
-
- LRYMajor:
- mov cx, si
- dec cx
- shr si, 1
- LRYMajorLoop:
- add bx, moveline
- sub si, di
- jge LRYMajorIterate
- add si, ydiff
- rol al, 1
- adc bx, 0
- LRYMajorIterate:
- out dx, al
- mov es:[bx], ah
- sub cx, 1
- jg LRYMajorLoop
- retn
-
-
- ; This is the actual starting point.
- ; On entry, registers look like this:
- ; X1: cx
- ; Y1: ax
- ; X2: di
- ; Y2: si
- ShortLine:
- sub si, ax ; height goes out in si
- sub di, cx ; width goes out in di
-
- mul [_ScrnLogicalByteWidth]
- mov dx, cx
- shr dx, 2
- add ax, dx
- add ax, AdjustedOffs
- mov bx, ax ; starting byte of X1, Y1 goes out in bx
- and cx, 3
- mov ax, 011h
- shl al, cl ; column mask goes out in al
- mov dx, SC_INDEX + 1
- mov ah, byte ptr Colort; color goes out in ah
- out dx, al
- mov es:[bx], ah ; plot first point
-
- cmp di, 0
-
- jg LeftToRight
- je VerticalLine
-
-
- RightToLeft:
- neg di ; much more useful this way
- mov xdiff, di
-
- mov cx, [_ScrnLogicalByteWidth]
- cmp si, 0 ; check if height is positive, negative, or zero
- je RLHorz
- jg RLTopToBottom
- neg si
- neg cx
- RLTopToBottom:
- mov ydiff, si
- mov moveline, cx
- cmp di, si
- jg RLXMajor
- je RL45Deg
-
-
- RLYMajor:
- mov cx, si
- dec cx
- shr si, 1
- RLYMajorLoop:
- add bx, moveline
- sub si, di
- jge RLYMajorIterate
- add si, ydiff
- ror al, 1
- sbb bx, 0
- RLYMajorIterate:
- out dx, al
- mov es:[bx], ah
- sub cx, 1
- jg RLYMajorLoop
- retn
-
-
- VerticalLine:
- mov cx, [_ScrnLogicalByteWidth]
- cmp si, 0 ; check if height is positive
- jg VTopToBottom
- neg si
- neg cx
- VTopToBottom:
- dec si
- VLoop:
- add bx, cx
- mov es:[bx], ah
- sub si, 1
- jg VLoop
- retn
-
-
- RLHorz:
- dec di
- RLHorzLoop:
- ror al, 1
- sbb bx, 0
- out dx, al
- mov es:[bx], ah
- sub di, 1
- jg RLHorzLoop
- retn
-
-
- RL45Deg:
- dec si
- RL45DegLoop:
- add bx, cx
- ror al, 1
- sbb bx, 0
- out dx, al
- mov es:[bx], ah
- sub si, 1
- jg RL45DegLoop
- retn
-
-
- RLXMajor:
- mov cx, di
- dec cx
- shr di, 1
- RLXMajorLoop:
- sub di, si
- jge RLXMajorIterate
- add di, xdiff
- add bx, moveline
- RLXMajorIterate:
- ror al, 1
- sbb bx, 0
- out dx, al
- mov es:[bx], ah
- sub cx,1
- jg RLXMajorLoop
- retn
-
-
- _x_bezier endp
-
- end
-
-