Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/MaterialEditor.Base/MaterialEditor.Base.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)UI\Sections\Properties\PropertyRowBuilders.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\MaterialTextureImportTransaction.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\MaterialCubemapImportTransaction.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\MaterialEditResult.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\MaterialEditRequestQueue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)NormalMapManager.cs" />
Expand Down
105 changes: 0 additions & 105 deletions src/MaterialEditor.Base/Operations/MaterialCubemapImportTransaction.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,23 @@ internal static MaterialEditResult Execute<T>(GameObject root, string materialNa
}
}

// Keep the existing DTO identity: animation bindings may still reference it.
internal static void Commit<T, TController, TAnimation>(IList<T> records, IDictionary<T, TController> animations,
T existing, T candidate, Func<T, int?> getId, Action<T, int?> setId,
Func<T, TAnimation> getAnimation, Action<T, TAnimation> setAnimation) where T : class
// Move the binding before the caller assigns the two DTO fields. If the
// map update fails, the existing record and its binding remain unchanged.
internal static void CommitAnimationBinding<T, TController>(
IDictionary<T, TController> animations, T existing, T candidate) where T : class
{
if (existing == null)
{
records.Add(candidate);
return;
}
var previousId = getId(existing);
var previousAnimation = getAnimation(existing);
TController previousController;
TController candidateController;
var hadPrevious = animations.TryGetValue(existing, out previousController);
var hasCandidate = animations.TryGetValue(candidate, out candidateController);
try
{
setId(existing, getId(candidate));
setAnimation(existing, getAnimation(candidate));
animations.Remove(candidate);
if (hasCandidate) animations[existing] = candidateController;
else animations.Remove(existing);
}
catch
{
setId(existing, previousId);
setAnimation(existing, previousAnimation);
animations.Remove(candidate);
if (hadPrevious) animations[existing] = previousController;
else animations.Remove(existing);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,38 +82,45 @@ private bool SetMaterialCubemap(
var existing = MaterialCubemapPropertyList.FirstOrDefault(x => x.ID == id && x.Property == propertyName && x.MaterialName == material.NameFormatted());
var result = MaterialCubemapImportTransaction.Execute(data, contentKey,
go, material.NameFormatted(), propertyName, logNormalizationWarning,
new MaterialCubemapImportStorage
{
Count = () => TextureDictionary.Count,
StoreData = SetAndGetTextureID,
StoreLease = CubemapLeases.Store,
RemoveCreated = RemoveFailedCubemapData,
PurgeLeases = PurgeUnusedCubemapLeases
}, MaterialCubemapPropertyList, existing,
texId => new MaterialCubemapProperty(id, material.NameFormatted(), propertyName, texId),
CubemapRecordAccess, candidate => SetCubemapWithProperty(go, candidate));
TextureDictionary, CubemapLeases, ApplyAndCommit, PurgeUnusedCubemapLeases);
if (!result.Succeeded)
MaterialEditorPluginBase.Logger?.LogWarning("Cubemap import: " + result.Stage + ": " + result.Diagnostic);
return result.Succeeded;
}

private static readonly MaterialCubemapRecordAccess<MaterialCubemapProperty> CubemapRecordAccess =
new MaterialCubemapRecordAccess<MaterialCubemapProperty>
bool ApplyAndCommit(int texId)
{
GetId = x => x.TexID,
SetId = (x, id) => x.TexID = id,
Original = x => x.CubemapOriginalState
};

private void RemoveFailedCubemapData(int texId)
{
CubemapLeases.Release(texId);
TextureContainer container;
if (!TextureDictionary.TryGetValue(texId, out container)) return;
try { container?.Dispose(); }
finally { TextureDictionary.Remove(texId); }
var candidate = new MaterialCubemapProperty(id, material.NameFormatted(), propertyName, texId);
var committed = false;
try
{
if (existing != null)
candidate.CubemapOriginalState.RestoreCheckpoint(
existing.CubemapOriginalState.CaptureCheckpoint(), false);
if (!SetCubemapWithProperty(go, candidate))
return false;

if (existing == null)
MaterialCubemapPropertyList.Add(candidate);
else
{
// Finish all potentially throwing preparation before updating the
// existing record. Checkpoint restoration only assigns state fields.
var state = candidate.CubemapOriginalState.CaptureCheckpoint();
existing.CubemapOriginalState.RestoreCheckpoint(state, false);
existing.TexID = texId;
}
committed = true;
return true;
}
finally
{
if (!committed)
candidate.CubemapOriginalState.Clear();
}
}
}


