Skip to content

Commit 10a579f

Browse files
committed
WIP: batching static JSILabels
1 parent 75696e0 commit 10a579f

File tree

3 files changed

+152
-46
lines changed

3 files changed

+152
-46
lines changed

RasterPropMonitor/Auxiliary modules/JSILabel.cs

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,62 @@ namespace JSI
2727
// Note 1: http://docs.unity3d.com/Manual/StyledText.html details the "richText" abilities
2828
public class JSILabel : InternalModule
2929
{
30+
internal class TextBatchInfo : ScriptableObject
31+
{
32+
public void OnLoad(ConfigNode node)
33+
{
34+
variableName = node.GetValue(nameof(variableName));
35+
node.TryGetValue(nameof(flashRate), ref flashRate);
36+
}
37+
38+
public void OnStart(ConfigNode node, RasterPropMonitorComputer rpmComp)
39+
{
40+
ReadColor(node, nameof(zeroColor), rpmComp, ref zeroColor);
41+
ReadColor(node, nameof(positiveColor), rpmComp, ref positiveColor);
42+
ReadColor(node, nameof(negativeColor), rpmComp, ref negativeColor);
43+
}
44+
45+
void ReadColor(ConfigNode node, string key, RasterPropMonitorComputer rpmComp, ref Color32 color)
46+
{
47+
var colorString = node.GetValue(key);
48+
if (colorString != null)
49+
{
50+
color = JUtil.ParseColor32(colorString, rpmComp);
51+
}
52+
}
53+
54+
public override bool Equals(object obj)
55+
{
56+
return obj is TextBatchInfo info &&
57+
base.Equals(obj) &&
58+
variableName == info.variableName &&
59+
EqualityComparer<Color32>.Default.Equals(zeroColor, info.zeroColor) &&
60+
EqualityComparer<Color32>.Default.Equals(positiveColor, info.positiveColor) &&
61+
EqualityComparer<Color32>.Default.Equals(negativeColor, info.negativeColor) &&
62+
flashRate == info.flashRate;
63+
}
64+
65+
public override int GetHashCode()
66+
{
67+
var hashCode = -1112470117;
68+
hashCode = hashCode * -1521134295 + base.GetHashCode();
69+
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(variableName);
70+
hashCode = hashCode * -1521134295 + zeroColor.GetHashCode();
71+
hashCode = hashCode * -1521134295 + positiveColor.GetHashCode();
72+
hashCode = hashCode * -1521134295 + negativeColor.GetHashCode();
73+
hashCode = hashCode * -1521134295 + flashRate.GetHashCode();
74+
return hashCode;
75+
}
76+
77+
public string variableName;
78+
public Color32 zeroColor = XKCDColors.White;
79+
public Color32 positiveColor = XKCDColors.White;
80+
public Color32 negativeColor = XKCDColors.White;
81+
public float flashRate = 0.0f;
82+
}
83+
3084
[SerializeReference] ConfigNodeHolder moduleConfig;
85+
[SerializeField] internal TextBatchInfo batchInfo;
3186

3287
[KSPField]
3388
public string labelText = "uninitialized";
@@ -46,8 +101,6 @@ public enum EmissiveMode
46101
passive,
47102
flash
48103
};
49-
[KSPField]
50-
public float flashRate = 0.0f;
51104

52105
[KSPField]
53106
public float fontSize = 8.0f;
@@ -73,22 +126,12 @@ public enum EmissiveMode
73126
public int refreshRate = 10;
74127
[KSPField]
75128
public bool oneshot;
76-
[KSPField]
77-
public string variableName = string.Empty;
78-
[KSPField]
79-
public string positiveColor = string.Empty;
80-
private Color positiveColorValue = XKCDColors.White;
81-
[KSPField]
82-
public string negativeColor = string.Empty;
83-
private Color negativeColorValue = XKCDColors.White;
84-
[KSPField]
85-
public string zeroColor = string.Empty;
86-
private Color zeroColorValue = XKCDColors.White;
129+
87130
private bool variablePositive = false;
88131
private bool flashOn = true;
89132

90-
[SerializeField] private JSITextMesh textObj;
91-
private readonly int emissiveFactorIndex = Shader.PropertyToID("_EmissiveFactor");
133+
[SerializeField] internal JSITextMesh textObj;
134+
static readonly int emissiveFactorIndex = Shader.PropertyToID("_EmissiveFactor");
92135

93136
private List<JSILabelSet> labels = new List<JSILabelSet>();
94137
private int activeLabel = 0;
@@ -105,6 +148,9 @@ public override void OnLoad(ConfigNode node)
105148
moduleConfig = ScriptableObject.CreateInstance<ConfigNodeHolder>();
106149
moduleConfig.Node = node;
107150

