green_shoes 0.129.0
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.
- 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
|