public MyDecalsForRenderObjectsTriangleBuffer GetTrianglesBuffer(MyRenderObject renderObject, MyDecalTexturesEnum decalTexture)
        {
            MyDecalsForModelsDictionaryKey key = new MyDecalsForModelsDictionaryKey(renderObject, decalTexture);

            MyDecalsForRenderObjectsTriangleBuffer outValue;

            if (m_triangleBuffersByKey.TryGetValue(key, out outValue))
            {
                //  Combination of model/texture was found in dictionary, so we can return in right now
                return(outValue);
            }
            else
            {
                if (m_triangleBuffersByKey.Count >= m_capacity)
                {
                    //  We are full, can't place decal on a new model/texture. Need to wait for next CheckBufferFull.
                    return(null);
                }
                else
                {
                    //  This is first time we want to place decal on this model/texture, so here we allocate and initialize buffer
                    MyDecalsForRenderObjectsTriangleBuffer newBuffer = m_freeTriangleBuffers.Pop();
                    m_triangleBuffersByKey.Add(key, newBuffer);
                    m_usedTriangleBuffers.Add(newBuffer);
                    newBuffer.Start(renderObject, decalTexture);
                    return(newBuffer);
                }
            }
        }
        public void ReturnTrianglesBuffer(MyRenderObject renderObject)
        {
            foreach (byte value in Enum.GetValues(typeof(MyDecalTexturesEnum)))
            {
                var key = new MyDecalsForModelsDictionaryKey(renderObject, (MyDecalTexturesEnum)value);

                MyDecalsForRenderObjectsTriangleBuffer outValue;
                if (m_triangleBuffersByKey.TryGetValue(key, out outValue))
                {
                    MyDecalsForRenderObjectsTriangleBuffer usedBuffer = outValue;

                    m_triangleBuffersByKey.Remove(key);
                    usedBuffer.Clear();
                    m_usedTriangleBuffers.Remove(usedBuffer);
                    m_freeTriangleBuffers.Push(usedBuffer);
                }
            }
        }
        public MyDecalsForRenderObjects(int capacity)
        {
            m_status                = MyDecalForModelsState.READY;
            m_capacity              = capacity;
            m_fadingOutStartLimit   = (int)(m_capacity * MyDecalsConstants.TEXTURE_LARGE_FADING_OUT_START_LIMIT_PERCENT);
            m_fadingOutBuffersCount = (int)(m_capacity * MyDecalsConstants.TEXTURE_LARGE_FADING_OUT_MINIMAL_TRIANGLE_COUNT_PERCENT);

            m_sortTriangleBuffersByTexture = new List <MyDecalsForRenderObjectsTriangleBuffer>(m_capacity);
            m_triangleBuffersByKey         = new Dictionary <MyDecalsForModelsDictionaryKey, MyDecalsForRenderObjectsTriangleBuffer>(m_capacity);
            m_freeTriangleBuffers          = new Stack <MyDecalsForRenderObjectsTriangleBuffer>(m_capacity);
            m_usedTriangleBuffers          = new List <MyDecalsForRenderObjectsTriangleBuffer>(m_capacity);

            m_triangleBuffers = new MyDecalsForRenderObjectsTriangleBuffer[m_capacity];
            for (int i = 0; i < m_capacity; i++)
            {
                m_triangleBuffers[i] = new MyDecalsForRenderObjectsTriangleBuffer(MyDecalsConstants.MAX_DECAL_TRIANGLES_IN_BUFFER);
                m_freeTriangleBuffers.Push(m_triangleBuffers[i]);
            }
        }
        public void CheckIfBufferIsFull()
        {
            if (m_status == MyDecalForModelsState.FADING_OUT)
            {
                if ((MyRender.RenderTimeInMS - m_fadingOutStartTime) > MyDecalsConstants.DECALS_FADE_OUT_INTERVAL_MILISECONDS)
                {
                    //  If fading-out phase finished, we change state and remove faded-out buffers
                    for (int i = 0; i < m_fadingOutBuffersCount; i++)
                    {
                        if (m_usedTriangleBuffers.Count > 0)
                        {
                            MyDecalsForRenderObjectsTriangleBuffer releasedBuffer = m_usedTriangleBuffers[0];
                            m_usedTriangleBuffers.RemoveAt(0);
                            releasedBuffer.Clear();
                            m_freeTriangleBuffers.Push(releasedBuffer);
                            m_triangleBuffersByKey.Remove(new MyDecalsForModelsDictionaryKey(releasedBuffer.RenderObject, releasedBuffer.DecalTexture));
                        }
                    }

                    m_status = MyDecalForModelsState.READY;
                }
            }
            else
            {
                if (m_triangleBuffersByKey.Count >= m_fadingOutStartLimit)
                {
                    int i = 0;
                    foreach (MyDecalsForRenderObjectsTriangleBuffer buffer in m_usedTriangleBuffers)
                    {
                        if (i < m_fadingOutBuffersCount)
                        {
                            buffer.FadeOutAll();
                        }
                        i++;
                    }

                    m_status             = MyDecalForModelsState.FADING_OUT;
                    m_fadingOutStartTime = (int)MyRender.RenderTimeInMS;
                }
            }
        }
        public void Draw(MyVertexFormatDecal[] vertices, MyEffectDecals effect, MyTexture2D[] texturesDiffuse, MyTexture2D[] texturesNormalMap)
        {
            CheckIfBufferIsFull();

            //  SortForSAP buffers by texture
            m_sortTriangleBuffersByTexture.Clear();
            foreach (MyDecalsForRenderObjectsTriangleBuffer buffer in m_usedTriangleBuffers)
            {
                if (buffer.RenderObject.Visible == true)
                {
                    /*  todo drawdecals flag
                     * if ((buffer.Entity == MyGuiScreenGamePlay.Static.ControlledEntity
                     || buffer.Entity.Parent == MyGuiScreenGamePlay.Static.ControlledEntity) &&
                     || MyGuiScreenGamePlay.Static.IsFirstPersonView)
                     ||{
                     || //  Don't draw decals if they are on an entity in which the camera is
                     || continue;
                     ||} */

                    // Decal with "ExplosionSmut" texture is much larger, so it must be drawed to larger distance.
                    float fadeoutDistance = MyDecals.GetMaxDistanceForDrawingDecals();
                    //if (buffer.DecalTexture == MyDecalTexturesEnum.ExplosionSmut)
                    //  fadeoutDistance *= MyDecalsConstants.DISTANCE_MULTIPLIER_FOR_LARGE_DECALS;

                    //if (Vector3.Distance(MyCamera.m_initialSunWindPosition, buffer.PhysObject.GetPosition()) >= (MyDecals.GetMaxDistanceForDrawingDecals()))
                    //if (buffer.PhysObject.GetDistanceBetweenCameraAndBoundingSphere() >= MyDecals.GetMaxDistanceForDrawingDecals())

                    /*if (buffer.RenderObject.GetDistanceBetweenCameraAndBoundingSphere() >= fadeoutDistance)
                     * {
                     *  continue;
                     * } */

                    m_sortTriangleBuffersByTexture.Add(buffer);
                }
            }
            m_sortTriangleBuffersByTexture.Sort();

            //  Draw decals - sorted by texture
            MyDecalTexturesEnum?lastDecalTexture = null;

            for (int i = 0; i < m_sortTriangleBuffersByTexture.Count; i++)
            {
                MyDecalsForRenderObjectsTriangleBuffer buffer = m_sortTriangleBuffersByTexture[i];

                int trianglesCount = buffer.CopyDecalsToVertices(vertices);

                if (trianglesCount <= 0)
                {
                    continue;
                }

                //  Switch texture only if different than previous one
                if ((lastDecalTexture == null) || (lastDecalTexture != buffer.DecalTexture))
                {
                    int textureIndex = (int)buffer.DecalTexture;
                    effect.SetDecalDiffuseTexture(texturesDiffuse[textureIndex]);
                    effect.SetDecalNormalMapTexture(texturesNormalMap[textureIndex]);
                    lastDecalTexture = buffer.DecalTexture;
                }

                //effect.SetWorldMatrix(buffer.Entity.WorldMatrix * Matrix.CreateTranslation(-MyCamera.Position));
                if (buffer.RenderObject is MyRenderTransformObject)
                {
                    effect.SetWorldMatrix((Matrix)((MyRenderTransformObject)buffer.RenderObject).GetWorldMatrixForDraw());
                }
                else
                {
                    effect.SetWorldMatrix((Matrix)((MyManualCullableRenderObject)buffer.RenderObject).GetWorldMatrixForDraw());
                }

                effect.SetViewProjectionMatrix(MyRenderCamera.ViewProjectionMatrixAtZero);

                // set FadeoutDistance
                float fadeoutDistance = MyDecals.GetMaxDistanceForDrawingDecals();
                //if (buffer.DecalTexture == MyDecalTexturesEnum.ExplosionSmut)
                //  fadeoutDistance *= MyDecalsConstants.DISTANCE_MULTIPLIER_FOR_LARGE_DECALS;

                effect.SetFadeoutDistance(fadeoutDistance);

                effect.SetTechnique(MyEffectDecals.Technique.Model);

                MyRender.GraphicsDevice.VertexDeclaration = MyVertexFormatDecal.VertexDeclaration;

                effect.Begin();
                MyRender.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, 0, trianglesCount, vertices);
                effect.End();

                MyPerformanceCounter.PerCameraDrawWrite.DecalsForEntitiesInFrustum += trianglesCount;
            }
        }
        //  For sorting buffers by texture
        public int CompareTo(object compareToObject)
        {
            MyDecalsForRenderObjectsTriangleBuffer compareToBuffer = (MyDecalsForRenderObjectsTriangleBuffer)compareToObject;

            return(((int)compareToBuffer.DecalTexture).CompareTo((int)this.DecalTexture));
        }