sys7.1-doc-wip/Libs/InterfaceSrcs/Graf3DAsm.a
2019-07-27 22:37:48 +08:00

980 lines
32 KiB
Plaintext

;
; File: Graf3DAsm.a
;
; Copyright: © 1984-1992 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM2> 10/28/92 SWC Changed INCLUDEs to a LOAD of StandardEqu.d.
;
LOAD 'StandardEqu.d'
INCLUDE 'FixMath.a'
FixRad EQU 3754936 ;radConst = 57.29578
FracRad EQU 1073741824
;offsets
;Point3D and Point2D
x EQU 0 ;Fixed
y EQU 4 ;Fixed
z EQU 8 ;Fixed
;XfMatrix = ARRAY[0..3,0..3] OF fixed
xf00 EQU 0
xf01 EQU 4
xf02 EQU 8
xf03 EQU 12
xf10 EQU 16
xf11 EQU 20
xf12 EQU 24
xf13 EQU 28
xf20 EQU 32
xf21 EQU 36
xf22 EQU 40
xf23 EQU 44
xf30 EQU 48
xf31 EQU 52
xf32 EQU 56
xf33 EQU 60
;Port3D
GrPort EQU 0 ;GrafPtr
viewRect EQU 4 ;Rect
xLeft EQU 12 ;Fixed
yTop EQU 16 ;Fixed
xRight EQU 20 ;Fixed
yBottom EQU 24 ;Fixed
pen EQU 28 ;Point3D
penPrime EQU 40 ;Point3D
eye EQU 52 ;Point3D
hSize EQU 64 ;Fixed
vSize EQU 68 ;Fixed
hCenter EQU 72 ;Fixed
vCenter EQU 76 ;Fixed
xCotan EQU 80 ;Fixed
yCotan EQU 84 ;Fixed
ident EQU 88 ;BOOLEAN
xForm EQU 90 ;XfMatrix
szPort3D EQU 154 ;size of Port3D
GRAF3D PROC EXPORT
;GRAF3DIMPL translated into assembly, a little at a time
EXPORT InitGrf3D
InitGrf3D ;PROCEDURE InitGrf3D(globalPtr: Ptr);
MOVE.L (SP)+,A0
MOVE.L (SP)+,4(A5)
JMP (A0)
EXPORT SetPort3D ;PROCEDURE SetPort3D(port: Port3DPtr);
EXPORT GetPort3D
;change to another Port3D
SetPort3D
MOVE.L 4(SP),A0 ;port
MOVE.L 4(A5),A1
MOVE.L A0,(A1) ;thePort3D := port;
MOVE.L GrPort(A0),-(SP) ;port^.GPort
_SetPort ;SetPort(port^.GPort);
popRet MOVE.L (SP)+,(SP) ;pop param off stack
RTS ;END;
GetPort3D ;PROCEDURE GetPort3D(VAR port: Port3DPtr);
;inquire the current Port3D
;BEGIN
MOVE.L 4(A5),A0 ;VAR port
MOVE.L 4(SP),A1
MOVE.L (A0),(A1) ;port := thePort3D;
BRA.S popRet ;pop param off stack
;PROCEDURE Open3DPort(port:Port3DPtr);
EXPORT Open3DPort
EXPORT MoveTo2D, MoveTo3D, LineTo2D, LineTo3D
EXPORT Move2D, Move3D, Line2D, Line3D
EXPORT ViewAngle, Identity, TransForm, Clip3D
EXPORT ViewPort, LookAt
;initialize all values in port^ to their defaults
Open3DPort
MOVE.L A2,-(SP) ;BEGIN
MOVE.L 8(SP),A1 ;port
MOVE.L 4(A5),A0
MOVE.L A1,(A0) ;thePort3D := port;
MOVE.L (A5),A0 ;get globals
MOVE.L (A0),GrPort(A1) ;port^.GPort := thePort;
MOVE.L (A0),A0 ;thePort^
LEA portRect(A0),A2 ;WITH thePort^.portRect DO
MOVE.L A2,-(SP) ;thePort^.portRect
BSR ViewPort ;ViewPort(thePort^.portRect);
MOVEQ #7,D0
@1 CLR.L -(SP)
DBRA D0,@1 ;clear 8 longs on the stack for later operations
MOVE (A2)+,12(SP) ;put left, right, top, bottom in high words as fixed #s
MOVE (A2)+,8(SP)
MOVE (A2)+,4(SP)
MOVE (A2),(SP)
BSR LookAt ;LookAt(FixRatio(left,1), FixRatio(top,1), FixRatio(right,1), FixRatio(bottom,1));
BSR ViewAngle ;ViewAngle(0)
BSR Identity ;Identity
BSR.S MoveTo3D ;MoveTo3D(0, 0, 0)
MOVE.L (SP)+,A2 ;preserved reg.
MOVE.L (SP)+,(SP) ;return address
RTS ;END
MoveTo3D ;PROCEDURE MoveTo3D(x, y, z: fixed);
;Move from current position to x,y,z without drawing
pt1 EQU -4 ;POINT
pt2 EQU -8 ;POINT
oldPrime EQU -20 ;Point3D
local EQU -24 ;local return address
BSR.S CmnTo3D
BEQ.S dontMove
MOVE.L pt2(A6),-(SP)
_MoveTo ;THEN MoveTo(pt2.H, pt2.V);
dontMove MOVE.L (SP)+,A2
UNLK A6
MOVE.L (SP),A0
ADD #16,SP
JMP (A0) ;END
CmnTo3D MOVE.L (SP)+,D0 ;local return address
LINK A6,#local ;BEGIN
MOVE.L D0,local(A6) ;save local return
MOVE.L A2,-(SP)
MOVE.L 4(A5),A2 ;WITH thePort3D^ DO
MOVE.L (A2),A2
LEA penPrime(A2),A0 ;BEGIN
LEA oldPrime(A6),A1 ;oldPrime := penPrime
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0),(A1)
LEA 20(A6),A0 ;x
LEA pen+x(A2),A1 ;pen + x
MOVE.L -(A0),(A1)+ ;pen.x := x;
MOVE.L -(A0),(A1)+ ;pen.y := y;
MOVE.L -(A0),(A1) ;pen.z := z;
PEA pen(A2)
PEA penPrime(A2) ;
BSR TransForm ;TransForm(pen, penPrime);
SUBQ #2,SP ;room for result
PEA oldPrime(A6)
PEA penPrime(A2)
PEA pt1(A6)
PEA pt2(A6)
BSR Clip3D ;IF Clip3D(oldPrime, penPrime, pt1, pt2)
MOVE.B (SP)+,D0
MOVE.L local(A6),A0 ;retrieve local return
JMP (A0)
LineTo3D ;PROCEDURE LineTo3D(x, y, z: fixed);
;nearly the same as MoveTo3D, just moveTo pt1, LineTo pt2
BSR.S CmnTo3D
BEQ.S dontMove
_HidePen ;changed to support Polygons
MOVE.L pt1(A6),-(SP)
_LineTo ;THEN MoveTo(pt1.h, pt1.v);
_ShowPen
MOVE.L pt2(A6),-(SP) ;LineTo(pt2.h, pt2.v);
_LineTo
BRA.S dontMove
Move3D ;PROCEDURE Move3D(dx, dy, dz: fixed);
BSR.S Cmn3D
BRA.S MoveTo3D ;MoveTo3D(pen.x + dx, pen.y + dy, pen.z + dz)
Cmn3D MOVE.L (SP)+,D2 ;save ret. address
MOVE.L 4(A5),A0 ;thePort3D
MOVE.L (A0),A0
LEA pen(A0),A0 ;thePort3D^.pen
LEA 16(SP),A1 ;add 4 for the predecrement
MOVEQ #2,D1 ;3 times, for x, y and z
@0 MOVE.L (A0)+,D0
ADD.L D0,-(A1) ;pen.? + d?
DBRA D1,@0 ;WITH thePort3D^ DO
MOVE.L D2,A0 ;get ret. addr.
JMP (A0)
Line3D ;PROCEDURE Line3D(dx, dy, dz: fixed);
BSR.S Cmn3D
BRA.S LineTo3D ;LineTo3D(pen.x + dx, pen.y + dy, pen.z + dz)
MoveTo2D ;PROCEDURE MoveTo2D(x, y: fixed);
BSR.S CmnTo2D
BRA.S MoveTo3D ;MoveTo3D(x, y, thePort3D^.pen.z);
CmnTo2D MOVE.L (SP)+,A1 ;save return address
MOVE.L (SP),-(SP) ;get prior return address
MOVE.L 4(A5),A0 ;thePort3D
MOVE.L (A0),A0
MOVE.L pen+z(A0),4(SP)
JMP (A1)
Move2D ;PROCEDURE Move2D(dx, dy: fixed);
BSR.S Cmd2D
BRA.S Move3D ;Move3D(dx, dy, 0);
Cmd2D MOVE.L (SP)+,A0 ;save local return address
MOVE.L (SP),-(SP) ;move Move2D return address
CLR.L 4(SP) ; to make room for '0'
JMP (A0)
LineTo2D ;PROCEDURE LineTo2D(x, y: fixed);
BSR.S CmnTo2D
BRA.S LineTo3D ;LineTo3D(x, y, thePort3D^.pen.z);
Line2D ;PROCEDURE Line2D(dx, dy: fixed);
BSR.S Cmd2D
BRA.S Line3D ;Line3D(dx, dy, 0);
ViewLook ;PROCEDURE ViewLook
;re-calculate offsets and scales after LookAt or ViewPort
MOVE.L 4(A5),A0 ;WITH thePort3D^, viewRect DO
MOVE.L (A0),A0
MOVE viewRect+right(A0),D0
MOVE viewRect+left(A0),D2
SUB D2,D0
SWAP D0
CLR.W D0
ASR.L #1,D0
MOVE.L D0,hsize(A0) ;hSize:=(right-left)/2.0
SWAP D2
CLR.W D2
ADD.L D2,D0
MOVE.L D0,hCenter(A0) ;hCenter:=left + hSize;
MOVE viewRect+bottom(A0),D0
MOVE viewRect+top(A0),D2
SUB D2,D0
SWAP D0
CLR.W D0
ASR.L #1,D0
NEG.L D0
MOVE.L D0,vsize(A0) ;vSize:=(bottom-top)/(-2.0)
SWAP D2
CLR.W D2
SUB.L D0,D2
MOVE.L D2,vCenter(A0) ;vCenter:=top - vSize
RTS
ViewPort ;PROCEDURE ViewPort(r: Rect);
;specify what portion of the folder to map onto
MOVE.L 4(A5),A0 ;thePort3D
MOVE.L (A0),A0
LEA viewRect(A0),A0
MOVE.L (SP)+,D0 ;save return address
MOVE.L (SP)+,A1 ;thePort3D^.viewRect := r;
MOVE.L (A1)+,(A0)+
MOVE.L (A1),(A0)
MOVE.L D0,-(SP) ;restore return address
BRA.S ViewLook ;ViewLook; { re-calculate scales and offsets }
LookAt ;PROCEDURE LookAt(left, top, right, bottom: fixed);
;specify the fixed number coordinates of the portRect
MOVE.L 4(A5),A0 ; WITH thePort3D^ DO
MOVE.L (A0),A0
MOVEQ #3,D0
LEA xLeft(A0),A0 ; xLeft:= left;
LEA 20(SP),A1 ; add 4 for predecrement
@0 MOVE.L -(A1),(A0)+ ;xRight := right;
DBRA D0,@0 ;yBottom := bottom;
;yTop := top;
MOVE.L 4(A5),A0
MOVE.L (A0),A0
MOVE.L 16(SP),D0
ADD.L 8(SP),D0
ASR.L #1,D0
MOVE.L D0,eye+x(A0) ;eye.x:=(left+right)/2.0
MOVE.L 12(SP),D0
ADD.L 4(SP),D0
ASR.L #1,D0
MOVE.L D0,eye+y(A0) ;eye.y:=(top+bottom)/2.0
MOVE.L (SP)+,A0 ;save return address
ADD #16,SP ;pop parameters
MOVE.L A0,-(SP) ;restore return address
BRA.S ViewLook ;re-calculate scales and offsets
ViewAngle ;PROCEDURE ViewAngle(angle: fixed);
;specify the horizontal angle subtended by the viewing pyramid }
MOVE.L A2,-(SP)
MOVE.L 8(SP),D0
MOVE.L #6553,D1
CMP.L D1,D0 ;IF angle < 0.1 THEN angle:=0.1
BGE.S @0
MOVE.L D1,D0
@0 MOVE.L #117899236,D1
CMP.L D1,D0
BLE.S @1
MOVE.L D1,D0 ;IF angle > 179.9 THEN angle := 179.9
@1 SUB #36,SP ;room for _FixDiv, _FracCos, _FracSin, (_FracRatio), 2 _FixMul, _FixDiv
MOVE.L D0,-(SP)
MOVE.L #7509872,-(SP)
_FixDiv ;angle:=angle/(2.0*radConst); } { halve angle & convert to rad }
MOVE.L (SP),8(SP) ;put a copy on stack for Sin
_FracCos
MOVE.L (SP)+,8(SP) ;save result for FracRatio
_FracSin
_FixDiv
MOVE.L 4(A5),A2
MOVE.L (A2),A2
MOVE.L (SP)+,xCotan(A2) ;xCotan := FracRatio(FracCos(angle), FracSin(angle)); { remember for perspective calc }
MOVE.L xRight(A2),D0
SUB.L xLeft(A2),D0
MOVE.L D0,-(SP) ;one for FixDiv, below
MOVE.L yTop(A2),D0
SUB.L yBottom(A2),D0
MOVE.L D0,-(SP)
_FixDiv
MOVE.L xCotan(A2),-(SP) ;note: must divide first or overflow will occur for small angles
_FixMul
MOVE.L (SP)+,yCotan(A2) ;yCotan:=xCotan * (xRight-xLeft)/(yTop-yBottom)
MOVE.L xRight(A2),D0
SUB.L xLeft(A2),D0
ASR.L #1,D0
MOVE.L D0,-(SP)
MOVE.L xCotan(A2),-(SP)
_FixMul
MOVE.L (SP)+,eye+z(A2) ;eye.z:=xCotan * (xRight-xLeft)/2;
MOVE.L (SP)+,A2
MOVE.L (SP)+,(SP)
RTS
TransForm ;PROCEDURE TransForm(src: Point3D; VAR dst: Point3D);
;use the current xForm matrix to transform
;a 3D source point into a 3D destination point.
LINK A6,#-12 ;12 bytes off the stack, thank you
MOVEM.L D3/D4/A2-A4,-(SP)
MOVE.L 12(A6),A0
LEA -12(A6),A1
MOVE.L (A0)+, (A1)+
MOVE.L (A0)+, (A1)+
MOVE.L (A0), (A1)
MOVE.L 4(A5),A2 ;BEGIN
MOVE.L (A2),A2
MOVE.L 8(A6),A3
LEA -12(A6),A4 ; oops Wargo bugo -- fixed 5/8/86
TST.B ident(A2) ;IF thePort3D^.ident
BEQ.S trans1
MOVE.L (A4)+,(A3)+
MOVE.L (A4)+,(A3)+
MOVE.L (A4),(A3) ;THEN dst := src
BRA.S leave
trans1 MOVEQ #8,D3 ;do all three evaluations in this loop
@0 SUB #12,SP ;for 3 _FixMuls
MOVE.L x(A4),-(SP)
MOVE.L xForm+xF00(A2,D3),-(SP)
_FixMul ;dst.x:=src.x * xForm[0,0] +
MOVE.L (SP)+,D4
MOVE.L y(A4),-(SP)
MOVE.L xForm+xF10(A2,D3),-(SP)
_FixMul ; src.y * xForm[1,0] +
ADD.L (SP)+,D4
MOVE.L z(A4),-(SP)
MOVE.L xForm+xF20(A2,D3),-(SP)
_FixMul ; src.z * xForm[2,0]
ADD.L (SP)+,D4
LEA xForm+xF30(A2),A0 ;changed 'cause xForm+xF30(A2,D3) too big
ADD.L 0(A0,D3),D4 ; + xForm[3,0];
MOVE.L D4,x(A3,D3)
SUBQ #4,D3 ;dst.y := src.x * xForm[0,1] + src.y * xForm[1,1] + src.z * xForm[2,1] + xForm[3,1]
BPL.S @0 ;dst.z := src.x * xForm[0,2] + src.y * xForm[1,2] + src.z * xForm[2,2] + xForm[3,2]
leave MOVEM.L (SP)+,D3/D4/A2-A4
UNLK A6
MOVE.L (SP)+,A0
ADDQ #8,SP
JMP (A0)
bTop EQU 0
bLeft EQU 1
bBottom EQU 2
bRight EQU 3
Code ;FUNCTION Code(pt3D: Point3D) : OutCode;
MOVE.L 4(SP),A0 ;pt3D
MOVEQ #0,D1 ;c := []
MOVE.L z(A0),D0
MOVE.L x(A0),D2
CMP.L D2,D0 ;IF pt3D.x > pt3D.z
BGE.S @0
BSET #bRight,D1 ;THEN c := [right]
BRA.S @1
@0 NEG.L D0
CMP.L D2,D0 ;ELSE IF pt3D.x < -pt3D.z
BLE.S @1
BSET #bLeft,D1 ;THEN c := [left];
@1 MOVE.L z(A0),D0
MOVE.L y(A0),D2
CMP.L D2,D0 ;ELSE IF pt3D.y > pt3D.z
BGE.S @2
BSET #bTop,D1 ;THEN c := c + [top]
BRA.S @3
@2 NEG.L D0
CMP.L D2,D0 ;IF pt3D.y < -pt3D.z
BLE.S @3
BSET #bBottom,D1 ;THEN c := c + [bottom]
@3 MOVE.L (SP)+,A0
ADDQ.L #6,SP ;remove parameter & function result space
MOVE.B D1,-(SP) ;return byte sized result
JMP (A0)
convert MOVEQ #4,D3 ;do 'y' first
@0 MOVE.L x(A2,D3),D0
SUB.L eye+x(A3,D3),D0
SUBQ #4,SP
MOVE.L D0,-(SP)
MOVE.L xCotan(A3,D3),-(SP)
_FixMul
MOVE.L (SP)+,x(A2,D3) ;src1.y := (src1.y - eye.y) * yCotan
SUBQ #4,D3 ;src1.x := (src1.x - eye.x) * xCotan;
BPL.S @0
MOVE.L eye+z(A3),D0
SUB.L z(A2),D0
MOVE.L D0,z(A2) ;src1.z := eye.z - src1.z
RTS
Clip3D ;FUNCTION Clip3D(src1, src2: Point3D; VAR dst1, dst2: POINT) : BOOLEAN;
;do full 3D clipping to viewing pyramid and return 2D
;screen coords in dst. Function value true if visible.
; D3 = c A2 = src1, scratch across ROM calls
; D4 = c * [left, right] A3 = thePort3D^
; D5 = _FixMul, _FFixMul flag A4 = src2, scratch
; D6 = t*(src2.z-src1.z),etc.
; D7 = Clip3D result flag
dst2 EQU 8
dst1 EQU 12
src2 EQU 16
src1 EQU 20
c1 EQU -1 ;SET OF (left,top,right,bottom)
c2 EQU -2 ;SET OF (left,top,right,bottom)
pt3D EQU -14 ;Point3D
src1copy EQU -26
src2copy EQU -38
LINK A6,#src2copy
MOVEM.L D3-D7/A2-A4,-(SP) ;BEGIN
MOVE.L src1(A6),A0
LEA src1copy(A6),A1
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0),(A1)
MOVE.L src2(A6),A0
LEA src2copy(A6),A1
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0),(A1)
MOVEQ #0,D7 ;Clip3D:=FALSE
MOVE.L 4(A5),A3 ;WITH thePort3D^ DO
MOVE.L (A3),A3
LEA src1Copy(A6),A2
BSR.S convert
SUBQ #4,SP ;reserve room for 2 calls to Code
MOVE.L A2,-(SP)
BSR.S Code ;c1 := Code(src1)
MOVE.B (SP)+,c1(A6)
LEA src2Copy(A6),A2 ;src2.x := (src2.x - eye.x) * xCotan
BSR.S convert ;src2.y := (src2.y - eye.y) * yCotan
;src2.z := eye.z - src2.z;
MOVE.L A2,-(SP)
BSR Code ;c2 := Code(src2)
MOVE.B (SP)+,c2(A6)
while ;WHILE c1 + c2 <> [] DO
MOVE.B c2(A6),D0
MOVE.B c1(A6),D3
MOVE.B D0,D2
OR.B D3,D2
BEQ endWhile
MOVE.B D0,D2
AND.B D3,D2 ;IF c1 * c2 <> [] THEN GOTO 0; { both out on same side }
BNE endItAll
TST.B D3
BNE.S @0
MOVE.B D0,D3 ;c := c1; IF c = [] THEN c := c2
@0 LEA src1Copy(A6),A2
LEA src2Copy(A6),A4
MOVE.L z(A2),D0
BTST #bLeft,D3 ;IF left IN c THEN
BEQ.S @1
ADD.L x(A2),D0 ;calc intersect with left edge
MOVE.L D0,D1 ;num := src1.z + src1.x
SUB.L x(A4),D1 ;denom := (src1.x-src2.x) - (src2.z-src1.z)
BRA.S @4
@1 BTST #bRight,D3 ;ELSE IF right IN c THEN
BEQ.S @2
SUB.L x(A2),D0 ;calc intersect with right edge
MOVE.L D0,D1 ;num := src1.z-src1.x
ADD.L x(A4),D1 ;denom := (src2.x-src1.x) - (src2.z-src1.z)
BRA.S @4
@2 BTST #bBottom,D3 ;ELSE IF bottom IN c THEN
BEQ.S @3
ADD.L y(A2),D0 ;calc intersect with bottom edge
MOVE.L D0,D1 ;num := src1.z + src1.y
SUB.L y(A4),D1 ;denom := (src1.y-src2.y) - (src2.z-src1.z)
BRA.S @4
@3 BTST #bTop,D3 ;ELSE IF top IN c THEN
BEQ.S @4
SUB.L y(A2),D0 ;calc intersect with bottom edge
MOVE.L D0,D1 ;num := src1.z - src1.y
ADD.L y(A4),D1
@4 SUB.L z(A4),D1 ;denom := (src2.y-src1.y) - (src2.z-src1.z)
SUBQ.L #4,SP
MOVE.L D0,-(SP) ;num (for FFixRatio later, if needed)
MOVE.L D1,-(SP) ;denom
SUBQ.L #4,SP
MOVE.L D0,-(SP) ;num
MOVE.L D1,-(SP) ;denom
_FixDiv
MOVE.L (SP),D0 ;t := FixDiv(num, denom);
BPL.S @5
NEG.L D0
@5 CMP.L #$00020000,D0 ;IF ABS(t) < 131072 { < 2} THEN
BGE.S @9
MOVEQ #1,D5 ;set _FFixMul flag
ADDQ #4,SP ;throw away _FixDiv result
_FracDiv
MOVE.L (SP),-(SP) ;room for 2nd FixMul result, copy t for 2nd FixMul
SUBQ #8,SP ;room for 1st FixMul result, t for 1st FixMul
MOVE.L 8(SP),(SP) ;copy t for 1st FixMul
@55 MOVE.L z(A4),D0
SUB.L z(A2),D0
BSR.S @8 ;_FFixMul
MOVE.L (SP)+,D6 ;num := FFixMul(t, src2.z - src1.z);
MOVE.L D3,D4
AND.B #$A,D4 ;IF c * [left, right] <> []
BEQ.S @6
MOVE.L y(A4),D0
SUB.L y(A2),D0 ;THEN t := FFixMul(t, src2.y - src1.y)
BRA.S @7
@6 MOVE.L x(A4),D0
SUB.L x(A2),D0 ;ELSE t := FFixMul(t, src2.x - src1.x);
@7 BSR.S @8 ;_FFixMul
BRA.S @10
@8 MOVE.L (SP)+,D7 ;save return address
MOVE.L D0,-(SP)
TST D5
BNE.S @85
_FixMul
BRA.S @87
@85 _FracMul
@87 MOVE.L D7,A0
MOVEQ #0,D7
JMP (A0)
@9 MOVE.L (SP),8(SP) ;put 2nd copy on for 2nd _FixMul
MOVEQ #0,D5 ;flag for _FixMul
BRA.S @55
;ELSE
;num := FixMul(t, src2.z - src1.z);
;IF c * [left, right] <> []
;THEN t := FixMul(t, src2.y - src1.y)
;ELSE t := FixMul(t, src2.x - src1.x);
@10 ADD.L z(A2),D6 ;pt3D.z:=t*(src2.z-src1.z) + src1.z;
MOVE.L D6,pt3D+z(A6)
MOVE.L (SP)+,D0 ;get t*(src2.y-src1.y) from above
TST.B D4 ;IF c * [left, right] <> []
BEQ.S @11
ADD.L y(A2),D0
MOVE.L D0,pt3D+y(A6) ;pt3D.y:=t*(src2.y-src1.y) + src1.y;
BRA.S @12
@11 ADD.L x(A2),D0
MOVE.L D0,pt3D+x(A6) ;pt3D.x:=t*(src2.x-src1.x) + src1.x
@12 MOVE.L pt3D+z(A6),D0
MOVE.L D3,D1
AND.B #6,D1 ;left or bottom,
BEQ.S @13
NEG.L D0 ;-pt3D.z
@13 TST.B D4 ;left or right,
BEQ.S @14
MOVE.L D0,pt3D+x(A6) ;IF left IN c THEN pt3D.x := -pt3D.z ELSE
BRA.S @15 ;IF right IN c THEN pt3D.x := pt3D.z ELSE
@14 MOVE.L D0,pt3D+y(A6) ;IF bottom IN c THEN pt3D.y := -pt3D.z ELSE
;IF top IN c THEN pt3D.y := pt3D.z;
@15 LEA pt3D(A6),A0
CMP.B c1(A6),D3 ;IF c = c1 THEN
BNE.S @16
LEA c1(A6),A4 ;** note: A4 no longer means src2
LEA src1Copy(A6),A1 ;src1 := pt3D
BRA.S @17 ;ELSE
@16 LEA c2(A6),A4
LEA src2Copy(A6),A1 ;src2 := pt3D
@17 MOVE.L A1,A2 ;** note: A2 no longer means src1
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0),(A1)
SUBQ #2,SP ;IF c = c1 THEN
MOVE.L A2,-(SP) ;c1 := Code(src1)
;ELSE
BSR Code ;c2 := Code(src2)
MOVE.B (SP)+,(A4)
BRA while
EndWhile
;if we reach here, the line from src1 to src2 is visible
MOVEQ #1,D7 ;Clip3D := TRUE;
;convert clip coords to screen coords
LEA src1Copy(A6),A2
MOVE.L dst1(A6),A4
BSR.S figDst
LEA src2Copy(A6),A2 ;dst2.H:=ROUND(hCenter + hSize * src2.x / src2.z)
MOVE.L dst2(A6),A4 ;dst2.V:=ROUND(vCenter + vSize * src2.y / src2.z)
BSR.S figDst
endItAll MOVE.B D7,24(A6)
MOVEM.L (SP)+,D3-D7/A2-A4
UNLK A6
Exit20 MOVE.L (SP),A0
ADD #20,SP
JMP (A0)
figDst SUB #20,SP ;(4 for _FixDiv, 4 for _FixMul, 2 for _FixRound) * 2
MOVEQ #4,D3 ;do 'v', 'y' first
@0 MOVE.L hSize(A3,D3),-(SP) ;h or v = 0, 4
MOVE.L z(A2),-(SP) ;src1 or src2
_FixDiv
MOVE.L x(A2,D3),-(SP) ;D3; x or y = 0, 4 {src1 or src2}
_FixMul
MOVE.L hCenter(A3,D3),D0 ;D3; h or v = 0, 4
ADD.L D0,(SP)
_FixRound
ASR #1,D3 ;make 4 into 2 (or 0 into 0)
EOR #2,D3 ;make 2 into 0 (0 into 2)
MOVE.W (SP)+,v(A4,D3) ;dst1.V:=ROUND(vCenter + vSize * src1.y / src1.z)
EOR #2,D3 ;fix D3 back
SUBQ #2,D3 ;dst1.H:=ROUND(hCenter + hSize * src1.x / src1.z)
BPL.S @0
RTS
Identity ;PROCEDURE Identity;
;reset the transform matrix to identity
MOVE.L 4(A5),A0 ;WITH thePort3D^ DO
MOVE.L (A0),A0
MOVEQ #1,D0
MOVE.B D0,ident(A0) ;ident:=TRUE; { SET FLAG SO xForm CAN BE SKIPPED }
LEA xForm(A0),A0
SWAP D0
MOVEQ #3,D1 ;FOR ROW:=0 TO 3 DO
@0 MOVEQ #3,D2 ;FOR COL:=0 TO 3 DO
@1 CMP D1,D2 ;IF ROW=COL
BNE.S @2
MOVE.L D0,(A0)+ ;THEN xForm[ROW,COL]:=65536
BRA.S @3
@2 CLR.L (A0)+ ;ELSE xForm[ROW,COL]:=0
@3 DBRA D2,@1
DBRA D1,@0
RTS ;END;
EXPORT Scale ;PROCEDURE Scale(xFactor, yFactor, zFactor: fixed);
;change xForm matrix to provide scaling
Scale
MOVEM.L D3-D4/A2-A3,-(SP) ;BEGIN
MOVE.L 4(A5),A0 ;WITH thePort3D^ DO
MOVE.L (A0),A0
CLR.B ident(A0) ;ident:=FALSE;
MOVEQ #3,D3 ;FOR ROW:=0 TO 3 DO (four rows)
LEA xForm(A0),A2
@0 LEA 32(SP),A3 ;xFactor + 4
MOVEQ #2,D4 ;three multiplies for a row
@1 SUBQ.L #4,SP
MOVE.L (A2),-(SP) ;xForm plus offset for each prior *
MOVE.L -(A3),-(SP) ;xFactor, then yFactor, then zFactor
_FixMul
MOVE.L (SP)+,(A2)+ ;xForm[ROW,0]:=xForm[ROW,0]*xFactor;
DBRA D4,@1 ;xForm[ROW,1]:=xForm[ROW,1]*yFactor
DBRA D3,@0 ;xForm[ROW,2]:=xForm[ROW,2]*zFactor
MOVEM.L (SP)+,D3-D4/A2-A3
MOVE.L (SP),A0
ADD #16,SP
JMP (A0) ;END
EXPORT Translate ;PROCEDURE Translate(dx, dy, dz: fixed);
;change xForm matrix to translate
Translate
MOVE.L 4(A5),A0 ;WITH thePort3D^ DO
MOVE.L (A0),A0
CLR.B ident(A0) ;ident:=FALSE;
LEA xForm+xf30(A0),A0
LEA 16(SP),A1
MOVEQ #2,D1
@0 MOVE.L (A0),D0
ADD.L -(A1),D0
MOVE.L D0,(A0)+ ;xForm[3,0]:=xForm[3,0]+dx;
DBRA D1,@0 ;xForm[3,1]:=xForm[3,1]+dy;
MOVE.L (SP),A0
ADD #16,SP
JMP (A0) ;END
EXPORT Yaw, Roll, Pitch
RotEntry MOVE.L (SP)+,A1 ;return address
LINK A6,#0
MOVEM.L A2-A4/D3-D7,-(SP) ;BEGIN
SUB #16,SP ;reserve space for FixDiv, FracSin & FracCos
MOVE.L 8(A6),-(SP)
MOVE.L #fixRad,-(SP)
_FixDiv
MOVE.L (SP),8(SP) ;save result for FracCos
_FracSin
MOVE.L (SP)+,D3 ;si
_FracCos
MOVE.L (SP)+,D4 ;co
MOVE.L 4(A5),A4 ;WITH thePort3D^ DO
MOVE.L (A4),A4
CLR.B ident(A4) ;ident := FALSE
MOVEQ #3,D5
JMP (A1)
Yaw ;PROCEDURE Yaw(yAngle: fixed);
;change xForm matrix to rotate yAngle degrees around y-Axis
BSR.S RotEntry ;yAngle := yAngle/radConst { convert degrees to rads }
;si:=SIN(yAngle)
;co:=COS(yAngle)
;WITH thePort3D^ DO ident := FALSE;
LEA xForm+xf02+48(A4),A2 ;TEMP := xForm[0,0]*co-xForm[0,2]*si (do row 3 first)
LEA xForm+xf00+48(A4),A3 ;xForm[0,2] := xForm[0,0]*si+xForm[0,2]*co
BRA.S CmnRot ;xForm[0,0] := TEMP
;TEMP := xForm[1,0]*co-xForm[1,2]*si
;xForm[1,2] := xForm[1,0]*si+xForm[1,2]*co
;xForm[1,0] := TEMP
;TEMP := xForm[2,0]*co-xForm[2,2]*si
;xForm[2,2] := xForm[2,0]*si+xForm[2,2]*co
;xForm[2,0] := TEMP
;TEMP := xForm[3,0]*co-xForm[3,2]*si
;xForm[3,2] := xForm[3,0]*si+xForm[3,2]*co
;xForm[3,0] := TEMP
Roll ;PROCEDURE Roll(zAngle: fixed);
;change xForm matrix to rotate zAngle degrees around z-Axis
BSR.S RotEntry ;zAngle := zAngle/radConst { convert degrees to rads }
;si:=SIN(zAngle)
;co:=COS(zAngle)
;WITH thePort3D^ DO ident := FALSE;
LEA xForm+xf00+48(A4),A2 ;TEMP := xForm[0,0]*co+xForm[0,1]*si (row 3 first)
LEA xForm+xf01+48(A4),A3 ;xForm[0,1] := xForm[0,1]*co-xForm[0,0]*si
BRA.S CmnRot ;xForm[0,0] := TEMP
;TEMP := xForm[1,0]*co+xForm[1,1]*si
;xForm[1,1] := xForm[1,1]*co-xForm[1,0]*si
;xForm[1,0] := TEMP;
;TEMP := xForm[2,0]*co+xForm[2,1]*si
;xForm[2,1] := xForm[2,1]*co-xForm[2,0]*si
;xForm[2,0] := TEMP;
;TEMP := xForm[3,0]*co+xForm[3,1]*si
;xForm[3,1] := xForm[3,1]*co-xForm[3,0]*si
;xForm[3,0] := TEMP
Pitch ;PROCEDURE Pitch(xAngle: fixed);
;change xForm matrix to rotate xAngle degrees around x-Axis
; D3 = si A2 = xForm + xf01
; D4 = co A3 = xForm + xf02
; A4 = thePort3D^
; D6 = xForm[0,1]
; D7 = xForm[0,2]
BSR.S RotEntry
LEA xForm+xf01+48(A4),A2 ;xForm[3,1]
LEA xForm+xf02+48(A4),A3 ;xForm[3,2]
CmnRot MOVE.L (A2),D6
MOVE.L (A3),D7
SUB #16,SP ;4 _FFixMuls
MOVE.L D6,-(SP)
MOVE.L D4,-(SP)
_FracMul
MOVE.L (SP),4(SP)
MOVE.L D7,-(SP)
MOVE.L D3,-(SP)
_FracMul
MOVE.L (SP)+,D0
ADD.L (SP)+,D0
MOVE.L D0,(A2) ;TEMP := xForm[0,1]*co+xForm[0,2]*si;
MOVE.L D6,-(SP)
MOVE.L D3,-(SP)
_FracMul
MOVE.L (SP),4(SP)
MOVE.L D7,-(SP)
MOVE.L D4,-(SP)
_FracMul
MOVE.L (SP)+,D0
SUB.L (SP)+,D0
MOVE.L D0,(A3) ;xForm[0,2] := xForm[0,2]*co-xForm[0,1]*si
;xForm[0,1] := TEMP
MOVEQ #16,D0 ;TEMP:=xForm[1,1]*co+xForm[1,2]*si
SUB.L D0,A2 ;xForm[1,2]:=xForm[1,2]*co-xForm[1,1]*si
SUB.L D0,A3
DBRA D5,CmnRot ;xForm[1,1] := TEMP
MOVEM.L (SP)+,D3-D7/A2-A4 ;TEMP:=xForm[2,1]*co+xForm[2,2]*si
UNLK A6 ;xForm[2,2]:=xForm[2,2]*co-xForm[2,1]*si
MOVE.L (SP)+,(SP) ;xForm[2,1] := TEMP
RTS ;TEMP:=xForm[3,1]*co+xForm[3,2]*si
;xForm[3,2]:=xForm[3,2]*co-xForm[3,1]*si
;xForm[3,1] := TEMP
EXPORT Skew ;PROCEDURE Skew(zAngle: fixed);
;change xForm matrix to skew zAngle degrees around z-Axis
;x := (x + y*TAN(zAngle)) zAngle limited to +-90 degrees
Skew LINK A6,#0
MOVEM.L D3/D5/A3-A4,-(SP)
SUB #16,SP ;space for FixDiv, FracSin, FracCos, FracRatio
MOVE.L 8(A6),-(SP)
MOVE.L #fixRad,-(SP)
_FixDiv ;{ co := COS(zAngle); }
;{IF ABS(co) > 1.0E-5 THEN BEGIN}
MOVE.L (SP),8(SP) ;copy for FracCos
_FracSin
MOVE.L (SP)+,4(SP) ;move for FracRatio
_FracCos
_FixDiv
MOVE.L (SP)+,D3 ;TA := SIN(zAngle)/co;
MOVE.L 4(A5),A4 ;WITH thePort3D^ DO
MOVE.L (A4),A4
CLR.B ident(A4) ;ident := FALSE
MOVEQ #8,D5 ;FOR COL := 0 TO 2
@0 LEA xForm+xf10(A4,D5),A3
MOVE.L xForm+xf00(A4,D5),-(SP)
MOVE.L D3,-(SP)
_FixMul
MOVE.L (SP)+,D0
ADD.L (A3),D0
MOVE.L D0,(A3) ;xForm[1,COL] := xForm[1,COL]+xForm[0,COL]*TA
SUBQ #4,D5
BNE.S @0
MOVEM.L (SP)+,D3/D5/A3-A4
UNLK A6
MOVE.L (SP)+,(SP)
RTS ;END
EXPORT SetPt3D ;PROCEDURE SetPt3D(VAR pt3D: Point3D; x,y,z: fixed);
SetPt3D LEA 20(SP),A1
MOVE.L -(A1),A0
MOVE.L -(A1),(A0)+ ;pt3D.x := x;
MOVE.L -(A1),(A0)+ ;pt3D.y := y;
MOVE.L -(A1),(A0) ;pt3D.z := z;
MOVE.L (SP),A0
ADD #20,SP
JMP (A0) ;END
EXPORT SetPt2D ;PROCEDURE SetPt2D(VAR pt2D: Point2D; x,y: fixed);
SetPt2D LEA 16(SP),A1
MOVE.L -(A1),A0
MOVE.L -(A1),(A0)+ ;pt2D.x := x;
MOVE.L -(A1),(A0) ;pt2D.y := y;
MOVE.L (SP),A0
ADD #16,SP
JMP (A0) ;END
END ;of Unit