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