; Program to illustrate the color mapping capabilities of the
; EGA's palette registers.
;
VGA_SEGMENT	equ	0a000h
SC_INDEX	equ	3c4h		;Sequence Controller Index register
MAP_MASK	equ	2		;Map Mask register index in SC
BAR_HEIGHT	equ	14		;height of each bar
TOP_BAR		equ	BAR_HEIGHT*6	;start the bars down a bit to
					; leave room for text
;
stack	segment para stack 'STACK'
	db	512 dup (?)
stack	ends
;
Data	segment word 'DATA'
KeyMsg	db	'Press any key to see the next color set. '
	db	'There are 64 color sets in all.'
	db	0dh, 0ah, 0ah, 0ah, 0ah
	db	13 dup (' '), 'Attribute'
	db	38 dup (' '), 'Color$'
;
; Used to label the attributes of the color bars.
;
AttributeNumbers	label	byte
x=	0
	rept	16
if x lt 10
	db	'0', x+'0', 'h', 0ah, 8, 8, 8
else
	db	'0', x+'A'-10, 'h', 0ah, 8, 8, 8
endif
x=	x+1
	endm
	db	'$'
;
; Used to label the colors of the color bars. (Color values are
; filled in on the fly.)
;
ColorNumbers	label	byte
	rept	16
	db	'000h', 0ah, 8, 8, 8, 8
	endm
COLOR_ENTRY_LENGTH	equ	($-ColorNumbers)/16
	db	'$'
;
CurrentColor	db	?
;
; Space for the array of 16 colors we'll pass to the BIOS, plus
; an overscan setting of black.
;
ColorTable	db	16 dup (?), 0
Data	ends
;
Code	segment
	assume	cs:Code, ds:Data
Start	proc	near
	cld
	mov	ax,Data
	mov	ds,ax
;
; Go to hi-res graphics mode.
;
	mov	ax,10h		;AH = 0 means mode set, AL = 10h selects
				; hi-res graphics mode
	int	10h		;BIOS video interrupt
;
; Put up relevant text.
;
	mov	ah,9		;DOS print string function
	mov	dx,offset KeyMsg
	int	21h
;
; Put up the color bars, one in each of the 16 possible pixel values
; (which we'll call attributes).
;
	mov	cx,16		;we'll put up 16 color bars
	sub	al,al		;start with attribute 0
BarLoop:
	push	ax
	push	cx
	call	BarUp
	pop	cx
	pop	ax
	inc	ax		;select the next attribute
	loop	BarLoop
;
; Put up the attribute labels.
;
	mov	ah,2		;video interrupt set cursor position function
	sub	bh,bh		;page 0
	mov	dh,TOP_BAR/14	;counting in character rows, match to
				; top of first bar, counting in
				; scan lines
	mov	dl,16		;just to left of bars
	int	10h
	mov	ah,9		;DOS print string function
	mov	dx,offset AttributeNumbers
	int	21h
;
; Loop through the color set, one new setting per keypress.
;
	mov	[CurrentColor],0	;start with color zero
ColorLoop:
;
; Set the palette registers to the current color set, consisting
; of the current color mapped to attribute 0, current color + 1
; mapped to attribute 1, and so on.
;
	mov	al,[CurrentColor]
	mov	bx,offset ColorTable
	mov	cx,16		;we have 16 colors to set
PaletteSetLoop:
	and	al,3fh		;limit to 6-bit color values
	mov	[bx],al		;built the 16-color table used for setting
	inc	bx		; the palette registers
	inc	ax
	loop	PaletteSetLoop
	mov	ah,10h		;video interrupt palette function
	mov	al,2		;subfunction to set all 16 palette registers
				; and overscan at once
	mov	dx,offset ColorTable
	push	ds
	pop	es		;ES:DX points to the color table
	int	10h		;invoke the video interrupt to set the palette
;
; Put up the color numbers, so we can see how attributes map
; to color values, and so we can see how each color # looks
; (at least on this particular screen).
;
	call	ColorNumbersUp
;
; Wait for a keypress, so they can see this color set.
;
WaitKey:
	mov	ah,8		;DOS input without echo function
	int	21h
;
; Advance to the next color set.
;
	mov	al,[CurrentColor]
	inc	ax
	mov	[CurrentColor],al
	cmp	al,64
	jbe	ColorLoop
;
; Restore text mode.
;
	mov	ax,3
	int	10h
;
; Done.
;
Done:
	mov	ah,4ch		;DOS terminate function
	int	21h
;
; Puts up a bar consisting of the specified attribute (pixel value),
; at a vertical position corresponding to the attribute.
;
; Input: AL = attribute
;
BarUp	proc	near
	mov	dx,SC_INDEX
	mov	ah,al
	mov	al,MAP_MASK
	out	dx,al
	inc	dx
	mov	al,ah
	out	dx,al		;set the Map Mask register to produce
				; the desired color
	mov	ah,BAR_HEIGHT
	mul	ah		;row of top of bar
	add	ax,TOP_BAR	;start a few lines down to leave room for
				; text
	mov	dx,80		;rows are 80 bytes long
	mul	dx		;offset in bytes of start of scan line bar
				; starts on
	add	ax,20		;offset in bytes of upper left corner of bar
	mov	di,ax
	mov	ax,VGA_SEGMENT
	mov	es,ax		;ES:DI points to offset of upper left
				; corner of bar
	mov	dx,BAR_HEIGHT
	mov	al,0ffh
BarLineLoop:
	mov	cx,40		;make the bars 40 wide
	rep	stosb		;do one scan line of the bar
	add	di,40		;point to the start of the next scan line
				; of the bar
	dec	dx
	jnz	BarLineLoop
	ret
BarUp	endp
;
; Converts AL to a hex digit in the range 0-F.
;
BinToHexDigit	proc	near
	cmp	al,9
	ja	IsHex
	add	al,'0'
	ret
IsHex:
	add	al,'A'-10
	ret
BinToHexDigit	endp
;
; Displays the color values generated by the color bars given the
; current palette register settings off to the right of the color
; bars.
;
ColorNumbersUp	proc	near
	mov	ah,2		;video interrupt set cursor position function
	sub	bh,bh		;page 0
	mov	dh,TOP_BAR/14	;counting in character rows, match to
				; top of first bar, counting in
				; scan lines
	mov	dl,20+40+1	;just to right of bars
	int	10h
	mov	al,[CurrentColor]	;start with the current color
	mov	bx,offset ColorNumbers+1
				;build the color number text string on the fly
	mov	cx,16		;we've got 16 colors to do
ColorNumberLoop:
	push	ax		;save the color #
	and	al,3fh		;limit to 6-bit color values
	shr	al,1
	shr	al,1
	shr	al,1
	shr	al,1		;isolate the high nibble of the
				; color #
	call	BinToHexDigit	;convert the high color # nibble
	mov	[bx],al		; and put it into the text
	pop	ax		;get back the color #
	push	ax		;save the color #
	and	al,0fh		;isolate the low color # nibble
	call	BinToHexDigit	;convert the low nibble of the
				; color # to ASCII
	mov	[bx+1],al	; and put it into the text
	add	bx,COLOR_ENTRY_LENGTH	;point to the next entry
	pop	ax		;get back the color #
	inc	ax		;next color #
	loop	ColorNumberLoop
	mov	ah,9		;DOS print string function
	mov	dx,offset ColorNumbers
	int	21h		;put up the attribute numbers
	ret
ColorNumbersUp	endp
;
Start	endp
Code	ends
	end	Start
