Compare commits

..

10 Commits

106 changed files with 1044 additions and 2923 deletions

3
.gitignore vendored
View File

@ -15,9 +15,6 @@
*.userprefs
# compiled shaders
assets/shaders/*.spv
# Mono auto generated files
mono_crash.*

View File

@ -4,9 +4,9 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(WIN32)
set(CMAKE_CXX_FLAGS "")
set(CMAKE_CXX_FLAGS "-D_DEBUG")
else()
set(CMAKE_CXX_FLAGS "-D_DEBUG -Wall")
set(CMAKE_CXX_FLAGS "-D_DEBUG -Wall -D_GLIBCXX_DEBUG -g -fsanitize=address")
endif()
project(Pleascach)
@ -25,22 +25,17 @@ add_executable (pleascach ${SOURCES})
# shader compilation
file(GLOB SHADER_SOURCE_FILES
assets/shaders/**/*.frag
assets/shaders/**/*.vert
assets/shaders/**/*.geom
assets/shaders/**/*.tese
assets/shaders/**/*.tesc
assets/shaders/*/*/*.frag
assets/shaders/*/*/*.vert
assets/shaders/*/*/*.geom
assets/shaders/*/*/*.tese
assets/shaders/*/*/*.tesc
assets/shaders/*.frag
assets/shaders/*.vert
assets/shaders/*.geom
assets/shaders/*.tese
assets/shaders/*.tesc
)
foreach(SHADER_SOURCE ${SHADER_SOURCE_FILES})
message("Processing shader file")
get_filename_component(FILE_NAME ${SHADER_SOURCE} NAME)
set(SPIRV "${CMAKE_SOURCE_DIR}/assets/shaders/bin/${FILE_NAME}.spv")
set(SPIRV "${CMAKE_SOURCE_DIR}/assets/shaders/${FILE_NAME}.spv")
add_custom_command(
OUTPUT ${SPIRV}
COMMAND glslc -o ${SPIRV} ${SHADER_SOURCE}
@ -49,6 +44,7 @@ foreach(SHADER_SOURCE ${SHADER_SOURCE_FILES})
list(APPEND SPIRV_BIN_FILES ${SPIRV})
endforeach(SHADER_SOURCE)
add_custom_target (
shaders
DEPENDS ${SPIRV_BIN_FILES}

View File

@ -77,25 +77,23 @@ void Input::handleMovementKeys(Renderer& ren) {
if (ImGui::GetIO().WantCaptureKeyboard && ren.in_menu)
return;
auto dir = ren.cam.dir();
glm::vec3 forward;
if (ren.flycam)
forward = glm::normalize(glm::vec3(glm::sin(ren.cam.theta)*glm::cos(ren.cam.phi), glm::cos(ren.cam.theta), glm::sin(ren.cam.theta)*glm::sin(ren.cam.phi)));
else {
forward = glm::normalize(glm::vec3(glm::cos(ren.cam.phi), 0.0, glm::sin(ren.cam.phi)));
}
forward = dir;
else
forward = glm::normalize(glm::vec3(dir.x, 0.0, dir.z));
const auto right = glm::normalize(glm::cross(forward, glm::vec3(0.0, 1.0, 0.0)));
auto speed = glfwGetKey(in, GLFW_KEY_LEFT_SHIFT)? 2.0f : 1.0f;
speed *= ren.speed * ren.frametime / 8.0;
const auto up = glm::normalize(glm::cross(right, forward));
const auto speed = glfwGetKey(in, GLFW_KEY_LEFT_SHIFT)? 2.0f : 1.0f;
if(glfwGetKey(in, GLFW_KEY_UP)) {
ren.cam.theta -= 0.01;
}
if(glfwGetKey(in, GLFW_KEY_UP)) {
ren.cam.theta -= 0.01;
ren.cam.theta -= 0.02;
}
if(glfwGetKey(in, GLFW_KEY_DOWN)) {
ren.cam.theta += 0.01;
ren.cam.theta += 0.02;
}
if(glfwGetKey(in, GLFW_KEY_LEFT)) {
@ -107,28 +105,28 @@ void Input::handleMovementKeys(Renderer& ren) {
}
/* move "forward" or "backward" */
if (glfwGetKey(in, GLFW_KEY_W)) {
ren.cam.pos += forward * 1.0f * speed;
ren.cam.pos += forward * 0.1f * speed;
}
if (glfwGetKey(in, GLFW_KEY_S)) {
ren.cam.pos += forward * -1.0f * speed;
ren.cam.pos += forward * -0.1f * speed;
}
/* move "left" or "right" */
if (glfwGetKey(in, GLFW_KEY_A)) {
ren.cam.pos -= right * 1.0f * speed;
ren.cam.pos -= right * 0.1f * speed;
}
if (glfwGetKey(in, GLFW_KEY_D)) {
ren.cam.pos += right * 1.0f * speed;
ren.cam.pos += right * 0.1f * speed;
}
if(glfwGetKey(in, GLFW_KEY_SPACE)) {
ren.cam.pos.y += 1.0 * speed;
ren.cam.pos.y += 0.1;
}
if(glfwGetKey(in, GLFW_KEY_LEFT_CONTROL)) {
ren.cam.pos.y -= 1.0 * speed;
ren.cam.pos.y -= 0.1;
}
ren.cam.theta = glm::clamp(ren.cam.theta, 0.01f, glm::pi<float>() - 0.01f);
@ -149,8 +147,9 @@ void Input::handleCursorMovement(Renderer& ren, double x, double y) {
return;
}
ren.cam.phi += rel_mouse_x / 100.0;
ren.cam.theta += rel_mouse_y / 100.0;
// scaling factor
ren.cam.phi += rel_mouse_x / 200.0;
ren.cam.theta += rel_mouse_y / 200.0;
last_mouse = glm::vec2(x,y);

View File

@ -1,160 +0,0 @@
#include <Model/Model.hpp>
#include <util/log.hpp>
#include <util/file.hpp>
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <tinygltf/tiny_gltf.h>
#include <glm/gtc/type_ptr.hpp>
Model::Model(vk::PhysicalDevice phys_dev, vk::Device dev, const std::string& fname) {
Log::debug("Loading model " + fname + "\n");
tinygltf::TinyGLTF loader;
std::string err, warn;
model = std::make_shared<tinygltf::Model>();
auto ret = loader.LoadASCIIFromFile(model.get(), &err, &warn, fname);
if(!warn.empty()) {
Log::debug(fname + ": " + warn);
}
if(!err.empty()) {
Log::debug(fname + ": " + err);
}
if(!ret) {
Log::error("Failed to pase glTF model\n");
}
for(auto& node: model->nodes)
initNode(node, nullptr);
/* vertex, index buffer should be populated now */
Log::debug("%zu vertices loaded from model " + fname + "\n", vertices.size());
vertex_buffer = std::make_unique<VertexBuffer>(phys_dev, dev, vertices.size());
vertex_buffer->upload(vertices);
index_buffer = std::make_unique<Buffer>(phys_dev, dev, indices.size()*sizeof(uint16_t),
vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
index_buffer->upload(reinterpret_cast<uint8_t*>(indices.data()), static_cast<vk::DeviceSize>(indices.size()*sizeof(uint16_t)));
}
void Model::initVertices(Node* node, const tinygltf::Primitive& prim) {
Log::debug("Loading vertices\n");
uint32_t first_idx = indices.size();
uint32_t vert_start = vertices.size();
uint32_t idx_count = 0;
const float* pos_buff = nullptr;
const float* norm_buff = nullptr;
const float* uv_buff = nullptr;
size_t vertex_count = 0;
auto loc = prim.attributes.find("POSITION");
if(loc != prim.attributes.end()) {
auto& accessor = model->accessors[loc->second];
const auto& view = model->bufferViews[accessor.bufferView];
pos_buff = reinterpret_cast<const float*>(&model->buffers[view.buffer].data[accessor.byteOffset+view.byteOffset]);
vertex_count = accessor.count;
}
loc = prim.attributes.find("NORMAL");
if(loc != prim.attributes.end()) {
auto& accessor = model->accessors[loc->second];
const auto& view = model->bufferViews[accessor.bufferView];
norm_buff = reinterpret_cast<const float*>(&model->buffers[view.buffer].data[accessor.byteOffset+view.byteOffset]);
}
loc = prim.attributes.find("TEXCOORD_0");
if(loc != prim.attributes.end()) {
auto& accessor = model->accessors[loc->second];
const auto& view = model->bufferViews[accessor.bufferView];
uv_buff = reinterpret_cast<const float*>(&model->buffers[view.buffer].data[accessor.byteOffset+view.byteOffset]);
}
for(size_t i = 0; i < vertex_count; i++) {
vertices.push_back(glTFVertex {
.pos = pos_buff? glm::make_vec3(pos_buff+i*3) : glm::vec3(0.0),
.norm = norm_buff? glm::normalize(glm::make_vec3(norm_buff+i*3)) : glm::vec3(0.0),
.uv = uv_buff? glm::make_vec2(uv_buff+i*2) : glm::vec2(0.0),
.color = glm::vec3(0.0),
});
}
Log::debug("Finished loading %zu vertices\n", vertex_count);
const auto& accessor = model->accessors[prim.indices];
const auto& view = model->bufferViews[accessor.bufferView];
const auto& buffer = model->buffers[view.buffer];
idx_count += accessor.count;
switch(accessor.componentType) {
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT:
for(size_t i = 0; i < accessor.count; i++)
indices.push_back(
reinterpret_cast<const uint32_t*>(
&buffer.data[accessor.byteOffset+view.byteOffset
])[i]
+ vert_start
);
break;
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT:
for(size_t i = 0; i < accessor.count; i++)
indices.push_back(
reinterpret_cast<const uint16_t*>(
&buffer.data[accessor.byteOffset+view.byteOffset
])[i]
+ vert_start
);
break;
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE:
for(size_t i = 0; i < accessor.count; i++)
indices.push_back(
reinterpret_cast<const uint8_t*>(
&buffer.data[accessor.byteOffset+view.byteOffset
])[i]
+ vert_start
);
break;
default:
Log::error("Unrecognized index type in model\n");
break;
}
Log::debug("Loaded %zu indices of type %d\n", accessor.count, (accessor.componentType-TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE)/2+1);
node->mesh.push_back(Primitive {
.first_idx = first_idx,
.idx_count = idx_count,
});
}
void Model::initNode(const tinygltf::Node& node, Node* parent, int level) {
Log::debug("%*sNode:"+node.name+"\n", level*4, " ");
Node* ret = new Node;
ret->parent = parent;
/* load kids */
for(auto& child_idx : node.children) {
initNode(model->nodes[child_idx], ret, level+1);
}
if(node.mesh >= 0) {
const auto& mesh = model->meshes[node.mesh];
for(auto& prim : mesh.primitives) {
initVertices(ret, prim);
}
}
if(ret->parent)
ret->parent->children.push_back(ret);
else
nodes.push_back(ret);
}

View File

@ -1,54 +0,0 @@
#pragma once
#include <Memory/Buffer.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <memory>
#include <glm/glm.hpp>
#include <tinygltf/tiny_gltf.h>
struct Model {
struct Primitive {
uint32_t first_idx;
uint32_t idx_count;
uint32_t mat_idx;
};
using Mesh = std::vector<Primitive>;
struct Node {
Node* parent;
std::vector<Node*> children;
Mesh mesh;
glm::mat4 mat;
~Node() {
for(auto& n : children)
delete n;
}
};
Model(vk::PhysicalDevice phys_dev, vk::Device dev, const std::string& fname);
std::shared_ptr<tinygltf::Model> model;
void initVertices(Node*, const tinygltf::Primitive&);
std::unique_ptr<VertexBuffer> vertex_buffer;
std::unique_ptr<Buffer> index_buffer;
std::vector<glTFVertex> vertices;
std::vector<uint16_t> indices;
/* recusively initialize nodes with an accumulative vertex and index buffer collector */
void initNode(const tinygltf::Node& node, Node* parent, int level = 0);
std::vector<Node*> nodes;
~Model() {
for(auto& n : nodes)
delete n;
vertex_buffer.reset();
index_buffer.reset();
}
};

View File

@ -1,34 +1,12 @@
# Pléascach
# Pléascach - Dronuilleog
###### Check out the raymarching branch (pléascach-dronuilleog)!
No models, everything RAYMARCHED!!!!
Small Vulkan 3D renderer.
![really cool wireframe tessellated terrain)](terrain_capture.png "Terrain Capture")
![Quake 3 style map (unlit)](bsp_capture.png "BSP Capture")
#### List of 3rd party code included in this repository:
- Imgui (and Imgui-console): for debugging UI
- STB: for image loading
- GLM: for math
- GLFW: for cross-platform windowing
- TinyglTF: for glTF parsing
## Features
- glTF Model loading
- QuakeIII BSP Map Loading
- Tessellation-controlled heightmap terrains with dynamic normal calculation
- Working lighting!
## Short Term Changes
- Make index buffer device-local instead of host-coherent
- Possibly restructure Buffer class to use templates to change
constructor and functions to use staging buffers if needed.
## Constant Improvements
- Add more comments
## Long Term Improvements
- ~~Properly query surface to find supported formats for surfaces~~
- Fix all this cleanup vs destructor NONSENSE (inconsistency)
- Add pipeline caching
- Make more robust solution to window minimization (flushing out Input system should provide candidates)
- Command buffer per swapchain image
- Make smaller memory allocation object to pass around instead of directly passing physical device to everything

View File

@ -2,10 +2,6 @@
#include <Renderer/Pipeline.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <Scene/Terrain.hpp>
#include <Model/Model.hpp>
#include <Memory/Buffer.hpp>
#include <Memory/Image.hpp>
@ -65,30 +61,18 @@ void CommandBuffer::copy(Buffer& src, Image& dst, vk::ImageLayout layout) {
void CommandBuffer::bind(const GraphicsPipeline& pipeline) {
command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.pipeline);
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.layout, 0, pipeline.desc_set, nullptr);
}
void CommandBuffer::bind(vk::PipelineLayout layout, vk::ArrayProxy<vk::DescriptorSet> desc_sets) {
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, desc_sets, nullptr);
}
void CommandBuffer::bind(std::shared_ptr<Model> model) {
bind(*model->vertex_buffer);
command_buffer.bindIndexBuffer(*model->index_buffer, 0, vk::IndexType::eUint16);
void CommandBuffer::bind(const VertexBuffer& vertex_buffer, uint32_t binding) {
const std::array<vk::DeviceSize, 1> offsets = {0};
command_buffer.bindVertexBuffers(binding, vertex_buffer.buffer->buffer, offsets);
}
void CommandBuffer::bind(Terrain* terrain) {
bind(*terrain->vertex_buffer);
command_buffer.bindIndexBuffer(*terrain->index_buffer, 0, vk::IndexType::eUint32);
}
void CommandBuffer::bind(HLBSP::BSP* bsp) {
bind(*bsp->pipeline);
bind(*bsp->vertex_buffer);
bind(bsp->pipeline->layout, bsp->pipeline->desc_set);
}
void CommandBuffer::draw(uint32_t vertex_count, uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance) {
command_buffer.draw(vertex_count, instance_count, first_vertex, first_instance);
}
@ -99,7 +83,6 @@ void CommandBuffer::end() {
void CommandBuffer::recycle() {
command_buffer.reset();
}
void CommandBuffer::cleanup(vk::Device dev) {

View File

@ -7,14 +7,11 @@
#include <memory>
#include <Renderer/VertexBuffer.hpp>
#include <Scene/BSP.hpp>
struct Buffer;
struct Image;
struct GraphicsPipeline;
struct ComputePipeline;
struct VertexBuffer;
struct Model;
struct Terrain;
@ -33,17 +30,7 @@ struct CommandBuffer {
void bind(const GraphicsPipeline& pipeline);
void bind(vk::PipelineLayout layout, vk::ArrayProxy<vk::DescriptorSet> desc_sets);
template <typename Vertex>
void bind(const GeneralVertexBuffer<Vertex>& vertex_buffer, uint32_t binding = 0) {
const std::array<vk::DeviceSize, 1> offsets = { 0 };
command_buffer.bindVertexBuffers(binding, vertex_buffer.buffer->buffer, offsets);
}
void bind(std::shared_ptr<Model> model);
void bind(Terrain* terrain);
void bind(HLBSP::BSP* bsp);
void bind(const VertexBuffer& vertex_buffer, uint32_t binding = 0);
void draw(uint32_t vertex_count, uint32_t instance_count, uint32_t first_vertex = 0, uint32_t first_instance = 0);

View File

@ -2,6 +2,7 @@
#include <Renderer/Shader.hpp>
#include <Renderer/RenderPass.hpp>
#include <Renderer/UniformBuffer.hpp>
#include <Renderer/ShaderBuffer.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <Resources/Texture.hpp>
@ -9,9 +10,7 @@
#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, bool wireframe, bool culling)
: dev(dev), shaders(shaders), extent(extent), render_pass(render_pass), bindings(bindings), vertex_binding(vertex_binding), vertex_attrs(vertex_attrs), type(type) {
GraphicsPipeline::GraphicsPipeline(vk::Device dev, const std::vector<Shader>& shaders, const vk::Extent2D& extent, const RenderPass& render_pass, vk::ArrayProxy<vk::DescriptorSetLayoutBinding> bindings, const VertexBuffer& vertex_buffer) : dev(dev) {
/* create layout
* Eventually add a graphicspipline constructor that allows specification of layouts etc
* kinda like how Image::Image has all those versions
@ -57,93 +56,65 @@ 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 */
vertex_bindings = {
vertex_binding,
const std::vector<vk::VertexInputBindingDescription> vertex_bindings = {
vertex_buffer.binding(0),
};
vertex_input_info = vk::PipelineVertexInputStateCreateInfo {
auto attrs = vertex_buffer.attrs(0);
const auto 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(),
.vertexAttributeDescriptionCount = static_cast<uint32_t>(attrs.size()),
.pVertexAttributeDescriptions = attrs.data(),
};
input_asm_info = vk::PipelineInputAssemblyStateCreateInfo {
const auto input_asm_info = vk::PipelineInputAssemblyStateCreateInfo{
.topology = vk::PrimitiveTopology::eTriangleList,
/* matters later if we use strip primitives */
.primitiveRestartEnable = vk::False,
};
switch (type) {
case eVERTEX:
case eGLTF:
case eBSP:
input_asm_info.topology = vk::PrimitiveTopology::eTriangleList;
break;
case eTERRAIN:
input_asm_info.topology = vk::PrimitiveTopology::ePatchList;
break;
case eBOX:
input_asm_info.topology = vk::PrimitiveTopology::ePointList;
break;
}
const vk::PipelineTessellationStateCreateInfo* ptesselation_info = nullptr;
tess_info = vk::PipelineTessellationStateCreateInfo {
/* quads*/
.patchControlPoints = 4,
};
if(type == Type::eTERRAIN) {
ptesselation_info = &tess_info;
}
raster_info = vk::PipelineRasterizationStateCreateInfo {
const auto raster_info = vk::PipelineRasterizationStateCreateInfo {
.depthClampEnable = vk::False,
.polygonMode = (type == eBOX || wireframe) ? vk::PolygonMode::eLine : vk::PolygonMode::eFill,
.cullMode = (type == eBOX || !culling) ? vk::CullModeFlagBits::eNone : vk::CullModeFlagBits::eBack,
.polygonMode = vk::PolygonMode::eFill,
.cullMode = vk::CullModeFlagBits::eNone,
.frontFace = vk::FrontFace::eCounterClockwise,
.depthBiasEnable = type == eBOX,
.depthBiasConstantFactor = 0.01,
.depthBiasEnable = vk::False,
.lineWidth = 1.0,
};
multisample_info = vk::PipelineMultisampleStateCreateInfo {
const auto multisample_info = vk::PipelineMultisampleStateCreateInfo {
.rasterizationSamples = vk::SampleCountFlagBits::e1,
.sampleShadingEnable = vk::False,
};
depth_stencil_info = vk::PipelineDepthStencilStateCreateInfo{
.depthTestEnable = vk::True,
.depthWriteEnable = type != eBOX,
.depthCompareOp = vk::CompareOp::eLess,
const auto depth_stencil_info = vk::PipelineDepthStencilStateCreateInfo{
.depthTestEnable = vk::False,
.depthWriteEnable = vk::False,
.depthCompareOp = vk::CompareOp::eLessOrEqual,
.depthBoundsTestEnable = vk::False,
.stencilTestEnable = vk::False,
.minDepthBounds = 0.0,
.maxDepthBounds = 1.0,
};
color_blend_attachment = vk::PipelineColorBlendAttachmentState {
/* only the box has blending */
.blendEnable = type == eBOX,
.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha,
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
.colorBlendOp = vk::BlendOp::eMax,
.srcAlphaBlendFactor = vk::BlendFactor::eOne,
.dstAlphaBlendFactor = vk::BlendFactor::eZero,
.alphaBlendOp = vk::BlendOp::eAdd,
const auto color_blend_attachment = vk::PipelineColorBlendAttachmentState{
.blendEnable = vk::False,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eB
| vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eA,
};
blend_constants = {0.0f, 0.0f, 0.0f, 0.0f };
color_blend_info = vk::PipelineColorBlendStateCreateInfo{
const std::array<float, 4> blend_constants = {0.0f, 0.0f, 0.0f, 0.0f};
const auto color_blend_info = vk::PipelineColorBlendStateCreateInfo{
.logicOpEnable = vk::False,
.logicOp = vk::LogicOp::eCopy,
.attachmentCount = 1,
@ -152,34 +123,36 @@ 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 */
viewport = vk::Viewport{
const auto viewport = vk::Viewport{
.x = 0.0,
.y = static_cast<float>(extent.height),
.width = static_cast<float>(extent.width),
.height = -static_cast<float>(extent.height),
};
scissor = vk::Rect2D {
const auto scissor = vk::Rect2D {
.offset = 0,
.extent = extent,
};
viewport_info = vk::PipelineViewportStateCreateInfo {
const auto viewport_info = vk::PipelineViewportStateCreateInfo {
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
};
dyn_states[0] = vk::DynamicState::eScissor;
dyn_states[1] = vk::DynamicState::eViewport;
const vk::DynamicState dyn_states[] = {
vk::DynamicState::eScissor,
vk::DynamicState::eViewport,
};
dyn_info = vk::PipelineDynamicStateCreateInfo {
.dynamicStateCount = (uint32_t)std::size(dyn_states),
const auto dyn_info = vk::PipelineDynamicStateCreateInfo{
.dynamicStateCount = std::size(dyn_states),
.pDynamicStates = dyn_states,
};
pipeline_info = vk::GraphicsPipelineCreateInfo {
const auto pipeline_info = vk::GraphicsPipelineCreateInfo {
.stageCount = static_cast<uint32_t>(shaders.size()),
.pStages = shader_info.data(),
.pVertexInputState = &vertex_input_info,
@ -219,6 +192,21 @@ void GraphicsPipeline::update(uint32_t binding, const UniformBuffer& uni) {
}, nullptr);
}
void GraphicsPipeline::update(uint32_t binding, const ShaderBuffer& ssbo) {
auto buff_info = vk::DescriptorBufferInfo{
.buffer = ssbo,
.offset = 0,
.range = vk::WholeSize,
};
dev.updateDescriptorSets(vk::WriteDescriptorSet {
.dstSet = desc_set,
.dstBinding = binding,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eStorageBuffer,
.pBufferInfo = &buff_info,
}, nullptr);
}
void GraphicsPipeline::update(uint32_t binding, const Texture& tex) {
auto tex_info = vk::DescriptorImageInfo {
.sampler = tex.sampler,
@ -235,30 +223,7 @@ void GraphicsPipeline::update(uint32_t binding, const Texture& tex) {
}, nullptr);
}
void GraphicsPipeline::rebuild(bool wireframe, bool culling) {
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.cullMode = culling ? vk::CullModeFlagBits::eBack : vk::CullModeFlagBits::eNone;
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,81 +3,34 @@
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <util/log.hpp>
#include <Renderer/VertexBuffer.hpp>
struct Shader;
struct ShaderBuffer;
struct UniformBuffer;
struct VertexBuffer;
struct RenderPass;
struct Texture;
struct GraphicsPipeline {
enum Type {
eVERTEX,
eGLTF,
eBSP,
eTERRAIN,
eBOX,
};
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, bool wireframe = false, bool culling = true);
/* everything needed for recreation */
const VertexBuffer& vertex_buffer);
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;
}
/* create overload for every type of object we need to update */
void update(uint32_t binding, const UniformBuffer& uni);
void update(uint32_t binding, const ShaderBuffer& ssbo);
void update(uint32_t binding, const Texture& tex);
void rebuild(bool wireframe, bool culling);
~GraphicsPipeline();
};

View File

@ -43,7 +43,7 @@ RenderPass::RenderPass(vk::Device dev, vk::Format image_format, vk::Format depth
/* designates producer and consumer of the image to position subpass */
auto color_dep = vk::SubpassDependency {
auto color_dep = vk::SubpassDependency{
.srcSubpass = vk::SubpassExternal,
.dstSubpass = 0,
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,

View File

@ -15,12 +15,12 @@
#include <Renderer/UniformBuffer.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <Scene/March.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <UI/UI.hpp>
using namespace std::string_literals;
Renderer::Renderer(Window& win) : win(win) {
@ -194,40 +194,78 @@ Renderer::Renderer(Window& win) : win(win) {
uniform_buffer = std::make_unique<UniformBuffer>(phys_dev, dev);
objects.reserve(2);
uint id = 0;
objects.push_back(Object{
.center = glm::vec4(0.0),
.dimensions = glm::vec4(1.0),
.id = id,
.shape = Shape::eSPHERE,
});
objects.push_back(Object{
.center = glm::vec4(1.0),
.dimensions = glm::vec4(0.5),
.id = id,
.shape = Shape::eBOX,
});
#if 0
for (const auto& plane : bsp->planes) {
/* for planes, center.xyz holds normal, dimensions.x holds distance */
objects.push_back(Object{
.center = glm::vec4(plane.norm, 0.0),
.dimensions = glm::vec4(plane.dist, 0.0, 0.0, 0.0),
.id = id,
.shape = Shape::ePLANE,
});
id++;
}
#endif
shader_buffer = std::make_unique<ShaderBuffer>(phys_dev, dev, MAX_OBJECTS);
shader_buffer->upload(objects);
textures = createResources({
"assets/textures/oil.jpg",
});
std::vector<Shader> shaders = {
{dev, "assets/shaders/ray.vert.spv", vk::ShaderStageFlagBits::eVertex },
{ dev, "assets/shaders/ray.frag.spv", vk::ShaderStageFlagBits::eFragment },
};
std::vector<vk::DescriptorSetLayoutBinding> bindings = {
uniform_buffer->binding(0),
textures[0].binding(1),
shader_buffer->binding(2),
};
/* BSP loader */
bsp = std::make_unique<HLBSP::BSP>(phys_dev, dev, "assets/maps/dmc.bsp");
bsp_shaders = {
{ dev, "assets/shaders/bin/bsp.vert.spv", vk::ShaderStageFlagBits::eVertex },
{ dev, "assets/shaders/bin/bsp.frag.spv", vk::ShaderStageFlagBits::eFragment },
};
vertex_buffer = std::make_unique<VertexBuffer>(phys_dev, dev, 6);
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);
/* simple quad */
vertex_buffer->upload(std::vector<Vertex> {
{ { -1.0, -1.0 } },
{ { -1.0, 1.0 } },
{ { 1.0, 1.0 } },
{ { 1.0, 1.0 } },
{ { 1.0,-1.0 } },
{ { -1.0,-1.0 } },
});
/* bounding and hitboxs */
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 },
};
pipeline = std::make_unique<GraphicsPipeline>(dev, shaders, swapchain->extent, *render_pass, bindings, *vertex_buffer);
std::vector<BoxVertex> boxes;
boxes.reserve(bsp->leaves.size());
for (auto& leaf : bsp->leaves) {
boxes.push_back(BoxVertex{
.mins = leaf.bb_mins,
.maxes = leaf.bb_maxes,
});
}
box_buffer = std::make_unique<GeneralVertexBuffer<BoxVertex>>(phys_dev, dev, boxes.size());
box_buffer->upload(boxes);
pipeline->update(0, *uniform_buffer);
pipeline->update(1, textures[0]);
pipeline->update(2, *shader_buffer);
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 : shaders)
shader.cleanup();
ui = std::make_unique<UI>(this);
}
@ -317,7 +355,7 @@ void Renderer::draw() {
auto scissor = vk::Rect2D {
.offset = {0, 0},
.extent = win.getDimensions(),
.extent = swapchain->extent,
};
/* no secondary command buffers (yet), so contents are passed inline */
@ -325,38 +363,28 @@ void Renderer::draw() {
auto sz = win.getDimensions();
const auto p = glm::perspective(glm::radians(90.0f), static_cast<float>(sz.width) / static_cast<float>(sz.height), near_plane, far_plane);
/* re-upload objects if out-of-sync */
if(uniform_buffer->data_copy.n_objects != objects.size())
shader_buffer->upload(objects);
auto uni = UniformData{
.view = cam.view(),
.proj = p,
.time = time,
uniform_buffer->upload(UniformData{
.cam_pos = cam.pos,
.time = time,
.viewport = glm::vec4(viewport.width, viewport.y, 0.0, 0.0),
.cam_dir = cam.dir(),
.viewport = glm::vec2(viewport.width, viewport.y),
.tess_factor = tess_factor,
.tess_edge_size = tess_edge_size,
};
.n_objects = static_cast<unsigned int>(objects.size()),
.rad = rad,
});
std::memcpy(uni.frustum, frustum(p * uni.view).data(), sizeof(uni.frustum));
uniform_buffer->upload(uni);
command_buffer->bind(*pipeline);
command_buffer->command_buffer.setViewport(0, viewport);
command_buffer->command_buffer.setScissor(0, scissor);
bsp->load_vertices(cam.pos, visibility_testing, p * uni.view);
command_buffer->bind(bsp.get());
/*command_buffer->draw(bsp->vertices.size(), 1);*/
command_buffer->draw(bsp->textured_vertices.size(), 1);
n_indices = bsp->textured_vertices.size();
if (show_bboxes) {
command_buffer->bind(*box_pipeline);
command_buffer->bind(*box_buffer);
command_buffer->draw(box_buffer->buffer->size / sizeof(BoxVertex), 1);
}
command_buffer->bind(pipeline->layout, pipeline->desc_set);
command_buffer->bind(*vertex_buffer);
//shader_buffer->objects[0].center.y += glm::sin(time)/10.0;
command_buffer->command_buffer.draw(6, 1, 0, 0);
/* draw User Interface stuff */
ui->newFrame();
@ -403,26 +431,22 @@ void Renderer::present() {
default:
Log::error("Failed to present surface.\n");
break;
}
time += frametime / 1000.0 * speed * static_cast<float>(!paused);
frame++;
time += frametime / 1000.0 * speed * static_cast<float>(!paused);
}
Renderer::~Renderer() {
dev.waitIdle();
ui.reset();
bsp.reset();
box_buffer.reset();
box_pipeline.reset();
uniform_buffer.reset();
for (auto& shader : box_shaders)
shader.cleanup();
for (auto& shader : bsp_shaders)
shader.cleanup();
shader_buffer.reset();
vertex_buffer.reset();
pipeline.reset();
for (auto& tex : textures) {
tex.cleanup();

View File

@ -5,25 +5,23 @@
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <Renderer/Swapchain.hpp>
#include <Renderer/CommandBuffer.hpp>
#include <Renderer/RenderPass.hpp>
#include <Renderer/ShaderBuffer.hpp>
#include <Renderer/Swapchain.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <map>
#include <Scene/Camera.hpp>
#include <Scene/BSP.hpp>
#include <Scene/Terrain.hpp>
#include <Model/Model.hpp>
#include <UI/UI.hpp>
struct Window;
struct UniformBuffer;
struct VertexBuffer;
struct Texture;
#define MAX_OBJECTS 256
/* Contains all of the Vulkan objects involved in rendering the scene */
struct Renderer {
Renderer(Window& win);
@ -51,45 +49,39 @@ 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<GraphicsPipeline> pipeline;
/* just holds single quad */
std::unique_ptr<ShaderBuffer> shader_buffer;
std::unique_ptr<VertexBuffer> vertex_buffer;
std::unique_ptr<UniformBuffer> uniform_buffer;
std::vector<Shader> bsp_shaders;
std::unique_ptr<HLBSP::BSP> bsp;
std::vector<Texture> textures;
uint32_t current_image_idx;
uint64_t frame = 0;
std::vector<Object> objects;
std::unique_ptr<UI> ui;
Camera cam{ .pos = glm::vec3(0.0, 5.0, 0.0), };
Camera cam{ .pos = glm::vec3(0.0, 0.0, -1.0), };
float fps;
bool in_menu = false;
bool capture_mouse = false;
bool flycam = false;
/* time speed */
float time = 0.0;
float speed = 1.0;
bool paused = false;
bool visibility_testing = false;
bool show_bboxes = false;
bool should_close = false;
bool wireframe_mode = false;
bool backface_culling = true;
size_t n_indices;
float near_plane = 2.0f;
float far_plane = 10000.0f;
float tess_factor = 1.8f;
float tess_edge_size = 20.0f;
float frametime = 0.0;
float max_fps = 120.0;
float fps = 0.0;
float max_fps = 60.0;
float speed = 1.0;
float rad = 1.0;
bool in_menu = false;
bool should_close = false;
bool paused = false;
bool running = true;
std::map<std::string, int> scene_map;
std::string scene_file = "scene.txt";
};

View File

@ -0,0 +1,3 @@
#include <Renderer/ShaderBuffer.hpp>

54
Renderer/ShaderBuffer.hpp Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include <memory>
#include <util/glsl_types.hpp>
#include <Scene/Object.hpp>
#include <Memory/Buffer.hpp>
using namespace glsl;
/* Wrapper for SSBO */
struct ShaderBuffer {
ShaderBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, const size_t n_objects = 0x1000) : phys_dev(phys_dev), dev(dev), n_objects(n_objects) {
buffer = std::make_unique<Buffer>(
phys_dev, dev, n_objects * sizeof(Object),
vk::BufferUsageFlagBits::eStorageBuffer,
vk::MemoryPropertyFlagBits::eHostCoherent
| vk::MemoryPropertyFlagBits::eHostVisible
);
objects = reinterpret_cast<Object*>(buffer->p);
}
vk::PhysicalDevice phys_dev;
vk::Device dev;
size_t n_objects;
Object* objects;
std::unique_ptr<Buffer> buffer;
operator vk::Buffer&() const {
return *buffer;
}
inline vk::DescriptorSetLayoutBinding binding(uint32_t binding, vk::ShaderStageFlags stages = vk::ShaderStageFlagBits::eFragment) {
return vk::DescriptorSetLayoutBinding {
.binding = binding,
.descriptorType = vk::DescriptorType::eStorageBuffer,
.descriptorCount = 1,
.stageFlags = stages,
.pImmutableSamplers = nullptr,
};
}
inline void upload(const std::vector<Object>& scene) {
buffer->upload(reinterpret_cast<const uint8_t*>(scene.data()), scene.size() * sizeof(Object));
}
~ShaderBuffer() {
buffer.reset();
}
};

View File

@ -60,7 +60,7 @@ void Swapchain::create(vk::SwapchainKHR old_swapchain) {
/* see if this allows see through windows on Wayland */
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque,
/* waits for refresh (V-Sync), consider playing with relaxed fifo later on*/
// .presentMode = vk::PresentModeKHR::eFifoRelaxed,
// .presentMode = vk::PresentModeKHR::eFifo,
.presentMode = vk::PresentModeKHR::eMailbox,
.clipped = VK_TRUE,
.oldSwapchain = old_swapchain,

View File

@ -8,19 +8,9 @@ UniformBuffer::UniformBuffer(vk::PhysicalDevice phys_dev, vk::Device dev) {
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible
);
Log::debug("Offset of view: %zu\n", offsetof(UniformData, view));
Log::debug("Offset of proj: %zu\n", offsetof(UniformData, proj));
Log::debug("Offset of time: %zu\n", offsetof(UniformData, time));
Log::debug("Offset of pad0: %zu\n", offsetof(UniformData, pad0));
Log::debug("Offset of pad1: %zu\n", offsetof(UniformData, pad1));
Log::debug("Offset of pad2: %zu\n", offsetof(UniformData, pad2));
Log::debug("Offset of cam_pos: %zu\n", offsetof(UniformData, cam_pos));
Log::debug("Offset of viewport: %zu\n", offsetof(UniformData, viewport));
Log::debug("Offset of tess_factor: %zu\n", offsetof(UniformData, tess_factor));
Log::debug("Offset of tess_edge_size: %zu\n", offsetof(UniformData, tess_edge_size));
}
void UniformBuffer::upload(const UniformData& data) {
data_copy = data;
buffer->upload(reinterpret_cast<const uint8_t*>(&data), sizeof(UniformData));
}

View File

@ -9,43 +9,36 @@
#include <memory>
#include <util/glsl_types.hpp>
using namespace glsl;
/* Uniform:
*
* layout (set = 0, binding = 0) uniform Matrices {
* mat4 view;
* mat4 proj;
* float time;
* vec3 cam_pos;
* vec3 cam_dir;
* vec4 frustum[6];
* vec2 viewport;
* float tess_factor;
* float tess_edge_size;
* };
*
layout (set = 0, binding = 0) uniform Matrices {
vec3 cam_pos;
float time;
vec4 viewport;
vec3 cam_dir;
uint n_objects;
float rad;
};
*/
struct UniformData {
glm::mat4 view;
glm::mat4 proj;
vec3 cam_pos;
float time;
float pad0;
float pad1;
float pad2;
glm::vec3 cam_pos;
float pad3;
glm::vec3 cam_dir;
float pad4;
glm::vec4 frustum[6];
glm::vec2 viewport;
float tess_factor;
float tess_edge_size;
vec4 viewport;
vec3 cam_dir;
uint n_objects;
float rad;
};
struct UniformBuffer {
UniformBuffer(vk::PhysicalDevice phys_dev, vk::Device dev);
std::unique_ptr<Buffer> buffer;
UniformData data_copy { 0.0 };
void upload(const UniformData& data);

19
Renderer/VertexBuffer.cpp Normal file
View File

@ -0,0 +1,19 @@
#include <Renderer/VertexBuffer.hpp>
#include <Memory/Buffer.hpp>
#include <tinygltf/tiny_gltf.h>
VertexBuffer::VertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n_vertices) {
buffer = std::make_unique<Buffer>(phys_dev, dev, n_vertices * sizeof(Vertex),
vk::BufferUsageFlagBits::eVertexBuffer,
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
}
void VertexBuffer::upload(const std::vector<Vertex>& data) {
buffer->upload(reinterpret_cast<const uint8_t*>(data.data()), sizeof(Vertex)*data.size());
}
void VertexBuffer::upload(const tinygltf::Buffer& buff, const tinygltf::BufferView& view) {
std::memcpy(buffer->p, buff.data.data() + view.byteOffset, view.byteLength);
}

View File

@ -8,91 +8,18 @@
#include <tinygltf/tiny_gltf.h>
struct glTFVertex {
glm::vec3 pos;
glm::vec3 norm;
glm::vec2 uv;
glm::vec3 color;
static inline std::vector<vk::VertexInputAttributeDescription> attrs(uint32_t binding) {
return std::vector<vk::VertexInputAttributeDescription> {
{
.location = 0,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(glTFVertex, pos),
}, {
.location = 1,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(glTFVertex, norm),
}, {
.location = 2,
.binding = binding,
.format = vk::Format::eR32G32Sfloat,
.offset = offsetof(glTFVertex, uv),
}, {
.location = 3,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(glTFVertex, color),
}
};
}
struct Vertex {
glm::vec2 pos;
};
enum BoxType {
eBounding,
eEnemyHit,
};
/* for hitboxes and bounding boxes */
struct BoxVertex {
glm::vec3 mins;
glm::vec3 maxes;
unsigned int id;
static inline std::vector<vk::VertexInputAttributeDescription> attrs(uint32_t binding) {
return std::vector<vk::VertexInputAttributeDescription> {
{
.location = 0,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(BoxVertex, mins),
}, {
.location = 1,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(BoxVertex, maxes),
}, {
.location = 2,
.binding = binding,
.format = vk::Format::eR32Uint,
.offset = offsetof(BoxVertex, id),
}
};
}
};
template<typename Vertex>
struct GeneralVertexBuffer {
struct VertexBuffer {
std::unique_ptr<Buffer> buffer;
GeneralVertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n_vertices) {
buffer = std::make_unique<Buffer>(phys_dev, dev, n_vertices * sizeof(Vertex),
vk::BufferUsageFlagBits::eVertexBuffer,
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
}
void upload(const std::vector<Vertex>& data) {
buffer->upload(reinterpret_cast<const uint8_t*>(data.data()), sizeof(Vertex) * data.size());
}
void upload(const tinygltf::Buffer& buff, const tinygltf::BufferView& view) {
std::memcpy(buffer->p, buff.data.data() + view.byteOffset, view.byteLength);
}
VertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n_vertices);
void upload(const std::vector<Vertex>& data);
void upload(const tinygltf::Buffer& buff, const tinygltf::BufferView& view);
inline vk::VertexInputBindingDescription binding(uint32_t binding, vk::ShaderStageFlags stages = vk::ShaderStageFlagBits::eVertex) const {
return vk::VertexInputBindingDescription {
@ -103,9 +30,13 @@ struct GeneralVertexBuffer {
}
inline std::vector<vk::VertexInputAttributeDescription> attrs(uint32_t binding) const {
return Vertex::attrs(binding);
return std::vector<vk::VertexInputAttributeDescription> {
{
.location = 0,
.binding = binding,
.format = vk::Format::eR32G32Sfloat,
.offset = offsetof(Vertex, pos),
},
};
}
};
using VertexBuffer = GeneralVertexBuffer<glTFVertex>;
};

View File

@ -1,257 +0,0 @@
#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) {
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);
}

View File

@ -1,239 +0,0 @@
#pragma once
#include <util/int.hpp>
#include <glm/glm.hpp>
#include <vector>
#include <string>
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <Renderer/Pipeline.hpp>
#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;
};
using rgb = glm::u8vec3;
using rgba = glm::u8vec4;
using vec3 = glm::vec3;
using vec2 = glm::vec2;
using ivec3 = glm::vec<3, i16>;
struct Header {
u32 version;
union {
Lump lumps[15];
struct {
Lump entities,
planes,
textures,
vertices,
visibility,
nodes,
texinfo,
faces,
lighting,
clip_nodes,
leaves,
mark_surfaces,
edges,
surf_edges,
models;
};
};
};
struct Plane {
vec3 norm;
float dist;
/* exists for certain optimizations (swaped y and z) */
enum PlaneType {
eX,
eZ,
eY,
eAnyX,
eAnyZ,
eAnyY,
} type;
};
struct TextureLump {
u32 n_mip_textures;
i32 offsets[];
};
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 {
vec3 pos;
vec2 uv;
static inline std::vector<vk::VertexInputAttributeDescription> attrs(uint32_t binding) {
return std::vector<vk::VertexInputAttributeDescription> {
{
.location = 0,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(Vertex, pos),
}, {
.location = 1,
.binding = binding,
.format = vk::Format::eR32G32Sfloat,
.offset = offsetof(Vertex, uv),
}
};
}
};
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 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 {
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 {
rgb* lights;
};
struct ClipNode {
i32 plane_idx;
/* negative numbers are contents */
i16 children[2];
};
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_vertices(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::vector<::std::map<::std::string, std::string>> entities;
std::vector<Plane> planes;
std::vector<MipTexture> textures;
std::vector<glm::vec3> vertices;
std::vector<glm::vec3> processed_vertices;
/* skipping vis for now */
std::vector<Node> nodes;
std::vector<TexInfo> tex_infos;
std::vector<Face> faces;
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<Vertex> textured_vertices;
std::unique_ptr<GeneralVertexBuffer<Vertex>> vertex_buffer;
std::unique_ptr<GraphicsPipeline> pipeline;
/* to eliminate needless re-loading*/
int last_leaf = -0x1337;
~BSP() {
vertex_buffer.reset();
pipeline.reset();
}
};
}

View File

@ -15,7 +15,11 @@ struct Camera {
glm::vec3 pos = glm::vec3(0.0f);
inline glm::vec3 dir() {
return glm::vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
return glm::vec3(
sin(theta) * cos(phi),
cos(theta),
sin(theta) * sin(phi)
);
}
inline glm::mat4 view() {

168
Scene/March.hpp Normal file
View File

@ -0,0 +1,168 @@
#pragma once
/* file format for storing raymarched scene for dynamic SDF */
#include <Scene/Object.hpp>
#include <util/log.hpp>
#include <fstream>
#include <map>
namespace March {
static std::vector<Object> readFile(const std::string& fname, std::map<std::string, int>& name_map) {
/* this should be rewritten once we are loading more than 250 objects */
std::ifstream in(fname);
std::vector<Object> ret;
Object tmp;
std::string name;
std::string type;
int id = 0;
while(in >> type) {
Log::info("Object Type: %s\n", type.c_str());
char dummy;
in >> dummy;
if (dummy != '(') {
Log::error("Expected '(', found %c\n", dummy);
}
in >> tmp.center.x;
in >> tmp.center.y;
in >> tmp.center.z;
in >> dummy;
if (dummy != ')') {
Log::error("Expected ')', found %c\n", dummy);
}
if (type == "SPHERE") {
tmp.shape = Shape::eSPHERE;
char dummy;
in >> dummy;
if (dummy != '(') {
Log::error("Expected '(', found %c\n", dummy);
}
in >> tmp.dimensions.x;
in >> dummy;
if (dummy != ')') {
Log::error("Expected ')', found %c\n", dummy);
}
} else if (type == "BOX") {
tmp.shape = Shape::eBOX;
char dummy;
in >> dummy;
if (dummy != '(') {
Log::error("Expected '(', found %c\n", dummy);
}
in >> tmp.dimensions.x;
in >> tmp.dimensions.y;
in >> tmp.dimensions.z;
in >> dummy;
if (dummy != ')') {
Log::error("Expected ')', found %c\n", dummy);
}
} else {
Log::error("Expected type name, but not recognized %s!\n", type.c_str());
}
in >> name;
if (name_map.find(name) == name_map.end())
name_map[name] = id++;
tmp.id = name_map[name];
ret.push_back(tmp);
}
return ret;
}
static std::string find_name(const std::map<std::string, int>& map, const int id, bool& found) {
found = false;
std::string name = "##";
for (const auto& p : map) {
if (p.second == id) {
found = true;
name = p.first;
break;
}
}
return name;
}
static void add_sphere(const std::string& name, glm::vec3 center, float rad, Renderer* ren) {
unsigned int id = 0xDEADBEEF;
if (ren->scene_map.find(name) == ren->scene_map.end()) {
/* start iterating from the number of total objects, which will break immediately if stuff is deleted and new things added before saving, so please change this */
id = ren->scene_map.size();
ren->scene_map[name] = id;
} else {
id = ren->scene_map[name];
}
ren->objects.push_back(Object{
.center = glm::vec4(center.x, center.y, center.z, 0.0),
.dimensions = glm::vec4(rad),
.id = id,
.shape = eSPHERE,
});
}
static void add_box(const std::string& name, glm::vec3 center, glm::vec3 dim, Renderer* ren) {
unsigned int id = 0xDEADBEEF;
if (ren->scene_map.find(name) == ren->scene_map.end()) {
/* start iterating from the number of total objects, which will break immediately if stuff is deleted and new things added before saving, so please change this */
id = ren->scene_map.size();
ren->scene_map[name] = id;
} else {
id = ren->scene_map[name];
}
ren->objects.push_back(Object{
.center = glm::vec4(center.x, center.y, center.z, 0.0),
.dimensions = glm::vec4(dim.x, dim.y, dim.z, 0.0),
.id = id,
.shape = eBOX,
});
}
static void writeFile(const std::string& fname, const std::vector<Object>& objs, const std::map<std::string, int>& map) {
std::ofstream out(fname);
const char* shape_names[] = {
"SPHERE",
"BOX",
"PLANE",
};
int anon = 0;
for (const auto& obj : objs) {
out << shape_names[obj.shape] << " ( " << obj.center.x << " " << obj.center.y << " " << obj.center.z << " ) ( ";
switch (obj.shape) {
case eSPHERE:
out << obj.dimensions.x << " ";
break;
case eBOX:
out << obj.dimensions.x << " "
<< obj.dimensions.y << " "
<< obj.dimensions.z << " ";
break;
case ePLANE:
out << obj.dimensions.x << " "
<< obj.dimensions.y << " "
<< obj.dimensions.z << " ";
break;
}
bool found = false;
auto name = find_name(map, obj.id, found);
if (!found || name[0] == '#') {
name = std::string("#") + std::to_string(anon++);
}
out << ") " << name << std::endl;
}
out.close();
}
};

21
Scene/Object.hpp Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <util/glsl_types.hpp>
using namespace glsl;
enum Shape {
eSPHERE,
eBOX,
ePLANE,
};
struct Object {
vec4 center;
vec4 dimensions;
uint id;
Shape shape;
float pad0;
float pad1;
};

View File

@ -1,123 +0,0 @@
#include <Renderer/CommandBuffer.hpp>
#include <Scene/Terrain.hpp>
#include <util/int.hpp>
float Terrain::getHeight(int32_t x, int32_t y) {
if (x < 0)
x += 64;
if (y < 0)
y += 64;
x %= 64;
y %= 64;
float xf = x;
float yf = y;
xf /= 64.0;
xf *= heightmap_tex->extent.width;
yf /= 64.0;
yf *= heightmap_tex->extent.height;
return static_cast<float>(heightmap_tex->image_data[static_cast<int>(static_cast<int>(yf) * heightmap_tex->extent.width + xf) * 4]) / 256.0f * 15.0f;
}
Terrain::Terrain(vk::PhysicalDevice phys_dev, vk::Device dev, Texture& tex) : phys_dev(phys_dev), dev(dev) {
/* tell Texture() not to free so we can apply our sobel filter */
heightmap_tex = &tex;
const auto patch_size = 64_u32;
const auto uv_scale = 1.0f;
const auto vertex_count = patch_size * patch_size;
vertices.resize(vertex_count);
for (size_t x = 0; x < patch_size; x++)
for (size_t y = 0; y < patch_size; y++)
vertices[x + y*patch_size] = (glTFVertex {
.pos = glm::vec3(
2.0f * x + 1.0f - patch_size,
0.0f,
2.0f * y + 1.0f - patch_size),
.uv = glm::vec2(static_cast<float>(x)/patch_size, static_cast<float>(y) / patch_size) * uv_scale,
});
/* use sobel filters to get normal:
* X sobel:
* +----+----+----+
* | +1 | +0 | -1 |
* +----+----+----+
* | +2 | +0 | -2 |
* +----+----+----+
* | +1 | +0 | -1 |
* +----+----+----+
* Y sobel:
* +----+----+----+
* | +1 | +2 | +1 |
* +----+----+----+
* | +0 | +0 | +0 |
* +----+----+----+
* | -1 | -2 | -1 |
* +----+----+----+
*/
for(auto x = 0_i32; x < patch_size; x++)
for (auto y = 0_i32; y < patch_size; y++) {
float moores_heights[3][3] = {
{ getHeight(x - 1, y - 1), getHeight(x - 1, y), getHeight(x - 1, y + 1) },
{ getHeight(x + 0, y - 1), getHeight(x + 0, y), getHeight(x + 0, y + 1) },
{ getHeight(x + 1, y - 1), getHeight(x + 1, y), getHeight(x + 1, y + 1) },
};
// auto normal = glm::vec3(
// /* x gets X sobel filter */
// moores_heights[0][0] + 2.0f * moores_heights[0][1] + moores_heights[0][2]
// - moores_heights[2][0] - 2.0f * moores_heights[2][1] - moores_heights[2][2],
// 0.0,
// /* z gets Y sobel filter */
// moores_heights[0][0] + 2.0f * moores_heights[1][0] + moores_heights[2][0]
// - moores_heights[0][2] - 2.0f * moores_heights[1][2] - moores_heights[2][2]
// );
auto relx = glm::vec3(2.0, getHeight(x + 1, y)-getHeight(x, y), 0.0);
auto relz = glm::vec3(0.0, getHeight(x, y + 1)-getHeight(x, y), 2.0);
auto normal = glm::normalize(glm::cross(relz, relx));
/* fill in missing component, first scalar scales bump */
//normal.y = 0.25 * glm::sqrt(glm::abs(1.0 - normal.x*normal.x - normal.z*normal.z));
//vertices[x + y * patch_size].norm = glm::vec3(getHeight(x, y));
vertices[x + y * patch_size].norm = normal;
}
vertex_buffer = std::make_unique<VertexBuffer>(phys_dev, dev, vertices.size());
vertex_buffer->upload(vertices);
/* index generation */
const auto w = patch_size - 1;
indices.resize(w * w * 4);
for (auto x = 0_u32; x < w; x++)
for (auto y = 0_u32; y < w; y++) {
auto idx = (x + y * w) * 4;
indices[idx] = x+y*patch_size;
indices[idx+1] = indices[idx] + patch_size;
indices[idx+2] = indices[idx+1] + 1;
indices[idx + 3] = indices[idx] + 1;
}
index_buffer = std::make_unique<Buffer>(phys_dev, dev, sizeof(uint32_t)*indices.size(),
vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent
| vk::MemoryPropertyFlagBits::eHostVisible);
index_buffer->upload(indices);
}
void Terrain::draw(CommandBuffer& cmd) {
}
Terrain::~Terrain() {
index_buffer.reset();
vertex_buffer.reset();
}

View File

@ -1,26 +0,0 @@
#pragma once
#include <Resources/Texture.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <Memory/Buffer.hpp>
#include <string>
struct CommandBuffer;
struct Terrain {
vk::PhysicalDevice phys_dev;
vk::Device dev;
Texture* heightmap_tex;
std::unique_ptr<VertexBuffer> vertex_buffer;
std::unique_ptr<Buffer> index_buffer;
std::vector<glTFVertex> vertices;
std::vector<uint32_t> indices;
Terrain(vk::PhysicalDevice phys_dev, vk::Device dev, Texture& hieghtmap);
float getHeight(int32_t x, int32_t y);
void draw(CommandBuffer& cmd);
~Terrain();
};

105
UI/UI.cpp
View File

@ -11,6 +11,7 @@
#include <Renderer/Renderer.hpp>
#include <Scene/Camera.hpp>
#include <Scene/March.hpp>
/* this pains me to do, but its the only way :( */
Renderer* __ren;
@ -24,14 +25,18 @@ static csys::ItemLog& operator<<(csys::ItemLog& log, ImVector<float>& vec) {
return log << vec[vec.size() - 1] << " }";
}
static void pipeline_setter(bool& v, bool in) {
if(v == in)
return;
v = in;
__ren->bsp->pipeline->rebuild(__ren->wireframe_mode, __ren->backface_culling);
static void scene_load(csys::String fname) {
__ren->objects = March::readFile(fname.m_String, __ren->scene_map);
__ren->shader_buffer->upload(__ren->objects);
}
UI::UI(Renderer* ren) : ren(ren), dev(ren->dev) {
static void scene_write(csys::String fname) {
March::writeFile(fname.m_String, __ren->objects, __ren->scene_map);
}
UI::UI(Renderer* ren) : ren(ren) {
__ren = ren;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
@ -105,40 +110,59 @@ UI::UI(Renderer* ren) : ren(ren), dev(ren->dev) {
auto& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
console = std::make_unique<ImGuiConsole>("developer console");
console = new ImGuiConsole("developer console");
console->System().RegisterCommand("pause", "Pauses or unpauses the engine", [this]() {
this->ren->paused = !this->ren->paused;
console->System().Log(csys::ItemType::eINFO) << "Paused: " << (this->ren->paused? "True" : "False") << csys::endl;
console->System().Log(csys::ItemType::eINFO) << "Paused: " << (this->ren->paused ? "True" : "False") << csys::endl;
});
console->System().RegisterCommand("quit", "Quits the engine", [this]() {
this->ren->should_close = true;
console->System().Log(csys::ItemType::eINFO) << "Quitting..." << csys::endl;
});
console->System().RegisterCommand("read_scene", "Adds elements from a scene file", [this](csys::String fname) {
console->System().Log(csys::ItemType::eINFO) << "Loading file: " << fname.m_String << csys::endl;
scene_load(fname);
}, csys::Arg<csys::String>("file-name"));
console->System().RegisterCommand("write_scene", "Writes elements to a scene file (destroys underlying data if present)", [this](csys::String fname) {
Log::info("Writing to " + fname.m_String + "\n");
console->System().Log(csys::ItemType::eINFO) << "Writing to file: " << fname.m_String << "\n";
scene_write(fname);
}, csys::Arg<csys::String>("file-name"));
console->System().RegisterCommand("add_sphere", "Adds sphere to the scene.", [this](csys::String name, float cx, float cy, float cz, float rad) {
March::add_sphere(name.m_String, glm::vec3(cx, cy, cz), rad, __ren);
}, csys::Arg<csys::String>("Name"), csys::Arg<float>("center.x"), csys::Arg<float>("center.y"), csys::Arg<float>("center.z"), csys::Arg<float>("radius"));
console->System().RegisterCommand("add_box", "Adds box to the scene.", [this](csys::String name, float cx, float cy, float cz, float dx, float dy, float dz) {
March::add_box(name.m_String, glm::vec3(cx, cy, cz), glm::vec3(dx, dy, dz), __ren);
}, csys::Arg<csys::String>("Name"),
csys::Arg<float>("center.x"), csys::Arg<float>("center.y"), csys::Arg<float>("center.z"),
csys::Arg<float>("dim.x"), csys::Arg<float>("dim.y"), csys::Arg<float>("dim.z"));
console->System().RegisterCommand("list-vars", "List variables accessible from developer console", [this]() {
const std::vector<std::string> names = {
"show_bboxes",
"visibility_testing",
// "show_bboxes",
// "visibility_testing",
"flycam",
"speed",
"max_fps",
"wireframe",
"backface_culling",
// "wireframe",
// "backface_culling",
};
for(const auto& name : names)
for (const auto& name : names)
console->System().Log(csys::ItemType::eINFO) << name << csys::endl;
});
});
console->System().RegisterVariable("show_bboxes", ren->show_bboxes, csys::Arg<bool>("value"));
console->System().RegisterVariable("visibility_testing", ren->visibility_testing, csys::Arg<bool>("value"));
// console->System().RegisterVariable("show_bboxes", ren->show_bboxes, csys::Arg<bool>("value"));
// console->System().RegisterVariable("visibility_testing", ren->visibility_testing, csys::Arg<bool>("value"));
console->System().RegisterVariable("flycam", ren->flycam, csys::Arg<bool>("value"));
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, pipeline_setter);
console->System().RegisterVariable("backface_culling", ren->backface_culling, pipeline_setter);
// console->System().RegisterVariable("wireframe", ren->wireframe_mode, pipeline_setter);
// console->System().RegisterVariable("backface_culling", ren->backface_culling, pipeline_setter);
console->System().Log(csys::ItemType::eINFO) << "Welcome to Pleascach!" << csys::endl;
}
@ -148,15 +172,39 @@ void UI::newFrame() {
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowBgAlpha(0.5f);
ImGui::Begin("Rendering Info", nullptr, ImGuiWindowFlags_::ImGuiWindowFlags_NoFocusOnAppearing);
ImGui::Begin("Rendering Info", nullptr);
ImGui::Text("# of Indices: %zu", ren->n_indices);
ImGui::Text("FPS: %f", ren->fps);
ImGui::Text("Time: %f", ren->time);
ImGui::Text("Speed: %f", ren->speed * ren->frametime / 8.0);
ImGui::SliderFloat("Rad", &ren->rad, 0.0, 3.0);
ImGui::SliderFloat("Theta", &ren->cam.theta, 0.0, glm::pi<float>());
ImGui::SliderFloat("Phi", &ren->cam.phi, 0.0, glm::two_pi<float>());
ImGui::SliderFloat("X", &ren->cam.pos.x, -1000.0, 1000.0);
ImGui::SliderFloat("Y", &ren->cam.pos.y, -1000.0, 1000.0);
ImGui::SliderFloat("Z", &ren->cam.pos.z, -1000.0, 1000.0);
if(ren->in_menu)
if(ImGui::CollapsingHeader("Objects")) {
int anon = 0;
for (const auto& obj : ren->objects) {
bool found = false;
auto name = March::find_name(ren->scene_map, obj.id, found);
if (!found || name[0] == '#') {
name = std::string("#") + std::to_string(anon++);
}
ImGui::Text("(%f %f %f %f) (%f %f %f %f) \"%s\"",
obj.center.x, obj.center.y, obj.center.z, obj.center.w,
obj.dimensions.x, obj.dimensions.y, obj.dimensions.z, obj.dimensions.w,
name.c_str());
}
}
if (ren->in_menu)
console->Draw();
ImGui::End();
@ -168,12 +216,9 @@ void UI::render(vk::CommandBuffer cmd) {
}
UI::~UI() {
console.reset();
dev.destroyDescriptorPool(desc_pool);
// dev.destroyDescriptorPool(desc_pool);
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
// for whatever reason, this segfaults with a read to -1 when it tries saving characteristics.
// TOOD: Debug
// ImGui::DestroyContext();
ImGui::DestroyContext();
}

View File

@ -3,12 +3,14 @@
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <Renderer/CommandBuffer.hpp>
#include <imgui/imgui_console.h>
#include <memory>
#include <vector>
struct Object;
struct Renderer;
struct Camera;
@ -19,8 +21,8 @@ struct UI {
UI(Renderer* ren);
ImGuiConsole* console;
std::unique_ptr<ImGuiConsole> console;
void newFrame();
void render(vk::CommandBuffer cmd);

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,108 +0,0 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v4.0.44",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0,
1,
2,
3
]
}
],
"nodes":[
{
"name":"Mball"
},
{
"name":"Circle",
"translation":[
0,
0,
-2.97784423828125
]
},
{
"name":"Circle.001"
},
{
"mesh":0,
"name":"Sphere"
}
],
"meshes":[
{
"name":"Sphere",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1
},
"indices":2
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":30729,
"max":[
0.9991506934165955,
0.9976890087127686,
0.9973824620246887
],
"min":[
-0.9990072846412659,
-0.9995680451393127,
-0.9988008141517639
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":30729,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5123,
"count":56796,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":368748,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":368748,
"byteOffset":368748,
"target":34962
},
{
"buffer":0,
"byteLength":113592,
"byteOffset":737496,
"target":34963
}
],
"buffers":[
{
"byteLength":851088,
"uri":"ball.bin"
}
]
}

Binary file not shown.

View File

@ -1,107 +0,0 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v4.0.44",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0
]
}
],
"nodes":[
{
"mesh":0,
"name":"stanford-bunny",
"rotation":[
0.7071068286895752,
0,
0,
0.7071068286895752
],
"scale":[
10.410737037658691,
10.410737037658691,
10.410737037658691
],
"translation":[
0,
-0.39514416456222534,
0
]
}
],
"meshes":[
{
"name":"stanford-bunny",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1
},
"indices":2
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":207619,
"max":[
0.0610090009868145,
0.058800000697374344,
-0.032986998558044434
],
"min":[
-0.0946900025010109,
-0.06187399849295616,
-0.1873210072517395
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":207619,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5125,
"count":208353,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":2491428,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":2491428,
"byteOffset":2491428,
"target":34962
},
{
"buffer":0,
"byteLength":833412,
"byteOffset":4982856,
"target":34963
}
],
"buffers":[
{
"byteLength":5816268,
"uri":"bunny.bin"
}
]
}

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,219 +0,0 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v4.0.44",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0,
1
]
}
],
"nodes":[
{
"mesh":0,
"name":"Suzanne",
"rotation":[
0.06356222927570343,
0.536848247051239,
-0.8056020140647888,
0.2424030303955078
],
"translation":[
0.1063065230846405,
-0.6601571440696716,
-0.6140139698982239
]
},
{
"mesh":1,
"name":"Cube",
"rotation":[
0.1050531193614006,
-0.23102691769599915,
-0.3264787197113037,
0.9104955196380615
],
"scale":[
0.6794998645782471,
1,
1
]
}
],
"materials":[
{
"doubleSided":true,
"name":"Material",
"pbrMetallicRoughness":{
"baseColorFactor":[
0.800000011920929,
0.800000011920929,
0.800000011920929,
1
],
"metallicFactor":0,
"roughnessFactor":0.5
}
}
],
"meshes":[
{
"name":"Suzanne",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1,
"TEXCOORD_0":2
},
"indices":3
}
]
},
{
"name":"Cube",
"primitives":[
{
"attributes":{
"POSITION":4,
"NORMAL":5,
"TEXCOORD_0":6
},
"indices":7,
"material":0
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":1970,
"max":[
1.3671875,
0.984375,
0.8515625
],
"min":[
-1.3671875,
-0.984375,
-0.8515625
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":1970,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5126,
"count":1970,
"type":"VEC2"
},
{
"bufferView":3,
"componentType":5123,
"count":2904,
"type":"SCALAR"
},
{
"bufferView":4,
"componentType":5126,
"count":24,
"max":[
1,
1,
1
],
"min":[
-1,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":5,
"componentType":5126,
"count":24,
"type":"VEC3"
},
{
"bufferView":6,
"componentType":5126,
"count":24,
"type":"VEC2"
},
{
"bufferView":7,
"componentType":5123,
"count":36,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":23640,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":23640,
"byteOffset":23640,
"target":34962
},
{
"buffer":0,
"byteLength":15760,
"byteOffset":47280,
"target":34962
},
{
"buffer":0,
"byteLength":5808,
"byteOffset":63040,
"target":34963
},
{
"buffer":0,
"byteLength":288,
"byteOffset":68848,
"target":34962
},
{
"buffer":0,
"byteLength":288,
"byteOffset":69136,
"target":34962
},
{
"buffer":0,
"byteLength":192,
"byteOffset":69424,
"target":34962
},
{
"buffer":0,
"byteLength":72,
"byteOffset":69616,
"target":34963
}
],
"buffers":[
{
"byteLength":69688,
"uri":"monk.bin"
}
]
}

Binary file not shown.

View File

@ -1,219 +0,0 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v4.0.44",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0,
1
]
}
],
"nodes":[
{
"mesh":0,
"name":"Suzanne",
"rotation":[
0.06356222927570343,
0.536848247051239,
-0.8056020140647888,
0.2424030303955078
],
"translation":[
0.1063065230846405,
-0.6601571440696716,
-0.6140139698982239
]
},
{
"mesh":1,
"name":"Cube",
"rotation":[
0.1050531193614006,
-0.23102691769599915,
-0.3264787197113037,
0.9104955196380615
],
"scale":[
0.6794998645782471,
1,
1
]
}
],
"materials":[
{
"doubleSided":true,
"name":"Material",
"pbrMetallicRoughness":{
"baseColorFactor":[
0.800000011920929,
0.800000011920929,
0.800000011920929,
1
],
"metallicFactor":0,
"roughnessFactor":0.5
}
}
],
"meshes":[
{
"name":"Suzanne",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1,
"TEXCOORD_0":2
},
"indices":3
}
]
},
{
"name":"Cube",
"primitives":[
{
"attributes":{
"POSITION":4,
"NORMAL":5,
"TEXCOORD_0":6
},
"indices":7,
"material":0
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":1970,
"max":[
1.3671875,
0.984375,
0.8515625
],
"min":[
-1.3671875,
-0.984375,
-0.8515625
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":1970,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5126,
"count":1970,
"type":"VEC2"
},
{
"bufferView":3,
"componentType":5123,
"count":2904,
"type":"SCALAR"
},
{
"bufferView":4,
"componentType":5126,
"count":24,
"max":[
1,
1,
1
],
"min":[
-1,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":5,
"componentType":5126,
"count":24,
"type":"VEC3"
},
{
"bufferView":6,
"componentType":5126,
"count":24,
"type":"VEC2"
},
{
"bufferView":7,
"componentType":5123,
"count":36,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":23640,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":23640,
"byteOffset":23640,
"target":34962
},
{
"buffer":0,
"byteLength":15760,
"byteOffset":47280,
"target":34962
},
{
"buffer":0,
"byteLength":5808,
"byteOffset":63040,
"target":34963
},
{
"buffer":0,
"byteLength":288,
"byteOffset":68848,
"target":34962
},
{
"buffer":0,
"byteLength":288,
"byteOffset":69136,
"target":34962
},
{
"buffer":0,
"byteLength":192,
"byteOffset":69424,
"target":34962
},
{
"buffer":0,
"byteLength":72,
"byteOffset":69616,
"target":34963
}
],
"buffers":[
{
"byteLength":69688,
"uri":"monkebox.bin"
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,37 +0,0 @@
#version 450 core
layout (triangles) in;
layout (triangle_strip) out;
layout (max_vertices = 3) out;
layout (location = 0) in vec3 norm[];
layout (location = 1) in vec2 texCoord[];
layout (location = 2) in vec3 pos[];
layout (location = 0) out vec3 _norm;
layout (location = 1) out vec2 _texCoord;
layout (location = 2) out vec3 _pos;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
void main(void) {
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = proj * view * gl_in[i].gl_Position;
_norm = norm[i];
_texCoord = texCoord[i];
_pos = pos[i];
EmitVertex();
}
EndPrimitive();
}

View File

@ -1,27 +0,0 @@
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNorm;
layout (location = 2) in vec2 aTexCoord;
layout (location = 0) out vec3 norm;
layout (location = 1) out vec2 texCoord;
layout (location = 2) out vec3 pos;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
void main() {
pos = (aPos + (vec3(10.0) * gl_InstanceIndex));
gl_Position = vec4(pos, 1.0);
texCoord = aTexCoord;
norm = aNorm;
}

View File

@ -1,38 +0,0 @@
#version 460 core
layout (location = 0) in vec3 norm;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 pos;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
layout (set = 0, binding = 1) uniform sampler2D tex;
void main() {
vec3 light_pos = normalize(vec3(cos(time), sin(time), 0.0))*10.0;
/* calculate highlight using angle between fragment and viewer */
vec3 I = normalize(cam_pos-pos);
vec3 L = normalize(light_pos-pos);
vec3 cool = vec3(0.0, 0.0, 0.55);
vec3 warm = vec3(0.3, 0.3, 0);
float t = (dot(norm, L)+1.0)/2.0;
vec3 r = 2.0*(dot(norm,L)*norm)-L;
float s = 100.0*(dot(r,I))-97.0;
if(s < 0.0)
s = 0.0;
else if(s > 1.0)
s = 1.0;
FragColor = vec4((1.0-s)*(t*warm + (vec3(0.5)-t)*cool) + s*vec3(1.0), 1.0);
}

View File

@ -1,29 +0,0 @@
#version 460 core
layout (location = 0) in vec3 norm;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 pos;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
layout (set = 0, binding = 1) uniform sampler2D tex;
void main() {
vec3 light_pos = normalize(vec3(cos(time), sin(time), 0.0))*10.0;
vec3 L = normalize(light_pos-pos);
float r = length(light_pos-pos);
float t = clamp(dot(L, norm), 0.0, 1.0) * 20.0/(r*r);
FragColor = vec4(t, t/2.0, t*2.0, 1.0);
}

View File

@ -1,65 +0,0 @@
#version 460 core
layout (location = 0) in vec3 norm;
layout (location = 1) in vec2 texCoord;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
mat4 mvp;
float time;
float aspect_ratio;
};
/* 4-float alignment in memory*/
struct Ray {
vec3 orig;
float min;
vec3 dir;
float max;
};
vec3 ray_color(vec3 ray) {
float a = 0.5 * (ray.y+1.0);
return vec3(1.0-a) + a*vec3(0.5, 0.7, 1.0);
}
/* returns float of where you hit, or -1.0 */
float sphere(vec3 center, float r, Ray ray) {
vec3 p = ray.orig-center;
float a = dot(ray.dir, ray.dir);
float half_b = dot(p, ray.dir);
float c = dot(p, p) - r*r;
float discr = half_b*half_b - a*c;
if(discr < 0.0)
return -1.0;
return -half_b-sqrt(discr)/a;
}
void main() {
vec2 pixel = texCoord*2.0-1.0;
Ray ray;
ray.orig = vec3(0.0);
ray.min = 0.1;
ray.max = 10000.0;
float fov = radians(90);
ray.dir = normalize(vec3(pixel.x * aspect_ratio, pixel.y, tan(fov/2.0)));
vec3 sphere_center = vec3(0.0, 0.0, 1.0);
float d = sphere(sphere_center, 0.5, ray);
FragColor = vec4(texCoord, 1.0, 1.0);
return;
if(d < 0.0) {
FragColor = vec4(0.0);
return;
}
vec3 n = normalize(ray.dir*d-sphere_center);
FragColor = vec4((n+vec3(1.0)) / 2.0, 1.0);
}

126
assets/shaders/manual.frag Normal file
View File

@ -0,0 +1,126 @@
#version 450 core
#define MAX_STEPS 100
#define MAX_DIST 1000.0
layout (set = 0, binding = 1) uniform sampler2D tex;
layout (set = 0, binding = 0) uniform Matrices {
vec3 cam_pos;
float time;
vec4 viewport;
vec3 cam_dir;
uint n_objects;
float rad;
};
layout (location = 0) in vec2 pos;
layout (location = 0) out vec4 fragColor;
vec2 eps = vec2(0.001, 0.0);
/* joins two parts of a scene */
float op_union(float v1, float v2) {
return min(v1, v2);
}
/* subtracts sdf from scene */
float op_subtract(float v1, float v2) {
return max(v1, -v2);
}
/* twists! in the xz */
vec3 op_twist(vec3 p, float k) {
float c = cos(k*p.y);
float s = sin(k*p.y);
mat2 m = mat2(c, -s, s, c);
return vec3(m*p.xz, p.y);
}
float box(vec3 p, vec3 r) {
vec3 q = abs(p) - r;
return length(max(q,0.0)) + min(max(q.x, max(q.y,q.z)), 0.0);
}
/* square, centered at the origin */
float box(vec2 p, vec2 r) {
vec2 d = abs(p)-r;
return length(max(d, 0.0)) + min(max(d.x,d.y), 0.0);
}
/* infinite cross, used for construction of serpinski cube */
float infcross(vec3 p, float r) {
vec2 unit = vec2(r);
float box1 = box(p.xy, unit);
float box2 = box(p.yz, unit);
float box3 = box(p.zx, unit);
return op_union(op_union(box1, box2), box3);
}
float sphere(vec3 p, float r) {
return length(p) - r;
}
float sdf(vec3 p) {
p = op_twist(p.xzy, cos(time)).xzy;
float d = box(p, vec3(1.0));
float s = 1.0;
for(int i = 0; i < 5; i++) {
/* using mod to repeat across domain, then shift to +- */
vec3 a = mod(p * s, 2.0) - 1.0;
s *= 3.0;
vec3 r = 1.0 - 3.0*abs(a);
float c = infcross(r, rad)/s;
d = max(d, c);
}
return d;
}
vec3 norm(vec3 pos) {
return normalize(
vec3(
sdf(pos+eps.xyy),
sdf(pos+eps.yxy),
sdf(pos+eps.yyx)
) - sdf(pos)
);
}
vec2 raycast(vec3 dir) {
float t = 0.0;
for(int i = 0; i < MAX_STEPS; i++) {
float dt = sdf(cam_pos + dir * t);
if(dt < 0.0001*t)
return vec2(t, float(i));
else if(dt > MAX_DIST)
return vec2(0.0, -1.0);
t += dt;
}
return vec2(0.0, 64.0);
}
vec3 raygen() {
vec3 forward = cam_dir;
vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0)));
vec3 up = normalize(cross(right, forward));
return normalize(pos.x * right + pos.y * up + forward * 2.0);
}
vec3 gamma(vec3 c) {
return pow(c, vec3(0.4545));
}
void main() {
vec3 dir = raygen();
vec2 d = raycast(dir);
if(d.y == -1.0) {
fragColor = vec4(0.0);
return;
}
fragColor = vec4(d.y/MAX_STEPS);
fragColor.xyz = gamma(fragColor.xyz);
}

Binary file not shown.

View File

@ -1,34 +0,0 @@
#version 460 core
layout (location = 0) in vec4 color;
layout (location = 1) in vec2 texCoord;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
layout (set = 0, binding = 1) uniform sampler2D tex;
vec3 tex_map(vec2 coords) {
return vec3(
1-abs(cos(normalize(texCoord.xxy)))
// 0.0,
// sin(texCoord.y)
// sin(texCoord.x/texCoord.y)
);
}
void main() {
FragColor.xyz = tex_map(texCoord);
FragColor.w = 1.0;
}

Binary file not shown.

View File

@ -1,35 +0,0 @@
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 0) out vec4 color;
layout (location = 1) out vec2 texCoord;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
vec4 unpackABGR(uint packedABGR) {
float scale = 1.0 / 255.0;
float a = float((packedABGR >> 24) & 0xFF) * scale;
float b = float((packedABGR >> 16) & 0xFF) * scale;
float g = float((packedABGR >> 8) & 0xFF) * scale;
float r = float(packedABGR & 0xFF) * scale;
return vec4(r,g,b,a);
}
void main() {
gl_Position = proj * view * vec4(aPos, 1.0);
color = vec4(0.0);
texCoord = aTexCoord;
}

Binary file not shown.

View File

@ -1,23 +0,0 @@
#version 460 core
layout (location = 0) in vec3 norm;
layout (location = 1) in vec2 texCoord;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
layout (set = 0, binding = 1) uniform sampler2D tex;
void main() {
FragColor = vec4(norm, 1.0);
}

Binary file not shown.

View File

@ -1,34 +0,0 @@
#version 450 core
layout (triangles) in;
layout (triangle_strip) out;
layout (max_vertices = 3) out;
layout (location = 0) in vec3 norm[];
layout (location = 1) in vec2 texCoord[];
layout (location = 0) out vec3 _norm;
layout (location = 1) out vec2 _texCoord;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
void main(void) {
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = proj * view * gl_in[i].gl_Position;
_norm = norm[i];
_texCoord = texCoord[i];
EmitVertex();
}
EndPrimitive();
}

Binary file not shown.

View File

@ -1,25 +0,0 @@
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNorm;
layout (location = 2) in vec2 aTexCoord;
layout (location = 0) out vec3 norm;
layout (location = 1) out vec2 texCoord;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
void main() {
gl_Position = proj * view * vec4(aPos, 1.0);
texCoord = aTexCoord;
norm = aNorm;
}

Binary file not shown.

View File

@ -1,51 +0,0 @@
#version 450 core
layout (triangles) in;
layout (triangle_strip) out;
layout (max_vertices = 3) out;
layout (location = 0) in vec3 norm[];
layout (location = 1) in vec2 texCoord[];
layout (location = 0) out vec3 _norm;
layout (location = 1) out vec2 _texCoord;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
vec4 explode(vec4 pos, vec3 n) {
float mag = 2.0;
vec3 dir = n * (time-3.0)/10.0 * mag;
return pos + vec4(dir, 0.0);
}
void main(void) {
if (time < 3.0) {
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = proj * view * gl_in[i].gl_Position;
_norm = norm[i];
_texCoord = texCoord[i];
EmitVertex();
}
EndPrimitive();
return;
}
vec3 n = norm[0] + norm[1] + norm[2];
n/=3;
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = proj * view * explode(gl_in[i].gl_Position, n);
_texCoord = texCoord[i];
_norm = n;
EmitVertex();
}
EndPrimitive();
}

Binary file not shown.

157
assets/shaders/ray.frag Normal file
View File

@ -0,0 +1,157 @@
#version 450 core
#define MAX_STEPS 64
const vec2 eps = vec2(0.001, 0.0);
layout (set = 0, binding = 1) uniform sampler2D tex;
layout (set = 0, binding = 0) uniform Matrices {
vec3 cam_pos;
float time;
vec4 viewport;
vec3 cam_dir;
uint n_objects;
};
/*
enum Shape {
SPHERE,
BOX,
PLANE,
};
*/
#define SPHERE 0
#define BOX 1
#define PLANE 2
struct Object {
vec4 center;
vec4 dimensions;
uint id;
uint shape;
};
layout (set = 0, binding = 2) readonly buffer Objects {
Object objects[];
};
layout (location = 0) in vec2 pos;
layout (location = 0) out vec4 fragColor;
/* joins two parts of a scene */
vec2 op_union(vec2 v1, float v2, float id) {
if(v1.x > v2)
return vec2(v2, id);
return v1;
}
/* subtracts sdf from scene */
float op_subtract(float v1, float v2) {
return max(v1, -v2);
}
float sphere(vec3 p, vec3 c, float r) {
return abs(length(p-c) - r);
}
float box(vec3 p, vec3 c, vec3 r) {
p -= c;
vec3 q = abs(p) - r;
return length(max(q,0.0)) + min(max(q.x, max(q.y,q.z)), 0.0);
}
float plane(vec3 p, vec3 norm, float d) {
return dot(p, normalize(norm)) + d;
}
float obj_to_sdf(vec3 p, uint n) {
switch(objects[n].shape) {
case SPHERE:
return sphere(p, objects[n].center.xyz, objects[n].dimensions.x);
break;
case BOX:
return box(p, objects[n].center.xyz, objects[n].dimensions.xyz);
break;
case PLANE:
return plane(p, objects[n].center.xyz, objects[n].dimensions.x);
break;
}
}
float map(vec2 p) {
return sin(p.x)*sin(p.y);
}
float terrain(vec3 p) {
/* render terrain with bumps */
return box(p, vec3(0.0), vec3(100.0, 0.1, 100.0)) - abs(map(p.xz));
}
/* <distance, id> */
vec2 sdf(vec3 pos) {
vec2 d = vec2(100000000.0, -1.0);
for(uint i = 0; i < n_objects; i++) {
d = op_union(d, obj_to_sdf(pos, i), 1.0);
// d = op_union(d, sphere(pos, objects[i].center.xyz, objects[i].dimensions.x), 1.0);
}
/*float dsphere = sphere(pos, vec3(0.0, 3.0*sin(time)-10.0, 0.0), 1.0);
float dbox = box(pos, vec3(0.0, -10.0, 0.0), vec3(10.0, 1.0, 10.0));
float dpellet = sphere(pos, vec3(0.0, 10.0*sin(time) - 10.0, 0.0), 0.1);
float d = op_union(op_subtract(dbox, dsphere), dpellet);*/
//d = op_union(d, plane(pos, normalize(vec3(1.0)), 50.0));
return d;
}
vec2 raycast(vec3 dir) {
float t = 0.0;
for(int i = 0; i < MAX_STEPS; i++) {
vec2 dt = sdf(cam_pos + dir * t);
if(dt.y == -1.0)
return dt;
if(dt.x < 0.0001*t)
// return vec2(t, dt.y);
return vec2(t, float(i)/MAX_STEPS);
else if(dt.x > 2000.0)
return vec2(dt.x, -1.0);
t += dt.x;
}
return vec2(0.0, -1.0);
}
vec3 norm(vec3 pos) {
return normalize(
vec3(
sdf(pos+eps.xyy).x,
sdf(pos+eps.yxy).x,
sdf(pos+eps.yyx).x
) - sdf(pos).x
);
}
vec3 raygen() {
vec3 forward = cam_dir;
vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0)));
vec3 up = normalize(cross(right, forward));
return normalize(pos.x * right + pos.y * up + forward * 2.0);
}
void main() {
vec3 dir = raygen();
vec2 d = raycast(dir);
vec3 p = d.x*dir + cam_pos;
if(d.y != -1.0)
fragColor = vec4(d.y);
else
fragColor = vec4(0.0);
}

