• Please review our updated Terms and Rules here

CGA Tiny Font (4x4)

neilobremski

Experienced Member
Joined
Oct 9, 2016
Messages
55
Location
Seattle, USA
In accordance with yesterday's entry on text rendering, I've now created the routine for a "tiny" font. What this does is take the 8x8 glyphs and compresses them into 4x4 squares by creating a sort of average brightness of each pixel based on the surrounding 4. The four distinct colors of CGA mode 4 (black, magenta, white, cyan) are thus used for brightness and the caller cannot specify the foreground or background colors of the text.


The result is a bit hard to read but that is okay. The point of this is not for UI labels that the user is expected to read but rather to denote data such as version visually on the screen. This way, any screenshot of the game will necessarily include what version it is. The scheme I use is simply a main version number (2 is the assembler rewrite) followed by a build date. You can see this in screenshots from the original Magenta's Maze.


The averaging is crudely weighted thus: the upper-left is counted 3x, the upper-right and lower-left are counted 2x, and the bottom-right is counted 1x. This means there are 8 possible brightness levels which are then spread across black, magenta, white, and cyan in that order. I've played around with various ways of weighting the corners and decided that I could do that until the end of time and not come up with something entirely satisfactory. Obviously I could create a full table of 4x4 glyphs and they'd look better but this way I use whatever font data is installed in the user's computer (which I think is kinda cool).

Here's the code:

Code:
e 1C77 00 00 02 02 03 03 01 01
a 1C80
; ----------------------------------------------------------------------------
; TinyBlit()							:TINYBLIT
;
; Prints string at DS:SI with 4x4 character glyphs.
; 0x00, 0xAA, 0xFF, 0xFF, 0x55, 0x55
;
;	[input]		[output]	[within]
; AX	X		(trashed)	2 font bytes
; BX	Y		(trashed)	brightness
; CX			(trashed)	CH=XCount,CL=YCount
; DX			(trashed)	pixel data
; SI	pString+Offs	pString+Len	BIOS font data
; DS	pString		pString		BIOS font data
; ES	vidptr		vidptr		vidptr
; DI			pixel location	pixel location
; BP			(trashed)	
;
CALL	1B80	; C80 >PIXELPOS
CLD		; C83
		;
		; TINYBLIT: OUTER LOOP (string characters)
		;
LODSB		; C84 read next character from string		:TINY_LOOP_CHR
OR	AL, AL	; C85
JZ	1CFC	; C87 >TINYBLIT_RET
		;
PUSH	DI	; C89
PUSH	SI	; C8A
PUSH	DS	; C8B
CALL	0370	; C8C >BIOSCHAR
MOV	CL, 04	; C8F CL = YCount (scanlines remaining)
CLD		; C91 read/write forward
XOR	BP, BP	; C92
		; ------------------------------------------------------------
		; TINYBLIT: INNER LOOPS (Y|scanlines and X|pixels)
		;
LODSW		; C94 read two bytes|lines of font pixel map	:TINY_LOOP_Y
MOV	CH, 04	; C95 CH = XCount (pixels remaining)
XOR	BL, BL	; C97						:TINY_LOOP_X
ROL	AL, 1	; C99
MOV	BH, AL	; C9B
AND	AL, 1	; C9D
ADD	BL, AL	; C9F
ADD	BL, AL	; CA1
ADD	BL, AL	; CA3 3x boost for upper-left
MOV	AL, BH	; CA5
ROL	AL, 1	; CA7
MOV	BH, AL	; CA9
AND	AL, 1	; CAB
ADD	BL, AL	; CAD
ADD	BL, AL	; CAF 2x boost for upper-right
MOV	AL, BH	; CB1
XCHG	AL, AH	; CB3 swap rows so AL=second and AH=first
ROL	AL, 1	; CB5
MOV	BH, AL	; CB7
AND	AL, 1	; CB9
ADD	BL, AL	; CBB
ADD	BL, AL	; CBD 2x boost for lower-left
MOV	AL, BH	; CBF
ROL	AL, 1	; CC1
MOV	BH, AL	; CC3
AND	AL, 1	; CC5
ADD	BL, AL	; CC7
MOV	AL, BH	; CC9
XCHG	AL, AH	; CCB swap rows so AL=first and AH=second
		;
MOV	BP, AX	; CCD 
MOV	BH, 1C	; CCF
ADD	BL, 77	; CD1
CS:		; CD4
XLAT		; CD5 translate brightness using table @1C7A
SHL	DX, 1	; CD6
SHL	DX, 1	; CD8
OR	DX, AX	; CDA
MOV	AX, BP	; CDC
		;
DEC	CH	; CDE
JNZ	1C97	; CE0 >TINY_LOOP_X
		;
NOP		; CE2 debugging breakpoint			:TINY_LINE_DRW
STOSB		; CE3 plot 4 pixels for this scanline
ADD	DI, 1FFF; CE4
CMP	DI, 4000; CE8 
JB	1CF2	; CEC >TINY_LOOP_END
SUB	DI, 3FB0; CEE 
DEC	CL	; CF2						:TINY_LOOP_END
JNZ	1C94	; CF4 >TINY_LOOP_Y
		; ------------------------------------------------------------
		;
POP	DS	; CF6						:TINY_CHR_NEXT
POP	SI	; CF7
POP	DI	; CF8
INC	DI	; CF9
JMP	1C84	; CFA >TINY_LOOP_CHR
RET		; CFC						:TINYBLIT_RET

You may notice there's some overlap in the code addresses from yesterday. I created a PIXELPOS method that both this and TEXTBLIT use which freed up enough space such that both text renderers fit within 0x1C??.
 
Back
Top