From 2a082d82837e7cb083d99a067f348ea5d1a10b44 Mon Sep 17 00:00:00 2001 From: koniifer Date: Tue, 15 Oct 2024 01:24:29 +0100 Subject: [PATCH] rudimentary render surfaces --- Cargo.lock | 10 +- sysdata/libraries/render/src/image.hb | 37 ++- sysdata/libraries/render/src/lib.hb | 45 +++- sysdata/libraries/render/src/software.hb | 236 +++++++++--------- sysdata/libraries/render/src/svga.hb | 78 ------ sysdata/libraries/stn/src/memory.hb | 2 +- .../render_example/src/examples/able.bmp | Bin 100534 -> 102454 bytes .../render_example/src/examples/amogus.hb | 16 +- .../render_example/src/examples/colors.hb | 6 +- .../render_example/src/examples/image.hb | 26 +- .../render_example/src/examples/lines.hb | 20 +- .../render_example/src/examples/random.hb | 7 +- .../render_example/src/examples/square.hb | 14 +- .../render_example/src/examples/surface.hb | 39 +++ .../render_example/src/examples/svga.hb | 8 - .../src/examples/tactical_screen.hb | 28 +-- sysdata/system_config.toml | 8 +- 17 files changed, 293 insertions(+), 287 deletions(-) delete mode 100644 sysdata/libraries/render/src/svga.hb create mode 100644 sysdata/programs/render_example/src/examples/surface.hb delete mode 100644 sysdata/programs/render_example/src/examples/svga.hb diff --git a/Cargo.lock b/Cargo.lock index 25cd7bfc..bc371f91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -350,12 +350,12 @@ checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "hbbytecode" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#c9b85f9004b7a5d4a4cad68bdf4eb2c1e75d811e" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#ea736d88244ce1d85999d7ce6387a63c655b7000" [[package]] name = "hblang" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#c9b85f9004b7a5d4a4cad68bdf4eb2c1e75d811e" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#ea736d88244ce1d85999d7ce6387a63c655b7000" dependencies = [ "hashbrown 0.15.0", "hbbytecode", @@ -367,7 +367,7 @@ dependencies = [ [[package]] name = "hbvm" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#c9b85f9004b7a5d4a4cad68bdf4eb2c1e75d811e" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#ea736d88244ce1d85999d7ce6387a63c655b7000" dependencies = [ "hbbytecode", ] @@ -985,9 +985,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" diff --git a/sysdata/libraries/render/src/image.hb b/sysdata/libraries/render/src/image.hb index ee43be28..1f55cbd6 100644 --- a/sysdata/libraries/render/src/image.hb +++ b/sysdata/libraries/render/src/image.hb @@ -1,11 +1,5 @@ -.{Color} := @use("./lib.hb"); -.{memory, log} := @use("../../stn/src/lib.hb") - -Image := struct { - buf: ^Color, - width: i32, - height: i32, -} +.{Color, Surface} := @use("./lib.hb"); +.{log} := @use("../../stn/src/lib.hb") BitmapFileHeader := packed struct { img_type: u16, @@ -38,14 +32,35 @@ BitmapColorHeader := packed struct { unused: u32, } -from_bmp := fn(bmp: ^u8): Image { +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(Image, idk) + return @as(Surface, idk) } info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader))) bmp += file_header.offset - return .(@bitcast(bmp), @bitcast(info_header.width), @bitcast(info_header.height)) + a := 0 + px := info_header.width * info_header.height + ptr := @as(^Color, @bitcast(bmp)) + tmp := @as(Color, idk) + row := 0 + + loop if row == info_header.height / 2 break else { + col := 0 + loop if col == info_header.width break else { + top_index := row * info_header.width + col + bottom_index := (info_header.height - 1 - row) * info_header.width + col + + tmp = *(ptr + top_index); + *(ptr + top_index) = *(ptr + bottom_index); + *(ptr + bottom_index) = tmp + + col += 1 + } + row += 1 + } + + return .(@bitcast(bmp), @intcast(info_header.width), @intcast(info_header.height)) } \ No newline at end of file diff --git a/sysdata/libraries/render/src/lib.hb b/sysdata/libraries/render/src/lib.hb index 556387c6..3bb56c3c 100644 --- a/sysdata/libraries/render/src/lib.hb +++ b/sysdata/libraries/render/src/lib.hb @@ -1,4 +1,4 @@ -svga := @use("svga.hb") +.{memory} := @use("../../stn/src/lib.hb") software := @use("software.hb") image := @use("image.hb") @@ -8,9 +8,36 @@ mode := software init := mode.init doublebuffer := mode.doublebuffer +Surface := struct { + buf: ^Color, + width: int, + height: int, +} + +new_surface := fn(width: int, height: int): Surface { + return .( + @inline(memory.alloc, Color, width * height * @bitcast(@sizeof(Color))), + width, + height, + ) +} + +surface_from_ptr := fn(ptr: ^Color, width: int, height: int): Surface { + return .( + ptr, + width, + height, + ) +} + +clone_surface := fn(surface: Surface): Surface { + new := new_surface(surface.width, surface.height) + @inline(memory.copy, Color, surface.buf, new.buf, @intcast(surface.width * surface.height)) + return new +} + // Colours Color := packed struct {b: u8, g: u8, r: u8, a: u8} -Image := image.Image white := Color.(255, 255, 255, 255) black := Color.(0, 0, 0, 255) gray := Color.(127, 127, 127, 255) @@ -34,17 +61,17 @@ put_rect := mode.put_rect put_filled_rect := mode.put_filled_rect put_line := mode.put_line clear := mode.clear -put_image := mode.put_image +put_surface := mode.put_surface // thanks peony for these three! put_trirect := mode.put_trirect put_vline := mode.put_vline put_hline := mode.put_hline // Display -width := mode.width -height := mode.height -dimensions := mode.dimensions -set_height := mode.set_height -set_width := mode.set_width -set_dimensions := mode.set_dimensions +// width := mode.width +// height := mode.height +// dimensions := mode.dimensions +// set_height := mode.set_height +// set_width := mode.set_width +// set_dimensions := mode.set_dimensions sync := mode.sync \ No newline at end of file diff --git a/sysdata/libraries/render/src/software.hb b/sysdata/libraries/render/src/software.hb index aa83562f..3dcbd09f 100644 --- a/sysdata/libraries/render/src/software.hb +++ b/sysdata/libraries/render/src/software.hb @@ -1,102 +1,109 @@ .{math, memory, dt} := @use("../../stn/src/lib.hb"); -.{Color, Image} := @use("lib.hb"); +.{Color, Surface, new_surface} := @use("lib.hb"); .{Vec2} := math -ctx := @as(Context, idk) +framebuffer := @as(^Color, idk) -Context := struct { - fb: ^Color, - bb: ^Color, - buf: ^Color, - width: int, - height: int, - pixels: int, - double_buffer: bool, -} +// init := fn(): void { +// width := dt.get(int, "framebuffer/fb0/width\0") +// height := dt.get(int, "framebuffer/fb0/height\0") +// pixels := width * height +// back_buffer := memory.alloc(Color, pixels * @bitcast(@sizeof(Color))) +// ctx = Context.{ +// fb: dt.get(^Color, "framebuffer/fb0/ptr\0"), +// bb: back_buffer, +// buf: back_buffer, +// width, +// height, +// pixels, +// double_buffer: true, +// } +// return +// } -init := fn(): void { +init := fn(double_buffer: bool): Surface { + framebuffer = dt.get(^Color, "framebuffer/fb0/ptr\0") width := dt.get(int, "framebuffer/fb0/width\0") height := dt.get(int, "framebuffer/fb0/height\0") - pixels := width * height - back_buffer := memory.alloc(Color, pixels * @bitcast(@sizeof(Color))) - ctx = Context.{ - fb: dt.get(^Color, "framebuffer/fb0/ptr\0"), - bb: back_buffer, - buf: back_buffer, - width, - height, - pixels, - double_buffer: true, - } - return -} - -doublebuffer := fn(enable: bool): void { - if enable { - ctx.buf = ctx.bb + if double_buffer { + return new_surface(width, height) } else { - ctx.buf = ctx.fb + return .(framebuffer, width, height) } - ctx.double_buffer = enable +} + +clear := fn(surface: Surface, color: Color): void { + return @inline(memory.set, Color, &color, surface.buf, @bitcast(surface.width * surface.height)) +} + +sync := fn(surface: Surface): void { + return @inline(memory.copy, Color, surface.buf, framebuffer, @bitcast(surface.width * surface.height)) +} + +screenidx := fn(surface: Surface, x: int, y: int): int { + return x + surface.width * y +} + +put_pixel := fn(surface: Surface, pos: Vec2(int), color: Color): void { + *(surface.buf + @inline(screenidx, surface, pos.x, pos.y)) = color return } -clear := fn(color: Color): void { - return @inline(memory.set, Color, &color, ctx.buf, @bitcast(ctx.pixels)) -} +// put_filled_rect := fn(surface: Surface, pos: Vec2(int), tr: Vec2(int), color: Color): void { +// start_idx := @inline(screenidx, surface, pos.x, pos.y) +// end_idx := @inline(screenidx, surface, pos.x, pos.y + tr.y) -sync := fn(): void { - return @inline(memory.copy, Color, ctx.buf, ctx.fb, @bitcast(ctx.pixels)) -} +// loop if start_idx >= end_idx break else { +// @inline(memory.set, Color, &color, surface.buf + start_idx, @bitcast(tr.x)) +// start_idx += surface.width +// } -width := fn(): int { - return ctx.width -} +// return +// } -height := fn(): int { - return ctx.height -} +put_filled_rect := fn(surface: Surface, pos: Vec2(int), tr: Vec2(int), color: Color): void { + top_start_idx := @inline(screenidx, surface, pos.x, pos.y) + bottom_start_idx := @inline(screenidx, surface, pos.x, pos.y + tr.y - 1) + rows_to_fill := tr.y / 2 + top_cursor := 0 + bottom_cursor := (tr.y - 1) * surface.width + i := 0 + loop if i == rows_to_fill break else { + @inline(memory.set, Color, &color, surface.buf + top_start_idx, @bitcast(tr.x)) + @inline(memory.set, Color, &color, surface.buf + bottom_start_idx, @bitcast(tr.x)) -screenidx := fn(x: int, y: int): int { - return x + ctx.width * y -} + top_start_idx += surface.width + bottom_start_idx -= surface.width + i += 1 + } -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 { - start_idx := @inline(screenidx, pos.x, pos.y) - end_idx := @inline(screenidx, pos.x, pos.y + tr.y) - - loop if start_idx >= end_idx break else { - @inline(memory.set, Color, &color, ctx.buf + start_idx, @bitcast(tr.x)) - start_idx += ctx.width + if tr.y % 2 != 0 { + middle_idx := @inline(screenidx, surface, pos.x, pos.y + rows_to_fill) + @inline(memory.set, Color, &color, surface.buf + middle_idx, @bitcast(tr.x)) } return } -put_rect := fn(pos: Vec2(int), tr: Vec2(int), color: Color): void { - start_idx := @inline(screenidx, pos.x, pos.y) - end_idx := @inline(screenidx, pos.x, pos.y + tr.y) - right_start_idx := @inline(screenidx, pos.x + tr.x, pos.y) +put_rect := fn(surface: Surface, pos: Vec2(int), tr: Vec2(int), color: Color): void { + start_idx := @inline(screenidx, surface, pos.x, pos.y) + end_idx := @inline(screenidx, surface, pos.x, pos.y + tr.y) + right_start_idx := @inline(screenidx, surface, pos.x + tr.x, pos.y) loop if start_idx > end_idx break else { - *(ctx.buf + start_idx) = color; - *(ctx.buf + right_start_idx) = color - start_idx += ctx.width - right_start_idx += ctx.width + *(surface.buf + start_idx) = color; + *(surface.buf + right_start_idx) = color + start_idx += surface.width + right_start_idx += surface.width } - @inline(memory.set, Color, &color, ctx.buf + @inline(screenidx, pos.x, pos.y), @bitcast(tr.x + 1)) - @inline(memory.set, Color, &color, ctx.buf + @inline(screenidx, pos.x, pos.y + tr.y), @bitcast(tr.x + 1)) + @inline(memory.set, Color, &color, surface.buf + @inline(screenidx, surface, pos.x, pos.y), @bitcast(tr.x + 1)) + @inline(memory.set, Color, &color, surface.buf + @inline(screenidx, surface, pos.x, pos.y + tr.y), @bitcast(tr.x + 1)) return } -put_line_low := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { +put_line_low := fn(surface: Surface, p0: Vec2(int), p1: Vec2(int), color: Color): void { dx := p1.x - p0.x dy := p1.y - p0.y yi := 1 @@ -108,7 +115,7 @@ put_line_low := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { y := p0.y x := p0.x loop if x == p1.x break else { - *(ctx.buf + @inline(screenidx, x, y)) = color + *(surface.buf + @inline(screenidx, surface, x, y)) = color if D > 0 { y += yi D += 2 * (dy - dx) @@ -120,7 +127,7 @@ put_line_low := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { return } -put_line_high := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { +put_line_high := fn(surface: Surface, p0: Vec2(int), p1: Vec2(int), color: Color): void { dx := p1.x - p0.x dy := p1.y - p0.y xi := 1 @@ -132,7 +139,7 @@ put_line_high := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { x := p0.x y := p0.y loop if y == p1.y break else { - *(ctx.buf + @inline(screenidx, x, y)) = color + *(surface.buf + @inline(screenidx, surface, x, y)) = color if D > 0 { x += xi D += 2 * (dx - dy) @@ -144,61 +151,64 @@ put_line_high := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { return } -put_line := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { +put_line := fn(surface: Surface, 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) + @inline(put_line_low, surface, p1, p0, color) } else { - @inline(put_line_low, p0, p1, color) + @inline(put_line_low, surface, p0, p1, color) } } else { if p0.y > p1.y { - @inline(put_line_high, p1, p0, color) + @inline(put_line_high, surface, p1, p0, color) } else { - @inline(put_line_high, p0, p1, color) + @inline(put_line_high, surface, p0, p1, color) } } return } -set_height := fn(new: int): void { - return -} +// put_surface := fn(surface: Surface, top: Surface, pos: Vec2(int)): void { +// start_idx := @inline(screenidx, surface, pos.x, pos.y) +// end_idx := @inline(screenidx, surface, pos.x, pos.y + top.height) +// cursor := top.width * top.height -set_width := fn(new: int): void { - return -} +// loop if start_idx >= end_idx break else { +// @inline(memory.copy, Color, top.buf + cursor, surface.buf + start_idx, @intcast(top.width)) +// start_idx += surface.width +// cursor -= top.width +// } +// return +// } -dimensions := fn(): Vec2(int) { - return .(ctx.width, ctx.height) -} +put_surface := fn(surface: Surface, top: Surface, pos: Vec2(int)): void { + top_start_idx := @inline(screenidx, surface, pos.x, pos.y) + bottom_start_idx := @inline(screenidx, surface, pos.x, pos.y + top.height - 1) + rows_to_copy := top.height / 2 + top_cursor := 0 + bottom_cursor := top.width * (top.height - 1) + i := 0 + loop if i == rows_to_copy break else { + @inline(memory.copy, Color, top.buf + top_cursor, surface.buf + top_start_idx, @intcast(top.width)) + @inline(memory.copy, Color, top.buf + bottom_cursor, surface.buf + bottom_start_idx, @intcast(top.width)) -set_dimensions := fn(new: Vec2(int)): void { - return -} - -put_image := fn(image: Image, pos: Vec2(int)): void { - // y := 0 - // loop if y == image.height break else { - // @inline(memory.copy, Color, image.buf + y * image.width, ctx.buf + @inline(screenidx, pos.x, pos.y + image.height - y), @intcast(image.width)) - // y += 1 - // } - // return - - start_idx := @inline(screenidx, pos.x, pos.y) - end_idx := @inline(screenidx, pos.x, pos.y + image.height) - cursor := image.width * image.height - - loop if start_idx >= end_idx break else { - @inline(memory.copy, Color, image.buf + cursor, ctx.buf + start_idx, @intcast(image.width)) - start_idx += ctx.width - cursor -= image.width + top_start_idx += surface.width + bottom_start_idx -= surface.width + top_cursor += top.width + bottom_cursor -= top.width + i += 1 } + + if top.height % 2 != 0 { + middle_idx := @inline(screenidx, surface, pos.x, pos.y + rows_to_copy) + @inline(memory.copy, Color, top.buf + top_cursor, surface.buf + middle_idx, @intcast(top.width)) + } + return } // peony-made -put_trirect := fn(pos: Vec2(int), size: Vec2(int), color0: Color, color1: Color): void { +put_trirect := fn(surface: Surface, pos: Vec2(int), size: Vec2(int), color0: Color, color1: Color): void { step := Vec2(int).(1, 1) if size.x < 0 { step.x = -1 @@ -211,8 +221,8 @@ put_trirect := fn(pos: Vec2(int), size: Vec2(int), color0: Color, color1: Color) target := pos + size loop if pos.x == target.x break else { - put_vline(pos.x, pos.y, target.y, color0) - @inline(put_vline, pos.x, pos.y, start_y, color1) + put_vline(surface, pos.x, pos.y, target.y, color0) + @inline(put_vline, surface, pos.x, pos.y, start_y, color1) pos += step } @@ -220,7 +230,7 @@ put_trirect := fn(pos: Vec2(int), size: Vec2(int), color0: Color, color1: Color) } // peony-made -put_vline := fn(x: int, y0: int, y1: int, color: Color): void { +put_vline := fn(surface: Surface, x: int, y0: int, y1: int, color: Color): void { if y1 < y0 { tmp := y0 y0 = y1 @@ -229,7 +239,7 @@ put_vline := fn(x: int, y0: int, y1: int, color: Color): void { y := y0 loop if y == y1 break else { - *(ctx.buf + @inline(screenidx, x, y)) = color + *(surface.buf + @inline(screenidx, surface, x, y)) = color y += 1 } @@ -237,7 +247,7 @@ put_vline := fn(x: int, y0: int, y1: int, color: Color): void { } // peony-made -put_hline := fn(y: int, x0: int, x1: int, color: Color): void { +put_hline := fn(surface: Surface, y: int, x0: int, x1: int, color: Color): void { if x1 < x0 { tmp := x0 x0 = x1 @@ -246,7 +256,7 @@ put_hline := fn(y: int, x0: int, x1: int, color: Color): void { x := x0 loop if x == x1 break else { - *(ctx.buf + @inline(screenidx, x, y)) = color + *(surface.buf + @inline(screenidx, surface, x, y)) = color x += 1 } diff --git a/sysdata/libraries/render/src/svga.hb b/sysdata/libraries/render/src/svga.hb deleted file mode 100644 index 033d7626..00000000 --- a/sysdata/libraries/render/src/svga.hb +++ /dev/null @@ -1,78 +0,0 @@ -.{Vec2} := @use("../../stn/src/lib.hb").math; -.{Image, Color} := @use("lib.hb") - -clear := fn(color: Color): void { - return -} - -width := fn(): int { - return 0 -} - -height := fn(): int { - return 0 -} - -dimensions := fn(): Vec2(int) { - return .(0, 0) -} - -put_pixel := fn(position: Vec2(int), color: Color): void { - return -} - -put_filled_rect := fn(pos: Vec2(int), tr: Vec2(int), color: Color): void { - return -} - -put_rect := fn(pos: Vec2(int), tr: Vec2(int), color: Color): void { - return -} - -put_line_low := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { - return -} -// do not use, use line() instead -put_line_high := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { - return -} - -put_line := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { - return -} - -set_height := fn(new: int): void { - return -} - -set_width := fn(new: int): void { - return -} - -set_dimensions := fn(new: Vec2(int)): void { - return -} - -sync := fn(): void { - return -} - -init := fn(): void { - return -} - -put_image := fn(img: Image, pos: Vec2(int)): void { - return -} - -put_trirect := fn(pos: Vec2(int), size: Vec2(int), color0: Color, color1: Color): void { - return -} - -put_vline := fn(x: int, y0: int, y1: int, color: Color): void { - return -} - -put_hline := fn(y: int, x0: int, x1: int, color: Color): void { - return -} \ No newline at end of file diff --git a/sysdata/libraries/stn/src/memory.hb b/sysdata/libraries/stn/src/memory.hb index 9167b327..9b89cbea 100644 --- a/sysdata/libraries/stn/src/memory.hb +++ b/sysdata/libraries/stn/src/memory.hb @@ -2,7 +2,7 @@ PAGE_SIZE := 4096 MAX_ALLOC := 0xFF alloc := fn($Expr: type, bytes: int): ^Expr { - pages := (1 + bytes) / PAGE_SIZE + pages := 1 + bytes / PAGE_SIZE if pages <= MAX_ALLOC { return @bitcast(@inline(request_page, pages)) } diff --git a/sysdata/programs/render_example/src/examples/able.bmp b/sysdata/programs/render_example/src/examples/able.bmp index 7de373dd62363316506fe61ed31f1084e3526180..059086b3f0c1c4a974acf8fb72b2cc073567c430 100644 GIT binary patch literal 102454 zcmeIb=T=+Ux-ELno7|uG3C;uD|NFGv_FAOfLP#KybB+#Rk})<8IAPxw4r*uQW5fB*G=X8iB}rN95f@&9tP z_mBVmzy2TY@vr~+@PqJw#QtJ45SxM648&$2HUqI4h|NH324XW1n}OI2#AYBi1F;#1 z%|L7hVlxn%f!GYhW*{~Lu^EWXKx_tLGZ34B*bKyGAT|TB8Hmk5YzAU85SxM648&$2 zHUqI4h|NH324XW1n}OI2#AYBi1F;$S%gw;=Z~l#6e*FV4U;TlHy>D^t*6%oX={KA_ z{~8yr{)U@(f5(%jZ}G>wzuZrc{h)soz+9KRNL2j+E_7FkhO_&Rn_ad$03DT>cBBOt#SMpfdeS}KyA+_W#@}}L#lC>{z z{m#Gf`uDH>3u52*EziKY%dgQwU79z&2WjQPTMyDJpY&tx32}A@sRgHzlDi*)oIMC+ z@8sAHf5rwRr>}=ExD=k`HU!cZpt5=e+UIY=kt3&Ym_y&%lnW2iW9`B?jQL^w+&9;;^~Wb#%KDCa`;Ok_QlWd@Sx`{?ml>n-oCfcTz>FJ zBL8{=qxd}gm}w`-I5IJlmyt~-Edel;2;KFt}>2N z*b;n5oDy%IOHN;hAn}@-cQ}mM&`LNxb+FkAVYOt!X3c@q+kmv}^{B7zLQ`=e>N2e; zOa1|Q?(dQ5nt~KpGQ7SfBxmiUyuC}T_8Gk|8$kDl?9P;u@CXz?H1~?^gpygksG>hK zb8Z-?bCy5Hg05HSSo+fRC=3CgX^)|Nc>BasNzv0-~cQ||b4Q||dgWe}^ zA^T%2e}C|GcZjuvCtqXz_E+@DUSRf;XK3nphPLI;u$gGMcoTX1`_rAn7>it6}f5lbG(MONp;n|Bn z(9`#h_QM-oy8Z^IF8+>nJAOvvf+xtSxrgNZTksd&LZJ8#Qp~sqf6;wpRrR20(K8%A z{hNtdJ$w2Lt2!6s-072e_bwJAh`zyOi)B_mqFr~8_S^a0;Ij_+Q;_MvK%kM|o zf%H8p`^@9_wqYNSQC~}b(ieV@5y{iXMwiN8$*g>cg1iot`X{5Fm|I@u#iiwWxV5Sf zcUBkSHn-=O|4reuh8c ze~|C_4h0;!?tdcP_CK&q{(&+%4W7U<`13EpU;GHZf`>>he2A>-9!zU{LS6ry^7AFy zI-g_aydG4{x{iYCGw@{}hBti|lG4`k+?H{4(*9j*Y+!%p7T#;SXdfRya?UAaRo+B< zXCKa-e~J}LJFsE(O8oru%joIu6l>y zYOov%<1HF@!#)29g%!t<-? zxx4$%Vd(ehvHbGK#;#1`y(0g}VGSWE;YXDCCt*>U3wvABaG)(6`?&3%m4fO}9DJ64 z8Qa1aTuz(w$^gFQcNrO4d=G(wD@e*Z4sTjF9Nren&Qji=d9-=cjqPELbHW<$L{Yi5Ly?y?{) zI1?Eqr>M(M5MPJP{SlzNPR&1xjN&uMtGb4q%4@{w0p3T`kYfE2ExA_gnVp6kD+}>7 z3g^8WOR=Lli1L&;*d~2P+cn9^uk?zC{Jrx1?}hD@E>augTVVn$_&u>+&8!QXlR@Tr#w z<*cT>NHaceNOHj7Zm693v-o>}-0b;CwNJt7X~}rJ@k882W3i98e9>KoduxkOpOuJw zzZ<#fwQzZ+!RDxhoj$hPRSch}7-=b0s4QwjNx?#R-6il@6S1Jgg|i(w=6jwB&rvvk zyr~q&7i7`yw8B00A4vG&ziDeW($1hiQ+yfztgYs;!)o0UI-1`&M9(ZPJx~Hw4gjS5h?a~SSS6{_%C|TL+bIq%^%|YG3DRIWqDXx zlY~s?kFfmsPvh%IZ%f{}Je&{8E4QbHe%AtnCp{M|zDU`4hcZ%flDfgzy!5l^Z-w_| z1NYl1v;%}?y-&8G$Jb1~osYyxKO)WNz`T|Q96x%9zR2G%0|zI;c+f`c#QW!nLm!PrKv~?%ro-J?XEI1E+zj6(n_y| z=fn6=5sXD_;gR%%j`t6}uisZoD}TWI`wTId1xMVE@FY$~NnSd79{zo8!IwY(fs&cG zd5?D>h593%bM!f|_TgtdgrBiNhsA^HU;-XcE=904maSx1-=?rlsQsq{BYaGsA$*=) zoP$I2GO%ujAB#%eI5aoIV05JKI6OBKMafgCV`cxXGjdL`%XIqB<~I!Z^CMwxtoJJ4 zZ{*?w_)_K};Pug7$Ts8p)yscdJ$&QN@5n1ZU~HX`bnh3Eed&xNC#B4Xo%T;#p$k3K zeJZyEnTEC@YIc)$@C2hmhl$LYb6p{2BSq;W>!NxUu4E?5|U<(rpi7 z*33q1@7{u!FQ5M{@uwWomR*c9q|Grgzff6pd~NLWITp-@O0H7J*TWS*6RvwnS`g&i?GOZz#6L z@>nsL4fR1J(+<7tKwN0D=F=;dk%;jaTH3 z96S3fWBFH@$7K$e_I9e`eT+SfcP_{Jdc`Fa-^um4aA02kgutKtlGQVU@WfB%98}Ub zIQzwZfAl1P|GcG$l!;N!G3MK^p9<49MikejVqEp~bn#tJ8rLTfN-RI)1Iho^hduo|?xritpq_SL^N6|q=zI20?K78`Sj-iG-l9{L4^ z69RwoQI=JwFjp}(?0?Zl{Zqel9QSXCaYRp2oynhsO0Q$ivZqkJ!(Z)B@x4owd9xOX zAJETVD!RlN>pb3n`G(u~rRQ96XAkqq&iFWV)uu2W^5uMwvDkf)*F0QTf~8d{Cids? zHSj+CdiYBt&&U^AZgg-e`9zsjkMQi}Uk`u}$%(9=*T=kkn4=^;8(>aT{+GB-;um~L z{H0OX`18(@k2(!*`o8OEZ}kp|2Z#Mt`K(cXtJ&{ACV#enM6mNYwhxHEj*1BW8o#_A z7$P47%<(C2oJ8K5>KFcMI`|z)l1tV-AA~RE*S!8#;;#^a%&lM4=LnVZ9?!iFYtnWk z#1|mwuwfg0U&UU8HDO3TsJJeQ9V=FMZ%ufs$HIr6lb;Y7k+{u!tSbH-#^-o3d1rMo z+DrY0BjEM7k>7P|&|H1V`%<5sT6og%!<^0nq|+x^xBaih$+|=Ct$4xj=kbBbK{y@c zS82Y#puH{Zc{48~A?Y~cZJkJ%5pAcokOVO9;y!<1|EL^xDc2G#3be z@r;cx`l9it_t)TkTs2g7i`StAc5=29lWAPk_m?sMUjP0FHnUbY`gf<5-WbTMD+cNELW1`g;@n3NZ=HvP$qr1*@Z;>#Vw3w_JF3E(^r*HB-sqn`&NL%54QXQ{uz4mX%_9wx8S-D{Zl5)CKnj%~$l?eUW|HCYhV)|JY4@Aa5FNKyt1B3V#>b zlR*64_w)9E`Q1H+!5#evV`Q{F|8SI&82P=RS;hO9K)nC8Dh)gj=gi zadbZ8uH*>hdM1$rnqaWBsXoQ}&}du8s1-*NI8VOzCvV!D9hhrZPPINF@5w#!ETs>@wr@V{*RbH-=CZ49b5X3L(RQ7~OO%rLgn=;N!N z!|k2H8jXH#=@5H3^4dSMmA~OkyU>rlBitTBe8NmvCR0w;WEwl}COP)vA8&0;!Aasx zJg6tM;lvLWPcND$`m9^r=n6dNc(%F1;70h7j62evLERiOdU|e=6VuWxMn($PLHiHn zKK~QR#AF6BDf!w~XvYd-c{laBc>aeMl%gOd+3=QC*AnJbecpTVV{@t4i|Pk$aV{wT z9^(8RIPojg@8nzkQ*CSqdt}JxHNT&n7JpW^ndjtCCuLthwl5L8|S0B*p!c{KJ1?TT?0ywils*HmU3{f5xW&2>x_^JdAx?r&gf9>wbyt`+N%k8*uwfvNxKqF>Wi=rF#_u?4J4rY)K5^dlpG+rWH9|DLb0 z?`M6V_|YzMUB&xX?bEUi&++^ljR&5&_}bKJhv!Z z_Z%INe+lm0@H>KN$+H{3btq=O)?>wJA{^E$o%!gYzr3F|W&!1*c>QH%(!XC<_eQ=? zbx#gkx`{=r_EpF0*x%{mwQsX|$wAr=WsTw91;*!P?Tl)*QVUM}xj81@QrVY4{zX#u zRd}7=p>8nj% zGJ=V(x}|-j+7s#EupRKo^m^KRCpFxd#yO6*FW1_qb%m*)^xx8CjF50jHB!Pg*VmF*b_tKJRTfB z_9*XCitfM>JZF50NIY*a#`^8Nh`krJjdve}&$pO$=2m0->6(8ne0}VDq>IJTmoFmU zd3nn!<{^GcI^yH25a-x{c>8LTXNz-eMx1LeF?pD_-)@wI3TS7AMyx^m znwX3JF6Bfzt5|#K`VmVQmt4@YYy9~8oc;=JKyeTii;mdo?JJ(K|ID|AKlNf3$1hZT zg|X&3^P9#KS2c2PIP5Ww5}(-0JcbRHpZ8}BgzW)E|eeoF<_9LnPALd)B{GN09GY|LzZkQK zM`NBBvkSba3RzK`nS}1fOjFCVkk_;-XhEiXDn}x6lkBF?%LB%S|I?U@{(j-Fz1U^) z$_uM2QCoe8JY@A)`ttQhBiTNxQBcp0a4zs6jQnF?vTx<@<*RpCO1@PFYsix`){)*emnS6-%oLP(#SU!zsl73k>fMc{WkP?GG$-b=2QHbK89-_hxG0o z%03IqQY_(I?HK%6;Y~J{uJc60o-nO*5)VQ=uUgimIN84{ezF@0aoMoDW}2RAsRbv$ zDh|a3R=-7Yu@$$~Is<**kpHW=vwDDvQ=z&R54i^8(Y*t_0oN|X*_LoDr0m;B{E5Gk zfN7a-TxY+uFC~-ox#1j|`Wy6f5x7+zEu1F~=Z-(u_upSv4DoHc$UU4vPED?N3S3iv zK>UwCz%ps7;iRa?Q0NPD#0TU6Wv+S{D<7;{fMx4m;AgJ4@-6(mWsQ+~cdEam=1jF6 zzSJdSmVK(pGPw)q7V@QL(Z9{)b_U|~m^e(BY%@L34$jRYKjrhs@x*HuSI^{X$t^w8 zk!$!^>d&GfUV(b38U7Sy>gU3s~XZ3-JKUaytUyylvt*0_mQ? zleM)WXn3UyN?oQeZ*7`*f>!pCbdxi!-dUgb9*{m37VopS(JkWtR7W0WP~Im_`pNW= z3^I2q&Tb0(tf_u?tn)gq*HQktSO>2@5joX2&3ZrI0tZI-h}P@KsbSxGQ)|Zh4rd|z zG>hXrHoMqga0?0crNo{U@o{-Z?im{}5?gj|AHZOcJBA)o(Jz z{D%v;#cHK!)}-y8B2*KPmVtWlufDSnlD=eph1jAI@fGyanE zF2WL*MLnBDeM{R<{zn9Rk*#wlF<4KG#<6F>6g201aJ4fJ&&d(}oU$+)6WSMNP_;-J z;;npc**En2B9D(y&Sp5La*YZ0<7ds5`k$(osrs^w$F3eL{*(i8FlM2e?AqD)&AMk3 z8Go|*4s*RVt&b7;jq0Nzp0jLNt%DFb{;_QmdmCFO#Z&ebQQs!f&c2>`k026$ z`ib?FlTj2Pw}m|fRB!QuI1FQPux=FhN%#~e??rb7UTzJK7yVm3*75MD3_riE04DyUP(ZX-l|A8nt}#y!a1Z2rWb%sMBkPf|QVy?0a8 zpKTm5)sM}62uT#FZ%}Y$h+7x6TT;m;w=Ll`+hr5Yh`H70YC9H9y{4bUcP1W z6vkSbN0xm97?f<3UqU(Q*n+8+Cd5riGcmNBq$G4y=HbHfO59vsiOb6huzseW94DLU zNt*7Mgye)tNU=^ux--1aN0#$@WOHOXR6q1RG92HN7w|8nlADr}_&s0CEo+R@SksZ8 zG#TiDTW;D!d!rZ1hENHAoXHyBf8Vj+yAqQP` z8CYE9Cojc|dBtwSkDAV!wnFcZ$g=+nY1V%t#qtl?w<_5tBbh|)goP^oDJh} zuq=$oN#XPEnsWLzW!N~2Yv7QJKP^plpp%iq&&qU7MSwlxtdnVrOiknO>VPe90)c$4 z!H~Mp%#qd=8PB~v_!^Cj*W}ENVf^LpHS3G1H|<3Ili$(8H9Mkzo8i2$H@k~H;l;fg zPd%Y}ktFhdPqep=5r5J4p>RmO?A*%hMc>8JhD2*K+zC$hma=jEm~3(sa#@3(1h>Bd z`OQbr*v+0hJFa8y&TE*r^9q)4Kf!x`KQ?dOj_q4EVArNj?B1{h`_?VO{&nrxxuON@ z7tF+xmTELjD@9R$HgW@YV*4k<;q$BZl3W7S9PK6!O`E}MvGW`~ye}NIKdkh>JeWE;g?4a0xjvng@%vy)Ig8Zdo2Dmp;-pEe6=wbF zXOBs%N7x$b_*%mqnY;Wc9&w%TiTWp=mDb}Mgg?$nQeXk&_T{uu#>eMStXgYTIFc5@ z!uqwTgLG{))<)Wo$V1{#^3Xy#IyraXyGJ@$Jx6qGh9AtvXsCY3z z*O5o?rR}l)A)X9}Co)cOUxSaGJHmcSzb_qcoy*vMI!fnmM9cn1n7zOEgVD18F`o;M z=KW7FXhdOk_Q5`b-KBdjVR!dhY-p`ueWiu|iwkYVsmxQyBWV2}u5lBOO|vqwp>YOk za_ivr%!b9W6jN+nm}+0cbKK5*We*4M8Od+vy2HF$#h${yS9J!-c{ezh_l<3nNE_Mf zpF@lczaHIK=K90eaJ?JGZMDvW;T{lw?c`qda?QDk`lmJWipaBy{w=}c3#N`m@$>P- zUi2AZ?vI7Br&d#A6eze${_`~?282Um%3Kd!Cvu*tlj0SRrtc9R@4Jcm z#&)imnS|`rS*XbGLRPSiG28g6$Db>!tib02*j#<$Pd8RO1cH`&g0MYVQ~9xqz;e8To) zQ*FG?Pj#Zvzg2t<^*7KuTI20yFMTcUV=%o9wR8KBKjQ&;kjLQiuZ6|d%D6Lg!EqIc zn_5a=w}c}Hag#ErV>u=TIZ_e#6SqHcJ1LzbizAzl(`irT!pe15lY@E4EU!bstVJkp zUXIeXwW#dahMLZOn6dT*>Nj0L)2=&c+4~4{h(&|XBQMYv!Kv_RFxp3)hDXajt`%6` zKpQg&3C`6>bghHM-p=!_;+jVPWUP|5oMY_(rUrbbkJuNI`&QZ^0p^7wbFBQE=1Bfs zkX)(A@lW3hdk+jx-NE&gU9O4&xw@3xgI``xO#fGF)lMJO+a>H%rRE(W?`4|#J>!Y} zY5o*b)!e3L%s_410b~|;5XaU0yh7%ZS(|EOpIS#2W3X9_(R2M@dnO;}Ql}QP#;J(7 zXB;r8kg@MP%HSMwZ_?pS3c=@3vF!D6B=H!BFBwTbACi&-@CP#xNY6%Ub`e7P z<;X0X$vU7W6x7W}VZ&k+&t8d&1zS+N@(^aOJB|9ymoaP06*O+YiKd-*P`BYMg1M!z zBo<(*@RiwT$`nOAlxtMoTFDLQGqM!TNzG_6& zhsSC6ASEN8BNv$!^^{X9Q9i#L6^nMFYUv?VFFlN^C5O2^it6PjP~CYNH7iaN9~@m8 zr?`KdGVL(8hcSKC5pECg^}CF$D{tROxwi&|jZ2U>eJ*p>EnGXWh8QX_SWHSL&(-UN z$K&DJZZ0!)%$E{EAWb+eL~2$c(hIAQRWS?Ml?~>6txj@woU{R4-Lwy6*J*4c?qt(R zpUP&9=-H8cDE8{2&b6j+eO20g(b&`c$v?1>Cn%0yu<+0KD%TpyW-U9eBOmq`!&p}@ z)V14Qj(IKYuW2K`{_WpTU6gw14#kx8gPZl1sv}4n2k%s$lg70_Y@7$X#ez^?8Or9Z zqdq*3=H2(uN_(vJP#^W7Y&Pme+G^TwJ0cw!8R28^U!&tZrq>$1NuNPJFKxD#eUH$* z>#mVu4O_3FZsU3C-;=Zr4-nfsiT6z?ncYPhxR7h-Hge6&X-H0GpHRw8x109}<8w|s z^&p3fJuRJf2NL6w8GB@2FfIocOF1monMialhQ-aij(ZCdT(m`LyT*GCBY{3`f|q>> zhtw{Mf2MkR^{^Q_w_*Gdn@0ZSn0|f3y=JV(jK4vrqgTJLq!^?E{*}zGYkY zy&5wnzUB*W-G5{1+lKqS>SZYYtm;?B8=n_%Q1)*iEsu8ADayRCtQrwZqxhyRd``aU zoP)h+JM=b?#- zzq=3Lus6-%xO4d26+d5Rj)p(5gM;@d7@Dt1%z%Vgse?Q>_@M@eBt#~-^aMZ_8;?yj7F8KOM&Yi{OtkjCFkD$-NnDl0%bIyNUj(-(0H*md3M{3~N99*kG&k%u}p9JJ#_G zUFTk)>-GN6LS21(_X;jnB%$wFqKc)iyP&)lKH+8kvE2n<7kpmTIGckd%9uWq)PF~&t>R-F5 z3mK|2$8vv%=b3%6nIq5|>B>0`XQx-TJi)Ou6LUQpah>NZ8_xfDXx4CZI_XCm-u?La zK^fJLP&#jqiIEi4FU0J9J;v@caW-B*`4O!HzJ%h$)QOTqQF>U|ldM}o?2KugCGLnh z;cfBZJ6O2yDi$%%w)E(ItUU7!D~R9d&k-h92$RHP$MGlB?NJzvI*;gc3h&F_?8l|a zorLYn#%(u@?^CmUABtN#8Jn!956<|Kjs6Vd%uYuU0vTP%D8FFtciq>CQy8Q7HBml( zS|3H_sI>Ngcvj&Y{rmV%1jEX!p1CwJ@z?w09U2x6=YJ4?%uCAt^N&;hi9c90`w@N6 zbBy8nSbNYyoz`Rg)P}8BF|F&UiKR^IQcUF#rmZ?k{dSQ)!oz`h@Epn=>C$MtjJCg$ z@=nh$+{;+r%Izp`n2W-inJB8QN7d{OgToc4NB+D{;;@5yTDIedcpJkpV`KK~a{kt^ zY`ns_(Lof{FGh$lMVFKPfb2e`X3jx+$tlw-JaI|_>udNt^JNjdjD7onF&x^Etnqa- zM-}St^*8kW^|Y@p-}r5;D)Fnn?);VCP}BNh4VL(5;s>ejQufQx-!$6eZ1!EBzP1;Q zjOQk&rX#JOg7G@`Zke-+@wGjXQ2*K4stX(~?;n zqsc!#&#{P{f?3PEQBXAlet%NfKd?ICOti!8u%o(l36>nWH|l3eKhNX$jvaq`?J%#8 zV9~^fh{gW6c79zuk^?EU6O+iNZ0GzgVT?Y(*x702pHPFu7(;T}D%0;bIc>GcvkiA$ zW-k%<;LTUX)mXo54{K6NS>rqOyw%g$8<=ZqKgR2uRWI*hyoEA@av+$)e1_A`90lVU z)&$tYZqAynEf~?mvJDKbv<=6Q zB7TdBC-pyX_9O4nR_`GW^;+cvm4gYS>;9`|oTrZbd-i8xPsLB+pDJhUa#fldBjr+t zUc<;^^)GuhLD$3Fy7y<+Mh$~M@`I9SGs|usZ@;U?or-@vMnm@%Bs0&D@Z1}j#r#i}*y(Al{Xvzu6>mCcxN;v^(||9`ojw*>_?^_a8yIF_I6 z9aau@o~F&V^(6J|EXt87>`7ffye+0qlDzI^?Bkh52 zpqJb}$IUwraQN_1tXRGbrTJOpn*LyLo0(sP=C%8XnP>EW2g^bE7!}P65lBfvT7Cm# z7^jFi`tnsTh`aunn|N@_MU%H0Ok-a(%GA;DCx54{AAgEjYA7yPy?igStGTvkVKq{i zTTV{PqHW7Mwm=Z6xn(A=QqvQdYJRtLVX(#f07HW z?HxFL_9|}OxsSW|AF&7GQ#|NZFGOz5P+zd;ctkwj=i|eNkDz^SD{|BPtO5A}q0DSF zt=eP!*l2sO#9Z8H3hIHb5ONcTArO0prq$6m^9w~hU7lYB@k zsxe%gnd{FC`2FwYDeYq7Ie#W|Wz4ClzGggi4UubPdh(E$WQ|K?d}2HC_o3gb*9w38 zxlZmx{aZg0{>c4P?kzcE{kZ3+dhtEx^o!Zo?|)ENKMQBhU&hT_cX8)_5AEP5xOC+v zPMtZA<0nqx_{r0_aPcZ`-hP1leD40EKK4iq%flVpx1*-42(E-5kxctdSnE9XWI%p( zp6Np;b+c@`vif;&bKL`nEy#FUE_pK37!PYB$8!xiA-idRR>3xPG778f>4)4M_>AFX zq2e*Kci*C|wuJU?GC6wRBiWgNhMCi`eCZObUcCw%H*CO;?K`k-+jgv7y&8+=w_|2? zIkJOEaK?SloJbr(^t+^=n|IwC(8tOH)~+~28<0F8#*D{nTSxFGKAh@@?aZ-{W*>=r zaQ4!~^nG@_Pt(tR#++aWP_YbUG*@bI2ZW;Z0 z``#m*K63$!7cRieno3lc7NVxS7;P<0*sy**PM{W| z)5({=Fc>@1$&^`*t9Bv3f@^>CHL0Og=E;)aVZ6g>Po{mIVX$eP%-XkLC>)C!LHtBv1|)#&%(vHhjsFIMn+sW z*Xt2ZP}T`+$P_XvAo`{5yN3E2gY4_;GMJS_TFwB=pwouu62Xuof`c?uOArml;JoxaDxgNJbA_C3nLJ6PGd9LWyW zA@Z777;mwV?_{xA$Z`6KJvjbhFgAbg9HWaP7`%1&AbVGRhubPnlM)QFt|$)6mUPfw zxJvnU3pZ}vF*5n`)f+fPS$*u-3EB{+d45-n43sS^`&BaW%C%cYHwS4W$_^2~Q1O@2 zIcq6b!||cfeAeOSHF8WjJk@omcY@YGiyR+rn@{e`L|*%C`T7?h@a_%%@=qB1FOZ|U z%kkZ#>UXWaueQnm!k#^Q>32NDnX?yAS6gMSMIz&YR>oni)P>em4!@sVChDsxtiKKV z%(ac+@AkbOUdx-bx7JZkPJ+uCXJRtL;pY7@`O42t9!|M9`OeEvJTi9Q@{>KI%D&~a zCCgd=;c-|{UYw5;r%n-jH+c>>aQ@O|Y~8vQbDA4aRZ@V`yeyO!WTS3c6;^k3;S6ny zJ3L?E&*kCh>d2xp~Qq;YTBL zTNC+j$y(NZ&_*3}{*>q9&$~QT{T%Kg&yVn1BcGvKE{BEdFjLNLSicUpDZ`E(KZ)|9 zT)4}iY zH#pC$WDZB$rqVW2 z&Q0sEj8?ZK-*?;oi5q*-eX+Xx#fSP=_~ZIA>QAEB*=Tby+;i%C<0Pj@w%wA&i*TFr z@9eotXsDY`yN`YDX@}V<|7?_fHu8{dp$z!4vXK$=)7Sk8-L&EFKIkf_YJcZ{_-oP8~iPpH^<;k*t>A)3Z_+*vPb_v zkdf*`c76_Ql-t%MFKvi;_8R$@k?l2Q#W;HO#K8R{44yoF7TFfX|gj1&(s_zyVPvn5eBAaimq##V9)i;xju9-TUNJL4J=KUntPRr=4u zpKL?ffCY@9w5&hKalrT+^R}Pu*R9Nx5K~6heIgze&nYBl!RtuC+}7qW{-}S?(*G!7 zT-?e2eMP0kNG&Sum)+U0F|KW8+%JLmhHc7sXs(~h^S#pVLp?FSWgTNQiXWykH$AI) zE4fM#AYqx*LjCn)(FZAze!)XoeXiksh zc@}w9iYaM-xDlBPaaXNVCNr0jZQ>Tf({;uG*RNfNbo#n($~h~sB-`9;n~JOyuer84 zA%B$ocubrBp0U5q6MwT?Sno~w<6)jxyjIl|DUY0*mX31f*6Qh7%-MX5T!ib84;vjT z9E{IMe z`tJl|Yq`0KX@5uVNG)yFwakaDBv)Y`>zk^HNk8o&i{ZLt7nP%?ojK)A$Ix;39{GJw z4F7a27*zhFrfoSn_EyFwi;UjALir~fw5zid!6XOViR_sX@WCEr9jU=!hOr^6tOd2u z=l9WX?pm>eK5;nS9=0LK?Wh0cnEE{$X4GKkzALD09XW0ijiu=QP|0P3J-aoC;3zfg zl`W4ae805_4u`A16d%%KIOOdnzFt6Vl{Y>@MgOR53h!$h*)MMhW3#A^Se(wad~>@Q zgH51pOTvbA>y7*i+vQJrJ?~)Oz5~W@>|C}Cn>KDVes4r($d6R)Prm2H%h$1b%{Kaw z3AD2&GrzVSx%E9LXzoE#>s@jU&k>JX5X@i1bLM&ntQk_RWqLswD%w_{Y12t8Jp7P+ z!Y5e9+=lWShI=}U{U?kzFh`f{b<<|^;mDDr2LFmVpFYd_y;pXW&07ZikXv^j@H1{2c`6@&dSxjN96pcs<>OxyB*+>|TLRE2ZaD5i{de^EDdgwX!ovOo_C&wA z@5ONqj~-;!_9A=6V`NXiPY&ij^68fHywwv(HoD8?!KymC(bRnrZTlav2IPsU4H4I6 z*~t&_xR4x$H0GQY|69Fs1+jD8$YJF<4jyC;GV^R+%0T7W+{B^s95&h$HeyS0@+R7U ziVy0yXxt!nCBs{rW*PfXa`o8pvsk`v{Ohx-CQMuk^^6%QE?Y~!bI&)l&YOwB4C%cg znJ-S6`X7jcn!)Q@T6b@p80Zg?&+GJzjz4;8P8~IokLr4Dq}C-kxRzsQ`sxs7i#CZvzC%PRMq=t zmd+qAfOW{MzieeLLUm25MH1gYbxIw?qxdgNj`yNydW(slR}(8oj~z4jg6sj^8^WM` z@pP_puDoz6<3?Gu?J5~BTrh7g4jnpb;?csM{H{p+a7J|n@5S#KFRY|2y@0Mw1G)FI1KspR((?DAgtlL_9{!jN zET44`d1d?IaTU;a{gLYlPGL^VkD{D(=7HNyPEN8xcD{0}!rakg$FXzgPAqJn$KF4z zw`JZ|JavzMHf_-{_F?F+xlN-T8Z6vFu62>I4{Zrk*xw+})c-c`zR#L~er|m~?_PDD z;-60M;=N~QT{`^@*`=pWp9#xA;wc>0>oMo6nDd#l7ilM6HTP3QmJ54#8N0lCBOJR{ z{w~en)q*997BXjYecbX-ac4LArgru!QE%O$*GqbL&eEq)FUN1`PwSH8)DG6ak>4hN z%b&51d3^R^;rf>u759wKAzN=K_JqqK`6$9@)boYY@0mEZaBQ6t2PZkuNsO6IqaD;S ze;$^0us<>5gbU}-MboSq16zn=RsMlIw2Yl(8yC!}bIj@gzADH@Hhc%74 z(Sw6@ukLxp(0aMH<+mpLgg>40nyth0umbc)rwyQi@7biYKA!1vTO93k$k(4e#c1PJ>+;s)m`f3qvXyv(YE!P z{#@#5P`{aVpi%l*7;M;fo%OscDgP}d@2kAF{D@?y1rQ%>eg6%_l^E`~M;}Woxnb@@Cu@DA3&c+qZbqsk-MhN$%BgZTg23xUcvCz{aq1;P@{n znEr7aOR+(-E(m3y)}&V72h*Q-#JI@ty7157QMz3@nMgkH(?3f+f+&yk=dy2$hjQJH z!dV^ct8rxjdl3vaZf8A6=YAA5En_Tax~Xk;IT(9ROrqW3qdk$poZ`Q@UW5ht?7&m`U{y^v(P;6D3+{d?~gTi4DPC$AAIt;nL1zPe7SC%dO_*@3t2O}0l4B@EV!4jmIDdr8^3kGcKXuqL`wvB!61Ra_Pqy zERBFkJzqv&J39Vja(_Ig&y(LRyJ-AayhAK)W6V0!a2rbIbkP=k?~e$BO}l#8pS1^t zE&Ti{$ujw7M`)KR-@-n?j1vTl&hfj$c#GU$AI{xa?-Q*7w2?A4MBU4}5`MP$>igI? z;LQZ>r#lv$jrN*fiNPbppt#!~pSOpG18I7-IasU4`_%Yn?Eg2~d&O5Mi;59Oup}G_ zTZ$nHlZ71l{qimHd3nO$Fz=224DlpP9(u@oBcCzSR^0YL))v|oe)=RitmQpFAOjn= z^`dNH4|4dK8N7dly#RH9lRCgU)nZ~);Xab1|Mro-d${BB|2@7&Q|IOzOd$A3ZO_ z?Wgfx_3@fG=of3<;rLxAXb2$F;wicM=EPX-h** z-EN#b|1)0y{tXBD#)ZD{i}h=j&z7IBHA2QD2gz5}ntBe}%vw8rq#BusZ7y7V3_qXa z`G{>PKS%k)(dD81d-W$(|5En!=K2VM?A?YFuKbN^FVuG+oEQ9rn92xxA)+soFH$cN zJNpZj6u02Q7P_)b~bz&Zq1vrmy;rG_D_T zVE&MPrOj;=j=WF3w?pdMs|D*htkE08R)vHUVpS&EyeGODVOB8M(n~* zvGYd5+|cI~s}c4`!iVuadH#y~Dz2hFw@F-M!}JPg{BxxD{psUI_8lZ=EfXu3Ey1&= zPyfVK`)j>bwe+Vi{)Sfej234rSgM@v$k$ML60J+2wHV~f4eFy`srXJf#*g|CDsH9Up}En1WQ_iP#`M`gGsT}n-b^{3KAqV83&x6>FY!A0C6{mf zj-_i^!_NAVkuWGssmH8hGe&n&Zl>0phd0PK;L0Y{8aCokD{nk925%WZI5dsDo9fxyBa7>)C9wApYqssQ zvEAj3aD?(I zerb%mhIQWPF~&2YG%=_@o+Qph}_8^){p1s2f@3e(TS#b&>@-ai*_YvHD8!26<;mj;22DwHm`%H|d z=0h??Lzog5+tddrwjEWYESyAM_i?#56eAx#)@Mn_3U3h~DH?0T?UxaMI*-Bl0# zF>kQp20~kDV{N6)P5hbdHm>{CyajewD)}U-T>D1-k;#W1!1B=RHu7WHio&6M7Wo;H zjl#>PeAY^4$DXu-M?Hd00d!;!(6Z*m*^Ny2u@6p@v zy291>;V<9GUQubVsNN_!1%ZzJ2yGz`KY}}9&&aFY6TLEqmx*YUZ)`1CnY zHIF%@SN`MCCZXv@71u%}}wtIok&!#Hmy>ojd{`o;++f0tTtnlexrR9xnX z8R;f=_-S|?38$ZOTsmBOek8mNJ+9Xd#Ju?%6q8pk1Jz$C)|ke;M>E%h{1)qoJ{N92 z*XNvM-D_%Y9uisW>nLE)isieJ!Zlbz+o*51gk_%5yOMvzUvNFwY@W|LhZOahoJ7uL z3b|b56uK)-?OhVrS@CCen;2p^4lF%Jp6q`ZizX&SJukmTzO9D*-=SlWzeC?%y~mTe zHje7K+?0QcZ_9t~;(9T$zdttvy-yx9PTYt@^$;kjLDHII2(Yg};7}h@ce5UNJ25Ez z+dqQaSzpJsb_1KPz>$&9^&G=>uF0%@_fjqhhbI53+B;q=Zwl9)VO?-);mQ7bFzV+4 zEPh@aZ(MRwF(Zy}41Mr6ybgNUj?nr(inVCH@!-3TfUp> z5S=a?oJCdettIvjKStn4AGc44!N*8poo(u#_alXUFj5Zm@U>i1ifaZty!G(qot0w+)tOMma&>8W{pn6M`5hn*ot3NCQ9!MXA#Ux2CH7- zy^SjVifo4P5O+)a+S2Y-jG0_!aU@-?a+70;tS?_bzYkCUCj8Pbg~*;q4^fcIo_KC2 zT+?PFiTLxg?^NK((=h&o!G0VHi)Qe#|G-0d7j1!+v6*7__iI}Ch&7?l%xGEMhpHy( zX!hmzrEfJ{cel5O*HChiJ=e%LRBf^^xXi3K6JF0WY%hlO^LS)pKeh(^ohYnDjuB6? z0kjT`)*MgC-OF{kb{m=O&)j10m7KnYycvzv14B6=@mh4wrk@1!%E}K#WbE<{&ttyt zp9JR9KCW}mUM`;LEEzy{Y&O79>8C~wGDGlnCq=|Vx_~JcIs`$u2qkxoNa(OFga!B z^Ub<&m0A-{GHMts@_0s7pLw0+n8AdpqhjvEVC@F6f5vbq)Pp3My)g8>;y0>KyY2&* zvyiempM&>=Baax%HJllz_PGXnc$;aCtCn0?jL1Emleipvk4)UPvi>A2zS`U0y?u+G z9`=Xaa~1BErLgC6tpNJIF0N1S+e98`L=Q({Px3H%`!zVL8ckk9r-+u9uu~d$}esdo>6@(u)R* z{aDj}dS##S1+<=|aODkf{ROV;qB<(!Lpf{7H$A5qv3lWn`5oSrb|Y`a4ICJfd8~s` z&6;ZSB?|}kc@E~7>{fCuLaZ~1z8A_G*h}U?Ea&mLfZBTX7us~JVOYT$n!<8e-7dIi zEux-fJ^v8w$v*ULJ_mbtA==n$s<-FSsHdU&s7u#>!@BLSP}lwp{$kpXrH`3&q3ohw z^i!{?W?R0qUHxV_)H77MWnnReHIpeh`wg#3YutH!^+tAu`_R}aPs_rxlQx^yr&N8t z`qv0IW-wkXo0=O4-dtWqGfTgG`vow?y=b4=b3>$k6t4veS4@E z-cHu@aGeD^Ya0FAt`390USlU}U52g|OY!mrgNI}IQ$57ZyT4=IwwI=Vi1-i5g*^xe zk0rD@^UotGjee%P9@d0Z_SE9qUvYNYi#!*`cf@VB#k=_&d)ks;su-LvxPts<)=nAy zE88!OEya4GN7&El$6W+}16%2MJr~(V_6O_!AamvZqK9bdc*?bC-wnw6G5qw{OFl9K zFW&rtoa4kF`->*;ya`v`JXk$0_*QZKN6A0=BN1Ipj3%w5ob-9IZR-~N_S^W@Y!nCL z&Vx7D%ew59?8h^A`7_L%_Y_qvPuUy4kLzQy-+akF<10Hnly&`mU4=KTWhK3+{tb$Y z2v3!(Xfj`B2Q~vKU*W9~t=Z&dXJi&bQ*~@RR zW$*8pz2pV?)DPK<@+MM>=)amedHTu59%TQeKM}VPo}x#nA7{dvhWrZ+VOD%e<;b`0 z`x%e>Vm9A6VKwHLZ@%{{(vODYeu@LybGYtpNv-jRJqtHc<{d!twkyW>_0mU9N^;@U ziDT45pWhBrf16wP-r@-T=#JGdQQFW)94Kz5I)Vs3xb4SFG?qr%7sev5R~{sbHL9v1 z(0Uf?laWVGWIpSsCFjZ-dMS?|Gp@una>$oFcIGvHc}>9``}<-uaOc%q%(?s$Db%y_ zeI13B%!#mnnLhv<*A%y9vOjoj3%rZT{hLMZGuJ@6c>dfMJ0E?ppnaeG2=!3W`io7A z`q+z9>ke}58Rj2~h!x>R9KB59N&JNfXDhvbUt2vVj1|}QQrGuU=RZaJif35R^$d$w zbIn73w$>M2OWSnIo}Y2(#4oI!d5!Co%UTolT?~3(^g8Rq-|=D}ef%4;kM$v`>mY1g zXV5bBNAh7(U?=v3!$hae_$H35JmjPYaO>ucFMeM70&%z1GxWxt-*M*BYs$r6vHQp? zgOycW7q4UWbIhY{*0$^^TG`io_LA^u?cd7ARJ>Sys8ok=hdmVUK74DiEk14!Kl|zP zcX-ZxhGg#_vkQ!prqIq>qypZ-=vzYsGQxDr@3Y z6tgeB@+bd^KcPeQeZq=xBMjZ8Pov(Px9)v7jtF~jr>Ez8Tq^JlSo*NJ;Izr8bi_s2UNI=GMhq*(L8 zb!a@R4#Ug!HarI(BS^cj`a}=cC0}Fu)|TaG;?>VDzr7zBJL3sE1Aj0$ckc8_RF`nw zm%5o~JAEIs7?;uLy!i@eAOC{G#HacvPp>G(>tAEF4-@ucexoP$`q$UEcjp!!KDbYQ z$G`E4w*N02GRYNddBo!@mMp}c9b0Lq#~j0N^fG_br)^?>F;o7VzJ{@rkIg`A24XW1 zn}OI2#AYBi1F;#1%|L7hVlxn%f!GYhW*{~Lu^EWXKx_tLGZ34B*bKyGAT|TB8Hmk5 nYzAU85SxM648&$2HUqI4h|NH324XW1n}OI2#Ae{znSuWw<~qWO literal 100534 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 height break else { - render.put_line(p0, p1, .(255, 180, 100, 255)) - render.put_line(.(width, height) - p0, .(width, height) - p1, .(255, 180, 100, 255)) - p0.y += height >> 6 - p1.x += width >> 6 + p1 := Vec2(int).(0, screen.height) + loop if p0.y >= screen.height break else { + render.put_line(screen, p0, p1, .(255, 180, 100, 255)) + render.put_line(screen, .(screen.width, screen.height) - p0, .(screen.width, screen.height) - p1, .(255, 180, 100, 255)) + p0.y += screen.height >> 6 + p1.x += screen.width >> 6 } - render.sync() + render.sync(screen) return } \ No newline at end of file diff --git a/sysdata/programs/render_example/src/examples/random.hb b/sysdata/programs/render_example/src/examples/random.hb index 7c68c5e1..fed2790d 100644 --- a/sysdata/programs/render_example/src/examples/random.hb +++ b/sysdata/programs/render_example/src/examples/random.hb @@ -2,16 +2,15 @@ render := @use("../../../../libraries/render/src/lib.hb") example := fn(): void { - render.init() - render.doublebuffer(false) - render.clear(render.black) + screen := render.init(false) + render.clear(screen, render.black) loop { x := random.range(int, 0, 1024) y := random.range(int, 0, 768) r := random.range(int, 0, 255) g := random.range(int, 0, 75) b := random.range(int, 0, 155) - render.put_pixel(.(x, y), .(b, g, r, 255)) + render.put_pixel(screen, .(x, y), .(b, g, r, 255)) } return } \ No newline at end of file diff --git a/sysdata/programs/render_example/src/examples/square.hb b/sysdata/programs/render_example/src/examples/square.hb index 46ee8109..09f71e09 100644 --- a/sysdata/programs/render_example/src/examples/square.hb +++ b/sysdata/programs/render_example/src/examples/square.hb @@ -6,22 +6,20 @@ render := @use("../../../../libraries/render/src/lib.hb") a square that changes colour bounces around the screen */ example := fn(): void { - render.init() + screen := render.init(true) vel := Vec2(int).(1, 1) pos := Vec2(int).(100, 100) - width := render.width() - height := render.height() color := @as(render.Color, @intcast(random.range(int, 0, 0xFFFFFF))) loop { - render.put_filled_rect(pos, .(100, 100), color) - render.sync() - render.clear(render.black) + render.put_filled_rect(screen, pos, .(100, 100), color) + render.sync(screen) + render.clear(screen, render.black) - if pos.x == 0 | pos.x == width - 100 { + if pos.x == 0 | pos.x == screen.width - 100 { vel.x = -vel.x color = @as(render.Color, @intcast(random.range(int, 0, 0xFFFFFF))) } - if pos.y == 0 | pos.y == height - 100 { + if pos.y == 0 | pos.y == screen.height - 100 { vel.y = -vel.y color = @as(render.Color, @intcast(random.range(int, 0, 0xFFFFFF))) } diff --git a/sysdata/programs/render_example/src/examples/surface.hb b/sysdata/programs/render_example/src/examples/surface.hb new file mode 100644 index 00000000..95fbd514 --- /dev/null +++ b/sysdata/programs/render_example/src/examples/surface.hb @@ -0,0 +1,39 @@ +.{Vec2} := @use("../../../../libraries/stn/src/lib.hb").math +render := @use("../../../../libraries/render/src/lib.hb") + +/* expected result: + the lines example bounces around the screen */ + +example := fn(): void { + screen := render.init(true) + + image := render.new_surface(341, 256) + + p0 := Vec2(int).(0, 0) + p1 := Vec2(int).(0, image.height) + render.clear(image, .(100, 50, 0, 255)) + loop if p0.y >= image.height break else { + render.put_line(image, p0, p1, .(255, 180, 100, 255)) + render.put_line(image, .(image.width, image.height) - p0, .(image.width, image.height) - p1, .(255, 180, 100, 255)) + p0.y += image.height >> 6 + p1.x += image.width >> 6 + } + + vel := Vec2(int).(1, 1) + pos := Vec2(int).(100, 100) + loop { + render.put_surface(screen, image, pos) + render.sync(screen) + render.clear(screen, render.black) + + if pos.x == 0 | pos.x == screen.width - image.width { + vel.x = -vel.x + } + if pos.y == 0 | pos.y == screen.height - image.height { + vel.y = -vel.y + } + + pos += vel + } + return +} \ No newline at end of file diff --git a/sysdata/programs/render_example/src/examples/svga.hb b/sysdata/programs/render_example/src/examples/svga.hb deleted file mode 100644 index 101aa6fb..00000000 --- a/sysdata/programs/render_example/src/examples/svga.hb +++ /dev/null @@ -1,8 +0,0 @@ -render := @use("../../../../libraries/render/src/lib.hb") - -render.mode = render.svga - -example := fn(): void { - render.init() - return -} \ No newline at end of file diff --git a/sysdata/programs/render_example/src/examples/tactical_screen.hb b/sysdata/programs/render_example/src/examples/tactical_screen.hb index 4f227de2..5b2e909e 100644 --- a/sysdata/programs/render_example/src/examples/tactical_screen.hb +++ b/sysdata/programs/render_example/src/examples/tactical_screen.hb @@ -7,10 +7,10 @@ Vec2 := math.Vec2 with a "target" randomly apperaing in one of them and a "seeker" "catching" it*/ example := fn(): void { - render.init() + screen := render.init(true) - width := render.width() - height := render.height() + width := screen.width + height := screen.height cell_size := 0 range := Vec2(int).(0, 0) if width > height { @@ -33,32 +33,32 @@ example := fn(): void { seeker := Vec2(int).(random.range(int, 0, range.x), random.range(int, 0, range.y)) loop { - render.clear(render.black) + render.clear(screen, render.black) target_pixel_coord := target * .(cell_size, cell_size) + .(scroll, scroll) - render.put_trirect(target_pixel_coord, .(cell_size, cell_size), render.red, render.light_red) + render.put_trirect(screen, target_pixel_coord, .(cell_size, cell_size), render.red, render.light_red) - render.put_hline(target_pixel_coord.y + halfcell, target_pixel_coord.x - octcell, target_pixel_coord.x - sevenoctcell, render.light_red) - render.put_hline(target_pixel_coord.y + halfcell, target_pixel_coord.x + cell_size + octcell, target_pixel_coord.x + cell_size + sevenoctcell, render.light_red) - render.put_vline(target_pixel_coord.x + halfcell, target_pixel_coord.y - octcell, target_pixel_coord.y - sevenoctcell, render.light_red) - render.put_vline(target_pixel_coord.x + halfcell, target_pixel_coord.y + cell_size + octcell, target_pixel_coord.y + cell_size + sevenoctcell, render.light_red) + render.put_hline(screen, target_pixel_coord.y + halfcell, target_pixel_coord.x - octcell, target_pixel_coord.x - sevenoctcell, render.light_red) + render.put_hline(screen, target_pixel_coord.y + halfcell, target_pixel_coord.x + cell_size + octcell, target_pixel_coord.x + cell_size + sevenoctcell, render.light_red) + render.put_vline(screen, target_pixel_coord.x + halfcell, target_pixel_coord.y - octcell, target_pixel_coord.y - sevenoctcell, render.light_red) + render.put_vline(screen, target_pixel_coord.x + halfcell, target_pixel_coord.y + cell_size + octcell, target_pixel_coord.y + cell_size + sevenoctcell, render.light_red) x := scroll loop if x > width break else { - render.put_vline(x, 0, height, .(0, 127, 0, 127)) + render.put_vline(screen, x, 0, height, .(0, 127, 0, 127)) x += cell_size } y := scroll loop if y > height break else { - render.put_hline(y, 0, width, .(0, 127, 0, 127)) + render.put_hline(screen, y, 0, width, .(0, 127, 0, 127)) y += cell_size } - render.put_hline(seeker.y * cell_size + halfcell + scroll, 0, width, render.light_green) - render.put_vline(seeker.x * cell_size + halfcell + scroll, 0, height, render.light_green) + render.put_hline(screen, seeker.y * cell_size + halfcell + scroll, 0, width, render.light_green) + render.put_vline(screen, seeker.x * cell_size + halfcell + scroll, 0, height, render.light_green) - render.sync() + render.sync(screen) if seeker.x < target.x { seeker.x += 1 diff --git a/sysdata/system_config.toml b/sysdata/system_config.toml index 1792d684..e5deef95 100644 --- a/sysdata/system_config.toml +++ b/sysdata/system_config.toml @@ -37,11 +37,11 @@ path = "boot:///render_example.hbf" # [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"