diff --git a/.gitignore b/.gitignore
index 56251b1..7fb5c0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
Assets/*
!Assets/Shaders/
!Assets/Textures/
+!Assets/Scripts/
KSP/
Library/
Logs/
diff --git a/Assets/Plugins/DecalProjectorTest.cs b/Assets/Scripts/DecalProjectorTest.cs
similarity index 100%
rename from Assets/Plugins/DecalProjectorTest.cs
rename to Assets/Scripts/DecalProjectorTest.cs
diff --git a/Assets/Scripts/TextRenderTest.cs b/Assets/Scripts/TextRenderTest.cs
new file mode 100644
index 0000000..8369fe3
--- /dev/null
+++ b/Assets/Scripts/TextRenderTest.cs
@@ -0,0 +1,90 @@
+using System.Collections;
+using System.Collections.Generic;
+using TMPro;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+public class TextRenderTest : MonoBehaviour {
+ //[InspectorButton("go")] public bool button;
+
+ public Camera _camera;
+
+ public GameObject _cameraObject;
+
+ public TextMeshPro _tmp;
+
+ public Material _blitMaterial;
+
+ public Material _targetMaterial;
+
+ public RenderTexture renderTex;
+ private float pixelDensity = 36;
+ private int MaxTextureSize = 4096;
+
+ public const TextureFormat TextTextureFormat = TextureFormat.RG16;
+ public const RenderTextureFormat TextRenderTextureFormat = RenderTextureFormat.R8;
+
+ // Start is called before the first frame update
+ void Start() {
+ Debug.Log("starting...");
+
+ StartCoroutine(OnRender());
+ }
+
+ // Update is called once per frame
+ void Update() {
+ }
+
+ private void go() {
+ Debug.Log("starting...");
+ }
+
+ private IEnumerator OnRender() {
+ Debug.Log("starting...2");
+
+ // calculate camera and texture size
+ _tmp.ForceMeshUpdate();
+ var mesh = _tmp.mesh;
+ mesh.RecalculateBounds();
+ var bounds = mesh.bounds;
+ Debug.Log(bounds.size);
+
+ var width = Mathf.NextPowerOfTwo((int) (bounds.size.x * pixelDensity));
+ var height = Mathf.NextPowerOfTwo((int) (bounds.size.y * pixelDensity));
+
+ Debug.Log($"width = {width}");
+ Debug.Log($"height = {height}");
+
+ _camera.orthographicSize = height / pixelDensity / 2;
+ _camera.aspect = (float) width / height;
+
+ _cameraObject.transform.localPosition = new Vector3(bounds.center.x, bounds.center.y, -1);
+
+ width = Mathf.Min(width, MaxTextureSize);
+ height = Mathf.Min(height, MaxTextureSize);
+
+ // setup texture
+ var texture = new Texture2D(width, height, TextTextureFormat, true);
+ _targetMaterial.mainTexture = texture;
+
+ // setup render texture
+ renderTex = RenderTexture.GetTemporary(width, height, 0, TextRenderTextureFormat, RenderTextureReadWrite.Linear, 1);
+ renderTex.autoGenerateMips = true;
+ _camera.targetTexture = renderTex;
+
+ // setup material
+ _blitMaterial.mainTexture = _tmp.font.atlas;
+
+ // draw the mesh
+ Graphics.DrawMesh(mesh, _tmp.renderer.localToWorldMatrix, _blitMaterial, 0, _camera, 0);
+ _camera.Render();
+
+ yield return null;
+
+ RenderTexture.active = renderTex;
+ texture.ReadPixels(new Rect(0, 0, width, height), 0, 0, true);
+ texture.Apply(false, true);
+
+ RenderTexture.ReleaseTemporary(renderTex);
+ }
+}
diff --git a/Assets/Shaders/TMPBlit.shader b/Assets/Shaders/TMPBlit.shader
new file mode 100644
index 0000000..1ef6391
--- /dev/null
+++ b/Assets/Shaders/TMPBlit.shader
@@ -0,0 +1,51 @@
+Shader "ConformalDecals/TMP_Blit"
+{
+ Properties
+ {
+ _MainTex("_MainTex (RGB spec(A))", 2D) = "white" {}
+
+ }
+ SubShader
+ {
+ Tags { "Queue" = "Transparent" }
+ Cull Off
+ ZWrite Off
+
+ Pass
+ {
+ Blend One One
+
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+
+ sampler2D _MainTex;
+
+ #include "UnityCG.cginc"
+ #include "Lighting.cginc"
+ #include "AutoLight.cginc"
+
+ struct v2f {
+ float4 pos : SV_POSITION;
+ float2 uv : TEXCOORD0;
+ };
+
+ v2f vert(float4 vertex : POSITION, float2 uv : TEXCOORD0) {
+ v2f o;
+ o.pos = UnityObjectToClipPos(vertex);
+ o.uv = uv;
+ return o;
+ }
+
+ fixed4 frag (v2f i) : SV_Target {
+ fixed4 c = 0;
+
+ c.r = tex2D(_MainTex,(i.uv)).a;
+
+ return c;
+ }
+
+ ENDCG
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ConformalDecals/ConformalDecals.csproj b/Source/ConformalDecals/ConformalDecals.csproj
index 13a5b8a..d8e5c33 100644
--- a/Source/ConformalDecals/ConformalDecals.csproj
+++ b/Source/ConformalDecals/ConformalDecals.csproj
@@ -52,6 +52,9 @@
dlls\UnityEngine.PhysicsModule.dll
+
+ dlls\UnityEngine.UI.dll
+
@@ -70,6 +73,7 @@
+
diff --git a/Source/ConformalDecals/ModuleConformalText.cs b/Source/ConformalDecals/ModuleConformalText.cs
index 322e4de..659b694 100644
--- a/Source/ConformalDecals/ModuleConformalText.cs
+++ b/Source/ConformalDecals/ModuleConformalText.cs
@@ -1,3 +1,4 @@
+using ConformalDecals.Text;
using ConformalDecals.Util;
using TMPro;
using UnityEngine;
diff --git a/Source/ConformalDecals/Text/TextRenderer.cs b/Source/ConformalDecals/Text/TextRenderer.cs
index e9bfe89..c625328 100644
--- a/Source/ConformalDecals/Text/TextRenderer.cs
+++ b/Source/ConformalDecals/Text/TextRenderer.cs
@@ -1,146 +1,112 @@
using System;
-using ConformalDecals.Util;
+using System.Collections;
using TMPro;
using UnityEngine;
+using UnityEngine.Rendering;
-namespace ConformalDecals {
- public class TextRenderer {
- private struct GlyphInfo {
- public TMP_Glyph glyph;
- public Vector2Int size;
- public Vector2Int position;
- public int fontIndex;
- public bool needsResample;
+namespace ConformalDecals.Text {
+ [KSPAddon(KSPAddon.Startup.FlightAndEditor, true)]
+ public class TextRenderer : MonoBehaviour {
+ public static TextRenderer Instance {
+ get {
+ if (!_instance._isSetup) {
+ _instance.Setup();
+ }
+
+ return _instance;
+ }
}
- private struct FontInfo {
- public TMP_FontAsset font;
- public Texture2D fontAtlas;
- public Color32[] fontAtlasColors;
+ public const TextureFormat TextTextureFormat = TextureFormat.Alpha8;
+ public const RenderTextureFormat TextRenderTextureFormat = RenderTextureFormat.R8;
+
+ private const string BlitShader = "ConformalDecals/TMP_Blit";
+ private const int MaxTextureSize = 4096;
+
+ private static TextRenderer _instance;
+
+ private bool _isSetup;
+ private TextMeshPro _tmp;
+ private GameObject _cameraObject;
+ private Camera _camera;
+ private Material _blitMaterial;
+
+ private void Start() {
+ if (_instance._isSetup) {
+ Debug.Log("[ConformalDecals] Duplicate TextRenderer created???");
+ }
+
+ Debug.Log("[ConformalDecals] Creating TextRenderer Object");
+ _instance = this;
+ DontDestroyOnLoad(gameObject);
}
- public static Texture2D RenderToTexture(TMP_FontAsset font, string text) {
- Debug.Log($"Rendering text: {text}");
- var charArray = text.ToCharArray();
- var glyphInfoArray = new GlyphInfo[charArray.Length];
- var fontInfoArray = new FontInfo[charArray.Length];
+ public void Setup() {
+ if (_isSetup) return;
- var baseScale = font.fontInfo.Scale;
- var padding = (int) font.fontInfo.Padding;
- var ascender = (int) font.fontInfo.Ascender;
- var descender = (int) font.fontInfo.Descender;
- var baseline = (int) baseScale * (descender + padding);
- Debug.Log($"baseline: {baseline}");
- Debug.Log($"ascender: {ascender}");
- Debug.Log($"descender: {descender}");
- Debug.Log($"baseScale: {baseScale}");
+ Debug.Log("[ConformalDecals] Setting Up TextRenderer Object");
- fontInfoArray[0].font = font;
+ _tmp = gameObject.AddComponent();
+ _tmp.renderer.enabled = false; // dont automatically render
- int xAdvance = 0;
- for (var i = 0; i < charArray.Length; i++) {
+ _cameraObject = new GameObject("ConformalDecals text camera");
+ _cameraObject.transform.parent = transform;
+ _cameraObject.transform.SetPositionAndRotation(Vector3.back, Quaternion.identity);
- var glyphFont = TMP_FontUtilities.SearchForGlyph(font, charArray[i], out var glyph);
+ _camera = _cameraObject.AddComponent();
+ _camera.enabled = false; // dont automatically render
+ _camera.orthographic = true;
+ _camera.depthTextureMode = DepthTextureMode.None;
+ _camera.nearClipPlane = 0.1f;
+ _camera.farClipPlane = 2f;
+ _isSetup = true;
- if (glyphFont == font) {
- glyphInfoArray[i].fontIndex = 0;
- }
- else {
- for (int f = 1; i < charArray.Length; i++) {
- if (fontInfoArray[f].font == null) {
- fontInfoArray[f].font = glyphFont;
- glyphInfoArray[i].fontIndex = f;
- break;
- }
+ _blitMaterial = new Material(Shabby.Shabby.FindShader(BlitShader));
+ }
- if (fontInfoArray[f].font == glyphFont) {
- glyphInfoArray[i].fontIndex = f;
- break;
- }
- }
- }
+ public Texture2D RenderToTexture(Texture2D texture2D, TMP_FontAsset font, string text, float fontSize, float pixelDensity) {
+ // generate text mesh
+ _tmp.SetText(text);
+ _tmp.font = font;
+ _tmp.fontSize = fontSize;
+ _tmp.ForceMeshUpdate();
- Debug.Log($"getting font info for character: '{charArray[i]}'");
- Debug.Log($"character font: {glyphFont.name}");
+ // calculate camera and texture size
+ var mesh = _tmp.mesh;
+ var bounds = mesh.bounds;
- glyphInfoArray[i].glyph = glyph;
- glyphInfoArray[i].needsResample = false;
+ var width = Mathf.NextPowerOfTwo((int) (bounds.size.x * pixelDensity));
+ var height = Mathf.NextPowerOfTwo((int) (bounds.size.y * pixelDensity));
- float elementScale = glyph.scale;
+ _camera.orthographicSize = height / pixelDensity / 2;
+ _camera.aspect = (float) width / height;
- if (glyphFont == font) {
- if (!Mathf.Approximately(elementScale, 1)) {
- glyphInfoArray[i].needsResample = true;
- }
+ _cameraObject.transform.localPosition = new Vector3(bounds.center.x, bounds.center.y, -1);
- elementScale *= baseScale;
- }
- else {
- var fontScale = glyphFont.fontInfo.Scale / glyphFont.fontInfo.PointSize;
- if (!Mathf.Approximately(fontScale, baseScale)) {
- glyphInfoArray[i].needsResample = true;
- }
+ width = Mathf.Min(width, MaxTextureSize);
+ height = Mathf.Max(height, MaxTextureSize);
- elementScale *= fontScale;
- }
+ // setup render texture
+ var renderTex = RenderTexture.GetTemporary(width, height, 0, TextRenderTextureFormat, RenderTextureReadWrite.Linear, 1);
+ _camera.targetTexture = renderTex;
- Debug.Log($"character scale: {glyphFont.fontInfo.Scale / glyphFont.fontInfo.PointSize}");
- Debug.Log($"character needs resampling: {glyphInfoArray[i].needsResample}");
+ // setup material
+ _blitMaterial.SetTexture(PropertyIDs._MainTex, font.atlas);
+ _blitMaterial.SetPass(0);
- glyphInfoArray[i].size.x = (int) ((glyph.width + (padding * 2)) * elementScale);
- glyphInfoArray[i].size.y = (int) ((glyph.height + (padding * 2)) * elementScale);
- glyphInfoArray[i].position.x = (int) ((xAdvance + glyph.xOffset - padding) * elementScale);
- glyphInfoArray[i].position.y = (int) ((baseline + glyph.yOffset - padding) * elementScale);
-
- Debug.Log($"character size: {glyphInfoArray[i].size}");
- Debug.Log($"character position: {glyphInfoArray[i].position}");
+ // draw the mesh
+ Graphics.DrawMeshNow(mesh, _tmp.renderer.localToWorldMatrix);
+
+ var request = AsyncGPUReadback.Request(renderTex, 0, TextTextureFormat);
+
+ request.WaitForCompletion();
+
+ if (request.hasError) {
+ throw new Exception("[ConformalDecals] Error encountered trying to request render texture data from the GPU!");
}
-
- // calculate texture bounds
- int xOffset = glyphInfoArray[0].position.x;
- var textureWidth = (glyphInfoArray[charArray.Length - 1].position.x + glyphInfoArray[charArray.Length - 1].size.x) - xOffset;
- var textureHeight = (int) baseScale * (ascender + descender + padding * 2);
-
- // ensure texture sizes are powers of 2
- textureWidth = Mathf.NextPowerOfTwo(textureWidth);
- textureHeight = Mathf.NextPowerOfTwo(textureHeight);
- Debug.Log($"texture is {textureWidth} x {textureHeight}");
-
- var texture = new Texture2D(textureWidth, textureHeight, TextureFormat.Alpha8, true);
-
- var colors = new Color32[textureWidth * textureHeight];
-
- for (var i = 0; i < fontInfoArray.Length; i++) {
- if (fontInfoArray[i].font == null) break;
- fontInfoArray[i].fontAtlas = fontInfoArray[i].font.atlas;
- fontInfoArray[i].fontAtlasColors = fontInfoArray[i].fontAtlas.GetPixels32();
- }
-
- for (int i = 0; i < charArray.Length; i++) {
- var glyphInfo = glyphInfoArray[i];
- var glyph = glyphInfo.glyph;
- var fontInfo = fontInfoArray[glyphInfo.fontIndex];
-
- var srcPos = new Vector2Int((int) glyph.x, (int) glyph.y);
- var dstPos = glyphInfo.position;
- dstPos.x += xOffset;
- var dstSize = glyphInfo.size;
-
- Debug.Log($"rendering character number {i}");
-
- if (glyphInfo.needsResample) {
- var srcSize = new Vector2(glyph.width, glyph.height);
- TextureUtils.BlitRectBilinearAlpha(fontInfo.fontAtlas, srcPos, srcSize, texture, colors, dstPos, dstSize, TextureUtils.BlitMode.Add);
- }
- else {
- TextureUtils.BlitRectAlpha(fontInfo.fontAtlas, fontInfo.fontAtlasColors, srcPos, texture, colors, dstPos, dstSize, TextureUtils.BlitMode.Add);
- }
- }
-
- texture.Apply(true);
-
- return texture;
+
+
}
}
}
\ No newline at end of file
diff --git a/Source/ConformalDecals/Text/TextSettings.cs b/Source/ConformalDecals/Text/TextSettings.cs
new file mode 100644
index 0000000..366c02f
--- /dev/null
+++ b/Source/ConformalDecals/Text/TextSettings.cs
@@ -0,0 +1,5 @@
+namespace ConformalDecals.Text {
+ public struct TextSettings {
+
+ }
+}
\ No newline at end of file