More work trying to fix part icons

feature-multiSDF
Andrew Cassidy 4 years ago
parent e9c8f3dafb
commit 0ef46a3182

@ -0,0 +1,62 @@
using System.Collections.Generic;
using UnityEngine;
namespace ConformalDecals {
[KSPAddon(KSPAddon.Startup.EditorAny, true)]
public class ConformalDecalIconFixer : MonoBehaviour {
private static readonly List<string> PartNames = new List<string>();
public static void QueuePart(string name) {
PartNames.Add(name);
}
public void Start() {
foreach (var name in PartNames) {
Debug.Log($"Unf*&king decal preview on {name}");
var partInfo = PartLoader.getPartInfoByName(name);
if (partInfo == null) {
Debug.Log($"Part {name} not found!");
continue;
}
var icon = partInfo.iconPrefab;
var decalModule = partInfo.partPrefab.FindModuleImplementing<ModuleConformalDecalBase>();
if (partInfo == null) {
Debug.Log($"Part {name} has no decal module!");
continue;
}
var frontTransform = Part.FindHeirarchyTransform(icon.transform, decalModule.decalFront);
var backTransform = Part.FindHeirarchyTransform(icon.transform, decalModule.decalBack);
if (frontTransform == null) {
Debug.Log($"Part {name} has no frontTransform");
continue;
}
if (backTransform == null) {
Debug.Log($"Part {name} has no backTransform");
continue;
}
Vector2 backScale = default;
if (decalModule.updateBackScale) {
var aspectRatio = decalModule.materialProperties.AspectRatio;
var size = new Vector2(decalModule.scale, decalModule.scale * aspectRatio);
backScale.x = size.x * decalModule.backTextureBaseScale.x;
backScale.y = size.y * decalModule.backTextureBaseScale.y;
Debug.Log($"backscale is {backScale}");
}
backTransform.GetComponent<MeshRenderer>().material = decalModule.backMaterial;
if (decalModule.updateBackScale) {
backTransform.GetComponent<MeshRenderer>().material.SetTextureScale(PropertyIDs._MainTex, backScale);
}
}
}
}
}

@ -50,6 +50,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ConformalDecalConfig.cs" />
<Compile Include="ConformalDecalIconFixer.cs" />
<Compile Include="MaterialModifiers\MaterialColorProperty.cs" />
<Compile Include="MaterialModifiers\MaterialFloatProperty.cs" />
<Compile Include="MaterialModifiers\MaterialProperty.cs" />

