GUI and HLSL compiler extensions:
Most of the new GUI customization is done through HLSL-style annotations. This is handled by a custom parser that reads all of the newly added syntax. Example:
float MyParameter <
string UIName     = "My Param";        // > Name that's shown in the UI
string UIGroup    = "My Group";        // > Group(s) that the parameter should be put into
float  UIMin      = -10.0;             // > Minimum allowed value
float  UIMax      =  10.0;             // > Maximum allowed value
string Separation = "ExteriorWeather"; // > Enable exterior-only weather separation
> = 0.0;                                   // > Default value



List of native ENB variable annotations

UIName:
Type: string
Sets the name of a parameter in the UI. This is also used as the unique identifier for parameter binding, saving to configs and when interfacing with other mods that use the ENB API (if UniqueName or UIGroups aren't specified).


UIMin and UIMax:
Type: same as variable
Sets the upper and lower limit in the UI.


UIWidget:
Type: string
Changes the used widget type, meaning how the variable is presented in the UI.

Spinner:
Default. Used when no widget is specified and available for all scalar and vector types (except bool).

Vector (float3 only):
Normalized vector representation of a float3 variable

Color (float3 and float4 only):
Normalized color representation. Can switch between RGB and HSL modes and optionally includes and alpha channel when used on a float4 variable.

Dropdown (int only):
Represents integer values as a dropdown menu. Use in combination with UIList.

Quality (int only):
A pre-defined dropdown menu for quality selection. Ranges from Very High (-1) to Very Low (3).


UIList:
Type: string
Used in combination with the Dropdown UIWidget. A comma separated list that is used as textual representation for integers. Example:
int MyDropdown <
string UIName   = "My Dropdown Menu";
string UIWidget = "Dropdown";
string UIList   = "Default,First,Second";
> = 0;
Gives you a dropdown menu with the name My Dropdown Menu. Values are represented like this: 0 = Default, 1 = First, 2 = Second


UIHidden:
Type: int
Set this to 1 to hide a variable from the UI. This is usually only needed when interfacing with mods that use the ENB API (like other .dllplugins).
It is NOT RECOMMENDED to use this with the Extender! Use UIVisible instead!



List of Extender variable annotations

Separation:
Type: string
Only available for floating point types (float, float2, float3 and float4).
Separates variable according to the weather system in your ENB preset. Otherwise uses the normal fallback values (the ones that are found in the FX shaders window and the .fx.ini files.

None:
Default behaviour. No separation. Uses fallback values all the time.

ExteriorWeather:
Uses per-weather values in exteriors and fallback values for undefined weathers and interiors. Equivalent to disabling IgnoreWeatherSystem and enabling IgnoreWeatherSystemInterior.

Weather:
Uses per-weather values whenever possible. Fallback values are only used for undefined weathers. Equivalent to disabling IgnoreWeatherSystem and IgnoreWeatherSystemInterior.


UIGroup:
Type: string
Assigns a parameter to one or multiple (sub) groups. To specify multiple sub-groups at once use dots to separate them. Example:
float MyParameter <
    string UIName  = "My Param";
    string UIGroup = "My Group.My Subgroup.My 2nd Subgroup";
> = 0.0;
Puts My Param into UI groups like this: My Group > My Subgroup > My 2nd Subgroup.


UIGroupName:
Type: string
Needs to be part of the first definition of a UIGroup!
Changes the display name of a group without affecting the unique identifier of underlying variables. These still use UIGroup.


UIGroupOpen:
Type: bool
Needs to be part of the first definition of a UIGroup!
Changes the default open state of a group when loading up the UI for the first time in a session.


UITopLevel:
Type: bool
Set this to true to move a parameter out of its default FX file based group. Can be added to the first definition of a UIGroup to move the entire group into the top level.


UIOrdering:
Type: int
Allows free re-ordering of parameters in the UI. Higher values will be added earlier than lower ones, regardless of where they appear in a shader. All parameters are considered to have an order value of 0 (except for Technique dropdown menus, these have a value of 1). If two parameters have the same ordering, they will be added according to the default file order and when they appear in each file.
Can be added to the first definition of a UIGroup to give the entire group a specific order value.


UIVisible:
Type: bool
Set to false to hide a parameter from the UI. Usually used in combination with either parameter binding to hide variables in real-time or to interface with other ENB API based mods.


UIReadOnly:
Type: bool
Set to true to make the parameter not editable through the UI. It will just show the grayed out value. Can also be combined with parameter binding or ENB API based mods.


UniqueName:
Type: string
Replaces the unique identifier of a parameter with a custom one. Normally this is a combination of all UIGroups (dot separated) plus the UIName.
This is mostly relevant if you plan on using parameter binding or other mods that use the ENB API.
Can also be used in the rare case when your unique identifiers exceed the maximum length that ENB can handle.


UIIgnorePerfMode:
Type: bool
Set to true to display a parameter even when performance mode is enabled.



Improved string handling with the Extender
In addition to the unique annotations that only strings can use, most of the normal variable annotation are also available (within reason - you can't put a min/max on a string for example).
Strings without any annotation are also now displayed in the correct order, so are actually usable to provide meaningful information to users.


UIGroupBegin and UIGroupEnd:
Type: bool
Instead of embeding groups into the annotation of each variable, you can also use groups scopes. Enter a scope with UIGroupBegin and leave it with UIGroupEnd. All variables inside of a scope are automatically added to the corresponding group. Group scopes can host sub-group scopes as well if you want to create a hierarchy.
The UIGroup will use the string value as its name. This can also be used as the first definition of UIGroup for things like ordering, top level, etc.


UISeparator:
Type: bool
Turns the string into a separator


UIWeatherString and UIWeatherOnlyString:
Type: bool
Adds the string to the FX weather window (or only to the FX weather window)


FXGroups
Instead of using techniques directly with trailing indices, the extender adds something called fxgroups.
This is usually implemented through the effect framework directly but because the Extender is operating at a lower level, this isn't possible. The Extender instead rolls its own implementation of fxgroups, reusing the reserved keyword for its purposes.

Example:
// New fxgroup based declaration
fxgroup MyEffect <string UIName = "My Effect"; /* other annotations for the entire group */> {
technique11 <string RenderTarget = "RenderTargetRGBA64";> {
pass {
SetVertexShader(CompileShader(vs_5_0, MyVS1()));
SetPixelShader( CompileShader(vs_5_0, MyPS1()));
}
}
technique11 {
pass {
SetVertexShader(CompileShader(vs_5_0, MyVS2()));
SetPixelShader( CompileShader(vs_5_0, MyPS2()));
}
}
}

// Is equivalent to this
technique11 MyEffect <
    string UIName       = "My Effect";
    string RenderTarget = "RenderTargetRGBA64";
    /* other annotations for the entire group */> {
pass {
SetVertexShader(CompileShader(vs_5_0, MyVS1()));
SetPixelShader( CompileShader(vs_5_0, MyPS1()));
}
}
technique11 MyEffect1 {
pass {
SetVertexShader(CompileShader(vs_5_0, MyVS2()));
SetPixelShader( CompileShader(vs_5_0, MyPS2()));
}
}




List of native ENB technique annotations

UIName:
Type: string
Sets the name of the technique in the UI. Needs to be part of a fxgroup or the first technique in a group.

RenderTarget:
Type: string
Sets the output rendertarget to the one with the given name. Can be added to any technique.



List of Extender technique annotations

UIDefault:
Type: bool
Declares a technique group as the default one if no other one has been slected by the user. Needs to be part of ONE fxgroup or the first technique in ONE group.


UIDropdownName:
Type: string
Sets the name of the technique dropdown menu in the UI. Uses Technique if not specified. Needs to be part of the FIRST fxgroup or technique in a file.


UIDropdownVisible:
Type: bool
Hides or shows the technique dropdown menu. Combine with UIDefault to always have a technique selected without needing a UI widget. Needs to be part of the FIRST fxgroup or technique in a file.


UIDropdownTopLevel:
Type: bool
Set this to true to move the technique dropdown menu out of its default FX file based group. Needs to be part of the FIRST fxgroup or technique in a file.


UIDropdownOrdering:
Type: int
Changes ordering of the technique dropdown menu. See UIOrdering above for details. Needs to be part of the FIRST fxgroup or technique in a file.


UIDropdownGroup:
Type: string
Assigns the technique dropdown menu to one or multiple (sub) groups. See UIGroup for details. Needs to be part of the FIRST fxgroup or technique in a file.


UIDropdownGroupName:
Type: string
Changes the display name of the technique dropdown menu group without affecting the unique identifier. That one still use UIDropdownGroup.


UIDropdownGroupOpen:
Type: bool
Changes the default open state of the technique dropdown menu group when loading up the UI for the first time in a session.



Extern Bindings
The Extender can provide additional data from supported games to external shaders (current only available for Skyrim SE). To do that, declare a variable and add the corresponding annotation to it.

Example:
float4 WVPMatColumn0 <string ExternBinding = "WVPMatColumn0";>;

Inverted camera rotation matrix
Type: float3
Name: InvCamRotMatColumn[0-2]

World-View-Projection matrix
Type: float4
Name: WVPMatColumn[0-3]

Inverted World-View-Projection matrix
Type: float4
Name: InvWVPMatColumn[0-3]



Parameter Binding
The Extender let's you bind parameters or their properties to other parameters, allowing them react to one another in real-time. This is handled through annotations again, like most other features.
To reference a parameter you need to use its unique name, not just the name that's shown in the UI. That one is either specified outright (UniqueName) or is a combination of the UIName and all UIGroups it's a part of.
A variable with the name "My Var" that's in the group hierarchy "My Group > My SubGroup" for example, will be addressable with the unique name "My Group.My SubGroup.My Var".


UIBinding:
Type: string
The unique name of the parameter you want to bind to.


UIBindingFile:
Type: string
Which file the parameter belongs to. This is only needed if you want to address parameters from other files. Otherwise this can be omitted.


UIBindingProperty:
Type: string
Specifies the property that should be affected by the bound to parameter. This is only needed if you want property binding.

readonly:
Makes parameter read-only if the bound to parameter is non-zero or the condition is met. Otherwise it remains writeable.

readwrite:
Allows writing to the parameter as long as the bound to parameter is non-zero or the condition is met. Otherwise it remains read-only.

hidden:
Hides the parameter if the bound to parameter is non-zero or the condition is met. Otherwise it remains visible.

visible:
Shows the parameter as long as the bound to parameter is non-zero or the condition is met. Otherwise it remains hidden.


UIBindingCondition:
Type: string
Specify a condition that has to be met in order to toggle the bound property. Accepts an expression string in the form of a comparison operation and a comparand.
Operations: ==, !=, <, >, =<, =>
Comparands: Scalar types (float, int and bool)

Example:
int MyInt <string UIName = "My Integer"; int UIMin = 0; UIMax = 2;> = 0;

float MyHiddenFloat <
string UIBinding          = "My Integer";
string UIBindingProperty  = "visible";
string UIBindingCondition = "==2";
> = 0.0;
This will only show the "My Hidden Float" variable if the "My Integer" parameter is exactly 2.



Compile time UI parameters
Instead of only supporting runtime variables in the UI, the Extender adds a way to add compile time ones as well. This is done by allowing preprocessor defines to be added to the UI and to be saved/loaded to/from .fx.ini files.

Example:
#pragma uidefine(int MY_INT_DEFINE <     \
    string UIName = "My Integer Define"; \
    int    UIMin  = 0;                   \
    int    UIMax  = 2;                   \
> = 0)

This is equivalent of writing
#define MY_INT_DEFINE X
with X being replaced by the value found in the .fx.ini file (or the default value if none can be found)

Note that the uidefine pragma is evaluated prior to the preprocessor in a completely separate scope. Meaning you don't have access to other defines or globals in here. Group scopes are currently not fully supported either, so it's required to use in-line grouping if needed.

Article information

Added on

Edited on

Written by

KitsuuneNivis

0 comments