Personal JRubyArt blog
Monkstone
Ruby-Processing group blog
Ruby Processing Group
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
# 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
# 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
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
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) endOK a bit more experimentation also works with FX2D, blows up with P2D, but that's the same with vanilla processing (threading error).
# 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
// 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...
# 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
# 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
# We extend the language of conditionals by adding the # keyword "elsif". This allows conditionals to ask # two or more sequential questions, each with a different # action. def setup background 0 2.step(by: 2, to: width - 2) do |i| # If 'i' divides by 20 with no remainder # draw the first line.. # else if 'i' divides by 10 with no remainder # draw second line, else draw third line if (i % 20) == 0 stroke 255 line i, 80, i, height / 2 elsif (i % 10) == 0 stroke 153 line i, 20, i, 180 else stroke 102 line i, height / 2, i, height - 20 end end end def settings size 640, 360 end
class JWishy < Processing::App # bare sketch code endBare sketches instead get listed as the super class, but to be honest listing of the code in the pry console is not that exciting see embedded video, the exciting bit is to be able to futz with sketch code from the console and watch it affect the running console (but why not try it for yourself). In the "Wishy Worm" example we change the background of the sketch by changing the @back_color variable, and change the bluish accessor method to a custom method that returns bluish as function of the y_wiggle variable
Live coding in ruby-processing now using pry
Bounce.rb code used in video# An pry shell for live coding. # Will start with your sketch. require_relative 'base' Processing.load_and_run_sketch ARGV.clear # So that pry doesn't try to load them as files. require 'pry' $app.pry
class Fred < Processing::App def setup sketch_title 'Fred' end def draw end def settings size 300, 300, FX2D # smooth # here end end
# experimental ArcBall class class ArcBall attr_reader :applet, :x, :y, :r def initialize(app:, center_x: nil, center_y: nil, radius: nil) @applet = app @x = (center_x.nil?) ? app.width * 0.5 : center_x @y = (center_y.nil?) ? app.height * 0.5 : center_y @r = (radius.nil?) ? app.width * 0.8 : radius end def to_s format('ArcBall.new(applet: %s, centre_x: %d, centre_y: %d, radius: %d)', applet, x, y, r) end end Applet = Struct.new(:width, :height) do def to_s 'MyApplet' end end applet = Applet.new(800, 600) puts ArcBall.new(app: applet).to_s puts ArcBall.new(app: applet, center_x: 300, center_y: 200, radius: 800).to_s
ArcBall.new(applet: MyApplet, centre_x: 400, centre_y: 300, radius: 640) ArcBall.new(applet: MyApplet, centre_x: 300, centre_y: 200, radius: 800)
load_library :arcball def setup sketch_title 'Arcball Box' ArcBall.new(app: self) fill 180 end def draw background 50 box 300, 300, 300 end def settings size 600, 600, P3D smooth 8 end # experimental ArcBall class class ArcBall include_package 'arcball' attr_reader :applet, :x, :y, :r def initialize(app:, center_x: nil, center_y: nil, radius: nil) @applet = app @x = (center_x.nil?) ? app.width * 0.5 : center_x @y = (center_y.nil?) ? app.height * 0.5 : center_y @r = (radius.nil?) ? app.width * 0.8 : radius app = JarcBall.new applet.to_java, x.to_java(:float), y.to_java(:float), r.to_java(:float) app.set_active true end def to_s format('ArcBall.new(applet: %s, centre_x: %d, centre_y: %d, radius: %d)', applet, x, y, r) end end
cp jruby/lib/jruby.jar myapp.jar # adjust path to jruby.jar echo "puts 'hello'" >> jar-bootstrap.rb jar ufe myapp.jar org.jruby.JarBootstrapMain jar-bootstrap.rb java -jar myapp.jar
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Built-By: tux Created-By: Apache Maven 3.3.3 Build-Jdk: 1.8.0_45 Main-Class: org.jruby.JarBootstrapMain
Using refined includes in ruby-processing, don't over pollute your classes: http://t.co/WQ9OmnvgcV
— monkstone (@monkstoneT) June 26, 2015
load_library :hemesh # Module used to include java packages module MS include_package 'wblut.math' include_package 'wblut.processing' include_package 'wblut.hemesh' include_package 'wblut.geom' end NUM = 50 attr_reader :mesh, :render, :points def setup sketch_title 'Sponge' ArcBall.init(self) create_mesh @render = MS::WB_Render3D.new(self) end def draw background(255) directional_light(255, 255, 255, 1, 1, -1) directional_light(127, 127, 127, -1, -1, 1) stroke(0) render.draw_edges(mesh) no_stroke render.draw_faces(mesh) end def mouse_pressed create_mesh end def create_mesh rs = MS::WB_RandomOnSphere.new creator = MS::HEC_ConvexHull.new @points = (0..NUM).map { rs.next_point.mul_self(300.0) } creator.set_points(points) creator.setN(NUM) @mesh = MS::HE_Mesh.new(creator) @mesh = MS::HE_Mesh.new(MS::HEC_Dual.new(mesh)) ext = MS::HEM_Extrude.new.set_chamfer(25).set_relative(false) mesh.modify(ext) sel = ext.extruded ext = MS::HEM_Extrude.new.set_distance(-40) mesh.modify_selected(ext, sel) mesh.smooth(2) end def settings size(800, 800, P3D) smooth(8) end
# A ruby processing-3.0 sketch # # # This example implements a custom VolumetricSpace using an implicit function # to calculate each voxel. This is slower than the default array or HashMap # based implementations, but also has much less memory requirements and so might # be an interesting and more viable approach for very highres voxel spaces # (e.g. >32 million voxels). This implementation here also demonstrates how to # achieve an upper boundary on the iso value (in addition to the one given and # acting as lower threshold when computing the iso surface) # # Usage: # move mouse to rotate camera # w: toggle wireframe on/off # -/=: zoom in/out # l: apply laplacian mesh smooth # # # # Copyright (c) 2010 Karsten Schmidt & ruby-processing version Martin Prout 2012 # This sketch relies on a custom toxiclibscore library for PovRAY export # # This library is free software you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation either # version 2.1 of the License, or (at your option) any later version. # # http://creativecommons.org/licenses/LGPL/2.1/ # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # require 'toxiclibs' load_library :vecmath RES = 64 ISO = 0.2 MAX_ISO = 0.66 attr_reader :mesh, :gfx, :curr_zoom, :is_wire_frame def setup sketch_title 'Isosurface' ArcBall.init(self) @gfx = Gfx::ToxiclibsSupport.new(self) vol = EvaluatingVolume.new(TVec3D.new(400, 400, 400), RES, RES, RES, MAX_ISO) surface = Volume::HashIsoSurface.new(vol) @mesh = WETriangleMesh.new surface.compute_surface_mesh(mesh, ISO) @is_wire_frame = false end def settings size(720, 720, P3D) end def draw background(200, 0, 200) if is_wire_frame no_fill stroke(255) else fill(255) no_stroke define_lights lights end @gfx.mesh(mesh, true) end def key_pressed case key when 'w', 'W' @is_wire_frame = !is_wire_frame when 'l', 'L' LaplacianSmooth.new.filter(mesh, 1) when 's', 'S' save_frame('implicit.png') end end def define_lights ambient_light(50, 50, 50) point_light(30, 30, 30, 200, -150, 0) directional_light(0, 30, 50, 1, 0, 0) spot_light(30, 30, 30, 0, 40, 200, 0, -0.5, -0.5, PI / 2, 2) end # Creating a volumetric space class # class EvaluatingVolume < Volume::VolumetricSpace include Processing::Proxy attr_reader :upper_bound FREQ = PI * 3.8 def initialize(scal_vec, resX, resY, resZ, upper_limit) super(scal_vec, resX, resY, resZ) @upper_bound = upper_limit end def clear # nothing to do here end def getVoxelAt(i) getVoxel(i % resX, (i % sliceRes) / resX, i / sliceRes) end def getVoxel(x, y, z) # can't overload so we renamed val = 0 if x > 0 && x < resX1 && y > 0 && y < resY1 && z > 0 && z < resZ1 xx = x * 1.0 / resX - 0.5 # NB: careful about integer division !!! yy = y * 1.0 / resY - 0.5 zz = z * 1.0 / resZ - 0.5 val = cos(xx * FREQ) * sin(yy * FREQ) + cos(yy * FREQ) * sin(zz* FREQ) + cos(zz * FREQ) * sin(xx * FREQ) # val = sin(xx * FREQ) + cos(yy * FREQ) + sin(zz * FREQ) # val = sin(xx * FREQ) * (xx * FREQ) + sin(yy * FREQ) * (yy * FREQ) + sin(zz * FREQ) * (zz * FREQ) val = 0 if val > upper_bound end val end end
# Description: # This is a full-screen demo # Since processing-3.0a10 set in settings class FullScreen < Processing::App def setup sketch_title 'Full Screen' no_stroke end def draw lights background 0 fill 120, 160, 220 (width/100).times do |x| (height/100).times do |y| new_x, new_y = x * 100, y * 100 push_matrix translate new_x + 50, new_y + 50 rotate_y(((mouse_x.to_f + new_x) / width) * Math::PI) rotate_x(((mouse_y.to_f + new_y) / height) * Math::PI) box 90 pop_matrix end end end def settings full_screen P3D end endPS: does not need to be a class wrapped sketch any-more, we are not passing any parameters at runtime.
def setup sketch_title 'FX2D' end def draw background 0 fill 200, 0, 0 ellipse width / 2, height / 2, 300, 200 end def settings size 400, 300, FX2D end
Prototyping Java-Processing in Ruby-Processing | Viget: http://t.co/IktN1UvQbW, and just brilliant for shader sketches .
— monkstone (@monkstoneT) June 6, 2015
Well actually there's an argument for sticking with ruby-processing since there is not much of a performance improvement to be gained by using vanilla processing. I have now included some modififications to ruby-processing that give it the "winning edge" for developing shader sketches in the since ruby-processing-2.6.11 the watch mode has been extended to monitor changes to the glsl shader code (in addition to the ruby code).
rp5 watch edge_detect_capture.rb
vim data/edge.glsl
// Original shader by Ken Slade // https://www.shadertoy.com/view/ldsSWr // Ported to Processing by Raphaël de Courville <twitter: @sableRaph> #ifdef GL_ES precision highp float; #endif uniform sampler2D texture; // iChannel0 in Shadertoy uniform vec2 sketchSize; // iResolution in Shadertoy //options are edge, colorEdge, or trueColorEdge #define EDGE_FUNC edge //options are KAYYALI_NESW, KAYYALI_SENW, PREWITT, ROBERTSCROSS, SCHARR, or SOBEL #define SOBEL // Use these parameters to fiddle with settings #ifdef SCHARR #define STEP 0.15 #else #define STEP 1.0 #endif #ifdef KAYYALI_NESW const mat3 kayyali_NESW = mat3(-6.0, 0.0, 6.0, 0.0, 0.0, 0.0, 6.0, 0.0, -6.0); #endif #ifdef KAYYALI_SENW const mat3 kayyali_SENW = mat3(6.0, 0.0, -6.0, 0.0, 0.0, 0.0, -6.0, 0.0, 6.0); #endif #ifdef PREWITT // Prewitt masks (see http://en.wikipedia.org/wiki/Prewitt_operator) const mat3 prewittKernelX = mat3(-1.0, 0.0, 1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0); const mat3 prewittKernelY = mat3(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, -1.0, -1.0, -1.0); #endif #ifdef ROBERTSCROSS // Roberts Cross masks (see http://en.wikipedia.org/wiki/Roberts_cross) const mat3 robertsCrossKernelX = mat3(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0); const mat3 robertsCrossKernelY = mat3(0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0); #endif #ifdef SCHARR // Scharr masks (see http://en.wikipedia.org/wiki/Sobel_operator#Alternative_operators) const mat3 scharrKernelX = mat3(3.0, 10.0, 3.0, 0.0, 0.0, 0.0, -3.0, -10.0, -3.0); const mat3 scharrKernelY = mat3(3.0, 0.0, -3.0, 10.0, 0.0, -10.0, 3.0, 0.0, -3.0); #endif #ifdef SOBEL // Sobel masks (see http://en.wikipedia.org/wiki/Sobel_operator) const mat3 sobelKernelX = mat3(1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0); const mat3 sobelKernelY = mat3(-1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0); #endif //performs a convolution on an image with the given kernel float convolve(mat3 kernel, mat3 image) { float result = 0.0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { result += kernel[i][j]*image[i][j]; } } return result; } //helper function for colorEdge() float convolveComponent(mat3 kernelX, mat3 kernelY, mat3 image) { vec2 result; result.x = convolve(kernelX, image); result.y = convolve(kernelY, image); return clamp(length(result), 0.0, 255.0); } //returns color edges using the separated color components for the measure of intensity //for each color component instead of using the same intensity for all three. This results //in false color edges when transitioning from one color to another, but true colors when //the transition is from black to color (or color to black). vec4 colorEdge(float stepx, float stepy, vec2 center, mat3 kernelX, mat3 kernelY) { //get samples around pixel vec4 colors[9]; colors[0] = texture2D(texture,center + vec2(-stepx,stepy)); colors[1] = texture2D(texture,center + vec2(0,stepy)); colors[2] = texture2D(texture,center + vec2(stepx,stepy)); colors[3] = texture2D(texture,center + vec2(-stepx,0)); colors[4] = texture2D(texture,center); colors[5] = texture2D(texture,center + vec2(stepx,0)); colors[6] = texture2D(texture,center + vec2(-stepx,-stepy)); colors[7] = texture2D(texture,center + vec2(0,-stepy)); colors[8] = texture2D(texture,center + vec2(stepx,-stepy)); mat3 imageR, imageG, imageB, imageA; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { imageR[i][j] = colors[i*3+j].r; imageG[i][j] = colors[i*3+j].g; imageB[i][j] = colors[i*3+j].b; imageA[i][j] = colors[i*3+j].a; } } vec4 color; color.r = convolveComponent(kernelX, kernelY, imageR); color.g = convolveComponent(kernelX, kernelY, imageG); color.b = convolveComponent(kernelX, kernelY, imageB); color.a = convolveComponent(kernelX, kernelY, imageA); return color; } //finds edges where fragment intensity changes from a higher value to a lower one (or //vice versa). vec4 edge(float stepx, float stepy, vec2 center, mat3 kernelX, mat3 kernelY){ // get samples around pixel mat3 image = mat3(length(texture2D(texture,center + vec2(-stepx,stepy)).rgb), length(texture2D(texture,center + vec2(0,stepy)).rgb), length(texture2D(texture,center + vec2(stepx,stepy)).rgb), length(texture2D(texture,center + vec2(-stepx,0)).rgb), length(texture2D(texture,center).rgb), length(texture2D(texture,center + vec2(stepx,0)).rgb), length(texture2D(texture,center + vec2(-stepx,-stepy)).rgb), length(texture2D(texture,center + vec2(0,-stepy)).rgb), length(texture2D(texture,center + vec2(stepx,-stepy)).rgb)); vec2 result; result.x = convolve(kernelX, image); result.y = convolve(kernelY, image); float color = clamp(length(result), 0.0, 255.0); return vec4(color); } //Colors edges using the actual color for the fragment at this location vec4 trueColorEdge(float stepx, float stepy, vec2 center, mat3 kernelX, mat3 kernelY) { vec4 edgeVal = edge(stepx, stepy, center, kernelX, kernelY); return edgeVal * texture2D(texture,center); } void main( void ){ vec2 uv = gl_FragCoord.xy / sketchSize.xy; vec4 color = texture2D(texture, uv.xy); #ifdef KAYYALI_NESW gl_FragColor = EDGE_FUNC(STEP/sketchSize[0], STEP/sketchSize[1], uv, kayyali_NESW, kayyali_NESW); #endif #ifdef KAYYALI_SENW gl_FragColor = EDGE_FUNC(STEP/sketchSize[0], STEP/sketchSize[1], uv, kayyali_SENW, kayyali_SENW); #endif #ifdef PREWITT gl_FragColor = EDGE_FUNC(STEP/sketchSize[0], STEP/sketchSize[1], uv, prewittKernelX, prewittKernelY); #endif #ifdef ROBERTSCROSS gl_FragColor = EDGE_FUNC(STEP/sketchSize[0], STEP/sketchSize[1], uv, robertsCrossKernelX, robertsCrossKernelY); #endif #ifdef SOBEL gl_FragColor = EDGE_FUNC(STEP/sketchSize[0], STEP/sketchSize[1], uv, sobelKernelX, sobelKernelY); #endif #ifdef SCHARR gl_FragColor = EDGE_FUNC(STEP/sketchSize[0], STEP/sketchSize[1], uv, scharrKernelX, scharrKernelY); #endif }
:wAnd the sketch reloads with new EDGE_FUNCTION brilliant....
package processing.core; /** * This interface makes it easier/possible to use the reflection methods * void captureEvent(Capture capture); and * void movieEvent(Movie movie); from ruby-processing * @author Martin Prout */ public interface VideoInterface { void movieEvent(processing.video.Movie movie); void captureEvent(processing.video.Capture capture); }
require 'rpextras' class Processing::App include Java::ProcessingCore::VideoInterface endNow if those processing guys had only created some decent interfaces in the first place this would have been a bit easier.
# # Speed. # # Use the Movie.speed method to change # the playback speed. The video_event library is # required to use "movieEvent" java reflection method # load_libraries :video, :video_event include_package 'processing.video' attr_reader :mov def setup size(640, 360) background(0) @mov = Movie.new(self, "transit.mov") mov.loop end def draw image(mov, 0, 0) new_speed = map(mouse_x, 0, width, 0.1, 2) mov.speed(new_speed) fill(255) text("%.2f" % new_speed << "X", 10, 30) end # The java reflection method def movieEvent(mov) mov.read end
load_library :video, :video_event include_package 'processing.video' attr_reader :cam, :my_shader def setup size(640, 480, P2D) cameras = Capture.list @my_shader = load_shader('edge_detect.glsl') my_shader.set('sketchSize', width.to_f, height.to_f) start_capture(width, height) end def start_capture(w, h) @cam = Capture.new(self, w, h) cam.start end def draw image(cam, 0, 0) return if mouse_pressed? filter(my_shader) end # The java reflection method def captureEvent(cam) cam.read end