home *** CD-ROM | disk | FTP | other *** search
- ; 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