/// <summary>
 /// Return the group to its cache if there is one
 /// </summary>
 public void Reset()
 {
     LightParameters = null;
     Segments.Clear();
     Lights.Clear();
     StartIndex = 0;
 }
        private void CreateLightsForGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, LightningBoltQualitySetting quality, int maxLights)
        {
            if (lightCount == MaximumLightCount || maxLights <= 0)
            {
                return;
            }

            float fadeOutTime       = (lifeTime - group.PeakEnd) * lp.FadeOutMultiplier;
            float peakGap           = (group.PeakEnd - group.PeakStart) * lp.FadeFullyLitMultiplier;
            float peakStart         = group.PeakStart * lp.FadeInMultiplier;
            float peakEnd           = peakStart + peakGap;
            float maxLifeWithLights = peakEnd + fadeOutTime;

            maxLifeTime = Mathf.Max(maxLifeTime, group.Delay + maxLifeWithLights);

            segmentGroupsWithLight.Add(group);

            int   segmentCount = group.SegmentCount;
            float lightPercent, lightShadowPercent;

            if (quality == LightningBoltQualitySetting.LimitToQualitySetting)
            {
                int level = QualitySettings.GetQualityLevel();
                LightningQualityMaximum maximum;
                if (LightningBoltParameters.QualityMaximums.TryGetValue(level, out maximum))
                {
                    lightPercent       = Mathf.Min(lp.LightPercent, maximum.MaximumLightPercent);
                    lightShadowPercent = Mathf.Min(lp.LightShadowPercent, maximum.MaximumShadowPercent);
                }
                else
                {
                    Debug.LogError("Unable to read lightning quality for level " + level.ToString());
                    lightPercent       = lp.LightPercent;
                    lightShadowPercent = lp.LightShadowPercent;
                }
            }
            else
            {
                lightPercent       = lp.LightPercent;
                lightShadowPercent = lp.LightShadowPercent;
            }

            maxLights = Mathf.Max(1, Mathf.Min(maxLights, (int)(segmentCount * lightPercent)));
            int nthLight         = Mathf.Max(1, (int)((segmentCount / maxLights)));
            int nthShadows       = maxLights - (int)((float)maxLights * lightShadowPercent);
            int nthShadowCounter = nthShadows;

            // add lights evenly spaced
            for (int i = group.StartIndex + (int)(nthLight * 0.5f); i < group.Segments.Count; i += nthLight)
            {
                if (AddLightToGroup(group, lp, i, nthLight, nthShadows, ref maxLights, ref nthShadowCounter))
                {
                    return;
                }
            }

            // Debug.Log("Lightning light count: " + lightCount.ToString());
        }
        private Light GetOrCreateLight(LightningLightParameters lp)
        {
            Light light;

            while (true)
            {
                if (lightCache.Count == 0)
                {
                    GameObject lightningLightObject = new GameObject("LightningBoltLight");

#if UNITY_EDITOR
                    lightningLightObject.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
#endif

                    light      = lightningLightObject.AddComponent <Light>();
                    light.type = LightType.Point;
                    break;
                }
                else
                {
                    light = lightCache[lightCache.Count - 1];
                    lightCache.RemoveAt(lightCache.Count - 1);
                    if (light == null)
                    {
                        // may have been disposed or the level re-loaded
                        continue;
                    }
                    break;
                }
            }

#if UNITY_4
#else
            light.bounceIntensity  = lp.BounceIntensity;
            light.shadowNormalBias = lp.ShadowNormalBias;
#endif

            light.color          = lp.LightColor;
            light.renderMode     = lp.RenderMode;
            light.range          = lp.LightRange;
            light.shadowStrength = lp.ShadowStrength;
            light.shadowBias     = lp.ShadowBias;
            light.intensity      = 0.0f;
            light.gameObject.transform.parent = dependencies.Parent.transform;
            light.gameObject.SetActive(true);

            dependencies.LightAdded(light);

            return(light);
        }
        private void UpdateLight(LightningLightParameters lp, IEnumerable <Light> lights, float delay, float peakStart, float peakEnd, float lifeTime)
        {
            if (elapsedTime < delay)
            {
                return;
            }

            // depending on whether we have hit the mid point of our lifetime, fade the light in or out

            // adjust lights for fade parameters
            float fadeOutTime = (lifeTime - peakEnd) * lp.FadeOutMultiplier;
            float peakGap     = (peakEnd - peakStart) * lp.FadeFullyLitMultiplier;

            peakStart *= lp.FadeInMultiplier;
            peakEnd    = peakStart + peakGap;
            lifeTime   = peakEnd + fadeOutTime;
            float realElapsedTime = elapsedTime - delay;

            if (realElapsedTime >= peakStart)
            {
                if (realElapsedTime <= peakEnd)
                {
                    // fully lit
                    foreach (Light l in lights)
                    {
                        l.intensity = lp.LightIntensity;
                    }
                }
                else
                {
                    // fading out
                    float lerp = (realElapsedTime - peakEnd) / (lifeTime - peakEnd);
                    foreach (Light l in lights)
                    {
                        l.intensity = Mathf.Lerp(lp.LightIntensity, 0.0f, lerp);
                    }
                }
            }
            else
            {
                // fading in
                float lerp = realElapsedTime / peakStart;
                foreach (Light l in lights)
                {
                    l.intensity = Mathf.Lerp(0.0f, lp.LightIntensity, lerp);
                }
            }
        }
        private bool AddLightToGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, int segmentIndex,
                                     int nthLight, int nthShadows, ref int maxLights, ref int nthShadowCounter)
        {
            Light light = GetOrCreateLight(lp);

            group.Lights.Add(light);
            Vector3 pos = (group.Segments[segmentIndex].Start + group.Segments[segmentIndex].End) * 0.5f;

            if (dependencies.CameraIsOrthographic)
            {
                if (dependencies.CameraMode == CameraMode.OrthographicXZ)
                {
                    pos.y = dependencies.CameraPos.y + lp.OrthographicOffset;
                }
                else
                {
                    pos.z = dependencies.CameraPos.z + lp.OrthographicOffset;
                }
            }
            if (dependencies.UseWorldSpace)
            {
                light.gameObject.transform.position = pos;
            }
            else
            {
                light.gameObject.transform.localPosition = pos;
            }
            if (lp.LightShadowPercent == 0.0f || ++nthShadowCounter < nthShadows)
            {
                light.shadows = LightShadows.None;
            }
            else
            {
                light.shadows    = LightShadows.Soft;
                nthShadowCounter = 0;
            }

            // return true if no more lights possible, false otherwise
            return(++lightCount == MaximumLightCount || --maxLights == 0);
        }
        private Transform RenderLightningBolt(LightningBoltQualitySetting quality, int generations, int startGroupIndex, int endGroupIndex, LightningBoltParameters parameters)
        {
            if (segmentGroups.Count == 0 || startGroupIndex >= segmentGroups.Count || endGroupIndex > segmentGroups.Count)
            {
                return(null);
            }

            Transform transform         = null;
            LightningLightParameters lp = parameters.LightParameters;

            if (lp != null)
            {
                if ((hasLight |= lp.HasLight))
                {
                    lp.LightPercent       = Mathf.Clamp(lp.LightPercent, Mathf.Epsilon, 1.0f);
                    lp.LightShadowPercent = Mathf.Clamp(lp.LightShadowPercent, 0.0f, 1.0f);
                }
                else
                {
                    lp = null;
                }
            }

            LightningBoltSegmentGroup mainTrunkGroup = segmentGroups[startGroupIndex];
            Vector3 start = mainTrunkGroup.Segments[mainTrunkGroup.StartIndex].Start;
            Vector3 end   = mainTrunkGroup.Segments[mainTrunkGroup.StartIndex + mainTrunkGroup.SegmentCount - 1].End;

            parameters.FadePercent = Mathf.Clamp(parameters.FadePercent, 0.0f, 0.5f);

            // create a new line renderer mesh right now if we have a custom transform
            if (parameters.CustomTransform != null)
            {
                LineRendererMesh currentLineRenderer = (activeLineRenderers.Count == 0 || !activeLineRenderers[activeLineRenderers.Count - 1].Empty ? null : activeLineRenderers[activeLineRenderers.Count - 1]);

                if (currentLineRenderer == null)
                {
#if !UNITY_WEBGL
                    if (dependencies.ThreadState != null)
                    {
                        // we need to block until this action is run, Unity objects can only be modified and created on the main thread
                        dependencies.ThreadState.AddActionForMainThread(() =>
                        {
                            EnableCurrentLineRenderer();
                            currentLineRenderer = GetOrCreateLineRenderer();
                        }, true);
                    }
                    else
#endif

                    {
                        EnableCurrentLineRenderer();
                        currentLineRenderer = GetOrCreateLineRenderer();
                    }
                }
                if (currentLineRenderer == null)
                {
                    return(null);
                }

                currentLineRenderer.CustomTransform = parameters.CustomTransform;
                transform = currentLineRenderer.Transform;
            }

            for (int i = startGroupIndex; i < endGroupIndex; i++)
            {
                LightningBoltSegmentGroup group = segmentGroups[i];
                group.Delay     = parameters.delaySeconds;
                group.LifeTime  = parameters.LifeTime;
                group.PeakStart = group.LifeTime * parameters.FadePercent;
                group.PeakEnd   = group.LifeTime - group.PeakStart;
                float peakGap = group.PeakEnd - group.PeakStart;
                float fadeOut = group.LifeTime - group.PeakEnd;
                group.PeakStart      *= parameters.FadeInMultiplier;
                group.PeakEnd         = group.PeakStart + (peakGap * parameters.FadeFullyLitMultiplier);
                group.LifeTime        = group.PeakEnd + (fadeOut * parameters.FadeOutMultiplier);
                group.LightParameters = lp;
                RenderGroup(group, parameters);
            }

#if !UNITY_WEBGL
            if (dependencies.ThreadState != null)
            {
                dependencies.ThreadState.AddActionForMainThread(() =>
                {
                    RenderParticleSystems(start, end, parameters.TrunkWidth, parameters.LifeTime, parameters.delaySeconds);

                    // create lights only on the main trunk
                    if (lp != null)
                    {
                        CreateLightsForGroup(segmentGroups[startGroupIndex], lp, quality, parameters.maxLights);
                    }
                });
            }
            else
#endif

            {
                RenderParticleSystems(start, end, parameters.TrunkWidth, parameters.LifeTime, parameters.delaySeconds);

                // create lights only on the main trunk
                if (lp != null)
                {
                    CreateLightsForGroup(segmentGroups[startGroupIndex], lp, quality, parameters.maxLights);
                }
            }

            return(transform);
        }
        private Light CreateLight(LightningLightParameters lp)
        {
            Light light;
            while (true)
            {
                if (lightCache.Count == 0)
                {
                    GameObject lightningLightObject = new GameObject();
                    lightningLightObject.hideFlags = HideFlags.HideAndDontSave;
                    lightningLightObject.name = "LightningBoltLight";
                    light = lightningLightObject.AddComponent<Light>();
                    light.type = LightType.Point;
                    break;
                }
                else
                {
                    light = lightCache[lightCache.Count - 1];
                    lightCache.RemoveAt(lightCache.Count - 1);
                    if (light == null)
                    {
                        // may have been disposed or the level re-loaded
                        continue;
                    }
                    break;
                }
            }

#if UNITY_4

#else

			light.bounceIntensity = lp.BounceIntensity;
			light.shadowNormalBias = lp.ShadowNormalBias;

#endif

            light.color = lp.LightColor;
            light.renderMode = lp.RenderMode;
            light.range = lp.LightRange;
            light.shadowStrength = lp.ShadowStrength;
            light.shadowBias = lp.ShadowBias;
            light.intensity = 0.0f;
            light.gameObject.transform.parent = Parent.transform;
            light.gameObject.SetActive(true);

            return light;
        }
        private void UpdateLight(LightningLightParameters lp, IEnumerable<Light> lights, float delay, float peakStart, float peakEnd, float lifeTime)
        {
            if (elapsedTime < delay)
            {
                return;
            }

            // depending on whether we have hit the mid point of our lifetime, fade the light in or out
            float realElapsedTime = elapsedTime - delay;
            if (realElapsedTime >= peakStart)
            {
                if (realElapsedTime <= peakEnd)
                {
                    // fully lit
                    foreach (Light l in lights)
                    {
                        l.intensity = lp.LightIntensity;
                    }
                }
                else
                {
                    // fading out
                    float lerp = (realElapsedTime - peakEnd) / (lifeTime - peakEnd);
                    foreach (Light l in lights)
                    {
                        l.intensity = Mathf.Lerp(lp.LightIntensity, 0.0f, lerp);
                    }
                }
            }
            else
            {
                // fading in
                float lerp = realElapsedTime / peakStart;
                foreach (Light l in lights)
                {
                    l.intensity = Mathf.Lerp(0.0f, lp.LightIntensity, lerp);
                }
            }
        }
        private bool AddLightToGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, int segmentIndex,
            int nthLight, int nthShadows, ref int maxLights, ref int nthShadowCounter)
        {
            Light light = CreateLight(lp);
            group.Lights.Add(light);
            Vector3 pos = (group.Segments[segmentIndex].Start + group.Segments[segmentIndex].End) * 0.5f;
            if (Camera != null && Camera.orthographic)
            {
                pos.z = Camera.transform.position.z;
            }
            light.gameObject.transform.position = pos;
            if (lp.LightShadowPercent == 0.0f || ++nthShadowCounter < nthShadows)
            {
                light.shadows = LightShadows.None;
            }
            else
            {
                light.shadows = LightShadows.Soft;
                nthShadowCounter = 0;
            }

            // return true if no more lights possible, false otherwise
            return (++lightCount == MaximumLightCount || --maxLights == 0);
        }
        private void CreateLightsForGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, LightningBoltQualitySetting quality,
            int maxLights, int groupIndex)
        {
            if (lightCount == MaximumLightCount || maxLights <= 0)
            {
                return;
            }

            segmentGroupsWithLight.Add(group);

            int segmentCount = group.SegmentCount;
            float lightPercent, lightShadowPercent;
            if (quality == LightningBoltQualitySetting.LimitToQualitySetting)
            {
                int level = QualitySettings.GetQualityLevel();
                LightningQualityMaximum maximum;
                if (LightningBoltParameters.QualityMaximums.TryGetValue(level, out maximum))
                {
                    lightPercent = Mathf.Min(lp.LightPercent, maximum.MaximumLightPercent);
                    lightShadowPercent = Mathf.Min(lp.LightShadowPercent, maximum.MaximumShadowPercent);
                }
                else
                {
                    Debug.LogError("Unable to read lightning quality for level " + level.ToString());
                    lightPercent = lp.LightPercent;
                    lightShadowPercent = lp.LightShadowPercent;
                }
            }
            else
            {
                lightPercent = lp.LightPercent;
                lightShadowPercent = lp.LightShadowPercent;
            }

            maxLights = Mathf.Max(1, Mathf.Min(maxLights, (int)(segmentCount * lightPercent)));
            int nthLight = Mathf.Max(1, (int)((segmentCount / maxLights)));
            int nthShadows = maxLights - (int)((float)maxLights * lightShadowPercent);

            int nthShadowCounter = nthShadows;

            // add lights evenly spaced
            for (int i = group.StartIndex + (int)(nthLight * 0.5f); i < group.Segments.Count; i += nthLight)
            {
                if (AddLightToGroup(group, lp, i, nthLight, nthShadows, ref maxLights, ref nthShadowCounter))
                {
                    return;
                }
            }

            // Debug.Log("Lightning light count: " + lightCount.ToString());
        }
 private void CreateLightOnly(LightningBoltParameters p, LightningLightParameters lp, Vector3 pos)
 {
     lightOnlyParameters = lp;
     lightOnlyObject = CreateLight(lp);
     hasLight = true;
 }
        private void RenderLightningBolt(LightningBoltQualitySetting quality, int generations, Vector3 start, Vector3 end, int groupIndex,
            ParticleSystem originParticleSystem, ParticleSystem destParticleSystem, LightningBoltParameters parameters,
            LightningLightParameters lp, int maxLights)
        {
            if (parameters.Generations < 1)
            {
                CreateLightOnly(parameters, lp, start);
                return;
            }
            else if (segmentGroups.Count == 0 || groupIndex >= segmentGroups.Count)
            {
                return;
            }

            float delayBase = parameters.LifeTime / (float)segmentGroups.Count;
            float minDelayValue = delayBase * 0.9f;
            float maxDelayValue = delayBase * 1.1f;
            float delayDiff = maxDelayValue - minDelayValue;
            parameters.FadePercent = Mathf.Clamp(parameters.FadePercent, 0.0f, 0.5f);

            if (originParticleSystem != null)
            {
                // we have a strike, create a particle where the lightning is coming from
                Script.StartCoroutine(GenerateParticle(originParticleSystem, start, parameters.Delay));
            }
            if (destParticleSystem != null)
            {
                Script.StartCoroutine(GenerateParticle(destParticleSystem, end, parameters.Delay * 1.1f));
            }

            if (HasGlow)
            {
                lightningBoltRenderer.GlowIntensityMultiplier = parameters.GlowIntensity;
                lightningBoltRenderer.GlowWidthMultiplier = parameters.GlowWidthMultiplier;
            }

            float currentDelayAmount = 0.0f;
            for (int i = groupIndex; i < segmentGroups.Count; i++)
            {
                LightningBoltSegmentGroup group = segmentGroups[i];
                group.Delay = currentDelayAmount + parameters.Delay;
                group.LifeTime = parameters.LifeTime - currentDelayAmount;
                group.PeakStart = group.LifeTime * parameters.FadePercent;
                group.PeakEnd = group.LifeTime - group.PeakStart;
                group.LightParameters = lp;

                lightningBoltRenderer.AddGroup(this, group, parameters.GrowthMultiplier);
                currentDelayAmount += ((float)parameters.Random.NextDouble() * minDelayValue) + delayDiff;

                // create lights only on the main trunk
                if (lp != null && group.Generation == generations)
                {
                    CreateLightsForGroup(group, lp, quality, maxLights, groupIndex);
                }
            }
        }
 public void Cleanup()
 {
     foreach (LightningBoltSegmentGroup g in segmentGroups)
     {
         foreach (Light l in g.Lights)
         {
             CleanupLight(l);
         }
         g.LightParameters = null;
         g.Segments.Clear();
         g.Lights.Clear();
         g.StartIndex = 0;
         LightningGenerator.groupCache.Add(g);
     }
     CleanupLight(lightOnlyObject);
     lightOnlyObject = null;
     lightOnlyParameters = null;
     segmentGroups.Clear();
     segmentGroupsWithLight.Clear();
     if (lightningBoltRenderer != null)
     {
         lightningBoltRenderer.Cleanup(this);
         lightningBoltRenderer = null;
     }
     hasLight = false;
     elapsedTime = 0.0f;
     lifeTime = 0.0f;
     lightningBoltCache.Add(this);
 }