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.worldbox; 7 8 import voxelman.log; 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, Color4ub 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 shiftAndClampBoxByBorders(WorldBox box, Box dimBorders) 29 { 30 if (box.position.x < dimBorders.position.x) 31 box.position.x = dimBorders.position.x; 32 if (box.position.y < dimBorders.position.y) 33 box.position.y = dimBorders.position.y; 34 if (box.position.z < dimBorders.position.z) 35 box.position.z = dimBorders.position.z; 36 37 if (box.endPosition.x > dimBorders.endPosition.x) 38 box.position.x = dimBorders.endPosition.x - box.size.x + 1; 39 if (box.endPosition.y > dimBorders.endPosition.y) 40 box.position.y = dimBorders.endPosition.y - box.size.y + 1; 41 if (box.endPosition.z > dimBorders.endPosition.z) 42 box.position.z = dimBorders.endPosition.z - box.size.z + 1; 43 44 return WorldBox(boxIntersection(box, dimBorders), box.dimension); 45 } 46 47 WorldBox calcBox(ChunkWorldPos cwp, int viewRadius) 48 { 49 int size = viewRadius*2 + 1; 50 return WorldBox(cast(ivec3)(cwp.ivector3 - viewRadius), 51 ivec3(size, size, size), cwp.w); 52 } 53 54 WorldBox worldBoxFromCorners(ivec3 a, ivec3 b, ushort dimension) 55 { 56 return WorldBox(boxFromCorners(a, b), dimension); 57 } 58 59 WorldBox blockBoxToChunkBox(WorldBox blockBox) 60 { 61 auto startPosition = blockToChunkPosition(blockBox.position); 62 auto endPosition = blockToChunkPosition(blockBox.endPosition); 63 return worldBoxFromCorners(startPosition, endPosition, blockBox.dimension); 64 } 65 66 // makes block box in chunk-local space out of world space 67 WorldBox blockBoxToChunkLocalBox(WorldBox blockBox) 68 { 69 blockBox.position -= chunkStartBlockPos(blockBox.position); 70 return blockBox; 71 } 72 73 /// Returns chunks if their mesh may have changed after specified modification 74 /// WorldBox is specified in block space 75 WorldBox calcModifiedMeshesBox(WorldBox modificationBox) 76 { 77 // We increase size by 1 in every direction. 78 // After rounding chunks on the border of modification will be included 79 WorldBox expandedBox = modificationBox; 80 expandedBox.position -= ivec3(1,1,1); 81 expandedBox.size += ivec3(2,2,2); 82 WorldBox chunkBox = blockBoxToChunkBox(expandedBox); 83 return chunkBox; 84 } 85 86 WorldBox chunkToBlockBox(ChunkWorldPos cwp) { 87 return chunkToBlockBox(cwp.ivector3, cwp.dimension); 88 } 89 90 WorldBox chunkToBlockBox(ivec3 cwp, ushort dimension) { 91 ivec3 startPosition = chunkToBlockPosition(cwp); 92 return WorldBox(startPosition, CHUNK_SIZE_VECTOR, dimension); 93 } 94 95 Box chunkToBlockBox(ivec3 cwp) { 96 ivec3 startPosition = chunkToBlockPosition(cwp); 97 return Box(startPosition, CHUNK_SIZE_VECTOR); 98 } 99 100 struct WorldBox 101 { 102 Box box; 103 alias box this; 104 ushort dimension; 105 106 this(ivec3 pos, ivec3 size, ushort dim) 107 { 108 box = Box(pos, size); 109 dimension = dim; 110 } 111 112 this(Box box, ushort dim) 113 { 114 this.box = box; 115 dimension = dim; 116 } 117 118 bool contains(ivec3 point, ushort dimension) const 119 { 120 if (this.dimension != dimension) return false; 121 return box.contains(point); 122 } 123 124 import std.algorithm : cartesianProduct, map, joiner, equal, canFind; 125 import std.range : iota, walkLength; 126 import std.array : array; 127 128 /// iterate all posisions within a box 129 int opApply(scope int delegate(ivec4) del) { 130 foreach (y; position.y .. position.y + size.y) 131 foreach (z; position.z .. position.z + size.z) 132 foreach (x; position.x .. position.x + size.x) 133 if (auto ret = del(ivec4(x, y, z, dimension))) 134 return ret; 135 return 0; 136 } 137 138 /// ditto 139 int opApply(scope int delegate(ChunkWorldPos) del) { 140 foreach (y; position.y .. position.y + size.y) 141 foreach (z; position.z .. position.z + size.z) 142 foreach (x; position.x .. position.x + size.x) 143 if (auto ret = del(ChunkWorldPos(x, y, z, dimension))) 144 return ret; 145 return 0; 146 } 147 148 WorldBox intersection(WorldBox other) { 149 return worldBoxIntersection(this, other); 150 } 151 152 WorldBox intersection(Box other) { 153 return WorldBox(boxIntersection(this, other), dimension); 154 } 155 156 bool opEquals()(auto const ref WorldBox other) const 157 { 158 return box == other.box && dimension == other.dimension; 159 } 160 } 161 162 TrisectResult trisect4d(WorldBox a, WorldBox b) 163 { 164 WorldBox intersection = worldBoxIntersection(a, b); 165 166 // no intersection 167 if (intersection.empty) 168 { 169 return TrisectResult([a], Box(), [b]); 170 } 171 172 auto result = trisectIntersecting(a, b); 173 result.intersection = intersection; 174 return result; 175 } 176 177 unittest 178 { 179 assert(WorldBox(Box(), 0) != WorldBox(Box(), 1)); 180 assert(WorldBox(Box(), 0) == WorldBox(Box(), 0)); 181 } 182 183 WorldBox worldBoxIntersection(WorldBox a, WorldBox b) 184 { 185 if (a.dimension != b.dimension) 186 { 187 return WorldBox(); 188 } 189 190 auto box = boxIntersection(a.box, b.box); 191 return WorldBox(box, a.dimension); 192 }