Big application changes

This commit is contained in:
2026-09-06 23:41:40 -07:00
parent d9a5cf6cae
commit dc8b363354
2 changed files with 278 additions and 12 deletions
+36 -2
View File
@@ -1,7 +1,14 @@
#pragma once
#include <cstdlib>
#include <iostream>
#include <memory>
#include <sophia/camera_2d.hpp>
#include <sophia/canvas.hpp>
#include <sophia/frame_info.hpp>
#include <sophia/types.hpp>
#include <string>
#include <vector>
namespace sophia {
@@ -11,20 +18,47 @@ class Application {
int width;
int height;
std::string name;
bool headless = false;
};
Application(const Application&) = delete;
Application& operator=(const Application&) = delete;
Application(const Config& config);
~Application();
virtual ~Application();
void run();
static void setCommandLineArgs(int argc, const char* const* argv);
protected:
virtual void onCreate() {}
virtual void onUpdate(const FrameInfo& frameInfo) { (void)frameInfo; }
virtual void onRender() {}
virtual void onDestroy() {}
Canvas canvas;
Camera2D camera;
std::vector<std::string> args;
private:
friend class Canvas;
void pushModel(std::vector<CanvasVertex> vertices, std::vector<u32> indices);
void clearModels();
class Impl;
std::unique_ptr<Impl> impl;
};
} // namespace sophia
#define SOPHIA_MAIN(AppType) \
int main(int argc, const char** argv) { \
std::cout << __FILE__ << "::" << __LINE__ << '\n'; \
\
sophia::Application::setCommandLineArgs(argc, argv); \
AppType app; \
app.run(); \
\
return EXIT_SUCCESS; \
}
+242 -10
View File
@@ -1,25 +1,257 @@
#include <array>
#include <chrono>
#include <cstddef>
#include <sophia/application.hpp>
#include <sophia/util/logger.hpp>
#include <string>
#include <utility>
#include <vector>
#include <vulkan/vulkan.hpp>
#include "engine.hpp"
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include "buffer.hpp"
#include "device.hpp"
#include "model.hpp"
#include "pipelines/graphics_pipeline.hpp"
#include "render_context.hpp"
#include "shader.hpp"
#include "systems/model_render_system.hpp"
#include "window.hpp"
namespace sophia {
class Application::Impl {
public:
Impl(const Application::Config& config)
: engine{{config.width, config.height, config.name, config.headless}} {}
namespace {
void run() { engine.run(); }
private:
Engine engine;
struct Vertex {
glm::vec2 position;
glm::vec3 color;
};
struct PushConstants {
glm::mat4 transform;
glm::vec4 color;
glm::vec4 data;
};
std::vector<std::string> commandLineArgs;
} // namespace
class Application::Impl {
public:
Impl(Application& application, const Application::Config& config)
: application{application},
config{config},
window{config.width, config.height, config.name},
device{&window},
renderContext{window, device} {}
/*void run(const std::string& vertShaderPath,
const std::string& fragShaderPath) {
log::info("Running Render Triangle Test...");
RenderContext renderContext{window, device};
auto vertexShader = Shader::Builder()
.fromGLSL(vertShaderPath)
.setStage(ShaderStage::VERTEX)
.build();
auto fragmentShader = Shader::Builder()
.fromGLSL(fragShaderPath)
.setStage(ShaderStage::FRAGMENT)
.build();
vk::PushConstantRange pushConstantRange{};
pushConstantRange.stageFlags =
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment;
pushConstantRange.offset = 0;
pushConstantRange.size = sizeof(PushConstants);
vk::PipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
vk::UniquePipelineLayout pipelineLayout =
device.get()->createPipelineLayoutUnique(pipelineLayoutInfo);
std::vector<vk::VertexInputBindingDescription> bindingDescriptions{
{0, sizeof(Vertex), vk::VertexInputRate::eVertex}};
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions{
{0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, position)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color)}};
std::unique_ptr<sophia::GraphicsPipeline> graphicsPipeline =
GraphicsPipeline::Builder(device)
.setVertexShader(*vertexShader)
.setFragmentShader(*fragmentShader)
.setPipelineLayout(pipelineLayout.get())
.setColorAttachmentFormats({renderContext.getImageFormat()})
.setVertexInput(bindingDescriptions, attributeDescriptions)
.build();
// Oversized triangle covering the full screen so the fragment shader runs
// for every pixel.
std::vector<Vertex> vertices{
{{-1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}},
{{3.0f, -1.0f}, {0.0f, 1.0f, 0.0f}},
{{-1.0f, 3.0f}, {0.0f, 0.0f, 1.0f}},
};
Buffer vertexBuffer{device, sizeof(Vertex),
static_cast<u32>(vertices.size()),
vk::BufferUsageFlagBits::eVertexBuffer,
vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent};
vertexBuffer.map();
vertexBuffer.writeToBuffer(vertices.data(),
sizeof(Vertex) * vertices.size());
vertexBuffer.unmap();
}*/
void run() {
ModelRenderSystem modelRenderSystem{device, renderContext};
this->application.onCreate();
auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = startTime;
u32 frameIndex = 0;
while (!window.shouldClose()) {
glfwPollEvents();
auto newTime = std::chrono::high_resolution_clock::now();
double deltaTime =
std::chrono::duration<double>(newTime - currentTime).count();
currentTime = newTime;
double elapsedTime =
std::chrono::duration<double>(currentTime - startTime).count();
vk::Extent2D extent = renderContext.getExtent();
FrameInfo frameInfo{frameIndex, elapsedTime, deltaTime,
glm::vec2(static_cast<float>(extent.width),
static_cast<float>(extent.height)),
this->application.camera};
this->application.onUpdate(frameInfo);
this->application.onRender();
this->application.camera.setProjection(
-frameInfo.currentFramebufferExtent.x / 2.f,
frameInfo.currentFramebufferExtent.x / 2.f,
-frameInfo.currentFramebufferExtent.y / 2.f,
frameInfo.currentFramebufferExtent.y / 2.f);
vk::CommandBuffer commandBuffer = renderContext.beginFrame();
if (!commandBuffer) {
continue;
}
renderContext.transitionCurrentImage(
commandBuffer, vk::ImageLayout::eColorAttachmentOptimal);
vk::ClearValue clearValue{};
clearValue.color =
vk::ClearColorValue{std::array<float, 4>{0.01f, 0.01f, 0.02f, 1.0f}};
vk::RenderingAttachmentInfo colorAttachment{};
colorAttachment.imageView = renderContext.getCurrentImageView();
colorAttachment.imageLayout = vk::ImageLayout::eColorAttachmentOptimal;
colorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
colorAttachment.clearValue = clearValue;
vk::RenderingInfo renderingInfo{};
renderingInfo.renderArea = vk::Rect2D{{0, 0}, extent};
renderingInfo.layerCount = 1;
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &colorAttachment;
commandBuffer.beginRendering(renderingInfo);
vk::Viewport viewport{0.0f,
0.0f,
static_cast<float>(extent.width),
static_cast<float>(extent.height),
0.0f,
1.0f};
vk::Rect2D scissor{{0, 0}, extent};
commandBuffer.setViewport(0, viewport);
commandBuffer.setScissor(0, scissor);
modelRenderSystem.render(commandBuffer, this->models, frameInfo);
commandBuffer.endRendering();
renderContext.transitionCurrentImage(commandBuffer,
vk::ImageLayout::ePresentSrcKHR);
renderContext.endFrame();
frameIndex++;
}
this->application.onDestroy();
device.waitIdle();
auto endTime = std::chrono::high_resolution_clock::now();
double totalRuntime =
std::chrono::duration<double>(endTime - startTime).count();
log::info("Application ran for", totalRuntime, "s");
}
void pushModel(std::vector<CanvasVertex> vertices, std::vector<u32> indices) {
Model::Builder builder{};
builder.vertices.reserve(vertices.size());
for (const CanvasVertex& vertex : vertices) {
builder.vertices.push_back({vertex.position, vertex.color});
}
builder.indices = std::move(indices);
this->models.push_back(std::make_unique<Model>(this->device, builder));
}
void clearModels() {
// Models back live GPU vertex buffers and up to MAX_FRAMES_IN_FLIGHT
// command buffers may still be executing against them, so wait for the
// device to go idle before freeing anything.
this->device.waitIdle();
this->models.clear();
}
private:
Application& application;
const Application::Config config;
Window window;
Device device;
RenderContext renderContext;
std::vector<std::unique_ptr<Model>> models;
};
void Application::setCommandLineArgs(int argc, const char* const* argv) {
commandLineArgs.assign(argv, argv + argc);
}
Application::Application(const Config& config)
: impl{std::make_unique<Impl>(config)} {}
: impl{std::make_unique<Impl>(*this, config)},
canvas{this},
args{std::move(commandLineArgs)} {}
Application::~Application() = default;
void Application::run() { impl->run(); }
void Application::pushModel(std::vector<CanvasVertex> vertices,
std::vector<u32> indices) {
impl->pushModel(std::move(vertices), std::move(indices));
}
void Application::clearModels() { impl->clearModels(); }
} // namespace sophia