///
//  Update time-based variables
//
void Update(Example *example, KDfloat32 deltaTime)
{
    UserData *userData = (UserData *)example->userptr;

    userData->time += deltaTime;

    if(userData->time >= 1.0f)
    {
        KDfloat32 centerPos[3];
        KDfloat32 color[4];

        userData->time = 0.0f;

        KDuint8 buffer[6] = {0};
        kdCryptoRandom(buffer, 6);

        // Pick a new start location and color
        centerPos[0] = ((KDfloat32)((buffer[0] * 128) % 10000) / 10000.0f) - 0.5f;
        centerPos[1] = ((KDfloat32)((buffer[1] * 128) % 10000) / 10000.0f) - 0.5f;
        centerPos[2] = ((KDfloat32)((buffer[2] * 128) % 10000) / 10000.0f) - 0.5f;

        glUniform3fv(userData->centerPositionLoc, 1, &centerPos[0]);

        // Random color
        color[0] = ((KDfloat32)((buffer[3] * 128) % 10000) / 20000.0f) + 0.5f;
        color[1] = ((KDfloat32)((buffer[4] * 128) % 10000) / 20000.0f) + 0.5f;
        color[2] = ((KDfloat32)((buffer[5] * 128) % 10000) / 20000.0f) + 0.5f;
        color[3] = 0.5;

        glUniform4fv(userData->colorLoc, 1, &color[0]);
    }

    // Load uniform time variable
    glUniform1f(userData->timeLoc, userData->time);
}
///
// Initialize the shader and program object
//
KDboolean Init(Example *example)
{
    UserData *userData = (UserData *)example->userptr;

    const KDchar *vShaderStr =
        "uniform float u_time;		                            \n"
        "uniform vec3 u_centerPosition;                         \n"
        "attribute float a_lifetime;                            \n"
        "attribute vec3 a_startPosition;                        \n"
        "attribute vec3 a_endPosition;                          \n"
        "varying float v_lifetime;                              \n"
        "void main()                                            \n"
        "{                                                      \n"
        "  if ( u_time <= a_lifetime )                          \n"
        "  {                                                    \n"
        "    gl_Position.xyz = a_startPosition +                \n"
        "                      (u_time * a_endPosition);        \n"
        "    gl_Position.xyz += u_centerPosition;               \n"
        "    gl_Position.w = 1.0;                               \n"
        "  }                                                    \n"
        "  else                                                 \n"
        "     gl_Position = vec4( -1000, -1000, 0, 0 );         \n"
        "  v_lifetime = 1.0 - ( u_time / a_lifetime );          \n"
        "  v_lifetime = clamp ( v_lifetime, 0.0, 1.0 );         \n"
        "  gl_PointSize = ( v_lifetime * v_lifetime ) * 40.0;   \n"
        "}";

    const KDchar *fShaderStr =
        "#ifdef GL_FRAGMENT_PRECISION_HIGH                      \n"
        "   precision highp float;                              \n"
        "#else                                                  \n"
        "   precision mediump float;                            \n"
        "#endif                                                 \n"
        "                                                       \n"
        "uniform vec4 u_color;		                            \n"
        "varying float v_lifetime;                              \n"
        "uniform sampler2D s_texture;                           \n"
        "void main()                                            \n"
        "{                                                      \n"
        "  vec4 texColor;                                       \n"
        "  texColor = texture2D( s_texture, gl_PointCoord );    \n"
        "  gl_FragColor = vec4( u_color ) * texColor;           \n"
        "  gl_FragColor.a *= v_lifetime;                        \n"
        "}                                                      \n";

    // Store the program object
    userData->programObject = exampleCreateProgram(vShaderStr, fShaderStr, KD_TRUE);

    // Use the program object
    glUseProgram(userData->programObject);

    // Get the attribute locations
    userData->lifetimeLoc = glGetAttribLocation(userData->programObject, "a_lifetime");
    userData->startPositionLoc = glGetAttribLocation(userData->programObject, "a_startPosition");
    userData->endPositionLoc = glGetAttribLocation(userData->programObject, "a_endPosition");

    // Get the uniform locations
    userData->timeLoc = glGetUniformLocation(userData->programObject, "u_time");
    userData->centerPositionLoc = glGetUniformLocation(userData->programObject, "u_centerPosition");
    userData->colorLoc = glGetUniformLocation(userData->programObject, "u_color");
    userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // Fill in particle data array
    for(KDint i = 0; i < NUM_PARTICLES; i++)
    {
        GLfloat *particleData = &userData->particleData[i * PARTICLE_SIZE];

        KDuint8 buffer[7] = {0};
        kdCryptoRandom(buffer, 7);

        // Lifetime of particle
        (*particleData++) = ((KDfloat32)((buffer[0] * 128) % 10000) / 10000.0f);

        // End position of particle
        (*particleData++) = ((KDfloat32)((buffer[1] * 128) % 10000) / 5000.0f) - 1.0f;
        (*particleData++) = ((KDfloat32)((buffer[2] * 128) % 10000) / 5000.0f) - 1.0f;
        (*particleData++) = ((KDfloat32)((buffer[3] * 128) % 10000) / 5000.0f) - 1.0f;

        // Start position of particle
        (*particleData++) = ((KDfloat32)((buffer[4] * 128) % 10000) / 40000.0f) - 0.125f;
        (*particleData++) = ((KDfloat32)((buffer[5] * 128) % 10000) / 40000.0f) - 0.125f;
        (*particleData++) = ((KDfloat32)((buffer[6] * 128) % 10000) / 40000.0f) - 0.125f;
    }

    glGenBuffers(1, &userData->vertexObject);
    glBindBuffer(GL_ARRAY_BUFFER, userData->vertexObject);
    glBufferData(GL_ARRAY_BUFFER, NUM_PARTICLES * PARTICLE_SIZE * 4, userData->particleData, GL_STATIC_DRAW);

    // Initialize time to cause reset on first update
    userData->time = 1.0f;

    userData->textureId = exampleLoadTexture("data/smoke.png");
    if(userData->textureId <= 0)
    {
        return KD_FALSE;
    }

    return KD_TRUE;
}
/*!
* \brief	Render the OpenGL ES scene.
* \param	time Current time in milliseconds
* \note	Renders the OpenGL ES scene
*//*-------------------------------------------------------------------*/
void renderGLESScene(unsigned int time)
{

    int width = 0;
    int height = 0;
#if defined(TEST_LOCKSURFACE)
    KDuint16 *fb = KD_NULL;
    int y = 0;
    EGLint pitch = 0;
    EGLint origin = 0;
    EGLint r, g, b;
#else
    /* Time needed for the rotation */
    const KDfloat32 effectTime	= kdFmodf(time / 4000.0f, 360.0f);
#endif

    /* Query the current window surface size from EGL */
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_WIDTH, (EGLint *)&width);
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_HEIGHT, (EGLint *)&height);

