21 Commits

Author SHA1 Message Date
0281759d5f SDF experiments 2020-06-22 01:43:47 -07:00
545f0d538b Merge branch 'master' into develop 2020-06-20 11:46:51 -07:00
d557df49fa Update version and changelog 2020-06-20 00:10:03 -07:00
0f383ccb65 Merge branch 'develop' 2020-06-19 23:55:04 -07:00
4cdfac8ccd Global override for selectability and kill part on detach 2020-06-19 23:54:32 -07:00
5db788ed37 Allow selectability in flight to be disabled 2020-06-19 23:24:01 -07:00
5fc9394908 Enable selection for decal colliders in flight, change layer 2020-06-19 22:45:29 -07:00
d8087cce3a Disable collision in flight scene 2020-06-19 22:09:25 -07:00
7487d3fb04 Fix color parsing 2020-06-19 21:55:05 -07:00
533b1f1cf4 Consolidate config parsing and parse layer value 2020-06-19 21:44:43 -07:00
7980ef4791 Fix infinitely scaled decals with zero scale and depth 2020-06-19 17:03:17 -07:00
4d2623a1c6 Layer Test module
idk man
2020-06-19 16:37:35 -07:00
35381fae65 Rename MaterialModifiers namespace 2020-06-19 16:35:10 -07:00
00acb45e18 Fix zbuffer writing in bounds shader 2020-06-18 14:15:59 -07:00
8acf17f189 Shader formatting 2020-06-17 16:43:14 -07:00
4ed4676488 Update README.md 2020-06-17 15:32:42 -07:00
2e32de00e7 Fix deploy config 2020-06-17 14:19:19 -07:00
32097e8baf Add spacedock deployment 2020-06-17 14:04:57 -07:00
ccd71208dc Update version and add SpaceDock deployment 2020-06-17 14:04:42 -07:00
fae34be358 Multiple fixes 2020-06-17 13:57:36 -07:00
26b59400e9 Update README.md 2020-06-16 22:42:07 -07:00
30 changed files with 693 additions and 390 deletions

View File

@ -23,5 +23,8 @@ dependencies: # Configure dependencies
url: http://taniwha.org/~bill/Shabby_v0.1.2.zip url: http://taniwha.org/~bill/Shabby_v0.1.2.zip
zip: true zip: true
deploy: deploy:
SpaceDock:
enabled: true # activate/deactivate this deployment script
mod-id: 2451 # The Spacedock mod ID for deployment
GitHub: GitHub:
enabled: true # activate/deactivate this deployment script enabled: true # activate/deactivate this deployment script

View File

