From 30a5edfdfed5cd763b09069099da0fb9d503b40a Mon Sep 17 00:00:00 2001
From: ZZYZX <zzyzx@virtual>
Date: Fri, 20 Jan 2017 00:17:43 +0200
Subject: [PATCH] Added: attenuated dynamic light support

---
 .../Configurations/Includes/GZDoom_things.cfg | 138 ++++++++++++++++++
 Source/Core/GZBuilder/Data/DynamicLight.cs    |  11 +-
 Source/Core/GZBuilder/Data/LinksCollector.cs  |   9 +-
 Source/Core/GZBuilder/GZGeneral.cs            |   9 +-
 Source/Core/Properties/AssemblyInfo.cs        |   4 +-
 Source/Core/Rendering/Renderer3D.cs           |  31 +++-
 Source/Core/Resources/world3d.fx              |   9 +-
 Source/Core/VisualModes/VisualThing.cs        |  17 ++-
 .../BuilderModes/Properties/AssemblyInfo.cs   |   2 +-
 9 files changed, 205 insertions(+), 25 deletions(-)

diff --git a/Build/Configurations/Includes/GZDoom_things.cfg b/Build/Configurations/Includes/GZDoom_things.cfg
index dd589837e..3f8d02d8e 100755
--- a/Build/Configurations/Includes/GZDoom_things.cfg
+++ b/Build/Configurations/Includes/GZDoom_things.cfg
@@ -428,6 +428,144 @@ gzdoom_lights
 			}
 		}
 		9825 = "Vavoom Light (obsolete)";
+		9830
+		{
+			title = "Attenuated Light";
+			arg0
+			{
+				title = "Red";
+				default = 255;
+			}
+			arg1
+			{
+				title = "Green";
+				default = 255;
+			}
+			arg2
+			{
+				title = "Blue";
+				default = 255;
+			}
+			arg3
+			{
+				title = "Intensity";
+				default = 64;
+			}
+		}
+		9831
+		{
+			title = "Attenuated Pulse Light";
+			fixedrotation = true;
+			arg0
+			{
+				title = "Red";
+				default = 255;
+			}
+			arg1
+			{
+				title = "Green";
+				default = 255;
+			}
+			arg2
+			{
+				title = "Blue";
+				default = 255;
+			}
+			arg3
+			{
+				title = "Start intensity";
+				default = 64;
+			}
+			arg4
+			{
+				title = "End intensity";
+				default = 32;
+			}
+		}
+		9832
+		{
+			title = "Attenuated Flicker Light";
+			fixedrotation = true;
+			arg0
+			{
+				title = "Red";
+				default = 255;
+			}
+			arg1
+			{
+				title = "Green";
+				default = 255;
+			}
+			arg2
+			{
+				title = "Blue";
+				default = 255;
+			}
+			arg3
+			{
+				title = "Primary intensity";
+				default = 64;
+			}
+			arg4
+			{
+				title = "Secondary intensity";
+				default = 32;
+			}
+		}
+		9833
+		{
+			title = "Attenuated Sector Light";
+			arg0
+			{
+				title = "Red";
+				default = 255;
+			}
+			arg1
+			{
+				title = "Green";
+				default = 255;
+			}
+			arg2
+			{
+				title = "Blue";
+				default = 255;
+			}
+			arg3
+			{
+				title = "Intensity scale";
+				default = 4;
+			}
+		}
+		9834
+		{
+			title = "Attenuated Random Light";
+			fixedrotation = true;
+			arg0
+			{
+				title = "Red";
+				default = 255;
+			}
+			arg1
+			{
+				title = "Green";
+				default = 255;
+			}
+			arg2
+			{
+				title = "Blue";
+				default = 255;
+			}
+			arg3
+			{
+				title = "Minimal intensity";
+				default = 32;
+			}
+			arg4
+			{
+				title = "Maximal intensity";
+				default = 64;
+			}
+		}
 		1502
 		{
 			title = "Vavoom Light";
diff --git a/Source/Core/GZBuilder/Data/DynamicLight.cs b/Source/Core/GZBuilder/Data/DynamicLight.cs
index c8b7878cf..0e82d2f81 100755
--- a/Source/Core/GZBuilder/Data/DynamicLight.cs
+++ b/Source/Core/GZBuilder/Data/DynamicLight.cs
@@ -35,10 +35,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 	//divide these by 100 to get light color alpha
 	public enum DynamicLightRenderStyle
 	{
-		NONE = 0,
-		NORMAL = 99,
-		VAVOOM = 50,
+        NEGATIVE = 100,
+        NORMAL = 99,
+        ATTENUATED = 98,
+        VAVOOM = 50,
 		ADDITIVE = 25,
-		NEGATIVE = 100,
-	}
+        NONE = 0,
+    }
 }