#if !defined(TEST_LOCKSURFACE)
    /* Update the GLES state */
    updateOpenGLESState		(width, height);
    glClear 				(GL_COLOR_BUFFER_BIT);

    /* Rotate the world matrix and translate it on the z-axis */
    glMatrixMode			(GL_MODELVIEW);
    glLoadIdentity			();
    glTranslatex			(F2F(0.f), F2F(0.f), F2F(-30.f));
    glRotatex				(F2F((float)(effectTime*29.77f)), F2F(1.0f), F2F(2.0f), F2F(0.0f));
    glRotatex				(F2F((float)(effectTime*22.311f)), F2F(-0.1f), F2F(0.0f), -F2F(5.0f));

    glBindTexture(GL_TEXTURE_2D, GLOBALS->tex);

    /* Set the pointer to the arrays containing the cube vertices, normals 
    and texture coordinates */
    glVertexPointer			(3, GL_BYTE, 0, s_cubeVertices);
    glNormalPointer			(GL_BYTE, 0, s_cubeNormals);
    glTexCoordPointer		(2, GL_BYTE, 0, s_cubeTexCoords);

    /* Draw the cube one face at a time in the same order thay have been defined 
    in the s_cubeVertices array */
    glDrawArrays			(GL_TRIANGLE_STRIP, 0, 4);
    glDrawArrays			(GL_TRIANGLE_STRIP, 4, 4);
    glDrawArrays			(GL_TRIANGLE_STRIP, 8, 4);
    glDrawArrays			(GL_TRIANGLE_STRIP, 12, 4);
    glDrawArrays			(GL_TRIANGLE_STRIP, 16, 4);
    glDrawArrays			(GL_TRIANGLE_STRIP, 20, 4);

#else

    /* Lock the surface and query for the properties */
    eglLockSurfaceKHR(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, KD_NULL);
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_BITMAP_POINTER_KHR, (EGLint *)&fb);
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_BITMAP_PITCH_KHR, &pitch);
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_BITMAP_ORIGIN_KHR, &origin);
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_BITMAP_PIXEL_RED_OFFSET_KHR, &r);
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR, &g);
    eglQuerySurface(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface, EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR, &b);

    /* Fill the surface with random noise */
    for(y = 0; y < height; y++)
    {
        kdCryptoRandom((KDuint8 *)fb, width * 2);
        fb += pitch / 2;
    }

    eglUnlockSurfaceKHR(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface);
#endif

    /* Display the result on the screen */
    eglSwapBuffers			(GLOBALS->eglDisplay, GLOBALS->eglWindowSurface);

}