$NOLIST
$DEBUG
	NAME	Compass_II_Console

$INCLUDE (``OsIncs`WinASM~Inc~)

CGROUP	GROUP	CODE

	PUBLIC	BlitRectangle
	PUBLIC	CpDrawChars

	EXTRN	InitWinParms:NEAR,	StartPosition:NEAR, RestoreEmsSlot:NEAR

bitsPerByte	EQU 8
bitsPerWord	EQU 16
pelsPerWord	EQU 16
fontOverhead	EQU 8
fastWidth		EQU 8
ellipsis		EQU 0F7H
ellipsisCh	EQU 086H
shiftRet		EQU 0CDH
shiftRetCh	EQU 080H

screenSeg	EQU	0B800h	; display is at 0B800h:0
pcFormat  EQU       0

csrOn	EQU	1
XHOME	EQU	1
YHOME	EQU	1

CR	EQU	0DH
LF	EQU	0AH
BS	EQU	08H

allOnes	EQU	0FFFFH
MOD16	EQU	000FH
MOD8	     EQU	0007H
colorMask EQU  08000H
pelMask   EQU  07FFFH

$EJ

CODE  SEGMENT PUBLIC	'CODE'

	ASSUME	CS:CGROUP

Masks	DW	0FFFFH
     	DW	07FFFH
	     DW	03FFFH
     	DW	01FFFH
	     DW	00FFFH
	     DW	007FFH
	     DW	003FFH
	     DW	001FFH
	     DW	000FFH


$EJ

; parameters & locals for MoveHLine

params		STRUC
oddLineFlag         DB ?
dummy               DB ?
firstWord		DW ?
fromAlign		DB ?
toAlign		DB ?
fromFullWords	DB ?
toFullWords	DB ?
toLastBits	DB ?
fromLastBits	DB ?
preMask		DW ?
postMask		DW ?

oldBP		DW ?
oldDS		DW ?
returnIP		DW ?
returnCS		DW ?

toY		DW ?
toX		DW ?
windowHeight        DW ?
bytesPerLine        DW ?
screen              DW ?
rectHeight	DW ?
rectWidth		DW ?
nextRow		DW ?
rect		DD ?

params		ENDS

localBytes	EQU 14
loc		EQU [BP-localBytes]
paramBytes	EQU 20

$EJ
$LIST
BlitRectangle	PROC FAR

;PROCEDURE BlitRectangle (VAR rectangle: BYTE;
;                         nextRow: WORD;
;                         width, height: WORD;
;                         screen, bytesPerLine,
;                         windowHeight : WORD;
;                         toX,  toY:   WORD);
;
; This routine takes a rectangle in memory (a character, icon, etc.) which was 
; defined by GRiDFONT and blits it to the display.

BlitRectangleNear LABEL NEAR
	PUSH	DS		; save data segment
	PUSH	BP		; save old BP value
	MOV	BP,SP		; set BP to parameters
	SUB	SP,localBytes	; reserve space for local variables

	MOV	 AX,loc.screen	   ; get the screen segment value
 MOV  DX,loc.bytesPerLine
 MOV  DI,loc.windowHeight

 CALL InitWinParms

	MOV	 ES,AX		          ; set up ES a screen segment
 MOV  loc.windowHeight,DI
 PUSH SI               ; save old ems slot

; Calls StartPosition to
; Compute word address & shift count, given x & y
;   INPUT:  AX = y, BX = x, CX=format, DX=bytesperline
;		  DI = oddline offset
;   OUTPUT: DI = offset to word, CX = shift count
;   USES:   DX

; CX, DX and DI set by InitWinParms

	MOV	AX,loc.toY	; get destination Y value
	MOV	BX,loc.toX	; get destination x value

 CALL StartPosition	; compute destination addr and shift count

	CLD
	LDS	 SI,loc.rect	     ; set up DS and SI to point to rect
$EJ

; DS:SI => fontTable
; ES:DI => display word
; CX    =  shift count

	MOV  loc.oddlineflag,AL
	CMP	loc.rectWidth,fastWidth   ; get the font width
	JLE	fastBlit		           ; is it less than 8 pixels
	JMP	slowBlit		           ; no - use slower routine

FastBlit:
	MOV	AX,CX                     ; shift count
	MOV  BX,loc.rectWidth
	ADD  AX,BX
;     SHL	AX,1	                	; 2 bits per pel
	CMP	AX,bitsPerWord	          ; is it greater than a word ?
	JG	Split		      	; yes - jump


	SHL	BX,1	               	; masks array is a word wide
	MOV	DX,WORD PTR CS:Masks[BX]   ; 
;	SHL  CX,1					; 2 bits / pel

     ROR	DX,CL
	XCHG	DL,DH		;reverse bytes

	CLD

	MOV	AX,loc.rectHeight
	MOV  CH,AL
	SHR  CH,1
	PUSH DI
	PUSH SI
	PUSH CX
	ADC  CH,0
	CALL FastLoop

	POP  CX
	POP  SI
	POP  DI

	XOR  loc.oddLineFlag,1
	JNZ	nextLineOdd1		    ; jump if next line odd

	SUB  DI,loc.windowHeight
	ADD	DI,loc.bytesPerLine
	JMP  adjustSourcePtr1
NextLineOdd1:
	ADD  DI,loc.windowHeight
adjustSourcePtr1:
	ADD  SI,loc.nextRow

	CALL FastLoop

FastExit:
 POP AX
 INC AX
 JZ  FastExitRet

 DEC AX
 CALL RestoreEmsSlot

FastExitRet:
	MOV	SP,BP
	POP	BP
	POP	DS
	RET	paramBytes


FastLoop PROC NEAR	
	MOV	BH,BYTE PTR [SI]
	XOR  BL,BL
	SHR  BX,CL
	XCHG	BL,BH		
	MOV  AX,DX
	AND  AX,WORD PTR ES:[DI]
	OR   AX,BX
	STOSW
	ADD  DI, loc.bytesPerLine	  ; go to next row
	SUB  DI, 2				  ; account for stosw
	MOV  AX,loc.NextRow
	SHL  AX,1					  ; only doing 1/2 of char
	ADD  SI,AX
	DEC  CH
	JNZ   FastLoop
	RET
FastLoop ENDP

$EJ

Split:
	MOV	loc.toAlign,CL		; example: 10
     MOV  BX, loc.rectWidth ; assume 7
	SHL  BX, 1             ; masks is a word wide array
	MOV  DX, WORD PTR CS:Masks[BX]  ;01FFH
	ROR  DX, CL				  ;0111 1111 1100 0000
	MOV  BX, DX
	MOV  BH, 0FFH				  ;1111 1111 1100 0000
	MOV  DL, 0FFH				  ;0111 1111 1111 1111
     XCHG	BL, BH
     XCHG	DL, DH

	CLD
	MOV	AX,loc.rectHeight
	MOV  CH,AL
	SHR  CH,1
	PUSH DI
	PUSH SI
	PUSH CX
	ADC  CH,0
	CALL SplitLoop

	POP  CX
	POP  SI
	POP  DI

	XOR  loc.oddLineFlag,1
	JNZ	nextLineOdd2		    ; jump if next line odd

	SUB  DI,loc.windowHeight
	ADD	DI,loc.bytesPerLine
	JMP  adjustSourcePtr2

NextLineOdd2:
	ADD  DI,loc.windowHeight

adjustSourcePtr2:
	ADD	SI,loc.nextRow

	CALL SplitLoop

SplitExit:
 POP AX
 INC AX
 JZ  SplitExitRet

 DEC AX
 CALL RestoreEmsSlot

SplitExitRet:
	MOV	SP,BP
	POP	BP
	POP	DS
	RET	paramBytes




SplitLoop PROC NEAR	
	MOV	CL,loc.toAlign
SplitLoop2:
	MOV	AH,BYTE PTR [SI]
	XOR  AL,AL
	ROR	AX,CL
	XCHG	AL,AH		;reverse again

	PUSH CX				   ; store align
	PUSH	AX				   ; store font bits
	MOV  CX,AX			   ; CX = rotated char

	MOV  AX, WORD PTR ES:[DI]   ; orig word

	AND	AX,BX			   ; mask 
     NOT  BX
     AND	CX,BX
	OR	AX,CX
	STOSW
	NOT	BX

	POP	CX				   ; retrieve font bits
	MOV  AX, WORD PTR ES:[DI]

	AND	AX,DX
     NOT  DX
     AND	CX,DX
	OR	AX,CX
	STOSW
     NOT  DX

; calculate new DI
     POP	CX					; retrieve toAlign
	ADD  DI, loc.bytesPerLine	; go to next row
	SUB  DI, 4				; account for stosw
	MOV  AX,loc.NextRow
	SHL  AX,1
	ADD  SI,AX
	DEC  CH
	JNZ  SplitLoop2
	RET
splitLoop ENDP

$EJECT
slowBlit:
	MOV  loc.toAlign, CL  	 ; save the shift count

	MOV	AX,loc.rectWidth	 ; charWidth
	NEG	CX		           ;returned by StartPosition
	ADD	CX,bitsPerWord	      ;CX := 16 - toAlign
						 ; = # bits to write into word
	SUB	AX,CX		      ;width - (16-toAlign)
						 ; = # bits past first word to write
	JG 	SHORT calcWords
	ADD	AX, bitsPerWord	 ;width + toAlign (<= 16)
	MOV	loc.toFullWords,0	 ; no full words
	MOV	loc.toLastBits,AL	 ; last bits to write (includes toAlign)
	JMP	SHORT setMasks
calcWords:
	MOV	BX,AX			 ; store # bits past 1st word
	AND	BX,MOD16			 ; get remaining bits mod 16
	MOV	loc.toLastBits,BL	 ; = # bits in last word
	SHR	AX,1				 ; divide # bits past 1st word by 16
	SHR	AX,1
	SHR	AX,1
	SHR	AX,1		           ; AX / 16
	MOV	loc.toFullWords,AL	 ; store it in toFullWords

setMasks:
	MOV	BX,allOnes		 ; mask
	MOV	CL,loc.toAlign
	SHR	BX,CL			 ; 1s are in least sig bits
	MOV	loc.preMask,BX		 ; mask for 1st word

	MOV	BX,allOnes		 ; mask
	MOV	CL,loc.toLastBits	 ; # bits in last word
	SHR	BX,CL			 ; 1s in least sig bits
	NOT	BX				 ; now most sig bits
	MOV	loc.postMask,BX	 ; mask for last word

$EJ

	CLD
	MOV	CX,loc.rectHeight    ; get the number of lines
	SHR  CX,1
	PUSH CX
	PUSH SI
	PUSH DI
	ADC  CX,0
	CALL SlowLoop			 ; loop on 1/2 of char
	POP  DI
	POP  SI
	POP  CX
	XOR  loc.oddLineFlag,1

	JNZ	nextLineOdd3		 ; jump if next line odd
	SUB  DI,loc.windowHeight
	ADD	DI,loc.bytesPerLine
	JMP  adjustSourcePtr3
NextLineOdd3:
	ADD  DI,loc.windowHeight
adjustSourcePtr3:
	ADD  SI, loc.nextRow      ; increment to next font row
	CALL SlowLoop
	JMP  SplitExit

slowLoop PROC NEAR
slowStart:
	PUSH	CX		           ; save the number as a loop cnt
	PUSH DI	              	 ; save the screen pointer
	PUSH	SI		           ; save the font pointer


	LODSW				 ; get the first char
	XCHG	AL,AH			 ; swap bytes

	MOV	loc.firstWord,AX	 ; save the first word
	MOV	CL,loc.toAlign
	MOV	DH,CL			 ; save toAlign
	SHR	AX,CL			 ; move char in right spot
	NEG	CL
	ADD	CL,bitsPerWord		 ; 16 - toAlign = useful bits
	MOV	DL,CL			 ; save 16 - toAlign

	MOV	BX,loc.preMask		 ; get the mask for 1st word
	AND	AX,BX			 ; mask out all useless bits
	NOT	BX				 ; set mask for bits outside char
	XCHG BL, BH
	AND	BX,ES:[DI]		 ; set bit image from dest
	XCHG BL, BH
	OR	AX,BX			 ; merge the two
	MOV	CL,loc.toAlign
	XOR	CH,CH
	ADD	CX,loc.rectWidth
	CMP	CX,bitsPerWord
	JLE	SHORT lastWord		 
	XCHG AL, AH			 ; bytes are reversed
	STOSW				 ; store the word

$EJ

;set up for word loop:

	MOV	CH,loc.toFullWords
	PUSH	BP
	MOV	BP,loc.firstWord
	INC	CH		;include once through for partial word
middleLoop:
	MOV	BX,BP			; get previous word
	MOV	CL,DL			; mask for prev word
	SHL	BX,CL			; shift it left
	LODSW				; get next word
	XCHG	AL,AH			; swap it
	MOV	BP,AX			; store for next time
	MOV	CL,DH			; mask for this word
	SHR	AX,CL			; shift it right
	OR	AX,BX			; merge the two
	DEC	CH				; decrement counter
	JE	SHORT endLoop
	XCHG AL, AH			; reverse the bytes
	STOSW				; store the word
	JMP	SHORT middleLoop
endLoop:
	POP	BP

lastWord:
	MOV	CH,loc.toLastBits	; # bits in word
	CMP	CH,0
	JE	SHORT endYLoop

	MOV	BX,loc.postMask	; mask for last word
	AND	AX,BX
	NOT	BX		;0000111111111111

	XCHG BL, BH
	AND	BX,ES:[DI]		; get the bits to right of char
	XCHG AL, AH
	OR	AX,BX			; merge em all
	STOSW				; store it finally
endYLoop:
	POP	SI
	POP	DI
	POP	CX
	ADD	DI, loc.bytesPerLine
	ADD	SI, loc.nextRow
	ADD	SI, loc.nextRow    ; were doing every other line
	DEC  CX
	JZ   EndIt
	JMP  slowStart

EndIt:
	RET
SlowLoop ENDP
$EJ
$NOLIST
BlitRectangle ENDP
	PURGE	params
	PURGE	oldBP
	PURGE	oldDS
	PURGE	returnIP
	PURGE	returnCS
	PURGE	toX
	PURGE	toY
	PURGE	rect
	PURGE	nextRow
	PURGE	rectWidth
	PURGE	rectHeight
	PURGE	localBytes
	PURGE	loc
	PURGE	paramBytes
	PURGE	windowHeight
	PURGE	screen
	PURGE	bytesperline
	PURGE     oddlineflag
	PURGE     dummy
$EJECT

; PROCEDURE CpDrawChars ( screen, bytesperline, windowHeight : WORD;
;                     x,y: WORD; 
;                    VAR ch: BYTES; 
;	              count: WORD;
;		VAR font: BYTES);

; parameters & locals for MoveHLine

params		STRUC
charWidth           DW ?
oldBP		DW ?
oldDS		DW ?
returnIP		DW ?
returnCS		DW ?

pFont		DD ?
count		DW ?
pString   	DD ?
yLoc		DW ?
xLoc		DW ?
windowHeight        DW ?
bytesPerLine        DW ?
screen              DW ?

params		ENDS

localBytes	EQU 2
loc		EQU [BP-localBytes]
paramBytes	EQU 20


CpDrawChars PROC FAR

	PUSH	DS
	PUSH	BP
	MOV	BP,SP
     SUB  SP, localBytes

	LES	BX, loc.pFont
	MOV	AL, BYTE PTR ES:[BX+1] 	; width
     XOR  AH, AH
     MOV  loc.charWidth, AX
	MOV	DX,AX
	SHR	DX,1
	SHR	DX,1
	SHR	DX,1
	AND	AX,MOD8
	JZ	gfxLnMOD8
	INC	DX			; bytes per row
gfxLnMOD8:
	MOV	AL, BYTE PTR ES:[BX] 	; chars in fonttable
	XOR	AH,AH
 CMP AL,0
 JNE gfxLnNot256
 MOV AH,1
gfxLnNot256:
	CMP	DX,1
	JE	gfxLnSkip2
	PUSH	DX
	IMUL	DX			; zeros DX as result
	POP	DX
gfxLnSkip2:
	MOV	SI,AX			; offset to next row

	LES	DI, loc.pString
	MOV	CX, loc.count			; count
GfxLoop:
	MOV	AL,ES:[DI]
	XOR	AH,AH
	PUSH	ES
	PUSH	CX
	PUSH	DI
	PUSH	DX
     PUSH	SI

	CMP	AL,ellipsis
	JNE	gNOT_Ellipsis
	MOV	AL,ellipsisCh
gNOT_Ellipsis:
	CMP	AL,shiftRet
	JNE	gNOT_ShiftRet
	MOV	AL,shiftRetCh
gNOT_ShiftRet:

	LES	BX, loc.pFont
	MOV	CL,BYTE PTR ES:[BX]
	XOR	CH,CH
 CMP CL,0
 JNE gfxLnNot256Again
 MOV CH,1
gfxLnNot256Again:
	CMP	AX,CX
	JL	gLegalCh
	MOV	AX,CX
	DEC	AX
gLegalCh:
	CMP	DX,1
	JE	gSkip1
	IMUL	DX	; char * bytesPerRow => first row
; DX is zero now as a result of the multiply
gSkip1:
	ADD	AX,BX     ; add fontTable offset
	ADD	AX,8	; add fontTable overhead
	PUSH	ES
	PUSH	AX
	PUSH	SI

	XOR	AH,AH
	MOV	AL, BYTE PTR ES:[BX+1]
	PUSH	AX
	MOV	AL, BYTE PTR ES:[BX+2]
	PUSH	AX
	MOV	AX, loc.screen
	PUSH	AX
	MOV	AX, loc.bytesPerLine
	PUSH	AX
	MOV	AX, loc.windowHeight
	PUSH	AX
	MOV	AX, loc.XLoc
	PUSH	AX
	MOV	AX, loc.YLoc
	PUSH	AX

;This is a non-fixup generating way to CALL	BlitRectangle (A FAR PROC)

 MOV  AX, OFFSET returnFromBlitRect
 PUSH CS
 PUSH AX
 JMP  BlitRectangleNear

returnFromBlitRect:
	MOV	AX, loc.charWidth
	ADD	loc.XLoc, AX

	POP	SI
	POP	DX
	POP	DI
	POP	CX
	POP	ES
	INC	DI
	LOOP	GfxLoop

     MOV  SP, BP
	POP	BP
	POP	DS
	RET	paramBytes

CpDrawChars ENDP

		  
CODE	ENDS

END
