Skip to content

Brush editing#860

Draft
andybak wants to merge 170 commits into
mainfrom
features/brush-editing
Draft

Brush editing#860
andybak wants to merge 170 commits into
mainfrom
features/brush-editing

Conversation

@andybak

@andybak andybak commented May 29, 2025

Copy link
Copy Markdown
Contributor

No description provided.

andybak and others added 30 commits March 29, 2021 15:23
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.
andybak added 14 commits April 8, 2024 12:57
# 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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 a userbrush.py helper to create variant brush configs.
  • Extended save/load format to include FallbackBrushIndex in metadata and embed user brush data inside the .tilt container; 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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Feature added

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants