feat(options): Implement game options for texture filter mode, anisotropy and MSAA selection#2482
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Source/Common/OptionPreferences.cpp | Adds getAntiAliasing(), getTextureFilterMode(), getTextureAnisotropyLevel() — logic is sound except for an inconsistent == guard in getAntiAliasing() that should be <=. |
| Core/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp | _Init_Filters now takes an explicit anisotropy_level argument and forwards it to _Set_Max_Anisotropy instead of hardcoding 2X. Correct. |
| GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp | Adds Set_Anisotropy_level() with correct ≤-based clamping and a new AnisotropyLevel static; Set_Texture_Filter() now passes the stored anisotropy level through. No issues. |
| GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h | MultiSampleModeEnum values are now explicitly assigned (0, 2, 4, 8) to match the INI values; new Set/Get_Anisotropy_level API added. Clean. |
| GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp | Anti-aliasing saving/loading now correctly converts between combo-box position and MSAA sample count. Two always-true val >= 0 guards in the texture filter / anisotropy blocks. |
| GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp | Applies MSAA mode from global data before device creation, then reads back the GPU-accepted mode afterwards and applies texture filter + anisotropy level. Post-init read-back pattern is sound. |
Sequence Diagram
sequenceDiagram
participant INI as Options.ini
participant OP as OptionPreferences
participant GD as GlobalData
participant W3DD as W3DDisplay::init()
participant WW3D as WW3D
participant TF as TextureFilterClass
INI->>OP: load("Options.ini")
OP->>GD: getAntiAliasing() → m_antiAliasLevel
OP->>GD: getTextureFilterMode() → m_textureFilteringMode
OP->>GD: getTextureAnisotropyLevel() → m_textureAnisotropyLevel
GD->>W3DD: m_antiAliasLevel
W3DD->>WW3D: Set_MSAA_Mode(m_antiAliasLevel)
W3DD->>WW3D: Set_Render_Device(...)
WW3D-->>W3DD: Get_MSAA_Mode() [GPU-clamped]
W3DD->>GD: m_antiAliasLevel ← GPU-accepted value
W3DD->>WW3D: Set_Texture_Filter(m_textureFilteringMode)
WW3D->>TF: _Init_Filters(TextureFilter, AnisotropyLevel)
W3DD->>WW3D: Set_Anisotropy_level(m_textureAnisotropyLevel)
WW3D->>TF: _Set_Max_Anisotropy(level)
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Core/GameEngine/Source/Common/OptionPreferences.cpp
Line: 79-80
Comment:
**No-op branch, inconsistent with the `<=` pattern**
The first `if` branch is a no-op — it reads `if (level == MULTISAMPLE_MODE_NONE) level = MULTISAMPLE_MODE_NONE`, which assigns the same value it just tested for. It works correctly only because `UnsignedInt` can never be less than zero, but it is inconsistent with every other range-clamp in the file (including `getTextureAnisotropyLevel()` and `Set_Anisotropy_level()`), all of which use `<=`. Prefer `<=` here for clarity and uniformity:
```suggestion
if (level <= WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_NONE)
level = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_NONE;
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp
Line: 586
Comment:
**`val >= 0` is an always-true condition**
`val` is declared as `Int`, and both `getTextureFilterMode()` and `getTextureAnisotropyLevel()` always return a small, bounded `UnsignedInt` (0–4 and 2/4/8/16 respectively), so this guard is never false. The same always-true pattern appears at line 616 in the anisotropy block. If the intent is simply to guard against a null `TheGlobalData`, the condition should reflect that directly:
```suggestion
if (TheGlobalData)
```
The same applies to the matching check at line 616.
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: "feat(options): Imple..."
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp
Show resolved
Hide resolved
120d3db to
cfff7d1
Compare
|
Generals is currently broken till i replicate across due to changes in initaialising the texture filtering |
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp
Outdated
Show resolved
Hide resolved
cfff7d1 to
915e548
Compare
915e548 to
53085fc
Compare
xezon
left a comment
There was a problem hiding this comment.
This implementation can be polished more.
|
|
||
| enum AliasingMode CPP_11(: Int) | ||
| { | ||
| OFF = 0, |
There was a problem hiding this comment.
Please put more into the name to avoid shadowing or macro conflicts.
|
|
||
| UnsignedInt getAntiAliasing(); | ||
| UnsignedInt getTextureFilterMode(); | ||
| UnsignedInt getTextureAnisotropyLevel(); |
| level = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_8X; | ||
|
|
||
| if (level > WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_8X) | ||
| level = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_8X; |
There was a problem hiding this comment.
enums are unscoped, so MultiSampleModeEnum:: is redundant.
| else if (level <= WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_4X) | ||
| level = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_4X; | ||
| else if (level <= WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_8X) | ||
| level = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_8X; |
There was a problem hiding this comment.
I think it is a bit odd that Value 5 would become 8. I would expect 7 becomes 4.
Can be simplified and improved by doing
Int level = atoi(it->second.str());
level = clamp(WW3D::MULTISAMPLE_MODE_FIRST, level, WW3D::MULTISAMPLE_MODE_LAST);
level = highestBit(level);Then add in BaseType.h or so
template <typename T>
T highestBit(T v)
{
static_assert(sizeof(T) <= 8, "T must be smaller equal 8");
UnsignedInt64 i = static_cast<UnsignedInt64>(v);
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
i |= i >> 32;
return static_cast<T>(i - (i >> 1));
}This will work for as long as the values are expected to be power of 2, which I think is always the case.
Same for AnisotropicFilterMode
|
|
||
| UnsignedInt OptionPreferences::getTextureAnisotropyLevel() | ||
| { | ||
| OptionPreferences::const_iterator it = find("AnisotropyLevel"); |
There was a problem hiding this comment.
Is this an intuitive term for players? If I am not mistaken NVIDIA and AMD drivers call this Anisotropic.
There was a problem hiding this comment.
It's often hidden by having the user facing texture filter mode option showing Anisotropic x2, Anisotropic x4 etc
The underlying graphics API's use Anisotropy level to set the sampling mode for Anisotropic filtering.
| m_antiAliasBoxValue = 0; | ||
| m_antiAliasLevel = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_NONE; | ||
| m_textureFilteringMode = TextureFilterClass::TextureFilterMode::TEXTURE_FILTER_BILINEAR; | ||
| m_textureAnisotropyLevel = TextureFilterClass::AnisotropicFilterMode::TEXTURE_FILTER_ANISOTROPIC_2X; |
There was a problem hiding this comment.
Do these need to be in GlobalData or is there a better place for them?
There was a problem hiding this comment.
There's not really a nice place to centralise them apart from global data, Texture Class is mostly handled by static functions and MSAA is handled inside dx8wrapper through ww3d.
| return load("Options.ini"); | ||
| } | ||
|
|
||
| UnsignedInt OptionPreferences::getAntiAliasing() |
There was a problem hiding this comment.
Should this return the enum type instead?
There was a problem hiding this comment.
I was avoiding adding ww3d and texturefilter headers to the globaldata header
There was a problem hiding this comment.
If you move the enums out of TextureFilterClass then you can forward declare them.
| mode = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_4X; | ||
| break; | ||
| case OptionPreferences::AliasingMode::X8: | ||
| mode = WW3D::MultiSampleModeEnum::MULTISAMPLE_MODE_8X; |
There was a problem hiding this comment.
This can also be simplified by using bit shift
mode = (index > 0) ? 1 << index : 0;| prefString = "Trilinear"; | ||
| break; | ||
| case TextureFilterClass::TextureFilterMode::TEXTURE_FILTER_ANISOTROPIC: | ||
| prefString = "Anisotropic"; |
There was a problem hiding this comment.
I suggest provide an enum to string array or function near the enum declaration instead so that the string mapping could be reused elsewhere too and is closer to the enum declaration, which reduces maintenance mistakes.
Merge By Rebase
Closes: #2474
Closes: #2375
This PR implements options for allowing the enablement of MSAA and the selection of different texture filtering modes and setting the anisotropic filtering level.
The following options are added for anti aliasing
AntiAliasing = 0, 2, 4, 8
The numbers relate to the MSAA sample level and Zero disables MSAA.
TextureFilter = None, Point, Bilinear, Trilinear, Anisotropic
Self explanatory, just choose one and see how the game looks
AnisotropyLevel = 2, 4, 8, 16
The anisotropy level only comes into play when Anisotropic filtering is set. 2 is also the minimum value.
Generals is broken untill the changes are replicated due to changes in texture filter init.