Skip to content

Commit b9f8c41

Browse files
committed
Adds member search and better architecture.
1 parent 6b904f3 commit b9f8c41

File tree

9 files changed

+299
-155
lines changed

9 files changed

+299
-155
lines changed

Stride.ShaderExplorer/AdditionalPathsWindow.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private void OnClearAllClick(object sender, RoutedEventArgs e)
6262
private void OnDetectVvvvPathsClick(object sender, RoutedEventArgs e)
6363
{
6464
var mvm = (MainViewModel)DataContext;
65-
var detectedPaths = mvm.DetectVvvvShaderPaths();
65+
var detectedPaths = VvvvPathResolver.Instance.GetVLStrideShaderPaths();
6666

6767
if (detectedPaths.Count == 0)
6868
{

Stride.ShaderExplorer/App.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
FalseBrush="#33d4d4d4"
1212
TrueBrush="#d4d4d4" />
1313

14+
<local:SearchModeConverter x:Key="SearchModeConverter" />
15+
1416
<Style TargetType="Button">
1517
<Setter Property="Background" Value="#FF900520" />
1618
<Setter Property="Foreground" Value="#d4d4d4" />

Stride.ShaderExplorer/MainViewModel.cs

Lines changed: 66 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
using CommunityToolkit.Mvvm.ComponentModel;
2-
using Stride.Core.Shaders.Ast;
3-
using Stride.ShaderParser;
42
using System;
53
using System.Collections.Generic;
6-
using System.Diagnostics;
74
using System.IO;
85
using System.Linq;
96
using System.Text.Json;
10-
using System.Text.RegularExpressions;
117
using System.Windows;
128

139
namespace StrideShaderExplorer
@@ -18,15 +14,24 @@ public enum StrideSourceDirMode
1814
Dev
1915
}
2016

17+
public enum SearchMode
18+
{
19+
FilesAndMembers,
20+
FilenameOnly,
21+
MembersOnly
22+
}
23+
2124
public class MainViewModel : ObservableRecipient
2225
{
2326
private const string StrideEnvironmentVariable = "StrideDir";
2427
private const string NugetEnvironmentVariable = "NUGET_PACKAGES";
2528

2629
private readonly NuGetDownloader _nugetDownloader = new();
30+
private readonly ShaderRepository _shaderRepository = new();
31+
private readonly ShaderTreeBuilder _shaderTreeBuilder;
2732

2833
private string _filterText;
29-
private bool _directParentsOnly = true;
34+
private SearchMode _searchMode = SearchMode.FilesAndMembers;
3035
private ShaderViewModel _selectedShader;
3136
private IReadOnlyList<string> _paths;
3237

@@ -36,53 +41,11 @@ public List<string> AdditionalPaths
3641
set;
3742
}
3843

39-
public Dictionary<string, ShaderViewModel> shaders = new Dictionary<string, ShaderViewModel>();
40-
public Dictionary<string, Dictionary<ShaderViewModel, MemberList>> members = new Dictionary<string, Dictionary<ShaderViewModel, MemberList>>();
41-
public Dictionary<string, ShaderViewModel> ShaderMap => shaders;
44+
public IReadOnlyDictionary<string, ShaderViewModel> ShaderMap => _shaderRepository.Shaders;
4245

4346
public bool FindMember(string name, ShaderViewModel shader, out MemberList mems, out List<ShaderViewModel> scopedShaders)
4447
{
45-
mems = null;
46-
scopedShaders = null;
47-
var result = members.TryGetValue(name, out var memberCandidates);
48-
49-
if (result)
50-
{
51-
// defined locally?
52-
if (memberCandidates.TryGetValue(shader, out mems))
53-
{
54-
55-
}
56-
57-
//find base shaders that defines the member, could be multiple for method overrides
58-
scopedShaders = new List<ShaderViewModel>();
59-
var definingShader = shader;
60-
foreach (var baseShader in shader.BaseShaders)
61-
{
62-
63-
if (memberCandidates.TryGetValue(baseShader, out var ms))
64-
{
65-
//find highest definition in hierarchy
66-
if (definingShader.BaseShaders.Contains(baseShader))
67-
{
68-
mems = ms;
69-
}
70-
71-
scopedShaders.Add(baseShader);
72-
}
73-
}
74-
75-
//also add derived shaders
76-
foreach (var derivedShader in shader.DerivedShaders)
77-
{
78-
if (memberCandidates.TryGetValue(derivedShader, out var _))
79-
{
80-
scopedShaders.Add(derivedShader);
81-
}
82-
}
83-
}
84-
85-
return result;
48+
return _shaderRepository.FindMember(name, shader, out mems, out scopedShaders);
8649
}
8750

8851
/// <summary>
@@ -106,13 +69,29 @@ public string FilterText
10669
}
10770
}
10871

72+
public SearchMode SearchMode
73+
{
74+
get { return _searchMode; }
75+
set
76+
{
77+
if (SetProperty(ref _searchMode, value))
78+
UpdateFiltering();
79+
}
80+
}
81+
82+
public IEnumerable<SearchMode> SearchModeOptions => Enum.GetValues<SearchMode>();
83+
10984
public bool DirectParentsOnly
11085
{
111-
get { return _directParentsOnly; }
86+
get { return _shaderTreeBuilder.DirectParentsOnly; }
11287
set
11388
{
114-
if (SetProperty(ref _directParentsOnly, value))
89+
if (_shaderTreeBuilder.DirectParentsOnly != value)
90+
{
91+
_shaderTreeBuilder.DirectParentsOnly = value;
92+
OnPropertyChanged();
11593
Refresh();
94+
}
11695
}
11796
}
11897

@@ -182,7 +161,7 @@ internal void Refresh()
182161
// If no Stride packages found in nuget, try vvvv's packs folder
183162
if (paths.Count == 0)
184163
{
185-
var vvvvPaths = DetectVvvvStridePackages();
164+
var vvvvPaths = VvvvPathResolver.Instance.GetStridePackagePaths();
186165
if (vvvvPaths.Count > 0)
187166
paths = vvvvPaths;
188167
}
@@ -276,7 +255,7 @@ public IReadOnlyList<string> Paths
276255
{
277256
try
278257
{
279-
RootShaders = BuildShaderTree().OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase).ToList();
258+
RootShaders = _shaderTreeBuilder.BuildTree(value);
280259
OnPropertyChanged(nameof(RootShaders));
281260
OnPropertyChanged(nameof(AllShaders));
282261
UpdateFiltering();
@@ -294,12 +273,14 @@ public IReadOnlyList<string> Paths
294273

295274
public MainViewModel()
296275
{
276+
_shaderTreeBuilder = new ShaderTreeBuilder(_shaderRepository);
277+
297278
AdditionalPaths = Properties.UserSettings.Default.AdditionalPaths.Split(';').ToList();
298279

299280
// Auto-detect vvvv paths on first run
300281
if (!Properties.UserSettings.Default.VvvvPathsDetected)
301282
{
302-
var vvvvPaths = DetectVvvvShaderPaths();
283+
var vvvvPaths = VvvvPathResolver.Instance.GetVLStrideShaderPaths();
303284
foreach (var path in vvvvPaths)
304285
{
305286
if (!AdditionalPaths.Contains(path))
@@ -349,22 +330,12 @@ private bool DownloadStridePackages()
349330
return false;
350331
}
351332

352-
private List<string> DetectVvvvStridePackages()
353-
{
354-
return VvvvPathResolver.Instance.GetStridePackagePaths();
355-
}
356-
357-
public List<string> DetectVvvvShaderPaths()
358-
{
359-
return VvvvPathResolver.Instance.GetVLStrideShaderPaths();
360-
}
361-
362333
public void ExportShaderHierarchy(string filePath)
363334
{
364335
var export = new HierarchyExport
365336
{
366337
ExportedAt = DateTime.Now.ToString("o"),
367-
ShaderCount = shaders.Count,
338+
ShaderCount = _shaderRepository.Count,
368339
RootShaders = RootShaders.Select(ShaderToExport).ToList()
369340
};
370341

@@ -394,9 +365,36 @@ private void UpdateFiltering()
394365
{
395366
foreach (var shader in AllShaders)
396367
{
397-
shader.IsVisible = string.IsNullOrEmpty(_filterText) ||
398-
shader.Name.ToLower().Contains(_filterText.ToLower());
399-
shader.IsExpanded = shader.DerivedShaders.Any(o => o.IsVisible);
368+
if (string.IsNullOrEmpty(_filterText))
369+
{
370+
shader.IsVisible = true;
371+
// Don't change IsExpanded when filter is empty
372+
}
373+
else
374+
{
375+
var lowerFilter = _filterText.ToLower();
376+
bool matchesName = shader.Name.ToLower().Contains(lowerFilter);
377+
bool matchesMember = false;
378+
379+
if (_searchMode != SearchMode.FilenameOnly && shader.ParsedShader != null)
380+
{
381+
matchesMember = shader.ParsedShader.Variables?.Any(v =>
382+
v.Name?.Text?.ToLower().Contains(lowerFilter) == true) == true ||
383+
shader.ParsedShader.Methods?.Any(m =>
384+
m.Name?.Text?.ToLower().Contains(lowerFilter) == true) == true;
385+
}
386+
387+
shader.IsVisible = _searchMode switch
388+
{
389+
SearchMode.FilesAndMembers => matchesName || matchesMember,
390+
SearchMode.FilenameOnly => matchesName,
391+
SearchMode.MembersOnly => matchesMember,
392+
_ => matchesName || matchesMember
393+
};
394+
395+
// Auto-expand parents of visible items only when filtering
396+
shader.IsExpanded = shader.DerivedShaders.Any(o => o.IsVisible);
397+
}
400398
}
401399
}
402400

@@ -421,88 +419,6 @@ private static IEnumerable<ShaderViewModel> ShadersInPostOrder(ShaderViewModel s
421419
yield return shader;
422420
}
423421

424-
private IEnumerable<ShaderViewModel> BuildShaderTree()
425-
{
426-
var files = Paths.Where(p => !string.IsNullOrWhiteSpace(p) && Directory.Exists(p))
427-
.SelectMany(path => Directory.GetFiles(path, "*.sdsl", SearchOption.AllDirectories));
428-
429-
shaders.Clear();
430-
var duplicates = new Dictionary<string, ShaderViewModel>();
431-
432-
foreach (var file in files)
433-
{
434-
var name = Path.GetFileNameWithoutExtension(file);
435-
if(!shaders.ContainsKey(name))
436-
shaders[name] = new ShaderViewModel { Path = file, Name = name };
437-
else
438-
duplicates[name] = new ShaderViewModel { Path = file, Name = name };
439-
}
440-
441-
foreach (var shader in shaders.Values)
442-
{
443-
if (EffectUtils.TryParseEffect(shader.Name, shaders, out var parsedShader))
444-
{
445-
var baseShaderNames = parsedShader.BaseShaders.Select(s => s.ShaderClass.Name.Text).ToList();
446-
shader.ParsedShader = parsedShader;
447-
448-
// get all declrarations in this shader
449-
foreach (var m in parsedShader.ShaderClass.Members.OfType<IDeclaration>() ?? Enumerable.Empty<IDeclaration>())
450-
{
451-
var mn = m.Name.Text;
452-
if (string.IsNullOrWhiteSpace(mn))
453-
{
454-
continue;
455-
}
456-
457-
if (!members.TryGetValue(mn, out var memberCandidates))
458-
{
459-
memberCandidates = new Dictionary<ShaderViewModel, MemberList>();
460-
}
461-
462-
if (!memberCandidates.TryGetValue(shader, out var mems))
463-
{
464-
mems = new MemberList();
465-
}
466-
467-
mems.Add(new MemberViewModel(mn, m));
468-
469-
memberCandidates[shader] = mems;
470-
members[mn] = memberCandidates;
471-
}
472-
473-
if (baseShaderNames.Count > 0)
474-
{
475-
var baseShaders = baseShaderNames
476-
.Select(s => shaders.TryGetValue(s, out var b) ? b : null)
477-
.Where(s => s != null);
478-
479-
foreach (var baseShader in baseShaders)
480-
{
481-
shader.BaseShaders.Add(baseShader);
482-
baseShader.DerivedShaders.Add(shader);
483-
if (_directParentsOnly)
484-
{
485-
if (parsedShader.ShaderClass.BaseClasses.FirstOrDefault(bc => bc.Name.Text == baseShader.Name) != null)
486-
{
487-
baseShader.TreeViewChildren.Add(shader);
488-
}
489-
}
490-
else
491-
{
492-
baseShader.TreeViewChildren.Add(shader);
493-
}
494-
}
495-
}
496-
else
497-
{
498-
yield return shader;
499-
}
500-
}
501-
502-
}
503-
504-
Debug.WriteLine($"Found {shaders.Count} shaders");
505-
}
506422
}
507423

508424
public class ShaderExport

Stride.ShaderExplorer/MainWindow.xaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,22 @@
4343
Text="Filter list of shaders" />
4444
</local:WatermarkService.Watermark>
4545
</TextBox>
46+
<ComboBox
47+
Margin="2,0,2,0"
48+
ItemsSource="{Binding SearchModeOptions}"
49+
SelectedItem="{Binding SearchMode}"
50+
ToolTip="Filter search scope">
51+
<ComboBox.ItemTemplate>
52+
<DataTemplate>
53+
<TextBlock Text="{Binding Converter={StaticResource SearchModeConverter}}" />
54+
</DataTemplate>
55+
</ComboBox.ItemTemplate>
56+
</ComboBox>
4657
<CheckBox
4758
Margin="2,4,2,0"
4859
Content="Direct Parents Only"
49-
IsChecked="{Binding DirectParentsOnly}" />
60+
IsChecked="{Binding DirectParentsOnly}"
61+
ToolTip="When enabled, shaders appear only under their direct parent in the tree.&#x0a;When disabled, shaders appear under all inherited base classes." />
5062
<Rectangle
5163
Width="1"
5264
Margin="8,0"

Stride.ShaderExplorer/MainWindow.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ private void OnExportButtonClick(object sender, RoutedEventArgs e)
235235
try
236236
{
237237
ViewModel.ExportShaderHierarchy(dialog.FileName);
238-
MessageBox.Show($"Exported {ViewModel.shaders.Count} shaders to:\n{dialog.FileName}",
238+
MessageBox.Show($"Exported {ViewModel.ShaderMap.Count} shaders to:\n{dialog.FileName}",
239239
"Export Complete", MessageBoxButton.OK, MessageBoxImage.Information);
240240
}
241241
catch (Exception ex)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows.Data;
4+
5+
namespace StrideShaderExplorer
6+
{
7+
public class SearchModeConverter : IValueConverter
8+
{
9+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
10+
{
11+
if (value is SearchMode mode)
12+
{
13+
return mode switch
14+
{
15+
SearchMode.FilesAndMembers => "Files & Members",
16+
SearchMode.FilenameOnly => "Filename Only",
17+
SearchMode.MembersOnly => "Members Only",
18+
_ => value.ToString()
19+
};
20+
}
21+
return value?.ToString() ?? string.Empty;
22+
}
23+
24+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
25+
{
26+
throw new NotImplementedException();
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)