diff --git a/GameData/ConformalDecals/Localization/en-us.cfg b/GameData/ConformalDecals/Localization/en-us.cfg
index aa55ce9..022d7ab 100644
--- a/GameData/ConformalDecals/Localization/en-us.cfg
+++ b/GameData/ConformalDecals/Localization/en-us.cfg
@@ -18,6 +18,14 @@ Localization
#LOC_ConformalDecals_gui-aspectratio = Aspect Ratio
#LOC_ConformalDecals_gui-select-flag = Select Flag
#LOC_ConformalDecals_gui-reset-flag = Reset Flag
+ #LOC_ConformalDecals_gui-set-text = Set Text
+ #LOC_ConformalDecals_gui-group-fill = Fill
+ #LOC_ConformalDecals_gui-group-outline = Outline
+ #LOC_ConformalDecals_gui-fill = Fill
+ #LOC_ConformalDecals_gui-set-fill-color = Set Fill Color
+ #LOC_ConformalDecals_gui-outline = Outline
+ #LOC_ConformalDecals_gui-outline-width = Outline Width
+ #LOC_ConformalDecals_gui-set-outline-color = Set Outline Color
// PARTS
diff --git a/GameData/ConformalDecals/Plugins/ConformalDecals.dll b/GameData/ConformalDecals/Plugins/ConformalDecals.dll
index abddca6..b27fa72 100644
Binary files a/GameData/ConformalDecals/Plugins/ConformalDecals.dll and b/GameData/ConformalDecals/Plugins/ConformalDecals.dll differ
diff --git a/Source/ConformalDecals/ConformalDecals.csproj b/Source/ConformalDecals/ConformalDecals.csproj
index b6a10d0..fd8404b 100644
--- a/Source/ConformalDecals/ConformalDecals.csproj
+++ b/Source/ConformalDecals/ConformalDecals.csproj
@@ -89,7 +89,7 @@
-
+
diff --git a/Source/ConformalDecals/ModuleConformalText.cs b/Source/ConformalDecals/ModuleConformalText.cs
index 6e3615a..018e204 100644
--- a/Source/ConformalDecals/ModuleConformalText.cs
+++ b/Source/ConformalDecals/ModuleConformalText.cs
@@ -1,38 +1,129 @@
using ConformalDecals.Text;
using ConformalDecals.UI;
+using ConformalDecals.Util;
+using TMPro;
using UnityEngine;
namespace ConformalDecals {
- public class ModuleConformalText : ModuleConformalDecal {
- [KSPField(isPersistant = true)] public string text = "Hello World!";
+ public class ModuleConformalText : ModuleConformalDecal, ISerializationCallbackReceiver {
+ [KSPField(isPersistant = true)] public string text = "Hello World!";
+ [KSPField(isPersistant = true)] public Color fillColor = Color.black;
+ [KSPField(isPersistant = true)] public Color outlineColor = Color.white;
+
+ // serialization-only fields. do not use except in serialization functions
[KSPField(isPersistant = true)] public string fontName = "Calibri SDF";
[KSPField(isPersistant = true)] public int style;
[KSPField(isPersistant = true)] public bool vertical;
- [KSPField(isPersistant = true)] public Color fillColor = Color.black;
- [KSPField(isPersistant = true)] public Color outlineColor = Color.white;
- [KSPField(isPersistant = true)] public float outlineWidth;
+ [KSPField(isPersistant = true)] public float lineSpacing;
+ [KSPField(isPersistant = true)] public float characterSpacing;
+
+ // KSP TWEAKABLES
+
+ [KSPEvent(guiName = "#LOC_ConformalDecals_gui-set-text", guiActive = false, guiActiveEditor = true)]
+ public void SetText() {
+ if (_textEntryController == null) {
+ _textEntryController = TextEntryController.Create(text, _font, _style, OnTextUpdate);
+ }
+ }
+
+ // FILL
+
+ [KSPField(guiName = "#LOC_ConformalDecals_gui-fill", groupName = "decal-fill", groupDisplayName = "#LOC_ConformalDecals_gui-group-fill",
+ guiActive = false, guiActiveEditor = true, isPersistant = true),
+ UI_Toggle()]
+ public bool fillEnabled = true;
+
+ [KSPEvent(guiName = "#LOC_ConformalDecals_gui-fill-color", groupName = "decal-fill", groupDisplayName = "#LOC_ConformalDecals_gui-group-fill",
+ guiActive = false, guiActiveEditor = true)]
+ public void SetFillColor() {
+ if (_fillColorPickerController == null) {
+ _fillColorPickerController = ColorPickerController.Create(fillColor, OnFillColorUpdate);
+ }
+ }
+
+ // OUTLINE
+
+ [KSPField(guiName = "#LOC_ConformalDecals_gui-outline", groupName = "decal-outline", groupDisplayName = "#LOC_ConformalDecals_gui-group-outline",
+ guiActive = false, guiActiveEditor = true, isPersistant = true),
+ UI_Toggle()]
+ public bool outlineEnabled;
+
+ [KSPField(guiName = "#LOC_ConformalDecals_gui-outline-width", groupName = "decal-outline", groupDisplayName = "#LOC_ConformalDecals_gui-group-outline",
+ guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2"),
+ UI_FloatRange(stepIncrement = 0.05f)]
+ public float outlineWidth = 0.1f;
+
+ [KSPEvent(guiName = "#LOC_ConformalDecals_gui-set-outline-color", groupName = "decal-outline", groupDisplayName = "#LOC_ConformalDecals_gui-group-outline",
+ guiActive = false, guiActiveEditor = true)]
+ public void SetOutlineColor() {
+ if (_outlineColorPickerCOntroller == null) {
+ _outlineColorPickerCOntroller = ColorPickerController.Create(outlineColor, OnOutlineColorUpdate);
+ }
+ }
private DecalTextStyle _style;
- private DecalFont _font;
-
+ private DecalFont _font;
+
private TextEntryController _textEntryController;
private ColorPickerController _fillColorPickerController;
private ColorPickerController _outlineColorPickerCOntroller;
+ public override void OnLoad(ConfigNode node) {
+ base.OnLoad(node);
+ OnAfterDeserialize();
+ }
+
+ public override void OnSave(ConfigNode node) {
+ OnBeforeSerialize();
+ base.OnSave(node);
+ }
+
public override void OnStart(StartState state) {
base.OnStart(state);
_font = DecalConfig.GetFont(fontName);
_style = new DecalTextStyle();
+ // handle tweakables
+
+ if (HighLogic.LoadedSceneIsEditor) {
+ GameEvents.onEditorPartEvent.Add(OnEditorEvent);
+ }
- var decalText = new DecalText("Hello World!", _font, _style);
-
//TextRenderer.Instance.RenderText(decalText, out var texture, out var window);
//materialProperties.AddOrGetTextureProperty("_Decal", true).Texture = texture;
UpdateMaterials();
UpdateScale();
}
+ public override void OnDestroy() {
+ base.OnDestroy();
+ this.Log("OnDestroy");
+
+ if (HighLogic.LoadedSceneIsEditor) {
+ GameEvents.onEditorPartEvent.Remove(OnEditorEvent);
+ }
+ }
+
+ public void OnPartDeleted() {
+ this.Log("OnPartDeleted");
+ }
+
+ public void OnPartSymmetryDeleted() {
+ this.Log("OnPartSymmetryDeleted");
+ }
+
+ protected new void OnEditorEvent(ConstructionEventType eventType, Part eventPart) {
+ if (eventPart != part) return;
+ switch (eventType) {
+ case ConstructionEventType.PartSymmetryDeleted:
+ OnPartSymmetryDeleted();
+ break;
+ case ConstructionEventType.PartDeleted:
+ OnPartDeleted();
+ break;
+ }
+ }
+
public void OnTextUpdate(string newText, DecalFont newFont, DecalTextStyle newStyle) {
text = newText;
_font = newFont;
@@ -40,32 +131,40 @@ namespace ConformalDecals {
}
public void OnFillColorUpdate(Color rgb, Util.ColorHSV hsv) {
+ fillColor = rgb;
Debug.Log($"new fill color: {rgb}, {hsv}");
}
public void OnOutlineColorUpdate(Color rgb, Util.ColorHSV hsv) {
+ outlineColor = rgb;
Debug.Log($"new outline color: {rgb}, {hsv}");
}
- [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_ConformalDecals_gui-select-flag")]
- public void SetText() {
- if (_textEntryController == null) {
- _textEntryController = TextEntryController.Create(text, _font, _style, OnTextUpdate);
+ public void OnFillToggle() {
+ if (!fillEnabled && !outlineEnabled) {
+ outlineEnabled = true;
+ OnOutlineToggle();
}
}
- [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Set Fill Color")]
- public void SetFillColor() {
- if (_fillColorPickerController == null) {
- _fillColorPickerController = ColorPickerController.Create(fillColor, OnFillColorUpdate);
+ public void OnOutlineToggle() {
+ if (!fillEnabled && !outlineEnabled) {
+ fillEnabled = true;
+ OnFillToggle();
}
}
- [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Set Outline Color")]
- public void SetOutlineColor() {
- if (_outlineColorPickerCOntroller == null) {
- _outlineColorPickerCOntroller = ColorPickerController.Create(outlineColor, OnOutlineColorUpdate);
- }
+ public void OnBeforeSerialize() {
+ fontName = _font.Name;
+ style = (int) _style.FontStyle;
+ vertical = _style.Vertical;
+ lineSpacing = _style.LineSpacing;
+ characterSpacing = _style.CharacterSpacing;
+ }
+
+ public void OnAfterDeserialize() {
+ _font = DecalConfig.GetFont(fontName);
+ _style = new DecalTextStyle((FontStyles) style, vertical, lineSpacing, characterSpacing);
}
}
}
\ No newline at end of file
diff --git a/Source/ConformalDecals/Text/TextRenderJob.cs b/Source/ConformalDecals/Text/TextRenderJob.cs
index 0d17cbd..b1128ce 100644
--- a/Source/ConformalDecals/Text/TextRenderJob.cs
+++ b/Source/ConformalDecals/Text/TextRenderJob.cs
@@ -10,19 +10,19 @@ namespace ConformalDecals.Text {
public bool IsDone { get; private set; }
public readonly TextRenderer.TextRenderEvent onRenderFinished = new TextRenderer.TextRenderEvent();
-
- public TextRenderJob(DecalText oldText, DecalText newText, UnityAction renderFinishedCallback) {
+
+ public TextRenderJob(DecalText oldText, DecalText newText, UnityAction renderFinishedCallback) {
OldText = oldText ?? throw new ArgumentNullException(nameof(oldText));
NewText = newText ?? throw new ArgumentNullException(nameof(newText));
Needed = true;
-
+
if (renderFinishedCallback != null) onRenderFinished.AddListener(renderFinishedCallback);
}
-
- public TextRenderJob( DecalText newText, UnityAction renderFinishedCallback) {
+
+ public TextRenderJob(DecalText newText, UnityAction renderFinishedCallback) {
NewText = newText ?? throw new ArgumentNullException(nameof(newText));
Needed = true;
-
+
if (renderFinishedCallback != null) onRenderFinished.AddListener(renderFinishedCallback);
}
@@ -34,7 +34,7 @@ namespace ConformalDecals.Text {
IsStarted = true;
}
- public void Finish(RenderedText output) {
+ public void Finish(TextRenderOutput output) {
IsDone = true;
onRenderFinished.Invoke(output);
}
diff --git a/Source/ConformalDecals/Text/RenderedText.cs b/Source/ConformalDecals/Text/TextRenderOutput.cs
similarity index 73%
rename from Source/ConformalDecals/Text/RenderedText.cs
rename to Source/ConformalDecals/Text/TextRenderOutput.cs
index fc31ae4..f90caa0 100644
--- a/Source/ConformalDecals/Text/RenderedText.cs
+++ b/Source/ConformalDecals/Text/TextRenderOutput.cs
@@ -1,14 +1,14 @@
using UnityEngine;
namespace ConformalDecals.Text {
- public class RenderedText {
+ public class TextRenderOutput {
public Texture2D Texture { get; private set; }
public Rect Window { get; private set; }
public int UserCount { get; set; }
- public RenderedText(Texture2D texture, Rect window) {
+ public TextRenderOutput(Texture2D texture, Rect window) {
Texture = texture;
Window = window;
}
diff --git a/Source/ConformalDecals/Text/TextRenderer.cs b/Source/ConformalDecals/Text/TextRenderer.cs
index 8cd57df..d07d882 100644
--- a/Source/ConformalDecals/Text/TextRenderer.cs
+++ b/Source/ConformalDecals/Text/TextRenderer.cs
@@ -21,7 +21,7 @@ namespace ConformalDecals.Text {
}
[Serializable]
- public class TextRenderEvent : UnityEvent { }
+ public class TextRenderEvent : UnityEvent { }
private const string BlitShader = "ConformalDecals/Text Blit";
private const int MaxTextureSize = 4096;
@@ -34,26 +34,26 @@ namespace ConformalDecals.Text {
private TextMeshPro _tmp;
private Material _blitMaterial;
- private readonly Dictionary _renderCache = new Dictionary();
- private readonly Queue _renderJobs = new Queue();
+ private static readonly Dictionary RenderCache = new Dictionary();
+ private static readonly Queue RenderJobs = new Queue();
- public TextRenderJob RenderText(DecalText text, UnityAction renderFinishedCallback) {
+ public static TextRenderJob RenderText(DecalText text, UnityAction renderFinishedCallback) {
var job = new TextRenderJob(text, renderFinishedCallback);
- _renderJobs.Enqueue(job);
+ RenderJobs.Enqueue(job);
return job;
}
- public TextRenderJob UpdateText(DecalText oldText, DecalText newText, UnityAction renderFinishedCallback) {
+ public static TextRenderJob UpdateText(DecalText oldText, DecalText newText, UnityAction renderFinishedCallback) {
var job = new TextRenderJob(oldText, newText, renderFinishedCallback);
- _renderJobs.Enqueue(job);
+ RenderJobs.Enqueue(job);
return job;
}
- public void UnregisterText(DecalText text) {
- if (_renderCache.TryGetValue(text, out var renderedText)) {
+ public static void UnregisterText(DecalText text) {
+ if (RenderCache.TryGetValue(text, out var renderedText)) {
renderedText.UserCount--;
if (renderedText.UserCount <= 0) {
- _renderCache.Remove(text);
+ RenderCache.Remove(text);
Destroy(renderedText.Texture);
}
}
@@ -70,13 +70,12 @@ namespace ConformalDecals.Text {
}
private void Update() {
- TextRenderJob nextJob;
+ bool renderNeeded;
do {
- if (_renderJobs.Count <= 0) return;
- nextJob = _renderJobs.Dequeue();
- } while (nextJob.Needed);
-
- RunJob(nextJob);
+ if (RenderJobs.Count <= 0) return;
+ var nextJob = RenderJobs.Dequeue();
+ renderNeeded = nextJob.Needed && RunJob(nextJob);
+ } while (!renderNeeded);
}
private void Setup() {
@@ -94,47 +93,48 @@ namespace ConformalDecals.Text {
_isSetup = true;
}
- private void RunJob(TextRenderJob job) {
- Debug.Log($"Starting Text Rendering Job. queue depth = {_renderJobs.Count}, cache size = {_renderCache.Count}");
+ private bool RunJob(TextRenderJob job) {
+ Debug.Log($"Starting Text Rendering Job. queue depth = {RenderJobs.Count}, cache size = {RenderCache.Count}");
job.Start();
-
+
Texture2D texture = null;
- if (job.OldText != null && _renderCache.TryGetValue(job.OldText, out var oldRender)) {
+ if (job.OldText != null && RenderCache.TryGetValue(job.OldText, out var oldRender)) {
// old output still exists
oldRender.UserCount--;
-
+
if (oldRender.UserCount <= 0) {
// this is the only usage of this output, so we are free to re-render into the texture
Debug.Log("Render output is not shared with other users, so reusing texture and removing cache slot");
-
+
texture = oldRender.Texture;
- _renderCache.Remove(job.OldText);
+ RenderCache.Remove(job.OldText);
}
else {
// other things are using this render output, so decriment usercount, and we'll make a new entry instead
Debug.Log("Render output is shared with other users, so making new output");
}
}
-
+
// now that all old references are handled, begin rendering the new output
- if (_renderCache.TryGetValue(job.NewText, out var cachedRender)) {
+ if (RenderCache.TryGetValue(job.NewText, out var cachedRender)) {
Debug.Log("Using Cached Render Output");
- Debug.Log($"Finished Text Rendering Job. queue depth = {_renderJobs.Count}, cache size = {_renderCache.Count}");
+ Debug.Log($"Finished Text Rendering Job. queue depth = {RenderJobs.Count}, cache size = {RenderCache.Count}");
cachedRender.UserCount++;
- return;
+ return false;
}
var output = RenderText(job.NewText, texture);
- _renderCache.Add(job.NewText, output);
-
+ RenderCache.Add(job.NewText, output);
+
job.Finish(output);
- Debug.Log($"Finished Text Rendering Job. queue depth = {_renderJobs.Count}, cache size = {_renderCache.Count}");
+ Debug.Log($"Finished Text Rendering Job. queue depth = {RenderJobs.Count}, cache size = {RenderCache.Count}");
+ return true;
}
- public RenderedText RenderText(DecalText text, Texture2D texture) {
+ public TextRenderOutput RenderText(DecalText text, Texture2D texture) {
// SETUP TMP OBJECT FOR RENDERING
_tmp.text = text.FormattedText;
_tmp.font = text.Font.FontAsset;
@@ -220,7 +220,7 @@ namespace ConformalDecals.Text {
// RELEASE RENDERTEX
RenderTexture.ReleaseTemporary(renderTex);
- return new RenderedText(texture, window);
+ return new TextRenderOutput(texture, window);
}
}
}
\ No newline at end of file