aboutsummaryrefslogtreecommitdiff
path: root/client/pictures.ha
diff options
context:
space:
mode:
Diffstat (limited to 'client/pictures.ha')
-rw-r--r--client/pictures.ha145
1 files changed, 145 insertions, 0 deletions
diff --git a/client/pictures.ha b/client/pictures.ha
new file mode 100644
index 0000000..1db3954
--- /dev/null
+++ b/client/pictures.ha
@@ -0,0 +1,145 @@
+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);
+};