Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0

Friday, 28 December 2012

Bezier Patch as a VBO (PShape)

Hardly needs introduction here is an alternative version of the bezier patch sketch, features ArcBall (arcball library is built in to my fork of ruby-processing, which is required to run a sketch with processing-2.0 functionality such as PShape) to rotate the patch and uses PShape object to store the geometry as a vbo.
# bezier bez_patch By Marius Watz:
# http://www.openprocessing.org/sketch/57709
# Normal calculation added by Andres Colubri
# Direct port of sample code by Paul Bourke.
# Original code: http://paulbourke.net/geometry/bezier/
#
# hit "spacebar" to generate a new shape and save current
#


load_library :vecmath

NI=4
NJ=5
RESI=NI*10
RESJ=NJ*10

attr_accessor :outp, :inp, :normp, :auto_normals, :arcball, :bez_patch


def setup
  size(1024, 768, P3D)
  @arcball = ArcBall.new(width/2.0, height/2.0, min(width - 20, height - 20) * 0.5)
  @auto_normals = false
  build_geometry
  @bez_patch = build_shape
end

def draw
  background(255)
  translate(width/2,height/2)
  smooth(8)
  lights
  define_lights
  #scale(0.9)
  update
  shape(bez_patch)
end

#######
# use bez patch geometry to
# create a vbo object (PShape)
#######

def build_shape
    no_stroke
    bez = create_shape(QUAD_STRIP)
    bez.fill(192, 192, 192)
    bez.ambient(20, 20, 20)
    (0 ... RESI - 1).each do |i|
        (0 ... RESJ).each do |j|
            if (!auto_normals)
                bez.normal(*normp[i][j])
            end
            bez.vertex(*outp[i][j])
            bez.vertex(*outp[i+1][j])
        end
    end
    bez.end     # end has unfortunate ruby highlighting in jedit, not in vim though
    return bez
end

##########
# build geometry
# for bez patch
##########

def build_geometry
  @outp = []
  @normp = []
  @inp = []
  uitang = PVector.new
  ujtang = PVector.new

  (0 ... NI).each do |i|
    row = Array.new
    (0 ... NJ).each do |j|
      row << PVector.new(i, j, (rand * 6) - 3)
    end
    inp << row
  end

  (0 ... RESI).each do |i|
    mui = i.fdiv(RESI - 1)
    row = []
    row_n = []
    (0 ... RESJ).each do |j|
      muj = j.fdiv(RESJ - 1)
      vect = PVector.new
      uitang.set(0, 0, 0)
      ujtang.set(0, 0, 0)
      (0 ... NI).each do |ki|
        bi = bezier_blend(ki, mui, NI)
        dbi = d_bezier_blend(ki, mui, NI)
        (0 ... NJ).each do |kj|
          bj = bezier_blend(kj, muj, NJ)
          dbj = d_bezier_blend(kj, muj, NJ)
          vect.x += (inp[ki][kj].x * bi * bj)
          vect.y += (inp[ki][kj].y * bi * bj)
          vect.z += (inp[ki][kj].z * bi * bj)

          uitang.x += (inp[ki][kj].x * dbi * bj)
          uitang.y += (inp[ki][kj].y * dbi * bj)
          uitang.z += (inp[ki][kj].z * dbi * bj)

          ujtang.x += (inp[ki][kj].x * bi * dbj)
          ujtang.y += (inp[ki][kj].y * bi * dbj)
          ujtang.z += (inp[ki][kj].z * bi * dbj)
        end
      end
      vect.add(PVector.new(-NI/2,-NJ/2,0))
      vect.mult(100)
      row << vect.array()
      uitang.normalize
      ujtang.normalize
      row_n << uitang.cross(ujtang).array()
    end
    @outp << row
    @normp << row_n
  end
end

