Category : Files from Magazines
Archive   : PJ96.ZIP
Filename : HERCLINE.ASM

 
Output of file : HERCLINE.ASM contained in archive : PJ96.ZIP
; hercline.asm: line-drawing routine for the Hercules monochrome
; graphics card.
; Copyright (C) 1990 by Nicholas Wilt. All rights reserved.

.MODEL COMPACT

PAGE ,132

.CODE

ASSUME cs:_TEXT,ds:_TEXT

PUBLIC _hercline

BytesPerRow EQU 90 ; Change to 80 for 640x400 mode
BytesPerBank EQU 7830 ; Change to 8000 for 640x400 mode
; BytesPerBank is (YRes/4)*BytesPerRow.

; The IncY and DecY macros update the offset-mask pair in DI and AH to
; point to the above or below pixel. They do not depend on whether
; the routine is drawing or erasing.
IncY MACRO
LOCAL ExitIncY
add di,bp ;; 8192 in BP
jno ExitIncY ;; Leave if done
;; Undo and compensate
sub di,24576+BytesPerBank-BytesPerRow+8192
jge ExitIncY ;; Leave if done
add di,BytesPerBank ;; Undo and compensate
ExitIncY:
ENDM

DecY MACRO
LOCAL ExitDecY
sub di,bp ;; 8192 in BP
jns ExitDecY ;; Leave if done
sub di,BytesPerRow-8192-24576 ;; Undo and compensate
jge ExitDecY ;; Leave if done
add di,BytesPerBank ;; Undo and compensate
ExitDecY:
ENDM

; ******************************************************************
; void hercline(int x1, int y1, int x2, int y2, int color);
; C-callable in tiny, small, compact memory models.
; To use medium, large, or huge, just add 2 to the indices when
; loading the parameters.
; Color is nonzero to draw the line, 0 to erase the line (set to 0).
; ******************************************************************
_hercline PROC
push bp ; Enter
mov bp,sp ; Set up stack frame
push ds ; Save regs
push di ;
push si ;

; Add two to each of the indices below to use a large code model.
mov ax,[bp+4] ; Load x1
mov bx,[bp+6] ; Load y1
mov cx,[bp+8] ; Load x2
mov dx,[bp+10] ; Load y2
mov bp,[bp+12] ; Load color into BP. Dangerous.

cld ; String ops go forward
push cs ; Copy CS to DS for table lookup
pop ds ;

sub dx,bx ; DX <- diffy
sub cx,ax ; CX <- diffx
jge CheckForNull ; Jump if x2 >= x1
add ax,cx ; Make ax contain x2
add bx,dx ; Make bx contain y2
neg dx ; Negate diffx and diffy
neg cx ;
CheckForNull: ; Make sure the line's start and end
; points are different
jnz DrawLine ; If diffx nonzero, draw the line
or dx,dx ; Check diffy against 0
jnz DrawLine ; If not zero, draw the line
jmp LeaveLine ; Do not try to draw line if
; x1==x2 && y1==y2
DrawLine:
mov di,ax ; Load X into DI
shr di,1 ; Divide by 8 for initial offset
shr di,1 ;
shr di,1 ;

push cx ; Save DIFFX and DIFFY on stack
push dx ;
xchg ax,cx ; CX <- X; AX <- DIFFX
mov ax,bx ; AX <- Y

and bx,3 ; Add bank into offset
shl bx,1 ;
add di,Banks[BX] ; Lookup table located after routine

shr ax,1 ; Divide Y by 4
shr ax,1 ;
mov dx,BytesPerRow ; Load factor to multiply by
mul dx ; Perform multiply
add di,ax ; Add to offset

and cl,7 ; x &= 7
mov ah,80h ; AH <- Initial mask
shr ah,cl ;

mov cx,0B000H ; Point DS and ES at video memory
mov ds,cx ;
mov es,cx ;

