Category : C Source Code
Archive   : XLIB06.ZIP
Filename : XBEZIER.ASM

 
Output of file : XBEZIER.ASM contained in archive : XLIB06.ZIP

;-----------------------------------------------------------------------
; MODULE XBEZIER
;
;
; Compile with TASM.
; C near-callable.
;
; This module was written by Matthew MacKenzie
; [email protected]
;-----------------------------------------------------------------------
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



  3 Responses to “Category : C Source Code
Archive   : XLIB06.ZIP
Filename : XBEZIER.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/