diff --git a/GameData/ConformalDecals/Plugins/ConformalDecals.dll b/GameData/ConformalDecals/Plugins/ConformalDecals.dll index 95daf2b..2c9d0fe 100644 Binary files a/GameData/ConformalDecals/Plugins/ConformalDecals.dll and b/GameData/ConformalDecals/Plugins/ConformalDecals.dll differ diff --git a/Source/ConformalDecals/MaterialProperties/MaterialPropertyCollection.cs b/Source/ConformalDecals/MaterialProperties/MaterialPropertyCollection.cs index 579ff23..5ffafbd 100644 --- a/Source/ConformalDecals/MaterialProperties/MaterialPropertyCollection.cs +++ b/Source/ConformalDecals/MaterialProperties/MaterialPropertyCollection.cs @@ -105,6 +105,28 @@ namespace ConformalDecals.MaterialProperties { _materialProperties ??= new Dictionary(); } + public void Load(ConfigNode node) { + // add keyword nodes + foreach (var keywordNode in node.GetNodes("KEYWORD")) { + ParseProperty(keywordNode); + } + + // add texture nodes + foreach (var textureNode in node.GetNodes("TEXTURE")) { + ParseProperty(textureNode); + } + + // add float nodes + foreach (var floatNode in node.GetNodes("FLOAT")) { + ParseProperty(floatNode); + } + + // add color nodes + foreach (var colorNode in node.GetNodes("COLOR")) { + ParseProperty(colorNode); + } + } + public void OnDestroy() { if (_decalMaterial != null) Destroy(_decalMaterial); if (_previewMaterial != null) Destroy(_previewMaterial); diff --git a/Source/ConformalDecals/MaterialProperties/MaterialTextureProperty.cs b/Source/ConformalDecals/MaterialProperties/MaterialTextureProperty.cs index 9a096aa..e7310ab 100644 --- a/Source/ConformalDecals/MaterialProperties/MaterialTextureProperty.cs +++ b/Source/ConformalDecals/MaterialProperties/MaterialTextureProperty.cs @@ -44,7 +44,7 @@ namespace ConformalDecals.MaterialProperties { public float AspectRatio { get { if (_texture == null) return 1; - if (_textureUrl?.Contains("Squad/Flags") == true) return 0.625f; + if (_textureUrl?.Contains("Squad/Flags") == true) return 0.625f; // squad flags are slightly stretched, so unstretch them return MaskedHeight / (float) MaskedWidth; } } diff --git a/Source/ConformalDecals/ModuleConformalDecal.cs b/Source/ConformalDecals/ModuleConformalDecal.cs index 2fb883d..3580f2e 100644 --- a/Source/ConformalDecals/ModuleConformalDecal.cs +++ b/Source/ConformalDecals/ModuleConformalDecal.cs @@ -119,6 +119,8 @@ namespace ConformalDecals { } } + // EVENTS + /// public override void OnAwake() { base.OnAwake(); @@ -133,116 +135,20 @@ namespace ConformalDecals { /// public override void OnLoad(ConfigNode node) { + // Load try { - // SETUP TRANSFORMS - decalFrontTransform = part.FindModelTransform(decalFront); - if (decalFrontTransform == null) throw new FormatException($"Could not find decalFront transform: '{decalFront}'."); - - decalBackTransform = part.FindModelTransform(decalBack); - if (decalBackTransform == null) throw new FormatException($"Could not find decalBack transform: '{decalBack}'."); - - decalModelTransform = part.FindModelTransform(decalModel); - if (decalModelTransform == null) throw new FormatException($"Could not find decalModel transform: '{decalModel}'."); - - decalProjectorTransform = part.FindModelTransform(decalProjector); - if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'."); - - decalColliderTransform = part.FindModelTransform(decalCollider); - if (decalColliderTransform == null) throw new FormatException($"Could not find decalCollider transform: '{decalCollider}'."); - - // SETUP BACK MATERIAL - if (updateBackScale) { - var backRenderer = decalBackTransform.GetComponent(); - 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); - } - } - } - - // PARSE MATERIAL PROPERTIES - - // set shader - materialProperties.SetShader(shader); - materialProperties.AddOrGetProperty("DECAL_BASE_NORMAL").value = useBaseNormal; - - // add keyword nodes - foreach (var keywordNode in node.GetNodes("KEYWORD")) { - materialProperties.ParseProperty(keywordNode); - } - - // add texture nodes - foreach (var textureNode in node.GetNodes("TEXTURE")) { - materialProperties.ParseProperty(textureNode); - } - - // add float nodes - foreach (var floatNode in node.GetNodes("FLOAT")) { - materialProperties.ParseProperty(floatNode); - } - - // add color nodes - foreach (var colorNode in node.GetNodes("COLOR")) { - materialProperties.ParseProperty(colorNode); - } - - // handle texture tiling parameters - var tileString = node.GetValue("tile"); - if (!string.IsNullOrEmpty(tileString)) { - var tileValid = ParseExtensions.TryParseRect(tileString, out tileRect); - if (!tileValid) throw new FormatException($"Invalid rect value for tile '{tileString}'"); - } - - if (tileRect.x >= 0) { - materialProperties.UpdateTile(tileRect); - } - else if (tileIndex >= 0) { - materialProperties.UpdateTile(tileIndex, tileSize); - } + LoadDecal(node); } catch (Exception e) { - this.LogException("Exception parsing partmodule", e); + this.LogException("Error loading decal", e); } - UpdateMaterials(); - - foreach (var keyword in _decalMaterial.shaderKeywords) { - this.Log($"keyword: {keyword}"); + // Setup + try { + SetupDecal(); } - - if (HighLogic.LoadedSceneIsEditor) { - UpdateTweakables(); - UpdateTextures(); - UpdateScale(); - UpdateTargets(); - } - else if (HighLogic.LoadedSceneIsFlight) { - UpdateTextures(); - UpdateScale(); - UpdateTargets(); - //TODO: Target loading - } - else { - scale = defaultScale; - depth = defaultDepth; - opacity = defaultOpacity; - cutoff = defaultCutoff; - wear = defaultWear; - - UpdateTextures(); - UpdateScale(); - - // QUEUE PART FOR ICON FIXING IN VAB - DecalIconFixer.QueuePart(part.name); + catch (Exception e) { + this.LogException("Error setting up decal", e); } } @@ -267,6 +173,8 @@ namespace ConformalDecals { } } + /// Called after OnStart is finished for all parts + /// This is mostly used to make sure all B9 variants are already in place for the rest of the vessel public override void OnStartFinished(StartState state) { // handle game events if (HighLogic.LoadedSceneIsGame) { @@ -295,6 +203,7 @@ namespace ConformalDecals { } } + /// Called when the decal is destroyed public virtual void OnDestroy() { // remove GameEvents if (HighLogic.LoadedSceneIsEditor) { @@ -313,6 +222,7 @@ namespace ConformalDecals { Destroy(materialProperties); } + /// Called when the decal's projection and scale is modified through a tweakable protected void OnProjectionTweakEvent(BaseField field, object obj) { // scale or depth values have been changed, so update scale // and update projection matrices if attached @@ -326,6 +236,7 @@ namespace ConformalDecals { } } + /// Called when the decal's material is modified through a tweakable protected void OnMaterialTweakEvent(BaseField field, object obj) { materialProperties.SetOpacity(opacity); materialProperties.SetCutoff(cutoff); @@ -343,6 +254,7 @@ namespace ConformalDecals { } } + /// Called when a new variant is applied in the editor protected void OnVariantApplied(Part eventPart, PartVariant variant) { if (_isAttached && eventPart != null) { if (projectMultiple && eventPart != part.parent) return; @@ -352,6 +264,7 @@ namespace ConformalDecals { } } + /// Called when an editor event occurs protected void OnEditorEvent(ConstructionEventType eventType, Part eventPart) { if (this.part != eventPart && !part.symmetryCounterparts.Contains(eventPart)) return; switch (eventType) { @@ -369,6 +282,7 @@ namespace ConformalDecals { } } + /// Called when part `willDie` will be destroyed protected void OnPartWillDie(Part willDie) { if (willDie == part.parent) { this.Log("Parent part about to be destroyed! Killing decal part."); @@ -376,6 +290,7 @@ namespace ConformalDecals { } } + /// Called when decal is attached to a new part protected virtual void OnAttach() { if (part.parent == null) { this.LogError("Attach function called but part has no parent!"); @@ -399,6 +314,7 @@ namespace ConformalDecals { UpdateTargets(); } + /// Called when decal is detached from its parent part protected virtual void OnDetach() { _isAttached = false; @@ -415,117 +331,91 @@ namespace ConformalDecals { UpdateScale(); } - protected void UpdateScale() { + // FUNCTIONS + + /// Load any settings from the decal config + protected virtual void LoadDecal(ConfigNode node) { + // PARSE TRANSFORMS + decalFrontTransform = part.FindModelTransform(decalFront); + if (decalFrontTransform == null) throw new FormatException($"Could not find decalFront transform: '{decalFront}'."); - // Update scale and depth - scale = Mathf.Max(0.01f, scale); - depth = Mathf.Max(0.01f, depth); - var aspectRatio = Mathf.Max(0.01f, materialProperties.AspectRatio); - Vector2 size; + decalBackTransform = part.FindModelTransform(decalBack); + if (decalBackTransform == null) throw new FormatException($"Could not find decalBack transform: '{decalBack}'."); - switch (scaleMode) { - default: - case DecalScaleMode.HEIGHT: - size = new Vector2(scale / aspectRatio, scale); - break; - case DecalScaleMode.WIDTH: - size = new Vector2(scale, scale * aspectRatio); - break; - case DecalScaleMode.AVERAGE: - var width1 = 2 * scale / (1 + aspectRatio); - size = new Vector2(width1, width1 * aspectRatio); - break; - case DecalScaleMode.AREA: - var width2 = Mathf.Sqrt(scale / aspectRatio); - size = new Vector2(width2, width2 * aspectRatio); - break; - case DecalScaleMode.MINIMUM: - if (aspectRatio > 1) goto case DecalScaleMode.WIDTH; - else goto case DecalScaleMode.HEIGHT; - case DecalScaleMode.MAXIMUM: - if (aspectRatio > 1) goto case DecalScaleMode.HEIGHT; - else goto case DecalScaleMode.WIDTH; - } + decalModelTransform = part.FindModelTransform(decalModel); + if (decalModelTransform == null) throw new FormatException($"Could not find decalModel transform: '{decalModel}'."); - // update material scale - materialProperties.UpdateScale(size); + decalProjectorTransform = part.FindModelTransform(decalProjector); + if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'."); - if (_isAttached) { - // Update projection targets - if (_targets == null) { - _targets = new List(); + decalColliderTransform = part.FindModelTransform(decalCollider); + if (decalColliderTransform == null) throw new FormatException($"Could not find decalCollider transform: '{decalCollider}'."); + + // SETUP BACK MATERIAL + if (updateBackScale) { + var backRenderer = decalBackTransform.GetComponent(); + if (backRenderer == null) { + this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false."); + updateBackScale = false; } else { - _targets.Clear(); - } - - // update orthogonal matrix - _orthoMatrix = Matrix4x4.identity; - _orthoMatrix[0, 3] = 0.5f; - _orthoMatrix[1, 3] = 0.5f; - - decalProjectorTransform.localScale = new Vector3(size.x, size.y, depth); - } - else { - // rescale preview model - decalModelTransform.localScale = new Vector3(size.x, size.y, (size.x + size.y) / 2); - - // update back material scale - if (updateBackScale) { - backMaterial.SetTextureScale(PropertyIDs._MainTex, new Vector2(size.x * backTextureBaseScale.x, size.y * backTextureBaseScale.y)); - } - } - } - - protected void UpdateTargets() { - if (!_isAttached) return; - - IEnumerable targetParts; - if (projectMultiple) { - targetParts = HighLogic.LoadedSceneIsFlight ? part.vessel.parts : EditorLogic.fetch.ship.parts; - } - else { - targetParts = new[] {part.parent}; - } - - foreach (var targetPart in targetParts) { - if (targetPart.GetComponent() != null) continue; // skip other decals - - foreach (var renderer in targetPart.FindModelComponents()) { - var target = renderer.transform; - var filter = target.GetComponent(); - - // check if the target has any missing data - if (!ProjectionTarget.ValidateTarget(target, renderer, filter)) continue; - - // check bounds for intersection - if (_boundsRenderer.bounds.Intersects(renderer.bounds)) { - // create new ProjectionTarget to represent the renderer - var projectionTarget = new ProjectionTarget(targetPart, target, renderer, filter, _orthoMatrix, decalProjectorTransform, useBaseNormal); - - // add the target to the list - _targets.Add(projectionTarget); + 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); } } } - } - protected virtual void UpdateTextures() { } + // PARSE MATERIAL PROPERTIES + // set shader + materialProperties.SetShader(shader); + materialProperties.AddOrGetProperty("DECAL_BASE_NORMAL").value = useBaseNormal; + materialProperties.Load(node); - protected virtual void UpdateMaterials() { - materialProperties.UpdateMaterials(); - materialProperties.SetOpacity(opacity); - materialProperties.SetCutoff(cutoff); - if (useBaseNormal) { - materialProperties.SetWear(wear); + // handle texture tiling parameters + var tileString = node.GetValue("tile"); + if (!string.IsNullOrEmpty(tileString)) { + var tileValid = ParseExtensions.TryParseRect(tileString, out tileRect); + if (!tileValid) throw new FormatException($"Invalid rect value for tile '{tileString}'"); } - _decalMaterial = materialProperties.DecalMaterial; - _previewMaterial = materialProperties.PreviewMaterial; - - if (!_isAttached) decalFrontTransform.GetComponent().material = _previewMaterial; + if (tileRect.x >= 0) { + materialProperties.UpdateTile(tileRect); + } + else if (tileIndex >= 0) { + materialProperties.UpdateTile(tileIndex, tileSize); + } } + /// Setup decal by calling update functions relevent for the current situation + protected virtual void SetupDecal() { + if (HighLogic.LoadedSceneIsEditor) { + // Update tweakables in editor mode + UpdateTweakables(); + } + + if (HighLogic.LoadedSceneIsGame) { + UpdateAll(); + } + else { + scale = defaultScale; + depth = defaultDepth; + opacity = defaultOpacity; + cutoff = defaultCutoff; + wear = defaultWear; + + UpdateAll(); + + // QUEUE PART FOR ICON FIXING IN VAB + DecalIconFixer.QueuePart(part.name); + } + } + + /// Update decal editor tweakables protected virtual void UpdateTweakables() { // setup tweakable fields var scaleField = Fields[nameof(scale)]; @@ -604,6 +494,130 @@ namespace ConformalDecals { multiprojectEditor.onFieldChanged = OnProjectionTweakEvent; } + /// Updates textures, materials, scale and targets + protected virtual void UpdateAll() { + UpdateTextures(); + UpdateMaterials(); + UpdateScale(); + UpdateTargets(); + } + + /// Update decal textures + protected virtual void UpdateTextures() { } + + /// Update decal materials + protected virtual void UpdateMaterials() { + materialProperties.UpdateMaterials(); + materialProperties.SetOpacity(opacity); + materialProperties.SetCutoff(cutoff); + if (useBaseNormal) { + materialProperties.SetWear(wear); + } + + _decalMaterial = materialProperties.DecalMaterial; + _previewMaterial = materialProperties.PreviewMaterial; + + if (!_isAttached) decalFrontTransform.GetComponent().material = _previewMaterial; + } + + /// Update decal scale and projection + protected void UpdateScale() { + + // Update scale and depth + scale = Mathf.Max(0.01f, scale); + depth = Mathf.Max(0.01f, depth); + var aspectRatio = Mathf.Max(0.01f, materialProperties.AspectRatio); + Vector2 size; + + switch (scaleMode) { + default: + case DecalScaleMode.HEIGHT: + size = new Vector2(scale / aspectRatio, scale); + break; + case DecalScaleMode.WIDTH: + size = new Vector2(scale, scale * aspectRatio); + break; + case DecalScaleMode.AVERAGE: + var width1 = 2 * scale / (1 + aspectRatio); + size = new Vector2(width1, width1 * aspectRatio); + break; + case DecalScaleMode.AREA: + var width2 = Mathf.Sqrt(scale / aspectRatio); + size = new Vector2(width2, width2 * aspectRatio); + break; + case DecalScaleMode.MINIMUM: + if (aspectRatio > 1) goto case DecalScaleMode.WIDTH; + else goto case DecalScaleMode.HEIGHT; + case DecalScaleMode.MAXIMUM: + if (aspectRatio > 1) goto case DecalScaleMode.HEIGHT; + else goto case DecalScaleMode.WIDTH; + } + + // update material scale + materialProperties.UpdateScale(size); + + if (_isAttached) { + // Update projection targets + if (_targets == null) { + _targets = new List(); + } + else { + _targets.Clear(); + } + + // update orthogonal matrix + _orthoMatrix = Matrix4x4.identity; + _orthoMatrix[0, 3] = 0.5f; + _orthoMatrix[1, 3] = 0.5f; + + decalProjectorTransform.localScale = new Vector3(size.x, size.y, depth); + } + else { + // rescale preview model + decalModelTransform.localScale = new Vector3(size.x, size.y, (size.x + size.y) / 2); + + // update back material scale + if (updateBackScale) { + backMaterial.SetTextureScale(PropertyIDs._MainTex, new Vector2(size.x * backTextureBaseScale.x, size.y * backTextureBaseScale.y)); + } + } + } + + /// Called when updating decal targets + protected void UpdateTargets() { + if (!_isAttached) return; + + IEnumerable targetParts; + if (projectMultiple) { + targetParts = HighLogic.LoadedSceneIsFlight ? part.vessel.parts : EditorLogic.fetch.ship.parts; + } + else { + targetParts = new[] {part.parent}; + } + + foreach (var targetPart in targetParts) { + if (targetPart.GetComponent() != null) continue; // skip other decals + + foreach (var renderer in targetPart.FindModelComponents()) { + var target = renderer.transform; + var filter = target.GetComponent(); + + // check if the target has any missing data + if (!ProjectionTarget.ValidateTarget(target, renderer, filter)) continue; + + // check bounds for intersection + if (_boundsRenderer.bounds.Intersects(renderer.bounds)) { + // create new ProjectionTarget to represent the renderer + var projectionTarget = new ProjectionTarget(targetPart, target, renderer, filter, _orthoMatrix, decalProjectorTransform, useBaseNormal); + + // add the target to the list + _targets.Add(projectionTarget); + } + } + } + } + + /// Render the decal public void Render(Camera camera) { if (!_isAttached) return; diff --git a/Source/ConformalDecals/ModuleConformalFlag.cs b/Source/ConformalDecals/ModuleConformalFlag.cs index cc11d07..a537916 100644 --- a/Source/ConformalDecals/ModuleConformalFlag.cs +++ b/Source/ConformalDecals/ModuleConformalFlag.cs @@ -1,4 +1,6 @@ +using ConformalDecals.MaterialProperties; using ConformalDecals.Util; +using UniLinq; using UnityEngine; namespace ConformalDecals { @@ -9,6 +11,8 @@ namespace ConformalDecals { [KSPField(isPersistant = true)] public bool useCustomFlag; + private MaterialTextureProperty _flagTextureProperty; + public string MissionFlagUrl { get { if (HighLogic.LoadedSceneIsEditor) { @@ -23,15 +27,10 @@ namespace ConformalDecals { } } - public override void OnLoad(ConfigNode node) { - base.OnLoad(node); + protected override void SetupDecal() { + _flagTextureProperty = materialProperties.AddOrGetTextureProperty("_Decal"); - if (useCustomFlag) { - SetFlag(flagUrl); - } - else { - SetFlag(MissionFlagUrl); - } + base.SetupDecal(); } public override void OnStart(StartState state) { @@ -44,17 +43,10 @@ namespace ConformalDecals { if (HighLogic.LoadedSceneIsEditor) { Events[nameof(ResetFlag)].guiActiveEditor = useCustomFlag; } - - if (useCustomFlag) { - SetFlag(flagUrl); - } - else { - SetFlag(MissionFlagUrl); - } } public override void OnDestroy() { - GameEvents.onMissionFlagSelect.Remove(SetFlag); + GameEvents.onMissionFlagSelect.Remove(OnEditorFlagSelected); base.OnDestroy(); } @@ -66,45 +58,43 @@ namespace ConformalDecals { [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_ConformalDecals_gui-reset-flag")] public void ResetFlag() { - SetFlag(MissionFlagUrl); - SetFlagSymmetryCounterparts(MissionFlagUrl); - - useCustomFlag = false; Events[nameof(ResetFlag)].guiActiveEditor = false; - } - - private void OnCustomFlagSelected(FlagBrowser.FlagEntry newFlagEntry) { - SetFlag(newFlagEntry.textureInfo.name); - SetFlagSymmetryCounterparts(newFlagEntry.textureInfo.name); - - useCustomFlag = true; - Events[nameof(ResetFlag)].guiActiveEditor = true; - } - - private void OnEditorFlagSelected(string newFlagUrl) { - if (!useCustomFlag) { - SetFlag(newFlagUrl); - SetFlagSymmetryCounterparts(newFlagUrl); + flagUrl = MissionFlagUrl; + useCustomFlag = false; + UpdateAll(); + foreach (var decal in part.symmetryCounterparts.Select(o => o.GetComponent())) { + decal.Events[nameof(ResetFlag)].guiActiveEditor = false; + decal.flagUrl = flagUrl; + decal.useCustomFlag = false; + decal.UpdateAll(); } } - private void SetFlag(string newFlagUrl) { - this.Log($"Loading flag texture '{newFlagUrl}'."); + private void OnCustomFlagSelected(FlagBrowser.FlagEntry newFlagEntry) { + Events[nameof(ResetFlag)].guiActiveEditor = true; + flagUrl = newFlagEntry.textureInfo.name; + useCustomFlag = true; + UpdateAll(); - flagUrl = newFlagUrl; - materialProperties.AddOrGetTextureProperty("_Decal", true).TextureUrl = newFlagUrl; - - UpdateMaterials(); - UpdateScale(); - UpdateTargets(); + foreach (var decal in part.symmetryCounterparts.Select(o => o.GetComponent())) { + decal.Events[nameof(ResetFlag)].guiActiveEditor = true; + decal.flagUrl = flagUrl; + decal.useCustomFlag = true; + decal.UpdateAll(); + } } - private void SetFlagSymmetryCounterparts(string newFlagUrl) { - foreach (var counterpart in part.symmetryCounterparts) { - var decal = counterpart.GetComponent(); + private void OnEditorFlagSelected(string newFlagUrl) { + if (!useCustomFlag) UpdateAll(); + } - decal.SetFlag(newFlagUrl); - decal.useCustomFlag = useCustomFlag; + protected override void UpdateTextures() { + base.UpdateTextures(); + if (useCustomFlag) { + _flagTextureProperty.TextureUrl = flagUrl; + } + else { + _flagTextureProperty.TextureUrl = MissionFlagUrl; } } } diff --git a/Source/ConformalDecals/ModuleConformalText.cs b/Source/ConformalDecals/ModuleConformalText.cs index 0b6145b..608fb58 100644 --- a/Source/ConformalDecals/ModuleConformalText.cs +++ b/Source/ConformalDecals/ModuleConformalText.cs @@ -90,43 +90,9 @@ namespace ConformalDecals { private MaterialColorProperty _outlineColorProperty; private MaterialFloatProperty _outlineWidthProperty; - private DecalText _currentText; + private DecalText _currentText; - public override void OnLoad(ConfigNode node) { - base.OnLoad(node); - - string textRaw = ""; - if (ParseUtil.ParseStringIndirect(ref textRaw, node, "text")) { - text = WebUtility.UrlDecode(textRaw); - } - - string fontName = ""; - if (ParseUtil.ParseStringIndirect(ref fontName, node, "fontName")) { - font = DecalConfig.GetFont(fontName); - } - else if (font == null) font = DecalConfig.GetFont("Calibri SDF"); - - int styleInt = 0; - if (ParseUtil.ParseIntIndirect(ref styleInt, node, "style")) { - style = (FontStyles) styleInt; - } - - ParseUtil.ParseColor32Indirect(ref fillColor, node, "fillColor"); - ParseUtil.ParseColor32Indirect(ref outlineColor, node, "outlineColor"); - - if (HighLogic.LoadedSceneIsGame) { - // For some reason, rendering doesnt work right on the first frame a scene is loaded - // So delay any rendering until the next frame when called in OnLoad - // This is probably a problem with Unity, not KSP - StartCoroutine(UpdateTextLate()); - } - else { - UpdateTextures(); - UpdateMaterials(); - UpdateScale(); - UpdateTargets(); - } - } + // EVENTS public override void OnSave(ConfigNode node) { node.AddValue("text", WebUtility.UrlEncode(text)); @@ -254,18 +220,69 @@ namespace ConformalDecals { base.OnDetach(); } + // FUNCTIONS + + protected override void LoadDecal(ConfigNode node) { + base.LoadDecal(node); + + string textRaw = ""; + if (ParseUtil.ParseStringIndirect(ref textRaw, node, "text")) { + text = WebUtility.UrlDecode(textRaw); + } + + string fontName = ""; + if (ParseUtil.ParseStringIndirect(ref fontName, node, "fontName")) { + font = DecalConfig.GetFont(fontName); + } + else if (font == null) font = DecalConfig.GetFont("Calibri SDF"); + + int styleInt = 0; + if (ParseUtil.ParseIntIndirect(ref styleInt, node, "style")) { + style = (FontStyles) styleInt; + } + + ParseUtil.ParseColor32Indirect(ref fillColor, node, "fillColor"); + ParseUtil.ParseColor32Indirect(ref outlineColor, node, "outlineColor"); + } + + protected override void SetupDecal() { + if (HighLogic.LoadedSceneIsEditor) { + // Update tweakables in editor mode + UpdateTweakables(); + } + + if (HighLogic.LoadedSceneIsGame) { + // For some reason text rendering fails on the first frame of a scene, so this is my workaround + StartCoroutine(UpdateTextLate()); + } + else { + scale = defaultScale; + depth = defaultDepth; + opacity = defaultOpacity; + cutoff = defaultCutoff; + wear = defaultWear; + + UpdateTextures(); + UpdateMaterials(); + UpdateScale(); + + // QUEUE PART FOR ICON FIXING IN VAB + DecalIconFixer.QueuePart(part.name); + } + } + protected void UpdateText() { UpdateTextures(); UpdateMaterials(); UpdateScale(); UpdateTargets(); } - + private IEnumerator UpdateTextLate() { yield return null; UpdateText(); } - + protected override void UpdateTextures() { // Render text var newText = new DecalText(text, font, style, vertical, lineSpacing, charSpacing);