<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>vendor/Chipmunk-4.1.0/CMakeLists.txt</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/CMakeLists.txt</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo1.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo2.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo3.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo4.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo5.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo6.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo7.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/Demo8.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/build.sh</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/Demo/main.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/LICENSE.txt</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/Chipmunk4MSVC2k3.ncb</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/Chipmunk4MSVC2k3.sln</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/Chipmunk4MSVC2k3.suo</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/Chipmunk4MSVC2k3/ChipmunkMSVC.vcproj</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/glut.def</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/glut.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/glut32.dll</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/MSVCSolution/glut32.lib</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/README.txt</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/docsrc/chipmunk-docs.textile</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/docsrc/doc_dummy.rb</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/docsrc/makedocs.rb</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/macosx/Chipmunk.xcodeproj/project.pbxproj</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/macosx/main-Info.plist</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/extconf.rb</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_chipmunk.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_chipmunk.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_cpBB.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_cpBody.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_cpJoint.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_cpShape.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_cpSpace.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/ruby/rb_cpVect.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/CMakeLists.txt</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/chipmunk.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/chipmunk.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpArbiter.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpArbiter.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpArray.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpArray.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpBB.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpBB.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpBody.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpBody.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpCollision.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpCollision.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpHashSet.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpHashSet.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpJoint.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpJoint.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpPolyShape.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpPolyShape.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpShape.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpShape.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpSpace.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpSpace.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpSpaceHash.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpSpaceHash.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpVect.c</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/cpVect.h</filename>
    </added>
    <added>
      <filename>vendor/Chipmunk-4.1.0/src/prime.h</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -56,6 +56,18 @@ rescue LoadError
   exit
 end
 
+begin
+  require 'chipmunk'
+rescue LoadError
+  puts &quot;Missing Chipmunk C extension.&quot;
+  puts &quot;Ubuntu:&quot;
+  puts &quot;  cd vendor/Chipmunk-4.1.0/ruby&quot;
+  puts &quot;  ruby extconf.rb&quot;
+  puts &quot;  sudo make install&quot;
+  puts &quot;  cd ../../../&quot;
+  exit
+end
+
 $:.unshift(File.dirname(__FILE__)) # this should be obsolete once its a gem
 
 # load our libraries</diff>
      <filename>lib/gl_tail.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,9 +6,10 @@
 
 class Activity
   attr_accessor :x, :y, :z, :wx, :wy, :wz, :xi, :yi, :zi
-  attr_accessor :message, :color, :size, :type
+  attr_accessor :message, :color, :size, :type, :body, :shape, :gl_list
 
   def initialize(message, x, y, z, color, size, type = 0)
+    @shape = @body = nil
     @message = message
     @x, @y, @z = x, y, z
 #    @xi, @yi, @zi = 0.012 + (rand(100)/100.0 ) * 0.0012 , 0.002 + (rand(1000)/1000.0 ) * 0.002, 0
@@ -26,88 +27,83 @@ class Activity
     @type  = type
 
     @rx, @ry, @rz = rand(360), rand(360), 0
+    @gl_list     = nil
+    @text_list   = nil
   end
 
   def render(engine)
-    if @type != 5
-      if engine.screen.wanted_fps == 0
+
+    @screen_width  ||= engine.screen.window_width * engine.screen.aspect
+    @screen_height ||= engine.screen.window_height
+    @top ||= engine.screen.top
+
+    unless @body
+      if @type != 5
         @x += @xi
         @y += @yi
         @yi = @yi - 0.00008
-      else
-        @fps_mod ||= (60.0 / engine.screen.wanted_fps)
-        @x += @xi * @fps_mod
-        @y += @yi * @fps_mod
-        @yi = @yi - 0.00008 * @fps_mod
-      end
 
 #      @yi = @yi * 1.01
 #      @xi = @xi * 0.9995
 
-      if @y - @size/2 &lt; -engine.screen.top
-        @y = -engine.screen.top + @size/2
-        @yi = -@yi * 0.7
-        @x = 30.0 if(@type == 2 || (engine.screen.bounce.nil? || engine.screen.bounce == false ) )
-      end
-    else
-      dy = @wy - @y
-      if dy.abs &lt; 0.001
-        @y = @wy
+#        if @y - @size/2 &lt; -@top
+#          @y = -@top + @size/2
+#          @yi = -@yi * 0.7
+#        end
       else
-        @y += dy / 20
-      end
+        dy = @wy - @y
+        if dy.abs &lt; 0.001
+          @y = @wy
+        else
+          @y += dy / 20
+        end
+        
+        dx = @wx - @x
+        if dx.abs &lt; 0.001
+          @x = @wx
+        else
+          @x += dx / 20
+        end
 