def bezier_blend( k, mu,  n)
    blend = 1.0
    nn = n
    kn = k
    nkn = n - k

    while (nn >= 1)
        blend *= nn
        nn -= 1
        if (kn > 1)
            blend = blend.fdiv(kn)
            kn -= 1
        end
        if (nkn > 1)
            blend = blend.fdiv(nkn)
            nkn -= 1
        end
    end
    blend *= pow(mu, k.to_f) if (k > 0)
    blend *= pow(1-mu, (n - k).to_f) if (n - k > 0)
    return(blend)
end

def d_bezier_blend( k, mu,  n)
  dblendf = 1.0

  nn = n
  kn = k
  nkn = n - k

  while (nn >= 1)
    dblendf *= nn
    nn -= 1
    if (kn > 1)
      dblendf  = dblendf.fdiv(kn)
      kn -= 1
    end
    if (nkn > 1)
      dblendf  = dblendf.fdiv(nkn)
      nkn -= 1
    end
  end

  fk = 1
  dk = 0
  fnk = 1
  dnk = 0
  if (k > 0)
    fk = pow(mu, k.to_f)
    dk = k * pow(mu, (k - 1).to_f)
  end
  if (n - k > 0)
    fnk = pow(1 - mu, (n - k).to_f)
    dnk = (k - n)*pow(1 - mu, (n - k - 1).to_f)
  end
  dblendf *= (dk * fnk + fk * dnk)

  return(dblendf)
end

######################
# ArcBall control
# and lighting + re-run
######################

def update
    theta, x, y, z = arcball.update
    rotate(theta, x, y, z)
end

def mouse_pressed
    arcball.mouse_pressed(mouse_x, mouse_y)
end

def mouse_dragged
    arcball.mouse_dragged(mouse_x, mouse_y)
end

def define_lights
    ambient_light(60, 60, 60)
    point_light(30, 30, 30, 0, 0, 0)
    directional_light(40, 40, 50, 1, 0, 0)
    spot_light(30, 30, 30, 0, 40, 200, 0, -0.5, 0.5, PI / 2, 2)
end

def key_pressed
    case(key)
    when ' '
        save_frame("bezPatch.png")
        build_geometry
        @bez_patch = build_shape
    when 'x'
        arcball.select_axis(X)
    when 'y'
        arcball.select_axis(Y)
    when 'z'
        arcball.select_axis(Z)
    end
end

def key_released
    arcball.select_axis(-1)
end
Updated 20 February 2014 (arcball library is now in vecmath).

Thursday, 27 December 2012

Bezier Patch in ruby-processing

This is getting to be a habit? Another sketch by Marius Watz translated to ruby-processing. The main reason is that I've been working on updating ruby-processing to processing-2.0, and in the course of that I'm including some sketches included with the processing-2.0 distribution and this is just another. Both these sketches benefit from taking a different approach building arrays in ruby cf java. This one has benefited from bit more tuning, as there no real need for an arrays of PVector once the math has been done. Further it is so easy to just splat array to the vertex coordinates, don't you just love ruby.
# bezier patch By Marius Watz:
# http://www.openprocessing.org/sketch/57709
# Normal calculation added by Andres Colubri
# Direct port of sample code by Paul Bourke.
# Original code: http://paulbourke.net/geometry/bezier/
#
# hit "spacebar" to generate a new shape and save current
#

NI=4
NJ=5
RESI=NI*10
RESJ=NJ*10

attr_accessor :outp, :inp, :normp, :auto_normals


def setup
  size(1024, 768, P3D)
  @auto_normals = false
  build
end

def draw
  background(255)
  translate(width/2,height/2)
  smooth(8)
  lights
  #scale(0.9)
  rotate_y(map(mouse_x, 0, width, -PI, PI))
  rotate_x(map(mouse_y, 0, height, -PI, PI))
  no_stroke
  fill(192, 192, 192)
  ambient_light(100, 100, 100)
  ambient(40)
  specular(30)
  (0 ... RESI - 1).each do |i|
    beginShape(QUAD_STRIP)
    (0 ... RESJ).each do |j|
      if (!auto_normals)
        normal(*normp[i][j])
      end
      vertex(*outp[i][j])
      vertex(*outp[i+1][j])
    end
    endShape
  end
