1 /** 2 Copyright: Copyright (c) 2015-2018 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 void toString()(scope void delegate(const(char)[]) sink) 173 { 174 import std.format : formattedWrite; 175 sink.formattedWrite("bcp(%(%s %))", vector.arrayof); 176 } 177 } 178 179 struct ChunkRegionIndex 180 { 181 this(ChunkRegionPos chunkRegionPos) 182 { 183 index = chunkRegionPos.x + 184 chunkRegionPos.y * REGION_SIZE + 185 chunkRegionPos.z * REGION_SIZE_SQR; 186 } 187 188 size_t index; 189 190 size_t getIndex() @property { return index; } 191 alias getIndex this; 192 } 193 194 // Position of chunk in world space. -int.max..int.max 195 struct ChunkWorldPos 196 { 197 enum ChunkWorldPos MAX = ChunkWorldPos(svec4(short.max,short.max,short.max,short.max)); 198 199 this(BlockWorldPos blockWorldPos) 200 { 201 vector = svec4( 202 floor(cast(float)blockWorldPos.x / CHUNK_SIZE), 203 floor(cast(float)blockWorldPos.y / CHUNK_SIZE), 204 floor(cast(float)blockWorldPos.z / CHUNK_SIZE), 205 blockWorldPos.w); 206 } 207 208 this(ivec4 chunkWorldPos) 209 { 210 vector = chunkWorldPos; 211 } 212 213 this(int[4] chunkWorldPos) 214 { 215 vector = svec4(chunkWorldPos); 216 } 217 218 this(ivec3 chunkWorldPos, DimensionId dim) 219 { 220 vector = svec4(chunkWorldPos.x, chunkWorldPos.y, chunkWorldPos.z, dim); 221 } 222 223 this(svec4 chunkWorldPos) 224 { 225 vector = chunkWorldPos; 226 } 227 228 this(int x, int y, int z, int dim) 229 { 230 vector = svec4(x, y, z, dim); 231 } 232 233 this(ulong val) 234 { 235 enum MASK16 = 0b1111_1111_1111_1111; 236 vector = svec4(val&MASK16, (val>>16)&MASK16, (val>>32)&MASK16, (val>>48)&MASK16); 237 } 238 239 svec4 vector; 240 241 ivec4 ivector() @property 242 { 243 return ivec4(vector); 244 } 245 246 ivec3 ivector3() @property 247 { 248 return ivec3(vector); 249 } 250 251 ushort dimension() @property 252 { 253 return vector.w; 254 } 255 256 ulong asUlong() @property 257 { 258 ulong id = cast(ulong)vector.w<<48 | 259 cast(ulong)(cast(ushort)vector.z)<<32 | 260 cast(ulong)(cast(ushort)vector.y)<<16 | 261 cast(ulong)(cast(ushort)vector.x); 262 return id; 263 } 264 265 auto ref opDispatch(string s)() 266 { 267 return mixin("vector." ~ s); 268 } 269 270 void toString()(scope void delegate(const(char)[]) sink) 271 { 272 import std.format : formattedWrite; 273 sink.formattedWrite("cwp(%(%s %))", vector.arrayof); 274 } 275 } 276 277 void adjacentPositions(size_t numAdjacent, T)(T center, out T[numAdjacent] positions) 278 if (numAdjacent == 6 || numAdjacent == 26) 279 { 280 import voxelman.geometry : sideOffsets; 281 foreach(i, offset; sideOffsets!numAdjacent) 282 { 283 positions[i] = T(center.x + offset[0], 284 center.y + offset[1], 285 center.z + offset[2], 286 center.w); 287 } 288 } 289 290 T[numAdjacent] adjacentPositions(size_t numAdjacent, T)(T center) 291 if (numAdjacent == 6 || numAdjacent == 26) 292 { 293 T[numAdjacent] positions; 294 adjacentPositions(center, positions); 295 return positions; 296 } 297 298 // Position of chunk in region space. 0..RegionSize 299 struct ChunkRegionPos 300 { 301 this(ChunkWorldPos chunkWorldPos) 302 { 303 vector.x = chunkWorldPos.x % REGION_SIZE; 304 vector.y = chunkWorldPos.y % REGION_SIZE; 305 vector.z = chunkWorldPos.z % REGION_SIZE; 306 if (vector.x < 0) vector.x += REGION_SIZE; 307 if (vector.y < 0) vector.y += REGION_SIZE; 308 if (vector.z < 0) vector.z += REGION_SIZE; 309 } 310 311 this(ivec3 blockWorldPos) 312 { 313 vector = blockWorldPos; 314 } 315 316 ivec3 vector; 317 auto opDispatch(string s)() 318 { 319 return mixin("vector." ~ s); 320 } 321 } 322 323 // Position of region in world space. -int.max..int.max 324 struct RegionWorldPos 325 { 326 this(ChunkWorldPos chunkWorldPos) 327 { 328 vector = ivec3( 329 floor(cast(float)chunkWorldPos.x / REGION_SIZE), 330 floor(cast(float)chunkWorldPos.y / REGION_SIZE), 331 floor(cast(float)chunkWorldPos.z / REGION_SIZE),); 332 } 333 334 this(ivec3 blockWorldPos) 335 { 336 vector = blockWorldPos; 337 } 338 339 ivec3 vector; 340 auto opDispatch(string s)() 341 { 342 return mixin("vector." ~ s); 343 } 344 }