-      dx = @wx - @x
-      if dx.abs &lt; 0.001
-        @x = @wx
-      else
-        @x += dx / 20
-      end
+        if @x == @wx
+          @x = 20.0
+        end
 
-      if @x == @wx
-        @x = 20.0
       end
-
-    end
+    else 
+      p = body.p
+      @x = p.x / @screen_width
+      @y = p.y / @screen_height
+    end 
 
     glPushMatrix()
     glColor(@color)
 
     if @type == 0 || @type == 5
-      glTranslate(@x, @y, @z)
-      if engine.screen.mode == 1
-        glRotatef(@rx, 1.0, 0.0, 0.0)
-        glRotatef(@ry, 0.0, 1.0, 0.0)
-        @rx += 2
-        @ry += 1
-        unless BlobStore.has(@size)
-          list = glGenLists(1)
-          glNewList(list, GL_COMPILE)
-
-          glBegin(GL_QUADS)
-          glVertex3f(-@size,  @size, 0)
-          glVertex3f( @size,  @size, 0)
-          glVertex3f( @size, -@size, 0)
-          glVertex3f(-@size, -@size, 0)
+      if @gl_list.nil?
+        @gl_list = BlobStore.get((@size * 1000).to_i)
+        if @gl_list.nil?
+          @gl_list = glGenLists(1)
+          glNewList(@gl_list, GL_COMPILE)
+          glEnable(GL_LINE_SMOOTH)
+          glBegin(GL_LINE_STRIP)
+          r = @size
+
+          angle = 0.0
+          while angle &lt; 6.28318530717959 do
+            glVertex3f(r * Math::sin(angle), r * Math::cos(angle), 0.0)
+            angle += 0.392699081698724
+          end 
+          glVertex3f(0, r, 0.0)
           glEnd
+          glDisable(GL_LINE_SMOOTH);
 
           glEndList()
-          BlobStore.put(@size,list)
+          BlobStore.put((@size * 1000).to_i, @gl_list)
         end
-      else
-        unless BlobStore.has(@size)
-
-          list = glGenLists(1)
-          glNewList(list, GL_COMPILE)
-
-          tmp = 10 + 10 * ((@size-engine.screen.min_blob_size)/engine.screen.max_blob_size)
-          glutSolidSphere(@size, tmp, 2)
-
-          glEndList()
-          BlobStore.put(@size,list)
-        end
-      end
-      glCallList(BlobStore.get(@size))
+      end 
+      glTranslate(@x,@y,@z)
+      glCallList(@gl_list)
     elsif @type == 1
       glTranslate(@x, @y, @z)
       glRotatef(@rx, 1.0, 0.0, 0.0)
@@ -134,9 +130,30 @@ class Activity
       glTranslate(@x, @y, @z)
       glRasterPos(0.0, 0.0)
 
-      engine.render_string(@message)
+      @text_list ||= engine.render_string(@message, false)
+
+      glCallList(@text_list)
+
     end
 
     glPopMatrix()
   end
+
+  def free_vertex_lists
+    unless @text_list.nil?
+      glDeleteLists(@text_list, 1)
+      @text_list = nil
+    end 
+  end 
+
+  def reshape
+    free_vertex_lists
+    
+    @gl_list = nil
+    @screen_width  = nil
+    @screen_height = nil
+    @top = nil
+  end 
+
+
 end</diff>
      <filename>lib/gl_tail/activity.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,9 @@
 class BlobStore
   @store = { }
   @used_keys = { }
+
+  @last_prune = nil
+
   def self.get(key)
     @used_keys[key] = true
     return @store[key]
@@ -23,14 +26,22 @@ class BlobStore
     @used_keys.size
   end
 
-  def self.prune
-    @store.keys.each do |k|
-      unless @used_keys.include? k
-        glDeleteLists(@store[k], 1)
-        @store.delete k
+  def self.mark(key)
+    @used_keys[key] = true
+  end 
+
+  def self.prune(since)
+    @last_prune ||= since
+    if since - @last_prune &gt;= 60000
+      @store.keys.each do |k|
+        unless @used_keys.include? k
+          glDeleteLists(@store[k], 1)
+          @store.delete k
+        end
       end
+      @used_keys = { }
+      @last_prune = since
     end
-    @used_keys = { }
   end
 
   def self.empty</diff>
      <filename>lib/gl_tail/blob_store.rb</filename>
    </modified>
    <modified>
      <diff>@@ -35,7 +35,7 @@ class Block
     @elements = { }
     @bottom_position = -@config.screen.top
     @max_rate = 1.0/599