151+
batchInfo = ScriptableObject.CreateInstance<TextBatchInfo>();
152+
batchInfo.OnLoad(node);
153+
108154
Transform textObjTransform = JUtil.FindPropTransform(internalProp, transformName);
109155
Vector3 localScale = internalProp.transform.localScale;
110156

@@ -144,6 +190,8 @@ public void Start()
144190
{
145191
rpmComp = RasterPropMonitorComputer.FindFromProp(internalProp);
146192

193+
batchInfo.OnStart(moduleConfig.Node, rpmComp);
194+
147195
// "Normal" mode
148196
if (string.IsNullOrEmpty(switchTransform))
149197
{
@@ -161,7 +209,15 @@ public void Start()
161209
}
162210
labels.Add(new JSILabelSet(sourceString, rpmComp, oneshot));
163211

164-
if (!oneshot)
212+
if (oneshot)
213+
{
214+
var propBatcher = internalModel.FindModelComponent<PropBatcher>();
215+
if (propBatcher != null)
216+
{
217+
//propBatcher.AddStaticLabel(this);
218+
}
219+
}
220+
else
165221
{
166222
rpmComp.UpdateDataRefreshRate(refreshRate);
167223
}
@@ -199,18 +255,12 @@ public void Start()
199255
}
200256
}
201257

202-
if (!string.IsNullOrEmpty(zeroColor))
203-
{
204-
zeroColorValue = JUtil.ParseColor32(zeroColor, rpmComp);
205-
textObj.color = zeroColorValue;
206-
}
258+
textObj.color = batchInfo.zeroColor;
207259

208-
if (!(string.IsNullOrEmpty(variableName) || string.IsNullOrEmpty(positiveColor) || string.IsNullOrEmpty(negativeColor) || string.IsNullOrEmpty(zeroColor)))
260+
if (!string.IsNullOrEmpty(batchInfo.variableName))
209261
{
210-
positiveColorValue = JUtil.ParseColor32(positiveColor, rpmComp);
211-
negativeColorValue = JUtil.ParseColor32(negativeColor, rpmComp);
212262
del = (Action<float>)Delegate.CreateDelegate(typeof(Action<float>), this, "OnCallback");
213-
rpmComp.RegisterVariableCallback(variableName, del);
263+
rpmComp.RegisterVariableCallback(batchInfo.variableName, del);
214264

215265
emissive = EmissiveMode.active;
216266

@@ -219,10 +269,10 @@ public void Start()
219269

220270
if (emissive == EmissiveMode.flash)
221271
{
222-
if (flashRate > 0.0f)
272+
if (batchInfo.flashRate > 0.0f)
223273
{
224274
emissive = EmissiveMode.flash;
225-
fm = JUtil.InstallFlashModule(part, flashRate);
275+
fm = JUtil.InstallFlashModule(part, batchInfo.flashRate);
226276
if (fm != null)
227277
{
228278
fm.flashSubscribers += FlashToggle;
@@ -254,7 +304,7 @@ private void FlashToggle(bool newFlashState)
254304

255305
if(variablePositive)
256306
{
257-
textObj.color = (flashOn) ? positiveColorValue : negativeColorValue;
307+
textObj.color = (flashOn) ? batchInfo.positiveColor : batchInfo.negativeColor;
258308
}
259309
}
260310

@@ -337,15 +387,13 @@ public void OnDestroy()
337387
{
338388
try
339389
{
340-
rpmComp.UnregisterVariableCallback(variableName, del);
390+
rpmComp.UnregisterVariableCallback(batchInfo.variableName, del);
341391
}
342392
catch
343393
{
344394
//JUtil.LogMessage(this, "Trapped exception unregistering JSIVariableLabel (you can ignore this)");
345395
}
346396
}
347-
Destroy(textObj);
348-
textObj = null;
349397
}
350398

351399
/// <summary>
@@ -358,7 +406,7 @@ private void OnCallback(float value)
358406
if (vessel == null)
359407
{
360408
// We're not attached to a ship?
361-
rpmComp.UnregisterVariableCallback(variableName, del);
409+
rpmComp.UnregisterVariableCallback(batchInfo.variableName, del);
362410
JUtil.LogErrorMessage(this, "Received an unexpected OnCallback()");
363411
return;
364412
}
@@ -369,27 +417,27 @@ private void OnCallback(float value)
369417
// getting called when textObj is null - did the callback
370418
// fail to unregister on destruction? It can't get called
371419
// before textObj is created.
372-
if (del != null && !string.IsNullOrEmpty(variableName))
420+
if (del != null && !string.IsNullOrEmpty(batchInfo.variableName))
373421
{
374-
rpmComp.UnregisterVariableCallback(variableName, del);
422+
rpmComp.UnregisterVariableCallback(batchInfo.variableName, del);
375423
}
376424
JUtil.LogErrorMessage(this, "Received an unexpected OnCallback() when textObj was null");
377425
return;
378426
}
379427

380428
if (value < 0.0f)
381429
{
382-
textObj.color = negativeColorValue;
430+
textObj.color = batchInfo.negativeColor;
383431
variablePositive = false;
384432
}
385433
else if (value > 0.0f)
386434
{
387-
textObj.color = (flashOn) ? positiveColorValue : negativeColorValue;
435+
textObj.color = (flashOn) ? batchInfo.positiveColor : batchInfo.negativeColor;
388436
variablePositive = true;
389437
}
390438
else
391439
{
392-
textObj.color = zeroColorValue;
440+
textObj.color = batchInfo.zeroColor;
393441
variablePositive = false;
394442
}
395443

RasterPropMonitor/Auxiliary modules/PropBatcher.cs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ public override void OnLoad(ConfigNode node)
163163
foreach (var batchList in batchLists.Values)
164164
{
165165
CombineInstance[] instances = new CombineInstance[batchList.Count];
166-
Material material = batchList[0].GetComponent<MeshRenderer>().material;
167166
var worldToLocal = batchList[0].transform.worldToLocalMatrix;
168167

169168
for (int i = 0; i < batchList.Count; i++)
@@ -194,5 +193,64 @@ public override void OnLoad(ConfigNode node)
194193
internalModel.props = newProps;
195194
}
196195
}
196+
197+
// Text label batching:
198+
// A large number of JSILabel modules are completely static - things like labels on switches, buttons, etc.
199+
// But these can still sometimes change color, especially when the backlight is turned on.
200+
// For all the JSILabels with the same controlling variable and color settings, we can render them all at once in a single mesh.
201+
202+
class LabelBatch
203+
{
204+
public JSILabel firstLabel;
205+
public List<JSITextMesh> textMeshes = new List<JSITextMesh>();
206+
public bool needsUpdate = true;
207+
}
208+
209+
Dictionary<JSILabel.TextBatchInfo, LabelBatch> labelBatches = new Dictionary<JSILabel.TextBatchInfo, LabelBatch>();
210+
211+
public void AddStaticLabel(JSILabel label)
212+
{
213+
LabelBatch labelBatch;
214+
if (!labelBatches.TryGetValue(label.batchInfo, out labelBatch))
215+
{
216+
labelBatch = new LabelBatch();
217+
labelBatch.firstLabel = label;
218+
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?
231+
}
232+
233+
labelBatch.textMeshes.Add(label.textObj);
234+
labelBatch.needsUpdate = true;
235+
}
236+
237+
void LateUpdate()
238+
{
239+
foreach (var labelBatch in labelBatches.Values)
240+
{
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+
}
253+
}
254+
}
197255
}
198256
}