@ -14,10 +14,10 @@ Shader "ConformalDecals/Decal Back"
_Shininess ("Shininess", Range (0.03, 10)) = 0.4 _Shininess ("Shininess", Range (0.03, 10)) = 0.4
[Header(Effects)] [Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1 [PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0) [PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0 [PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
} }
SubShader SubShader

View File

@ -3,22 +3,22 @@ Shader "ConformalDecals/Feature/Bumped"
Properties Properties
{ {
[Header(Texture Maps)] [Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {} _Decal("Decal Texture", 2D) = "gray" {}
_DecalBumpMap("Decal Bump Map", 2D) = "bump" {} _DecalBumpMap("Decal Bump Map", 2D) = "bump" {}
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_DecalOpacity("Opacity", Range(0,1) ) = 1 _DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7) _Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2 [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0 [Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)] [Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1) [PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1 [PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0) [PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0 [PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
} }
SubShader SubShader
{ {
@ -29,8 +29,8 @@ Shader "ConformalDecals/Feature/Bumped"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardBase" } Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward
@ -78,8 +78,8 @@ Shader "ConformalDecals/Feature/Bumped"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" } Tags { "LightMode" = "ForwardAdd" }
Blend One One Blend One One
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward

View File

@ -3,25 +3,25 @@ Shader "ConformalDecals/Paint/Diffuse"
Properties Properties
{ {
[Header(Texture Maps)] [Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {} _Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {} _BumpMap("Bump Map", 2D) = "bump" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100 _EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1 _EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_DecalOpacity("Opacity", Range(0,1) ) = 1 _DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7) _Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2 [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0 [Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)] [Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1) [PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1 [PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0) [PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0 [PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
} }
SubShader SubShader
{ {
@ -32,8 +32,8 @@ Shader "ConformalDecals/Paint/Diffuse"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardBase" } Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward
@ -86,8 +86,8 @@ Shader "ConformalDecals/Paint/Diffuse"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" } Tags { "LightMode" = "ForwardAdd" }
Blend One One Blend One One
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward

View File

@ -3,27 +3,27 @@ Shader "ConformalDecals/Paint/DiffuseSDF"
Properties Properties
{ {
[Header(Texture Maps)] [Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {} _Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {} _BumpMap("Bump Map", 2D) = "bump" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100 _EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1 _EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Smoothness ("SDF smoothness", Range(0,1)) = 0.15 _Smoothness ("SDF smoothness", Range(0,1)) = 0.15
_SmoothnessMipScale ("Smoothness fadeout", Range(0,1)) = 0.1 _SmoothnessMipScale ("Smoothness fadeout", Range(0,1)) = 0.1
_DecalOpacity("Opacity", Range(0,1) ) = 1 _DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7) _Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2 [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0 [Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)] [Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1) [PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1 [PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0) [PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0 [PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
} }
SubShader SubShader
{ {
@ -34,8 +34,8 @@ Shader "ConformalDecals/Paint/DiffuseSDF"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardBase" } Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward
@ -95,8 +95,8 @@ Shader "ConformalDecals/Paint/DiffuseSDF"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" } Tags { "LightMode" = "ForwardAdd" }
Blend One One Blend One One
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward

View File

@ -3,16 +3,16 @@ Shader "ConformalDecals/Paint/Specular"
Properties Properties
{ {
[Header(Texture Maps)] [Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {} _Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {} _BumpMap("Bump Map", 2D) = "bump" {}
_SpecMap("Specular Map", 2D) = "black" {} _SpecMap("Specular Map", 2D) = "black" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100 _EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1 _EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_DecalOpacity("Opacity", Range(0,1) ) = 1 _DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7) _Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Header(Specularity)] [Header(Specularity)]
_SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1) _SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1)
@ -21,12 +21,12 @@ Shader "ConformalDecals/Paint/Specular"
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2 [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0 [Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)] [Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1) [PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1 [PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0) [PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0 [PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
} }
SubShader SubShader
{ {
@ -37,8 +37,8 @@ Shader "ConformalDecals/Paint/Specular"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardBase" } Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward
@ -100,8 +100,8 @@ Shader "ConformalDecals/Paint/Specular"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" } Tags { "LightMode" = "ForwardAdd" }
Blend One One Blend One One
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward

View File

@ -3,18 +3,18 @@ Shader "ConformalDecals/Paint/SpecularSDF"
Properties Properties
{ {
[Header(Texture Maps)] [Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {} _Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {} _BumpMap("Bump Map", 2D) = "bump" {}
_SpecMap("Specular Map", 2D) = "black" {} _SpecMap("Specular Map", 2D) = "black" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100 _EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1 _EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Smoothness ("SDF smoothness", Range(0,1)) = 0.15 _Smoothness ("SDF smoothness", Range(0,1)) = 0.15
_SmoothnessMipScale ("Smoothness fadeout", Range(0,1)) = 0.1 _SmoothnessMipScale ("Smoothness fadeout", Range(0,1)) = 0.1
_DecalOpacity("Opacity", Range(0,1) ) = 1 _DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7) _Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Header(Specularity)] [Header(Specularity)]
_SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1) _SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1)
@ -23,12 +23,12 @@ Shader "ConformalDecals/Paint/SpecularSDF"
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2 [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0 [Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)] [Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1) [PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1 [PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0) [PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0 [PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
} }
SubShader SubShader
{ {
@ -39,8 +39,8 @@ Shader "ConformalDecals/Paint/SpecularSDF"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardBase" } Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward
@ -108,8 +108,8 @@ Shader "ConformalDecals/Paint/SpecularSDF"
Pass Pass
{ {
Name "FORWARD" Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" } Tags { "LightMode" = "ForwardAdd" }
Blend One One Blend One One
CGPROGRAM CGPROGRAM
#pragma vertex vert_forward #pragma vertex vert_forward

View File

@ -91,17 +91,17 @@ inline float CalcMipLevel(float2 texture_coord) {
// modifed version of the KSP BlinnPhong because it does some weird things // modifed version of the KSP BlinnPhong because it does some weird things
inline fixed4 LightingBlinnPhongDecal(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) inline fixed4 LightingBlinnPhongDecal(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{ {
s.Normal = normalize(s.Normal); s.Normal = normalize(s.Normal);
half3 h = normalize(lightDir + viewDir); half3 h = normalize(lightDir + viewDir);
fixed diff = max(0, dot(s.Normal, lightDir)); fixed diff = max(0, dot(s.Normal, lightDir));
float nh = max(0, dot(s.Normal, h)); float nh = max(0, dot(s.Normal, h));
float spec = pow(nh, s.Specular*128.0) * s.Gloss; float spec = pow(nh, s.Specular*128.0) * s.Gloss;
fixed4 c = 0; fixed4 c = 0;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten); c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten);
return c; return c;
} }
// declare surf function, // declare surf function,

View File

@ -3,18 +3,18 @@
inline fixed4 LightingBlinnPhongSmooth(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) inline fixed4 LightingBlinnPhongSmooth(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{ {
s.Normal = normalize(s.Normal); s.Normal = normalize(s.Normal);
half3 h = normalize(lightDir + viewDir); half3 h = normalize(lightDir + viewDir);
fixed diff = max(0, dot(s.Normal, lightDir)); fixed diff = max(0, dot(s.Normal, lightDir));
float nh = max(0, dot(s.Normal, h)); float nh = max(0, dot(s.Normal, h));
float spec = pow(nh, s.Specular*128.0) * s.Gloss; float spec = pow(nh, s.Specular*128.0) * s.Gloss;
fixed4 c; fixed4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten); c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten);
c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten; c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
return c; return c;
} }
@ -22,12 +22,12 @@ inline fixed4 LightingBlinnPhongSmooth(SurfaceOutput s, fixed3 lightDir, half3 v
inline half4 LightingUnlit(SurfaceOutput s, half3 lightDir, half atten) inline half4 LightingUnlit(SurfaceOutput s, half3 lightDir, half atten)
{ {
// half diff = max (0, dot (s.Normal, lightDir)); // half diff = max (0, dot (s.Normal, lightDir));
half4 c; half4 c;
c.rgb = s.Albedo; c.rgb = s.Albedo;
c.a = s.Alpha; c.a = s.Alpha;
return c; return c;
} }
@ -35,10 +35,10 @@ inline half4 LightingUnlit(SurfaceOutput s, half3 lightDir, half atten)
inline half4 LightingUnlit_PrePass(SurfaceOutput s, half4 light) inline half4 LightingUnlit_PrePass(SurfaceOutput s, half4 light)
{ {
half4 c; half4 c;
c.rgb = s.Albedo; c.rgb = s.Albedo;
c.a = s.Alpha; c.a = s.Alpha;
return c; return c;
} }
@ -53,21 +53,21 @@ fixed4 LightingNoLighting(SurfaceOutput s, fixed3 lightDir, fixed atten) { retur
float4 _Color; float4 _Color;
half _LightBoost; half _LightBoost;
half4 LightingLightWrapped(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) { half4 LightingLightWrapped(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
float3 w = _Color.rgb*0.5; float3 w = _Color.rgb*0.5;
half3 NdotL = dot(s.Normal, lightDir); half3 NdotL = dot(s.Normal, lightDir);
//Specular term //Specular term
half3 h = normalize(lightDir + viewDir); half3 h = normalize(lightDir + viewDir);
s.Normal = normalize(s.Normal); s.Normal = normalize(s.Normal);
float NdotH = dot(s.Normal, h); float NdotH = dot(s.Normal, h);
float spec = pow(max(NdotH, 0), s.Specular * 128.0) * s.Gloss; float spec = pow(max(NdotH, 0), s.Specular * 128.0) * s.Gloss;
fixed3 specColor = _SpecColor.rgb * _LightColor0.rgb; fixed3 specColor = _SpecColor.rgb * _LightColor0.rgb;
half3 diff = NdotL * (1 - w) + w; half3 diff = NdotL * (1 - w) + w;
half4 c; half4 c;
c.rgb = ((s.Albedo * _LightColor0.rgb * diff) + (specColor * spec)) * (atten * _LightBoost); c.rgb = ((s.Albedo * _LightColor0.rgb * diff) + (specColor * spec)) * (atten * _LightBoost);
c.a = s.Alpha + (_LightColor0.a * _SpecColor.a * spec * atten); c.a = s.Alpha + (_LightColor0.a * _SpecColor.a * spec * atten);
return c; return c;
} }
@ -84,19 +84,19 @@ float _UnderwaterFogFactor;
float4 UnderwaterFog(float3 worldPos, float3 color) float4 UnderwaterFog(float3 worldPos, float3 color)
{ {
float3 toPixel = worldPos - _LocalCameraPos.xyz; float3 toPixel = worldPos - _LocalCameraPos.xyz;
float toPixelLength = length(toPixel); ///< Comment out the math--looks better without it. float toPixelLength = length(toPixel); ///< Comment out the math--looks better without it.
//float angleDot = dot(_LocalCameraDir.xyz, toPixel / toPixelLength); //float angleDot = dot(_LocalCameraDir.xyz, toPixel / toPixelLength);
//angleDot = lerp(0.00000001, angleDot, saturate(sign(angleDot))); //angleDot = lerp(0.00000001, angleDot, saturate(sign(angleDot)));
//float waterDist = -_LocalCameraPos.w / angleDot; //float waterDist = -_LocalCameraPos.w / angleDot;
//float dist = min(toPixelLength, waterDist); //float dist = min(toPixelLength, waterDist);
float underwaterDetection = _UnderwaterFogFactor * _LocalCameraDir.w; ///< sign(1 - sign(_LocalCameraPos.w)); float underwaterDetection = _UnderwaterFogFactor * _LocalCameraDir.w; ///< sign(1 - sign(_LocalCameraPos.w));
float albedoLerpValue = underwaterDetection * (_UnderwaterMaxAlbedoFog * saturate(toPixelLength * _UnderwaterAlbedoDistanceScalar)); float albedoLerpValue = underwaterDetection * (_UnderwaterMaxAlbedoFog * saturate(toPixelLength * _UnderwaterAlbedoDistanceScalar));
float alphaFactor = 1 - underwaterDetection * (_UnderwaterMaxAlphaFog * saturate((toPixelLength - _UnderwaterMinAlphaFogDistance) * _UnderwaterAlphaDistanceScalar)); float alphaFactor = 1 - underwaterDetection * (_UnderwaterMaxAlphaFog * saturate((toPixelLength - _UnderwaterMinAlphaFogDistance) * _UnderwaterAlphaDistanceScalar));
return float4(lerp(color, _UnderwaterFogColor.rgb, albedoLerpValue), alphaFactor); return float4(lerp(color, _UnderwaterFogColor.rgb, albedoLerpValue), alphaFactor);
} }
#endif #endif

View File

@ -0,0 +1,76 @@
Shader "ConformalDecals/SDF4test"
{
Properties
{
_MainTex("_MainTex (RGB spec(A))", 2D) = "white" {}
_Color1("Color 1", Color) = (0,0,0,0)
_Color2("Color 2", Color) = (0,0,0,0)
_Color3("Color 3", Color) = (0,0,0,0)
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Smoothness ("SDF smoothness", Range(0,1)) = 0.15
}
SubShader
{
Tags { "Queue" = "Transparent" }
Cull Back
ZWrite On
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
float4 _Color1;
float4 _Color2;
float4 _Color3;
float _Smoothness;
float _Cutoff;
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldPosition : TEXCOORD1;
half3 worldNormal : TEXCOORD2;
};
v2f vert(float4 vertex : POSITION, float2 uv : TEXCOORD0) {
v2f o;
o.pos = UnityObjectToClipPos(vertex);
o.uv = uv;
o.worldPosition = mul(unity_ObjectToWorld, vertex).xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 c = 0;
float4 s = tex2D(_MainTex,(i.uv));
s.rgb = s.rbg;
c = lerp(c, _Color1, smoothstep(_Cutoff, saturate(_Smoothness+ _Cutoff), s.r + s.g + s.b));
c = lerp(c, _Color2, smoothstep(_Cutoff, saturate(_Smoothness+ _Cutoff), s.g + s.b ));
c = lerp(c, _Color3, smoothstep(_Cutoff, saturate(_Smoothness+ _Cutoff), s.b ));
// if (s.r + s.g + s.b > 0.5) {
// if (s.r > s.g && s.r > s.b) c = _Color1;
// if (s.g > s.r && s.g > s.b) c = _Color2;
// if (s.b > s.g && s.b > s.r) c = _Color3;
// }
return c;
}
ENDCG
}
}
}

View File

@ -2,22 +2,23 @@ Shader "ConformalDecals/SelectionGlow"
{ {
Properties Properties
{ {
[Header(Effects)] [Header(Effects)]
_RimEdgeGlow("Rim Edge Glow", Range(0, 1)) = 0.45 _RimEdgeGlow("Rim Edge Glow", Range(0, 1)) = 0.45
_RimEdgePow("Rim Edge Falloff", Range(0,5)) = 5 _RimEdgePow("Rim Edge Falloff", Range(0,5)) = 5
_RimEdgeOpacity("Rim Edge Opacity", Range(0,1)) = 0.2 _RimEdgeOpacity("Rim Edge Opacity", Range(0,1)) = 0.2
_RimFalloff("Rim Falloff", Range(0.01,5) ) = 0.1 _RimFalloff("Rim Falloff", Range(0.01,5) ) = 0.1
_RimColor("Rim Color", Color) = (0,0,0,0) _RimColor("Rim Color", Color) = (0,0,0,0)
_RimOpacity("Rim Opacity", Range(0,1)) = 0.5 _RimOpacity("Rim Opacity", Range(0,1)) = 0.5
} }
SubShader SubShader
{ {
Tags { "Queue" = "Transparent" } Tags { "Queue" = "Transparent" }
Cull Back Cull Back
ZWrite Off
Pass Pass
{ {
Blend One One Blend One One
CGPROGRAM CGPROGRAM
#pragma vertex vert #pragma vertex vert

View File

@ -1,4 +1,7 @@
CONFORMALDECALS { CONFORMALDECALS {
decalLayer = 31
selectableInFlight = false
SHADERBLACKLIST { SHADERBLACKLIST {
shader = DepthMask shader = DepthMask
shader = KSP/Alpha/Cutoff shader = KSP/Alpha/Cutoff

View File

@ -6,7 +6,7 @@
{ {
"MAJOR":0, "MAJOR":0,
"MINOR":1, "MINOR":1,
"PATCH":0, "PATCH":3,
"BUILD":0 "BUILD":0
}, },
"KSP_VERSION": "KSP_VERSION":

View File

@ -1,16 +1,21 @@
# Conformal Decals v0.1.0 # Conformal Decals v0.1.3
[![Build Status](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals.svg?branch=release)](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals) [![Art: CC BY-SA 4.0](https://img.shields.io/badge/Art%20License-CC%20BY--SA%204.0-orange.svg)](https://creativecommons.org/licenses/by-sa/4.0/) [![Code: GPL v3](https://img.shields.io/badge/Code%20License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Build Status](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals.svg?branch=release)](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals) [![Art: CC BY-SA 4.0](https://img.shields.io/badge/Art%20License-CC%20BY--SA%204.0-orange.svg)](https://creativecommons.org/licenses/by-sa/4.0/) [![Code: GPL v3](https://img.shields.io/badge/Code%20License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
![Screenshot](http://pileof.rocks/KSP/images/ConformalDecalsHeader.png)
Conformal Decals adds a set of decal stickers to KSP, as well as providing a framework for creating your own decals which conform to the surface of the parts they are attached to. Conformal Decals adds a set of decal stickers to KSP, as well as providing a framework for creating your own decals which conform to the surface of the parts they are attached to.
## Dependencies ## Dependencies
Required: Required:
- KSP (1.8.0 to 1.9.0) - KSP (1.8.x to 1.9.x)
- B9 Part Switch (2.16.0). Bundled with release. - B9 Part Switch (2.16.0). Bundled with release.
- ModuleManager (4.1.3). Bundled with release. - ModuleManager (4.1.3). Bundled with release.
- Shabby (0.1.2). Bundled with release. - Shabby (0.1.2). Bundled with release.
Optional:
- Wild Blue Tools. For custom decals category in the VAB and SPH.
## Credits ## Credits
- Art and Plugin code: Andrew Cassidy (Cineboxandrew) - Art and Plugin code: Andrew Cassidy (Cineboxandrew)
@ -27,6 +32,6 @@ Art assets and configuration files are licensed CC-BY-SA 4.0, as described in th
Plugin code is distributed under the GPL v3, as described in the LICENSE-SOURCE.md file Plugin code is distributed under the GPL v3, as described in the LICENSE-SOURCE.md file
Any bundled mods are distributed under their own license: Any bundled mods are distributed under their own license:
- ModuleManager by blowfish and sarbian is distributed under a Creative Commons Sharealike license. More details, including source code, can be found here: https://forum.kerbalspaceprogram.com/index.php?/topic/50533-* - ModuleManager by blowfish and sarbian is distributed under a Creative Commons Sharealike license. More details, including source code, can be found [here](https://forum.kerbalspaceprogram.com/index.php?/topic/50533-*).
- B9PartSwitch by blowfish is distributed under the LGPL v3 license. - B9PartSwitch by blowfish is distributed under the LGPL v3 license.
- Shabby by taniwha is distributed under the GPL v3 license. - Shabby by taniwha is distributed under the GPL v3 license.

View File

@ -54,20 +54,22 @@
<Compile Include="DecalConfig.cs" /> <Compile Include="DecalConfig.cs" />
<Compile Include="DecalIconFixer.cs" /> <Compile Include="DecalIconFixer.cs" />
<Compile Include="DecalPropertyIDs.cs" /> <Compile Include="DecalPropertyIDs.cs" />
<Compile Include="MaterialModifiers\MaterialColorProperty.cs" /> <Compile Include="MaterialProperties\MaterialColorProperty.cs" />
<Compile Include="MaterialModifiers\MaterialFloatProperty.cs" /> <Compile Include="MaterialProperties\MaterialFloatProperty.cs" />
<Compile Include="MaterialModifiers\MaterialProperty.cs" /> <Compile Include="MaterialProperties\MaterialProperty.cs" />
<Compile Include="MaterialModifiers\MaterialPropertyCollection.cs" /> <Compile Include="MaterialProperties\MaterialPropertyCollection.cs" />
<Compile Include="MaterialModifiers\MaterialTextureProperty.cs" /> <Compile Include="MaterialProperties\MaterialTextureProperty.cs" />
<Compile Include="ModuleConformalFlag.cs" /> <Compile Include="ModuleConformalFlag.cs" />
<Compile Include="ProjectionTarget.cs" /> <Compile Include="ProjectionTarget.cs" />
<Compile Include="ModuleConformalDecal.cs" /> <Compile Include="ModuleConformalDecal.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Test\TestLayers.cs" />
<Compile Include="Util\Logging.cs" /> <Compile Include="Util\Logging.cs" />
<Compile Include="Util\OrientedBounds.cs" /> <Compile Include="Util\OrientedBounds.cs" />
<Compile Include="Util\ParseUtil.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent>sh -e -c "cp -v '$(TargetPath)' '$(SolutionDir)/../Distribution/GameData/ConformalDecals/Plugins'"</PostBuildEvent> <PostBuildEvent>sh -e -c "cp -v '$(TargetPath)' '$(SolutionDir)/../GameData/ConformalDecals/Plugins'"</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@ -1,14 +1,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace ConformalDecals { namespace ConformalDecals {
public static class DecalConfig { public static class DecalConfig {
private static Texture2D _blankNormal; private static Texture2D _blankNormal;
private static List<string> _shaderBlacklist; private static List<string> _shaderBlacklist;
private static int _decalLayer = 31;
private static bool _selectableInFlight = false;
public static Texture2D BlankNormal => _blankNormal; public static Texture2D BlankNormal => _blankNormal;
public static int DecalLayer => _decalLayer;
public static bool SelectableInFlight => _selectableInFlight;
public static bool IsBlacklisted(Shader shader) { public static bool IsBlacklisted(Shader shader) {
return IsBlacklisted(shader.name); return IsBlacklisted(shader.name);
} }
@ -22,6 +28,9 @@ namespace ConformalDecals {
foreach (var shaderName in blacklist.GetValuesList("shader")) { foreach (var shaderName in blacklist.GetValuesList("shader")) {
_shaderBlacklist.Add(shaderName); _shaderBlacklist.Add(shaderName);
} }
ParseUtil.ParseIntIndirect(ref _decalLayer, node, "decalLayer");
ParseUtil.ParseBoolIndirect(ref _selectableInFlight, node, "selectableInFlight");
} }
} }
@ -30,7 +39,7 @@ namespace ConformalDecals {
var width = 2; var width = 2;
var height = 2; var height = 2;
var color = new Color32(255, 128, 128, 128); var color = new Color32(255, 128, 128, 128);
var colors = new Color32[] { color, color, color, color }; var colors = new[] {color, color, color, color};
var tex = new Texture2D(width, height, TextureFormat.RGBA32, false); var tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
for (var x = 0; x <= width; x++) { for (var x = 0; x <= width; x++) {
@ -38,11 +47,13 @@ namespace ConformalDecals {
tex.SetPixels32(colors); tex.SetPixels32(colors);
} }
} }
tex.Apply(); tex.Apply();
return tex; return tex;
} }
// ReSharper disable once UnusedMember.Global
public static void ModuleManagerPostLoad() { public static void ModuleManagerPostLoad() {
_shaderBlacklist = new List<string>(); _shaderBlacklist = new List<string>();
@ -55,6 +66,14 @@ namespace ConformalDecals {
} }
} }
// setup physics for decals, ignore collision with everything
Physics.IgnoreLayerCollision(_decalLayer, 1, true); // default
Physics.IgnoreLayerCollision(_decalLayer, 17, true); // EVA
Physics.IgnoreLayerCollision(_decalLayer, 19, true); // PhysicalObjects
Physics.IgnoreLayerCollision(_decalLayer, 23, true); // AeroFXIgnore
Physics.IgnoreLayerCollision(_decalLayer, 26, true); // wheelCollidersIgnore
Physics.IgnoreLayerCollision(_decalLayer, 27, true); // wheelColliders
_blankNormal = MakeBlankNormal(); _blankNormal = MakeBlankNormal();
} }
} }

View File

@ -1,79 +0,0 @@
using System;
using UnityEngine;
namespace ConformalDecals.MaterialModifiers {
public abstract class MaterialProperty : ScriptableObject {
public string PropertyName {
get => _propertyName;
set {
_propertyName = value;
_propertyID = Shader.PropertyToID(_propertyName);
}
}
[SerializeField] protected int _propertyID;
[SerializeField] protected string _propertyName;
public virtual void ParseNode(ConfigNode node) {
if (node == null) throw new ArgumentNullException(nameof(node));
PropertyName = node.GetValue("name");
Debug.Log($"Parsing material property {_propertyName}");
}
public abstract void Modify(Material material);
private delegate bool TryParseDelegate<T>(string valueString, out T value);
protected bool ParsePropertyBool(ConfigNode node, string valueName, bool isOptional = false, bool defaultValue = false) {
return ParsePropertyValue(node, valueName, bool.TryParse, isOptional, defaultValue);
}
protected float ParsePropertyFloat(ConfigNode node, string valueName, bool isOptional = false, float defaultValue = 0.0f) {
return ParsePropertyValue(node, valueName, float.TryParse, isOptional, defaultValue);
}
protected int ParsePropertyInt(ConfigNode node, string valueName, bool isOptional = false, int defaultValue = 0) {
return ParsePropertyValue(node, valueName, int.TryParse, isOptional, defaultValue);
}
protected Color ParsePropertyColor(ConfigNode node, string valueName, bool isOptional = false, Color defaultValue = default) {
return ParsePropertyValue(node, valueName, ParseExtensions.TryParseColor, isOptional, defaultValue);
}
protected Rect ParsePropertyRect(ConfigNode node, string valueName, bool isOptional = false, Rect defaultValue = default) {
return ParsePropertyValue(node, valueName, ParseExtensions.TryParseRect, isOptional, defaultValue);
}
protected Vector2 ParsePropertyVector2(ConfigNode node, string valueName, bool isOptional = false, Vector2 defaultValue = default) {
return ParsePropertyValue(node, valueName, ParseExtensions.TryParseVector2, isOptional, defaultValue);
}
private T ParsePropertyValue<T>(ConfigNode node, string valueName, TryParseDelegate<T> tryParse, bool isOptional = false, T defaultValue = default) {
string valueString = node.GetValue(valueName);
if (isOptional) {
if (string.IsNullOrEmpty(valueString)) return defaultValue;
}
else {
if (valueString == null)
throw new FormatException($"Missing {typeof(T)} value for {valueName} in property '{PropertyName}'");
if (valueString == string.Empty)
throw new FormatException($"Empty {typeof(T)} value for {valueName} in property '{PropertyName}'");
}
if (tryParse(valueString, out var value)) {
return value;
}
if (isOptional) {
return defaultValue;
}
else {
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} in property '{PropertyName}' : '{valueString}");
}
}
}
}

View File

@ -1,18 +1,19 @@
using System; using System;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialColorProperty : MaterialProperty { public class MaterialColorProperty : MaterialProperty {
[SerializeField] public Color color; [SerializeField] public Color32 color = new Color32(0, 0, 0, byte.MaxValue);
public override void ParseNode(ConfigNode node) { public override void ParseNode(ConfigNode node) {
base.ParseNode(node); base.ParseNode(node);
color = ParsePropertyColor(node, "color", true, color); ParseUtil.ParseColor32Indirect(ref color, node, "color");
} }
public override void Modify(Material material) { public override void Modify(Material material) {
if (material == null) throw new ArgumentNullException("material cannot be null"); if (material == null) throw new ArgumentNullException(nameof(material));
material.SetColor(_propertyID, color); material.SetColor(_propertyID, color);
} }

View File

@ -1,18 +1,19 @@
using System; using System;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialFloatProperty : MaterialProperty { public class MaterialFloatProperty : MaterialProperty {
[SerializeField] public float value; [SerializeField] public float value;
public override void ParseNode(ConfigNode node) { public override void ParseNode(ConfigNode node) {
base.ParseNode(node); base.ParseNode(node);
value = ParsePropertyFloat(node, "value", true, value); ParseUtil.ParseFloatIndirect(ref value, node, "value");
} }
public override void Modify(Material material) { public override void Modify(Material material) {
if (material == null) throw new ArgumentNullException("material cannot be null"); if (material == null) throw new ArgumentNullException(nameof(material));
material.SetFloat(_propertyID, value); material.SetFloat(_propertyID, value);
} }

View File

@ -0,0 +1,26 @@
using System;
using UnityEngine;
namespace ConformalDecals.MaterialProperties {
public abstract class MaterialProperty : ScriptableObject {
public string PropertyName {
get => _propertyName;
set {
_propertyName = value;
_propertyID = Shader.PropertyToID(_propertyName);
}
}
[SerializeField] protected int _propertyID;
[SerializeField] protected string _propertyName;
public virtual void ParseNode(ConfigNode node) {
if (node == null) throw new ArgumentNullException(nameof(node));
PropertyName = node.GetValue("name");
Debug.Log($"Parsing material property {_propertyName}");
}
public abstract void Modify(Material material);
}
}

View File

@ -1,11 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using ConformalDecals.Util;
using UniLinq; using UniLinq;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialPropertyCollection : ScriptableObject, ISerializationCallbackReceiver { public class MaterialPropertyCollection : ScriptableObject, ISerializationCallbackReceiver {
public int RenderQueue { public int RenderQueue {
get => _renderQueue; get => _renderQueue;
@ -163,8 +164,8 @@ namespace ConformalDecals.MaterialModifiers {
} }
public T ParseProperty<T>(ConfigNode node) where T : MaterialProperty { public T ParseProperty<T>(ConfigNode node) where T : MaterialProperty {
var propertyName = node.GetValue("name"); string propertyName = "";
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentException("node has no name"); if (!ParseUtil.ParseStringIndirect(ref propertyName, node, "name")) throw new ArgumentException("node has no name");
var newProperty = AddOrGetProperty<T>(propertyName); var newProperty = AddOrGetProperty<T>(propertyName);
newProperty.ParseNode(node); newProperty.ParseNode(node);

View File

@ -1,7 +1,8 @@
using System; using System;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialTextureProperty : MaterialProperty { public class MaterialTextureProperty : MaterialProperty {
[SerializeField] public bool isNormal; [SerializeField] public bool isNormal;
[SerializeField] public bool isMain; [SerializeField] public bool isMain;
@ -9,7 +10,7 @@ namespace ConformalDecals.MaterialModifiers {
[SerializeField] public bool autoTile; [SerializeField] public bool autoTile;
[SerializeField] private string _textureUrl; [SerializeField] private string _textureUrl;
[SerializeField] private Texture2D _texture; [SerializeField] private Texture2D _texture = Texture2D.whiteTexture;
[SerializeField] private bool _hasTile; [SerializeField] private bool _hasTile;
[SerializeField] private Rect _tileRect; [SerializeField] private Rect _tileRect;
@ -42,24 +43,17 @@ namespace ConformalDecals.MaterialModifiers {
public override void ParseNode(ConfigNode node) { public override void ParseNode(ConfigNode node) {
base.ParseNode(node); base.ParseNode(node);
isNormal = ParsePropertyBool(node, "isNormalMap", true, (PropertyName == "_BumpMap") || (PropertyName == "_DecalBumpMap") || isNormal); ParseUtil.ParseBoolIndirect(ref isMain, node, "isMain");
isMain = ParsePropertyBool(node, "isMain", true, isMain); ParseUtil.ParseBoolIndirect(ref isNormal, node, "isNormalMap");
autoScale = ParsePropertyBool(node, "autoScale", true, autoScale); ParseUtil.ParseBoolIndirect(ref autoScale, node, "autoScale");
autoTile = ParsePropertyBool(node, "autoTile", true, autoTile); ParseUtil.ParseBoolIndirect(ref autoTile, node, "autoTile");
var textureUrl = node.GetValue("textureUrl"); if (!autoTile) {
ParseUtil.ParseRectIndirect(ref _tileRect, node, "tile");
if (string.IsNullOrEmpty(textureUrl)) {
if (string.IsNullOrEmpty(_textureUrl)) {
TextureUrl = "";
}
}
else {
TextureUrl = node.GetValue("textureUrl");
} }
if (node.HasValue("tile") && !autoTile) { if (ParseUtil.ParseStringIndirect(ref _textureUrl, node, "textureUrl")) {
SetTile(ParsePropertyRect(node, "tile", true, _tileRect)); _texture = LoadTexture(_textureUrl, isNormal);
} }
} }

View File

@ -1,11 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ConformalDecals.MaterialModifiers; using System.Diagnostics.CodeAnalysis;
using ConformalDecals.MaterialProperties;
using ConformalDecals.Util; using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals { namespace ConformalDecals {
public class ModuleConformalDecal : PartModule { public class ModuleConformalDecal : PartModule {
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DecalScaleMode { public enum DecalScaleMode {
HEIGHT, HEIGHT,
WIDTH, WIDTH,
@ -17,43 +19,21 @@ namespace ConformalDecals {
// CONFIGURABLE VALUES // CONFIGURABLE VALUES
/// <summary>
/// Shader name. Should be one that supports decal projection.
/// </summary>
[KSPField] public string shader = "ConformalDecals/Paint/Diffuse"; [KSPField] public string shader = "ConformalDecals/Paint/Diffuse";
/// <summary> [KSPField] public string decalFront = "Decal-Front";
/// Decal front transform name. Required [KSPField] public string decalBack = "Decal-Back";
/// </summary> [KSPField] public string decalModel = "Decal-Model";
[KSPField] public string decalFront = "Decal-Front";
/// <summary>
/// Decal back transform name. Required if <see cref="updateBackScale"/> is true.
/// </summary>
[KSPField] public string decalBack = "Decal-Back";
/// <summary>
/// Decal model transform name. Is rescaled to preview the decal scale when unattached.
/// </summary>
/// <remarks>
/// If unspecified, the decal front transform is used instead.
/// </remarks>
[KSPField] public string decalModel = "Decal-Model";
/// <summary>
/// Decal projector transform name. The decal will project along the +Z axis of this transform.
/// </summary>
/// <remarks>
/// if unspecified, the part "model" transform will be used instead.
/// </remarks>
[KSPField] public string decalProjector = "Decal-Projector"; [KSPField] public string decalProjector = "Decal-Projector";
[KSPField] public string decalCollider = "Decal-Collider";
// Parameters // Parameters
[KSPField] public bool scaleAdjustable = true; [KSPField] public bool scaleAdjustable = true;
[KSPField] public float defaultScale = 1; [KSPField] public float defaultScale = 1;
[KSPField] public Vector2 scaleRange = new Vector2(0, 4); [KSPField] public Vector2 scaleRange = new Vector2(0, 4);
[KSPField] public DecalScaleMode scaleMode = DecalScaleMode.HEIGHT;
[KSPField] public DecalScaleMode scaleMode = DecalScaleMode.HEIGHT;
[KSPField] public bool depthAdjustable = true; [KSPField] public bool depthAdjustable = true;
[KSPField] public float defaultDepth = 0.1f; [KSPField] public float defaultDepth = 0.1f;
@ -75,55 +55,39 @@ namespace ConformalDecals {
[KSPField] public Vector2 tileSize; [KSPField] public Vector2 tileSize;
[KSPField] public int tileIndex = -1; [KSPField] public int tileIndex = -1;
/// <summary>
/// Should the back material scale be updated automatically?
/// </summary>
[KSPField] public bool updateBackScale = true; [KSPField] public bool updateBackScale = true;
[KSPField] public bool selectableInFlight;
// INTERNAL VALUES // INTERNAL VALUES
/// <summary>
/// Decal scale factor, in meters.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-scale", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"), [KSPField(guiName = "#LOC_ConformalDecals_gui-scale", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"),
UI_FloatRange(stepIncrement = 0.05f)] UI_FloatRange(stepIncrement = 0.05f)]
public float scale = 1.0f; public float scale = 1.0f;
/// <summary>
/// Projection depth value for the decal projector, in meters.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-depth", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"), [KSPField(guiName = "#LOC_ConformalDecals_gui-depth", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"),
UI_FloatRange(stepIncrement = 0.02f)] UI_FloatRange(stepIncrement = 0.02f)]
public float depth = 0.2f; public float depth = 0.2f;
/// <summary>
/// Opacity value for the decal shader.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-opacity", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"), [KSPField(guiName = "#LOC_ConformalDecals_gui-opacity", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"),
UI_FloatRange(stepIncrement = 0.05f)] UI_FloatRange(stepIncrement = 0.05f)]
public float opacity = 1.0f; public float opacity = 1.0f;
/// <summary>
/// Alpha cutoff value for the decal shader.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-cutoff", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"), [KSPField(guiName = "#LOC_ConformalDecals_gui-cutoff", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"),
UI_FloatRange(stepIncrement = 0.05f)] UI_FloatRange(stepIncrement = 0.05f)]
public float cutoff = 0.5f; public float cutoff = 0.5f;
/// <summary>
/// Edge wear value for the decal shader. Only relevent when useBaseNormal is true and the shader is a paint shader
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-wear", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F0"), [KSPField(guiName = "#LOC_ConformalDecals_gui-wear", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F0"),
UI_FloatRange()] UI_FloatRange()]
public float wear = 100; public float wear = 100;
[KSPField(isPersistant = true)] public bool projectMultiple; // reserved for future features. do not modify
[KSPField] public MaterialPropertyCollection materialProperties; [KSPField] public MaterialPropertyCollection materialProperties;
[KSPField] public Transform decalFrontTransform; [KSPField] public Transform decalFrontTransform;
[KSPField] public Transform decalBackTransform; [KSPField] public Transform decalBackTransform;
[KSPField] public Transform decalModelTransform; [KSPField] public Transform decalModelTransform;
[KSPField] public Transform decalProjectorTransform; [KSPField] public Transform decalProjectorTransform;
[KSPField] public Transform decalColliderTransform;
[KSPField] public Material backMaterial; [KSPField] public Material backMaterial;
[KSPField] public Vector2 backTextureBaseScale; [KSPField] public Vector2 backTextureBaseScale;
@ -137,9 +101,9 @@ namespace ConformalDecals {
private bool _isAttached; private bool _isAttached;
private Matrix4x4 _orthoMatrix; private Matrix4x4 _orthoMatrix;
private Material _decalMaterial; private Material _decalMaterial;
private Material _previewMaterial; private Material _previewMaterial;
private BoxCollider _boundsCollider; private MeshRenderer _boundsRenderer;
private int DecalQueue { private int DecalQueue {
get { get {
@ -169,43 +133,22 @@ namespace ConformalDecals {
this.Log("Loading module"); this.Log("Loading module");
try { try {
// SETUP TRANSFORMS // SETUP TRANSFORMS
// find front transform
decalFrontTransform = part.FindModelTransform(decalFront); decalFrontTransform = part.FindModelTransform(decalFront);
if (decalFrontTransform == null) throw new FormatException($"Could not find decalFront transform: '{decalFront}'."); if (decalFrontTransform == null) throw new FormatException($"Could not find decalFront transform: '{decalFront}'.");
// find back transform decalBackTransform = part.FindModelTransform(decalBack);
if (string.IsNullOrEmpty(decalBack)) { if (decalBackTransform == null) throw new FormatException($"Could not find decalBack transform: '{decalBack}'.");
if (updateBackScale) {
this.LogWarning("updateBackScale is true but has no specified decalBack transform!");
this.LogWarning("Setting updateBackScale to false.");
updateBackScale = false;
}
}
else {
decalBackTransform = part.FindModelTransform(decalBack);
if (decalBackTransform == null) throw new FormatException($"Could not find decalBack transform: '{decalBack}'.");
}
// find model transform decalModelTransform = part.FindModelTransform(decalModel);
if (string.IsNullOrEmpty(decalModel)) { if (decalModelTransform == null) throw new FormatException($"Could not find decalModel transform: '{decalModel}'.");
decalModelTransform = decalFrontTransform;
}
else {
decalModelTransform = part.FindModelTransform(decalModel);
if (decalModelTransform == null) throw new FormatException($"Could not find decalModel transform: '{decalModel}'.");
}
// find projector transform decalProjectorTransform = part.FindModelTransform(decalProjector);
if (string.IsNullOrEmpty(decalProjector)) { if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'.");
decalProjectorTransform = part.transform;
}
else {
decalProjectorTransform = part.FindModelTransform(decalProjector);
if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'.");
}
// get back material if necessary decalColliderTransform = part.FindModelTransform(decalCollider);
if (decalColliderTransform == null) throw new FormatException($"Could not find decalCollider transform: '{decalCollider}'.");
// SETUP BACK MATERIAL
if (updateBackScale) { if (updateBackScale) {
this.Log("Getting material and base scale for back material"); this.Log("Getting material and base scale for back material");
var backRenderer = decalBackTransform.GetComponent<MeshRenderer>(); var backRenderer = decalBackTransform.GetComponent<MeshRenderer>();
@ -294,17 +237,11 @@ namespace ConformalDecals {
public override void OnStart(StartState state) { public override void OnStart(StartState state) {
this.Log("Starting module"); this.Log("Starting module");
// handle tweakables
if (HighLogic.LoadedSceneIsEditor) {
GameEvents.onEditorPartEvent.Add(OnEditorEvent);
GameEvents.onVariantApplied.Add(OnVariantApplied);
UpdateTweakables();
}
materialProperties.RenderQueue = DecalQueue; materialProperties.RenderQueue = DecalQueue;
_boundsCollider = decalProjectorTransform.GetComponent<BoxCollider>(); _boundsRenderer = decalProjectorTransform.GetComponent<MeshRenderer>();
UpdateMaterials(); UpdateMaterials();
@ -317,12 +254,40 @@ namespace ConformalDecals {
OnAttach(); OnAttach();
} }
} }
// handle tweakables
if (HighLogic.LoadedSceneIsEditor) {
GameEvents.onEditorPartEvent.Add(OnEditorEvent);
GameEvents.onVariantApplied.Add(OnVariantApplied);
UpdateTweakables();
}
// handle flight events
if (HighLogic.LoadedSceneIsFlight) {
GameEvents.onPartWillDie.Add(OnPartWillDie);
Part.layerMask |= 1 << DecalConfig.DecalLayer;
decalColliderTransform.gameObject.layer = DecalConfig.DecalLayer;
if (!selectableInFlight || !DecalConfig.SelectableInFlight) {
decalColliderTransform.GetComponent<Collider>().enabled = false;
}
if (part.parent == null) part.explode();
}
} }
public virtual void OnDestroy() { public virtual void OnDestroy() {
// remove GameEvents // remove GameEvents
GameEvents.onEditorPartEvent.Remove(OnEditorEvent); if (HighLogic.LoadedSceneIsEditor) {
GameEvents.onVariantApplied.Remove(OnVariantApplied); GameEvents.onEditorPartEvent.Remove(OnEditorEvent);
GameEvents.onVariantApplied.Remove(OnVariantApplied);
}
if (HighLogic.LoadedSceneIsFlight) {
GameEvents.onPartWillDie.Remove(OnPartWillDie);
}
// remove from preCull delegate // remove from preCull delegate
Camera.onPreCull -= Render; Camera.onPreCull -= Render;
@ -381,6 +346,13 @@ namespace ConformalDecals {
} }
} }
protected void OnPartWillDie(Part willDie) {
if (willDie == part.parent) {
this.Log("Parent part about to be destroyed! Killing decal part.");
part.Die();
}
}
protected void OnAttach() { protected void OnAttach() {
if (part.parent == null) { if (part.parent == null) {
this.LogError("Attach function called but part has no parent!"); this.LogError("Attach function called but part has no parent!");
@ -423,6 +395,8 @@ namespace ConformalDecals {
} }
protected void UpdateScale() { protected void UpdateScale() {
scale = Mathf.Max(0.01f, scale);
depth = Mathf.Max(0.01f, depth);
var aspectRatio = materialProperties.AspectRatio; var aspectRatio = materialProperties.AspectRatio;
Vector2 size; Vector2 size;
@ -463,7 +437,7 @@ namespace ConformalDecals {
// update projection // update projection
foreach (var target in _targets) { foreach (var target in _targets) {
target.Project(_orthoMatrix, decalProjectorTransform, _boundsCollider.bounds, useBaseNormal); target.Project(_orthoMatrix, decalProjectorTransform, _boundsRenderer.bounds, useBaseNormal);
} }
} }
else { else {

View File

@ -95,6 +95,7 @@ namespace ConformalDecals {
materialProperties.AddOrGetTextureProperty("_Decal", true).TextureUrl = newFlagUrl; materialProperties.AddOrGetTextureProperty("_Decal", true).TextureUrl = newFlagUrl;
UpdateMaterials(); UpdateMaterials();
UpdateScale();
} }
private void SetFlagSymmetryCounterparts(string newFlagUrl) { private void SetFlagSymmetryCounterparts(string newFlagUrl) {

View File

@ -0,0 +1,34 @@
using System;
using UnityEngine;
namespace ConformalDecals.Test {
public class TestLayers : PartModule {
[KSPField(guiActive = true)]
public int layer = 2;
public override void OnStart(StartState state) {
base.OnStart(state);
Part.layerMask.value |= (1 << 3);
}
public void Update() {
foreach (var collider in GameObject.FindObjectsOfType<Collider>()) {
if (collider.gameObject.layer == 3) {
Debug.Log($"Has layer 3: {collider.gameObject.name}");
}
}
}
[KSPEvent(guiActive = true, guiActiveEditor = true, guiName = "switch layers")]
public void Switch() {
Debug.Log(Part.layerMask.value);
var cube = part.FindModelTransform("test");
layer = (layer + 1) % 32;
cube.gameObject.layer = layer;
}
}
}

View File

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
namespace ConformalDecals.Util {
public static class ParseUtil {
private static readonly Dictionary<string, Color> NamedColors = new Dictionary<string, Color>();
private static readonly char[] Separator = {',', ' ', '\t'};
public delegate bool TryParseDelegate<T>(string valueString, out T value);
static ParseUtil() {
// setup named colors
foreach (var propertyInfo in typeof(Color).GetProperties(BindingFlags.Static | BindingFlags.Public)) {
if (!propertyInfo.CanRead) continue;
if (propertyInfo.PropertyType != typeof(Color)) continue;
NamedColors.Add(propertyInfo.Name, (Color) propertyInfo.GetValue(null, null));
}
foreach (var propertyInfo in typeof(XKCDColors).GetProperties(BindingFlags.Static | BindingFlags.Public)) {
if (!propertyInfo.CanRead) continue;
if (propertyInfo.PropertyType != typeof(Color)) continue;
if (NamedColors.ContainsKey(propertyInfo.Name)) throw new Exception("duplicate key " + propertyInfo.Name);
NamedColors.Add(propertyInfo.Name, (Color) propertyInfo.GetValue(null, null));
}
}
public static string ParseString(ConfigNode node, string valueName, bool isOptional = false, string defaultValue = "") {
if (!node.HasValue(valueName)) throw new FormatException($"Missing value for {valueName}");
return node.GetValue(valueName);
}
public static bool ParseStringIndirect(ref string value, ConfigNode node, string valueName) {
if (node.HasValue(valueName)) {
value = node.GetValue(valueName);
return true;
}
return false;
}
public static bool ParseBool(ConfigNode node, string valueName, bool isOptional = false, bool defaultValue = false) {
return ParseValue(node, valueName, bool.TryParse, isOptional, defaultValue);
}
public static bool ParseBoolIndirect(ref bool value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, bool.TryParse);
}
public static float ParseFloat(ConfigNode node, string valueName, bool isOptional = false, float defaultValue = 0.0f) {
return ParseValue(node, valueName, float.TryParse, isOptional, defaultValue);
}
public static bool ParseFloatIndirect(ref float value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, float.TryParse);
}
public static int ParseInt(ConfigNode node, string valueName, bool isOptional = false, int defaultValue = 0) {
return ParseValue(node, valueName, int.TryParse, isOptional, defaultValue);
}
public static bool ParseIntIndirect(ref int value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, int.TryParse);
}
public static Color32 ParseColor32(ConfigNode node, string valueName, bool isOptional = false, Color32 defaultValue = default) {
return ParseValue(node, valueName, TryParseColor32, isOptional, defaultValue);
}
public static bool ParseColor32Indirect(ref Color32 value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, TryParseColor32);
}
public static Rect ParseRect(ConfigNode node, string valueName, bool isOptional = false, Rect defaultValue = default) {
return ParseValue(node, valueName, ParseExtensions.TryParseRect, isOptional, defaultValue);
}
public static bool ParseRectIndirect(ref Rect value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, ParseExtensions.TryParseRect);
}
public static Vector2 ParseVector2(ConfigNode node, string valueName, bool isOptional = false, Vector2 defaultValue = default) {
return ParseValue(node, valueName, ParseExtensions.TryParseVector2, isOptional, defaultValue);
}
public static bool ParseVector2Indirect(ref Vector2 value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, ParseExtensions.TryParseVector2);
}
public static Vector3 ParseVector3(ConfigNode node, string valueName, bool isOptional = false, Vector3 defaultValue = default) {
return ParseValue(node, valueName, ParseExtensions.TryParseVector3, isOptional, defaultValue);
}
public static bool ParseVector3Indirect(ref Vector3 value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, ParseExtensions.TryParseVector3);
}
public static T ParseValue<T>(ConfigNode node, string valueName, TryParseDelegate<T> tryParse, bool isOptional = false, T defaultValue = default) {
string valueString = node.GetValue(valueName);
if (isOptional) {
if (string.IsNullOrEmpty(valueString)) return defaultValue;
}
else {
if (valueString == null)
throw new FormatException($"Missing {typeof(T)} value for {valueName}");
if (valueString == string.Empty)
throw new FormatException($"Empty {typeof(T)} value for {valueName}");
}
if (tryParse(valueString, out var value)) {
return value;
}
if (isOptional) {
return defaultValue;
}
else {
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} : '{valueString}");
}
}
public static bool ParseValueIndirect<T>(ref T value, ConfigNode node, string valueName, TryParseDelegate<T> tryParse) {
if (!node.HasValue(valueName)) return false;
var valueString = node.GetValue(valueName);
if (tryParse(valueString, out var newValue)) {
value = newValue;
return true;
}
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} : '{valueString}");
}
public static bool TryParseColor32(string valueString, out Color32 value) {
value = new Color32(0, 0, 0, byte.MaxValue);
// HTML-style hex color
if (valueString[0] == '#') {
var hexColorString = valueString.Substring(1);
if (!int.TryParse(hexColorString, System.Globalization.NumberStyles.HexNumber, null, out var hexColor)) return false;
switch (hexColorString.Length) {
case 8: // RRGGBBAA
value.a = (byte) (hexColor & 0xFF);
hexColor >>= 8;
goto case 6;
case 6: // RRGGBB
value.b = (byte) (hexColor & 0xFF);
hexColor >>= 8;
value.g = (byte) (hexColor & 0xFF);
hexColor >>= 8;
value.r = (byte) (hexColor & 0xFF);
return true;
case 4: // RGBA
value.a = (byte) ((hexColor & 0xF) << 4);
hexColor >>= 4;
goto case 3;
case 3: // RGB
value.b = (byte) (hexColor & 0xF << 4);
hexColor >>= 4;
value.g = (byte) (hexColor & 0xF << 4);
hexColor >>= 4;
value.r = (byte) (hexColor & 0xF << 4);
return true;
default:
return false;
}
}
// named color
if (NamedColors.TryGetValue(valueString, out var namedColor)) {
value = namedColor;
return true;
}
// float color
var split = valueString.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < split.Length; i++) {
split[i] = split[i].Trim();
}
switch (split.Length) {
case 4:
if (!float.TryParse(split[4], out var alpha)) return false;
value.a = (byte) (alpha * 0xFF);
goto case 3;
case 3:
if (!float.TryParse(split[0], out var red)) return false;
if (!float.TryParse(split[1], out var green)) return false;
if (!float.TryParse(split[2], out var blue)) return false;
value.r = (byte) (red * 0xFF);
value.g = (byte) (green * 0xFF);
value.b = (byte) (blue * 0xFF);
return true;
default:
return false;
}
}
}
}

View File

@ -1,6 +1,31 @@
v0.1.3
------
Fixes:
- Fixed decals being able to be scaled down to 0
Changes:
- Made decal bounds no longer collide in flight, this is done by repurposing layer 31 (which is configurable in the ConformalDecals.cfg file)
- Decals will now be unselectable in flight by default. This can be disabled with the `selectableInFlight` value in ConformalDecals.cfg, or in the module config itself.
- Decal parts will now destroy themselves automatically when the parent part is destroyed
- Small refactor of node parsing code
- Colors can now be specified in hex (#RGB, #RGBA, #RRGGBB, or #RRGGBBAA) or using the colors specified in the XKCDColors class
v0.1.2
------
Fixes:
- Disabled writing to the zbuffer in the decal bounds shader. Should fix any issues with Scatterer or EVE.
v0.1.1
------
Fixes:
- Fixed flag decal not adjusting to new texture sizes immediately.
- Fixed decal bounds being visible on launch.
- Fixed decal bounds being visible in the part icon.
v0.1.0 v0.1.0
------ ------
Initial release! Initial release!
New parts: New parts: