/// <inheritdoc/>
        protected override void OnEntityRemoved(Entity entity, EntityLightShadow data)
        {
            if (ManageShadows && data.ShadowMap != null)
            {
                InternalShadowMaps.Remove(data.ShadowMap);

                List<ShadowMap> shadowMaps = null;
                if (!texturesDefault.TryGetValue(data.ShadowMap.Texture, out shadowMaps))
                    texturesVsm.TryGetValue(data.ShadowMap.Texture, out shadowMaps);

                if (shadowMaps == null)
                    throw new Exception("Untracked shadow map texture");

                shadowMaps.Remove(data.ShadowMap);

                // if no more shadow maps on this texture, delete it.
                if (shadowMaps.Count == 0)
                {
                    InternalShadowMapTextures.Remove(data.ShadowMap.Texture);
                    Utilities.Dispose(ref data.ShadowMap.Texture.ShadowMapDepthTexture);
                    Utilities.Dispose(ref data.ShadowMap.Texture.ShadowMapTargetTexture);
                    Utilities.Dispose(ref data.ShadowMap.Texture.IntermediateBlurTexture);

                    if (!texturesDefault.Remove(data.ShadowMap.Texture))
                        texturesVsm.Remove(data.ShadowMap.Texture);
                }
            }
            base.OnEntityRemoved(entity, data);
        }
        protected override void CreateShadowMap(EntityLightShadow light)
        {
            var shadowMapDesc = light.Light.Shadow as LightShadowMap;


            // create the shadow map
            var shadowMap = new ShadowMap
            {
                LightDirection = light.Light.Direction,
                LightPosition = light.Entity.Transformation.Translation,
                ShadowMapSize = shadowMapDesc.MaxSize,
                ShadowNearDistance = shadowMapDesc.NearDistance,
                ShadowFarDistance = shadowMapDesc.FarDistance,
                CascadeCount = light.Light.Type is LightDirectional ? shadowMapDesc.CascadeCount : 1, // cascades are only supported for directional shadow maps
                //Fov = light.Light.SpotFieldAngle,
                Filter = shadowMapDesc.FilterType,
                Layers = light.Light.Layers
            };

            // find or create the shadow map texture
            ShadowMapTexture chosenTexture = null;
            chosenTexture = AllocateOrChooseTexture(shadowMap, shadowMapDesc.FilterType == LightShadowMapFilterType.Variance ? texturesVsm : texturesDefault);

            shadowMap.Texture = chosenTexture;
            InternalShadowMaps.Add(shadowMap);
            light.ShadowMap = shadowMap;
        }
        // returns shadow0 - shadow1
        private static int CompareShadows(EntityLightShadow shadow0, EntityLightShadow shadow1)
        {
            var lightTypeComparaison = GetLightTypeValue(shadow0.Light.Type) - GetLightTypeValue(shadow1.Light.Type);
            if (lightTypeComparaison != 0)
                return lightTypeComparaison;

            // TODO: Shadow light comparison

            //var shadowMapSizeDiff = shadow0.Light.ShadowMapMaxSize - shadow1.Light.ShadowMapMaxSize;
            //if (shadowMapSizeDiff > 0)
            //    return -1;
            //if (shadowMapSizeDiff < 0)
            //    return 1;

            // TODO: more comparisons

            return 0;
        }
        private bool ChooseShadowMapTexture(EntityLightShadow light, List<ShadowMapTexture> shadowMapTextures, Dictionary<ShadowMapTexture, int> shadowMapRemainingSize)
        {
            var shadowMap = light.ShadowMap;
            var shadowMapDesc = (LightShadowMap)light.Light.Shadow;
            var shadowMapSize = shadowMapDesc.MaxSize;
            // find best texture
            while (shadowMapSize > 0)
            {
                if (shadowMapSize < shadowMapDesc.MinSize)
                    shadowMapSize = shadowMapDesc.MinSize;

                foreach (var shadowMapTexture in shadowMapTextures)
                {
                    if (shadowMapTexture.GuillotinePacker.TryInsert(shadowMapSize, shadowMapSize, shadowMap.CascadeCount))
                    {
                        shadowMap.Texture = shadowMapTexture;
                        shadowMapRemainingSize[shadowMapTexture] = shadowMapRemainingSize[shadowMapTexture] - (shadowMap.CascadeCount * shadowMapSize * shadowMapSize);
                        shadowMap.ShadowMapSize = shadowMapSize;
                        return true;
                    }
                }

                if (shadowMapSize == shadowMapDesc.MinSize)
                    break;
                shadowMapSize /= 2;
            }

            // Issue a warning only once
            if (!shadowMapFullWarningDone)
            {
                shadowMapFullWarningDone = true;
                Logger.Warning("Unable to find a texture to create the shadow map.");
            }

            shadowMap.Texture = null;
            return false;
        }
 private void RemoveShadowMap(EntityLightShadow data)
 {
     InternalShadowMaps.Remove(data.ShadowMap);
     InternalActiveShadowMaps.Remove(data.ShadowMap);
     data.ShadowMap = null;
 }
        protected override void CreateShadowMap(EntityLightShadow light)
        {
            var shadowMapDesc = (LightShadowMap)light.Light.Shadow;

            // create the shadow map
            var shadowMap = new ShadowMap
            {
                LightDirection = light.Light.Direction,
                ShadowMapSize = shadowMapDesc.MinSize,
                ShadowNearDistance = shadowMapDesc.NearDistance,
                ShadowFarDistance = shadowMapDesc.FarDistance,
                CascadeCount = shadowMapDesc.CascadeCount,
                Filter = shadowMapDesc.FilterType,
                Layers = light.Light.Layers
            };

            InternalShadowMaps.Add(shadowMap);
            light.ShadowMap = shadowMap;
        }
 /// <inheritdoc/>
 protected override void OnEntityRemoved(Entity entity, EntityLightShadow data)
 {
     if (ManageShadows && data.ShadowMap != null)
         RemoveShadowMap(data);
     base.OnEntityRemoved(entity, data);
 }