Skip to content

Commit 021c7a8

Browse files
committed
glvideo
1 parent 8960fd9 commit 021c7a8

File tree

7 files changed

+208
-0
lines changed

7 files changed

+208
-0
lines changed
Loading
Binary file not shown.
2.08 MB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
require 'forwardable'
3+
# placeholder for vector coordinates
4+
Vect = Struct.new(:x, :y)
5+
6+
# A class to contain frame corners, uses forwardable
7+
class Corners
8+
include Enumerable
9+
extend Forwardable
10+
def_delegators :@corners, :each_with_index, :[], :[]=, :<<
11+
attr_reader :idx
12+
13+
def initialize(width, height, ws, wh)
14+
@corners = [
15+
Vect.new(width / 2 - ws, height / 2 - wh),
16+
Vect.new(width / 2 + ws, height / 2 - wh),
17+
Vect.new(width / 2 + ws, height / 2 + wh),
18+
Vect.new(width / 2 - ws, height / 2 + wh)
19+
]
20+
@idx = -1
21+
end
22+
23+
def set_corner(mx, my)
24+
self[idx] = Vect.new(mx, my)
25+
end
26+
27+
def selected?
28+
idx != -1
29+
end
30+
31+
def set_index(sel)
32+
@idx = sel
33+
end
34+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env jruby
2+
require 'propane'
3+
# The sketch class
4+
class SimpleCapture < Propane::App
5+
load_library :glvideo
6+
include_package 'gohai.glvideo'
7+
attr_reader :video
8+
9+
def settings
10+
size(320, 240, P2D)
11+
end
12+
13+
def setup
14+
sketch_title 'Simple Capture'
15+
report_config
16+
# this will use the first recognized camera by default
17+
@video = GLCapture.new(self)
18+
# you could be more specific also, e.g.
19+
# video = GLCapture.new(self, devices[0])
20+
# video = GLCapture.new(self, devices[0], 640, 480, 25)
21+
# video = GLCapture.new(self, devices[0], configs[0])
22+
video.play
23+
end
24+
25+
def draw
26+
background 0
27+
video.read if video.available
28+
image(video, 0, 0, width, height)
29+
end
30+
31+
def report_config
32+
devices = GLCapture.list
33+
puts('Devices:')
34+
devices.each { |dev| puts dev }
35+
return unless 0 < devices.length
36+
configs = GLCapture.configs(devices[0]).to_a # ruby array
37+
puts('Configs:')
38+
configs.map { |cam| puts cam.strip }
39+
end
40+
end
41+
42+
SimpleCapture.new
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env jruby
2+
require 'propane'
3+
# The sketch class
4+
class SingleVideo < Propane::App
5+
6+
load_library :glvideo
7+
8+
include_package 'gohai.glvideo'
9+
10+
attr_reader :video
11+
12+
def setup
13+
sketch_title 'Single Video'
14+
@video = GLMovie.new(self, data_path('launch1.mp4'))
15+
video.loop
16+
end
17+
18+
def draw
19+
background(0)
20+
video.read if video.available
21+
image(video, 0, 0, width, height)
22+
end
23+
24+
def settings
25+
size(560, 406, P2D)
26+
end
27+
end
28+
29+
SingleVideo.new
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env jruby
2+
require 'propane'
3+
# The sketch class
4+
class VideoMapping < Propane::App
5+
load_libraries :glvideo, :corners
6+
include_package 'gohai.glvideo'
7+
8+
# placeholder for image sources
9+
ImageSource = Struct.new(:video, :image)
10+
11+
attr_reader :sources, :sel, :video, :corners, :quads, :last_mouse_move
12+
RES = 5 # number of subdivisions (e.g. 5 x 5)
13+
14+
def setup
15+
@last_mouse_move = 0
16+
no_cursor
17+
@video = GLMovie.new(self, data_path('launch2.mp4'))
18+
video.loop
19+
image = load_image(data_path('checkerboard.png'))
20+
@sources = ImageSource.new(video, image)
21+
@sel = sources.video
22+
@corners = Corners.new(width, height, sources.image.width / 2, sources.image.height / 2)
23+
@quads = create_mesh(sel, corners, RES)
24+
end
25+
26+
def draw
27+
background(0)
28+
video.read if sel.respond_to?(:read) && video.available
29+
# regenerate mesh if we're dragging a corner
30+
if corners.selected? && (pmouse_x != mouse_x || pmouse_y != mouse_y)
31+
corners.set_corner(mouse_x, mouse_y)
32+
# this improves performance, but will be replaced by a
33+
# more elegant way in a future release
34+
@quads = []
35+
# Java::JavaLang::System.gc # this is generally not recommended
36+
@quads = create_mesh(sel, corners, RES)
37+
end
38+
39+
# display
40+
quads.map { |quad| shape(quad) } unless quads.empty?
41+
# hide the mouse cursor after two seconds
42+
if pmouse_x != mouse_x || pmouse_y != mouse_y
43+
cursor
44+
@last_mouse_move = millis
45+
elsif !last_mouse_move.zero? && 2000 < millis - last_mouse_move
46+
no_cursor
47+
@last_mouse_move = 0
48+
end
49+
end
50+
51+
def mouse_pressed
52+
corners.each_with_index do |corner, i|
53+
return corners.set_index(i) if dist(mouse_x, mouse_y, corner.x, corner.y) < 20
54+
end
55+
# no corner? then switch texture
56+
@sel = sel.respond_to?(:loop) ? sources.image : sources.video
57+
@quads = create_mesh(sel, corners, RES)
58+
end
59+
60+
def mouse_released
61+
corners.set_index(-1)
62+
end
63+
64+
def create_mesh(tex, corners, res)
65+
transform = PerspectiveTransform.get_quad_to_quad(
66+
0, 0, tex.width, 0, # top left, top right
67+
tex.width, tex.height, 0, tex.height, # bottom right, bottom left
68+
corners[0].x, corners[0].y, corners[1].x, corners[1].y,
69+
corners[2].x, corners[2].y, corners[3].x, corners[3].y
70+
)
71+
warp_perspective = WarpPerspective.new(transform)
72+
x_step = tex.width.to_f / res
73+
y_step = tex.height.to_f / res
74+
quads = []
75+
(0...res).each do |y|
76+
(0...res).each do |x|
77+
texture_mode(NORMAL)
78+
sh = create_shape
79+
sh.begin_shape(QUAD)
80+
sh.no_stroke
81+
sh.texture(tex)
82+
sh.normal(0, 0, 1)
83+
point = warp_perspective.map_dest_point(x * x_step, y * y_step)
84+
sh.vertex(point.get_x.to_f, point.get_y.to_f, 0, x.to_f / res, y.to_f / res)
85+
point = warp_perspective.map_dest_point((x + 1) * x_step, y * y_step)
86+
sh.vertex(point.get_x.to_f, point.get_y.to_f, 0, (x + 1).to_f / res, y.to_f / res)
87+
point = warp_perspective.map_dest_point((x + 1) * x_step, (y + 1) * y_step)
88+
sh.vertex(point.get_x.to_f, point.get_y.to_f, 0, (x + 1).to_f / res, (y + 1).to_f / res)
89+
point = warp_perspective.map_dest_point(x * x_step, (y + 1) * y_step)
90+
sh.vertex(point.get_x.to_f, point.get_y.to_f, 0, x.to_f / res, (y + 1).to_f / res)
91+
sh.end_shape
92+
quads[y * res + x] = sh
93+
end
94+
end
95+
quads
96+
end
97+
98+
def settings
99+
full_screen(P2D)
100+
end
101+
end
102+
103+
VideoMapping.new

0 commit comments

Comments
 (0)