propane 0.3.0.pre-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.mvn/extensions.xml +8 -0
- data/.mvn/wrapper/maven-wrapper.properties +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +69 -0
- data/Rakefile +59 -0
- data/VERSION.txt +4 -0
- data/bin/propane +8 -0
- data/examples/complete/Rakefile +32 -0
- data/examples/complete/data/Texture01.jpg +0 -0
- data/examples/complete/data/Texture02.jpg +0 -0
- data/examples/complete/data/Univers45.vlw +0 -0
- data/examples/complete/data/displaceFrag.glsl +8 -0
- data/examples/complete/data/displaceVert.glsl +201 -0
- data/examples/complete/glsl_heightmap_noise.rb +121 -0
- data/examples/complete/kinetic_type.rb +79 -0
- data/examples/regular/Rakefile +30 -0
- data/examples/regular/arcball_box.rb +36 -0
- data/examples/regular/creating_colors.rb +57 -0
- data/examples/regular/elegant_ball.rb +159 -0
- data/examples/regular/flight_patterns.rb +63 -0
- data/examples/regular/grey_circles.rb +28 -0
- data/examples/regular/jwishy.rb +100 -0
- data/examples/regular/letters.rb +42 -0
- data/examples/regular/lib/boundary.rb +38 -0
- data/examples/regular/lib/particle.rb +77 -0
- data/examples/regular/lib/particle_system.rb +111 -0
- data/examples/regular/liquidy.rb +40 -0
- data/examples/regular/mouse_button_demo.rb +34 -0
- data/examples/regular/polyhedrons.rb +248 -0
- data/examples/regular/ribbon_doodle.rb +89 -0
- data/examples/regular/vector_math.rb +36 -0
- data/examples/regular/words.rb +41 -0
- data/lib/PROCESSING_LICENSE.txt +456 -0
- data/lib/export.txt +10 -0
- data/lib/propane.rb +12 -0
- data/lib/propane/app.rb +197 -0
- data/lib/propane/helper_methods.rb +177 -0
- data/lib/propane/helpers/numeric.rb +9 -0
- data/lib/propane/library_loader.rb +117 -0
- data/lib/propane/runner.rb +88 -0
- data/lib/propane/underscorer.rb +19 -0
- data/lib/propane/version.rb +5 -0
- data/library/boids/boids.rb +201 -0
- data/library/control_panel/control_panel.rb +172 -0
- data/pom.rb +113 -0
- data/pom.xml +198 -0
- data/propane.gemspec +28 -0
- data/src/monkstone/ColorUtil.java +67 -0
- data/src/monkstone/MathTool.java +195 -0
- data/src/monkstone/PropaneLibrary.java +47 -0
- data/src/monkstone/core/AbstractLibrary.java +102 -0
- data/src/monkstone/fastmath/Deglut.java +115 -0
- data/src/monkstone/vecmath/AppRender.java +87 -0
- data/src/monkstone/vecmath/JRender.java +56 -0
- data/src/monkstone/vecmath/ShapeRender.java +87 -0
- data/src/monkstone/vecmath/vec2/Vec2.java +670 -0
- data/src/monkstone/vecmath/vec3/Vec3.java +708 -0
- data/test/respond_to_test.rb +208 -0
- data/vendors/Rakefile +48 -0
- metadata +130 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
# Description:
|
2
|
+
# Flight Patterns is that ol' Euruko 2008 demo.
|
3
|
+
# Reworked version for Propane
|
4
|
+
# Usage:
|
5
|
+
# Drag mouse to steer 'invisible' flock attractor, use 'f' key to toggle flee
|
6
|
+
# Mouse 'click' to toggle 'sphere' or 'circle' display
|
7
|
+
require 'propane'
|
8
|
+
|
9
|
+
class FlightPatterns < Propane::App
|
10
|
+
load_library :boids
|
11
|
+
|
12
|
+
attr_reader :flee, :radius
|
13
|
+
|
14
|
+
def setup
|
15
|
+
size 1024, 768, P3D
|
16
|
+
sphere_detail 8
|
17
|
+
color_mode RGB, 1.0
|
18
|
+
no_stroke
|
19
|
+
shininess 1.0
|
20
|
+
specular 0.3, 0.1, 0.1
|
21
|
+
emissive 0.03, 0.03, 0.1
|
22
|
+
@radius = 0.02 * height
|
23
|
+
@click = false
|
24
|
+
@flee = false
|
25
|
+
@flocks = (0..3).map { Boids.flock(n: 20, x: 0, y: 0, w: width, h: height) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def mouse_pressed
|
29
|
+
@click = !@click
|
30
|
+
end
|
31
|
+
|
32
|
+
def key_pressed
|
33
|
+
return unless key == 'f'
|
34
|
+
@flee = !@flee
|
35
|
+
end
|
36
|
+
|
37
|
+
def draw
|
38
|
+
background 0.05
|
39
|
+
ambient_light 0.01, 0.01, 0.01
|
40
|
+
light_specular 0.4, 0.2, 0.2
|
41
|
+
point_light 1.0, 1.0, 1.0, mouse_x, mouse_y, 190
|
42
|
+
@flocks.each_with_index do |flock, i|
|
43
|
+
flock.goal(target: Vec3D.new(mouse_x, mouse_y, 0), flee: @flee)
|
44
|
+
flock.update(goal: 185, limit: 13.5)
|
45
|
+
flock.each do |boid|
|
46
|
+
r = (0.15 * boid.pos.z) + radius
|
47
|
+
case i
|
48
|
+
when 0 then fill 0.85, 0.65, 0.65
|
49
|
+
when 1 then fill 0.65, 0.85, 0.65
|
50
|
+
when 2 then fill 0.65, 0.65, 0.85
|
51
|
+
end
|
52
|
+
push_matrix
|
53
|
+
point_array = (boid.pos.to_a).map { |p| p - (r / 2.0) }
|
54
|
+
translate(*point_array)
|
55
|
+
@click ? sphere(r / 2) : ellipse(0, 0, r, r)
|
56
|
+
@click ? hint(ENABLE_DEPTH_TEST) : hint(DISABLE_DEPTH_TEST)
|
57
|
+
pop_matrix
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
FlightPatterns.new title: 'Flight Patterns'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# grey circles : borrowed from https://github.com/quil/quil
|
4
|
+
require 'propane'
|
5
|
+
|
6
|
+
class GreyCircles < Propane::App
|
7
|
+
|
8
|
+
def setup
|
9
|
+
size(323, 200)
|
10
|
+
smooth
|
11
|
+
frame_rate(1)
|
12
|
+
background(200)
|
13
|
+
end
|
14
|
+
|
15
|
+
def draw
|
16
|
+
stroke_setup
|
17
|
+
diameter = rand(100)
|
18
|
+
ellipse(rand(width), rand(height), diameter, diameter)
|
19
|
+
end
|
20
|
+
|
21
|
+
def stroke_setup
|
22
|
+
[:stroke, :stroke_weight, :fill].each do |method|
|
23
|
+
send(method, rand(255))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
GreyCircles.new title: 'Oh so many circles'
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'propane'
|
4
|
+
# Iconic ruby-processing example for Propane
|
5
|
+
class JWishy < Propane::App
|
6
|
+
load_library :control_panel
|
7
|
+
|
8
|
+
attr_reader :alpha, :back_color, :bluish, :hide, :magnitude, :panel
|
9
|
+
attr_reader :x_wiggle, :y_wiggle
|
10
|
+
|
11
|
+
def setup
|
12
|
+
size 600, 600
|
13
|
+
control_panel do |c|
|
14
|
+
c.title = 'Control Panel'
|
15
|
+
c.look_feel 'Nimbus'
|
16
|
+
c.slider :bluish, 0.0..1.0, 0.5
|
17
|
+
c.slider :alpha, 0.0..1.0, 0.5
|
18
|
+
c.checkbox :go_big
|
19
|
+
c.button :reset
|
20
|
+
c.menu :shape, %w(oval square triangle)
|
21
|
+
@panel = c
|
22
|
+
end
|
23
|
+
@hide = false
|
24
|
+
@shape = 'oval'
|
25
|
+
@x_wiggle, @y_wiggle = 10.0, 0
|
26
|
+
@magnitude = 8.15
|
27
|
+
@back_color = [0.06, 0.03, 0.18]
|
28
|
+
color_mode RGB, 1
|
29
|
+
ellipse_mode CORNER
|
30
|
+
smooth
|
31
|
+
end
|
32
|
+
|
33
|
+
def draw_background
|
34
|
+
back_color[3] = alpha
|
35
|
+
fill(*back_color.to_java(:float))
|
36
|
+
rect 0, 0, width, height
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset
|
40
|
+
@y_wiggle = 0
|
41
|
+
end
|
42
|
+
|
43
|
+
def draw
|
44
|
+
# only make control_panel visible once, or again when hide is false
|
45
|
+
unless hide
|
46
|
+
@hide = true
|
47
|
+
panel.set_visible(hide)
|
48
|
+
end
|
49
|
+
draw_background
|
50
|
+
# Seed the random numbers for consistent placement from frame to frame
|
51
|
+
srand(0)
|
52
|
+
horiz, vert, mag = x_wiggle, y_wiggle, magnitude
|
53
|
+
if @go_big
|
54
|
+
mag *= 2
|
55
|
+
vert /= 2
|
56
|
+
end
|
57
|
+
blu = bluish
|
58
|
+
x, y = (width / 2), -27
|
59
|
+
c = 0.0
|
60
|
+
64.times do
|
61
|
+
x += cos(horiz) * mag
|
62
|
+
y += log10(vert) * mag + sin(vert) * 2
|
63
|
+
fill(sin(y_wiggle + c), rand * 0.2, rand * blu, 0.5)
|
64
|
+
s = 42 + cos(vert) * 17
|
65
|
+
args = [@shape, x - s / 2, y - s / 2, s, s]
|
66
|
+
draw_shape(args)
|
67
|
+
vert += rand * 0.25
|
68
|
+
horiz += rand * 0.25
|
69
|
+
c += 0.1
|
70
|
+
end
|
71
|
+
@x_wiggle += 0.05
|
72
|
+
@y_wiggle += 0.1
|
73
|
+
end
|
74
|
+
|
75
|
+
def mouse_pressed
|
76
|
+
return unless hide
|
77
|
+
@hide = false
|
78
|
+
end
|
79
|
+
|
80
|
+
def draw_shape(args)
|
81
|
+
case args[0]
|
82
|
+
when 'triangle'
|
83
|
+
draw_triangle(args)
|
84
|
+
when 'square'
|
85
|
+
rect(args[1], args[2], args[3], args[4])
|
86
|
+
else
|
87
|
+
ellipse(args[1], args[2], args[3], args[4]) # oval for Shoes
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def draw_triangle(args)
|
92
|
+
x2 = args[1] + (args[3] * 0.6)
|
93
|
+
y0 = args[2] + (args[4] * 0.396)
|
94
|
+
y1 = args[2] - (args[4] * 0.792)
|
95
|
+
y2 = args[2] + (args[4] * 0.396)
|
96
|
+
triangle(args[1] - (args[3] * 0.6), y0, args[1], y1, x2, y2)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
JWishy.new title: 'Wishy Worm'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# Letters.
|
4
|
+
#
|
5
|
+
require 'propane'
|
6
|
+
|
7
|
+
LETTERS = ('A'..'Z').to_a + ('0'..'9').to_a + ('a'..'z').to_a
|
8
|
+
|
9
|
+
# Draws letters to the screen. This requires loading a font,
|
10
|
+
# setting the font, and then drawing the letters.
|
11
|
+
class Letters < Propane::App
|
12
|
+
def setup
|
13
|
+
size 640, 360
|
14
|
+
@font = create_font 'Georgia', 24
|
15
|
+
text_font @font
|
16
|
+
text_align CENTER, CENTER
|
17
|
+
end
|
18
|
+
|
19
|
+
def draw
|
20
|
+
background 0
|
21
|
+
translate 24, 32
|
22
|
+
x, y = 0.0, 0.0
|
23
|
+
gap = 30
|
24
|
+
# ranges -> arrays -> joined!
|
25
|
+
LETTERS.each do |letter|
|
26
|
+
fill 255
|
27
|
+
fill 204, 204, 0 if letter =~ /[AEIOU]/
|
28
|
+
fill 0, 204, 204 if letter =~ /[aeiou]/
|
29
|
+
fill 153 if letter =~ /[0-9]/
|
30
|
+
fill 255, 100, 0 if key_pressed? && (letter.downcase.eql? key)
|
31
|
+
fill 0, 100, 255 if key_pressed? && (letter.upcase.eql? key)
|
32
|
+
text letter, x, y
|
33
|
+
x += gap
|
34
|
+
if x > width - 30
|
35
|
+
x = 0
|
36
|
+
y += gap
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Letters.new title: 'Letters'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Re-usable Boundary class
|
2
|
+
class Boundary
|
3
|
+
include Propane::Proxy
|
4
|
+
attr_reader :box2d, :b, :pos, :size, :a
|
5
|
+
|
6
|
+
def initialize(b2d, pos, sz, a = 0)
|
7
|
+
@box2d, @pos, @size, @a = b2d, pos, sz, a
|
8
|
+
# Define the polygon
|
9
|
+
sd = PolygonShape.new
|
10
|
+
# Figure out the box2d coordinates
|
11
|
+
box2d_w = box2d.scale_to_world(size.x / 2)
|
12
|
+
box2d_h = box2d.scale_to_world(size.y / 2)
|
13
|
+
# We're just a box
|
14
|
+
sd.set_as_box(box2d_w, box2d_h)
|
15
|
+
# Create the body
|
16
|
+
bd = BodyDef.new
|
17
|
+
bd.type = BodyType::STATIC
|
18
|
+
bd.angle = a
|
19
|
+
bd.position.set(box2d.processing_to_world(pos.x, pos.y))
|
20
|
+
@b = box2d.create_body(bd)
|
21
|
+
# Attached the shape to the body using a Fixture
|
22
|
+
b.create_fixture(sd, 1)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Draw the boundary, it doesn't move so we don't ask for location
|
26
|
+
def display
|
27
|
+
fill(0)
|
28
|
+
stroke(0)
|
29
|
+
stroke_weight(1)
|
30
|
+
rect_mode(PConstants::CENTER)
|
31
|
+
a = b.get_angle
|
32
|
+
push_matrix
|
33
|
+
translate(pos.x, pos.y)
|
34
|
+
rotate(-a)
|
35
|
+
rect(0, 0, size.x, size.y)
|
36
|
+
pop_matrix
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Note the particle class change method is use to change color to red
|
2
|
+
# when two particles collide (no change just hitting boundary)
|
3
|
+
class Particle
|
4
|
+
extend Forwardable
|
5
|
+
def_delegators(:@app, :box2d, :begin_shape, :color, :end_shape, :line,
|
6
|
+
:pop_matrix, :ellipse, :translate, :rotate, :stroke,
|
7
|
+
:push_matrix, :fill, :no_fill, :stroke_weight)
|
8
|
+
attr_accessor :body
|
9
|
+
attr_reader :radius, :col
|
10
|
+
|
11
|
+
def initialize(app, x, y, r)
|
12
|
+
@app, @x, @y, @radius = app, x, y, r
|
13
|
+
# This function puts the particle in the Box2d world
|
14
|
+
make_body(x, y, radius)
|
15
|
+
@col = color('#c0c0c0') # silvergrey
|
16
|
+
body.setUserData(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
# This function removes the particle from the box2d world
|
20
|
+
def kill_body
|
21
|
+
box2d.destroy_body(body)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Change color when hit
|
25
|
+
def change
|
26
|
+
@col = color('#cc0000') # red
|
27
|
+
end
|
28
|
+
|
29
|
+
# Is the particle ready for deletion?
|
30
|
+
def done
|
31
|
+
# Let's find the screen position of the particle
|
32
|
+
pos = box2d.body_coord(body)
|
33
|
+
# Is it off the bottom of the screen?
|
34
|
+
return false unless pos.y > (box2d.height + radius * 2)
|
35
|
+
kill_body
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def display
|
40
|
+
# We look at each body and get its screen position
|
41
|
+
pos = box2d.body_coord(body)
|
42
|
+
# Get its angle of rotation
|
43
|
+
a = body.get_angle
|
44
|
+
push_matrix
|
45
|
+
translate(pos.x, pos.y)
|
46
|
+
rotate(a)
|
47
|
+
fill(col)
|
48
|
+
stroke(0)
|
49
|
+
stroke_weight(1)
|
50
|
+
ellipse(0, 0, radius * 2, radius * 2)
|
51
|
+
# Let's add a line so we can see the rotation
|
52
|
+
line(0, 0, radius, 0)
|
53
|
+
pop_matrix
|
54
|
+
end
|
55
|
+
|
56
|
+
# Here's our function that adds the particle to the Box2D world
|
57
|
+
def make_body(x, y, r)
|
58
|
+
# Define a body
|
59
|
+
bd = BodyDef.new
|
60
|
+
# Set its position
|
61
|
+
bd.position = box2d.processing_to_world(x, y)
|
62
|
+
bd.type = BodyType::DYNAMIC
|
63
|
+
@body = box2d.create_body(bd)
|
64
|
+
# Make the body's shape a circle
|
65
|
+
cs = CircleShape.new
|
66
|
+
cs.m_radius = box2d.scale_to_world(r)
|
67
|
+
fd = FixtureDef.new
|
68
|
+
fd.shape = cs
|
69
|
+
# Parameters that affect physics
|
70
|
+
fd.density = 1
|
71
|
+
fd.friction = 0.01
|
72
|
+
fd.restitution = 0.3
|
73
|
+
# Attach fixture to body
|
74
|
+
body.create_fixture(fd)
|
75
|
+
body.set_angular_velocity(rand(-10.0..10))
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Runnable
|
4
|
+
def run
|
5
|
+
reject!(&:done)
|
6
|
+
each(&:display)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Not be confused with the jbox2d ParticleSystem
|
11
|
+
class ParticleSystem
|
12
|
+
include Enumerable, Runnable
|
13
|
+
extend Forwardable
|
14
|
+
def_delegators(:@particles, :each, :reject!, :<<, :empty?)
|
15
|
+
def_delegator(:@particles, :empty?, :dead?)
|
16
|
+
|
17
|
+
attr_reader :x, :y
|
18
|
+
|
19
|
+
def initialize(bd, num, x, y)
|
20
|
+
@particles = [] # Initialize the Array
|
21
|
+
@x, @y = x, y # Store the origin point
|
22
|
+
num.times do
|
23
|
+
self << Particle.new(bd, x, y)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_particles(bd, n)
|
28
|
+
n.times do
|
29
|
+
self << Particle.new(bd, x, y)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# A Particle
|
35
|
+
require 'pbox2d'
|
36
|
+
|
37
|
+
class Particle
|
38
|
+
include Propane::Proxy
|
39
|
+
TRAIL_SIZE = 6
|
40
|
+
# We need to keep track of a Body
|
41
|
+
|
42
|
+
attr_reader :trail, :body, :box2d
|
43
|
+
|
44
|
+
# Constructor
|
45
|
+
def initialize(b2d, x, y)
|
46
|
+
@box2d = b2d
|
47
|
+
@trail = Array.new(TRAIL_SIZE, [x, y])
|
48
|
+
# Add the box to the box2d world
|
49
|
+
# Here's a little trick, let's make a tiny tiny radius
|
50
|
+
# This way we have collisions, but they don't overwhelm the system
|
51
|
+
make_body(x, y, 0.2)
|
52
|
+
end
|
53
|
+
|
54
|
+
# This function removes the particle from the box2d world
|
55
|
+
def kill_body
|
56
|
+
box2d.destroy_body(body)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Is the particle ready for deletion?
|
60
|
+
def done
|
61
|
+
# Let's find the screen position of the particle
|
62
|
+
pos = box2d.body_coord(body)
|
63
|
+
# Is it off the bottom of the screen?
|
64
|
+
return false unless pos.y > box2d.height + 20
|
65
|
+
kill_body
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
# Drawing the box
|
70
|
+
def display
|
71
|
+
# We look at each body and get its screen position
|
72
|
+
pos = box2d.body_coord(body)
|
73
|
+
# Keep track of a history of screen positions in an array
|
74
|
+
(TRAIL_SIZE - 1).times do |i|
|
75
|
+
trail[i] = trail[i + 1]
|
76
|
+
end
|
77
|
+
trail[TRAIL_SIZE - 1] = [pos.x, pos.y]
|
78
|
+
# Draw particle as a trail
|
79
|
+
begin_shape
|
80
|
+
no_fill
|
81
|
+
stroke_weight(2)
|
82
|
+
stroke(0, 150)
|
83
|
+
trail.each do |v|
|
84
|
+
vertex(v[0], v[1])
|
85
|
+
end
|
86
|
+
end_shape
|
87
|
+
end
|
88
|
+
|
89
|
+
# This function adds the rectangle to the box2d world
|
90
|
+
def make_body(x, y, r)
|
91
|
+
# Define and create the body
|
92
|
+
bd = BodyDef.new
|
93
|
+
bd.type = BodyType::DYNAMIC
|
94
|
+
bd.position.set(box2d.processing_to_world(x, y))
|
95
|
+
@body = box2d.create_body(bd)
|
96
|
+
# Give it some initial random velocity
|
97
|
+
body.set_linear_velocity(Vec2.new(rand(-1.0..1), rand(-1.0..1)))
|
98
|
+
# Make the body's shape a circle
|
99
|
+
cs = CircleShape.new
|
100
|
+
cs.m_radius = box2d.scale_to_world(r)
|
101
|
+
fd = FixtureDef.new
|
102
|
+
fd.shape = cs
|
103
|
+
fd.density = 1
|
104
|
+
fd.friction = 0 # Slippery when wet!
|
105
|
+
fd.restitution = 0.5
|
106
|
+
# We could use this if we want to turn collisions off
|
107
|
+
# cd.filter.groupIndex = -10
|
108
|
+
# Attach fixture to body
|
109
|
+
body.create_fixture(fd)
|
110
|
+
end
|
111
|
+
end
|