@ -7,26 +7,27 @@ using UnityEngine;
namespace ConformalDecals {
public abstract class ModuleConformalDecalBase : PartModule {
[ KSPField ( guiName = "#LOC_ConformalDecals_gui-scale" , guiActive = false , guiActiveEditor = true , isPersistant = true , guiFormat = "F2" , guiUnits = "m" ) ,
UI_FloatRange ( minValue = 0.05f , maxValue = 4f , stepIncrement = 0.05f ) ]
UI_FloatRange ( stepIncrement = 0.05f ) ]
public float scale = 1.0f ;
[ KSPField ( guiName = "#LOC_ConformalDecals_gui-depth" , guiActive = false , guiActiveEditor = true , isPersistant = true , guiFormat = "F2" , guiUnits = "m" ) ,
UI_FloatRange ( minValue = 0.05f , maxValue = 4f , stepIncrement = 0.05 f) ]
public float depth = 1. 0f;
UI_FloatRange ( stepIncrement = 0.02 f) ]
public float depth = 0.2 f;
[ KSPField ( guiName = "#LOC_ConformalDecals_gui-opacity" , guiActive = false , guiActiveEditor = true , isPersistant = true , guiFormat = "P0" ) ,
UI_FloatRange ( minValue = 0.0f , maxValue = 1f , stepIncrement = 0.05f ) ]
UI_FloatRange ( stepIncrement = 0.05f ) ]
public float opacity = 1.0f ;
[ KSPField ( guiName = "#LOC_ConformalDecals_gui-cutoff" , guiActive = false , guiActiveEditor = true , isPersistant = true , guiFormat = "P0" ) ,
UI_FloatRange ( minValue = 0.0f , maxValue = 1f , stepIncrement = 0.05f ) ]
UI_FloatRange ( stepIncrement = 0.05f ) ]
public float cutoff = 0.5f ;
[KSPField] public string shader = "ConformalDecals/Paint/Diffuse" ;
[KSPField] public string decalFront = string . Empty ;
[KSPField] public string decalBack = string . Empty ;
[KSPField] public string decalModel = string . Empty ;
[KSPField] public string decalProjector = string . Empty ;
[KSPField] public string decalShader = "ConformalDecals/Paint/Diffuse" ;
[KSPField] public Transform decalFrontTransform ;
[KSPField] public Transform decalBackTransform ;
@ -38,11 +39,10 @@ namespace ConformalDecals {
[KSPField] public bool opacityAdjustable = true ;
[KSPField] public bool cutoffAdjustable = true ;
[KSPField] public Vector2 scaleRange = new Vector2 ( 0 , 4 ) ;
[KSPField] public Vector2 depthRange = new Vector2 ( 0 , 4 ) ;
[KSPField] public Vector2 opacityRange = new Vector2 ( 0 , 1 ) ;
[KSPField] public Vector2 cutoffRange = new Vector2 ( 0 , 1 ) ;
[KSPField] public Vector2 decalQueueRange = new Vector2 ( 2100 , 2400 ) ;
[KSPField] public Vector2 scaleRange = new Vector2 ( 0 , 4 ) ;
[KSPField] public Vector2 depthRange = new Vector2 ( 0 , 2 ) ;
[KSPField] public Vector2 opacityRange = new Vector2 ( 0 , 1 ) ;
[KSPField] public Vector2 cutoffRange = new Vector2 ( 0 , 1 ) ;
[KSPField] public bool updateBackScale = true ;
[KSPField] public bool useBaseNormal = true ;
@ -50,7 +50,10 @@ namespace ConformalDecals {
[KSPField] public MaterialPropertyCollection materialProperties ;
[KSPField] public Material backMaterial ;
[KSPField] public Vector2 backTextureBaseScale ;
private const int DecalQueueMin = 2100 ;
private const int DecalQueueMax = 2400 ;
private static int _decalQueueCounter = - 1 ;
private List < ProjectionTarget > _targets ;
@ -58,13 +61,16 @@ namespace ConformalDecals {
private bool _isAttached ;
private Matrix4x4 _orthoMatrix ;
private Bounds _decalBounds ;
private Vector2 _backTextureBaseScale ;
private Material _decalMaterial ;
private Material _previewMaterial ;
private int DecalQueue {
get {
_decalQueueCounter + + ;
if ( _decalQueueCounter > decalQueueRange. y | | _decalQueueCounter < decalQueueRange . x ) {
_decalQueueCounter = ( int ) decalQueueRange . x ;
if ( _decalQueueCounter > DecalQueueMax | | _decalQueueCounter < DecalQueueMin ) {
_decalQueueCounter = DecalQueueMin ;
}
return _decalQueueCounter ;
@ -74,10 +80,6 @@ namespace ConformalDecals {
public override void OnLoad ( ConfigNode node ) {
this . Log ( "Loading module" ) ;
try {
if ( HighLogic . LoadedSceneIsEditor ) {
UpdateTweakables ( ) ;
}
// find front transform
decalFrontTransform = part . FindModelTransform ( decalFront ) ;
if ( decalFrontTransform = = null ) throw new FormatException ( $"Could not find decalFront transform: '{decalFront}'." ) ;
@ -112,32 +114,25 @@ namespace ConformalDecals {
decalProjectorTransform = part . FindModelTransform ( decalProjector ) ;
if ( decalProjectorTransform = = null ) throw new FormatException ( $"Could not find decalProjector transform: '{decalProjector}'." ) ;
}
// get back material if necessary
if ( updateBackScale ) {
this . Log ( "Getting material and base scale for back material" ) ;
var backRenderer = decalBackTransform . GetComponent < MeshRenderer > ( ) ;
if ( backRenderer = = null ) {
this . LogError ( $"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false." ) ;
updateBackScale = false ;
}
else {
backMaterial = backRenderer . material ;
if ( backMaterial = = null ) {
this . LogError ( $"Specified decalBack transform {decalBack} has a renderer but no material! Setting updateBackScale to false." ) ;
updateBackScale = false ;
}
else {
_backTextureBaseScale = backMaterial . GetTextureScale ( PropertyIDs . _MainTex ) ;
}
}
if ( HighLogic . LoadedSceneIsEditor ) {
UpdateTweakables ( ) ;
}
// update EVERYTHING if currently attached
if ( _isAttached ) {
UpdateScale ( ) ;
UpdateTargets( ) ;
// setup material properties
if ( HighLogic . LoadedSceneIsGame ) {
// additional load, in flight or in the editor
materialProperties = ScriptableObject . Instantiate ( materialProperties ) ;
}
else {
// first load, so get everything set up
materialProperties = ScriptableObject . CreateInstance < MaterialPropertyCollection > ( ) ;
materialProperties . Initialize ( ) ;
}
// set shader
materialProperties . SetShader ( shader ) ;
}
catch ( Exception e ) {
this . LogException ( "Exception parsing partmodule" , e ) ;
@ -147,6 +142,7 @@ namespace ConformalDecals {
public override void OnStart ( StartState state ) {
this . Log ( "Starting module" ) ;
// handle tweakables
if ( HighLogic . LoadedSceneIsEditor ) {
GameEvents . onEditorPartEvent . Add ( OnEditorEvent ) ;
GameEvents . onVariantApplied . Add ( OnVariantApplied ) ;
@ -154,21 +150,22 @@ namespace ConformalDecals {
UpdateTweakables ( ) ;
}
// generate orthogonal projection matrix and offset it by 0.5 on x and y axes
_orthoMatrix = Matrix4x4 . identity ;
_orthoMatrix [ 0 , 3 ] = 0.5f ;
_orthoMatrix [ 1 , 3 ] = 0.5f ;
// instantiate decal material and set uniqueish queue
materialProperties . SetRenderQueue ( DecalQueue ) ;
// clone materialProperties and setup queue
if ( HighLogic . LoadedSceneIsGame ) {
materialProperties = ScriptableObject . Instantiate ( materialProperties ) ;
materialProperties . SetRenderQueue ( DecalQueue ) ;
// set initial attachment state
if ( part . parent = = null ) {
OnDetach ( ) ;
}
else {
OnAttach ( ) ;
// set initial attachment state
if ( part . parent = = null ) {
_isAttached = false ;
}
else {
OnAttach ( ) ;
}
}
UpdateMaterials ( ) ;
UpdateScale ( ) ;
}
public void OnDestroy ( ) {
@ -179,25 +176,25 @@ namespace ConformalDecals {
Camera . onPreCull - = Render ;
}
pr ivate void OnSizeTweakEvent ( BaseField field , object obj ) {
pr otected void OnSizeTweakEvent ( BaseField field , object obj ) {
// scale or depth values have been changed, so update scale
// and update projection matrices if attached
UpdateScale ( ) ;
if ( _isAttached ) UpdateProjection ( ) ;
}
pr ivate void OnMaterialTweakEvent ( BaseField field , object obj ) {
pr otected void OnMaterialTweakEvent ( BaseField field , object obj ) {
materialProperties . SetOpacity ( opacity ) ;
materialProperties . SetCutoff ( cutoff ) ;
}
pr ivate void OnVariantApplied ( Part eventPart , PartVariant variant ) {
pr otected void OnVariantApplied ( Part eventPart , PartVariant variant ) {
if ( _isAttached & & eventPart = = part . parent ) {
UpdateTargets ( ) ;
}
}
pr ivate void OnEditorEvent ( ConstructionEventType eventType , Part eventPart ) {
pr otected void OnEditorEvent ( ConstructionEventType eventType , Part eventPart ) {
if ( eventPart ! = this . part ) return ;
switch ( eventType ) {
case ConstructionEventType . PartAttached :
@ -213,7 +210,7 @@ namespace ConformalDecals {
}
}
pr ivate void OnAttach ( ) {
pr otected void OnAttach ( ) {
if ( part . parent = = null ) {
this . LogError ( "Attach function called but part has no parent!" ) ;
_isAttached = false ;
@ -224,7 +221,6 @@ namespace ConformalDecals {
this . Log ( $"Decal attached to {part.parent.partName}" ) ;
UpdateTargets ( ) ;
// hide preview model
decalFrontTransform . gameObject . SetActive ( false ) ;
@ -233,11 +229,12 @@ namespace ConformalDecals {
// add to preCull delegate
Camera . onPreCull + = Render ;
UpdateScale ( ) ;
//UpdateScale();
UpdateTargets ( ) ;
UpdateProjection ( ) ;
}
pr ivate void OnDetach ( ) {
pr otected void OnDetach ( ) {
_isAttached = false ;
// unhide preview model
@ -247,13 +244,19 @@ namespace ConformalDecals {
// remove from preCull delegate
Camera . onPreCull - = Render ;
UpdateScale ( ) ;
//UpdateScale() ;
}
private void UpdateScale ( ) {
protected void UpdateScale ( ) {
var aspectRatio = materialProperties . AspectRatio ;
this . Log ( $"Aspect ratio is {aspectRatio}" ) ;
var size = new Vector2 ( scale , scale * materialProperties . AspectRatio ) ;
// update orthogonal matrix scale
_orthoMatrix = Matrix4x4 . identity ;
_orthoMatrix [ 0 , 3 ] = 0.5f ;
_orthoMatrix [ 1 , 3 ] = 0.5f ;
_orthoMatrix [ 0 , 0 ] = 1 / size . x ;
_orthoMatrix [ 1 , 1 ] = 1 / size . y ;
_orthoMatrix [ 2 , 2 ] = 1 / depth ;
@ -262,28 +265,67 @@ namespace ConformalDecals {
_decalBounds . center = Vector3 . forward * ( depth / 2 ) ;
_decalBounds . extents = new Vector3 ( size . x / 2 , size . y / 2 , depth / 2 ) ;
if ( decalModelTransform = = null ) {
this . LogError ( "decalModelTransform is null!" ) ;
}
// rescale preview model
decalModelTransform . localScale = new Vector3 ( size . x , size . y , ( size . x + size . y ) / 2 ) ;
// update back material scale
if ( updateBackScale ) {
backMaterial . SetTextureScale ( PropertyIDs . _MainTex , new Vector2 ( size . x * _ backTextureBaseScale. x , size . y * _ backTextureBaseScale. y ) ) ;
backMaterial . SetTextureScale ( PropertyIDs . _MainTex , new Vector2 ( size . x * backTextureBaseScale. x , size . y * backTextureBaseScale. y ) ) ;
}
// update material scale
materialProperties . SetScale ( size ) ;
}
private void UpdateProjection ( ) {
protected void UpdateMaterials ( ) {
materialProperties . UpdateMaterials ( ) ;
_decalMaterial = materialProperties . DecalMaterial ;
_previewMaterial = materialProperties . PreviewMaterial ;
// get back material if necessary
if ( updateBackScale ) {
this . Log ( "Getting material and base scale for back material" ) ;
var backRenderer = decalBackTransform . GetComponent < MeshRenderer > ( ) ;
if ( backRenderer = = null ) {
this . LogError ( $"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false." ) ;
updateBackScale = false ;
}
else {
backMaterial = backRenderer . material ;
if ( backMaterial = = null ) {
this . LogError ( $"Specified decalBack transform {decalBack} has a renderer but no material! Setting updateBackScale to false." ) ;
updateBackScale = false ;
}
else {
if ( backTextureBaseScale = = default ) backTextureBaseScale = backMaterial . GetTextureScale ( PropertyIDs . _MainTex ) ;
}
}
}
if ( decalFrontTransform = = null ) {
this . LogError ( "No reference to decal front transform" ) ;
return ;
}
decalFrontTransform . GetComponent < MeshRenderer > ( ) . material = _previewMaterial ;
}
protected void UpdateProjection ( ) {
if ( ! _isAttached ) return ;
var bounds = new OrientedBounds ( decalProjectorTransform . localToWorldMatrix , _decalBounds ) ;
// project to each target object
foreach ( var target in _targets ) {
target . Project ( _orthoMatrix , new OrientedBounds ( decalProjectorTransform . localToWorldMatrix , _decalBounds ) , decalProjectorTransform ) ;
target . Project ( _orthoMatrix , bounds , decalProjectorTransform , useBaseNormal ) ;
}
}
private void UpdateTargets ( ) {
pr otected void UpdateTargets ( ) {
if ( _targets = = null ) {
_targets = new List < ProjectionTarget > ( ) ;
}
@ -319,7 +361,7 @@ namespace ConformalDecals {
}
}
pr ivate void UpdateTweakables ( ) {
pr otected void UpdateTweakables ( ) {
// setup tweakable fields
var scaleField = Fields [ nameof ( scale ) ] ;
var depthField = Fields [ nameof ( depth ) ] ;
@ -369,12 +411,12 @@ namespace ConformalDecals {
}
}
pr ivate void Render ( Camera camera ) {
pr otected void Render ( Camera camera ) {
if ( ! _isAttached ) return ;
// render on each target object
foreach ( var target in _targets ) {
target . Render ( materialProperties. D ecalMaterial, part . mpb , camera ) ;
target . Render ( _d ecalMaterial, part . mpb , camera ) ;
}
}
}