.
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Simple yet powerful GUI framework for XXMI
6 |
7 |
8 | Features •
9 | Installation •
10 | How To Use As Mod User •
11 | How To Use As Mod Author •
12 | Resources •
13 | License
14 |
15 |
16 |
17 |
18 |
19 | ## Features
20 | - **INI Native** — Designed as .ini with bunch of HLSL shaders, no .dll required
21 | - **Fully Dynamic** — All Tile properties can be changed on the fly
22 | - **Expandible** — Create your own CustomShaders to directly modify data arrays
23 | - **Highly Optimized** — Aims to minimize performance footprint
24 | - **Robust** — Stateless architecture isolates clients from each other
25 |
26 |
27 | ## Installation
28 |
29 | 1. Download the [latest release](https://github.com/SpectrumQT/TileGUI/releases/latest) of **TileGUI_vX.X.X.zip**
30 | 2. Extract **TileGUI_vX.X.X.zip** to `\Mods\` folder
31 |
32 | Correct path to extracted TileGUI folder should look like:
33 |
34 | ```
35 | \Mods\TileGUI
36 | ```
37 |
38 | ## How To Use As Mod User
39 |
40 | Just install it if you have any mods requiring TileGUI. Framework won't do anything on its own.
41 |
42 |
43 | ## How To Use As Mod Author
44 |
45 | Framework is currently in the early alpha-testing phase with no docs ready. Also, while current API is unlikely to change significantly, there's absolutely no guarantee that it'll be compatible with first modder-friendly release. I'd advice to wait for further announcements before jump into.
46 |
47 |
48 | ## Showcase Mods
49 |
50 | - [Camellya x Acheron (TileGUI 0.8.0)](https://gamebanana.com/mods/594216)
51 | - [Eula in Skirk's outfit (TileGUI 0.7.0)](https://gamebanana.com/mods/478260)
52 | - [Raiden in Acheron's outfit (TileGUI 0.7.0)](https://gamebanana.com/mods/495878)
53 |
54 | ## License
55 | TileGUI is licensed under the [GPLv3 License](https://github.com/SpectrumQT/TileGUI/blob/main/LICENSE).
56 |
--------------------------------------------------------------------------------
/TileGUI/Modules/Textures/virtual_cursor.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpectrumQT/TileGUI/5d6beebcfdfa6925a2577a45dbb48f32ed6fd246/TileGUI/Modules/Textures/virtual_cursor.dds
--------------------------------------------------------------------------------
/TileGUI/Modules/VirtualCursor.ini:
--------------------------------------------------------------------------------
1 | ; ----------------------------------------------------------------
2 | ; !!! WARNING !!! Do NOT use this .ini as template for your GUI code!
3 | ; ----------------------------------------------------------------
4 | ; This module is used to draw fake mouse cursor for universal keyboard and gamepad support
5 | ; Requires to be called the last to overlay other GUIs, so it uses a bit different render approach
6 |
7 | namespace=TileGUI_VirtualCursor
8 |
9 |
10 | [CommandListDrawVirtualCursor]
11 | if $\TileGUI\virtual_cursor_x != -1 || $\TileGUI\virtual_cursor_y != -1
12 | $gui_active = 1
13 | run = CommandListOnFrameDrawGUI
14 | endif
15 |
16 |
17 | [Constants]
18 | ; Variables: TileGUI Instance Core
19 | global $api_status = -1
20 | global $gui_initialized = 0
21 | global $gui_active = 0
22 | global $gui_scale = 1.0
23 | ; Constants: TileGUI Tile Ids
24 | global $TILE_VIRTUAL_CURSOR = 0
25 |
26 |
27 | ; TileGUI Resources -------------------------
28 |
29 | [ResourceTextureVirtualCursor]
30 | filename = Textures\virtual_cursor.dds
31 |
32 | [ResourceTextureVirtualCursorOverride]
33 |
34 |
35 | ; TileGUI Tiles -------------------------
36 |
37 | [CommandListRegisterTiles]
38 | $\TileGUI\target_tile_id = $TILE_VIRTUAL_CURSOR
39 | $\TileGUI\width = 32 * $gui_scale
40 | $\TileGUI\height = 32 * $gui_scale
41 | $\TileGUI\texture_id = 64
42 | run = CommandList\TileGUI\SetTile
43 |
44 |
45 | ; TileGUI Controller -------------------------
46 |
47 | [CommandListOnGuiFrame]
48 | if ResourceTextureVirtualCursorOverride !== null
49 | ps-t64 = ResourceTextureVirtualCursorOverride
50 | else
51 | ps-t64 = ResourceTextureVirtualCursor
52 | endif
53 |
54 | local $offset_x
55 | local $offset_y
56 |
57 | local $new_offset_x = $\TileGUI\virtual_cursor_x + 16
58 | local $new_offset_y = $\TileGUI\virtual_cursor_y - 16
59 |
60 | if $new_offset_x != $offset_x || $new_offset_y != $offset_y
61 | $offset_x = $new_offset_x
62 | $offset_y = $new_offset_y
63 |
64 | $\TileGUI\target_tile_id = $TILE_VIRTUAL_CURSOR
65 | $\TileGUI\offset_x = $new_offset_x
66 | $\TileGUI\offset_y = $new_offset_y
67 | run = CommandList\TileGUI\SetTile
68 | endif
69 |
70 |
71 | ; TileGUI Instance Configuration -------------------------
72 |
73 | ; === START: TILEGUI INSTANCE CONFIGURATION === === === === === === === === === === === === === === === === ===
74 | ; Here you can adjust this instance to fit your needs
75 | ; Please don't set those values any higer than you actually need, don't load GPU with useless work
76 | ; =================================================================================================
77 | [CommandListSetConfiguration]
78 | ; Configure minimal required TileGUI version
79 | ; User with older TileGUI version will get Error Message displayed and to ensure user safety GUI won't run
80 | $\TileGUI\required_version = 0.80
81 | ; Configure the number of tiles to process (allowed values: 128, 256, 512, 1024)
82 | ; Pick the lowest acceptable value from the allowed ones (i.e. for 17 tile GUI pick 128)
83 | ; WARNING! For this setting to have effect, you should also resize [ResourceTilesData]:
84 | ; For example, for $max_tiles_count = 256, find 'array = 128' in [ResourceTilesData] below and replace with 'array = 256'
85 | $\TileGUI\max_tiles_count = 128
86 | ; Configure the number of GUI layers to process (allowed values: 1 ... 32)
87 | ; For most cases 1 layer is enough because within one layer tiles with higher TileID are always rendered on top of ones with lower
88 | $\TileGUI\max_layers_count = 1
89 | ; Configure the max length of parent chain checked by per-frame tile positions updates (allowed values: 0 ... 8)
90 | ; Set it to 0 if you're not going to use draggable windows in your GUI, otherwise make sure to not go above 8
91 | $\TileGUI\max_parent_recursion = 0
92 | ; Configure how much screen scale should affect tile sizes
93 | ; Default factor of 0.25 makes tiles 25% bigger for each 100% of scale above base 100%
94 | ; For 4k displays Windows returns 300% scale, so factor of 0.25 will make tiles 50% bigger
95 | $\TileGUI\scaling_factor = 0.25
96 | ; === END: TILEGUI INSTANCE CONFIGURATION === === === === === === === === === === === === === === === === === ===
97 |
98 |
99 | ; === START: TILEGUI INSTANCE RESOURCES === === === === === === === === === === === === === === === === === === ===
100 |
101 | ; Stores tiles
102 | ; Allowed array length values: 128, 256, 512, 1024 (default: array = 128)
103 | [ResourceTilesData]
104 | type = RWStructuredBuffer
105 | array = 128
106 | data = R32_FLOAT 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
107 |
108 | ; Stores templates
109 | ; Allowed array length values: 64, 128, 256, 512, 1024 (default: array = 64)
110 | [ResourceTemplatesData]
111 | type = RWStructuredBuffer
112 | array = 64
113 | data = R32_FLOAT 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
114 |
115 | ; === END: TILEGUI INSTANCE RESOURCES === === === === === === === === === === === === === === === === === === === ===
116 |
117 |
118 | ; TileGUI Instance Core -------------------------
119 |
120 | ; WARNING! TILEGUI INSTANCE CORE CODE IS LISTED BELOW, DO NOT EDIT IF YOU'RE NOT SURE WHAT YOU'RE DOING!!!
121 |
122 | [ResourceInstance]
123 | type = RWStructuredBuffer
124 | array = 1
125 | data = R32_FLOAT 0 0 0 0 0 0 0 0 0 0 0 0
126 |
127 | ; Error message displayed to user when CommandListOnFrameDrawGUI code is FUBAR
128 | [ResourceErrorCoreIsFUBAR]
129 | type = Buffer
130 | data = "Error! Virtual Cursor Core is FUBAR"
131 |
132 | ; Error message displayed to user when TileGUI is not installed
133 | [ResourceErrorNotInstalledTileGUI]
134 | type = Buffer
135 | data = "Error! Virtual Cursor requires TileGUI to function! Please install TileGUI from https://gamebanana.com/mods/505941"
136 |
137 | ; Error message displayed to user when TileGUI version is below than minimally required
138 | [ResourceErrorWrongVersionTileGUI]
139 | type = Buffer
140 | data = "Error! Virtual Cursor requires newer TileGUI version to function! Please update TileGUI from https://gamebanana.com/mods/505941"
141 |
142 | ; Error mesage display parameters
143 | [ResourceErrorMessageFormat]
144 | type = StructuredBuffer
145 | array = 1
146 | data = R32_FLOAT -0.25 -0.85 +0.25 -0.90 1.00 1.00 0.00 1.00 0.00 0.00 0.00 0.95 0.02 0.05 2 3 1 1.0
147 | ; x1-^ y1-^ x2-^ y2-^ | R-^ G-^ B-^ A-^ | R-^ G-^ B-^ A-^ | ^-H V-^ | ^ ^ | ^- text alignment: 0=left 1=center 2=right | ^- font scale
148 | ; Rectangle (range -1:+1) | Text Color | Background Color | Border | ^- h/v-anchor: 0=none 1=left/top 2=center 3=right/bottom
149 |
150 | [CommandListOnFrameDrawGUI]
151 | post $gui_active = 0
152 |
153 | if $gui_active == 1
154 |
155 | if $gui_initialized == 0
156 | ; Pass our instance data to the library
157 | run = CommandListConnectLibrary
158 | ; Initialize API status as 'FUBAR'
159 | $api_status = -1
160 | ; Declare local variables so we can compare potentially non-existing $\TileGUI\ values
161 | local $api_version = -1
162 | local $api_required_version = -1
163 | ; If TileGUI is installed, this value is set by CommandListSetConfiguration via CommandListConnectLibrary
164 | ; If TileGUI is missing, it defaults to -1
165 | $api_required_version = $\TileGUI\required_version
166 | ; Detect actual API status
167 | if $api_required_version != -1
168 | ; Get version of currently installed TileGUI
169 | run = CommandList\TileGUI\GetVersion
170 | $api_version = $\TileGUI\return_version
171 |
172 | if $api_version >= $api_required_version
173 | ; Change API status to 'OK'
174 | $api_status = 200
175 | else
176 | ; Change API status to 'Upgrade Required'
177 | $api_status = 426
178 | endif
179 | else
180 | ; Change API status to 'Not Found'
181 | $api_status = 404
182 | endif
183 | ; Initialize GUI if API status is 'OK'
184 | if $api_status == 200
185 | ; Initialize instance data
186 | run = CommandListInitializeDataStorage
187 | endif
188 | ; Remember that we're initialized so we don't have to do it again
189 | $gui_initialized = 1
190 | endif
191 |
192 | if $api_status == 200
193 | ; Pass our instance data to the library
194 | run = CommandListConnectLibrary
195 | ; Execute user per-frame GUI logic
196 | run = CommandListOnGuiFrame
197 | ; Draw GUI to back buffer to show on next frame if there are layers to draw
198 | run = CommandListDrawGUI
199 | ; Detach our instance data from the library
200 | run = CommandListDisconnectLibrary
201 | else
202 | if $api_status == 404
203 | ; Display TileGUI Not Installed Error Message
204 | Resource\ShaderFixes\help.ini\Help = ref ResourceErrorNotInstalledTileGUI
205 | else if $api_status == 426
206 | ; Display TileGUI Wrong Version Error Message
207 | Resource\ShaderFixes\help.ini\Help = ref ResourceErrorWrongVersionTileGUI
208 | else
209 | ; Display Core Is FUBAR Error Message
210 | Resource\ShaderFixes\help.ini\Help = ref ResourceErrorCoreIsFUBAR
211 | endif
212 | Resource\ShaderFixes\help.ini\Params = ref ResourceErrorMessageFormat
213 | run = CustomShader\ShaderFixes\help.ini\FormatText
214 | endif
215 | else if $api_status != 200
216 | ; Clean Up Error Message
217 | if $gui_initialized == 1
218 | $gui_initialized = 0
219 | Resource\ShaderFixes\help.ini\Help = null
220 | Resource\ShaderFixes\help.ini\Params = null
221 | endif
222 | endif
223 |
224 |
225 | [CommandListConnectLibrary]
226 | ; Clear any leftover data
227 | run = CommandList\TileGUI\ResetTempVars
228 | ; Pass configuration variables
229 | run = CommandListSetConfiguration
230 | ; Pass our data storage to the library
231 | Resource\TileGUI\ClientInstanceData = reference ResourceInstance
232 | Resource\TileGUI\ClientTilesData = reference ResourceTilesData
233 | Resource\TileGUI\ClientTemplatesData = reference ResourceTemplatesData
234 |
235 |
236 | [CommandListInitializeDataStorage]
237 | ; Load our instance configuration to the data storage
238 | run = CommandList\TileGUI\SetInstance
239 | ; Load our tiles to the data storage
240 | run = CommandListRegisterTiles
241 |
242 |
243 | [CommandListDrawGUI]
244 | ; Run compute shader to process "shader-accelerated" features like hover-overlays, loops and dragging
245 | run = CustomShader\TileGUI\TileFeaturesService
246 | ; Run compute shader to update tile positions
247 | run = CustomShader\TileGUI\TilePositionService
248 | ; Run GUI shaders
249 | run = CustomShader\TileGUI\TileDrawService
250 |
251 |
252 | [CommandListDisconnectLibrary]
253 | Resource\TileGUI\ClientInstanceData = null
254 | Resource\TileGUI\ClientTilesData = null
255 | Resource\TileGUI\ClientTemplatesData = null
256 | ResourceTextureVirtualCursorOverride = null
257 |
258 |
259 | ; EOF -------------------------
260 |
--------------------------------------------------------------------------------
/TileGUI/Shaders/instance_writer.hlsl:
--------------------------------------------------------------------------------
1 | // Updates client's instance storage with given ini variables
2 |
3 | Texture1D IniParams : register(t120);
4 |
5 | // #define WindowWidth IniParams[0].x
6 | // #define WindowHeight IniParams[0].y
7 | #define CursorX IniParams[0].z
8 | #define CursorY IniParams[0].w
9 |
10 | #define MaxTilesCount IniParams[10].x
11 | #define MaxLayersCount IniParams[10].y
12 |
13 | #define DragTileId IniParams[15].x
14 |
15 | struct Instance {
16 | float max_tiles_count;
17 | float max_layers_count;
18 | float2 unused1;
19 |
20 | float drag_tile_id;
21 | float2 drag_pos;
22 | float1 unused2;
23 |
24 | float4 unused3;
25 | };
26 |
27 | RWStructuredBuffer InstanceContainerRW : register(u0);
28 | #define CurrentInstance InstanceContainerRW[0]
29 |
30 | //RWBuffer DebugRW : register(u7);
31 |
32 |
33 | void UpdateInstanceFromIni(inout Instance instance_data)
34 | {
35 | if (MaxTilesCount != 100000) {
36 | instance_data.max_tiles_count = MaxTilesCount;
37 | }
38 | if (MaxLayersCount != 100000) {
39 | instance_data.max_layers_count = MaxLayersCount;
40 | }
41 | if (DragTileId != 100000) {
42 | instance_data.drag_tile_id = DragTileId;
43 | instance_data.drag_pos = float2(0, 0);
44 | } else {
45 | instance_data.drag_tile_id = -1;
46 | }
47 | }
48 |
49 |
50 | // #ifdef COMPUTE_SHADER
51 |
52 | [numthreads(1,1,1)]
53 | void main(uint3 ThreadId : SV_DispatchThreadID)
54 | {
55 | UpdateInstanceFromIni(CurrentInstance);
56 |
57 | InstanceContainerRW[0] = CurrentInstance;
58 |
59 | // DebugRW[0] = float4(0, 0, 0, 0);
60 | }
61 |
62 | // #endif
63 |
64 |
--------------------------------------------------------------------------------
/TileGUI/Shaders/tile_draw_service.hlsl:
--------------------------------------------------------------------------------
1 | // Draws all tiles on screen
2 |
3 | struct vs2gs {
4 | uint vertex_id : TEXCOORD0;
5 | };
6 |
7 | struct gs2ps {
8 | float4 pos : SV_Position0;
9 | float2 uv : TEXCOORD1;
10 | float texture_index : PSIZE0;
11 | float tex_arr_id : PSIZE1;
12 | };
13 |
14 |
15 | #ifdef VERTEX_SHADER
16 | void main(uint vertex_id : SV_VertexID, out vs2gs output)
17 | {
18 | output.vertex_id = vertex_id;
19 | }
20 | #endif
21 |
22 |
23 | #ifdef GEOMETRY_SHADER
24 |
25 | struct Instance {
26 | float max_tiles_count;
27 | float max_layers_count;
28 | float2 unused1;
29 |
30 | float drag_tile_id;
31 | float2 drag_pos;
32 | float1 unused2;
33 |
34 | float4 unused3;
35 | };
36 |
37 | StructuredBuffer InstanceContainer : register(t121);
38 | #define CurrentInstance InstanceContainer[0]
39 |
40 | struct Tile {
41 | // Base config
42 | float sys_state_id;
43 | float layer_id;
44 | float parent_tile_id;
45 | float template_id;
46 | // Features config
47 | float show;
48 | float select;
49 | float clamp;
50 | float track_mouse;
51 | // Advanced features config
52 | float loop_start;
53 | float loop_method;
54 | float hover_overlay_tile_id;
55 | float select_overlay_tile_id;
56 | // Display config
57 | float2 size;
58 | float texture_id;
59 | float tex_arr_id;
60 | // Texture config
61 | float4 tex_uv;
62 | // Texture config 2
63 | float opacity;
64 | float saturation;
65 | float2 reserved_1;
66 | // Layout config
67 | float2 offset;
68 | float2 anchor;
69 | // Current state
70 | float loop_stage;
71 | float is_hovered_over;
72 | float2 reserved_2;
73 | // Absolute coords of current position
74 | float4 abs_pos;
75 | // Relative coords of current position
76 | float4 rel_pos;
77 | };
78 |
79 | StructuredBuffer Tiles : register(t122);
80 |
81 | // Here we devide MaxTilesCount (128, 256, 512 or 1024) by the number of geometry shader instances (32)
82 | #define OutputTilesPerInstance (CurrentInstance.max_tiles_count / 32)
83 |
84 | // Packs unsigned float with max integer part of 999 into another unsigned integer
85 | float Pack(uint integer_var, float float_var)
86 | {
87 | return integer_var * 1000 + abs(float_var) % 1000;
88 | }
89 |
90 | // Our aim is to draw the whole GUI layer of 1024 tiles per vertex on input
91 | // Each tile consists of 4 vertices (2 triangles)
92 | // Each geometry shader invocation will output up to 128 vertices (32 tiles)
93 | // So we'll use 32 instances, making total of 32 * 32 = 1024 tiles
94 | [instance(32)]
95 | // Our gs2ps has size of 8, and maxvertexcount * sizeof(gs2ps) cannot exceed 1024, thus 1024 / 8 = 128
96 | // Note: While UV and tex ids could be packed to unused pos floats, marginal performance gain doesn't worth the precision loss
97 | [maxvertexcount(128)]
98 | void main(uint instance_id : SV_GSInstanceID, point vs2gs input[1], inout TriangleStream triangle_stream)
99 | {
100 | int layer_id = input[0].vertex_id;
101 |
102 | gs2ps output;
103 |
104 | for (int i = 0; i < OutputTilesPerInstance; i++) {
105 | int tile_id = instance_id * OutputTilesPerInstance + i;
106 |
107 | Tile tile = Tiles[tile_id];
108 |
109 | if (tile.sys_state_id == 0 || tile.show != 1 || tile.texture_id == -1) {
110 | continue;
111 | }
112 |
113 | if (tile.layer_id != layer_id) {
114 | continue;
115 | }
116 |
117 | output.texture_index = Pack(tile.texture_id - 64, tile.opacity); // Pack opacity as floating point value
118 | output.tex_arr_id = Pack(tile.tex_arr_id, tile.saturation); // Pack saturation as floating point value
119 |
120 | output.pos = float4(tile.rel_pos.x, tile.rel_pos.w, 1, 1); // X, Y, Z coord and View Space Depth
121 | output.uv = float2(tile.tex_uv.x, tile.tex_uv.y); // X, Y
122 | triangle_stream.Append(output);
123 |
124 | output.pos = float4(tile.rel_pos.x, tile.rel_pos.y, 1, 1); // X, Y, Z coord and View Space Depth
125 | output.uv = float2(tile.tex_uv.x, tile.tex_uv.w); // X, Y
126 | triangle_stream.Append(output);
127 |
128 | output.pos = float4(tile.rel_pos.z, tile.rel_pos.w, 1, 1); // X, Y, Z coord and View Space Depth
129 | output.uv = float2(tile.tex_uv.z, tile.tex_uv.y); // X, Y
130 | triangle_stream.Append(output);
131 |
132 | output.pos = float4(tile.rel_pos.z, tile.rel_pos.y, 1, 1); // X, Y, Z coord and View Space Depth
133 | output.uv = float2(tile.tex_uv.z, tile.tex_uv.w); // X, Y
134 | triangle_stream.Append(output);
135 |
136 | triangle_stream.RestartStrip();
137 | }
138 | }
139 |
140 | #endif
141 |
142 |
143 | #ifdef PIXEL_SHADER
144 |
145 | Texture2DArray ImageTextures[64] : register(t64);
146 |
147 | SamplerState LinearSampler : register(s0);
148 |
149 | float4 Saturate(float4 color, float saturation)
150 | {
151 | float3 luminance_weights = float3(0.299, 0.587, 0.114);
152 | float luminance = dot(color.rgb, luminance_weights);
153 | return float4(lerp(luminance, color.rgb, saturation), color.a);
154 | }
155 |
156 | void main(gs2ps input, out float4 result : SV_Target0)
157 | {
158 | result.xyzw = 0;
159 | uint texture_index = uint(input.texture_index / 1000);
160 |
161 | [unroll]
162 | for (uint i = 0; i < 64; i++) {
163 | if (texture_index == i) {
164 | // Unpack opacity and saturation
165 | uint tex_arr_id = uint(input.tex_arr_id / 1000);
166 | float opacity = input.texture_index % 1000;
167 | float saturation = input.tex_arr_id % 1000;
168 |
169 | // Get pixel float4 RGBA color from texture
170 | result = ImageTextures[i].Sample(LinearSampler, float3(input.uv, tex_arr_id));
171 |
172 | // Blend opacity setting
173 | if (opacity != 1) {
174 | result.a *= opacity;
175 | }
176 | // Blend saturation setting
177 | if (saturation != 1) {
178 | result = Saturate(result, saturation);
179 | }
180 |
181 | return;
182 | }
183 | }
184 | }
185 |
186 | #endif
187 |
--------------------------------------------------------------------------------
/TileGUI/Shaders/tile_features_service.hlsl:
--------------------------------------------------------------------------------
1 | // Handles special (re)actions for all tiles, like hover over, overlays, dragging and so on
2 | // Simplifies and accelerates common GUI logic that would require tons of STORE calls otherwise
3 |
4 | Texture1D IniParams : register(t120);
5 |
6 | #define WindowWidth IniParams[0].x
7 | #define WindowHeight IniParams[0].y
8 | #define CursorX IniParams[0].z
9 | #define CursorY IniParams[0].w
10 |
11 | #define RootParentCoords float4(0, 0, IniParams[0].x, IniParams[0].y)
12 |
13 | struct Instance {
14 | float max_tiles_count;
15 | float max_layers_count;
16 | float2 unused1;
17 |
18 | float drag_tile_id;
19 | float2 drag_pos;
20 | float1 unused2;
21 |
22 | float4 unused3;
23 | };
24 |
25 | RWStructuredBuffer InstanceContainerRW : register(u0);
26 | #define Instance InstanceContainerRW[0]
27 |
28 | struct Tile {
29 | // Base config
30 | float sys_state_id;
31 | float layer_id;
32 | float parent_tile_id;
33 | float template_id;
34 | // Features config
35 | float show;
36 | float select;
37 | float clamp;
38 | float track_mouse;
39 | // Advanced features config
40 | float loop_start;
41 | float loop_method;
42 | float hover_overlay_tile_id;
43 | float select_overlay_tile_id;
44 | // Display config
45 | float2 size;
46 | float texture_id;
47 | float tex_arr_id;
48 | // Texture config
49 | float4 tex_uv;
50 | // Texture config 2
51 | float opacity;
52 | float saturation;
53 | float2 reserved_1;
54 | // Layout config
55 | float2 offset;
56 | float2 anchor;
57 | // Current state
58 | float loop_stage;
59 | float is_hovered_over;
60 | float2 reserved_2;
61 | // Absolute coords of current position
62 | float4 abs_pos;
63 | // Relative coords of current position
64 | float4 rel_pos;
65 | };
66 |
67 | RWStructuredBuffer TilesRW : register(u1);
68 | //RWBuffer DebugRW : register(u7);
69 |
70 | void HandleDrag(int tile_id, inout Tile tile)
71 | {
72 | if (Instance.drag_tile_id != tile_id) {
73 | return;
74 | }
75 | float cursor_abs_x = abs(CursorX + 1) / 2 * WindowWidth;
76 | float cursor_abs_y = abs(CursorY + 1) / 2 * WindowHeight;
77 |
78 | if (Instance.drag_pos.x == 0) {
79 | Instance.drag_pos.x = cursor_abs_x;
80 | }
81 | if (Instance.drag_pos.y == 0) {
82 | Instance.drag_pos.y = cursor_abs_y;
83 | }
84 |
85 | float drag_abs_x = cursor_abs_x - Instance.drag_pos.x;
86 | float drag_abs_y = cursor_abs_y - Instance.drag_pos.y;
87 |
88 | // Tile tile = TilesRW[Instance.drag_tile_id];
89 |
90 | // Ignore cursor movement outside of parent's range (conventional slider behavior)
91 | // Requires more checks to be less wanky, so lets comment it for now
92 | // float4 parent_coords = (tile.parent_tile_id == -1 ? RootParentCoords : TilesRW[tile.parent_tile_id].abs_pos);
93 | // float parent_right_edge = parent_coords.z;
94 | // float parent_left_edge = parent_coords.x;
95 | // if (cursor_abs_x > parent_right_edge || cursor_abs_x < parent_left_edge) {
96 | // drag_abs_x = 0;
97 | // }
98 | // float parent_top_edge = parent_coords.w;
99 | // float parent_bot_edge = parent_coords.y;
100 | // if (cursor_abs_y > parent_top_edge || cursor_abs_y < parent_bot_edge) {
101 | // drag_abs_y = 0;
102 | // }
103 |
104 | if (drag_abs_x != 0 || drag_abs_y != 0) {
105 | Instance.drag_pos.x = cursor_abs_x;
106 | Instance.drag_pos.y = cursor_abs_y;
107 |
108 | tile.offset.x += drag_abs_x;
109 | tile.offset.y += drag_abs_y;
110 | }
111 |
112 | // DebugRW[Instance.drag_tile_id] = float4(drag_abs_x, CursorX, drag_abs_y, CursorY);
113 | }
114 |
115 | void AddOverlay(int target_tile_id, int overlay_tile_id)
116 | {
117 | Tile overlay_tile = TilesRW[overlay_tile_id];
118 | overlay_tile.parent_tile_id = target_tile_id;
119 | overlay_tile.show = 1;
120 | TilesRW[overlay_tile_id] = overlay_tile;
121 | }
122 |
123 | void RemoveOverlay(int target_tile_id, int overlay_tile_id)
124 | {
125 | Tile overlay_tile = TilesRW[overlay_tile_id];
126 | if (overlay_tile.parent_tile_id != target_tile_id) {
127 | return;
128 | }
129 | overlay_tile.parent_tile_id = -1;
130 | overlay_tile.show = 0;
131 | TilesRW[overlay_tile_id] = overlay_tile;
132 | }
133 |
134 | void HandleHoverOver(int tile_id, inout Tile tile)
135 | {
136 | if (tile.show == 0) {
137 | return;
138 | }
139 | if (CursorX > tile.rel_pos.x && CursorY > tile.rel_pos.y && CursorX < tile.rel_pos.z && CursorY < tile.rel_pos.w) {
140 | if (tile.is_hovered_over == 1) {
141 | return;
142 | }
143 | if (tile.hover_overlay_tile_id != -1) {
144 | AddOverlay(tile_id, tile.hover_overlay_tile_id);
145 | }
146 | tile.is_hovered_over = 1;
147 | } else {
148 | if (tile.is_hovered_over == 0) {
149 | return;
150 | }
151 | if (tile.hover_overlay_tile_id != -1) {
152 | RemoveOverlay(tile_id, tile.hover_overlay_tile_id);
153 | }
154 | tile.is_hovered_over = 0;
155 | };
156 | }
157 |
158 | void HandleSelect(int tile_id, inout Tile tile)
159 | {
160 | if (tile.show == 0) {
161 | return;
162 | }
163 | if (tile.select_overlay_tile_id == -1) {
164 | return;
165 | }
166 | if (tile.select == 1) {
167 | AddOverlay(tile_id, tile.select_overlay_tile_id);
168 | } else {
169 | RemoveOverlay(tile_id, tile.select_overlay_tile_id);
170 | }
171 | }
172 |
173 | void HandleLoopStage(int tile_id, inout Tile tile)
174 | {
175 | if (tile.loop_method < 1) {
176 | return;
177 | }
178 | if (tile.loop_method == 1) {
179 | // Loop via tex_arr_id
180 | tile.tex_arr_id = tile.loop_start + tile.loop_stage;
181 | } else if (tile.loop_method == 2) {
182 | // Set current UV coords as loop start
183 | if (tile.loop_start == -1) {
184 | tile.loop_start = tile.tex_uv.x;
185 | }
186 | // Loop via UV
187 | float uv_width = tile.tex_uv.z - tile.tex_uv.x;
188 | tile.tex_uv.x = tile.loop_start + uv_width * tile.loop_stage;
189 | tile.tex_uv.z = tile.tex_uv.x + uv_width;
190 | }
191 | }
192 |
193 | // #ifdef COMPUTE_SHADER
194 |
195 | [numthreads(64,1,1)]
196 | void main(uint3 ThreadId : SV_DispatchThreadID)
197 | {
198 | int tile_id = ThreadId.x;
199 | Tile tile = TilesRW[tile_id];
200 |
201 | if (tile.sys_state_id != 1) {
202 | return;
203 | }
204 |
205 | if (tile.track_mouse == 1) {
206 | HandleDrag(tile_id, tile);
207 | HandleHoverOver(tile_id, tile);
208 | };
209 |
210 | HandleSelect(tile_id, tile);
211 | HandleLoopStage(tile_id, tile);
212 |
213 | TilesRW[tile_id] = tile;
214 | }
215 |
216 | // #endif
217 |
218 |
--------------------------------------------------------------------------------
/TileGUI/Shaders/tile_group_writer.hlsl:
--------------------------------------------------------------------------------
1 | // Streamlines multiple tiles declaration and property updates both for initialization and runtime
2 |
3 | Texture1D IniParams : register(t120);
4 |
5 | #define RequestType (IniParams[0].x != 100000 ? IniParams[0].x : -1)
6 | #define TemplateId (IniParams[0].y != 100000 ? IniParams[0].y : -1)
7 | #define ParentTileId (IniParams[0].z != 100000 ? IniParams[0].z : -1000)
8 |
9 | #define FirstTileId (IniParams[1].x != 100000 ? IniParams[1].x : -1)
10 | #define LastTileId (IniParams[1].y != 100000 ? IniParams[1].y : FirstTileId)
11 |
12 | #define CreateTiles (IniParams[2].x != 100000 ? IniParams[2].x : 0)
13 | #define SkipExistingTiles (IniParams[2].y != 100000 ? IniParams[2].y : 0)
14 |
15 | #define ColsCount (IniParams[3].x != 100000 ? IniParams[3].x : -1)
16 | #define RowsCount (IniParams[3].y != 100000 ? IniParams[3].y : -1)
17 | #define ColsPadding (IniParams[3].z != 100000 ? IniParams[3].z : 0)
18 | #define RowsPadding (IniParams[3].w != 100000 ? IniParams[3].w : 0)
19 |
20 | #define AnchorX (IniParams[4].x != 100000 ? IniParams[4].x : 0)
21 | #define AnchorY (IniParams[4].y != 100000 ? IniParams[4].y : 0)
22 |
23 | struct Tile {
24 | // Base config
25 | float sys_state_id;
26 | float layer_id;
27 | float parent_tile_id;
28 | float template_id;
29 | // Features config
30 | float show;
31 | float select;
32 | float clamp;
33 | float track_mouse;
34 | // Advanced features config
35 | float loop_start;
36 | float loop_method;
37 | float hover_overlay_tile_id;
38 | float select_overlay_tile_id;
39 | // Display config
40 | float2 size;
41 | float texture_id;
42 | float tex_arr_id;
43 | // Texture config
44 | float4 tex_uv;
45 | // Texture config 2
46 | float opacity;
47 | float saturation;
48 | float2 reserved_1;
49 | // Layout config
50 | float2 offset;
51 | float2 anchor;
52 | // Current state
53 | float loop_stage;
54 | float is_hovered_over;
55 | float2 reserved_2;
56 | // Absolute coords of current position
57 | float4 abs_pos;
58 | // Relative coords of current position
59 | float4 rel_pos;
60 | };
61 |
62 | RWStructuredBuffer TileTemplateDataRW : register(u0);
63 | RWStructuredBuffer TilesRW : register(u1);
64 | //RWBuffer DebugRW : register(u7);
65 |
66 | void InitializeTile(inout Tile tile)
67 | {
68 | // Base config
69 | tile.sys_state_id = 1;
70 | tile.layer_id = 0;
71 | tile.parent_tile_id = -1;
72 | tile.template_id = -1;
73 | // Features config
74 | tile.show = 1;
75 | tile.select = 0;
76 | tile.clamp = 1;
77 | tile.track_mouse = 1;
78 | // Advanced features config
79 | tile.loop_start = -1;
80 | tile.loop_method = -1;
81 | tile.hover_overlay_tile_id = -1;
82 | tile.select_overlay_tile_id = -1;
83 | // Display config
84 | tile.size = 0;
85 | tile.texture_id = -1;
86 | tile.tex_arr_id = 0;
87 | // Texture config
88 | tile.tex_uv = float4(0, 0, 1, 1);
89 | // Texture config 2
90 | tile.opacity = 1;
91 | tile.saturation = 1;
92 | tile.reserved_1 = 0;
93 | // Layout config
94 | tile.offset = 0;
95 | tile.anchor = 0;
96 | // Current state
97 | tile.loop_stage = 0;
98 | tile.is_hovered_over = 0;
99 | tile.reserved_2 = 0;
100 | // Absolute coords of current position
101 | tile.abs_pos = 0;
102 | // Relative coords of current position
103 | tile.rel_pos = 0;
104 | }
105 |
106 | void LoadDataUpdate(Tile tile_data, inout Tile tile)
107 | {
108 | // Base config
109 | if (tile_data.sys_state_id != 100000) {
110 | tile.sys_state_id = tile_data.sys_state_id;
111 | }
112 | if (tile_data.layer_id != 100000) {
113 | tile.layer_id = tile_data.layer_id;
114 | }
115 | if (tile_data.parent_tile_id != 100000) {
116 | tile.parent_tile_id = tile_data.parent_tile_id;
117 | }
118 | if (tile_data.template_id != 100000) {
119 | tile.template_id = tile_data.template_id;
120 | }
121 | // Features config
122 | if (tile_data.show != 100000) {
123 | tile.show = tile_data.show;
124 | }
125 | if (tile_data.select != 100000) {
126 | tile.select = tile_data.select;
127 | }
128 | if (tile_data.clamp != 100000) {
129 | tile.clamp = tile_data.clamp;
130 | }
131 | if (tile_data.track_mouse != 100000) {
132 | tile.track_mouse = tile_data.track_mouse;
133 | }
134 | // Advanced features config
135 | if (tile_data.loop_start != 100000) {
136 | tile.loop_start = tile_data.loop_start;
137 | }
138 | if (tile_data.loop_method != 100000) {
139 | tile.loop_method = tile_data.loop_method;
140 | }
141 | if (tile_data.hover_overlay_tile_id != 100000) {
142 | tile.hover_overlay_tile_id = tile_data.hover_overlay_tile_id;
143 | }
144 | if (tile_data.select_overlay_tile_id != 100000) {
145 | tile.select_overlay_tile_id = tile_data.select_overlay_tile_id;
146 | }
147 | // Display config
148 | if (tile_data.size.x != 100000) {
149 | tile.size.x = tile_data.size.x;
150 | }
151 | if (tile_data.size.y != 100000) {
152 | tile.size.y = tile_data.size.y;
153 | }
154 | if (tile_data.texture_id != 100000) {
155 | tile.texture_id = tile_data.texture_id;
156 | }
157 | if (tile_data.tex_arr_id != 100000) {
158 | tile.tex_arr_id = tile_data.tex_arr_id;
159 | }
160 | // Texture config
161 | if (tile_data.tex_uv.x != 100000) {
162 | tile.tex_uv.x = tile_data.tex_uv.x;
163 | }
164 | if (tile_data.tex_uv.y != 100000) {
165 | tile.tex_uv.y = tile_data.tex_uv.y;
166 | }
167 | if (tile_data.tex_uv.z != 100000) {
168 | tile.tex_uv.z = tile_data.tex_uv.z;
169 | }
170 | if (tile_data.tex_uv.w != 100000) {
171 | tile.tex_uv.w = tile_data.tex_uv.w;
172 | }
173 | // Texture config 2
174 | if (tile_data.opacity != 100000) {
175 | tile.opacity = tile_data.opacity;
176 | }
177 | if (tile_data.saturation != 100000) {
178 | tile.saturation = tile_data.saturation;
179 | }
180 | // Layout config
181 | if (tile_data.offset.x != 100000) {
182 | tile.offset.x = tile_data.offset.x;
183 | }
184 | if (tile_data.offset.y != 100000) {
185 | tile.offset.y = tile_data.offset.y;
186 | }
187 | if (tile_data.anchor.x != 100000) {
188 | tile.anchor.x = tile_data.anchor.x;
189 | }
190 | if (tile_data.anchor.y != 100000) {
191 | tile.anchor.y = tile_data.anchor.y;
192 | }
193 | // Current state
194 | if (tile_data.loop_stage != 100000) {
195 | tile.loop_stage = tile_data.loop_stage;
196 | }
197 | // if (tile_data.is_hovered_over != 100000) {
198 | // tile.is_hovered_over = tile_data.is_hovered_over;
199 | // }
200 | // tile_data.not_used_2 = 0;
201 | }
202 |
203 | void ApplyTemplate(int tile_id)
204 | {
205 | // Skip tile if template isn't specified
206 | if (TemplateId == -1) {
207 | return;
208 | }
209 |
210 | Tile tile = TilesRW[tile_id];
211 |
212 | // Check if tile doesn't have requested template
213 | if (tile.template_id != TemplateId) {
214 | // Check if parent isn't specified or if tile doesn't have requested parent
215 | if ((ParentTileId == -1000) || (tile.parent_tile_id != ParentTileId)) {
216 | // Check if tile isn't in requested range
217 | if (FirstTileId > tile_id || tile_id > LastTileId) {
218 | // Skip tile if all checks passed
219 | return;
220 | }
221 | }
222 | }
223 |
224 | // Get requested template
225 | Tile tile_template = TileTemplateDataRW[TemplateId];
226 | // Skip non-existing template
227 | if (tile_template.sys_state_id == 0) {
228 | return;
229 | }
230 |
231 | if (tile.sys_state_id != 1) {
232 | // Handle non-existing tile
233 | if (CreateTiles == 1) {
234 | // Create new tile if requested
235 | InitializeTile(tile);
236 | } else {
237 | // Skip non-existing tile
238 | return;
239 | }
240 | } else {
241 | // Skip existing tile if requested
242 | if (SkipExistingTiles == 1) {
243 | return;
244 | }
245 | }
246 |
247 | LoadDataUpdate(tile_template, tile);
248 | TilesRW[tile_id] = tile;
249 | }
250 |
251 | void ApplyLayout(int tile_id)
252 | {
253 | // Skip if layout is not specified
254 | if (ColsCount < 1 || RowsCount < 1) {
255 | return;
256 | }
257 | // Skip out-of-requested-range tile
258 | if (FirstTileId > tile_id || tile_id > LastTileId) {
259 | return;
260 | }
261 |
262 | Tile tile = TilesRW[tile_id];
263 |
264 | // Skip non-existing tile
265 | if (tile.sys_state_id != 1) {
266 | return;
267 | }
268 |
269 | uint total_tiles = LastTileId - FirstTileId + 1;
270 | uint tile_number = tile_id - LastTileId + total_tiles - 1;
271 | uint tile_row = tile_number / uint(ColsCount);
272 | uint tile_col = tile_number % uint(ColsCount);
273 |
274 | tile.offset.x += (tile.size.x + ColsPadding) * tile_col;
275 | tile.offset.y += (tile.size.y + RowsPadding) * tile_row;
276 |
277 | tile.anchor.x = AnchorX;
278 | tile.anchor.y = AnchorY;
279 |
280 | // Quick, dirty but efficient approach to anchor entire layout
281 | // Relies heavily on current position_service implementation and trusts it blindly, leaving the rest of the work to it
282 | if (AnchorX == 0) {
283 | tile.offset.x -= ((tile.size.x + ColsPadding) * ColsCount - ColsPadding) / 2 - tile.size.x / 2;
284 | } else if (abs(AnchorX == 2)) {
285 | tile.offset.x -= ((tile.size.x + ColsPadding) * (ColsCount - 1));
286 | }
287 | if (AnchorY == 0) {
288 | tile.offset.y -= ((tile.size.y + RowsPadding) * RowsCount - RowsPadding) / 2 - tile.size.y / 2;
289 | } else if (abs(AnchorY == 2)) {
290 | tile.offset.y -= ((tile.size.y + RowsPadding) * (RowsCount - 1));
291 | }
292 |
293 | // DebugRW[tile_id] = float4(tile_col, tile_row, tile.offset.x, tile.offset.y);
294 | // DebugRW[tile_id] = float4(AnchorX, AnchorY, tile.offset.x, tile.offset.y);
295 |
296 | TilesRW[tile_id] = tile;
297 | }
298 |
299 | // #ifdef COMPUTE_SHADER
300 |
301 | [numthreads(64,1,1)]
302 | void main(uint3 ThreadId : SV_DispatchThreadID)
303 | {
304 | int tile_id = ThreadId.x;
305 |
306 | if (RequestType == 1) {
307 | ApplyTemplate(tile_id);
308 | } else if (RequestType == 2) {
309 | ApplyLayout(tile_id);
310 | }
311 | }
312 |
313 | // #endif
314 |
--------------------------------------------------------------------------------
/TileGUI/Shaders/tile_position_service.hlsl:
--------------------------------------------------------------------------------
1 | // Updates positions of all tiles based on sizes, offsets, anchors and parents
2 |
3 | Texture1D IniParams : register(t120);
4 |
5 | #define WindowWidth IniParams[0].x
6 | #define WindowHeight IniParams[0].y
7 |
8 | #define MaxParentRecursion (IniParams[1].x <= 8 ? IniParams[1].x : 0)
9 |
10 | #define RootParentCoords float4(0, 0, IniParams[0].x, IniParams[0].y)
11 |
12 | struct Tile {
13 | // Base config
14 | float sys_state_id;
15 | float layer_id;
16 | float parent_tile_id;
17 | float template_id;
18 | // Features config
19 | float show;
20 | float select;
21 | float clamp;
22 | float track_mouse;
23 | // Advanced features config
24 | float loop_start;
25 | float loop_method;
26 | float hover_overlay_tile_id;
27 | float select_overlay_tile_id;
28 | // Display config
29 | float2 size;
30 | float texture_id;
31 | float tex_arr_id;
32 | // Texture config
33 | float4 tex_uv;
34 | // Texture config 2
35 | float opacity;
36 | float saturation;
37 | float2 reserved_1;
38 | // Layout config
39 | float2 offset;
40 | float2 anchor;
41 | // Current state
42 | float loop_stage;
43 | float is_hovered_over;
44 | float2 reserved_2;
45 | // Absolute coords of current position
46 | float4 abs_pos;
47 | // Relative coords of current position
48 | float4 rel_pos;
49 | };
50 |
51 | RWStructuredBuffer TilesRW : register(u1);
52 | //RWBuffer DebugRW : register(u7);
53 |
54 | float2 GetAnchoredAxisCoords(float anchor, float child_size, float2 parent_coords) {
55 | float2 axis_coords;
56 | if (anchor == 1) {
57 | // Min Inside (align child's Min edge to Min edge of the parent)
58 | // [[ C ]P ] ----axis---->
59 | axis_coords.x = parent_coords.x;
60 | axis_coords.y = axis_coords.x + child_size;
61 | } else if (anchor == 2) {
62 | // Max Inside (align child's Max edge to Max edge of the parent)
63 | // [ P[ C ]] ----axis---->
64 | axis_coords.y = parent_coords.y;
65 | axis_coords.x = axis_coords.y - child_size;
66 | } else if (anchor == -1) {
67 | // Min Outside (align child's Max edge to Min edge of the parent)
68 | // [ C ][ P ] ----axis---->
69 | axis_coords.y = parent_coords.x;
70 | axis_coords.x = axis_coords.y - child_size;
71 | } else if (anchor == -2) {
72 | // Max Outside (align child's Min edge to Max edge of the parent)
73 | // [ P ][ C ] ----axis---->
74 | axis_coords.x = parent_coords.y;
75 | axis_coords.y = axis_coords.x + child_size;
76 | } else {
77 | // Center (align child's Center to Center of the parent)
78 | // [ P [ C ] P ] ----axis---->
79 | float parent_width = parent_coords.y - parent_coords.x;
80 | float parent_anchor_x = parent_coords.y - parent_width / 2;
81 | axis_coords.x = parent_anchor_x - child_size / 2;
82 | axis_coords.y = parent_anchor_x + child_size / 2;
83 | }
84 | return axis_coords;
85 | }
86 |
87 | float4 GetAnchoredAbsolutePosition(float2 anchor, float2 child_size, float4 parent_coords) {
88 | // Absolute screen space coords:
89 | // x1 (Left) = 0
90 | // y1 (Bottom) = 0
91 | // x2 (Right) = window_max_x - 1
92 | // y2 (Top) = window_max_y - 1
93 |
94 | // Image position is described by two points:
95 | // 1. Bottom-Left aka (x1, y1), where x1 is absolute_coords.x and y1 is absolute_coords.y
96 | // 1. Top-Right aka (x2, y2), where x2 is absolute_coords.z and y2 is absolute_coords.w
97 | // Calculate x1 and x2 coords based on anchor point
98 | float2 absolute_coords_x = GetAnchoredAxisCoords(anchor.x, child_size.x, parent_coords.xz);
99 | // Calculate y1 and y2 coords based on anchor point
100 | float2 absolute_coords_y = GetAnchoredAxisCoords(anchor.y, child_size.y, parent_coords.yw);
101 |
102 | return float4(absolute_coords_x.x, absolute_coords_y.x, absolute_coords_x.y, absolute_coords_y.y);
103 | }
104 |
105 | float GetClampedAxisOffset(float offset, float child_size, float2 parent_coords, float2 child_coords) {
106 | // Keeps tile a1 and a2 coords within the parent's axis range
107 | float parent_size = parent_coords.y - parent_coords.x;
108 | if (child_size <= parent_size) {
109 | float excess_min = child_coords.x + offset - parent_coords.x;
110 | if (excess_min < 0) {
111 | offset -= excess_min;
112 | }
113 | float excess_max = child_coords.y + offset - parent_coords.y;
114 | if (excess_max > 0) {
115 | offset -= excess_max;
116 | }
117 | } else if (parent_size != 0) {
118 | offset = 0;
119 | }
120 | return offset;
121 | }
122 |
123 | float2 GetClampedOffset(float2 offset, float2 anchor, float2 child_size, float4 parent_coords, float4 child_coords) {
124 | if (anchor.x >= 0 && anchor.y >= 0) {
125 | offset.x = GetClampedAxisOffset(offset.x, child_size.x, parent_coords.xz, child_coords.xz);
126 | offset.y = GetClampedAxisOffset(offset.y, child_size.y, parent_coords.yw, child_coords.yw);
127 | }
128 | return offset;
129 | }
130 |
131 | Tile UpdateAbsolutePosition(Tile tile, float4 parent_coords)
132 | {
133 | float4 absolute_coords = GetAnchoredAbsolutePosition(tile.anchor, tile.size, parent_coords);
134 |
135 | if (tile.clamp == 1) {
136 | tile.offset = GetClampedOffset(tile.offset, tile.anchor, tile.size, parent_coords, absolute_coords);
137 | }
138 |
139 | absolute_coords.xz += tile.offset.x;
140 | absolute_coords.yw += tile.offset.y;
141 |
142 | tile.abs_pos = absolute_coords;
143 |
144 | return tile;
145 | }
146 |
147 | //
148 | // Supports recursive
149 | float4 GetParentAbsolutePosition(Tile tile)
150 | {
151 | int parent_tile_id = tile.parent_tile_id;
152 |
153 | if (parent_tile_id == -1) {
154 | // Return app window absolute coords if parent chain is empty
155 | return RootParentCoords;
156 | } else if (MaxParentRecursion == 0) {
157 | // Return parent tile absolute coords without updating them
158 | return TilesRW[parent_tile_id].abs_pos;
159 | } else {
160 | // Recursively calculate up-to-date position of up to 8 parents in the chain
161 | // Makes child tiles to move after parent without lagging but puts a bit more stress on GPU
162 | Tile parent_tiles[8];
163 | // Index chain of parents
164 | for (int i = 0; i < MaxParentRecursion; i++) {
165 | // Cache current parent
166 | parent_tiles[i] = TilesRW[parent_tile_id];
167 | // Remember id of the next parent
168 | parent_tile_id = parent_tiles[i].parent_tile_id;
169 | // Stop if no more parents in the chain
170 | if (parent_tile_id == -1) {
171 | break;
172 | }
173 | }
174 | // Calculate absolute coords of last parent in the chain
175 | Tile updated_parent_tile = UpdateAbsolutePosition(parent_tiles[i], RootParentCoords);
176 | // Calculate absolute coords of previous parents in reversed order
177 | for (int r = i - 1; r >= 0; r--) {
178 | updated_parent_tile = UpdateAbsolutePosition(parent_tiles[r], updated_parent_tile.abs_pos);
179 | }
180 | // Return absolute coords of first parent in the chain
181 | return updated_parent_tile.abs_pos;
182 | }
183 | }
184 |
185 | void UpdateRelativePosition(inout Tile tile)
186 | {
187 | if (tile.abs_pos.x == 0 && tile.abs_pos.z == 0) {
188 | return;
189 | }
190 |
191 | // Relative screen space coords:
192 | // x1 (Left) = -1.0
193 | // y1 (Bottom) = -1.0
194 | // x2 (Right) = 1
195 | // y2 (Top) = 1
196 | // Screen center point coords (x, y) are (0.0, 0.0)
197 |
198 | // Relative position is relative to the center of the screen
199 | // For example we'll use common 1920x1080 screen:
200 | // window_max_x=1920
201 | // window_max_y=1080
202 |
203 | // 1. At first, we need to calculate absolute coords for central point of the screen
204 | // Current coordinate range: x = [1, 1920] and y = [1, 1080]
205 | float center_x = WindowWidth / 2; // 1920 / 2 = 960
206 | float center_y = WindowHeight / 2; // 1080 / 2 = 540
207 |
208 | // 2. Then we need to make said central point a new reference point of the absolute coordinate system
209 | // New coordinate range: x = [-960,960] and y = [-540,540]
210 | // 3. Finally, we need to transform coordinate range from absolute to relative
211 | // New coordinate range: x = [-1,1] and y = [-1,1]
212 |
213 | // Both 2. and 3. steps can be done by simply deducting central point coords and then dividing by the same value
214 | tile.rel_pos.xz = (tile.abs_pos.xz - center_x) / center_x;
215 | tile.rel_pos.yw = (tile.abs_pos.yw - center_y) / center_y;
216 | }
217 |
218 |
219 | // #ifdef COMPUTE_SHADER
220 |
221 | // Runs 1 thread per tile, 64 threads per group, and expects up to 16 thread groups
222 | // Processes up to 1 * 64 * 16 = 1024 tiles total per dispatch
223 | [numthreads(64,1,1)]
224 | void main(uint3 ThreadId : SV_DispatchThreadID)
225 | {
226 | int tile_id = ThreadId.x;
227 | Tile tile = TilesRW[tile_id];
228 |
229 | if (tile.sys_state_id == 0 || tile.show != 1) {
230 | return;
231 | }
232 |
233 | tile = UpdateAbsolutePosition(tile, GetParentAbsolutePosition(tile));
234 |
235 | UpdateRelativePosition(tile);
236 |
237 | TilesRW[tile_id] = tile;
238 | }
239 |
240 | // #endif
241 |
242 |
--------------------------------------------------------------------------------
/TileGUI/Shaders/tile_reader.hlsl:
--------------------------------------------------------------------------------
1 |
2 | Texture1D IniParams : register(t120);
3 |
4 | #define RequestType IniParams[1].x
5 | #define TileId IniParams[1].y
6 | #define VarId IniParams[1].z
7 |
8 | struct Instance {
9 | float max_tiles_count;
10 | float max_layers_count;
11 | float2 unused1;
12 |
13 | float drag_tile_id;
14 | float2 drag_pos;
15 | float1 unused2;
16 |
17 | float4 unused3;
18 | };
19 |
20 | StructuredBuffer InstanceContainer : register(t121);
21 | #define Instance InstanceContainer[0]
22 |
23 | struct Tile {
24 | // Base config
25 | float sys_state_id;
26 | float layer_id;
27 | float parent_tile_id;
28 | float template_id;
29 | // Features config
30 | float show;
31 | float select;
32 | float clamp;
33 | float track_mouse;
34 | // Advanced features config
35 | float loop_start;
36 | float loop_method;
37 | float hover_overlay_tile_id;
38 | float select_overlay_tile_id;
39 | // Display config
40 | float2 size;
41 | float texture_id;
42 | float tex_arr_id;
43 | // Texture config
44 | float4 tex_uv;
45 | // Texture config 2
46 | float opacity;
47 | float saturation;
48 | float2 reserved_1;
49 | // Layout config
50 | float2 offset;
51 | float2 anchor;
52 | // Current state
53 | float loop_stage;
54 | float is_hovered_over;
55 | float2 reserved_2;
56 | // Absolute coords of current position
57 | float4 abs_pos;
58 | // Relative coords of current position
59 | float4 rel_pos;
60 | };
61 |
62 | StructuredBuffer Tiles : register(t122);
63 | RWBuffer OutputRW : register(u0);
64 | //RWBuffer DebugRW : register(u7);
65 |
66 | float GetTileVar()
67 | {
68 | if (TileId == 100000) {
69 | return 100000;
70 | }
71 | Tile tile = Tiles[TileId];
72 | if (VarId == 0) {
73 | return tile.sys_state_id;
74 | } else if (VarId == 1) {
75 | return tile.layer_id;
76 | } else if (VarId == 2) {
77 | return tile.parent_tile_id;
78 | } else if (VarId == 3) {
79 | return tile.template_id;
80 | } else if (VarId == 4) {
81 | return tile.show;
82 | } else if (VarId == 5) {
83 | return tile.select;
84 | } else if (VarId == 6) {
85 | return tile.clamp;
86 | } else if (VarId == 7) {
87 | return tile.track_mouse;
88 | } else if (VarId == 8) {
89 | return tile.loop_start;
90 | } else if (VarId == 9) {
91 | return tile.loop_method;
92 | } else if (VarId == 10) {
93 | return tile.hover_overlay_tile_id;
94 | } else if (VarId == 11) {
95 | return tile.select_overlay_tile_id;
96 | } else if (VarId == 12) {
97 | return tile.size.x;
98 | } else if (VarId == 13) {
99 | return tile.size.y;
100 | } else if (VarId == 14) {
101 | return tile.texture_id;
102 | } else if (VarId == 15) {
103 | return tile.tex_arr_id;
104 | } else if (VarId == 16) {
105 | return tile.tex_uv.x;
106 | } else if (VarId == 17) {
107 | return tile.tex_uv.y;
108 | } else if (VarId == 18) {
109 | return tile.tex_uv.z;
110 | } else if (VarId == 19) {
111 | return tile.tex_uv.w;
112 | } else if (VarId == 20) {
113 | return tile.opacity;
114 | } else if (VarId == 21) {
115 | return tile.saturation;
116 | // } else if (VarId == 22) {
117 | // return tile.reserved_1.x;
118 | // } else if (VarId == 23) {
119 | // return tile.reserved_1.y;
120 | } else if (VarId == 24) {
121 | return tile.offset.x;
122 | } else if (VarId == 25) {
123 | return tile.offset.y;
124 | } else if (VarId == 26) {
125 | return tile.anchor.x;
126 | } else if (VarId == 27) {
127 | return tile.anchor.y;
128 | } else if (VarId == 28) {
129 | return tile.loop_stage;
130 | } else if (VarId == 29) {
131 | return tile.is_hovered_over;
132 | // } else if (VarId == 30) {
133 | // return tile.reserved_2;
134 | // } else if (VarId == 31) {
135 | // return tile.reserved_2;
136 | } else if (VarId == 32) {
137 | return tile.abs_pos.x;
138 | } else if (VarId == 33) {
139 | return tile.abs_pos.y;
140 | } else if (VarId == 34) {
141 | return tile.abs_pos.z;
142 | } else if (VarId == 35) {
143 | return tile.abs_pos.w;
144 | } else {
145 | return 100000;
146 | }
147 | }
148 |
149 | float GetHoveredOverTileId()
150 | {
151 | float hovered_tile_id = -1;
152 | float layer_id = -1;
153 | for (int tile_id = Instance.max_tiles_count; tile_id > -1; tile_id--) {
154 | Tile tile = Tiles[tile_id];
155 | if (tile.is_hovered_over == 1) {
156 | if (tile.layer_id > layer_id) {
157 | layer_id = tile.layer_id;
158 | hovered_tile_id = tile_id;
159 | }
160 | };
161 | }
162 | return hovered_tile_id;
163 | }
164 |
165 | float GetSliderValue()
166 | {
167 | if (TileId == 100000) {
168 | return 100000;
169 | }
170 | Tile tile = Tiles[TileId];
171 | if (tile.parent_tile_id == -1) {
172 | return 100000;
173 | }
174 | Tile parent_tile = Tiles[tile.parent_tile_id];
175 | if (parent_tile.size.x > parent_tile.size.y) {
176 | return (tile.abs_pos.x - parent_tile.abs_pos.x) / (parent_tile.size.x - tile.size.x);
177 | } else {
178 | return (tile.abs_pos.y - parent_tile.abs_pos.y) / (parent_tile.size.y - tile.size.y);
179 | }
180 | }
181 |
182 | // #ifdef COMPUTE_SHADER
183 |
184 | [numthreads(1,1,1)]
185 | void main(uint3 ThreadId : SV_DispatchThreadID)
186 | {
187 | switch(RequestType) {
188 | // GetTileVar
189 | case 1:
190 | OutputRW[33] = GetTileVar();
191 | break;
192 | // GetHoveredOverTileId
193 | case 2:
194 | OutputRW[33] = GetHoveredOverTileId();
195 | break;
196 | // GetSliderValue
197 | case 3:
198 | OutputRW[33] = GetSliderValue();
199 | break;
200 | // Unknown
201 | default:
202 | OutputRW[33] = 100000;
203 | break;
204 | };
205 | }
206 |
207 | // #endif
208 |
--------------------------------------------------------------------------------
/TileGUI/Shaders/tile_writer.hlsl:
--------------------------------------------------------------------------------
1 | // Updates client's tile storage with given ini variables
2 |
3 | Texture1D IniParams : register(t120);
4 |
5 | #define TileType IniParams[1].x
6 | #define TemplateId IniParams[1].y
7 | #define TileId IniParams[1].z
8 | #define SetValue IniParams[1].w
9 |
10 | // Base config
11 | #define SysStateId IniParams[2].x
12 | #define LayerId IniParams[2].y
13 | #define ParentTileId IniParams[2].z
14 | #define DynamicTemplateId IniParams[2].w
15 | // Features config
16 | #define Show IniParams[3].x
17 | #define Select IniParams[3].y
18 | #define Clamp IniParams[3].z
19 | #define TrackMouse IniParams[3].w
20 | // Advanced features config
21 | #define LoopStartTexArrId IniParams[4].x
22 | #define LoopEndTexArrId IniParams[4].y
23 | #define HoverOverlayTileId IniParams[4].z
24 | #define SelectOverlayTileId IniParams[4].w
25 | // Display config
26 | #define Size IniParams[5].xy
27 | #define TextureId IniParams[5].z
28 | #define TexArrId IniParams[5].w
29 | // Texture config
30 | #define TexUV IniParams[6].xyzw
31 | // Texture config 2
32 | #define Opacity IniParams[7].x
33 | #define Saturation IniParams[7].y
34 | // Layout config
35 | #define Offset IniParams[8].xy
36 | #define Anchor IniParams[8].zw
37 | // Current state
38 | #define LoopStage IniParams[9].x
39 |
40 | struct Tile {
41 | // Base config
42 | float sys_state_id;
43 | float layer_id;
44 | float parent_tile_id;
45 | float template_id;
46 | // Features config
47 | float show;
48 | float select;
49 | float clamp;
50 | float track_mouse;
51 | // Advanced features config
52 | float loop_start;
53 | float loop_method;
54 | float hover_overlay_tile_id;
55 | float select_overlay_tile_id;
56 | // Display config
57 | float2 size;
58 | float texture_id;
59 | float tex_arr_id;
60 | // Texture config
61 | float4 tex_uv;
62 | // Texture config 2
63 | float opacity;
64 | float saturation;
65 | float2 reserved_1;
66 | // Layout config
67 | float2 offset;
68 | float2 anchor;
69 | // Current state
70 | float loop_stage;
71 | float is_hovered_over;
72 | float2 reserved_2;
73 | // Absolute coords of current position
74 | float4 abs_pos;
75 | // Relative coords of current position
76 | float4 rel_pos;
77 | };
78 |
79 | RWStructuredBuffer TileTemplateDataRW : register(u0);
80 | RWStructuredBuffer TilesRW : register(u1);
81 | // RWBuffer DebugRW : register(u7);
82 |
83 | void InitializeTile(inout Tile tile)
84 | {
85 | // Base config
86 | tile.sys_state_id = 1;
87 | tile.layer_id = 0;
88 | tile.parent_tile_id = -1;
89 | tile.template_id = -1;
90 | // Features config
91 | tile.show = 1;
92 | tile.select = 0;
93 | tile.clamp = 1;
94 | tile.track_mouse = 1;
95 | // Advanced features config
96 | tile.loop_start = -1;
97 | tile.loop_method = -1;
98 | tile.hover_overlay_tile_id = -1;
99 | tile.select_overlay_tile_id = -1;
100 | // Display config
101 | tile.size = 0;
102 | tile.texture_id = -1;
103 | tile.tex_arr_id = 0;
104 | // Texture config
105 | tile.tex_uv = float4(0, 0, 1, 1);
106 | // Texture config 2
107 | tile.opacity = 1;
108 | tile.saturation = 1;
109 | tile.reserved_1 = 0;
110 | // Layout config
111 | tile.offset = 0;
112 | tile.anchor = 0;
113 | // Current state
114 | tile.loop_stage = 0;
115 | tile.is_hovered_over = 0;
116 | tile.reserved_2 = 0;
117 | // Absolute coords of current position
118 | tile.abs_pos = 0;
119 | // Relative coords of current position
120 | tile.rel_pos = 0;
121 | }
122 |
123 | void InitializeTemplate(inout Tile tile)
124 | {
125 | // Base config
126 | tile.sys_state_id = 100000;
127 | tile.layer_id = 100000;
128 | tile.parent_tile_id = 100000;
129 | tile.template_id = 100000;
130 | // Features config
131 | tile.show = 100000;
132 | tile.select = 100000;
133 | tile.clamp = 100000;
134 | tile.track_mouse = 100000;
135 | // Advanced features config
136 | tile.loop_start = 100000;
137 | tile.loop_method = 100000;
138 | tile.hover_overlay_tile_id = 100000;
139 | tile.select_overlay_tile_id = 100000;
140 | // Display config
141 | tile.size = 100000;
142 | tile.texture_id = 100000;
143 | tile.tex_arr_id = 100000;
144 | // Texture config
145 | tile.tex_uv = 100000;
146 | // Texture config 2
147 | tile.opacity = 100000;
148 | tile.saturation = 100000;
149 | tile.reserved_1 = 100000;
150 | // Layout config
151 | tile.offset = 100000;
152 | tile.anchor = 100000;
153 | // Current state
154 | tile.loop_stage = 100000;
155 | tile.is_hovered_over = 100000;
156 | tile.reserved_2 = 100000;
157 | }
158 |
159 | void LoadDataUpdate(Tile tile_data, inout Tile tile)
160 | {
161 | // Base config
162 | if (tile_data.sys_state_id != 100000) {
163 | tile.sys_state_id = tile_data.sys_state_id;
164 | }
165 | if (tile_data.layer_id != 100000) {
166 | tile.layer_id = tile_data.layer_id;
167 | }
168 | if (tile_data.parent_tile_id != 100000) {
169 | tile.parent_tile_id = tile_data.parent_tile_id;
170 | }
171 | if (tile_data.template_id != 100000) {
172 | tile.template_id = tile_data.template_id;
173 | }
174 | // Features config
175 | if (tile_data.show != 100000) {
176 | tile.show = tile_data.show;
177 | }
178 | if (tile_data.select != 100000) {
179 | tile.select = tile_data.select;
180 | }
181 | if (tile_data.clamp != 100000) {
182 | tile.clamp = tile_data.clamp;
183 | }
184 | if (tile_data.track_mouse != 100000) {
185 | tile.track_mouse = tile_data.track_mouse;
186 | }
187 | // Advanced features config
188 | if (tile_data.loop_start != 100000) {
189 | tile.loop_start = tile_data.loop_start;
190 | }
191 | if (tile_data.loop_method != 100000) {
192 | tile.loop_method = tile_data.loop_method;
193 | }
194 | if (tile_data.hover_overlay_tile_id != 100000) {
195 | tile.hover_overlay_tile_id = tile_data.hover_overlay_tile_id;
196 | }
197 | if (tile_data.select_overlay_tile_id != 100000) {
198 | tile.select_overlay_tile_id = tile_data.select_overlay_tile_id;
199 | }
200 | // Display config
201 | if (tile_data.size.x != 100000) {
202 | tile.size.x = tile_data.size.x;
203 | }
204 | if (tile_data.size.y != 100000) {
205 | tile.size.y = tile_data.size.y;
206 | }
207 | if (tile_data.texture_id != 100000) {
208 | tile.texture_id = tile_data.texture_id;
209 | }
210 | if (tile_data.tex_arr_id != 100000) {
211 | tile.tex_arr_id = tile_data.tex_arr_id;
212 | }
213 | // Texture config
214 | if (tile_data.tex_uv.x != 100000) {
215 | tile.tex_uv.x = tile_data.tex_uv.x;
216 | }
217 | if (tile_data.tex_uv.y != 100000) {
218 | tile.tex_uv.y = tile_data.tex_uv.y;
219 | }
220 | if (tile_data.tex_uv.z != 100000) {
221 | tile.tex_uv.z = tile_data.tex_uv.z;
222 | }
223 | if (tile_data.tex_uv.w != 100000) {
224 | tile.tex_uv.w = tile_data.tex_uv.w;
225 | }
226 | // Texture config 2
227 | if (tile_data.opacity != 100000) {
228 | tile.opacity = tile_data.opacity;
229 | }
230 | if (tile_data.saturation != 100000) {
231 | tile.saturation = tile_data.saturation;
232 | }
233 | // Layout config
234 | if (tile_data.offset.x != 100000) {
235 | tile.offset.x = tile_data.offset.x;
236 | }
237 | if (tile_data.offset.y != 100000) {
238 | tile.offset.y = tile_data.offset.y;
239 | }
240 | if (tile_data.anchor.x != 100000) {
241 | tile.anchor.x = tile_data.anchor.x;
242 | }
243 | if (tile_data.anchor.y != 100000) {
244 | tile.anchor.y = tile_data.anchor.y;
245 | }
246 | // Current state
247 | if (tile_data.loop_stage != 100000) {
248 | tile.loop_stage = tile_data.loop_stage;
249 | }
250 | // if (tile_data.is_hovered_over != 100000) {
251 | // tile.is_hovered_over = tile_data.is_hovered_over;
252 | // }
253 | // tile_data.not_used_2 = 0;
254 | }
255 |
256 | Tile GetDataFromIni()
257 | {
258 | Tile tile_data;
259 | // Base config
260 | tile_data.sys_state_id = SysStateId;
261 | tile_data.layer_id = LayerId;
262 | tile_data.parent_tile_id = ParentTileId;
263 | tile_data.template_id = DynamicTemplateId;
264 | // Features config
265 | tile_data.show = Show;
266 | tile_data.select = Select;
267 | tile_data.clamp = Clamp;
268 | tile_data.track_mouse = TrackMouse;
269 | // Advanced features config
270 | tile_data.loop_start = LoopStartTexArrId;
271 | tile_data.loop_method = LoopEndTexArrId;
272 | tile_data.hover_overlay_tile_id = HoverOverlayTileId;
273 | tile_data.select_overlay_tile_id = SelectOverlayTileId;
274 | // Display config
275 | tile_data.size = Size;
276 | tile_data.texture_id = TextureId;
277 | tile_data.tex_arr_id = TexArrId;
278 | // Texture config
279 | tile_data.tex_uv = TexUV;
280 | // Texture config 2
281 | tile_data.opacity = Opacity;
282 | tile_data.saturation = Saturation;
283 | // Layout config
284 | tile_data.offset = Offset;
285 | tile_data.anchor = Anchor;
286 | // Current state
287 | tile_data.loop_stage = LoopStage;
288 | // tile_data.is_hovered_over = IsHoveredOver;
289 | // tile_data.not_used_2 = 0;
290 | return tile_data;
291 | }
292 |
293 |
294 | void UpdateTileTemplate(int template_id)
295 | {
296 | // Get template from storage
297 | Tile tile_template = TileTemplateDataRW[TemplateId];
298 | // Initialize template if empty
299 | if (tile_template.sys_state_id == 0) {
300 | InitializeTemplate(tile_template);
301 | }
302 | // Read update data from ini variables to cache
303 | Tile update_data = GetDataFromIni();
304 | // Write cached update data to template
305 | LoadDataUpdate(update_data, tile_template);
306 | // Save updated template to storage
307 | TileTemplateDataRW[TemplateId] = tile_template;
308 | }
309 |
310 | void UpdateTile(int tile_id, int template_id)
311 | {
312 | // Get tile from storage
313 | Tile tile = TilesRW[tile_id];
314 | // Initialize tile if empty
315 | if (tile.sys_state_id == 0) {
316 | InitializeTile(tile);
317 | }
318 | // Load data from provided template
319 | if (template_id != 100000) {
320 | LoadDataUpdate(TileTemplateDataRW[template_id], tile);
321 | }
322 | // Read update data from ini variables to cache
323 | Tile update_data = GetDataFromIni();
324 | // Write cached update data to tile
325 | LoadDataUpdate(update_data, tile);
326 | // Save updated tile to storage
327 | TilesRW[tile_id] = tile;
328 | }
329 |
330 | void SetSliderValue()
331 | {
332 | if (TileId == 100000) {
333 | return;
334 | }
335 | Tile tile = TilesRW[TileId];
336 | if (tile.parent_tile_id == -1) {
337 | return;
338 | }
339 | Tile parent_tile = TilesRW[tile.parent_tile_id];
340 | if (parent_tile.size.x > parent_tile.size.y) {
341 | tile.offset.x = parent_tile.abs_pos.x + (parent_tile.size.x - tile.size.x) * SetValue - tile.abs_pos.x;
342 | } else {
343 | tile.offset.y = parent_tile.abs_pos.y + (parent_tile.size.y - tile.size.y) * SetValue - tile.abs_pos.y;
344 | }
345 | TilesRW[TileId] = tile;
346 | }
347 |
348 |
349 | // #ifdef COMPUTE_SHADER
350 |
351 | [numthreads(1,1,1)]
352 | void main(uint3 ThreadId : SV_DispatchThreadID)
353 | {
354 | if (TileType == 1) {
355 | UpdateTileTemplate(TemplateId);
356 | } else if (TileType == 2) {
357 | UpdateTile(TileId, TemplateId);
358 | // DebugRW[TileId] = float4(TilesRW[TileId].anchor, 0, 0);
359 | } else if (TileType == 3) {
360 | SetSliderValue();
361 | }
362 | }
363 |
364 | // #endif
365 |
--------------------------------------------------------------------------------
/TileGUI/TileGUI.ini:
--------------------------------------------------------------------------------
1 | ; TileGUI v0.8.2 BETA
2 | ; Simple yet powerful GUI framework for XXMI
3 | ; https://github.com/SpectrumQT/TileGUI
4 |
5 | namespace=TileGUI
6 |
7 |
8 | ; API -------------------------
9 |
10 | [CommandListGetVersion]
11 | $return_version = 0.82
12 |
13 |
14 | [CommandListDrawGUI]
15 | ; Run compute shader to process "shader-accelerated" features like hover-overlays, loops and dragging
16 | run = CustomShaderTileFeaturesService
17 | ; Run compute shader to update tile positions
18 | run = CustomShaderTilePositionService
19 | ; Run GUI shaders
20 | run = CustomShaderTileDrawService
21 | ; Draw virtual cursor for gamepad & keyboard controls support
22 | run = CommandList\TileGUI_VirtualCursor\DrawVirtualCursor
23 |
24 |
25 | [CommandListSetInstance]
26 | if ResourceClientInstanceData !== null
27 | run = CustomShaderInstanceWriter
28 | run = CommandListSetScale
29 | endif
30 |
31 |
32 | [CommandListSetTemplate]
33 | if ResourceClientTemplatesData !== null
34 | $set_tile_type = 1
35 | run = CustomShaderTileWriter
36 | endif
37 |
38 |
39 | [CommandListApplyTemplate]
40 | if ResourceClientTemplatesData !== null
41 | $request_type = 1
42 | run = CustomShaderTileGroupWriter
43 | endif
44 |
45 |
46 | [CommandListApplyLayout]
47 | if ResourceClientTilesData !== null
48 | $request_type = 2
49 | run = CustomShaderTileGroupWriter
50 | endif
51 |
52 |
53 | [CommandListSetTile]
54 | if ResourceClientTilesData !== null
55 | $set_tile_type = 2
56 | run = CustomShaderTileWriter
57 | endif
58 |
59 |
60 | [CommandListSetSliderValue]
61 | if ResourceClientTilesData !== null
62 | $set_tile_type = 3
63 | run = CustomShaderTileWriter
64 | endif
65 |
66 |
67 | [CommandListGetHoveredOverTileId]
68 | if ResourceClientTilesData !== null
69 | $arg_request_type = 2
70 | run = CustomShaderTileReader
71 | endif
72 |
73 |
74 | [CommandListGetSliderValue]
75 | if ResourceClientTilesData !== null
76 | $arg_request_type = 3
77 | run = CustomShaderTileReader
78 | endif
79 |
80 |
81 | [CommandListGetTileVar]
82 | if ResourceClientTilesData !== null
83 | $arg_request_type = 1
84 | run = CustomShaderTileReader
85 | endif
86 |
87 |
88 | [CommandListGetSysStateId]
89 | $arg_tile_var_id = 0
90 | run = CommandListGetTileVar
91 |
92 | [CommandListGetLayerId]
93 | $arg_tile_var_id = 1
94 | run = CommandListGetTileVar
95 |
96 | [CommandListGetParentTileId]
97 | $arg_tile_var_id = 2
98 | run = CommandListGetTileVar
99 |
100 | [CommandListGetDynamicTemplateId]
101 | $arg_tile_var_id = 3
102 | run = CommandListGetTileVar
103 |
104 | [CommandListGetShow]
105 | $arg_tile_var_id = 4
106 | run = CommandListGetTileVar
107 |
108 | [CommandListGetSelect]
109 | $arg_tile_var_id = 5
110 | run = CommandListGetTileVar
111 |
112 | [CommandListGetClamp]
113 | $arg_tile_var_id = 6
114 | run = CommandListGetTileVar
115 |
116 | [CommandListGetTrackMouse]
117 | $arg_tile_var_id = 7
118 | run = CommandListGetTileVar
119 |
120 | [CommandListGetLoopStartTexArrId]
121 | $arg_tile_var_id = 8
122 | run = CommandListGetTileVar
123 |
124 | [CommandListGetLoopEndTexArrId]
125 | $arg_tile_var_id = 9
126 | run = CommandListGetTileVar
127 |
128 | [CommandListGetHoverOverlayTileId]
129 | $arg_tile_var_id = 10
130 | run = CommandListGetTileVar
131 |
132 | [CommandListGetSelectOverlayTileId]
133 | $arg_tile_var_id = 11
134 | run = CommandListGetTileVar
135 |
136 | [CommandListGetWidth]
137 | $arg_tile_var_id = 12
138 | run = CommandListGetTileVar
139 |
140 | [CommandListGetHeight]
141 | $arg_tile_var_id = 13
142 | run = CommandListGetTileVar
143 |
144 | [CommandListGetTextureId]
145 | $arg_tile_var_id = 14
146 | run = CommandListGetTileVar
147 |
148 | [CommandListGetTexArrId]
149 | $arg_tile_var_id = 15
150 | run = CommandListGetTileVar
151 |
152 | [CommandListGetTexUvX]
153 | $arg_tile_var_id = 16
154 | run = CommandListGetTileVar
155 |
156 | [CommandListGetTexUvY]
157 | $arg_tile_var_id = 17
158 | run = CommandListGetTileVar
159 |
160 | [CommandListGetTexUvZ]
161 | $arg_tile_var_id = 18
162 | run = CommandListGetTileVar
163 |
164 | [CommandListGetTexUvW]
165 | $arg_tile_var_id = 19
166 | run = CommandListGetTileVar
167 |
168 | [CommandListGetOpacity]
169 | $arg_tile_var_id = 20
170 | run = CommandListGetTileVar
171 |
172 | [CommandListGetSaturation]
173 | $arg_tile_var_id = 21
174 | run = CommandListGetTileVar
175 |
176 | ; [CommandListGetReserved1X]
177 | ; $arg_tile_var_id = 22
178 | ; run = CommandListGetTileVar
179 |
180 | ; [CommandListGetReserved1Y]
181 | ; $arg_tile_var_id = 23
182 | ; run = CommandListGetTileVar
183 |
184 | [CommandListGetOffsetX]
185 | $arg_tile_var_id = 24
186 | run = CommandListGetTileVar
187 |
188 | [CommandListGetOffsetY]
189 | $arg_tile_var_id = 25
190 | run = CommandListGetTileVar
191 |
192 | [CommandListGetAnchorX]
193 | $arg_tile_var_id = 26
194 | run = CommandListGetTileVar
195 |
196 | [CommandListGetAnchorY]
197 | $arg_tile_var_id = 27
198 | run = CommandListGetTileVar
199 |
200 | [CommandListGetLoopStage]
201 | $arg_tile_var_id = 28
202 | run = CommandListGetTileVar
203 |
204 | [CommandListGetIsHoveredOver]
205 | $arg_tile_var_id = 29
206 | run = CommandListGetTileVar
207 |
208 | ; [CommandListGetReserved2X]
209 | ; $arg_tile_var_id = 30
210 | ; run = CommandListGetTileVar
211 |
212 | ; [CommandListGetReserved2Y]
213 | ; $arg_tile_var_id = 31
214 | ; run = CommandListGetTileVar
215 |
216 | [CommandListGetAbsPosX]
217 | $arg_tile_var_id = 32
218 | run = CommandListGetTileVar
219 |
220 | [CommandListGetAbsPosY]
221 | $arg_tile_var_id = 33
222 | run = CommandListGetTileVar
223 |
224 | [CommandListGetAbsPosZ]
225 | $arg_tile_var_id = 34
226 | run = CommandListGetTileVar
227 |
228 | [CommandListGetAbsPosW]
229 | $arg_tile_var_id = 35
230 | run = CommandListGetTileVar
231 |
232 |
233 | ; VARIABLES -------------------------
234 |
235 | [Constants]
236 | global $return_version = -1
237 | global $required_version = -1
238 | ; While TileGUI is a stateless library, we still need to pass variables and get results somehow
239 | ; So we'll use temp variables that are explicitly getting reset on connect or after a method call
240 | ; Also, as we can't exchange 'null' with shaders, we'll mask it with 100000 instead
241 | ; This arbitrary big number doesn't have any sense for any value used by this library
242 | ;=================================================================================================
243 | ; Temp vars of client configuration
244 | global $max_tiles_count = 128
245 | global $max_layers_count = 1
246 | global $max_parent_recursion = 0
247 | global $scaling_factor = 0.25
248 | ;=================================================================================================
249 | ; Temp vars of user controls
250 | global $toggle_gui = 0
251 | global $mouse_left = 0
252 | global $mouse_right = 0
253 | global $mouse_mid = 0
254 | global $mouse_forward = 0
255 | global $mouse_backward = 0
256 | global $virtual_cursor_x = -1
257 | global $virtual_cursor_y = -1
258 | ;=================================================================================================
259 | ; Temp vars of CustomShaderInstanceWriter
260 | global $drag_tile_id = 100000
261 | ;=================================================================================================
262 | ; Temp vars of CustomShaderTileWriter
263 | global $screen_scaling = 1.0
264 | global $set_tile_type = 100000
265 | global $target_template_id = 100000
266 | global $target_tile_id = 100000
267 | global $set_value = 100000
268 | ; System config
269 | global $sys_state_id = 100000
270 | global $layer_id = 100000
271 | global $parent_tile_id = 100000
272 | global $template_id = 100000
273 | ; Features config
274 | global $show = 100000
275 | global $select = 100000
276 | global $clamp = 100000
277 | global $track_mouse = 100000
278 | ; Advanced features config
279 | global $loop_start = 100000
280 | global $loop_method = 100000
281 | global $hover_overlay_tile_id = 100000
282 | global $select_overlay_tile_id = 100000
283 | ; Display config
284 | global $width = 100000
285 | global $height = 100000
286 | global $texture_id = 100000
287 | global $tex_arr_id = 100000
288 | ; Texture config
289 | global $tex_uv_x = 100000
290 | global $tex_uv_y = 100000
291 | global $tex_uv_z = 100000
292 | global $tex_uv_w = 100000
293 | ; Texture config 2
294 | global $opacity = 100000
295 | global $saturation = 100000
296 | ; Layout config
297 | global $offset_x = 100000
298 | global $offset_y = 100000
299 | global $anchor_x = 100000
300 | global $anchor_y = 100000
301 | ; Current state
302 | global $loop_stage = 100000
303 | ;=================================================================================================
304 | ; Temp vars of CustomShaderTileGroupWriter
305 | global $request_type = 100000
306 | global $first_tile_id = 100000
307 | global $last_tile_id = 100000
308 | global $create_tiles = 100000
309 | global $skip_existing_tiles = 100000
310 | global $cols_count = 100000
311 | global $rows_count = 100000
312 | global $cols_padding = 100000
313 | global $rows_padding = 100000
314 | ;=================================================================================================
315 | ; Temp vars of CustomShaderTileReader
316 | global $arg_request_type = 100000
317 | global $arg_tile_var_id = 100000
318 | global $return_var = 100000
319 | ;=================================================================================================
320 |
321 |
322 |
323 | ; HELPERS -------------------------
324 |
325 | ; Make sure to make temp variables really 'temp' via calling this method on connect!
326 | [CommandListResetTempVars]
327 | ; Reset configuration to defaults
328 | $return_version = -1
329 | $required_version = -1
330 | $max_tiles_count = 128
331 | $max_layers_count = 1
332 | $max_parent_recursion = 0
333 | $scaling_factor = 0.25
334 | ; Reset all temp vars used by shaders
335 | run = CommandListResetVarsOfCustomShaderInstanceWriter
336 | run = CommandListResetVarsOfCustomShaderTileWriter
337 | run = CommandListResetVarsOfCustomShaderTileGroupWriter
338 | run = CommandListResetVarsOfCustomShaderTileReader
339 |
340 |
341 | [CommandListPassWindowInfo]
342 | ; Pass a game window size to the shader
343 | x0 = window_width
344 | y0 = window_height
345 | ; Pass cursor relative coords to the shader
346 | if $virtual_cursor_x == -1 && $virtual_cursor_y == -1
347 | ; Pass real mouse cursor
348 | z0 = cursor_x * 2 - 1
349 | w0 = -(cursor_y * 2 - 1)
350 | else
351 | ; Pass virtual mouse cursor
352 | z0 = $\TileGUI\virtual_cursor_x / (x0 / 2)
353 | w0 = $\TileGUI\virtual_cursor_y / (y0 / 2)
354 | endif
355 |
356 |
357 | ; Set UI scaling factor
358 | [CommandListSetScale]
359 | ; Windows returns 96 as effective_dpi for 100% scale
360 | $screen_scaling = effective_dpi / 96
361 | if $screen_scaling > 1.0
362 | $screen_scaling = 1.0 + ($screen_scaling - 1.0) * $scaling_factor
363 | endif
364 |
365 |
366 | ; INSTANCE WRITER SHADER -------------------------
367 |
368 | ; Updates client's instance storage with given ini variables
369 | [CustomShaderInstanceWriter]
370 | ; Load shader and explicitly unbind other shaders for safety
371 | cs = Shaders/instance_writer.hlsl
372 | vs = null
373 | ps = null
374 | hs = null
375 | ds = null
376 | gs = null
377 | ; Pass RWBuffers to communicate with the shader
378 | cs-u0 = ResourceClientInstanceData
379 | ; cs-u7 = ResourceDebugRW
380 | ; Backup IniParams we are about to use
381 | local $bak_x0 = x0
382 | local $bak_y0 = y0
383 | local $bak_z0 = z0
384 | local $bak_w0 = w0
385 | local $bak_x10 = x10
386 | local $bak_y10 = y10
387 | local $bak_x15 = x15
388 | ; Pass a game window size and cursor relative coords to the shader
389 | run = CommandListPassWindowInfo
390 | ; Pass variables to the shader
391 | x10 = $max_tiles_count
392 | y10 = $max_layers_count
393 | x15 = $drag_tile_id
394 | ; Run calulations
395 | Dispatch = 1, 1, 1
396 | ; Reset variables
397 | run = CommandListResetVarsOfCustomShaderInstanceWriter
398 | ; Unbind RWBuffers
399 | post cs-u0 = null
400 | ; Restore IniParams:
401 | post x0 = $bak_x0
402 | post y0 = $bak_y0
403 | post z0 = $bak_z0
404 | post w0 = $bak_w0
405 | post x10 = $bak_x10
406 | post y10 = $bak_y10
407 | post x15 = $bak_x15
408 |
409 | [CommandListResetVarsOfCustomShaderInstanceWriter]
410 | $drag_tile_id = 100000
411 |
412 |
413 | ; TILE WRITER SHADER -------------------------
414 |
415 | ; Updates client's tile storage with given ini variables
416 | [CustomShaderTileWriter]
417 | ; Load shader and explicitly unbind other shaders for safety
418 | cs = Shaders/tile_writer.hlsl
419 | vs = null
420 | ps = null
421 | hs = null
422 | ds = null
423 | gs = null
424 | ; Backup IniParams we are about to use
425 | local $bak_x1 = x1
426 | local $bak_y1 = y1
427 | local $bak_z1 = z1
428 | local $bak_w1 = w1
429 | local $bak_x2 = x2
430 | local $bak_y2 = y2
431 | local $bak_z2 = z2
432 | local $bak_w2 = w2
433 | local $bak_x3 = x3
434 | local $bak_y3 = y3
435 | local $bak_z3 = z3
436 | local $bak_w3 = w3
437 | local $bak_x4 = x4
438 | local $bak_y4 = y4
439 | local $bak_z4 = z4
440 | local $bak_w4 = w4
441 | local $bak_x5 = x5
442 | local $bak_y5 = y5
443 | local $bak_z5 = z5
444 | local $bak_w5 = w5
445 | local $bak_x6 = x6
446 | local $bak_y6 = y6
447 | local $bak_z6 = z6
448 | local $bak_w6 = w6
449 | local $bak_x7 = x7
450 | local $bak_y7 = y7
451 | local $bak_z7 = z7
452 | local $bak_w7 = w7
453 | local $bak_x8 = x8
454 | local $bak_y8 = y8
455 | local $bak_z8 = z8
456 | local $bak_w8 = w8
457 | local $bak_x9 = x9
458 | ; local $bak_y9 = y9
459 | ; local $bak_z9 = z9
460 | ; local $bak_w9 = w9
461 | ; Pass RWBuffers to communicate with the shader
462 | cs-u0 = ResourceClientTemplatesData
463 | cs-u1 = ResourceClientTilesData
464 | ; cs-u7 = ResourceDebugRW
465 | ; For template we should pass only TemplateId
466 | if $set_tile_type == 1
467 | x1 = 1
468 | y1 = $target_template_id
469 | ; For regular tile we should pass both TileID and TemplateId (TemplateId is optional though)
470 | else if $set_tile_type == 2
471 | x1 = 2
472 | y1 = $template_id
473 | z1 = $target_tile_id
474 | else if $set_tile_type == 3
475 | x1 = 3
476 | z1 = $target_tile_id
477 | w1 = $set_value
478 | endif
479 | ; Pass a tile update data to the shader
480 | ; System config
481 | x2 = $sys_state_id
482 | y2 = $layer_id
483 | z2 = $parent_tile_id
484 | w2 = $template_id
485 | ; Features config
486 | x3 = $show
487 | y3 = $select
488 | z3 = $clamp
489 | w3 = $track_mouse
490 | ; Advanced features config
491 | x4 = $loop_start
492 | y4 = $loop_method
493 | z4 = $hover_overlay_tile_id
494 | w4 = $select_overlay_tile_id
495 | ; Display config
496 | if $width == 100000
497 | x5 = $width
498 | else
499 | x5 = $width * $screen_scaling
500 | endif
501 | if $height == 100000
502 | y5 = $height
503 | else
504 | y5 = $height * $screen_scaling
505 | endif
506 | z5 = $texture_id
507 | w5 = $tex_arr_id
508 | ; Texture config
509 | x6 = $tex_uv_x
510 | y6 = $tex_uv_y
511 | z6 = $tex_uv_z
512 | w6 = $tex_uv_w
513 | ; Texture config 2
514 | x7 = $opacity
515 | y7 = $saturation
516 | ; z7 = $reserved_1
517 | ; w7 = $reserved_1
518 | ; Layout config
519 | x8 = $offset_x
520 | y8 = $offset_y
521 | z8 = $anchor_x
522 | w8 = $anchor_y
523 | ; Current state
524 | x9 = $loop_stage
525 | ; Run calulations
526 | Dispatch = 1, 1, 1
527 | ; Reset variables
528 | run = CommandListResetVarsOfCustomShaderTileWriter
529 | ; Unbind RWBuffers
530 | post cs-u0 = null
531 | post cs-u1 = null
532 | ; Restore IniParams:
533 | post x1 = $bak_x1
534 | post y1 = $bak_y1
535 | post z1 = $bak_z1
536 | post w1 = $bak_w1
537 | post x2 = $bak_x2
538 | post y2 = $bak_y2
539 | post z2 = $bak_z2
540 | post w2 = $bak_w2
541 | post x3 = $bak_x3
542 | post y3 = $bak_y3
543 | post z3 = $bak_z3
544 | post w3 = $bak_w3
545 | post x4 = $bak_x4
546 | post y4 = $bak_y4
547 | post z4 = $bak_z4
548 | post w4 = $bak_w4
549 | post x5 = $bak_x5
550 | post y5 = $bak_y5
551 | post z5 = $bak_z5
552 | post w5 = $bak_w5
553 | post x6 = $bak_x6
554 | post y6 = $bak_y6
555 | post z6 = $bak_z6
556 | post w6 = $bak_w6
557 | post x7 = $bak_x7
558 | post y7 = $bak_y7
559 | post z7 = $bak_z7
560 | post w7 = $bak_w7
561 | post x8 = $bak_x8
562 | post y8 = $bak_y8
563 | post z8 = $bak_z8
564 | post w8 = $bak_w8
565 | post x9 = $bak_x9
566 | ; post y9 = $bak_y9
567 | ; post z9 = $bak_z9
568 | ; post w9 = $bak_w9
569 |
570 | [CommandListResetVarsOfCustomShaderTileWriter]
571 | ; Request config
572 | $set_tile_type = 100000
573 | $target_template_id = 100000
574 | $target_tile_id = 100000
575 | $set_value = 100000
576 | ; System config
577 | $sys_state_id = 100000
578 | $layer_id = 100000
579 | $parent_tile_id = 100000
580 | $template_id = 100000
581 | ; Features config
582 | $show = 100000
583 | $select = 100000
584 | $clamp = 100000
585 | $track_mouse = 100000
586 | ; Advanced features config
587 | $loop_start = 100000
588 | $loop_method = 100000
589 | $hover_overlay_tile_id = 100000
590 | $select_overlay_tile_id = 100000
591 | ; Display config
592 | $width = 100000
593 | $height = 100000
594 | $texture_id = 100000
595 | $tex_arr_id = 100000
596 | ; Texture config
597 | $tex_uv_x = 100000
598 | $tex_uv_y = 100000
599 | $tex_uv_z = 100000
600 | $tex_uv_w = 100000
601 | ; Texture config 2
602 | $opacity = 100000
603 | $saturation = 100000
604 | ; Layout config
605 | $offset_x = 100000
606 | $offset_y = 100000
607 | $anchor_x = 100000
608 | $anchor_y = 100000
609 | ; Current state
610 | $loop_stage = 100000
611 |
612 |
613 | ; TILE GROUP WRITER SHADER -------------------------
614 |
615 | ; Streamlines multiple tiles declaration and property updates both for initialization and runtime
616 | [CustomShaderTileGroupWriter]
617 | ; Load shader and explicitly unbind other shaders for safety
618 | cs = Shaders/tile_group_writer.hlsl
619 | vs = null
620 | ps = null
621 | hs = null
622 | ds = null
623 | gs = null
624 | ; Pass RWBuffers to communicate with the shader
625 | cs-u0 = ResourceClientTemplatesData
626 | cs-u1 = ResourceClientTilesData
627 | ; cs-u7 = ResourceDebugRW
628 | ; Backup IniParams we are about to use
629 | local $bak_x0 = x0
630 | local $bak_y0 = y0
631 | local $bak_z0 = z0
632 | local $bak_x1 = x1
633 | local $bak_y1 = y1
634 | local $bak_x2 = x2
635 | local $bak_y2 = y2
636 | local $bak_x3 = x3
637 | local $bak_y3 = y3
638 | local $bak_z3 = z3
639 | local $bak_w3 = w3
640 | local $bak_x4 = x4
641 | local $bak_y4 = y4
642 | ; Pass data to the shader
643 | x0 = $request_type
644 | y0 = $template_id
645 | z0 = $parent_tile_id
646 | x1 = $first_tile_id
647 | y1 = $last_tile_id
648 | x2 = $create_tiles
649 | y2 = $skip_existing_tiles
650 | x3 = $cols_count
651 | y3 = $rows_count
652 | if $cols_padding == 100000
653 | z3 = $cols_padding
654 | else
655 | z3 = $cols_padding * $screen_scaling
656 | endif
657 | if $rows_padding == 100000
658 | w3 = $rows_padding
659 | else
660 | w3 = $rows_padding * $screen_scaling
661 | endif
662 | x4 = $anchor_x
663 | y4 = $anchor_y
664 | ; Shader requires 1 thread per tile and has thread group size of 64 declared
665 | ; We'll need max_tiles_count / 64 thread groups total to process all the tiles
666 | local $thread_groups_count = $max_tiles_count / 64
667 | ; Run the compute shader
668 | Dispatch = $thread_groups_count, 1, 1
669 | ; Unbind RWBuffers
670 | post cs-u0 = null
671 | post cs-u1 = null
672 | ; Reset variables
673 | run = CommandListResetVarsOfCustomShaderTileGroupWriter
674 | ; Restore IniParams:
675 | post x0 = $bak_x0
676 | post y0 = $bak_y0
677 | post z0 = $bak_z0
678 | post x1 = $bak_x1
679 | post y1 = $bak_y1
680 | post x2 = $bak_x2
681 | post y2 = $bak_y2
682 | post x3 = $bak_x3
683 | post y3 = $bak_y3
684 | post z3 = $bak_z3
685 | post w3 = $bak_w3
686 | post x4 = $bak_x4
687 | post y4 = $bak_y4
688 |
689 | [CommandListResetVarsOfCustomShaderTileGroupWriter]
690 | ; Request config
691 | $request_type = 100000
692 |
693 | $template_id = 100000
694 | $parent_tile_id = 100000
695 | $first_tile_id = 100000
696 | $last_tile_id = 100000
697 | $create_tiles = 100000
698 | $skip_existing_tiles = 100000
699 | $cols_count = 100000
700 | $rows_count = 100000
701 | $cols_padding = 100000
702 | $rows_padding = 100000
703 | $anchor_x = 100000
704 | $anchor_y = 100000
705 |
706 |
707 | ; TILE FEATURES SERVICE SHADER -------------------------
708 |
709 | ; Handles special (re)actions for all tiles, like hover over, overlays, dragging and so on
710 | ; Simplifies and accelerates common GUI logic that would require tons of STORE calls otherwise
711 | [CustomShaderTileFeaturesService]
712 | ; Load shader and explicitly unbind other shaders for safety
713 | cs = Shaders/tile_features_service.hlsl
714 | vs = null
715 | ps = null
716 | hs = null
717 | ds = null
718 | gs = null
719 | ; Pass RWBuffers to communicate with the shader
720 | cs-u0 = ResourceClientInstanceData
721 | cs-u1 = ResourceClientTilesData
722 | ; cs-u7 = ResourceDebugRW
723 | ; Backup IniParams we are about to use
724 | local $bak_x0 = x0
725 | local $bak_y0 = y0
726 | local $bak_z0 = z0
727 | local $bak_w0 = w0
728 | ; Pass a game window size and cursor relative coords to the shader
729 | run = CommandListPassWindowInfo
730 | ; Shader requires 1 thread per tile and has thread group size of 64 declared
731 | ; We'll need max_tiles_count / 64 thread groups total to process all the tiles
732 | local $thread_groups_count = $max_tiles_count / 64
733 | ; Run the compute shader
734 | Dispatch = $thread_groups_count, 1, 1
735 | ; Unbind RWBuffers
736 | post cs-u0 = null
737 | post cs-u1 = null
738 | ; Restore IniParams:
739 | post x0 = $bak_x0
740 | post y0 = $bak_y0
741 | post z0 = $bak_z0
742 | post w0 = $bak_w0
743 |
744 |
745 | ; TILE POSITION SERVICE SHADER -------------------------
746 |
747 | ; Updates positions of all tiles based on sizes, offsets, anchors and those of parents
748 | [CustomShaderTilePositionService]
749 | ; Load shader and explicitly unbind other shaders for safety
750 | cs = Shaders/tile_position_service.hlsl
751 | vs = null
752 | ps = null
753 | hs = null
754 | ds = null
755 | gs = null
756 | ; Pass RWBuffers to communicate with the shader
757 | cs-u1 = ResourceClientTilesData
758 | ; cs-u7 = ResourceDebugRW
759 | ; Backup IniParams we are about to use
760 | local $bak_x0 = x0
761 | local $bak_y0 = y0
762 | local $bak_x1 = x1
763 | ; Pass a game window size to the shader
764 | x0 = window_width
765 | y0 = window_height
766 | ; Pass max length of parents chain to process in single pass
767 | x1 = $max_parent_recursion
768 | ; Shader requires 1 thread per tile and has thread group size of 64 declared
769 | ; We'll need max_tiles_count / 64 thread groups total to process all the tiles
770 | local $thread_groups_count = $max_tiles_count / 64
771 | ; Run the compute shader
772 | Dispatch = $thread_groups_count, 1, 1
773 | ; Unbind RWBuffers
774 | post cs-u0 = null
775 | post cs-u1 = null
776 | ; Restore IniParams:
777 | post x0 = $bak_x0
778 | post y0 = $bak_y0
779 | post x1 = $bak_x1
780 |
781 |
782 | ; TILE DRAW SERVICE SHADER -------------------------
783 |
784 | ; Draws all tiles on screen
785 | [CustomShaderTileDrawService]
786 | ; Load shader and explicitly unbind other shaders for safety
787 | cs = null
788 | vs = Shaders/tile_draw_service.hlsl
789 | ps = Shaders/tile_draw_service.hlsl
790 | hs = null
791 | ds = null
792 | gs = Shaders/tile_draw_service.hlsl
793 | ; Disable front/back face culling so the vertices can be in any rotation
794 | cull = none
795 | ; Use points as the primitive from the vertex shader to the geometry shader
796 | topology = point_list
797 | ; Clear all render + depth targets to avoid compatibility issues
798 | run = BuiltInCommandListUnbindAllRenderTargets
799 | ; Bind the back buffer as a render target. set_viewport ensures that the view
800 | ; port is the size of the buffer so the draw call will work
801 | o0 = set_viewport bb
802 | ; Enable blending images with alpha channel (transparency support)
803 | blend = ADD SRC_ALPHA INV_SRC_ALPHA
804 | ; Pass RWStructuredBuffers as read-only to the geometry shader (t instead of u slot)
805 | gs-t121 = ResourceClientInstanceData
806 | gs-t122 = ResourceClientTilesData
807 | ; Draw images
808 | Draw = $max_layers_count, 0
809 | ; Unbind resources
810 | post gs-t121 = null
811 | post gs-t122 = null
812 |
813 |
814 | ; TILE READER SHADER -------------------------
815 |
816 | ; Fetches tile properties from RWBuffers to ini variables
817 | [CustomShaderTileReader]
818 | ; Load shader and explicitly unbind other shaders for safety
819 | cs = Shaders/tile_reader.hlsl
820 | vs = null
821 | ps = null
822 | hs = null
823 | ds = null
824 | gs = null
825 | ; Clear output buffer
826 | clear = ResourceTempBuffer
827 | ; Pass RWBuffers to communicate with the shader
828 | cs-t121 = ResourceClientInstanceData
829 | cs-t122 = ResourceClientTilesData
830 | cs-u0 = ResourceTempBuffer
831 | ; cs-u7 = ResourceDebugRW
832 | ; Backup IniParams we are about to use
833 | local $bak_x1 = x1
834 | local $bak_y1 = y1
835 | local $bak_z1 = z1
836 | ; Pass the update data to the shader
837 | x1 = $arg_request_type
838 | y1 = $target_tile_id
839 | z1 = $arg_tile_var_id
840 | ; Run the compute shader
841 | Dispatch = 1, 1, 1
842 | ; Update $return_var temp variable
843 | $return_var = 100000
844 | store = $return_var, ResourceTempBuffer, 33
845 | ; Reset variables
846 | $arg_request_type = 100000
847 | $target_tile_id = 100000
848 | $arg_tile_var_id = 100000
849 | ; Unbind RWBuffers
850 | post cs-t121 = null
851 | post cs-t122 = null
852 | post cs-u0 = null
853 | ; Restore IniParams:
854 | post x1 = $bak_x1
855 | post y1 = $bak_y1
856 | post z1 = $bak_z1
857 |
858 | [CommandListResetVarsOfCustomShaderTileReader]
859 | $arg_request_type = 100000
860 | $target_tile_id = 100000
861 | $arg_tile_var_id = 100000
862 | $return_var = 100000
863 |
864 |
865 | ; RESOURCES -------------------------
866 |
867 | [ResourceTempBuffer]
868 | type = buffer
869 | format = R32_FLOAT
870 | array = 34
871 |
872 | ; [ResourceDebugRW]
873 | ; type = RWBuffer
874 | ; format = R32G32B32A32_FLOAT
875 | ; array = 128
876 |
877 | [ResourceClientInstanceData]
878 |
879 | [ResourceClientTilesData]
880 |
881 | [ResourceClientTemplatesData]
882 |
883 |
884 | ; EOF -------------------------
885 |
--------------------------------------------------------------------------------
/TileGUI/UserControls.ini:
--------------------------------------------------------------------------------
1 | ;
2 | ; How To Change Key Bindings
3 | ;
4 | ; 1. Find button (i.e. [KeyLeftButtonClick])
5 | ; 2. Find line below 'Xbox Gamepad Binding', 'Keyboard Binding' or 'Mouse Binding' comment
6 | ; 3. Replace 'key = OLD_KEY_CODE' with 'key = NEW_KEY_CODE'
7 | ;
8 | ; Key Codes:
9 | ; * For Gamepad buttons, use following codes:
10 | ; XB_LEFT_TRIGGER, XB_RIGHT_TRIGGER,
11 | ; XB_LEFT_SHOULDER, XB_RIGHT_SHOULDER,
12 | ; XB_LEFT_THUMB, XB_RIGHT_THUMB,
13 | ; XB_DPAD_UP, XB_DPAD_DOWN, XB_DPAD_LEFT, XB_DPAD_RIGHT,
14 | ; XB_A, XB_B, XB_X, XB_Y, XB_START, XB_BACK, XB_GUIDE
15 | ; * For A-Z and 0-9 on the number row, just use that single character
16 | ; * For everything else (including mouse buttons) use the Virtual Key Code
17 | ; - Virtual Key Codes list: https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
18 | ; - Usage of 'VK_' prefix is optional, you can specify buttons with or without it
19 | ;
20 | ; Key Combination:
21 | ; * To specify key combination, separate key names with spaces (e.g. "SHIFT ALT Q")
22 | ;
23 | ; Modifiers:
24 | ; * To specify key that should NOT be held for binding to activate use 'NO_' prefix (e.g. "NO_ALT CTRL F1")
25 | ; * To exclude all standard modifiers (Ctrl, Alt, Shift, Windows) use 'NO_MODIFIERS' (e.g. "NO_MODIFIERS VK_LBUTTON")
26 |
27 |
28 | ; Configuration -------------------------
29 |
30 | [CommandListSetupConfiguration]
31 | ; Affects the Horizontal Speed of Virtual Cursor controlled via Gamepad or Keyboard
32 | ; For reasonable speed keep the value between 0.25 and 2.0
33 | $cursor_sensivity_x = 0.5
34 | ; Affects the Vertical Speed of Virtual Cursor controlled via Gamepad or Keyboard
35 | ; For reasonable speed keep the value between 0.25 and 2.0
36 | $cursor_sensivity_y = 0.5
37 |
38 |
39 | ; General Hotkeys -------------------------
40 |
41 | ; Action: Toggle (Show/Hide) Mod's GUI
42 | [KeyToggleGUI]
43 | ; Xbox Gamepad Binding:
44 | key = XB_START XB_BACK
45 | ; Keyboard Binding:
46 | key = SHIFT ALT T
47 | ; Mouse Binding:
48 | ; Doesn't have much sense for mouse tbh
49 | ;------------------------------------------
50 | ; Input Configuration:
51 | type = cycle
52 | $toggle_gui = 0,1
53 |
54 |
55 | ; Suggested Action: Select or Toggle UI element hovered over by cursor
56 | [KeyLeftButtonClick]
57 | ; Xbox Gamepad Binding:
58 | key = XB_X
59 | ; Keyboard Binding:
60 | key = SHIFT ALT Q
61 | ; Mouse Binding:
62 | key = VK_LBUTTON
63 | ;------------------------------------------
64 | ; Input Configuration:
65 | type = hold
66 | $mouse_left_state = 1
67 | run = CommandListHandleMouseLeft
68 |
69 |
70 | ; Suggested Action: Deselect or Configure UI element hovered over by cursor
71 | [KeyRightButtonClick]
72 | ; Xbox Gamepad Binding:
73 | key = XB_B
74 | ; Keyboard Binding:
75 | key = SHIFT ALT E
76 | ; Mouse Binding:
77 | key = VK_RBUTTON
78 | ;------------------------------------------
79 | ; Input Configuration:
80 | type = hold
81 | $mouse_right_state = 1
82 | run = CommandListHandleMouseRight
83 |
84 |
85 | ; Suggested Action: Drag or Scroll UI element hovered over by cursor
86 | [KeyMiddleButtonClick]
87 | ; Xbox Gamepad Binding:
88 | key = XB_Y
89 | ; Keyboard Binding:
90 | key = SHIFT ALT R
91 | ; Mouse Binding:
92 | key = VK_MBUTTON
93 | ;------------------------------------------
94 | ; Input Configuration:
95 | type = hold
96 | $mouse_mid_state = 1
97 | run = CommandListHandleMouseMid
98 |
99 |
100 | ; Suggested Action: Close Child Panel or Go To Previous UI State
101 | [KeyBackwardButtonClick]
102 | ; Xbox Gamepad Binding:
103 | key = XB_BACK
104 | ; Keyboard Binding:
105 | key = SHIFT ALT Z
106 | ; Mouse Binding:
107 | key = VK_XBUTTON1
108 | ;------------------------------------------
109 | ; Input Configuration:
110 | type = hold
111 | $mouse_backward_state = 1
112 | run = CommandListHandleMouseBackward
113 |
114 |
115 | ; Suggested Action: Open Child Panel or Go To Next UI State
116 | [KeyForwardButtonClick]
117 | ; Xbox Gamepad Binding:
118 | key = XB_START
119 | ; Keyboard Binding:
120 | key = SHIFT ALT X
121 | ; Mouse Binding:
122 | key = VK_XBUTTON2
123 | ;------------------------------------------
124 | ; Input Configuration:
125 | type = hold
126 | $mouse_forward_state = 1
127 | run = CommandListHandleMouseForward
128 |
129 |
130 | ; Virtual Cursor Hotkeys -------------------------
131 |
132 | ; Action: Hide Virtual Cursor
133 | [KeyVirtualCursorHide]
134 | ; Xbox Gamepad Binding:
135 | ; Doesn't have much sense for gamepad tbh
136 | ; Keyboard Binding:
137 | key = SHIFT ALT A D
138 | key = SHIFT ALT W S
139 | ;------------------------------------------
140 | ; Input Configuration:
141 | run = CommandListHideVirtualCursor
142 |
143 |
144 | ; Action: Move Virtual Cursor in LEFT direction
145 | [KeyVirtualCursorLeft]
146 | ; Xbox Gamepad Binding:
147 | key = XB_DPAD_LEFT
148 | ; Keyboard Binding:
149 | key = SHIFT ALT A
150 | ;------------------------------------------
151 | ; Input Configuration:
152 | type = hold
153 | $arrow_left_state = 1
154 |
155 |
156 | ; Action: Move Virtual Cursor in RIGHT direction
157 | [KeyVirtualCursorRight]
158 | ; Xbox Gamepad Binding:
159 | key = XB_DPAD_RIGHT
160 | ; Keyboard Binding:
161 | key = SHIFT ALT D
162 | ;------------------------------------------
163 | ; Input Configuration:
164 | type = hold
165 | $arrow_right_state = 1
166 |
167 |
168 | ; Action: Move Virtual Cursor in UP direction
169 | [KeyVirtualCursorUp]
170 | ; Xbox Gamepad Binding:
171 | key = XB_DPAD_UP
172 | ; Keyboard Binding:
173 | key = SHIFT ALT W
174 | ;------------------------------------------
175 | ; Input Configuration:
176 | type = hold
177 | $arrow_top_state = 1
178 |
179 |
180 | ; Action: Move Virtual Cursor in DOWN direction
181 | [KeyVirtualCursorDown]
182 | ; Edit the line below to change key binding:
183 | key = XB_DPAD_DOWN
184 | ; Keyboard Binding:
185 | key = SHIFT ALT S
186 | ;------------------------------------------
187 | ; Input Configuration:
188 | type = hold
189 | $arrow_down_state = 1
190 |
191 |
192 |
193 | ;=================================================================================================
194 | ;= DO NOT EDIT THE CODE BELOW IF YOU'RE NOT SURE WHAT YOU'RE DOING!!!
195 | ;=================================================================================================
196 |
197 | ; Constants -------------------------
198 |
199 | [Constants]
200 | global $initialized = 0
201 |
202 | global $cursor_sensivity_x = 0
203 | global $cursor_sensivity_y = 0
204 |
205 | global $toggle_gui = 0
206 | global $mouse_left_state = 0
207 | global $mouse_left_counter = 1
208 | global $mouse_right_state = 0
209 | global $mouse_right_counter = 1
210 | global $mouse_mid_state = 0
211 | global $mouse_mid_counter = 1
212 | global $mouse_backward_state = 0
213 | global $mouse_backward_counter = 1
214 | global $mouse_forward_state = 0
215 | global $mouse_forward_counter = 1
216 |
217 | global $virtual_cursor_hide_cooldown = 0
218 | global $arrow_left_state = 0
219 | global $arrow_right_state = 0
220 | global $arrow_top_state = 0
221 | global $arrow_down_state = 0
222 |
223 |
224 | ; Present -------------------------
225 |
226 | [Present]
227 | ; Load configuration values
228 | if $initialized == 0
229 | $initialized = 1
230 | run = CommandListSetupConfiguration
231 | endif
232 |
233 | ; Update states of buttons in TileGUI.ini
234 | ; Button state is encoded in a following way:
235 | ; * Each button press increases counter's absolute value by 1
236 | ; * When button is DOWN (held aka pressed), counter value is positive
237 | ; * When button is UP (released), counter value is negative
238 | ; This way client .ini may easily detect:
239 | ; * Button state changes
240 | ; local $last_mouse_left_state
241 | ; if $last_mouse_left_state != $\TileGUI\mouse_left
242 | ; ; Do something if button state changed
243 | ; endif
244 | ; * Button state
245 | ; if $\TileGUI\mouse_left < 0
246 | ; ; Do something if button is UP
247 | ; else
248 | ; ; Do something if button is DOWN
249 | ; endif
250 | ; * Arbitrary amount of presses within timeframe (i.e. double clicks)
251 | ; local $first_press_time
252 | ; local $first_press_state
253 | ; local $abs_state = ($\TileGUI\mouse_left**2)**(1/2)
254 | ; if time - $first_press_time < 0.500
255 | ; if $abs_state - $first_press_state >= 1
256 | ; ; Do something if left mouse button was pressed 2 times within 500ms interval
257 | ; endif
258 | ; else
259 | ; $first_press_time = time
260 | ; $first_press_state = $abs_state
261 | ; endif
262 | local $prev_mouse_left_state
263 | if $mouse_left_state != $prev_mouse_left_state
264 | $prev_mouse_left_state = $mouse_left_state
265 | if $mouse_left_state == 0
266 | $\TileGUI\mouse_left = -$mouse_left_counter
267 | else
268 | $\TileGUI\mouse_left = $mouse_left_counter
269 | endif
270 | endif
271 | local $prev_mouse_right_state
272 | if $mouse_right_state != $prev_mouse_right_state
273 | $prev_mouse_right_state = $mouse_right_state
274 | if $mouse_right_state == 0
275 | $\TileGUI\mouse_right = -$mouse_right_counter
276 | else
277 | $\TileGUI\mouse_right = $mouse_right_counter
278 | endif
279 | endif
280 | local $prev_mouse_mid_state
281 | if $mouse_mid_state != $prev_mouse_mid_state
282 | $prev_mouse_mid_state = $mouse_mid_state
283 | if $mouse_mid_state == 0
284 | $\TileGUI\mouse_mid = -$mouse_mid_counter
285 | else
286 | $\TileGUI\mouse_mid = $mouse_mid_counter
287 | endif
288 | endif
289 | local $prev_mouse_forward_state
290 | if $mouse_forward_state != $prev_mouse_forward_state
291 | $prev_mouse_forward_state = $mouse_forward_state
292 | if $mouse_forward_state == 0
293 | $\TileGUI\mouse_forward = -$mouse_forward_counter
294 | else
295 | $\TileGUI\mouse_forward = $mouse_forward_counter
296 | endif
297 | endif
298 | local $prev_mouse_backward_state
299 | if $mouse_backward_state != $prev_mouse_backward_state
300 | $prev_mouse_backward_state = $mouse_backward_state
301 | if $mouse_backward_state == 0
302 | $\TileGUI\mouse_backward = -$mouse_backward_counter
303 | else
304 | $\TileGUI\mouse_backward = $mouse_backward_counter
305 | endif
306 | endif
307 | local $prev_toggle_gui
308 | if $toggle_gui != $prev_toggle_gui
309 | $prev_toggle_gui = $toggle_gui
310 | $\TileGUI\toggle_gui = $toggle_gui
311 | endif
312 |
313 |
314 | ; Update Virtual Cursor coords in TileGUI.ini based on pressed arrow buttons
315 | if time > $virtual_cursor_hide_cooldown
316 | if $arrow_left_state == 1
317 | $\TileGUI\virtual_cursor_x = $\TileGUI\virtual_cursor_x - 10 * $cursor_sensivity_x
318 | endif
319 | if $arrow_right_state == 1
320 | $\TileGUI\virtual_cursor_x = $\TileGUI\virtual_cursor_x + 10 * $cursor_sensivity_x
321 | endif
322 | if $arrow_top_state == 1
323 | $\TileGUI\virtual_cursor_y = $\TileGUI\virtual_cursor_y + 10 * $cursor_sensivity_y
324 | endif
325 | if $arrow_down_state == 1
326 | $\TileGUI\virtual_cursor_y = $\TileGUI\virtual_cursor_y - 10 * $cursor_sensivity_y
327 | endif
328 | endif
329 |
330 |
331 | ; Button Handlers -------------------------
332 |
333 | [CommandListHandleMouseLeft]
334 | $mouse_left_counter = $mouse_left_counter + 1
335 |
336 |
337 | [CommandListHandleMouseRight]
338 | $mouse_right_counter = $mouse_right_counter + 1
339 |
340 |
341 | [CommandListHandleMouseMid]
342 | $mouse_mid_counter = $mouse_mid_counter + 1
343 |
344 |
345 | [CommandListHandleMouseBackward]
346 | $mouse_backward_counter = $mouse_backward_counter + 1
347 |
348 |
349 | [CommandListHandleMouseForward]
350 | $mouse_forward_counter = $mouse_forward_counter + 1
351 |
352 |
353 | [CommandListHideVirtualCursor]
354 | $virtual_cursor_hide_cooldown = time + 1
355 | $\TileGUI\virtual_cursor_x = -1
356 | $\TileGUI\virtual_cursor_y = -1
357 |
358 |
359 | ; EOF -------------------------
360 |
--------------------------------------------------------------------------------