	PAGE	,132								;AN000;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;					;AN000;
;; DOS - GRAPHICS Command
;; (c) Copyright 1988 Microsoft
;;										;AN000;
;; File Name:  GRCOMMON.ASM							;AN000;
;; ----------									;AN000;
;;										;AN000;
;; Description: 								;AN000;
;; ------------ 								;AN000;
;;										;AN000;
;;	 This file contains the modules common to the Print Screen		;AN000;
;;	 process of GRAPHICS.COM.						;AN000;
;;	 This file is included by both set of Print modules.			;AN000;
;;										;AN000;
;;	 This file MUST BE COMPILED WITH EACH SET OF MODULES since,		;AN000;
;;	 one set is relocated in memory at installation time; all		;AN000;
;;	 references to the common procedures must be resolved from		;AN000;
;;	 within each set of print modules.					;AN000;
;;										;AN000;
;;	 The set of common modules is relocated in memory along with		;AN000;
;;	 the selected set of print modules.					;AN000;
;;										;AN000;
;; Documentation Reference:							;AN000;
;; ------------------------							;AN000;
;;	 OASIS High Level Design						;AN000;
;;	 OASIS GRAPHICS I1 Overview						;AN000;
;;										;AN000;
;; Procedures Contained in This File:						;AN000;
;; ----------------------------------						;AN000;
;;	READ_DOT								;AN000;
;;	LOC_MODE_PRT_INFO							;AN000;
;;	STORE_BOX								;AN000;
;;	PRINT_BUFFER								;AN000;
;;	GET_SCREEN_INFO 							;AN000;
;;	SETUP_PRT								;AN000;
;;	RESTORE_PRT								;AN000;
;;	NEW_PRT_LINE								;AN000;
;;	PRINT_BYTE								;AN000;
;;	DET_CUR_SCAN_LNE_LENGTH 						;AN000;
;;										;AN000;
;; Include Files Required:							;AN000;
;; -----------------------							;AN000;
;;	none									;AN000;
;;										;AN000;
;; External Procedure References:						;AN000;
;; ------------------------------						;AN000;
;;	 FROM FILE  GRCTRL.ASM: 						;AN000;
;;	      PRT_SCR	       - Main module for printing the screen.		;AN000;
;;	 FROM FILE  GRBWPRT.ASM:						;AN000;
;;	      PRT_BW_APA       - Main module for printing on BW printer.	;AN000;
;;	 FROM FILE  GRCOLPRT.ASM:						;AN000;
;;	      PRINT_COLOR      - Main module for printing on COLOR printer.	;AN000;
;;										;AN000;
;; Linkage Instructions:							;AN000;
;; -------------------- 							;AN000;
;;										;AN000;
;;	 This file is included by both GRBWPRT.ASM and GRCOLPRT.ASM and is	;AN000;
;;	 compiled with each of them. However, only one copy is made resident.	;AN000;
;;										;AN000;
;; Change History:								;AN000;
;; ---------------								;AN000;
;;										;AN000;
;;										;AN000;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;					;AN000;
										;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; LOC_MODE_PRT_INFO: LOCATE DISPLAYMODE PRINTER INFO. FOR THE CURRENT		;AN000;
;		     MODE							;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT:	BP		= Offset of the shared data area		;AN000;
;		CUR_MODE	= Current video mode				;AN000;
;										;AN000;
;	OUTPUT: CUR_MODE_PTR	= Absolute Offset of the			;AN000;
;				  current DISPLAYMODE INFO record.		;AN000;
;										;AN000;
;		ERROR_CODE	= DISPLAYMODE_INFO_NOT_FOUND if not found.	;AN000;
;										;AN000;
;	CALLED BY: PRINT_COLOR							;AN000;
;		   PRINT_BW_APA 						;AN000;
;										;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION:	DISPLAYMODE_PTR is pointing to the first DISPLAYMODE		;AN000;
; INFO record within the Shared Data Area.					;AN000;
;										;AN000;
; This (chained) list of DISPLAYMODE records is scanned until the record	;AN000;
; for the current mode is found.						;AN000;
;										;AN000;
; Note: All pointers in the DISPLAYMODE records are relative to the beginning	;AN000;
;	of the shared data area. Therefore, we must add the offset of the	;AN000;
;	shared data area (in BP) in order to access the data these pointers	;AN000;
;	are referencing.							;AN000;
;										;AN000;
;	The CUR_MODE_PTR is relative to the segment and references the		;AN000;
;	DISPLAYMODE record for the video mode currently set at print screen	;AN000;
;	time.									;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; FOUND := FALSE								;AN000;
; DO UNTIL FOUND OR END_OF_LIST 						;AN000;
;   Get a display mode information record					;AN000;
;   IF record.DISP_MODE = CUR_MODE						;AN000;
;     THEN FOUND := TRUE							;AN000;
;   ELSE									;AN000;
;     CUR_MODE_PTR := record.NEXT_DISP_MODE					;AN000;
;										;AN000;
;										;AN000;
										;AN000;
