from libs import * import region class MapGen: def __init__(self): self.grads = [{} for _ in range(4)] self.regions = {} def fetch(self, pos): if pos in self.regions: return self.regions[pos] else: wr = region.WorldRegion() wr.pos = vec(pos) self.world_natural(wr) wr.remesh() wr.onclick = lambda s, b, c: self.click_region(s, b, c) self.regions[pos] = wr return wr def voxel_at(self, pos): r = next(iter(self.regions.values())).r pr, pf = np.divmod(pos + 0.5, r) wr = self.fetch(tuple(int(r * c) for c in pr)) return wr.grid[*tuple(int(c) for c in pf)] def click_region(self, wr, button, coords): match button: case 1: wr.set_voxel(coords[1]) case 2: print(f"coords {coords}") case 3: offset = axis2offset(coords[0]) p = wr.set_voxel(coords[1] + offset, 1) if p is not None: rc = wr.pos + p // wr.r * wr.r awr = self.fetch(tuple(int(x) for x in rc)) p = p % wr.r if not awr.grid[*p]: awr.set_voxel(p, 1) if button % 2 == 1: for i in range(len(VERTEX_ATTRS)): update_attr(wr, i) def perlin(self, name, pos, period): dim = pos.shape[0] gt = self.grads[dim].setdefault(name, {}) corner, fract = np.divmod(pos, period) fract /= period # https://stackoverflow.com/a/58827205 corners = np.arange(1 << dim)[:, None] >> np.arange(dim) & 1 dots = [] for c in corners: ci = tuple(np.add(c, corner, dtype=int, casting="unsafe")) cg = gt.setdefault(ci, normalise(np.random.normal(size=dim))) assert abs(np.linalg.norm(cg) - 1) < 1e-3 dots.append(np.dot(fract - c, cg)) return 2 * smerp(dots, fract) def world_natural(self, wr): n = 0 for i in range(wr.r): for j in range(wr.r): h = 4 + 4 * self.perlin("height", np.add(wr.pos[[0, 2]], (i, j)), np.array([10, 5])) - wr.pos[1] for k in range(min(int(h), wr.r)): wr.grid[i, k, j] = 3 n += 1 if h > 0 and h < wr.r: wr.grid[i, int(h), j] = 4 return n def world_min(self, wr): wr.set_voxel((0, 0, 0), 1) return 1 def world_grid(self, wr): n = 0 for i in range(0, wr.r, 2): for j in range(0, wr.r, 2): for k in range(0, wr.r, 2): wr.grid[i, j, k] = 1 n += 1 return n def world_checker(self, wr): n = 0 for i in range(wr.r): for j in range(wr.r): for k in range(wr.r): if not (i + j + k) % 2: wr.grid[i, j, k] = 1 n += 1 return n