mov al,[di] ; Pick up initial value
pop dx ; Restore DIFFX and DIFFY
pop bx ;
or dx,dx ; If DIFFY 0, draw span
jnz CheckDrawing
call hercspan ; Call span routine
jmp LeaveLine ; Leave
CheckDrawing:
or bp,bp ; Are we drawing?
jnz CheckDIFFY ; Yes, don't take one's comp of mask
not ah ; AH <- ~AH
CheckDIFFY:
or dx,dx ; Compare DIFFY to 0
jl DIFFYNegative ; Jump if less than
jmp DIFFYPositive
DIFFYNegative:
mov cx,dx ; Copy DIFFY to CX for compare
neg cx ; Negate for compare
cmp cx,bx ; Compare to DIFFX
jle LineXYM ; Jump if -diffy <= diffx
LineYMX: ; Decrement Y before incrementing X
; (count is already in cx)
mov si,dx ; Initialize error
sar si,1 ;
or bp,bp ; Are we drawing?
mov bp,8192 ; Set up for changes in Y
jne DrawYMX ; Jump if yes

; *************************************
; Loop: Erase, decrement Y, and increment X if appropriate.
; *************************************
EraseYMX:
and byte ptr [di],ah ; Erase
sub di,bp ; Decrement Y
js FixupEraseYMX ; Jump if we need to fixup
ContinueEraseYMX:
add si,bx ; Add DIFFX to error
jns ELoopYMX ; Jump if positive
loop EraseYMX ; Loop until done
jmp short DoneEYMX ; Leave if done
FixupEraseYMX:
sub di,BytesPerRow-8192-24576 ; Undo and compensate
jge ContinueEraseYMX ; Leave if done
add di,BytesPerBank ; Undo and compensate
jmp short ContinueEraseYMX
ELoopYMX:
ror ah,1 ; Increment X
sbb di,-1 ;
add si,dx ; Add DIFFY to error
loop EraseYMX ; Loop until done
DoneEYMX:
and byte ptr [di],ah ; Last plot
jmp LeaveLine ; Jump to exit code

; *************************************
; Loop: Draw, decrement Y, and increment X if appropriate.
; *************************************
DrawYMX:
or byte ptr [di],ah ; Plot
sub di,bp ; Decrement Y
js FixupDrawYMX ; Jump if fixup needed
ContinueDrawYMX:
add si,bx ; Add DIFFX to err
jns DLoopYMX ; Jump if positive
loop DrawYMX ; Loop until done
jmp short DoneDYMX ; Jump if done
FixupDrawYMX:

sub di,BytesPerRow-8192-24576 ; Undo and compensate
jge ContinueDrawYMX ; Leave if done
add di,BytesPerBank ; Undo and compensate
jmp short ContinueDrawYMX
DLoopYMX:
ror ah,1 ; Increment X
adc di,0 ;
add si,dx ; Add DIFFY
loop DrawYMX ; Loop until done
DoneDYMX:
or byte ptr [di],ah ; Last plot
jmp LeaveLine ; Jump to exit code

LineXYM:
mov cx,bx ; Get count
mov si,bx ; Initialize error
neg si ;
sar si,1 ;
or bp,bp ; Are we drawing?
mov bp,8192 ; Set up for changes in Y
jne DrawXYM ; Jump if drawing

; *************************************
; Loop: Erase, increment X, and decrement Y if appropriate.
; *************************************
EraseXYM:
and al,ah ; Erase
ror ah,1 ; Rotate mask right
jnc GetNextEraseXYM ; Jump if we need another byte
ContinueEraseXYM:
sub si,dx ; Subtract DIFFY from err
jns ELoopXYM ; Jump if positive
loop EraseXYM ; Loop until done
jmp short DoneEXYM ; Jump if done
GetNextEraseXYM:
stosb ; Store and increment DI
mov al,[di] ; Get next byte
jmp short ContinueEraseXYM
ELoopXYM:
mov [di],al ; Save to video memory
DecY ; Decrement Y
mov al,[di] ; Load from video memory
sub si,bx ; Subtract DIFFX from err
loop EraseXYM ; Loop until done
DoneEXYM:
and al,ah ; Last plot
jmp WriteLastByte ; Jump to exit code