-	 @last_clean = 0
+    @last_clean = 0
 
     @sorted = []
   end
@@ -80,7 +80,6 @@ class Block
     return num if @elements.size == 0 || @sorted.size == 0
 
     @header.wy = top - (num * line_size)
-    #    @header.y = @header.wy if @header.y == -$CONFIG.top
     @header.render(engine)
     num += 1
 
@@ -154,6 +153,7 @@ class Block
     for e in deleted do 
       @elements.delete(e.name)
       @sorted.delete(e)
+      e.free_vertex_lists
     end
 
     return if @sorted.size == 0
@@ -231,4 +231,11 @@ class Block
     @sorted = @ordered
   end
 
+  def reshape
+    @header.reshape
+    @sorted.each do |e|
+      e.reshape
+    end 
+  end 
+
 end</diff>
      <filename>lib/gl_tail/block.rb</filename>
    </modified>
    <modified>
      <diff>@@ -37,7 +37,10 @@ class Element
     @color = color || [1.0, 1.0, 1.0, 1.0]
     @type = (@block.activity_type == &quot;blobs&quot; ? :blobs : :bars)
     @bar_color ||= @color.dup
-
+    @text_list   = nil
+    @number_list = nil
+    @last_text   = nil
+    @last_number = nil
   end
 
   def add_activity(message, color, size,  type, real_size)
@@ -96,37 +99,45 @@ class Element
     @color ||= [1.0, 1.0, 1.0, 1.0]
 
     t = glutGet(GLUT_ELAPSED_TIME)
-    while( (@queue.size &gt; 0) &amp;&amp; (@last_time &lt; t ) )
-
-      @last_time += @step
-      item = @queue.pop
-      url = item.message
-      color = item.color
-      size = item.size
-      type = item.type
-
-      if type == 2
-        @activities.push Activity.new(url, 0.0 - (0.008 * url.length), engine.screen.top, 0.0, color, size, type)
-      end
-    end
-
-    @activities.each do |a|
-      if a.x &gt; 1.0 || a.x &lt; -1.0 || a.y &lt; -(engine.screen.aspect*1.5)
-        @activities.delete a
+    @queue.clear
+#    while( (item = @queue.pop) &amp;&amp; (@last_time &lt; t ) )
+
+#      @last_time += @step
+#      item = @queue.pop
+
+#    end
+
+    @delete = []
+    cutoff = -(engine.screen.aspect * 1.5)
+    for a in @activities do 
+      if a.x &gt; 1.0 || a.x &lt; -1.0 || a.y &lt; cutoff
+        if a.body 
+          engine.space.remove_body(a.body)
+          engine.space.remove_shape(a.shape)
+          a.free_vertex_lists
+        end 
+        @delete &lt;&lt;  a
       else
         a.wy = @wy + 0.005 if(a.type == 5 &amp;&amp; @wy != a.wy)
         a.render(engine)
         engine.stats[1] += 1
       end
     end
+    
+    @activities = @activities - @delete
 
   end
 
   def render(engine, options = { })
 
+    @is_right ||= @block.is_right
+
+    @block_width ||= @block.width
+    @block_width_times_8 ||= @block_width * 8
+
     # this used to be in the constructor, couldnt leave it there without using globals
-    if not defined? @x
-      @x = (@block.is_right ? @block.alignment : (@block.alignment - (8.0 / (@block.config.screen.window_width / 2.0)) * (@block.width + 8)))
+    if not defined? @x 
+      @x = (@is_right ? @block.alignment : (@block.alignment - (8.0 / (@block.config.screen.window_width / 2.0)) * (@block_width + 8)))
       @y = @start_position
       @z = 0
       @wy = @start_position
@@ -134,9 +145,13 @@ class Element
       @color = @block.color.dup if @color.nil? &amp;&amp; @block.color
       @color ||= [1.0, 1.0, 1.0, 1.0]
       @size = 0.01
+
+
     end
 
-    @wx = @block.is_right ? (@block.alignment - (@block.width+8)*8.0 / (engine.screen.window_width / 2.0)) : @block.alignment
+    if @wx.nil?
+      @wx = @is_right ? (@block.alignment - (@block_width_times_8+64.0) / (engine.screen.window_width / 2.0)) : @block.alignment
+    end 
 
     if(@y == -@block.top)
       @y = @wy
@@ -159,83 +174,73 @@ class Element
     glPushMatrix()
     glTranslate(@x, @y, @z)
 
