Edit

kc3-lang/SDL/Xcode-iOS/Demos/src/fireworks.c

Branch :

  • Show log

    Commit

  • Author : Philipp Wiesemann
    Date : 2017-04-09 23:00:26
    Hash : 37b49e63
    Message : ios: Fixed compiler warnings about unused variables in demo.

  • Xcode-iOS/Demos/src/fireworks.c
  • /*
     *  fireworks.c
     *  written by Holmes Futrell
     *  use however you want
     */
    
    #include "SDL.h"
    #include "SDL_opengles.h"
    #include "common.h"
    #include <math.h>
    #include <time.h>
    
    #define ACCEL 0.0001f           /* acceleration due to gravity, units in pixels per millesecond squared */
    #define WIND_RESISTANCE 0.00005f        /* acceleration per unit velocity due to wind resistance */
    #define MAX_PARTICLES 2000      /* maximum number of particles displayed at once */
    
    static GLuint particleTextureID;        /* OpenGL particle texture id */
    static SDL_bool pointSizeExtensionSupported;    /* is GL_OES_point_size_array supported ? */
    static float pointSizeScale;
    /*
        used to describe what type of particle a given struct particle is.
        emitter - this particle flies up, shooting off trail particles, then finally explodes into dust particles.
        trail   - shoots off, following emitter particle
        dust    - radiates outwards from emitter explosion
    */
    enum particleType
    {
        emitter = 0,
        trail,
        dust
    };
    /*
        struct particle is used to describe each particle displayed on screen
    */
    struct particle
    {
        GLfloat x;                  /* x position of particle */
        GLfloat y;                  /* y position of particle */
        GLubyte color[4];           /* rgba color of particle */
        GLfloat size;               /* size of particle in pixels */
        GLfloat xvel;               /* x velocity of particle in pixels per milesecond */
        GLfloat yvel;               /* y velocity of particle in pixels per millescond */
        int isActive;               /* if not active, then particle is overwritten */
        enum particleType type;     /* see enum particleType */
    } particles[MAX_PARTICLES];     /* this array holds all our particles */
    
    static int num_active_particles;        /* how many members of the particle array are actually being drawn / animated? */
    static int screen_w, screen_h;
    
    /* function declarations */
    void spawnTrailFromEmitter(struct particle *emitter);
    void spawnEmitterParticle(GLfloat x, GLfloat y);
    void explodeEmitter(struct particle *emitter);
    void initializeParticles(void);
    void initializeTexture();
    int nextPowerOfTwo(int x);
    void drawParticles();
    void stepParticles(double deltaTime);
    
    /*  helper function (used in texture loading)
        returns next power of two greater than or equal to x
    */
    int
    nextPowerOfTwo(int x)
    {
        int val = 1;
        while (val < x) {
            val *= 2;
        }
        return val;
    }
    
    /*
        steps each active particle by timestep deltaTime
    */
    void
    stepParticles(double deltaTime)
    {
        float deltaMilliseconds = deltaTime * 1000;
        int i;
        struct particle *slot = particles;
        struct particle *curr = particles;
        for (i = 0; i < num_active_particles; i++) {
            /* is the particle actually active, or is it marked for deletion? */
            if (curr->isActive) {
                /* is the particle off the screen? */
                if (curr->y > screen_h)
                    curr->isActive = 0;
                else if (curr->y < 0)
                    curr->isActive = 0;
                if (curr->x > screen_w)
                    curr->isActive = 0;
                else if (curr->x < 0)
                    curr->isActive = 0;
    
                /* step velocity, then step position */
                curr->yvel += ACCEL * deltaMilliseconds;
                curr->xvel += 0.0f;
                curr->y += curr->yvel * deltaMilliseconds;
                curr->x += curr->xvel * deltaMilliseconds;
    
                /* particle behavior */
                if (curr->type == emitter) {
                    /* if we're an emitter, spawn a trail */
                    spawnTrailFromEmitter(curr);
                    /* if we've reached our peak, explode */
                    if (curr->yvel > 0.0) {
                        explodeEmitter(curr);
                    }
                } else {
                    float speed =
                        sqrt(curr->xvel * curr->xvel + curr->yvel * curr->yvel);
                    /*      if wind resistance is not powerful enough to stop us completely,
                       then apply winde resistance, otherwise just stop us completely */
                    if (WIND_RESISTANCE * deltaMilliseconds < speed) {
                        float normx = curr->xvel / speed;
                        float normy = curr->yvel / speed;
                        curr->xvel -=
                            normx * WIND_RESISTANCE * deltaMilliseconds;
                        curr->yvel -=
                            normy * WIND_RESISTANCE * deltaMilliseconds;
                    } else {
                        curr->xvel = curr->yvel = 0;        /* stop particle */
                    }
    
                    if (curr->color[3] <= deltaMilliseconds * 0.1275f) {
                        /* if this next step will cause us to fade out completely
                           then just mark for deletion */
                        curr->isActive = 0;
                    } else {
                        /* otherwise, let's fade a bit more */
                        curr->color[3] -= deltaMilliseconds * 0.1275f;
                    }
    
                    /* if we're a dust particle, shrink our size */
                    if (curr->type == dust)
                        curr->size -= deltaMilliseconds * 0.010f;
    
                }
    
                /* if we're still active, pack ourselves in the array next
                   to the last active guy (pack the array tightly) */
                if (curr->isActive)
                    *(slot++) = *curr;
            }                       /* endif (curr->isActive) */
            curr++;
        }
        /* the number of active particles is computed as the difference between
           old number of active particles, where slot points, and the
           new size of the array, where particles points */
        num_active_particles = (int) (slot - particles);
    }
    
    /*
        This draws all the particles shown on screen
    */
    void
    drawParticles()
    {
    
        /* draw the background */
        glClear(GL_COLOR_BUFFER_BIT);
    
        /* set up the position and color pointers */
        glVertexPointer(2, GL_FLOAT, sizeof(struct particle), particles);
        glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(struct particle),
                       particles[0].color);
    
        if (pointSizeExtensionSupported) {
            /* pass in our array of point sizes */
            glPointSizePointerOES(GL_FLOAT, sizeof(struct particle),
                                  &(particles[0].size));
        }
    
        /* draw our particles! */
        glDrawArrays(GL_POINTS, 0, num_active_particles);
    
    }
    
    /*
        This causes an emitter to explode in a circular bloom of dust particles
    */
    void
    explodeEmitter(struct particle *emitter)
    {
        /* first off, we're done with this particle, so turn active off */
        emitter->isActive = 0;
        int i;
        for (i = 0; i < 200; i++) {
    
            if (num_active_particles >= MAX_PARTICLES)
                return;
    
            /* come up with a random angle and speed for new particle */
            float theta = randomFloat(0, 2.0f * 3.141592);
            float exponent = 3.0f;
            float speed = randomFloat(0.00, powf(0.17, exponent));
            speed = powf(speed, 1.0f / exponent);
    
            /* select the particle at the end of our array */
            struct particle *p = &particles[num_active_particles];
    
            /* set the particles properties */
            p->xvel = speed * cos(theta);
            p->yvel = speed * sin(theta);
            p->x = emitter->x + emitter->xvel;
            p->y = emitter->y + emitter->yvel;
            p->isActive = 1;
            p->type = dust;
            p->size = 15 * pointSizeScale;
            /* inherit emitter's color */
            p->color[0] = emitter->color[0];
            p->color[1] = emitter->color[1];
            p->color[2] = emitter->color[2];
            p->color[3] = 255;
            /* our array has expanded at the end */
            num_active_particles++;
        }
    
    }
    
    /*
        This spawns a trail particle from an emitter
    */
    void
    spawnTrailFromEmitter(struct particle *emitter)
    {
    
        if (num_active_particles >= MAX_PARTICLES)
            return;
    
        /* select the particle at the slot at the end of our array */
        struct particle *p = &particles[num_active_particles];
    
        /* set position and velocity to roughly that of the emitter */
        p->x = emitter->x + randomFloat(-3.0, 3.0);
        p->y = emitter->y + emitter->size / 2.0f;
        p->xvel = emitter->xvel + randomFloat(-0.005, 0.005);
        p->yvel = emitter->yvel + 0.1;
    
        /* set the color to a random-ish orangy type color */
        p->color[0] = (0.8f + randomFloat(-0.1, 0.0)) * 255;
        p->color[1] = (0.4f + randomFloat(-0.1, 0.1)) * 255;
        p->color[2] = (0.0f + randomFloat(0.0, 0.2)) * 255;
        p->color[3] = (0.7f) * 255;
    
        /* set other attributes */
        p->size = 10 * pointSizeScale;
        p->type = trail;
        p->isActive = 1;
    
        /* our array has expanded at the end */
        num_active_particles++;
    
    }
    
    /*
        spawns a new emitter particle at the bottom of the screen
        destined for the point (x,y).
    */
    void
    spawnEmitterParticle(GLfloat x, GLfloat y)
    {
    
        if (num_active_particles >= MAX_PARTICLES)
            return;
    
        /* find particle at endpoint of array */
        struct particle *p = &particles[num_active_particles];
    
        /* set the color randomly */
        switch (rand() % 4) {
        case 0:
            p->color[0] = 255;
            p->color[1] = 100;
            p->color[2] = 100;
            break;
        case 1:
            p->color[0] = 100;
            p->color[1] = 255;
            p->color[2] = 100;
            break;
        case 2:
            p->color[0] = 100;
            p->color[1] = 100;
            p->color[2] = 255;
            break;
        case 3:
            p->color[0] = 255;
            p->color[1] = 150;
            p->color[2] = 50;
            break;
        }
        p->color[3] = 255;
        /* set position to (x, screen_h) */
        p->x = x;
        p->y = screen_h;
        /* set velocity so that terminal point is (x,y) */
        p->xvel = 0;
        p->yvel = -sqrt(2 * ACCEL * (screen_h - y));
        /* set other attributes */
        p->size = 10 * pointSizeScale;
        p->type = emitter;
        p->isActive = 1;
        /* our array has expanded at the end */
        num_active_particles++;
    }
    
    /* just sets the endpoint of the particle array to element zero */
    void
    initializeParticles(void)
    {
        num_active_particles = 0;
    }
    
    /*
        loads the particle texture
     */
    void
    initializeTexture()
    {
    
        int bpp;                    /* texture bits per pixel */
        Uint32 Rmask, Gmask, Bmask, Amask;  /* masks for pixel format passed into OpenGL */
        SDL_Surface *bmp_surface;   /* the bmp is loaded here */
        SDL_Surface *bmp_surface_rgba8888;  /* this serves as a destination to convert the BMP
                                               to format passed into OpenGL */
    
        bmp_surface = SDL_LoadBMP("stroke.bmp");
        if (bmp_surface == NULL) {
            fatalError("could not load stroke.bmp");
        }
    
        /* Grab info about format that will be passed into OpenGL */
        SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &Rmask, &Gmask,
                                   &Bmask, &Amask);
        /* Create surface that will hold pixels passed into OpenGL */
        bmp_surface_rgba8888 =
            SDL_CreateRGBSurface(0, bmp_surface->w, bmp_surface->h, bpp, Rmask,
                                 Gmask, Bmask, Amask);
        /* Blit to this surface, effectively converting the format */
        SDL_BlitSurface(bmp_surface, NULL, bmp_surface_rgba8888, NULL);
    
        glGenTextures(1, &particleTextureID);
        glBindTexture(GL_TEXTURE_2D, particleTextureID);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                     nextPowerOfTwo(bmp_surface->w),
                     nextPowerOfTwo(bmp_surface->h),
                     0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        /* this is where we actually pass in the pixel data */
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmp_surface->w, bmp_surface->h, 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, bmp_surface_rgba8888->pixels);
    
        /* free bmp surface and converted bmp surface */
        SDL_FreeSurface(bmp_surface);
        SDL_FreeSurface(bmp_surface_rgba8888);
    
    }
    
    int
    main(int argc, char *argv[])
    {
        SDL_Window *window;         /* main window */
        SDL_GLContext context;
        int drawableW, drawableH;
        int done;                   /* should we clean up and exit? */
    
        /* initialize SDL */
        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
            fatalError("Could not initialize SDL");
        }
        /* seed the random number generator */
        srand(time(NULL));
        /*
           request some OpenGL parameters
           that may speed drawing
         */
        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
        SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
        SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
        SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
    
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    
        /* create main window and renderer */
        window = SDL_CreateWindow(NULL, 0, 0, 320, 480,
                                    SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALLOW_HIGHDPI);
        context = SDL_GL_CreateContext(window);
    
        /* The window size and drawable size may be different when highdpi is enabled,
         * due to the increased pixel density of the drawable. */
        SDL_GetWindowSize(window, &screen_w, &screen_h);
        SDL_GL_GetDrawableSize(window, &drawableW, &drawableH);
    
        /* In OpenGL, point sizes are always in pixels. We don't want them looking
         * tiny on a retina screen. */
        pointSizeScale = (float) drawableH / (float) screen_h;
    
        /* load the particle texture */
        initializeTexture();
    
        /*      check if GL_POINT_SIZE_ARRAY_OES is supported
           this is used to give each particle its own size
         */
        pointSizeExtensionSupported =
            SDL_GL_ExtensionSupported("GL_OES_point_size_array");
    
        /* set up some OpenGL state */
        glDisable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    
        glViewport(0, 0, drawableW, drawableH);
    
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrthof((GLfloat) 0,
                 (GLfloat) screen_w,
                 (GLfloat) screen_h,
                 (GLfloat) 0, 0.0, 1.0);
    
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
    
        glEnable(GL_POINT_SPRITE_OES);
        glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1);
    
        if (pointSizeExtensionSupported) {
            /* we use this to set the sizes of all the particles */
            glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
        } else {
            /* if extension not available then all particles have size 10 */
            glPointSize(10 * pointSizeScale);
        }
    
        done = 0;
        /* enter main loop */
        while (!done) {
            SDL_Event event;
            double deltaTime = updateDeltaTime();
            while (SDL_PollEvent(&event)) {
                if (event.type == SDL_QUIT) {
                    done = 1;
                }
                if (event.type == SDL_MOUSEBUTTONDOWN) {
                    int x, y;
                    SDL_GetMouseState(&x, &y);
                    spawnEmitterParticle(x, y);
                }
            }
            stepParticles(deltaTime);
            drawParticles();
            SDL_GL_SwapWindow(window);
            SDL_Delay(1);
        }
    
        /* delete textures */
        glDeleteTextures(1, &particleTextureID);
        /* shutdown SDL */
        SDL_Quit();
    
        return 0;
    }