258 lines
7.1 KiB
C++
258 lines
7.1 KiB
C++
#include <Scene/BSP.hpp>
|
|
|
|
#include <Renderer/Pipeline.hpp>
|
|
|
|
#include <util/geo.hpp>
|
|
#include <util/file.hpp>
|
|
#include <util/log.hpp>
|
|
|
|
#include <set>
|
|
|
|
#include <cstring>
|
|
|
|
/* changes handedness by swapping z and y */
|
|
template<typename T>
|
|
static inline void change_swizzle(T& v) {
|
|
auto tmp = v.y;
|
|
v.y = v.z;
|
|
v.z = tmp;
|
|
}
|
|
|
|
using namespace HLBSP;
|
|
|
|
static inline void copy_data(void* file_data, std::string& dst, Lump& lump) {
|
|
dst.resize(lump.len);
|
|
std::memcpy(dst.data(), (u8*)file_data + (size_t)lump.offset, lump.len);
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void copy_data(void* file_data, std::vector<T>& dst, Lump& lump) {
|
|
Log::debug("%zu items\n", lump.len / sizeof(T));
|
|
dst.resize(lump.len / sizeof(T));
|
|
std::memcpy(dst.data(), ((u8*)file_data) + lump.offset, lump.len);
|
|
}
|
|
|
|
static inline glm::vec2 calc_tex_coords(glm::vec3 v, const TexInfo& t) {
|
|
change_swizzle(v);
|
|
return glm::vec2(
|
|
t.shift_s + glm::dot(v, t.shift_s_dir),
|
|
t.shift_t + glm::dot(v, t.shift_t_dir)
|
|
);
|
|
}
|
|
|
|
void BSP::load_vertices(const glm::vec3& cam_pos, bool visibility_test, const glm::mat4& view) {
|
|
std::set<int> present_faces;
|
|
std::vector<Face> visible_faces;
|
|
// if (visibility_test) {
|
|
if(false) {
|
|
auto leaf_idx = determine_leaf(cam_pos);
|
|
|
|
auto fr_planes = frustum(view);
|
|
|
|
if (leaf_idx == last_leaf)
|
|
return;
|
|
|
|
last_leaf = leaf_idx;
|
|
auto& cam_leaf = leaves[leaf_idx];
|
|
|
|
|
|
std::vector<Leaf> visible_leafs;
|
|
for (auto& leaf : leaves) {
|
|
|
|
const auto min = leaf.bb_mins;
|
|
const auto max = leaf.bb_maxes;
|
|
|
|
const glm::vec3 bounding_planes[8] = {
|
|
{ min.x, min.y, min.z },
|
|
{ max.x, min.y, min.z },
|
|
{ max.x, max.y, min.z },
|
|
{ min.x, max.y, min.z },
|
|
{ min.x, min.y, max.z },
|
|
{ max.x, min.y, max.z },
|
|
{ max.x, max.y, max.z },
|
|
{ min.x, max.y, max.z },
|
|
};
|
|
|
|
if (determine_visibility(cam_leaf, leaf, fr_planes, bounding_planes))
|
|
visible_leafs.push_back(leaf);
|
|
}
|
|
|
|
for (const auto& leaf : visible_leafs) {
|
|
for (size_t i = 0; i < leaf.n_mark_surfaces; i++) {
|
|
auto idx = mark_surfaces[leaf.first_mark_surface_idx + i];
|
|
if (present_faces.contains(idx))
|
|
continue;
|
|
|
|
present_faces.insert(idx);
|
|
visible_faces.push_back(faces[idx]);
|
|
}
|
|
}
|
|
} else {
|
|
visible_faces = faces;
|
|
}
|
|
|
|
textured_vertices.clear();
|
|
|
|
for (auto& face : visible_faces) {
|
|
auto& tex_info = tex_infos[face.tex_info_idx];
|
|
|
|
for (i16 i = 1, j = 2; j < face.n_surf_edges; i++, j++) {
|
|
textured_vertices.push_back(Vertex{
|
|
.pos = processed_vertices[face.first_surf_edge_idx],
|
|
.uv = calc_tex_coords(processed_vertices[face.first_surf_edge_idx], tex_info),
|
|
});
|
|
textured_vertices.push_back(Vertex{
|
|
.pos = processed_vertices[face.first_surf_edge_idx+i],
|
|
.uv = calc_tex_coords(processed_vertices[face.first_surf_edge_idx+i], tex_info),
|
|
});
|
|
textured_vertices.push_back(Vertex{
|
|
.pos = processed_vertices[face.first_surf_edge_idx+j],
|
|
.uv = calc_tex_coords(processed_vertices[face.first_surf_edge_idx+j], tex_info),
|
|
});
|
|
}
|
|
}
|
|
|
|
vertex_buffer->upload(textured_vertices);
|
|
}
|
|
|
|
int BSP::get_index_from_surfedge(int surfedge) {
|
|
int surf = surfedges[surfedge];
|
|
if(surf >= 0) {
|
|
return edges[surf].vertex_indices[0];
|
|
}
|
|
else {
|
|
return edges[-surf].vertex_indices[1];
|
|
}
|
|
}
|
|
|
|
int BSP::determine_leaf(glm::vec3 cam_pos) {
|
|
/* use SDF of planes to determine relative position with respect to partitioning planes */
|
|
int idx = 0;
|
|
/* positive values are node indices, negative values are leaf indices */
|
|
while (idx >= 0) {
|
|
const auto& plane = planes[nodes[idx].plane];
|
|
const auto dist = glm::dot(plane.norm, cam_pos) - plane.dist;
|
|
|
|
if (dist >= 0)
|
|
idx = nodes[idx].children[0];
|
|
else
|
|
idx = nodes[idx].children[1];
|
|
}
|
|
|
|
return -idx - 1;
|
|
}
|
|
|
|
|
|
bool BSP::determine_visibility(const Leaf& cam_leaf, const Leaf& leaf, const std::array<glm::vec4, 6>& frustum, const glm::vec3 box_verts[8]) {
|
|
/* perform fustrum culling */
|
|
return box_in_frustum(frustum, box_verts);
|
|
}
|
|
|
|
static std::vector<std::map<std::string, std::string>> load_entities(const std::string& in) {
|
|
/* TODO */
|
|
return {
|
|
{{"test", "this"}},
|
|
};
|
|
}
|
|
|
|
static std::vector<MipTexture> load_mip_textures(const u8* data, u32 offset) {
|
|
const TextureLump* lump = reinterpret_cast<const TextureLump*>(data + offset);
|
|
std::vector<MipTexture> ret;
|
|
ret.resize(lump->n_mip_textures);
|
|
|
|
for(size_t i = 0; i < ret.size(); i++) {
|
|
ret[i] = *reinterpret_cast<const MipTexture*>(data + lump->offsets[i]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
BSP::BSP(vk::PhysicalDevice phys_dev, vk::Device dev, const std::string& fname) : dev(dev), filename(fname) {
|
|
file_data = file::slurpb(fname);
|
|
Log::debug("BSP file size: %zu\n", file_data.size());
|
|
header = reinterpret_cast<Header*>(file_data.data());
|
|
|
|
Log::info("Loading BSP: %s\n", fname.c_str());
|
|
|
|
if(header->version != 30) {
|
|
Log::error("BSP file not expected version (Half Life has version 30)!\n");
|
|
}
|
|
|
|
Log::debug("Loading entities\n");
|
|
std::string entities_buff;
|
|
copy_data(file_data.data(), entities_buff, header->entities);
|
|
entities = load_entities(entities_buff);
|
|
|
|
Log::debug("Loading planes\n");
|
|
copy_data(file_data.data(), planes, header->planes);
|
|
/* change swizzle */
|
|
for (auto& plane : planes) {
|
|
change_swizzle(plane.norm);
|
|
}
|
|
|
|
Log::debug("Loading textures\n");
|
|
textures = load_mip_textures(file_data.data(), header->textures.offset);
|
|
|
|
Log::debug("Loading vertices\n");
|
|
copy_data(file_data.data(), vertices, header->vertices);
|
|
for (auto& vertex : vertices) {
|
|
change_swizzle(vertex);
|
|
}
|
|
|
|
Log::debug("Loading nodes\n");
|
|
copy_data(file_data.data(), nodes, header->nodes);
|
|
for (auto& node : nodes) {
|
|
change_swizzle(node.bb_mins);
|
|
change_swizzle(node.bb_maxes);
|
|
}
|
|
|
|
Log::debug("Loading texinfo\n");
|
|
copy_data(file_data.data(), tex_infos, header->texinfo);
|
|
|
|
Log::debug("Loading faces\n");
|
|
copy_data(file_data.data(), faces, header->faces);
|
|
|
|
Log::debug("Loading lightmap\n");
|
|
lightmap.lights = reinterpret_cast<rgb*>(file_data.data()+header->lighting.offset);
|
|
|
|
Log::debug("Loading clip nodes\n");
|
|
copy_data(file_data.data(), clip_nodes, header->clip_nodes);
|
|
|
|
Log::debug("Loading leaves\n");
|
|
copy_data(file_data.data(), leaves, header->leaves);
|
|
for (auto& leaf : leaves) {
|
|
change_swizzle(leaf.bb_mins);
|
|
change_swizzle(leaf.bb_maxes);
|
|
}
|
|
|
|
Log::debug("Loading mark surfaces\n");
|
|
copy_data(file_data.data(), mark_surfaces, header->mark_surfaces);
|
|
|
|
Log::debug("Loading edges\n");
|
|
copy_data(file_data.data(), edges, header->edges);
|
|
|
|
Log::debug("Loading surfedges\n");
|
|
copy_data(file_data.data(), surfedges, header->surf_edges);
|
|
processed_vertices.reserve(surfedges.size());
|
|
/* use this to build our processed_vertices, idea thanks to gzalo's HalfMapper */
|
|
for(const auto& s : surfedges) {
|
|
processed_vertices.push_back(vertices[edges[s > 0? s : -s].vertex_indices[s<=0]]);
|
|
}
|
|
|
|
Log::debug("Loading models\n");
|
|
copy_data(file_data.data(), models, header->models);
|
|
for (auto& model : models) {
|
|
change_swizzle(model.bb_mins);
|
|
change_swizzle(model.bb_maxes);
|
|
}
|
|
|
|
size_t max_vertex_count = 0;
|
|
|
|
for (const auto& face : faces) {
|
|
max_vertex_count += (face.n_surf_edges - 2) * 3;
|
|
}
|
|
|
|
Log::debug("Creating vertex buffer of size %zu\n", max_vertex_count);
|
|
vertex_buffer = std::make_unique<GeneralVertexBuffer<Vertex>>(phys_dev, dev, max_vertex_count);
|
|
textured_vertices.reserve(max_vertex_count);
|
|
} |