green_shoes 0.129.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/README.rdoc +23 -0
- data/README_old.md +132 -0
- data/lib/ext/bloops.rb +1 -0
- data/lib/ext/bloops/bloops.so +0 -0
- data/lib/ext/bloops/libportaudio-2.dll +0 -0
- data/lib/ext/bloops/songs/1901_by_Aanand_Prasad.rb +478 -0
- data/lib/ext/bloops/songs/bloopsaphone_theme_song_by_why.rb +31 -0
- data/lib/ext/bloops/songs/feepogram.rb +67 -0
- data/lib/ext/bloops/songs/simpsons_theme_song_by_why.rb +14 -0
- data/lib/ext/chipmunk.rb +34 -0
- data/lib/ext/chipmunk/chipmunk.so +0 -0
- data/lib/ext/projector.rb +1 -0
- data/lib/ext/projector/matrix3d.rb +73 -0
- data/lib/ext/projector/projector.rb +306 -0
- data/lib/green_shoes.rb +45 -0
- data/lib/shoes/anim.rb +19 -0
- data/lib/shoes/app.rb +591 -0
- data/lib/shoes/basic.rb +242 -0
- data/lib/shoes/colors.rb +150 -0
- data/lib/shoes/download.rb +26 -0
- data/lib/shoes/help.rb +171 -0
- data/lib/shoes/helper_methods.rb +308 -0
- data/lib/shoes/main.rb +99 -0
- data/lib/shoes/manual.rb +6 -0
- data/lib/shoes/mask.rb +29 -0
- data/lib/shoes/projector.rb +42 -0
- data/lib/shoes/ruby.rb +73 -0
- data/lib/shoes/slot.rb +68 -0
- data/lib/shoes/text.rb +44 -0
- data/lib/shoes/url.rb +14 -0
- data/lib/shoes/widget.rb +18 -0
- data/static/Coolvetica.ttf +0 -0
- data/static/Lacuna.ttf +0 -0
- data/static/downloading.png +0 -0
- data/static/gshoes-heading-icon.png +0 -0
- data/static/gshoes-icon.png +0 -0
- data/static/man-app.png +0 -0
- data/static/man-builds.png +0 -0
- data/static/man-builds1.png +0 -0
- data/static/man-editor-notepad.png +0 -0
- data/static/man-editor-osx.png +0 -0
- data/static/man-ele-background.png +0 -0
- data/static/man-ele-border.png +0 -0
- data/static/man-ele-button.png +0 -0
- data/static/man-ele-check.png +0 -0
- data/static/man-ele-editbox.png +0 -0
- data/static/man-ele-editline.png +0 -0
- data/static/man-ele-image.png +0 -0
- data/static/man-ele-listbox.png +0 -0
- data/static/man-ele-progress.png +0 -0
- data/static/man-ele-radio.png +0 -0
- data/static/man-ele-shape.png +0 -0
- data/static/man-ele-textblock.png +0 -0
- data/static/man-ele-video.png +0 -0
- data/static/man-intro-dmg.png +0 -0
- data/static/man-intro-exe.png +0 -0
- data/static/man-look-tiger.png +0 -0
- data/static/man-look-ubuntu.png +0 -0
- data/static/man-look-vista.png +0 -0
- data/static/man-run-osx.png +0 -0
- data/static/man-run-vista.png +0 -0
- data/static/man-run-xp.png +0 -0
- data/static/man-shot1.png +0 -0
- data/static/manual-en.txt +3523 -0
- data/static/manual-ja.txt +2825 -0
- data/static/shoes-manual-apps.png +0 -0
- metadata +146 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
# the bloops o' phone
|
3
|
+
b = Bloops.new
|
4
|
+
b.tempo = 320
|
5
|
+
|
6
|
+
# melodious
|
7
|
+
s1 = b.sound Bloops::SQUARE
|
8
|
+
s1.punch = 0.5
|
9
|
+
s1.sustain = 0.4
|
10
|
+
s1.decay = 0.2
|
11
|
+
s1.arp = 0.4
|
12
|
+
s1.aspeed = 0.6
|
13
|
+
s1.repeat = 0.6
|
14
|
+
s1.phase = 0.2
|
15
|
+
s1.psweep = 0.2
|
16
|
+
|
17
|
+
# beats
|
18
|
+
s2 = b.sound Bloops::NOISE
|
19
|
+
s2.punch = 0.5
|
20
|
+
s2.sustain = 0.2
|
21
|
+
s2.decay = 0.4
|
22
|
+
s2.slide = -0.4
|
23
|
+
s2.phase = 0.2
|
24
|
+
s2.psweep = 0.2
|
25
|
+
|
26
|
+
# the tracks
|
27
|
+
b.tune s1, "f#5 c6 e4 b6 g5 d6 4 f#5 e5 c5 b6 c6 d6 4 "
|
28
|
+
b.tune s2, "4 c6 4 b5 4 4 e4 4 c6 4 b5 4 4 e4"
|
29
|
+
|
30
|
+
b.play
|
31
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# downloaded from http://github.com/aanand/feepogram
|
2
|
+
class Feepogram
|
3
|
+
attr_reader :bloops, :length
|
4
|
+
|
5
|
+
def initialize(bloops, &block)
|
6
|
+
@bloops = bloops
|
7
|
+
@length = 0
|
8
|
+
|
9
|
+
@sounds = {}
|
10
|
+
@tracks = {}
|
11
|
+
@track_lengths = {}
|
12
|
+
|
13
|
+
instance_eval(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def metaclass
|
17
|
+
class << self; self; end
|
18
|
+
end
|
19
|
+
|
20
|
+
def metaclass_eval(&block)
|
21
|
+
metaclass.class_eval(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def sound(name, base, &block)
|
25
|
+
name = name.to_sym
|
26
|
+
|
27
|
+
sound = bloops.sound(base)
|
28
|
+
|
29
|
+
@sounds[name] = sound
|
30
|
+
@tracks[name] = ""
|
31
|
+
@track_lengths[name] = 0
|
32
|
+
|
33
|
+
block.call(sound)
|
34
|
+
|
35
|
+
instance_variable_set("@#{name}", sound)
|
36
|
+
|
37
|
+
metaclass_eval do
|
38
|
+
define_method(name) do |notes|
|
39
|
+
dub(name, notes)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def phrase(&block)
|
45
|
+
instance_eval(&block)
|
46
|
+
@length += 32
|
47
|
+
end
|
48
|
+
|
49
|
+
def dub sound_name, notes
|
50
|
+
catchup = @length - @track_lengths[sound_name]
|
51
|
+
|
52
|
+
@tracks[sound_name] << ("4 " * catchup)
|
53
|
+
@tracks[sound_name] << notes
|
54
|
+
@track_lengths[sound_name] = length+32
|
55
|
+
end
|
56
|
+
|
57
|
+
def play
|
58
|
+
@tracks.each do |sound_name, notes|
|
59
|
+
bloops.tune @sounds[sound_name], notes
|
60
|
+
|
61
|
+
#puts "#{sound_name}: #{notes.gsub(/\s+/, ' ')}"
|
62
|
+
end
|
63
|
+
|
64
|
+
bloops.play
|
65
|
+
sleep 1 while !bloops.stopped?
|
66
|
+
end
|
67
|
+
end
|
data/lib/ext/chipmunk.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'chipmunk/chipmunk'
|
2
|
+
|
3
|
+
module ChipMunk
|
4
|
+
def cp_space
|
5
|
+
@space = CP::Space.new
|
6
|
+
@space.damping = 0.8
|
7
|
+
@space.gravity = vec2 0, 25
|
8
|
+
@space
|
9
|
+
end
|
10
|
+
|
11
|
+
def cp_oval l, t, r, opts = {}
|
12
|
+
b = CP::Body.new 1,1
|
13
|
+
b.p = vec2 l, t
|
14
|
+
@space.add_body b
|
15
|
+
@space.add_shape CP::Shape::Circle.new(b, r, vec2(0, 0))
|
16
|
+
|
17
|
+
opts = opts.merge({left: l-r-1, top: t-r-1, width: 2*r+2, height: 2*r+2, body: b, inflate: r-2})
|
18
|
+
oval opts
|
19
|
+
end
|
20
|
+
|
21
|
+
def cp_line x0, y0, x1, y1, opts = {}
|
22
|
+
opts[:strokewidth] = 5 unless opts[:strokewidth]
|
23
|
+
sb = CP::Body.new 1.0/0.0, 1.0/0.0
|
24
|
+
seg = CP::Shape::Segment.new sb, vec2(x0, y0), vec2(x1, y1), opts[:strokewidth]
|
25
|
+
@space.add_shape seg
|
26
|
+
line x0, y0, x1, y1, opts
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Shoes::ShapeBase.class_eval do
|
31
|
+
def cp_move
|
32
|
+
move args[:body].p.x.to_i - args[:inflate], args[:body].p.y.to_i - args[:inflate]
|
33
|
+
end
|
34
|
+
end
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'projector/projector'
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Author:: MIZUTANI Tociyuki <tociyuki@gmail.com>
|
2
|
+
# Copyright: Copyright 2010 by MIZUTANI Tociyuki
|
3
|
+
# License:: GNU General Public License Version 2
|
4
|
+
|
5
|
+
require 'matrix'
|
6
|
+
|
7
|
+
module Matrix3d
|
8
|
+
def identity() Matrix.identity(4) end
|
9
|
+
|
10
|
+
def frustum(left, right, bottom, top, znear, zfar)
|
11
|
+
x = 2.0 * znear / (right - left)
|
12
|
+
y = 2.0 * znear / (top - bottom)
|
13
|
+
a = (right + left) / (right - left)
|
14
|
+
b = (top + bottom) / (top - bottom)
|
15
|
+
c = -(zfar + znear) / (zfar - znear)
|
16
|
+
d = -2.0 * zfar * znear / (zfar - znear)
|
17
|
+
Matrix[
|
18
|
+
[x, 0.0, a, 0.0],
|
19
|
+
[0.0, y, b, 0.0],
|
20
|
+
[0.0, 0.0, c, d],
|
21
|
+
[0.0, 0.0, -1.0, 0.0]
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
def perspective(fov, aspect, znear, zfar)
|
26
|
+
yhi = znear * Math.tan(fov * Math::PI / 360.0)
|
27
|
+
ylo = -yhi
|
28
|
+
xlo = ylo * aspect
|
29
|
+
xhi = yhi * aspect
|
30
|
+
frustum(xlo, xhi, ylo, yhi, znear, zfar)
|
31
|
+
end
|
32
|
+
|
33
|
+
def translate(v)
|
34
|
+
v.size >= 3 or raise 'vector size >= 3.'
|
35
|
+
Matrix[
|
36
|
+
[1.0, 0.0, 0.0, v[0]],
|
37
|
+
[0.0, 1.0, 0.0, v[1]],
|
38
|
+
[0.0, 0.0, 1.0, v[2]],
|
39
|
+
[0.0, 0.0, 0.0, 1.0]
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
def scale(v)
|
44
|
+
v.size >= 3 or raise 'vector size >= 3.'
|
45
|
+
Matrix[
|
46
|
+
[v[0], 0.0, 0.0, 0.0],
|
47
|
+
[0.0, v[1], 0.0, 0.0],
|
48
|
+
[0.0, 0.0, v[2], 0.0],
|
49
|
+
[0.0, 0.0, 0.0, 1.0]
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
def rotate(theta, axis)
|
54
|
+
axis.size >= 3 or raise 'axis vector size >= 3.'
|
55
|
+
theta = Math::PI / 180.0 * theta
|
56
|
+
axis = Vector[axis[0], axis[1], axis[2]]
|
57
|
+
axis_r = axis.r
|
58
|
+
axis_r > axis_r * Float::EPSILON or raise 'r must not be zero vector.'
|
59
|
+
x = axis[0] / axis_r
|
60
|
+
y = axis[1] / axis_r
|
61
|
+
z = axis[2] / axis_r
|
62
|
+
s = Math.sin(theta)
|
63
|
+
c = Math.cos(theta)
|
64
|
+
cc = 1.0 - c
|
65
|
+
Matrix[
|
66
|
+
[cc * x * x + c, cc * y * x - s * z, cc * z * x + s * y, 0.0],
|
67
|
+
[cc * x * y + s * z, cc * y * y + c, cc * z * y - s * x, 0.0],
|
68
|
+
[cc * x * z - s * y, cc * y * z + s * x, cc * z * z + c, 0.0],
|
69
|
+
[0.0, 0.0, 0.0, 1.0]
|
70
|
+
]
|
71
|
+
end
|
72
|
+
module_function :identity, :frustum, :perspective, :translate, :scale, :rotate
|
73
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: UTF-8 -*-
|
3
|
+
# Author:: MIZUTANI Tociyuki <tociyuki@gmail.com>
|
4
|
+
# Copyright: Copyright 2010 by MIZUTANI Tociyuki
|
5
|
+
# License:: GNU General Public License Version 2
|
6
|
+
#
|
7
|
+
# wget -O akatsukiface.png http://img.f.hatena.ne.jp/images/fotolife/t/tociyuki/20101219/20101219152034_original.png
|
8
|
+
# ruby akatsuki-papermodel.rb
|
9
|
+
|
10
|
+
#require 'gtk2'
|
11
|
+
require_relative 'matrix3d'
|
12
|
+
require 'observer'
|
13
|
+
|
14
|
+
module AkatsukiFace
|
15
|
+
# JAXA PLANET-C Akatsuki paper craft
|
16
|
+
# http://www.jaxa.jp/countdown/f17/special/craft_j.html
|
17
|
+
|
18
|
+
#IMG_SOURCE = 'akatsukiface.png'
|
19
|
+
|
20
|
+
# body size: 1040mm 1450mm 1400mm
|
21
|
+
SCALE = Vector[1040.0/1450.0, 1.0, 1400.0/1450.0, 1.0]
|
22
|
+
FACES = [
|
23
|
+
{
|
24
|
+
'label' => 'loof',
|
25
|
+
'angle' => -90.0, 'axis' => Vector[1.0, 0.0, 0.0, 1.0],
|
26
|
+
'texture' => [0.00, 0.00, 0.25, 0.50], # left, top, width, height
|
27
|
+
},
|
28
|
+
{
|
29
|
+
'label' => 'front',
|
30
|
+
'angle' => 0.0, 'axis' => Vector[0.0, 1.0, 0.0, 1.0],
|
31
|
+
'texture' => [0.00, 0.50, 0.25, 0.50],
|
32
|
+
},
|
33
|
+
{
|
34
|
+
'label' => 'floor',
|
35
|
+
'angle' => +90.0, 'axis' => Vector[1.0, 0.0, 0.0, 1.0],
|
36
|
+
'texture' => [0.25, 0.00, 0.25, 0.50],
|
37
|
+
},
|
38
|
+
{
|
39
|
+
'label' => 'right',
|
40
|
+
'angle' => +90.0, 'axis' => Vector[0.0, 1.0, 0.0, 1.0],
|
41
|
+
'texture' => [0.25, 0.50, 0.25, 0.50],
|
42
|
+
},
|
43
|
+
{
|
44
|
+
'label' => 'back',
|
45
|
+
'angle' => +180.0, 'axis' => Vector[0.0, 1.0, 0.0, 1.0],
|
46
|
+
'texture' => [0.50, 0.50, 0.25, 0.50],
|
47
|
+
},
|
48
|
+
{
|
49
|
+
'label' => 'left',
|
50
|
+
'angle' => +270.0, 'axis' => Vector[0.0, 1.0, 0.0, 1.0],
|
51
|
+
'texture' => [0.75, 0.50, 0.25, 0.50],
|
52
|
+
},
|
53
|
+
]
|
54
|
+
|
55
|
+
# divide MESH x MESH rectangles per a FACE
|
56
|
+
MESH = 2
|
57
|
+
|
58
|
+
# the modeling unit: right-hand 3d object coordinates
|
59
|
+
VERTEXS = [
|
60
|
+
Vector[0.0, 0.0, +1.0, 1.0], # left bottom
|
61
|
+
Vector[1.0, 0.0, +1.0, 1.0], # right bottom
|
62
|
+
Vector[1.0, 1.0, +1.0, 1.0], # right top
|
63
|
+
Vector[0.0, 1.0, +1.0, 1.0], # left top
|
64
|
+
]
|
65
|
+
# the texture unit: left-hand 2d Gtk::DrawingArea coordinates
|
66
|
+
TEXTURES = [
|
67
|
+
Vector[0.0, 1.0], # left bottom
|
68
|
+
Vector[1.0, 1.0], # right bottom
|
69
|
+
Vector[1.0, 0.0], # right top
|
70
|
+
Vector[0.0, 0.0], # left top
|
71
|
+
]
|
72
|
+
|
73
|
+
def create
|
74
|
+
scale = Matrix3d::scale(SCALE)
|
75
|
+
divide = MESH.to_f
|
76
|
+
FACES.inject([]) do |list, face|
|
77
|
+
transform = scale * Matrix3d::rotate(face['angle'], face['axis'])
|
78
|
+
(0 ... MESH).to_a.product((0 ... MESH).to_a).each do |part|
|
79
|
+
x, y = part.map{|i| i.to_f }
|
80
|
+
v = VERTEXS.map {|c|
|
81
|
+
transform * Vector[
|
82
|
+
(c[0] + x) * 2.0 / divide - 1.0,
|
83
|
+
(c[1] + divide - 1.0 - y) * 2.0 / divide - 1.0,
|
84
|
+
c[2],
|
85
|
+
c[3]
|
86
|
+
]
|
87
|
+
}
|
88
|
+
t = TEXTURES.map {|c|
|
89
|
+
left, top, width, height = face['texture']
|
90
|
+
Vector[
|
91
|
+
(c[0] + x) * width / divide + left,
|
92
|
+
(c[1] + y) * height / divide + top
|
93
|
+
]
|
94
|
+
}
|
95
|
+
|
96
|
+
# to keep simple calculations on S^{-1},
|
97
|
+
# we assume s1 - s0 = (s00, 0.0), s2 - s0 = (0.0, s11)
|
98
|
+
# left-bottom triangle counterclockwise
|
99
|
+
# (left, bottom) -> (right, bottom) -> (left, top)
|
100
|
+
list.push({
|
101
|
+
'vertex' => [0, 1, 3].map {|i| v[i] },
|
102
|
+
'texture' => [0, 1, 3].map {|i| t[i] },
|
103
|
+
})
|
104
|
+
# right-top triangle counterclockwise
|
105
|
+
# (right, top) -> (left, top) -> (right, bottom)
|
106
|
+
list.push({
|
107
|
+
'vertex' => [2, 3, 1].map {|i| v[i] },
|
108
|
+
'texture' => [2, 3, 1].map {|i| t[i] },
|
109
|
+
})
|
110
|
+
end
|
111
|
+
list
|
112
|
+
end
|
113
|
+
end
|
114
|
+
module_function :create
|
115
|
+
end
|
116
|
+
|
117
|
+
class TextureMappingData
|
118
|
+
include Observable
|
119
|
+
|
120
|
+
SCALE_A = 50.0
|
121
|
+
|
122
|
+
attr_reader :texture, :transform, :face_list
|
123
|
+
def texture=(x) @texture = x; update; x end
|
124
|
+
def transform=(x) @transform = x; update; x end
|
125
|
+
def face_list=(x) @face_list = x; update; x end
|
126
|
+
|
127
|
+
def initialize
|
128
|
+
@texture = nil
|
129
|
+
@transform = Matrix3d::identity
|
130
|
+
@transform *= Matrix3d::rotate(+20.0, Vector[1.0, 0.0, 0.0, 1.0])
|
131
|
+
@transform *= Matrix3d::rotate(+30.0, Vector[0.0, 1.0, 0.0, 1.0])
|
132
|
+
@transform *= Matrix3d::rotate(+90.0, Vector[0.0, 0.0, 1.0, 1.0])
|
133
|
+
@face_list = []
|
134
|
+
@transform_begin = nil
|
135
|
+
end
|
136
|
+
|
137
|
+
def update
|
138
|
+
changed
|
139
|
+
notify_observers
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
def begin_work
|
144
|
+
@transform_begin = @transform
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def swing_step(dx, dy)
|
149
|
+
a = Math::sqrt(dx * dx + dy * dy) * SCALE_A
|
150
|
+
a > a * Float::EPSILON or return self
|
151
|
+
self.transform = Matrix3d::rotate(a, Vector[dy, dx, 0.0, 1.0]) * @transform_begin
|
152
|
+
self
|
153
|
+
end
|
154
|
+
|
155
|
+
def commit
|
156
|
+
@transform_begin = nil
|
157
|
+
self
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class Projector
|
162
|
+
include Observable
|
163
|
+
|
164
|
+
attr_accessor :widget
|
165
|
+
attr_reader :controller
|
166
|
+
|
167
|
+
def controller=(c)
|
168
|
+
@controller = c
|
169
|
+
@controller.add_observer(self)
|
170
|
+
c
|
171
|
+
end
|
172
|
+
|
173
|
+
def initialize
|
174
|
+
@widget = nil
|
175
|
+
@invalid_drawing = true
|
176
|
+
end
|
177
|
+
|
178
|
+
def update
|
179
|
+
@invalid_drawing = true
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
183
|
+
def draw
|
184
|
+
@invalid_drawing or return self
|
185
|
+
drawing_area_context = @widget.window.create_cairo_context
|
186
|
+
port = @widget.allocation
|
187
|
+
fb = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, port.width, port.height)
|
188
|
+
fb_context = Cairo::Context.new(fb)
|
189
|
+
scene(fb_context, port)
|
190
|
+
drawing_area_context.set_source(fb)
|
191
|
+
drawing_area_context.paint
|
192
|
+
@invalid_drawing = false
|
193
|
+
self
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def scene(context, port)
|
199
|
+
context.set_source_rgb(0, 0, 0)
|
200
|
+
context.paint
|
201
|
+
w = port.width.to_f / 2
|
202
|
+
h = port.height.to_f / 2
|
203
|
+
projection = Matrix3d::perspective(50.0, w/h, 1.0, 100.0)
|
204
|
+
projection *= Matrix3d::translate(Vector[0.0, 0.0, -5.0, 1.0])
|
205
|
+
projection *= controller.content.transform
|
206
|
+
texture = controller.content.texture
|
207
|
+
controller.content.face_list.each do |face|
|
208
|
+
vertex_list = face['vertex'].map{|r|
|
209
|
+
v = projection * r
|
210
|
+
Vector[w + v[0]/v[3] * w, h - v[1]/v[3] * h] # widget canvas coordinate
|
211
|
+
}
|
212
|
+
vertex10 = vertex_list[1] - vertex_list[0]
|
213
|
+
vertex20 = vertex_list[2] - vertex_list[0]
|
214
|
+
next if vertex10[0] * vertex20[1] - vertex10[1] * vertex20[0] > 0
|
215
|
+
fill_triangle(context, texture, vertex_list, face['texture'])
|
216
|
+
end
|
217
|
+
self
|
218
|
+
end
|
219
|
+
|
220
|
+
# left-hand Gtk::DrawingArea coordinates
|
221
|
+
def fill_triangle(context, texture, dst, src_uv)
|
222
|
+
scale_x, scale_y = texture.width.to_f, texture.height.to_f
|
223
|
+
src = src_uv.map {|v| Vector[scale_x * v[0], scale_y * v[1]] }
|
224
|
+
# r_d = D S^-1 (r_s - r_s0) + r_d0
|
225
|
+
# we assume S is a daigonal matrix.
|
226
|
+
s00 = src[1][0] - src[0][0]
|
227
|
+
s11 = src[2][1] - src[0][1]
|
228
|
+
d0 = dst[1] - dst[0]
|
229
|
+
d1 = dst[2] - dst[0]
|
230
|
+
ds = Matrix[[d0[0]/s00, d1[0]/s11], [d0[1]/s00, d1[1]/s11]]
|
231
|
+
ds0 = dst[0] - ds * src[0]
|
232
|
+
context.save do
|
233
|
+
context.set_antialias(Cairo::ANTIALIAS_NONE)
|
234
|
+
context.transform(Cairo::Matrix.new(ds[0, 0], ds[1, 0], ds[0, 1], ds[1, 1], ds0[0], ds0[1]))
|
235
|
+
texture.source_set(context)
|
236
|
+
context.move_to(src[0][0], src[0][1])
|
237
|
+
context.line_to(src[1][0], src[1][1])
|
238
|
+
context.line_to(src[2][0], src[2][1])
|
239
|
+
context.line_to(src[0][0], src[0][1])
|
240
|
+
context.fill
|
241
|
+
end
|
242
|
+
self
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
class SwingController
|
247
|
+
include Observable
|
248
|
+
|
249
|
+
attr_reader :content
|
250
|
+
|
251
|
+
def initialize
|
252
|
+
@content = nil
|
253
|
+
@drag = false
|
254
|
+
@ratio_x = 0.01
|
255
|
+
@ratio_y = 0.01
|
256
|
+
@start_x = 0
|
257
|
+
@start_y = 0
|
258
|
+
end
|
259
|
+
|
260
|
+
def content=(x)
|
261
|
+
@content = x
|
262
|
+
@content.add_observer(self)
|
263
|
+
x
|
264
|
+
end
|
265
|
+
|
266
|
+
def update
|
267
|
+
changed
|
268
|
+
notify_observers
|
269
|
+
self
|
270
|
+
end
|
271
|
+
|
272
|
+
def region(allocation)
|
273
|
+
@ratio_x = 1.0 / allocation.width.to_f
|
274
|
+
@ratio_y = 1.0 / allocation.height.to_f
|
275
|
+
self
|
276
|
+
end
|
277
|
+
|
278
|
+
def press(event)
|
279
|
+
@drag = true
|
280
|
+
@start_x, @start_y = event.x, event.y
|
281
|
+
content.begin_work
|
282
|
+
self
|
283
|
+
end
|
284
|
+
|
285
|
+
def motion(event)
|
286
|
+
@drag or return self
|
287
|
+
swing_to(event.x, event.y)
|
288
|
+
self
|
289
|
+
end
|
290
|
+
|
291
|
+
def release(event)
|
292
|
+
swing_to(event.x, event.y)
|
293
|
+
content.commit
|
294
|
+
@drag = false
|
295
|
+
self
|
296
|
+
end
|
297
|
+
|
298
|
+
private
|
299
|
+
|
300
|
+
def swing_to(x, y)
|
301
|
+
dx = (x - @start_x).to_f * @ratio_x
|
302
|
+
dy = (y - @start_y).to_f * @ratio_y
|
303
|
+
content.swing_step(dx, dy)
|
304
|
+
self
|
305
|
+
end
|
306
|
+
end
|