diff --git a/Source/Core/GZBuilder/Data/LinksCollector.cs b/Source/Core/GZBuilder/Data/LinksCollector.cs
index 2ac555e5e..63cb46830 100755
--- a/Source/Core/GZBuilder/Data/LinksCollector.cs
+++ b/Source/Core/GZBuilder/Data/LinksCollector.cs
@@ -500,12 +500,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 				int primaryradius;
 				int secondaryradius = 0;
 
-				if(lightid < GZGeneral.GZ_LIGHT_TYPES[2]) //if it's gzdoom light
+				if(lightid < GZGeneral.GZ_LIGHT_TYPES[3]) //if it's gzdoom light
 				{
 					int n;
-					if(lightid < GZGeneral.GZ_LIGHT_TYPES[0]) n = 0;
-					else if(lightid < GZGeneral.GZ_LIGHT_TYPES[1]) n = 10;
-					else n = 20;
+                    if (lightid < GZGeneral.GZ_LIGHT_TYPES[0]) n = 0;
+                    else if (lightid < GZGeneral.GZ_LIGHT_TYPES[1]) n = 10;
+                    else if (lightid < GZGeneral.GZ_LIGHT_TYPES[2]) n = 20;
+                    else n = 30;
 					DynamicLightType lightType = (DynamicLightType)(t.Type - 9800 - n);
 
 					if(lightType == DynamicLightType.SECTOR)
diff --git a/Source/Core/GZBuilder/GZGeneral.cs b/Source/Core/GZBuilder/GZGeneral.cs
index 6448de5f3..7ba2babb7 100755
--- a/Source/Core/GZBuilder/GZGeneral.cs
+++ b/Source/Core/GZBuilder/GZGeneral.cs
@@ -12,9 +12,14 @@ namespace CodeImp.DoomBuilder.GZBuilder
 		#region ================== Properties
 
 		//gzdoom light types
-		private static readonly int[] gzLights = { /* normal lights */ 9800, 9801, 9802, 9803, 9804, /* additive lights */ 9810, 9811, 9812, 9813, 9814, /* negative lights */ 9820, 9821, 9822, 9823, 9824, /* vavoom lights */ 1502, 1503};
+		private static readonly int[] gzLights = {
+            /* normal lights */ 9800, 9801, 9802, 9803, 9804,
+            /* additive lights */ 9810, 9811, 9812, 9813, 9814,
+            /* negative lights */ 9820, 9821, 9822, 9823, 9824,
+            /* attenuated lights */ 9830, 9831, 9832, 9833, 9834,
+            /* vavoom lights */ 1502, 1503};
 		public static int[] GZ_LIGHTS { get { return gzLights; } }
-		private static readonly int[] gzLightTypes = { 5, 10, 15 }; //these are actually offsets in gz_lights
+		private static readonly int[] gzLightTypes = { 5, 10, 15, 20 }; //these are actually offsets in gz_lights
 		public static int[] GZ_LIGHT_TYPES { get { return gzLightTypes; } }
 		private static readonly DynamicLightType[] gzAnimatedLightTypes = { DynamicLightType.FLICKER, DynamicLightType.RANDOM, DynamicLightType.PULSE };
 		public static DynamicLightType[] GZ_ANIMATED_LIGHT_TYPES { get { return gzAnimatedLightTypes; } }
diff --git a/Source/Core/Properties/AssemblyInfo.cs b/Source/Core/Properties/AssemblyInfo.cs
index 13b3eda48..15bfa90e6 100755
--- a/Source/Core/Properties/AssemblyInfo.cs
+++ b/Source/Core/Properties/AssemblyInfo.cs
@@ -30,6 +30,6 @@ using CodeImp.DoomBuilder;
 //      Build Number
 //      Revision
 //
-[assembly: AssemblyVersion("2.3.0.2835")]
+[assembly: AssemblyVersion("2.3.0.2836")]
 [assembly: NeutralResourcesLanguageAttribute("en")]
-[assembly: AssemblyHash("55b24ee")]
+[assembly: AssemblyHash("819ef64")]
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index c67ba3b56..16ed641e7 100755
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -523,7 +523,7 @@ namespace CodeImp.DoomBuilder.Rendering
 
 			// Sort things by light render style
 			lightthings.Sort((t1, t2) => Math.Sign(t1.LightRenderStyle - t2.LightRenderStyle));
-			lightOffsets = new int[3];
+			lightOffsets = new int[4];
 
 			foreach(VisualThing t in lightthings) 
 			{
@@ -533,7 +533,8 @@ namespace CodeImp.DoomBuilder.Rendering
 					case DynamicLightRenderStyle.NORMAL:
 					case DynamicLightRenderStyle.VAVOOM: lightOffsets[0]++; break;
 					case DynamicLightRenderStyle.ADDITIVE: lightOffsets[1]++; break;
-					default: lightOffsets[2]++; break;
+                    case DynamicLightRenderStyle.NEGATIVE: lightOffsets[2]++; break;
+					default: lightOffsets[3]++; break;
 				}
 			}
 		}
