9#include <glm/ext/matrix_clip_space.hpp>
10#include <glm/ext/matrix_transform.hpp>
19 GlitchCubeWindow(
const std::string &filename,
const std::string &path,
const std::string &title,
int width,
int height,
bool fullscreen,
bool enable_vsync)
21 assetRoot((path.empty() || path ==
".") ? std::string(GLITCH_CUBE_ASSET_DIR) : path) {
22 const std::string shaderRoot = assetRoot +
"/data";
23 const std::string modelPath = filename.empty() ? (assetRoot +
"/data/cube.mxmod.z") : filename;
24 const std::string textureManifestPath = assetRoot +
"/data/cube.tex";
25 const std::string textureBasePath = assetRoot +
"/data";
26 const std::string modelVertPath = shaderRoot +
"/model.vert.spv";
27 const std::string modelFragPath = shaderRoot +
"/model.frag.spv";
28 setFont(assetRoot +
"/data/font.ttf", 22);
29 model.load(
this, modelPath, textureManifestPath, textureBasePath, 1.0f);
30 model.setShaders(
this, modelVertPath, modelFragPath);
34 if (
device != VK_NULL_HANDLE) {
40 void event(SDL_Event &e)
override {
41 if (e.type == SDL_EVENT_KEY_DOWN) {
47 rotXFactor = (rotXFactor > 0.0f) ? 0.0f : 1.0f;
51 if (cubeScale > 4.0f) {
57 if (cubeScale < 0.2f) {
67 if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN && e.button.button == SDL_BUTTON_LEFT) {
69 lastMouseX =
static_cast<int>(e.button.x);
70 lastMouseY =
static_cast<int>(e.button.y);
74 if (e.type == SDL_EVENT_MOUSE_BUTTON_UP && e.button.button == SDL_BUTTON_LEFT) {
75 mouseDragging =
false;
79 if (e.type == SDL_EVENT_MOUSE_MOTION && mouseDragging) {
80 const int x =
static_cast<int>(e.motion.x);
81 const int y =
static_cast<int>(e.motion.y);
82 const int deltaX = x - lastMouseX;
83 const int deltaY = y - lastMouseY;
85 yawDegrees +=
static_cast<float>(deltaX) * mouseSensitivity;
86 pitchDegrees +=
static_cast<float>(deltaY) * mouseSensitivity;
87 pitchDegrees = std::clamp(pitchDegrees, -80.0f, 80.0f);
94 if (e.type == SDL_EVENT_MOUSE_WHEEL) {
95 const float delta = (e.wheel.y != 0.0f) ? e.wheel.y :
static_cast<float>(e.wheel.integer_y);
96 cameraDistance -= delta * 0.45f;
97 cameraDistance = std::clamp(cameraDistance, 1.8f, 12.0f);
102 printText(
"Drag left mouse to orbit the cube", 25, 25, {255, 255, 255, 255});
103 printText(
"Mouse wheel zooms the camera", 25, 60, {255, 255, 255, 255});
104 printText(
"Space toggles the rotation axis", 25, 95, {255, 255, 255, 255});
105 printText(
"Page Up / Page Down adjust cube scale", 25, 130, {255, 255, 255, 255});
106 printText(std::format(
"Current scale: {:.1f}", cubeScale), 25, 165, {230, 245, 255, 255});
114 const float elapsedSeconds = std::chrono::duration<float>(std::chrono::steady_clock::now() - start).count();
117 const float aspect = (extent.height > 0U)
118 ?
static_cast<float>(extent.width) /
static_cast<float>(extent.height)
121 const float rotationAngle = elapsedSeconds * glm::radians(50.0f);
124 ubo.
model = glm::rotate(glm::mat4(1.0f), rotationAngle, glm::vec3(rotXFactor, 1.0f, 0.0f));
125 ubo.
model = glm::scale(ubo.
model, glm::vec3(model.modelRenderScale() * cubeScale));
126 ubo.
model = glm::translate(ubo.
model, model.modelCenterOffset());
128 const float yawRadians = glm::radians(yawDegrees);
129 const float pitchRadians = glm::radians(pitchDegrees);
130 const glm::vec3 cameraPos{
131 cameraDistance * std::cos(pitchRadians) * std::sin(yawRadians),
132 cameraDistance * std::sin(pitchRadians),
133 cameraDistance * std::cos(pitchRadians) * std::cos(yawRadians)};
135 ubo.
view = glm::lookAt(cameraPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
136 ubo.
proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 100.0f);
137 ubo.
proj[1][1] *= -1.0f;
139 model.updateUBO(imageIndex, ubo);
140 model.render(cmd, imageIndex,
false);
144 std::string assetRoot;
146 float rotXFactor = 1.0f;
147 float cubeScale = 1.0f;
148 std::chrono::steady_clock::time_point start{std::chrono::steady_clock::now()};
149 bool mouseDragging =
false;
152 float yawDegrees = 0.0f;
153 float pitchDegrees = 12.0f;
154 float cameraDistance = 5.0f;
155 float mouseSensitivity = 0.35f;
160int main(
int argc,
char **argv) {
166 std::cerr << std::format(
"mxvk: Exception: {}\n", e.
text());
169 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.
GlitchCubeWindow(const std::string &filename, const std::string &path, const std::string &title, int width, int height, bool fullscreen, bool enable_vsync)
~GlitchCubeWindow() override
void onSwapchainRecreated() override
Called after swapchain and render resources are recreated.
void proc() override
Execute one processing/update step.
void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t imageIndex) override
Optional hook for derived classes to record extra draw commands.
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.
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).