Ejemplo n.º 1
0
        //draw the particle update data
        void IDraw.Draw(DrawState state)
        {
            int copyIndex = 0;

            //keep an application wide cache of the vertices used
            AllocateVertices(state);


            //special mode, renderig the life / age of particles

            if (renderLifeStoreMode)
            {
                DrawLifeAgeToStore(state);
                return;
            }
            //otherwise, render normal

            //move particles
            if (activeRenderPass.CopyCount > 0)
            {
                while (activeRenderPass.CopyCount > 0)
                {
                    int count = (this.processorData.FrameMoveShader as GpuParticleShader).SetMoveShaderEnabled(state, this, null, activeRenderPass.CopyData, null, activeRenderPass.CopyCount, copyIndex);

                    this.processorData.FrameMoveShader.Bind(state);

                    verticesRenderIndex.Draw(state, null, PrimitiveType.PointList, Math.Min(count, activeRenderPass.CopyCount), 0, 0);

                    activeRenderPass.CopyCount -= count;
                    copyIndex += count;
                }
            }

            //particle are being added?
            for (int i = 0; i < activeRenderPass.AddLists.Length; i++)
            {
                ProcessorAddList list = activeRenderPass.AddLists[i];

                if (list.AddCount > 0)
                {
                    copyIndex = 0;

                    GpuParticleShader shader = this.processorData.OnceShader as GpuParticleShader;

                    //added from a different processor?
                    if (list.processor != null)
                    {
                        shader = this.processorData.OnceCloneShader as GpuParticleShader;

                        Texture2D t0, t1, t2, t3, t4;
                        list.processor.GetLogicTextures(state, out t0, out t1, out t2, out t3, out t4);
                        shader.SetTextures(state, t0, t1, t2, t3, randomTexture.GetTexture(state), t4);
                    }
                    else
                    {
                        shader.SetTextures(state, null, null, null, null, randomTexture.GetTexture(state), null);
                    }

                    while (list.AddCount > 0)
                    {
                        //draw them
                        int count = shader.SetMoveShaderEnabled(state, this, list.processor, list.AddData, list.AddDetails, list.AddCount, copyIndex);

                        shader.Bind(state);

                        verticesRenderIndex.Draw(state, null, PrimitiveType.PointList, Math.Min(count, list.AddCount), 0, 0);

                        list.AddCount -= count;
                        copyIndex     += count;
                    }
                }
            }
        }
