From 1f8e6e98b924ee4661be2e7b75cf09a6a8bb7cd3 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Sun, 14 Apr 2024 18:38:10 +0100 Subject: change brush size and colour --- .gitignore | 1 + client/main.ha | 29 ++++++++++++++++++++--------- client/paintui/paintui.ha | 39 +++++++++++++++++++++++++++++++++++++-- drawing/drawing.ha | 27 +++++++++++++++++++++++++-- drawing/op.ha | 28 +++++++++++++++++++--------- server/main.ha | 4 ++-- todo | 3 ++- 7 files changed, 106 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 218cb60..5321b16 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.ppm +e/* diff --git a/client/main.ha b/client/main.ha index 2a341c4..04e6854 100644 --- a/client/main.ha +++ b/client/main.ha @@ -47,8 +47,6 @@ export fn main() void = { case let err: net::error => fmt::fatal("couldn't connect to server:",net::strerror(err)); }; - - const pollfd: [1]poll::pollfd = [ poll::pollfd { fd = conn, events=poll::event::POLLIN, revents = 0 @@ -56,7 +54,7 @@ export fn main() void = { const packet_reader = packet_reader::new(); // paintui state - let pstate = paintui::state { ... }; + let pstate = paintui::state { size_idx = 4, ... }; let camera_pos: pos = (25, 50); let quit = false; @@ -65,10 +63,14 @@ export fn main() void = { let requested_chunks: []pos = []; - // in WORLD coords + // in SCREEN coords let mouse_pos: pos = (0,0); let mouse_down = false; request_visible_chunks(pictures, conn, camera_pos, &requested_chunks); + + + const win_pic = picture_from_surface(wsurf, (9,9)); + for (!quit) { const did_move = do_movement(&camera_pos); @@ -86,20 +88,27 @@ export fn main() void = { case sdl2::SDL_EventType::QUIT => quit = true; case sdl2::SDL_EventType::KEYDOWN => const keysym = ev.key.keysym.sym; - if (keysym == sdl2::SDL_Keycode::ESCAPE) quit = true; + if (keysym == sdl2::SDL_Keycode::ESCAPE) quit = true + else if (sdl2::SDL_Keycode::ZERO <= keysym + && keysym <= sdl2::SDL_Keycode::NINE) + paintui::key(&pstate, keysym - sdl2::SDL_Keycode::ZERO); case sdl2::SDL_EventType::MOUSEBUTTONDOWN, sdl2::SDL_EventType::MOUSEBUTTONUP => const edata = ev.button; - mouse_pos = (edata.x + camera_pos.0, edata.y + camera_pos.1); + mouse_pos = (edata.x, edata.y); if (edata.button == 1) mouse_down = (edata.state == 1); case sdl2::SDL_EventType::MOUSEMOTION => const edata = ev.motion; - mouse_pos = (edata.x + camera_pos.0, edata.y + camera_pos.1); + mouse_pos = (edata.x, edata.y); + case sdl2::SDL_EventType::MOUSEWHEEL => + const edata = ev.wheel; + paintui::mousewheel(&pstate, edata.y); case => void; }; - match (paintui::tick(&pstate, mouse_pos, mouse_down)) { + const mouse_pos_world = (mouse_pos.0 + camera_pos.0, mouse_pos.1 + camera_pos.1); + match (paintui::tick(&pstate, mouse_pos_world, mouse_down)) { case void => yield; case let op: drawing::op => drawing::perform(pictures, op); @@ -140,7 +149,8 @@ export fn main() void = { }; }; - drawing::clear_picture(&picture_from_surface(wsurf,(9,9)), 0xff0000); + + drawing::clear_picture(&win_pic, 0xff0000); for (let i = 0z; i < len(pictures); i += 1) { const psurf = picture_surfaces[i]; @@ -148,6 +158,7 @@ export fn main() void = { render_picture(pic, psurf, wsurf, camera_pos); }; + drawing::circle_hollow(&win_pic, mouse_pos, paintui::sizes[pstate.size_idx]: i32, pstate.color); sdl2::SDL_UpdateWindowSurface(win)!; n += 1; diff --git a/client/paintui/paintui.ha b/client/paintui/paintui.ha index ce55bb7..212e16b 100644 --- a/client/paintui/paintui.ha +++ b/client/paintui/paintui.ha @@ -10,12 +10,31 @@ use drawing; use drawing::{pos}; +export const sizes: [_]u8 = [ + 1, 2, 4, 8, 16, 32, 48, 64, 80, 96, 112, 128 +]; + +const colors: [_]u32 = [ + 0xffffff, // white + 0xff4040, // red + 0xff8000, // orange + 0xc0c040, // yellow + 0x00c000, // green + 0x00c0c0, // teal + 0x4040ff, // blue + 0xc000c0, // purple + 0x808080, // grey + 0x000000, // black +]; + export type state = struct { // last known mouse position, in world coordinates last_mouse_pos: pos, // last known mouse pressed-ness - last_mouse_pressed: bool + last_mouse_pressed: bool, + size_idx: size, + color: u32 }; export fn tick( @@ -32,7 +51,23 @@ export fn tick( && (mouse_pos.0 != pstate.last_mouse_pos.0 || mouse_pos.1 != pstate.last_mouse_pos.1 || (!pstate.last_mouse_pressed))) - mouse_pos: drawing::op_circle + drawing::op_circle { + pos = mouse_pos, + radius = sizes[pstate.size_idx], + color = pstate.color, + } else void; }; +export fn mousewheel(pstate: *state, amt: i32) void = { + if (amt < 0 && pstate.size_idx > 0) + pstate.size_idx -= 1 + else if (amt > 0 && pstate.size_idx < len(sizes) - 1) + pstate.size_idx += 1; +}; + +export fn key(pstate: *state, key: uint) void = { + assert(key <= 9, "what what what what what"); + pstate.color = colors[key]; +}; + diff --git a/drawing/drawing.ha b/drawing/drawing.ha index fc59e1b..54a877b 100644 --- a/drawing/drawing.ha +++ b/drawing/drawing.ha @@ -77,15 +77,38 @@ export fn circle(picture: *picture, c: pos, r: i32, color: u32) void = { }; }; +export fn circle_hollow(picture: *picture, c: pos, r: i32, color: u32) void = { + const (cx,cy) = c; + const ymin = max(0, cy-r); + const ymax = min(picture.h:i32-1, cy+r); + const xmin = max(0, cx-r); + const xmax = min(picture.w:i32-1, cx+r); + + const r2l = r*r - r; + const r2u = r*r + r; + + for (let y = ymin; y<=ymax; y+=1) { + const yd = y-cy; + for (let x = xmin; x<=xmax; x+=1) { + const xd = x-cx; + const v = yd*yd + xd*xd; + if (r2l <= v && v <= r2u) { + pic_set(picture, (x,y), color); + }; + }; + }; +}; export fn perform(pictures: []picture, op: op) void = { match (op) { case op_other => abort("oopsy"); case let o: op_circle => - const x = o.0, y=o.1; + const x = o.pos.0, y=o.pos.1; + const r = o.radius; + const c = o.color & 0xffffff; for (const pic &.. pictures) { let pos_within_pic = (x - pic.world_pos.0, y - pic.world_pos.1): pos; - circle(pic, pos_within_pic, 20, 0xff0088); + circle(pic, pos_within_pic, r: i32, c); }; }; }; diff --git a/drawing/op.ha b/drawing/op.ha index acbca29..532fd75 100644 --- a/drawing/op.ha +++ b/drawing/op.ha @@ -1,25 +1,35 @@ use io; use endian; -export type op_circle = pos; +export type op_circle = struct { + pos: pos, + radius: u8, + color: u32 +}; export type op_other = void; export type op = (op_circle| op_other); +def SER_LEN: size = 13; + // return value must be freed... for now. ehh export fn ser_op(op: op) []u8 = { const opc = op as op_circle; - let buf: []u8 = alloc([0...],8); - endian::leputu32(buf[0..4], opc.0: u32); - endian::leputu32(buf[4..8], opc.1: u32); + let buf: []u8 = alloc([0...],SER_LEN); + endian::leputu32(buf[0..4], opc.pos.0: u32); + endian::leputu32(buf[4..8], opc.pos.1: u32); + endian::leputu32(buf[8..12], opc.color: u32); + buf[12] = opc.radius; return buf; }; export fn deser_op(bytes: []u8) op = { - assert(len(bytes) == 8, "wrong length somehow"); - return ( - endian::legetu32(bytes[0..4]): i32, - endian::legetu32(bytes[4..8]): i32, - ) : op_circle; + assert(len(bytes) == SER_LEN, "wrong length somehow"); + return op_circle { + pos = (endian::legetu32(bytes[0..4]): i32, + endian::legetu32(bytes[4..8]): i32), + color = endian::legetu32(bytes[8..12]), + radius = bytes[12], + }; }; diff --git a/server/main.ha b/server/main.ha index 31cb6dc..71bb71b 100644 --- a/server/main.ha +++ b/server/main.ha @@ -195,8 +195,8 @@ fn handle_packet( match (packet) { case let op: packet_reader::packet_drawop => const opc = op as drawing::op_circle; - fmt::printfln("#{}: drawop ({:+6},{:+6})", - conn_idx,opc.0,opc.1)!; + fmt::printfln("#{}: drawop ({:+6},{:+6}) r{}", + conn_idx,opc.pos.0,opc.pos.1, opc.radius)!; drawing::perform(state.pictures, opc); for (let other_idx = 0z; other_idx < len(state.connections); diff --git a/todo b/todo index 8b13789..111b85b 100644 --- a/todo +++ b/todo @@ -1 +1,2 @@ - +smooth brush strokes +rle compression -- cgit v1.2.3