Shifted to Half Life BSPs, learned how to unwind their really weird triangle fans

This commit is contained in:
Conál 2024-02-22 13:44:40 -05:00
parent 0bba09a055
commit 4433d34e32
13 changed files with 363 additions and 273 deletions

View File

@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(WIN32)
set(CMAKE_CXX_FLAGS "-D_DEBUG")
else()
set(CMAKE_CXX_FLAGS "-D_DEBUG -Wall -O3")
set(CMAKE_CXX_FLAGS "-D_DEBUG -Wall")
endif()
project(Pleascach)

View File

@ -82,7 +82,7 @@ void CommandBuffer::bind(Terrain* terrain) {
command_buffer.bindIndexBuffer(*terrain->index_buffer, 0, vk::IndexType::eUint32);
}
void CommandBuffer::bind(Q3BSP::BSP* bsp) {
void CommandBuffer::bind(HLBSP::BSP* bsp) {
bind(*bsp->pipeline);
bind(*bsp->vertex_buffer);
command_buffer.bindIndexBuffer(*bsp->index_buffer, 0, vk::IndexType::eUint32);

View File

@ -43,7 +43,7 @@ struct CommandBuffer {
void bind(std::shared_ptr<Model> model);
void bind(Terrain* terrain);
void bind(Q3BSP::BSP* bsp);
void bind(HLBSP::BSP* bsp);
void draw(uint32_t vertex_count, uint32_t instance_count, uint32_t first_vertex = 0, uint32_t first_instance = 0);

View File

@ -10,7 +10,8 @@
#include <util/log.hpp>
GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& shaders, const vk::Extent2D& extent, const RenderPass& render_pass, vk::ArrayProxy<vk::DescriptorSetLayoutBinding> bindings, const vk::VertexInputBindingDescription& vertex_binding, const std::vector<vk::VertexInputAttributeDescription>& vertex_attrs, enum Type type) : dev(dev) {
GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& shaders, const vk::Extent2D& extent, const RenderPass& render_pass, vk::ArrayProxy<vk::DescriptorSetLayoutBinding> bindings, const vk::VertexInputBindingDescription& vertex_binding, const std::vector<vk::VertexInputAttributeDescription>& vertex_attrs, enum Type type, bool wireframe)
: dev(dev), shaders(shaders), extent(extent), render_pass(render_pass), bindings(bindings), vertex_binding(vertex_binding), vertex_attrs(vertex_attrs), type(type) {
/* create layout
* Eventually add a graphicspipline constructor that allows specification of layouts etc
* kinda like how Image::Image has all those versions
@ -56,24 +57,23 @@ GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& sh
})[0];
/* shader setup */
std::vector<vk::PipelineShaderStageCreateInfo> shader_info;
shader_info.reserve(shaders.size());
for (const auto& shader : shaders)
shader_info.push_back(shader.info());
/* vertex input setup */
const std::vector<vk::VertexInputBindingDescription> vertex_bindings = {
vertex_bindings = {
vertex_binding,
};
const auto vertex_input_info = vk::PipelineVertexInputStateCreateInfo{
vertex_input_info = vk::PipelineVertexInputStateCreateInfo {
.vertexBindingDescriptionCount = static_cast<uint32_t>(vertex_bindings.size()),
.pVertexBindingDescriptions = vertex_bindings.data(),
.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_attrs.size()),
.pVertexAttributeDescriptions = vertex_attrs.data(),
};
auto input_asm_info = vk::PipelineInputAssemblyStateCreateInfo {
input_asm_info = vk::PipelineInputAssemblyStateCreateInfo {
/* matters later if we use strip primitives */
.primitiveRestartEnable = vk::False,
};
@ -94,7 +94,7 @@ GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& sh
const vk::PipelineTessellationStateCreateInfo* ptesselation_info = nullptr;
const auto tess_info = vk::PipelineTessellationStateCreateInfo {
tess_info = vk::PipelineTessellationStateCreateInfo {
/* quads*/
.patchControlPoints = 4,
};
@ -103,22 +103,22 @@ GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& sh
ptesselation_info = &tess_info;
}
const auto raster_info = vk::PipelineRasterizationStateCreateInfo {
raster_info = vk::PipelineRasterizationStateCreateInfo {
.depthClampEnable = vk::False,
.polygonMode = type == eBOX ? vk::PolygonMode::eLine : vk::PolygonMode::eFill,
.cullMode = type == eBOX ? vk::CullModeFlagBits::eNone : vk::CullModeFlagBits::eBack,
.polygonMode = (type == eBOX || wireframe) ? vk::PolygonMode::eLine : vk::PolygonMode::eFill,
.cullMode = type == eBOX ? vk::CullModeFlagBits::eNone : vk::CullModeFlagBits::eNone,
.frontFace = vk::FrontFace::eCounterClockwise,
.depthBiasEnable = type == eBOX,
.depthBiasConstantFactor = 0.01,
.lineWidth = 1.0,
};
const auto multisample_info = vk::PipelineMultisampleStateCreateInfo {
multisample_info = vk::PipelineMultisampleStateCreateInfo {
.rasterizationSamples = vk::SampleCountFlagBits::e1,
.sampleShadingEnable = vk::False,
};
const auto depth_stencil_info = vk::PipelineDepthStencilStateCreateInfo{
depth_stencil_info = vk::PipelineDepthStencilStateCreateInfo{
.depthTestEnable = vk::True,
.depthWriteEnable = type != eBOX,
.depthCompareOp = vk::CompareOp::eLess,
@ -128,7 +128,7 @@ GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& sh
.maxDepthBounds = 1.0,
};
const auto color_blend_attachment = vk::PipelineColorBlendAttachmentState {
color_blend_attachment = vk::PipelineColorBlendAttachmentState {
/* only the box has blending */
.blendEnable = type == eBOX,
.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha,
@ -142,8 +142,8 @@ GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& sh
};
std::array<float, 4> blend_constants = {0.0f, 0.0f, 0.0f, 0.0f };
auto color_blend_info = vk::PipelineColorBlendStateCreateInfo{
blend_constants = {0.0f, 0.0f, 0.0f, 0.0f };
color_blend_info = vk::PipelineColorBlendStateCreateInfo{
.logicOpEnable = vk::False,
.logicOp = vk::LogicOp::eCopy,
.attachmentCount = 1,
@ -152,36 +152,34 @@ GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& sh
};
/* temporary viewport and scissor, since it is a dynamic state due to the existence of window resizing */
const auto viewport = vk::Viewport{
viewport = vk::Viewport{
.x = 0.0,
.y = static_cast<float>(extent.height),
.width = static_cast<float>(extent.width),
.height = -static_cast<float>(extent.height),
};
const auto scissor = vk::Rect2D {
scissor = vk::Rect2D {
.offset = 0,
.extent = extent,
};
const auto viewport_info = vk::PipelineViewportStateCreateInfo {
viewport_info = vk::PipelineViewportStateCreateInfo {
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
};
const vk::DynamicState dyn_states[] = {
vk::DynamicState::eScissor,
vk::DynamicState::eViewport,
};
dyn_states[0] = vk::DynamicState::eScissor;
dyn_states[1] = vk::DynamicState::eViewport;
const auto dyn_info = vk::PipelineDynamicStateCreateInfo{
.dynamicStateCount = std::size(dyn_states),
dyn_info = vk::PipelineDynamicStateCreateInfo {
.dynamicStateCount = (uint32_t)std::size(dyn_states),
.pDynamicStates = dyn_states,
};
const auto pipeline_info = vk::GraphicsPipelineCreateInfo {
pipeline_info = vk::GraphicsPipelineCreateInfo {
.stageCount = static_cast<uint32_t>(shaders.size()),
.pStages = shader_info.data(),
.pVertexInputState = &vertex_input_info,
@ -237,7 +235,29 @@ void GraphicsPipeline::update(uint32_t binding, const Texture& tex) {
}, nullptr);
}
void GraphicsPipeline::rebuild(bool wireframe) {
vertex_input_info = vk::PipelineVertexInputStateCreateInfo {
.vertexBindingDescriptionCount = static_cast<uint32_t>(vertex_bindings.size()),
.pVertexBindingDescriptions = vertex_bindings.data(),
.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_attrs.size()),
.pVertexAttributeDescriptions = vertex_attrs.data(),
};
raster_info.polygonMode = wireframe ? vk::PolygonMode::eLine : vk::PolygonMode::eFill;
auto res = dev.createGraphicsPipeline(nullptr, pipeline_info);
if (res.result != vk::Result::eSuccess) {
Log::error("Failed to create pipeline: (Vulkan error code: %d)\n", res.result);
}
defunct_pipelines.push_back(pipeline);
pipeline = res.value;
}
GraphicsPipeline::~GraphicsPipeline() {
for(auto& p : defunct_pipelines) {
dev.destroyPipeline(p);
}
dev.destroyDescriptorSetLayout(desc_layout);
dev.destroyPipelineLayout(layout);
dev.destroyDescriptorPool(desc_pool);

View File

@ -3,6 +3,8 @@
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <util/log.hpp>
#include <Renderer/VertexBuffer.hpp>
struct Shader;
@ -22,14 +24,49 @@ struct GraphicsPipeline {
GraphicsPipeline(vk::Device dev, const std::vector<Shader>& shaders,
const vk::Extent2D& extent, const RenderPass& render_pass,
vk::ArrayProxy<vk::DescriptorSetLayoutBinding> bindings,
const vk::VertexInputBindingDescription& vertex_binding, const std::vector<vk::VertexInputAttributeDescription>& vertex_attrs, enum Type type = Type::eVERTEX);
const vk::VertexInputBindingDescription& vertex_binding,
const std::vector<vk::VertexInputAttributeDescription>& vertex_attrs,
enum Type type = Type::eVERTEX, bool wireframe = false);
/* everything needed for recreation */
vk::Device dev;
const std::vector<Shader> shaders;
const vk::Extent2D extent;
const RenderPass& render_pass;
const vk::ArrayProxy<vk::DescriptorSetLayoutBinding> bindings;
const vk::VertexInputBindingDescription vertex_binding;
const std::vector<vk::VertexInputAttributeDescription> vertex_attrs;
const Type type;
vk::Pipeline pipeline;
vk::PipelineLayout layout;
vk::DescriptorSetLayout desc_layout;
vk::DescriptorPool desc_pool;
vk::DescriptorSet desc_set;
/* pipeline creation info cached for rebuilding */
std::vector<vk::PipelineShaderStageCreateInfo> shader_info;
std::vector<vk::VertexInputBindingDescription> vertex_bindings;
vk::PipelineVertexInputStateCreateInfo vertex_input_info;
vk::PipelineInputAssemblyStateCreateInfo input_asm_info;
vk::PipelineTessellationStateCreateInfo tess_info;
vk::PipelineRasterizationStateCreateInfo raster_info;
vk::PipelineMultisampleStateCreateInfo multisample_info;
vk::PipelineDepthStencilStateCreateInfo depth_stencil_info;
vk::PipelineColorBlendAttachmentState color_blend_attachment;
std::array<float, 4> blend_constants;
vk::PipelineColorBlendStateCreateInfo color_blend_info;
vk::Viewport viewport;
vk::Rect2D scissor;
vk::PipelineViewportStateCreateInfo viewport_info;
vk::DynamicState dyn_states[2];
vk::PipelineDynamicStateCreateInfo dyn_info;
vk::GraphicsPipelineCreateInfo pipeline_info;
std::vector<vk::Pipeline> defunct_pipelines;
inline operator vk::Pipeline&() {
return pipeline;
}
@ -38,6 +75,9 @@ struct GraphicsPipeline {
void update(uint32_t binding, const UniformBuffer& uni);
void update(uint32_t binding, const Texture& tex);
void rebuild(bool wireframe);
~GraphicsPipeline();
};

View File

@ -199,24 +199,25 @@ Renderer::Renderer(Window& win) : win(win) {
};
/* BSP loader */
bsp = std::make_unique<Q3BSP::BSP>(phys_dev, dev, "assets/maps/git.bsp");
std::vector<Shader> bsp_shaders = {
bsp = std::make_unique<HLBSP::BSP>(phys_dev, dev, "assets/maps/hl1.bsp");
bsp_shaders = {
{ dev, "assets/shaders/bin/bsp.vert.spv", vk::ShaderStageFlagBits::eVertex },
{ dev, "assets/shaders/bin/bsp.frag.spv", vk::ShaderStageFlagBits::eFragment },
};
bsp->pipeline = std::make_unique<GraphicsPipeline>(dev, bsp_shaders, swapchain->extent, *render_pass, bindings, bsp->vertex_buffer->binding(0), bsp->vertex_buffer->attrs(0));
bsp->pipeline->update(0, *uniform_buffer);
/* bounding and hitboxs */
std::vector<Shader> box_shaders = {
box_shaders = {
{ dev, "assets/shaders/bin/box.vert.spv", vk::ShaderStageFlagBits::eVertex },
{ dev, "assets/shaders/bin/box.geom.spv", vk::ShaderStageFlagBits::eGeometry },
{ dev, "assets/shaders/bin/box.frag.spv", vk::ShaderStageFlagBits::eFragment },
};
std::vector<BoxVertex> boxes;
boxes.reserve(bsp->leafs.size());
for (auto& leaf : bsp->leafs) {
boxes.reserve(bsp->leaves.size());
for (auto& leaf : bsp->leaves) {
boxes.push_back(BoxVertex{
.mins = leaf.bb_mins,
.maxes = leaf.bb_maxes,
@ -228,11 +229,6 @@ Renderer::Renderer(Window& win) : win(win) {
box_pipeline = std::make_unique<GraphicsPipeline>(dev, box_shaders, swapchain->extent, *render_pass, bindings, box_buffer->binding(0), box_buffer->attrs(0), GraphicsPipeline::Type::eBOX);
box_pipeline->update(0, *uniform_buffer);
for (auto& shader : box_shaders)
shader.cleanup();
for (auto& shader : bsp_shaders)
shader.cleanup();
ui = std::make_unique<UI>(this);
}
@ -351,6 +347,7 @@ void Renderer::draw() {
bsp->load_indices(cam.pos, visibility_testing, p * uni.view);
command_buffer->bind(bsp.get());
/*command_buffer->draw(bsp->vertices.size(), 1);*/
command_buffer->command_buffer.drawIndexed(bsp->indices.size(), 1, 0, 0, 0);
n_indices = bsp->indices.size();
@ -422,6 +419,10 @@ Renderer::~Renderer() {
box_pipeline.reset();
uniform_buffer.reset();
for (auto& shader : box_shaders)
shader.cleanup();
for (auto& shader : bsp_shaders)
shader.cleanup();
for (auto& tex : textures) {
tex.cleanup();

View File

@ -51,11 +51,13 @@ struct Renderer {
std::unique_ptr<CommandBuffer> command_buffer;
std::unique_ptr<RenderPass> render_pass;
std::vector<Shader> box_shaders;
std::unique_ptr<GraphicsPipeline> box_pipeline;
std::unique_ptr<GeneralVertexBuffer<BoxVertex>> box_buffer;
std::unique_ptr<UniformBuffer> uniform_buffer;
std::unique_ptr<Q3BSP::BSP> bsp;
std::vector<Shader> bsp_shaders;
std::unique_ptr<HLBSP::BSP> bsp;
std::vector<Texture> textures;
@ -77,6 +79,7 @@ struct Renderer {
bool visibility_testing = false;
bool show_bboxes = false;
bool should_close = false;
bool wireframe_mode = false;
size_t n_indices;

View File

@ -11,7 +11,7 @@
#include <cstring>
using namespace Q3BSP;
using namespace HLBSP;
static inline void copy_data(void* file_data, std::string& dst, Lump& lump) {
dst.resize(lump.len);
@ -20,6 +20,7 @@ static inline void copy_data(void* file_data, std::string& dst, Lump& lump) {
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);
}
@ -27,7 +28,8 @@ static inline void copy_data(void* file_data, std::vector<T>& dst, Lump& lump) {
void BSP::load_indices(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 (visibility_test) {
if(false) {
auto leaf_idx = determine_leaf(cam_pos);
auto fr_planes = frustum(view);
@ -36,11 +38,11 @@ void BSP::load_indices(const glm::vec3& cam_pos, bool visibility_test, const glm
index_buffer->upload(indices);
last_leaf = leaf_idx;
auto& cam_leaf = leafs[leaf_idx];
auto& cam_leaf = leaves[leaf_idx];
std::vector<Leaf> visible_leafs;
for (auto& leaf : leafs) {
for (auto& leaf : leaves) {
const auto min = leaf.bb_mins;
const auto max = leaf.bb_maxes;
@ -61,8 +63,8 @@ void BSP::load_indices(const glm::vec3& cam_pos, bool visibility_test, const glm
}
for (const auto& leaf : visible_leafs) {
for (size_t i = 0; i < leaf.n_leaf_faces; i++) {
auto idx = leaf_faces[leaf.first_leaf_face_idx + i].face_idx;
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;
@ -77,22 +79,27 @@ void BSP::load_indices(const glm::vec3& cam_pos, bool visibility_test, const glm
indices.clear();
for (auto& face : visible_faces) {
switch (face.type) {
case Face::ePATCH:
break;
case Face::ePOLYGON:
case Face::eMESH:
for (size_t i = 0; i < face.n_mesh_vertices; i++)
indices.push_back(face.first_vertex_idx + mesh_vertices[face.first_mesh_vertex_idx+i].idx);
break;
for (i16 i = 1, j = 2; j < face.n_surf_edges; i++, j++) {
indices.push_back(face.first_surf_edge_idx);
indices.push_back(face.first_surf_edge_idx+i);
indices.push_back(face.first_surf_edge_idx+j);
}
// indices.push_back(get_index_from_surfedge(face.first_surf_edge_idx));
}
assert(indices.size() % 3 == 0);
index_buffer->upload(indices);
}
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;
@ -112,16 +119,6 @@ int BSP::determine_leaf(glm::vec3 cam_pos) {
bool BSP::determine_visibility(const Leaf& cam_leaf, const Leaf& leaf, const std::array<glm::vec4, 6>& frustum, const glm::vec3 box_verts[8]) {
int vis = cam_leaf.cluster_idx, cluster = leaf.cluster_idx;
if (vis_info.vectors.size() == 0 || vis < 0)
return true;
int i = (vis * vis_info.sz_vectors) + (cluster >> 3);
u8 set = vis_info.vectors[i];
if (!(set & (1 << (cluster & 0x7))))
return false;
/* perform fustrum culling */
return box_in_frustum(frustum, box_verts);
}
@ -134,64 +131,109 @@ static inline void change_swizzle(T& v) {
v.z = tmp;
}
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("File size: %zu\n", file_data.size());
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->magic != BSP_MAGIC) {
Log::error("BSP file missing magic!\n");
if(header->version != 30) {
Log::error("BSP file not expected version (Half Life has version 30)!\n");
}
copy_data(file_data.data(), entities, header->entities);
copy_data(file_data.data(), textures, header->textures);
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.pos);
}
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);
}
copy_data(file_data.data(), leafs, header->leafs);
for (auto& leaf : leafs) {
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);
}
copy_data(file_data.data(), leaf_faces, header->leaf_faces);
copy_data(file_data.data(), leaf_brushes, header->leaf_brushes);
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);
vertices_prime.reserve(surfedges.size());
/* use this to build our vertices_prime, idea thanks to gzalo's HalfMapper */
for(const auto& s : surfedges) {
vertices_prime.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);
}
copy_data(file_data.data(), brushes, header->brushes);
copy_data(file_data.data(), brush_sides, header->brush_sides);
copy_data(file_data.data(), vertices, header->vertices);
/* correct for handedness */
for (auto& vertex : vertices) {
change_swizzle(vertex.pos);
change_swizzle(vertex.norm);
}
copy_data(file_data.data(), mesh_vertices, header->mesh_vertices);
copy_data(file_data.data(), effects, header->effects);
copy_data(file_data.data(), faces, header->faces);
copy_data(file_data.data(), lightmaps, header->lightmaps);
copy_data(file_data.data(), lightvols, header->lightvols);
vis_info.sz_vectors = reinterpret_cast<u32*>(file_data.data() + header->vis_info.offset)[1];
auto sz = header->vis_info.len;
vis_info.vectors.resize(sz);
std::memcpy(vis_info.vectors.data(), file_data.data() + header->vis_info.offset + 2*sizeof(u32), sz);
vertex_buffer = std::make_unique<GeneralVertexBuffer<Vertex>>(phys_dev, dev, vertices.size());
vertex_buffer->upload(vertices);
Log::debug("Creating vertex buffer of size %zu\n", vertices.size());
vertex_buffer = std::make_unique<GeneralVertexBuffer<Vertex>>(phys_dev, dev, vertices_prime.size());
vertex_buffer->upload(vertices_prime);
Log::debug("Creating index buffer\n");
/* set limit at 256Mi indices */
index_buffer = std::make_unique<Buffer>(phys_dev, dev, 100000 * sizeof(u32),
vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible

View File

@ -12,8 +12,14 @@
#include <Renderer/VertexBuffer.hpp>
#include <Renderer/Pipeline.hpp>
/* contains loading functions for Quake III-style BSPs */
namespace Q3BSP {
#define MAX_TEXTURE_NAME 16
#define MIP_LEVELS 4
#define MAX_MAP_HULLS 4
/* contains loading functions for Half Life BSPs */
namespace HLBSP {
struct Lump {
u32 offset;
u32 len;
@ -21,106 +27,63 @@ namespace Q3BSP {
using rgb = glm::u8vec3;
using rgba = glm::u8vec4;
/* "IBSP" */
const uint32_t BSP_MAGIC = 0x50534249U;
using vec3 = glm::vec3;
using ivec3 = glm::vec<3, i16>;
struct Header {
u32 magic;
u32 version;
union {
Lump lumps[17];
Lump lumps[15];
struct {
Lump entities,
textures,
planes,
nodes,
leafs,
leaf_faces,
leaf_brushes,
models,
brushes,
brush_sides,
textures,
vertices,
mesh_vertices,
effects,
visibility,
nodes,
texinfo,
faces,
lightmaps,
lightvols,
vis_info;
lighting,
clip_nodes,
leaves,
mark_surfaces,
edges,
surf_edges,
models;
};
};
};
struct Texture {
char name[64];
/* values of unknown meaning - TODO: check darkplaces or some other 3rd party loader */
i32 flags;
i32 contents;
};
struct Plane {
glm::vec3 norm;
vec3 norm;
float dist;
/* exists for certain optimizations (swaped y and z) */
enum PlaneType {
eX,
eZ,
eY,
eAnyX,
eAnyZ,
eAnyY,
} type;
};
struct Node {
u32 plane;
/* negative numbers are leaf indices */
i32 children[2];
/* bounding box coords (integer) */
glm::ivec3 bb_mins;
glm::ivec3 bb_maxes;
struct TextureLump {
u32 n_mip_textures;
i32 offsets[];
};
struct Leaf {
i32 cluster_idx;
u32 area;
glm::ivec3 bb_mins;
glm::ivec3 bb_maxes;
i32 first_leaf_face_idx;
u32 n_leaf_faces;
i32 first_leaf_brush_idx;
u32 n_leaf_brushes;
};
struct LeafFaces {
/* list of face indices (one list per leaf) */
i32 face_idx;
};
struct LeafBrush {
/* list of brush indices (one list leaf) */
i32 brush_idx;
};
struct Model {
glm::vec3 bb_mins;
glm::vec3 bb_maxes;
i32 first_face_idx;
u32 n_faces;
i32 first_brush_idx;
u32 n_brushes;
};
struct Brush {
i32 first_brushside_idx;
u32 n_brushsides;
i32 texture_idx;
};
struct BrushSide {
i32 plane_idx;
i32 texture_idx;
struct MipTexture {
char name[MAX_TEXTURE_NAME];
u32 width, height;
/* is 0 if stored in WAD, otherwise, offset is from beginning of this struct */
u32 mip_offsets[MIP_LEVELS];
};
struct Vertex {
glm::vec3 pos;
glm::vec2 uv;
glm::vec2 lightmap_coords;
glm::vec3 norm;
glm::u8vec4 color;
vec3 pos;
static inline std::vector<vk::VertexInputAttributeDescription> attrs(uint32_t binding) {
return std::vector<vk::VertexInputAttributeDescription> {
{
@ -128,109 +91,132 @@ namespace Q3BSP {
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(Vertex, pos),
}, {
.location = 1,
.binding = binding,
.format = vk::Format::eR32G32Sfloat,
.offset = offsetof(Vertex, uv),
}, {
.location = 2,
.binding = binding,
.format = vk::Format::eR32G32Sfloat,
.offset = offsetof(Vertex, lightmap_coords),
}, {
.location = 3,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(Vertex, norm),
}, {
.location = 4,
.binding = binding,
.format = vk::Format::eR32Uint,
.offset = offsetof(Vertex, color),
}
};
}
};
struct MeshVertex {
i32 idx;
struct Vis {};
struct Node {
i32 plane;
/* negative numbers are leaf indices */
i16 children[2];
/* bounding box coords (integer) */
ivec3 bb_mins;
ivec3 bb_maxes;
i16 first_face_idx;
i16 n_faces;
};
struct Effect {
char name[64];
i32 brush_idx;
/* almost always 5 for some reason */
i32 unknown;
struct TexInfo {
vec3 shift_s_dir;
float shift_s;
vec3 shift_t_dir;
float shift_t;
u32 mip_tex_idx;
/* seems to always be 0 */
u32 flags;
};
struct Face {
i32 texture_idx;
/* -1 if no effect */
i32 effect_idx;
enum FaceType {
ePOLYGON = 1,
ePATCH = 2,
eMESH = 3,
eBILLBOARD = 4,
} type;
i32 first_vertex_idx;
u32 n_vertices;
i32 first_mesh_vertex_idx;
u32 n_mesh_vertices;
i32 lightmap_idx;
glm::vec2 lightmap_start;
glm::vec2 lightmap_end;
glm::vec3 lightmap_origin;
glm::vec3 lightmap_unit_vectors[2];
glm::vec3 norm;
glm::ivec2 patch_dimensions;
u16 plane_idx;
/* set if different normals orientation */
u16 plane_side;
u32 first_surf_edge_idx;
i16 n_surf_edges;
i16 tex_info_idx;
u8 lighting_styles[4];
u32 lightmap_offset;
};
struct Lightmap {
u8 map[128][128][3];
rgb* lights;
};
struct Lightvol {
rgb ambient;
rgb directional;
/* spherical coordinates */
glm::u8vec2 direction;
struct ClipNode {
i32 plane_idx;
/* negative numbers are contents */
i16 children[2];
};
struct VisibilityInfo {
u32 sz_vectors;
std::vector<u8> vectors;
struct Leaf {
enum {
eEmpty = -1,
eSolid = -2,
eWater = -3,
eSlime = -4,
eLava = -5,
eSky = -6,
eOrigin = -7,
eClip = -8,
eCurrent0 = -9,
eCurrent90 = -10,
eCurrent180 = -11,
eCurrent270 = -12,
eCurrentUp = -13,
eCurrentDown = -14,
eTranslucent = -15,
} contents;
/* if this is -1, no VIS data */
i32 vis_offset;
ivec3 bb_mins;
ivec3 bb_maxes;
u16 first_mark_surface_idx;
u16 n_mark_surfaces;
u8 ambient_sound_levels[4];
};
typedef u16 MarkSurface;
struct Edge {
u16 vertex_indices[2];
};
typedef i32 Surfedge;
struct Model {
vec3 bb_mins;
vec3 bb_maxes;
vec3 origin;
i32 head_node_indices[MAX_MAP_HULLS];
i32 vis_leafs;
i32 first_face_idx;
i32 n_faces;
};
struct BSP {
BSP(vk::PhysicalDevice phys_dev, vk::Device dev, const std::string& fname);
void load_indices(const glm::vec3& cam_pos, bool visibility_testing, const glm::mat4& view);
int determine_leaf(glm::vec3 cam_pos);
bool determine_visibility(const Leaf& cam_leaf, const Leaf& leaf, const std::array<glm::vec4, 6>& frustum, const glm::vec3 box_verts[8]);
void load_indices(const vec3& cam_pos, bool visibility_testing, const glm::mat4& view);
int determine_leaf(vec3 cam_pos);
bool determine_visibility(const Leaf& cam_leaf, const Leaf& leaf, const std::array<glm::vec4, 6>& frustum, const vec3 box_verts[8]);
int get_index_from_surfedge(int surfedge);
vk::Device dev;
Header* header;
std::string filename;
std::vector<u8> file_data;
std::string entities;
std::vector<Texture> textures;
std::vector<::std::map<::std::string, std::string>> entities;
std::vector<Plane> planes;
std::vector<Node> nodes;
std::vector<Leaf> leafs;
std::vector<LeafBrush> leaf_brushes;
std::vector<LeafFaces> leaf_faces;
std::vector<Model> models;
std::vector<Brush> brushes;
std::vector<BrushSide> brush_sides;
std::vector<MipTexture> textures;
std::vector<Vertex> vertices;
std::vector<MeshVertex> mesh_vertices;
std::vector<Effect> effects;
std::vector<Vertex> vertices_prime;
/* skipping vis for now */
std::vector<Node> nodes;
std::vector<TexInfo> tex_infos;
std::vector<Face> faces;
std::vector<Lightmap> lightmaps;
std::vector<Lightvol> lightvols;
VisibilityInfo vis_info;
Lightmap lightmap;
std::vector<ClipNode> clip_nodes;
std::vector<Leaf> leaves;
std::vector<MarkSurface> mark_surfaces;
std::vector<Edge> edges;
std::vector<Surfedge> surfedges;
std::vector<Model> models;
std::vector<u32> indices;
std::unique_ptr<Buffer> index_buffer;

View File

@ -12,6 +12,9 @@
#include <Scene/Camera.hpp>
/* this pains me to do, but its the only way :( */
Renderer* __ren;
static csys::ItemLog& operator<<(csys::ItemLog& log, ImVector<float>& vec) {
if (!vec.size())
return log << "vector<f32> {}";
@ -21,12 +24,15 @@ static csys::ItemLog& operator<<(csys::ItemLog& log, ImVector<float>& vec) {
return log << vec[vec.size() - 1] << " }";
}
/*static void vec_setter(ImVector<float>& v, std::vector<float> in) {
v.reserve(in.size());
std::memcpy(v.Data, in.data(), sizeof(float) * in.size());
}*/
static void wireframe_setter(bool& v, bool in) {
if(v == in)
return;
v = in;
__ren->bsp->pipeline->rebuild(in);
}
UI::UI(Renderer* ren) : ren(ren), dev(ren->dev) {
__ren = ren;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
@ -117,6 +123,7 @@ UI::UI(Renderer* ren) : ren(ren), dev(ren->dev) {
"flycam",
"speed",
"max_fps",
"wireframe",
};
for(const auto& name : names)
@ -129,6 +136,8 @@ UI::UI(Renderer* ren) : ren(ren), dev(ren->dev) {
console->System().RegisterVariable("speed", ren->speed, csys::Arg<float>("value"));
console->System().RegisterVariable("max_fps", ren->max_fps, csys::Arg<float>("value"));
console->System().RegisterVariable("wireframe", ren->wireframe_mode, wireframe_setter);
console->System().Log(csys::ItemType::eINFO) << "Welcome to Pleascach!" << csys::endl;
}
@ -157,9 +166,8 @@ void UI::render(vk::CommandBuffer cmd) {
}
UI::~UI() {
dev.destroyDescriptorPool(desc_pool);
console.reset();
dev.destroyDescriptorPool(desc_pool);
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();

View File

@ -1,8 +1,6 @@
#version 460 core
layout (location = 0) in vec3 norm;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec4 color;
layout (location = 0) in vec4 color;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
@ -20,5 +18,5 @@ layout (set = 0, binding = 0) uniform Matrices {
layout (set = 0, binding = 1) uniform sampler2D tex;
void main() {
FragColor = color;
FragColor = (color + vec4(1.0)) / 2.0;
}

View File

@ -1,13 +1,7 @@
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 2) in vec2 lightmapCoord;
layout (location = 3) in vec3 aNorm;
layout (location = 4) in uint aColor;
layout (location = 0) out vec3 norm;
layout (location = 1) out vec2 texCoord;
layout (location = 2) out vec4 color;
layout (location = 0) out vec4 color;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
@ -34,7 +28,6 @@ vec4 unpackABGR(uint packedABGR) {
void main() {
gl_Position = proj * view * vec4(aPos, 1.0);
texCoord = aTexCoord;
norm = aNorm;
color = unpackABGR(aColor);
color = vec4(normalize(aPos), 1.0);
}

View File

@ -22,9 +22,8 @@ int main(int argc, char* argv[]) {
Renderer ren(win);
in->setCursor(false);
bool should_close = false;
while (!in->shouldClose() || ren.should_close) {
while (!in->shouldClose() && !ren.should_close) {
Timer frame_timer;
in->poll();
in->handleMovementKeys(ren);
@ -88,5 +87,5 @@ int main(int argc, char* argv[]) {
}
quit:
Log::info("Quitting");
Log::info("Quitting\n");
}