Ejemplo n.º 2
0
        void IParticleProcessor.Update(int particleCount, float particleCountF, float delatTime, float[] globals, CopyAction[] copyActions, int copyActionCount, AddAction[] addActions, int addActionCount, int step)
        {
            //update may be called multiple times for a single frame
            //so store the update data in GpuParticleRenderPass instances

            //instances are reused

            //get a free pass to copy in action data
            if (renderPassCount == renderPasses.Length)
            {
                Array.Resize(ref renderPasses, renderPasses.Length * 2);
            }

            GpuParticleRenderPass pass = renderPasses[renderPassCount];

            if (pass == null)
            {
                //allocate a pass
                pass = new GpuParticleRenderPass(this.allProcessors);
                renderPasses[renderPassCount] = pass;
            }

            //copy in the action data...
            pass.ParticleCount  = particleCount;
            pass.ParticleCountF = particleCountF;

            for (int i = 0; i < globals.Length; i++)
            {
                pass.globals[i] = globals[i];
            }

            if (copyActionCount > 0)
            {
                //allocate
                int count = 2;
                while (copyActionCount > count)
                {
                    count *= 2;                     // keep allocations as powers of two
                }
                if (pass.CopyData == null ||
                    pass.CopyData.Length < copyActionCount)
                {
                    Array.Resize(ref pass.CopyData, count);
                }

                //reset the count
                pass.CopyCount = copyActionCount;

                //write the data
                int i = 0;
                while (i != copyActionCount)
                {
                    pass.CopyData[i].X = copyActions[i].indexToF;
                    pass.CopyData[i].Y = copyActions[i].indexFromF;

                    i++;
                    //ZW store the life / age data
                }
            }


            if (addActionCount > 0)
            {
                //count the number of actions for each type
                for (int i = 0; i < addActionCount; i++)
                {
                    pass.AddLists[addActions[i].cloneTypeIndex + 1].AddCount++;
                }

                //allocate the storage for each action by type
                for (int i = 0; i < pass.AddLists.Length; i++)
                {
                    int listCount = pass.AddLists[i].AddCount;
                    pass.AddLists[i].AddCount = 0;

                    if (listCount == 0)
                    {
                        continue;
                    }

                    Vector4[] list = pass.AddLists[i].AddData;

                    if (list != null &&
                        list.Length >= listCount)
                    {
                        continue;
                    }

                    int count = 4;
                    while (listCount > count)
                    {
                        count *= 2;                         // keep allocations as powers of two
                    }
                    if (list == null || list.Length < listCount)
                    {
                        Array.Resize(ref pass.AddLists[i].AddData, count);

                        if (pass.AddLists[i].processor == null)
                        {
                            //this processor also sets positions
                            Array.Resize(ref pass.AddLists[i].AddDetails, count);
                        }
                    }
                }

                //fill up the data
                for (int i = 0; i < addActionCount; i++)
                {
                    ProcessorAddList list = pass.AddLists[addActions[i].cloneTypeIndex + 1];
                    int index             = list.AddCount;

                    list.AddData[index].X = addActions[i].indexF;

                    //when cloneFromIndex is -1, cloneFromIndexF stores the starting x coord
                    list.AddData[index].Y = addActions[i].cloneFromIndexF;

                    //ZW store the life / age data (set in next block, if needed)

                    if (addActions[i].cloneFromIndex == -1)
                    {
                        //store the position of the particle (it's not being cloned)
                        list.AddDetails[index] = addActions[i].spawnDetails;
                    }

                    list.AddCount++;
                }
            }
            //done...

            //except...

            //copy in the data to the 'Life storage' list.
            //this is a separate texture that stores life and age of each particle
            //this is rather inefficient unfortunately

            if (usesLifeStorage && (copyActionCount > 0 || addActionCount > 0))
            {
                //unfortunately, there is a lot of int-to-float conversion here

                //stored step is wrapped to help precision
                float startStep = ((float)(step & (this.maxParticleTimeStep - 1))) * this.systemStepDeltaTime;

                //allocate
                int count = 2;
                while (copyActionCount + addActionCount > count)
                {
                    count *= 2;                     // keep allocations as powers of two
                }
                if (pass.LifeData == null ||
                    pass.LifeData.Length < copyActionCount + addActionCount)
                {
                    Array.Resize(ref pass.LifeData, count);
                }

                count = 2;
                while (pass.ParticleCount > count)
                {
                    count *= 2;
                }
                if (lifeStepParticleData == null ||
                    lifeStepParticleData.Length < pass.ParticleCount)
                {
                    Array.Resize(ref lifeStepParticleData, count);
                }

                count = 0;
                Vector3[] data  = pass.LifeData;
                Vector3   v     = new Vector3();
                Vector2   store = new Vector2();

                for (int i = 0; i < pass.AddLists.Length; i++)
                {
                    pass.AddLists[i].AddCount = 0;
                }


                //move a particle
                for (int i = 0; i < copyActionCount; i++)
                {
                    v.X = copyActions[i].indexToF;

                    //get it's life data
                    store = lifeStepParticleData[copyActions[i].indexFrom];
                    //store in case it moves again
                    lifeStepParticleData[copyActions[i].indexTo] = store;

                    v.Y = store.X;
                    v.Z = store.Y;
#if DEBUG
                    if (v.Y == 0 &&
                        v.Z == 0)
                    {
                        throw new ArgumentException();
                    }
#endif

                    //a copy will read the life / age from the texture

                    //update the CopyData data too
                    //as the ZW values need to store this data
                    pass.CopyData[count].Z = store.X;
                    pass.CopyData[count].W = store.Y;

                    data[count++] = v;
                }

                //data is stored as 'index, age, start time'
                for (int i = 0; i < addActionCount; i++)
                {
                    v.X = addActions[i].indexF;
                    v.Y = ((float)addActions[i].lifeSteps) * this.systemStepDeltaTime;
                    v.Z = startStep;

                    //update the AddList data too
                    //as the ZW values need to store this data

                    ProcessorAddList list = pass.AddLists[addActions[i].cloneTypeIndex + 1];

                    list.AddData[list.AddCount].Z = v.Y;
                    list.AddData[list.AddCount].W = v.Z;
                    list.AddCount++;



                    store.X = v.Y;
                    store.Y = v.Z;

                    //need to store this data for particles that are moved (see above)
                    lifeStepParticleData[addActions[i].index] = store;

                    data[count++] = v;
                }

                pass.LifeCount = count;
            }

            renderPassCount++;
        }