MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
dark.cpp
Go to the documentation of this file.
1#include <cstdlib>
2
3#include <algorithm>
4#include <chrono>
5#include <cmath>
6#include <format>
7#include <iostream>
8#include <string>
9
10#include <glm/ext/matrix_clip_space.hpp>
11#include <glm/ext/matrix_transform.hpp>
12#include <glm/glm.hpp>
13
14#include "mxvk/argz.hpp"
15#include "mxvk/mxvk.hpp"
18
19namespace example {
20
21 class DarkWindow : public mxvk::VK_Window {
22 public:
23 DarkWindow(const std::string &filename, const std::string &path, const std::string &title, int width, int height, bool fullscreen, bool enable_vsync)
24 : mxvk::VK_Window(title, width, height, fullscreen, MXVK_VALIDATION, enable_vsync),
25 assetRoot((path.empty() || path == ".") ? std::string(DARK_ASSET_DIR) : path) {
26 fallbackWidth = width;
27 fallbackHeight = height;
28
29 const std::string shaderRoot = assetRoot + "/data";
30 const std::string modelPath = filename.empty() ? (assetRoot + "/data/pyramid.obj") : filename;
31 const std::string beamModelPath = assetRoot + "/data/beam.obj";
32 const std::string vertPath = shaderRoot + "/dark.vert.spv";
33 const std::string fragPath = shaderRoot + "/dark.frag.spv";
34 const std::string beamVertPath = shaderRoot + "/beam3d.vert.spv";
35 const std::string beamFragPath = shaderRoot + "/beam.frag.spv";
36
37 setFont(assetRoot + "/data/font.ttf", 48);
38
39 beamModel.load(this, beamModelPath, "", "", 1.0f);
40 beamModel.setAlphaBlending(true);
41 beamModel.setShaders(this, beamVertPath, beamFragPath);
42
43 model.load(this, modelPath, "", "", 1.0f);
44 model.setAlphaBlending(true);
45 model.setShaders(this, vertPath, fragPath);
46 }
47
48 ~DarkWindow() override {
49 if (device != VK_NULL_HANDLE) {
50 vkDeviceWaitIdle(device);
51 }
52 beamModel.cleanup(this);
53 model.cleanup(this);
54 }
55
56 void event(SDL_Event &e) override {
57 if (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE) {
58 exit();
59 return;
60 }
61
62 if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN && e.button.button == SDL_BUTTON_LEFT) {
63 mouseDragging = true;
64 lastMouseX = static_cast<int>(e.button.x);
65 lastMouseY = static_cast<int>(e.button.y);
66 return;
67 }
68
69 if (e.type == SDL_EVENT_MOUSE_BUTTON_UP && e.button.button == SDL_BUTTON_LEFT) {
70 mouseDragging = false;
71 return;
72 }
73
74 if (e.type == SDL_EVENT_MOUSE_MOTION && mouseDragging) {
75 const int x = static_cast<int>(e.motion.x);
76 const int y = static_cast<int>(e.motion.y);
77 const int deltaX = x - lastMouseX;
78 const int deltaY = y - lastMouseY;
79
80 yawDegrees += static_cast<float>(deltaX) * mouseSensitivity;
81 pitchDegrees += static_cast<float>(deltaY) * mouseSensitivity;
82 pitchDegrees = std::clamp(pitchDegrees, -55.0f, 55.0f);
83
84 lastMouseX = x;
85 lastMouseY = y;
86 return;
87 }
88
89 if (e.type == SDL_EVENT_MOUSE_WHEEL) {
90 const float delta = (e.wheel.y != 0.0f) ? e.wheel.y : static_cast<float>(e.wheel.integer_y);
91 cameraDistance -= delta * 0.35f;
92 cameraDistance = std::clamp(cameraDistance, 2.0f, 10.0f);
93 return;
94 }
95 }
96
97 void onSwapchainRecreated() override {
98 beamModel.resize(this);
99 model.resize(this);
100 }
101
102 void proc() override {
103 const VkExtent2D extent = getSwapchainExtent();
104 const int width = extent.width > 0U ? static_cast<int>(extent.width) : fallbackWidth;
105
106 constexpr const char *titleText = "the Lunatic iS in my heaD";
107 int textWidth = 0;
108 int textHeight = 0;
109 if (getTextDimensions(titleText, textWidth, textHeight)) {
110 const int textX = std::max(0, (width - textWidth) / 2);
111 printText(titleText, textX, 24, {255, 255, 255, 255});
112 }
113 }
114
115 void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t imageIndex) override {
116 const auto now = std::chrono::steady_clock::now();
117 const float deltaSeconds = std::chrono::duration<float>(now - lastFrameTime).count();
118 elapsedSeconds = std::chrono::duration<float>(now - startTime).count();
119 lastFrameTime = now;
120
121 if (autoSpinEnabled) {
122 autoSpinRadians += deltaSeconds * 0.55f;
123 }
124
125 const VkExtent2D extent = getSwapchainExtent();
126 const float aspect = (extent.height > 0U)
127 ? static_cast<float>(extent.width) / static_cast<float>(extent.height)
128 : 1.0f;
129
130 const float yawRadians = glm::radians(yawDegrees);
131 const float pitchRadians = glm::radians(pitchDegrees);
132 const glm::vec3 cameraPos{
133 cameraDistance * std::cos(pitchRadians) * std::sin(yawRadians),
134 0.35f + cameraDistance * std::sin(pitchRadians),
135 cameraDistance * std::cos(pitchRadians) * std::cos(yawRadians)};
136
138 ubo.model = glm::rotate(glm::mat4(1.0f), autoSpinRadians, glm::vec3(0.0f, 1.0f, 0.0f));
139 ubo.model = glm::rotate(ubo.model, glm::radians(0.0f), glm::vec3(1.0f, 0.0f, 0.0f));
140 ubo.model = glm::scale(ubo.model, glm::vec3(model.modelRenderScale() * 1.18f));
141 ubo.model = glm::translate(ubo.model, model.modelCenterOffset());
142 ubo.view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.35f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
143 ubo.proj = glm::perspective(glm::radians(48.0f), aspect, 0.1f, 100.0f);
144 ubo.proj[1][1] *= -1.0f;
145 ubo.fx = glm::vec4(elapsedSeconds, 0.0f, 0.0f, 0.42f);
146
148 beamUbo.model = glm::mat4(1.0f);
149 beamUbo.view = ubo.view;
150 beamUbo.proj = ubo.proj;
151 beamUbo.fx = glm::vec4(elapsedSeconds, autoSpinRadians, 1.0f, 1.0f);
152
153 beamModel.updateUBO(imageIndex, beamUbo);
154 beamModel.render(cmd, imageIndex, false);
155
156 model.updateUBO(imageIndex, ubo);
157 model.render(cmd, imageIndex, false);
158 }
159
160 private:
161 std::string assetRoot;
162 mxvk::VKAbstractModel beamModel{};
163 mxvk::VKAbstractModel model{};
164 bool mouseDragging = false;
165 bool autoSpinEnabled = true;
166 int lastMouseX = 0;
167 int lastMouseY = 0;
168 float yawDegrees = 0.0f;
169 float pitchDegrees = 0.0f;
170 float cameraDistance = 5.35f;
171 float mouseSensitivity = 0.35f;
172 float autoSpinRadians = 0.0f;
173 float elapsedSeconds = 0.0f;
174 int fallbackWidth = 1280;
175 int fallbackHeight = 720;
176 std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
177 std::chrono::steady_clock::time_point lastFrameTime = std::chrono::steady_clock::now();
178 };
179
180} // namespace example
181
182int main(int argc, char **argv) {
183 try {
184 const Arguments args = proc_args(argc, argv);
185 example::DarkWindow window(args.filename, args.path, "MXVK Dark Crystal Pyramid", args.width, args.height, args.fullscreen, args.enable_vsync);
186 window.loop();
187 } catch (mxvk::Exception &e) {
188 std::cerr << std::format("mxvk: Exception: {}\n", e.text());
189 return EXIT_FAILURE;
190 } catch (ArgException<std::string> &e) {
191 std::cerr << std::format("mxvk: Argument Exception: {}\n", e.text());
192 return EXIT_FAILURE;
193 }
194
195 return EXIT_SUCCESS;
196}
Lightweight, header-only, template command-line argument parser.
Arguments proc_args(int &argc, char **argv)
Parse standard libmx2 command-line options from main()'s argv.
Definition argz.hpp:872
Exception thrown by Argz::proc() on unrecognised or malformed options.
Definition argz.hpp:178
void event(SDL_Event &e) override
Handle one SDL event.
Definition dark.cpp:56
~DarkWindow() override
Definition dark.cpp:48
void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t imageIndex) override
Optional hook for derived classes to record extra draw commands.
Definition dark.cpp:115
void onSwapchainRecreated() override
Called after swapchain and render resources are recreated.
Definition dark.cpp:97
DarkWindow(const std::string &filename, const std::string &path, const std::string &title, int width, int height, bool fullscreen, bool enable_vsync)
Definition dark.cpp:23
void proc() override
Execute one processing/update step.
Definition dark.cpp:102
std::string text() const
Convenience wrapper that owns mesh, textures, descriptors, and pipeline state.
Main Vulkan window wrapper for MXVK.
Definition mxvk.hpp:37
VkExtent2D getSwapchainExtent() const noexcept
Get the current swapchain extent.
Definition mxvk.hpp:186
void loop()
Run the main event/render loop.
Definition mxvk.cpp:600
VkDevice device
Definition mxvk.hpp:485
bool getTextDimensions(const std::string &text, int &width, int &height)
Measure text dimensions in pixels.
Definition mxvk.cpp:3069
void exit()
Request loop termination.
Definition mxvk.cpp:1126
VK_Window()=default
Construct an empty window object.
void setFont(const std::string &fontPath, int fontSize=24)
Set the active text-render font.
Definition mxvk.cpp:2991
void printText(const std::string &text, int x, int y, const SDL_Color &col)
Queue a text string for rendering during the current frame.
Definition mxvk.cpp:3018
int main(void)
Definition main.cpp:7
#define MXVK_VALIDATION
Definition mxvk.hpp:27
High-level model wrapper integrated with MXVK dynamic rendering.
Utilities for loading and saving PNG images.
Definition mxvk.hpp:30
Plain data structure returned by proc_args() with all common libmx2 CLI options.
Definition argz.hpp:730
bool fullscreen
Whether fullscreen mode was requested.
Definition argz.hpp:736
bool enable_vsync
Enable FIFO present mode / v-sync (--enable-vsync).
Definition argz.hpp:750
int height
Viewport height in pixels (default: 720).
Definition argz.hpp:733
std::string filename
Optional input filename (--filename).
Definition argz.hpp:738
std::string path
Asset root; proc_args() defaults it to the executable directory.
Definition argz.hpp:735
int width
Viewport width in pixels (default: 1280).
Definition argz.hpp:732
Default transform UBO payload for model shaders.