33 PostprocessWindow(
const std::string &path,
int width,
int height,
bool fullscreen,
bool enable_vsync)
35 asset_root((path.empty() || path ==
".") ? std::string(postprocess_ASSET_DIR) : path) {
36 resizeCanvas(width, height);
38 attachEffects(loadEffects(asset_root +
"/data/shaders.txt"));
41 void event(SDL_Event &e)
override {
42 if (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE) {
45 if (e.type == SDL_EVENT_QUIT) {
52 const int targetWidth = extent.width > 0U ?
static_cast<int>(extent.width) : canvas_width;
53 const int targetHeight = extent.height > 0U ?
static_cast<int>(extent.height) : canvas_height;
54 if (targetWidth != canvas_width || targetHeight != canvas_height) {
55 resizeCanvas(targetWidth, targetHeight);
59 if (sprite !=
nullptr) {
60 sprite->updateTexture(canvas.get());
61 sprite->drawSpriteRect(0, 0, canvas_width, canvas_height);
66 static std::string trim(std::string value) {
67 const auto first = std::ranges::find_if(value, [](
unsigned char ch) {
68 return !std::isspace(ch);
70 const auto last = std::ranges::find_if(value | std::views::reverse, [](
unsigned char ch) {
71 return !std::isspace(ch);
76 return std::string(first, last);
79 std::vector<mxvk::VK_Window::PostProcessingEffect> loadEffects(
const std::string &manifestPath)
const {
80 std::ifstream file(manifestPath);
81 if (!file.is_open()) {
82 throw mxvk::Exception(
"postprocess: failed to open " + manifestPath);
85 std::vector<mxvk::VK_Window::PostProcessingEffect> effects;
87 while (std::getline(file, line)) {
88 const size_t comment = line.find(
'#');
89 if (comment != std::string::npos) {
97 std::filesystem::path shader_path(line);
98 if (shader_path.is_relative()) {
99 shader_path = std::filesystem::path(asset_root) /
"data" / shader_path;
101 if (!std::filesystem::exists(shader_path)) {
102 throw mxvk::Exception(
"postprocess: shader listed in shaders.txt was not found: " + shader_path.string());
105 mxvk::VK_Window::PostProcessingEffect effect{};
107 effect.
params = {0.0f, 1.0f, 1.0f, 0.0f};
109 effects.push_back(effect);
115 void attachEffects(
const std::vector<mxvk::VK_Window::PostProcessingEffect> &effects) {
116 if (effects.empty()) {
122 for (
size_t i = 0; i < effects.size(); ++i) {
126 std::cout << std::format(
"postprocess: attached {} post-processing effect(s)\n", effects.size());
129 void resizeCanvas(
int width,
int height) {
130 if (width <= 0 || height <= 0) {
133 if (canvas !=
nullptr && canvas_width == width && canvas_height == height) {
137 canvas.reset(SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32));
138 if (canvas ==
nullptr) {
139 throw mxvk::Exception(
"postprocess: failed to create SDL surface: " + std::string(SDL_GetError()));
141 canvas_width = width;
142 canvas_height = height;
146 if (canvas ==
nullptr || !SDL_LockSurface(canvas.get())) {
151 auto *pixels =
static_cast<std::uint8_t *
>(canvas->pixels);
152 for (
int y = 0; y < canvas_height; ++y) {
153 std::uint8_t *row = pixels + y * canvas->pitch;
154 for (
int x = 0; x < canvas_width; ++x) {
155 const float nx =
static_cast<float>(x) /
static_cast<float>(std::max(canvas_width - 1, 1));
156 const float ny =
static_cast<float>(y) /
static_cast<float>(std::max(canvas_height - 1, 1));
157 const int checker = ((x / 48) + (y / 48)) & 1;
158 const std::uint8_t red =
static_cast<std::uint8_t
>(40.0f + nx * 180.0f);
159 const std::uint8_t green =
static_cast<std::uint8_t
>(50.0f + ny * 160.0f);
160 const std::uint8_t blue =
static_cast<std::uint8_t
>(checker != 0 ? 220 : 80);
161 std::uint8_t *pixel = row + x * 4;
162 pixel[0] =
static_cast<std::uint8_t
>((red + frame) & 0xFF);
169 SDL_UnlockSurface(canvas.get());
172 std::string asset_root;
173 mxvk::VK_Sprite *sprite =
nullptr;
174 std::unique_ptr<SDL_Surface, SurfaceDeleter> canvas;
175 int canvas_width = 1280;
176 int canvas_height = 720;
177 std::uint8_t frame = 0;
void event(SDL_Event &e) override
Handle one SDL event.
void proc() override
Execute one processing/update step.
PostprocessWindow(const std::string &path, int width, int height, bool fullscreen, bool enable_vsync)
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.
std::array< float, 4 > params
std::string fragmentShaderPath