+glm::vec3 World::CombinedInterpenetration(
+ const EntityState &state,
+ const std::vector<WorldCollision> &col
+) noexcept {
+ // determine displacement for each cardinal axis and move entity accordingly
+ glm::vec3 min_pen(0.0f);
+ glm::vec3 max_pen(0.0f);
+ for (const WorldCollision &c : col) {
+ if (!c.Blocks()) continue;
+ glm::vec3 local_pen(c.normal * c.depth);
+ // swap if neccessary (normal may point away from the entity)
+ if (dot(c.normal, state.RelativePosition(c.ChunkPos()) - c.BlockCoords()) > 0) {
+ local_pen *= -1;
+ }
+ min_pen = min(min_pen, local_pen);
+ max_pen = max(max_pen, local_pen);
+ }
+ glm::vec3 pen(0.0f);
+ // only apply correction for axes where penetration is only in one direction
+ for (std::size_t i = 0; i < 3; ++i) {
+ if (min_pen[i] < -std::numeric_limits<float>::epsilon()) {
+ if (max_pen[i] < std::numeric_limits<float>::epsilon()) {
+ pen[i] = min_pen[i];
+ }
+ } else {
+ pen[i] = max_pen[i];
+ }
+ }
+ return pen;
+}
+