//this method is called back from the particle system void Content.IParticleSystemDrawer.DrawGpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint count, Texture2D positionSize, Texture2D velocityRotation, Texture2D colour, Texture2D userValues) { if ((drawMask & (1u << particleType.TypeIndex)) != 0) { this.DrawGpuParticles(state, particleType, count, alphaBlendState ?? particleType.BlendMode, positionSize, velocityRotation, colour, userValues, particleType.GpuBufferPosition); } }
void Content.IParticleSystemDrawer.DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint count, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colour, Vector4[] userValues) { if ((drawMask & (1u << particleType.TypeIndex)) != 0) { this.DrawCpuParticles(state, particleType, count, alphaBlendState ?? particleType.BlendMode, positionSize, velocityRotation, colour, userValues); } }
/// <summary> /// draws the particles on a GPU system /// </summary> protected override void DrawGpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Texture2D positionTex, Texture2D velocityRotation, Texture2D colourTex, Texture2D userValues, bool usesUserValuesPositionBuffer) { //this is very similar to the billboard drawer (see it for reference) Vector2 targetSize = state.DrawTarget.Size; state.PushRenderState(); state.RenderState.AlphaBlend = blendMode; state.RenderState.DepthColourCull.DepthWriteEnabled = false; Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state); //get the shared vertice BillboardParticles2DElement.GenerateBillboardVertices(state, ref vertices, ref indices); int count = (int)particleCount; DrawVelocityParticles_GpuTex shaderNoColour = null; DrawVelocityParticlesColour_GpuTex shaderColour = null; //user variants DrawVelocityParticles_GpuTex_UserOffset shaderNoColour_UO = null; DrawVelocityParticlesColour_GpuTex_UserOffset shaderColour_UO = null; float resolutionXF = (float)positionTex.Width; float resolutionYF = (float)positionTex.Height; Vector2 invTextureSize; Vector2 velScale = new Vector2(velocityScale, 0); if (this.useRotationToScaleVelocityEffect) { velScale = new Vector2(0, velocityScale); } invTextureSize = new Vector2(1.0f / resolutionXF, 1.0f / resolutionYF); IShader shader; if (!usesUserValuesPositionBuffer) { if (colourTex != null) { shader = shaderColour = state.GetShader <DrawVelocityParticlesColour_GpuTex>(); shaderColour.PositionTexture = positionTex; shaderColour.ColourTexture = colourTex; shaderColour.VelocityTexture = velocityRotation; shaderColour.DisplayTexture = displayTexture; shaderColour.SetVelocityScale(ref velScale); } else { shader = shaderNoColour = state.GetShader <DrawVelocityParticles_GpuTex>(); shaderNoColour.PositionTexture = positionTex; shaderNoColour.VelocityTexture = velocityRotation; shaderNoColour.DisplayTexture = displayTexture; shaderNoColour.SetVelocityScale(ref velScale); } } else { if (colourTex != null) { shader = shaderColour_UO = state.GetShader <DrawVelocityParticlesColour_GpuTex_UserOffset>(); shaderColour_UO.PositionTexture = positionTex; shaderColour_UO.ColourTexture = colourTex; shaderColour_UO.VelocityTexture = velocityRotation; shaderColour_UO.UserTexture = userValues; shaderColour_UO.DisplayTexture = displayTexture; shaderColour_UO.SetVelocityScale(ref velScale); } else { shader = shaderNoColour_UO = state.GetShader <DrawVelocityParticles_GpuTex_UserOffset>(); shaderNoColour_UO.PositionTexture = positionTex; shaderNoColour_UO.VelocityTexture = velocityRotation; shaderNoColour_UO.UserTexture = userValues; shaderNoColour_UO.DisplayTexture = displayTexture; shaderNoColour_UO.SetVelocityScale(ref velScale); } } int drawn = 0; while (count > 0) { int drawCount = Math.Min(count, vertices.Count / 4); if (!usesUserValuesPositionBuffer) { if (colourTex != null) { shaderColour.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } else { shaderNoColour.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } } else { if (colourTex != null) { shaderColour_UO.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } else { shaderNoColour_UO.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } } //bind shader.Bind(state); vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0); count -= drawCount; drawn += drawCount; } state.PopRenderState(); }
//draws on CPU particle systems /// <summary> /// draws the particles from a CPU system /// </summary> protected override void DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colourData, Vector4[] userValues) { //this is very similar to the billboard drawer (see it for reference) Vector2 targetSize = state.DrawTarget.Size; state.PushRenderState(); state.RenderState.AlphaBlend = blendMode; state.RenderState.DepthColourCull.DepthWriteEnabled = false; Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state); BillboardParticles2DElement.GenerateBillboardVertices(state, ref this.vertices, ref this.indices); int count = (int)particleCount; DrawVelocityParticles_BillboardCpu shaderNoColour = null; DrawVelocityParticlesColour_BillboardCpu shaderColour = null; if (colourData != null) { shaderColour = state.GetShader <DrawVelocityParticlesColour_BillboardCpu>(); } else { shaderNoColour = state.GetShader <DrawVelocityParticles_BillboardCpu>(); } Vector2 velScale = new Vector2(velocityScale, 0); if (this.useRotationToScaleVelocityEffect) { velScale = new Vector2(0, velocityScale); } int drawn = 0; while (count > 0) { int drawCount; drawCount = Math.Min(count, 80); if (colourData != null) { shaderColour.PositionData.SetArray(positionSize, drawn); shaderColour.VelocityData.SetArray(velocityRotation, drawn); shaderColour.ColourData.SetArray(colourData, drawn); shaderColour.DisplayTexture = displayTexture; shaderColour.SetVelocityScale(ref velScale); shaderColour.Bind(state); } else { shaderNoColour.PositionData.SetArray(positionSize, drawn); shaderNoColour.VelocityData.SetArray(velocityRotation, drawn); shaderNoColour.DisplayTexture = displayTexture; shaderNoColour.SetVelocityScale(ref velScale); shaderNoColour.Bind(state); } vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0); count -= drawCount; drawn += drawCount; } state.PopRenderState(); }
/// <summary> /// This method is only present on Windows builds /// </summary> /// <param name="blendMode"></param><param name="colour"></param><param name="count"></param><param name="particleType"></param> /// <param name="positionSize"></param><param name="state"></param><param name="userValues"></param><param name="velocityRotation"></param> protected abstract void DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint count, AlphaBlendState blendMode, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colour, Vector4[] userValues);
/// <summary> /// <para>Method to override to draw 3D particles</para> /// <para>Note: When 'usesUserValuesPositionBuffer' is true, the values 'user1, user2 and user3' (yzw in the UserTexture) store a position offset for the particle</para></summary> /// <param name="state"></param><param name="particleType"></param><param name="count"></param><param name="blendMode"></param> /// <param name="positionSize"></param><param name="velocityRotation"></param><param name="colour"></param><param name="userValues"></param><param name="usesUserValuesPositionBuffer"></param> protected abstract void DrawGpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint count, AlphaBlendState blendMode, Texture2D positionSize, Texture2D velocityRotation, Texture2D colour, Texture2D userValues, bool usesUserValuesPositionBuffer);
/// <summary> /// implements the method to draw gpu particles /// </summary> protected override void DrawGpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Texture2D positionTex, Texture2D velocityRotation, Texture2D colourTex, Texture2D userValues, bool usesUserValuesPositionBuffer) { Vector2 targetSize = state.DrawTarget.Size; state.PushRenderState(); state.RenderState.AlphaBlend = blendMode; state.RenderState.DepthColourCull.DepthWriteEnabled = false; //get the display texture, or a white texture if none exists Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state); //get / create the shared vertices and indices for drawing billboard particles BillboardParticles2DElement.GenerateBillboardVertices(state, ref vertices, ref indices); int count = (int)particleCount; //instances of the two possible shaders DrawVelocityBillboardParticles_GpuTex3D shaderNoColour = null; DrawVelocityBillboardParticlesColour_GpuTex3D shaderColour = null; //user variantes DrawVelocityBillboardParticles_GpuTex3D_UserOffset shaderNoColour_UO = null; DrawVelocityBillboardParticlesColour_GpuTex3D_UserOffset shaderColour_UO = null; float resolutionXF = (float)positionTex.Width; float resolutionYF = (float)positionTex.Height; Vector2 invTextureSize = new Vector2(1.0f / resolutionXF, 1.0f / resolutionYF); Matrix cameraMatrix; state.Camera.GetCameraMatrix(out cameraMatrix); Vector3 worldSpaceYAxis = new Vector3(cameraMatrix.M21, cameraMatrix.M22, cameraMatrix.M23); Vector2 velScale = new Vector2(velocityScale, 0); if (this.useRotationToScaleVelocityEffect) { velScale = new Vector2(0, velocityScale); } IShader shader; if (!usesUserValuesPositionBuffer) { if (colourTex != null) // does this particle system use colours? { //get the shader shaderColour = state.GetShader <DrawVelocityBillboardParticlesColour_GpuTex3D>(); //set the samplers shaderColour.PositionTexture = positionTex; shaderColour.ColourTexture = colourTex; shaderColour.VelocityTexture = velocityRotation; shaderColour.DisplayTexture = displayTexture; shaderColour.SetWorldSpaceYAxis(ref worldSpaceYAxis); shaderColour.SetVelocityScale(ref velScale); shader = shaderColour; } else { shaderNoColour = state.GetShader <DrawVelocityBillboardParticles_GpuTex3D>(); shaderNoColour.PositionTexture = positionTex; shaderNoColour.VelocityTexture = velocityRotation; shaderNoColour.DisplayTexture = displayTexture; shaderNoColour.SetWorldSpaceYAxis(ref worldSpaceYAxis); shaderNoColour.SetVelocityScale(ref velScale); shader = shaderNoColour; } } else { if (colourTex != null) // does this particle system use colours? { //get the shader shaderColour_UO = state.GetShader <DrawVelocityBillboardParticlesColour_GpuTex3D_UserOffset>(); //set the samplers shaderColour_UO.PositionTexture = positionTex; shaderColour_UO.ColourTexture = colourTex; shaderColour_UO.VelocityTexture = velocityRotation; shaderColour_UO.UserTexture = userValues; shaderColour_UO.DisplayTexture = displayTexture; shaderColour_UO.SetWorldSpaceYAxis(ref worldSpaceYAxis); shaderColour_UO.SetVelocityScale(ref velScale); shader = shaderColour_UO; } else { shaderNoColour_UO = state.GetShader <DrawVelocityBillboardParticles_GpuTex3D_UserOffset>(); shaderNoColour_UO.PositionTexture = positionTex; shaderNoColour_UO.VelocityTexture = velocityRotation; shaderNoColour_UO.UserTexture = userValues; shaderNoColour_UO.DisplayTexture = displayTexture; shaderNoColour_UO.SetWorldSpaceYAxis(ref worldSpaceYAxis); shaderNoColour_UO.SetVelocityScale(ref velScale); shader = shaderNoColour_UO; } } int drawn = 0; while (count > 0) { //draw upto vertices.Count / 4 (4 vertices per quad) int drawCount = Math.Min(count, vertices.Count / 4); //set the inverse texture size, and the start offset value, then bind the shader if (!usesUserValuesPositionBuffer) { if (colourTex != null) { shaderColour.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } else { shaderNoColour.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } } else { if (colourTex != null) { shaderColour_UO.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } else { shaderNoColour_UO.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn); } } //bind shader.Bind(state); //draw! vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0); count -= drawCount; drawn += drawCount; } //and done. state.PopRenderState(); }
/// <summary> /// implements the method to draw cpu processed particles /// </summary> protected override void DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colourData, Vector4[] userValues) { //this is a bit more complex, but mostly the same as the GPU draw method Vector2 targetSize = state.DrawTarget.Size; state.PushRenderState(); state.RenderState.AlphaBlend = blendMode; state.RenderState.DepthColourCull.DepthWriteEnabled = false; Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state); BillboardParticles2DElement.GenerateBillboardVertices(state, ref this.vertices, ref this.indices); Matrix cameraMatrix; state.Camera.GetCameraMatrix(out cameraMatrix); Vector3 worldSpaceYAxis = new Vector3(cameraMatrix.M21, cameraMatrix.M22, cameraMatrix.M23); Vector2 velScale = new Vector2(velocityScale, 0); if (this.useRotationToScaleVelocityEffect) { velScale = new Vector2(0, velocityScale); } int count = (int)particleCount; DrawVelocityBillboardParticles_BillboardCpu3D shaderNoColour = null; DrawVelocityBillboardParticlesColour_BillboardCpu3D shaderColour = null; if (colourData != null) { shaderColour = state.GetShader <DrawVelocityBillboardParticlesColour_BillboardCpu3D>(); shaderColour.SetWorldSpaceYAxis(ref worldSpaceYAxis); shaderColour.SetVelocityScale(ref velScale); } else { shaderNoColour = state.GetShader <DrawVelocityBillboardParticles_BillboardCpu3D>(); shaderNoColour.SetWorldSpaceYAxis(ref worldSpaceYAxis); shaderNoColour.SetVelocityScale(ref velScale); } int drawn = 0; while (count > 0) { int drawCount; drawCount = Math.Min(count, 75); if (colourData != null) { shaderColour.PositionData.SetArray(positionSize, drawn); shaderColour.VelocityData.SetArray(velocityRotation, drawn); shaderColour.ColourData.SetArray(colourData, drawn); shaderColour.DisplayTexture = displayTexture; shaderColour.Bind(state); } else { shaderNoColour.PositionData.SetArray(positionSize, drawn); shaderNoColour.VelocityData.SetArray(velocityRotation, drawn); shaderNoColour.DisplayTexture = displayTexture; shaderNoColour.Bind(state); } vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0); count -= drawCount; drawn += drawCount; } state.PopRenderState(); }
/// <summary> /// implements the method to draw cpu particles /// </summary> protected override void DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colourData, Vector4[] userValues) { //this is a bit more complex, but mostly the same as the GPU draw method Vector2 targetSize = state.DrawTarget.Size; state.PushRenderState(); state.RenderState.AlphaBlend = blendMode; state.RenderState.DepthColourCull.DepthWriteEnabled = false; Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state); GenerateBillboardVertices(state, ref this.vertices, ref this.indices); int count = (int)particleCount; DrawBillboardParticles_BillboardCpu shaderNoColour = null; DrawBillboardParticlesColour_BillboardCpu shaderColour = null; if (positionBuffer == null) { positionBuffer = GetPositionBuffer(state, positionBuffer); } if (colourData != null) { shaderColour = state.GetShader <DrawBillboardParticlesColour_BillboardCpu>(); } else { shaderNoColour = state.GetShader <DrawBillboardParticles_BillboardCpu>(); } int drawn = 0; while (count > 0) { int drawCount; drawCount = Math.Min(count, 120); //the only major difference from the GPU drawer is here for (int i = 0; i < drawCount; i++) { //copy position xy and w (size), and velocity.w (rotation) positionBuffer[i] = positionSize[drawn + i]; positionBuffer[i].Z = velocityRotation[drawn + i].W; } if (colourData != null) { shaderColour.PositionData.SetArray(positionBuffer, 0); shaderColour.ColourData.SetArray(colourData, drawn); shaderColour.DisplayTexture = displayTexture; shaderColour.Bind(state); } else { shaderNoColour.PositionData.SetArray(positionBuffer, 0); shaderNoColour.DisplayTexture = displayTexture; shaderNoColour.Bind(state); } vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0); count -= drawCount; drawn += drawCount; } state.PopRenderState(); }
/// <summary> /// draws the particles from a CPU system /// </summary> protected override void DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colourData, Vector4[] userValues) { Vector2 targetSize = state.DrawTarget.Size; state.PushRenderState(); state.RenderState.AlphaBlend = blendMode; state.RenderState.DepthColourCull.DepthWriteEnabled = false; VelocityLineParticles2DElement.GenerateLinesVertices(state, ref this.vertices); int count = (int)particleCount; DrawVelocityParticles_LinesCpu shaderNoColour = null; DrawVelocityParticlesColour_LinesCpu shaderColour = null; if (colourData != null) { shaderColour = state.GetShader <DrawVelocityParticlesColour_LinesCpu>(); } else { shaderNoColour = state.GetShader <DrawVelocityParticles_LinesCpu>(); } Vector2 velScale = new Vector2(velocityScale, 0); if (this.useRotationToScaleVelocityEffect) { velScale = new Vector2(0, velocityScale); } int drawn = 0; while (count > 0) { int drawCount; drawCount = Math.Min(count, 80); if (colourData != null) { shaderColour.PositionData.SetArray(positionSize, drawn); shaderColour.VelocityData.SetArray(velocityRotation, drawn); shaderColour.ColourData.SetArray(colourData, drawn); shaderColour.SetVelocityScale(ref velScale); shaderColour.Bind(state); } else { shaderNoColour.PositionData.SetArray(positionSize, drawn); shaderNoColour.VelocityData.SetArray(velocityRotation, drawn); shaderNoColour.SetVelocityScale(ref velScale); shaderNoColour.Bind(state); } vertices.Draw(state, null, PrimitiveType.LineList, drawCount, 0, 0); count -= drawCount; drawn += drawCount; } state.PopRenderState(); }