end

def keyPressed
    if (key == ' ')
        save_frame("bezPatch.png")
        build
    end
end

def build
  @outp = []
  @normp = []
  @inp = []
  uitang = PVector.new
  ujtang = PVector.new

  (0 ... NI).each do |i|
    row = Array.new
    (0 ... NJ).each do |j|
      row << PVector.new(i, j, (rand * 6) - 3)
    end
    inp << row
  end

  (0 ... RESI).each do |i|
    mui = i.fdiv(RESI - 1)
    row = []
    row_n = []
    (0 ... RESJ).each do |j|
      muj = j.fdiv(RESJ - 1)
      vect = PVector.new
      uitang.set(0, 0, 0)
      ujtang.set(0, 0, 0)
      (0 ... NI).each do |ki|
        bi = bezier_blend(ki, mui, NI)
        dbi = d_bezier_blend(ki, mui, NI)
        (0 ... NJ).each do |kj|
          bj = bezier_blend(kj, muj, NJ)
          dbj = d_bezier_blend(kj, muj, NJ)
          vect.x += (inp[ki][kj].x * bi * bj)
          vect.y += (inp[ki][kj].y * bi * bj)
          vect.z += (inp[ki][kj].z * bi * bj)

          uitang.x += (inp[ki][kj].x * dbi * bj)
          uitang.y += (inp[ki][kj].y * dbi * bj)
          uitang.z += (inp[ki][kj].z * dbi * bj)

          ujtang.x += (inp[ki][kj].x * bi * dbj)
          ujtang.y += (inp[ki][kj].y * bi * dbj)
          ujtang.z += (inp[ki][kj].z * bi * dbj)
        end
      end
      vect.add(PVector.new(-NI/2,-NJ/2,0))
      vect.mult(100)
      row << vect.array()
      uitang.normalize
      ujtang.normalize
      row_n << uitang.cross(ujtang).array()
    end
    @outp << row
    @normp << row_n
  end
end

def bezier_blend( k, mu,  n)
    blend = 1.0
    nn = n
    kn = k
    nkn = n - k

    while (nn >= 1)
        blend *= nn
        nn -= 1
        if (kn > 1)
            blend = blend.fdiv(kn)
            kn -= 1
        end
        if (nkn > 1)
            blend = blend.fdiv(nkn)
            nkn -= 1
        end
    end
    blend *= pow(mu, k.to_f) if (k > 0)
    blend *= pow(1-mu, (n - k).to_f) if (n - k > 0)
    return(blend)
end

def d_bezier_blend( k, mu,  n)
  dblendf = 1.0

  nn = n
  kn = k
  nkn = n - k

  while (nn >= 1)
    dblendf *= nn
    nn -= 1
    if (kn > 1)
      dblendf  = dblendf.fdiv(kn)
      kn -= 1
    end
    if (nkn > 1)
      dblendf  = dblendf.fdiv(nkn)
      nkn -= 1
    end
  end

  fk = 1
  dk = 0
  fnk = 1
  dnk = 0
  if (k > 0)
    fk = pow(mu, k.to_f)
    dk = k * pow(mu, (k - 1).to_f)
  end
  if (n - k > 0)
    fnk = pow(1 - mu, (n - k).to_f)
    dnk = (k - n)*pow(1 - mu, (n - k - 1).to_f)
  end
  dblendf *= (dk * fnk + fk * dnk)

  return(dblendf)
end

Monday, 24 December 2012

Rotating Arcs Sketch in Ruby Processing