BIN
assets/shaders/ray.frag.spv Normal file

Binary file not shown.

17
assets/shaders/ray.vert Normal file
View File

@ -0,0 +1,17 @@
#version 460 core
layout (location = 0) in vec2 aCoord;
layout (location = 0) out vec2 pos;
layout (set = 0, binding = 0) uniform Matrices {
vec3 cam_pos;
float time;
vec4 viewport;
vec3 cam_dir;
};
void main() {
gl_Position = vec4(aCoord, 0.0, 1.0);
pos = vec2(aCoord.x * viewport.x / viewport.y, aCoord.y);
}

BIN
assets/shaders/ray.vert.spv Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,29 +0,0 @@
#version 460 core
layout (location = 0) in vec3 norm;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 pos;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
layout (set = 0, binding = 1) uniform sampler2D heightmap;
void main() {
/* extract L (light direction) from view matrix */
vec3 L = -cam_dir;
float r = length(cam_pos-pos);
float t = clamp(dot(L, norm), 0.0, 1.0) * 200.0/(r*r);
FragColor = vec4(vec3(t), 1.0);
}

View File

@ -1,89 +0,0 @@
#version 450 core
#extension GL_EXT_debug_printf : enable
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
layout(set = 0, binding = 1) uniform sampler2D heightmap;
layout (vertices = 4) out;
layout (location = 0) in vec3 norm[];
layout (location = 1) in vec2 texCoord[];
layout (location = 2) in vec3 pos[];
layout (location = 0) out vec3 _norm[4];
layout (location = 1) out vec2 _texCoord[4];
layout (location = 2) out vec3 _pos[4];
float screen_space_tess(vec4 p0, vec4 p1) {
/* calc midpoint + distance btw the two points */
vec4 midp = 0.5*(p0+p1);
float r = distance(p0, p1) / 2.0;
vec4 v0 = view * midp;
/* project into clip spaace */
vec4 clip0 = proj * (v0 - vec4(r, vec3(0.0)));
vec4 clip1 = proj * (v0 + vec4(r, vec3(0.0)));
clip0 /= clip0.w;
clip1 /= clip1.w;
/* convert to viewport coords */
clip0.xy *= viewport;
clip1.xy *= viewport;
return clamp(distance(clip0, clip1) / tess_edge_size * tess_factor, 1.0, 64.0);
}
bool frustum_culling() {
/* square root of patch size */
const float r = 8.0f;
/* ensure this is consistent with tese shader */
vec4 fpos = gl_in[gl_InvocationID].gl_Position;
fpos.y += 15.0 * textureLod(heightmap, texCoord[0], 0.0).r;
for(int i = 0; i < 6; i++) {
if(dot(fpos, frustum[i]) + r < 0.0)
return false;
}
return true;
}
void main() {
if(gl_InvocationID == 0) {
/* perform frustum culling */
if(frustum_culling()) {
gl_TessLevelOuter[0] = screen_space_tess(gl_in[3].gl_Position, gl_in[0].gl_Position);
gl_TessLevelOuter[1] = screen_space_tess(gl_in[0].gl_Position, gl_in[1].gl_Position);
gl_TessLevelOuter[2] = screen_space_tess(gl_in[1].gl_Position, gl_in[2].gl_Position);
gl_TessLevelOuter[3] = screen_space_tess(gl_in[2].gl_Position, gl_in[3].gl_Position);
gl_TessLevelInner[0] = mix(gl_TessLevelOuter[0], gl_TessLevelOuter[3], 0.5);
gl_TessLevelInner[1] = mix(gl_TessLevelOuter[2], gl_TessLevelOuter[1], 0.5);
} else {
gl_TessLevelOuter[0] = 0.0;
gl_TessLevelOuter[1] = 0.0;
gl_TessLevelOuter[2] = 0.0;
gl_TessLevelOuter[3] = 0.0;
gl_TessLevelInner[0] = 0.0;
gl_TessLevelInner[1] = 0.0;
}
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
_norm[gl_InvocationID] = norm[gl_InvocationID];
_texCoord[gl_InvocationID] = texCoord[gl_InvocationID];
_pos[gl_InvocationID] = pos[gl_InvocationID];
}

View File

@ -1,49 +0,0 @@
#version 450 core
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec3 cam_dir;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
layout(set = 0, binding = 1) uniform sampler2D heightmap;
layout(quads, equal_spacing, ccw) in;
layout (location = 0) in vec3 norm[];
layout (location = 1) in vec2 texCoord[];
layout (location = 2) in vec3 pos[];
layout (location = 0) out vec3 _norm;
layout (location = 1) out vec2 _texCoord;
layout (location = 2) out vec3 _pos;
void main() {
/* interpolation of UV coordinates */
vec2 uv1 = mix(texCoord[0], texCoord[1], gl_TessCoord.x);
vec2 uv2 = mix(texCoord[3], texCoord[2], gl_TessCoord.x);
_texCoord = mix(uv1, uv2, gl_TessCoord.y);
vec3 norm1 = mix(norm[0], norm[1], gl_TessCoord.x);
vec3 norm2 = mix(norm[3], norm[2], gl_TessCoord.x);
_norm = mix(norm1, norm2, gl_TessCoord.y);
/* not displacing yet */
vec4 pos1 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);
vec4 pos2 = mix(gl_in[3].gl_Position, gl_in[2].gl_Position, gl_TessCoord.x);
vec4 fpos = mix(pos1, pos2, gl_TessCoord.y);
fpos.y = 15.0 * texture(heightmap, _texCoord).r;
_pos = fpos.xyz;
gl_Position = proj * view * fpos;
}

