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,121 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# Noise-Based GLSL Heightmap by Amnon Owed (May 2013)
|
4
|
+
# https://github.com/AmnonOwed
|
5
|
+
# http://vimeo.com/amnon
|
6
|
+
#
|
7
|
+
# Creating a GLSL heightmap running on shader-based procedural noise.
|
8
|
+
#
|
9
|
+
# c = cycle through the color maps
|
10
|
+
#
|
11
|
+
# Tested with propane-0.3.0
|
12
|
+
#
|
13
|
+
# Photographs by Folkert Gorter (@folkertgorter / http://superfamous.com/) made available under a CC Attribution 3.0 license.
|
14
|
+
|
15
|
+
require 'propane'
|
16
|
+
|
17
|
+
class HeightMap < Propane::App
|
18
|
+
include Propane::Render
|
19
|
+
DIM = 300 # the grid dimensions of the heightmap
|
20
|
+
attr_reader :blur_factor # the blur for the displacement map
|
21
|
+
attr_reader :resize_factor # the resize factor for the displacement map
|
22
|
+
attr_reader :displace_strength
|
23
|
+
attr_reader :positions
|
24
|
+
attr_reader :tex_coords
|
25
|
+
attr_reader :height_map # PShape holds the geometry, textures etc.
|
26
|
+
attr_reader :displace # GLSL shader
|
27
|
+
attr_reader :images # array to hold 2 input images
|
28
|
+
attr_reader :color_map # variable to keep track of the current colorMap
|
29
|
+
|
30
|
+
def setup
|
31
|
+
size(1280, 720, P3D) # use the P3D OpenGL renderer
|
32
|
+
@blur_factor = 3
|
33
|
+
@resize_factor = 0.25
|
34
|
+
displace_strength = 0.25 # the displace strength of the GLSL shader displacement effect
|
35
|
+
# load the images from the _Images folder (relative path from this sketch's folder)
|
36
|
+
textures = %w(Texture01.jpg Texture02.jpg)
|
37
|
+
@images = textures.map { |texture| load_image(data_path(texture)) }
|
38
|
+
@color_map = 0
|
39
|
+
# load the PShader with a fragment and a vertex shader
|
40
|
+
@displace = load_shader('displaceFrag.glsl', 'displaceVert.glsl')
|
41
|
+
displace.set('displaceStrength', displace_strength) # set the displace_strength
|
42
|
+
displace.set('colorMap', images[color_map]) # set the initial colorMap
|
43
|
+
# create the heightmap PShape (see custom creation method) and put it in the global height_map reference
|
44
|
+
@height_map = create_plane(DIM, DIM)
|
45
|
+
end
|
46
|
+
|
47
|
+
def draw
|
48
|
+
# required for texLight shader
|
49
|
+
pointLight(255, 255, 255, 2 * (mouse_x - width / 2), 2 * (mouse_y - height / 2), 500)
|
50
|
+
translate(width / 2, height / 2) # translate to center of the screen
|
51
|
+
rotate_x(60.radians) # fixed rotation of 60 degrees over the X axis
|
52
|
+
rotate_z(frame_count * 0.005) # dynamic frameCount-based rotation over the Z axis
|
53
|
+
background(0) # black background
|
54
|
+
perspective(PI/3.0, width.to_f / height, 0.1, 1_000_000) # perspective for close shapes
|
55
|
+
scale(750) # scale by 750 (the model itself is unit length
|
56
|
+
displace.set('time', millis / 5_000.0) # feed time to the GLSL shader
|
57
|
+
shader(displace) # use shader
|
58
|
+
shape(height_map) # display the PShape
|
59
|
+
end
|
60
|
+
|
61
|
+
# custom method to create a PShape plane with certain xy DIMensions
|
62
|
+
def create_plane(xsegs, ysegs)
|
63
|
+
# STEP 1: create all the relevant data
|
64
|
+
|
65
|
+
@positions = [] # arrayList to hold positions
|
66
|
+
@tex_coords = [] # arrayList to hold texture coordinates
|
67
|
+
|
68
|
+
usegsize = 1 / xsegs.to_f # horizontal stepsize
|
69
|
+
vsegsize = 1 / ysegs.to_f # vertical stepsize
|
70
|
+
|
71
|
+
xsegs.times do |x|
|
72
|
+
ysegs.times do |y|
|
73
|
+
u = x / xsegs.to_f
|
74
|
+
v = y / ysegs.to_f
|
75
|
+
|
76
|
+
# generate positions for the vertices of each cell
|
77
|
+
# (-0.5 to center the shape around the origin)
|
78
|
+
positions << Vec3D.new(u - 0.5, v - 0.5, 0)
|
79
|
+
positions << Vec3D.new(u + usegsize - 0.5, v - 0.5, 0)
|
80
|
+
positions << Vec3D.new(u + usegsize - 0.5, v + vsegsize - 0.5, 0)
|
81
|
+
positions << Vec3D.new(u - 0.5, v + vsegsize - 0.5, 0)
|
82
|
+
|
83
|
+
# generate texture coordinates for the vertices of each cell
|
84
|
+
tex_coords << Vec2D.new(u, v)
|
85
|
+
tex_coords << Vec2D.new(u + usegsize, v)
|
86
|
+
tex_coords << Vec2D.new(u + usegsize, v + vsegsize)
|
87
|
+
tex_coords << Vec2D.new(u, v + vsegsize)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# STEP 2: put all the relevant data into the PShape
|
92
|
+
|
93
|
+
texture_mode(NORMAL) # set texture_mode to normalized (range 0 to 1)
|
94
|
+
tex = images[0]
|
95
|
+
|
96
|
+
mesh = create_shape # create the initial PShape
|
97
|
+
renderer = ShapeRender.new(mesh) # initialize the shape renderer
|
98
|
+
mesh.begin_shape(QUADS) # define the PShape type: QUADS
|
99
|
+
mesh.no_stroke
|
100
|
+
mesh.texture(tex) # set a texture to make a textured PShape
|
101
|
+
# put all the vertices, uv texture coordinates and normals into the PShape
|
102
|
+
positions.each_with_index do |p, i|
|
103
|
+
p.to_vertex_uv(renderer, tex_coords[i]) # NB: tex_coords as Vec2D
|
104
|
+
# p.to_vertex_uv(renderer, u, v) # u, v as floats is the alternate form
|
105
|
+
end
|
106
|
+
mesh.end_shape
|
107
|
+
mesh # our work is done here, return DA MESH! -)
|
108
|
+
end
|
109
|
+
|
110
|
+
def key_released
|
111
|
+
case key
|
112
|
+
when '1', '2'
|
113
|
+
@color_map = key.to_i - 1 # images.size for more than two
|
114
|
+
displace.set('colorMap', images[color_map])
|
115
|
+
else
|
116
|
+
puts format('key pressed: %s', key)
|
117
|
+
end # cycle through colorMaps (set variable and set colorMap in PShader)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
HeightMap.new title: 'Height Map'
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# From the Processing Examples
|
4
|
+
# by Zach Lieberman
|
5
|
+
|
6
|
+
WORDS = %w(sometimes\ it's\ like the\ lines\ of\ text are\ so\ happy
|
7
|
+
that\ they\ want\ to\ dance or\ leave\ the\ page\ or\ jump
|
8
|
+
can\ you\ blame\ them? living\ on\ the\ page\ like\ that
|
9
|
+
waiting\ to\ be\ read...)
|
10
|
+
|
11
|
+
require 'propane' # temporary local
|
12
|
+
|
13
|
+
# dispay them 'words'
|
14
|
+
class KineticType < Propane::App
|
15
|
+
|
16
|
+
def setup
|
17
|
+
size(200, 200, P3D)
|
18
|
+
frame_rate 30
|
19
|
+
# Load the font from the sketch's data directory.
|
20
|
+
text_font load_font(data_path('Univers45.vlw')), 1.0
|
21
|
+
fill 255
|
22
|
+
# Creating the line objects
|
23
|
+
@lines = WORDS.map.with_index { |word, i| Line.new(self, word, 0, i * 70) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def draw
|
27
|
+
background 0
|
28
|
+
translate(-240, -120, -450)
|
29
|
+
rotate_y 0.3
|
30
|
+
# Now animate every line object & draw it...
|
31
|
+
@lines.each_with_index do |line, i|
|
32
|
+
push_matrix
|
33
|
+
translate 0.0, line.ypos, 0.0
|
34
|
+
line.draw(i)
|
35
|
+
pop_matrix
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
class Line
|
42
|
+
attr_accessor :app, :string, :xpos, :ypos, :letters
|
43
|
+
|
44
|
+
def initialize(app, string, x, y)
|
45
|
+
@app, @string, @xpos, @ypos = app, string, x, y
|
46
|
+
spacing = 0.0
|
47
|
+
@letters = string.split('').map do |c|
|
48
|
+
spacing += app.text_width(c)
|
49
|
+
Letter.new(c, spacing, 0.0)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def compute_curve(line_num)
|
54
|
+
base = app.millis / 10_000.0 * Math::PI * 2
|
55
|
+
Math.sin((line_num + 1.0) * base) * Math.sin((8.0 - line_num) * base)
|
56
|
+
end
|
57
|
+
|
58
|
+
def draw(line_num)
|
59
|
+
curve = compute_curve(line_num)
|
60
|
+
letters.each_with_index do |letter, i|
|
61
|
+
return if i < 0
|
62
|
+
app.translate(app.text_width(letters[i - 1].char) * 75, 0.0, 0.0)
|
63
|
+
app.rotate_y(curve * 0.035)
|
64
|
+
app.push_matrix
|
65
|
+
app.scale(75.0, 75.0, 75.0)
|
66
|
+
app.text(letter.char, 0.0, 0.0)
|
67
|
+
app.pop_matrix
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Letter
|
73
|
+
attr_accessor :char, :x, :y
|
74
|
+
def initialize(c, x, y)
|
75
|
+
@char, @x, @y = c, x, y
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
KineticType.new title: 'Kinetic Type'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Simple demo Rakefile to autorun samples in current directory
|
2
|
+
# adjust path to rp5 executable, and or opts as required
|
3
|
+
|
4
|
+
SAMPLES_DIR = './'
|
5
|
+
|
6
|
+
desc 'run demo'
|
7
|
+
task default: [:demo]
|
8
|
+
|
9
|
+
desc 'demo'
|
10
|
+
task :demo do
|
11
|
+
samples_list.shuffle.each { |sample| run_sample sample }
|
12
|
+
end
|
13
|
+
|
14
|
+
def samples_list
|
15
|
+
files = []
|
16
|
+
Dir.chdir(SAMPLES_DIR)
|
17
|
+
Dir.glob('*.rb').each do |file|
|
18
|
+
files << File.join(SAMPLES_DIR, file)
|
19
|
+
end
|
20
|
+
return files
|
21
|
+
end
|
22
|
+
|
23
|
+
def run_sample(sample_name)
|
24
|
+
puts "Running #{sample_name}...quit to run next sample"
|
25
|
+
open("|jruby #{sample_name}", 'r') do |io|
|
26
|
+
while l = io.gets
|
27
|
+
puts(l.chop)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'arcball'
|
2
|
+
|
3
|
+
############################
|
4
|
+
# Use mouse drag to rotate
|
5
|
+
# the arcball. Use mousewheel
|
6
|
+
# to zoom. Hold down x, y, z
|
7
|
+
# to constrain rotation axis.
|
8
|
+
############################
|
9
|
+
|
10
|
+
require_relative '../../lib/propane' # temporary local
|
11
|
+
|
12
|
+
# Include processing opengl classes that we'd like to use:
|
13
|
+
%w(PGL PGraphics3D PGraphicsOpenGL PShapeOpenGL Texture).each do |klass|
|
14
|
+
java_import "processing.opengl.#{klass}"
|
15
|
+
end
|
16
|
+
|
17
|
+
class ArcballBox < Propane::App
|
18
|
+
|
19
|
+
def setup
|
20
|
+
size(600, 600, P3D)
|
21
|
+
smooth(8)
|
22
|
+
Processing::ArcBall.init(self, 300, 300)
|
23
|
+
fill 180
|
24
|
+
end
|
25
|
+
|
26
|
+
def draw
|
27
|
+
background(50)
|
28
|
+
box(300, 300, 300)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
ArcballBox.new title: 'ArcBall Box'
|
34
|
+
|
35
|
+
|
36
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# Creating Colors (Homage to Albers).
|
4
|
+
#
|
5
|
+
require 'propane'
|
6
|
+
|
7
|
+
# Creating variables for colors that may be referred to
|
8
|
+
# in the program by their name, rather than a number.
|
9
|
+
class CreatingColors < Propane::App
|
10
|
+
attr_reader :redder, :yellower, :orangish
|
11
|
+
|
12
|
+
def setup
|
13
|
+
size 640, 360
|
14
|
+
@redder = color 204, 102, 0
|
15
|
+
@yellower = color 204, 153, 0
|
16
|
+
@orangish = color 153, 51, 0
|
17
|
+
# These statements are equivalent to the statements above.
|
18
|
+
# Programmers may use the format they prefer.
|
19
|
+
|
20
|
+
# hex color as a String (NB quotes are required)
|
21
|
+
|
22
|
+
# @redder = color '#CC6600'
|
23
|
+
# @yellower = color '#CC9900'
|
24
|
+
# @orangish = color '#993300'
|
25
|
+
|
26
|
+
# or alternatively as a hexadecimal
|
27
|
+
|
28
|
+
# @redder = color 0xFFCC6600
|
29
|
+
# @yellower = color 0xFFCC9900
|
30
|
+
# @orangish = color 0xFF993300
|
31
|
+
end
|
32
|
+
|
33
|
+
def draw
|
34
|
+
no_stroke
|
35
|
+
background 51, 0, 0
|
36
|
+
push_matrix
|
37
|
+
translate 80, 80
|
38
|
+
fill orangish
|
39
|
+
rect 0, 0, 200, 200
|
40
|
+
fill yellower
|
41
|
+
rect 40, 60, 120, 120
|
42
|
+
fill redder
|
43
|
+
rect 60, 90, 80, 80
|
44
|
+
pop_matrix
|
45
|
+
push_matrix
|
46
|
+
translate 360, 80
|
47
|
+
fill redder
|
48
|
+
rect 0, 0, 200, 200
|
49
|
+
fill orangish
|
50
|
+
rect 40, 60, 120, 120
|
51
|
+
fill yellower
|
52
|
+
rect 60, 90, 80, 80
|
53
|
+
pop_matrix
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
CreatingColors.new title: 'Homage to Albers'
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# elegant_ball.rb
|
2
|
+
# After a vanilla processing sketch by
|
3
|
+
# Ben Notorianni aka lazydog
|
4
|
+
#
|
5
|
+
# elegant_ball.rb
|
6
|
+
|
7
|
+
require 'propane'
|
8
|
+
|
9
|
+
class ElegantBall < Propane::App
|
10
|
+
|
11
|
+
attr_reader :start_t
|
12
|
+
|
13
|
+
def setup
|
14
|
+
size(800, 800, P3D)
|
15
|
+
color_mode(RGB, 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
def draw
|
19
|
+
background(0)
|
20
|
+
# Move the origin so that the scene is centered on the screen.
|
21
|
+
translate(width / 2, height / 2, 0.0)
|
22
|
+
# Set up the lighting.
|
23
|
+
setup_lights
|
24
|
+
# Rotate the local coordinate system.
|
25
|
+
smooth_rotation(5.0, 6.7, 7.3)
|
26
|
+
# Draw the inner object.
|
27
|
+
no_stroke
|
28
|
+
fill(smooth_colour(10.0, 12.0, 7.0))
|
29
|
+
draw_icosahedron(5, 60.0, false)
|
30
|
+
# Rotate the local coordinate system again.
|
31
|
+
smooth_rotation(4.5, 3.7, 7.3)
|
32
|
+
# Draw the outer object.
|
33
|
+
stroke(0.2)
|
34
|
+
fill(smooth_colour(6.0, 9.2, 0.7))
|
35
|
+
draw_icosahedron(5, 200.0, true)
|
36
|
+
end
|
37
|
+
|
38
|
+
def renderer
|
39
|
+
@renderer ||= Propane::Render::AppRender.new(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_lights
|
43
|
+
ambient_light(0.025, 0.025, 0.025)
|
44
|
+
directional_light(0.2, 0.2, 0.2, -1, -1, -1)
|
45
|
+
spot_light(1.0, 1.0, 1.0, -200, 0, 300, 1, 0, -1, Math::PI / 4, 20)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generate a vector whose components change smoothly over time in the range
|
49
|
+
# (0..1). Each component uses a Math.sin function to map the current time in
|
50
|
+
# milliseconds in the range (0..1).A 'speed' factor is specified for each
|
51
|
+
# component.
|
52
|
+
def smooth_vector(s1, s2, s3)
|
53
|
+
mills = millis * 0.00003 ## Lazydogs factor
|
54
|
+
# mills = millis * 0.0000001 ## worked for me a bit slower!!
|
55
|
+
x = 0.5 * Math.sin(mills * s1) + 0.5
|
56
|
+
y = 0.5 * Math.sin(mills * s2) + 0.5
|
57
|
+
z = 0.5 * Math.sin(mills * s3) + 0.5
|
58
|
+
Vec3D.new(x, y, z)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Generate a colour which smoothly changes over time.
|
62
|
+
# The speed of each component is controlled by the parameters s1, s2 and s3.
|
63
|
+
def smooth_colour(s1, s2, s3)
|
64
|
+
v = smooth_vector(s1, s2, s3)
|
65
|
+
color(v.x, v.y, v.z)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Rotate the current coordinate system.
|
69
|
+
# Uses smooth_vector to smoothly animate the rotation.
|
70
|
+
def smooth_rotation(s1, s2, s3)
|
71
|
+
r1 = smooth_vector(s1, s2, s3)
|
72
|
+
rotate_x(2.0 * Math::PI * r1.x)
|
73
|
+
rotate_y(2.0 * Math::PI * r1.y)
|
74
|
+
rotate_x(2.0 * Math::PI * r1.z)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Draw an icosahedron defined by a radius r and recursive depth d.
|
78
|
+
# Geometry data will be saved into dst. If spherical is true then the
|
79
|
+
# icosahedron is projected onto the sphere with radius r.
|
80
|
+
def draw_icosahedron(depth, r, spherical)
|
81
|
+
# Calculate the vertex data for an icosahedron inscribed by a sphere radius
|
82
|
+
# 'r'. Use 4 Golden Ratio rectangles as the basis.
|
83
|
+
gr = (1.0 + Math.sqrt(5.0)) / 2.0
|
84
|
+
h = r / Math.sqrt(1.0 + gr * gr)
|
85
|
+
v = [
|
86
|
+
Vec3D.new(0, -h, h * gr),
|
87
|
+
Vec3D.new(0, -h, -h * gr),
|
88
|
+
Vec3D.new(0, h, -h * gr),
|
89
|
+
Vec3D.new(0, h, h * gr),
|
90
|
+
Vec3D.new(h, -h * gr, 0),
|
91
|
+
Vec3D.new(h, h * gr, 0),
|
92
|
+
Vec3D.new(-h, h * gr, 0),
|
93
|
+
Vec3D.new(-h, -h * gr, 0),
|
94
|
+
Vec3D.new(-h * gr, 0, h),
|
95
|
+
Vec3D.new(-h * gr, 0, -h),
|
96
|
+
Vec3D.new(h * gr, 0, -h),
|
97
|
+
Vec3D.new(h * gr, 0, h)
|
98
|
+
]
|
99
|
+
# Draw the 20 triangular faces of the icosahedron.
|
100
|
+
r = 0.0 unless spherical
|
101
|
+
begin_shape(TRIANGLES)
|
102
|
+
draw_triangle(depth, r, v[0], v[7], v[4])
|
103
|
+
draw_triangle(depth, r, v[0], v[4], v[11])
|
104
|
+
draw_triangle(depth, r, v[0], v[11], v[3])
|
105
|
+
draw_triangle(depth, r, v[0], v[3], v[8])
|
106
|
+
draw_triangle(depth, r, v[0], v[8], v[7])
|
107
|
+
draw_triangle(depth, r, v[1], v[4], v[7])
|
108
|
+
draw_triangle(depth, r, v[1], v[10], v[4])
|
109
|
+
draw_triangle(depth, r, v[10], v[11], v[4])
|
110
|
+
draw_triangle(depth, r, v[11], v[5], v[10])
|
111
|
+
draw_triangle(depth, r, v[5], v[3], v[11])
|
112
|
+
draw_triangle(depth, r, v[3], v[6], v[5])
|
113
|
+
draw_triangle(depth, r, v[6], v[8], v[3])
|
114
|
+
draw_triangle(depth, r, v[8], v[9], v[6])
|
115
|
+
draw_triangle(depth, r, v[9], v[7], v[8])
|
116
|
+
draw_triangle(depth, r, v[7], v[1], v[9])
|
117
|
+
draw_triangle(depth, r, v[2], v[1], v[9])
|
118
|
+
draw_triangle(depth, r, v[2], v[10], v[1])
|
119
|
+
draw_triangle(depth, r, v[2], v[5], v[10])
|
120
|
+
draw_triangle(depth, r, v[2], v[6], v[5])
|
121
|
+
draw_triangle(depth, r, v[2], v[9], v[6])
|
122
|
+
end_shape
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Draw a triangle either immediately or subdivide it first.
|
127
|
+
# If depth is 1 then draw the triangle otherwise subdivide first.
|
128
|
+
#
|
129
|
+
def draw_triangle(depth, r, p1, p2, p3)
|
130
|
+
if depth == 1
|
131
|
+
p1.to_vertex(renderer)
|
132
|
+
p2.to_vertex(renderer)
|
133
|
+
p3.to_vertex(renderer)
|
134
|
+
else
|
135
|
+
# Calculate the mid points of this triangle.
|
136
|
+
v1 = (p1 + p2) * 0.5
|
137
|
+
v2 = (p2 + p3) * 0.5
|
138
|
+
v3 = (p3 + p1) * 0.5
|
139
|
+
unless r == 0.0
|
140
|
+
# Project the vertices out onto the sphere with radius r.
|
141
|
+
v1.normalize!
|
142
|
+
v1 *= r
|
143
|
+
v2.normalize!
|
144
|
+
v2 *= r
|
145
|
+
v3.normalize!
|
146
|
+
v3 *= r
|
147
|
+
end
|
148
|
+
## Generate the next level of detail
|
149
|
+
depth -= 1
|
150
|
+
draw_triangle(depth, r, p1, v1, v3)
|
151
|
+
draw_triangle(depth, r, v1, p2, v2)
|
152
|
+
draw_triangle(depth, r, v2, p3, v3)
|
153
|
+
# Uncomment out the next line to include the central part of the triangle.
|
154
|
+
# draw_triangle(depth, r, v1, v2, v3)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
ElegantBall.new title: 'Elegant Ball'
|