--- /dev/null
+;-----------------------------------------------------------\r
+;\r
+; MXLN.ASM - Line function\r
+; Copyright (c) 1993,1994 by Alessandro Scotti\r
+;\r
+;-----------------------------------------------------------\r
+WARN PRO\r
+NOWARN RES\r
+INCLUDE MODEX.DEF\r
+\r
+PUBLIC mxLine\r
+\r
+MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'\r
+ ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
+\r
+EXTRN mx_BytesPerLine : WORD\r
+EXTRN mx_VideoSegment : WORD\r
+\r
+EXTRN mx_ClipX1 : WORD\r
+EXTRN mx_ClipY1 : WORD\r
+EXTRN mx_ClipX2 : WORD\r
+EXTRN mx_ClipY2 : WORD\r
+\r
+tblDrawFunc LABEL WORD\r
+ DW subWidthMove\r
+ DW subHeightMove\r
+ DW subWidthOp\r
+ DW subHeightOp\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Draws a line from (X1,Y1) to (X2,Y2) using the Bresenham\r
+; algorithm.\r
+;\r
+; Input:\r
+; X1, Y1 = start point\r
+; X2, Y2 = end point\r
+; Color = line color\r
+; Op = raster operator\r
+; Output:\r
+; none\r
+;\r
+; Note: the end point (X2,Y2) *IS* drawed. I don't like this very much\r
+; but clipping is much simpler.\r
+;\r
+mxLine PROC FAR\r
+ ARG Op:WORD, \\r
+ Color:WORD, \\r
+ Y2:WORD, \\r
+ X2:WORD, \\r
+ Y1:WORD, \\r
+ X1:WORD = ARG_SIZE\r
+ LOCAL Width:WORD, \\r
+ Height:WORD, \\r
+ ErrorAdd:WORD, \\r
+ ErrorSub:WORD, \\r
+ DeltaX:WORD, \\r
+ DeltaY:WORD, \\r
+ P1:BYTE, \\r
+ P2:BYTE, \\r
+ WritePlane:BYTE = AUTO_SIZE\r
+ .enter AUTO_SIZE\r
+ .push ds, si, di\r
+ ASSUME ds:NOTHING\r
+\r
+ mov ax, [X1]\r
+ mov bx, [Y1]\r
+ mov cx, [X2]\r
+ mov dx, [Y2]\r
+ call subClipLine\r
+ jc @@Exit ; Line is full clipped\r
+\r
+; Get width\r
+ mov si, cx\r
+ xchg ax, si ; SI = X1, AX = X2\r
+ sub ax, si\r
+ jge @@1\r
+; Swap points, we want X1 < X2\r
+ xchg si, cx ; Swap X1 and X2\r
+ xchg bx, dx ; Swap Y1 and Y2\r
+ neg ax\r
+@@1:\r
+ mov [Width], ax\r
+\r
+; Get height\r
+ mov cx, [mx_BytesPerLine] ; We don't need X2 anymore\r
+ mov ax, dx\r
+ sub ax, bx\r
+ jge @@2\r
+ neg cx ; Move from bottom to top\r
+ neg ax ; Get absolute value of AX\r
+@@2:\r
+ mov [Height], ax\r
+ mov [DeltaY], cx\r
+\r
+; Get pixel address and write plane\r
+ mov ax, bx\r
+ mul [mx_BytesPerLine]\r
+ mov cx, si ; CX = X1\r
+ shr si, 1\r
+ shr si, 1\r
+ add si, ax ; SI = pixel offset\r
+ and cl, 03h\r
+ mov ax, 1102h\r
+ shl ah, cl\r
+ mov [WritePlane], ah\r
+ mov dx, TS\r
+ out dx, ax ; Set write plane\r
+ mov ax, [mx_VideoSegment]\r
+ mov ds, ax ; DS:SI points to (X1,Y1)\r
+\r
+; Select the function to handle the drawing loop\r
+ xor bx, bx\r
+ mov al, BYTE PTR [Op]\r
+ cmp al, OP_MOVE\r
+ je @@3\r
+ and al, 03h\r
+ shl al, 1\r
+ shl al, 1\r
+ shl al, 1\r
+ mov ah, al\r
+ mov al, 03h\r
+ mov dx, GDC\r
+ out dx, ax ; Set logical function\r
+ inc bx\r
+ inc bx\r
+@@3:\r
+ mov ax, [Width]\r
+ mov cx, [Height]\r
+; Horizontal, vertical and diagonal lines are not optimized yet\r
+ cmp ax, cx\r
+ jae @@4\r
+ inc bx\r
+@@4:\r
+ shl bx, 1\r
+ call tblDrawFunc[bx]\r
+\r
+; Reset logical function if needed\r
+ cmp BYTE PTR [Op], OP_MOVE\r
+ je @@Exit\r
+ mov ax, 0003h\r
+ mov dx, GDC\r
+ out dx, ax\r
+\r
+@@Exit:\r
+ xor ax, ax\r
+ .pop ds, si, di\r
+ .leave ARG_SIZE\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Checks the coordinates of a line against the active\r
+; clip region.\r
+; Uses a variation of the Cohen-Sutherland algorithm developed\r
+; by Victor Duvanenko.\r
+;\r
+; Input:\r
+; AX, BX = X1, Y1\r
+; CX, DX = X2, Y2\r
+; Output:\r
+; CF = set if line is full clipped\r
+; AX, BX = clipped X1, Y1\r
+; CX, DX = clipped X2, Y2\r
+; Note:\r
+; destroys SI, DI\r
+;\r
+subClipLine PROC NEAR\r
+ mov di, ax ; Copy X1 to DI and free AX\r
+ mov si, dx ; Copy Y2 to SI and free DX\r
+; Compute clip codes for point (X2,Y2)=(CX,SI)\r
+ xor al, al\r
+@@P2X1: cmp cx, [mx_ClipX1]\r
+ jge @@P2X2\r
+ or al, 1\r
+@@P2X2: cmp cx, [mx_ClipX2]\r
+ jle @@P2Y1\r
+ or al, 2\r
+@@P2Y1: cmp si, [mx_ClipY1]\r
+ jge @@P2Y2\r
+ or al, 4\r
+@@P2Y2: cmp si, [mx_ClipY2]\r
+ jle @@P2XY\r
+ or al, 8\r
+@@P2XY: mov [P2], al\r
+; Compute clip codes for point (X1,Y1)=(DI,BX)\r
+ xor al, al\r
+@@P1X1: cmp di, [mx_ClipX1]\r
+ jge @@P1X2\r
+ or al, 1\r
+@@P1X2: cmp di, [mx_ClipX2]\r
+ jle @@P1Y1\r
+ or al, 2\r
+@@P1Y1: cmp bx, [mx_ClipY1]\r
+ jge @@P1Y2\r
+ or al, 4\r
+@@P1Y2: cmp bx, [mx_ClipY2]\r
+ jle @@P1XY\r
+ or al, 8\r
+@@P1XY: mov [P1], al\r
+; Check codes for trivial cases\r
+ mov ah, [P2]\r
+ test al, ah ; Is line invisible?\r
+ jnz @@FullClip ; Yes, exit\r
+ or ah, al ; Both points clipped?\r
+ jz @@Done ; Yes, exit\r
+; Calculate deltas\r
+ mov ax, cx\r
+ sub ax, di\r
+ mov [DeltaX], ax\r
+ mov ax, si\r
+ sub ax, bx\r
+ mov [DeltaY], ax\r
+ mov al, [P1] ; Init clipping code\r
+; Clipping loop\r
+@@ClipLoop:\r
+ test al, al ; Is first point clipped?\r
+ jnz @@ClipX1 ; No, continue\r
+ xchg cx, di ; Swap points...\r
+ xchg bx, si\r
+ xchg al, [P2] ; ...and codes\r
+; Clip left: Y1 = Y1 + DeltaY*(mx_ClipX1-X1)/DeltaX\r
+@@ClipX1:\r
+ test al, 1\r
+ jz @@ClipX2\r
+ mov ax, [mx_ClipX1]\r
+ sub ax, di\r
+ mov di, [mx_ClipX1]\r
+ jmp @@ClipX1X2\r
+; Clip right: Y1 = Y1 + DeltaY*(mx_ClipX2-X1)/DeltaX\r
+@@ClipX2:\r
+ test al, 2\r
+ jz @@ClipY1\r
+ mov ax, [mx_ClipX2]\r
+ sub ax, di\r
+ mov di, [mx_ClipX2]\r
+@@ClipX1X2:\r
+ imul [DeltaY]\r
+ idiv [DeltaX]\r
+ add bx, ax\r
+ mov al, 8\r
+ cmp bx, [mx_ClipY2]\r
+ jg @@CheckLoop\r
+ mov al, 4\r
+ cmp bx, [mx_ClipY1]\r
+ jl @@CheckLoop\r
+ xor al, al\r
+ jmp @@CheckLoop\r
+; Clip top: X1 = X1 + DeltaX*(mx_ClipY1-Y1)/DeltaY\r
+@@ClipY1:\r
+ test al, 4\r
+ jz @@ClipY2\r
+ mov ax, [mx_ClipY1]\r
+ sub ax, bx\r
+ mov bx, [mx_ClipY1]\r
+ jmp @@ClipY1Y2\r
+; Clip bottom: X1 = X1 + DeltaX*(mx_ClipY2-Y1)/DeltaY\r
+@@ClipY2:\r
+ mov ax, [mx_ClipY2]\r
+ sub ax, bx\r
+ mov bx, [mx_ClipY2]\r
+@@ClipY1Y2:\r
+ imul [DeltaX]\r
+ idiv [DeltaY]\r
+ add di, ax\r
+ mov al, 1\r
+ cmp di, [mx_ClipX1]\r
+ jl @@CheckLoop\r
+ mov al, 2\r
+ cmp di, [mx_ClipX2]\r
+ jg @@CheckLoop\r
+ xor al, al\r
+@@CheckLoop:\r
+ mov ah, [P2]\r
+ test al, ah\r
+ jnz @@FullClip\r
+ or ah, al\r
+ jnz @@ClipLoop\r
+\r
+@@Done:\r
+ mov ax, di\r
+ mov dx, si\r
+ clc\r
+ ret\r
+@@FullClip:\r
+ stc\r
+ ret\r
+subClipLine ENDP\r
+\r
+; Called when Width >= Height and Op = OP_MOVE\r
+subWidthMove PROC NEAR\r
+ mov di, ax\r
+ neg di ; Initialize error term\r
+ shl cx, 1\r
+ mov [ErrorAdd], cx\r
+ mov cx, ax\r
+ shl ax, 1\r
+ mov [ErrorSub], ax\r
+ mov al, 02h\r
+ mov ah, [WritePlane]\r
+ mov bl, BYTE PTR [Color]\r
+ mov dx, TS\r
+ inc cx\r
+@@Loop:\r
+ mov ds:[si], bl\r
+ dec cx\r
+ jz @@Exit\r
+ rol ah, 1\r
+ adc si, 0\r
+ out dx, ax\r
+ add di, [ErrorAdd]\r
+ jl @@Loop\r
+ add si, [DeltaY]\r
+ sub di, [ErrorSub]\r
+ jmp @@Loop\r
+@@Exit:\r
+ ret\r
+subWidthMove ENDP\r
+\r
+; Called when Width < Height and Op = OP_MOVE\r
+subHeightMove PROC NEAR\r
+ mov di, cx\r
+ neg di ; Initialize error term\r
+ shl ax, 1\r
+ mov [ErrorAdd], ax\r
+ mov ax, cx\r
+ shl ax, 1\r
+ mov [ErrorSub], ax\r
+ mov bl, BYTE PTR [Color]\r
+ mov ah, [WritePlane]\r
+ mov al, 02h\r
+ mov dx, TS\r
+ inc cx\r
+@@Loop:\r
+ mov ds:[si], bl\r
+ dec cx\r
+ jz @@Exit\r
+ add si, [DeltaY]\r
+ add di, [ErrorAdd]\r
+ jl @@Loop\r
+ rol ah, 1 ; Next write plane\r
+ adc si, 0 ; Bump video offset if plane overflows\r
+ out dx, ax\r
+ sub di, [ErrorSub] ; Adjust error down\r
+ jmp @@Loop\r
+@@Exit:\r
+ ret\r
+subHeightMove ENDP\r
+\r
+; Called when Width >= Height and Op <> OP_MOVE\r
+subWidthOp PROC NEAR\r
+ mov di, ax\r
+ neg di ; Initialize error term\r
+ shl cx, 1\r
+ mov [ErrorAdd], cx\r
+ mov cx, ax\r
+ shl ax, 1\r
+ mov [ErrorSub], ax\r
+ mov al, 02h\r
+ mov ah, [WritePlane]\r
+ mov bl, BYTE PTR [Color]\r
+ mov dx, TS\r
+ inc cx\r
+@@Loop:\r
+ mov bh, ds:[si] ; Latch data\r
+ mov ds:[si], bl\r
+ dec cx\r
+ jz @@Exit\r
+ rol ah, 1\r
+ adc si, 0\r
+ out dx, ax\r
+ add di, [ErrorAdd]\r
+ jl @@Loop\r
+ add si, [DeltaY]\r
+ sub di, [ErrorSub]\r
+ jmp @@Loop\r
+@@Exit:\r
+ ret\r
+subWidthOp ENDP\r
+\r
+; Called when Width < Height and Op <> OP_MOVE\r
+subHeightOp PROC NEAR\r
+ mov di, cx\r
+ neg di ; Initialize error term\r
+ shl ax, 1\r
+ mov [ErrorAdd], ax\r
+ mov ax, cx\r
+ shl ax, 1\r
+ mov [ErrorSub], ax\r
+ mov bl, BYTE PTR [Color]\r
+ mov ah, [WritePlane]\r
+ mov al, 02h\r
+ mov dx, TS\r
+ inc cx\r
+@@Loop:\r
+ mov bh, ds:[si]\r
+ mov ds:[si], bl\r
+ dec cx\r
+ jz @@Exit\r
+ add si, [DeltaY]\r
+ add di, [ErrorAdd]\r
+ jl @@Loop\r
+ rol ah, 1 ; Next write plane\r
+ adc si, 0 ; Bump video offset if plane overflows\r
+ out dx, ax\r
+ sub di, [ErrorSub] ; Adjust error down\r
+ jmp @@Loop\r
+@@Exit:\r
+ ret\r
+subHeightOp ENDP\r
+\r
+mxLine ENDP\r
+\r
+MX_TEXT ENDS\r
+END\r