Brush editing#860
Draft
andybak wants to merge 170 commits into
Draft
Conversation
[CI BUILD]
This change adds a new folder into the Open Brush user folder called 'Brushes'. The user can add a subfolder with some files in to create a new brush. Currently the files needed are: Brush.cfg - a JSON file with Name, Guid, and VariantOf icon.png/jpg Also supported are: main.png/jpg normal.png.jpg
Flag VARIANT_BRUSHES turns off brush panel atlasing.
This is so that we can use AtomicWriter for other files int the future.
This updates the metadata schema version to 3. The schema now has a FallbackBrushIndex guid array that stores the guid of the built-in brush that should be used if the requested brush cannot be found. In the case the brush can't be found, a new brush descriptor is created by duplicating the descriptor of the fallback brush and changing its guid to match the missing brush. In this way the scene can be saved out again without the strokes of the missing brush being affected.
Currently the entire brush source data is being saved on load. I'm not sure if we want to keep it this way, but it works for the time being.
Does not yet work with Google Drive and Poly sketches. Also there is nothing to cope with brushes that are duplicated in sketches and in the brushes directory. I'm not happy with the weird split between FileOrZip and AtomicWriter, but it works for now. Some more thought required, perhaps.
FileOrZip was misnamed! A zip *is* a file!
Brushes that are loaded with a scene will only get retained while that scene is open. trashing a scene or loading a new one will drop them. If a dropped brush is selected at the time it is dropped, it will be switched with the default brush.
Almost all fields from brush Descriptor can now be set on UserVariantBrush from Brush.cfg.
I had overridded Equals, so I needed to override Hashcode as well.
Currently just standard manifest ones. Does not export Materials yet.
... when exporting brush descriptors. Also include the exported brush data. This will be used for creating new user brushes.
Authors can add copy restrictions that determines whether a brush can be shared or not.
* Changes serialization of copyrestrictions from integer to string * Uses actual json rather than string manipulation to create brushes. * Puts default values of the brush into 'Original' subsection. * Sets the GUID correctly in the exported brushes. * Sets author of all exported brushes to 'Open Brush'. * Re-exports all brushes.
# Conflicts: # Assets/Prefabs/Panels/LabsPanel.prefab # Assets/Resources/Brushes/Basic/Bubbles/Bubbles.shader # Assets/Resources/Brushes/Basic/CelVinyl/CelVinyl.shader # Assets/Resources/Brushes/Basic/ChromaticWave/ChromaticWave.shader # Assets/Resources/Brushes/Basic/Comet/Comet.shader # Assets/Resources/Brushes/Basic/DanceFloor/DanceFloor.shader # Assets/Resources/Brushes/Basic/Dots/Dots.shader # Assets/Resources/Brushes/Basic/DoubleTaperedMarker/DoubleTaperedMarker.shader # Assets/Resources/Brushes/Basic/DuctTape/normal.png.meta # Assets/Resources/Brushes/Basic/Electricity/Electricity.shader # Assets/Resources/Brushes/Basic/Embers/Embers.shader # Assets/Resources/Brushes/Basic/Felt/normal.png.meta # Assets/Resources/Brushes/Basic/Fire/Fire.shader # Assets/Resources/Brushes/Basic/Highlighter/AdditiveCutout.shader # Assets/Resources/Brushes/Basic/HyperGrid/HyperGrid.shader # Assets/Resources/Brushes/Basic/Hypercolor/normal.png.meta # Assets/Resources/Brushes/Basic/Icing/normal.png.meta # Assets/Resources/Brushes/Basic/Ink/maintexture_normal.png.meta # Assets/Resources/Brushes/Basic/Leaves/normal.png.meta # Assets/Resources/Brushes/Basic/OilPaint/normal.png.meta # Assets/Resources/Brushes/Basic/Paper/bump.png.meta # Assets/Resources/Brushes/Basic/Plasma/Plasma.shader # Assets/Resources/Brushes/Basic/Rainbow/Rainbow.shader # Assets/Resources/Brushes/Basic/Smoke/Smoke.shader # Assets/Resources/Brushes/Basic/Snow/Snow.shader # Assets/Resources/Brushes/Basic/SoftHighlighter/SoftHighlighter.shader # Assets/Resources/Brushes/Basic/Stars/Stars.shader # Assets/Resources/Brushes/Basic/Streamers/Streamers.shader # Assets/Resources/Brushes/Basic/ThickPaint/streakystroke_bump.png.meta # Assets/Resources/Brushes/Basic/Toon/Toon.shader # Assets/Resources/Brushes/Basic/TubeToonInverted/TubeToonInverted.shader # Assets/Resources/Brushes/Basic/VelvetInk/VelvetInk.shader # Assets/Resources/Brushes/Basic/Waveform/Waveform.shader # Assets/Resources/Brushes/Basic/WaveformFFT/WaveformFFT.shader # Assets/Resources/Brushes/Basic/WaveformParticles/WaveformParticles.shader # Assets/Resources/Brushes/Basic/WaveformTube/WaveformTube.shader # Assets/Resources/Brushes/Basic/WetPaint/normal.png.meta # Assets/Resources/Brushes/Basic/Wireframe/Wireframe.shader # Assets/Resources/Brushes/Shared/Shaders/Additive.shader # Assets/Resources/Brushes/Shared/Shaders/Bloom.shader # Assets/Resources/Brushes/Shared/Shaders/Multiplicative.shader # Assets/Resources/Brushes/Shared/Shaders/Special/Faceted.shader # Assets/Resources/Brushes/Shared/Shaders/Unlit.shader # Assets/Resources/X/Brushes/Charcoal/normal.png.meta # Assets/Resources/X/Brushes/Digital/Digital.shader # Assets/Resources/X/Brushes/Drafting/Drafting.shader # Assets/Resources/X/Brushes/DryBrush/normal.jpg.meta # Assets/Resources/X/Brushes/Fairy/Fairy.shader # Assets/Resources/X/Brushes/Fire 2/Fire2.shader # Assets/Resources/X/Brushes/Gouache/normal.png.meta # Assets/Resources/X/Brushes/Guts/normal.png.meta # Assets/Resources/X/Brushes/Lacewing/normal.png.meta # Assets/Resources/X/Brushes/MarbledRainbow/normal.png.meta # Assets/Resources/X/Brushes/Muscle/muscle_normal.png.meta # Assets/Resources/X/Brushes/Race/Race.shader # Assets/Resources/X/Brushes/Rain/Rain.shader # Assets/Resources/X/Brushes/RisingBubbles/RisingBubbles.shader # Assets/Resources/X/Brushes/Slice/Slice.shader # Assets/Resources/X/Brushes/Space/Space.shader # Assets/Resources/X/Brushes/Sparks/Sparks.shader # Assets/Resources/X/Brushes/Square/normal.png.meta # Assets/Resources/X/Brushes/TaperedHueShift/TaperedHueShift.shader # Assets/Resources/X/Brushes/WatercolorPaper/normal.png.meta # Assets/Resources/X/Brushes/Wind/Wind.shader # Assets/Shaders/FlatLit.shader # Assets/Shaders/Include/Particles.cginc
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces end-to-end support for editing/using “user variant” brushes, including new exported brush property definitions, UI components for brush editing, and save/load pipeline changes to embed custom brushes in .tilt files (plus fallback brush GUID support for missing brushes on load).
Changes:
- Added a large set of exported brush property JSON files under
Support/Brushes/ExportedProperties/and auserbrush.pyhelper to create variant brush configs. - Extended save/load format to include
FallbackBrushIndexin metadata and embed user brush data inside the.tiltcontainer; introduced shared zip/folder IO utilities (AtomicWriter,FolderOrZipReader). - Added/updated UI plumbing for brush editing and brush-library indicators.
Reviewed changes
Copilot reviewed 104 out of 118 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| Support/Brushes/ExportedProperties/Wire.txt | Adds exported properties definition for Wire brush. |
| Support/Brushes/ExportedProperties/WigglyGraphite.txt | Adds exported properties definition for WigglyGraphite brush. |
| Support/Brushes/ExportedProperties/WetPaint.txt | Adds exported properties definition for WetPaint brush. |
| Support/Brushes/ExportedProperties/Waveform.txt | Adds exported properties definition for Waveform brush. |
| Support/Brushes/ExportedProperties/VelvetInk.txt | Adds exported properties definition for VelvetInk brush. |
| Support/Brushes/ExportedProperties/UnlitHull.txt | Adds exported properties definition for UnlitHull brush. |
| Support/Brushes/ExportedProperties/Toon.txt | Adds exported properties definition for Toon brush. |
| Support/Brushes/ExportedProperties/ThickPaint.txt | Adds exported properties definition for ThickPaint brush. |
| Support/Brushes/ExportedProperties/TaperedMarker.txt | Adds exported properties definition for TaperedMarker brush. |
| Support/Brushes/ExportedProperties/TaperedFlat.txt | Adds exported properties definition for TaperedFlat brush. |
| Support/Brushes/ExportedProperties/Streamers.txt | Adds exported properties definition for Streamers brush. |
| Support/Brushes/ExportedProperties/Stars.txt | Adds exported properties definition for Stars brush. |
| Support/Brushes/ExportedProperties/Splatter.txt | Adds exported properties definition for Splatter brush. |
| Support/Brushes/ExportedProperties/Spikes.txt | Adds exported properties definition for Spikes brush. |
| Support/Brushes/ExportedProperties/SoftHighlighter.txt | Adds exported properties definition for SoftHighlighter brush. |
| Support/Brushes/ExportedProperties/Snow.txt | Adds exported properties definition for Snow brush. |
| Support/Brushes/ExportedProperties/Smoke.txt | Adds exported properties definition for Smoke brush. |
| Support/Brushes/ExportedProperties/ShinyHull.txt | Adds exported properties definition for ShinyHull brush. |
| Support/Brushes/ExportedProperties/Rainbow.txt | Adds exported properties definition for Rainbow brush. |
| Support/Brushes/ExportedProperties/Petal.txt | Adds exported properties definition for Petal brush. |
| Support/Brushes/ExportedProperties/Paper.txt | Adds exported properties definition for Paper brush. |
| Support/Brushes/ExportedProperties/OilPaint.txt | Adds exported properties definition for OilPaint brush. |
| Support/Brushes/ExportedProperties/NeonPulse.txt | Adds exported properties definition for NeonPulse brush. |
| Support/Brushes/ExportedProperties/MatteHull.txt | Adds exported properties definition for MatteHull brush. |
| Support/Brushes/ExportedProperties/Marker.txt | Adds exported properties definition for Marker brush. |
| Support/Brushes/ExportedProperties/Lofted.txt | Adds exported properties definition for Lofted brush. |
| Support/Brushes/ExportedProperties/LightWire.txt | Adds exported properties definition for LightWire brush. |
| Support/Brushes/ExportedProperties/Light.txt | Adds exported properties definition for Light brush. |
| Support/Brushes/ExportedProperties/Ink.txt | Adds exported properties definition for Ink brush. |
| Support/Brushes/ExportedProperties/Icing.txt | Adds exported properties definition for Icing brush. |
| Support/Brushes/ExportedProperties/HyperGrid.txt | Adds exported properties definition for HyperGrid brush. |
| Support/Brushes/ExportedProperties/Hypercolor.txt | Adds exported properties definition for Hypercolor brush. |
| Support/Brushes/ExportedProperties/Highlighter.txt | Adds exported properties definition for Highlighter brush. |
| Support/Brushes/ExportedProperties/Flat.txt | Adds exported properties definition for Flat brush. |
| Support/Brushes/ExportedProperties/Fire.txt | Adds exported properties definition for Fire brush. |
| Support/Brushes/ExportedProperties/Embers.txt | Adds exported properties definition for Embers brush. |
| Support/Brushes/ExportedProperties/Electricity.txt | Adds exported properties definition for Electricity brush. |
| Support/Brushes/ExportedProperties/DuctTape.txt | Adds exported properties definition for DuctTape brush. |
| Support/Brushes/ExportedProperties/DoubleTaperedMarker.txt | Adds exported properties definition for DoubleTaperedMarker brush. |
| Support/Brushes/ExportedProperties/DoubleTaperedFlat.txt | Adds exported properties definition for DoubleTaperedFlat brush. |
| Support/Brushes/ExportedProperties/Dots.txt | Adds exported properties definition for Dots brush. |
| Support/Brushes/ExportedProperties/Disco.txt | Adds exported properties definition for Disco brush. |
| Support/Brushes/ExportedProperties/DiamondHull.txt | Adds exported properties definition for DiamondHull brush. |
| Support/Brushes/ExportedProperties/Comet.txt | Adds exported properties definition for Comet brush. |
| Support/Brushes/ExportedProperties/CoarseBristles.txt | Adds exported properties definition for CoarseBristles brush. |
| Support/Brushes/ExportedProperties/ChromaticWave.txt | Adds exported properties definition for ChromaticWave brush. |
| Support/Brushes/ExportedProperties/CelVinyl.txt | Adds exported properties definition for CelVinyl brush. |
| Support/Brushes/ExportedProperties/Bubbles.txt | Adds exported properties definition for Bubbles brush. |
| Support/bin/userbrush.py | Adds a CLI utility to list/analyze/create user brush configs from exported properties. |
| Assets/Scripts/Util/SerializableGuid.cs | Extends SerializableGuid with constructors/operators and overrides. |
| Assets/Scripts/TiltBrushManifest.cs | Minor imports/formatting; maintains brush GUID export support. |
| Assets/Scripts/SketchMemoryScript.cs | Adds repaint filtering/silent mode for sketch rebuild coroutine. |
| Assets/Scripts/Sharing/IcosaSketchSet.cs | Adds GetContentsAt stub to satisfy SceneFileInfo interface. |
| Assets/Scripts/Sharing/GoogleDriveSketchSet.cs | Tracks cached vs original file paths; forwards GetContentsAt to TiltFile. |
| Assets/Scripts/Save/TiltFile.cs | Refactors to inherit FolderOrZipReader; uses TiltAtomicWriter and adds GetContentsAt override. |
| Assets/Scripts/Save/SketchWriter.cs | Adds fallback brush GUID list output when writing sketches. |
| Assets/Scripts/Save/SketchSnapshot.cs | Writes fallback brush GUID metadata and embeds user brushes into saved .tilt. |
| Assets/Scripts/Save/SketchMetadata.cs | Bumps schema version and adds FallbackBrushIndex field/documentation. |
| Assets/Scripts/Save/SceneFileInfo.cs | Adds GetContentsAt to SceneFileInfo interface. |
| Assets/Scripts/Save/SaveLoadScript.cs | Loads embedded brushes from .tilt and creates fallback brushes when missing. |
| Assets/Scripts/Save/MetadataUtils.cs | Adds schema upgrade path 2→3 for fallback brush indices. |
| Assets/Scripts/Save/FolderOrZipReader.cs.meta | Unity meta for new FolderOrZipReader. |
| Assets/Scripts/Save/FolderOrZipReader.cs | New zip/folder reader abstraction with GetReadStream/GetContentsAt. |
| Assets/Scripts/Save/DiskSceneFileInfo.cs | Implements GetContentsAt by delegating to TiltFile. |
| Assets/Scripts/Save/AtomicWriter.cs.meta | Unity meta for new AtomicWriter. |
| Assets/Scripts/Save/AtomicWriter.cs | New shared atomic writer (zip/folder) base used by TiltFile writer. |
| Assets/Scripts/JsonGlue.cs | Extends JSON writer/converter to support nullable Unity types and float[]. |
| Assets/Scripts/GUI/EditBrushSlider.cs.meta | Unity meta for new EditBrushSlider component. |
| Assets/Scripts/GUI/EditBrushSlider.cs | New slider widget for editing brush float/vector material properties. |
| Assets/Scripts/GUI/EditBrushPanel.cs.meta | Unity meta for EditBrush panel. |
| Assets/Scripts/GUI/EditBrushEditorTextureButton.cs.meta | Unity meta for texture icon button. |
| Assets/Scripts/GUI/EditBrushEditorTextureButton.cs | New texture selection icon button for brush editor popup. |
| Assets/Scripts/GUI/BrushTypeButton.cs | Adds library/experimental brush type icon support. |
| Assets/Scripts/GUI/BrushGrid.cs | Adds helper to jump to the page containing a particular brush. |
| Assets/Scripts/GUI/BrushEditorTexturePopUpWindow.cs.meta | Unity meta for texture picker popup window. |
| Assets/Scripts/GUI/BrushEditorTexturePopUpWindow.cs | New paging popup window for choosing brush textures. |
| Assets/Scripts/GUI/BrushEditorTexturePickerButton.cs.meta | Unity meta for texture picker opener button. |
| Assets/Scripts/GUI/BrushEditorTexturePickerButton.cs | New option button to open texture picker popup and apply selection. |
| Assets/Scripts/GUI/BrushEditorColorPickerButton.cs.meta | Unity meta for color picker opener button. |
| Assets/Scripts/GUI/BrushEditorColorPickerButton.cs | New option button to open color picker and apply brush color properties. |
| Assets/Scripts/GUI/BasePanel.cs | Adds new panel type enum entry for EditBrush panel. |
| Assets/Scripts/FileWatcher.cs | Adds includeSubdirectories parameter to FileWatcher constructors. |
| Assets/Scripts/DevOptions.cs | Switches preferred tilt format enum to AtomicWriter.SaveFormat. |
| Assets/Scripts/Brushes/UserVariantBrush.cs.meta | Unity meta for UserVariantBrush implementation. |
| Assets/Scripts/Brushes/BrushDescriptor.cs | Adds BaseGuid/UserVariantBrush hooks and description override support. |
| Assets/Scripts/BrushController.cs | Ensures active brush falls back to default when catalog changes remove it. |
| Assets/Scripts/App.cs | Adds UserBrushesPath() helper. |
| Assets/Scenes/Main.unity | Registers EditBrush panel prefab in the main scene configuration. |
| Assets/Resources/Icons/reference_transparent.png.meta | Adds meta for icon asset used by the new LibraryIcon material. |
| Assets/Prefabs/UIComponents/EditBrushEditorTextureIcon.prefab.meta | Unity meta for new prefab. |
| Assets/Prefabs/UIComponents/EditBrushEditorTextureIcon.prefab | New UI prefab for texture icon entries in brush editor popup. |
| Assets/Prefabs/UIComponents/BrushEditorTexturePickerButton.prefab.meta | Unity meta for new prefab. |
| Assets/Prefabs/UIComponents/BrushEditorTexturePickerButton.prefab | New UI prefab for opening texture picker popup. |
| Assets/Prefabs/UIComponents/BrushEditorColorPickerButton.prefab.meta | Unity meta for new prefab. |
| Assets/Prefabs/UIComponents/BrushEditorColorPickerButton.prefab | New UI prefab for opening color picker popup. |
| Assets/Prefabs/PopUps/PopUpWindow_TexturePicker.prefab.meta | Unity meta for new popup prefab. |
| Assets/Prefabs/Panels/Widgets/EditBrushSlider.prefab.meta | Unity meta for EditBrush slider widget prefab. |
| Assets/Prefabs/Panels/Widgets/BrushButton.prefab.meta | Unity meta updates for brush button prefab (supports new icon material usage). |
| Assets/Prefabs/Panels/EditBrushPanel.prefab.meta | Unity meta for EditBrush panel prefab. |
| Assets/Materials/LibraryIcon.mat.meta | Unity meta for new LibraryIcon material. |
| Assets/Materials/LibraryIcon.mat | New material used to render the “library brush” icon. |
| Assets/Editor/GlTF_EditorExporter.cs | Includes user variant brushes in editor glTF export brush catalog. |
| Assets/Editor/BrushLister.cs | Adds editor menu item to check brush textures for read/write settings. |
Files not reviewed (9)
- Assets/Materials/LibraryIcon.mat.meta: Language not supported
- Assets/Prefabs/Panels/EditBrushPanel.prefab.meta: Language not supported
- Assets/Prefabs/Panels/Widgets/BrushButton.prefab.meta: Language not supported
- Assets/Prefabs/Panels/Widgets/EditBrushSlider.prefab.meta: Language not supported
- Assets/Prefabs/PopUps/PopUpWindow_TexturePicker.prefab.meta: Language not supported
- Assets/Prefabs/UIComponents/BrushEditorColorPickerButton.prefab.meta: Language not supported
- Assets/Prefabs/UIComponents/BrushEditorTexturePickerButton.prefab.meta: Language not supported
- Assets/Prefabs/UIComponents/EditBrushEditorTextureIcon.prefab.meta: Language not supported
- Assets/Resources/Icons/reference_transparent.png.meta: Language not supported
Comments suppressed due to low confidence (1)
Assets/Scripts/JsonGlue.cs:228
- ReadJson() doesn't handle float[] but CustomJsonContractResolver now assigns this converter to float[] (and WriteJson supports it). This will throw during deserialization of types like UserVariantBrush properties (which include float[] values). Add a float[] branch (or stop assigning this converter to float[]).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+80
to
+83
| public override int GetHashCode() | ||
| { | ||
| return m_storage.GetHashCode(); | ||
| } |
Comment on lines
+927
to
930
| Stroke stroke = node.Value; | ||
| if (brushesToRepaint != null && brushesToRepaint.Contains(stroke.m_BrushGuid.ToString())) continue; | ||
| if (stroke.m_Type == Stroke.Type.BatchedBrushStroke) | ||
| { |
Comment on lines
+134
to
+138
| virtual public IEnumerable<string> GetContentsAt(string path) | ||
| { | ||
| if (m_IsFile) | ||
| { | ||
| var entries = new HashSet<string>(); |
Comment on lines
+117
to
+134
| public override bool Equals(object obj) | ||
| { | ||
| if (obj == null) | ||
| { | ||
| return false; | ||
| } | ||
| return m_storage.Equals(obj.ToString()); | ||
| } | ||
|
|
||
| public static bool operator ==(SerializableGuid lhs, SerializableGuid rhs) | ||
| { | ||
| return lhs.Equals(rhs); | ||
| } | ||
|
|
||
| public static bool operator !=(SerializableGuid lhs, SerializableGuid rhs) | ||
| { | ||
| return !lhs.Equals(rhs); | ||
| } |
Comment on lines
+114
to
+122
| if (m_IsFile) | ||
| { | ||
| string filenameLower = Path.Combine(m_subfolder, filename).ToLowerInvariant(); | ||
| if (!m_ZipEntryMap.ContainsKey(filenameLower)) | ||
| { | ||
| return null; | ||
| } | ||
| return new ZipSubfileReader(m_RootPath, m_ZipEntryMap[filenameLower]); | ||
| } |
Comment on lines
+534
to
+541
| public void GotoPageForBrush(BrushDescriptor brush) | ||
| { | ||
| int brushIndex = Array.FindIndex(m_TagFilteredBrushes, b => b.m_Guid == brush.m_Guid); | ||
| int page = Mathf.FloorToInt(brushIndex / m_BrushButtons.Length); | ||
| m_PageIndex = Mathf.Clamp(0, page, m_NumPages - 1); | ||
| m_RequestedPageIndex = m_PageIndex; | ||
| RefreshButtonPositions(); | ||
| } |
Comment on lines
+29
to
33
| public FileWatcher(string path, bool includeSubdirectories = false) | ||
| { | ||
| if (App.PlatformConfig.UseFileSystemWatcher) | ||
| { | ||
| m_InternalFileWatcher = new FileSystemWatcher(path); |
Comment on lines
220
to
224
| if (!brushMap.TryGetValue(brushGuid, out brushIndex)) | ||
| { | ||
| brushIndex = brushList.Count; | ||
| brushMap[brushGuid] = brushIndex; | ||
| brushList.Add(brushGuid); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.