Ruby Processing

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

Monday 12 October 2015

Bye Bye Blogger Hello Github

It was nice to be gothic but I've moved onto github.io for blogging about JRubyArt:-

Personal JRubyArt blog



Monkstone

Ruby-Processing group blog



Ruby Processing Group

Wednesday 16 September 2015

Fraction Sums

# fraction_sums.rb, by Martin Prout
attr_reader :f, :two, :three, :four, :five, :six

def setup
  sketch_title 'Math Blackboard'
  @f = createFont('Arial', 24, true)
  half = 1 / 2r     # since ruby 2.1.0 (and jruby-9.0.0.0)
  third = 1 / 3r
  quarter = 1 / 4r
  fifth = 1 / 5r
  sixth = 1 / 6r
  seventh = 1 / 7r
  format2 = '%s + %s                                     = %s'
  format3 = '%s + %s + %s                            = %s'
  format4 = '%s + %s + %s + %s                   = %s'
  format5 = '%s + %s + %s + %s + %s          = %s'
  format6 = '%s + %s + %s + %s + %s + %s = %s'
  sum2 =  half + third
  result2 = numeric_to_mixed_number(sum2)
  @two = format(format2, half, third, result2)
  sum3 =  half + third + quarter
  result3 = numeric_to_mixed_number(sum3)
  @three = format(format3, half, third, quarter, result3)
  sum4 =  half + third + quarter + fifth
  result4 = numeric_to_mixed_number(sum4)
  @four = format(format4, half, third, quarter, fifth, result4)
  sum5 =  half + third + quarter + fifth + sixth
  result5 = numeric_to_mixed_number(sum5)
  @five = format(format5, half, third, quarter, fifth, sixth, result5)
  sum6 =  half + third + quarter + fifth + sixth + seventh
  result6 = numeric_to_mixed_number(sum6)
  @six = format(format6, half, third, quarter, fifth, sixth, seventh, result6)
end

def draw
  background 10
  text_font(f, 24)
  fill(220)
  text('Math Blackboard JRubyArt', 110, 50)
  text(two, 100, 80)
  text(three, 100, 105)
  text(four, 100, 130)
  text(five, 100, 155)
  text(six, 100, 180)
end

def numeric_to_mixed_number(amount)
  amount_as_integer = amount.to_i
  if (amount_as_integer != amount.to_f) && (amount_as_integer > 0)
    fraction = amount - amount_as_integer
    format('%s %s', amount_as_integer, fraction)
  else
    amount.to_s
  end
end

def settings
  size 640, 250
  smooth 4
end

Tuesday 15 September 2015

Bresenham's Algorithm in JRubyArt

After ruby-processing version, published by norioc on qiita
# ruby-processing sketch
# http://qiita.com/norioc/items/99514cb659aad03ab7d7
# http://aidiary.hatenablog.com/entry/20050402/1251514618
N = 15
attr_reader :rows, :cols

def setup
  sketch_title 'Bresenham`s Algorithm'
  @rows = height / N
  @cols = width / N
end

def settings
  size 400, 400
end

def build_line(from:, to:)
  next_x = from.x
  next_y = from.y
  delta_x = to.x - from.x
  delta_y = to.y - from.y
  step_x = delta_x < 0 ? -1 : 1
  step_y = delta_y < 0 ? -1 : 1
  delta_x = (delta_x * 2).abs
  delta_y = (delta_y * 2).abs
  b_line = Array.new(1, Vec2D.new(next_x, next_y))
  if delta_x > delta_y
    fraction = delta_y - delta_x / 2
    while next_x != to.x
      if fraction >= 0
        next_y += step_y
        fraction -= delta_x
      end
      next_x += step_x
      fraction += delta_y
      b_line << Vec2D.new(next_x, next_y)
    end
  else
    fraction = delta_x - delta_y / 2
    while next_y != to.y
      if fraction >= 0
        next_x += step_x
        fraction -= delta_y
      end
      next_y += step_y
      fraction += delta_x
      b_line << Vec2D.new(next_x, next_y)
    end
  end
  b_line
end

def draw
  background 255
  translate width / 2, height / 2
  rect_mode CENTER
  no_fill
  stroke 60
  (0..rows).each do |i|
    (0..cols).each do |j|
      rect((j - cols / 2) * N, (i - rows / 2) * N, N, N)
    end
  end
  x = mouse_x - width / 2 + N / 2
  y = mouse_y - height / 2 + N / 2
  b_line = build_line(from: Vec2D.new, to: Vec2D.new(x / N, y / N))
  unless b_line.empty?
    fill color('#C7B097')
    b_line.each { |v| rect(v.x * N, v.y * N, N, N) }
  end
  stroke color('#0000FF')
  stroke_width 2
  line 0, 0, mouse_x - width / 2, mouse_y - height / 2
  stroke 0
  stroke_width 1
end

Saturday 29 August 2015

Changing window / surface dynamically in JRubyArt

Since the changes to processing-3.0 we are able to resize our sketches dynamically:-
def settings
  size(400, 400)
end

def setup
  sketch_title 'Resizable Surface'
  surface.set_resizable(true)
end

def draw
  background(255)
  stroke_weight 4
  line(100, 100, width - 100, height - 100)
end

def key_pressed
  surface.set_size(rand(200..500).floor, rand(200..500).floor)
end

In this sketch "sketch_title" actually calls surface under the hood with another 'set' method but we don't want these ugly get set prefixed methods in ruby do we. I guess I could similary "fix" resizable and convert set_size to sketch_size? And since true is given as default argument to resizable we don't need that either...
def settings
  size(400, 400)
end

def setup
  sketch_title 'Resizable Surface'
  resizable(true)
end

def draw
  background(255)
  stroke_weight 4
  line(100, 100, width - 100, height - 100)
end

def key_pressed
  sketch_size(rand(200..500).floor, rand(200..500).floor)
end
OK a bit more experimentation also works with FX2D, blows up with P2D, but that's the same with vanilla processing (threading error).

Thursday 27 August 2015

Advanced shader sketches in JRubyArt

