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 }