Here is vanilla sketch that wasn't easy to translate to ruby, the more hacks there are, the harder it is to translate. However conversely it should make me a bit bit more sensitive to the same issue in reverse. The original sketch featured sincos look up tables which are a dubious benefit in java, especially when not optimised. It also featured a nasty ++ increment hack. The original sketch had quite lot of casting to int, I found there no casting required in ruby-processing, just a nifty built in deg to radian conversion using a patched Numeric class.
# 
#  Geometry 
#  by Marius Watz. 
#  
load_library 'pdf'
include_package 'processing.pdf'

attr_reader :num, :pt, :style, :dosave

def setup
  size(1024, 768, P3D)
  background(255)
  @dosave = false
  @num = 150
  @pt = []
  @style = []

  # Set up arc shapes
  index = 0
  (0 ... num).each do |i|
    pt.push(rand(TWO_PI)) # Random X axis rotation
    pt.push(rand(TWO_PI)) # Random Y axis rotation

    pt.push(rand(60 .. 80)) # Short to quarter-circle arcs
    if (rand(100)>90)
      pt[pt.length - 1] = rand(8 .. 27) * 10
    end
    pt.push(rand(2 .. 50) * 5) # Radius. Space them out nicely

    pt.push(rand(4 .. 32)) # Width of band
    if (rand(100) > 90)
      pt[pt.length - 1] = rand(40 .. 60) # Width of band
    end

    pt.push(rand(0.005 .. 0.0334))# Speed of rotation

    # get colors
    prob = rand(100)
    if (prob < 30)
      style[i*2] = color_blended(rand, 255,0,100, 255,0,0, 210)
    elsif(prob < 70)
      style[i*2] = color_blended(rand, 0,153,255, 170,225,255, 210)
    elsif(prob<90)
      style[i*2] = color_blended(rand, 200,255,0, 150,255,0, 210)
    else
      style[i*2] = color(255,255,255, 220)
    end

    if (prob < 50)
      style[i*2] = color_blended(rand, 200,255,0, 50,120,0, 210)
    elsif(prob < 90)
      style[i*2] = color_blended(rand, 255,100,0, 255,255,0, 210)
    else
      style[i*2] = color(255, 255, 255, 220)
      style[i*2+1] = rand(100) % 3
    end
  end
end

def draw
  if(dosave)
    # set up PGraphicsPDF for use with beginRaw
    pdf = begin_raw(PDF, "pdf_complex_out.pdf")
    # set default Illustrator stroke styles and paint background rect.
    pdf.stroke_join(MITER)
    pdf.stroke_cap(SQUARE)
    pdf.fill(0)
    pdf.no_stroke
    pdf.rect(0,0, width,height)
  end
  background(0)
  index = 0
  translate(width/2, height/2, 0)
  rotate_x(PI/6)
  rotate_y(PI/6)
  (0 ... num).each do |i|
    push_matrix
    rotate_x(pt[index])
    rotate_y(pt[index + 1])
    index += 2
    if (style[i*2+1] == 0)
      stroke(style[i*2])
      no_fill
      stroke_weight(1)
      arc_line(0,0, pt[index],pt[index + 1],pt[index + 2])
      index += 3
    elsif (style[i*2+1] == 1)
      fill(style[i*2])
      no_stroke
      arc_line_bars(0,0, pt[index],pt[index + 1],pt[index + 2])
      index += 3
    else
      fill(style[i*2])
      no_stroke
      arc(0,0, pt[index],pt[index + 1],pt[index + 2])
      index += 3
    end
    # increase rotation
    pt[index-5] += pt[index] / 10
    pt[index-4] += pt[index] / 20
    index += 1
    pop_matrix
  end
  if (dosave)
    end_raw
    @dosave=false
  end
end


# Get blend of two colors
def color_blended(fract, r, g, b, r2, g2, b2, a)
  r2 = (r2 - r)
  g2 = (g2 - g)
  b2 = (b2 - b)
  return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a)
end


# Draw arc line
def arc_line(x, y, deg, rad, w)
  a=(deg < 360)? deg : 0
  numlines = w/2
  (0 ... numlines).each do
    begin_shape
    (0 ... a).each do |i|
      vertex(cos(i.radians)*rad+x,sin(i.radians)*rad+y)
    end
    end_shape
    rad += 2
  end