-
-    if( rate &gt; 0.0 )
-      glBegin(GL_QUADS)
-
-      if @x &gt;= 0
-        y2 = 0.0
-        @x1 = 7*8.0 / (engine.screen.window_width / 2.0)
-        y1 = engine.screen.line_size * 0.9
-        x2 = @x1 + ((@block.width+1) * 8.0 / (engine.screen.window_width / 2.0) ) * (rate / @block.max_rate)
-
-        @x2 ||= @x1
-        d = (@x2 - x2)
-        if d.abs &lt; 0.001
-          @x2 = x2
-        else
-          @x2 -= d / 40
-        end
-        glColor(@bar_color)
-        glVertex3f(@x1, y1, @z)
-        glColor(@bar_color)
-        glVertex3f(@x2, y1, @z)
-        glColor([0.0, 0.0, 0.0, 0.0])
-        glVertex3f(@x2, y2, @z)
-        glColor(@bar_color)
-        glVertex3f(@x1, y2, @z)
-
+    glBegin(GL_QUADS)
+
+    if @x &gt;= 0
+      y2 = 0.0
+      @x1 = 7*8.0 / (engine.screen.window_width / 2.0)
+      y1 = engine.screen.line_size * 0.9
+      x2 = @x1 + ((@block_width_times_8+8.0) / (engine.screen.window_width / 2.0) ) * (rate / @block.max_rate)
+      
+      @x2 ||= @x1
+      d = (@x2 - x2)
+      if d.abs &lt; 0.001
+        @x2 = x2
       else
-        @x2 = (@block.width+1)*8.0 / (engine.screen.window_width / 2.0)
-        y2  = 0.0
-        y1  = engine.screen.line_size * 0.9
-        x1 = ((@block.width * 8.0) / (engine.screen.window_width / 2.0) ) * (1.0 - rate / @block.max_rate)
-
-        @x1 ||= @x2
-        d = (@x1 - x1)
-        if d.abs &lt; 0.001
-          @x1 = x1
-        else
-          @x1 -= d / 20
-        end
-
-        glColor(@bar_color)
-        glVertex3f(@x1, y1, @z)
-        glColor(@bar_color)
-        glVertex3f(@x2, y1, @z)
-        glColor(@bar_color)
-        glVertex3f(@x2, y2, @z)
-        glColor([0.0, 0.0, 0.0, 0.0])
-        glVertex3f(@x1, y2, @z)
-
+        @x2 -= d / 40
       end
-
-
-      glEnd
-
+      glColor(@bar_color)
+      glVertex3f(@x1, y1, @z)
+      glColor(@bar_color)
+      glVertex3f(@x2, y1, @z)
+      glColor([0.0, 0.0, 0.0, 0.0])
+      glVertex3f(@x2, y2, @z)
+      glColor(@bar_color)
+      glVertex3f(@x1, y2, @z)
+    else
+      @x2 = (@block_width_times_8+8) / (engine.screen.window_width / 2.0)
+      y2  = 0.0
+      y1  = engine.screen.line_size * 0.9
+      x1 = ((@block_width_times_8+8) / (engine.screen.window_width / 2.0) ) * (1.0 - rate / @block.max_rate)
+      
+      @x1 ||= @x2
+      d = (@x1 - x1)
+      if d.abs &lt; 0.001
+        @x1 = x1
+      else
+        @x1 -= d / 20
+      end
+      
+      glColor(@bar_color)
+      glVertex3f(@x1, y1, @z)
+      glColor(@bar_color)
+      glVertex3f(@x2, y1, @z)
+      glColor(@bar_color)
+      glVertex3f(@x2, y2, @z)
+      glColor([0.0, 0.0, 0.0, 0.0])
+      glVertex3f(@x1, y2, @z)
+      
     end
-
-
-#    glTranslate(@x, @y, @z)
+    glEnd
 
     glColor( (@queue.size &gt; 0 ? (engine.screen.highlight_color || [1.0, 0.0, 0.0, 1.0]) : @color ) )
 
     case @block.show
     when 0
-      if @rate &lt; 0.0001
-        txt = &quot;    r/m &quot;
+      if @rate == 0
+        txt = &quot;     r/m &quot;
       else
         txt = &quot;#{sprintf(&quot;%8.2f&quot;,@rate * 60)} &quot;
       end
     when 1
       if @total == 0
-        txt = &quot;  total &quot;
+        txt = &quot;   total &quot;
       else
         txt = &quot;#{sprintf(&quot;%8d&quot;,@total)} &quot;
       end
     when 2
       if @average == 0
-        txt = &quot;    avg &quot;
+        txt = &quot;     avg &quot;
       else
         txt = &quot;#{sprintf(&quot;%8.2f&quot;,@average)} &quot;
       end
