home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
progjour
/
1991
/
06
/
hercline.asm
< prev
next >
Wrap
Assembly Source File
|
1991-03-06
|
13KB
|
458 lines
; 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