1 /** 2 Copyright: Copyright (c) 2015-2017 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.world.storage.coordinates; 7 8 import voxelman.core.config; 9 import voxelman.world.storage.utils; 10 import voxelman.math; 11 public import voxelman.core.config : DimensionId; 12 13 ivec3 blockToChunkPosition(ivec3 blockPos) 14 { 15 return ivec3( 16 floor(cast(float)blockPos.x / CHUNK_SIZE), 17 floor(cast(float)blockPos.y / CHUNK_SIZE), 18 floor(cast(float)blockPos.z / CHUNK_SIZE)); 19 } 20 21 ivec3 chunkToBlockPosition(ivec3 cp) 22 { 23 return ivec3(cp.x*CHUNK_SIZE, cp.y*CHUNK_SIZE, cp.z * CHUNK_SIZE); 24 } 25 26 ivec3 chunkStartBlockPos(ivec3 worldBlockPos) { 27 return ivec3( 28 floor(cast(float)worldBlockPos.x / CHUNK_SIZE) * CHUNK_SIZE, 29 floor(cast(float)worldBlockPos.y / CHUNK_SIZE) * CHUNK_SIZE, 30 floor(cast(float)worldBlockPos.z / CHUNK_SIZE) * CHUNK_SIZE); 31 } 32 33 struct ClientDimPos 34 { 35 vec3 pos = vec3(0,0,0); 36 vec2 heading = vec2(0,0); 37 } 38 39 struct BlockChunkIndex 40 { 41 this(BlockChunkPos blockChunkPos) 42 { 43 index = cast(ushort)(blockChunkPos.x + 44 blockChunkPos.y * CHUNK_SIZE_SQR + 45 blockChunkPos.z * CHUNK_SIZE); 46 } 47 48 this(BlockWorldPos blockWorldPos) 49 { 50 this(BlockChunkPos(blockWorldPos)); 51 } 52 53 this(ushort index) 54 { 55 this.index = index; 56 } 57 58 this(int x, int y, int z) 59 { 60 index = cast(ushort)(x + y * CHUNK_SIZE_SQR + z * CHUNK_SIZE); 61 } 62 63 this(T)(Vector!(T, 3) pos) 64 { 65 index = cast(ushort)(pos.x + pos.y * CHUNK_SIZE_SQR + pos.z * CHUNK_SIZE); 66 } 67 68 ushort index; 69 70 size_t getIndex() @property { return index; } 71 alias getIndex this; 72 } 73 74 // Position of block in world space. -int.max..int.max 75 struct BlockWorldPos 76 { 77 this(ChunkWorldPos cwp, ushort index) { 78 ubyte bx = index & CHUNK_SIZE_BITS; 79 ubyte by = (index / CHUNK_SIZE_SQR) & CHUNK_SIZE_BITS; 80 ubyte bz = (index / CHUNK_SIZE) & CHUNK_SIZE_BITS; 81 vector = ivec4( 82 cwp.x * CHUNK_SIZE + bx, 83 cwp.y * CHUNK_SIZE + by, 84 cwp.z * CHUNK_SIZE + bz, 85 cwp.w); 86 } 87 88 this(ivec3 blockWorldPos, int dim) 89 { 90 vector = ivec4(blockWorldPos.x, blockWorldPos.y, blockWorldPos.z, dim); 91 } 92 93 this(ivec4 blockWorldPos) 94 { 95 vector = blockWorldPos; 96 } 97 98 this(vec3 blockWorldPos, int dim) 99 { 100 vector = ivec4(blockWorldPos.x, blockWorldPos.y, blockWorldPos.z, dim); 101 } 102 103 this(int x, int y, int z, int dim) 104 { 105 vector = ivec4(x, y, z, dim); 106 } 107 108 this(int[4] pos) 109 { 110 vector = ivec4(pos[0], pos[1], pos[2], pos[3]); 111 } 112 113 ivec4 vector; 114 auto opDispatch(string s)() 115 { 116 return mixin("vector." ~ s); 117 } 118 119 void toString()(scope void delegate(const(char)[]) sink) 120 { 121 import std.format : formattedWrite; 122 sink.formattedWrite("bwp(%(%s %))", vector.arrayof); 123 } 124 } 125 126 static assert(!is(typeof({ 127 ChunkRegionPos vector = ChunkRegionPos(BlockWorldPos()); 128 }))); 129 static assert(!is(typeof({ 130 ChunkRegionPos vector = BlockWorldPos(); 131 }))); 132 static assert(!is(typeof({ 133 BlockWorldPos vector = BlockWorldPos(BlockWorldPos()); 134 }))); 135 136 // Position of block in chunk space. 0..ChunkSize 137 struct BlockChunkPos 138 { 139 this(BlockWorldPos blockWorldPos) 140 { 141 vector.x = blockWorldPos.x % CHUNK_SIZE; 142 vector.y = blockWorldPos.y % CHUNK_SIZE; 143 vector.z = blockWorldPos.z % CHUNK_SIZE; 144 if (vector.x < 0) vector.x += CHUNK_SIZE; 145 if (vector.y < 0) vector.y += CHUNK_SIZE; 146 if (vector.z < 0) vector.z += CHUNK_SIZE; 147 } 148 149 this(BlockChunkIndex blockIndex) 150 { 151 this(blockIndex.index); 152 } 153 154 this(ushort blockIndex) 155 { 156 vector.x = blockIndex & CHUNK_SIZE_BITS; 157 vector.y = (blockIndex / CHUNK_SIZE_SQR) & CHUNK_SIZE_BITS; 158 vector.z = (blockIndex / CHUNK_SIZE) & CHUNK_SIZE_BITS; 159 } 160 161 this(uvec3 blockChunkPos) 162 { 163 vector = blockChunkPos; 164 } 165 166 ivec3 vector; 167 auto opDispatch(string s)() 168 { 169 return mixin("vector." ~ s); 170 } 171 } 172 173 struct ChunkRegionIndex 174 { 175 this(ChunkRegionPos chunkRegionPos) 176 { 177 index = chunkRegionPos.x + 178 chunkRegionPos.y * REGION_SIZE + 179 chunkRegionPos.z * REGION_SIZE_SQR; 180 } 181 182 size_t index; 183 184 size_t getIndex() @property { return index; } 185 alias getIndex this; 186 } 187 188 // Position of chunk in world space. -int.max..int.max 189 struct ChunkWorldPos 190 { 191 this(BlockWorldPos blockWorldPos) 192 { 193 vector = svec4( 194 floor(cast(float)blockWorldPos.x / CHUNK_SIZE), 195 floor(cast(float)blockWorldPos.y / CHUNK_SIZE), 196 floor(cast(float)blockWorldPos.z / CHUNK_SIZE), 197 blockWorldPos.w); 198 } 199 200 this(ivec4 chunkWorldPos) 201 { 202 vector = chunkWorldPos; 203 } 204 205 this(int[4] chunkWorldPos) 206 { 207 vector = svec4(chunkWorldPos); 208 } 209 210 this(ivec3 chunkWorldPos, DimensionId dim) 211 { 212 vector = svec4(chunkWorldPos.x, chunkWorldPos.y, chunkWorldPos.z, dim); 213 } 214 215 this(svec4 chunkWorldPos) 216 { 217 vector = chunkWorldPos; 218 } 219 220 this(int x, int y, int z, int dim) 221 { 222 vector = svec4(x, y, z, dim); 223 } 224 225 this(ulong val) 226 { 227 enum MASK16 = 0b1111_1111_1111_1111; 228 vector = svec4(val&MASK16, (val>>16)&MASK16, (val>>32)&MASK16, (val>>48)&MASK16); 229 } 230 231 svec4 vector; 232 233 ivec4 ivector() @property 234 { 235 return ivec4(vector); 236 } 237 238 ivec3 ivector3() @property 239 { 240 return ivec3(vector); 241 } 242 243 ushort dimension() @property 244 { 245 return vector.w; 246 } 247 248 ulong asUlong() @property 249 { 250 ulong id = cast(ulong)vector.w<<48 | 251 cast(ulong)(cast(ushort)vector.z)<<32 | 252 cast(ulong)(cast(ushort)vector.y)<<16 | 253 cast(ulong)(cast(ushort)vector.x); 254 return id; 255 } 256 257 auto ref opDispatch(string s)() 258 { 259 return mixin("vector." ~ s); 260 } 261 262 void toString()(scope void delegate(const(char)[]) sink) 263 { 264 import std.format : formattedWrite; 265 sink.formattedWrite("cwp(%(%s %))", vector.arrayof); 266 } 267 } 268 269 void adjacentPositions(size_t numAdjacent, T)(T center, out T[numAdjacent] positions) 270 if (numAdjacent == 6 || numAdjacent == 26) 271 { 272 import voxelman.geometry.cube : sideOffsets; 273 foreach(i, offset; sideOffsets!numAdjacent) 274 { 275 positions[i] = T(center.x + offset[0], 276 center.y + offset[1], 277 center.z + offset[2], 278 center.w); 279 } 280 } 281 282 T[numAdjacent] adjacentPositions(size_t numAdjacent, T)(T center) 283 if (numAdjacent == 6 || numAdjacent == 26) 284 { 285 T[numAdjacent] positions; 286 adjacentPositions(center, positions); 287 return positions; 288 } 289 290 // Position of chunk in region space. 0..RegionSize 291 struct ChunkRegionPos 292 { 293 this(ChunkWorldPos chunkWorldPos) 294 { 295 vector.x = chunkWorldPos.x % REGION_SIZE; 296 vector.y = chunkWorldPos.y % REGION_SIZE; 297 vector.z = chunkWorldPos.z % REGION_SIZE; 298 if (vector.x < 0) vector.x += REGION_SIZE; 299 if (vector.y < 0) vector.y += REGION_SIZE; 300 if (vector.z < 0) vector.z += REGION_SIZE; 301 } 302 303 this(ivec3 blockWorldPos) 304 { 305 vector = blockWorldPos; 306 } 307 308 ivec3 vector; 309 auto opDispatch(string s)() 310 { 311 return mixin("vector." ~ s); 312 } 313 } 314 315 // Position of region in world space. -int.max..int.max 316 struct RegionWorldPos 317 { 318 this(ChunkWorldPos chunkWorldPos) 319 { 320 vector = ivec3( 321 floor(cast(float)chunkWorldPos.x / REGION_SIZE), 322 floor(cast(float)chunkWorldPos.y / REGION_SIZE), 323 floor(cast(float)chunkWorldPos.z / REGION_SIZE),); 324 } 325 326 this(ivec3 blockWorldPos) 327 { 328 vector = blockWorldPos; 329 } 330 331 ivec3 vector; 332 auto opDispatch(string s)() 333 { 334 return mixin("vector." ~ s); 335 } 336 }