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 }