@@ -1332,8 +1333,8 @@ namespace CodeImp.DoomBuilder.Rendering
 						}
 					}
 
-					//additive lights
-					if(lightOffsets[1] > 0) 
+                    //additive lights
+                    if (lightOffsets[1] > 0) 
 					{
 						count += lightOffsets[1];
 						graphics.Device.SetRenderState(RenderState.BlendOperation, BlendOperation.Add);
@@ -1372,7 +1373,27 @@ namespace CodeImp.DoomBuilder.Rendering
 							}
 						}
 					}
-				}
+
+                    //attenuated lights
+                    if (lightOffsets[3] > 0)
+                    {
+                        count += lightOffsets[3];
+                        graphics.Device.SetRenderState(RenderState.BlendOperation, BlendOperation.Add);
+
+                        for (int i = lightOffsets[0] + lightOffsets[1] + lightOffsets[2]; i < count; i++)
+                        {
+                            if (BoundingBoxesIntersect(g.BoundingBox, lights[i].BoundingBox))
+                            {
+                                lpr = new Vector4(lights[i].Center, lights[i].LightRadius);
+                                if (lpr.W == 0) continue;
+                                graphics.Shaders.World3D.LightColor = lights[i].LightColor;
+                                graphics.Shaders.World3D.LightPositionAndRadius = lpr;
+                                graphics.Shaders.World3D.ApplySettings();
+                                graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, g.VertexOffset, g.Triangles);
+                            }
+                        }
+                    }
+                }
 			}
 
 			graphics.Shaders.World3D.EndPass();