end

# Draw arc line with bars
def arc_line_bars(x, y, deg, rad, w)
  a=(deg < 360)? deg / 4 : 0
  begin_shape(QUADS)
  (0 ... a).step(4) do |i|
    vertex(cos(i.radians)*(rad)+x,sin(i.radians)*(rad)+y)
    vertex(cos(i.radians)*(rad+w)+x,sin(i.radians)*(rad+w)+y)
    vertex(cos((i + 2).radians)*(rad+w)+x,sin((i + 2).radians)*(rad+w)+y)
    vertex(cos((i + 2).radians)*(rad)+x,sin((i + 2).radians)*(rad)+y)
  end
  end_shape
end

# Draw solid arc
def arc(x,y,deg,rad,w)
  a = (deg < 360)? deg : 0
  begin_shape(QUAD_STRIP)
  (0 ... a).each do |i|
    vertex(cos(i.radians)*(rad)+x,sin(i.radians)*(rad)+y)
    vertex(cos(i.radians)*(rad+w)+x,sin(i.radians)*(rad+w)+y)
  end
  end_shape
end

def mouse_pressed
  @dosave = true
end
# 
#  Geometry 
#  by Marius Watz. 
#  
load_library 'pdf'
include_package 'processing.pdf'

attr_reader :num, :pt, :style, :dosave

def setup
  size(1024, 768, P3D)
  background(255)
  @dosave = false
  @num = 150
  @pt = []
  @style = []

  # Set up arc shapes
  index = 0
  (0 ... num).each do |i|
    pt.push(rand(TWO_PI)) # Random X axis rotation
    pt.push(rand(TWO_PI)) # Random Y axis rotation

    pt.push(rand(60 .. 80)) # Short to quarter-circle arcs
    if (rand(100)>90)
      pt[pt.length - 1] = rand(8 .. 27) * 10
    end
    pt.push(rand(2 .. 50) * 5) # Radius. Space them out nicely

    pt.push(rand(4 .. 32)) # Width of band
    if (rand(100) > 90)
      pt[pt.length - 1] = rand(40 .. 60) # Width of band
    end

    pt.push(radians(rand(5 .. 30)) / 5 )# Speed of rotation

    # get colors
    prob = rand(100)
    if (prob < 30)
      style[i*2] = color_blended(rand, 255,0,100, 255,0,0, 210)
    elsif(prob < 70)
      style[i*2] = color_blended(rand, 0,153,255, 170,225,255, 210)
    elsif(prob<90)
      style[i*2] = color_blended(rand, 200,255,0, 150,255,0, 210)
    else
      style[i*2] = color(255,255,255, 220)
    end

    if (prob < 50)
      style[i*2] = color_blended(rand, 200,255,0, 50,120,0, 210)
    elsif(prob < 90)
      style[i*2] = color_blended(rand, 255,100,0, 255,255,0, 210)
    else
      style[i*2] = color(255, 255, 255, 220)
      style[i*2+1] = rand(100).to_i % 3
    end
  end
end

def draw
  if(dosave)
    # set up PGraphicsPDF for use with beginRaw
    pdf = begin_raw(PDF, "pdf_complex_out.pdf")
    # set default Illustrator stroke styles and paint background rect.
    pdf.stroke_join(MITER)
    pdf.stroke_cap(SQUARE)
    pdf.fill(0)
    pdf.no_stroke
    pdf.rect(0,0, width,height)
  end
  background(0)
  index = 0
  translate(width/2, height/2, 0)
  rotate_x(PI/6)
  rotate_y(PI/6)
  (0 ... num).each do |i|
    push_matrix
    rotate_x(pt[index])
    rotate_y(pt[index + 1])
    index += 2
    if (style[i*2+1] == 0)
      stroke(style[i*2])
      no_fill
      stroke_weight(1)
      arc_line(0,0, pt[index],pt[index + 1],pt[index + 2])
      index += 3
    elsif (style[i*2+1] == 1)
      fill(style[i*2])
      no_stroke
      arc_line_bars(0,0, pt[index],pt[index + 1],pt[index + 2])
      index += 3
    else
      fill(style[i*2])
      no_stroke
      arc(0,0, pt[index],pt[index + 1],pt[index + 2])
      index += 3
    end
    # increase rotation
    pt[index-5] += pt[index] / 10
    pt[index-4] += pt[index] / 20
    index += 1
    pop_matrix
  end
  if (dosave)
    end_raw
    @dosave=false
  end
