rbgl 1.0.0 → 1.0.1
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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +7 -1
- data/README.md +130 -74
- data/Rakefile +7 -0
- data/bench/renderer_bench.rb +283 -0
- data/docs/.nojekyll +1 -0
- data/docs/index.html +38 -0
- data/examples/array_test.rb +1 -1
- data/examples/color_test.rb +1 -1
- data/examples/cube_spinning.rb +1 -1
- data/examples/gradient.rb +1 -1
- data/examples/multi_return_test.rb +1 -1
- data/examples/plasma.rb +1 -1
- data/examples/sphere_raymarch.rb +1 -1
- data/examples/triangle_window.rb +1 -1
- data/exe/rbgl +42 -0
- data/lib/rbgl/cli/doctor.rb +155 -0
- data/lib/rbgl/engine/buffer.rb +49 -8
- data/lib/rbgl/engine/clip_space_clipper.rb +23 -3
- data/lib/rbgl/engine/context.rb +23 -6
- data/lib/rbgl/engine/framebuffer.rb +137 -41
- data/lib/rbgl/engine/immutable_color.rb +32 -0
- data/lib/rbgl/engine/rasterizer/attribute_interpolator.rb +100 -10
- data/lib/rbgl/engine/rasterizer/line_renderer.rb +30 -14
- data/lib/rbgl/engine/rasterizer/point_renderer.rb +3 -3
- data/lib/rbgl/engine/rasterizer/triangle_renderer.rb +72 -23
- data/lib/rbgl/engine/rasterizer.rb +3 -20
- data/lib/rbgl/engine/shader/base_shader.rb +3 -7
- data/lib/rbgl/engine/shader/builtins.rb +13 -10
- data/lib/rbgl/engine/shader/dynamic_data.rb +18 -10
- data/lib/rbgl/engine/texture.rb +74 -50
- data/lib/rbgl/engine.rb +3 -1
- data/lib/rbgl/gui/backend.rb +12 -7
- data/lib/rbgl/gui/backend_factory.rb +7 -3
- data/lib/rbgl/gui/cocoa/backend.rb +50 -17
- data/lib/rbgl/gui/cocoa/key_mapper.rb +48 -0
- data/lib/rbgl/gui/event.rb +4 -2
- data/lib/rbgl/gui/file_backend/bmp_writer.rb +2 -2
- data/lib/rbgl/gui/file_backend/frame_writer.rb +7 -0
- data/lib/rbgl/gui/file_backend/png_writer.rb +18 -0
- data/lib/rbgl/gui/file_backend/ppm_writer.rb +1 -0
- data/lib/rbgl/gui/file_backend.rb +24 -6
- data/lib/rbgl/gui/wayland/backend.rb +127 -55
- data/lib/rbgl/gui/wayland/codec.rb +7 -11
- data/lib/rbgl/gui/wayland/connection.rb +137 -20
- data/lib/rbgl/gui/wayland/event_dispatcher.rb +103 -12
- data/lib/rbgl/gui/wayland/global_binder.rb +6 -4
- data/lib/rbgl/gui/wayland/input_mapper.rb +61 -0
- data/lib/rbgl/gui/wayland/protocol_objects/arguments.rb +14 -2
- data/lib/rbgl/gui/wayland/protocol_objects/seat.rb +115 -0
- data/lib/rbgl/gui/wayland/protocol_objects/shm.rb +23 -12
- data/lib/rbgl/gui/wayland/protocol_objects/xdg_shell.rb +15 -0
- data/lib/rbgl/gui/wayland/protocol_objects.rb +1 -0
- data/lib/rbgl/gui/window/render_loop.rb +71 -18
- data/lib/rbgl/gui/window.rb +39 -8
- data/lib/rbgl/gui/x11/atom_cache.rb +4 -1
- data/lib/rbgl/gui/x11/backend.rb +66 -28
- data/lib/rbgl/gui/x11/connection.rb +216 -86
- data/lib/rbgl/gui/x11/event_parser.rb +13 -2
- data/lib/rbgl/gui/x11/key_mapper.rb +48 -0
- data/lib/rbgl/gui/x11/pixel_encoder.rb +164 -0
- data/lib/rbgl/gui/x11/request_encoder.rb +29 -28
- data/lib/rbgl/gui/x11/setup_parser.rb +138 -0
- data/lib/rbgl/gui/x11/transport.rb +52 -2
- data/lib/rbgl/gui/x11/x_authority.rb +107 -0
- data/lib/rbgl/gui.rb +2 -5
- data/lib/rbgl/version.rb +1 -1
- metadata +36 -24
- data/examples/chemical_heartbeat.rb +0 -166
- data/examples/dark_transit.rb +0 -166
- data/examples/fractured_orb.rb +0 -428
- data/examples/fractured_orb_rb.rb +0 -598
- data/examples/hexagonal_flow.rb +0 -333
- data/examples/teapot.rb +0 -362
- data/examples/teapot_mcu.rb +0 -344
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# chemical heartbeat
|
|
4
|
-
# Original: https://www.shadertoy.com/view/lXtXD4
|
|
5
|
-
# License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0
|
|
6
|
-
# https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
|
|
7
|
-
|
|
8
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
9
|
-
|
|
10
|
-
require "rbgl"
|
|
11
|
-
require "rlsl"
|
|
12
|
-
|
|
13
|
-
WIDTH = 640
|
|
14
|
-
HEIGHT = 480
|
|
15
|
-
|
|
16
|
-
# Define shader using pure Ruby DSL
|
|
17
|
-
shader = RLSL.define(:chemical_heartbeat) do
|
|
18
|
-
uniforms do
|
|
19
|
-
float :time
|
|
20
|
-
float :camera_x
|
|
21
|
-
float :camera_y
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
fragment do |frag_coord, resolution, u|
|
|
25
|
-
uv = frag_coord / resolution.y
|
|
26
|
-
|
|
27
|
-
# Constants
|
|
28
|
-
inv_hex_size = 50.0
|
|
29
|
-
sqrt3_div3 = 0.5773502691896257
|
|
30
|
-
one_div3 = 0.3333333333333333
|
|
31
|
-
two_div3 = 0.6666666666666666
|
|
32
|
-
inv_warp_grid = 5.0
|
|
33
|
-
warp_clamp = 1.7
|
|
34
|
-
warp_scale = 4.4
|
|
35
|
-
warp_amplitude = 0.015
|
|
36
|
-
warp_speed = 1.5
|
|
37
|
-
time_dilation = 0.2
|
|
38
|
-
|
|
39
|
-
# Colors
|
|
40
|
-
color_a = vec3(58.0 / 255.0, 1.0 / 255.0, 92.0 / 255.0)
|
|
41
|
-
color_b = vec3(201.0 / 255.0, 100.0 / 255.0, 128.0 / 255.0)
|
|
42
|
-
color_c = vec3(59.0 / 255.0, 206.0 / 255.0, 172.0 / 255.0)
|
|
43
|
-
color_d = vec3(17.0 / 255.0, 0.0 / 255.0, 28.0 / 255.0)
|
|
44
|
-
|
|
45
|
-
# Apply camera offset
|
|
46
|
-
base_ux = uv.x - 0.5 + u.camera_x
|
|
47
|
-
base_uy = uv.y - 0.5 + u.camera_y
|
|
48
|
-
|
|
49
|
-
# Zoomy warp
|
|
50
|
-
pos_x = base_ux * inv_warp_grid
|
|
51
|
-
pos_y = base_uy * inv_warp_grid
|
|
52
|
-
ax = floor(pos_x)
|
|
53
|
-
ay = floor(pos_y)
|
|
54
|
-
|
|
55
|
-
hash_a = hash21(vec2(ax, ay))
|
|
56
|
-
hash_b = hash21(vec2(ax + 1.0, ay))
|
|
57
|
-
hash_c = hash21(vec2(ax, ay + 1.0))
|
|
58
|
-
hash_d = hash21(vec2(ax + 1.0, ay + 1.0))
|
|
59
|
-
|
|
60
|
-
diff_x = pos_x - ax
|
|
61
|
-
diff_y = pos_y - ay
|
|
62
|
-
|
|
63
|
-
warp = hash_a + (hash_b - hash_a) * diff_x
|
|
64
|
-
warp = warp + ((hash_c + (hash_d - hash_c) * diff_x) - warp) * diff_y
|
|
65
|
-
warp = warp + u.time * warp_speed
|
|
66
|
-
|
|
67
|
-
smoothed = (1.0 + cos(warp * TAU)) * 0.5
|
|
68
|
-
clamped = smoothed * warp_scale - warp_clamp
|
|
69
|
-
clamped = clamp(clamped, 0.0, 1.0)
|
|
70
|
-
|
|
71
|
-
ux = base_ux + cos(clamped) * warp_amplitude
|
|
72
|
-
uy = base_uy + sin(clamped) * warp_amplitude
|
|
73
|
-
|
|
74
|
-
# Axial from pixel
|
|
75
|
-
axial_q = (sqrt3_div3 * ux - one_div3 * uy) * inv_hex_size
|
|
76
|
-
axial_r = two_div3 * uy * inv_hex_size
|
|
77
|
-
axial_s = 0.0 - axial_q - axial_r
|
|
78
|
-
|
|
79
|
-
# Axial round
|
|
80
|
-
q = floor(axial_q)
|
|
81
|
-
r = floor(axial_r)
|
|
82
|
-
s = floor(axial_s)
|
|
83
|
-
|
|
84
|
-
q_diff = abs(q - axial_q)
|
|
85
|
-
r_diff = abs(r - axial_r)
|
|
86
|
-
s_diff = abs(s - axial_s)
|
|
87
|
-
|
|
88
|
-
if q_diff > r_diff && q_diff > s_diff
|
|
89
|
-
q = 0.0 - r - s
|
|
90
|
-
elsif r_diff > s_diff
|
|
91
|
-
r = 0.0 - q - s
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Hash for hex cell
|
|
95
|
-
hash_val = hash21(vec2(q, r))
|
|
96
|
-
|
|
97
|
-
# Animated color value
|
|
98
|
-
value = fract(hash_val + u.time * time_dilation)
|
|
99
|
-
value = smoothstep(0.0, 1.0, value)
|
|
100
|
-
value = (1.0 + cos(value * TAU)) * 0.5
|
|
101
|
-
|
|
102
|
-
# Color mixing
|
|
103
|
-
ab = mix(color_a, color_b, value)
|
|
104
|
-
bc = mix(color_b, color_c, value)
|
|
105
|
-
cd = mix(color_c, color_d, value)
|
|
106
|
-
|
|
107
|
-
left = mix(ab, bc, value)
|
|
108
|
-
right = mix(bc, cd, value)
|
|
109
|
-
|
|
110
|
-
mix(left, right, value)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Initialize display
|
|
115
|
-
window = RBGL::GUI::Window.new(width: WIDTH, height: HEIGHT, title: "Chemical Heartbeat")
|
|
116
|
-
|
|
117
|
-
puts "Chemical Heartbeat"
|
|
118
|
-
puts "Original: https://www.shadertoy.com/view/lXtXD4"
|
|
119
|
-
puts "License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0"
|
|
120
|
-
puts "https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en"
|
|
121
|
-
puts "Press 'q' or Escape to quit"
|
|
122
|
-
|
|
123
|
-
start_time = Time.now
|
|
124
|
-
frame_count = 0
|
|
125
|
-
last_fps_time = start_time
|
|
126
|
-
running = true
|
|
127
|
-
|
|
128
|
-
buffer = "\x00" * (WIDTH * HEIGHT * 4)
|
|
129
|
-
|
|
130
|
-
while running && !window.should_close?
|
|
131
|
-
time = Time.now - start_time
|
|
132
|
-
|
|
133
|
-
# Camera movement
|
|
134
|
-
circle_value = time * 0.1
|
|
135
|
-
wave_value = time * 0.33
|
|
136
|
-
radius = 1.0 + Math.cos(wave_value) * 0.25
|
|
137
|
-
camera_x = Math.cos(circle_value) * radius
|
|
138
|
-
camera_y = Math.sin(circle_value) * radius
|
|
139
|
-
|
|
140
|
-
# Render using compiled shader
|
|
141
|
-
shader.render(buffer, WIDTH, HEIGHT, {
|
|
142
|
-
time: time,
|
|
143
|
-
camera_x: camera_x,
|
|
144
|
-
camera_y: camera_y
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
window.set_pixels(buffer)
|
|
148
|
-
|
|
149
|
-
events = window.poll_events_raw
|
|
150
|
-
events.each do |e|
|
|
151
|
-
if e[:type] == :key_press && (e[:key] == 12 || e[:key] == "q")
|
|
152
|
-
running = false
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
frame_count += 1
|
|
157
|
-
now = Time.now
|
|
158
|
-
if now - last_fps_time >= 1.0
|
|
159
|
-
fps = frame_count / (now - last_fps_time)
|
|
160
|
-
puts "FPS: #{fps.round(1)}"
|
|
161
|
-
frame_count = 0
|
|
162
|
-
last_fps_time = now
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
window.close
|
data/examples/dark_transit.rb
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Dark Transit
|
|
4
|
-
# Original: https://www.shadertoy.com/view/WcdczB
|
|
5
|
-
# 28 steps raymarching tunnel
|
|
6
|
-
# License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0
|
|
7
|
-
# https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
|
|
8
|
-
|
|
9
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
10
|
-
|
|
11
|
-
require "rbgl"
|
|
12
|
-
require "rlsl"
|
|
13
|
-
|
|
14
|
-
WIDTH = 640
|
|
15
|
-
HEIGHT = 480
|
|
16
|
-
|
|
17
|
-
shader = RLSL.define(:dark_transit) do
|
|
18
|
-
uniforms do
|
|
19
|
-
float :time
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Register helper function signatures for Ruby mode
|
|
23
|
-
functions do
|
|
24
|
-
define :get_t, returns: :float, params: { time: :float }
|
|
25
|
-
define :path_point, returns: :vec3, params: { z: :float }
|
|
26
|
-
define :noise_a, returns: :float, params: { f: :float, h: :float, k: :float, p: :vec3 }
|
|
27
|
-
define :cross_prod, returns: :vec3, params: { a: :vec3, b: :vec3 }
|
|
28
|
-
define :mat3_mul, returns: :vec3, params: { c0: :vec3, c1: :vec3, c2: :vec3, v: :vec3 }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
helpers do
|
|
32
|
-
def get_t(time)
|
|
33
|
-
time * 4.0 + 5.0 + 5.0 * sin(time * 0.3)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def path_point(z)
|
|
37
|
-
vec3(12.0 * cos(z * 0.1), 12.0 * cos(z * 0.12), z)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def noise_a(f, h, k, p)
|
|
41
|
-
abs(h * (sin(f * p.x * k) + sin(f * p.y * k) + sin(f * p.z * k))) / k
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def cross_prod(a, b)
|
|
45
|
-
vec3(
|
|
46
|
-
a.y * b.z - a.z * b.y,
|
|
47
|
-
a.z * b.x - a.x * b.z,
|
|
48
|
-
a.x * b.y - a.y * b.x
|
|
49
|
-
)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def mat3_mul(c0, c1, c2, v)
|
|
53
|
-
vec3(
|
|
54
|
-
c0.x * v.x + c1.x * v.y + c2.x * v.z,
|
|
55
|
-
c0.y * v.x + c1.y * v.y + c2.y * v.z,
|
|
56
|
-
c0.z * v.x + c1.z * v.y + c2.z * v.z
|
|
57
|
-
)
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
fragment do |frag_coord, resolution, u|
|
|
62
|
-
i_time = u.time
|
|
63
|
-
t_val = get_t(i_time)
|
|
64
|
-
|
|
65
|
-
# Scaled coords
|
|
66
|
-
screen_uv = vec2(
|
|
67
|
-
(frag_coord.x - resolution.x * 0.5) / resolution.y,
|
|
68
|
-
(frag_coord.y - resolution.y * 0.5) / resolution.y
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
# Cinema bars
|
|
72
|
-
if abs(screen_uv.y) > 0.375
|
|
73
|
-
vec3(0.0, 0.0, 0.0)
|
|
74
|
-
else
|
|
75
|
-
# Setup variables
|
|
76
|
-
t = 0.0
|
|
77
|
-
s = 0.0
|
|
78
|
-
i = 0.0
|
|
79
|
-
d = 0.0
|
|
80
|
-
e = 0.0
|
|
81
|
-
c = vec3(0.0, 0.0, 0.0)
|
|
82
|
-
|
|
83
|
-
# Camera path
|
|
84
|
-
p = path_point(t_val)
|
|
85
|
-
z_dir = normalize(path_point(t_val + 4.0) - p)
|
|
86
|
-
x_dir = normalize(vec3(z_dir.z, 0.0, 0.0 - z_dir.x))
|
|
87
|
-
|
|
88
|
-
# View matrix
|
|
89
|
-
neg_x = vec3(0.0 - x_dir.x, 0.0 - x_dir.y, 0.0 - x_dir.z)
|
|
90
|
-
cross_xz = cross_prod(x_dir, z_dir)
|
|
91
|
-
ray_d = mat3_mul(neg_x, cross_xz, z_dir, vec3(screen_uv.x, screen_uv.y, 1.0))
|
|
92
|
-
|
|
93
|
-
# Raymarching loop
|
|
94
|
-
while i < 28.0 && d < 30.0
|
|
95
|
-
i = i + 1.0
|
|
96
|
-
p = p + ray_d * s
|
|
97
|
-
x_dir = path_point(p.z)
|
|
98
|
-
t = sin(i_time)
|
|
99
|
-
|
|
100
|
-
# Orb position
|
|
101
|
-
orb = vec3(x_dir.x + t, x_dir.y + t * 2.0, 6.0 + t_val + t * 2.0)
|
|
102
|
-
e = length(p - orb) - 0.01
|
|
103
|
-
|
|
104
|
-
# Tunnel distance
|
|
105
|
-
px_offset = x_dir.x + 6.0
|
|
106
|
-
d1 = length(vec2(p.x - px_offset, p.y - px_offset))
|
|
107
|
-
d2 = length(vec2(p.x - x_dir.x, p.y - x_dir.y))
|
|
108
|
-
|
|
109
|
-
s = cos(p.z * 0.6) * 2.0 + 4.0 - min(d1, d2) + noise_a(4.0, 0.25, 0.1, p) + noise_a(8.0, 0.22, 2.0, p)
|
|
110
|
-
s = min(e, 0.01 + 0.25 * abs(s))
|
|
111
|
-
d = d + s
|
|
112
|
-
|
|
113
|
-
# Accumulate color
|
|
114
|
-
inv_s = 1.0 / s
|
|
115
|
-
inv_e = 10.0 / max(e, 0.6)
|
|
116
|
-
c = vec3(c.x + inv_s + inv_e, c.y + inv_s + inv_e * 2.0, c.z + inv_s + inv_e * 5.0)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Output color
|
|
120
|
-
vec3(c.x * c.x / 1000000.0, c.y * c.y / 1000000.0, c.z * c.z / 1000000.0)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Initialize display
|
|
126
|
-
window = RBGL::GUI::Window.new(width: WIDTH, height: HEIGHT, title: "Dark Transit")
|
|
127
|
-
|
|
128
|
-
puts "Dark Transit"
|
|
129
|
-
puts "Original: https://www.shadertoy.com/view/WcdczB"
|
|
130
|
-
puts "License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0"
|
|
131
|
-
puts "https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en"
|
|
132
|
-
puts "Press 'q' or Escape to quit"
|
|
133
|
-
|
|
134
|
-
start_time = Time.now
|
|
135
|
-
frame_count = 0
|
|
136
|
-
last_fps_time = start_time
|
|
137
|
-
running = true
|
|
138
|
-
|
|
139
|
-
buffer = "\x00" * (WIDTH * HEIGHT * 4)
|
|
140
|
-
|
|
141
|
-
while running && !window.should_close?
|
|
142
|
-
time = Time.now - start_time
|
|
143
|
-
|
|
144
|
-
shader.render(buffer, WIDTH, HEIGHT, { time: time })
|
|
145
|
-
|
|
146
|
-
window.set_pixels(buffer)
|
|
147
|
-
|
|
148
|
-
events = window.poll_events_raw
|
|
149
|
-
events.each do |e|
|
|
150
|
-
case e[:type]
|
|
151
|
-
when :key_press
|
|
152
|
-
running = false if e[:key] == 12 || e[:key] == "q"
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
frame_count += 1
|
|
157
|
-
now = Time.now
|
|
158
|
-
if now - last_fps_time >= 1.0
|
|
159
|
-
fps = frame_count / (now - last_fps_time)
|
|
160
|
-
puts "FPS: #{fps.round(1)}"
|
|
161
|
-
frame_count = 0
|
|
162
|
-
last_fps_time = now
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
window.close
|