@ -4,7 +4,7 @@ using Object = UnityEngine.Object;
namespace ConformalDecals.MaterialModifiers {
public abstract class MaterialProperty : ScriptableObject {
public string Name {
public string PropertyName {
get => _propertyName;
set {
_propertyName = value;
@ -18,7 +18,7 @@ namespace ConformalDecals.MaterialModifiers {
public virtual void ParseNode(ConfigNode node) {
if (node == null) throw new ArgumentNullException("node cannot be null");
Name = node.GetValue("name");
PropertyName = node.GetValue("name");
}
public abstract void Modify(Material material);
@ -57,10 +57,10 @@ namespace ConformalDecals.MaterialModifiers {
}
else {
if (valueString == null)
throw new FormatException($"Missing {typeof(T)} value for {valueName} in property '{Name}'");
throw new FormatException($"Missing {typeof(T)} value for {valueName} in property '{PropertyName}'");
if (valueString == string.Empty)
throw new FormatException($"Empty {typeof(T)} value for {valueName} in property '{Name}'");
throw new FormatException($"Empty {typeof(T)} value for {valueName} in property '{PropertyName}'");
}
if (tryParse(valueString, out var value)) {
@ -72,7 +72,7 @@ namespace ConformalDecals.MaterialModifiers {
}
else {
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} in property '{Name}' : '{valueString}");
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} in property '{PropertyName}' : '{valueString}");
}
}
}

@ -1,19 +1,18 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using UniLinq;
using UnityEngine;
namespace ConformalDecals.MaterialModifiers {
public class MaterialPropertyCollection : ScriptableObject {
public class MaterialPropertyCollection : ScriptableObject, ISerializationCallbackReceiver {
private static readonly int OpacityId = Shader.PropertyToID("_DecalOpacity");
private static readonly int CutoffId = Shader.PropertyToID("_Cutoff");
public MaterialTextureProperty MainMaterialTextureProperty => _mainTexture;
public Shader DecalShader => _shader;
public Material DecalMaterial {
get {
Debug.Log($"{_textureMaterialProperties == null}");
if (_decalMaterial == null) {
_decalMaterial = new Material(_shader);
UpdateMaterial(_decalMaterial);
@ -35,54 +34,108 @@ namespace ConformalDecals.MaterialModifiers {
}
}
public MaterialTextureProperty MainTexture {
get => _mainTexture;
set {
if (!_materialProperties.ContainsValue(value))
throw new ArgumentException($"Texture property {value.name} is not part of this property collection.");
_mainTexture = value;
}
}
public float AspectRatio {
get {
if (MainMaterialTextureProperty == null) return 1;
return MainMaterialTextureProperty.AspectRatio;
if (MainTexture == null) {
Debug.Log("No main texture specified! returning 1 for aspect ratio");
return 1;
}
return MainTexture.AspectRatio;
}
}
[SerializeField] private Shader _shader;
[SerializeField] private List<MaterialProperty> _materialProperties;
[SerializeField] private List<MaterialTextureProperty> _textureMaterialProperties;
[SerializeField] private MaterialTextureProperty _mainTexture;
[SerializeField] private string[] _serializedIDs;
[SerializeField] private MaterialProperty[] _serializedProperties;
[SerializeField] private Shader _shader;
[SerializeField] private MaterialTextureProperty _mainTexture;
private Dictionary<string, MaterialProperty> _materialProperties;
private Material _decalMaterial;
private Material _previewMaterial;
public void Initialize() {
_materialProperties = new List<MaterialProperty>();
_textureMaterialProperties = new List<MaterialTextureProperty>();
public void OnBeforeSerialize() {
Debug.Log($"Serializing MaterialPropertyCollection {this.GetInstanceID()}");
if (_materialProperties == null) throw new SerializationException("Tried to serialize an unininitalized MaterialPropertyCollection");
_serializedIDs = _materialProperties.Keys.ToArray();
_serializedProperties = _materialProperties.Values.ToArray();
}
public void AddProperty(MaterialProperty property) {
if (property == null) throw new ArgumentNullException("Tried to add a null property");
if (_materialProperties == null || _textureMaterialProperties == null) {
Initialize();
Debug.LogWarning("Tried to add a property to uninitialized property collection! correcting now.");
}
public void OnAfterDeserialize() {
Debug.Log($"Deserializing MaterialPropertyCollection {this.GetInstanceID()}");
if (_serializedIDs == null) throw new SerializationException("ID array is null");
if (_serializedProperties == null) throw new SerializationException("Property array is null");
if (_serializedProperties.Length != _serializedIDs.Length) throw new SerializationException("Material property arrays are different lengths.");
_materialProperties ??= new Dictionary<string, MaterialProperty>();
foreach (var p in _materialProperties) {
if (p.Name == property.Name) {
_materialProperties.Remove(property);
for (var i = 0; i < _serializedIDs.Length; i++) {
var property = MaterialProperty.Instantiate(_serializedProperties[i]);
Debug.Log($"insantiating {property.GetType().Name} {property.GetInstanceID()}");
_materialProperties.Add(_serializedIDs[i], property);
if (property is MaterialTextureProperty textureProperty) {
_mainTexture = textureProperty;
}
}
}
_materialProperties.Add(property);
public void Awake() {
Debug.Log($"MaterialPropertyCollection {this.GetInstanceID()} onAwake");
_materialProperties ??= new Dictionary<string, MaterialProperty>();
}
if (property is MaterialTextureProperty textureProperty) {
foreach (var p in _textureMaterialProperties) {
if (p.Name == textureProperty.Name) {
_textureMaterialProperties.Remove(textureProperty);
}
}
public void AddProperty(MaterialProperty property) {
if (property == null) throw new ArgumentNullException("Tried to add a null property");
_textureMaterialProperties.Add(textureProperty);
_materialProperties.Add(property.name, property);
if (property is MaterialTextureProperty textureProperty) {
if (textureProperty.isMain) _mainTexture ??= textureProperty;
}
}
public void ParseProperty<T>(ConfigNode node) where T : MaterialProperty {
var name = node.GetValue("name");
if (string.IsNullOrEmpty(name)) throw new ArgumentException("node has no name");
Debug.Log($"Parsing material property {name}");
T newProperty;
if (_materialProperties.ContainsKey(name)) {
if (_materialProperties[name] is T property) {
newProperty = property;
property.ParseNode(node);
}
else {
throw new ArgumentException("Material property already exists for {name} but it has a different type");
}
}
else {
newProperty = MaterialProperty.CreateInstance<T>();
Debug.Log($"Adding new material property of type {newProperty.GetType().Name} {newProperty.GetInstanceID()}");
newProperty.ParseNode(node);
_materialProperties.Add(name, newProperty);
}
if (newProperty is MaterialTextureProperty textureProperty && textureProperty.isMain) {
_mainTexture = textureProperty;
}
}
public void SetShader(string shaderName) {
if (string.IsNullOrEmpty(shaderName)) {
if (_shader == null) {
@ -107,9 +160,12 @@ namespace ConformalDecals.MaterialModifiers {
DecalMaterial.renderQueue = queue;
}
public void SetScale(Vector2 scale) {
foreach (var textureProperty in _textureMaterialProperties) {
textureProperty.UpdateScale(DecalMaterial, scale);
public void UpdateScale(Vector2 scale) {
foreach (var entry in _materialProperties) {
if (entry.Value is MaterialTextureProperty textureProperty) {
textureProperty.UpdateScale(DecalMaterial, scale);
textureProperty.UpdateScale(PreviewMaterial, scale);
}
}
}
@ -125,20 +181,23 @@ namespace ConformalDecals.MaterialModifiers {
if (_decalMaterial == null) {
_decalMaterial = DecalMaterial;
}
else {
UpdateMaterial(_decalMaterial);
}
if (_previewMaterial == null) {
_previewMaterial = PreviewMaterial;
}
UpdateMaterial(_decalMaterial);
UpdateMaterial(_previewMaterial);
else {
UpdateMaterial(_previewMaterial);
}
}
public void UpdateMaterial(Material material) {
if (material == null) throw new ArgumentNullException("material cannot be null");
if (material == null) throw new ArgumentNullException(nameof(material));
foreach (var property in _materialProperties) {
property.Modify(material);
foreach (var entry in _materialProperties) {
entry.Value.Modify(material);
}
}
}

@ -16,8 +16,16 @@ namespace ConformalDecals.MaterialModifiers {
public float AspectRatio {
get {
if (texture == null) return 1;
if (!_hasTile || Mathf.Approximately(0, _tileRect.width)) return ((float) texture.height) / ((float) texture.width);
if (texture == null) {
Debug.Log("Returning 1");
return 1;
}
if (!_hasTile) {
Debug.Log("Returning texture aspect ratio");
return ((float) texture.height) / ((float) texture.width);
}
return _tileRect.height / _tileRect.width;
}
}
@ -35,7 +43,7 @@ namespace ConformalDecals.MaterialModifiers {
public override void ParseNode(ConfigNode node) {
base.ParseNode(node);
isNormal = ParsePropertyBool(node, "isNormalMap", true, (Name == "_BumpMap") || isNormal);
isNormal = ParsePropertyBool(node, "isNormalMap", true, (PropertyName == "_BumpMap") || isNormal);
isMain = ParsePropertyBool(node, "isMain", true, isMain);
autoScale = ParsePropertyBool(node, "autoScale", true, autoScale);

@ -115,28 +115,51 @@ namespace ConformalDecals {
if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'.");
}
if (HighLogic.LoadedSceneIsEditor) {
UpdateTweakables();
}
// setup material properties
if (HighLogic.LoadedSceneIsGame) {
// additional load, in flight or in the editor
materialProperties = ScriptableObject.Instantiate(materialProperties);
}
else {
// first load, so get everything set up
materialProperties = ScriptableObject.CreateInstance<MaterialPropertyCollection>();
materialProperties.Initialize();
// get back material if necessary
if (updateBackScale) {
this.Log("Getting material and base scale for back material");
var backRenderer = decalBackTransform.GetComponent<MeshRenderer>();
if (backRenderer == null) {
this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false.");
updateBackScale = false;
}
else {
backMaterial = backRenderer.material;
if (backMaterial == null) {
this.LogError($"Specified decalBack transform {decalBack} has a renderer but no material! Setting updateBackScale to false.");
updateBackScale = false;
}
else {
if (backTextureBaseScale == default) backTextureBaseScale = backMaterial.GetTextureScale(PropertyIDs._MainTex);
}
}
}
ConformalDecalIconFixer.QueuePart(part.name);
// set shader
materialProperties.SetShader(shader);
}
catch (Exception e) {
this.LogException("Exception parsing partmodule", e);
}
if (HighLogic.LoadedSceneIsGame) {
UpdateMaterials();
UpdateScale();
UpdateProjection();
}
}
public override void OnAwake() {
base.OnAwake();
if (materialProperties == null) {
materialProperties = ScriptableObject.CreateInstance<MaterialPropertyCollection>();
}
else {
materialProperties = ScriptableObject.Instantiate(materialProperties);
}
}
public override void OnStart(StartState state) {
@ -149,31 +172,33 @@ namespace ConformalDecals {
UpdateTweakables();
}
materialProperties.SetRenderQueue(DecalQueue);
// clone materialProperties and setup queue
UpdateMaterials();
UpdateScale();
if (HighLogic.LoadedSceneIsGame) {
materialProperties = ScriptableObject.Instantiate(materialProperties);
materialProperties.SetRenderQueue(DecalQueue);
// set initial attachment state
if (part.parent == null) {
_isAttached = false;
OnDetach();
}
else {
OnAttach();
}
}
UpdateMaterials();
UpdateScale();
}
public void OnDestroy() {
public virtual void OnDestroy() {
// remove GameEvents
GameEvents.onEditorPartEvent.Remove(OnEditorEvent);
GameEvents.onVariantApplied.Remove(OnVariantApplied);
// remove from preCull delegate
Camera.onPreCull -= Render;
// destroy material properties object
Destroy(materialProperties);
}
protected void OnSizeTweakEvent(BaseField field, object obj) {
@ -229,7 +254,7 @@ namespace ConformalDecals {
// add to preCull delegate
Camera.onPreCull += Render;
//UpdateScale();
UpdateScale();
UpdateTargets();
UpdateProjection();
}
@ -244,13 +269,13 @@ namespace ConformalDecals {
// remove from preCull delegate
Camera.onPreCull -= Render;
//UpdateScale();
UpdateScale();
}
protected void UpdateScale() {
var aspectRatio = materialProperties.AspectRatio;
this.Log($"Aspect ratio is {aspectRatio}");
var size = new Vector2(scale, scale * materialProperties.AspectRatio);
var size = new Vector2(scale, scale * aspectRatio);
// update orthogonal matrix scale
_orthoMatrix = Matrix4x4.identity;
@ -278,7 +303,7 @@ namespace ConformalDecals {
}
// update material scale
materialProperties.SetScale(size);
materialProperties.UpdateScale(size);
}
protected void UpdateMaterials() {
@ -286,26 +311,6 @@ namespace ConformalDecals {
_decalMaterial = materialProperties.DecalMaterial;
_previewMaterial = materialProperties.PreviewMaterial;
// get back material if necessary
if (updateBackScale) {
this.Log("Getting material and base scale for back material");
var backRenderer = decalBackTransform.GetComponent<MeshRenderer>();
if (backRenderer == null) {
this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false.");
updateBackScale = false;
}
else {
backMaterial = backRenderer.material;
if (backMaterial == null) {
this.LogError($"Specified decalBack transform {decalBack} has a renderer but no material! Setting updateBackScale to false.");
updateBackScale = false;
}
else {
if (backTextureBaseScale == default) backTextureBaseScale = backMaterial.GetTextureScale(PropertyIDs._MainTex);
}
}
}
if (decalFrontTransform == null) {
this.LogError("No reference to decal front transform");
return;
@ -340,22 +345,16 @@ namespace ConformalDecals {
if (renderer.gameObject.activeInHierarchy == false) continue;
// skip blacklisted shaders
if (ConformalDecalConfig.IsBlacklisted(renderer.material.shader)) {
this.Log($"Skipping blacklisted shader '{renderer.material.shader.name}' in '{renderer.gameObject.name}'");
continue;
}
if (ConformalDecalConfig.IsBlacklisted(renderer.material.shader)) continue;
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter == null) continue; // object has a meshRenderer with no filter, invalid
var mesh = meshFilter.mesh;
if (mesh == null) continue; // object has a null mesh, invalid
this.Log($"Adding target for object {meshFilter.gameObject.name} with the mesh {mesh.name}");
// create new ProjectionTarget to represent the renderer
var target = new ProjectionTarget(renderer, mesh, useBaseNormal);
this.Log("done.");
// add the target to the list
_targets.Add(target);
}

@ -11,11 +11,11 @@ namespace ConformalDecals {
public override void OnLoad(ConfigNode node) {
base.OnLoad(node);
if (HighLogic.LoadedSceneIsGame) {
UpdateMaterials();
UpdateScale();
UpdateProjection();
UpdateFlag(EditorLogic.FlagURL != string.Empty ? EditorLogic.FlagURL : HighLogic.CurrentGame.flagURL);
}
else {
UpdateFlag(defaultFlag);
}
}
@ -23,20 +23,20 @@ namespace ConformalDecals {
base.OnStart(state);
if (HighLogic.LoadedSceneIsGame) {
UpdateFlag(EditorLogic.FlagURL != string.Empty ? EditorLogic.FlagURL : HighLogic.CurrentGame.flagURL);
GameEvents.onMissionFlagSelect.Add(UpdateFlag);
}
else {
UpdateFlag(defaultFlag);
}
}
public override void OnIconCreate() {
this.Log("called OnIconCreate");
OnStart(StartState.None);
UpdateScale();
}
public override void OnDestroy() {
GameEvents.onMissionFlagSelect.Remove(UpdateFlag);
base.OnDestroy();
}
private void UpdateFlag(string flagUrl) {
this.Log($"Loading flag texture '{flagUrl}'.");
var flagTexture = GameDatabase.Instance.GetTexture(flagUrl, false);
@ -48,9 +48,10 @@ namespace ConformalDecals {
if (flagTextureProperty == null) {
this.Log("Initializing flag property");
flagTextureProperty = ScriptableObject.CreateInstance<MaterialTextureProperty>();
flagTextureProperty.Name = "_Decal";
flagTextureProperty.PropertyName = "_Decal";
flagTextureProperty.isMain = true;
materialProperties.AddProperty(flagTextureProperty);
materialProperties.MainTexture = flagTextureProperty;
}
else { }

@ -5,41 +5,29 @@ using UnityEngine;
namespace ConformalDecals {
public class ModuleConformalDecalGeneric : ModuleConformalDecalBase {
public override void OnLoad(ConfigNode node) {
base.OnLoad(node);
// set shader
materialProperties.SetShader(shader);
// add texture nodes
foreach (var textureNode in node.GetNodes("TEXTURE")) {
var textureProperty = ScriptableObject.CreateInstance<MaterialTextureProperty>();
textureProperty.ParseNode(textureNode);
materialProperties.AddProperty(textureProperty);
materialProperties.ParseProperty<MaterialTextureProperty>(textureNode);
}
// add float nodes
foreach (var floatNode in node.GetNodes("FLOAT")) {
var floatProperty = ScriptableObject.CreateInstance<MaterialFloatProperty>();
floatProperty.ParseNode(floatNode);
materialProperties.AddProperty(floatProperty);
materialProperties.ParseProperty<MaterialTextureProperty>(floatNode);
}
// add color nodes
foreach (var colorNode in node.GetNodes("COLOR")) {
var colorProperty = ScriptableObject.CreateInstance<MaterialColorProperty>();
colorProperty.ParseNode(colorNode);
materialProperties.AddProperty(colorProperty);
materialProperties.ParseProperty<MaterialColorProperty>(colorNode);
}
if (HighLogic.LoadedSceneIsGame) {
UpdateMaterials();
UpdateScale();
UpdateProjection();
}
base.OnLoad(node);
}
public override void OnIconCreate() {
this.Log("called OnIconCreate");
OnStart(StartState.None);
UpdateScale();
}
}

Loading…
Cancel
Save