Implement text rendering
This commit is contained in:
parent
ddbf083d1b
commit
2c507b6ecb
|
@ -2,22 +2,23 @@ import json
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
# generates:
|
# generates:
|
||||||
# font_data.dat (binary file, expected to load at location 0xf000_0100)
|
# font_data.bin
|
||||||
# font_data.inc (fox32 assembly)
|
# font_table.bin
|
||||||
# font_data.inc defines constants
|
# font_data.inc
|
||||||
# N_CHARS: number of defined characters (u32)
|
|
||||||
# CHAR_TABLE: pointer to main char table (&Char)
|
|
||||||
# UNKNOWN_CHAR: pointer to unknown character (&Char)
|
|
||||||
#
|
#
|
||||||
# struct Char {
|
# struct Char {
|
||||||
# width: u8, height: u8, baseline: u8,
|
# width: u8, height: u8, baseline: u8,
|
||||||
# data_ptr: &[u8],
|
# data_offset: offset into font_data
|
||||||
# } (7 bytes)
|
# } (7 bytes)
|
||||||
|
|
||||||
DATA_FILE_ORIGIN = 0xf000_0100
|
CODEPAGE = {
|
||||||
|
0: None,
|
||||||
|
128: 'Ξ',
|
||||||
|
}
|
||||||
|
for x in range(32, 127):
|
||||||
|
CODEPAGE[x] = chr(x)
|
||||||
|
|
||||||
BASELINE = 7
|
BASELINE = 7
|
||||||
N_CHARS = 127
|
|
||||||
|
|
||||||
codepoints = json.load(open("ultlf/codepoints.json"))
|
codepoints = json.load(open("ultlf/codepoints.json"))
|
||||||
font_data = json.load(open("ultlf/data.json"))
|
font_data = json.load(open("ultlf/data.json"))
|
||||||
|
@ -33,34 +34,51 @@ UNKNOWN = [
|
||||||
"# # #",
|
"# # #",
|
||||||
]
|
]
|
||||||
|
|
||||||
with open("xenrom/data/font_data.inc", "w") as inc, open("xenrom/data/font_data.dat", "wb") as dat:
|
SPACE = [" "]
|
||||||
table = b''
|
|
||||||
char_data = b''
|
|
||||||
|
|
||||||
for ch in [None] + list(range(N_CHARS)):
|
SCALE = 2
|
||||||
if ch in codepoints:
|
def scale(glyph):
|
||||||
i = codepoints.index(ch)
|
out = []
|
||||||
glyph = font_data[i]
|
for line in glyph:
|
||||||
baseline = baselines[i]
|
line_scaled = ""
|
||||||
if '?' in "".join(glyph):
|
for ch in line:
|
||||||
print(f"Font doesn't have char {ch}")
|
line_scaled += ch * SCALE
|
||||||
glyph = UNKNOWN
|
out.extend([line_scaled] * SCALE)
|
||||||
baseline = 6
|
return out
|
||||||
else:
|
|
||||||
|
with open("xenrom/data/font_table.dat", "wb") as table_file, open("xenrom/data/font_data.dat", "wb") as data_file, open("xenrom/data/font_data.inc", "w") as inc_file:
|
||||||
|
table = b''
|
||||||
|
data = b''
|
||||||
|
|
||||||
|
for i in range(256):
|
||||||
|
ch = CODEPAGE.get(i, None)
|
||||||
|
unicode_codepoint = ord(ch) if ch is not None else None
|
||||||
|
if unicode_codepoint is None:
|
||||||
glyph = UNKNOWN
|
glyph = UNKNOWN
|
||||||
baseline = 6
|
baseline = 6
|
||||||
print(f"Couldn't find char {ch}")
|
elif unicode_codepoint == 32:
|
||||||
|
glyph = SPACE
|
||||||
|
baseline = 1
|
||||||
|
else:
|
||||||
|
ultlf_idx = codepoints.index(unicode_codepoint)
|
||||||
|
glyph = font_data[ultlf_idx]
|
||||||
|
baseline = baselines[ultlf_idx]
|
||||||
|
|
||||||
table += struct.pack("BBBI", len(glyph[0]), len(glyph), baseline, DATA_FILE_ORIGIN + len(char_data))
|
if "X" in "".join(glyph):
|
||||||
|
glyph = UNKNOWN
|
||||||
|
baseline = 6
|
||||||
|
|
||||||
|
glyph = scale(glyph)
|
||||||
|
baseline *= SCALE
|
||||||
|
|
||||||
|
table += struct.pack("<BBBI", len(glyph[0]), len(glyph), baseline, len(data))
|
||||||
|
|
||||||
for line in glyph:
|
for line in glyph:
|
||||||
for ch in glyph:
|
for ch in line:
|
||||||
char_data += b'\x00' if ch == ' ' else b'\x01'
|
data += b'\x00' if ch == ' ' else b'\x01'
|
||||||
|
|
||||||
dat.write(char_data + table)
|
table_file.write(table)
|
||||||
|
data_file.write(data)
|
||||||
|
|
||||||
inc.write(f'''
|
inc_file.write(f"const FONT_SIZE: {SCALE}\n")
|
||||||
const N_CHARS: {N_CHARS}
|
inc_file.write(f"const FONT_LINE_HEIGHT: {8 * SCALE}\n")
|
||||||
const CHAR_TABLE: {hex(DATA_FILE_ORIGIN + len(char_data))}
|
|
||||||
const UNKNOWN_CHAR: {hex(DATA_FILE_ORIGIN)}
|
|
||||||
''')
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ const BG_FRAMEBUFFER: 0x2000000
|
||||||
const SCREEN_WIDTH: 640
|
const SCREEN_WIDTH: 640
|
||||||
const SCREEN_HEIGHT: 480
|
const SCREEN_HEIGHT: 480
|
||||||
|
|
||||||
|
const COLOR_WHITE: 0xffffffc0
|
||||||
|
const COLOR_BLUE: 0xffffff40
|
||||||
|
const COLOR_ORANGE: 0xff4080ff
|
||||||
|
|
||||||
; Globals
|
; Globals
|
||||||
const FRAMENR: 0x00000000
|
const FRAMENR: 0x00000000
|
||||||
|
@ -17,8 +20,6 @@ entry:
|
||||||
mcl ; disable MMU
|
mcl ; disable MMU
|
||||||
mov rsp, SYS_STACK_START ; set stack pointer
|
mov rsp, SYS_STACK_START ; set stack pointer
|
||||||
|
|
||||||
mov r0, entry_str
|
|
||||||
call serial_print
|
|
||||||
mov r0, version_str_1
|
mov r0, version_str_1
|
||||||
call serial_print
|
call serial_print
|
||||||
mov r0, version_str
|
mov r0, version_str
|
||||||
|
@ -32,18 +33,64 @@ entry:
|
||||||
|
|
||||||
call show_logo
|
call show_logo
|
||||||
|
|
||||||
|
mov r0, BG_FRAMEBUFFER
|
||||||
|
mov r1, 640 ; width
|
||||||
|
mov r2, entry_str
|
||||||
|
mov r3, 20 ; x
|
||||||
|
mov r4, 20 ; y
|
||||||
|
mov r5, 20 ; l
|
||||||
|
mov r6, 620 ; r
|
||||||
|
mov r7, 100000 ; bot
|
||||||
|
mov r30, 2
|
||||||
|
mov r31, COLOR_WHITE
|
||||||
|
|
||||||
|
call draw_str_at
|
||||||
|
mov r2, version_str_1
|
||||||
|
call draw_str_at
|
||||||
|
mov r2, version_str
|
||||||
|
mov r31, COLOR_BLUE
|
||||||
|
call draw_str_at
|
||||||
|
mov r2, version_str_2
|
||||||
|
mov r31, COLOR_WHITE
|
||||||
|
call draw_str_at
|
||||||
|
mov r2, sha_str
|
||||||
|
mov r31, COLOR_ORANGE
|
||||||
|
call draw_str_at
|
||||||
|
mov r31, COLOR_WHITE
|
||||||
|
mov r2, version_str_3
|
||||||
|
call draw_str_at
|
||||||
|
|
||||||
|
mov r31, COLOR_WHITE
|
||||||
|
mov r2, credit_str_1
|
||||||
|
call draw_str_at
|
||||||
|
mov r31, COLOR_BLUE
|
||||||
|
mov r2, credit_str_2
|
||||||
|
call draw_str_at
|
||||||
|
mov r31, COLOR_WHITE
|
||||||
|
mov r2, credit_str_3
|
||||||
|
call draw_str_at
|
||||||
|
mov r31, COLOR_ORANGE
|
||||||
|
mov r2, credit_str_4
|
||||||
|
call draw_str_at
|
||||||
|
|
||||||
|
|
||||||
mov r0, booting_str
|
mov r0, booting_str
|
||||||
call serial_print
|
call serial_print
|
||||||
|
|
||||||
halt
|
halt
|
||||||
|
|
||||||
entry_str: data.str "== Welcome to Xen32OS" data.8 0
|
entry_str: data.str "= " data.8 128 data.str "EN32OS =" data.8 10 data.8 0
|
||||||
; defines version_str, sha_str
|
; defines version_str, sha_str
|
||||||
#include "data/version.inc"
|
#include "data/version.inc"
|
||||||
|
|
||||||
version_str_1: data.str " - version " data.8 0
|
version_str_1: data.str "version " data.8 0
|
||||||
version_str_2: data.str " (" data.8 0
|
version_str_2: data.str " (commit " data.8 0
|
||||||
version_str_3: data.str ") ==" data.8 10 data.8 0
|
version_str_3: data.str ")" data.8 10 data.8 0
|
||||||
|
|
||||||
|
credit_str_1: data.str "font by " data.8 0
|
||||||
|
credit_str_2: data.str "ultlang" data.8 0
|
||||||
|
credit_str_3: data.str ", os by " data.8 0
|
||||||
|
credit_str_4: data.str "xenia" data.8 0
|
||||||
|
|
||||||
booting_str: data.str "booting..." data.8 10 data.8 0
|
booting_str: data.str "booting..." data.8 10 data.8 0
|
||||||
|
|
||||||
|
@ -96,4 +143,5 @@ serial_print_nl:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
#include "logo.asm"
|
#include "logo.asm"
|
||||||
|
#include "text.asm"
|
||||||
|
|
||||||
|
|
202
xenrom/text.asm
202
xenrom/text.asm
|
@ -1 +1,203 @@
|
||||||
|
font_table: #include_bin "data/font_table.dat"
|
||||||
|
font_data: #include_bin "data/font_data.dat"
|
||||||
|
; defines FONT_SIZE and FONT_LINE_HEIGHT
|
||||||
|
#include "data/font_data.inc"
|
||||||
|
|
||||||
|
|
||||||
|
; input:
|
||||||
|
; r0: pointer to frame buffer
|
||||||
|
; r1: frame buffer width
|
||||||
|
; r2: pointer to string to draw
|
||||||
|
; r3: x coordinate to draw at
|
||||||
|
; r4: y coordinate to draw at
|
||||||
|
; r5: text box left
|
||||||
|
; r6: text box right
|
||||||
|
; r7: text box bottom
|
||||||
|
; r30: text delay (ms, blocking)
|
||||||
|
; r31: text color
|
||||||
|
; returns:
|
||||||
|
; r0, r1, r5, r6, r7, r30, r31 kept
|
||||||
|
; r2: pointer to last char drawn
|
||||||
|
; r3: x coordinate to next char to draw
|
||||||
|
; r4: y coordinate to next char to draw
|
||||||
|
|
||||||
|
draw_str_at:
|
||||||
|
; store char pointer in r8
|
||||||
|
mov r8, r2
|
||||||
|
|
||||||
|
draw_str_at_loop:
|
||||||
|
cmp r30, 0
|
||||||
|
ifnz call font_sleep
|
||||||
|
|
||||||
|
; r2: current char
|
||||||
|
movz.8 r2, [r8]
|
||||||
|
cmp r2, 0 ; check for null terminator
|
||||||
|
ifz jmp draw_str_at_loop_end
|
||||||
|
|
||||||
|
; check for newline
|
||||||
|
cmp r2, 10
|
||||||
|
ifz jmp draw_str_at_newline
|
||||||
|
|
||||||
|
; r9: char entry
|
||||||
|
mov r9, r2
|
||||||
|
mul r9, 7
|
||||||
|
add r9, font_table
|
||||||
|
; r10: width, r11: end x
|
||||||
|
movz.8 r10, [r9]
|
||||||
|
mov r11, r3
|
||||||
|
add r11, r10
|
||||||
|
|
||||||
|
; are we after the edge?
|
||||||
|
cmp r11, r6
|
||||||
|
iflt jmp draw_str_at_loop_draw
|
||||||
|
; if we have a space, don't reset
|
||||||
|
cmp r2, 32
|
||||||
|
ifz jmp draw_str_at_loop_draw
|
||||||
|
|
||||||
|
draw_str_at_linebreak:
|
||||||
|
|
||||||
|
mov r3, r5 ; reset x
|
||||||
|
; update end x
|
||||||
|
mov r11, r5
|
||||||
|
add r11, r10
|
||||||
|
; step to next line, check if we've overrun the box
|
||||||
|
add r4, FONT_LINE_HEIGHT
|
||||||
|
cmp r4, r7
|
||||||
|
ifgteq jmp draw_str_at_loop_end
|
||||||
|
|
||||||
|
draw_str_at_loop_draw:
|
||||||
|
push r0
|
||||||
|
push r1
|
||||||
|
push r2
|
||||||
|
push r3
|
||||||
|
push r4
|
||||||
|
call draw_char_at
|
||||||
|
pop r4
|
||||||
|
pop r3
|
||||||
|
pop r2
|
||||||
|
pop r1
|
||||||
|
pop r0
|
||||||
|
|
||||||
|
draw_str_at_spaceskip:
|
||||||
|
inc r8 ; update string index
|
||||||
|
mov r3, r11 ; update x coordinate
|
||||||
|
add r3, FONT_SIZE ; padding
|
||||||
|
jmp draw_str_at_loop
|
||||||
|
|
||||||
|
draw_str_at_newline:
|
||||||
|
inc r8 ; update string index
|
||||||
|
mov r3, r5 ; reset x
|
||||||
|
; step to next line, check if we've overrur the box
|
||||||
|
add r4, FONT_LINE_HEIGHT
|
||||||
|
cmp r4, r7
|
||||||
|
ifgteq jmp draw_str_at_loop_end
|
||||||
|
jmp draw_str_at_loop
|
||||||
|
|
||||||
|
draw_str_at_loop_end:
|
||||||
|
|
||||||
|
; restore char pointer into r2
|
||||||
|
mov r2, r8
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
; input:
|
||||||
|
; r0: pointer to frame buffer
|
||||||
|
; r1: frame buffer width
|
||||||
|
; r2: char to draw
|
||||||
|
; r3: x coordinate to draw at
|
||||||
|
; r4: y coordinate to draw at
|
||||||
|
; r31: color
|
||||||
|
; returns:
|
||||||
|
; nothing
|
||||||
|
|
||||||
|
draw_char_at:
|
||||||
|
push r5
|
||||||
|
push r6
|
||||||
|
push r7
|
||||||
|
push r8
|
||||||
|
push r9
|
||||||
|
; r5: width
|
||||||
|
; r7: baseline
|
||||||
|
; r8: char data pointer
|
||||||
|
; r9: number of pixels to draw
|
||||||
|
|
||||||
|
mul r2, 7 ; size of char
|
||||||
|
add r2, font_table
|
||||||
|
|
||||||
|
movz.8 r5, [r2]
|
||||||
|
inc r2
|
||||||
|
movz.8 r9, [r2]
|
||||||
|
mul r9, r5
|
||||||
|
|
||||||
|
inc r2
|
||||||
|
movz.8 r7, [r2]
|
||||||
|
inc r2
|
||||||
|
mov r8, [r2]
|
||||||
|
add r8, font_data
|
||||||
|
|
||||||
|
; adjust y for baseline
|
||||||
|
sub r4, r7
|
||||||
|
|
||||||
|
; calculate init framebuffer address into r4
|
||||||
|
mul r4, r1
|
||||||
|
add r4, r3
|
||||||
|
mul r4, 4
|
||||||
|
add r4, r0
|
||||||
|
|
||||||
|
; r6: x counter in glyph
|
||||||
|
; r9: countdown
|
||||||
|
mov r6, 0
|
||||||
|
draw_char_at_loop:
|
||||||
|
cmp r9, 0 ; zero terminator
|
||||||
|
ifz jmp draw_char_at_loop_done
|
||||||
|
|
||||||
|
cmp.8 [r8], 0
|
||||||
|
ifnz mov [r4], r31
|
||||||
|
|
||||||
|
inc r8 ; advance glyph data pointer
|
||||||
|
dec r9 ; lower count
|
||||||
|
add r4, 4 ; advance screen pointer
|
||||||
|
inc r6 ; advance x counter
|
||||||
|
cmp r6, r5 ; are we at the end of the glyph line?
|
||||||
|
ifnz jmp draw_char_at_loop
|
||||||
|
; move screen pointer down one (x4 for 4 bytes per pixel)
|
||||||
|
add r4, r1
|
||||||
|
add r4, r1
|
||||||
|
add r4, r1
|
||||||
|
add r4, r1
|
||||||
|
sub r4, r5
|
||||||
|
sub r4, r5
|
||||||
|
sub r4, r5
|
||||||
|
sub r4, r5
|
||||||
|
mov r6, 0
|
||||||
|
|
||||||
|
jmp draw_char_at_loop
|
||||||
|
|
||||||
|
draw_char_at_loop_done:
|
||||||
|
|
||||||
|
pop r9
|
||||||
|
pop r8
|
||||||
|
pop r7
|
||||||
|
pop r6
|
||||||
|
pop r5
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
; input
|
||||||
|
; r30: time to sleep (ms)
|
||||||
|
font_sleep:
|
||||||
|
push r0
|
||||||
|
push r1
|
||||||
|
; r0: end time
|
||||||
|
; r1: current time
|
||||||
|
in r0, 0x8000_0706 ; RTC uptime (ms)
|
||||||
|
add r0, 30
|
||||||
|
font_sleep_busyloop:
|
||||||
|
in r1, 0x8000_0706
|
||||||
|
cmp r1, r0
|
||||||
|
iflt jmp font_sleep_busyloop
|
||||||
|
|
||||||
|
pop r1
|
||||||
|
pop r0
|
||||||
|
ret
|
||||||
|
|
Loading…
Reference in New Issue
Block a user