浏览代码

Remove `elements` from MaterialNodePresenter. Sub-presenters are accessed through independent properties now.

Much simpler to work with and also less garbage generation :)
/main
Peter Bay Bastian 7 年前
当前提交
693b0aa5
共有 33 个文件被更改,包括 87 次插入88 次删除
  1. 4
      MaterialGraphProject/Assets/NewNodes/Editor/BlendModeNodePresenter.cs
  2. 4
      MaterialGraphProject/Assets/NewNodes/Editor/ConstantsNodePresenter.cs
  3. 4
      MaterialGraphProject/Assets/NewNodes/Editor/ToggleNodePresenter.cs
  4. 4
      MaterialGraphProject/Assets/NewNodes/Editor/TransformNodePresenter.cs
  5. 8
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialGraphPresenter.cs
  6. 39
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialNodePresenter.cs
  7. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/ColorNodePresenter.cs
  8. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/CubemapNodePresenter.cs
  9. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/GradientNodePresenter.cs
  10. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/IfNodePresenter.cs
  11. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/LevelsNodePresenter.cs
  12. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/MasterNodePresenter.cs
  13. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Matrix2NodePresenter.cs
  14. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Matrix3NodePresenter.cs
  15. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Matrix4NodePresenter.cs
  16. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/MatrixCommonNodePresenter.cs
  17. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/RemapInputNodePresenter.cs
  18. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/RemapMasterNodePresenter.cs
  19. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SamplerStateNodePresenter.cs
  20. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SubgraphIONodePresenter.cs
  21. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SubgraphNodePresenter.cs
  22. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SurfaceMasterNodePresenter.cs
  23. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SwizzleNodePresenter.cs
  24. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/TextureAssetNodePresenter.cs
  25. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/TextureLODNodePresenter.cs
  26. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/TextureSamplerNodePresenter.cs
  27. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/UVNodePresenter.cs
  28. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector1NodePresenter.cs
  29. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector2NodePresenter.cs
  30. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector3NodePresenter.cs
  31. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector4NodePresenter.cs
  32. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/PropertyNodePresenter.cs
  33. 8
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialNodeView.cs

4
MaterialGraphProject/Assets/NewNodes/Editor/BlendModeNodePresenter.cs


[Serializable]
public class BlendModeNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/NewNodes/Editor/ConstantsNodePresenter.cs


[Serializable]
public class ConstantsNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/NewNodes/Editor/ToggleNodePresenter.cs


[Serializable]
public class ToggleNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/NewNodes/Editor/TransformNodePresenter.cs


[Serializable]
public class TransformNodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

8
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialGraphPresenter.cs


var baseNode = addedNode.node;
foreach (var slot in baseNode.GetOutputSlots<ISlot>())
{
var sourceAnchors = addedNode.elements.OfType<GraphAnchorPresenter>();
var sourceAnchors = addedNode.outputAnchors.OfType<GraphAnchorPresenter>();
var sourceAnchor = sourceAnchors.FirstOrDefault(x => x.slot == slot);
var edges = baseNode.owner.GetEdges(new SlotReference(baseNode.guid, slot.id));

var toSlot = toNode.FindInputSlot<ISlot>(edge.inputSlot.slotId);
var targetNode = addedNodes.FirstOrDefault(x => x.node == toNode);
var targetAnchors = targetNode.elements.OfType<GraphAnchorPresenter>();
var targetAnchors = targetNode.inputAnchors.OfType<GraphAnchorPresenter>();
var targetAnchor = targetAnchors.FirstOrDefault(x => x.slot == toSlot);
var edgeData = CreateInstance<GraphEdgePresenter>();

var fromNode = graphAsset.graph.GetNodeFromGuid(edge.outputSlot.nodeGuid);
var fromSlot = fromNode.FindOutputSlot<ISlot>(edge.outputSlot.slotId);
var sourceNode = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(x => x.node == fromNode);
var sourceAnchors = sourceNode.elements.OfType<GraphAnchorPresenter>();
var sourceAnchors = sourceNode.outputAnchors.OfType<GraphAnchorPresenter>();
var targetAnchors = targetNode.elements.OfType<GraphAnchorPresenter>();
var targetAnchors = targetNode.inputAnchors.OfType<GraphAnchorPresenter>();
var targetAnchor = targetAnchors.FirstOrDefault(x => x.slot == toSlot);
OnNodeChanged(targetNode.node, ModificationScope.Graph);

39
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialNodePresenter.cs


public INode node { get; private set; }
[SerializeField]
protected List<GraphElementPresenter> m_Controls = new List<GraphElementPresenter>();
protected List<GraphControlPresenter> m_Controls = new List<GraphControlPresenter>();
NodePreviewPresenter m_NodePreviewPresenter;
NodePreviewPresenter m_Preview;
[SerializeField]
int m_Version;

get { return node is IRequiresTime; }
}
public IEnumerable<GraphElementPresenter> elements
{
// TODO JOCE Sub ideal to use yield, but will do for now.
get
{
return inputAnchors.Concat(outputAnchors).Cast<GraphElementPresenter>().Concat(m_Controls).Concat(new [] {m_NodePreviewPresenter});
}
}
public override bool expanded
{
get { return base.expanded; }

}
}
public List<GraphControlPresenter> controls
{
get { return m_Controls; }
}
public NodePreviewPresenter preview
{
get { return m_Preview; }
}
towatch.Add(m_NodePreviewPresenter);
towatch.Add(preview);
return towatch.ToArray();
}

}
// TODO: Propagate callback rather than setting property
if (m_NodePreviewPresenter != null)
m_NodePreviewPresenter.modificationScope = scope;
if (preview != null)
preview.modificationScope = scope;
}
public override void CommitChanges()