LOC_MODE_PRT_INFO PROC NEAR							;AN000;
	PUSH	BX								;AN000;
	PUSH	CX								;AN000;
	PUSH	DX								;AN000;
	PUSH	SI								;AN000;
										;AN000;
	MOV	BX,DS:[BP].DISPLAYMODE_PTR	; [BX] := Current DISPLAYMODE	;AN000;
	ADD	BX,BP				;	   record		;AN000;
	MOV	DL,CUR_MODE			; DL := Current mode		;AN000;
										;AN000;
SCAN_1_DISPLAYMODE_RECORD:							;AN000;
	MOV	SI,[BX].DISP_MODE_LIST_PTR	; [SI] : First mode covered	;AN000;
	ADD	SI,BP				;    by this DISPLAYMODE record ;AN000;
	MOV	CL,[BX].NUM_DISP_MODE		; Scan each mode in the list	;AN000;
	XOR	CH,CH								;AN000;
SCAN_LIST_OF_MODES:								;AN000;
	CMP	CS:[SI],DL			; FOUND ?			;AN000;
	JE	FOUND								;AN000;
	INC	SI				; NO, get next mode in		;AN000;
	LOOP	SCAN_LIST_OF_MODES		;      DISPLAYMODE record	;AN000;
										;AN000;
	CMP	[BX].NEXT_DISP_MODE,-1		; END OF DISPLAYMODE LIST ?	;AN000;
	JE	NOT_FOUND			; Yes, this mode not supported	;AN000;
NEXT_RECORD:					; No,				;AN000;
	MOV	BX,[BX].NEXT_DISP_MODE		;     [BX] := Next record	;AN000;
	ADD	BX,BP				;				;AN000;
	JMP	SHORT SCAN_1_DISPLAYMODE_RECORD 				;AN000;
										;AN000;
FOUND:						; Found:			;AN000;
	MOV	CUR_MODE_PTR,BX 		; Update pointer to current	;AN000;
	JMP	SHORT LOC_MODE_PRT_INFO_END	; DISPLAYMODE record.		;AN000;
										;AN000;
NOT_FOUND:					; Not found:			;AN000;
	MOV	ERROR_CODE,DISPLAYMODE_INFO_NOT_FOUND ; Return error condition	;AN000;
										;AN000;
LOC_MODE_PRT_INFO_END:								;AN000;
	POP	SI								;AN000;
	POP	DX								;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	RET									;AN000;
LOC_MODE_PRT_INFO ENDP								;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; STORE_BOX : STORE ONE BOX IN THE PRINT BUFFER.				;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT:	SI	   = OFFSET OF THE BOX TO BE PRINTED			;AN000;
;		BOX_W	   = BOX WIDTH IN BITS					;AN000;
;		BOX_H	   = BOX HEIGHT IN BITS 				;AN000;
;										;AN000;
;	OUTPUT: PRT_BUF  = THE PRINT BUFFER					;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION: The print buffer is first shifted left in order to make		;AN000;
; room for the new box (Note: the MSB's are lost; they are assumed to           ;AN000;
; have been printed), then the box is inserted in the low-order bits of 	;AN000;
; the printer buffer.								;AN000;
;										;AN000;
PAGE										;AN000;
;			      EXAMPLE						;AN000;
;			      -------						;AN000;
; BEFORE:				     AFTER:				;AN000;
;										;AN000;
; BOX: 0    0	0								;AN000;
;      0    0	0								;AN000;
;      0    0	0								;AN000;
;      0    0	0								;AN000;
;      0    0	0								;AN000;
;      0    0	0								;AN000;
;      b1  b2  b3								;AN000;
;      b4  b5  b6								;AN000;
;										;AN000;
; PRT_BUF: byte1 byte2 byte3		     PRT_BUF:  byte1 byte2 byte3	;AN000;
;	     0	   1	 0				 1     1     1		;AN000;
;	     1	   0	 1				 1     1     1		;AN000;
;	     1	   1	 1				 1     1     1		;AN000;
;	     1	   1	 1				 1     1     1		;AN000;
;	     1	   1	 1				 1     1     1		;AN000;
;	     1	   1	 1				 1     1     1		;AN000;
;	     1	   1	 1				 b1    b2    b3 	;AN000;
;    LSB --> 1	   1	 1				 b4    b5    b6 	;AN000;
;										;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; FOR each byte of the buffer (BOX_W)						;AN000;
;   BEGIN									;AN000;
;   Make room for the box to be inserted					;AN000;
;   Insert the box								;AN000;
;   END 									;AN000;
;										;AN000;
STORE_BOX PROC NEAR								;AN000;
	PUSH	BX								;AN000;
	PUSH	CX								;AN000;
	PUSH	DI								;AN000;
										;AN000;
	MOV	DI,OFFSET PRT_BUF ; DI := Offset of the Print buffer		;AN000;
	XOR	BX,BX		  ; BX := Byte index number			;AN000;
										;AN000;
	MOV	CL,BOX_H	  ; CL := Number of BITS to be shifted		;AN000;
; FOR each column (byte) of the box to be stored in the buffer: 		;AN000;
STORE_1_BYTE:									;AN000;
	SHL	BYTE PTR [BX][DI],CL	; Make room for the bits to be inserted ;AN000;
	MOV	CH,[BX][SI]		; CH := column of the box to be inserted;AN000;
	OR	[BX][DI],CH		; Insert the box column in the buffer	;AN000;
	INC	BL			; Get next column (byte) of the box	;AN000;
	CMP	BL,BOX_W		; All columns (bytes) of box stored ?	;AN000;
	JL	STORE_1_BYTE		; No, store next one.			;AN000;
										;AN000;
STORE_BOX_END:									;AN000;
	POP	DI								;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	RET									;AN000;
STORE_BOX ENDP									;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; PRINT_BUFFER : PRINT THE BUFFER						;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT:	PRT_BUF  = BYTES TO BE PRINTED					;AN000;
;		BOW_W	 = BOX WIDTH						;AN000;
;										;AN000;
;	OUTPUT: PRINTER 							;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION: Prints BOX_W bytes.						;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; DO for each column in one pattern						;AN000;
;   BEGIN									;AN000;
;   Print one byte from the buffer						;AN000;
;   END 									;AN000;
;										;AN000;
PRINT_BUFFER PROC NEAR								;AN000;
	PUSH	AX								;AN000;
	PUSH	BX								;AN000;
	PUSH	CX								;AN000;
										;AN000;
	MOV	BX,OFFSET PRT_BUF						;AN000;
	XOR	CX,CX								;AN000;
	MOV	CL,BOX_W							;AN000;
PRINT_1_BUF_COLUMN:								;AN000;
	MOV	AL,[BX] 	; Print one byte				;AN000;
	CALL	PRINT_BYTE							;AN000;
	JC	PRINT_BUFFER_END; If printer error, quit the loop		;AN000;
	INC	BX		; Get next byte 				;AN000;
	LOOP	PRINT_1_BUF_COLUMN						;AN000;
PRINT_BUFFER_END:								;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	POP	AX								;AN000;
	RET									;AN000;
PRINT_BUFFER ENDP								;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; GET_SCREEN_INFO : GET INFORMATION ABOUT HOW TO READ THE SCREEN.		;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT:	SCREEN_HEIGHT	  = Number of pixel rows on the screen		;AN000;
;		SCREEN_WIDTH	  = Number of pixel columns on screen		;AN000;
;		CUR_MODE_PTR	  = Offset of the current DISPLAYMODE info rec. ;AN000;
;										;AN000;
;	OUTPUT: PRINTER 							;AN000;
;		SCAN_LINE_MAX_LENGTH = Maximum length of Screen scan line.	;AN000;
;		NB_SCAN_LINES	  = Number of SCAN LINES on the screen		;AN000;
;		CUR_ROW,CUR_COLUMN = Coordinates of the first pixel to be	;AN000;
;					 read on the screen			;AN000;
;		NB_BOXES_PER_PRT_BUF = Number of boxes fitting in the Print	;AN000;
;				       buffer					;AN000;
;										;AN000;
;	CALLED BY: PRINT_COLOR							;AN000;
;		   PRT_BW_APA							;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION:									;AN000;
;										;AN000;
;    1) Determine where to start reading the screen.				;AN000;
;	For non-rotated printing, it should start with the top-left		;AN000;
;	corner pixel.								;AN000;
;	For rotated printing, it should start with the low-left corner		;AN000;
;	pixel.									;AN000;
;										;AN000;
;    2) Determine the length of a scan line.					;AN000;
;	For non-rotated printing, it is the WIDTH of the screen.		;AN000;
;	For rotated printing, it is the HEIGHT of the screen.			;AN000;
;										;AN000;
;    3) Determine the number of scan lines on the screen.			;AN000;
;	For non-rotated printing, it is the HEIGHT of the screen divided	;AN000;
;	by the number of boxes fitting in the print buffer.			;AN000;
;	For rotated printing, it is the WIDTH of the screen divided by		;AN000;
;	the number of boxes fitting in the print buffer.			;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; CUR_COLUMN   := 0								;AN000;
; IF printing is sideways							;AN000;
;   THEN									;AN000;
;     CUR_ROW := SCREEN_HEIGHT - 1	  ; Low-left pixel			;AN000;
;     SCAN_LINE_MAX_LENGTH := SCREEN_HEIGHT					;AN000;
;     NB_SCAN_LINES :=	SCREEN_WIDTH / NB_BOXES_PER_PRT_BUF			;AN000;
;   ELSE									;AN000;
;     CUR_ROW := 0			  ; Top-left pixel			;AN000;
;     SCAN_LINE_MAX_LENGTH := SCREEN_WIDTH					;AN000;
;     NB_SCAN_LINES :=	SCREEN_HEIGHT / NB_BOXES_PER_PRT_BUF			;AN000;
;										;AN000;
;										;AN000;
GET_SCREEN_INFO PROC NEAR							;AN000;
	PUSH	AX								;AN000;
	PUSH	BX			; Used for DIV				;AN000;
	PUSH	DX			; Used for DIV				;AN000;
										;AN000;
	MOV	BX,CUR_MODE_PTR 	; BX := Offset DISPLAYMODE info record	;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; Calculate how many printer boxes fit in the print buffer:			;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
	MOV	AX,8			; Num := 8 bits / Box heigth		;AN000;
	MOV	DL,[BX].BOX_HEIGHT						;AN000;
	DIV	DL								;AN000;
	MOV	NB_BOXES_PER_PRT_BUF,AL 					;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; Determine where to start reading the screen:					;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
	MOV	CUR_COLUMN,0		; Reading always start from left of scr ;AN000;
