Ruby Processing

Here is my blog in which I will describe my experiments with ruby-processing, find out more about my fork of ruby-processing at:- https://github.com/monkstone/ruby-processing where I have updated it to processing-2.0 and https://github.com/monkstone/ruby-cf3 for my version of the cfdg DSL (context-free-art)

Friday, 14 June 2013

Alternative install of ruby-processing for ArchLinux

It is possible to install JRuby using pacman on ArchLinux:-

sudo pacman -S jruby
This will install any dependency such as openjdk
You should now build the ruby-processing-1.0.12.gem

rake 
or:-

jruby -S rake 

To install:-

jruby -S gem install ruby-processing-1.0.12.gem 
Currently pacman installs JRuby-1.7.4 which is what we want, but there may be an issue of amd64 installs at runtime with it trying to load libjiffi-1.2.so for other architectures such as arm and i386 the fix is to install the latest jruby-launcher. However this should be installed locally from a downloaded gem (ie in the same way you just installed ruby-processing). You can then run the rp5 script by calling it from jruby:-

jruby -S rp5 run mysketch.rb 
or:-

/opt/jruby/bin/rp5 run mysketch.rb 
or after adding the path to the bin:-

rp5 run mysketch.rb 

It may also be possible to use pacgem to manage gems on ArchLinux, but I haven't tried it, and jruby is probably different anyway.

Wednesday, 5 June 2013

Ditching jruby-complete, what is holding me back?

Well it is only the glsl shader sketches (I think). So something is added by including the jruby-complete.jar classpath in the command line that allows these sketches to run. So one area of experimentation is to try to add similar classpath when firing up ruby-processing using jruby, rather than from java.

-J-cp="${RP5_ROOT}/lib/core/"

Should ensure processing core and jogl/gluegen run-times get included, but something more seems to be required...
Something that enables compiling of glsl shaders?

Useful Bookmarks?

  1. http://www.compoundtheory.com/
  2. https://github.com/markmandel/jruby-lwjgl
  3. http://codeanticode.wordpress.com/tag/glsl/
  4. http://arcsynthesis.org/gltut/ 
Hey radical thought, since jruby-lwgl seems to work really well, time to ditch ruby-processing, and try something new for a bit at least?

Monday, 3 June 2013

Using pure (gem) ruby libraries with ruby-processing

Now you can create your own ruby libraries, and it relatively easy to include them, but what about using external gems? Well essentially what you are looking at is, can the library be used from jruby, if so you can probably use it with ruby-processing? The simplest way is to just to set the GEM_HOME environmental variable

export GEM_HOME=/var/lib/gems/1.9.1 (worked for me on ubuntu linux)

If this doesn't work for you then you could install your gems using jruby.

jruby -S gem install rake (etc...)

But to be extra safe you should probably install ruby-processing the same way

jruby -S gem install ruby-processing


Further belt and braces stuff to run sketches you should probably start ruby-processing from jruby using the --ruby flag

jruby -S rp5 run --jruby sketch.rb

Here is one such sketch
require 'perlin_noise'

attr_reader :md, :points, :p, :n2d

def setup
  size(800, 600)
  @n2d = Perlin::Noise.new 2, :curve => Perlin::Curve::CUBIC
  md = false
  @points = []
  background(255)
  smooth(8)
end

def draw
  if (md)
    500.times do
      points << Point.new(rand(0 ... width), rand(0 ... height))
    end
  end
  noise_detail(8,0)

  (points.size - 1).downto(1) do |i|
    @p = points[i]
    p.update n2d
    if (p.finished)
      points.delete_at(i)
    end
  end
  # puts(points.size)
end

def mousePressed
  @md = true
end

def mouseReleased
  @md = false
end

def keyPressed
  background(255)
  (points.size - 1).downto(1) do |i|
    @p = points[i]
    points.delete_at(i)
  end
end

class Point
  include Processing::Proxy

  MAX_SPEED = 3000000

  attr_reader :finished, :x, :y, :xv, :yv, :width, :height

  def initialize(x = 0, y = 0)
    @x, @y = x, y
    @xv, @yv = 0, 0
    @finished = false
    @width = $app.width
    @height = $app.height
  end

  def update n2d
    stroke(0, 16)
    @xv = cos(n2d[x * 0.01, y * 0.01] * TWO_PI)
    @yv = -sin(n2d[x * 0.01, y * 0.01] * TWO_PI)

    if ((x > width) || (x < 0))
      @finished = true
    end

    if ((y > height) || (y < 0))
      @finished = true
    end

    if (xv > MAX_SPEED)
      @xv = MAX_SPEED
    else
      @xv = -MAX_SPEED if (xv < -MAX_SPEED)
    end

    if (yv>MAX_SPEED)
      @yv = MAX_SPEED
    else
      @yv = -MAX_SPEED if (yv < -MAX_SPEED)
    end

    @x += xv
    @y += yv

    line(x + xv, y + yv, x, y )
  end