View File

@ -1,26 +0,0 @@
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNorm;
layout (location = 2) in vec2 aTexCoord;
layout (location = 0) out vec3 norm;
layout (location = 1) out vec2 texCoord;
layout (location = 2) out vec3 pos;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
vec3 cam_pos;
vec4 frustum[6];
vec2 viewport;
float tess_factor;
float tess_edge_size;
};
void main() {
pos = aPos;
gl_Position = vec4(pos, 1.0);
texCoord = aTexCoord;
norm = aNorm;
}

0
assets/shaders/test Normal file
View File

Binary file not shown.

View File

@ -1,14 +0,0 @@
#version 460 core
layout (location = 0) flat in uint id;
layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
float time;
};
void main() {
FragColor = vec4(0.0, 0.0, 1.0, 0.2);
}

View File

@ -1,42 +0,0 @@
#version 450 core
layout (points) in;
layout (triangle_strip, max_vertices = 14) out;
layout (location = 0) in vec3 mins[];
layout (location = 1) in vec3 maxes[];
layout (location = 2) in uint id[];
layout (location = 0) out uint _id;
layout (set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
};
void main(void) {
int cube_vertices[14] = {
0, 1, 2, 3, 7, 6, 5, 4, 0, 1, 5, 6, 2, 3
};
for(int i = 0; i < gl_in.length(); i++) {
vec3 vertices[] = {
vec3(mins[i].x, mins[i].y, mins[i].z),
vec3(mins[i].x, mins[i].y, maxes[i].z),
vec3(mins[i].x, maxes[i].y, mins[i].z),
vec3(mins[i].x, maxes[i].y, maxes[i].z),
vec3(maxes[i].x, mins[i].y, mins[i].z),
vec3(maxes[i].x, mins[i].y, maxes[i].z),
vec3(maxes[i].x, maxes[i].y, mins[i].z),
vec3(maxes[i].x, maxes[i].y, maxes[i].z),
};
_id = id[i];
for(int j = 0; j < 14; j++) {
gl_Position = proj*view*vec4(vertices[cube_vertices[j]], 1.0);
EmitVertex();
}
EndPrimitive();
}
}