.IF <[BX].PRINT_OPTIONS EQ ROTATE>						;AN000;
.THEN										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; Printing is sideways; screen must be read starting in low-left corner.	;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
	MOV	AX,SCREEN_HEIGHT						;AN000;
	MOV	SCAN_LINE_MAX_LENGTH,AX ; Scan line length := screen height	;AN000;
	DEC	AX								;AN000;
	MOV	CUR_ROW,AX		; First row := screen height - 1	;AN000;
										;AN000;
;-------Calculate the number of scan lines:					;AN000;
	MOV	AX,SCREEN_WIDTH 	; DX AX = Screen width			;AN000;
	CWD				;					;AN000;
	XOR	BX,BX			; BX	= Number of boxes per print buf ;AN000;
	MOV	BL,NB_BOXES_PER_PRT_BUF ;					;AN000;
	DIV	BX			; Screen width / number boxes per buff	;AN000;
	MOV	NB_SCAN_LINES,AX	; Number of scan lines := result	;AN000;
.ELSE										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; Printing is not sideways; screen must be read starting in top-left corner	;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
	MOV	AX,SCREEN_WIDTH 						;AN000;
	MOV	SCAN_LINE_MAX_LENGTH,AX ; Scan line length := screen width	;AN000;
	MOV	CUR_ROW,0		; First row := 0			;AN000;
										;AN000;
;-------Calculate the number of scan lines:					;AN000;
	MOV	AX,SCREEN_HEIGHT	; DX AX = Screen height 		;AN000;
	CWD				;					;AN000;
	XOR	BX,BX			; BX  = Number of boxes per print buff	;AN000;
	MOV	BL,NB_BOXES_PER_PRT_BUF ;					;AN000;
	DIV	BX			; Screen height/number boxes per buff.	;AN000;
	MOV	NB_SCAN_LINES,AX	; Number of scan lines := result	;AN000;
.ENDIF										;AN000;
	POP	DX								;AN000;
	POP	BX								;AN000;
	POP	AX								;AN000;
	RET									;AN000;
GET_SCREEN_INFO ENDP								;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; DET_CUR_SCAN_LNE_LENGTH : Determine where is the last non-blank "scan line    ;AN000;
;				column" on the current scan line.               ;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;     INPUT:  CUR_ROW,								;AN000;
;	      CUR_COLUMN	  = Coordinates of the top pixel of the current ;AN000;
;				    scan line.					;AN000;
;	      XLT_TAB		  = Color translation table			;AN000;
;										;AN000;
;     OUTPUT: CUR_SCAN_LNE_LENGTH = Number of "columns" of pixels from the      ;AN000;
;				    beginning of the scan line up to		;AN000;
;				    the last non-blank pixel.			;AN000;
;										;AN000;
; DATA	      SCREEN_WIDTH,							;AN000;
; REFERENCED: SCREEN_HEIGHT	  = Dimensions of the screen in pels		;AN000;
;	      SCAN_LINE_MAX_LENGTH= Maximum length of the scan line		;AN000;
;	      ROTATE_SW 	  = ON if printing is sideways			;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION: Determine where is the last non-blank "column" by reading        ;AN000;
; the scan line backwards, one column at a time.				;AN000;
;										;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; ; Obtain coordinates for the top pixel of the last column on the current	;AN000;
; ; scan line:									;AN000;
; IF printing is sideways							;AN000;
;   THEN									;AN000;
;   CUR_ROW := 0								;AN000;
; ELSE										;AN000;
;   CUR_COLUMN := SCREEN_WIDTH - 1						;AN000;
;										;AN000;
; CUR_SCAN_LNE_LENGTH := SCAN_LINE_MAX_LENGTH					;AN000;
; ; Read a column of pixels on the scan line until a non-blank is found:	;AN000;
; For each column on the screen 						;AN000;
;   CALL FILL_BUFF								;AN000;
; ; Check if PRT_BUF is empty							;AN000;
;   IF buffer is empty								;AN000;
;     THEN DEC	CUR_SCAN_LNE_LENGTH						;AN000;
;	   ; Get next column							;AN000;
;	   IF printing sideways THEN DEC CUR_ROW				;AN000;
;				ELSE DEC CUR_COLUMN				;AN000;
;   ELSE quit the loop								;AN000;
;										;AN000;
DET_CUR_SCAN_LNE_LENGTH PROC NEAR						;AN000;
	PUSH	AX								;AN000;
	PUSH	BX								;AN000;
	PUSH	CX								;AN000;
	PUSH	DX								;AN000;
	PUSH	SI								;AN000;
	PUSH	DI								;AN000;
	PUSH	CUR_COLUMN							;AN000;
	PUSH	CUR_ROW 							;AN000;
										;AN000;
	MOV	BX,OFFSET XLT_TAB	; BX := Offset of XLT_TAB		;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; Obtain coordinates of the top pixel for the last column of the current	;AN000;
