@ -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 < Vector3 > _girderVerts ;
private List < Vector2 > _girderUVs ;
private List < Vector3 > _girderNormals ;
private List < Vector4 > _girderTangents ;
private List < Color32 > _girderColors ;
private List < int > _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 < MeshFilter > ( ) . mesh ;
girderSegmentMesh = Instantiate < Mesh > ( girderMesh ) ;
}
base . OnLoad ( node ) ;
}
@ -35,50 +62,135 @@ namespace Restock
{
base . OnStart ( state ) ;
var girderRenderer = towerGirder . GetComponent < MeshRenderer > ( ) ;
_girderMaterial = girderRenderer . material ;
_girderMesh = towerGirder . GetComponent < MeshFilter > ( ) . mesh ;
girderMesh = towerGirder . GetComponent < MeshFilter > ( ) . mesh ;
girderRenderer . enabled = false ; // we'll render manually from now on
if ( instancingEnabled )
{
var girderRenderer = towerGirder . GetComponent < MeshRenderer > ( ) ;
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 < Vector3 > ( girderSegmentMesh . vertices ) ;
_girderUVs = new List < Vector2 > ( girderSegmentMesh . uv ) ;
_girderNormals = new List < Vector3 > ( girderSegmentMesh . normals ) ;
if ( girderSegmentMesh . tangents . Length > 0 )
{
_girderHasTangents = true ;
_girderTangents = new List < Vector4 > ( girderSegmentMesh . tangents ) ;
}
if ( girderSegmentMesh . colors32 . Length > 0 )
{
_girderHasColors = true ;
_girderColors = new List < Color32 > ( girderSegmentMesh . colors32 ) ;
}
_girderTris = new List < int > ( 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 ;
}
}
}