Edit

kc3-lang/angle/samples/particle_system/ParticleSystem.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-09-25 18:29:28
    Hash : 57b37b6b
    Message : Rename util/system_utils to util/test_utils. This removes a GN naming conflict between util/system_utils and common/system_utils. This conflict was preventing us from adding unit tests to utils' version of system_utils. Since these functions are only useful to tests and samples rename them test_utils for simplicity. Will enable further development of ANGLE's standalone testing harness. Bug: angleproject:3162 Change-Id: I9e34fb69f96c5de6dc2453fce4148a0f285e15ed Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1825268 Reviewed-by: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: Yuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • samples/particle_system/ParticleSystem.cpp
  • //
    // Copyright 2014 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    //            Based on ParticleSystem.c from
    // Book:      OpenGL(R) ES 2.0 Programming Guide
    // Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
    // ISBN-10:   0321502795
    // ISBN-13:   9780321502797
    // Publisher: Addison-Wesley Professional
    // URLs:      http://safari.informit.com/9780321563835
    //            http://www.opengles-book.com
    
    #include "SampleApplication.h"
    
    #include "common/vector_utils.h"
    #include "tga_utils.h"
    #include "util/random_utils.h"
    #include "util/shader_utils.h"
    
    #define _USE_MATH_DEFINES
    #include <math.h>
    
    #include <string>
    
    using namespace angle;
    
    class ParticleSystemSample : public SampleApplication
    {
      public:
        ParticleSystemSample(int argc, char **argv) : SampleApplication("ParticleSystem", argc, argv) {}
    
        bool initialize() override
        {
            constexpr char kVS[] = R"(uniform float u_time;
    uniform vec3 u_centerPosition;
    attribute float a_lifetime;
    attribute vec3 a_startPosition;
    attribute vec3 a_endPosition;
    varying float v_lifetime;
    void main()
    {
        if (u_time <= a_lifetime)
        {
            gl_Position.xyz = a_startPosition + (u_time * a_endPosition);
            gl_Position.xyz += u_centerPosition;
            gl_Position.w = 1.0;
        }
        else
        {
            gl_Position = vec4(-1000, -1000, 0, 0);
        }
        v_lifetime = 1.0 - (u_time / a_lifetime);
        v_lifetime = clamp(v_lifetime, 0.0, 1.0);
        gl_PointSize = (v_lifetime * v_lifetime) * 40.0;
    })";
    
            constexpr char kFS[] = R"(precision mediump float;
    uniform vec4 u_color;
    varying float v_lifetime;
    uniform sampler2D s_texture;
    void main()
    {
        vec4 texColor;
        texColor = texture2D(s_texture, gl_PointCoord);
        gl_FragColor = vec4(u_color) * texColor;
        gl_FragColor.a *= v_lifetime;
    })";
    
            mProgram = CompileProgram(kVS, kFS);
            if (!mProgram)
            {
                return false;
            }
    
            // Get the attribute locations
            mLifetimeLoc      = glGetAttribLocation(mProgram, "a_lifetime");
            mStartPositionLoc = glGetAttribLocation(mProgram, "a_startPosition");
            mEndPositionLoc   = glGetAttribLocation(mProgram, "a_endPosition");
    
            // Get the uniform locations
            mTimeLoc           = glGetUniformLocation(mProgram, "u_time");
            mCenterPositionLoc = glGetUniformLocation(mProgram, "u_centerPosition");
            mColorLoc          = glGetUniformLocation(mProgram, "u_color");
            mSamplerLoc        = glGetUniformLocation(mProgram, "s_texture");
    
            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    
            // Fill in particle data array
            for (size_t i = 0; i < mParticleCount; i++)
            {
                mParticles[i].lifetime = mRNG.randomFloatBetween(0.0f, 1.0f);
    
                float endAngle                = mRNG.randomFloatBetween(0, 2.0f * float(M_PI));
                float endRadius               = mRNG.randomFloatBetween(0.0f, 2.0f);
                mParticles[i].endPosition.x() = sinf(endAngle) * endRadius;
                mParticles[i].endPosition.y() = cosf(endAngle) * endRadius;
                mParticles[i].endPosition.z() = 0.0f;
    
                float startAngle                = mRNG.randomFloatBetween(0, 2.0f * float(M_PI));
                float startRadius               = mRNG.randomFloatBetween(0.0f, 0.25f);
                mParticles[i].startPosition.x() = sinf(startAngle) * startRadius;
                mParticles[i].startPosition.y() = cosf(startAngle) * startRadius;
                mParticles[i].startPosition.z() = 0.0f;
            }
    
            mParticleTime = 1.0f;
    
            std::stringstream smokeStr;
            smokeStr << angle::GetExecutableDirectory() << "/smoke.tga";
    
            TGAImage img;
            if (!LoadTGAImageFromFile(smokeStr.str(), &img))
            {
                return false;
            }
            mTextureID = LoadTextureFromTGAImage(img);
            if (!mTextureID)
            {
                return false;
            }
    
            return true;
        }
    
        void destroy() override { glDeleteProgram(mProgram); }
    
        void step(float dt, double totalTime) override
        {
            // Use the program object
            glUseProgram(mProgram);
    
            mParticleTime += dt;
            if (mParticleTime >= 1.0f)
            {
                mParticleTime = 0.0f;
    
                // Pick a new start location and color
                Vector3 centerPos(mRNG.randomFloatBetween(-0.5f, 0.5f),
                                  mRNG.randomFloatBetween(-0.5f, 0.5f),
                                  mRNG.randomFloatBetween(-0.5f, 0.5f));
                glUniform3fv(mCenterPositionLoc, 1, centerPos.data());
    
                // Random color
                Vector4 color(mRNG.randomFloatBetween(0.0f, 1.0f), mRNG.randomFloatBetween(0.0f, 1.0f),
                              mRNG.randomFloatBetween(0.0f, 1.0f), 0.5f);
                glUniform4fv(mColorLoc, 1, color.data());
            }
    
            // Load uniform time variable
            glUniform1f(mTimeLoc, mParticleTime);
        }
    
        void draw() override
        {
            // Set the viewport
            glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
    
            // Clear the color buffer
            glClear(GL_COLOR_BUFFER_BIT);
    
            // Use the program object
            glUseProgram(mProgram);
    
            // Load the vertex attributes
            glVertexAttribPointer(mLifetimeLoc, 1, GL_FLOAT, GL_FALSE, sizeof(Particle),
                                  &mParticles[0].lifetime);
            glVertexAttribPointer(mEndPositionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Particle),
                                  &mParticles[0].endPosition);
            glVertexAttribPointer(mStartPositionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Particle),
                                  &mParticles[0].startPosition);
    
            glEnableVertexAttribArray(mLifetimeLoc);
            glEnableVertexAttribArray(mEndPositionLoc);
            glEnableVertexAttribArray(mStartPositionLoc);
    
            // Blend particles
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    
            // Bind the texture
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, mTextureID);
    
            // Set the sampler texture unit to 0
            glUniform1i(mSamplerLoc, 0);
    
            glDrawArrays(GL_POINTS, 0, mParticleCount);
        }
    
      private:
        // Handle to a program object
        GLuint mProgram;
    
        // Attribute locations
        GLint mLifetimeLoc;
        GLint mStartPositionLoc;
        GLint mEndPositionLoc;
    
        // Uniform location
        GLint mTimeLoc;
        GLint mColorLoc;
        GLint mCenterPositionLoc;
        GLint mSamplerLoc;
    
        // Texture handle
        GLuint mTextureID;
    
        // Particle vertex data
        struct Particle
        {
            float lifetime;
            Vector3 startPosition;
            Vector3 endPosition;
        };
        static const size_t mParticleCount = 1024;
        std::array<Particle, mParticleCount> mParticles;
        float mParticleTime;
        RNG mRNG;
    };
    
    int main(int argc, char **argv)
    {
        ParticleSystemSample app(argc, argv);
        return app.run();
    }