; scan line:									;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
       .IF <ROTATE_SW EQ ON>		; If printing sideways			;AN000;
       .THEN				; then, 				;AN000;
	  MOV	  CUR_ROW,0		;   CUR_ROW := 0			;AN000;
       .ELSE				; else, 				;AN000;
	  MOV	  CX,SCREEN_WIDTH	;   CUR_COLUMN := SCREEN_WIDTH - 1	;AN000;
	  DEC	  CX			;					;AN000;
	  MOV	  CUR_COLUMN,CX 	;					;AN000;
       .ENDIF									;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; Read the scan line backwards "column" by "column" until a non-blank is found: ;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
	MOV	CX,SCAN_LINE_MAX_LENGTH ; CX := current length			;AN000;
;										;AN000;
;-------For each "column"                                                       ;AN000;
CHECK_1_COLUMN: 								;AN000;
	MOV	SI,CUR_ROW		; Save coordinates of the column	;AN000;
	MOV	DI,CUR_COLUMN		; in SI, DI				;AN000;
	XOR	DL,DL			; DL := Number of pixels verified in	;AN000;
					;	  one "column"                  ;AN000;
;										;AN000;
;-------For each pixel within that "column"                                     ;AN000;
CHECK_1_PIXEL:									;AN000;
	CALL	READ_DOT		; AL := Index into translation table	;AN000;
	XLAT	XLT_TAB 		; AL := Band mask or Intensity		;AN000;
										;AN000;
;-------Check if pixel will map to an empty box:				;AN000;
       .IF <DS:[BP].PRINTER_TYPE EQ BLACK_WHITE> ; If BLACK AND WHITE printer	;AN000;
       .THEN				; then, check for intensity of white	;AN000;
	  CMP	  AL,WHITE_INT		;      If curent pixel not blank	;AN000;
	  JNE	  DET_LENGTH_END	;      THEN, LEAVE THE LOOP		;AN000;
       .ELSE				; else, COLOR printer			;AN000;
	  OR	  AL,AL 		;      IF Band mask not blank		;AN000;
	  JNZ	  DET_LENGTH_END	;      THEN, LEAVE THE LOOP		;AN000;
       .ENDIF									;AN000;
										;AN000;
;-------All pixels so far on this "column" are blank, get next pixel:           ;AN000;
       .IF <ROTATE_SW EQ ON>		; If printing sideways			;AN000;
       .THEN				;					;AN000;
	  INC CUR_COLUMN		; then, increment column number 	;AN000;
       .ELSE				;					;AN000;
	  INC CUR_ROW			; else, increment row number		;AN000;
       .ENDIF				;					;AN000;
	INC	DL			; One more pixel checked		;AN000;
	CMP	DL,NB_BOXES_PER_PRT_BUF ; All pixels for that column done ?	;AN000;
	JL	CHECK_1_PIXEL		;   No, check next one. 		;AN000;
										;AN000;
;-------Nothing to print for this column, get next column			;AN000;
       .IF <ROTATE_SW EQ ON>		; If printing sideways			;AN000;
       .THEN				; then, 				;AN000;
	  MOV CUR_COLUMN,DI		;   Restore column number		;AN000;
	  INC CUR_ROW			;   Get next row			;AN000;
       .ELSE				; else, 				;AN000;
	  MOV CUR_ROW,SI		;   Restore row number			;AN000;
	  DEC CUR_COLUMN		;   Get next column			;AN000;
       .ENDIF				;					;AN000;
	LOOP CHECK_1_COLUMN		; CX (length) := CX - 1 		;AN000;
										;AN000;
DET_LENGTH_END: 								;AN000;
	MOV	CUR_SCAN_LNE_LENGTH,CX	; Get current length			;AN000;
										;AN000;
	POP	CUR_ROW 							;AN000;
	POP	CUR_COLUMN							;AN000;
	POP	DI								;AN000;
	POP	SI								;AN000;
	POP	DX								;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	POP	AX								;AN000;
	RET									;AN000;
