MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
surface.cpp
Go to the documentation of this file.
1#include "mxvk/argz.hpp"
2#include "mxvk/mxvk.hpp"
4#include <SDL3/SDL.h>
5#include <array>
6#include <cmath>
7#include <cstdint>
8#include <format>
9#include <iostream>
10#include <memory>
11#include <random>
12
13namespace surface {
14 struct Point {
15 float x = 0.0f;
16 float y = 0.0f;
17 };
18
19 constexpr float PI = 3.14159265358979323846f;
20
21 std::array<Point, 10> create_star_points(float center_x, float center_y, float outer_radius, float inner_radius) {
22 std::array<Point, 10> points{};
23 constexpr float start_angle = -PI * 0.5f;
24 constexpr float step = PI / 5.0f;
25
26 for (std::size_t i = 0; i < points.size(); ++i) {
27 const float radius = (i % 2U == 0U) ? outer_radius : inner_radius;
28 const float angle = start_angle + static_cast<float>(i) * step;
29 points[i] = {
30 .x = center_x + std::cos(angle) * radius,
31 .y = center_y + std::sin(angle) * radius,
32 };
33 }
34 return points;
35 }
36
37 bool point_in_star(float x, float y, const std::array<Point, 10> &points) {
38 bool inside = false;
39 for (std::size_t i = 0, j = points.size() - 1U; i < points.size(); j = i++) {
40 const Point &a = points[i];
41 const Point &b = points[j];
42 if (((a.y > y) != (b.y > y)) && (x < (b.x - a.x) * (y - a.y) / (b.y - a.y) + a.x)) {
43 inside = !inside;
44 }
45 }
46 return inside;
47 }
48
50 void operator()(SDL_Surface *surface) const {
51 if (surface != nullptr) {
52 SDL_DestroySurface(surface);
53 }
54 }
55 };
56
58
59 public:
60 SurfaceWindow(std::string shader_path, int width, int height, bool full, bool enable_vsync) : mxvk::VK_Window(" -[ MXVK Stencil Surface ] - ", width, height, full, MXVK_VALIDATION, enable_vsync) {
61 std::cout << "stencil_surface: started example.\n";
62 if (!resize_canvas_to_swapchain()) {
63 throw mxvk::Exception("stencil_surface: failed to initialize canvas from swapchain extent");
64 }
65 surf = createSprite(bg.get(), "", shader_path);
66 }
67 void event(SDL_Event &e) override {
68 switch (e.type) {
69 case SDL_EVENT_KEY_DOWN:
70 if (e.key.key == SDLK_ESCAPE) {
71 exit();
72 return;
73 }
74 break;
75 case SDL_EVENT_QUIT:
76 exit();
77 return;
78 }
79 }
80 void proc() override {
81 SDL_Surface *canvas = bg.get();
82 if (canvas == nullptr || !SDL_LockSurface(canvas)) {
83 return;
84 }
85 const float center_x = static_cast<float>(canvas->w) * 0.5f;
86 const float center_y = static_cast<float>(canvas->h) * 0.5f;
87 const float outer_radius = static_cast<float>(std::min(canvas->w, canvas->h)) * 0.42f;
88 const std::array<Point, 10> star = create_star_points(center_x, center_y, outer_radius, outer_radius * 0.42f);
89
90 auto *pixels = static_cast<Uint8 *>(canvas->pixels);
91 for (int y = 0; y < canvas->h; ++y) {
92 Uint8 *row = pixels + y * canvas->pitch;
93 for (int x = 0; x < canvas->w; ++x) {
94 Uint8 *p = row + x * 4;
95 if (point_in_star(static_cast<float>(x) + 0.5f, static_cast<float>(y) + 0.5f, star)) {
96 const std::uint32_t color = random_color(random_engine);
97 p[0] = static_cast<Uint8>(color & 0xFFU);
98 p[1] = static_cast<Uint8>((color >> 8U) & 0xFFU);
99 p[2] = static_cast<Uint8>((color >> 16U) & 0xFFU);
100 } else {
101 p[0] = 8U;
102 p[1] = 10U;
103 p[2] = 16U;
104 }
105 p[3] = static_cast<Uint8>(255);
106 }
107 }
108 SDL_UnlockSurface(canvas);
109 surf->updateTexture(canvas);
110 surf->drawSpriteRect(0, 0, target_width, target_height);
111 }
112
113 void onSwapchainRecreated() override {
114 resize_canvas_to_swapchain();
115 }
116
117 private:
118 bool resize_canvas_to_swapchain() {
119 if (!ensureRenderResources()) {
120 return false;
121 }
122 const VkExtent2D extent = getSwapchainExtent();
123 if (extent.width == 0U || extent.height == 0U) {
124 return false;
125 }
126 resize_canvas(static_cast<int>(extent.width), static_cast<int>(extent.height));
127 return true;
128 }
129
130 void resize_canvas(int width, int height) {
131 if (width <= 0 || height <= 0 || (bg != nullptr && bg->w == width && bg->h == height)) {
132 return;
133 }
134 bg.reset(SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32));
135 if (bg == nullptr) {
136 throw mxvk::Exception("Failed to create surface canvas: " + std::string(SDL_GetError()));
137 }
138 SDL_FillSurfaceRect(bg.get(), nullptr, SDL_MapSurfaceRGBA(bg.get(), 0, 0, 0, 255));
139 target_width = width;
140 target_height = height;
141 }
142
143 mxvk::VK_Sprite *surf = nullptr;
144 std::unique_ptr<SDL_Surface, surface::SurfaceDeleter> bg;
145 int target_width = 1280;
146 int target_height = 720;
147 std::mt19937 random_engine{std::random_device{}()};
148 std::uniform_int_distribution<std::uint32_t> random_color{0U, 0x00FFFFFFU};
149 };
150} // namespace surface
151
152int main(int argc, char **argv) {
153 try {
154 Arguments args = proc_args(argc, argv);
155 surface::SurfaceWindow window(args.filename, args.width, args.height, args.fullscreen, args.enable_vsync);
156 window.loop();
157 } catch (mxvk::Exception &e) {
158 std::cerr << std::format("mxvk: Exception: {}\n", e.text());
159 return EXIT_FAILURE;
160 } catch (ArgException<std::string> &e) {
161 std::cerr << std::format("mxvk: Argument Exception: {}\n", e.text());
162 return EXIT_FAILURE;
163 }
164 return EXIT_SUCCESS;
165}
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
std::string text() const
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
VK_Sprite * createSprite(const std::string &pngPath, const std::string &vertexShaderPath="", const std::string &fragmentShaderPath="")
Create a sprite from a PNG file and register it with this window.
Definition mxvk.cpp:3477
void exit()
Request loop termination.
Definition mxvk.cpp:1126
bool ensureRenderResources()
Ensure deferred render resources are initialized.
Definition mxvk.cpp:1406
VK_Window()=default
Construct an empty window object.
void onSwapchainRecreated() override
Called after swapchain and render resources are recreated.
Definition surface.cpp:113
SurfaceWindow(std::string shader_path, int width, int height, bool full, bool enable_vsync)
Definition surface.cpp:60
void proc() override
Execute one processing/update step.
Definition surface.cpp:80
void event(SDL_Event &e) override
Handle one SDL event.
Definition surface.cpp:67
int main(void)
Definition main.cpp:7
#define MXVK_VALIDATION
Definition mxvk.hpp:27
Utilities for loading and saving PNG images.
Definition mxvk.hpp:30
bool point_in_star(float x, float y, const std::array< Point, 10 > &points)
Definition surface.cpp:37
constexpr float PI
Definition surface.cpp:19
std::array< Point, 10 > create_star_points(float center_x, float center_y, float outer_radius, float inner_radius)
Definition surface.cpp:21
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
int width
Viewport width in pixels (default: 1280).
Definition argz.hpp:732
void operator()(SDL_Surface *surface) const
Definition surface.cpp:50