//  Update position, check collisions, etc. and draw if particle still lives.
        //  Return false if particle dies/timeouts in this tick.
        public bool Draw(VRageRender.MyBillboard billboard)
        {
            var actualPosition = m_actualPosition + m_actualPivot;

            MyTransparentGeometry.StartParticleProfilingBlock("Distance calculation");
            //  This time is scaled according to planned lifespan of the particle

            // Distance for sorting
            billboard.DistanceSquared = (float)Vector3D.DistanceSquared(MyTransparentGeometry.Camera.Translation, actualPosition);

            MyTransparentGeometry.EndParticleProfilingBlock();

            // If distance to camera is really small don't draw it.
            if (billboard.DistanceSquared <= 0.1f)
            {
                return(false);
            }

            MyTransparentGeometry.StartParticleProfilingBlock("Quad calculation");

            MyTransparentGeometry.StartParticleProfilingBlock("actualRadius");
            float actualRadius = 1;

            Radius.GetInterpolatedValue <float>(m_normalizedTime, out actualRadius);
            MyTransparentGeometry.EndParticleProfilingBlock();

            float actualAlphaCutout = 0;

            if (AlphaCutout != null)
            {
                MyTransparentGeometry.StartParticleProfilingBlock("AlphaCutout calculation");

                AlphaCutout.GetInterpolatedValue <float>(m_normalizedTime, out actualAlphaCutout);

                MyTransparentGeometry.EndParticleProfilingBlock();
            }

            billboard.ContainedBillboards.Clear();

            billboard.Near   = m_generation.GetEffect().Near;
            billboard.Lowres = m_generation.GetEffect().LowRes || VRageRender.MyRenderConstants.RenderQualityProfile.LowResParticles;
            billboard.CustomViewProjection = -1;
            billboard.ParentID             = -1;
            billboard.AlphaCutout          = actualAlphaCutout;


            float alpha = 1;

            if (Type == MyParticleTypeEnum.Point)
            {
                MyTransparentGeometry.StartParticleProfilingBlock("GetBillboardQuadRotated");
                GetBillboardQuadRotated(billboard, ref actualPosition, actualRadius, m_actualAngle);
                MyTransparentGeometry.EndParticleProfilingBlock();
            }
            else if (Type == MyParticleTypeEnum.Line)
            {
                if (MyUtils.IsZero(Velocity.LengthSquared()))
                {
                    Velocity = MyUtils.GetRandomVector3Normalized();
                }

                MyQuadD quad = new MyQuadD();

                Vector3 actualVelocity = (Vector3)(m_actualPosition - m_previousPosition);

                MyPolyLineD polyLine = new MyPolyLineD();
                //polyLine.LineDirectionNormalized = MyUtils.Normalize(Velocity);
                if (actualVelocity.LengthSquared() > 0)
                {
                    polyLine.LineDirectionNormalized = MyUtils.Normalize(actualVelocity);
                }
                else
                {
                    polyLine.LineDirectionNormalized = MyUtils.Normalize(Velocity);
                }

                if (m_actualAngle > 0)
                {
                    polyLine.LineDirectionNormalized = Vector3.TransformNormal(polyLine.LineDirectionNormalized, Matrix.CreateRotationY(MathHelper.ToRadians(m_actualAngle)));
                }

                float radiusBySpeed = m_generation.RadiusBySpeed;
                if (radiusBySpeed > 0)
                {
                    float actualSpeed = actualVelocity.Length();
                    actualRadius = Math.Max(actualRadius, actualRadius * m_generation.RadiusBySpeed * actualSpeed);
                }


                polyLine.Point0   = actualPosition;
                polyLine.Point1.X = actualPosition.X - polyLine.LineDirectionNormalized.X * actualRadius;
                polyLine.Point1.Y = actualPosition.Y - polyLine.LineDirectionNormalized.Y * actualRadius;
                polyLine.Point1.Z = actualPosition.Z - polyLine.LineDirectionNormalized.Z * actualRadius;

                if (m_actualAngle > 0)
                { //centerize
                    polyLine.Point0.X = polyLine.Point0.X - polyLine.LineDirectionNormalized.X * actualRadius * 0.5f;
                    polyLine.Point0.Y = polyLine.Point0.Y - polyLine.LineDirectionNormalized.Y * actualRadius * 0.5f;
                    polyLine.Point0.Z = polyLine.Point0.Z - polyLine.LineDirectionNormalized.Z * actualRadius * 0.5f;
                    polyLine.Point1.X = polyLine.Point1.X - polyLine.LineDirectionNormalized.X * actualRadius * 0.5f;
                    polyLine.Point1.Y = polyLine.Point1.Y - polyLine.LineDirectionNormalized.Y * actualRadius * 0.5f;
                    polyLine.Point1.Z = polyLine.Point1.Z - polyLine.LineDirectionNormalized.Z * actualRadius * 0.5f;
                }

                polyLine.Thickness = Thickness;
                var camPos = MyTransparentGeometry.Camera.Translation;
                MyUtils.GetPolyLineQuad(out quad, ref polyLine, camPos);

                if (this.m_generation.AlphaAnisotropic)
                {
                    float angle     = 1 - Math.Abs(Vector3.Dot(MyUtils.Normalize(MyTransparentGeometry.Camera.Forward), polyLine.LineDirectionNormalized));
                    float alphaCone = (float)Math.Pow(angle, 0.5f);
                    alpha = alphaCone;
                }

                billboard.Position0 = quad.Point0;
                billboard.Position1 = quad.Point1;
                billboard.Position2 = quad.Point2;
                billboard.Position3 = quad.Point3;
            }
            else if (Type == MyParticleTypeEnum.Trail)
            {
                if (Quad.Point0 == Quad.Point2) //not moving particle
                {
                    return(false);
                }
                if (Quad.Point1 == Quad.Point3) //not moving particle was previous one
                {
                    return(false);
                }
                if (Quad.Point0 == Quad.Point3) //not moving particle was previous one
                {
                    return(false);
                }

                billboard.Position0 = Quad.Point0;
                billboard.Position1 = Quad.Point1;
                billboard.Position2 = Quad.Point2;
                billboard.Position3 = Quad.Point3;

                //if (this.m_generation.AlphaAnisotropic)

                /*   { //Trails are anisotropic by default (nobody wants them to see ugly)
                 *     Vector3 lineDir = Vector3.Normalize(Quad.Point1 - Quad.Point0);
                 *     float angle = 1 - Math.Abs(Vector3.Dot(MyMwcUtils.Normalize(MyCamera.ForwardVector), lineDir));
                 *     float alphaCone = (float)Math.Pow(angle, 0.3f);
                 *     alpha = alphaCone;
                 * }*/
            }
            else
            {
                throw new NotSupportedException(Type + " is not supported particle type");
            }

            MyTransparentGeometry.EndParticleProfilingBlock();

            MyTransparentGeometry.StartParticleProfilingBlock("Material calculation");

            Vector4 color;

            Color.GetInterpolatedValue <Vector4>(m_normalizedTime, out color);

            var   material1         = MyTransparentMaterials.GetMaterial("ErrorMaterial");
            var   material2         = MyTransparentMaterials.GetMaterial("ErrorMaterial");
            float textureBlendRatio = 0;

            if ((Flags & ParticleFlags.BlendTextures) != 0)
            {
                float prevTime, nextTime, difference;
                Material.GetPreviousValue(m_normalizedTime, out material1, out prevTime);
                Material.GetNextValue(m_normalizedTime, out material2, out nextTime, out difference);

                if (prevTime != nextTime)
                {
                    textureBlendRatio = (m_normalizedTime - prevTime) * difference;
                }
            }
            else
            {
                Material.GetInterpolatedValue(m_normalizedTime, out material1);
            }

            MyTransparentGeometry.EndParticleProfilingBlock();

            //This gets 0.44ms for 2000 particles
            MyTransparentGeometry.StartParticleProfilingBlock("billboard.Start");


            billboard.Material          = material1.Name;
            billboard.BlendMaterial     = material2.Name;
            billboard.BlendTextureRatio = textureBlendRatio;
            billboard.EnableColorize    = false;

            billboard.Color          = color * alpha * m_generation.GetEffect().UserColorMultiplier;
            billboard.ColorIntensity = ColorIntensity;

            MyTransparentGeometry.EndParticleProfilingBlock();

            return(true);
        }
        private void CreateParticle(Vector3D interpolatedEffectPosition)
        {
            MyAnimatedParticle particle = MyTransparentGeometry.AddAnimatedParticle();

            if (particle == null)
            {
                return;
            }

            particle.Type = (MyParticleTypeEnum)ParticleType.GetValue <int>();

            MyUtils.AssertIsValid(m_effect.WorldMatrix);

            Vector3D startOffset;

            m_emitter.CalculateStartPosition(m_effect.GetElapsedTime(), MatrixD.CreateWorld(interpolatedEffectPosition, m_effect.WorldMatrix.Forward, m_effect.WorldMatrix.Up), m_effect.UserEmitterScale * m_effect.UserAxisScale, m_effect.UserEmitterScale * m_effect.UserScale, out startOffset, out particle.StartPosition);

            Vector3D particlePosition = particle.StartPosition;

            m_AABB = m_AABB.Include(ref particlePosition);

            Life.GetInterpolatedValue <float>(m_effect.GetElapsedTime(), out particle.Life);
            float lifeVar = LifeVar;

            if (lifeVar > 0)
            {
                particle.Life = MathHelper.Max(MyUtils.GetRandomFloat(particle.Life - lifeVar, particle.Life + lifeVar), 0.1f);
            }

            Vector3 vel;

            Velocity.GetInterpolatedValue <Vector3>(m_effect.GetElapsedTime(), out vel);
            vel.X            *= m_effect.UserScale;
            vel.Y            *= m_effect.UserScale;
            vel.Z            *= m_effect.UserScale;
            particle.Velocity = vel;

            if (VelocityDir == MyVelocityDirEnum.FromEmitterCenter)
            {
                if (!MyUtils.IsZero(startOffset - particle.StartPosition))
                {
                    float length = particle.Velocity.Length();
                    particle.Velocity = MyUtils.Normalize(particle.StartPosition - (Vector3D)startOffset) * length;
                }
            }
            particle.Velocity = Vector3D.TransformNormal(particle.Velocity, GetEffect().WorldMatrix);

            Angle.GetInterpolatedValue <float>(m_effect.GetElapsedTime(), out particle.Angle);
            float angleVar = AngleVar;

            if (angleVar > 0)
            {
                particle.Angle = MyUtils.GetRandomFloat(particle.Angle - AngleVar, particle.Angle + AngleVar);
            }

            RotationSpeed.GetInterpolatedValue <float>(m_effect.GetElapsedTime(), out particle.RotationSpeed);
            float rotationSpeedVar = RotationSpeedVar;

            if (rotationSpeedVar > 0)
            {
                particle.RotationSpeed = MyUtils.GetRandomFloat(particle.RotationSpeed - RotationSpeedVar, particle.RotationSpeed + RotationSpeedVar);
            }

            float radiusVar;

            RadiusVar.GetInterpolatedValue <float>(m_effect.GetElapsedTime(), out radiusVar);
            float lodRadius = 1.0f;

            if (GetEffect().EnableLods)
            {
                LODRadius.GetInterpolatedValue <float>(GetEffect().Distance, out lodRadius);
            }

            Radius.GetInterpolatedKeys(m_effect.GetElapsedTime(),
                                       radiusVar,
                                       (EnableCustomRadius.GetValue <bool>() ? m_effect.UserRadiusMultiplier : 1.0f)
                                       * lodRadius
                                       * GetEffect().UserScale,
                                       particle.Radius);

            if (particle.Type != MyParticleTypeEnum.Point)
            {
                Thickness.GetInterpolatedValue <float>(m_effect.GetElapsedTime(), out particle.Thickness);
            }

            particle.Thickness *= lodRadius;

            float colorVar;

            ColorVar.GetInterpolatedValue <float>(m_effect.GetElapsedTime(), out colorVar);
            Color.GetInterpolatedKeys(m_effect.GetElapsedTime(), colorVar, 1.0f, particle.Color);
            ColorIntensity.GetInterpolatedValue <float>(m_effect.GetElapsedTime(), out particle.ColorIntensity);

            Material.GetInterpolatedKeys(m_effect.GetElapsedTime(), 0, 1.0f, particle.Material);

            particle.Flags  = 0;
            particle.Flags |= BlendTextures.GetValue <bool>() ? MyAnimatedParticle.ParticleFlags.BlendTextures : 0;

            if (PivotRotation.GetKeysCount() > 0 && PivotDistance.GetKeysCount() > 0)
            {
                particle.PivotDistance = new MyAnimatedPropertyFloat(PivotDistance.Name);
                particle.PivotRotation = new MyAnimatedPropertyVector3(PivotRotation.Name);
                PivotDistance.GetInterpolatedKeys(m_effect.GetElapsedTime(), PivotDistVar, 1.0f, particle.PivotDistance);
                PivotRotation.GetInterpolatedKeys(m_effect.GetElapsedTime(), 1.0f, particle.PivotRotation);
            }

            if (Acceleration.GetKeysCount() > 0)
            {
                particle.Acceleration = new MyAnimatedPropertyVector3(Acceleration.Name);
                float multiplier = MyUtils.GetRandomFloat(1 - AccelerationVar, 1 + AccelerationVar);
                Acceleration.GetInterpolatedKeys(m_effect.GetElapsedTime(), multiplier, particle.Acceleration);
            }

            if (AlphaCutout.GetKeysCount() > 0)
            {
                particle.AlphaCutout = new MyAnimatedPropertyFloat(AlphaCutout.Name);
                AlphaCutout.GetInterpolatedKeys(m_effect.GetElapsedTime(), 0, 1, particle.AlphaCutout);
            }

            particle.Start(this);

            m_particles.Add(particle);
        }
        //  Update position, check collisions, etc. and draw if particle still lives.
        //  Return false if particle dies/timeouts in this tick.
        public bool Draw(VRageRender.MyBillboard billboard)
        {
            if (Pivot != null && !MyParticlesManager.Paused)
            {
                if (PivotRotation != null)
                {
                    Matrix pivotRotationTransform =
                        Matrix.CreateRotationX(MathHelper.ToRadians(m_actualPivotRotation.X) * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS) *
                        Matrix.CreateRotationY(MathHelper.ToRadians(m_actualPivotRotation.Y) * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS) *
                        Matrix.CreateRotationZ(MathHelper.ToRadians(m_actualPivotRotation.Z) * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS);

                    m_actualPivot = Vector3.TransformNormal(m_actualPivot, pivotRotationTransform);
                }

                m_actualPivot = Vector3D.TransformNormal(m_actualPivot, m_generation.GetEffect().WorldMatrix);
            }

            var actualPosition = m_actualPosition + m_actualPivot;

            MyTransparentGeometry.StartParticleProfilingBlock("Distance calculation");
            //  This time is scaled according to planned lifespan of the particle

            // Distance for sorting
            billboard.DistanceSquared = (float)Vector3D.DistanceSquared(MyTransparentGeometry.Camera.Translation, actualPosition);

            MyTransparentGeometry.EndParticleProfilingBlock();

            // If distance to camera is really small don't draw it.
            if (billboard.DistanceSquared <= 0.1f)
            {
                return(false);
            }

            MyTransparentGeometry.StartParticleProfilingBlock("Quad calculation");

            MyTransparentGeometry.StartParticleProfilingBlock("actualRadius");
            float actualRadius = 1;

            Radius.GetInterpolatedValue <float>(m_normalizedTime, out actualRadius);
            MyTransparentGeometry.EndParticleProfilingBlock();

            float actualAlphaCutout = 0;

            if (AlphaCutout != null)
            {
                MyTransparentGeometry.StartParticleProfilingBlock("AlphaCutout calculation");

                AlphaCutout.GetInterpolatedValue <float>(m_normalizedTime, out actualAlphaCutout);

                MyTransparentGeometry.EndParticleProfilingBlock();
            }

            billboard.ContainedBillboards.Clear();

            billboard.Near   = m_generation.GetEffect().Near;
            billboard.Lowres = VRageRender.MyRenderConstants.RenderQualityProfile.LowResParticles;
            billboard.CustomViewProjection = -1;
            billboard.ParentID             = -1;
            billboard.AlphaCutout          = actualAlphaCutout;
            billboard.UVOffset             = Vector2.Zero;
            billboard.UVSize = Vector2.One;



            float alpha = 1;


            Matrix  transform = Matrix.Identity;
            Vector3 normal    = Vector3.Forward;

            Vector3 actualVelocity = (Vector3)(m_actualPosition - m_previousPosition);

            float radiusBySpeed = m_generation.RadiusBySpeed;

            if (radiusBySpeed > 0)
            {
                float actualSpeed = actualVelocity.Length();
                actualRadius = Math.Max(actualRadius, actualRadius * m_generation.RadiusBySpeed * actualSpeed);
            }


            if (Type == MyParticleTypeEnum.Point)
            {
                MyTransparentGeometry.StartParticleProfilingBlock("GetBillboardQuadRotated");

                Vector2 actualRadiusV2 = new Vector2(actualRadius, actualRadius);

                if (Thickness > 0)
                {
                    actualRadiusV2.Y = Thickness;
                }

                if (m_generation.RotationReference == MyRotationReference.Camera)
                {
                    transform =
                        Matrix.CreateFromAxisAngle(MyTransparentGeometry.Camera.Right, m_actualAngle.X) *
                        Matrix.CreateFromAxisAngle(MyTransparentGeometry.Camera.Up, m_actualAngle.Y) *
                        Matrix.CreateFromAxisAngle(MyTransparentGeometry.Camera.Forward, m_actualAngle.Z);

                    GetBillboardQuadRotated(billboard, ref actualPosition, actualRadiusV2, ref transform, MyTransparentGeometry.Camera.Left, MyTransparentGeometry.Camera.Up);
                }
                else if (m_generation.RotationReference == MyRotationReference.Local)
                {
                    transform = Matrix.CreateFromAxisAngle(m_generation.GetEffect().WorldMatrix.Right, m_actualAngle.X) *
                                Matrix.CreateFromAxisAngle(m_generation.GetEffect().WorldMatrix.Up, m_actualAngle.Y) *
                                Matrix.CreateFromAxisAngle(m_generation.GetEffect().WorldMatrix.Forward, m_actualAngle.Z);

                    GetBillboardQuadRotated(billboard, ref actualPosition, actualRadiusV2, ref transform, m_generation.GetEffect().WorldMatrix.Left, m_generation.GetEffect().WorldMatrix.Up);
                }
                else if (m_generation.RotationReference == MyRotationReference.Velocity)
                {
                    if (actualVelocity.LengthSquared() < 0.00001f)
                    {
                        return(false);
                    }

                    Matrix velocityRef = Matrix.CreateFromDir(Vector3.Normalize(actualVelocity));

                    transform = Matrix.CreateFromAxisAngle(velocityRef.Right, m_actualAngle.X) *
                                Matrix.CreateFromAxisAngle(velocityRef.Up, m_actualAngle.Y) *
                                Matrix.CreateFromAxisAngle(velocityRef.Forward, m_actualAngle.Z);

                    GetBillboardQuadRotated(billboard, ref actualPosition, actualRadiusV2, ref transform, velocityRef.Left, velocityRef.Up);
                }
                else if (m_generation.RotationReference == MyRotationReference.VelocityAndCamera)
                {
                    if (actualVelocity.LengthSquared() < 0.0001f)
                    {
                        return(false);
                    }

                    Vector3 cameraToPoint = Vector3.Normalize(m_actualPosition - MyTransparentGeometry.Camera.Translation);
                    Vector3 velocityDir   = Vector3.Normalize(actualVelocity);

                    Vector3 sideVector = Vector3.Cross(cameraToPoint, velocityDir);
                    Vector3 upVector   = Vector3.Cross(sideVector, velocityDir);

                    Matrix velocityRef = Matrix.CreateWorld(m_actualPosition, velocityDir, upVector);

                    transform = Matrix.CreateFromAxisAngle(velocityRef.Right, m_actualAngle.X) *
                                Matrix.CreateFromAxisAngle(velocityRef.Up, m_actualAngle.Y) *
                                Matrix.CreateFromAxisAngle(velocityRef.Forward, m_actualAngle.Z);

                    GetBillboardQuadRotated(billboard, ref actualPosition, actualRadiusV2, ref transform, velocityRef.Left, velocityRef.Up);
                }
                else if (m_generation.RotationReference == MyRotationReference.LocalAndCamera)
                {
                    Vector3 cameraToPoint = Vector3.Normalize(m_actualPosition - MyTransparentGeometry.Camera.Translation);
                    Vector3 localDir      = m_generation.GetEffect().WorldMatrix.Forward;
                    float   dot           = cameraToPoint.Dot(localDir);
                    Matrix  velocityRef;
                    if (dot >= 0.9999f)
                    {
                        // TODO Petr: probably not correct, at least it does not produce NaN positions
                        velocityRef = Matrix.CreateTranslation(m_actualPosition);
                    }
                    else
                    {
                        Vector3 sideVector = Vector3.Cross(cameraToPoint, localDir);
                        Vector3 upVector   = Vector3.Cross(sideVector, localDir);

                        velocityRef = Matrix.CreateWorld(m_actualPosition, localDir, upVector);
                    }

                    transform = Matrix.CreateFromAxisAngle(velocityRef.Right, m_actualAngle.X) *
                                Matrix.CreateFromAxisAngle(velocityRef.Up, m_actualAngle.Y) *
                                Matrix.CreateFromAxisAngle(velocityRef.Forward, m_actualAngle.Z);

                    GetBillboardQuadRotated(billboard, ref actualPosition, actualRadiusV2, ref transform, velocityRef.Left, velocityRef.Up);
                }
                else
                {
                    System.Diagnostics.Debug.Fail("Unknown RotationReference enum");
                }

                MyTransparentGeometry.EndParticleProfilingBlock();
            }
            else if (Type == MyParticleTypeEnum.Line)
            {
                if (MyUtils.IsZero(Velocity.LengthSquared()))
                {
                    Velocity = MyUtils.GetRandomVector3Normalized();
                }

                MyQuadD quad = new MyQuadD();

                MyPolyLineD polyLine = new MyPolyLineD();
                //polyLine.LineDirectionNormalized = MyUtils.Normalize(Velocity);
                if (actualVelocity.LengthSquared() > 0)
                {
                    polyLine.LineDirectionNormalized = MyUtils.Normalize(actualVelocity);
                }
                else
                {
                    polyLine.LineDirectionNormalized = MyUtils.Normalize(Velocity);
                }

                if (m_actualAngle.Z != 0)
                {
                    polyLine.LineDirectionNormalized = Vector3.TransformNormal(polyLine.LineDirectionNormalized, Matrix.CreateRotationY(m_actualAngle.Z));
                }

                polyLine.Point0   = actualPosition;
                polyLine.Point1.X = actualPosition.X - polyLine.LineDirectionNormalized.X * actualRadius;
                polyLine.Point1.Y = actualPosition.Y - polyLine.LineDirectionNormalized.Y * actualRadius;
                polyLine.Point1.Z = actualPosition.Z - polyLine.LineDirectionNormalized.Z * actualRadius;

                if (m_actualAngle.LengthSquared() > 0)
                { //centerize
                    polyLine.Point0.X = polyLine.Point0.X - polyLine.LineDirectionNormalized.X * actualRadius * 0.5f;
                    polyLine.Point0.Y = polyLine.Point0.Y - polyLine.LineDirectionNormalized.Y * actualRadius * 0.5f;
                    polyLine.Point0.Z = polyLine.Point0.Z - polyLine.LineDirectionNormalized.Z * actualRadius * 0.5f;
                    polyLine.Point1.X = polyLine.Point1.X - polyLine.LineDirectionNormalized.X * actualRadius * 0.5f;
                    polyLine.Point1.Y = polyLine.Point1.Y - polyLine.LineDirectionNormalized.Y * actualRadius * 0.5f;
                    polyLine.Point1.Z = polyLine.Point1.Z - polyLine.LineDirectionNormalized.Z * actualRadius * 0.5f;
                }

                polyLine.Thickness = Thickness;
                var camPos = MyTransparentGeometry.Camera.Translation;
                MyUtils.GetPolyLineQuad(out quad, ref polyLine, camPos);

                transform.Forward = polyLine.LineDirectionNormalized;

                billboard.Position0 = quad.Point0;
                billboard.Position1 = quad.Point1;
                billboard.Position2 = quad.Point2;
                billboard.Position3 = quad.Point3;
            }
            else if (Type == MyParticleTypeEnum.Trail)
            {
                if (Quad.Point0 == Quad.Point2) //not moving particle
                {
                    return(false);
                }
                if (Quad.Point1 == Quad.Point3) //not moving particle was previous one
                {
                    return(false);
                }
                if (Quad.Point0 == Quad.Point3) //not moving particle was previous one
                {
                    return(false);
                }

                billboard.Position0 = Quad.Point0;
                billboard.Position1 = Quad.Point1;
                billboard.Position2 = Quad.Point2;
                billboard.Position3 = Quad.Point3;
            }
            else
            {
                throw new NotSupportedException(Type + " is not supported particle type");
            }

            if (this.m_generation.AlphaAnisotropic)
            {
                normal = Vector3.Normalize(Vector3.Cross(billboard.Position0 - billboard.Position1, billboard.Position0 - billboard.Position2));

                Vector3 forward = (billboard.Position0 + billboard.Position1 + billboard.Position2 + billboard.Position3) / 4 - MyTransparentGeometry.Camera.Translation;

                //Vector3 forward = MyTransparentGeometry.Camera.Forward;

                float angle = Math.Abs(Vector3.Dot(MyUtils.Normalize(forward), normal));


                float alphaCone = 1 - (float)Math.Pow(1 - angle, 4);
                alpha = alphaCone;
            }


            MyTransparentGeometry.EndParticleProfilingBlock();

            MyTransparentGeometry.StartParticleProfilingBlock("Material calculation");

            Vector4 color = Vector4.One;

            if (Color.GetKeysCount() > 0)
            {
                Color.GetInterpolatedValue <Vector4>(m_normalizedTime, out color);
            }

            if (m_arrayIndex != -1)
            {
                Vector3 arraySize = m_generation.ArraySize;
                if (arraySize.X > 0 && arraySize.Y > 0)
                {
                    int arrayOffset = m_generation.ArrayOffset;
                    int arrayModulo = m_generation.ArrayModulo == 0 ? (int)arraySize.X * (int)arraySize.Y : m_generation.ArrayModulo;

                    m_arrayIndex = m_arrayIndex % arrayModulo + arrayOffset;

                    float xDiv   = 1.0f / arraySize.X;
                    float yDiv   = 1.0f / arraySize.Y;
                    int   xIndex = m_arrayIndex % (int)arraySize.X;
                    int   yIndex = m_arrayIndex / (int)arraySize.X;

                    billboard.UVOffset = new Vector2(xDiv * xIndex, yDiv * yIndex);
                    billboard.UVSize   = new Vector2(xDiv, yDiv);
                }
            }


            var   material1         = MyTransparentMaterials.GetMaterial("ErrorMaterial");
            var   material2         = MyTransparentMaterials.GetMaterial("ErrorMaterial");
            float textureBlendRatio = 0;

            if ((Flags & ParticleFlags.BlendTextures) != 0)
            {
                float prevTime, nextTime, difference;
                Material.GetPreviousValue(m_normalizedTime, out material1, out prevTime);
                Material.GetNextValue(m_normalizedTime, out material2, out nextTime, out difference);

                if (prevTime != nextTime)
                {
                    textureBlendRatio = (m_normalizedTime - prevTime) * difference;
                }
            }
            else
            {
                Material.GetInterpolatedValue(m_normalizedTime, out material1);
            }

            MyTransparentGeometry.EndParticleProfilingBlock();

            //This gets 0.44ms for 2000 particles
            MyTransparentGeometry.StartParticleProfilingBlock("billboard.Start");

            if (material1 != null)
            {
                billboard.Material = material1.Name;
            }

            billboard.BlendMaterial     = material2.Name;
            billboard.BlendTextureRatio = textureBlendRatio;
            billboard.EnableColorize    = false;

            billboard.Color                     = color * alpha * m_generation.GetEffect().UserColorMultiplier;
            billboard.ColorIntensity            = ColorIntensity;
            billboard.SoftParticleDistanceScale = SoftParticleDistanceScale;

            MyTransparentGeometry.EndParticleProfilingBlock();

            return(true);
        }
        private void UpdateParticlesLife()
        {
            int counter = 0;

            VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("ParticleGeneration-UpdateParticlesLife");

            MyParticleGeneration inheritedGeneration      = null;
            Vector3D             previousParticlePosition = m_effect.WorldMatrix.Translation;
            float particlesToCreate = 0;

            m_AABB = BoundingBoxD.CreateInvalid();
            m_AABB = m_AABB.Include(ref previousParticlePosition);

            if (OnDie.GetValue <int>() != -1)
            {
                inheritedGeneration = GetInheritedGeneration(OnDie.GetValue <int>());

                if (inheritedGeneration == null)
                {
                    OnDie.SetValue(-1);
                }
                else
                {
                    inheritedGeneration.IsInherited = true;
                    particlesToCreate = inheritedGeneration.m_particlesToCreate;
                }
            }

            VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();

            VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("ParticleGeneration-Update01");

            Vector3D previousTrail0 = previousParticlePosition;
            Vector3D previousTrail1 = previousParticlePosition;

            using (ParticlesLock.AcquireExclusiveUsing())
            {
                while (counter < m_particles.Count)
                {
                    float motionInheritance;
                    MotionInheritance.GetInterpolatedValue(m_effect.GetElapsedTime(), out motionInheritance);

                    MyAnimatedParticle particle = m_particles[counter];

                    if (motionInheritance > 0)
                    {
                        m_effect.CalculateDeltaMatrix = true;
                    }

                    if (particle.Update())
                    {
                        if (motionInheritance > 0)
                        {
                            var delta = m_effect.GetDeltaMatrix();
                            particle.AddMotionInheritance(ref motionInheritance, ref delta);
                        }

                        if (counter == 0)
                        {
                            previousParticlePosition = particle.ActualPosition;
                            previousTrail0           = particle.Quad.Point1;
                            previousTrail1           = particle.Quad.Point2;
                            particle.Quad.Point0     = particle.ActualPosition;
                            particle.Quad.Point2     = particle.ActualPosition;
                        }

                        counter++;


                        if (particle.Type == MyParticleTypeEnum.Trail)
                        {
                            if (particle.ActualPosition == previousParticlePosition)
                            {
                                particle.Quad.Point0 = particle.ActualPosition;
                                particle.Quad.Point1 = particle.ActualPosition;
                                particle.Quad.Point2 = particle.ActualPosition;
                                particle.Quad.Point3 = particle.ActualPosition;
                            }
                            else
                            {
                                MyPolyLineD polyLine = new MyPolyLineD();
                                polyLine.Thickness = particle.Thickness;
                                polyLine.Point0    = particle.ActualPosition;
                                polyLine.Point1    = previousParticlePosition;

                                Vector3D direction           = polyLine.Point1 - polyLine.Point0;
                                Vector3D normalizedDirection = MyUtils.Normalize(polyLine.Point1 - polyLine.Point0);

                                polyLine.LineDirectionNormalized = normalizedDirection;
                                var camPos = MyTransparentGeometry.Camera.Translation;
                                MyUtils.GetPolyLineQuad(out particle.Quad, ref polyLine, camPos);

                                particle.Quad.Point0 = previousTrail0 + direction * 0.15f;
                                particle.Quad.Point3 = previousTrail1 + direction * 0.15f;
                                previousTrail0       = particle.Quad.Point1;
                                previousTrail1       = particle.Quad.Point2;
                            }
                        }

                        previousParticlePosition = particle.ActualPosition;

                        m_AABB = m_AABB.Include(ref previousParticlePosition);
                        continue;
                    }

                    if (inheritedGeneration != null)
                    {
                        inheritedGeneration.m_particlesToCreate = particlesToCreate;
                        inheritedGeneration.EffectMatrix        = MatrixD.CreateWorld(particle.ActualPosition, Vector3D.Normalize(particle.Velocity), Vector3D.Cross(Vector3D.Left, particle.Velocity));
                        inheritedGeneration.UpdateParticlesCreation();
                    }

                    m_particles.Remove(particle);
                    MyTransparentGeometry.DeallocateAnimatedParticle(particle);
                }
            }

            VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();
        }
        public bool Update()
        {
            m_elapsedTime += VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;

            if (m_elapsedTime >= Life)
            {
                return(false);
            }

            m_normalizedTime += m_elapsedTimeDivider;

            m_velocity += m_generation.GetEffect().Gravity *m_generation.Gravity *VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;

            m_previousPosition  = m_actualPosition;
            m_actualPosition.X += Velocity.X * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;
            m_actualPosition.Y += Velocity.Y * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;
            m_actualPosition.Z += Velocity.Z * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;

            if (Pivot != null)
            {
                MyTransparentGeometry.StartParticleProfilingBlock("Pivot calculation");

                Pivot.GetInterpolatedValue <Vector3>(m_normalizedTime, out m_actualPivot);

                MyTransparentGeometry.EndParticleProfilingBlock();
            }

            if (Acceleration != null)
            {
                MyTransparentGeometry.StartParticleProfilingBlock("Acceleration calculation");

                Acceleration.GetInterpolatedValue <Vector3>(m_normalizedTime, out m_actualAcceleration);

                Matrix transform = Matrix.Identity;

                if (m_generation.AccelerationReference == MyAccelerationReference.Camera)
                {
                    transform = MyTransparentGeometry.Camera;
                }
                else if (m_generation.AccelerationReference == MyAccelerationReference.Local)
                {
                }
                else if ((m_generation.AccelerationReference == MyAccelerationReference.Velocity))
                {
                    Vector3 actualVelocity = (Vector3)(m_actualPosition - m_previousPosition);

                    if (actualVelocity.LengthSquared() < 0.00001f)
                    {
                        m_actualAcceleration = Vector3.Zero;
                    }
                    else
                    {
                        transform = Matrix.CreateFromDir(Vector3.Normalize(actualVelocity));
                    }
                }
                else if ((m_generation.AccelerationReference == MyAccelerationReference.Gravity))
                {
                    if (m_generation.GetEffect().Gravity.LengthSquared() < 0.00001f)
                    {
                        m_actualAcceleration = Vector3.Zero;
                    }
                    else
                    {
                        transform = Matrix.CreateFromDir(Vector3.Normalize(m_generation.GetEffect().Gravity));
                    }
                }
                else
                {
                    System.Diagnostics.Debug.Fail("Unknown RotationReference enum");
                }

                m_actualAcceleration = Vector3.TransformNormal(m_actualAcceleration, transform);

                Velocity += m_actualAcceleration * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;

                MyTransparentGeometry.EndParticleProfilingBlock();
            }

            if (RotationSpeed != null)
            {
                Vector3 rotationSpeed;
                RotationSpeed.GetInterpolatedValue <Vector3>(m_normalizedTime, out rotationSpeed);
                m_actualAngle += new Vector3(MathHelper.ToRadians(rotationSpeed.X), MathHelper.ToRadians(rotationSpeed.Y), MathHelper.ToRadians(rotationSpeed.Z)) * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;
            }

            if (PivotRotation != null)
            {
                Vector3 pivotRotation;
                PivotRotation.GetInterpolatedValue <Vector3>(m_normalizedTime, out pivotRotation);
                m_actualPivotRotation += pivotRotation;
            }

            if (ArrayIndex != null)
            {
                ArrayIndex.GetInterpolatedValue <int>(m_normalizedTime, out m_arrayIndex);
            }

            MyUtils.AssertIsValid(m_actualPosition);
            MyUtils.AssertIsValid(m_actualAngle);

            return(true);
        }