DET_CUR_SCAN_LNE_LENGTH ENDP							;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; SETUP_PRT : SET UP THE PRINTER FOR PRINTING IN GRAPHIC MODE			;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information		;AN000;
;			      record for the current mode			;AN000;
;										;AN000;
;	OUTPUT: PRINTER 							;AN000;
;										;AN000;
;	CALLED BY: PRINT_COLOR							;AN000;
;		   PRT_BW_APA							;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION: Extract the SETUP escape sequence from the DISPLAYMODE		;AN000;
; information record; Send this escape sequence to the printer. 		;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_SETUP_ESC			;AN000;
;										;AN000;
; Get the escape sequence:							;AN000;
; SI := CUR_MODE_PTR.SETUP_ESC_PTR						;AN000;
;										;AN000;
; FOR each byte to be printed							;AN000;
;   PRINT_BYTE [SI]			; Send the byte to the printer		;AN000;
;   INC SI				; Get the next byte			;AN000;
;										;AN000;
SETUP_PRT PROC NEAR								;AN000;
	PUSH	AX								;AN000;
	PUSH	BX								;AN000;
	PUSH	CX								;AN000;
										;AN000;
	MOV	BX,CUR_MODE_PTR 	; BX := Displaymode info record.	;AN000;
										;AN000;
	XOR	CX,CX			; CX := Number of bytes to print	;AN000;
	MOV	CL,[BX].NUM_SETUP_ESC	;					;AN000;
.IF <CL G 0>				; If there is at least one		;AN000;
.THEN					; byte to be printed:			;AN000;
	MOV	BX,[BX].SETUP_ESC_PTR	; BX := Offset sequence to send 	;AN000;
	ADD	BX,BP								;AN000;
										;AN000;
SEND_1_SETUP_BYTE:								;AN000;
	MOV	AL,[BX] 		; AL := byte to print			;AN000;
	CALL	PRINT_BYTE		; Send it to the printer		;AN000;
	JC	SETUP_PRT_END		; If printer error, quit the loop	;AN000;
	INC	BX			; Get next byte 			;AN000;
	LOOP	SEND_1_SETUP_BYTE						;AN000;
.ENDIF										;AN000;
SETUP_PRT_END:									;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	POP	AX								;AN000;
	RET									;AN000;
SETUP_PRT ENDP									;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; RESTORE_PRT : RESTORE THE PRINTER TO ITS INITIAL STATUS			;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information		;AN000;
;				 record for the current mode			;AN000;
;										;AN000;
;	OUTPUT: PRINTER 							;AN000;
;										;AN000;
;	CALLED BY: PRINT_COLOR							;AN000;
;		   PRT_BW_APA							;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION: Extract the RESTORE escape sequence from the DISPLAYMODE 	;AN000;
; information record; Send this escape sequence to the printer. 		;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_RESTORE_ESC			;AN000;
;										;AN000;
; Get the escape sequence:							;AN000;
; SI := CUR_MODE_PTR.RESTORE_ESC_PTR						;AN000;
; FOR each byte to be printed							;AN000;
;   PRINT_BYTE [SI]			; Send the byte to the printer		;AN000;
;   INC SI				; Get the next byte			;AN000;
;										;AN000;
RESTORE_PRT PROC NEAR								;AN000;
	PUSH	AX								;AN000;
	PUSH	BX								;AN000;
	PUSH	CX								;AN000;
										;AN000;
	MOV	BX,CUR_MODE_PTR 	; BX := Displaymode info record.	;AN000;
										;AN000;
	XOR	CX,CX			; CX := Number of bytes to print	;AN000;
	MOV	CL,[BX].NUM_RESTORE_ESC 					;AN000;
.IF <CL G 0>				; If there is at least one		;AN000;
.THEN					; byte to be printed:			;AN000;
	MOV	BX,[BX].RESTORE_ESC_PTR ; BX := Offset sequence to send 	;AN000;
	ADD	BX,BP								;AN000;
										;AN000;
SEND_1_RESTORE_BYTE:								;AN000;
	MOV	AL,[BX] 		; AL := byte to print			;AN000;
	CALL	PRINT_BYTE		; Send it to the printer		;AN000;
	JC	RESTORE_PRT_END 	; If printer error, quit the loop	;AN000;
	INC	BX			; Get next byte 			;AN000;
	LOOP	SEND_1_RESTORE_BYTE						;AN000;
.ENDIF										;AN000;
RESTORE_PRT_END:								;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	POP	AX								;AN000;
	RET									;AN000;
