/// <summary> /// Deep copy all of the Particle properties /// </summary> /// <param name="ParticleToCopy">The Particle to Copy the properties from</param> public override void CopyFrom(DPSFParticle ParticleToCopy) { // Cast the Particle to the type it really is DefaultSprite3DBillboardParticle cParticleToCopy = (DefaultSprite3DBillboardParticle)ParticleToCopy; base.CopyFrom(cParticleToCopy); this.DistanceFromCameraSquared = cParticleToCopy.DistanceFromCameraSquared; }
//=========================================================== // Particle System Update Functions //=========================================================== /// <summary> /// Sorts the particles to draw particles furthest from the camera first, in order to achieve proper depth perspective. /// /// <para>NOTE: This operation is very expensive and should only be used when you are /// drawing particles with both opaque and semi-transparent portions, and not using additive blending.</para> /// <para>Merge Sort is the sorting algorithm used, as it tends to be best for linked lists. /// TODO - WHILE MERGE SORT SHOULD BE USED, DUE TO TIME CONSTRAINTS A (PROBABLY) SLOWER METHOD (QUICK-SORT) /// IS BEING USED INSTEAD. THIS FUNCTION NEEDS TO BE UPDATED TO USE MERGE SORT STILL. /// THE LINKED LIST MERGE SORT ALGORITHM CAN BE FOUND AT http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html</para> /// </summary> /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param> protected void UpdateParticleSystemToSortParticlesByDistanceFromCamera(float fElapsedTimeInSeconds) { // Store the Number of Active Particles to sort int iNumberOfActiveParticles = ActiveParticles.Count; // If there is nothing to sort if (iNumberOfActiveParticles <= 1) { // Exit without sorting return; } // Create a List to put the Active Particles in to be sorted List <Particle> cActiveParticleList = new List <Particle>(iNumberOfActiveParticles); // Add all of the Particles to the List LinkedListNode <Particle> cNode = ActiveParticles.First; while (cNode != null) { // Copy this Particle into the Array cActiveParticleList.Add(cNode.Value); // Move to the next Active Particle cNode = cNode.Next; } // Now that the List is full, sort it cActiveParticleList.Sort(delegate(Particle Particle1, Particle Particle2) { DefaultSprite3DBillboardParticle cParticle1 = (DefaultSprite3DBillboardParticle)(DPSFParticle)Particle1; DefaultSprite3DBillboardParticle cParticle2 = (DefaultSprite3DBillboardParticle)(DPSFParticle)Particle2; return(cParticle1.DistanceFromCameraSquared.CompareTo(cParticle2.DistanceFromCameraSquared)); }); // Now that the List is sorted, add the Particles into the Active Particles Linked List in sorted order ActiveParticles.Clear(); for (int iIndex = 0; iIndex < iNumberOfActiveParticles; iIndex++) { // Add this Particle to the Active Particles Linked List. // List is sorted from smallest to largest, but we want // our Linked List sorted from largest to smallest, since // the Particles at the end of the Linked List are drawn last. ActiveParticles.AddFirst(cActiveParticleList[iIndex]); } }
//=========================================================== // Draw Sprite and Overridden Particle System Functions //=========================================================== /// <summary> /// Function to draw a Sprite Particle. This function should be used to draw the given /// Particle with the provided SpriteBatch. /// </summary> /// <param name="Particle">The Particle Sprite to Draw</param> /// <param name="cSpriteBatch">The SpriteBatch to use to doing the Drawing</param> protected override void DrawSprite(DPSFParticle Particle, SpriteBatch cSpriteBatch) { // Cast the Particle to the type it really is DefaultSprite3DBillboardParticle particle = (DefaultSprite3DBillboardParticle)Particle; // Calculate the sprites position in 3D space, and flip it vertically so that it is not upside-down. Vector3 viewSpacePosition = Vector3.Transform(particle.Position, this.View); // Get the Position of the Particle relative to the camera Vector2 destination = new Vector2(viewSpacePosition.X, viewSpacePosition.Y); // Get the Position and Dimensions from the Texture to use for this Sprite Rectangle sourceFromTexture = new Rectangle(0, 0, Texture.Width, Texture.Height); // Calculate how much to scale the sprite to get it to the desired Width and Height. // Use negative height in order to flip the texture to be right-side up. Vector2 scale = new Vector2(particle.Width / sourceFromTexture.Width, -particle.Height / sourceFromTexture.Height); // Make the Sprite rotate about its center Vector2 origin = new Vector2(sourceFromTexture.Width / 2, sourceFromTexture.Height / 2); // Draw the Sprite cSpriteBatch.Draw(Texture, destination, sourceFromTexture, Color.FromNonPremultiplied(particle.Color.ToVector4()), particle.Rotation, origin, scale, particle.FlipMode, viewSpacePosition.Z); }
//=========================================================== // Particle Update Functions //=========================================================== /// <summary> /// Updates the Particle's DistanceFromCameraSquared property to reflect how far this Particle is from the Camera. /// </summary> /// <param name="cParticle">The Particle to update.</param> /// <param name="fElapsedTimeInSeconds">How long it has been since the last update.</param> protected void UpdateParticleDistanceFromCameraSquared(DefaultSprite3DBillboardParticle cParticle, float fElapsedTimeInSeconds) { cParticle.DistanceFromCameraSquared = Vector3.DistanceSquared(this.CameraPosition, cParticle.Position); }