.{math, memory} := @use("../../stn/src/lib.hb"); .{dt_get} := @use("../../dt_api/src/lib.hb"); .{Image} := @use("lib.hb"); .{Vec2} := math 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) // might not work for some resolutions, but needs to be comptime because... copy_pixels := 0xC000 >> 2 ctx := @as(Context, idk) // some of these are redudant holdovers from fb_driver // will keep them for future work if necessary 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 := dt_get("framebuffer/fb0/width\0") height := dt_get("framebuffer/fb0/height\0") pixels := width * height bytes := pixels << 2 partitions := pixels / copy_pixels pages := 1 + bytes >> 12 back_buffer := create_back_buffer(pages) ctx = Context.{ fb: dt_get("framebuffer/fb0/ptr\0"), 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: Vec2(int), color: Color): void { *(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color return } put_filled_rect := fn(pos: Vec2(int), tr: Vec2(int), 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: Vec2(int), tr: Vec2(int), 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: Vec2(int), p1: Vec2(int), color: Color): void { dx := p1.x - p0.x dy := p1.y - p0.y yi := 1 if dy < 0 { yi = -1 dy = -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: Vec2(int), p1: Vec2(int), color: Color): void { dx := p1.x - p0.x dy := p1.y - p0.y xi := 1 if dy < 0 { xi = -1 dx = -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: Vec2(int), p1: Vec2(int), color: Color): void { if math.abs(int, p1.y - p0.y) < math.abs(int, 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(): Vec2(int) { return .(ctx.width, ctx.height) } set_dimensions := fn(new: Vec2(int)): void { return } put_img := fn(img: Image, pos: Vec2(int)): void { return }