# An PRY shell for live coding. # This flavor will either load up empty JRubyArt sketch, # or will start with your sketch. require "#{File.dirname(__FILE__)}/base.rb" Processing.load_and_run_sketch ARGV.clear # So that IRB doesn't try to load them as files. require 'pry' binding.pryYou still need to access sketch using $app, eg $app.background 0 sets background to 0 (but I expect that could be changed?). Ideally you will also install pry with rgem, and use the --gem flag to be sure that jruby can use the pry gem. Actually turn out this is still somewhat flakey, certainly on linux.
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Friday, 27 December 2013
Experimenting with pry and JRubyArt
If we replace ruby-processings 'live.rb' with the following version, we can easily use pry with ruby-processing (but I am not sure what for, because I don't use pry).
Labels:
pry,
repl,
ruby-processing
Thursday, 26 December 2013
Rakefile to run JRubyArt sketches in a directory from netbeans (tested with samples/contributed)
NB need to adjust path to "k9" executable...., since we are running with development version in netbeans (not an externally installed version)
# Simple demo Rakefile to autorun samples in current directory # from netbeans, adjust path to k9 executable as required SAMPLES_DIR="./" desc 'run demo' task :default => [:demo] desc 'demo' task :demo do samples_list.shuffle.each{|sample| run_sample sample} end def samples_list files = [] Dir.chdir(SAMPLES_DIR) Dir.glob("*.rb").each do |file| files << File.join(SAMPLES_DIR, file) end return files end def run_sample(sample_name) puts "Running #{sample_name}...quit to run next sample" open("|../../bin/k9 run #{sample_name}", "r") do |io| while l = io.gets puts(l.chop) end end end
Tuesday, 24 December 2013
Experimental handler for overloaded "background" in JRubyArt
Previously for ruby-processing, we allowed jruby to make sensible choices for methods with overloaded signatures (but to encourage more efficient operation, jruby is being very noisy about it) and we told you how you can use specific method signatures using java_alias to shut up jruby (and be more efficient). However background it could be argued (because of its ubiquity in sketches and the unique method signatures) might warrant special treatment. Here is an experiment to add such features via the helper_methods module.
JRubyArt is the development branch of ruby-processing.
# The vanilla processing background method is highly overloaded, a single # argument could be an instance of PImage, int or float (multiple arguments are # usually taken to be floats). # @param *args arguments for background as an Array # def background *args if (args.length == 1) if args[0].kind_of? Integer self.java_send :background, [Java::int], args[0] elsif args[0].kind_of? Float self.java_send :background, [Java::float], args[0] elsif args[0].kind_of? Java::ProcessingCore::PImage self.java_send :background, [Java::ProcessingCore::PImage], args[0] end elsif (args.length == 3) self.java_send :background, [Java::float, Java::float, Java::float], args[0], args[1], args[2] elsif (args.length == 2) # greyscale with transparency self.java_send :background, [Java::float, Java::float], args[0], args[1] elsif (args.length == 4) # color with transparency self.java_send :background, [Java::float, Java::float, Java::float, Java::float], args[0], args[1], args[2], args[3] end end
JRubyArt is the development branch of ruby-processing.
Saturday, 14 December 2013
Developing JRubyArt with Netbeans
Thanks largely to Thomas Enebo, I expect to be doing future development of JRubyArt all under Netbeans see screenshot click on image to see full size:-
Screenshot of me developing JRubyArt with Netbeans |
It is just bloody brilliant, brings all the code together, sensible refactoring hints, easy renaming etc.etc.
Labels:
JRubyArt,
ruby development with netbeans
Tuesday, 10 December 2013
Time to give up on the Mac
I have started a new development fork of ruby-processing, I am calling it JRubyArt, there will be no support for the Mac (in the foreseeable future, possibly never, depends on active co-operation Mac users). Calling it JRubyArt may not be so daft because the end point need not only be a processing sketch (PovRAY or Sunflow).
It is an absolute requirement of the development branch to be using at least java-7 (this is requirement for processing-2.1+, but I am really targeting java-8). The idea is that JRubyArt keeps step with jruby-9000 development (which will likely require at least java-7, but likely to work best with java-8). On this basis, there is absolutely no point in supporting the Mac, which post Maverick seems to be designed not to work with java (having said that many jruby users have Macs go figure).
It is an absolute requirement of the development branch to be using at least java-7 (this is requirement for processing-2.1+, but I am really targeting java-8). The idea is that JRubyArt keeps step with jruby-9000 development (which will likely require at least java-7, but likely to work best with java-8). On this basis, there is absolutely no point in supporting the Mac, which post Maverick seems to be designed not to work with java (having said that many jruby users have Macs go figure).
Labels:
bye bye mac,
jdk8,
jruby-9000,
processing
Friday, 6 December 2013
Revised advice for Mac users of ruby-processing
Update 7 December 2012
It appears that vanilla processing-2.1.0 may not be working on Mavericks, however processing-2.0.3 does work, especially using Apple jvm (but this is unsustainable in longer term, and I am sure you should be working towards using the latest Oracle jvm). It seems that you should really install the Oracle JDK rather than just the runtime (to get links updated etc) but if you have previously installed the Apple jvm make sure you do a thorough job of uninstalling it first.
I have just updated the main branch of ruby-processing (version 2.4.0) to make use of an installed version of vanilla processing. Until Ben Fry endorses processing-2.1+ on Mavericks, I recommend installing processing-2.0.3 on the Mac (and processing 2.1+ on linux and Microsoft windows).
It appears that vanilla processing-2.1.0 may not be working on Mavericks, however processing-2.0.3 does work, especially using Apple jvm (but this is unsustainable in longer term, and I am sure you should be working towards using the latest Oracle jvm). It seems that you should really install the Oracle JDK rather than just the runtime (to get links updated etc) but if you have previously installed the Apple jvm make sure you do a thorough job of uninstalling it first.
I have just updated the main branch of ruby-processing (version 2.4.0) to make use of an installed version of vanilla processing. Until Ben Fry endorses processing-2.1+ on Mavericks, I recommend installing processing-2.0.3 on the Mac (and processing 2.1+ on linux and Microsoft windows).
Thursday, 28 November 2013
Ruby-processing on MacOSX, Apple or Oracle JVM
UPDATED 1 February 2014 ruby-processing-2.4.2 (is now available as a rubygem)
Now this is entirely theoretical as I've exceptionally limited experience with a MAC (I once loaded some photos on my Artist friends MAC). However, from what I understand if you update to Mavericks, you won't have java installed. The ideal solution from my point of view, is that this forces you to install Oracle jdk1.7.0_51 (64 bit). However apparently if you are conservative, or otherwise need it, apparently you can get Apple jvm here.
For OSX users incapable of using google, for some reason following link may be helpful stackoverflow it may even encourage you to do the sensible thing and install the Oracle jvm?
But what does this mean for ruby-processing on MacOSX:
Use processing-2.0.3 especially if you are sticking with Apple jvm (Mavericks or otherwise)
Here is another link that might be useful re installing jdk7.
Now this is entirely theoretical as I've exceptionally limited experience with a MAC (I once loaded some photos on my Artist friends MAC). However, from what I understand if you update to Mavericks, you won't have java installed. The ideal solution from my point of view, is that this forces you to install Oracle jdk1.7.0_51 (64 bit). However apparently if you are conservative, or otherwise need it, apparently you can get Apple jvm here.
For OSX users incapable of using google, for some reason following link may be helpful stackoverflow it may even encourage you to do the sensible thing and install the Oracle jvm?
But what does this mean for ruby-processing on MacOSX:
Use processing-2.0.3 especially if you are sticking with Apple jvm (Mavericks or otherwise)
Step by step instruction to install of the latest version of ruby-processing:-
- Install jruby (at least version 1.7.3 but preferably 1.7.10)
- Install processing-2.0.3, or if not on Mavericks you could try processing-2.1.1 & jdk7
- Run the processing sketch here to set the path to the processing root
- gem install ruby-processing
- install_jruby_complete
- cd your work directory
- rp5 unpack samples
- cd samples/contributed
- rp5 run grapher.rb (or jwishy.rb or whatever)
Please report how you get on since if I can establish that this is working OK we will be able to return to ruby-gems distribution. If you don't have a system installed jruby, all sketches you would need to use the --nojruby flag to use the vendored jruby-complete eg
rp5 --nojruby run grapher.rb
Here is another link that might be useful re installing jdk7.
Monday, 25 November 2013
Running Ruby Processing from Netbeans-7.4
Hey this is a bit exciting I've managed to get ruby processing to run under Netbeans just checkout this screen shot:-
Labels:
netbeans-7.4,
ruby-processing-2.4.0 beta
Wednesday, 20 November 2013
A Rakefile to demo ruby-processing samples
Loosely based on a Shoes4 Rakefile, here is a Rakefile to demo ruby-processing files in a folder:-
# Simple demo Rakefile to autorun samples SAMPLES_DIR="/home/tux/samples/contributed" desc 'run demo' task :default => [:demo] desc 'demo' task :demo do samples_list.shuffle.each{|sample| run_sample sample} end def samples_list files = [] Dir.chdir(SAMPLES_DIR) Dir.glob("*.rb").each do |file| files << File.join(SAMPLES_DIR, file) end return files end def run_sample(sample_name) puts "Running #{sample_name}...quit to run next sample" system "rp5 run #{sample_name}" end
Labels:
demo,
Rakefile,
ruby-processing
Bleeding edge development of ruby-processing
I have just set myself up to do bleeding edge testing of ruby processing.
- To use the latest development version of jruby-complete I created this rake file.
- To use the latest development version of processing I cloned it from github.
- Did a linux build.
- Modified my .rp5rc to point PROCESSING_ROOT to the work folder (3)
To keep it separate I created a copy of my monkstone-branch to develop (taking care to remove the .git archive).
Update December 10th see a more recent blog entry for latest developments.
Update December 10th see a more recent blog entry for latest developments.
Labels:
bleeding edge,
gist,
github,
jruby-9000.dev,
ruby-processing
Tuesday, 19 November 2013
Testing the GLW renderer with ruby-processing
Andreas Colubri is working on an alternative renderer for processing (which seems to be stabilising as the GLW renderer). Here is an example sketch translated to ruby-processing requires processing-2.1.1 to run (OK development version as that is not currently available).
load_library :glw include_package 'processing.glw' def setup size(2560, 1440, GLW::P2D) frame_rate(180) # NB: here we are using the "processing" set frame rate method end def draw background(255, 0, 0) fill(255) # NB: here we access "processing" frame rate variable text("FPS: #{frame_rate}", mouse_x, mouse_y) end
Labels:
GLW,
NEWT,
processing-2.1.1,
ruby-processing
Tuesday, 12 November 2013
Working towards returning ruby-processing to gem distribution by rubygems.org
I have made the first steps toward returning ruby-processing to rubygems distribution. See my fork on github. This is work in progress, however it does work on Archlinux, and also should also work on the MAC, where the path to the processing jars should be stable?
- Install processing-2.1.0 (for your OS)
- Create or edit the YAML .rp5rc file to point to processing-root possibly using the sketch below (in the processing ide) config.pde
- Clone my fork
- cd ruby-processing (or whatever you call it)
- rake (MAC and linux) to see if tests work
- gem install ruby-processing-{version}.gem for more comprehensive testing
String processingRoot = "enter your processing root here"; // edit this line in the sketch String home; PFont font; void setup() { size(400, 200); font = createFont("Helvetica", 18); home = System.getProperty("user.home"); } void draw() { background(255); fill(255, 0, 0); textFont(font, 18); // this adds a blinking cursor after your text, at the expense of redrawing everything every frame text(processingRoot+(frameCount/10 % 2 == 0 ? "_" : ""), 35, 45); } void keyReleased() { if (key != CODED) { switch(key) { case BACKSPACE: processingRoot = processingRoot.substring(0, max(0, processingRoot.length()-1)); break; case ENTER: // save the processing root to the config file case RETURN: PrintWriter pw = createWriter(home + "/.rp5rc"); pw.write("PROCESSING_ROOT: \"" + processingRoot + "\""); pw.close(); break; case ESC: case DELETE: break; default: processingRoot += key; } } }
Labels:
jdk-7,
processing-2.1.0,
ruby-processing,
rubygems.org
Saturday, 2 November 2013
Promise for the future of jruby, ruby-processing
It was probably a bit too early when I last looked at tuning ruby processing, because it preceded the processing-2.1 release (now compiled for java 7, which means I can run ruby-processing with java 8). Also since I am looking to the future I will use jruby-9000.dev for future performance tests. The esfera test is good because it is dynamic (you can actually see both compiler and garbage collector kick-in, well thats unless I'm very much mistaken). Here are past results combined with current results using jruby-complete-9000.dev (2 November 2013 snapshot). On continued running current test stabilised at ca 6 fps. What the test doesn't show is elapsed time, because there is actual pause seen when I presume compiler kicks in (and the later lesser dips in performance must be the garbage collector).
These are my java args for the test (jdk 7 unless stated)
java_args.txt
PS: linux users it may also be worth doing the following, one-time exercise, to improve java startup
java_args.txt
- None
- Args 1. -XX:+TieredCompilation XX:CompileCommand=dontinline,org.jruby.runtime.invokedynamic.InvokeDynamicSupport::invocationFallback
- Args 2. -XX:+TieredCompilation -XX:TieredStopAtLevel=1 XX:CompileCommand=dontinline,org.jruby.runtime.invokedynamic.InvokeDynamicSupport::invocationFallback
- Args Java 8 -Xms2048M -Xmx2048M -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=80.
No Args | Args 1 | Args 2 | Java 8 |
---|---|---|---|
5.4547 | 5.17617 | 4.70084 | 5.27 |
4.26695 | 3.71662 | 2.90269 | 4.24 |
3.85179 | 3.22197 | 2.30053 | 3.889 |
3.769622 | 3.105720 | 2.077115 | 3.70 |
3.769622 | 3.122121 | 2.022429 | 4.15 |
3.756052 | 3.340643 | 1.940190 | 4.98 |
4.849481 | 3.122121 | 1.953019 | 5.03 |
5.173814 | 3.34064 | 5.09 |
PS: linux users it may also be worth doing the following, one-time exercise, to improve java startup
sudo java -Xshare:dump
Labels:
jdk8,
perfomance tuning,
ruby-processing
For Rails Hackers
I'm a bit disappointed so far with the response to my updating of ruby-processing to run with processing-2.1. Perhaps interest in the ruby language is on the decline, or could it be that rails hackers have become so dependent on their frameworks/tools they find it a challenge to work outside them (I mean just look at Shoes4 lots of meaningless tests many contributors, and it is travelling at snails pace to where? _why is surely less than impressed)!!! For inspiration just check out the Karsten Schmidt story.
Eyeo 2013 - Karsten Schmidt from Eyeo Festival on Vimeo.
Eyeo 2013 - Karsten Schmidt from Eyeo Festival on Vimeo.
Labels:
simple made easy.
Wednesday, 30 October 2013
An opportunity to restore ruby-processing as a rubygem distributable gem?
It occurs to me that at least on ArchLinux (since processing-2.0.1) and the Mac (since processing-2.1) the location (path) of processing jars could be relied on (albeit OS specific). Further the majority of sketches can now be run with an installed jruby (which is now the default) thus we could exclude jruby-complete and the processing jars from the gem, and we would easily return to rubygems distribution. It would be sensible to retain the the jruby-complete as an optional post install to enable access to shader sketches and possibly still support application export, although that would not be a priority. The folks at processing are still inviting integration with the processing ide (see below), but I would prefer ruby-processing to stick with the ruby ecology.
Our sister project Ruby-Processing version 2.2.0 is now available from github: https://t.co/rC2Quwz3hz
— Processing (@ProcessingOrg) October 10, 2013
Who wants to make a Ruby-Processing Mode for the PDE?
— Processing (@ProcessingOrg) October 10, 2013
Labels:
archlinux,
mac,
processing,
rubygems
Saturday, 26 October 2013
Using shaders in ruby-processing (tutorial example translated)
Anyone interested in using shaders in ruby-processing should read the vanilla processing tutorial here. All the code for the tutorial is available here, including the necessary glsl shader (and image) files used in this sketch, which is translated from one of the included examples.You might also like to read the codeanticode blog (by Andrés Colubri) to keep up to date with latest developments.
# Texture from Jason Liebig's FLICKR collection of vintage labels and wrappers: # http://www.flickr.com/photos/jasonliebigstuff/3739263136/in/photostream/ CAN_SIZE = 60 attr_reader :label, :can, :cap, :angle, :color_shader, :light_shader, :texlight_shader attr_reader :sel_shader, :pixlight_shader, :tex_shader, :texlightx_shader, :bw_shader attr_reader :edges_shader, :use_texture, :use_light, :emboss_shader def setup size(480, 480, P3D) @label = load_image("lachoy.jpg") @can = create_can(CAN_SIZE, 2 * CAN_SIZE, 32, label) @cap = create_cap(CAN_SIZE, 32) @angle = 0 @color_shader = load_shader("colorfrag.glsl", "colorvert.glsl") @light_shader = load_shader("lightfrag.glsl", "lightvert.glsl") @tex_shader = load_shader("texfrag.glsl", "texvert.glsl") @texlight_shader = load_shader("texlightfrag.glsl", "texlightvert.glsl") @pixlight_shader = load_shader("pixlightfrag.glsl", "pixlightvert.glsl") @texlightx_shader = load_shader("pixlightxfrag.glsl", "pixlightxvert.glsl") @bw_shader = load_shader("bwfrag.glsl") @edges_shader = load_shader("edgesfrag.glsl") @emboss_shader = load_shader("embossfrag.glsl") @sel_shader = texlight_shader @use_light = true @use_texture = true puts "Vertex lights, texture shading" end def draw background(0) x = 1.88 * CAN_SIZE y = 2 * CAN_SIZE 3.times do 3.times do draw_can(x, y, angle) x += (2 * CAN_SIZE + 8) end x = 1.88 * CAN_SIZE y += (2 * CAN_SIZE + 5) end @angle += 0.01 end def draw_can( centerx, centery, rot_angle) push_matrix if (use_light) point_light(255, 255, 255, centerx, centery, 200) end shader(sel_shader) translate(centerx, centery, 65) rotate_y(rot_angle) if (use_texture) can.set_texture(label) else can.set_texture(nil) end shape(can) no_lights reset_shader push_matrix translate(0, CAN_SIZE - 5, 0) shape(cap) pop_matrix push_matrix translate(0, -CAN_SIZE + 5, 0) shape(cap) pop_matrix pop_matrix end def create_can(r, h, detail, tex) texture_mode(NORMAL) sh = create_shape sh.begin_shape(QUAD_STRIP) sh.no_stroke sh.texture(tex) (0 .. detail).each do |i| angle = TAU / detail x = sin(i * angle) z = cos(i * angle) u = i.to_f / detail sh.normal(x, 0, z) sh.vertex(x * r, -h/2, z * r, u, 0) sh.vertex(x * r, +h/2, z * r, u, 1) end sh.end_shape return sh end def create_cap(r, detail) sh = create_shape sh.begin_shape(TRIANGLE_FAN) sh.no_stroke sh.fill(128) sh.vertex(0, 0, 0) (0 ... detail).each do |i| angle = TAU / detail x = sin(i * angle) z = cos(i * angle) sh.vertex(x * r, 0, z * r) end sh.end_shape return sh end def key_pressed case key when '1' puts "No lights, no texture shading" @sel_shader = color_shader @use_light = false @use_texture = false when '2' puts "Vertex lights, no texture shading" @sel_shader = light_shader @use_light = true @use_texture = false when '3' puts "No lights, texture shading" @sel_shader = tex_shader @use_light = false @use_texture = true when '4' puts "Vertex lights, texture shading" @sel_shader = texlight_shader @use_light = true @use_texture = true when '5' puts "Pixel lights, no texture shading" @sel_shader = pixlight_shader @use_light = true @use_texture = false when '6' puts "Pixel lights, texture shading" @sel_shader = texlightx_shader @use_light = true @use_texture = true when '7' puts "Black&white texture filtering" @sel_shader = bw_shader @use_light = false @use_texture = true when '8' puts "Edge detection filtering" @sel_shader = edges_shader @use_light = false @use_texture = true when '9' puts "Emboss filtering" @sel_shader = emboss_shader @use_light = false @use_texture = true end end
Emboss Filtering |
Labels:
GLSL shader,
ruby-processing,
tutorial
Friday, 25 October 2013
Low Level GL Shader Sketch in Ruby-Processing
Here is a sketch translated from the vanilla processing examples (where to get frag.gsl and vert.gsl), to run on the latest version of ruby-processing.
include_package 'java.nio' java_import 'processing.opengl.PGL' attr_reader :sh, :vert_loc, :color_loc, :vert_data, :color_data def setup size(640, 360, P3D) # Loads a shader to render geometry w/out # textures and lights. @sh = loadShader("frag.glsl", "vert.glsl") @vert_data = allocate_direct_float_buffer(12) @color_data = allocate_direct_float_buffer(12) end def draw background(0) # The geometric transformations will be automatically passed # to the shader. rotate(frame_count * 0.01, width, height, 0) update_geometry pgl = beginPGL sh.bind @vert_loc = pgl.getAttribLocation(sh.glProgram, "vertex") @color_loc = pgl.getAttribLocation(sh.glProgram, "color") pgl.enableVertexAttribArray(vert_loc) pgl.enableVertexAttribArray(color_loc) pgl.vertexAttribPointer(vert_loc, 4, PGL.FLOAT, false, 0, vert_data) pgl.vertexAttribPointer(color_loc, 4, PGL.FLOAT, false, 0, color_data) pgl.drawArrays(PGL.TRIANGLES, 0, 3) pgl.disableVertexAttribArray(vert_loc) pgl.disableVertexAttribArray(color_loc) sh.unbind endPGL end def update_geometry # Vertex 1 vertices = [0, 0, 0, 1] colors = [1, 0, 0, 1] # Corner 2 vertices += [width/2, height, 0, 1] colors += [0, 1, 0, 1] # Corner 3 vertices += [width, 0, 0, 1] colors += [0, 0, 1, 1] vert_data.rewind vert_data.put(vertices.to_java :float) vert_data.position(0) color_data.rewind color_data.put(colors.to_java :float) color_data.position(0) end def allocate_direct_float_buffer(n) ByteBuffer.allocateDirect(n * java.lang.Float::SIZE/8).order(ByteOrder.nativeOrder).asFloatBuffer end
Labels:
GLSL shader,
low level GL,
ruby-processing
Monday, 21 October 2013
Penrose Snowflake Revisited
The 1st time I revisited this sketch was in response to some refactoring by Dan Myer see http://learning-ruby-processing.blogspot.co.uk/2010/01/refactoring-my-penrose-snowflake.html. Since the advent of OPENGL for two dimensional sketches, that is all old hat, since we no longer need to keep generating the geometry, we can create a shape and reuse it (multiple times in the same sketch if need be). So here we use a generic grammar library for simple lsystems:-
Here is the animation code adapted from a processing example:-
Here is the penrose snowflake
############################ # Simple lsystem grammar ############################ class Grammar attr_reader :axiom, :rules def initialize(axiom, rules) @axiom = axiom @rules = rules end def expand(production, iterations, &block) production.each_char do |token| if rules.has_key?(token) && iterations > 0 expand(rules[token], iterations - 1, &block) else yield token end end end def each gen expand(axiom, gen) {|token| yield token } end def generate gen output = [] each(gen){ |token| output << token } return output end end
Here is the animation code adapted from a processing example:-
# A class to describe a Polygon (with a PShape) class Polygon include Processing::Proxy # The PShape object attr_reader :s, :x, :y, :speed, :height def initialize(s_, width, height) @x = rand(width) @y = rand(height * -1.5 .. -height / 3) @s = s_ @speed = rand(2 .. 6) @height = height end # Simple motion def move @y +=speed @y = -100 if (y > height + 100) end # Draw the object def display push_matrix translate(x, y) shape(s) pop_matrix end def run display move end end
Here is the penrose snowflake
load_libraries :grammar, :polygon class PenroseSnowflake include Processing::Proxy import 'grammar' attr_accessor :axiom, :grammar, :start_length, :theta, :production, :draw_length, :repeats, :xpos, :ypos DELTA = Math::PI / 10 # 18 degrees as radians def initialize width reset width end def reset width @axiom = "F3-F3-F3-F3-F" @grammar = Grammar.new( axiom, {"F" => "F3-F3-F45-F++F3-F"} ) @start_length = width / 40 @theta = 0 @xpos = width / 80 @ypos = 0 @draw_length = start_length end ############################################################################## # Parses the production string, and draws a line when 'F' is found, uses # trignometry to calculate dx and dy rather than processing transforms ############################################################################## def create_flake production flake = create_shape fil = [200, 220, 255].sample flake.begin_shape flake.fill fil flake.stroke fil flake.vertex(xpos, ypos) repeats = 1 production.each do |element| case element when 'F' flake.vertex(@xpos -= multiplier(repeats, :cos), @ypos += multiplier(repeats, :sin)) repeats = 1 when '+' @theta += DELTA * repeats repeats = 1 when '-' @theta -= DELTA * repeats repeats = 1 when '3', '4', '5' repeats += element.to_i else puts "Character '#{element}' is not in grammar" end end flake.end_shape CLOSE return flake end ########################################## # adjust draw length with number of repeats # uses grammar to set production string # see 'grammar.rb' ########################################## def create_grammar(gen) @draw_length *= 0.4**gen @production = grammar.generate gen end ########################################### # a helper method that returns dx or dy with type & repeat # multiplier after Dan Mayer ########################################### def multiplier(repeats, type) value = draw_length * repeats # using equal? for identity comparison (type.equal? :cos)? value * cos(theta) : value * sin(theta) end end ## # Lindenmayer System in ruby-processing by Martin Prout # Very loosely based on a processing Penrose L-System # by Geraldine Sarmiento ### attr_reader :polygons def setup size displayWidth, displayHeight, P2D #stroke 255 flakes = [] @polygons = [] penrose = PenroseSnowflake.new width (2 .. 4).each do |i| production = penrose.create_grammar(i) flakes << penrose.create_flake(production) penrose.reset width end 40.times do polygons << Polygon.new(flakes.sample, width, height) end end def draw background 0 # Display and move them all polygons.each do |poly| poly.run end end
Labels:
penrose snowflake,
PShape 2D,
retained shape
Wednesday, 16 October 2013
Graphic Exploration of Jruby tuning in ruby-processing
The esfera sketch in vanilla processing is in the demo (performance category) and has proved to an interesting test case for various perfomance tune-ups in jruby. For this sketch the rolling fps is a good measure of performance.
Args 1. -XX:+TieredCompilation XX:CompileCommand=dontinline,org.jruby.runtime.invokedynamic.InvokeDynamicSupport::invocationFallback
Args 2. -XX:+TieredCompilation -XX:TieredStopAtLevel=1 XX:CompileCommand=dontinline,org.jruby.runtime.invokedynamic.InvokeDynamicSupport::invocationFallback
Thereafter no args stabilized at ca 5.4 fps whereas "Args 1" stabilized at ca 5.7 fps. So compilation Tiered compilation beyond level 1 gives best performance, eventually.
java_args.txt
NoneArgs 1. -XX:+TieredCompilation XX:CompileCommand=dontinline,org.jruby.runtime.invokedynamic.InvokeDynamicSupport::invocationFallback
Args 2. -XX:+TieredCompilation -XX:TieredStopAtLevel=1 XX:CompileCommand=dontinline,org.jruby.runtime.invokedynamic.InvokeDynamicSupport::invocationFallback
No Args | Args 1 | Args 2 |
---|---|---|
5.4547 | 5.17617 | 4.70084 |
4.26695 | 3.71662 | 2.90269 |
3.85179 | 3.22197 | 2.30053 |
3.769622 | 3.105720 | 2.077115 |
3.769622 | 3.122121 | 2.022429 |
3.756052 | 3.340643 | 1.940190 |
4.849481 | 3.122121 | 1.953019 |
5.173814 | 3.34064 |
Thereafter no args stabilized at ca 5.4 fps whereas "Args 1" stabilized at ca 5.7 fps. So compilation Tiered compilation beyond level 1 gives best performance, eventually.
Tuesday, 8 October 2013
Multiple panels example grafica library
Sometime using array as method args is not such a good idea, here we need to explicitly cast our ruby arrays to Java::float arrays.
Since updated for JRubyArt
load_library :grafica include_package 'grafica' N_POINTS = 21 def setup size(500, 500) background(255) first_plot_pos = [0, 0] panel_dim = [200, 200] margins = [60, 70, 40, 30] # Create four plots to represent the 4 panels plot1 = GPlot.new(self) plot1.set_pos(first_plot_pos.to_java(Java::float)) plot1.set_mar([0, margins[1], margins[2], 0]) plot1.set_dim(panel_dim.to_java(Java::float)) plot1.set_axes_offset(0) plot1.set_ticks_length(-4) plot1.getXAxis.set_draw_tick_labels(false) plot2 = GPlot.new(self) plot2.set_pos(first_plot_pos[0] + margins[1] + panel_dim[0], first_plot_pos[1]) plot2.set_mar([0, 0, margins[2], margins[3]]) plot2.set_dim(panel_dim.to_java(Java::float)) plot2.set_axes_offset(0) plot2.set_ticks_length(-4) plot2.getXAxis.set_draw_tick_labels(false) plot2.getYAxis.set_draw_tick_labels(false) plot3 = GPlot.new(self) plot3.set_pos(first_plot_pos[0], first_plot_pos[1] + margins[2] + panel_dim[1]) plot3.set_mar([margins[0], margins[1], 0, 0]) plot3.set_dim(panel_dim.to_java(Java::float)) plot3.set_axes_offset(0) plot3.set_ticks_length(-4) plot4 = GPlot.new(self) plot4.set_pos(first_plot_pos[0] + margins[1] + panel_dim[0], first_plot_pos[1] + margins[2] + panel_dim[1]) plot4.set_mar([margins[0], 0, 0, margins[3]]) plot4.set_dim(panel_dim.to_java(Java::float)) plot4.set_axes_offset(0) plot4.set_ticks_length(-4) plot4.getYAxis.set_draw_tick_labels(false) # Prepare the points for the four plots points1 = GPointsArray.new(N_POINTS) points2 = GPointsArray.new(N_POINTS) points3 = GPointsArray.new(N_POINTS) points4 = GPointsArray.new(N_POINTS) N_POINTS.times do |i| points1.add(sin(TAU*i/(N_POINTS-1)), cos(TAU*i/(N_POINTS-1))) points2.add(i, cos(TAU*i/(N_POINTS-1))) points3.add(sin(TAU*i/(N_POINTS-1)), i) points4.add(i, i) end # Set the points, the title and the axis labels plot1.set_points(points1) plot1.getYAxis.set_axis_label_text("cos(i)") plot1.set_title_text("Plot with multiple panels") plot1.get_title.set_relative_pos(1) plot1.get_title.set_text_alignment(CENTER) plot2.set_points(points2) plot3.set_points(points3) plot3.getXAxis.set_axis_label_text("sin(i)") plot3.getYAxis.set_axis_label_text("i") plot3.setInvertedYScale(true) plot4.set_points(points4) plot4.getXAxis.set_axis_label_text("i") plot4.setInvertedYScale(true) # Draw the plots plot1.begin_draw plot1.draw_box plot1.drawXAxis plot1.drawYAxis plot1.draw_top_axis plot1.draw_right_axis plot1.draw_title plot1.draw_points plot1.draw_lines plot1.end_draw plot2.begin_draw plot2.draw_box plot2.drawXAxis plot2.drawYAxis plot2.draw_top_axis plot2.draw_right_axis plot2.draw_points plot2.draw_lines plot2.end_draw plot3.begin_draw plot3.draw_box plot3.drawXAxis plot3.drawYAxis plot3.draw_top_axis plot3.draw_right_axis plot3.draw_points plot3.draw_lines plot3.end_draw plot4.begin_draw plot4.draw_box plot4.drawXAxis plot4.drawYAxis plot4.draw_top_axis plot4.draw_right_axis plot4.draw_points plot4.draw_lines plot4.end_draw end
Since updated for JRubyArt
Monday, 7 October 2013
Reading csv data into a grafica sketch in ruby-processing
The clear superiority of ruby-processing in dealing with csv data is self evident in this sketch.
Get the grafica library by jagracar here.
Since updated for JRubyArt
require 'csv' load_library :grafica include_package 'grafica' MONTH_NAMES = %w(January February March April May June July August September October November December) DAYS_PER_MONTH = [31,28,31,30,31,30,31,31,30,31,30,31] DAYS_PER_MONTH_LEAP_YEAR = [31,29,31,30,31,30,31,31,30,31,30,31] attr_reader :plot, :points_oktoberfest, :points_elections def setup size(800, 400) # Load the Oktoberfest vs. Bundestagswahl (German elections day) Google # search history file (obtained from the Google trends page). # The csv file has the following format: # year,month,day,oktoberfest,bundestagswahl # 2004,0,1,5,1 # ... @points_oktoberfest = GPointsArray.new @points_elections = GPointsArray.new data = CSV.read("data/OktoberfestVSGermanElections.csv", :headers => true).map{|row| row.to_hash} data.each do |row| # You access the values via their column name (set by using headers option above) year = row["year"].to_i month = row["month"].to_i day = row["day"].to_i date = get_exact_date(year, month, day) oktoberfest_count = row["oktoberfest"].to_i elections_count = row["bundestagswahl"].to_i points_oktoberfest.add(date, oktoberfest_count, MONTH_NAMES[month]) points_elections.add(date, elections_count, MONTH_NAMES[month]) end # Create the plot @plot = GPlot.new(self) plot.set_dim(700, 300) plot.set_title_text("Oktoberfest vs. Bundestagwahl Google search history") plot.getXAxis.set_axis_label_text("Year") plot.getYAxis.set_axis_label_text("Google normalized searches") plot.getXAxis.setNTicks(10) plot.set_points(points_oktoberfest) plot.set_line_color(color(100, 100, 100)) plot.add_layer("German elections day", points_elections) plot.get_layer("German elections day").set_line_color(color(255, 100, 255)) plot.activate_point_labels end def draw background(255) # Draw the plot plot.begin_draw plot.draw_box plot.drawXAxis plot.drawYAxis plot.draw_title plot.draw_grid_lines(GPlot::VERTICAL) plot.draw_filled_contours(GPlot::HORIZONTAL, 0) plot.draw_legend(%w(Oktoberfest Bundestagswahl), [0.07,0.22], [0.92, 0.92]) plot.draw_labels plot.end_draw end def get_exact_date(year, month, day) leap_year = false if (year % 400 == 0) leap_year = true elsif (year % 100 == 0) leap_year = false elsif (year % 4 == 0) leap_year = true end if leap_year return year + (month + (day - 1) / DAYS_PER_MONTH_LEAP_YEAR[month]) / 12.0 else return year + (month + (day - 1)/ DAYS_PER_MONTH[month]) / 12.0 end end
Since updated for JRubyArt
Labels:
csv,
grafica,
oktoberfest,
ruby-processing
Using the grafica library in ruby-processing
Get the grafica library by jagracar here.
The output
Since updated for JRubyArt
load_library :grafica include_package 'grafica' POINTS = 100 def setup size(500, 350) background(150) # Prepare the points for the plot points = GPointsArray.new(POINTS) POINTS.times do |i| points.add(i, 10 * noise(0.1 * i)) end # Create a new plot and set its position on the screen plot = GPlot.new(self) plot.set_pos(25, 25) # Set the plot title and the axis labels plot.set_points(points) plot.getXAxis.setAxisLabelText("x axis") plot.getYAxis.setAxisLabelText("y axis") plot.setTitleText("A very simple example") # Draw it! plot.default_draw end
The output
Since updated for JRubyArt
Labels:
data,
grafica library,
graphs,
ruby-processing
Saturday, 5 October 2013
A custom Vector library for ruby processing
I recently got my copy of Practical Object Oriented Design in Ruby by Sandi Metz book, this got me thinking what could I could apply the ideas to in ruby-processing, and here is an early crack at it. Creating a custom (pure-ruby) vector library which can replace the hybrid RPVector (that extends PVector from processing) class of a previous post. This is very much a first crack (but it works, only difference needed is load_library :vec and use normalize! instead of normalize, much more ruby like I think) because I have ideas for extending the functionality along some of these lines, however my sentiment is with toxi re simple made easy. Further if I use vanilla processing logic the cross_product method (modulus, dist etc) could all live in Vec, but I can easily defer that decision. I haven't at this stage made use distance_squared externally, however this will be more efficient for testing boundary conditions of say a bouncing ball than regular dist. Not shown here are the rspec tests that I've been using to ensure the code behaves, I am tempted to bundle this and a Quaternion class and possibly some others as a core ruby-processing library, since the operations of PVector are not at all ruby like, and many more people seem to come to ruby-processing from ruby, not the other way round sadly.
A Little Test courtesy of Daniel Shiffman
Now interestingly the following also works so you can use the
class Vec attr_accessor :x, :y, :z EPSILON = 9.999999747378752e-05 # a value used by processing.org def initialize(x = 0 ,y = 0, z = 0) @x, @y, @z = x, y, z post_initialize end def post_initialize nil end def ==(vec) (x - vec.x).abs < EPSILON && (y - vec.y).abs < EPSILON && (z - vec.z).abs < EPSILON end end class Vec2D < Vec # Modulus of vec. Also known as length, size or norm def modulus Math.hypot(x, y) end def self.dist_squared(vec_a, vec_b) (vec_a.x - vec_b.x)**2 + (vec_a.y - vec_b.y)**2 end def self.dist(vec_a, vec_b) Math.hypot(vec_a.x - vec_b.x, vec_a.y - vec_b.y) end # vanilla processing returns a Vector, rather than Scalar (defaults to 3D result when z = 0) def cross_product(vec) x * vec.y - y * vec.x end # Scalar product, also known as inner product or dot product def dot(vec) x * vec.x + y * vec.y end def collinear_with?(vec) cross_product(vec).abs < EPSILON end def +(vec) Vec2D.new(x + vec.x, y + vec.y) end def -(vec) Vec2D.new(x - vec.x, y - vec.y) end def *(scalar) Vec2D.new(x * scalar, y * scalar) end def / (scalar) Vec2D.new(x / scalar, y / scalar) unless scalar == 0 end def normalize! @x, @y = x / modulus, y / modulus return self end alias :mag :modulus end class Vec3D < Vec def modulus Math.sqrt(x**2 + y**2 + z**2) end def self.dist_squared(vec_a, vec_b) (vec_a.x - vec_b.x)**2 + (vec_a.y - vec_b.y)**2 + (vec_a.z - vec_b.z)**2 end def self.dist(vec_a, vec_b) Math.sqrt(self.dist_squared(vec_a, vec_b)) end def cross_product(vec) xc = y * vec.z - z * vec.y yc = z * vec.x - x * vec.z zc = x * vec.y - y * vec.x Vec3D.new(xc, yc, zc) end # Scalar product, also known as inner product or dot product def dot(vec) x * vec.x + y * vec.y + z * vec.z end def collinear_with?(vec) cross_product(vec) == Vec3D.new end def +(vec) Vec3D.new(x + vec.x, y + vec.y, z + vec.z) end def -(vec) Vec3D.new(x - vec.x, y - vec.y, z - vec.z) end def * (scalar) Vec3D.new(x * scalar, y * scalar, z * scalar) end def / (scalar) Vec3D.new(x / scalar, y / scalar, z / scalar) unless scalar.abs < EPSILON end def normalize! @x, @y, @z = x / modulus, y / modulus, z / modulus return self end alias :mag :modulus end
A Little Test courtesy of Daniel Shiffman
# # Vector # by Daniel Shiffman. # # Demonstration some basic vector math: subtraction, normalization, scaling # Normalizing a vector sets its length to 1. # load_library :vec def setup size(640,360) end def draw background(0) # A vector that points to the mouse location mouse = Vec2D.new(mouse_x, mouse_y) # A vector that points to the center of the window center = Vec2D.new(width/2,height/2) # Subtract center from mouse which results in a vector that points from center to mouse mouse = mouse - center # note need assign result to mouse # Normalize the vector the ! means we are changing the value of mouse mouse.normalize! # Multiply its length by 150 (Scaling its length) mouse = mouse * 150 # note need assign the result to mouse translate(width/2,height/2) # Draw the resulting vector stroke(255) stroke_weight(4) line(0, 0, mouse.x, mouse.y) end
Now interestingly the following also works so you can use the
+=, -=, /=, and *= assignment methods ( but you cannot override += etc as a methods unlike C++ )So what this means is that in ruby += etc are just syntactic shortcuts, and not an operator in its own right (which is probably a good thing).
# # Vector # by Daniel Shiffman. # # Demonstration some basic vector math: subtraction, normalization, scaling # Normalizing a vector sets its length to 1. # load_library :vec def setup size(640,360) end def draw background(0) # A vector that points to the mouse location mouse = Vec2D.new(mouse_x, mouse_y) # A vector that points to the center of the window center = Vec2D.new(width/2,height/2) # Subtract center from mouse which results in a vector that points from center to mouse mouse -= center # note we can assign result to mouse using -= # Normalize the vector the ! means we are changing the value of mouse mouse.normalize! # Multiply its length by 150 (Scaling its length) mouse *= 150 # note we can assign result to mouse using *= translate(width/2,height/2) # Draw the resulting vector stroke(255) stroke_weight(4) line(0, 0, mouse.x, mouse.y) end
Thursday, 3 October 2013
Checking out jruby-complete-9000.dev.jar (waiting for jruby-1.7.5)
I just tested the 2 October 2013 snapshot of jruby-complete-9000 with ruby-processing, so far so good (still issue with fisica library that I had thought had gone away with jruby-1.7.5.dev, but I might have been using my "corrected" version of the fisica library, anyway I will be interested to see the effect of Charlies pruning basically removing ruby-1.8.7 compatibility). I've also been reviewing "app.rb", with a view to being a bit more specific about which processing classes to import. Having failed abysmally to make any use of processing event classes directly, they are in firing line. Also I will only import opengl classes for P2D and P3D sketches (work in progress, will be ready for next ruby-processing commit to coincide with jruby-1.7.5 release). On the processing front a new release of vanilla processing may not be too far away either (at long last, and then probably only because of the Mac Retina display issue, java version is going to be upgraded to version 1.7.0_40).
Labels:
jruby-9000,
Mac Retina,
ruby-processing,
vanilla processing
Subscribe to:
Posts (Atom)
Followers
Blog Archive
-
▼
2013
(94)
-
►
November
(8)
- Ruby-processing on MacOSX, Apple or Oracle JVM
- Running Ruby Processing from Netbeans-7.4
- A Rakefile to demo ruby-processing samples
- Bleeding edge development of ruby-processing
- Testing the GLW renderer with ruby-processing
- Working towards returning ruby-processing to gem d...
- Promise for the future of jruby, ruby-processing
- For Rails Hackers
-
►
October
(10)
- An opportunity to restore ruby-processing as a rub...
- Using shaders in ruby-processing (tutorial example...
- Low Level GL Shader Sketch in Ruby-Processing
- Penrose Snowflake Revisited
- Graphic Exploration of Jruby tuning in ruby-proces...
- Multiple panels example grafica library
- Reading csv data into a grafica sketch in ruby-pro...
- Using the grafica library in ruby-processing
- A custom Vector library for ruby processing
- Checking out jruby-complete-9000.dev.jar (waiting ...
-
►
November
(8)
About Me
- monkstone
- I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2