RESTORE_PRT ENDP								;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; NEW_PRT_LINE : INITIALIZE THE PRINTER FOR A GRAPHIC LINE			;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information		;AN000;
;				 record for the current mode			;AN000;
;	       CUR_SCAN_LNE_LENGTH = Number of bytes to send to the printer.	;AN000;
;										;AN000;
;	OUTPUT: PRINTER 							;AN000;
;										;AN000;
;	CALLED BY: PRINT_BAND							;AN000;
;		   PRT_BW_APA							;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION: Extract the GRAPHICS escape sequence from the DISPLAYMODE	;AN000;
; information record; Send this escape sequence to the printer. 		;AN000;
; Then, send the number of bytes that will follow.				;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_GRAPHICS_ESC			;AN000;
;										;AN000;
; Get the escape sequence:							;AN000;
; Set up the 2 bytes containing the number of bytes to send in this sequence.	;AN000;
; SI := CUR_MODE_PTR.GRAPHICS_ESC_PTR						;AN000;
;										;AN000;
; FOR each byte to be printed							;AN000;
;   PRINT_BYTE [SI]			; Send the byte to the printer		;AN000;
;   INC SI				; Get the next byte			;AN000;
;										;AN000;
; Send the byte count								;AN000;
;										;AN000;
										;AN000;
NEW_PRT_LINE PROC NEAR								;AN000;
	PUSH	AX								;AN000;
	PUSH	BX								;AN000;
	PUSH	CX								;AN000;
	PUSH	DX								;AN000;
	PUSH	DI								;AN000;
										;AN000;
	MOV	BX,CUR_MODE_PTR 	; BX := Displaymode info record.	;AN000;
										;AN000;
;-------------------------------------------------------------------------------;AN000;
; Set up the 2 bytes containing the number of bytes to send in the GRAPHICS seq.;AN000;
; NOTE: number of bytes to send is "CUR_SCAN_LNE_LENGTH * BOX_W"                ;AN000;
;-------------------------------------------------------------------------------;AN000;
	MOV	AL,BOX_W		;   cur_scan_lne_length *		;AN000;
	CBW				;   printer box width = nb bytes to send;AN000;
	MUL	CUR_SCAN_LNE_LENGTH	;     (result in DX AX) 		;AN000;
					;					;AN000;
;-------AX := Number of bytes to print						;AN000;
	MOV	DI,[BX].LOW_BYT_COUNT_PTR; DI := Offset of LOW byte of		;AN000;
	ADD	DI,BP			;	 byte count			;AN000;
	MOV	[DI],AL 		; Store low byte			;AN000;
	MOV	DI,[BX].HGH_BYT_COUNT_PTR; DI := Offset of HIGH byte of 	;AN000;
	ADD	DI,BP			;	 byte count			;AN000;
	MOV	[DI],AH 		; Store high byte			;AN000;
										;AN000;
;-------------------------------------------------------------------------------;AN000;
; Send the GRAPHICS escape sequence to the printer:				;AN000;
;-------------------------------------------------------------------------------;AN000;
	XOR	CX,CX				; CX := Length of the escape seq;AN000;
	MOV	CL,[BX].NUM_GRAPHICS_ESC					;AN000;
	MOV	BX,[BX].GRAPHICS_ESC_PTR	; BX := Offset sequence to send ;AN000;
	ADD	BX,BP								;AN000;
										;AN000;
SEND_1_GRAPHICS_BYTE:								;AN000;
	MOV	AL,[BX] 		; AL := byte to print			;AN000;
	CALL	PRINT_BYTE		; Send it to the printer		;AN000;
	JC	NEW_PRT_LINE_ENDP	; If printer error, quit the loop	;AN000;
	INC	BX			; Get next byte 			;AN000;
	LOOP	SEND_1_GRAPHICS_BYTE						;AN000;
										;AN000;
NEW_PRT_LINE_ENDP:								;AN000;
	POP	DI								;AN000;
	POP	DX								;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	POP	AX								;AN000;
	RET									;AN000;
NEW_PRT_LINE ENDP								;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; PRINT_BYTE : SEND A BYTE TO THE PRINTER AT LPT1				;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT:	AL		= Byte to be printed				;AN000;
;										;AN000;
;	OUTPUT: PRINTER 							;AN000;
;		ERROR_CODE	= PRINTER_ERROR if an error is detected.	;AN000;
;		Carry flag is set in case of error.				;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
PRINT_BYTE PROC    NEAR 							;AN000;
	PUSH	AX								;AN000;
	PUSH	DX								;AN000;
										;AN000;
	MOV	DX,0000 	; PRINTER NUMBER				;AN000;
	MOV	AH,00		; REQUEST PRINT 				;AN000;
	INT	17H		; CALL BIOS : SEND THE CHARACTER		;AN000;
										;AN000;
	AND	AH,00101001B	; Test error code returned in AH for		;AN000;
				;   "Out of paper", "I/O error" and "Time-out". ;AN000;
	JNZ	PRINT_BYTE_ERROR; Set the error code if error			;AN000;
	JMP	SHORT PRINT_BYTE_END ; else, return normally			;AN000;
PRINT_BYTE_ERROR:								;AN000;
	MOV	ERROR_CODE,PRINTER_ERROR					;AN000;
	STC			; Set the carry flag to indicate ERROR		;AN000;