node.drawState = drawState;
}
protected virtual IEnumerable<GraphElementPresenter> GetControlData()
protected virtual IEnumerable<GraphControlPresenter> GetControlData()
return Enumerable.Empty<GraphElementPresenter>();
return Enumerable.Empty<GraphControlPresenter>();
}
protected void AddSlots(IEnumerable<ISlot> slots)

AddSlots(node.GetSlots<ISlot>());
var controlData = GetControlData();
m_Controls.AddRange(controlData);
controls.AddRange(controlData);
position = new Rect(node.drawState.position.x, node.drawState.position.y, 0, 0);

if (materialNode == null || !materialNode.hasPreview)
return;
m_NodePreviewPresenter = CreateInstance<NodePreviewPresenter>();
m_NodePreviewPresenter.Initialize(materialNode);
m_Preview = CreateInstance<NodePreviewPresenter>();
preview.Initialize(materialNode);
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/ColorNodePresenter.cs


[Serializable]
public class ColorNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/CubemapNodePresenter.cs


[Serializable]
public class CubeNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/GradientNodePresenter.cs


[Serializable]
public class GradientNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/IfNodePresenter.cs


[Serializable]
public class IfNodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/LevelsNodePresenter.cs


[Serializable]
public class LevelsNodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/MasterNodePresenter.cs


[Serializable]
public class MasterNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Matrix2NodePresenter.cs


[Serializable]
public class Matrix2NodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Matrix3NodePresenter.cs


[Serializable]
public class Matrix3NodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Matrix4NodePresenter.cs


[Serializable]
public class Matrix4NodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/MatrixCommonNodePresenter.cs


[Serializable]
public class MatrixCommonNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/RemapInputNodePresenter.cs


[Serializable]
public class RemapInputNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/RemapMasterNodePresenter.cs


[Serializable]
public class RemapMasterNodePresenter : MasterNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
var controls = new List<GraphElementPresenter>(base.GetControlData());
var controls = new List<GraphControlPresenter>(base.GetControlData());
controls.Add(instance);
return controls;
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SamplerStateNodePresenter.cs


[Serializable]
public class SamplerStateNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SubgraphIONodePresenter.cs


[Serializable]
public class SubgraphIONodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SubgraphNodePresenter.cs


[Serializable]
public class SubgraphNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SurfaceMasterNodePresenter.cs


[Serializable]
public class SurfaceMasterNodePresenter : MasterNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
var controls = new List<GraphElementPresenter>(base.GetControlData());
var controls = new List<GraphControlPresenter>(base.GetControlData());
controls.Add(instance);
return controls;
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/SwizzleNodePresenter.cs


[Serializable]
public class SwizzleNodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/TextureAssetNodePresenter.cs


[Serializable]
public class TextureAssetNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/TextureLODNodePresenter.cs


[Serializable]
public class TextureLODNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/TextureSamplerNodePresenter.cs


[Serializable]
public class TextureSamplerNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/UVNodePresenter.cs


[Serializable]
public class UVNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector1NodePresenter.cs


[Serializable]
public class Vector1NodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector2NodePresenter.cs


[Serializable]
public class Vector2NodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector3NodePresenter.cs


[Serializable]
public class Vector3NodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/Nodes/Vector4NodePresenter.cs


[Serializable]
public class Vector4NodePresenter : PropertyNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter>(base.GetControlData()) { instance };
return new List<GraphControlPresenter>(base.GetControlData()) { instance };
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/PropertyNodePresenter.cs


[Serializable]
public abstract class PropertyNodePresenter : MaterialNodePresenter
{
protected override IEnumerable<GraphElementPresenter> GetControlData()
protected override IEnumerable<GraphControlPresenter> GetControlData()
return new List<GraphElementPresenter> { instance };
return new List<GraphControlPresenter> { instance };
}
}
}

8
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialNodeView.cs


void UpdateControls(MaterialNodePresenter nodeData)
{
var controlPresenters = nodeData.elements.OfType<GraphControlPresenter>().ToList();
if (controlPresenters.SequenceEqual(m_CurrentControlPresenter) && nodeData.expanded)
if (nodeData.controls.SequenceEqual(m_CurrentControlPresenter) && nodeData.expanded)
return;
m_ControlsContainer.Clear();

return;
foreach (var controlData in controlPresenters)
foreach (var controlData in nodeData.controls)
{
m_ControlsContainer.Add(CreateControl(controlData));
m_CurrentControlPresenter.Add(controlData);

UpdateControls(nodeData);
m_CurrentPreviewData = nodeData.elements.OfType<NodePreviewPresenter>().FirstOrDefault();
m_CurrentPreviewData = nodeData.preview;
UpdatePreviewTexture(m_CurrentPreviewData);
if (nodeData.expanded)

正在加载...
取消
保存