-
Notifications
You must be signed in to change notification settings - Fork 31
INI Language Extensions
XXMI DLL script language additions (on top of 3dmigoto base version).
For Bitwise & Bitshift operators precedence is the same as in C++.
-
NOT
~ -
AND
& -
XOR
^ -
OR
|
-
Left Shift
<< -
Right Shift
>>
In particular, it enables the efficient way to handle flags, which allow to store up to 24 distinct 1 or 0 states in a single INI variable:
; ID of current flag (from 0 to23)
local $flag_id = 0
; Flags storage
local $flags = 0
; Bitwise mask for the calculations below
local $flag = 1 << $flag_id
; Check if $flag_id has `0` state in $flags
if (($flags & $flag) == 0)
; Store `1` state for $flag_id in $flags
$flags = $flags | $flag
endif
; Check if $flag_id has `1` state in $flags
if (($flags & $flag) != 0)
; Store `0` state for $flag_id in $flags
$flags = $flags & ~$flag
endifOperator @ returns a resource identity value.
- Can be used with any "ResourceCopyTarget" entity (e.g.
@ResourceCustom,@vs-t0, etc.). - Returns
0if resource does not exist (akanullptr).
Resource Identity
$resource_id_custom = @ResourceFoo
$resource_id_d3d11 = @vs-t0Pool Resource Identity
When used with a pool resource, the operator returns the identity of the resolved pool entry.
$pool_resource_id_static = @PoolFoo[0]
$pool_resource_id_dynamic = @PoolFoo[$index]See Resource Pools → Identity Operator (@) for details.
Produces a 24-bit integer value derived from the underlying resource pointer and safely representable in float32.
Operator # provides additional metadata for pools.
Pool Resource Index
$fifo_pool_resource_index_static = #PoolFooFIFO[123.456]
$fifo_pool_resource_index_dynamic = #PoolFooFIFO[$resource_uid]Pool Size
$pool_size = #PoolFooSee Resource Pools → Index Operator (@) for details.
- Size - Returns resource size in bytes.
$size = ResourceFoo->Size- Stride - Returns resource stride in bytes.
$stride = ResourceFoo->Stride-
SourceStride - Returns stride of resource that was copied into ResourceFoo. Slots are not supported (e.g.
vb0).
[ResourceBar]
type = Buffer
stride = 42
filename = Bar.buf
[PoolFoo]
pool_size = 2
type = Buffer
format = R32_FLOAT
PoolFoo[0] = copy ResourceBar
$bar_stride = PoolFoo[0]->SourceStride ; 42
$foo_stride = PoolFoo[0]->Stride ; 4Using
->on custom resources (e.gResourceFoo->Size) is almost CPU cost free (~1ns), while slots (e.g.vb0->Size) perform slightly slower (~10-100ns).
Getters return specific values when data retrieval fails:
UNKNOWN = -1.0f; // All data sources returned `0` (getters are looking for mutiple semantically similar properties)
RESOURCE_NOT_FOUND = -2.0f; // No buffer is found for target
NOT_A_BUFFER = -3.0f; // Target is not a D3D11_RESOURCE_DIMENSION_BUFFERA Resource Pool is a collection of resources that share the same configuration and can be accessed through an index or UID.
Pools are declared using a dedicated [Pool] section and behave similarly to regular [Resource] sections, while allowing indexed access to multiple resource instances.
[PoolFoo]
pool_size = 4A pool supports all standard [Resource] parameters:
[PoolFoo]
pool_size = 4
type = Buffer
format = R32_FLOAT
stride = 4When a pool is parsed:
- A hidden template custom resource is created internally.
- The template stores all resource parameters and optional initial data.
- Individual pool resources are instantiated from this template on demand.
For example:
[PoolFoo]
pool_size = 4
type = Buffer
data = "Hello World!"Every resource created within the pool inherits the template configuration and initial data.
Pool resources can be accessed using either static or dynamic indexing and used anywhere a custom resource is accepted.
The pool resource is resolved during INI parsing.
PoolFoo[0] = ref ResourceTextStatically accessed resources are being instantiated at parsing time (data structs, not D3D buffer COM objects).
The pool resource is resolved at runtime.
local $index = 0
PoolFoo[$index] = ref ResourceTextDynamically accessed resources are being instantiated at runtime. That's where D3D buffer instantiation also happens.
Unused pool entries consume no custom resource allocations.
Pools support two indexing strategies, Ring and FIFO.
Ring indexing treats the pool as a circular array.
[PoolFoo]
pool_size = 4
pool_index_type = ringSince this is the default mode, the following is equivalent:
[PoolFoo]
pool_size = 4Negative indices wrap from the end of the pool.
PoolFoo[-1]returns the last resource.
For a pool of size 4:
| Expression | Pool Index |
|---|---|
PoolFoo[-1] |
3 |
PoolFoo[-2] |
2 |
PoolFoo[-3] |
1 |
PoolFoo[-4] |
0 |
Indices automatically wrap around the pool size.
For a pool of size 4:
| Expression | Pool Index |
|---|---|
PoolFoo[0] |
0 |
PoolFoo[1] |
1 |
PoolFoo[2] |
2 |
PoolFoo[3] |
3 |
PoolFoo[4] |
0 |
PoolFoo[5] |
1 |
PoolFoo[8] |
0 |
This allows continuous cyclic access without manual modulo operations.
For example, we want to keep results of shapekeys calculations for certain object from last 2 frames, and our game processes them all in single batch. Assuming shapekeys compute shader hash is 0123456789absdef and cs-u0 hash for our object is 12345678, we can do the following:
[Constants]
global $frame = 0
[PoolHistory]
pool_size = 2
max_copies_per_frame = 1
[Present]
$frame = $frame + 1
[ShaderOverrideShapeKeyCS]
hash = 0123456789absdef
allow_duplicate_hash = true
CheckTextureOverride = cs-u0
[TextureOverrideCSU0]
hash = 12345678
post PoolHistory[$frame] = copy cs-u0Resource copies will land like this:
Frame 0 -> PoolHistory[0]
Frame 1 -> PoolHistory[1]
Frame 2 -> PoolHistory[0]
Frame 3 -> PoolHistory[1]
and PoolHistory[0] and PoolHistory[1] will become available to use as inputs for some custom Compute Shader. For example, to calculate movement vectors of each vertex.
Unlike Ring mode, the value inside brackets is treated as a user-defined key (UID), rather than a direct pool index.
[PoolFooFIFO]
pool_index_type = fifo
pool_size = 4Any floating point value or INI variable can be used as a UID:
PoolFooFIFO[123]
PoolFooFIFO[-987.654]
PoolFooFIFO[$object_id]The same UID always resolves to the same pool resource until its assignment slot is recycled.
When a UID is encountered:
- If the UID already exists, its previously assigned slot is returned.
- If the UID is new, the next available slot is assigned.
- When the pool is full, the oldest assignment is replaced.
Initial accesses:
PoolFooFIFO[10]
PoolFooFIFO[20]
PoolFooFIFO[30]
PoolFooFIFO[40]produce:
| UID | Pool Index |
|---|---|
10 |
0 |
20 |
1 |
30 |
2 |
40 |
3 |
Subsequent lookups return the same assignments:
PoolFooFIFO[10] ; index 0
PoolFooFIFO[20] ; index 1Adding another UID:
PoolFooFIFO[50]overwrites the oldest slot assignment:
| UID | Pool Index |
|---|---|
20 |
1 |
30 |
2 |
40 |
3 |
50 |
0 |
UID 10 is no longer mapped.
Pools extend both the @ and # operators.
Returns the compacted identity of a resource.
$resource_id = @PoolFoo[0]Dynamic form:
$resource_id = @PoolFoo[$index]The returned value uniquely identifies the underlying resource buffer and can be compared with other identities.
Example:
if @PoolFoo[0] == @PoolFoo[1]
; Do something
endifThis condition is true when both resources reference the same buffer.
The meaning depends on the operand.
For Ring pools:
#PoolFoo[7]returns the normalized pool index.
For a pool size of 4:
#PoolFoo[7] ; returns 3For FIFO pools:
#PoolFooFIFO[123.456]returns the slot currently assigned to the specified UID.
Dynamic form:
#PoolFooFIFO[$uid]This is useful when a script needs to determine which actual pool resource was selected by FIFO assignment.
When applied directly to the pool:
#PoolFooreturns the configured pool capacity.
local $size = #PoolFooEquivalent to:
local $size = 4for:
[PoolFoo]
pool_size = 4[PoolFoo]
pool_size = 2
[ResourceText]
type = Buffer
data = "Text"
[Present]
PoolFoo[0] = ref ResourceText
local $src = 0
local $dst = 1
PoolFoo[$dst] = ref PoolFoo[$src]
local $pool_size = #PoolFoo
local $resource_text_id = @ResourceText
local $pool_resource_0_id = @PoolFoo[0]
local $pool_resource_1_id = @PoolFoo[1]
local $same_buffer = $resource_text_id == $pool_resource_0_id && $pool_resource_0_id == $pool_resource_1_id
; The more direct way also works:
local $same_buffer = @ResourceText == @PoolFoo[0] && @PoolFoo[0] == @PoolFoo[1]After execution, ResourceText, PoolFoo[0], and PoolFoo[1] all reference the same underlying resource buffer, causing all identity comparisons above to evaluate as true.