diff --git a/Distribution/Restock/GameData/ReStock/Plugins/Restock.dll b/Distribution/Restock/GameData/ReStock/Plugins/Restock.dll index ae666dac..f92c4c0a 100644 Binary files a/Distribution/Restock/GameData/ReStock/Plugins/Restock.dll and b/Distribution/Restock/GameData/ReStock/Plugins/Restock.dll differ diff --git a/Source/Restock/ModuleRestockLaunchClamp.cs b/Source/Restock/ModuleRestockLaunchClamp.cs index 22556fc3..8c21b99e 100644 --- a/Source/Restock/ModuleRestockLaunchClamp.cs +++ b/Source/Restock/ModuleRestockLaunchClamp.cs @@ -1,15 +1,11 @@ using System; +using System.Collections.Generic; using UnityEngine; namespace Restock { public class ModuleRestockLaunchClamp : LaunchClamp { - private Material _girderMaterial; - private Matrix4x4[] _girderMatrices; - private Mesh _girderMesh; - - private int _girderSegments; [KSPField] public int maxSegments = 100; [KSPField] public Transform towerAnchor; [KSPField] public Transform towerGirder; @@ -20,6 +16,28 @@ namespace Restock [KSPField] public string trf_towerGirder_name = ""; [KSPField] public string trf_towerYoke_name = ""; + [KSPField] public Mesh girderMesh; + + private Material _girderMaterial; + private Matrix4x4[] _girderMatrices; + + //used by non-instanced fallback girder implementation + [KSPField] public bool instancingEnabled = true; + [KSPField] public Mesh girderSegmentMesh; + + private List _girderVerts; + private List _girderUVs; + private List _girderNormals; + private List _girderTangents; + private List _girderColors; + private List _girderTris; + + private bool _girderHasTangents = false; + private bool _girderHasColors = false; + private int _girderVertCount; + private int _girderTriCount; + private int _girderSegments; + public override void OnLoad(ConfigNode node) { towerPivot = part.FindModelTransform(trf_towerPivot_name); @@ -28,6 +46,15 @@ namespace Restock towerGirder = part.FindModelTransform(trf_towerGirder_name); towerStretch = part.FindModelTransform(trf_towerStretch_name); + if (!SystemInfo.supportsInstancing) + { + this.LogWarning("You are using a computer which does not support instancing, " + + "falling back to a slower launch clamp implementation"); + instancingEnabled = false; + girderMesh = towerGirder.GetComponent().mesh; + girderSegmentMesh = Instantiate(girderMesh); + } + base.OnLoad(node); } @@ -35,50 +62,135 @@ namespace Restock { base.OnStart(state); - var girderRenderer = towerGirder.GetComponent(); - _girderMaterial = girderRenderer.material; - _girderMesh = towerGirder.GetComponent().mesh; + girderMesh = towerGirder.GetComponent().mesh; - girderRenderer.enabled = false; // we'll render manually from now on + if (instancingEnabled) + { + var girderRenderer = towerGirder.GetComponent(); + girderRenderer.enabled = false; // we'll render manually from now on - _girderSegments = 0; - _girderMatrices = new Matrix4x4[maxSegments]; + _girderMatrices = new Matrix4x4[maxSegments]; - _girderMaterial.enableInstancing = true; - if (!_girderMaterial.enableInstancing) + _girderMaterial = girderRenderer.material; + _girderMaterial.enableInstancing = true; + } + else { - this.LogError("Could not enable instancing! Aborting"); - _girderSegments = -1; + this.Log("Instancing is disabled, setting up fallback"); + _girderVertCount = girderSegmentMesh.vertexCount; + _girderTriCount = girderSegmentMesh.triangles.Length; + + _girderVerts = new List(girderSegmentMesh.vertices); + _girderUVs = new List(girderSegmentMesh.uv); + _girderNormals = new List(girderSegmentMesh.normals); + if (girderSegmentMesh.tangents.Length > 0) + { + _girderHasTangents = true; + _girderTangents = new List(girderSegmentMesh.tangents); + } + + if (girderSegmentMesh.colors32.Length > 0) + { + _girderHasColors = true; + _girderColors = new List(girderSegmentMesh.colors32); + } + + _girderTris = new List(girderSegmentMesh.triangles); + _girderSegments = 1; } } public void LateUpdate() { - if (_girderSegments < 0) return; - var height = HighLogic.LoadedSceneIsEditor ? towerStretch.position.y : this.height; var initialHeight = this.initialHeight; towerAnchor.position = towerStretch.position - towerStretch.up * height; - + var vec1 = Vector3.down; var vec2 = towerAnchor.localPosition - towerYoke.localPosition; towerYoke.localRotation = Quaternion.FromToRotation(vec1, vec2); - _girderSegments = Mathf.CeilToInt(height / this.initialHeight); - _girderSegments = Math.Min(_girderSegments, maxSegments); - _girderSegments = Math.Max(_girderSegments, 0); + var girderSegments = Mathf.CeilToInt(height / initialHeight); + girderSegments = Math.Min(girderSegments, maxSegments); + girderSegments = Math.Max(girderSegments, 0); + + if (instancingEnabled) + { + UpdateGirder(girderSegments); + } + else + { + UpdateGirderFallback(girderSegments); + } + } + private void UpdateGirder(int girderSegments) + { var matrix = towerGirder.localToWorldMatrix; var offset = Matrix4x4.Translate(towerGirder.TransformVector(Vector3.down * initialHeight)); - for (var i = 0; i < _girderSegments; i++) + for (var i = 0; i < girderSegments; i++) { _girderMatrices[i] = matrix; matrix = offset * matrix; } - Graphics.DrawMeshInstanced(_girderMesh, 0, _girderMaterial, _girderMatrices, _girderSegments, part.mpb); + Graphics.DrawMeshInstanced(girderMesh, 0, _girderMaterial, _girderMatrices, girderSegments, part.mpb); + } + + private void UpdateGirderFallback(int newGirderSegments) + { + + if (newGirderSegments == _girderSegments) return; + + if (newGirderSegments > _girderSegments) + { + for (int i = _girderSegments; i < newGirderSegments; i++) + { + var offset = Vector3.down * base.initialHeight * i; + var indexOffset = _girderVertCount * i; + for (int v = 0; v < _girderVertCount; v++) + { + _girderVerts.Add(girderSegmentMesh.vertices[v] + offset); + } + + _girderNormals.AddRange(girderSegmentMesh.normals); + _girderUVs.AddRange(girderSegmentMesh.uv); + + if (_girderHasTangents) _girderTangents.AddRange(girderSegmentMesh.tangents); + if (_girderHasColors) _girderColors.AddRange(girderSegmentMesh.colors32); + + for (int t = 0; t < _girderTriCount; t++) + { + _girderTris.Add(girderSegmentMesh.triangles[t] + indexOffset); + } + } + } + else if (newGirderSegments < _girderSegments) + { + var startIndex = newGirderSegments * _girderVertCount; + var count = (_girderSegments - newGirderSegments) * _girderVertCount; + _girderVerts.RemoveRange(startIndex, count); + _girderNormals.RemoveRange(startIndex, count); + _girderUVs.RemoveRange(startIndex, count); + if (_girderHasTangents) _girderTangents.RemoveRange(startIndex, count); + if (_girderHasColors) _girderColors.RemoveRange(startIndex, count); + + _girderTris.RemoveRange(newGirderSegments * _girderTriCount, (_girderSegments - newGirderSegments) * _girderTriCount); + } + + girderMesh.Clear(); + + girderMesh.SetVertices(_girderVerts); + girderMesh.SetNormals(_girderNormals); + girderMesh.SetUVs(0, _girderUVs); + if (_girderHasTangents) girderMesh.SetTangents(_girderTangents); + if (_girderHasColors) girderMesh.SetColors(_girderColors); + girderMesh.SetTriangles(_girderTris, 0); + + girderMesh.RecalculateBounds(); + _girderSegments = newGirderSegments; } } } \ No newline at end of file