diff --git a/GameData/ConformalDecals/Plugins/ConformalDecals.dll b/GameData/ConformalDecals/Plugins/ConformalDecals.dll
index e428004..fdb9d12 100644
--- a/GameData/ConformalDecals/Plugins/ConformalDecals.dll
+++ b/GameData/ConformalDecals/Plugins/ConformalDecals.dll
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f6f3c4a2f97982581ebc02fe5616f7be9c29cd2bc912201f9c5e0492de527785
-size 86528
+oid sha256:f4aa6f0c532cc3b47d31cca7c4f5d8052aa31416f858523da2f1418bfa73f2cb
+size 82944
diff --git a/Source/ConformalDecals/ConformalDecals.csproj b/Source/ConformalDecals/ConformalDecals.csproj
index 7def1b9..6d11eb6 100644
--- a/Source/ConformalDecals/ConformalDecals.csproj
+++ b/Source/ConformalDecals/ConformalDecals.csproj
@@ -100,7 +100,6 @@
-
diff --git a/Source/ConformalDecals/Text/DecalFont.cs b/Source/ConformalDecals/Text/DecalFont.cs
index 45ec8f7..efa0b6e 100644
--- a/Source/ConformalDecals/Text/DecalFont.cs
+++ b/Source/ConformalDecals/Text/DecalFont.cs
@@ -6,13 +6,17 @@ using UniLinq;
namespace ConformalDecals.Text {
public class DecalFont : IEquatable {
+ /// Human-readable name for the font
public string Title { get; }
- public TMP_FontAsset FontAsset { get; }
-
+ /// Internal name for the font
public string Name => FontAsset.name;
+ /// The font asset itself
+ public TMP_FontAsset FontAsset { get; }
+ /// Styles that are forced on for this font,
+ /// e.g. smallcaps for a font without lower case characters
public FontStyles FontStyle { get; }
public bool Bold => (FontStyle & FontStyles.Bold) != 0;
@@ -23,7 +27,8 @@ namespace ConformalDecals.Text {
public bool SmallCaps => (FontStyle & FontStyles.SmallCaps) != 0;
-
+ /// Styles that are forced off for this font,
+ /// e.g. underline for a font with no underscore character
public FontStyles FontStyleMask { get; }
public bool BoldMask => (FontStyleMask & FontStyles.Bold) != 0;
diff --git a/Source/ConformalDecals/Text/DecalText.cs b/Source/ConformalDecals/Text/DecalText.cs
index 07ff603..c974292 100644
--- a/Source/ConformalDecals/Text/DecalText.cs
+++ b/Source/ConformalDecals/Text/DecalText.cs
@@ -3,12 +3,16 @@ using System.Text.RegularExpressions;
namespace ConformalDecals.Text {
public class DecalText : IEquatable {
+ /// Raw text contents
public string Text { get; }
+ /// Font asset used by this text snippet
public DecalFont Font { get; }
+ /// Style used by this text snippet
public DecalTextStyle Style { get; }
+ /// The text formatted with newlines for vertical text
public string FormattedText {
get {
if (Style.Vertical) {
diff --git a/Source/ConformalDecals/Text/DecalTextStyle.cs b/Source/ConformalDecals/Text/DecalTextStyle.cs
index 528c995..ac55fc3 100644
--- a/Source/ConformalDecals/Text/DecalTextStyle.cs
+++ b/Source/ConformalDecals/Text/DecalTextStyle.cs
@@ -1,14 +1,15 @@
using System;
using TMPro;
using UnityEngine;
+
// ReSharper disable NonReadonlyMemberInGetHashCode
namespace ConformalDecals.Text {
public struct DecalTextStyle : IEquatable {
private FontStyles _fontStyle;
- private bool _vertical;
- private float _lineSpacing;
- private float _charSpacing;
+ private bool _vertical;
+ private float _lineSpacing;
+ private float _charSpacing;
public FontStyles FontStyle {
get => _fontStyle;
@@ -61,7 +62,7 @@ namespace ConformalDecals.Text {
get => _charSpacing;
set => _charSpacing = value;
}
-
+
public DecalTextStyle(FontStyles fontStyle, bool vertical, float lineSpacing, float charSpacing) {
_fontStyle = fontStyle;
_vertical = vertical;
@@ -70,7 +71,7 @@ namespace ConformalDecals.Text {
}
public bool Equals(DecalTextStyle other) {
- return FontStyle == other.FontStyle && Vertical == other.Vertical &&
+ return FontStyle == other.FontStyle && Vertical == other.Vertical &&
Mathf.Approximately(LineSpacing, other.LineSpacing) &&
Mathf.Approximately(CharSpacing, other.CharSpacing);
}
diff --git a/Source/ConformalDecals/Text/FontLoader.cs b/Source/ConformalDecals/Text/FontLoader.cs
index 76351cb..ddb13e5 100644
--- a/Source/ConformalDecals/Text/FontLoader.cs
+++ b/Source/ConformalDecals/Text/FontLoader.cs
@@ -6,6 +6,7 @@ using UniLinq;
using UnityEngine;
namespace ConformalDecals.Text {
+ /// KSP database loader for KSPFont files which contain TextMeshPro font assets
[DatabaseLoaderAttrib(new[] {"kspfont"})]
public class FontLoader : DatabaseLoader {
private const string FallbackName = "NotoSans-Regular SDF";
diff --git a/Source/ConformalDecals/Text/TextRenderOutput.cs b/Source/ConformalDecals/Text/TextRenderOutput.cs
index 035bda5..210e14a 100644
--- a/Source/ConformalDecals/Text/TextRenderOutput.cs
+++ b/Source/ConformalDecals/Text/TextRenderOutput.cs
@@ -1,11 +1,15 @@
using UnityEngine;
namespace ConformalDecals.Text {
+ /// Texture render output, used for cacheing and is the datastructure returned to the ModuleConformalText class
public class TextRenderOutput {
+ /// Texture with the rendered text
public Texture2D Texture { get; private set; }
+ /// The rectangle that the rendered text takes up within the texture
public Rect Window { get; private set; }
-
+
+ /// The number of users for this render output. If 0, it can be discarded from the cache and the texture reused
public int UserCount { get; set; }
public TextRenderOutput(Texture2D texture, Rect window) {
diff --git a/Source/ConformalDecals/Text/TextRenderer.cs b/Source/ConformalDecals/Text/TextRenderer.cs
index 44d1d62..f7eb319 100644
--- a/Source/ConformalDecals/Text/TextRenderer.cs
+++ b/Source/ConformalDecals/Text/TextRenderer.cs
@@ -5,11 +5,21 @@ using UnityEngine;
using UnityEngine.Events;
namespace ConformalDecals.Text {
+ // TODO: Testing shows the job system is unnecessary, so remove job system code.
+
+ /// Class handing text rendering.
+ /// Is a singleton referencing a single gameobject in the scene which contains the TextMeshPro component
[KSPAddon(KSPAddon.Startup.Instantly, true)]
public class TextRenderer : MonoBehaviour {
- public const TextureFormat TextTextureFormat = TextureFormat.RG16;
+ /// Texture format used for returned textures.
+ /// Unfortunately due to how Unity textures work, this cannot be R8 or Alpha8,
+ /// so theres always a superfluous green channel using memory
+ public const TextureFormat TextTextureFormat = TextureFormat.RG16;
+
+ /// Render Texture format used when rendering
public const RenderTextureFormat TextRenderTextureFormat = RenderTextureFormat.R8;
+ /// The text renderer object within the scene which contains the TextMeshPro component used for rendering.
public static TextRenderer Instance {
get {
if (!_instance._isSetup) {
@@ -20,6 +30,7 @@ namespace ConformalDecals.Text {
}
}
+ /// Text Render unityevent, used with the job system to signal render completion
[Serializable]
public class TextRenderEvent : UnityEvent { }
@@ -37,7 +48,7 @@ namespace ConformalDecals.Text {
private static readonly Dictionary RenderCache = new Dictionary();
private static readonly Queue RenderJobs = new Queue();
- // Update text using the job queue
+ /// Update text using the job queue
public static TextRenderJob UpdateText(DecalText oldText, DecalText newText, UnityAction renderFinishedCallback) {
if (newText == null) throw new ArgumentNullException(nameof(newText));
@@ -46,14 +57,14 @@ namespace ConformalDecals.Text {
return job;
}
- // Update text immediately without using job queue
+ /// Update text immediately without using job queue
public static TextRenderOutput UpdateTextNow(DecalText oldText, DecalText newText) {
if (newText == null) throw new ArgumentNullException(nameof(newText));
return Instance.RunJob(new TextRenderJob(oldText, newText, null), out _);
}
- // Unregister a user of a piece of text
+ /// Unregister a user of a piece of text
public static void UnregisterText(DecalText text) {
Debug.Log($"[ConformalDecals] Unregistering text '{text.Text}'");
if (RenderCache.TryGetValue(text, out var renderedText)) {
@@ -75,6 +86,7 @@ namespace ConformalDecals.Text {
DontDestroyOnLoad(gameObject);
}
+ /// Setup this text renderer instance for rendering
private void Setup() {
if (_isSetup) return;
@@ -89,7 +101,7 @@ namespace ConformalDecals.Text {
_isSetup = true;
}
- // Run a text render job
+ /// Run a text render job
private TextRenderOutput RunJob(TextRenderJob job, out bool renderNeeded) {
if (!job.Needed) {
renderNeeded = false;
@@ -100,6 +112,7 @@ namespace ConformalDecals.Text {
foreach (var cacheitem in RenderCache) {
Debug.Log($"[ConformalDecals] Cache item: '{cacheitem.Key.Text}' with {cacheitem.Value.UserCount} users");
}
+
job.Start();
Texture2D texture = null;
@@ -134,16 +147,16 @@ namespace ConformalDecals.Text {
}
renderOutput.UserCount++;
-
+
job.Finish(renderOutput);
return renderOutput;
}
- // Render a piece of text to a given texture
+ /// Render a piece of text to a given texture
public TextRenderOutput RenderText(DecalText text, Texture2D texture) {
if (text == null) throw new ArgumentNullException(nameof(text));
if (_tmp == null) throw new InvalidOperationException("TextMeshPro object not yet created.");
-
+
// SETUP TMP OBJECT FOR RENDERING
_tmp.text = text.FormattedText;
_tmp.font = text.Font.FontAsset;
@@ -171,13 +184,13 @@ namespace ConformalDecals.Text {
// SETUP MATERIALS AND BOUNDS
for (int i = 0; i < meshFilters.Length; i++) {
var renderer = meshFilters[i].gameObject.GetComponent();
-
+
meshes[i] = meshFilters[i].mesh;
if (i == 0) meshes[i] = _tmp.mesh;
materials[i] = Instantiate(renderer.material);
materials[i].shader = _blitShader;
-
+
if (renderer == null) throw new FormatException($"Object {meshFilters[i].gameObject.name} has filter but no renderer");
if (meshes[i] == null) throw new FormatException($"Object {meshFilters[i].gameObject.name} has a null mesh");
diff --git a/Source/ConformalDecals/Util/TextureUtils.cs b/Source/ConformalDecals/Util/TextureUtils.cs
deleted file mode 100644
index f835afe..0000000
--- a/Source/ConformalDecals/Util/TextureUtils.cs
+++ /dev/null
@@ -1,263 +0,0 @@
-using UnityEngine;
-
-namespace ConformalDecals.Util {
- public static class TextureUtils {
- public enum BlitMode {
- Set,
- Add,
- }
-
- public static Color32 AddColor32(Color32 color1, Color32 color2) {
- return new Color32((byte) (color1.r + color2.r), (byte) (color1.g + color2.g), (byte) (color1.b + color2.b), (byte) (color1.a + color2.a));
- }
-
- public static Color32 AddColor32Clamped(Color32 color1, Color32 color2) {
- var r = color1.r + color2.r;
- var g = color1.g + color2.g;
- var b = color1.b + color2.b;
- var a = color1.a + color2.a;
- if (r > byte.MaxValue) r = byte.MaxValue;
- if (g > byte.MaxValue) g = byte.MaxValue;
- if (b > byte.MaxValue) b = byte.MaxValue;
- if (a > byte.MaxValue) a = byte.MaxValue;
-
- return new Color32((byte) r, (byte) g, (byte) b, (byte) a);
- }
-
- public static void ClearTexture(Color32[] colors, Color32 clearColor = default) {
- for (var i = 0; i < colors.Length; i++) {
- colors[i] = clearColor;
- }
- }
-
- public static void BlitRectAlpha(
- Texture2D src, Color32[] srcColors, Vector2Int srcPos,
- Texture2D dst, Color32[] dstColors, Vector2Int dstPos,
- Vector2Int size, BlitMode mode) {
-
- ClipRect(src, ref srcPos, dst, ref dstPos, ref size);
-
- if (size.x <= 0 || size.y <= 0) return;
-
- int srcIndex = srcPos.x + srcPos.y * src.width;
- int dstIndex = dstPos.x + dstPos.y * dst.width;
-
- for (int dy = size.y - 1; dy >= 0; dy--) {
-
- for (int dx = size.x - 1; dx >= 0; dx--) {
- switch (mode) {
- case BlitMode.Set:
- dstColors[dstIndex + dx].a = srcColors[srcIndex + dx].a;
- break;
- case BlitMode.Add:
- var s = srcColors[srcIndex + dx].a;
- var d = dstColors[dstIndex + dx].a;
- var sum = s + d;
- if (sum > byte.MaxValue) sum = byte.MaxValue;
- dstColors[dstIndex + dx].a = (byte) sum;
- break;
- }
- }
-
- srcIndex += src.width;
- dstIndex += dst.width;
- }
- }
-
- public static void BlitRect(
- Texture2D src, Color32[] srcColors, Vector2Int srcPos,
- Texture2D dst, Color32[] dstColors, Vector2Int dstPos,
- Vector2Int size, BlitMode mode) {
-
- ClipRect(src, ref srcPos, dst, ref dstPos, ref size);
-
- if (size.x <= 0 || size.y <= 0) return;
-
- int srcIndex = srcPos.x + srcPos.y * src.width;
- int dstIndex = dstPos.x + dstPos.y * dst.width;
-
- for (int dy = 0; dy < size.y; dy++) {
-
- for (int dx = 0; dx < size.x; dx++) {
- switch (mode) {
- case BlitMode.Set:
- dstColors[dstIndex + dx] = srcColors[srcIndex + dx];
- break;
- case BlitMode.Add:
- dstColors[dstIndex + dx] = AddColor32Clamped(srcColors[srcIndex + dx], dstColors[dstIndex + dx]);
- break;
- }
- }
-
- srcIndex += src.width;
- dstIndex += dst.width;
- }
- }
-
- public static void BlitRectBilinearAlpha(
- Texture2D src, Vector2Int srcPos, Vector2 srcSize,
- Texture2D dst, Color32[] dstColors, Vector2Int dstPos, Vector2Int dstSize,
- BlitMode mode) {
-
- var sizeRatio = dstSize / srcSize;
-
- ClipRect(src, ref srcPos, dst, ref dstPos, ref srcSize, ref dstSize);
-
- if (dstSize.x <= 0 || dstSize.y <= 0) return;
-
- var srcPixel = new Vector2(1.0f / src.width, 1.0f / src.height);
- var srcStart = (srcPos * srcPixel) + (srcPixel / 2);
- var srcStep = sizeRatio * srcPixel;
- var srcY = srcStart.y;
-
- int dstIndex = dstPos.x + dstPos.y * dst.width;
- for (int dy = 0;
- dy < dstSize.y;
- dy++) {
- var srcX = srcStart.x;
-
- for (int dx = 0; dx < dstSize.x; dx++) {
- switch (mode) {
- case BlitMode.Set:
- dstColors[dstIndex + dx].a = (byte) (src.GetPixelBilinear(srcX, srcY).a * byte.MaxValue);
- break;
- case BlitMode.Add:
- var s = (byte) (src.GetPixelBilinear(srcX, srcY).a * byte.MaxValue);
- var d = dstColors[dstIndex + dx].a;
- var sum = s + d;
- if (sum > byte.MaxValue) sum = byte.MaxValue;
- dstColors[dstIndex + dx].a = (byte) sum;
- break;
- }
-
- srcX += srcStep.x;
- }
-
- srcY += srcStep.y;
- dstIndex += dst.width;
- }
- }
-
- public static void BlitRectBilinear(
- Texture2D src, Vector2Int srcPos, Vector2 srcSize,
- Texture2D dst, Color32[] dstColors, Vector2Int dstPos, Vector2Int dstSize,
- BlitMode mode) {
-
- var sizeRatio = dstSize / srcSize;
-
- ClipRect(src, ref srcPos, dst, ref dstPos, ref srcSize, ref dstSize);
-
- if (dstSize.x <= 0 || dstSize.y <= 0) return;
-
- var srcPixel = new Vector2(1.0f / src.width, 1.0f / src.height);
- var srcStart = (srcPos * srcPixel) + (srcPixel / 2);
- var srcStep = sizeRatio * srcPixel;
- var srcY = srcStart.y;
-
- int dstIndex = dstPos.x + dstPos.y * dst.width;
- for (int dy = 0;
- dy < dstSize.y;
- dy++) {
- var srcX = srcStart.x;
-
- for (int dx = 0; dx < dstSize.x; dx++) {
- switch (mode) {
- case BlitMode.Set:
- dstColors[dstIndex + dx] = src.GetPixelBilinear(srcX, srcY);
- break;
- case BlitMode.Add:
- dstColors[dstIndex + dx] = AddColor32Clamped(src.GetPixelBilinear(srcX, srcY), dstColors[dstIndex + dx]);
- break;
- }
-
- srcX += srcStep.x;
- }
-
- srcY += srcStep.y;
- dstIndex += dst.width;
- }
- }
-
- private static void ClipRect(Texture2D src, ref Vector2Int srcPos, Texture2D dst, ref Vector2Int dstPos, ref Vector2Int size) {
- if (srcPos.x < 0) {
- size.x += srcPos.x;
- dstPos.x -= srcPos.x;
- srcPos.x = 0;
- }
-
- if (srcPos.y < 0) {
- size.y += srcPos.y;
- dstPos.y -= srcPos.y;
- srcPos.y = 0;
- }
-
- if (dstPos.x < 0) {
- size.x += dstPos.x;
- srcPos.x -= dstPos.x;
- dstPos.x = 0;
- }
-
- if (dstPos.y < 0) {
- size.y += dstPos.y;
- srcPos.y -= dstPos.y;
- dstPos.y = 0;
- }
-
- if (srcPos.x + size.x > src.width) size.x = src.width - srcPos.x;
- if (srcPos.y + size.y > src.height) size.y = src.height - srcPos.y;
- if (dstPos.x + size.x > dst.width) size.x = dst.width - srcPos.x;
- if (dstPos.y + size.y > dst.height) size.y = dst.height - srcPos.y;
- }
-
- private static void ClipRect(Texture2D src, ref Vector2Int srcPos, Texture2D dst, ref Vector2Int dstPos, ref Vector2 srcSize, ref Vector2Int dstSize) {
- var sizeRatio = dstSize / srcSize;
- if (srcPos.x < 0) {
- dstSize.x += (int) (srcPos.x * sizeRatio.x);
- dstPos.x -= (int) (srcPos.x * sizeRatio.x);
- srcSize.x += srcPos.x;
- srcPos.x = 0;
- }
-
- if (srcPos.y < 0) {
- dstSize.y += (int) (srcPos.y * sizeRatio.y);
- dstPos.y -= (int) (srcPos.y * sizeRatio.y);
- srcSize.y += srcPos.y;
- srcPos.y = 0;
- }
-
- if (dstPos.x < 0) {
- srcSize.x += dstPos.x / sizeRatio.x;
- srcPos.x -= (int) (dstPos.x / sizeRatio.x);
- dstSize.x += dstPos.x;
- dstPos.x = 0;
- }
-
- if (dstPos.y < 0) {
- srcSize.y += dstPos.y / sizeRatio.y;
- srcPos.y -= (int) (dstPos.y / sizeRatio.y);
- dstSize.y += dstPos.y;
- dstPos.y = 0;
- }
-
- if (srcPos.x + srcSize.x > src.width) {
- srcSize.x = src.width - srcPos.x;
- dstSize.x = (int) (srcSize.x * sizeRatio.x);
- }
-
- if (srcPos.y + srcSize.y > src.height) {
- srcSize.y = src.height - srcPos.y;
- dstSize.y = (int) (srcSize.y * sizeRatio.y);
- }
-
- if (dstPos.x + dstSize.x > dst.width) {
- dstSize.x = dst.width - srcPos.x;
- srcSize.x = (int) (dstSize.x / sizeRatio.x);
- }
-
- if (dstPos.y + dstSize.y > dst.height) {
- dstSize.y = dst.height - srcPos.y;
- srcSize.y = (int) (dstSize.y / sizeRatio.y);
- }
- }
- }
-}
\ No newline at end of file