protected override void CreateShadowMap(EntityLightShadow light)
        {
            // create the shadow map
            var shadowMap = new ShadowMap
            {
                LightDirection     = light.Light.LightDirection,
                LightPosition      = light.Entity.Transformation.Translation,
                ShadowMapSize      = light.Light.ShadowMapMaxSize,
                ShadowNearDistance = light.Light.ShadowNearDistance,
                ShadowFarDistance  = light.Light.ShadowFarDistance,
                CascadeCount       = light.Light.Type == LightType.Directional ? light.Light.ShadowMapCascadeCount : 1, // cascades are only supported for directional shadow maps
                LightType          = light.Light.Type,
                Fov    = light.Light.SpotFieldAngle,
                Filter = light.Light.ShadowMapFilterType,
                Layers = light.Light.Layers
            };

            // find or create the shadow map texture
            ShadowMapTexture chosenTexture = null;

            chosenTexture = AllocateOrChooseTexture(shadowMap, light.Light.ShadowMapFilterType == ShadowMapFilterType.Variance ? texturesVsm : texturesDefault);

            shadowMap.Texture = chosenTexture;
            InternalShadowMaps.Add(shadowMap);
            light.ShadowMap = shadowMap;
        }
        private ShadowMapTexture AllocateOrChooseTexture(ShadowMap newShadowMap, Dictionary <ShadowMapTexture, List <ShadowMap> > shadowMapTextures)
        {
            ShadowMapTexture chosenTexture = null;

            // find best texture
            foreach (var shadowMapTexture in shadowMapTextures)
            {
                var shadowTexture = shadowMapTexture.Key;
                var shadowMaps    = shadowMapTexture.Value;

                shadowTexture.GuillotinePacker.Clear(shadowTexture.ShadowMapDepthTexture.Width, shadowTexture.ShadowMapDepthTexture.Height);

                var useShadowTexture = true;
                for (var i = 0; i < shadowMaps.Count && useShadowTexture; ++i)
                {
                    useShadowTexture = shadowTexture.GuillotinePacker.TryInsert(shadowMaps[i].ShadowMapSize, shadowMaps[i].ShadowMapSize, shadowMaps[i].CascadeCount);
                }

                useShadowTexture = useShadowTexture && shadowTexture.GuillotinePacker.TryInsert(newShadowMap.ShadowMapSize, newShadowMap.ShadowMapSize, newShadowMap.CascadeCount);

                shadowTexture.GuillotinePacker.Clear();

                if (useShadowTexture)
                {
                    chosenTexture = shadowMapTexture.Key;
                    break;
                }
            }

            if (chosenTexture == null)
            {
                // allocate a new texture
                chosenTexture = new ShadowMapTexture(GraphicsDevice, newShadowMap.Filter, 2048);
                chosenTexture.GuillotinePacker.Clear(chosenTexture.ShadowMapDepthTexture.Width, chosenTexture.ShadowMapDepthTexture.Height);

                // TODO: choose texture size based on the shadow map. For now throw exception
                if (!chosenTexture.GuillotinePacker.TryInsert(newShadowMap.ShadowMapSize, newShadowMap.ShadowMapSize, newShadowMap.CascadeCount))
                {
                    var message = new StringBuilder();
                    message.AppendFormat("Unable to allocate shadow map texture. The default size (2048 x 2048) is too small for the shadow map ({0} cascade(s) with size {1}).", newShadowMap.CascadeCount, newShadowMap.ShadowMapSize);
                    throw new Exception(message.ToString());
                }

                chosenTexture.GuillotinePacker.Clear();

                InternalShadowMapTextures.Add(chosenTexture);
                var shadowMaps = new List <ShadowMap> {
                    newShadowMap
                };
                shadowMapTextures.Add(chosenTexture, shadowMaps);
            }
            else
            {
                shadowMapTextures[chosenTexture].Add(newShadowMap);
            }

            return(chosenTexture);
        }
        /// <summary>
        /// Adds the shadow map texture to the budget of textures.
        /// </summary>
        /// <param name="shadowMapTexture">The shadow map texture.</param>
        /// <param name="filterType">The filtering that will be applied to this shadow.</param>
        protected void AddShadowMapTexture(ShadowMapTexture shadowMapTexture, ShadowMapFilterType filterType)
        {
            if (filterType == ShadowMapFilterType.Variance)
            {
                texturesVsm.Add(shadowMapTexture, shadowMapTexture.ShadowMapDepthTexture.Width * shadowMapTexture.ShadowMapDepthTexture.Height);
                shadowMapVsmTextures.Add(shadowMapTexture);
            }
            else
            {
                texturesDefault.Add(shadowMapTexture, shadowMapTexture.ShadowMapDepthTexture.Width * shadowMapTexture.ShadowMapDepthTexture.Height);
                shadowMapDefaultTextures.Add(shadowMapTexture);
            }

            InternalShadowMapTextures.Add(shadowMapTexture);
        }
 private int ShadowMapTextureComparerVsm(ShadowMapTexture texture0, ShadowMapTexture texture1)
 {
     return(texturesVsm[texture0] - texturesVsm[texture1]);
 }
 private int ShadowMapTextureComparerDefault(ShadowMapTexture texture0, ShadowMapTexture texture1)
 {
     return(texturesDefault[texture0] - texturesDefault[texture1]);
 }