PRINT_BYTE_END: 								;AN000;
	POP	DX								;AN000;
	POP	AX								;AN000;
	RET									;AN000;
PRINT_BYTE ENDP 								;AN000;
PAGE										;AN000;
;===============================================================================;AN000;
;										;AN000;
; READ_DOT: READ A PIXEL - RETURN A COLOR TRANSLATION TABLE INDEX		;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
;	INPUT:	CUR_MODE   = Current video mode.				;AN000;
;		CUR_ROW,							;AN000;
;		CUR_COLUMN = Coordinates of the pixel to be read.		;AN000;
;		CUR_PAGE   = Active page number 				;AN000;
;										;AN000;
;	OUTPUT: AL	   = Index into COLOR TRANSLATION TABLE.		;AN000;
;										;AN000;
;	DEPENDENCIES : COLOR TRANSLATION TABLE entries must be bytes		;AN000;
;										;AN000;
;										;AN000;
;-------------------------------------------------------------------------------;AN000;
;										;AN000;
; DESCRIPTION: Use VIDEO BIOS INTERRUPT 10H "READ DOT CALL".                    ;AN000;
;										;AN000;
; Depending on the video hardware, the dot returned by BIOS has 		;AN000;
; different meanings.								;AN000;
; With an EGA it is an index into the Palette registers,			;AN000;
; With a CGA it is a number from 0 to 3,  mapping to a specific color		;AN000;
; depending on the background color and the color palette currently		;AN000;
; selected.									;AN000;
;										;AN000;
; The Color Translation table has been set up to hold the correct color 	;AN000;
; mapping for any "dot" in any mode.  Therefore, the dot number returned        ;AN000;
; by INT 10H can be used with any mode as a direct index within that		;AN000;
; table.									;AN000;
;										;AN000;
; With APA Monochrome mode 0FH there are 4 different dots: white,		;AN000;
; blinking white, high-intensity white, and black.				;AN000;
;										;AN000;
; For mode 0FH, the dot returned by interrupt 10 "read dot" call is a byte      ;AN000;
; where only bits 0 and 2 are significant.  These 2 bits must be appended	;AN000;
; together in order to obtain a binary number (from 0 to 3) that will be used	;AN000;
; as an index in the Color Translation table.					;AN000;
;										;AN000;
; For mode 11H, the dot is either 0 (for background color) or 7 (for the	;AN000;
; foreground color) only the LSB is returned.  That is, we return either	;AN000;
; 0 or 1.									;AN000;
;										;AN000;
; LOGIC:									;AN000;
;										;AN000;
; Call VIDEO BIOS "READ DOT"                                                    ;AN000;
; IF CUR_MODE = 0FH								;AN000;
; THEN										;AN000;
;   Append bits 1 and 3.							;AN000;
; IF CUR_MODE = 11H								;AN000;
; THEN										;AN000;
;   Wipe out bits 1 and 2.							;AN000;
;										;AN000;
READ_DOT PROC NEAR								;AN000;
	PUSH	BX			; Save registers			;AN000;
	PUSH	CX								;AN000;
	PUSH	DX								;AN000;
										;AN000;
	MOV	BH,CUR_PAGE							;AN000;
	MOV	DX,CUR_ROW							;AN000;
	MOV	CX,CUR_COLUMN							;AN000;
	MOV	AH,READ_DOT_CALL						;AN000;
	INT	10H			; Call BIOS: AL <-- Dot read		;AN000;
										;AN000;
	CMP	CUR_MODE,0FH		; Is it Mode 0fH ?			;AN000;
	JNE	MODE_11H?		; No, look for mode 11h.		;AN000;
;-------Mode 0Fh is the current mode:						;AN000;
;-------Convert bits 2 and 0 into a 2 bit number:				;AN000;
	MOV	BL,AL			; BL := AL = "Pixel read"               ;AN000;
	AND	BL,00000100B		; Wipe off all bits but bit 2 in BL	;AN000;
	AND	AL,00000001B		; Wipe off all bits but bit 0 in AL	;AN000;
	SHR	BL,1			;  Move bit 2 to bit 1 in BL		;AN000;
	OR	AL,BL			;  Append bit 1 and bit 0		;AN000;
	JMP	SHORT READ_DOT_END	;  Quit.				;AN000;
										;AN000;
MODE_11H?:									;AN000;
	CMP	CUR_MODE,11H		; Is it Mode 0fH ?			;AN000;
	JNE	READ_DOT_END		; No, quit				;AN000;
										;AN000;
;-------Mode 11H is the current mode:						;AN000;
	AND	AL,00000001B		; Keep only the Least significant bit	;AN000;
										;AN000;
READ_DOT_END:									;AN000;
	POP	DX			; Restore registers			;AN000;
	POP	CX								;AN000;
	POP	BX								;AN000;
	RET									;AN000;
READ_DOT ENDP									;AN000;