; *************************************
; Loop: Draw, increment X, and decrement Y if appropriate.
; *************************************
DrawXYM:
or al,ah ; Plot
ror ah,1 ; Rotate mask right
jc GetNextDrawXYM ; Jump if we need another byte
DrawContinueXYM:
sub si,dx ; Subtract DIFFY from err
jns DLoopXYM ; Jump if positive
loop DrawXYM ; Loop until done
jmp short DoneDXYM ; Jump if done
GetNextDrawXYM:
stosb ; Store and increment DI
mov al,[di] ;
jmp short DrawContinueXYM
DLoopXYM:
mov [di],al ; Save to video memory
DecY ; Decrement Y
mov al,[di] ; Load from video memory
sub si,bx ; Subtract DIFFX
loop DrawXYM ; Loop until done

DoneDXYM:
or al,ah ; Plot last
jmp WriteLastByte ; Jump to exit code

DIFFYPositive:
cmp dx,bx ; Compare DIFFY to DIFFX
jle LineXYP ; Jump if less than or equal to
LineYPX:
mov cx,dx ; Load count
mov si,dx ; Initialize error
neg si ;
sar si,1 ;
or bp,bp ; Are we drawing?
mov bp,8192 ; Set up for changes in Y
jne DrawYPX ; Jump if yes

; *************************************
; Loop: Erase, increment Y, and increment X if appropriate.
; *************************************
EraseYPX:
and byte ptr [di],ah ; Erase
add di,bp ; Increment Y
jo FixupEraseYPX ; Jump if fixup needed
ContinueEraseYPX:
add si,bx ; Add DIFFX to err
jns ELoopYPX ; Jump if positive
loop EraseYPX ; Loop until done
jmp short DoneEYPX ; Jump if done
FixupEraseYPX:
sub di,24576+BytesPerBank-BytesPerRow+8192
jge ContinueEraseYPX ; Leave if done
add di,BytesPerBank ; Undo and compensate
jmp short ContinueEraseYPX
ELoopYPX:
ror ah,1 ; Increment X
sbb di,-1 ;
sub si,dx ; Subtract DIFFY from err
loop EraseYPX ; Loop until done
DoneEYPX:
and byte ptr [di],ah ; Erase last
jmp LeaveLine ; Jump to exit code

; *************************************
; Loop: Draw, increment Y, and increment X if appropriate.
; *************************************
DrawYPX:
or byte ptr [di],ah ; Plot
add di,bp ; Increment Y
jo FixupDrawYPX ; Jump if fixup needed
ContinueDrawYPX:
add si,bx ; Add DIFFX to err
jns DLoopYPX ; Jump if positive
loop DrawYPX ; Loop until done
jmp short DoneDYPX ; Jump if done
FixupDrawYPX:
sub di,24576+BytesPerBank-BytesPerRow+8192
jge ContinueDrawYPX ; Leave if done
add di,BytesPerBank ; Undo and compensate
jmp short ContinueDrawYPX
DLoopYPX:
ror ah,1 ; Increment X
adc di,0 ;
sub si,dx ; Subtract DIFFY from err
loop DrawYPX ; Loop until done
DoneDYPX:
or byte ptr [di],ah ; Plot last
jmp short LeaveLine ; Jump to exit code

LineXYP:
mov cx,bx ; Load count
mov si,cx ; Initialize error
neg si ;
sar si,1 ;
or bp,bp ; Are we drawing?
mov bp,8192 ; Set up for changes in Y
jne DrawXYP ; Jump if yes

