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

Sunday 4 April 2010

Plasma fractal (and carpet)

This is a variant of processing sketch by Giles Whitaker, that he in turn had adapted from "Plasma Fractal" - written January, 2002 by Justin Seyster. I have somewhat revised the code to make it a bit more efficient, the color is set using bit shifting. I have also introduced a (Sierpinksi) carpet variant which can be selected from the menu. Further I have included a save_it button which only be useful when run as application/script.... Graininess is controlled by a slider, a feature I think Giles introduced (although here we use the ruby-processing control panel).

#######################################
# plasma.rb
# A sketch that demonstrates the use of
# bit shifting to create color values
######################################
load_library 'control_panel'

ALPHA = 255
PHI = (1 +Math.sqrt(5)) / 2
attr_reader :control, :grain, :variant, :redraw


def setup
  size(500, 500)
  @variant = 'plasma'
  @grain = 3
  draw_plasma width, height  
  setup_control
end

def setup_control
  control_panel do |c|
    c.title = "Control Panel"
    c.slider :grain, 3...40, 3
    c.menu :variant, ['plasma', 'carpet']
    c.button :draw_it
    c.button :save_it
  end
end

def draw
end

def draw_it
  draw_plasma width, height
end

def save_it
  save_frame("plasma#{frame_count}.png")
end

def calc_color c
  # alpha value & int adjustment
  r = (c < 0.5)? c : 1.0 - c
  gr = (c >= 0.8)? 1.3 - c : (c < 0.3)? 0.3 - c : c - 0.3
  b = (c < 0.5)? 0.5 - c : c - 0.5
  # r, gr and b are bit shifted by an extra 1 to avoid doubling above values
  col = (ALPHA << 24)|((r * ALPHA).round << 17)|((gr * ALPHA).round << 9)| (b * ALPHA).round << 1
end

def displace num
  max = num / (width + height) * grain
  (rand - 0.5) * max
end

def draw_plasma w,  h
   #Assign the four corners of the intial grid random color values
   #These will end up being the colors of the four corners of the applet.  
   divide_grid(0.0, 0.0, w, h, rand, rand, rand, rand)
end


def divide_grid(x1, y1, w, h, c1, c2, c3, c4)
  new_width = w / 2.0    # NB dividing by 2.0 to ensure float
  new_height = h / 2.0
  c = (c1 + c2 + c3 + c4) / 4.0
  if (w <= 1.0 || h <= 1.0)
    #The four corners of the grid piece will be averaged and drawn as a single pixel    
    set(x1.round, y1.round, calc_color(c))
  else
  middle = c + displace(new_width + new_height)      #Randomly displace the midpoint!
  divisor = (variant == 'plasma')? 2.0 : PHI
  edge1 = (c1 + c2) / 2.0 #Calculate the edges by averaging the two corners of each edge.
  edge2 = (c2 + c3) / divisor
  edge3 = (c3 + c4) / divisor
  edge4 = (c4 + c1) / 2.0

  #Make sure that the midpoint doesn't accidentally "randomly displaced" past the boundaries!      
  middle = (middle <= 0) ? 0 : (middle < 1.0) ? middle : 1.0  

  #Do the operation over again for each of the four new grids.                  
  divide_grid(x1, y1, new_width, new_height, c1, edge1, middle, edge4)
  divide_grid(x1 + new_width, y1, new_width, new_height, edge1, c2, edge2, middle)
  divide_grid(x1 + new_width, y1 + new_height, new_width, new_height, middle, edge2, c3, edge3)
  divide_grid(x1, y1 + new_height, new_width, new_height, edge4, middle, edge3, c4)
  end
end









No comments:

Post a Comment

Followers

Blog Archive

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