end

Note with this sketch you would probably be better off using processing perlin noise

Friday, 31 May 2013

A little offscreen buffer test with ruby-processing-2.0

A little sketch from the processing discussion board, makes me think that I should revive lazydogs mirror sketch for ruby-processing-2.0, now that would be cool.
attr_reader :pg
def setup
  size(200, 200, P2D)
  @pg = create_graphics(100, 100, P3D)
  smooth(8)
end
def draw
  background 50
  pg.begin_draw
  pg.background 150
  pg.stroke 255
  pg.stroke_weight 3
  pg.translate(50, 50, 0)
  pg.rotate_y 0.45
  pg.no_fill
  pg.box(40)
  pg.end_draw
  image(pg, width / 2 - 50, height / 2 - 50)
end

Wednesday, 22 May 2013

Precast to a java object or use an alias method in ruby-processing (for overloaded java methods)


# alias_background.rb 
# 

class Java::ProcessingCore::PApplet
  java_alias :int_background, :background, [Java::int]
  java_alias :image_background, :background, [Java::ProcessingCore::PImage]
end

attr_reader :img, :show, :col_int, :back_image

def setup
  size(640, 360)
  @show = false
  @img = loadImage("test.png") # NB: test.png size should equal frame size
  #@back_image = img.to_java(Java::ProcessingCore::PImage)
end

def draw
  int_background(0)
  # background(0) # warns about ambigious method
  # background(img) if show
  image_background(img) if show # does not warn about ambiguous method
  # background(back_image) if show # uses a precast java object
end

def mouse_pressed
  @show = !show
end

Monday, 20 May 2013

Updating to Use JRuby-1.7.4

I've recently updated ruby-processing to use jruby-1.7.4, and for Mac and Windows users, it has been updated to use processing-2.0 (untested, you might be the guinea-pig). Seems to work OK linux. I am not all interested in updating ruby-processing processing-1.5.1 to use jruby-1.7.4 so unless someone volunteers the next release of ruby-processing will be a huge leap (if you've got a crappy graphics card the experience may not be so wonderful!!!!). Processing 2.0 uses opengl2 for P2D and P3D rendering so if you've got a reasonable graphics card there are decent improvements to be had including easy access to glsl shaders and FBO (buffered on graphics card). Read this and get inspired http://codeanticode.wordpress.com/2013/06/04/processing-2-0-is-out-processing-2-0-is-in/

Tuesday, 7 May 2013

Another PBox2D sketch, features a chain, and usual physics


# The Nature of Code
# <http://www.shiffman.net/teaching/nature>
# Spring 2010
# PBox2D example

# An uneven surface

load_library :pbox2d
load_library :surface

include SB

attr_reader :surface, :box2d, :particles

def setup
  size(500,300)
  smooth

  # Initialize box2d physics and create the world
  @box2d = PBox2D.new(self)
  box2d.create_world
  # We are setting a custom gravity
  box2d.set_gravity(0, -20)

  # Create the empty list
  @particles = []
  # Create the surface
  @surface = Surface.new(box2d)
end

def draw
  # If the mouse is pressed, we make new particles


  # We must always step through time!
  box2d.step

  background(138, 66, 54)
  # Draw the surface
  surface.display
  # NB question mark is reqd to call mouse_pressed value, else method gets called.
  particles << Particle.new(box2d, mouse_x, mouse_y, rand(2.0 .. 6)) if mouse_pressed?
  # Draw all particles
  particles.each do |p|
    p.display
  end
  # Particles that leave the screen, we delete them
  # (note they have to be deleted from both the box2d world and our list
  particles.each_with_index do |p, i|
    if (p.done)
      particles.delete_at(i)
    end
  end
  # Just drawing the framerate to see how many particles it can handle
  fill(0)
  text("framerate: #{frame_rate.to_i}", 12, 16)
end

The library module, which encapsulates the import of classes, and additional classes for surface and particles.
# The Nature of Code
# <http://www.shiffman.net/teaching/nature>
# Spring 2010
# PBox2D example

# An uneven surface boundary
module SB

  include_package 'org.jbox2d.collision.shapes'
  include_package 'org.jbox2d.common'
  include_package 'org.jbox2d.dynamics'
  java_import 'pbox2d.PBox2D'



  class Surface
    # We'll keep track of all of the surface points
    attr_reader :surface, :body, :box2d, :y, :width, :height


    def initialize b2d
      @box2d = b2d
      @surface = []
      @width, @height = $app.width, $app.height
      # This is what box2d uses to put the surface in its world
      chain = SB::ChainShape.new

      # Perlin noise argument
      xoff = 0.0

      # This has to go backwards so that the objects  bounce off the top of the surface
      # This "edgechain" will only work in one direction!
      (width + 10).step(-10, -5) do |x|
        # Doing some stuff with perlin noise to calculate a surface that points down on one side
        # and up on the other

        if (x > width/2)
          @y = 100 + (width - x)*1.1 + map(noise(xoff),0,1,-80,80)
        else
          @y = 100 + x*1.1 + map(noise(xoff),0,1,-80,80)
        end

        # Store the vertex in screen coordinates
        surface << SB::Vec2.new(x, y)

        # Move through perlin noise
        xoff += 0.1

      end

      # Build an array of vertices in Box2D coordinates
      # from the ArrayList we made
      vertices = []
      surface.each do |surf|
        vertices << box2d.coord_pixels_to_world(surf)
      end
     # Create the chain!
      chain.createChain(vertices, vertices.length)
      # The edge chain is now attached to a body via a fixture
      bd = SB::BodyDef.new
      bd.position.set(0.0, 0.0)
      @body = box2d.createBody(bd)
      # Shortcut, we could define a fixture if we
      # want to specify frictions, restitution, etc.
      body.createFixture(chain, 1)
    end

    # A simple function to just draw the edge chain as a series of vertex points
    def display
      stroke_weight(2)
      stroke(0)
      fill(135, 206, 250)
      beginShape
        vertex(width, 0)      # extra vertices so we can fill sky
        surface.each do |v|
          vertex(v.x, v.y)    # the mountain range
        end
        vertex(0, 0)          # extra vertices so we can fill sky
      endShape
    end
  end

  class Particle
    # We need to keep track of a Body

    attr_reader :body, :box2d, :x, :y, :r

    # Constructor
    def initialize(b2d, x, y, r)
      @box2d, @x, @y, @r = b2d, x, y, r
      # This function puts the particle in the Box2d world
      make_body(x, y, r)
    end

    # This function removes the particle from the box2d world
    def kill_body
      box2d.destroy_body(body)
    end

    # Is the particle ready for deletion?
    def done
      pos = box2d.get_body_pixel_coord(body)
      # Is it off the bottom of the screen?
      if (pos.y > $app.height + r * 2)
        kill_body
        return true
      end
        return false
    end

    def display
      # We look at each body and get its screen position
      pos = box2d.get_body_pixel_coord(body)
      # Get its angle of rotation
      a = body.get_angle
      push_matrix
      translate(pos.x,  pos.y)
      rotate(-a)
      fill(175)
      stroke(0)
      stroke_weight(1)
      ellipse(0,0,r*2,r*2)
      # Let's add a line so we can see the rotation
      line(0,0,r,0)
      pop_matrix
    end

    # This function adds the rectangle to the box2d world
    def make_body(x, y, r)
      # Define and create the body
      bd = SB::BodyDef.new
      bd.position = box2d.coord_pixels_to_world(x,y)
      bd.type = SB::BodyType::DYNAMIC
      @body = box2d.world.create_body(bd)
      # Make the body's shape a circle
      cs = SB::CircleShape.new
      cs.m_radius = box2d.scalar_pixels_to_world(r)
      fd = SB::FixtureDef.new
      fd.shape = cs
      # Parameters that affect physics
      fd.density = 1
      fd.friction = 0.01
      fd.restitution = 0.3
      # Attach fixture to body
      body.create_fixture(fd)
      # Give it a random initial velocity (and angular velocity)
      body.set_linear_velocity(SB::Vec2.new(rand(-10 .. 10), rand(5 .. 10)))
      body.set_angular_velocity(rand(-10 .. 10))
    end
  end
end

Followers

About Me

My Photo
Consolidating my online identity as monkstone. I am a 64 bit linux user and advocate of open source software, you can sometimes find me on the processing forum.