$NOLIST

NAME  WindowProcs

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

RAM_CGROUP GROUP RAM_CODE


PUBLIC WinClipLine, WinClipRectangle
PUBLIC WinDrawLine, WinEraseLine, WinInvertLine
PUBLIC WinSetClip, WinResetClip
PUBLIC WinSetWindow, WinInitDefaultWindow
PUBLIC WinEraseRectangle, WinInvertRectangle
PUBLIC WinEraseWindow, WinFrameWindow
PUBLIC WinDrawPixel, WinErasePixel, WinInvertPixel, WinTestPixel
PUBLIC WinCopyRectangle, WinScrollRectangle, WinScrollWindow
PUBLIC WinDrawChar, WinDrawChars
PUBLIC WinInvertChar, WinEraseChar
PUBLIC WinGetWindowExtent, GetWindowState


EXTRN BitEraseHLine:NEAR, BitInvertHLine:NEAR
EXTRN CpCopyRectangle:NEAR
EXTRN GfxDrawLine:NEAR, GfxInvertLine:NEAR, GfxEraseLine:NEAR
EXTRN GfxSetPixel:NEAR, GfxClrPixel:NEAR, GfxInvertPixel:NEAR
EXTRN GfxTestPixel:NEAR
EXTRN CpWhoAmI: NEAR

EXTRN GfxCharOut:FAR, GfxLineOut:FAR, GetMeWindowState:NEAR
EXTRN IntWinFrameWindow:FAR


$EJ

RAM_CODE SEGMENT  PUBLIC 'CODE'
	ASSUME CS:RAM_CGROUP
   ;General constants
  NULLWORD   EQU       0ffffh;
	; Meanings of code bits
  leftBit	EQU	1H;
  rightBit	EQU	2H;
  topBit	EQU	4H;
  bottomBit	EQU	8H;
	; Locals for 'ClipLine'
  lineCode1	EQU	0H;
  lineCode2	EQU	2H;
  x1		EQU	2H;
  y1		EQU	4H
  x2		EQU	6H
  y2		EQU	8H;

$EJ

;    GetWindowState : PROCEDURE SELECTOR;
;
;    This will return in AX, the window state selector
;    of the current process.  This will not change any registers except AX

GetWindowState PROC NEAR
    PUSH BX
    PUSH CX
    PUSH DX
    PUSH SI
    PUSH DI
    PUSH ES

    CALL GetMeWindowState

    POP ES
    POP DI
    POP SI
    POP DX
    POP CX
    POP BX
    RET
GetWindowState ENDP

;  The following routines provide an interface to 
;  the system dependent code.

GoToBitInvertHLine PROC NEAR
   POP AX
   CALL BitInvertHLine
	RET
GoToBitInvertHLine ENDP

GoToBitEraseHLine PROC NEAR
   POP AX
   CALL BitEraseHLine
	RET
GoToBitEraseHLine ENDP

GoToGfxEraseLine PROC NEAR
   POP AX
   CALL GfxEraseLine
	RET
GoToGfxEraseLine ENDP

GoToGfxInvertLine PROC NEAR
   POP AX
   CALL GfxInvertLine
	RET
GoToGfxInvertLine ENDP

GoToGfxTestPixel PROC NEAR
   POP AX
   CALL GfxTestPixel
	RET
GoToGfxTestPixel ENDP

GoToGfxSetPixel PROC NEAR
   POP AX
   CALL GfxSetPixel
	RET
GoToGfxSetPixel ENDP

GoToGfxInvertPixel PROC NEAR
   POP AX
   CALL GfxInvertPixel
	RET
GoToGfxInvertPixel ENDP

GoToGfxClrPixel PROC NEAR
   POP AX
   CALL GfxClrPixel
	RET
GoToGfxClrPixel ENDP

$EJ

