Skip to content

Commit 8167b5a

Browse files
committed
WIP: label batching is kind of working
1 parent 10a579f commit 8167b5a

File tree

2 files changed

+82
-77
lines changed

2 files changed

+82
-77
lines changed

RasterPropMonitor/Auxiliary modules/JSILabel.cs

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
****************************************************************************/
2121
using System;
2222
using System.Collections.Generic;
23+
using System.Linq;
2324
using UnityEngine;
25+
using UnityEngine.UI;
2426

2527
namespace JSI
2628
{
@@ -33,6 +35,13 @@ public void OnLoad(ConfigNode node)
3335
{
3436
variableName = node.GetValue(nameof(variableName));
3537
node.TryGetValue(nameof(flashRate), ref flashRate);
38+
39+
string fontName = "Arial";
40+
node.TryGetValue(nameof(fontName), ref fontName);
41+
int fontQuality = 32;
42+
node.TryGetValue(nameof(fontQuality), ref fontQuality);
43+
44+
font = JUtil.LoadFont(fontName, fontQuality);
3645
}
3746

3847
public void OnStart(ConfigNode node, RasterPropMonitorComputer rpmComp)
@@ -54,8 +63,8 @@ void ReadColor(ConfigNode node, string key, RasterPropMonitorComputer rpmComp, r
5463
public override bool Equals(object obj)
5564
{
5665
return obj is TextBatchInfo info &&
57-
base.Equals(obj) &&
5866
variableName == info.variableName &&
67+
font == info.font &&
5968
EqualityComparer<Color32>.Default.Equals(zeroColor, info.zeroColor) &&
6069
EqualityComparer<Color32>.Default.Equals(positiveColor, info.positiveColor) &&
6170
EqualityComparer<Color32>.Default.Equals(negativeColor, info.negativeColor) &&
@@ -65,8 +74,8 @@ public override bool Equals(object obj)
6574
public override int GetHashCode()
6675
{
6776
var hashCode = -1112470117;
68-
hashCode = hashCode * -1521134295 + base.GetHashCode();
6977
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(variableName);
78+
hashCode = hashCode * -1521134295 + font.GetHashCode();
7079
hashCode = hashCode * -1521134295 + zeroColor.GetHashCode();
7180
hashCode = hashCode * -1521134295 + positiveColor.GetHashCode();
7281
hashCode = hashCode * -1521134295 + negativeColor.GetHashCode();
@@ -75,6 +84,7 @@ public override int GetHashCode()
7584
}
7685

7786
public string variableName;
87+
public Font font;
7888
public Color32 zeroColor = XKCDColors.White;
7989
public Color32 positiveColor = XKCDColors.White;
8090
public Color32 negativeColor = XKCDColors.White;
@@ -107,13 +117,9 @@ public enum EmissiveMode
107117
[KSPField]
108118
public float lineSpacing = 1.0f;
109119
[KSPField]
110-
public string fontName = "Arial";
111-
[KSPField]
112120
public TextAnchor anchor;
113121
[KSPField]
114122
public TextAlignment alignment;
115-
[KSPField]
116-
public int fontQuality = 32;
117123

118124
[KSPField]
119125
public string switchTransform = string.Empty;
@@ -133,7 +139,7 @@ public enum EmissiveMode
133139
[SerializeField] internal JSITextMesh textObj;
134140
static readonly int emissiveFactorIndex = Shader.PropertyToID("_EmissiveFactor");
135141

136-
private List<JSILabelSet> labels = new List<JSILabelSet>();
142+
private List<StringProcessorFormatter> labels = new List<StringProcessorFormatter>();
137143
private int activeLabel = 0;
138144
private FXGroup audioOutput;
139145

@@ -162,16 +168,14 @@ public override void OnLoad(ConfigNode node)
162168

163169
textObj = offsetTransform.gameObject.AddComponent<JSITextMesh>();
164170

165-
var font = JUtil.LoadFont(fontName, fontQuality);
166-
167-
textObj.font = font;
171+
textObj.font = batchInfo.font;
168172
//textObj.fontSize = fontQuality; // This doesn't work with Unity-embedded fonts
169-
textObj.fontSize = font.fontSize;
173+
textObj.fontSize = batchInfo.font.fontSize;
170174

171175
textObj.anchor = anchor;
172176
textObj.alignment = alignment;
173177

174-
float sizeScalar = 32.0f / (float)font.fontSize;
178+
float sizeScalar = 32.0f / (float)batchInfo.font.fontSize;
175179
textObj.characterSize = fontSize * 0.00005f * sizeScalar;
176180
textObj.lineSpacing *= lineSpacing;
177181
}
@@ -195,8 +199,6 @@ public void Start()
195199
// "Normal" mode
196200
if (string.IsNullOrEmpty(switchTransform))
197201
{
198-
// Force oneshot if there's no variables:
199-
oneshot |= !labelText.Contains("$&$");
200202
string sourceString = labelText.UnMangleConfigText();
201203

202204
if (!string.IsNullOrEmpty(sourceString) && sourceString.Length > 1)
@@ -207,14 +209,17 @@ public void Start()
207209
sourceString = sourceString.Substring(1);
208210
}
209211
}
210-
labels.Add(new JSILabelSet(sourceString, rpmComp, oneshot));
212+
labels.Add(new StringProcessorFormatter(sourceString, rpmComp));
213+
oneshot |= labels[0].IsConstant;
211214

212215
if (oneshot)
213216
{
214-
var propBatcher = internalModel.FindModelComponent<PropBatcher>();
217+
var propBatcher = internalModel.GetComponentInChildren<PropBatcher>();
215218
if (propBatcher != null)
216219
{
217-
//propBatcher.AddStaticLabel(this);
220+
textObj.text = labels[0].Get();
221+
propBatcher.AddStaticLabel(this);
222+
return;
218223
}
219224
}
220225
else
@@ -236,13 +241,9 @@ public void Start()
236241
string lText = variableNodes[i].GetValue("labelText");
237242
if (lText != null)
238243
{
239-
bool lOneshot = false;
240-
variableNodes[i].TryGetValue("oneshot", ref lOneshot);
241-
242244
string sourceString = lText.UnMangleConfigText();
243-
lOneshot |= !lText.Contains("$&$");
244-
labels.Add(new JSILabelSet(sourceString, rpmComp, lOneshot));
245-
if (!lOneshot)
245+
labels.Add(new StringProcessorFormatter(sourceString, rpmComp));
246+
if (!labels.Last().IsConstant)
246247
{
247248
rpmComp.UpdateDataRefreshRate(refreshRate);
248249
}
@@ -289,7 +290,7 @@ public void Start()
289290
catch (Exception e)
290291
{
291292
JUtil.LogErrorMessage(this, "Start failed in prop {1} ({2}) with exception {0}", e, internalProp.propID, internalProp.propName);
292-
labels.Add(new JSILabelSet("ERR", rpmComp, true));
293+
labels.Add(new StringProcessorFormatter("ERR", rpmComp));
293294
}
294295
}
295296

@@ -320,10 +321,10 @@ public void Click()
320321
activeLabel = 0;
321322
}
322323

