unoptimised text load & render

This commit is contained in:
koniifer 2024-10-26 09:23:28 +01:00
parent 5af5631755
commit eaace7d9c1
26 changed files with 198 additions and 26 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,10 @@
Tamsyn font is free. You are hereby granted permission to use, copy, modify,
and distribute it as you see fit.
Tamsyn font is provided "as is" without any express or implied warranty.
The author makes no representations about the suitability of this font for
a particular purpose.
In no event will the author be held liable for damages arising from the use
of this font.

View file

@ -5,13 +5,10 @@
- Animation
# API
- Font Loader
- VGA fonts
- Colour operations:
- Alpha Composite
- Invert
- Surface Operations:
- FlipV
- FlipH
- Resize
- Wrap the colour operations
@ -20,8 +17,8 @@
- Draw operations:
- Curve raster algorithm
- VGA font fast blit
- VGA font render
- Polygon
- Rounded rects
# Backend
- SVGA Driver

View file

@ -36,7 +36,7 @@ surface_from_bmp := fn(bmp: ^u8): Surface {
file_header := @as(^BitmapFileHeader, @bitcast(bmp))
if file_header.img_type != 0x4D42 {
log.error("failed to load bmp image: not a bmp image, idiot\0")
return @as(Surface, idk)
return idk
}
info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader)))
bmp += file_header.offset
@ -68,7 +68,7 @@ new_surface_from_bmp := fn(bmp: ^u8): Surface {
file_header := @as(^BitmapFileHeader, @bitcast(bmp))
if file_header.img_type != 0x4D42 {
log.error("failed to load bmp image: not a bmp image, idiot\0")
return @as(Surface, idk)
return idk
}
info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader)))
bmp += file_header.offset

View file

@ -1,5 +1,6 @@
software := @use("software.hb")
image := @use("image.hb")
text := @use("text.hb")
// default mode
mode := software
@ -40,6 +41,7 @@ put_filled_rect := mode.put_filled_rect
put_line := mode.put_line
clear := mode.clear
put_surface := mode.put_surface
put_text := mode.put_text
// thanks peony for these three!
put_trirect := mode.put_trirect
put_vline := mode.put_vline

View file

@ -1,5 +1,6 @@
.{math, memory, dt} := @use("../../stn/src/lib.hb");
.{Color} := @use("lib.hb");
.{Color, text} := @use("lib.hb");
.{get_glyph, Font} := text;
.{Vec2} := math
Surface := struct {
@ -255,5 +256,65 @@ put_hline := fn(surface: Surface, y: uint, x0: uint, x1: uint, color: Color): vo
}
@inline(memory.set, Color, &color, @inline(indexptr, surface, x0, y), @bitcast(x1 - x0 - 1))
return
}
put_text := fn(surface: Surface, font: Font, pos: Vec2(uint), color: Color, str: ^u8): void {
cursor := Vec2(uint).(pos.x, pos.y)
current_char := str
loop if *current_char == 0 break else {
if *current_char == 10 {
cursor.x = pos.x
cursor.y += font.height + font.line_gap
current_char += 1
continue
}
glyph_data := @inline(get_glyph, font, @intcast(*current_char))
if glyph_data == idk {
current_char += 1
continue
}
if cursor.x % surface.width + font.width >= surface.width {
cursor.x = pos.x
cursor.y += font.height + font.line_gap
}
if cursor.y + font.height > surface.height break
dest := @inline(indexptr, surface, cursor.x, cursor.y)
src := glyph_data
rows_remaining := font.height
loop if rows_remaining == 0 break else {
byte := *glyph_data
pixel_dest := dest
mask := @as(u8, 0x80)
bits_remaining := font.width
loop if bits_remaining == 0 break else {
if (byte & mask) != 0 {
*pixel_dest = color
}
pixel_dest += 1
mask >>= 1
if mask == 0 {
glyph_data += 1
byte = *glyph_data
mask = 0x80
}
bits_remaining -= 1
}
glyph_data += 1
dest += surface.width
rows_remaining -= 1
}
cursor.x += font.width + font.char_gap
current_char += 1
}
return
}

View file

@ -0,0 +1,75 @@
.{log} := @use("../../stn/src/lib.hb")
PSF1Header := packed struct {
magic: u16,
font_mode: u8,
character_size: u8,
}
PSF2Header := packed struct {
magic: u32,
version: u32,
header_size: u32,
flags: u32,
num_glyph: u32,
bytes_per_glyph: u32,
height: u32,
width: u32,
}
Font := struct {
data: ^u8,
width: uint,
height: uint,
num_glyphs: uint,
bytes_per_glyph: uint,
has_unicode_table: bool,
line_gap: uint,
char_gap: uint,
}
font_from_psf1 := fn(psf: ^u8): Font {
header := @as(^PSF1Header, @bitcast(psf))
if header.magic != 0x436 {
log.error("failed to load psf font: not a psf1 font, idiot\0")
return idk
}
psf += @sizeof(PSF1Header)
return .(
psf,
8,
@intcast(header.character_size),
256,
@intcast(header.character_size),
false,
0,
0,
)
}
font_from_psf2 := fn(psf: ^u8): Font {
header := @as(^PSF2Header, @bitcast(psf))
if header.magic != 0x864AB572 {
log.error("failed to load psf font: not a psf2 font, idiot\0")
return idk
}
psf += header.header_size
return .(
psf,
@intcast(header.width),
@intcast(header.height),
@intcast(header.num_glyph),
@intcast(header.bytes_per_glyph),
(header.flags & 1) != 0,
0,
0,
)
}
get_glyph := fn(font: Font, index: uint): ^u8 {
return font.data + index * font.bytes_per_glyph
}