; *************************************
; Loop: Erase, increment X, and increment Y if appropriate.
; *************************************
EraseXYP:
and al,ah ; Erase
ror ah,1 ; Rotate mask right
jnc GetNextEraseXYP ; Jump if we need another byte
ContinueEraseXYP:
add si,dx ; Add DIFFY to err
jns ELoopXYP ; Jump if positive
loop EraseXYP ; Loop until done
jmp short DoneEXYP ; Jump to end
GetNextEraseXYP:
stosb ; Store and increment DI
mov al,[di] ; Get next byte
jmp short ContinueEraseXYP
ELoopXYP:
mov [di],al ; Save to video memory
IncY ; Increment Y
mov al,[di] ; Load from video memory
sub si,bx ; Add DIFFX to err
loop EraseXYP ; Loop until done
DoneEXYP:
and al,ah ; Erase last
jmp short WriteLastByte

; *************************************
; Loop: Draw, increment X, and increment Y if appropriate.
; *************************************
DrawXYP:
or al,ah ; Plot
ror ah,1 ; Rotate mask right
jc GetNextDrawXYP ; Jump if we need another byte
DrawContinueXYP:
add si,dx ; Add DIFFY to err
jns DLoopXYP ; Jump if positive
loop DrawXYP ; Loop until done
jmp short DoneDXYP ; Jump if done
GetNextDrawXYP:
stosb ; Store byte and increment
mov al,[di] ; Get next byte
jmp short DrawContinueXYP
DLoopXYP:
mov [di],al ; Save to video memory
IncY ; Increment Y
mov al,[di] ; Load from video memory
sub si,bx ; Subtract DIFFX from err
loop DrawXYP ; Loop until done
DoneDXYP:
or al,ah ; Plot last

WriteLastByte: ; Write the last byte before exiting
mov [di],al ; Save final byte
LeaveLine:
pop si ; Restore registers
pop di ;
pop ds ;
pop bp ; Restore stack frame
ret ; Exit routine

Banks DW 0,8192,16384,24576

_hercline ENDP

; hercspan called from _hercline if line is horizontal.
; Input register states as follows:
; DS,ES 0B000H
; BX DIFFX
; DX 0 (DIFFY)
; BP 0 if erasing, nonzero if drawing
; AL initial value
; AH initial mask
hercspan PROC
mov cx,bx ; Get count into CX
or bp,bp ; Are we drawing?
jnz DrawFirstLoop ; Yes
not ah ; AH <- ~AH
EraseFirstLoop:
and al,ah ; Write pixel
dec cx ; Decrement CX
ror ah,1 ; Rotate mask right
jnc DoneEraseFirstLoop
jcxz DoneEraseFirstLoop
jmp short EraseFirstLoop
DoneEraseFirstLoop:
stosb ; Store byte
mov dx,cx ; Copy count remaining
shr cx,1 ; Divide by 8
shr cx,1 ;
shr cx,1 ;
sub dx,cx ; Find remainder
xor al,al ; Write 0's
rep stosb ;
mov cx,dx ; Copy remainder to CX
jcxz LeaveSpan ; Leave if done
mov al,[di] ;
mov ah,7fh ; Set mask
EraseSecondLoop:
and al,ah ; Write pixel
ror ah,1 ; Rotate mask right
loop EraseSecondLoop ;
stosb ; Store byte
jmp short LeaveSpan ; Leave
DrawFirstLoop:
or al,ah ; Write pixel
dec cx ; Decrement CX
ror ah,1 ; Rotate mask right
jc DoneDrawFirstLoop
jcxz DoneDrawFirstLoop
jmp short DrawFirstLoop
DoneDrawFirstLoop:
stosb ; Store byte
mov dx,cx ; Copy count remaining
shr cx,1 ; Divide by 8
shr cx,1 ;
shr cx,1 ;
sub dx,cx ; Find remainder
mov al,0FFh ; Write FF's
rep stosb ;
mov cx,dx ; Copy remainder to CX
jcxz LeaveSpan ; Leave if done
mov al,[di] ;
mov ah,80h ; Set mask
DrawSecondLoop:
or al,ah ; Write pixel
ror ah,1 ; Rotate mask right
loop DrawSecondLoop ;
stosb ; Store byte
LeaveSpan:
ret
hercspan ENDP

END


  3 Responses to “Category : Files from Magazines
Archive   : PJ96.ZIP
Filename : HERCLINE.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/