323-
textObj.text = StringProcessor.ProcessString(labels[activeLabel].spf, rpmComp);
324+
textObj.text = labels[activeLabel].Get();
324325

325326
// do we need to activate the update loop?
326-
if (labels.Count > 1 && !labels[activeLabel].oneshot)
327+
if (labels.Count > 1 && !labels[activeLabel].IsConstant)
327328
{
328329
rpmComp.RestoreInternalModule(this);
329330
}
@@ -464,40 +465,18 @@ private bool UpdateCheck()
464465
/// </summary>
465466
public override void OnUpdate()
466467
{
467-
if (textObj == null)
468+
if (textObj == null || labels[activeLabel].IsConstant)
468469
{
469470
// Shouldn't happen ... but it does, thanks to the quirks of
470471
// docking and undocking.
471472
rpmComp.RemoveInternalModule(this);
472473
return;
473474
}
474475

475-
if (labels[activeLabel].oneshotComplete && labels[activeLabel].oneshot)
476-
{
477-
rpmComp.RemoveInternalModule(this);
478-
return;
479-
}
480-
481476
if (UpdateCheck() && JUtil.RasterPropMonitorShouldUpdate(part))
482477
{
483-
textObj.text = StringProcessor.ProcessString(labels[activeLabel].spf, rpmComp);
484-
labels[activeLabel].oneshotComplete = true;
478+
textObj.text = labels[activeLabel].Get();
485479
}
486480
}
487481
}
488-
489-
internal class JSILabelSet
490-
{
491-
public readonly StringProcessorFormatter spf;
492-
public bool oneshotComplete;
493-
public readonly bool oneshot;
494-
495-
internal JSILabelSet(string labelText, RasterPropMonitorComputer rpmComp, bool isOneshot)
496-
{
497-
oneshotComplete = false;
498-
spf = new StringProcessorFormatter(labelText, rpmComp);
499-
oneshot = isOneshot || spf.IsConstant;
500-
}
501-
}
502-
503482
}

