10#include <glm/ext/matrix_clip_space.hpp>
11#include <glm/ext/matrix_transform.hpp>
23 DarkWindow(
const std::string &filename,
const std::string &path,
const std::string &title,
int width,
int height,
bool fullscreen,
bool enable_vsync)
25 assetRoot((path.empty() || path ==
".") ? std::string(DARK_ASSET_DIR) : path) {
26 fallbackWidth = width;
27 fallbackHeight = height;
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";
37 setFont(assetRoot +
"/data/font.ttf", 48);
39 beamModel.load(
this, beamModelPath,
"",
"", 1.0f);
40 beamModel.setAlphaBlending(
true);
41 beamModel.setShaders(
this, beamVertPath, beamFragPath);
43 model.load(
this, modelPath,
"",
"", 1.0f);
44 model.setAlphaBlending(
true);
45 model.setShaders(
this, vertPath, fragPath);
49 if (
device != VK_NULL_HANDLE) {
52 beamModel.cleanup(
this);
56 void event(SDL_Event &e)
override {
57 if (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE) {
62 if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN && e.button.button == SDL_BUTTON_LEFT) {
64 lastMouseX =
static_cast<int>(e.button.x);
65 lastMouseY =
static_cast<int>(e.button.y);
69 if (e.type == SDL_EVENT_MOUSE_BUTTON_UP && e.button.button == SDL_BUTTON_LEFT) {
70 mouseDragging =
false;
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;
80 yawDegrees +=
static_cast<float>(deltaX) * mouseSensitivity;
81 pitchDegrees +=
static_cast<float>(deltaY) * mouseSensitivity;
82 pitchDegrees = std::clamp(pitchDegrees, -55.0f, 55.0f);
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);
98 beamModel.resize(
this);
104 const int width = extent.width > 0U ?
static_cast<int>(extent.width) : fallbackWidth;
106 constexpr const char *titleText =
"the Lunatic iS in my heaD";
110 const int textX = std::max(0, (width - textWidth) / 2);
111 printText(titleText, textX, 24, {255, 255, 255, 255});
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();
121 if (autoSpinEnabled) {
122 autoSpinRadians += deltaSeconds * 0.55f;
126 const float aspect = (extent.height > 0U)
127 ?
static_cast<float>(extent.width) /
static_cast<float>(extent.height)
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)};
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);
148 beamUbo.
model = glm::mat4(1.0f);
151 beamUbo.
fx = glm::vec4(elapsedSeconds, autoSpinRadians, 1.0f, 1.0f);
153 beamModel.updateUBO(imageIndex, beamUbo);
154 beamModel.render(cmd, imageIndex,
false);
156 model.updateUBO(imageIndex, ubo);
157 model.render(cmd, imageIndex,
false);
161 std::string assetRoot;
164 bool mouseDragging =
false;
165 bool autoSpinEnabled =
true;
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();
182int main(
int argc,
char **argv) {
188 std::cerr << std::format(
"mxvk: Exception: {}\n", e.
text());
191 std::cerr << std::format(
"mxvk: Argument Exception: {}\n", e.
text());
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.
Exception thrown by Argz::proc() on unrecognised or malformed options.
void event(SDL_Event &e) override
Handle one SDL event.
void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t imageIndex) override
Optional hook for derived classes to record extra draw commands.
void onSwapchainRecreated() override
Called after swapchain and render resources are recreated.
DarkWindow(const std::string &filename, const std::string &path, const std::string &title, int width, int height, bool fullscreen, bool enable_vsync)
void proc() override
Execute one processing/update step.
Convenience wrapper that owns mesh, textures, descriptors, and pipeline state.
Main Vulkan window wrapper for MXVK.
VkExtent2D getSwapchainExtent() const noexcept
Get the current swapchain extent.
void loop()
Run the main event/render loop.
bool getTextDimensions(const std::string &text, int &width, int &height)
Measure text dimensions in pixels.
void exit()
Request loop termination.
VK_Window()=default
Construct an empty window object.
void setFont(const std::string &fontPath, int fontSize=24)
Set the active text-render font.
void printText(const std::string &text, int x, int y, const SDL_Color &col)
Queue a text string for rendering during the current frame.
High-level model wrapper integrated with MXVK dynamic rendering.
Utilities for loading and saving PNG images.
Plain data structure returned by proc_args() with all common libmx2 CLI options.
bool fullscreen
Whether fullscreen mode was requested.
bool enable_vsync
Enable FIFO present mode / v-sync (--enable-vsync).
int height
Viewport height in pixels (default: 720).
std::string filename
Optional input filename (--filename).
std::string path
Asset root; proc_args() defaults it to the executable directory.
int width
Viewport width in pixels (default: 1280).