.{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 }