end


# Get blend of two colors
def color_blended(fract, r, g, b, r2, g2, b2, a)
  r2 = (r2 - r)
  g2 = (g2 - g)
  b2 = (b2 - b)
  return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a)
end


# Draw arc line
def arc_line(x, y, deg, rad, w)
  a=(deg < 360)? deg : 0
  numlines = w/2
  (0 ... numlines).each do
    begin_shape
    (0 ... a).each do |i|
      vertex(cos(radians(i))*rad+x,sin(radians(i))*rad+y)
    end
    end_shape
    rad += 2
  end
end

# Draw arc line with bars
def arc_line_bars(x, y, deg, rad, w)
  a=(deg < 360)? deg / 4 : 0
  begin_shape(QUADS)
  (0 ... a).step(4) do |i|
    vertex(cos(radians(i))*(rad)+x,sin(radians(i))*(rad)+y)
    vertex(cos(radians(i))*(rad+w)+x,sin(radians(i))*(rad+w)+y)
    vertex(cos(radians(i + 2))*(rad+w)+x,sin(radians(i + 2))*(rad+w)+y)
    vertex(cos(radians(i + 2))*(rad)+x,sin(radians(i + 2))*(rad)+y)
  end
  end_shape
end

# Draw solid arc
def arc(x,y,deg,rad,w)
  a = (deg < 360)? deg : 0
  begin_shape(QUAD_STRIP)
  (0 ... a).each do |i|
    vertex(cos(radians(i))*(rad)+x,sin(radians(i))*(rad)+y)
    vertex(cos(radians(i))*(rad+w)+x,sin(radians(i))*(rad+w)+y)
  end
  end_shape
end

def mouse_pressed
  @dosave = true
end

Friday, 21 December 2012

Context free sketch in regular ruby processing

Sometimes it is not necessary to use the ruby-cf3 library. I was contemplating adding parametrized shape to cf3ruby, so I thought I would try a simple context free art sketch to experiment with. Turn out this pretty easy to implement in regular ruby-processing (now using ruby-1.9 syntax for random range):-
# Grapher is based on a context free art design
# by ColorMeImpressed (takes a bit of time to run)
# http://www.contextfreeart.org/gallery/view.php?id=2844
#

CMIN = -2.0 # Important to specify float else get random int from range?
CMAX = 2.0
FUZZ = 0.04
SZ = 5

def setup
  size 600, 600
  no_stroke
  color_mode(HSB, 1.0)
  background(0)
  frame_rate(4000)
end

def draw
  translate(width/2, height/2)
  dot(rand(-PI .. PI), rand(-PI .. PI), rand(CMIN .. CMAX)) unless frame_count > 200000
end

def dot(px, py, c)
  func = sin(px) + sin(py) + c
  # change function to change the graph eg.
  #func = sin(px) + tan(py) + c    
  #func = cos(px) + sin(py) + c
  if abs(func) <= FUZZ
    fill(((CMIN - c) / (CMIN - CMAX)), 1, 1)
    ellipse px * width / TWO_PI, py * height / TWO_PI, SZ, SZ
  else
    dot(rand(-PI .. PI), rand(-PI .. PI), rand(CMIN .. CMAX))
  end
end

Wednesday, 19 December 2012

Exporting cf3ruby directly to 'large' pdf