private bool SetCubemapWithProperty(
GameObject gameObject,
MaterialCubemapProperty cubemapProperty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,18 @@ private bool TrySetMaterialTexture(int id, Material material, string propertyNam
var result = MaterialTextureImportTransaction.Execute(
go, materialName, propertyName, () =>
{
var texID = SetAndGetTextureID(data);
var animationDefinition = MEAnimationUtil.LoadAnimationDefFromBytes(texID, data, SetAndGetTextureID);
return new MaterialTextureProperty(
id,
materialName,
propertyName,
texID,
existingProperty == null ? null : existingProperty.Offset,
existingProperty == null ? null : existingProperty.OffsetOriginal,
existingProperty == null ? null : existingProperty.Scale,
existingProperty == null ? null : existingProperty.ScaleOriginal,
animationDefinition);
var texID = SetAndGetTextureID(data);
var animationDefinition = MEAnimationUtil.LoadAnimationDefFromBytes(texID, data, SetAndGetTextureID);
return new MaterialTextureProperty(
id,
materialName,
propertyName,
texID,
existingProperty == null ? null : existingProperty.Offset,
existingProperty == null ? null : existingProperty.OffsetOriginal,
existingProperty == null ? null : existingProperty.Scale,
existingProperty == null ? null : existingProperty.ScaleOriginal,
animationDefinition);
},
candidate => SetTextureWithProperty(go, candidate),
candidate => CommitTextureImport(existingProperty, candidate),
Expand All @@ -161,10 +161,20 @@ private bool TrySetMaterialTexture(int id, Material material, string propertyNam
return result.Succeeded;
}

private void CommitTextureImport(MaterialTextureProperty existingProperty, MaterialTextureProperty candidateProperty) =>
MaterialTextureImportTransaction.Commit(MaterialTexturePropertyList, AnimationControllerMap,
existingProperty, candidateProperty, x => x.TexID, (x, id) => x.TexID = id,
x => x.TexAnimationDef, (x, animation) => x.TexAnimationDef = animation);
private void CommitTextureImport(MaterialTextureProperty existingProperty, MaterialTextureProperty candidateProperty)
{
if (existingProperty == null)
{
MaterialTexturePropertyList.Add(candidateProperty);
return;
}

MaterialTextureImportTransaction.CommitAnimationBinding(
AnimationControllerMap, existingProperty, candidateProperty);
// These field assignments cannot fail; retain the existing record identity.
existingProperty.TexID = candidateProperty.TexID;
existingProperty.TexAnimationDef = candidateProperty.TexAnimationDef;
}

/// <summary>
/// Get the saved material property value or null if none is saved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,63 @@ private void LoadSceneMaterialVectorPropertyList(SceneLoadContext context)
});
}

private void LoadSceneMaterialTexturePropertyList(SceneLoadContext context)
{
context.Data.Read<MaterialTextureProperty>(nameof(MaterialTexturePropertyList), loadedProperty =>
{
GameObject go = ExtractGameObject(context.Items, loadedProperty.ID, out var objID);
if (go != null)
{
int? texID = null;
if (context.Operation == SceneOperationKind.Import)
{
if (loadedProperty.TexID != null)
texID = context.Data.RemapTexture(loadedProperty.TexID);
MEAnimationUtil.RemapTexID(loadedProperty.TexAnimationDef, context.Data.TextureIds);
}
else
texID = loadedProperty.TexID;

MaterialTextureProperty newTextureProperty = new MaterialTextureProperty(objID, loadedProperty.MaterialName, loadedProperty.Property, texID, loadedProperty.Offset, loadedProperty.OffsetOriginal, loadedProperty.Scale, loadedProperty.ScaleOriginal, loadedProperty.TexAnimationDef);

bool setTex = false;
if (newTextureProperty.TexID != null)
setTex = SetTextureWithProperty(go, newTextureProperty);

bool setOffset = SetTextureOffset(go, newTextureProperty.MaterialName, newTextureProperty.Property, newTextureProperty.Offset);
bool setScale = SetTextureScale(go, newTextureProperty.MaterialName, newTextureProperty.Property, newTextureProperty.Scale);

if (setTex || setOffset || setScale)
MaterialTexturePropertyList.Add(newTextureProperty);
}
});
}

private void LoadSceneMaterialCubemapPropertyList(SceneLoadContext context)
{
context.Data.Read<MaterialCubemapProperty>(nameof(MaterialCubemapPropertyList), loadedProperty =>
{
GameObject go = ExtractGameObject(
context.Items,
loadedProperty.ID,
out var objID);
if (go == null)
return;

int? texID = loadedProperty.TexID;
if (context.Operation == SceneOperationKind.Import
&& loadedProperty.TexID.HasValue)
texID = context.Data.RemapTexture(loadedProperty.TexID);

var newCubemapProperty = new MaterialCubemapProperty(
objID,
loadedProperty.MaterialName,
loadedProperty.Property,
texID);
if (newCubemapProperty.TexID.HasValue
&& SetCubemapWithProperty(go, newCubemapProperty))
MaterialCubemapPropertyList.Add(newCubemapProperty);
});
}
}
}
Loading
Loading