/// <summary> /// Renders the scene /// </summary> public void Render() { // Set the render states for using point sprites device.RenderState.ZBufferWriteEnable = false; device.RenderState.AlphaBlendEnable = true; device.RenderState.SourceBlend = Blend.One; device.RenderState.DestinationBlend = Blend.One; bool lightEnabled = device.RenderState.Lighting; device.RenderState.Lighting = false; device.SetTexture(0, particleTexture); device.Transform.World = Matrix.Identity; device.RenderState.PointSpriteEnable = true; device.RenderState.PointScaleEnable = true; device.RenderState.PointSize = 1.0f; device.RenderState.PointScaleA = 0f; device.RenderState.PointScaleB = 1.0f; device.RenderState.PointScaleC = 1.0f; // Set up the vertex buffer to be rendered device.SetStreamSource(0, vertexBuffer, 0); device.VertexFormat = PointVertex.Format; PointVertex[] vertices = null; int numParticlesToRender = 0; // Lock the vertex buffer. We fill the vertex buffer in small // chunks, using LockFlags.NoOverWrite. When we are done filling // each chunk, we call DrawPrim, and lock the next chunk. When // we run out of space in the vertex buffer, we start over at // the beginning, using LockFlags.Discard. baseParticle += flush; if (baseParticle >= discard) { baseParticle = 0; } int count = 0; vertices = (PointVertex[])vertexBuffer.Lock(baseParticle * DXHelp.GetTypeSize(typeof(PointVertex)), typeof(PointVertex), (baseParticle != 0) ? LockFlags.NoOverwrite : LockFlags.Discard, flush); foreach (Particle p in particlesList) { Vector3 vPos = p.positionVector; Vector3 vVel = p.velocityVector; float fLengthSq = vVel.LengthSq(); uint steps; if (fLengthSq < 1.0f) { steps = 2; } else if (fLengthSq < 4.00f) { steps = 3; } else if (fLengthSq < 9.00f) { steps = 4; } else if (fLengthSq < 12.25f) { steps = 5; } else if (fLengthSq < 16.00f) { steps = 6; } else if (fLengthSq < 20.25f) { steps = 7; } else { steps = 8; } vVel *= -0.01f / (float)steps; System.Drawing.Color diffuse = ColorOperator.Lerp(p.fadeColor, p.diffuseColor, p.fadeProgression); // Render each particle a bunch of times to get a blurring effect for (int i = 0; i < steps; i++) { vertices[count].v = vPos; vertices[count].color = diffuse.ToArgb(); count++; if (++numParticlesToRender == flush) { // Done filling this chunk of the vertex buffer. Lets unlock and // draw this portion so we can begin filling the next chunk. vertexBuffer.Unlock(); device.DrawPrimitives(PrimitiveType.PointList, baseParticle, numParticlesToRender); // Lock the next chunk of the vertex buffer. If we are at the // end of the vertex buffer, LockFlags.Discard the vertex buffer and start // at the beginning. Otherwise, specify LockFlags.NoOverWrite, so we can // continue filling the VB while the previous chunk is drawing. baseParticle += flush; if (baseParticle >= discard) { baseParticle = 0; } vertices = (PointVertex[])vertexBuffer.Lock(baseParticle * DXHelp.GetTypeSize(typeof(PointVertex)), typeof(PointVertex), (baseParticle != 0) ? LockFlags.NoOverwrite : LockFlags.Discard, flush); count = 0; numParticlesToRender = 0; } vPos += vVel; } } // Unlock the vertex buffer vertexBuffer.Unlock(); // Render any remaining particles if (numParticlesToRender > 0) { device.DrawPrimitives(PrimitiveType.PointList, baseParticle, numParticlesToRender); } // Reset render states device.RenderState.PointSpriteEnable = false; device.RenderState.PointScaleEnable = false; device.RenderState.Lighting = lightEnabled; device.RenderState.ZBufferWriteEnable = true; device.RenderState.AlphaBlendEnable = false; }
/// <summary> /// Updates the scene /// </summary> public void Update(float fSecsPerFrame, int NumParticlesToEmit, System.Drawing.Color clrEmitColor, System.Drawing.Color clrFadeColor, float fEmitVel, Vector3 vPosition) { time += fSecsPerFrame; for (int ii = particlesList.Count - 1; ii >= 0; ii--) { Particle p = (Particle)particlesList[ii]; // Calculate new position float fT = time - p.creationTime; float fGravity; if (p.isSpark) { fGravity = -5.0f; p.fadeProgression -= (fSecsPerFrame * 2.25f); } else { fGravity = -9.8f; p.fadeProgression -= fSecsPerFrame * 0.25f; } p.positionVector = p.initialVelocity * fT + p.initialPosition; p.positionVector.Y += (0.5f * fGravity) * (fT * fT); p.velocityVector.Y = p.initialVelocity.Y + fGravity * fT; if (p.fadeProgression < 0.0f) { p.fadeProgression = 0.0f; } // Kill old particles if (p.positionVector.Y < radius || p.isSpark && p.fadeProgression <= 0.0f) { // Emit sparks if (!p.isSpark) { for (int i = 0; i < 4; i++) { Particle spark; if (freeParticles.Count > 0) { spark = (Particle)freeParticles[0]; freeParticles.RemoveAt(0); } else { spark = new Particle(); } spark.isSpark = true; spark.initialVelocity = new Vector3(); spark.initialPosition = p.positionVector; spark.initialPosition.Y = radius; float fRand1 = ((float)rand.Next(int.MaxValue) / (float)int.MaxValue) * (float)Math.PI * 2.00f; float fRand2 = ((float)rand.Next(int.MaxValue) / (float)int.MaxValue) * (float)Math.PI * 0.25f; spark.initialVelocity.X = p.velocityVector.X * 0.25f + (float)Math.Cos(fRand1) * (float)Math.Sin(fRand2); spark.initialVelocity.Z = p.velocityVector.Z * 0.25f + (float)Math.Sin(fRand1) * (float)Math.Sin(fRand2); spark.initialVelocity.Y = (float)Math.Cos(fRand2); spark.initialVelocity.Y *= ((float)rand.Next(int.MaxValue) / (float)int.MaxValue) * 1.5f; spark.positionVector = spark.initialPosition; spark.velocityVector = spark.initialVelocity; spark.diffuseColor = ColorOperator.Lerp(p.fadeColor, p.diffuseColor, p.fadeProgression); spark.fadeColor = System.Drawing.Color.Black; spark.fadeProgression = 1.0f; spark.creationTime = time; particlesList.Add(spark); } } // Kill particle freeParticles.Add(p); particlesList.RemoveAt(ii); if (!p.isSpark) { particles--; } } else { particlesList[ii] = p; } } // Emit new particles int particlesEmit = particles + NumParticlesToEmit; while (particles < particlesLimit && particles < particlesEmit) { Particle particle; if (freeParticles.Count > 0) { particle = (Particle)freeParticles[0]; freeParticles.RemoveAt(0); } else { particle = new Particle(); } // Emit new particle float fRand1 = ((float)rand.Next(int.MaxValue) / (float)int.MaxValue) * (float)Math.PI * 2.0f; float fRand2 = ((float)rand.Next(int.MaxValue) / (float)int.MaxValue) * (float)Math.PI * 0.25f; particle.isSpark = false; particle.initialPosition = vPosition + new Vector3(0.0f, radius, 0.0f); particle.initialVelocity.X = (float)Math.Cos(fRand1) * (float)Math.Sin(fRand2) * 2.5f; particle.initialVelocity.Z = (float)Math.Sin(fRand1) * (float)Math.Sin(fRand2) * 2.5f; particle.initialVelocity.Y = (float)Math.Cos(fRand2); particle.initialVelocity.Y *= ((float)rand.Next(int.MaxValue) / (float)int.MaxValue) * fEmitVel; particle.positionVector = particle.initialPosition; particle.velocityVector = particle.initialVelocity; particle.diffuseColor = clrEmitColor; particle.fadeColor = clrFadeColor; particle.fadeProgression = 1.0f; particle.creationTime = time; particlesList.Add(particle); particles++; } }