View File

@ -1,16 +0,0 @@
#version 460 core
/* simple passthrough */
layout (location = 0) in vec3 aMins;
layout (location = 1) in vec3 aMaxes;
layout (location = 2) in uint aId;
layout (location = 0) out vec3 mins;
layout (location = 1) out vec3 maxes;
layout (location = 2) out uint id;
void main() {
mins = aMins;
maxes = aMaxes;
id = aId;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 KiB

61
flake.lock generated Normal file
View File

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1743315132,
"narHash": "sha256-6hl6L/tRnwubHcA4pfUUtk542wn2Om+D4UnDhlDW9BE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "52faf482a3889b7619003c0daec593a1912fddc1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

31
flake.nix Normal file
View File

@ -0,0 +1,31 @@
{
description = "Flake for Vulkan and GLSLC Project";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in {
devShells.default = pkgs.mkShell {
buildInputs = [
pkgs.git
pkgs.cmake
pkgs.vulkan-loader
pkgs.vulkan-headers
pkgs.vulkan-tools
pkgs.vulkan-validation-layers
pkgs.shaderc
pkgs.glfw3
];
shellHook = ''
echo "Vulkan development environment loaded."
'';
};
}
);
}

View File

@ -632,7 +632,7 @@ void ImGuiConsole::SettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHand
#define INI_CONSOLE_SAVE_FLOAT(var) buf->appendf(#var"=%.3f\n", console->var)
#define INI_CONSOLE_SAVE_BOOL(var) buf->appendf(#var"=%i\n", console->var)
// Set header for CONSOLE Console.
// Set header for CONSOLE Console
buf->appendf("[%s][%s]\n", handler->TypeName, console->m_ConsoleName.data());
// Window settings.

Some files were not shown because too many files have changed in this diff Show More