Files
SpartanPort/tests/test_motion_blur.cpp
Claude 359815822d Feat(Graphics): a setting to turn off the game's motion blur
The blur is a short chain of passes found in a frame capture: a half resolution pass draws a
velocity image, one draw blurs the half resolution scene colour along it (ps 107d87f9d56574cf) and
the next draw blends the result back over the full resolution scene colour (ps abd418f2b4587d5d,
the blended use of a plain copy shader). With "Motion blur" off those two draws are skipped, so the
scene colour is left as the game rendered it. On (the default) nothing changes.

- spartanport.ini: motion_blur (default 1); env override SPARTAN_MOTION_BLUR. Live.
- In-game menu (Graphics > Effects) and launcher (Graphics > Effects), with pt/es/zh texts.
- The skip rule is in gpu/shim/spartanport_motion_blur.h with its own test
  (tests/test_motion_blur.cpp); the setting is covered in tests/test_graphics_settings.cpp.
- The log notes the first skipped draw of each kind (Motion blur: off, skipping ...).

Not run on a real game yet: the hashes come from one capture of CUSA01623 01.02.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XtU1iHgWpXde4Af9YrW3Y6
2026-10-22 11:52:21 +02:00

55 lines
2.7 KiB
C++

// The motion blur skip rule (gpu/shim/spartanport_motion_blur.h): no GPU or game dump needed.
#include <cassert>
#include <cstdio>
#include "spartanport_motion_blur.h"
int main() {
using SpartanMotionBlur::Action;
using SpartanMotionBlur::BlurPass;
using SpartanMotionBlur::Composite;
constexpr std::uint64_t Other = 0x1234;
{
// On: nothing is skipped, whatever the shaders are.
SpartanMotionBlur::Rule rule;
assert(rule.Next(Other, false, false) == Action::Draw);
assert(rule.Next(BlurPass, false, false) == Action::Draw);
assert(rule.Next(Composite, true, false) == Action::Draw);
assert(rule.Next(Composite, false, false) == Action::Draw);
}
{
// Off: the blur draw and the blended copy right after it go, everything else stays.
SpartanMotionBlur::Rule rule;
assert(rule.Next(Other, false, true) == Action::Draw);
assert(rule.Next(Composite, false, true) == Action::Draw); // the copy without blending
assert(rule.Next(Composite, true, true) == Action::Draw); // blended, but no blur before it
assert(rule.Next(BlurPass, false, true) == Action::SkipBlur);
assert(rule.Next(Composite, true, true) == Action::SkipComposite);
assert(rule.Next(Composite, true, true) == Action::Draw); // only the one after the blur
assert(rule.Next(BlurPass, false, true) == Action::SkipBlur);
assert(rule.Next(BlurPass, false, true) == Action::SkipBlur); // a second blur draw
assert(rule.Next(Composite, true, true) == Action::SkipComposite);
}
{
// A draw between the two ends the wait: the copy after it is drawn.
SpartanMotionBlur::Rule rule;
assert(rule.Next(BlurPass, false, true) == Action::SkipBlur);
assert(rule.Next(Other, true, true) == Action::Draw);
assert(rule.Next(Composite, true, true) == Action::Draw);
// The copy without blending directly after the blur is not the composite either.
assert(rule.Next(BlurPass, false, true) == Action::SkipBlur);
assert(rule.Next(Composite, false, true) == Action::Draw);
assert(rule.Next(Composite, true, true) == Action::Draw);
}
{
// Switched on between the two draws: the copy of the skipped blur is still skipped (it
// would blend a picture nobody drew), and the next blur is drawn.
SpartanMotionBlur::Rule rule;
assert(rule.Next(BlurPass, false, true) == Action::SkipBlur);
assert(rule.Next(Composite, true, false) == Action::SkipComposite);
assert(rule.Next(BlurPass, false, false) == Action::Draw);
assert(rule.Next(Composite, true, false) == Action::Draw);
}
std::puts("Motion blur rule tests passed");
}