RasterPropMonitor/Core/JSITextMesh.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -497,11 +497,11 @@ private void GenerateRichText()
497497

498498
if (maxVerts == 0)
499499
{
500-
meshRenderer_.gameObject.SetActive(false);
500+
gameObject.SetActive(false);
501501
return;
502502
}
503503

504-
meshRenderer_.gameObject.SetActive(true);
504+
gameObject.SetActive(true);
505505

506506
PrepBuffers(maxVerts);
507507

@@ -685,15 +685,15 @@ void PopulateMesh()
685685

686686
private void PrepBuffers(int maxVerts)
687687
{
688+
vertices.Clear();
689+
colors32.Clear();
690+
uv.Clear();
691+
688692
vertices.Capacity = Math.Max(vertices.Capacity, maxVerts);
689693
colors32.Capacity = Math.Max(colors32.Capacity, maxVerts);
690694
tangents.Capacity = Math.Max(tangents.Capacity, maxVerts);
691695
uv.Capacity = Math.Max(uv.Capacity, maxVerts);
692696

693-
vertices.Clear();
694-
colors32.Clear();
695-
uv.Clear();
696-
697697
// these never change, so we populate it once and leave it
698698
for (int tangentCount = tangents.Count; tangentCount < maxVerts; ++tangentCount)
699699
{
@@ -751,11 +751,11 @@ private void GenerateText()
751751

752752
if (maxVerts == 0)
753753
{
754-
meshRenderer_.gameObject.SetActive(false);
754+
gameObject.SetActive(false);
755755
return;
756756
}
757757

758-
meshRenderer_.gameObject.SetActive(true);
758+
gameObject.SetActive(true);
759759

760760
PrepBuffers(maxVerts);
761761

0 commit comments

Comments
 (0)