use fmt; use net; use sdl2; use drawing::{picture,pos,CHUNKSIZE}; use drawing; use packet_reader; type picture_mgr = struct { pictures: []picture_c, requests: []pos, }; type picture_c = struct { picture, surface: *sdl2::SDL_Surface, }; fn is_picture_visible(camera_pos: pos, pic_pos: pos) bool = { const s_min: pos = camera_pos; const s_max: pos = (camera_pos.0 + WIN_W, camera_pos.1 + WIN_H); const p_min: pos = pic_pos; const p_max: pos = (pic_pos.0 + CHUNKSIZE: i32, pic_pos.1 + CHUNKSIZE: i32); return (s_min.0 <= p_max.0 && s_max.0 >= p_min.0) && (s_min.1 <= p_max.1 && s_max.1 >= p_min.1); }; fn find_picture_by_pos(pmgr: *picture_mgr, world_pos: pos) nullable *picture = { for (const pic &.. pmgr.pictures) { if (pic.world_pos.0 == world_pos.0 && pic.world_pos.1 == world_pos.1) { return pic; }; }; return null; }; // called when a new chunkdata packet comes in fn enact_chunkdata(pmgr: *picture_mgr, packet: packet_reader::packet_sendchunk, camera_pos: pos, ) void = { assert(packet.world_pos.0 % CHUNKSIZE == 0 && packet.world_pos.1 % CHUNKSIZE == 0, "bad chunk world pos"); assert(len(packet.chunk_data) == CHUNKSIZE*CHUNKSIZE, "bad chunk data size"); const surf = sdl2::SDL_CreateRGBSurface(0, CHUNKSIZE, CHUNKSIZE, 32, 0xff0000, 0xff00, 0xff, 0)!; append(pmgr.pictures, picture_c { w = CHUNKSIZE, h = CHUNKSIZE, d = (surf.pixels as *opaque: *[*]u32), world_pos = packet.world_pos, surface = surf, }); const p = &pmgr.pictures[len(pmgr.pictures)-1]; p.d[..p.w*p.h] = packet.chunk_data[..]; // delete extant request for (let i = 0z; i < len(pmgr.requests); i += 1) { const rc = pmgr.requests[i]; if (rc.0 == packet.world_pos.0 && rc.1 == packet.world_pos.1) { delete(pmgr.requests[i]); break; }; }; }; fn floor_div(a: i32, b: i32) i32 = { if (a < 0) return -1-floor_div(-(a+1),b); return a / b; }; fn is_request_inflight(pmgr: *picture_mgr, world_pos: pos) bool = { for (const rc .. pmgr.requests) if (rc.0 == world_pos.0 && rc.1 == world_pos.1) return true; return false; }; // called on startup and on camera movement // for each loaded chunk not visible, unload it // for each chunk that should be visible that isn't loaded // and which hasn't already been requested, // request it. fn process_chunk_loadedness( pmgr: *picture_mgr, conn: net::socket, camera_pos: pos, ) void = { // unload all invisible chunks for (let i1 = len(pmgr.pictures); i1 > 0; i1 -= 1) { const i = i1 - 1; const pic = pmgr.pictures[i]; if (!is_picture_visible(camera_pos, pic.world_pos)) { fmt::printfln("## unloading {},{}", pic.world_pos.0, pic.world_pos.1)!; delete(pmgr.pictures[i]); }; }; const x0 = CHUNKSIZE*floor_div(camera_pos.0,CHUNKSIZE); const y0 = CHUNKSIZE*floor_div(camera_pos.1,CHUNKSIZE); // use a 3x3 window for 'chunks that might need to be loaded' for (let dx = 0i32; dx < 3; dx += 1) { for (let dy = 0i32; dy < 3; dy += 1) { const world_pos = (x0 + CHUNKSIZE*dx, y0 + CHUNKSIZE*dy): pos; const visible = is_picture_visible(camera_pos, world_pos); const loaded = !(find_picture_by_pos(pmgr, world_pos) is null); const requested = is_request_inflight(pmgr, world_pos); if (!visible) { fmt::printfln("\tnot visible {},{}", world_pos.0, world_pos.1)!; continue; }; if (loaded) { fmt::printfln("\talready loaded {},{}", world_pos.0, world_pos.1)!; continue; }; if (requested) { fmt::printfln("\tnot requesting again {},{}", world_pos.0, world_pos.1)!; continue; }; fmt::printfln("!! requesting {},{}", world_pos.0, world_pos.1)!; packet_reader::send(conn, world_pos: packet_reader::packet_reqchunk)!; append(pmgr.requests, world_pos); }; }; }; fn perform_drawop(pmgr: *picture_mgr, op: drawing::op) void = { for (const pic &.. pmgr.pictures) drawing::perform(pic, op); };