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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
.{math, memory, dt} := @use("../../stn/src/lib.hb"); .{math, memory, dt} := @use("../../stn/src/lib.hb");
.{Color} := @use("lib.hb"); .{Color, text} := @use("lib.hb");
.{get_glyph, Font} := text;
.{Vec2} := math .{Vec2} := math
Surface := struct { 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)) @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 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} 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 { sin := fn(theta: int, amplitude: uint): int {
theta := theta_deg % 360
if theta < 0 { if theta < 0 {
theta += 360 theta += (-theta / 360 + 1) * 360
} else if theta >= 360 {
theta -= theta / 360 * 360
} }
quadrant := theta / 90 quadrant := theta / 90
theta = theta % 90 index := theta % 90
sign := 1 - ((quadrant & 2) >> 1) * 2 if @as(u8, @intcast(quadrant)) == @as(u8, 1) {
complement := quadrant & 1 index = 90 - index
}
index := theta * (1 - complement) + (90 - theta) * complement value := SIN_TABLE[@bitcast(index)]
sin_value := SIN_TABLE[index] * sign 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 { cos := fn(theta: int, amplitude: uint): int {
return @inline(sin_i, theta_deg + 90, amplitude) 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 main := example

View file

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