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 }