With the processing pdf export library it is easy to export processing sketches to pdf. This is also true for ruby-processing sketches, including those using the cf3ruby library see example below:-
# levy.rb ruby-processing NB: :alpha is now implemented ruby-processing
require 'cf3', 'pdf'
include_package 'processing.pdf'

def setup_the_levy
  @levy = ContextFree.define do
    shape :start do
      levy brightness: 0.9
    end
    shape :levy do
      square alpha: 0.1
     split do
        levy  size: 1/Math.sqrt(2), rotation: -45, x: 0.5, brightness: 0.9
        rewind
        levy  size: 1/Math.sqrt(2), rotation: 45, x: 0.5, brightness: 0.9
     end
    end
  end
end


def setup
  size 2000, 2000, PDF, "levy.pdf"
  setup_the_levy
  smooth
  draw_it
end


def draw
  exit
end


def draw_it
  background 255
  @levy.render :start, size: 250,  stop_size: 2,
        start_x: width/4, start_y: height/2
end

Tuesday, 18 December 2012

Context Free Tree in cf3ruby

#################################################################
# A non deterministic sketch run it until you get a result you like
# uncomment "srand 5" to get a more deterministic result. It looked
# pretty good on my linux box (however I'm not sure how universal the 
# random seeding is in jruby)
#################################################################

require 'cf3'

def setup_the_tree
  @tree = ContextFree.define do
    shape :trunk, 20 do                         # rule has a probability weighting of 20
      circle size: 0.25, brightness: 0.5     # giving an actual probability = 0.952381
      scraggle y: -0.1                      # the minus is require by the upside down coordinate system             
    end

    shape :trunk, 1 do                      # rule has a probability weighting of 1
      branch size: 0.7                      # giving an actual probability = 0.047619  
    end

    shape :trunk, 0.02 do                    # empty rule top stop early    
    end

    shape :branch do
      split do                               # split is like a branch, rewind returns original context
        trunk rotation: 10
      rewind
        trunk rotation: -10
      end
    end

    shape :scraggle do                       # without an explicit weighting    
      trunk rotation: 5                      # probability of each scraggle rule 
    end                                      # is 0.5

    shape :scraggle do
      trunk rotation: -5
    end
  end
end

def setup
  size 600, 600
  srand 5
  smooth
  setup_the_tree
  background 255         # NB color mode here is "RGB 255", within context free definition 
  draw_it                # the color mode is "HSB 1.0", supports :hue, :saturation, :brightness
  save_frame "/home/tux/tree4.png"
end

def draw_it
  @tree.render :trunk, start_x: width/2, start_y: height * 0.9, stop_size: height/150, size: height/15
end

New context_free.rb (cf3ruby)

Here is my "y" window sketch using my modified ruby-processing library (features CF3 syntax, ie shape replaces rule, also ruby 1.9 hash syntax).
# y.rb ruby-processing
require 'cf3'
Y_TOP = -1 / Math.sqrt(3)
Y_BOT = Math.sqrt(3) / 6

def setup_the_triangle
  @triangle = ContextFree.define do
    ########  
    shape :start do
    unit brightness: 1.0
    end

    shape :unit do
      triangle size: 1.0
      split do
        unit size: 0.5, x: 0, y: Y_TOP/2, brightness: 0.8
        rewind
        unit size: 0.5, x: -0.25, y: -Y_TOP/4, brightness: 0.8
        rewind
        unit size: 0.5, x: 0.25, y: -Y_TOP/4, brightness: 0.8
      end
    end
    ########
  end
end

def setup
  size 1024, 1024
  setup_the_triangle
  no_stroke
  color_mode RGB, 1
  smooth
  draw_it
  save_frame("y.png")
end


def draw
   # Do nothing.
end

def draw_it
  background 225, 225, 0
  @triangle.render :start, size: height, stop_size: 0.5,
  start_x: width/2, start_y: height * 0.6
end

Followers

About Me

My photo
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2