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