diff --git a/Source/Core/Resources/world3d.fx b/Source/Core/Resources/world3d.fx
index a957c3d65..72af1c902 100755
--- a/Source/Core/Resources/world3d.fx
+++ b/Source/Core/Resources/world3d.fx
@@ -237,8 +237,11 @@ float4 ps_vertex_color(PixelData pd) : COLOR
 float4 ps_lightpass(LitPixelData pd) : COLOR 
 {
 	//is face facing away from light source?
-	if(dot(pd.normal, normalize(lightPosAndRadius.xyz - pd.pos_w)) < -0.1f) // (lightPosAndRadius.xyz - pd.pos_w) == direction from light to current pixel
+	// [ZZ] oddly enough pd.normal is not a proper normal, so using dot on it returns rather unexpected results. wrapped in normalize().
+	float diffuseContribution = dot(normalize(pd.normal), normalize(lightPosAndRadius.xyz - pd.pos_w));
+	if (diffuseContribution < -0.1f) // (lightPosAndRadius.xyz - pd.pos_w) == direction from light to current pixel
 		clip(-1);
+	diffuseContribution = max(diffuseContribution, 0); // to make sure
 
 	//is pixel in light range?
 	float dist = distance(pd.pos_w, lightPosAndRadius.xyz);
@@ -254,10 +257,12 @@ float4 ps_lightpass(LitPixelData pd) : COLOR
 	float4 lightColorMod = float4(0.0f, 0.0f, 0.0f, 0.0f);
 
 	lightColorMod.rgb = lightColor.rgb * max(lightPosAndRadius.w - dist, 0.0f) / lightPosAndRadius.w;
+	if (lightColor.a > 0.979f && lightColor.a < 0.981f) // attenuated light 98%
+		lightColorMod.rgb *= diffuseContribution;
 	if(lightColorMod.r > 0.0f || lightColorMod.g > 0.0f || lightColorMod.b > 0.0f)
 	{
 		lightColorMod.rgb *= lightColor.a;
-		if(lightColor.a > 0.4f) //Normal, vavoom or negative light
+		if (lightColor.a > 0.4f) //Normal, vavoom or negative light (or attenuated)
 			return tcolor * lightColorMod;
 		return lightColorMod; //Additive light
 	}
diff --git a/Source/Core/VisualModes/VisualThing.cs b/Source/Core/VisualModes/VisualThing.cs
index 21253787b..6ce7aa667 100755
--- a/Source/Core/VisualModes/VisualThing.cs
+++ b/Source/Core/VisualModes/VisualThing.cs
@@ -655,10 +655,10 @@ namespace CodeImp.DoomBuilder.VisualModes
 		//mxd. Update light info
 		private void UpdateLight(int lightId) 
 		{
-			if(lightId < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[2]) //if it's gzdoom light
+			if(lightId < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[3]) //if it's gzdoom light
 			{ 
 				int n;
-				if(lightId < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[0]) 
+				if(lightId < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[0]) // normal
 				{
 					n = 0;
 					lightRenderStyle = DynamicLightRenderStyle.NORMAL;
@@ -668,7 +668,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 						thing.Args[1] / DYNLIGHT_INTENSITY_SCALER,
 						thing.Args[2] / DYNLIGHT_INTENSITY_SCALER);
 				} 
-				else if(lightId < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[1]) 
+				else if(lightId < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[1]) // additive
 				{
 					n = 10;
 					lightRenderStyle = DynamicLightRenderStyle.ADDITIVE;
@@ -677,7 +677,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 						thing.Args[1] / DYNLIGHT_INTENSITY_SCALER,
 						thing.Args[2] / DYNLIGHT_INTENSITY_SCALER);
 				} 
-				else 
+				else if (lightId < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[2]) // negative
 				{
 					n = 20;
 					lightRenderStyle = DynamicLightRenderStyle.NEGATIVE;
@@ -686,6 +686,15 @@ namespace CodeImp.DoomBuilder.VisualModes
 						thing.Args[1] / SUBLIGHT_INTENSITY_SCALER,
 						thing.Args[2] / SUBLIGHT_INTENSITY_SCALER);
 				}
+                else
+                {
+                    n = 30;
+                    lightRenderStyle = DynamicLightRenderStyle.ATTENUATED;
+                    lightColor = new Color4((float)lightRenderStyle / 100.0f,
+                        thing.Args[0] / DYNLIGHT_INTENSITY_SCALER,
+                        thing.Args[1] / DYNLIGHT_INTENSITY_SCALER,
+                        thing.Args[2] / DYNLIGHT_INTENSITY_SCALER);
+                }
 				lightType = (DynamicLightType)(thing.Type - 9800 - n);
 
 				if(lightType == DynamicLightType.SECTOR) 
diff --git a/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs b/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
index e690c210d..4b0235115 100755
--- a/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
+++ b/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Resources;
 //      Build Number
 //      Revision
 //
-[assembly: AssemblyVersion("2.3.0.2835")]
+[assembly: AssemblyVersion("2.3.0.2836")]
 [assembly: NeutralResourcesLanguageAttribute("en")]
-- 
GitLab