@@ -244,12 +249,52 @@ class Element
     end
 
     if @x &lt; 0
-      engine.render_string(sprintf(&quot;%#{@block.width}s&quot;, @name.length &gt; @block.width ? @name[-@block.width..-1] : @name), txt)
+      text = sprintf(&quot;%#{@block_width}s&quot;, @name.length &gt; @block_width ? @name[-@block_width..-1] : @name)
+
+      if text != @last_text
+        glDeleteLists(@text_list,1)
+        @text_list = nil
+      end 
+     
+      if txt != @last_number
+        @number_list = nil
+      else 
+        BlobStore.mark(txt)
+      end 
+
+      @text_list ||= engine.render_string(text, false, 1) 
+      @number_list ||= engine.render_string(txt, true, text.length)
+
+      @last_text = text
+      @last_number = txt
+
+      glCallList(@text_list)
+      glCallList(@number_list)
+
     else
-      engine.render_string(txt[1..-1], @name[0..@block.width-1])
+      txt = txt[1..-1]
+      text = @name[0..@block_width-1]
+      if text != @last_text
+        glDeleteLists(@text_list,1)
+        @text_list = nil
+      end 
+
+      if txt != @last_number
+        @number_list = nil
+      else 
+        BlobStore.mark(txt)
+      end 
+
+      @text_list ||= engine.render_string(text, false, txt.length)
+      @number_list ||= engine.render_string(txt, true)
+
+      @last_text = text
+      @last_number = txt
+
+      glCallList(@number_list)
+      glCallList(@text_list)
     end
 
-
     glPopMatrix()
 
     t = glutGet(GLUT_ELAPSED_TIME)
@@ -263,7 +308,9 @@ class Element
       type = item.type
 
       if type == 2
-        @activities.push Activity.new(url, 0.0 - (0.008 * url.length), engine.screen.top, 0.0, color, size, type)
+        a = Activity.new(url, 0.0 - (0.008 * url.length), engine.screen.top, 0.0, color, size, type)
+        @activities.push a
+
       elsif type == 5
         a = Activity.new(url, 0.0, engine.screen.top, 0.0, color, size, type)
         a.wx = @wx
@@ -271,15 +318,45 @@ class Element
         @activities.push a
       elsif type != 4
         if @x &gt;= 0
-          @activities.push Activity.new(url, (@block.alignment - (@block.width+8)*8.0 / (engine.screen.window_width / 2.0)), @y + engine.screen.line_size/2, @z, color, size, type)
+          a =  Activity.new(url, (@block.alignment - (@block_width_times_8+64) / (engine.screen.window_width / 2.0)), @y + engine.screen.line_size/2, @z, color, size, type)
         else
-          @activities.push Activity.new(url, (@block.alignment + (@block.width+8)*8.0 / (engine.screen.window_width / 2.0) ), @y + engine.screen.line_size/2, @z, color, size, type)
+          a =  Activity.new(url, (@block.alignment + (@block_width_times_8+64) / (engine.screen.window_width / 2.0) ), @y + engine.screen.line_size/2, @z, color, size, type)
         end
+        @activities.push a
+
+        bs = (size + 0.0005) * engine.screen.window_width * engine.screen.aspect 
+
+        a.body =  CP::Body.new(0.0001, 0.0001)
+        a.body.m = bs * 5.5
+        a.body.p = CP::Vec2.new(a.x * engine.screen.window_width * engine.screen.aspect, a.y * engine.screen.window_height)
+        if a.x &lt; 0.0 
+          a.body.v = CP::Vec2.new(250,0)
+        else 
+          a.body.v = CP::Vec2.new(-250,0)
+        end 
+        a.shape = CP::Shape::Circle.new(a.body, bs, CP::Vec2.new(0.0, 0.0))
+        a.shape.e = 0.9
+        a.shape.u = 1
+
+        engine.space.add_body(a.body)
+        engine.space.add_shape(a.shape)
       end
     end
 
-    @activities.each do |a|
-      if a.x &gt; 1.0 || a.x &lt; -1.0 || a.y &lt; -(engine.screen.aspect*1.5)
+    @delete = []
+    for a in @activities do
+      if a.body
+        if a.x &gt; 1.0 || a.x &lt; -1.0 || a.y &lt; -(engine.screen.aspect*1.5)
+          engine.space.remove_body(a.body)
+          engine.space.remove_shape(a.shape)
+          @delete &lt;&lt; a
+          a.free_vertex_lists
+        else 
+          a.render(engine)
+          engine.stats[1] += 1
+        end 
+        
+      elsif a.x &gt; 1.0 || a.x &lt; -1.0 || a.y &lt; -(engine.screen.aspect*1.5)
         @activities.delete a
       else
         a.wy = @wy + 0.005 if(a.type == 5 &amp;&amp; @wy != a.wy)
@@ -288,6 +365,8 @@ class Element
       end
     end
 
+    @activities = @activities - @delete
+
     @bar_color[0] = @bar_color[0] + (0.15 - @bar_color[0]) / 100
     @bar_color[1] = @bar_color[1] + (0.15 - @bar_color[1]) / 100
     @bar_color[2] = @bar_color[2] + (0.15 - @bar_color[2]) / 100
@@ -314,4 +393,31 @@ class Element
     b.rate &gt;= self.rate
   end
 
+  def free_vertex_lists
+    unless @text_list.nil?
+      glDeleteLists(@text_list, 1)
+      @text_list = nil
+    end 
+    @number_list = nil
+  end 
+
+  def reshape
+    free_vertex_lists
+
+    @last_text   = nil
+    @last_number = nil
+
+    @is_right = nil
+
+    @block_width = nil 
+    @block_width_times_8 = nil
+
+    @wx = nil
+
+    @activities.each do |a|
+      a.reshape
+    end 
+  end 
+
+
 end</diff>
      <filename>lib/gl_tail/element.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,12 +5,16 @@ include Glut
 module GlTail
   class Engine
 
-    def render_string(left,right = nil)
-      FontStore.render_string(self, left,right)
+    INF = 1.0/0
+
+    attr_accessor :space
+
+    def render_string(text, cache=true, pos=0)
+      FontStore.render_string(self, text, cache, pos)
     end
 
     def screen
-      @config.screen
+      @screen ||= @config.screen
     end
 
     def char_size
@@ -18,11 +22,11 @@ module GlTail
     end
 
     def line_size
-      @config.screen.line_size
+      self.screen.line_size
     end
 
     def highlight_color
-      @config.screen.highlight_color
+      self.screen.highlight_color
     end
 
     def reset_stats
@@ -37,6 +41,8 @@ module GlTail
       @render_time ||= 0
       @t = Time.new
 
+      @space.step(1.0/60.0)
+
       glClear(GL_COLOR_BUFFER_BIT);
       #    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
@@ -50,19 +56,42 @@ module GlTail
 
       glColor([0.15, 0.15, 0.15, 1.0])
       glBegin(GL_QUADS)
-        glNormal3f(1.0, 1.0, 0.0)
+      glNormal3f(1.0, 1.0, 0.0)
+
+      glVertex3f(@left_left, @config.screen.aspect, 0.0)
+      glVertex3f(@left_right, @config.screen.aspect, 0.0)
+      glVertex3f(@left_right, -@config.screen.aspect, 0.0)
+      glVertex3f(@left_left, -@config.screen.aspect, 0.0)
+      
+      glVertex3f(@right_left, @config.screen.aspect, 0.0)
+      glVertex3f(@right_right, @config.screen.aspect, 0.0)
+      glVertex3f(@right_right, -@config.screen.aspect, 0.0)
+      glVertex3f(@right_left, -@config.screen.aspect, 0.0)
 
-        glVertex3f(@left_left, @config.screen.aspect, 0.0)
-        glVertex3f(@left_right, @config.screen.aspect, 0.0)
-        glVertex3f(@left_right, -@config.screen.aspect, 0.0)
-        glVertex3f(@left_left, -@config.screen.aspect, 0.0)
+      glEnd()
 
-        glVertex3f(@right_left, @config.screen.aspect, 0.0)
-        glVertex3f(@right_right, @config.screen.aspect, 0.0)
-        glVertex3f(@right_right, -@config.screen.aspect, 0.0)
-        glVertex3f(@right_left, -@config.screen.aspect, 0.0)
+      if @config.screen.bounce
+        left  = @left_right
+        right = @right_right
+        bottom = (-@config.screen.top)
+        middle = (-@config.screen.top) / 2.0
+        center = 0.1 
+
+        glColor([0.15, 0.15, 0.15, 1.0])
+        glEnable(GL_LINE_SMOOTH)
+        glBegin(GL_LINES)
+        glVertex3f(left, middle, 0.0)
+        glVertex3f(-center, bottom, 0.0)
+
+        glVertex3f(left, middle, 0.0)
+        glVertex3f(-center, bottom, 0.0)
+
+        glVertex3f(right, middle, 0.0)
+        glVertex3f(center, bottom, 0.0)
+        glEnd()
+        glDisable(GL_LINE_SMOOTH)
+      end 
 
-      glEnd()
       glPopMatrix()
 
       @config.blocks.each do |block|
@@ -82,6 +111,7 @@ module GlTail
         @t0, @frames = t, 0
         puts &quot;Elements[#{stats[0]}], Activities[#{stats[1]}], Blobs[#{BlobStore.used}/#{BlobStore.size}]&quot; if $VRB &gt; 0
       end
+
       @render_time = (Time.new - @t)
     end
 
@@ -100,7 +130,7 @@ module GlTail
     end
 
     def timer(value)
-      glutTimerFunc(15, method(:timer).to_proc, 0)
+      glutTimerFunc(14, method(:timer).to_proc, 0)
       #    t = glutGet(GLUT_ELAPSED_TIME)
       glutPostRedisplay()
       glutSwapBuffers()
@@ -117,6 +147,8 @@ module GlTail
       when 32 # Space
         @config.screen.bounce ||= false
         @config.screen.bounce = !@config.screen.bounce
+        puts &quot;Bounce: #{@config.screen.bounce}&quot;
+        reshape(@config.screen.window_width, @config.screen.window_height)
       when 102 #f
         @config.screen.wanted_fps = case @config.screen.wanted_fps
                                     when 0
@@ -135,7 +167,7 @@ module GlTail
                                       0
                                     end
         puts &quot;WANTED_FPS[#{@config.screen.wanted_fps}]&quot;
-      when 98
+      when 98 #v
         @config.screen.mode = 1 - @config.screen.mode.to_i
         BlobStore.empty
       end
@@ -178,6 +210,62 @@ module GlTail
       glTranslate(0.0, 0.0, 0.0)
 
       BlobStore.empty # Flush cached objects to recreate with correct size
+
+      unless defined?(@static_body)
+        puts &quot;Adding static shapes..&quot;
+        @static_body = CP::Body.new(Float::MAX, Float::MAX)
+      end 
+
+      if @config.screen.bounce
+        if @static_shapes &amp;&amp; @static_shapes.size &gt; 0 
+          0.upto(3) do |i|
+            @space.remove_static_shape(@static_shapes[i])
+          end 
+          @static_shapes.clear
+        else 
+          @static_shapes = []
+        end 
+
+        left  = @left_right * @config.screen.window_width * @config.screen.aspect
+        right = @right_right * @config.screen.window_width * @config.screen.aspect
+        bottom = (-@config.screen.top) * @config.screen.window_height
+        middle = (-@config.screen.top) * @config.screen.window_height / 2.0
+        center = 0.1 * @config.screen.window_width * @config.screen.aspect
+
+        shape = CP::Shape::Segment.new(@static_body, CP::Vec2.new(left,middle), CP::Vec2.new(-center,bottom), 3)
+        shape.e = 0.9
+        shape.u = 1
+        @space.add_static_shape(shape)
+        @static_shapes[0] = shape
+      
+        shape = CP::Shape::Segment.new(@static_body, CP::Vec2.new(right,middle), CP::Vec2.new(center,bottom), 3)
+        shape.e = 0.9
+        shape.u = 1
+        @space.add_static_shape(shape)
+        @static_shapes[1] = shape
+        
+        shape = CP::Shape::Segment.new(@static_body, CP::Vec2.new(right,middle), CP::Vec2.new(right,-bottom), 3)
+        shape.e = 0.9
+        shape.u = 1
+        @space.add_static_shape(shape)
+        @static_shapes[2] = shape
+        
+        shape = CP::Shape::Segment.new(@static_body, CP::Vec2.new(left,middle), CP::Vec2.new(left,-bottom), 3)
+        shape.e = 0.9
+        shape.u = 1
+        @space.add_static_shape(shape)
+        @static_shapes[3] = shape
+      elsif @static_shapes &amp;&amp; @static_shapes.size &gt; 0
+        0.upto(3) do |i|
+          @space.remove_static_shape(@static_shapes[i])
+        end 
+        @static_shapes.clear
+      end 
+
+      @config.blocks.each do |block|
+        block.reshape
+      end
+
     end
 
     def visible(vis)
@@ -201,6 +289,11 @@ module GlTail
       @frames = 0
       @t0 = 0
       @left_left = @left_right = @right_left = @right_right = 0.0 # TODO: Why is draw called before these are set by reshape?
+      @space = CP::Space.new
+      @space.damping = 0.89
+      @space.gravity = CP::Vec2.new(0, -85)
+		@space.iterations = 2
+		@space.elastic_iterations = 0
     end
 
     def start
@@ -219,10 +312,10 @@ module GlTail
       glutMouseFunc(method(:mouse).to_proc)
       glutMotionFunc(method(:motion).to_proc)
 
-      glutIdleFunc(method(:idle).to_proc)
-      #    glutTimerFunc(33, method(:timer).to_proc, 0)
+#      glutIdleFunc(method(:idle).to_proc)
+      glutTimerFunc(14, method(:timer).to_proc, 0)
 
-      glLightfv(GL_LIGHT0, GL_POSITION, [5.0, 5.0, 0.0, 0.0])
+#      glLightfv(GL_LIGHT0, GL_POSITION, [5.0, 5.0, 0.0, 0.0])
       glLightfv(GL_LIGHT0, GL_AMBIENT, [0,0,0,1])
 
       glLightModel(GL_LIGHT_MODEL_AMBIENT, [0.1,0.1,0.1,1]);
@@ -230,8 +323,8 @@ module GlTail
 #      glLightModel(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
 
       glDisable(GL_CULL_FACE)
-      glEnable(GL_LIGHTING)
-      glEnable(GL_LIGHT0)
+#      glEnable(GL_LIGHTING)
+#      glEnable(GL_LIGHT0)
       glEnable(GL_TEXTURE_2D)
 #      glShadeModel(GL_FLAT)
       glDisable(GL_DEPTH_TEST)
@@ -263,7 +356,7 @@ module GlTail
         if glutGet(GLUT_ELAPSED_TIME) - @since &gt;= 1000
           @since = glutGet(GLUT_ELAPSED_TIME)
           @config.update
-          BlobStore.prune
+          BlobStore.prune(@since)
         end
       end
 </diff>
      <filename>lib/gl_tail/engine.rb</filename>
    </modified>
    <modified>
      <diff>@@ -135,19 +135,16 @@ class FontStore
   end
 
 
-  def self.render_string(engine, left, right = nil)
-    glPushMatrix
-
-    pos = 0
-
-    list = BlobStore.get(left)
+  def self.render_string(engine, text, cache, pos)
+    list = nil
+    list = BlobStore.get(text) if cache
     if list.nil?
       list = glGenLists(1)
       glNewList(list, GL_COMPILE)
       glEnable(GL_BLEND)
       glBindTexture(GL_TEXTURE_2D, @font_texture)
       glBegin(GL_QUADS)
-      left.each_byte do |c|
+      text.each_byte do |c|
         self.render_char(engine, c, pos) unless c == 32
         pos += 1
       end
@@ -155,35 +152,9 @@ class FontStore
       glBindTexture(GL_TEXTURE_2D, 0)
       glDisable(GL_BLEND)
       glEndList
-      BlobStore.put(left,list)
-    else
-      pos += left.length
+      BlobStore.put(text,list) if cache
     end 
-    glCallList(list)
-
-    unless right.nil?
-      list = BlobStore.get(right)
-      if list.nil?
-        list = glGenLists(1)
-        glNewList(list, GL_COMPILE)
-        glEnable(GL_BLEND)
-        glBindTexture(GL_TEXTURE_2D, @font_texture)
-        glBegin(GL_QUADS)
-        right.each_byte do |c|
-          self.render_char(engine, c, pos)
-          pos += 1
-        end
-        glEnd
-        glBindTexture(GL_TEXTURE_2D, 0)
-        glDisable(GL_BLEND)
-        glEndList
-        BlobStore.put(right,list)
-      end 
-      glCallList(list)
-    end
-    
-#    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
-    glPopMatrix
-  end
+    list
+  end 
 
 end</diff>
      <filename>lib/gl_tail/font_store.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>5de3dc0c7a8f9a1fe9e93430a9b3a21d63be361d</id>
    </parent>
  </parents>
  <author>
    <name>Erlend Simonsen</name>
    <email>mr@fudgie.org</email>
  </author>
  <url>http://github.com/Fudge/gltail/commit/f8fe114f39513f9e963c0853ede68a7c8d344791</url>
  <id>f8fe114f39513f9e963c0853ede68a7c8d344791</id>
  <committed-date>2008-12-15T05:38:40-08:00</committed-date>
  <authored-date>2008-12-15T05:38:40-08:00</authored-date>
  <message>Add Chipmunk Physics

Toggle sloped ground with &lt;space&gt;

- I've also added quite a bit of caching of Vertex Lists locally,
  as well as precalculate some commonly used maths.
- Font rendering should be a bit faster
- Changed from Solid balls, to circles
- Disabled lighting, as that was only used to shade the balls</message>
  <tree>d20a6af4f8e6353c518ae622d7278c05ed58d3c4</tree>
  <committer>
    <name>Erlend Simonsen</name>
    <email>mr@fudgie.org</email>
  </committer>
</commit>
