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

Showing posts with label jruby extension. Show all posts
Showing posts with label jruby extension. Show all posts

Wednesday, 18 June 2014

JRubyArt is now using java extensions to generate ruby (Vecmath, ArcBall, DegLut)

Still waiting for @headius to confirm I am the right track with my java extensions to jruby. But I am not waiting forever so now my updated JRubyArt now includes these extensions:-
  1. A vecmath library, featuring Vec2D and Vec3D classes (written in java, but loaded as ruby)
  2. Also featured in the vecmath library is an ArcBall class  (also written in java, but loaded as ruby)
  3. A deglut library which is  now all, java uses a sin90 look up table to create sin cos functionality(is actually slightly faster than regular math sin/cos)
The extension stuff is written up here 

Thing to do:-
  1. Fix overloaded methods for color? eg background, fill, stroke
  2. Experiment with jafama (again, why is Jonathan Feinberg including google guava libs)
  3. improve build now at least a two stage process
  4. Clone and BFG clobber processing-2.2.1 snapshot?
  5. Create a renderer class that is initialized with PApplet, and has medods to send vertex(arg), normal(arg), curvedVertex(arg) etc. where arg is an instance of Vec3D?

Saturday, 24 May 2014

Extending ruby-processing with built in jruby extensions

A jruby extension need not be a gem (and in some ways extension as gems can be limiting with ruby-processing, as they do not work too easily with jruby-complete) instead it can become a custom or built in library. In the development branch of ruby-processing (fastmath fork) I have created two built in libraries as jruby extensions:-
  1. vecmath, as direct replacement for PVector and incorporation arcball functionality (uses jafama under hood)
  2. fastmath, incorporating degree precision deg/cos lookup table and a wrapper for some jafama functions

For the vecmath I took the advantage of working with java to create arcball functionality using processing reflection calls. I also chose to allow simple Vec3D to vertex and Vec3D to normal (this has got to be most efficient way since it avoids unecessary java to ruby, ruby to java conversions something missing in vanilla processing). Here is a sketch (original by Andrés Colubri) that uses the FastMath sin and cos functions (from jafama) and Vec3D to vertex and Vec3D to normal conversions.
# Trefoil, by Andres Colubri
# A parametric surface is textured procedurally
# by drawing on an offscreen PGraphics surface.

load_libraries :vecmath, :fastmath

attr_reader :pg, :trefoil

def setup
  size(1024, 768, P3D)

  texture_mode(NORMAL)
  noStroke

  # Creating offscreen surface for 3D rendering.
  @pg = create_graphics(32, 512, P3D)
  pg.begin_draw
  pg.background(0, 0)
  pg.noStroke
  pg.fill(255, 0, 0, 200)
  pg.end_draw

  # Saving trefoil surface into a PShape3D object
  @trefoil = create_trefoil(350, 60, 15, pg)
end

def draw
  background(0)

  pg.begin_draw
  pg.ellipse(rand(0.0 .. pg.width), rand(0.0 .. pg.height), 4, 4)
  pg.end_draw

  ambient(250, 250, 250)
  pointLight(255, 255, 255, 0, 0, 200)

  push_matrix
  translate(width/2, height/2, -200)
  rotate_x(frame_count * PI / 500)
  rotate_y(frame_count * PI / 500)
  shape(trefoil)
  pop_matrix
end

# Code to draw a trefoil knot surface, with normals and texture 
# coordinates.
# Adapted from the parametric equations example by Philip Rideout:
# http://iphone-3d-programming.labs.oreilly.com/ch03.html

# This function draws a trefoil knot surface as a triangle mesh derived
# from its parametric equation.
def create_trefoil(s, ny, nx, tex)

  obj = create_shape()
  obj.begin_shape(TRIANGLES)
  obj.texture(tex)

  (0 ... nx).each do |j|
    u0 = j.to_f / nx
    u1 = (j + 1).to_f / nx
    (0 ... ny).each do |i|
      v0 = i.to_f / ny
      v1 = (i + 1).to_f / ny

      p0 = eval_point(u0, v0)
      n0 = eval_normal(u0, v0)

      p1 = eval_point(u0, v1)
      n1 = eval_normal(u0, v1)

      p2 = eval_point(u1, v1)
      n2 = eval_normal(u1, v1)

      # Triangle p0-p1-p2      
      n0.shape_normal(obj)
      pa = p0 * s
      pa.shape_vertex(obj, u0, v0)
      n1.shape_normal(obj)
      pb = p1 * s
      pb.shape_vertex(obj, u0, v1)
      n2.shape_normal(obj)
      pc = p2 * s
      pc.shape_vertex(obj, u1, v1)

      p1 = eval_point(u1, v0)
      n1 = eval_normal(u1, v0)

      # Triangle p0-p2-p1      
      n0.shape_normal(obj)
      pa.shape_vertex(obj, u0, v0)
      n2.shape_normal(obj)
      pc.shape_vertex(obj, u1, v1)
      n1.shape_normal(obj)
      pb = p1 * s
      pb.shape_vertex(obj, u1, v0)
    end
  end
  obj.end_shape
  return obj
end

# Evaluates the surface normal corresponding to normalized 
# parameters (u, v)
def eval_normal(u, v)
  # Compute the tangents and their cross product.
  p = eval_point(u, v)
  tangU = eval_point(u + 0.01, v)
  tangV = eval_point(u, v + 0.01)
  tangU -= p
  tangV -= p

  normUV = tangV.cross(tangU)
  normUV.normalize!
  return normUV
end

# Evaluates the surface point corresponding to normalized 
# parameters (u, v)
def eval_point(u, v)
  a = 0.5
  b = 0.3
  c = 0.5
  d = 0.1
  s = TWO_PI * u
  t = (TWO_PI * (1 - v)) * 2

  r = a + b * FastMath.cos(1.5 * t)
  x = r * FastMath.cos(t)
  y = r * FastMath.sin(t)
  z = c * FastMath.sin(1.5 * t)

  dv = Vec3D.new
  dv.x = -1.5 * b * FastMath.sin(1.5 * t) * FastMath.cos(t) - (a + b * FastMath.cos(1.5 * t)) * FastMath.sin(t)
  dv.y = -1.5 * b * FastMath.sin(1.5 * t) * FastMath.sin(t) + (a + b * FastMath.cos(1.5 * t)) * FastMath.cos(t)
  dv.z = 1.5 * c * FastMath.cos(1.5 * t)

  q = dv
  q.normalize!
  qvn = Vec3D.new(q.y, -q.x, 0)
  qvn.normalize!
  ww = q.cross(qvn)

  pt = Vec3D.new
  pt.x = x + d * (qvn.x * FastMath.cos(s) + ww.x * FastMath.sin(s))
  pt.y = y + d * (qvn.y * FastMath.cos(s) + ww.y * FastMath.sin(s))
  pt.z = z + d * ww.z * FastMath.sin(s)
  return pt
end



For the curious the current version of ruby-processings jruby extensions are available here.

Wednesday, 21 May 2014

Creating a jruby extension as a gem

What's an extension:-

Many MRI gems use extensions to wrap libraries that are written in C with a ruby wrapper. Examples include nokogiri which wraps libxml2 and libxslt, pg which is an interface to the PostgreSQL database and the mysql and mysql2 gems which provide an interface to the MySQL database. This above was copied from a guide to creating a gem with extensions. In jruby java alternatives are preferred.

A jruby extension can act as a wrapper for a java library

The Apache commons-math library is an example of such a library, here is gem I've created as a jruby extension.

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