;**************************************************
;*					*
;* PROCEDURE Encode (x, y: Integer; VAR c: Code)	*
;*					*
;*	(see Newman and Sproull's clipping)	*
;*					*
;*	entry: CX = x for encoding		*
;*	DX = y for encoding			*
;*	exit:  AX = code bits			*
;*					*
;**************************************************
$LIST
Encode	PROC NEAR
$NOLIST
	XOR	AX, AX
	CMP	CX, DS:wsClipRectTopLeftX
	JNL	xNotToLeft
	MOV	AL, leftBit
	JMP SHORT testY
xNotToLeft:
	CMP	CX, DS:wsClipRectExtentX
	JNG	testY
	MOV	AL, rightBit
testY:
	CMP	DX, DS:wsClipRectTopLeftY
	JNL	yNotAboveTop
	OR	AL, topBit
	JMP SHORT encodeEnd
yNotAboveTop:
	CMP	DX, DS:wsClipRectExtentY
	JNG	encodeEnd
	OR	AL, bottomBit
encodeEnd:
	RET
Encode  ENDP

$EJ
; aa := aa + (ab-aa)*(cc-ba) DIV (bb - ba)
%*DEFINE (TruncateLine (aa, ab, ba, bb, cc))
   ( PUSH	WORD PTR [BP - %aa]
	PUSH	WORD PTR [BP - %ba]	; push x1
	MOV	CX, %cc	; get DS:wsClipRectTopLeftX
	POP	BX		; pop x1
	SUB	CX, BX	; get DS:wsClipRectTopLeftX - x1
	MOV	AX, [BP - %ab]	; get y2
	POP	SI		; pop y1
	SUB	AX, SI	; get y2 - y1
	IMUL	CX		;(y2-y1)*(left-x1) ->[DX..AX]
	MOV	CX, [BP - %bb]	; get x2
	SUB	CX, [BP - %ba]	; get x2 - x1
	IDIV	CX		; do the division
	ADD	[BP - %aa]	, AX  ; add it to 'aa' store it back
	MOV	AX, %cc	; x1 = xLeft
	MOV	[BP - %ba], AX
	JMP	clippingLoop )
;****************************************
;*				*
;*  FUNCTION ClipLine: Boolean	*
;*				*
;*	entry: SS:[BP - 2H] = x1	*
;*	SS:[BP - 4H] = y1		*
;*	SS:[BP - 6H] = x2		*
;*	SS:[BP - 8H] = y2		*
;*	exit: values have been clipped	*
;*				*
;****************************************
$LIST
ClipLine  PROC  NEAR
$NOLIST
	MOV	CX, [BP - x2]	; CX gets x2
	MOV	DX, [BP - y2]	; DX gets y2
	CALL	Encode
	PUSH	AX
	PUSH	AX		; space for lineCode1
	MOV	DI, SP
  ; Loop while lineCode1 or lineCode2 is non-null
clippingLoop:
	MOV	CX, [BP - x1]	; CX gets x1
	MOV	DX, [BP - y1]	; DX gets y1
	CALL	Encode
	MOV	SS:[DI+lineCode1], AL ; save lineCode1
	MOV	BL, SS:[DI+lineCode2]
	TEST	BL, AL
	JZ	orTest
	XOR	AX, AX
	JMP	clipEnd
orTest:
	OR	BL, AL
	JNZ	caseClip
	INC	AL		; we know AL is 0
	JMP	clipEnd
caseClip:	; Now clip depending on what's in c1
	OR	AL, AL
	JNZ	testLeft
	MOV	BX, [BP - x1]	; switch [x1, y1] and [x2, y2]
	MOV	CX, [BP - x2]
	MOV	[BP - x1], CX
	MOV	[BP - x2], BX
	MOV	BX, [BP - y1]
	MOV	CX, [BP - y2]
	MOV	[BP - y1], CX
	MOV	[BP - y2], BX
	MOV	CL, SS:[DI+lineCode2]
	MOV	SS:[DI+lineCode1], CL
	MOV	SS:[DI+lineCode2], AL
	MOV	AL, CL
testLeft:
	TEST	AL, leftBit
	JZ	testRight
	%TruncateLine(y1,y2,x1,x2,DS:wsClipRectTopLeftX)
testRight:
	TEST	AL, rightBit
	JZ	testTop
	%TruncateLine(y1,y2,x1,x2,DS:wsClipRectExtentX)
testTop:
	TEST	AL, topBit
	JZ	testBottom
	%TruncateLine(x1,x2,y1,y2,DS:wsClipRectTopLeftY)
testBottom:
	TEST	AL, bottomBit
	JZ	nextLoop
	%TruncateLine(x1,x2,y1,y2,DS:wsClipRectExtentY)
nextLoop:
	JMP	clippingLoop
clipEnd:
	POP	BX	; get rid of lineCode 1 & 2
	POP	BX
	RET
ClipLine ENDP

$EJ
;**************************************************
;*					*
;* FUNCTION WinClipLine(VAR x1, y1,		*
;*		x2, y2: Integer): Boolean;	*
;*					*
;**************************************************
$LIST
WinClipLine  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	MOV	BP, SP
	CALL	GetWindowState
	MOV	DS, AX
; Copy parameters into our locals
	MOV	CX, 4H
	MOV	SI, 14H
pushingParams:
	LES	DI, DWORD PTR SS:[BP+SI]
	PUSH	ES:WORD PTR [DI]
	SUB	SI, 4H
	LOOP	pushingParams
; Clip the line
	CALL	ClipLine
; Copy locals back into parameters
	MOV	CX, 4H
	MOV	SI, 8H
poppingParams:
	LES	DI, DWORD PTR SS:[BP+SI]
	POP	ES:WORD PTR [DI]
	ADD	SI, 4H
	LOOP	poppingParams
; exit
	POP	BP
	POP	DS
	RET	10H
WinClipLine  ENDP


$EJ
;**************************************************
;*					*
;* PROCEDURE WinClipRectangle(VAR r: Rect);	*
;*					*
;*  during loop: ES:[BP] = clip -Left or -Right	*
;*		  DS:[DI] = rect.topLeft.x or .y	*
;*					*
;**************************************************
$LIST
WinClipRectangle  PROC FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	CALL	GetWindowState
	MOV	ES, AX
	MOV	BP, SP
	LDS	DI, DWORD PTR [BP+8H]
	XOR	SI, SI
	LEA	BP, DS:wsClipRectTopLeftX
clipRectLoop:
	MOV	CX, ES:[BP].rectExtentX
  ; is DS:wsClipRectTopLeftX < topLeft.x ?
	MOV	AX, ES:[BP].rectTopleftX
	CMP	AX, [DI]
	JLE	leftOK
  ; truncate the rect from the left
	PUSH	AX
	SUB	AX, [DI]
	SUB	[DI].rectExtentX, AX
	POP	WORD PTR [DI]
	JMP SHORT clipXExtent
leftOK:
  ; check for right side clipping
	CMP	CX, [DI]
	JNL	clipXExtent
  ; truncate at the right
	MOV	[DI], CX
	XOR	BX, BX
	MOV	[DI].rectExtentX, BX
  ; clip the extent if necessary
clipXExtent:
	MOV	BX, [DI].rectExtentX
	ADD	BX, [DI]
	INC	CX
	CMP	BX, CX
	JLE	xextentOK
  ; truncate from the right
	SUB	CX, [DI]
	MOV	[DI].rectExtentX, CX
  ; now test the vertical
xextentOK:
	OR	SI, SI
	JNZ	clipRectEnd
	INC	SI
	INC	DI
	INC	DI
	INC	BP
	INC	BP
	JMP SHORT clipRectLoop
clipRectEnd:
	POP	BP
	POP	DS
	RET	4H
WinClipRectangle ENDP

$EJ
;***************************************************
;*					 *
;* PROCEDURE WinDrawLine(x1, y1, x2, y2: Integer); *
;*					 *
;***************************************************
$LIST
WinDrawLine  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	CALL	GetWindowState
	MOV	DS, AX
 ; Try a little trick:
	MOV	BP, SP
	ADD	BP, 10H  ; now at TOP of parameters
	CALL	ClipLine
	RCR	AL, 1
	JNB	dontDraw
	PUSH      DS:wsPWindowSeg    ; screen location
	PUSH      DS:wsBytesPerLine  ; window info
	PUSH      DS:wsWindowHeight  ; window info

 ; for now, don't add in window topleft...
	MOV	AX, [BP-2H]
	ADD	AX, DS:wsTheWindowTopLeftX 
	PUSH	AX
	MOV	AX, [BP-4H]
	ADD	AX, DS:wsTheWindowTopLeftY
	PUSH	AX
	MOV	AX, [BP-6H]
	ADD	AX, DS:wsTheWindowTopLeftX
	PUSH	AX
	MOV	AX, [BP-8H]
	ADD	AX, DS:wsTheWindowTopLeftY
	PUSH	AX
	CALL	GfxDrawLine
dontDraw:
	POP	BP
	POP	DS
	RET	8H
WinDrawLine  ENDP

$EJ
;**************************************************
;*					*
;* PROCEDURE Win___Line(x1, y1, x2, y2: Integer); *
;*					*
;**************************************************
$LIST
WinInvertLine  PROC  FAR
$NOLIST
	MOV	AX, OFFSET GoToGfxInvertLine
	MOV	BX, OFFSET GoToBitInvertHLine
	JMP SHORT Win___Line
WinEraseLine  LABEL  FAR
	MOV	AX, OFFSET GoToGfxEraseLine
	MOV	BX, OFFSET GoToBitEraseHLine
Win___Line:
	PUSH	DS
	PUSH	BP
	PUSH	AX	; gfxProc
	PUSH	BX	; bitProc
	CALL	GetWindowState
	MOV	DS, AX
 ; Try a little trick:
	MOV	BP, SP
	ADD	BP, 14H  ; now at TOP of parameters
	CALL	ClipLine
	RCR	AL, 1
	JNB	end___
	MOV	BP, SP
 ; Call the horizontal routines for speed
   MOV       CX, OFFSET RAM_CGROUP:end___
	PUSH      CX        ; ret from GoTo___ routine

	PUSH      DS:wsPWindowSeg    ; screen parm
	PUSH      DS:wsBytesPerLine  ; window info
	PUSH      DS:wsWindowHeight  ; window info

	MOV	DX, DS:wsTheWindowTopLeftX
	MOV	AX, [BP+0EH]
	MOV	BX, [BP+12H]
	MOV	CX, [BP+10H]
	CMP	CX, [BP+0CH]
	JNE	gfxCall
	CMP	AX, BX
	JGE	bitCall
	XCHG	AX, BX
bitCall:
	ADD	CX, DS:wsTheWindowTopLeftY 
	PUSH	CX	; push y1+topLeft.y
	MOV	CX, BX
	ADD	BX, DX
	PUSH	BX	; push x1+topLeft.x
	SUB	AX, CX
	INC	AX
	PUSH	AX	; push x2 - x1+1
	MOV	AX, 1
	PUSH	AX	; only do 1 line
	CALL	WORD PTR [BP]
;	JMP SHORT end___

gfxCall:

	ADD	BX, DX
	PUSH	BX	; push x1+topLeft.x
	ADD	CX, DS:wsTheWindowTopLeftY 
	PUSH	CX	; push y1+topLeft.y
	ADD	AX, DX
	PUSH	AX	; push x2+topLeft.x
	MOV	AX, [BP+0CH]
	ADD	AX, DS:wsTheWindowTopLeftY
	PUSH	AX	; push y2+topLeft.y
	CALL	WORD PTR [BP+2H]
end___:
	POP	AX
	POP	BX
	POP	BP
	POP	DS
	RET	8H
WinInvertLine  ENDP

$EJ
;***************************
;*			  *
;* PROCEDURE WinResetClip; *
;*			  *
;***************************
$LIST
WinResetClip  PROC  FAR
$NOLIST
	PUSH	DS
	CALL	GetWindowState
	MOV	DS, AX
backDoorResetClip:
	XOR	AX, AX
	MOV	DS:wsClipRectTopLeftX, AX
	MOV	DS:wsClipRectTopLeftY, AX
	MOV	AX, DS:wsTheWindowExtentX
	DEC	AX
	MOV	DS:wsClipRectExtentX, AX
	MOV	AX, DS:wsTheWindowExtentY
	DEC	AX
	MOV	DS:wsClipRectExtentY, AX
	POP	DS
	RET
WinResetClip  ENDP

%*DEFINE (VarToLocalClippedRect)
   ( MOV	BP, SP
  ; move the VAR parameter to a local on the stack
	LDS	SI, DWORD PTR [BP+8H]
	PUSH	SS
	POP	ES
	MOV	CX, 8H	; rect size
	SUB	SP, CX	; room for local rect
	MOV	DI, SP
	CLD
	REP MOVSB

   PUSH AX
	CALL	GetWindowState
	MOV	DS, AX	; restore data seg
   POP	AX

  ; clip the local rect
	MOV	SI, SP
	PUSH	SS
	PUSH	SI
	CALL	WinClipRectangle )

;*******************************************
;*				   *
;* PROCEDURE WinSetClip(VAR r: Rectangle); *
;*				   *
;*******************************************
$LIST
WinSetClip  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	CALL	WinResetClip
	%VarToLocalClippedRect
  ; put the local into DS:wsClipRectTopLeftX etc.
	MOV	BP, SP
	MOV	AX, [BP].rectTopLeftX
	MOV	DS:wsClipRectTopLeftX, AX
	ADD	AX, [BP].rectExtentX
	DEC	AX
	MOV	DS:wsClipRectExtentX, AX
	MOV	AX, [BP].rectTopLeftY
	MOV	DS:wsClipRectTopLeftY, AX
	ADD	AX, [BP].rectExtentY
	DEC	AX
	MOV	DS:wsClipRectExtentY, AX
	ADD	SP, 8H   ; remove the local
	POP	BP
	POP	DS
	RET	4H
WinSetClip  ENDP

$EJ
;*******************************************
;*				   *
;* PROCEDURE Win___Rect(VAR r: Rectangle); *
;*				   *
;*******************************************
$LIST
WinInvertRectangle  PROC  FAR
$NOLIST
	MOV	AX, OFFSET GoToBitInvertHLine
	JMP SHORT Win___Rect
WinEraseRectangle LABEL FAR
	MOV	AX, OFFSET GoToBitEraseHLine
Win___Rect:
	PUSH	DS
	PUSH	BP
	PUSH	AX
	MOV	BP, SP
  ; move the VAR parameter to a local on the stack
	LDS	SI, DWORD PTR [BP+0AH]
	PUSH	SS
	POP	ES
	MOV	CX, 8H	; rect size
	SUB	SP, CX	; room for local rect
	MOV	DI, SP
	CLD
	REP MOVSB

   PUSH	AX
	CALL	GetWindowState
	MOV	DS, AX	; restore data seg
   POP	AX

  ; clip the local rect
	MOV	BP, SP
	PUSH	SS
	PUSH	BP
	CALL	WinClipRectangle
	MOV	AX, [BP].rectTopLeftX
	ADD	AX, DS:wsTheWindowTopLeftX
	MOV	BX, [BP].rectTopLeftY
	ADD	BX, DS:wsTheWindowTopLeftY
	MOV	DX, [BP].rectExtentX   ; rect.extent.x
	MOV	SI, [BP].rectExtentY   ; rect.extent.y
	ADD	BP, 8H	; points to bitProc

	CMP       SI, 0	; are there any lines to work on?
	JLE	Win___RectRet 
	CMP       DX, 0	; are there any lines to work on?
	JLE	Win___RectRet 

   MOV       CX, OFFSET RAM_CGROUP:Win___RectRet
   PUSH      CX        ; return from GoTo___
	PUSH      DS:wsPWindowSeg    ; screen location
	PUSH      DS:wsBytesPerLine  ; bytes per line
	PUSH      DS:wsWindowHeight      
	PUSH	BX	; y of line
	PUSH	AX	; left of line
	PUSH	DX	; length of line
	PUSH  	SI	; number of lines
	CALL	WORD PTR [BP]
Win___RectRet:

	ADD	SP, 0AH	; local rect and proc
	POP	BP
	POP	DS
	RET	4H
WinInvertRectangle  ENDP

$EJ
;******************************
;*			       *
;* PROCEDURE WinEraseWindow;  *
;*			       *
;******************************
$LIST
WinEraseWindow  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	CALL	GetWindowState
	MOV	DS, AX
	PUSH	DS:wsTheWindowExtentY
	PUSH	DS:wsTheWindowExtentX
	XOR	AX, AX
	PUSH	AX
	PUSH	AX
	MOV	SI, SP	; offset of the local
	PUSH	SS
	PUSH	SI
	CALL	WinEraseRectangle
	ADD	SP, 8H   ; remove local
	POP	BP
	POP	DS
	RET
WinEraseWindow  ENDP

%*DEFINE (DrawOneLine (r1, r2, r3, r4))
   ( PUSH	AX	; save regs for next call
	PUSH	BX
	PUSH	CX
	PUSH	DX
	PUSH      SI	; save screen location
	PUSH      DI	; save bytes per line
	PUSH      BP	; save window height

	PUSH      SI	; screen location
	PUSH      DI	; bytes per line
	PUSH      BP	; window height
	PUSH	%r1   ; left, bottom -> left, top
	PUSH	%r2
	PUSH	%r3
	PUSH	%r4
	CALL	GfxDrawLine

	POP       BP
   POP       DI
   POP       SI
	POP	DX	; restore regs
	POP	CX
	POP	BX
	POP	AX )
;******************************
;*			*
;* PROCEDURE WinFrameWindow;	*
;*			*
;******************************
$LIST
WinFrameWindow  PROC  FAR
	PUSH	DS
	PUSH	BP
;	NOP              ;release program Bug
;	NOP              ;release program Bug
;	NOP              ;release program Bug
;	NOP              ;release program Bug
;	NOP              ;release program Bug
;	NOP              ;release program Bug
	NOP              ;release program Bug
	NOP              ;release program Bug

	CALL	GetWindowState
	MOV	DS, AX
	MOV	AX, DS:wsTheWindowTopLeftX
	MOV	CX, AX
	ADD	CX, DS:wsTheWindowExtentX  ; CX = right
	DEC	AX		; AX = left
	MOV	BX, DS:wsTheWindowTopLeftY
	MOV	DX, BX
	ADD	DX, DS:wsTheWindowExtentY  ; DX = bottom
	DEC	BX		; BX = top
   MOV       SI, DS:wsPWindowSeg
   MOV       DI, DS:wsBytesPerLine
   MOV       BP, DS:wsWindowHeight
	%DrawOneLine(AX,BX,CX,BX)
	%DrawOneLine(CX,BX,CX,DX)
	%DrawOneLine(CX,DX,AX,DX)
	%DrawOneLine(AX,DX,AX,BX)	
	POP	BP
	POP	DS
	RET
WinFrameWindow  ENDP
$NOLIST
$NOLIST

$EJ
;*****************************************
;*				 *
;* PROCEDURE Win___Pixel(x, y: Integer); *
;*				 *   
;*****************************************
$LIST
WinDrawPixel  PROC  FAR
$NOLIST
	MOV	AX, OFFSET GoToGfxSetPixel
	JMP SHORT Win___Pixel
WinTestPixel LABEL FAR
   MOV       AX, OFFSET GoToGfxTestPixel
   JMP SHORT Win___Pixel
WinInvertPixel LABEL FAR
	MOV	AX, OFFSET GoToGfxInvertPixel
	JMP SHORT Win___Pixel
WinErasePixel  LABEL  FAR
	MOV	AX, OFFSET GoToGfxClrPixel
Win___Pixel:
	PUSH	DS
	PUSH	BP
	PUSH	AX
	CALL	GetWindowState
	MOV	DS, AX
	MOV	BP, SP
	MOV	CX, [BP+0CH]
	MOV	DX, [BP+0AH]
	CALL	Encode
	OR	AX, AX
	JNZ	dont___Pixel

   MOV       AX, OFFSET RAM_CGROUP:dont___Pixel
	PUSH      AX

   PUSH      DS:wsPWindowSeg ; screen location
	PUSH      DS:wsBytesPerLine     ; window size
	PUSH      DS:wsWindowHeight     ; window height
	ADD	CX, DS:wsTheWindowTopLeftX
	PUSH	CX
	ADD	DX, DS:wsTheWindowTopLeftY
	PUSH	DX
	CALL	WORD PTR [BP]
dont___Pixel:
	POP	BX	; proc
	POP	BP
	POP	DS
	RET	4H	; returns from Draw & Erase
WinDrawPixel  ENDP
$EJ
;**************************
;*			   *
;* PROCEDURE ResetWindow; *
;*			   *
;**************************
$LIST
;ResetWindow  PROC  FAR
$NOLIST
;	PUSH	DS
;	CALL	GetWindowState
;	MOV	DS, AX
;	XOR	AX, AX
;	MOV	DS:wsTheWindowTopLeftX, AX
;	MOV	DS:wsTheWindowTopLeftY, AX
;	MOV	AX, screenWidth
;	MOV	DS:wsTheWindowExtentX, AX
;	MOV	AX, screenHeight
;	MOV	DS:wsTheWindowExtentY, AX
;	JMP	backDoorResetClip
   ; done by backDoorResetClip:
	;POP	DS
	;RET
;ResetWindow  ENDP

;*********************************************
;*					*
;* PROCEDURE WinSetWindow(VAR r: Rectangle); *
;*					*
;*********************************************
$LIST
params STRUC
  oldBP	DW ?	; stack stuff
  oldDS	DW ?
  longReturn	DD ?
;--------------
  r_offset	DW ?	; param VAR r: Rectangle
  r_segment	DW ?
params ENDS
loc	EQU	[BP]
WinSetWindow  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	MOV       BP, SP
	CALL      GetWindowState
	MOV       ES, AX

	LEA	DI, ES:wsTheWindowTopLeftX
	LDS       SI, DWORD PTR loc.r_Offset
	MOV	CX, 4H	; rect size
	CLD
	REP MOVSW	          ; ship the bytes
  ; reset the clipping rect
	CALL	WinResetClip

	MOV	SP, BP
	POP	BP
	POP	DS
	RET	4H
WinSetWindow  ENDP
PURGE   loc
PURGE   oldBP
PURGE   oldDS
PURGE   longReturn
PURGE   r_offset
PURGE   r_segment
PURGE   params



;***********************************
;*				*
;* PROCEDURE WinInitDefaultWindow; *
;*				*
;***********************************
$LIST
WinInitDefaultWindow PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP


   CALL      WinResetClip
	CALL	WinEraseWindow
	CALL      IntWinFrameWindow

	POP	BP
	POP	DS
	RET
WinInitDefaultWindow ENDP

$EJ
;**************************************************
;*					*
;* PROCEDURE WinCopyRectangle (VAR r: Rectangle;	*
;*			newTopLeft: Point); 	*
;*					*
;**************************************************
params STRUC
  r2_tpl_x	DW ?	; local r2: Rectangle
  r2_tpl_y	DW ?
  r2_ext_x	DW ?
  r2_ext_y	DW ?
  r1_tpl_x	DW ?	; local r1: Rectangle
  r1_tpl_y	DW ?
  r1_ext_x	DW ?
  r1_ext_y	DW ?
;--------------
  oldBP	DW ?	; stack stuff
  oldDS	DW ?
  longReturn	DD ?
;--------------
  ntl_x	DW ?	; param newTopLeft: Point
  ntl_y	DW ?
  r_offset	DW ?	; param VAR r: Rectangle
  r_segment	DW ?
params ENDS
loc	EQU	[BP]
localBytes	EQU	10H
$LIST
WinCopyRectangle  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	MOV	BP, SP
  ; move the VAR parameter to a local on the stack
	LDS	SI, DWORD PTR [BP+0CH]
	PUSH	SS
	POP	ES
	MOV	CX, 8H		; rect size
	SUB	SP, CX		; room for local rect
	MOV	DI, SP
	CLD
	REP MOVSB

   PUSH	AX
	CALL	GetWindowState
	MOV	DS, AX		; restore data seg
   POP	AX

  ; clip the local rect
	MOV	BP, SP
	PUSH	SS
	PUSH	BP
	CALL	WinClipRectangle
	SUB	BP, 8H		; [BP] is now loc
  ; push another rect onto stack
	PUSH	loc.r1_ext_y	; -> r2.extent.y
	PUSH	loc.r1_ext_x	; r2.extent.x
	PUSH	loc.ntl_y
	PUSH	loc.ntl_x
	PUSH	SS		; address of r2
	PUSH	BP
	CALL	WinClipRectangle  ; Clip(r2)
  ; test for r2.topLeft.y being clipped
	MOV	AX, loc.r2_tpl_y
	SUB	AX, loc.ntl_y
	JE	checkXClipping
  ; re-adjust r1.topLeft.y
	ADD	loc.r1_tpl_y, AX
checkXClipping:
  ; test for r2.topLeft.x being clipped
	MOV	AX, loc.r2_tpl_x
	SUB	AX, loc.ntl_x
	JE	endClipping
  ; re-adjust r1.topLeft.x
	ADD	loc.r1_tpl_x, AX
endClipping:
	MOV	CX, loc.r2_ext_x
	OR	CX, CX
	JLE	noCopy
	MOV	BX, loc.r2_ext_y
	OR	BX, BX
	JLE	noCopy
  ; copy the rectangles
   MOV       AX, DS:wsPWindowSeg
	PUSH      AX                 ; source screen location
   MOV       DX, DS:wsBytesPerLine
	PUSH      DX                 ; source window info
   MOV       SI, DS:wsWindowHeight
	PUSH      SI                 ; source window info
	XOR       DI, DI
	PUSH      DI	         ; screen format

	PUSH      AX                 ; dest screen location
	PUSH      DX                 ; dest window info
	PUSH      SI                 ; dest window info
	PUSH      DI                 ; screen format
	MOV	AX, loc.r1_tpl_x
	ADD	AX, DS:wsTheWindowTopLeftX
	PUSH	AX
	MOV	AX, loc.r1_tpl_y
	ADD	AX, DS:wsTheWindowTopLeftY
	PUSH	AX
	MOV	AX, loc.r2_tpl_x
	ADD	AX, DS:wsTheWindowTopLeftX
	PUSH	AX
	MOV	AX, loc.r2_tpl_y
	ADD	AX, DS:wsTheWindowTopLeftY
	PUSH	AX
	PUSH	CX	; r2.extent.x
	PUSH	BX	; r2.extent.y
	PUSH      DI
	CALL	CpCopyRectangle
noCopy:
  ; return clipped rectangle
	LES	DI, DWORD PTR loc.r_offset
	PUSH	SS
	POP	DS
	MOV	SI, BP	; DS:[SI] -> r2
	MOV	CX, 8H
	CLD
	REP MOVSB
	ADD	SP, localBytes	; remove r1, r2
	POP	BP
	POP	DS
	RET	8H
WinCopyRectangle  ENDP
PURGE	params
PURGE	loc
PURGE	localBytes
PURGE	r2_tpl_x
PURGE	r2_tpl_y
PURGE	r2_ext_x
PURGE	r2_ext_y
PURGE	r1_tpl_x
PURGE	r1_tpl_y
PURGE	r1_ext_x
PURGE	r1_ext_y
PURGE	oldBP
PURGE	oldDS
PURGE	longReturn
PURGE	ntl_x
PURGE	ntl_y
PURGE	r_offset
PURGE	r_segment
$EJ
;*****************************************************
;*						*
;* PROCEDURE WinScrollRectangle(VAR r: Rectangle	*
;*			dir: Direction;		*
;*			distance: Integer);		*
;*						*
;*****************************************************
params  STRUC
  r1_tpl_x	DW ?	; local r1: Rectangle
  r1_tpl_y	DW ?
  r1_ext_x	DW ?
  r1_ext_y	DW ?
;--------------
  oldBP	DW ?	; stack stuff
  oldDS	DW ?
  longReturn	DD ?
;--------------
  distance	DW ?	; param distance: Integer
  dir	DW ?	; param dir: Direction
  r_offset	DW ?	; param VAR r: Rectangle
  r_segment	DW ?
params  ENDS
loc	EQU	[BP]
localBytes	EQU	8H
$LIST
WinScrollRectangle  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
backDoorScroll:
	MOV	BX, localBytes
	SUB	SP, BX
	MOV	BP, SP
	LDS	SI, DWORD PTR loc.r_offset
	MOV	CX, loc.distance
	PUSH	CX	; CX <- distance
  ; compute rectangle to be scrolled
	MOV	AX, loc.dir	; dir
	TEST	AL, 2H	; left/right bit
	JNZ	scrollAcross
  ; subtract dist from extent.y  
	SUB	[SI].rectExtentY, CX
	TEST	AL, 1H	; down bit
	JNZ	setLocalR1
	ADD	[SI].rectTopLeftY, CX
	JMP SHORT setLocalR1
scrollAcross:
  ; subtract dist from extent.x
	SUB	[SI].rectExtentX, CX
	TEST	AL, 1H	; right bit
	JNZ	setLocalR1
	ADD	[SI].rectTopLeftX, CX
setLocalR1:
  ; local r1 gets r (DS and SI already set up)
	PUSH	SS	; segment of local
	POP	ES
	MOV	DI, BP	; offset of local r1
	MOV	CX, BX
	CLD
	REP MOVSB		; copy the rect
  ;*********************************
  ;*  AL = dir		*
  ;*  BX = scratch register (8H)	*
  ;*  CX = +distance		*
  ;*  DX = dx		*
  ;*  DI = dy		*
  ;*  ES = +/- distance	*
  ;*  DS:[SI] -> VAR r parameter	*
  ;*********************************
	SUB	SI, BX	; undo MOVSB
	POP	CX		; CX = distance
	XOR	DX, DX	; DX = dx
	XOR	DI, DI	; DI = dy
	MOV	ES, CX
	TEST	AL, 1H
	JNZ	noNeg	; distance = - distance..
	NEG	CX		;   ..for left and down
	MOV	ES, CX
	NEG	CX
noNeg:
	TEST	AL, 2H	; left/right bit
	JNZ	moveAcross
	MOV	DI, ES	; dy gets +/- distance
	TEST	AL, 1H
	JNZ	setRectExtentY
  ; scrolling UP: reset topLeft.y of rect
	MOV	AX, [SI].rectExtentY
	SUB	AX, CX
	ADD	[SI].rectTopLeftY, AX
setRectExtentY:
	MOV	[SI].rectExtentY, CX	; extent.y gets distance
	JMP SHORT copyTheRect
  ; scrolling left/right:
moveAcross:
	MOV	DX, ES	; dx gets +/- distance
	TEST	AL, 1H
	JNZ	setRectExtentX
  ; scrolling LEFT: reset topLeft.x of rect
	MOV	AX, [SI].rectExtentX
	SUB	AX, CX
	ADD	[SI].rectTopLeftX, AX
setRectExtentX:
	MOV	[SI].rectExtentX, CX	; extent.x gets distance
copyTheRect:
  ; push lv r1, [r1.topLeft] + [dx, dy] onto stack
	PUSH	SS
	PUSH	BP		; still points to r1
	ADD	DI, loc.r1_tpl_y
	PUSH	DI		; newTopLeft.y
	ADD	DX, loc.r1_tpl_x
	PUSH	DX		; newTopLeft.x
	CALL	WinCopyRectangle
  ; ...and return
	ADD	SP, localBytes
	POP	BP
	POP	DS
	RET	8H
WinScrollRectangle  ENDP
PURGE	params
PURGE	loc
PURGE	localBytes
PURGE	r1_tpl_x
PURGE	r1_tpl_y
PURGE	r1_ext_x
PURGE	r1_ext_y
PURGE	oldBP
PURGE	oldDS
PURGE	longReturn
PURGE	dir
PURGE	distance
PURGE	r_offset
PURGE	r_segment

;*************************************************
;*					      *
;* PROCEDURE WinScrollWindow(VAR r: Rectangle;   *
;*			dir: Direction;	      *
;*			distance: Integer);       *
;*					      *
;*************************************************
$LIST
WinScrollWindow  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	CALL	GetWindowState
	MOV	ES, AX
	MOV	BP, SP
  ; put the window into r, then jump to WinScrollRectangle
	LDS	SI, DWORD PTR [BP+0CH]
	XOR	AX, AX
	MOV	[SI].rectTopLeftX, AX
	MOV	[SI].rectTopLeftY, AX
	MOV	AX, ES:wsTheWindowExtentX
	MOV	[SI].rectExtentX, AX
	MOV	AX, ES:wsTheWindowExtentY
	MOV	[SI].rectExtentY, AX
	JMP	backDoorScroll
WinScrollWindow  ENDP

$EJ
;***************************************************
;*					 *
;* PROCEDURE WinDrawChar(ch: Char; x, y: Integer); *
;*					 *
;***************************************************
params  STRUC
;--------------
  oldBP	DW ?	; stack stuff
  oldDS	DW ?
  longReturn DD ?
;--------------
  y	DW ?	; param y: Integer
  x	DW ?	; param x: Integer
  chr	DW ?	; param ch: Char
params  ENDS
fontInfo  STRUC
  fontNumChars   DB ?
  fontCharWidth  DB ?      ;font character size info
  fontCharHeight DB ?      
fontInfo  ENDS
loc	EQU   [BP]
font         EQU   ES:[BX]
$LIST
WinDrawChar  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	MOV	BP, SP	; BP is now loc
	CALL	GetWindowState
	MOV	DS, AX

  ; check clipping
	MOV	CX, loc.x	; char left
	MOV	DX, loc.y	; char top
	CALL	Encode
	OR	AX, AX
	JNZ	dontDrawChar
   LES       BX, DS:wsPFontTable
   XOR       AX, AX
   MOV       AL, font.fontCharWidth
   DEC       AX
	ADD	CX, AX	; char right
   MOV       AL, font.fontCharHeight
   DEC       AX
	ADD	DX, AX	; char bottom
	CALL	Encode
	OR	AX, AX
	JNZ	dontDrawChar
  ; draw the char
	CALL	GetWindowState
	MOV	ES, AX

	MOV	AX, loc.chr
	XOR	AH, AH
	PUSH	AX

	PUSH 	loc.x
	PUSH	loc.y
	CALL	GfxCharOut

dontDrawChar:
	POP	BP
	POP	DS
	RET	6H
WinDrawChar  ENDP
PURGE        fontInfo  
PURGE        fontNumChars
PURGE        fontCharWidth  
PURGE        fontCharHeight
PURGE        font
PURGE	params
PURGE	loc
PURGE	oldBP
PURGE	oldDS
PURGE	longReturn
PURGE	x
PURGE	y
PURGE	chr

$EJ
;***************************************************************
;*						   *
;* PROCEDURE WinDrawChars(VAR ch: Char; count, x, y: Integer); *
;*						   *
;***************************************************************
params  STRUC
  r1_tpl_x   DW ?	; local r1: Rectangle
  r1_tpl_y   DW ?
  r1_ext_x   DW ?
  r1_ext_y   DW ?
;--------------
  charHeight DW ?      ;font character size info
  charWidth  DW ?
;--------------
  oldBP	DW ?	; stack stuff
  oldDS	DW ?
  longReturn DD ?
;--------------
  y	DW ?	; param y: Integer
  x	DW ?	; param x: Integer
  count	DW ?	; param count: Integer
  ch_offset  DW ?	; param VAR ch: Char
  ch_segment DW ? 
params  ENDS
fontInfo  STRUC
  fontNumChars   DB ?
  fontCharWidth  DB ?      ;font character size info
  fontCharHeight DB ?      
fontInfo  ENDS
loc	EQU	[BP]
localBytes	EQU	0CH
font         EQU       ES:[BX]
$LIST
WinDrawChars  PROC  FAR
$NOLIST
	PUSH	DS
	PUSH	BP
	CALL	GetWindowState
	MOV	DS, AX
	MOV	BP, SP
	SUB	BP, localBytes	; BP is now loc

  ; calculate the character size
   LES       BX, DS:wsPFontTable
   XOR       AX, AX
   MOV       AL, font.fontCharWidth
   PUSH      AX
   MOV       AL, font.fontCharHeight
   PUSH      AX

  ; push a rectangle onto the stack
   PUSH      AX                  ;charHeight
	MOV	AX, loc.charWidth	; charWidth
	MOV	CX, loc.count
	IMUL	CX
	PUSH	AX		; string width
	PUSH	loc.y
	PUSH	loc.x
  ; clip the rectangle
	PUSH	SS
	PUSH	BP
	CALL	WinClipRectangle
  ; readjust count and beginning for new rect
	MOV	AX, loc.r1_tpl_x	; clipped topLeft.x
	SUB	AX, loc.x	          ; difference from clipped topLeft.x
	JZ	checkExtent	; no adjusting - just draw them
	CWD
	MOV	CX, loc.charWidth	; charWidth
	IDIV	CX		; AX gets how many chars to skip
	OR	DX, DX		; DX gets the remainder
	JZ	noLeadingSpace	; if zero, no leading space
	INC	AX		; one more char to skip, and...
	NEG       DX                  
	ADD       DX, loc.charWidth   ; charWidth - remainder
	ADD	loc.r1_tpl_x, DX	; ...skip this many dots
	SUB       loc.r1_ext_x, DX	; rectangle thus gets smaller
noLeadingSpace:
	ADD	loc.ch_offset, AX	; increment ch_offset

CheckExtent:
	MOV	AX, loc.r1_ext_x	; clipped rect width
	CWD
	MOV	CX, loc.charWidth	; charWidth
	IDIV	CX
	OR	AX, AX		; AX is how many chars will fit
	JLE	dontDrawChars	; don't draw zero chars
	MOV	BX, loc.r1_ext_y
	CMP	BX, loc.charHeight
	JL	dontDrawChars	; not enough vertical space
	MOV	SI, AX		; save new count in SI

  ; SI = # chars to draw
  ; loc.r1_tpl = where to draw them
  ; loc.ch points to first char

   PUSH	AX
	CALL	GetWindowState
	MOV	ES, AX
	POP	AX

	PUSH	loc.ch_segment
	PUSH	loc.ch_offset
	PUSH	SI		; count

	PUSH	loc.r1_tpl_x
	PUSH	loc.r1_tpl_y
	CALL	GfxLineOut

dontDrawChars:
	ADD	SP, localBytes
	POP	BP
	POP	DS
	RET	0AH
WinDrawChars  ENDP
PURGE        fontInfo
PURGE        fontNumChars
PURGE        fontCharHeight
PURGE        fontCharWidth
PURGE        font
PURGE	params
PURGE	loc
PURGE	localBytes
PURGE	r1_tpl_x
PURGE	r1_tpl_y
PURGE	r1_ext_x
PURGE	r1_ext_y
PURGE	oldBP
PURGE	oldDS
PURGE	longReturn
PURGE	count
PURGE	x
PURGE	y
PURGE	ch_offset
PURGE	ch_segment

$EJ
;****************************************
;*				*
;* PROCEDURE Win___Char(x, y: Integer); *
;*				*
;****************************************
fontInfo  STRUC
  fontNumChars   DB ?
  fontCharWidth  DB ?      ;font character size info
  fontCharHeight DB ?      
fontInfo  ENDS
font         EQU       ES:[BX]
$LIST
WinInvertChar  PROC  FAR
$NOLIST
	MOV	AX, OFFSET WinInvertRectangle
	JMP SHORT Win___Char
$LIST
WinEraseChar  LABEL  FAR
$NOLIST
	MOV	AX, OFFSET WinEraseRectangle
Win___Char:
	PUSH	DS
	PUSH	BP
	PUSH	CS		; proc segment
	PUSH	AX		; proc offset
	MOV	BP, SP

   CALL 	GetWindowState
   MOV 	DS, AX
   LES       BX, DS:wsPFontTable

   XOR       AX, AX
	MOV	AL, font.fontcharHeight	; charHeight
	PUSH	AX
	MOV	AL, font.fontcharWidth	; charWidth
	PUSH	AX
	PUSH	WORD PTR [BP+0CH]  ; y
	PUSH	WORD PTR [BP+0EH]  ; x
	MOV	SI, SP
	PUSH	SS		; push VAR of rect
	PUSH	SI
	CALL	DWORD PTR [BP]	; Erase or Invert
	ADD	SP, 0CH
	POP	BP
	POP	DS
	RET	4H
WinInvertChar  ENDP
PURGE        fontInfo
PURGE        font
PURGE        fontNumChars
PURGE        fontCharHeight
PURGE        fontCharWidth

$EJ

;    WinGetWindowExtent : PROCEDURE (pExtent) CLEAN
;
;    This will return the current window extent

pExtent EQU DWORD PTR [BP+8]
$LIST
WinGetWindowExtent PROC FAR
    PUSH DS
    CALL GetWindowState
    MOV DS, AX
    PUSH BP
    MOV BP, SP

    LES BX, pExtent               ; ES:BX ^ extent

    MOV AX, DS:wsTheWindowExtentX
    MOV ES:[BX].pointX, AX               ; extent.x := windowExtent.x

    MOV AX, DS:wsTheWindowExtentY
    MOV ES:[BX].pointY, AX             ; extent.y := windowExtent.y

    POP BP
    POP DS
    RET 4
WinGetWindowExtent ENDP

RAM_CODE ENDS

END