Binary file not shown.

View file

@ -30,26 +30,30 @@ Vec2 := fn($Expr: type): type {
return struct {x: Expr, y: Expr}
}
SIN_TABLE := [int].(0, 174, 348, 523, 697, 871, 1045, 1218, 1391, 1564, 1736, 1908, 2079, 2249, 2419, 2588, 2756, 2923, 3090, 3255, 3420, 3583, 3746, 3907, 4067, 4226, 4384, 4540, 4695, 4848, 5000, 5150, 5299, 5446, 5591, 5735, 5877, 6018, 6156, 6293, 6427, 6560, 6691, 6819, 6946, 7071, 7193, 7313, 7431, 7547, 7660, 7771, 7880, 7986, 8090, 8191, 8290, 8386, 8480, 8571, 8660, 8746, 8829, 8910, 8987, 9063, 9135, 9205, 9271, 9335, 9396, 9455, 9510, 9563, 9612, 9659, 9702, 9743, 9781, 9816, 9848, 9877, 9902, 9925, 9945, 9961, 9975, 9986, 9993, 9998, 10000)
SIN_TABLE := @as([int; 91], @bitcast(@embed("./assets/sin_table")))
sin_i := fn(theta_deg: int, amplitude: int): int {
theta := theta_deg % 360
sin := fn(theta: int, amplitude: uint): int {
if theta < 0 {
theta += 360
theta += (-theta / 360 + 1) * 360
} else if theta >= 360 {
theta -= theta / 360 * 360
}
quadrant := theta / 90
theta = theta % 90
index := theta % 90
sign := 1 - ((quadrant & 2) >> 1) * 2
complement := quadrant & 1
if @as(u8, @intcast(quadrant)) == @as(u8, 1) {
index = 90 - index
}
index := theta * (1 - complement) + (90 - theta) * complement
sin_value := SIN_TABLE[index] * sign
value := SIN_TABLE[@bitcast(index)]
if quadrant >= 2 {
value = -value
}
return (sin_value * amplitude + 5000) / 10000
return (value * @bitcast(amplitude) + 5000) / 10000
}
cos_i := fn(theta_deg: int, amplitude: int): int {
return @inline(sin_i, theta_deg + 90, amplitude)
cos := fn(theta: int, amplitude: uint): int {
return @inline(sin, theta + 90, amplitude)
}

View file

@ -0,0 +1,23 @@
.{Vec2, sin, cos} := @use("../../../../libraries/stn/src/lib.hb").math
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result:
words */
psf := @embed("../../../../consolefonts/tamsyn/10x20r.psf")
example := fn(): void {
screen := render.init(true)
font := render.text.font_from_psf2(@bitcast(&psf))
t := 0
str := "Hello, World!
This is a test
of multiline rendering\0"
loop {
render.clear(screen, render.black)
render.put_text(screen, font, .(t, t % screen.height), render.red, str)
render.sync(screen)
t += 1
}
return
}

View file

@ -1,3 +1,3 @@
.{example} := @use("./examples/surface.hb")
.{example} := @use("./examples/text.hb")
main := example

View file

@ -28,8 +28,8 @@ resolution = "1024x768x24"
# [boot.limine.ableos.modules.diskio_driver]
# path = "boot:///diskio_driver.hbf"
# [boot.limine.ableos.modules.render_example]
# path = "boot:///render_example.hbf"
[boot.limine.ableos.modules.render_example]
path = "boot:///render_example.hbf"
# [boot.limine.ableos.modules.serial_driver]
# path = "boot:///serial_driver.hbf"
@ -37,11 +37,11 @@ resolution = "1024x768x24"
# [boot.limine.ableos.modules.serial_driver_test]
# path = "boot:///serial_driver_test.hbf"
[boot.limine.ableos.modules.horizon]
path = "boot:///horizon.hbf"
# [boot.limine.ableos.modules.horizon]
# path = "boot:///horizon.hbf"
[boot.limine.ableos.modules.horizon_testing_program]
path = "boot:///horizon_testing_program.hbf"
# [boot.limine.ableos.modules.horizon_testing_program]
# path = "boot:///horizon_testing_program.hbf"
# [boot.limine.ableos.modules.dt_buffer_test]
# path = "boot:///dt_buffer_test.hbf"