263 lines
5.3 KiB
Plaintext
263 lines
5.3 KiB
Plaintext
|
.{math, memory} := @use("../../stn/src/lib.hb");
|
||
|
.{IVec2} := @use("rel:lib.hb")
|
||
|
|
||
|
Color := struct {b: u8, g: u8, r: u8, a: u8}
|
||
|
white := Color.(255, 255, 255, 255)
|
||
|
black := Color.(0, 0, 0, 255)
|
||
|
gray := Color.(127, 127, 127, 255)
|
||
|
red := Color.(0, 0, 205, 255)
|
||
|
green := Color.(0, 205, 0, 255)
|
||
|
yellow := Color.(0, 205, 205, 255)
|
||
|
blue := Color.(205, 0, 0, 255)
|
||
|
magenta := Color.(205, 0, 205, 255)
|
||
|
cyan := Color.(205, 205, 0, 255)
|
||
|
light_gray := Color.(229, 229, 229, 255)
|
||
|
light_red := Color.(0, 0, 255, 255)
|
||
|
light_green := Color.(0, 255, 0, 255)
|
||
|
light_yellow := Color.(0, 255, 255, 255)
|
||
|
light_blue := Color.(255, 0, 0, 255)
|
||
|
light_magenta := Color.(255, 0, 255, 255)
|
||
|
light_cyan := Color.(255, 255, 0, 255)
|
||
|
|
||
|
// fb_width := 1024
|
||
|
// fb_height := 768
|
||
|
// fb_pixels := fb_width * fb_height
|
||
|
// fb_bytes := fb_pixels << 2
|
||
|
copy_pixels := 0xC000 >> 2
|
||
|
// partitions := fb_pixels / copy_pixels
|
||
|
// total_pages := 1 + fb_bytes >> 12
|
||
|
|
||
|
ctx := @as(Context, idk)
|
||
|
|
||
|
Context := struct {
|
||
|
fb: ^Color,
|
||
|
bb: ^Color,
|
||
|
buf: ^Color,
|
||
|
width: int,
|
||
|
height: int,
|
||
|
partitions: int,
|
||
|
pixels: int,
|
||
|
bb_pages: int,
|
||
|
double_buffer: bool,
|
||
|
}
|
||
|
|
||
|
init := fn(): void {
|
||
|
width := @eca(int, 3, 6, "w\0", 2)
|
||
|
height := @eca(int, 3, 6, "h\0", 2)
|
||
|
// width := 1024
|
||
|
// height := 768
|
||
|
pixels := width * height
|
||
|
bytes := pixels << 2
|
||
|
partitions := pixels / copy_pixels
|
||
|
pages := 1 + bytes >> 12
|
||
|
back_buffer := create_back_buffer(pages)
|
||
|
ctx = Context.{
|
||
|
fb: @eca(^Color, 3, 6, "p\0", 2),
|
||
|
bb: back_buffer,
|
||
|
buf: back_buffer,
|
||
|
width,
|
||
|
height,
|
||
|
partitions,
|
||
|
pixels,
|
||
|
bb_pages: pages,
|
||
|
double_buffer: true,
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
doublebuffer := fn(enable: bool): void {
|
||
|
if enable {
|
||
|
ctx.buf = ctx.bb
|
||
|
} else {
|
||
|
ctx.buf = ctx.fb
|
||
|
}
|
||
|
ctx.double_buffer = enable
|
||
|
return
|
||
|
}
|
||
|
|
||
|
create_back_buffer := fn(pages: int): ^Color {
|
||
|
if pages <= 0xFF {
|
||
|
return @bitcast(@inline(memory.request_page, pages))
|
||
|
}
|
||
|
ptr := @inline(memory.request_page, 255)
|
||
|
remaining := pages - 0xFF
|
||
|
loop if remaining <= 0 break else {
|
||
|
if remaining < 0xFF {
|
||
|
memory.request_page(remaining)
|
||
|
} else {
|
||
|
memory.request_page(0xFF)
|
||
|
}
|
||
|
remaining -= 0xFF
|
||
|
}
|
||
|
return @bitcast(ptr)
|
||
|
}
|
||
|
|
||
|
clear := fn(color: Color): void {
|
||
|
cursor := ctx.buf
|
||
|
boundary := cursor + 512
|
||
|
loop if cursor == boundary break else {
|
||
|
*cursor = color
|
||
|
cursor += 1
|
||
|
}
|
||
|
boundary += 512 * 7
|
||
|
loop if cursor == boundary break else {
|
||
|
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
|
||
|
cursor += 512
|
||
|
}
|
||
|
boundary += copy_pixels - 4096
|
||
|
loop if cursor == boundary break else {
|
||
|
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
|
||
|
cursor += 4096
|
||
|
}
|
||
|
boundary += (ctx.partitions - 1) * copy_pixels
|
||
|
loop if cursor == boundary break else {
|
||
|
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
|
||
|
cursor += @sizeof([u8; copy_pixels])
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
sync := fn(): void {
|
||
|
if ctx.double_buffer {
|
||
|
bb := ctx.buf
|
||
|
fb := ctx.fb
|
||
|
boundary := bb + ctx.pixels
|
||
|
loop if bb == boundary break else {
|
||
|
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
|
||
|
bb += copy_pixels
|
||
|
fb += copy_pixels
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
width := fn(): int {
|
||
|
return ctx.width
|
||
|
}
|
||
|
|
||
|
height := fn(): int {
|
||
|
return ctx.height
|
||
|
}
|
||
|
|
||
|
screenidx := fn(x: int, y: int): int {
|
||
|
return x + ctx.width * y
|
||
|
}
|
||
|
|
||
|
put_pixel := fn(pos: IVec2, color: Color): void {
|
||
|
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
|
||
|
return
|
||
|
}
|
||
|
|
||
|
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
||
|
x := pos.x
|
||
|
y := pos.y
|
||
|
end := pos + tr
|
||
|
loop if x == end.x break else {
|
||
|
loop if y == end.y break else {
|
||
|
*(ctx.buf + @inline(screenidx, x, y)) = color
|
||
|
y += 1
|
||
|
}
|
||
|
x += 1
|
||
|
y = pos.y
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
||
|
x := pos.x
|
||
|
y := pos.y
|
||
|
end := pos + tr
|
||
|
loop if y == end.y break else {
|
||
|
*(ctx.buf + @inline(screenidx, x, y)) = color;
|
||
|
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
|
||
|
y += 1
|
||
|
}
|
||
|
y = pos.y
|
||
|
loop if x == end.x break else {
|
||
|
*(ctx.buf + @inline(screenidx, x, y)) = color;
|
||
|
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
|
||
|
x += 1
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
||
|
dx := p1.x - p0.x
|
||
|
dy := p1.y - p0.y
|
||
|
yi := 1
|
||
|
if dy < 0 {
|
||
|
yi = 0 - 1
|
||
|
dy = 0 - dy
|
||
|
}
|
||
|
D := 2 * dy - dx
|
||
|
y := p0.y
|
||
|
x := p0.x
|
||
|
loop if x == p1.x break else {
|
||
|
*(ctx.buf + @inline(screenidx, x, y)) = color
|
||
|
if D > 0 {
|
||
|
y += yi
|
||
|
D += 2 * (dy - dx)
|
||
|
} else {
|
||
|
D += 2 * dy
|
||
|
}
|
||
|
x += 1
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
||
|
dx := p1.x - p0.x
|
||
|
dy := p1.y - p0.y
|
||
|
xi := 1
|
||
|
if dy < 0 {
|
||
|
xi = 0 - 1
|
||
|
dx = 0 - dx
|
||
|
}
|
||
|
D := 2 * dx - dy
|
||
|
x := p0.x
|
||
|
y := p0.y
|
||
|
loop if y == p1.y break else {
|
||
|
*(ctx.buf + @inline(screenidx, x, y)) = color
|
||
|
if D > 0 {
|
||
|
x += xi
|
||
|
D += 2 * (dx - dy)
|
||
|
} else {
|
||
|
D += 2 * dx
|
||
|
}
|
||
|
y += 1
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
||
|
if @inline(math.abs, p1.y - p0.y) < @inline(math.abs, p1.x - p0.x) {
|
||
|
if p0.x > p1.x {
|
||
|
@inline(put_line_low, p1, p0, color)
|
||
|
} else {
|
||
|
@inline(put_line_low, p0, p1, color)
|
||
|
}
|
||
|
} else {
|
||
|
if p0.y > p1.y {
|
||
|
@inline(put_line_high, p1, p0, color)
|
||
|
} else {
|
||
|
@inline(put_line_high, p0, p1, color)
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
set_height := fn(new: int): void {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
set_width := fn(new: int): void {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
dimensions := fn(): IVec2 {
|
||
|
return .(ctx.width, ctx.height)
|
||
|
}
|
||
|
|
||
|
set_dimensions := fn(new: IVec2): void {
|
||
|
return
|
||
|
}
|