Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc8b363354 | |||
| d9a5cf6cae |
@@ -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; \
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
namespace sophia {
|
||||
|
||||
class Camera2D {
|
||||
public:
|
||||
glm::vec2 position{0.f, 0.f};
|
||||
|
||||
void setProjection(float left, float right, float bottom, float top) {
|
||||
projection = glm::ortho(left, right, bottom, top);
|
||||
}
|
||||
|
||||
const glm::mat4& getProjection() const { return projection; }
|
||||
|
||||
glm::mat4 getView() const {
|
||||
return glm::translate(glm::mat4(1.f), glm::vec3(-position, 0.f));
|
||||
}
|
||||
|
||||
glm::mat4 getViewProjection() const { return projection * getView(); }
|
||||
|
||||
private:
|
||||
glm::mat4 projection{1.f};
|
||||
};
|
||||
|
||||
} // namespace sophia
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <sophia/frame_info.hpp>
|
||||
#include <vector>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace sophia {
|
||||
|
||||
class Application;
|
||||
|
||||
struct CanvasVertex {
|
||||
glm::vec2 position;
|
||||
glm::vec3 color;
|
||||
};
|
||||
|
||||
class Canvas {
|
||||
public:
|
||||
Canvas(const Canvas&) = delete;
|
||||
Canvas& operator=(const Canvas&) = delete;
|
||||
|
||||
~Canvas();
|
||||
|
||||
void triangle(glm::vec2 a, glm::vec2 b, glm::vec2 c,
|
||||
glm::vec3 color = {1.0f, 1.0f, 1.0f});
|
||||
void quad(glm::vec2 position, glm::vec2 size,
|
||||
glm::vec3 color = {1.0f, 1.0f, 1.0f});
|
||||
void clear();
|
||||
|
||||
private:
|
||||
friend class Application;
|
||||
|
||||
Canvas(Application* application);
|
||||
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace sophia
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <sophia/camera_2d.hpp>
|
||||
#include <sophia/types.hpp>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
@@ -13,6 +14,7 @@ struct FrameInfo {
|
||||
double elapsedTime;
|
||||
double deltaTime;
|
||||
glm::vec2 currentFramebufferExtent;
|
||||
const Camera2D& camera;
|
||||
};
|
||||
|
||||
} // namespace sophia
|
||||
|
||||
+242
-10
@@ -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
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <sophia/application.hpp>
|
||||
#include <sophia/canvas.hpp>
|
||||
|
||||
namespace sophia {
|
||||
|
||||
class Canvas::Impl {
|
||||
public:
|
||||
explicit Impl(Application* application) : application{application} {}
|
||||
|
||||
void triangle(glm::vec2 a, glm::vec2 b, glm::vec2 c,
|
||||
glm::vec3 color = {1.0f, 1.0f, 1.0f}) {
|
||||
std::vector<CanvasVertex> vertices{
|
||||
{a, color},
|
||||
{b, color},
|
||||
{c, color},
|
||||
};
|
||||
|
||||
application->pushModel(std::move(vertices), {});
|
||||
}
|
||||
|
||||
void quad(glm::vec2 position, glm::vec2 size,
|
||||
glm::vec3 color = {1.0f, 1.0f, 1.0f}) {
|
||||
std::vector<CanvasVertex> vertices{
|
||||
{position, color},
|
||||
{position + glm::vec2(size.x, 0.f), color},
|
||||
{position + size, color},
|
||||
{position + glm::vec2(0.f, size.y), color},
|
||||
};
|
||||
std::vector<u32> indices{0, 1, 2, 2, 3, 0};
|
||||
|
||||
application->pushModel(std::move(vertices), std::move(indices));
|
||||
}
|
||||
|
||||
void clear() { application->clearModels(); }
|
||||
|
||||
private:
|
||||
Application* application;
|
||||
};
|
||||
|
||||
Canvas::Canvas(Application* application)
|
||||
: impl{std::make_unique<Impl>(application)} {}
|
||||
|
||||
Canvas::~Canvas() = default;
|
||||
|
||||
void Canvas::triangle(glm::vec2 a, glm::vec2 b, glm::vec2 c, glm::vec3 color) {
|
||||
impl->triangle(a, b, c, color);
|
||||
}
|
||||
|
||||
void Canvas::quad(glm::vec2 position, glm::vec2 size, glm::vec3 color) {
|
||||
impl->quad(position, size, color);
|
||||
}
|
||||
|
||||
void Canvas::clear() { impl->clear(); }
|
||||
|
||||
} // namespace sophia
|
||||
Reference in New Issue
Block a user