RasterPropMonitor/Auxiliary modules/PropBatcher.cs

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -201,55 +201,81 @@ public override void OnLoad(ConfigNode node)
201201

202202
class LabelBatch
203203
{
204-
public JSILabel firstLabel;
204+
public GameObject batchRoot;
205+
public MeshRenderer renderer;
206+
public MeshFilter meshFilter;
207+
205208
public List<JSITextMesh> textMeshes = new List<JSITextMesh>();
206209
public bool needsUpdate = true;
210+
211+
public LabelBatch()
212+
{
213+
batchRoot = new GameObject("Label Batch Root");
214+
batchRoot.layer = 20;
215+
batchRoot.transform.SetParent(InternalSpace.Instance.transform, true);
216+
217+
renderer = batchRoot.AddComponent<MeshRenderer>();
218+
renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
219+
renderer.receiveShadows = true;
220+
renderer.material = new Material(JUtil.LoadInternalShader("RPM/JSILabel"));
221+
meshFilter = batchRoot.AddComponent<MeshFilter>();
222+
}
223+
224+
public void LateUpdate()
225+
{
226+
if (!needsUpdate) return;
227+
228+
CombineInstance[] instances = new CombineInstance[textMeshes.Count];
229+
for (int i = 0; i < instances.Length; ++i)
230+
{
231+
instances[i] = new CombineInstance();
232+
textMeshes[i].Update();
233+
instances[i].mesh = textMeshes[i].mesh;
234+
instances[i].transform = textMeshes[i].transform.localToWorldMatrix;
235+
}
236+
237+
meshFilter.mesh.Clear();
238+
meshFilter.mesh.CombineMeshes(instances);
239+
meshFilter.mesh.UploadMeshData(false);
240+
241+
needsUpdate = false;
242+
}
207243
}
208244

209-
Dictionary<JSILabel.TextBatchInfo, LabelBatch> labelBatches = new Dictionary<JSILabel.TextBatchInfo, LabelBatch>();
245+
readonly Dictionary<JSILabel.TextBatchInfo, LabelBatch> labelBatches = new Dictionary<JSILabel.TextBatchInfo, LabelBatch>();
210246

211247
public void AddStaticLabel(JSILabel label)
212248
{
213249
LabelBatch labelBatch;
214250
if (!labelBatches.TryGetValue(label.batchInfo, out labelBatch))
215251
{
216252
labelBatch = new LabelBatch();
217-
labelBatch.firstLabel = label;
218253
labelBatches.Add(label.batchInfo, labelBatch);
219-
220-
var oldParent = label.textObj.transform.parent;
221-
label.textObj.transform.SetParent(null, true);
222-
label.transform.localPosition = Vector3.zero;
223-
label.transform.localRotation = Quaternion.identity;
224-
label.transform.localScale = Vector3.one;
225-
label.textObj.transform.SetParent(oldParent, true);
226-
}
227-
else
228-
{
229-
Component.Destroy(label.textObj.transform.GetComponent<MeshRenderer>());
230-
// TODO: destroy meshfilter?
254+
labelBatch.renderer.material = label.batchInfo.font.material;
255+
// TODO: hook up variable callback
256+
// TODO: hook up flashing behavior
231257
}
232258

259+
// TODO: hook up font change callback
260+
261+
label.textObj.transform.SetParent(labelBatch.batchRoot.transform, true);
262+
label.textObj.gameObject.SetActive(false);
263+
label.textObj.color = label.batchInfo.zeroColor;
264+
233265
labelBatch.textMeshes.Add(label.textObj);
234266
labelBatch.needsUpdate = true;
267+
268+
//Component.Destroy(label.textObj.transform.GetComponent<MeshRenderer>());
269+
// todo: destroy meshfilter? but we need the meshes to stick around.
270+
label.internalProp.internalModules.Remove(label);
271+
Component.Destroy(label);
235272
}
236273

237274
void LateUpdate()
238275
{
239276
foreach (var labelBatch in labelBatches.Values)
240277
{
241-
if (labelBatch.needsUpdate)
242-
{
243-
CombineInstance[] instances = new CombineInstance[labelBatch.textMeshes.Count];
244-
for (int i = 0; i < instances.Length; ++i)
245-
{
246-
instances[i] = new CombineInstance();
247-
instances[i].mesh = labelBatch.textMeshes[i].mesh;
248-
instances[i].transform = labelBatch.textMeshes[i].transform.localToWorldMatrix;
249-
}
250-
251-
labelBatch.needsUpdate = false;
252-
}
278+
labelBatch.LateUpdate();
253279
}
254280
}
255281
}

0 commit comments

Comments
 (0)