MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
planet.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 <memory>
9#include <string>
10
11#include <glm/ext/matrix_clip_space.hpp>
12#include <glm/ext/matrix_transform.hpp>
13#include <glm/glm.hpp>
14
15#include "mxvk/argz.hpp"
16#include "mxvk/mxvk.hpp"
19#include "rain.hpp"
20
21namespace example {
22 namespace {
23 constexpr int MATRIX_SURFACE_WIDTH = 1280;
24 constexpr int MATRIX_SURFACE_HEIGHT = 720;
25 } // namespace
26
27 using Clock = std::chrono::steady_clock;
28
29 class PlanetWindow;
30
32 public:
33 MatrixRainBackdrop(PlanetWindow &window, const std::string &assetRoot, bool binaryGlyphMode, int fontSize, const std::string &fontPath, const std::string &color);
35
38 void updateAndRender(PlanetWindow &window, VkCommandBuffer cmd);
39
40 private:
41 std::unique_ptr<matrix::Rain> rain;
42 Clock::time_point lastFrame{Clock::now()};
43 };
44
46 public:
47 PlanetWindow(const std::string &filename, const std::string &path, const std::string &title, int width, int height, bool fullscreen, bool enable_vsync, bool binary, int font_size, const std::string &font_path, const std::string &color) : mxvk::VK_Window(title, width, height, fullscreen, MXVK_VALIDATION, enable_vsync), assetRoot(path.empty() ? std::string(PLANET_ASSET_DIR) : path) {
48 const std::string modelPath = filename.empty() ? (assetRoot + "/data/saturn.mxmod.z") : filename;
49 const std::string textureManifestPath = assetRoot + "/data/saturn.tex";
50 const std::string textureBasePath = assetRoot + "/data";
51 const std::string vertPath = assetRoot + "/data/model.vert.spv";
52 const std::string fragPath = assetRoot + "/data/model.frag.spv";
53
54 model.load(this, modelPath, textureManifestPath, textureBasePath, 1.0f);
55 model.setBackfaceCulling(false);
56 model.setShaders(this, vertPath, fragPath);
57
58 backdrop = std::make_unique<MatrixRainBackdrop>(*this, assetRoot, binary, font_size, font_path, color);
59 }
60
61 ~PlanetWindow() override {
62 if (device != VK_NULL_HANDLE) {
63 vkDeviceWaitIdle(device);
64 }
65 model.cleanup(this);
66 }
67
68 void event(SDL_Event &e) override {
69 if (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE) {
70 exit();
71 return;
72 }
73
74 if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN && e.button.button == SDL_BUTTON_LEFT) {
75 mouseDragging = true;
76 lastMouseX = static_cast<int>(e.button.x);
77 lastMouseY = static_cast<int>(e.button.y);
78 return;
79 }
80
81 if (e.type == SDL_EVENT_MOUSE_BUTTON_UP && e.button.button == SDL_BUTTON_LEFT) {
82 mouseDragging = false;
83 return;
84 }
85
86 if (e.type == SDL_EVENT_MOUSE_MOTION && mouseDragging) {
87 const int x = static_cast<int>(e.motion.x);
88 const int y = static_cast<int>(e.motion.y);
89 const int deltaX = x - lastMouseX;
90 const int deltaY = y - lastMouseY;
91
92 yawDegrees += static_cast<float>(deltaX) * mouseSensitivity;
93 pitchDegrees += static_cast<float>(deltaY) * mouseSensitivity;
94 pitchDegrees = std::clamp(pitchDegrees, -80.0f, 80.0f);
95
96 lastMouseX = x;
97 lastMouseY = y;
98 return;
99 }
100
101 if (e.type == SDL_EVENT_MOUSE_WHEEL) {
102 const float delta = (e.wheel.y != 0.0f) ? e.wheel.y : static_cast<float>(e.wheel.integer_y);
103 cameraDistance -= delta * 0.45f;
104 cameraDistance = std::clamp(cameraDistance, 1.8f, 12.0f);
105 return;
106 }
107 }
108
110 if (backdrop) {
111 backdrop->onSwapchainAboutToRecreate();
112 }
113 }
114
115 void onSwapchainRecreated() override {
116 model.resize(this);
117 if (backdrop) {
118 backdrop->onSwapchainRecreated(*this);
119 }
120 }
121
122 void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t imageIndex) override {
123 if (backdrop) {
124 backdrop->updateAndRender(*this, cmd);
125 }
126
127 const float elapsedSeconds = std::chrono::duration<float>(std::chrono::steady_clock::now() - start).count();
128 const VkExtent2D extent = getSwapchainExtent();
129 const float aspect = (extent.height > 0U) ? static_cast<float>(extent.width) / static_cast<float>(extent.height) : 1.0f;
130
132 ubo.model = glm::rotate(glm::mat4(1.0f), glm::radians(pitchDegrees), glm::vec3(1.0f, 0.0f, 0.0f));
133 ubo.model = glm::rotate(ubo.model, glm::radians(yawDegrees), glm::vec3(0.0f, 1.0f, 0.0f));
134 ubo.model = glm::rotate(ubo.model, glm::radians(-18.0f), glm::vec3(1.0f, 0.0f, 0.0f));
135 ubo.model = glm::rotate(ubo.model, elapsedSeconds * 0.45f, glm::vec3(0.0f, 1.0f, 0.0f));
136 ubo.model = glm::scale(ubo.model, glm::vec3(model.modelRenderScale()));
137 ubo.model = glm::translate(ubo.model, model.modelCenterOffset());
138 ubo.view = glm::lookAt(glm::vec3(0.0f, 0.15f, cameraDistance), glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
139 ubo.proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 100.0f);
140 ubo.proj[1][1] *= -1.0f;
141
142 model.updateUBO(imageIndex, ubo);
143 model.render(cmd, imageIndex, false);
144 }
145
146 void renderBackgroundSprite(mxvk::VK_Sprite &sprite, VkCommandBuffer cmd) { renderStandaloneSprite(sprite, cmd); }
147
148 private:
149 std::string assetRoot;
151 std::unique_ptr<MatrixRainBackdrop> backdrop{};
152 std::chrono::steady_clock::time_point start{std::chrono::steady_clock::now()};
153 bool mouseDragging = false;
154 int lastMouseX = 0;
155 int lastMouseY = 0;
156 float yawDegrees = 0.0f;
157 float pitchDegrees = 0.0f;
158 float cameraDistance = 4.6f;
159 float mouseSensitivity = 0.35f;
160 };
161
162 MatrixRainBackdrop::MatrixRainBackdrop(PlanetWindow &window, const std::string &assetRootPath, bool binaryGlyphMode, int fontSize, const std::string &fontPath, const std::string &color)
163 : rain([&]() {
164 matrix::RainConfig config = matrix::make_matrix_rain_config(assetRootPath, binaryGlyphMode);
165 config.surface_width = MATRIX_SURFACE_WIDTH;
166 config.surface_height = MATRIX_SURFACE_HEIGHT;
167 if (binaryGlyphMode && fontPath.empty()) {
168 config.font_path = assetRootPath + "/data/binary.ttf";
169 }
170 config.font_size = std::max(1, fontSize);
171 if (!fontPath.empty()) {
172 config.font_path = fontPath;
173 }
174 config.color = color;
175 return std::make_unique<matrix::Rain>(window, std::move(config));
176 }()) {
177 lastFrame = Clock::now();
178 }
179
181
183
185 if (rain) {
186 rain->resize(window);
187 }
188 }
189
190 void MatrixRainBackdrop::updateAndRender(PlanetWindow &window, VkCommandBuffer cmd) {
191 const auto now = Clock::now();
192 float dt = std::chrono::duration<float>(now - lastFrame).count();
193 lastFrame = now;
194 dt = std::clamp(dt, 0.0f, 1.0f / 15.0f);
195
196 if (rain == nullptr) {
197 return;
198 }
199
200 rain->resize(window);
201 rain->update(dt);
202 const VkExtent2D extent = window.getSwapchainExtent();
203 rain->render(static_cast<int>(extent.width), static_cast<int>(extent.height));
204 if (rain->sprite() != nullptr) {
205 window.renderBackgroundSprite(*rain->sprite(), cmd);
206 rain->sprite()->clearQueue();
207 }
208 }
209} // namespace example
210
211int main(int argc, char **argv) {
212 try {
213 const Arguments args = proc_args(argc, argv);
214 example::PlanetWindow window(args.filename, args.path, "MXVK Planet Example", args.width, args.height, args.fullscreen, args.enable_vsync, args.binary, args.font_size, args.font_path, args.color);
215 window.loop();
216 } catch (mxvk::Exception &e) {
217 std::cerr << std::format("mxvk: Exception: {}\n", e.text());
218 return EXIT_FAILURE;
219 } catch (ArgException<std::string> &e) {
220 std::cerr << std::format("mxvk: Argument Exception: {}\n", e.text());
221 return EXIT_FAILURE;
222 }
223
224 return EXIT_SUCCESS;
225}
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:854
Exception thrown by Argz::proc() on unrecognised or malformed options.
Definition argz.hpp:169
void onSwapchainRecreated(PlanetWindow &window)
Definition planet.cpp:184
MatrixRainBackdrop(PlanetWindow &window, const std::string &assetRoot, bool binaryGlyphMode, int fontSize, const std::string &fontPath, const std::string &color)
Definition planet.cpp:162
void updateAndRender(PlanetWindow &window, VkCommandBuffer cmd)
Definition planet.cpp:190
~PlanetWindow() override
Definition planet.cpp:61
void onSwapchainRecreated() override
Called after swapchain and render resources are recreated.
Definition planet.cpp:115
void onSwapchainAboutToRecreate() override
Called right before swapchain-dependent resources are recreated.
Definition planet.cpp:109
void event(SDL_Event &e) override
Handle one SDL event.
Definition planet.cpp:68
void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t imageIndex) override
Optional hook for derived classes to record extra draw commands.
Definition planet.cpp:122
void renderBackgroundSprite(mxvk::VK_Sprite &sprite, VkCommandBuffer cmd)
Definition planet.cpp:146
PlanetWindow(const std::string &filename, const std::string &path, const std::string &title, int width, int height, bool fullscreen, bool enable_vsync, bool binary, int font_size, const std::string &font_path, const std::string &color)
Definition planet.cpp:47
std::string text() const
Convenience wrapper that owns mesh, textures, descriptors, and pipeline state.
Main Vulkan window wrapper for MXVK.
Definition mxvk.hpp:39
VkExtent2D getSwapchainExtent() const noexcept
Get the current swapchain extent.
Definition mxvk.hpp:222
void loop()
Run the main event/render loop.
Definition mxvk.cpp:651
VkDevice device
Definition mxvk.hpp:606
std::string font_path
Definition mxvk.hpp:714
void renderStandaloneSprite(VK_Sprite &sprite, VkCommandBuffer cmd)
Render one standalone sprite using the window's shared sprite pipeline.
Definition mxvk.cpp:1392
void exit()
Request loop termination.
Definition mxvk.cpp:1378
VK_Window()=default
Construct an empty window object.
#define MXVK_VALIDATION
Definition mxvk.hpp:28
High-level model wrapper integrated with MXVK dynamic rendering.
std::chrono::steady_clock Clock
Definition planet.cpp:27
int main()
Definition main.py:165
RainConfig make_matrix_rain_config(const std::string &asset_root, bool binary_glyph_mode)
Definition rain.cpp:142
Definition model.py:1
Utilities for loading and saving PNG images.
Definition mxvk.hpp:31
Plain data structure returned by proc_args() with all common libmx2 CLI options.
Definition argz.hpp:718
std::string font_path
Optional font file path (--font-path).
Definition argz.hpp:750
bool fullscreen
Whether fullscreen mode was requested.
Definition argz.hpp:724
bool enable_vsync
Enable FIFO present mode / v-sync (--enable-vsync).
Definition argz.hpp:738
int height
Viewport height in pixels (default: 720).
Definition argz.hpp:721
std::string color
Optional rain RGB tint (--color).
Definition argz.hpp:751
std::string filename
Optional input filename (--filename).
Definition argz.hpp:726
std::string path
Asset root; proc_args() defaults it to the executable directory.
Definition argz.hpp:723
int width
Viewport width in pixels (default: 1280).
Definition argz.hpp:720
int font_size
Matrix rain font size in pixels (--font-size).
Definition argz.hpp:749
bool binary
Use binary glyphs only (--binary).
Definition argz.hpp:736
std::string color
Definition rain.hpp:19
std::string font_path
Definition rain.hpp:18
Default transform UBO payload for model shaders.