Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion game/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,34 @@

using namespace Tempest;

namespace {
Pixmap downscaleSavePreviewPixmap(Pixmap src) {
if(src.isEmpty() || src.format()!=TextureFormat::RGBA8)
return src;
constexpr uint32_t kThumbW = 640, kThumbH = 480;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

480 is overkill in term of how small image. 1440p, maybe?
Note: images can be extracted as screen-shoots.

Copy link
Copy Markdown
Contributor Author

@jairus-kope jairus-kope Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change does not affect screen-shoots (F11 key I believe) which will keep as is.
This is only for the thumbnails in the load/save screen. images there are a small part of the screen so I wouldn't think they need a high resolution. anyways I've changed it to 1024 (maybe take this from ini settings?)
Regarding timings (I tested this manually with my phone's stopwatch so not that accurate..):
without this change it produced a 6K HDR (6016x3384), though my screen resolution is 3008x1692 - save took ~7 seconds
1440p took ~1.5 seconds
640x480 took ~0.3 seconds (keeping aspect ration of 16:9 will probably take less)
1024x768 took ~0.5 seconds
1024x576 ie. keeping 16:9 aspect ratio (using the latest code changes i pushed) - took about i guess ~0.4 seconds
Note that these changes also totally remove the lag of the load/save screen loading.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only for the thumbnails in the load/save screen

Yes; what I've been pointing to is fact that screen-shoot can be extracted from the save as *.png.
For move precise time you can leverage Application::tickCount utility.

const uint32_t w = src.w(), h = src.h();

if(w<=kThumbW || h<=kThumbH)
return src;

Pixmap out(kThumbW, kThumbH, TextureFormat::RGBA8);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code doesn't preserve proportions. 640x480 is 4:3 ratio, but most screens today is 16:9.

TextureFormat::RGBA8

While today it's rgba8, but there is HDR support in works - so, you should not relay strongly on format. Probably downsampling image on GPU would make more sense, to take care of formats and performance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good points. I modified the code to preserve aspect ratio and also the original texture format. Though I don't have the means to test it on HDR.
yeah I agree. downsampling on GPU would probably be best. Feel free to use this as a temp fix or just PoC

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it be OK, to you if I'll implement the feature on my own, with gpu-support and you your data only as reference?
Asking, since merging first and do full rewrite a week after is also not ideal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. please go ahead. just happy to have assisted with finding and debugging this issue. I think solving it will definitely improve the gaming experience.

const auto* s = static_cast<const uint32_t*>(src.data());
auto* d = static_cast<uint32_t*>(out.data());

// Copy source pixel map to reduced pixel map using Nearest-Neighbor interpolation
for(uint32_t y=0; y<kThumbH; ++y) {
const uint32_t sy = std::min(h-1u, uint32_t((size_t(y)*h)/kThumbH));
const uint32_t rowOffset = sy * w;

for(uint32_t x=0; x<kThumbW; ++x) {
const uint32_t sx = std::min(w-1u, uint32_t((size_t(x)*w)/kThumbW));
d[y * kThumbW + x] = s[rowOffset + sx];
}
}
return out;
}
}

MainWindow::MainWindow(Device& device)
: Window(Maximized),device(device),swapchain(device,hwnd()),
atlas(device),renderer(swapchain),
Expand Down Expand Up @@ -1062,7 +1090,9 @@ void MainWindow::loadGame(std::string_view slot) {

void MainWindow::saveGame(std::string_view slot, std::string_view name) {
auto tex = renderer.screenshoot(cmdId);
auto pm = device.readPixels(textureCast<const Texture2d&>(tex));

// reduce size of the save entry preview screenshot for faster save & load
auto pm = downscaleSavePreviewPixmap(device.readPixels(textureCast<const Texture2d&>(tex)));

if(dialogs.isActive())
return;
Expand Down