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.worldbox;
7 
8 import std.experimental.logger;
9 import voxelman.math;
10 
11 import voxelman.core.config;
12 import voxelman.world.storage.coordinates;
13 
14 import voxelman.graphics;
15 import voxelman.geometry.box;
16 
17 void putCube(ref Batch batch, Box box, Color3ub color, bool fill, bool offset = true)
18 {
19 	vec3 pos = box.position;
20 	vec3 size = box.size;
21 	if (offset) {
22 		pos -= vec3(0.01, 0.01, 0.01);
23 		size += vec3(0.02, 0.02, 0.02);
24 	}
25 	batch.putCube(pos, size, color, fill);
26 }
27 
28 WorldBox calcBox(ChunkWorldPos cwp, int viewRadius)
29 {
30 	int size = viewRadius*2 + 1;
31 	return WorldBox(cast(ivec3)(cwp.ivector3 - viewRadius),
32 		ivec3(size, size, size), cwp.w);
33 }
34 
35 WorldBox worldBoxFromCorners(ivec3 a, ivec3 b, ushort dimention)
36 {
37 	return WorldBox(boxFromCorners(a, b), dimention);
38 }
39 
40 WorldBox blockBoxToChunkBox(WorldBox blockBox)
41 {
42 	auto startPosition = blockToChunkPosition(blockBox.position);
43 	auto endPosition = blockToChunkPosition(blockBox.endPosition);
44 	return worldBoxFromCorners(startPosition, endPosition, blockBox.dimention);
45 }
46 
47 // makes block box in chunk-local space out of world space
48 WorldBox blockBoxToChunkLocalBox(WorldBox blockBox)
49 {
50 	blockBox.position -= chunkStartBlockPos(blockBox.position);
51 	return blockBox;
52 }
53 
54 /// Returns chunks if their mesh may have changed after specified modification
55 /// WorldBox is specified in block space
56 WorldBox calcModifiedMeshesBox(WorldBox modificationBox)
57 {
58 	// We increase size by 1 in every direction.
59 	// After rounding chunks on the border of modification will be included
60 	WorldBox expandedBox = modificationBox;
61 	expandedBox.position -= ivec3(1,1,1);
62 	expandedBox.size += ivec3(2,2,2);
63 	WorldBox chunkBox = blockBoxToChunkBox(expandedBox);
64 	return chunkBox;
65 }
66 
67 WorldBox chunkToBlockBox(ChunkWorldPos cwp) {
68 	return chunkToBlockBox(cwp.ivector3, cwp.dimention);
69 }
70 
71 WorldBox chunkToBlockBox(ivec3 cwp, ushort dimention) {
72 	ivec3 startPosition = chunkToBlockPosition(cwp);
73 	return WorldBox(startPosition, CHUNK_SIZE_VECTOR, dimention);
74 }
75 
76 Box chunkToBlockBox(ivec3 cwp) {
77 	ivec3 startPosition = chunkToBlockPosition(cwp);
78 	return Box(startPosition, CHUNK_SIZE_VECTOR);
79 }
80 
81 struct WorldBox
82 {
83 	Box box;
84 	alias box this;
85 	ushort dimention;
86 
87 	this(ivec3 pos, ivec3 size, ushort dim)
88 	{
89 		box = Box(pos, size);
90 		dimention = dim;
91 	}
92 
93 	this(Box box, ushort dim)
94 	{
95 		this.box = box;
96 		dimention = dim;
97 	}
98 
99 	bool contains(ivec3 point, ushort dimention) const
100 	{
101 		if (this.dimention != dimention) return false;
102 		return box.contains(point);
103 	}
104 
105 	import std.algorithm : cartesianProduct, map, joiner, equal, canFind;
106 	import std.range : iota, walkLength;
107 	import std.array : array;
108 
109 	// generates all positions within box.
110 	auto positions4d() const @property
111 	{
112 		return cartesianProduct(
113 			iota(position.x, position.x + size.x),
114 			iota(position.z, position.z + size.z),
115 			iota(position.y, position.y + size.y),)
116 			.map!((a)=>ivec4(a[0], a[2], a[1], dimention));
117 	}
118 
119 	bool opEquals()(auto const ref WorldBox other) const
120 	{
121 		return box == other.box && dimention == other.dimention;
122 	}
123 }
124 
125 TrisectResult trisect4d(WorldBox a, WorldBox b)
126 {
127 	WorldBox intersection = worldBoxIntersection(a, b);
128 
129 	// no intersection
130 	if (intersection.empty)
131 	{
132 		return TrisectResult([a], Box(), [b]);
133 	}
134 
135 	auto result = trisectIntersecting(a, b);
136 	result.intersection = intersection;
137 	return result;
138 }
139 
140 unittest
141 {
142 	assert(WorldBox(Box(), 0) != WorldBox(Box(), 1));
143 	assert(WorldBox(Box(), 0) == WorldBox(Box(), 0));
144 }
145 
146 WorldBox worldBoxIntersection(WorldBox a, WorldBox b)
147 {
148 	if (a.dimention != b.dimention)
149 	{
150 		return WorldBox();
151 	}
152 
153 	auto box = boxIntersection(a.box, b.box);
154 	return WorldBox(box, a.dimention);
155 }