1
0
Fork 0
Univerxel/src/core/world/raycast.hpp

49 lines
1.8 KiB
C++

#pragma once
#include "Universe.hpp"
#include "Chunk.hpp"
namespace world {
template<class Areas>
Universe::ray_result Raycast(const geometry::Ray& ray, const Areas& areas) {
//MAYBE: ray + offset to get float precision
Universe::ray_result target;
size_t dist = UINT32_MAX - 1;
for(auto& area: areas) {
if(ray.intersect(area.second->getBounding()) != geometry::IBox::ContainmentType::Disjoint) {
const auto &offset = area.second->getOffset().as_voxel();
const auto &chunks = area.second->getChunks();
std::shared_ptr<world::Chunk> chunk = nullptr;
chunk_pos chunk_vec(INT_MAX);
geometry::Ray::iterator it(ray);
glm::llvec3 point;
for (size_t i = 0; i < dist && it.next(point); i++) {
const auto pos = point - offset;
const chunk_pos cPos = glm::divide(pos);
if(cPos != chunk_vec) {
if (const auto it = chunks.find(cPos); it != chunks.end()) {
chunk = it->second;
chunk_vec = cPos;
} else if(chunks.inRange(cPos)) {
target.emplace<Universe::ray_out_of_range>(std::make_pair(area.first, cPos), offset);
break;
} else {
chunk = nullptr;
}
}
if(chunk != nullptr) {
const auto voxel = chunk->getAt(glm::modulo(pos));
if(voxel.is_solid()) {
target.emplace<Universe::ray_target>(std::make_pair(area.first, pos), voxel, offset);
dist = i;
break;
}
}
}
}
}
return target;
}
}