private ParticleSystem() { activeSpawnDetails = ParticleSpawnValues.Default; userSpawnDetails = ParticleSpawnValues.Default; userSpawnDetailsBuffer = ParticleSpawnValues.Default; this.threadAction = new SystemThreadAction(); this.threadAction.system = this; this.drawProc = new SystemDrawProc(); this.globalValues = new float[16]; }
//called on the task thread internal void UpdateParticles() { List<ParticleStore> sortedList = ComputeDependantOrderForFrame(); //first time updating? if (timeStep == 0 && this.systemLogic.OnceEmitter != null) { uint totalParticles = 0; for (int i = 0; i < particleStore.Length; i++) totalParticles += particleStore[i].Count; if (totalParticles > 0) // special case, the OnceEmitter has created particles, need to run a processor pass first RunProcessorLogic(sortedList); } //update the particle types for (int i = 0; i < sortedList.Count; i++) sortedList[i].Update(this, timeStep); //spawn from here activeSpawnDetails = this.userSpawnDetailsBuffer; if (systemLogic.FrameEmitter != null) systemLogic.FrameEmitter.Run(this, timeStep); foreach (ParticleSystemTrigger trigger in this.triggers) trigger.Run(timeStep, ref activeSpawnDetails); foreach (ParticleSystemToggleTrigger toggle in this.toggles) toggle.Run(timeStep, ref activeSpawnDetails); //run the processor RunProcessorLogic(sortedList); for (int i = 0; i < this.particleStore.Length; i++) this.particleStore[i].ClearTypeEmitDependance(); renderStepCount++; timeStep++; }
internal void GetSpawnDetails(out ParticleSpawnValues details) { details = activeSpawnDetails; }
//creates the particle system storage classes (store all particle life data) private void Initalise(ParticleSystemData systemData, Type processorType) { if (systemData == null) throw new ArgumentNullException(); this.systemData = systemData; this.enabled = true; //build the triggers this.triggers = new ParticleSystemTrigger[systemData.SystemLogicData.Triggers.Length]; for (int i = 0; i < this.triggers.Length; i++) this.triggers[i] = new ParticleSystemTrigger(this, i); this.toggles = new ParticleSystemToggleTrigger[systemData.SystemLogicData.ToggleTriggers.Length]; for (int i = 0; i < this.toggles.Length; i++) this.toggles[i] = new ParticleSystemToggleTrigger(this, i); this.systemLogic = systemData.SystemLogicData; //create the storage for the particle instances if (processorType == null) this.particleStore = systemData.CreateParticleProfilerStore(); else this.particleStore = systemData.CreateParticleStore(processorType); this.particleStoreSortedDrawOrder = new List<ParticleStore>[4]; //fill with a few empty entires for (int i = 0; i < particleStoreSortedDrawOrder.Length; i++) particleStoreSortedDrawOrder[i] = new List<ParticleStore>(particleStore.Length); typeDependancyList = new int[this.particleStore.Length * 2]; activeSpawnDetails = this.userSpawnDetails; //run the 'once' emitter if (this.systemLogic.OnceEmitter != null) this.systemLogic.OnceEmitter.Run(this, 0); }
//setup the shaders that copy or add particles public int SetMoveShaderEnabled(DrawState state, GpuParticleProcessor target, GpuParticleProcessor moveSource, Vector4[] constants, ParticleSpawnValues[] initialData, int count, int startIndex) { if (constants != null) { if (constantCache == null) { constantCache = state.Application.UserValues[ConstantCacheName] as ConstantCache; if (constantCache == null) { constantCache = new ConstantCache(); state.Application.UserValues[ConstantCacheName] = constantCache; } } Vector4[] buffer = null; int copyCount = 0; int regCount = count; if (initialData != null) regCount = Math.Min(240, count * 5); //adding requires potentially lots of space if (count > 128) { copyCount = Math.Min(240, regCount); buffer = constantCache.buffer240; } else if (regCount > 64) { copyCount = Math.Min(128, regCount); buffer = constantCache.buffer128; } else if (regCount > 32) { copyCount = Math.Min(64, regCount); buffer = constantCache.buffer64; } else if (regCount > 16) { copyCount = Math.Min(32, regCount); buffer = constantCache.buffer32; } else { copyCount = Math.Min(16, regCount); buffer = constantCache.buffer16; } if (initialData != null) this.enabledAddVS = true; else this.enabledMoveVS = true; this.vsMoveConstants = buffer; //write from the 7th index on int index = ConstantCacheOffset; if (initialData != null) { //initial data gets rather complex. //the initial particle data is huge (64bytes), but often there is loads of duplicates. // //the constants array also doesn't use the 'y' value. //So, the starting info will be put in a dictionary, to remove duplicates. //Then, the y value will be used to write indices to read from. //at this point, the copyCount value is useless. spawnIndices.Clear(); int space = buffer.Length - index; int written = 0; float indexF = 0; int endIndex = count + startIndex; //copy as many entries as possible copyCount = 0; float offset = 0; for (int i = startIndex; i < endIndex; i++) { float dataIndex; if (written == space) break; if (!spawnIndices.TryGetValue(initialData[i], out dataIndex)) { //have to write data if (written + 5 > space) break; Vector4 value = constants[i]; value.Y = indexF; buffer[index++] = value; spawnIndices.Add(initialData[i], indexF); written += 5; indexF += 4;//value takes 4 registers } else { //this is a duplicate Vector4 value = constants[i]; value.Y = dataIndex; buffer[index++] = value; written ++; } copyCount++; offset++; } //thats as much as can be written //fill in the details... //offset the indices with the starting point to read from for (int i = 0; i < copyCount; i++) buffer[ConstantCacheOffset + i].Y += offset; indexF = 0; foreach (ParticleSpawnValues value in spawnIndices.Keys) { //this should be in logical order if (indexF != spawnIndices[value]) throw new InvalidOperationException(); indexF += 4; buffer[index++] = value.PositionSize; buffer[index++] = value.VelocityRotation; buffer[index++] = value.Colour; buffer[index++] = value.UserValues; } } else { for (int i = 0; i < copyCount; i++) buffer[index++] = constants[startIndex++]; } //write target size into index 4 XY //write destination size into index 5 XY moveSource = moveSource ?? target; buffer[4] = new Vector4(target.ResolutionX, target.ResolutionY, 1.0f / target.ResolutionX, 1.0f / target.ResolutionY); buffer[5] = new Vector4(moveSource.ResolutionX, moveSource.ResolutionY, 1.0f / moveSource.ResolutionX, 1.0f / moveSource.ResolutionY); return copyCount; } else { this.vsMoveConstants = null; this.enabledMoveVS = false; this.enabledAddVS = false; return 0; } }