neilobremski
Experienced Member
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:
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??.
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??.