internal GpuParticleProcessorData(ParticleSystemTypeData typeData, bool useColourValues, bool usesUserValues, bool storeLifeData, TargetPlatform targetPlatform) : this( GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Once, GpuParticleShaderBuilder.LogicType.Once, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition), GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Once, GpuParticleShaderBuilder.LogicType.OnceClone, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition), GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Frame, GpuParticleShaderBuilder.LogicType.Frame, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition), GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Frame, GpuParticleShaderBuilder.LogicType.FrameMove, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition)) { }
void IParticleProcessor.Initalise(ParticleSystemTypeData typeData, IParticleProcessor[] allProcessors, bool useColourValues, uint maxLifeTimeSteps, uint timeStepHz, uint maxExpectedCount) { CpuParticleProcessorData processor = typeData.RuntimeLogicData.CpuParticleProcessorData; this.particleTypeData = typeData; this.timeStepHz = timeStepHz; this.processors = allProcessors; this.addIndices = new uint[8]; //max expected count is always a power of 2 this.maxCount = maxExpectedCount; this.countMask = maxExpectedCount - 1; bool usesUserValues = typeData.RuntimeLogicData.SystemUsesUserValues; bool usesLifeOrAge = typeData.RuntimeLogicData.SystemUsesLifeOrAgeValues; positions = new Vector4[maxExpectedCount]; velocity = new Vector4[maxExpectedCount]; if (useColourValues) { colours = new Vector4[maxExpectedCount]; } if (usesUserValues) { userdata = new Vector4[maxExpectedCount]; } if (usesLifeOrAge) { lifeData = new Vector2[maxExpectedCount]; } System.Reflection.Assembly asm = processor.Assembly; Type type = asm.GetType(processor.RuntimeClassName); System.Reflection.MethodInfo frameMethod = type.GetMethod(typeData.Name + "_frame", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public); System.Reflection.MethodInfo onceMethod = type.GetMethod(typeData.Name + "_once", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public); this.frameMethod = (UpdateParticleDelegate)Delegate.CreateDelegate(typeof(UpdateParticleDelegate), frameMethod); this.onceMethod = (AddParticleDelegate)Delegate.CreateDelegate(typeof(AddParticleDelegate), onceMethod); }
//build it public ParticleStore(uint maxTimeSteps, ParticleSystemTypeData type, IParticleProcessor processor, int particleTypeCount, int particleTypeIndex) { if (type == null) throw new ArgumentNullException(); this.typeEmitDependancy = new bool[particleTypeCount + 1]; this.particleTypeIndex = particleTypeIndex; this.particleType = type; this.processor = processor; this.frameEmitter = type.FrameEmitter; this.removeEmitter = type.RemoveEmitter; this.timeStepCount = 1; while (maxTimeSteps > this.timeStepCount) this.timeStepCount *= 2; this.timeStepMask = (int)this.timeStepCount - 1; this.timeSteps = new SystemTimeStep[timeStepCount]; this.particles = new Particle[Math.Max(4,type.ExpectedMaxCapacity)]; this.addActions = new AddAction[8]; this.copyActions = new CopyAction[8]; }
//all code for the particle types are stored in the same assmebly internal void AddParticleType(ParticleSystemTypeData typeData) { methods.Add(CpuParticleLogicBuilder.BuildCpuLogic(typeData.Name + "_frame", typeData.ParticleLogicData.Frame, false)); methods.Add(CpuParticleLogicBuilder.BuildCpuLogic(typeData.Name + "_once", typeData.ParticleLogicData.Once, true)); }
void IParticleProcessor.Initalise(ParticleSystemTypeData typeData, IParticleProcessor[] allProcessors, bool useColourValues, uint maxLifeTimeSteps, uint timeStepHz, uint maxExpectedCount) { this.processorData = typeData.RuntimeLogicData.GpuParticleProcessorData; //compute resolution to fit the particle count this.resolutionX = 2; this.resolutionY = 2; while (true) { int count = resolutionX * resolutionY; if (count >= maxExpectedCount) { break; } if (resolutionY >= resolutionX) { resolutionX *= 2; } else { resolutionY *= 2; } } resolutionXF = (float)resolutionX; resolutionYF = (float)resolutionY; this.particleTypeData = typeData; this.allProcessors = allProcessors; this.renderPasses = new GpuParticleRenderPass[4]; this.shaderRandomValues = new Random(); this.maxParticleTimeStep = maxLifeTimeSteps; this.systemStepDeltaTime = 1.0f / ((float)timeStepHz); bool usesUserValues = typeData.RuntimeLogicData.SystemUsesUserValues; bool usesLifeOrAge = typeData.RuntimeLogicData.SystemUsesLifeOrAgeValues; this.usesLifeStorage = usesLifeOrAge; SurfaceFormat vec4Format = SurfaceFormat.HalfVector4; if (!ParticleSystem.gpuVTexHalfVec4supported) { vec4Format = SurfaceFormat.Vector4; } this.positionSizeBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); this.velocityRotationBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); if (useColourValues) { this.colourBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } if (usesUserValues) { this.userBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } #if XBOX360 //technically doing this can produce bugs when the buffers combine to be greater than 10MiB //(approx ~320,000 particles) //This can happen as the textures are updated in tiles, and it's possible for a particle //to be shifted across a tile and recieve an invalid update. However the majority of the time, //this would only cause a particle to be a frame behind or ahead. Worst case is the particle //either dissapears or is duplicated. //it is considered a worthwhile tradeoff for half the render target memory usage this.positionSizeBufferB = positionSizeBufferA; this.velocityRotationBufferB = velocityRotationBufferA; this.colourBufferB = colourBufferA; this.userBufferB = userBufferA; #else this.positionSizeBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); this.velocityRotationBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); if (useColourValues) { this.colourBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } if (usesUserValues) { this.userBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } #endif //setup the render target groups (MRT) DrawTargetTexture2D[] targets = new DrawTargetTexture2D[2 + (useColourValues ? 1 : 0) + (usesUserValues ? 1 : 0)]; targets[0] = positionSizeBufferA; targets[1] = velocityRotationBufferA; if (useColourValues) { targets[2] = colourBufferA; } if (usesUserValues) { targets[targets.Length - 1] = userBufferA; } this.mrtGroupA = new DrawTargetTexture2DGroup(camera, targets); targets[0] = positionSizeBufferB; targets[1] = velocityRotationBufferB; if (useColourValues) { targets[2] = colourBufferB; } if (usesUserValues) { targets[targets.Length - 1] = userBufferB; } this.mrtGroupB = new DrawTargetTexture2DGroup(camera, targets); this.mrtGroupA.ClearBuffer.Enabled = false; this.mrtGroupB.ClearBuffer.Enabled = false; if (usesLifeOrAge) { SurfaceFormat ageFormat = SurfaceFormat.HalfVector2; if (!ParticleSystem.gpuVTexHalfVec2supported) { ageFormat = SurfaceFormat.HalfVector4; if (!ParticleSystem.gpuVTexHalfVec4supported) { ageFormat = SurfaceFormat.Vector4; } } #if XBOX360 lifeStoreBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat); lifeStoreBufferB = lifeStoreBufferA; lifeStoreBufferA.ClearBuffer.Enabled = false; lifeStoreBufferA.Add(new TexturedElement(lifeStoreBufferA, Vector2.One, true)); #else lifeStoreBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat); lifeStoreBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat); lifeStoreBufferA.ClearBuffer.Enabled = false; lifeStoreBufferB.ClearBuffer.Enabled = false; //setup so that when a store buffer is drawn, it copies in the other buffer. lifeStoreBufferA.Add(new TexturedElement(lifeStoreBufferB, Vector2.One, true)); lifeStoreBufferB.Add(new TexturedElement(lifeStoreBufferA, Vector2.One, true)); #endif } this.scissorTest = new Xen.Graphics.Modifier.ScissorModifier(0, 0, 1, 1); //scissor off the MRT, as it uses a fullsize quad to run the particle logic for every particle this.mrtGroupA.AddModifier(scissorTest); this.mrtGroupB.AddModifier(scissorTest); //this is the pass that runs per-frame logic on the particles this.backgroundFillPass = new ShaderElement(this.processorData.FrameShader, new Vector2(1, 1), true); this.mrtGroupA.Add(backgroundFillPass); this.mrtGroupB.Add(backgroundFillPass); this.mrtGroupA.Add(this); this.mrtGroupB.Add(this); if (usesLifeOrAge) { this.lifeStoreBufferA.Add(this); #if !XBOX360 this.lifeStoreBufferB.Add(this); #endif } }
internal GpuParticleProcessorData(ParticleSystemTypeData typeData, bool useColourValues, bool usesUserValues, bool storeLifeData, ContentTargetPlatform targetPlatform, string pathToShaderSystem) : this( GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Once, GpuParticleShaderBuilder.LogicType.Once, GpuParticleShaderBuilder.VertexShaderType.Once, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem), GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Once, GpuParticleShaderBuilder.LogicType.OnceClone, GpuParticleShaderBuilder.VertexShaderType.Clone, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem), GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Frame, GpuParticleShaderBuilder.LogicType.Frame, GpuParticleShaderBuilder.VertexShaderType.Frame, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem), GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Frame, GpuParticleShaderBuilder.LogicType.FrameMove, GpuParticleShaderBuilder.VertexShaderType.Clone, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem)) { }
//all code for the particle types are stored in the same assmebly internal void AddParticleType(ParticleSystemTypeData typeData) { methods.Add(CpuParticleLogicBuilder.BuildCpuLogic(typeData.Name+"_frame",typeData.ParticleLogicData.Frame,false)); methods.Add(CpuParticleLogicBuilder.BuildCpuLogic(typeData.Name+"_once",typeData.ParticleLogicData.Once,true)); }
void IParticleProcessor.Initalise(ParticleSystemTypeData typeData, IParticleProcessor[] allProcessors, bool useColourValues, uint maxLifeTimeSteps, uint timeStepHz, uint maxExpectedCount) { CpuParticleProcessorData processor = typeData.RuntimeLogicData.CpuParticleProcessorData; this.particleTypeData = typeData; this.timeStepHz = timeStepHz; this.processors = allProcessors; this.addIndices = new uint[8]; //max expected count is always a power of 2 this.maxCount = maxExpectedCount; this.countMask = maxExpectedCount - 1; bool usesUserValues = typeData.RuntimeLogicData.SystemUsesUserValues; bool usesLifeOrAge = typeData.RuntimeLogicData.SystemUsesLifeOrAgeValues; positions = new Vector4[maxExpectedCount]; velocity = new Vector4[maxExpectedCount]; if (useColourValues) colours = new Vector4[maxExpectedCount]; if (usesUserValues) userdata = new Vector4[maxExpectedCount]; if (usesLifeOrAge) lifeData = new Vector2[maxExpectedCount]; System.Reflection.Assembly asm = processor.Assembly; Type type = asm.GetType(processor.RuntimeClassName); System.Reflection.MethodInfo frameMethod = type.GetMethod(typeData.Name + "_frame", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public); System.Reflection.MethodInfo onceMethod = type.GetMethod(typeData.Name + "_once", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public); this.frameMethod = (UpdateParticleDelegate)Delegate.CreateDelegate(typeof(UpdateParticleDelegate), frameMethod); this.onceMethod = (AddParticleDelegate)Delegate.CreateDelegate(typeof(AddParticleDelegate), onceMethod); }