Andres Colubri has published some advanced shader experiments here for processing-3.0, this is one of the examples translated for JRubyArt (requires shader files from the repo. See also Andres write-up on Advanced-OpenGL. Cool sketch of a textured Earth with an independent cloud layer.
# Earth model with bump mapping, specular texture and dynamic cloud layer.
# Adapted from the THREE.js tutorial to processing by Andres Colubri,
# translated to JRubyArt by Martin Prout:
# http://learningthreejs.com/blog/2013/09/16/how-to-make-the-earth-in-webgl/

attr_reader :earth, :clouds, :earth_shader, :cloud_shader, :earth_rotation
attr_reader :clouds_rotation, :target_angle

def setup
  sketch_title 'Blue Marble'
  @earth_rotation = 0
  @clouds_rotation = 0
  earth_tex = load_image('earthmap1k.jpg')
  cloud_tex = load_image('earthcloudmap.jpg')
  alpha_tex = load_image('earthcloudmaptrans.jpg')
  bump_map = load_image('earthbump1k.jpg')
  spec_map = load_image('earthspec1k.jpg')
  @earth_shader = load_shader('EarthFrag.glsl', 'EarthVert.glsl')
  earth_shader.set('texMap', earth_tex)
  earth_shader.set('bumpMap', bump_map)
  earth_shader.set('specularMap', spec_map)
  earth_shader.set('bumpScale', 0.05)
  @cloud_shader = load_shader('CloudFrag.glsl', 'CloudVert.glsl')
  cloud_shader.set('texMap', cloud_tex)
  cloud_shader.set('alphaMap', alpha_tex)
  @earth = create_shape(SPHERE, 200)
  earth.setStroke(false)
  earth.setSpecular(color(125))
  earth.setShininess(10)
  @clouds = create_shape(SPHERE, 201)
  clouds.setStroke(false)
end

def draw
  background(0)
  translate(width / 2, height / 2)
  point_light(255, 255, 255, 300, 0, 500)
  target_angle = map1d(mouse_x, (0..width), (0..TWO_PI))
  @earth_rotation += 0.05 * (target_angle - earth_rotation)
  shader(earth_shader)
  push_matrix
  rotate_y(earth_rotation)
  shape(earth)
  pop_matrix
  shader(cloud_shader)
  push_matrix
  rotate_y(earth_rotation + clouds_rotation)
  shape(clouds)
  pop_matrix
  @clouds_rotation += 0.001
end

def settings
  size(600, 600, P3D)
end

Monday 17 August 2015

Java-8-lambda and jruby extensions

Should we be getting excited about java-8-lambda for jruby extensions (working in NetBeans I got this suggestion when updating source from java-7 to java-8 having listened to Charlies talk at JVMLS2015 perhaps we should?
// Java seven

public static void createVec2(final Ruby runtime) {
    RubyClass vec2Cls = runtime.defineClass("Vec2D", runtime.getObject(), new ObjectAllocator() {
            @Override
            public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
                return new Vec2(runtime, rubyClass);
            }
    });
    vec2Cls.defineAnnotatedMethods(Vec2.class);

}

// Java eight
public static void createVec2(final Ruby runtime) {
    RubyClass vec2Cls = runtime.defineClass("Vec2D", runtime.getObject(), (Ruby runtime1, RubyClass rubyClass) -> new Vec2(runtime1, rubyClass));
    vec2Cls.defineAnnotatedMethods(Vec2.class);
}
Update 22 August 2015 just released JRubyArt 0.5.0 featuring java8lambda in production...

Friday 14 August 2015

AABB for JRubyArt using keyword args

UPDATED ENTRY 2 September 2015, to avoid clash with toxicgem AABB is now AaBb since JRubyArt-0.6.0
I'm adding a 2D axis aligned bounding box to JRubyArt, here's what it looks like, position can be conditionally updated (ie if block given, only updates if the block evaluates to true):-
# Axis aligned bounding box class (AABB would clash with Toxicgem)
class AaBb
  attr_reader :center, :extent

  def initialize(center:, extent:)
    @center = center
    @extent = extent
  end

  def self.from_min_max(min:, max:)
    new(center: (min + max) * 0.5, extent: max - min)
  end

  def position(vec)
    return @center = vec unless block_given?
    @center = vec if yield
  end

  def scale(d)
    @extent *= d
  end

  def contains?(vec)
    rad = extent * 0.5
    return false unless (center.x - rad.x..center.x + rad.x).cover? vec.x
    (center.y - rad.y..center.y + rad.y).cover? vec.y
  end
end

Here is an example using it (based on processing Basics/Input/MouseFunctions.pde but vastly superior to my thinking). Two AaBb objects are used, one to define the window bounds so we can stop block going off screen (vanilla processing example fails to do that) and one to define the block area.
# Click on the box and drag it across the screen.

attr_reader :block, :block_locked, :over_block, :renderer, :bounds
BLOCK_WIDTH = 150

def setup
  sketch_title 'AaBb Example'
  @block = Block.new(
    center: Vec2D.new(width / 2, height / 2),
    size: Vec2D.new(BLOCK_WIDTH, BLOCK_WIDTH))
  @locked = false
  @over_block = false
  @bounds = AaBb.new(
    center: Vec2D.new(width / 2, height / 2),
    extent: Vec2D.new(width - BLOCK_WIDTH, height - BLOCK_WIDTH))
  @renderer = AppRender.new(self)
end

def draw
  background 0
  fill 153
  if block.over?(Vec2D.new(mouse_x, mouse_y))
    @over_block = true
    stroke 255
    fill 255 if block_locked?
  else
    @over_block = false
    stroke 153
  end
  # Draw the box as a shape
  begin_shape
  block.points_array.each { |vec| vec.to_vertex(renderer) }
  end_shape(CLOSE)
end

def block_locked?
  block_locked
end

def over_block?
  over_block
end

def mouse_pressed
  if over_block?
    @block_locked = true
    fill 255
  else
    @block_locked = false
  end
end

def mouse_dragged
  return unless block_locked?
  position = Vec2D.new(mouse_x, mouse_y)
  block.new_position(position) { bounds.contains? position }
end

def mouse_released
  @block_locked = false
end

def settings
  size 640, 360
  smooth 4
end

# Use class to contain block behaviour
class Block
  attr_reader :aabb

  def initialize(center:, size:)
    @aabb = AaBb.new(center: center, extent: size)
  end

  def new_position(center, &block)
    @aabb.position(center.dup, &block)
  end

  def over?(vec)
    aabb.contains? vec
  end

  # use for shape
  def points_array
    a = aabb.center - aabb.extent * 0.5
    c = aabb.center + aabb.extent * 0.5
    b = Vec2D.new(c.x, a.y)
    d = Vec2D.new(a.x, c.y)
    [a, b, c, d]
  end

  # use for rect
  def points
    [aabb.center, aabb.extent]
  end
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