mirror of
https://github.com/Toastconcern/FrameStudio.git
synced 2026-10-28 20:03:07 +01:00
Decode HDR-encoded colour ASTC textures, not just linear ones (fixes the Focused vista)
Some environments store colour (sRGB) textures as HDR-encoded ASTC — the Focused vista's sky, water and glow. The LDR decoder fills those with magenta error texels (the vista showed a huge magenta plane). We already re-decode linear UNORM textures through the HDR profile for the same reason; do it for colour textures too: when the LDR decode comes back mostly magenta, re-decode through the HDR profile and sRGB-encode the clamped linear colour so the sRGB view samples it right (alpha stays linear). Verified by rendering the vista before/after. (A few of the vista's special detail textures are neither plain LDR nor plain HDR colour and still look speckled; left for a follow-up.) Also: a GUI-subsystem Windows build now sends the tool modes' log (--snapshot, --panorama, --bench) to the file, since there's no console for them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
996c447a55
commit
b95fd82647
2 files changed
+29
-1
No files matched your search
+20
-1
@@ -2110,7 +2110,7 @@ void HslRenderer::startWorkers() {
|
||||
// Linear (UNORM) textures — normals, ORM, masks — may carry HDR-encoded ASTC blocks, which the LDR
|
||||
// profile turns into magenta error texels (a corrupt ORM made the converted Cascadia's floor a
|
||||
// mirror). Decode them with the HDR profile, unclamped, then clamp to 8 bits (HSR Studio decodes
|
||||
// every UNORM ASTC texture through float too). sRGB colour textures keep the LDR path.
|
||||
// every UNORM ASTC texture through float too). Colour (sRGB) textures start on the LDR path.
|
||||
bool decoded = false;
|
||||
if (!job.srgb) {
|
||||
std::vector<uint16_t> half;
|
||||
@@ -2125,6 +2125,25 @@ void HslRenderer::startWorkers() {
|
||||
}
|
||||
}
|
||||
if (decoded || astc::decodeASTC(job.src->astc.data() + off, static_cast<u32>(lvl), w, h, job.src->bw, job.src->bh, rgba, false, 1)) {
|
||||
// A colour texture can be HDR-encoded too (the Focused vista's sky, water and glow): the LDR decode
|
||||
// then fills it with magenta error texels. Spot that (a lot of exact-magenta texels) and re-decode
|
||||
// through the HDR profile, sRGB-encoding the clamped linear colour so the sRGB view samples it
|
||||
// right; alpha is linear either way.
|
||||
if (job.srgb && !decoded && rgba.size() >= static_cast<size_t>(w) * h * 4) {
|
||||
size_t mag = 0;
|
||||
for (size_t q = 0; q + 3 < rgba.size(); q += 4)
|
||||
if (rgba[q] > 250 && rgba[q + 1] < 8 && rgba[q + 2] > 250) ++mag;
|
||||
std::vector<uint16_t> half;
|
||||
if (mag * 4 > static_cast<size_t>(w) * h && // a quarter or more of the texels are the error colour
|
||||
astc::decodeASTCHalf(job.src->astc.data() + off, static_cast<u32>(lvl), w, h, job.src->bw, job.src->bh, half) &&
|
||||
half.size() >= static_cast<size_t>(w) * h * 4) {
|
||||
auto toSrgb = [](float c) { c = std::clamp(c, 0.0f, 1.0f); return c <= 0.0031308f ? c * 12.92f : 1.055f * std::pow(c, 1.0f / 2.4f) - 0.055f; };
|
||||
for (size_t q = 0; q < rgba.size(); ++q) {
|
||||
const float v = fromHalf(half[q]);
|
||||
rgba[q] = static_cast<u8>(std::lround(((q & 3) == 3 ? std::clamp(v, 0.0f, 1.0f) : toSrgb(v)) * 255.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
// A texture cooked without mips (a 6000^2 flipbook) arrives full size: brought within the cap here.
|
||||
while (std::max(w, h) > maxDecodedSide() && rgba.size() >= static_cast<size_t>(w) * h * 4) halveRGBA(rgba, w, h);
|
||||
// The image and its filled staging buffer are made here too: the frame only records the copy.
|
||||
|
||||
@@ -2064,6 +2064,15 @@ int runInstall(bool install) {
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
homeos::logCrashes();
|
||||
#ifdef _WIN32
|
||||
// A GUI-subsystem build (no console window) has nowhere for the tool modes (--snapshot, --panorama, --bench) to
|
||||
// print; send their messages to the log instead. runVr reopens it afresh for the environment itself.
|
||||
if (!homeos::stderrIsTerminal()) {
|
||||
std::error_code ec;
|
||||
fs::create_directories(rootDir() / "logs", ec);
|
||||
homeos::reopenStderr(rootDir() / "logs" / "frame-home.log", "a");
|
||||
}
|
||||
#endif
|
||||
#ifdef FH_USE_VOLK
|
||||
if (volkInitialize() != VK_SUCCESS) { std::fprintf(stderr, "frame-home: no Vulkan on this system\n"); return 1; }
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user