diff --git a/examples/gl_particle_animation.py b/examples/gl_particle_animation.py
new file mode 100644
index 0000000000000000000000000000000000000000..6cd008b072089fe73efc425ea9074fb4cd67bd83
--- /dev/null
+++ b/examples/gl_particle_animation.py
@@ -0,0 +1,180 @@
+# Visualization of particles with gravity
+# Source: http://enja.org/2010/08/27/adventures-in-opencl-part-2-particles-with-opengl/
+
+import pyopencl as cl # OpenCL - GPU computing interface
+mf = cl.mem_flags
+from pyopencl.tools import get_gl_sharing_context_properties
+from OpenGL.GL import * # OpenGL - GPU rendering interface
+from OpenGL.GLU import * # OpenGL tools (mipmaps, NURBS, perspective projection, shapes)
+from OpenGL.GLUT import * # OpenGL tool to make a visualization window
+from OpenGL.arrays import vbo 
+import numpy # Number tools
+import sys # System tools (path, modules, maxint)
+
+width = 800
+height = 600
+num_particles = 100000
+time_step = .005
+mouse_down = False
+mouse_old = {'x': 0., 'y': 0.}
+rotate = {'x': 0., 'y': 0., 'z': 0.}
+translate = {'x': 0., 'y': 0., 'z': 0.}
+initial_translate = {'x': 0., 'y': 0., 'z': -2.5}
+
+def glut_window():
+    glutInit(sys.argv)
+    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
+    glutInitWindowSize(width, height)
+    glutInitWindowPosition(0, 0)
+    window = glutCreateWindow("Particle Simulation")
+
+    glutDisplayFunc(on_display)  # Called by GLUT every frame
+    glutKeyboardFunc(on_key)
+    glutMouseFunc(on_click)
+    glutMotionFunc(on_mouse_move)
+    glutTimerFunc(10, on_timer, 10)  # Call draw every 30 ms
+
+    glViewport(0, 0, width, height)
+    glMatrixMode(GL_PROJECTION)
+    glLoadIdentity()
+    gluPerspective(60., width / float(height), .1, 1000.)
+
+    return(window)
+
+def initial_buffers(num_particles):
+    np_position = numpy.ndarray((num_particles, 4), dtype=numpy.float32)
+    np_color = numpy.ndarray((num_particles, 4), dtype=numpy.float32)
+    np_velocity = numpy.ndarray((num_particles, 4), dtype=numpy.float32)
+
+    np_position[:,0] = numpy.sin(numpy.arange(0., num_particles) * 2.001 * numpy.pi / num_particles) 
+    np_position[:,0] *= numpy.random.random_sample((num_particles,)) / 3. + .2
+    np_position[:,1] = numpy.cos(numpy.arange(0., num_particles) * 2.001 * numpy.pi / num_particles) 
+    np_position[:,1] *= numpy.random.random_sample((num_particles,)) / 3. + .2
+    np_position[:,2] = 0.
+    np_position[:,3] = 1.
+
+    np_color[:,:] = [1.,1.,1.,1.] # White particles
+
+    np_velocity[:,0] = np_position[:,0] * 2.
+    np_velocity[:,1] = np_position[:,1] * 2.
+    np_velocity[:,2] = 3.
+    np_velocity[:,3] = numpy.random.random_sample((num_particles, ))
+    
+    gl_position = vbo.VBO(data=np_position, usage=GL_DYNAMIC_DRAW, target=GL_ARRAY_BUFFER)
+    gl_position.bind()
+    gl_color = vbo.VBO(data=np_color, usage=GL_DYNAMIC_DRAW, target=GL_ARRAY_BUFFER)
+    gl_color.bind()
+
+    return (np_position, np_velocity, gl_position, gl_color)
+
+def on_timer(t):
+    glutTimerFunc(t, on_timer, t)
+    glutPostRedisplay()
+
+def on_key(*args):
+    if args[0] == '\033' or args[0] == 'q':
+        sys.exit()
+
+def on_click(button, state, x, y):
+    mouse_old['x'] = x
+    mouse_old['y'] = y
+
+def on_mouse_move(x, y):
+    rotate['x'] += (y - mouse_old['y']) * .2
+    rotate['y'] += (x - mouse_old['x']) * .2
+
+    mouse_old['x'] = x
+    mouse_old['y'] = y
+
+def on_display():
+    """Render the particles"""        
+    # Update or particle positions by calling the OpenCL kernel
+    cl.enqueue_acquire_gl_objects(queue, [cl_gl_position, cl_gl_color])
+    kernelargs = (cl_gl_position, cl_gl_color, cl_velocity, cl_start_position, cl_start_velocity, numpy.float32(time_step))
+    program.particle_fountain(queue, (num_particles,), None, *(kernelargs))
+    cl.enqueue_release_gl_objects(queue, [cl_gl_position, cl_gl_color])
+    queue.finish()
+    glFlush()
+
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+    glMatrixMode(GL_MODELVIEW)
+    glLoadIdentity()
+
+    # Handle mouse transformations
+    glTranslatef(initial_translate['x'], initial_translate['y'], initial_translate['z'])
+    glRotatef(rotate['x'], 1, 0, 0)
+    glRotatef(rotate['y'], 0, 1, 0) #we switched around the axis so make this rotate_z
+    glTranslatef(translate['x'], translate['y'], translate['z'])
+    
+    # Render the particles
+    glEnable(GL_POINT_SMOOTH)
+    glPointSize(2)
+    glEnable(GL_BLEND)
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+
+    # Set up the VBOs
+    gl_color.bind()
+    glColorPointer(4, GL_FLOAT, 0, gl_color)
+    gl_position.bind()
+    glVertexPointer(4, GL_FLOAT, 0, gl_position)
+    glEnableClientState(GL_VERTEX_ARRAY)
+    glEnableClientState(GL_COLOR_ARRAY)
+
+    # Draw the VBOs
+    glDrawArrays(GL_POINTS, 0, num_particles)
+
+    glDisableClientState(GL_COLOR_ARRAY)
+    glDisableClientState(GL_VERTEX_ARRAY)
+
+    glDisable(GL_BLEND)
+
+    glutSwapBuffers()
+
+window = glut_window()
+
+(np_position, np_velocity, gl_position, gl_color) = initial_buffers(num_particles)
+
+platform = cl.get_platforms()[0]
+context = cl.Context(properties=[(cl.context_properties.PLATFORM, platform)] + get_gl_sharing_context_properties())  
+queue = cl.CommandQueue(context)
+
+cl_velocity = cl.Buffer(context, mf.COPY_HOST_PTR, hostbuf=np_velocity)
+cl_start_position = cl.Buffer(context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np_position)
+cl_start_velocity = cl.Buffer(context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np_velocity)
+
+cl_gl_position = cl.GLBuffer(context, mf.READ_WRITE, int(gl_position.buffers[0]))
+cl_gl_color = cl.GLBuffer(context, mf.READ_WRITE, int(gl_color.buffers[0]))
+
+kernel = """__kernel void particle_fountain(__global float4* position, 
+                                            __global float4* color, 
+                                            __global float4* velocity, 
+                                            __global float4* start_position, 
+                                            __global float4* start_velocity, 
+                                            float time_step)
+{
+    unsigned int i = get_global_id(0);
+    float4 p = position[i];
+    float4 v = velocity[i];
+    float life = velocity[i].w;
+    life -= time_step;
+    if (life <= 0.f)
+    {
+        p = start_position[i];
+        v = start_velocity[i];
+        life = 1.0f;    
+    }
+
+    v.z -= 9.8f*time_step;
+    p.x += v.x*time_step;
+    p.y += v.y*time_step;
+    p.z += v.z*time_step;
+    v.w = life;
+
+    position[i] = p;
+    velocity[i] = v;
+
+    color[i].w = life; /* Fade points as life decreases */
+}"""
+program = cl.Program(context, kernel).build()
+
+glutMainLoop()
\ No newline at end of file